Класс 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-данных. Основной метод для сохранения контента.
Когда использовать
Вызывайте после await editor.isReady. Возвращённый JSON — ваш источник истины: сохраните его и передайте обратно в render().
Ошибки
The editor is in read-only mode when save() is called.
Blok's content can not be saved in read-only mode
Call
readOnly.set(false)before saving, or persist from the lastonSavepayload / your own mirrored state.
// 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 | Обязательный | — | Частичная карта живых колбэков. Пропущенные ключи остаются как есть; ключ со значением undefined снимает обработчик. |
// "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?)
stringNamed export of the package root (not a member of the Blok class) — builds a CSS selector from a `DATA_ATTR` value. With no `value` it produces a presence selector; with one it produces an equality selector. Use it together with `Blok.DATA_ATTR` instead of matching Blok's internal class names, which are not part of the public surface.
import { DATA_ATTR, createSelector } from '@bloklabs/core';
createSelector(DATA_ATTR.element); // '[data-blok-element]'
document.querySelectorAll(createSelector(DATA_ATTR.selected, true));icons
stringNamed exports of the `@bloklabs/core/icons` subpath (not members of the Blok class) — Blok's own glyphs as SVG strings, one `Icon*` constant per glyph (`IconBold`, `IconPlus`, `IconTrash`, `IconWarning`, …). Because they are plain strings they drop straight into the places a tool must supply markup: a tool's `static get toolbox()` icon and the entries returned by `renderSettings()`. The subpath ships a generated, self-contained declaration file (`types/icons.d.ts`) listing every constant, so editor autocomplete is the reference for the full set.
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> | Named export of the package root (`import { DATA_ATTR } from '@bloklabs/core'`), not a property of the editor instance — the stable `data-blok-*` attribute names Blok writes on its DOM. This is the supported way to query editor DOM and write host tests, instead of matching internal class names. The `DataAttrKey` / `DataAttrValue` types and the `createSelector()` helper are exported alongside it. |
BLOK_FONT_SIZE_TOKENS | BlokFontSizeTokens | Named export of the package root (`import { BLOK_FONT_SIZE_TOKENS } from '@bloklabs/core'`), not a property of the editor instance — the CSS custom property each `style.fontSize` scenario writes, in a map shaped exactly like the config itself (`BLOK_FONT_SIZE_TOKENS.paragraph`, `.heading[1]`, `.list.checklist`, `.bookmark.link`, …). Use it wherever typography is driven by a channel other than the constructor config — a per-region CSS rule, or `editor.tokens.set({ [BLOK_FONT_SIZE_TOKENS.paragraph]: '18px' })` at runtime — so the custom property names never have to be hand-copied and a rename is a compile error instead of a silent no-op. |
version | string | Named export of the package root (`import { version } from '@bloklabs/core'`), not a property of the editor instance — the running editor version, the same value stamped into `OutputData.version`. |
PendingBlok | { isReady; isRendered; destroy(); theme; width; placeholder; tokens; i18n } | A type exported from the package root (`import type { PendingBlok } from '@bloklabs/core'`), not a property of the editor instance — the surface guaranteed to exist synchronously between `new Blok(config)` and `isReady` resolving. Blok builds its module APIs (`blocks`, `caret`, `history`, `readOnly`, …) asynchronously, so reading them earlier returns `undefined`. `PendingBlok` declares only the eight members listed here, which turns that window into a compile error instead of an `undefined` at runtime: `const pending: PendingBlok = new Blok(config); const editor = await pending.isReady;`. |
isReady | Promise<Blok> | Promise, который разрешается готовым экземпляром редактора. Пространства имён API ниже (`blocks`, `caret`, `history`, `readOnly`, …) создаются асинхронно и равны `undefined`, пока он не разрешится — типизируйте ссылку, которой владеете в этот момент, как `PendingBlok`. |
isRendered | boolean | Синхронный флаг готовности рендера — true, когда текущая партия рендера попала в DOM (отражает атрибут `data-blok-rendered` на обёртке); false до первого рендера и во время повторного. Дополняет асинхронные `isReady`/`onReady`: не нужны await или колбэк, состояние монтирования можно опрашивать синхронно. |
blocks | Blocks | Модуль API для работы с блоками |
caret | Caret | Модуль API для управления курсором |
history | History | Модуль API истории |
saver | Saver | Модуль API сохранения |
toolbar | Toolbar | Модуль API панели инструментов |
inlineToolbar | InlineToolbar | Модуль API строчной панели |
tools | Tools | Tools API module |
uploader | Uploader | Uploader API module — asset uploads routed by asset kind |
events | Events | Модуль API событий |
listeners | Listeners | Listeners API module |
notifier | Notifier | Notifier API module |
sanitizer | Sanitizer | Sanitizer API module |
selection | Selection | Selection API module |
marks | Marks | Marks API module — range-aware inline-mark operations |
styles | Styles | Styles API module |
tooltip | Tooltip | Tooltip API module |
readOnly | ReadOnly | ReadOnly API module |
ui | Ui | UI API module |
theme | Theme | Theme API module |
width | Width | Width API module |
placeholder | Placeholder | Placeholder API module |
tokens | Tokens | Runtime theme-tokens API module |
i18n | EditorI18n | I18n API module — everything a tool gets through `api.i18n`, widened with `update()` |
config | Readonly<Pick<BlokConfig, 'linkPaste' | 'link'>> | Read-only view of selected editor configuration: the `link` and `linkPaste` options this instance was constructed with. A custom inline or link tool reads the host's link policy from here (as `api.config`) instead of re-deriving it. |
rectangleSelection | { cancelActiveSelection(): void; isRectActivated(): boolean; clearSelection(): void; startSelection(pageX: number, pageY: number, shiftKey?: boolean): void; endSelection(): void } | Drag-select (rubber-band) control, also reachable inside a tool as `api.rectangleSelection`. `startSelection(pageX, pageY, shiftKey?)` begins a rubber-band from page coordinates; `endSelection()` resets the drag state and hides the overlay; `isRectActivated()` reports whether a rubber-band is currently active; `clearSelection()` drops the active flag; `cancelActiveSelection()` aborts a selection in progress (clear + end) — what another selection system, e.g. table cell selection, calls when it takes priority. |