Класс Blok: создание и уничтожение редактора
Главный класс редактора. Он создаёт экземпляр редактора Blok и управляет им. Любое пространство имён, доступное инструменту через api.*, есть и на самом экземпляре как editor.*. Свойства ниже описывают ту же поверхность плюс пространства имён width, placeholder, tokens и i18n, которые класс объявляет сам.
Как получить экземпляр редактора
Методы ниже вызываются на редакторе, созданном через new Blok(). Они доступны после того, как разрешится editor.isReady.
// You already hold the instance returned by the constructor.
const editor = new Blok({ holder: 'editor' });
await editor.isReady;
// Call any API method on it.
editor.caret.setToLastBlock('end');Методы
save()
Promise<OutputData>Извлекает текущее содержимое редактора в виде структурированных JSON-данных. Это основной метод для сохранения содержимого редактора.
Поля с форматированным текстом, например paragraph.text, хранят фрагменты: массивы { text, marks? }. Документ, сохранённый старой версией, может хранить HTML-строки, пока его не сохранят снова. migrateToRichText переводит его.
Когда использовать
Вызывайте его после await editor.isReady. Возвращённый JSON и есть ваш источник истины. Сохраните его и передайте обратно в render().
Ошибки
Редактор находится в режиме только для чтения в момент вызова save().
Blok's content can not be saved in read-only mode
Вызовите
readOnly.set(false)перед сохранением. Ещё можно сохранить данные из последнего вызоваonSaveили из собственного зеркального состояния.
// Save editor content
const data = await editor.save();
console.log(data.blocks); // Array of block datarender(data)
Promise<void>Отображает содержимое редактора из ранее сохранённых JSON-данных. Принимает нестрогий формат (LooseOutputData). Значение null для data, id или time блока из backend-DTO нормализуется на границе.
Когда использовать
Загружает сохранённый контент и заменяет текущий документ. Чтобы добавить контент, а не заменить, используйте blocks.insertMany().
// Load saved content
const savedData = {
blocks: [
{ id: '1', type: 'paragraph', data: { text: 'Hello' } }
]
};
await editor.render(savedData);focus(atEnd?)
booleanУстанавливает фокус на редактор. Может также поставить курсор в конец содержимого.
Когда использовать
Передайте true, чтобы поставить курсор в самый конец. Для конкретного блока или смещения используйте API caret.
// Focus at start
editor.focus();
// Focus at end
editor.focus(true);clear()
Promise<void>Удаляет всё содержимое редактора. Остаётся один пустой блок инструмента по умолчанию, поэтому редактор никогда не бывает без блоков. При этом следующий вызов save() всё равно вернёт blocks: []. Пустой блок по умолчанию не проходит валидацию и отбрасывается из результата.
Когда использовать
Удаляет все блоки и оставляет один пустой параграф. Это действие можно отменить, в отличие от destroy(), который уничтожает экземпляр.
// Clear all content
await editor.clear();destroy()
voidУничтожает экземпляр редактора и удаляет все DOM-элементы и обработчики событий.
Когда использовать
Вызывайте его из хука размонтирования вашего фреймворка, чтобы не утекли слушатели. После этого экземпляр использовать нельзя. Создайте новый Blok, чтобы начать заново.
// Clean up on component unmount
editor.destroy();handlers.set(handlers)
voidУстанавливает, заменяет или удаляет живые колбэки редактора на месте: onChange, onSave, onEnter, onSubmit, onBeforeRender, onAfterRender. Замена идёт на месте, поэтому курсор, выделение, прокрутка и история отмен сохраняются.
Затрагиваются только переданные ключи. Ключ со значением undefined СНИМАЕТ обработчик. Это важно, потому что само наличие колбэка задаёт поведение.
- С
onSubmitклавиша Enter выполняет сериализацию и отправку вместо разбиения блока. - С
onSaveвключается конвейер отслеживания изменений.
Используйте метод, чтобы сделать колбэк реактивным без пересоздания редактора. Адаптеры React, Vue и Angular вызывают этот сеттер за вас, когда prop, слушатель или колбэк из [config] появляется или исчезает.
Когда использовать
Затрагиваются только переданные ключи. Ключ со значением undefined снимает обработчик. Именно так режим «Enter отправляет» выключается обратно.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
handlers | LiveHandlers | Обязательный | — | Частичная карта живых колбэков. Пропущенные ключи остаются как есть. Ключ со значением |
// "Enter sends" while composing, default Enter while editing a draft
editor.handlers.set({
onSubmit: sendsOnEnter ? (data) => send(data) : undefined,
});
// Start mirroring content into your store, later stop again
editor.handlers.set({ onSave: (data) => store.set(data) });
editor.handlers.set({ onSave: undefined });whenAllReady(options?)
Promise<void>Статический метод. Он резолвится, когда каждый экземпляр Blok в заданной области завершил загрузку, то есть его isReady завершился. Отклонение тоже считается завершением. Это общий сигнал готовности для страниц с несколькими экземплярами, он заменяет ручную сборку колбэков onReady по каждому экземпляру.
- Передайте
within(Element), чтобы учитывать только экземпляры внутри вашего поддерева.- Тогда посторонний редактор на странице не сможет держать проверку закрытой.
- Передайте
settleOn: 'rendered', чтобы готовность означала не конец конструктора, а появление контента в DOM. Это покрывает и повторные рендеры черезrender(data)после загрузки.
Пустая область резолвится сразу. Экземпляры, появившиеся пока промис в ожидании, продлевают ожидание. Экземпляры, созданные после его резолва, не учитываются: вызовите метод снова или используйте subscribeReady() для живого сигнала.
Когда использовать
Вызывайте как Blok.whenAllReady() на классе, а не на экземпляре. Экземпляр, который ещё загружается, учитывается в любой области, даже если его обёртка ещё не добавлена в документ. Лишнее ожидание безопасно. Недостаточное является ошибкой.
// A comments list: N read-only bodies + a composer.
// Wait only for the editors inside this list.
await Blok.whenAllReady({
within: listElement,
settleOn: 'rendered',
});
composer.focus();readyState(options?)
{ total: number; pending: number; ready: boolean }Статический метод. Он даёт синхронный снимок готовности для области.
Снимок показывает, сколько экземпляров попадает в within. Он также показывает, сколько из них ещё не готовы на запрошенном уровне settleOn и готова ли область целиком. Пустая область возвращает ready: true, поэтому отдельная проверка «ждать нечего» не нужна.
Когда использовать
Метод достаточно дёшев, чтобы вызывать его на каждое уведомление из subscribeReady(). Он обходит зарегистрированные экземпляры и проверяет вложенность в DOM.
const { pending, ready } = Blok.readyState({ within: listElement });
if (!ready) {
showSkeleton(pending);
}subscribeReady(listener)
() => voidСтатический метод. Он подписывается на изменения готовности всех экземпляров (создание, загрузка, смена состояния рендера, уничтожение) и возвращает функцию отписки. Слушатель вызывается без аргументов, поэтому перечитывайте Blok.readyState(scope), когда он сработает. Подходит для useSyncExternalStore и других адаптеров хранилищ и даёт живой сигнал вместо одноразовой защёлки.
Когда использовать
Во фреймворках лучше использовать обёртки адаптеров: useBlokReady() в @bloklabs/react и @bloklabs/vue, injectBlokReady() в @bloklabs/angular. Они оборачивают эту подписку и поиск области.
const unsubscribe = Blok.subscribeReady(() => {
setReady(Blok.readyState({ within: listElement }).ready);
});
// later
unsubscribe();createSelector(attr, value?)
stringИменованный экспорт корня пакета, а не член класса Blok. Строит CSS-селектор по значению DATA_ATTR.
- Без
valueполучается селектор по наличию атрибута. - Со значением получается селектор по равенству.
Используйте его вместе с Blok.DATA_ATTR вместо поиска по внутренним именам классов Blok, которые не входят в публичную поверхность.
import { DATA_ATTR, createSelector } from '@bloklabs/core';
createSelector(DATA_ATTR.element); // '[data-blok-element]'
document.querySelectorAll(createSelector(DATA_ATTR.selected, true));icons
stringИменованные экспорты подпути @bloklabs/core/icons, а не члены класса Blok. Это собственные глифы Blok в виде SVG-строк, по одной константе Icon* на глиф (IconBold, IconPlus, IconTrash, IconWarning, …).
Это обычные строки, поэтому они подставляются прямо туда, где инструмент обязан отдать разметку: в иконку static get toolbox() инструмента и в элементы, которые возвращает renderSettings(). Подпуть поставляется со сгенерированным самодостаточным файлом деклараций (types/icons.d.ts), где перечислены все константы. Полный набор смотрите в автодополнении редактора кода.
import { IconBold, IconPlus } from '@bloklabs/core/icons';
class Callout {
static get toolbox() {
return { title: 'Callout', icon: IconPlus };
}
renderSettings() {
return [{ icon: IconBold, title: 'Bold text', onActivate: () => this.toggleBold() }];
}
}Свойства
| Свойство | Тип | Описание |
|---|---|---|
DATA_ATTR | Record<DataAttrKey, DataAttrValue> | Именованный экспорт корня пакета ( Так и следует запрашивать DOM редактора и писать тесты на стороне хоста вместо поиска по внутренним именам классов. Рядом с ним экспортируются типы |
BLOK_FONT_SIZE_TOKENS | BlokFontSizeTokens | Именованный экспорт корня пакета ( Используйте её везде, где типографика задаётся не конфигурацией конструктора, а другим каналом: CSS-правилом для отдельной области или |
version | string | Именованный экспорт корня пакета ( |
PendingBlok | { isReady; isRendered; destroy(); theme; width; placeholder; tokens; i18n } | Тип, экспортируемый из корня пакета ( Это поверхность, которая гарантированно существует синхронно между
|
isReady | Promise<Blok> | Promise, который разрешается готовым экземпляром редактора. Пространства имён API ниже ( |
isRendered | boolean | Синхронный флаг готовности рендера. Он равен true, когда текущая партия рендера попала в DOM, и повторяет атрибут |
blocks | Blocks | Модуль API для работы с блоками |
caret | Caret | Модуль API для управления курсором |
history | History | Модуль API истории |
saver | Saver | Модуль API сохранения |
toolbar | Toolbar | Модуль API панели инструментов |
inlineToolbar | InlineToolbar | Модуль API строчной панели |
tools | Tools | Модуль API инструментов |
uploader | Uploader | Модуль API загрузчика: загрузка ассетов с маршрутизацией по виду ассета |
events | Events | Модуль API событий |
listeners | Listeners | Модуль API слушателей |
notifier | Notifier | Модуль API уведомлений |
sanitizer | Sanitizer | Модуль API очистки |
selection | Selection | Модуль API выделения |
marks | Marks | Модуль API меток: операции со строчными метками с учётом диапазона |
styles | Styles | Модуль API стилей |
tooltip | Tooltip | Модуль API подсказок |
readOnly | ReadOnly | Модуль API режима только для чтения |
ui | Ui | Модуль API интерфейса |
theme | Theme | Модуль API темы |
width | Width | Модуль API ширины |
placeholder | Placeholder | Модуль API плейсхолдера |
tokens | Tokens | Модуль API токенов темы в рантайме |
i18n | EditorI18n | Модуль API i18n. Всё, что инструмент получает через |
config | Readonly<Pick<BlokConfig, 'linkPaste' | 'link'>> | Доступное только для чтения представление отдельных настроек редактора: опции |
rectangleSelection | { cancelActiveSelection(): void; isRectActivated(): boolean; clearSelection(): void; startSelection(pageX: number, pageY: number, shiftKey?: boolean): void; endSelection(): void } | Управление выделением перетаскиванием (рамкой). Доступно также внутри инструмента как
Его вызывает другая система выделения, например выделение ячеек таблицы, когда она забирает приоритет. |