Перейти к содержимому
Фреймворк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().

Ошибки

  • Редактор находится в режиме только для чтения в момент вызова save().

    Blok's content can not be saved in read-only mode

    Вызвать readOnly.set(false) перед сохранением либо сохранить данные из последнего вызова onSave / собственного зеркального состояния.

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

Именованный экспорт корня пакета (не член класса Blok) — строит CSS-селектор по значению `DATA_ATTR`. Без `value` получается селектор по наличию атрибута, с ним — селектор по равенству значения. Используйте его вместе с `Blok.DATA_ATTR` вместо совпадения по внутренним именам классов Blok, которые не входят в публичную поверхность.

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

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>Именованный экспорт корня пакета (`import { DATA_ATTR } from '@bloklabs/core'`), а не свойство экземпляра редактора — стабильные имена атрибутов `data-blok-*`, которые Blok пишет в своём DOM. Это поддерживаемый способ запрашивать DOM редактора и писать тесты на стороне хоста вместо совпадения по внутренним именам классов. Рядом с ним экспортируются типы `DataAttrKey` / `DataAttrValue` и хелпер `createSelector()`.
BLOK_FONT_SIZE_TOKENSBlokFontSizeTokensИменованный экспорт корня пакета (`import { BLOK_FONT_SIZE_TOKENS } from '@bloklabs/core'`), а не свойство экземпляра редактора — CSS-переменная, которую пишет каждый сценарий `style.fontSize`, в карте ровно той же формы, что и сама конфигурация (`BLOK_FONT_SIZE_TOKENS.paragraph`, `.heading[1]`, `.list.checklist`, `.bookmark.link`, …). Используйте её везде, где типографика задаётся не конфигурацией конструктора, а другим каналом — CSS-правилом для отдельной области или `editor.tokens.set({ [BLOK_FONT_SIZE_TOKENS.paragraph]: '18px' })` в рантайме, — чтобы имена CSS-переменных не приходилось копировать руками, а переименование становилось ошибкой компиляции, а не молча проходило впустую.
versionstringИменованный экспорт корня пакета (`import { version } from '@bloklabs/core'`), а не свойство экземпляра редактора — версия работающего редактора, то же значение, что попадает в `OutputData.version`.
PendingBlok{ isReady; isRendered; destroy(); theme; width; placeholder; tokens; i18n }Тип, экспортируемый из корня пакета (`import type { PendingBlok } from '@bloklabs/core'`), а не свойство экземпляра редактора — поверхность, которая гарантированно существует синхронно между `new Blok(config)` и разрешением `isReady`. Модульные API Blok (`blocks`, `caret`, `history`, `readOnly`, …) создаются асинхронно, поэтому чтение их раньше вернёт `undefined`. `PendingBlok` объявляет только восемь перечисленных здесь членов, что превращает это окно в ошибку компиляции вместо `undefined` в рантайме: `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 строчной панели
toolsToolsМодуль API инструментов
uploaderUploaderМодуль API загрузчика — загрузка ассетов с маршрутизацией по виду ассета
eventsEventsМодуль API событий
listenersListenersМодуль API слушателей
notifierNotifierМодуль API уведомлений
sanitizerSanitizerМодуль API очистки
selectionSelectionМодуль API выделения
marksMarksМодуль API меток — range-aware операции со строчными метками
stylesStylesМодуль API стилей
tooltipTooltipМодуль API подсказок
readOnlyReadOnlyМодуль API режима только для чтения
uiUiМодуль API интерфейса
themeThemeМодуль API темы
widthWidthМодуль API ширины
placeholderPlaceholderМодуль API плейсхолдера
tokensTokensМодуль API токенов темы в рантайме
i18nEditorI18nМодуль API i18n — всё, что инструмент получает через `api.i18n`, расширенное методом `update()`
configReadonly<Pick<BlokConfig, 'linkPaste' | 'link'>>Доступное только для чтения представление отдельных настроек редактора: опции `link` и `linkPaste`, с которыми был создан этот экземпляр. Собственный строчный инструмент или инструмент ссылок читает политику ссылок хоста отсюда (как `api.config`), а не выводит её заново.
rectangleSelection{ cancelActiveSelection(): void; isRectActivated(): boolean; clearSelection(): void; startSelection(pageX: number, pageY: number, shiftKey?: boolean): void; endSelection(): void }Управление выделением перетаскиванием (рамкой); доступно также внутри инструмента как `api.rectangleSelection`. `startSelection(pageX, pageY, shiftKey?)` начинает рамку от координат страницы; `endSelection()` сбрасывает состояние перетаскивания и прячет оверлей; `isRectActivated()` сообщает, активна ли рамка сейчас; `clearSelection()` снимает флаг активности; `cancelActiveSelection()` прерывает начатое выделение (clear + end) — это то, что вызывает другая система выделения, например выделение ячеек таблицы, когда она забирает приоритет.