Blocks API: вставка, перенос и удаление блоков
Управление блоками в редакторе: создание, удаление, обновление и переупорядочивание контента.
Как получить экземпляр редактора
Методы ниже вызываются на редакторе, созданном через 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');Методы
blocks.clear()
Promise<void>Удалить все блоки из редактора.
Когда использовать
То же самое, что clear() верхнего уровня, но на модуле blocks. Используйте, когда у вас уже есть ссылка на editor.blocks.
await editor.blocks.clear();
// All content removed; editor keeps one empty paragraphblocks.render(data)
Promise<void>Отрисовывает переданные JSON-данные как блоки и заменяет текущий документ. Метод устойчив к эху: если входящий документ структурно равен текущему сохранённому содержимому (time и version игнорируются), вызов становится no-op и сохраняет курсор. Поэтому круговому пути data → render → onSave → setState → data не нужна дедупликация на вашей стороне.
Метод принимает нестрогий формат (LooseOutputData). Редактор делает глубокую копию данных, поэтому переданный объект не мутируется и не удерживается. Замороженное состояние хранилища (Redux, Immer) можно передавать напрямую.
Рендер, который заменяет документ, также очищает историю отмен, поэтому отмена не вернёт предыдущий документ.
Когда использовать
Заменяет весь документ. Повторная передача собственного вывода редактора становится no-op и сохраняет курсор, поэтому дедупликация на вашей стороне не нужна. Чтобы добавить блоки без очистки, используйте insert() или insertMany().
const data = {
blocks: [
{ id: '1', type: 'paragraph', data: { text: 'Hello World' } },
{ id: '2', type: 'header', data: { text: 'Title', level: 1 } }
]
};
await editor.blocks.render(data);blocks.renderFromHTML(data)
Promise<void>Отрисовать HTML-строку как блоки, преобразовав её в формат блоков.
Когда использовать
Удобно для импорта старого HTML, но результат зависит от обработчиков вставки в инструментах. Если источник под вашим контролем, JSON через render() сохраняет больше точности.
const html = '<h1>Title</h1><p>Hello World</p>';
await editor.blocks.renderFromHTML(html);
// HTML is converted to appropriate blocksblocks.importMarkdown(md, options?)
Promise<OutputData>Преобразует Markdown-строку в блоки и отрисовывает их. Это ЗАМЕНЯЕТ текущий документ, потому что внутри вызывается blocks.render().
Конвертер загружается лениво при первом вызове. Промис резолвится тем OutputData, который был отрисован. Параметр options имеет тип MarkdownImportConfig (сопоставление инструментов, переключатель GFM, расширения micromark/mdast).
Чтобы добавить блоки, а не заменить документ, используйте markdownToBlocks() из отдельного подпути @bloklabs/core/markdown вместе с blocks.insertMany().
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
md | string | Обязательный | — | Исходная Markdown-строка. |
options | MarkdownImportConfig | — | undefined | Сопоставление инструментов, переключатель GFM и расширения micromark/mdast. |
const data = await editor.blocks.importMarkdown('# Title\n\n- one\n- two');
// The whole document is replaced; data is the rendered OutputDatablocks.exportMarkdown()
Promise<string>Сериализует текущий документ в Markdown. Это исходящий близнец importMarkdown. Блоки читаются через Saver, поэтому вывод отражает сохранённый (провалидированный) документ, а не сырой DOM.
Промис резолвится в '', когда сохранять нечего. Блоки, принадлежащие ячейке таблицы, сериализуются внутри pipe-таблицы, а не повторяются отдельными строками.
То, что Markdown выразить не может, деградирует.
- Значения
colspanиrowspanтаблицы и столбцы заголовков отбрасываются. - Таблица без строки заголовков получает пустую строку заголовка, потому что GFM её требует.
const md = await editor.blocks.exportMarkdown();
// → '# Title\n\n- one\n- two'blocks.delete(index?, setCaret?)
Promise<void>Удалить блок по указанному индексу или текущий блок, если индекс не передан.
Когда использовать
Без индекса удаляет блок в фокусе. Удаление последнего оставшегося блока автоматически вставляет свежий пустой параграф, поэтому редактор никогда не остаётся без цели для курсора.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
index | number | — | current block index | Индекс блока для удаления. |
setCaret | boolean | — | true | Перемещать ли курсор на уцелевший блок после удаления. Передайте false, чтобы не отбирать курсор у пользователя при программном удалении. |
// Delete current block
await editor.blocks.delete();
// Delete block at index 0
await editor.blocks.delete(0);
// Delete without moving the user's caret (programmatic deletion)
await editor.blocks.delete(0, false);blocks.move(toIndex, fromIndex?)
voidПеремещает блок на новую позицию. Если fromIndex не передан, перемещает текущий блок.
Когда использовать
toIndex задаётся в индексах после удаления блока. При перемещении вперёд вычтите 1, иначе блок встанет на одну позицию дальше нужной.
// Move current block to top
editor.blocks.move(0);
// Move block from index 2 to index 0
editor.blocks.move(0, 2);blocks.getBlockByIndex(index)
BlockAPI | undefinedПолучить объект BlockAPI для блока по указанному индексу.
Когда использовать
Возвращает undefined для индексов вне диапазона. Вызов метода на результате undefined приведёт к ошибке, поэтому сначала проверьте результат.
const block = editor.blocks.getBlockByIndex(0);
if (block) {
console.log(block.id, block.name);
}blocks.getById(id)
BlockAPI | nullПолучить объект BlockAPI для блока с указанным ID.
Когда использовать
Надёжный способ ссылаться на блок между правками, так как индексы смещаются. Возвращает null, если id больше не существует.
const block = editor.blocks.getById('block-123');
if (block) {
await editor.blocks.update(block.id, { text: 'New content' });
}blocks.getCurrentBlockIndex()
numberПолучить индекс блока, который сейчас в фокусе.
Когда использовать
Отражает блок с курсором. Возвращает -1, когда ничего не в фокусе. Проверяйте значение, прежде чем использовать его как индекс.
const index = editor.blocks.getCurrentBlockIndex();
console.log('Current block index:', index);blocks.getBlockIndex(blockId)
number | undefinedПолучить индекс блока по его ID.
Когда использовать
Находит текущую позицию известного блока. Сочетайте его с getById(), когда есть id, а нужна позиция.
const index = editor.blocks.getBlockIndex('block-123');
if (index !== undefined) {
console.log('Block is at index:', index);
}blocks.getBlockByElement(element)
BlockAPI | undefinedПолучить объект BlockAPI для блока, который содержит переданный HTML-элемент.
Когда использовать
Мост от DOM-узла (например, от цели клика) обратно к его блоку. Полезно в собственных обработчиках событий.
document.addEventListener('click', (e) => {
const block = editor.blocks.getBlockByElement(e.target);
if (block) {
console.log('Clicked on block:', block.id);
}
});blocks.scrollToBlock(id)
voidПрокручивает страницу к блоку, выделяет его, показывает подсветку прибытия и объявляет переход вспомогательным технологиям. Это публичный аналог прокрутки по хешу URL при загрузке. Если блока с таким id в документе нет, метод ничего не делает.
Новый переход заменяет уже выделенные блоки. Передайте вторым аргументом { select: false }, чтобы перейти без выделения, как это делает навигация по странице, например оглавление: выделенный блок удаляется следующим нажатием Backspace.
Адаптеры фреймворков, которые монтируются в отсоединённый холдер (React/Vue/Angular), отрисовывают засеянный контент до того, как он попадёт на страницу, поэтому загрузочная прокрутка по хешу откладывается. @bloklabs/react выполняет её автоматически, как только холдер подключается.
Для глубоких ссылок вызывайте этот метод сами, после того как редактор готов.
editor.blocks.scrollToBlock(nodeId);blocks.getChildren(parentId)
BlockAPI[]Получить все дочерние блоки родительского блока-контейнера.
Когда использовать
Возвращает прямых потомков блока-контейнера (колонки, тоггла или базы данных). Пустой массив, если потомков нет.
const children = editor.blocks.getChildren('parent-block-id');
children.forEach(child => {
console.log('Child:', child.id);
});blocks.setBlockParent(blockId, parentId)
voidМеняет родителя блока. Обновляет parentId блока и contentIds родителя через единственную в ядре точку смены родителя.
- Передайте
null, чтобы вернуть блок на корневой уровень. - Неизвестный
blockIdничего не делает и пишет предупреждение в лог. parentId, который сделал бы блок потомком самого себя, выбрасывает ошибку.
Место блока в порядке документа следует за новым родителем.
- Если блок уже стоит внутри поддерева родителя, он не перемещается. Это значит, что он идёт сразу после родителя или сразу после одного из его потомков.
- Иначе блок переезжает в конец поддерева родителя. Его собственные дочерние блоки переезжают вместе с ним.
- Таблица и база данных сами расставляют свои дочерние блоки, поэтому блок, который к ним присоединяется, не перемещается.
- Блок, который уходит на корневой уровень или к одному из своих предков, переезжает вместе с дочерними блоками сразу за поддерево, из которого ушёл, если он ещё не стоит там. Чтобы вынести из контейнера несколько соседних блоков и сохранить их порядок, начните с последнего.
// Move a block into a container block
editor.blocks.setBlockParent('child-block-id', 'parent-block-id');
// Move it back to the root level
editor.blocks.setBlockParent('child-block-id', null);blocks.insertInsideParent(parentId, insertIndex, childData?, toolName?)
BlockAPIВставляет блок как дочерний для parentId атомарно. Создание и назначение родителя объединяются в ОДИН шаг отмены, поэтому одно нажатие Cmd+Z убирает блок полностью. Это лучше, чем insert() с последующей сменой родителя: там шага два.
- Параметр
insertIndexзадаёт ПЛОСКИЙ индекс документа, по которому должен появиться дочерний блок. Индекс ограничивается поддеревом родителя.- Индекс на месте родителя или раньше него превращается в позицию сразу после родителя.
- Индекс за концом поддерева превращается в конец поддерева.
toolNameвыбирает блочный инструмент дочернего блока и по умолчанию равенconfig.defaultBlock.- Инструмент, запрещённый внутри ячеек таблицы, понижается до блока по умолчанию, если новый дочерний блок попал бы в такую ячейку.
- Незарегистрированное имя выбрасывает ошибку до того, как что-либо будет записано.
childDataпо умолчанию равен{ text: '' }для блока по умолчанию.- Для любого другого
toolNameзначение по умолчанию равно{}, и тогда инструмент применяет собственные значения по умолчанию.
- Для любого другого
const parentIndex = editor.blocks.getBlockIndex('parent-block-id') ?? 0;
const child = editor.blocks.insertInsideParent(
'parent-block-id',
parentIndex + 1,
{ text: 'Nested content' },
);
// A TYPED child in the same single undo entry — no insert-then-reparent
editor.blocks.insertInsideParent(
'parent-block-id',
parentIndex + 1,
{ text: 'Nested heading', level: 2 },
'header',
);blocks.insertAt(type?, data?, options?)
BlockAPIВставляет новый блок в место, заданное родителем и соседями, а не плоским индексом. Это ОДИН шаг отмены.
positionпринимает'start','end'(по умолчанию),{ before: id }или{ after: id }.{ after: id }ставит блок после всего поддерева этого соседа, а не среди его детей.
parentIdзадаёт родителя;nullозначает корень.- Если его не передать,
before/afterберут родителя соседа, а'start'/'end'ставят блок в корень.
- Если его не передать,
replace: idставит новый блок на место этого блока. Родитель сохраняется, а дети следуют правилам смены типа блока. Нельзя сочетать сparentIdилиposition.focusпо умолчаниюfalse, поэтому программная вставка не меняет текущий блок.- Инструмент, который родитель не разрешает, заменяется, как в
insertInsideParent.
Метод бросает ошибку и ничего не меняет, если не найден родитель, сосед или заменяемый блок, или если сосед не является дочерним для parentId.
// Last child of a toggle
editor.blocks.insertAt('paragraph', { text: 'Inside' }, { parentId: toggleId });
// Right after a block's whole subtree, at the block's own level
editor.blocks.insertAt('header', { text: 'Next', level: 2 }, { position: { after: blockId } });
// First block of the document
editor.blocks.insertAt('paragraph', { text: 'Top' }, { parentId: null, position: 'start' });blocks.moveTo(id, target)
voidПеремещает блок вместе со всем поддеревом в место, заданное родителем и соседями. Это ОДИН шаг отмены, даже если меняется родитель.
positionработает так же, как вinsertAt.{ after: id }ставит блок после всего поддерева соседа.parentIdзадаёт нового родителя;nullозначает корень. Если его не передать,before/afterберут родителя соседа, а'start'/'end'ставят блок в корень.
Метод бросает ошибку и ничего не меняет, если:
- блок не найден или сосед не является дочерним для
parentId; - цель указывает на сам блок или на место внутри его поддерева;
- перемещение выводит блок из контейнера, который сам управляет детьми (таблица, ряд колонок), из колонки или ячейки таблицы, либо вводит его туда;
- новый родитель не разрешает этот инструмент (
childTools).
// Into a toggle, as its first child
editor.blocks.moveTo(blockId, { parentId: toggleId, position: 'start' });
// Out of a container, right after it
editor.blocks.moveTo(childId, { position: { after: containerId } });blocks.getBlocksCount()
numberПолучить общее количество блоков в редакторе.
Когда использовать
Считает все блоки, включая вложенные дочерние (колонки, тогглы, ячейки таблиц), а не только блоки верхнего уровня. Используйте его для проверки границ перед insert() или move() по индексу.
const count = editor.blocks.getBlocksCount();
console.log('Total blocks:', count);blocks.insert(type?, data?, config?, index?, needToFocus?, replace?, id?, tunes?, origin?)
BlockAPIВставить новый блок с полным контролем над его свойствами и позицией.
Когда использовать
Все параметры необязательны. Вызовите insert(), чтобы получить пустой параграф, или передайте type/data/index для полного контроля. Передайте replace: true, чтобы заменить блок по индексу index.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
type | string | — | config.defaultBlock | Имя инструмента для создания блока. |
data | BlockToolData | — | {} | Начальные данные инструмента для нового блока. |
config | ToolConfig | — | {} | Игнорируется. Принимается только ради того, чтобы позиционная сигнатура оставалась стабильной. Редактор связывает его с Передавайте |
index | number | — | current block index + 1 | Позиция для вставки блока. Новый блок также получает родителя, которого подразумевает эта позиция. Это верно и тогда, когда
Строка колонок никогда не принимает блок таким способом. Сразу после таблицы или базы данных, а также после блока внутри них, родитель не подбирается. Блок становится корневым, если только он не идёт сразу после блока в колонке. При Действуют правила |
needToFocus | boolean | — | true | Переводить ли фокус на вставленный блок. Передайте false, чтобы вставить блок, не перемещая курсор. |
replace | boolean | — | false | Заменить существующий блок по индексу вместо вставки рядом с ним. |
id | string | — | auto-generated | Собственный id для нового блока. |
tunes | { [name: string]: BlockTuneData } | — | undefined | Необязательные данные тюнов, применяемые при создании, с ключами по имени тюна. |
origin | BlockOrigin | — | 'api' | Зачем создаётся блок. Значение передаётся в конструктор инструмента как
|
Ошибки
Не указан
type, и в конфигурации не заданdefaultBlock.Could not insert Block. Tool name is not specified.
Передайте явный
typeили задайтеdefaultBlockв конфигурации редактора.Определённое имя инструмента не зарегистрировано в редакторе.
Could not compose Block. Tool «<type>» not found.
Зарегистрируйте инструмент в конфигурации
toolsредактора перед вставкой блока этого типа.Передан
replace: true, но поindexнет блока.Could not replace Block at index <index>. Block not found.
Проверьте
indexчерезblocks.getBlocksCount()перед вызовом сreplace: true.
// Insert after the current block with the default type
const block = editor.blocks.insert();
// → BlockAPI { id: 'kP3xQ...', name: 'paragraph', ... }
// Insert paragraph with data at index 0
const block = editor.blocks.insert('paragraph', { text: 'Hello' }, undefined, 0);
// Insert with custom ID
const block = editor.blocks.insert('header', { text: 'Title' }, undefined, undefined, undefined, undefined, 'custom-id');
// From your own slash menu / toolbar: declare the user gesture so a container
// tool seeds its default children (see BlockOrigin on the tool contract)
const block = editor.blocks.insert('column_list', undefined, undefined, index, undefined, undefined, undefined, undefined, 'user');blocks.insertMany(blocks, index?)
BlockAPI[]Вставить несколько блоков за раз. Когда индекс не передан, блоки добавляются в конец документа.
Когда использовать
Массовая вставка за одну операцию и один шаг отмены. Это гораздо дешевле, чем цикл из insert(), для больших вставок или импорта.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
blocks | OutputBlockData[] | LooseOutputBlockData[] | Обязательный | — | Блоки для вставки. Принимаются нестрогие блоки. |
index | number | — | end of document | Позиция для вставки. Когда не передана, по умолчанию блоки добавляются в конец документа. |
Ошибки
Переданный
indexотрицательный.Index should be greater than or equal to 0
Передайте
indexне меньше 0 либо не передавайте его, чтобы добавить блоки в конец.
const blocksToInsert = [
{ id: '1', type: 'paragraph', data: { text: 'First' } },
{ id: '2', type: 'paragraph', data: { text: 'Second' } }
];
const inserted = editor.blocks.insertMany(blocksToInsert, 0);
console.log('Inserted:', inserted.length, 'blocks');blocks.composeBlockData(toolName)
Promise<BlockToolData>Создать пустые данные блока для указанного типа инструмента.
Когда использовать
Создаёт данные инструмента по умолчанию, ничего не вставляя. Полезно, когда нужен корректный пустой payload для insert() или update().
Ошибки
toolNameне является зарегистрированным инструментом.Block Tool with type "<toolName>" not found
Сначала зарегистрируйте инструмент в конфигурации
toolsредактора.
const emptyData = await editor.blocks.composeBlockData('paragraph');
// Returns: { text: '' } or appropriate empty state for the toolblocks.update(id, data?, tunes?)
Promise<BlockAPI>Обновляет данные и/или тюны блока. Обновление данных применяется НА МЕСТЕ, когда инструмент блока реализует setData(newData) в своём прототипе. Так делает каждый React/Vue/Angular-блок, а также встроенные инструменты заголовка, списка, кода, тоггла и таблицы.
«На месте» означает, что тот же экземпляр блока, тот же DOM-холдер и тот же смонтированный компонент продолжают жить. Поэтому эфемерное состояние инструмента, принятые дочерние блоки и курсор сохраняются. Именно поэтому update() безопасно вызывать на каждое нажатие клавиши, например при переименовании карточки во время набора.
К пересборке блока откатываются три случая:
- инструменты без
setData - инструмент, чей
setDataвозвращаетfalse(ему нужна другая форма DOM) - любой вызов, передающий
tunes
Пересборка означает, что новый экземпляр инструмента заменяет старый, а старый уничтожается.
Когда использовать
Изменяет data/tunes на месте, сохраняя id и тип блока. Чтобы сменить тип, используйте convert().
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
id | string | Обязательный | — | Id блока для обновления. |
data | Partial<BlockToolData> | — | undefined | Частичные данные, объединяемые с существующими данными блока. |
tunes | Record<string, BlockTuneData> | — | undefined | Данные тюнов, объединяемые с существующими тюнами блока. |
Ошибки
Блок с указанным
idне существует.Block with id "<id>" not found
Проверьте id через
blocks.getById()перед вызовомupdate().
// Update block data
const block = await editor.blocks.update('block-123', { text: 'New text' });
// Update with tunes
const block = await editor.blocks.update('block-123', undefined, { alignment: 'center' });
// Guard against an id that no longer exists (e.g. the block was deleted
// concurrently) instead of letting the rejection surface unhandled
try {
await editor.blocks.update(staleId, { text: 'New text' });
} catch {
console.warn('Block was already removed, skipping update');
}blocks.convert(id, newType, dataOverrides?)
Promise<BlockAPI>Преобразовать блок в другой тип. Оба инструмента должны поддерживать конфигурацию преобразования.
Когда использовать
И исходный, и целевой инструменты должны объявлять conversionConfig, иначе вызов выбросит ошибку. По возможности сохраняет текст.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
id | string | Обязательный | — | Id блока для преобразования. Его инструмент должен объявлять |
newType | string | Обязательный | — | Имя зарегистрированного инструмента, в который идёт преобразование. Его инструмент должен объявлять |
dataOverrides | BlockToolData | — | undefined | Поля данных для перезаписи в результирующем блоке после преобразования. |
Ошибки
Блок с указанным
idне существует.Block with id "<id>" not found
Проверьте id через
blocks.getById()перед вызовомconvert().newTypeне является зарегистрированным инструментом.Block Tool with type "<newType>" not found
Зарегистрируйте целевой инструмент в конфигурации
toolsредактора.У исходного инструмента нет
conversionConfig.export, у целевого нетconversionConfig.import, либо нет ни того, ни другого.Conversion from "<sourceType>" to "<newType>" is not possible. <ToolName(s)> tool(s) should provide a "conversionConfig"
Добавьте
conversionConfigтому инструменту, у которого его нет, либо преобразуйте через промежуточный инструмент, который поддерживает оба направления.
// Convert paragraph to header
const headerBlock = await editor.blocks.convert('block-123', 'header', { level: 2 });
// Convert with data overrides
const headerBlock = await editor.blocks.convert('block-123', 'header', { text: 'New Title', level: 1 });
// Not every pair of tools supports conversion — guard it rather than
// assuming the target type is always convertible
try {
await editor.blocks.convert('block-123', 'table');
} catch (error) {
console.warn('Conversion not supported between these tools:', error);
}blocks.splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex)
BlockAPIАтомарно разделить блок, обновив текущий блок и вставив новый. Обе операции объединяются в один шаг отмены.
Когда использовать
Используйте его для разбиения с учётом курсора, например по Enter посреди текста. update и insert образуют один шаг отмены.
// Split a paragraph at cursor position
const newBlock = editor.blocks.splitBlock(
'current-block-id',
{ text: 'First part' },
'paragraph',
{ text: 'Second part' },
1
);blocks.stopBlockMutationWatching(index)
voidОстановить наблюдение за мутациями блока по указанному индексу. Используйте это, чтобы предотвратить ложные события block-changed при операциях замены блока.
Когда использовать
Нишевый метод. Вызывайте его перед программной заменой DOM блока, чтобы подавить ложные события block-changed. Следующий рендер включает наблюдение снова.
// Replace a block without triggering change events
editor.blocks.stopBlockMutationWatching(0);
// Perform block replacement...
// Mutation observer will not fire for this blockblocks.startBlockMutationWatching(blockId)
voidСнова включает наблюдение за мутациями блока, ранее заглушённого через stopBlockMutationWatching. Метод принимает id, а не индекс, потому что вставки и замены между двумя вызовами сдвигают индексы. Несуществующий id молча пропускается: блок, заменённый на месте, был создан с собственным наблюдателем.
const blockId = editor.blocks.getBlockByIndex(0)?.id;
editor.blocks.stopBlockMutationWatching(0);
// Perform block replacement...
if (blockId) {
editor.blocks.startBlockMutationWatching(blockId);
}blocks.transact(fn)
voidОбъединяет все операции с блоками внутри fn в один шаг отмены. fn должна быть СИНХРОННОЙ. Операции, которые выполняются после await, в группу уже не входят. Используйте это, чтобы структурные правки нельзя было отменить частично.
editor.blocks.transact(() => {
editor.blocks.insert('paragraph', { text: 'One' });
editor.blocks.insert('paragraph', { text: 'Two' });
});
// A single Cmd+Z removes both blocksblocks.beginTransaction()
voidОткрывает группу отмены, которая остаётся открытой через асинхронные границы. Каждая операция с блоками до endTransaction() попадает в один шаг отмены.
Используйте это для жестов указателем, которые непрерывно меняют документ, например для перетаскивания угла таблицы, чтобы добавить строки. transact() здесь не помогает, потому что оборачивает только синхронную функцию. Каждый вызов сопрягайте с endTransaction().
editor.blocks.beginTransaction();
// ... continuous mutations across async boundaries ...
editor.blocks.endTransaction();blocks.endTransaction()
voidЗакрыть группу отмены, открытую через beginTransaction().
editor.blocks.beginTransaction();
// ... continuous mutations across async boundaries ...
editor.blocks.endTransaction();blocks.transactWithoutCapture(fn)
voidВыполняет операции с блоками, ничего не записывая в историю отмен. Используйте это для автопочинки и нормализации (например, чтобы в пустой ячейке всегда был блок), через которые Cmd+Z никогда не должен проходить.
Передайте { derivedFrom: blockId, from: ['url'] }, если операции записывают данные, вычисленные из этих ключей блока. Так делает, например, загрузка, которая закончилась и заменяет блок. Они по-прежнему не добавляют шаг отмены и не сбрасывают повтор, но входят в шаг, который записал эти значения: отмена этого шага убирает их, повтор возвращает. update(), начатый внутри fn, тоже считается, хотя заканчивается позже. Пока сохранение этого блока ещё не завершено, fn выполнится после него, уже после возврата из вызова.
editor.blocks.transactWithoutCapture(() => {
editor.blocks.insert('paragraph', {}, undefined, 0);
});
// Nothing was added to the undo historyblocks.setPointerDragActive(active)
voidСообщает ядру, что перетаскивание указателем началось или закончилось. Пока оно активно, синхронизации Yjs, вызванные мутациями DOM, подавляются. Так изменения DOM в браузере во время перетаскивания не могут испортить состояние Yjs.
editor.blocks.setPointerDragActive(true);
// ... run the drag gesture ...
editor.blocks.setPointerDragActive(false);Свойства
| Свойство | Тип | Описание |
|---|---|---|
isSyncingFromYjs | boolean | Геттер только для чтения. Он равен true, пока идёт операция синхронизации Yjs (отмена или повтор). Инструменты читают его, чтобы пропустить очистку, которая конфликтовала бы с состоянием отмены. Обратите внимание: это СВОЙСТВО на |
isPointerDragActive | boolean | Геттер только для чтения. Он равен true, пока активно перетаскивание указателем. Адаптеры фреймворков читают его, чтобы отложить программный |
isApplyingRemoteChange | boolean | Геттер только для чтения. Он равен true, пока редактор применяет изменение, сделанное другим клиентом. Новый блок участника может прийти раньше записи, которая задаёт ему родителя. Инструмент-контейнер читает этот флаг, чтобы отличить такой блок от блока, который этот клиент добавляет в собственном окне синхронизации. |