Skip to content
ФреймворкJavaScript

Класс Blok: создание и уничтожение редактора

Основной класс редактора, который инициализирует экземпляр редактора Blok и управляет им. Любое пространство имён, доступное инструменту через `api.*`, доступно и на самом экземпляре как `editor.*` — свойства ниже описывают ту же поверхность плюс пространства имён `width`, `placeholder`, `tokens` и `i18n`, которые класс объявляет сам.

Обновлено 30 июн. 2026 г.Редактировать на GitHub

Как получить экземпляр редактора

Методы ниже вызываются на редакторе, созданном через new Blok(). Они доступны после того, как разрешится editor.isReady.

TypeScript
// 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 last onSave payload / your own mirrored state.

TypeScript
// Save editor content
const data = await editor.save();
console.log(data.blocks); // Array of block data

render(data)

Promise<void>

Отображает содержимое редактора из ранее сохранённых JSON-данных. Принимает нестрогий формат (`LooseOutputData`) — значения `null` для `data`, `id` или `time` блока из backend-DTO нормализуются на границе.

Когда использовать

Загружает сохранённый контент и заменяет текущий документ. Чтобы добавить, а не заменить, используйте blocks.insertMany().

TypeScript
// Load saved content
const savedData = {
  blocks: [
    { id: '1', type: 'paragraph', data: { text: 'Hello' } }
  ]
};
await editor.render(savedData);

focus(atEnd?)

boolean

Устанавливает фокус на редактор. Опционально позиционирует курсор в конце содержимого.

Когда использовать

Передайте true, чтобы поставить курсор в самый конец. Для конкретного блока или смещения используйте API caret.

TypeScript
// Focus at start
editor.focus();

// Focus at end
editor.focus(true);

clear()

Promise<void>

Удаляет всё содержимое редактора. Остаётся один пустой блок инструмента по умолчанию, поэтому редактор никогда не остаётся без блоков — при этом последующий save() всё равно вернёт `blocks: []`, так как пустой блок по умолчанию не проходит валидацию и отбрасывается из результата.

Когда использовать

Удаляет все блоки и оставляет один пустой параграф. Действие отменяемо — в отличие от destroy(), уничтожающего экземпляр.

TypeScript
// Clear all content
await editor.clear();

destroy()

void

Уничтожает экземпляр редактора и удаляет все DOM-элементы и обработчики событий.

Когда использовать

Вызывайте из хука размонтирования вашего фреймворка, чтобы не утекли слушатели. После этого экземпляр непригоден — создайте новый Blok.

TypeScript
// 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 отправляет» выключается обратно.

Параметры

ПараметрТипОбязательныйПо умолчаниюОписание
handlersLiveHandlersОбязательныйЧастичная карта живых колбэков. Пропущенные ключи остаются как есть; ключ со значением undefined снимает обработчик.
TypeScript
// "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() на классе, а не на экземпляре. Экземпляр, который ещё загружается и чья обёртка не добавлена в документ, учитывается в любой области — лишнее ожидание безопасно, недостаточное является ошибкой.

TypeScript
// 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.

TypeScript
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 — они оборачивают эту подписку и поиск области видимости.

TypeScript
const unsubscribe = Blok.subscribeReady(() => {
  setReady(Blok.readyState({ within: listElement }).ready);
});

// later
unsubscribe();

createSelector(attr, value?)

string

Named 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.

TypeScript
import { DATA_ATTR, createSelector } from '@bloklabs/core';

createSelector(DATA_ATTR.element); // '[data-blok-element]'
document.querySelectorAll(createSelector(DATA_ATTR.selected, true));

icons

string

Named 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.

TypeScript
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_ATTRRecord<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_TOKENSBlokFontSizeTokensNamed 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.
versionstringNamed 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;`.
isReadyPromise<Blok>Promise, который разрешается готовым экземпляром редактора. Пространства имён API ниже (`blocks`, `caret`, `history`, `readOnly`, …) создаются асинхронно и равны `undefined`, пока он не разрешится — типизируйте ссылку, которой владеете в этот момент, как `PendingBlok`.
isRenderedbooleanСинхронный флаг готовности рендера — true, когда текущая партия рендера попала в DOM (отражает атрибут `data-blok-rendered` на обёртке); false до первого рендера и во время повторного. Дополняет асинхронные `isReady`/`onReady`: не нужны await или колбэк, состояние монтирования можно опрашивать синхронно.
blocksBlocksМодуль API для работы с блоками
caretCaretМодуль API для управления курсором
historyHistoryМодуль API истории
saverSaverМодуль API сохранения
toolbarToolbarМодуль API панели инструментов
inlineToolbarInlineToolbarМодуль API строчной панели
toolsToolsTools API module
uploaderUploaderUploader API module — asset uploads routed by asset kind
eventsEventsМодуль API событий
listenersListenersListeners API module
notifierNotifierNotifier API module
sanitizerSanitizerSanitizer API module
selectionSelectionSelection API module
marksMarksMarks API module — range-aware inline-mark operations
stylesStylesStyles API module
tooltipTooltipTooltip API module
readOnlyReadOnlyReadOnly API module
uiUiUI API module
themeThemeTheme API module
widthWidthWidth API module
placeholderPlaceholderPlaceholder API module
tokensTokensRuntime theme-tokens API module
i18nEditorI18nI18n API module — everything a tool gets through `api.i18n`, widened with `update()`
configReadonly<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.