TextEditor - это текстовой редактор для веб-приложений на JavaScript с акцентом на надежность, доступность и производительность. TextEditorR7 нацелен на предоставление оптимального опыта разработчика, чтобы вы могли легко создавать прототипы и внедрять функции с уверенностью. Совмещенный с высокорасширяемой архитектурой, TextEditorR7 позволяет разработчикам создавать уникальные текстовые редакторы, масштабирующиеся по размеру и функциональности
import { Editor } from '@sinups/editor-dsd';
Инициализация текстового редактора.
По умолчанию TextEditorR7 работает с объектом и может возвращать объект или HTML.
Пример с объектом:
const text = 'Hello world';
const json = {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: text,
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
};
const onChange = (
data // json
) => <Editor initialContent={json} onChange={onChange} />;
Также в редактор можно передать HTML-строку.
Пример с HTML:
const html = `
<h2 dir="ltr" style="text-align: left;">
<span style="background-color: rgb(248, 231, 28); font-family: "Trebuchet MS"; white-space: pre-wrap;">Hello</span>
</h2>
<h2 dir="ltr">
<br>
</h2>
<p dir="ltr">
<br>
</p>
<p dir="ltr">
<span style="font-size: 21px; white-space: pre-wrap;">world</span>
</p>
`
const onChange = (data) => // json
<Editor initialContent={html} onChange={onChange} />
За вывод данных в функции onChange отвечает свойство outputFormat. outputFormat может быть равен либо "html", либо "json". Пример с outputFormat:
const html = `
<h2 dir="ltr" style="text-align: left;">
<span style="background-color: rgb(248, 231, 28); font-family: "Trebuchet MS"; white-space: pre-wrap;">Hello</span>
</h2>
<h2 dir="ltr">
<br>
</h2>
<p dir="ltr">
<br>
</p>
<p dir="ltr">
<span style="font-size: 21px; white-space: pre-wrap;">world</span>
</p>
`
const onChange = (data) => // html
<Editor initialContent={html} outputFormat="html" onChange={onChange} />
Используйте DocSpaceStylesProvider, чтобы добавить стили оформления к вашему HTML-контенту.
<DocSpaceStylesProvider>
<div
dangerouslySetInnerHTML={{ __html: '<p>Your html here</p>' }}
/>
</DocSpaceStylesProvider>
Чтобы начать работать с загрузкой картинок используйте функцию fetchUploadImage, которая принимает три параметра, file,success и error. После успешной загрузки картинок на ваш сервис нужно вызвать функцию success и передать два обязательных аргумента, URL изображения и ID.
const fetchUploadImage = async (
file: File,
success: (url: string, id: string) => void,
error?: (error?: Error) => void
) => {
const formData = new FormData();
formData.append('File', file);
formData.append('FileAccessModifier', '0');
try {
const response = await fetch('/api/v1/Files/Upload', {
method: 'POST',
body: formData,
credentials: 'include'
});
if (!response.ok) {
throw new Error('File upload failed');
}
const data = await response.json();
const { Id, Url } = data;
success(Url, Id);
} catch (err) {
if (error) {
if (err instanceof Error) {
error(err);
} else {
error(new Error('An unknown error occurred'));
}
}
}
};
<Editor
...props
fetchUploadImage={fetchUploadImage}
/>
Чтобы иметь больший контроль над удалением картинки передайте в редактор необязательную функцию fetchDeleteImage которая принимает три параметра, id, success и error. После успешного удаления картинки из вашего сервиса нужно вызвать функцию success.
const fetchDeleteImage = async (
id: string,
success: () => void,
error?: (error?: Error) => void
) => {
const body = { Ids: [id] };
try {
const response = await fetch('/api/v1/Documents/Delete', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body),
credentials: 'include'
});
await response.json();
success();
} catch (err) {
if (error) {
if (err instanceof Error) {
error(err);
} else {
error(new Error('An unknown error occurred'));
}
}
}
};
<Editor
...props
fetchUploadImage={fetchUploadImage}
fetchDeleteImage={fetchUploadImage}
/>
import { Editor, Dropzone } from "@sinups/editor-dsd";
const Content = () => (
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
{/*
Компоненты Dropzone.Accept, Dropzone.Reject и Dropzone.Idle видны только тогда, когда пользователь выполняет
определенное действие:
Dropzone.Accept отображается только тогда, когда пользователь перетаскивает файл, который можно принять, в зону сброса.
Dropzone.Reject отображается только тогда, когда пользователь перетаскивает файл, который не может быть принят, в зону сброса.
Dropzone.Idle виден, когда пользователь ничего не перетаскивает в зону сброса.
*/}
<Dropzone.Accept>
<IconUpload
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-blue-6)' }}
stroke={1.5}
/>
</Dropzone.Accept>
<Dropzone.Reject>
<IconX
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-red-6)' }}
stroke={1.5}
/>
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto
style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-dimmed)' }}
stroke={1.5}
/>
</Dropzone.Idle>
<div>
<Text size="xl" inline>
Перетащите изображения сюда или нажмите, чтобы выбрать файлы
</Text>
<Text size="sm" c="dimmed" inline mt={7}>
Прикрепляйте столько файлов, сколько хотите, каждый файл не должен превышать{' '}
{maxImageSize} МБ.
</Text>
</div>
</Group>
);
<Editor
...props
fetchUploadImage={fetchUploadImage}
contentModalUploadImage={Content}
maxImageSize={5}
maxImageSizeError={() => {}}
/>
<Editor
...props
ws={{
url: 'https://wss.dudoc.io/', //cсылка на websocket
id: '322323', // уникальный id документа
user: userProfile, // текущий пользователь
getActiveUsers: (users) => { / возвращает активных пользователей редактирующий документ
setActiveUsers(users);
}
}}
/>
import { CLEAR_EDITOR_COMMAND } from './EditorLexical';
<>
<button
onClick={() => {
if (editorRef.current) {
editorRef.current.update(() => {
editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
});
}
}}
>
Reset
</button>
<Editor
...props
editorRef={editorRef}
/>
<>
onChange: (value: string | object) => undefined - функция, срабатывает при каждом изменении редактора и возвращает HTML-строку или объект в зависимости от свойства outputFormat.
debounce?: number - Как часто вызывается функция onChange в ms.
onBlur: (value: string | object) => undefined - функция, срабатывает при расфокусировки редактора и возвращает HTML-строку или объект в зависимости от свойства outputFormat.
outputFormat?: 'html' | 'json' - свойство outputFormat передается, если мы хотим на выходе получать HTML-строку, по умолчанию json.
initialContent: string | object - изначальные данные для редактора.
placeholder?: string - подсказка пока текст не введен.
maxHeight?: number - задает высоту редактора, по умолчанию 100%.
mode?: 'simple' | 'default' | 'full' | 'editor' - режим редактора: в зависимости от выбранного режима урезается или добавляется новый функционал. По умолчанию default.
fetchUploadImage?: (file: File, success: (url: string, id: string, error?: (error?: Error) => void) => void - Функция для загрузки картинки на ваш сервис.
fetchDeleteImage?: (id: string, success: () => void, error?: (error?: Error) => void - Вспомогательная функция для удаления картинки
maxImageSize?: number - Максимальный размер картинки в мегабайтах
contentModalUploadImage?: React.FunctionComponent - React компонент для замены контента в DropZone
maxImageSizeError?: () => void - Функция вызывается если картинка превышает размер maxImageSize
disable?: boolean - Переключает в режим чтения
ws?:{{
url: string - //cсылка на websocket
id: string // уникальный id документа
user: {color: string, name: string}, // текущий пользователь
getActiveUsers: (users) => void / возвращает активных пользователей редактирующий документ
}}
editorRef?: {current: EditorType | null} // ссылка на редактор