Как создать собственный блочный инструмент
Создайте блок-инструмент с нуля — блок-выноску, которая отрисовывается, редактируется и сохраняется как любой встроенный блок.
Каждый встроенный блок — это просто инструмент, реализующий интерфейс BlockTool, и вы можете добавить свой. Здесь вы создадите блок Callout: редактируемую выноску, которая сохраняет свой текст и загружает его обратно, как любой другой блок.
Напишите класс инструмента
Блок-инструменту нужны три вещи: статический геттер toolbox, чтобы он появился в меню /, метод render(), возвращающий элемент блока, и метод save(), возвращающий данные для сохранения.
// callout-tool.ts
export class CalloutTool {
private data: { text: string };
// Shows the tool in the "/" menu.
static get toolbox() {
return { title: 'Callout', icon: '💡' };
}
constructor({ data }: { data: { text?: string } }) {
this.data = { text: data.text ?? '' };
}
// Return the element Blok mounts for this block.
render() {
const box = document.createElement('div');
box.classList.add('callout');
box.contentEditable = 'true';
box.textContent = this.data.text;
return box;
}
// Return the data Blok stores when the editor is saved.
save(block: HTMLElement) {
return { text: block.textContent ?? '' };
}
}Зарегистрируйте его в редакторе
Передайте класс в конфигурацию tools. Ключ, который вы зададите, станет значением type блока в сохранённых данных.
import { Blok } from '@bloklabs/core';
import { Paragraph } from '@bloklabs/core/tools';
import { CalloutTool } from './callout-tool';
const editor = new Blok({
holder: 'editor',
tools: {
paragraph: Paragraph, // the default block every empty editor starts with
callout: CalloutTool, // the key becomes the block's `type`
},
});Используйте и сохраните
Откройте меню /, выберите Callout, введите текст в выноску и вызовите save(). Ваш блок появится в результате рядом со встроенными.
const data = await editor.save();
// Your block round-trips exactly like a built-in one:
// {
// id: 'x9k2f1',
// type: 'callout',
// data: { text: 'Heads up — this is a callout.' },
// }Что дальше
Добавьте метод validate(), чтобы отбрасывать пустые блоки, меню настроек через renderSettings() или обработку вставки через onPaste. Интерфейс BlockTool покрывает весь жизненный цикл — rendered(), updated(), moved() и removed().
// callout-tool.ts (extended)
export class CalloutTool {
// ...constructor, render() unchanged
save(block: HTMLElement) {
return { text: block.textContent ?? '' };
}
// Drop empty callouts when the editor saves.
validate(savedData: { text: string }) {
return savedData.text.trim().length > 0;
}
}
// text-color-tune.ts — a block tune adds a control to the settings menu.
export class TextColorTune {
static isTune = true;
render() {
return { title: 'Text color', icon: '🎨', onActivate: () => {/* recolor */} };
}
}import { Blok } from '@bloklabs/core';
import { CalloutTool } from './callout-tool';
import { TextColorTune } from './text-color-tune';
const editor = new Blok({
holder: 'editor',
tools: {
callout: { class: CalloutTool, tunes: ['textColor'] },
// Register the tune as a tool so a block can list it by name.
textColor: TextColorTune,
},
});validate() выполняется перед тем, как разрешится save(), поэтому пустая выноска никогда не попадёт в результат. Tunes подключаются по желанию для каждого инструмента — зарегистрируйте класс тюна как инструмент (класс со static isTune = true), затем укажите его имя в tunes: [...], и Blok добавит его в меню настроек блока.
Полный контракт инструмента смотрите в Tools API и загляните в BlockData за точной формой данных, которые возвращает ваш `save()`.