Interface: Button
Интерфейс для кнопок в пользовательском интерфейсе редактора.
Кнопка — интерактивный элемент управления, который выполняет определённую операцию при нажатии пользователем. Используется в панели инструментов, боковых панелях, модальных окнах и других местах UI.
Наследует функциональность от BaseControl для единообразного управления и добавляет специфичные для кнопки свойства.
Remarks
Иерархия интерфейсов:
Button (текущий интерфейс)
├── extends BaseControl
│ ├── id: string (обязательно)
│ ├── title: string (обязательно)
│ ├── order?: number (опционально)
│ └── groupingId?: string (опционально)
├── extends MayHaveIcon
│ └── icon?: string (опционально)
├── extends MayBeDisabled
│ └── disabled?: boolean (опционально)
└── extends MayBeChecked
└── checked?: boolean (опционально)
└── onClick: Callback (обязательно, специфично для Button)
Типичные сценарии использования:
- Кнопки в панели инструментов (Save, Copy, Paste)
- Кнопки в боковых панелях (Open, Close, Settings)
- Кнопки в модальных окнах (OK, Cancel, Apply)
Наследуемые свойства:
- От BaseControl: id, title, order, groupingId
- От MayHaveIcon: icon (иконка кнопки)
- От MayBeDisabled: disabled (отключение кнопки)
- От MayBeChecked: checked (состояние checked для toggle кнопок)
Специфичные свойства Button:
type— маркер типа 'button'onClick— обработчик клика (обязательный)variant— стиль кнопки (primary, secondary, link)onlyIcon— отображение только иконкиfullWidth— растягивание на всю ширину
Example
Простая кнопка в панели инструментов
const saveButton: Button = {
id: 'plugin:save',
title: 'Сохранить',
icon: 'Save',
type: 'button',
onClick: editorApi.createCallback(async () => {
const content = await editorApi.document.getContent?.();
// сохранение
editorApi.ui.toasts.showToast({ id, content: 'Документ сохранён' });
})
};
Кнопка с вариантом стиля
const primaryButton: Button = {
id: 'plugin:submit',
title: 'Отправить',
type: 'button',
variant: 'primary', // Выделенная основная кнопка
onClick: editorApi.createCallback(() => {
console.log('Отправлено');
})
};
const linkButton: Button = {
id: 'plugin:help',
title: 'Помощь',
type: 'button',
variant: 'link', // Выглядит как ссылка
onClick: editorApi.createCallback(() => {
editorApi.ui.modals.showModal(...);
})
};
Кнопка с иконкой в панели инструментов
const copyButton: Button = {
id: 'plugin:copy',
title: 'Копировать',
icon: 'Copy', // Иконка кнопки
type: 'button',
groupingId: 'clipboard', // Группировка с другими кнопками буфера обмена
onClick: editorApi.createCallback(async () => {
await editorApi.document.clipboard.copy();
editorApi.ui.toasts.showToast({ id, content: 'Скопировано'});
})
};
Отключаемая кнопка
const deleteButton: Button = {
id: 'plugin:delete',
title: 'Удалить',
icon: 'Trash',
type: 'button',
disabled: true, // Кнопка отключена по умолчанию
onClick: editorApi.createCallback(async () => {
// удаление
})
};
Toggle кнопка (с состоянием checked)
const boldButton: Button = {
id: 'plugin:bold',
title: 'Жирный',
icon: 'Bold',
type: 'button',
checked: false, // Начальное состояние
onClick: editorApi.createCallback(async () => {
// переключение жирности
})
};
Только иконка без текста (применимо к кнопкам боковой панели)
const iconOnlyButton: Button = {
id: 'plugin:settings',
title: 'Настройки', // Всё ещё нужен для tooltip
icon: 'Settings',
type: 'button',
onlyIcon: true, // Отображать только иконку
onClick: editorApi.createCallback(() => {
editorApi.ui.modals.showSettings();
})
};
Полная ширина кнопки (применимо к кнопкам боковой панели)
const applyButton: Button = {
id: 'plugin:apply',
title: 'Применить',
type: 'button',
variant: 'primary',
fullWidth: true, // Растягивается на всю ширину контейнера
onClick: editorApi.createCallback(() => {
// применение изменений
})
};
Кнопки в панели инструментов
const buttons: Button[] = [
{
id: 'plugin:get-text',
title: 'Get as text',
icon: 'GetText',
type: 'button',
groupingId: 'get-selection',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
console.log('Текст:', text);
})
},
{
id: 'plugin:get-html',
title: 'Get as HTML',
icon: 'GetHTML',
type: 'button',
groupingId: 'get-selection',
onClick: editorApi.createCallback(async () => {
const html = await editorApi.document.selection.getSelectionAsText('html');
console.log('HTML:', html);
})
}
];
editorApi.ui.ribbon.addTab({
id: 'plugin:ribbon:tab',
title: 'My Plugin',
order: 27,
groups: [
{
id: 'plugin:group',
type: 'controls',
controls: buttons
}
]
});
Рекомендации дизайна:
- Используйте
primaryдля основного действия (сохранить, отправить) - Используйте
secondaryдля обычных действий (копировать, вставить) - Используйте
linkдля вспомогательных или информационных действий - Добавляйте иконки для быстрого визуального распознавания
- Группируйте связанные кнопки через
groupingId - Используйте
onlyIconдля экономии места в компактных UI - Отключайте кнопки, когда действие недоступно
See
- BaseControl — базовые свойства (id, title, order, groupingId)
- MayHaveIcon — поддержка иконок
- MayBeDisabled — состояние disabled
- MayBeChecked — состояние checked для toggle кнопок
- Callback — тип обработчика события
- RibbonApi — использование кнопок в панели инструментов
Extends
Properties
checked?
readonlyoptionalchecked:boolean
Состояние компонента: включено (true) или выключено (false).
Remarks
true — компонент в состоянии "включено":
- Галочка в флажке
- Переключатель в "ВКЛ" позиции
- Радиокнопка заполнена
- Визуально выглядит активным
false — компонент в состоянии "выключено":
- Флажок пуст
- Переключатель в "ВЫКЛ" позиции
- Радиокнопка не заполнена
- Визуально выглядит неактивным
undefined — состояние не определено:
- Используется редко
- Может означать неопределённое состояние (не да, не нет)
Example
Флажок (checkbox)
{
id: 'checkbox:confirm',
type: 'checkbox',
title: 'Я согласен с условиями',
checked: false // Изначально не отмечено
}
Переключатель (toggle)
{
id: 'toggle:darkmode',
type: 'toggle',
title: 'Тёмный режим',
checked: true // Изначально включено
}
Обновление состояния
editorApi.ui.updateUiNodes([{
id: 'checkbox:confirm',
checked: true // Отметить флажок
}]);
Inherited from
disabled?
readonlyoptionaldisabled:boolean
Флаг отключения элемента.
Remarks
true — элемент отключен:
- Визуально затемнен/затенён
- События клика/ввода игнорируются
- Подсказка может объяснить причину отключения
- Фокус не может перейти на отключённый элемент
false или не указано — элемент включен:
- Элемент активен и реагирует на действия
- Полная интерактивность
- Нормальный визуальный вид
Default
false (включено)
Example
Отключение кнопки во время загрузки
// Начало загрузки
editorApi.ui.updateUiNodes([{
id: 'button:submit',
disabled: true,
title: 'Загрузка...'
}]);
// После загрузки
editorApi.ui.updateUiNodes([{
id: 'button:submit',
disabled: false,
title: 'Отправить'
}]);
Отключение поля ввода в зависимости от условия
editorApi.events.subscribe('documentChange', (payload) => {
const isEmpty = payload.info.content.length === 0;
editorApi.ui.updateUiNodes([{
id: 'input:search',
disabled: isEmpty // Отключить если документ пуст
}]);
});
Inherited from
fullWidth?
readonlyoptionalfullWidth:boolean
Флаг растягивания кнопки на всю ширину контейнера.
Если установлено в true, кнопка займёт всю доступную ширину своего контейнера.
Remarks
Когда использовать:
- Для главных действий в диалогах (OK, Apply, Submit)
- В узких боковых панелях для лучшей видимости
- Когда нужно выделить кнопку среди других элементов
Когда не использовать:
- В панели инструментов (обычно игнорируется)
- Когда несколько кнопок в ряду (нужно согласовать размеры)
- Для вспомогательных кнопок
Контейнер может игнорировать:
- Некоторые контейнеры могут игнорировать
fullWidth - Это зависит от реализации контейнера
Default
false
Example
Полная ширина для главного действия
const submitButton: Button = {
id: 'plugin:submit',
title: 'Отправить',
type: 'button',
variant: 'primary',
fullWidth: true, // Занимает всю ширину
onClick: editorApi.createCallback(() => {
// отправка
})
};
Комбинация с другими свойствами
const actionButton: Button = {
id: 'plugin:apply',
title: 'Применить',
type: 'button',
variant: 'primary',
fullWidth: true,
icon: 'CheckMark',
onClick: editorApi.createCallback(async () => {
// применение действия
})
};
groupingId?
readonlyoptionalgroupingId:string
Идентификатор группы, к которой относится элемент.
Remarks
Поведение:
- Элементы с одинаковым groupingId визуально группируются
- Между группами (разные groupingId) отображается разделитель
- Элементы без groupingId не группируются
- Порядок групп определяется order первого элемента в группе
Example
[
{ id: 'copy', title: 'Copy', groupingId: 'clipboard' },
{ id: 'cut', title: 'Cut', groupingId: 'clipboard' },
{ id: 'paste', title: 'Paste', groupingId: 'clipboard' },
// Разделитель добавляется автоматически
{ id: 'delete', title: 'Delete', groupingId: 'edit' }
]
Inherited from
icon?
readonlyoptionalicon:string
Название встроенной иконки или SVG код пользовательской иконки.
Remarks
Если iconType === 'standard':
- Должно быть названием встроенной иконки редактора
- Примеры: 'Save', 'Delete', 'Settings', 'Help', 'Search', 'Download', 'Upload'
- Полный список доступных иконок см. в документации редактора
- Название чувствительно к регистру
Если iconType === 'svg':
- Должно содержать валидный SVG код
- Должен быть корректно оформлен XML
- Может содержать только безопасные SVG элементы
- Рекомендуется использовать viewBox для масштабируемости
Examples
{
icon: 'Save',
iconType: 'standard' // или не указывать, это значение по умолчанию
}
{
icon: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">' +
'<circle cx="12" cy="12" r="10" fill="currentColor"/>' +
'</svg>',
iconType: 'svg'
}
const customIconSvg = `
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"
fill="currentColor"/>
</svg>
`;
{
icon: customIconSvg,
iconType: 'svg'
}
See
iconType — тип иконки (standard или svg)
Inherited from
iconType?
readonlyoptionaliconType:"standard"|"svg"
Тип иконки, определяющий как интерпретировать поле icon.
Remarks
'standard' — встроенная иконка редактора:
- Быстрая загрузка (уже в памяти)
- Соответствует стилю редактора
- Автоматически масштабируется и окрашивается
- Поддерживает темы (светлая/тёмная)
- Ограниченный выбор (только встроенные иконки)
'svg' — пользовательская SVG иконка:
- Полная гибкость в дизайне
- Можно использовать любую иконку
- Меньше файлов (встроены в код)
- Требует корректного SVG кода
- Поддерживает CSS свойство currentColor для окраски
Default
'standard'
Example
Встроенная иконка (по умолчанию)
{
icon: 'Settings'
// iconType: 'standard' используется по умолчанию
}
SVG иконка
{
icon: '<svg>...</svg>',
iconType: 'svg'
}
Рекомендуемая SVG структура
{
icon: `
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<!-- viewBox позволяет масштабировать без потери качества -->
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"
fill="currentColor" />
<!-- currentColor наследует цвет из контекста -->
</svg>
`,
iconType: 'svg'
}
See
icon — содержимое иконки
Inherited from
id
readonlyid:string
Уникальный идентификатор элемента пользовательского интерфейса.
Remarks
Требования:
- Должен быть уникален среди всех элементов UI редактора
- Не может быть пустой строкой
- Не может содержать спецсимволы (кроме :, -, _)
- Чувствителен к регистру (case-sensitive)
Использование:
- Идентификация элемента при обновлении
- Идентификация элемента при событиях
- Ссылка на элемент в других местах кода
Соглашения:
'plugin:button:save' // Кнопка надстройки
'plugin:input:username' // Поле ввода
'plugin:panel:settings' // Панель параметров
'plugin:group:formatting' // Группа элементов
Example
// Создание элемента с уникальным id
{
id: 'plugin:button:submit',
title: 'Отправить',
type: 'button'
}
// Использование id для обновления
editorApi.ui.updateUiNodes([
{
id: 'plugin:button:submit',
disabled: false,
}
]);
// Использование id для удаления
editorApi.ui.ribbon.removeTabs(['plugin:ribbon:tab']);
Inherited from
onClick
readonlyonClick:Callback
Обработчик события, вызываемый при клике пользователя на кнопку.
Remarks
Как создать onClick:
const onClick = editorApi.createCallback(() => {
// Ваша логика здесь
});
Характеристики onClick:
- Обязательное свойство для кнопки
- Создаётся через
editorApi.createCallback() - Может быть синхронным или асинхронным (Promise)
- Вызывается в контексте редактора
- Имеет доступ к
editorApiчерез замыкание
Когда вызывается:
- При клике левой кнопкой мыши на кнопку
- При нажатии Enter когда кнопка в фокусе
- На мобильных устройствах: при tap на кнопку
Обработка ошибок:
- Используйте try-catch для асинхронных операций
- Показывайте ошибки пользователю через
editorApi.ui.toasts.showToast({ type: 'error' })
Example
Синхронный обработчик
const button: Button = {
id: 'plugin:action',
title: 'Действие',
type: 'button',
onClick: editorApi.createCallback(() => {
console.log('Кнопка нажата');
editorApi.ui.toasts.showToast({ id, content: 'Готово' });
})
};
Асинхронный обработчик
const button: Button = {
id: 'plugin:load-data',
title: 'Загрузить',
type: 'button',
onClick: editorApi.createCallback(async () => {
editorApi.ui.toasts.showToast({ id, content: 'Загрузка...' });
const data = await fetchData();
await editorApi.document.insertContent(JSON.stringify(data));
editorApi.ui.toasts.showToast({ id, content: 'Загружено' });
})
};
Обработчик с проверками
const button: Button = {
id: 'plugin:copy',
title: 'Копировать',
type: 'button',
onClick: editorApi.createCallback(async () => {
try {
const text = await editorApi.document.selection.getSelectionAsText();
if (!text) {
editorApi.ui.toasts.showToast({ id, content: 'Пожалуйста, выделите текст' });
return;
}
await editorApi.document.clipboard.copy();
editorApi.ui.toasts.showToast({ id, content: 'Скопировано' });
} catch (error) {
editorApi.ui.toasts.showToast({ id, type: 'error', content: 'Ошибка при копировании' });
}
})
};
See
- Callback — полное описание интерфейса Callback
- EditorApi.createCallback — как создать callback
onlyIcon?
readonlyoptionalonlyIcon:boolean
Флаг отображения только иконки без текста названия.
Если установлено в true, кнопка отображается только как иконка,
название (title) будет использовано как tooltip при наведении.
Remarks
Когда использовать:
- В плотных UI (панели инструментов, боковые панели)
- Для экономии места при множестве кнопок
- Когда иконка достаточно понятна без текста
Когда не использовать:
- Для новых или неочевидных операций
- Когда нужно видеть текст
- Для кнопок в диалогах (там лучше видеть текст)
Требования:
- Кнопка должна иметь
iconдля отображения titleвсё ещё должен быть понятным (используется как tooltip)
Контейнер может игнорировать:
- Некоторые контейнеры могут показывать текст несмотря на
onlyIcon: true - Это зависит от реализации контейнера
Default
false
Example
Кнопка только с иконкой (компактная)
const saveButton: Button = {
id: 'plugin:save',
title: 'Сохранить', // Используется как tooltip
icon: 'Save',
type: 'button',
onlyIcon: true,
onClick: editorApi.createCallback(async () => {
// сохранение
})
};
Кнопка с иконкой и текстом (обычная)
const saveButton: Button = {
id: 'plugin:save',
title: 'Сохранить',
icon: 'Save',
type: 'button',
onlyIcon: false, // Или не указывать (default)
onClick: editorApi.createCallback(async () => {
// сохранение
})
};
Кнопки для панели инструментов
const toolbarButtons: Button[] = [
{
id: 'plugin:save',
title: 'Сохранить',
icon: 'Save',
type: 'button',
onlyIcon: true,
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:copy',
title: 'Копировать',
icon: 'Copy',
type: 'button',
onlyIcon: true,
onClick: editorApi.createCallback(() => {})
}
];
title
readonlytitle:string
Название/заголовок элемента пользовательского интерфейса.
Remarks
Требования:
- Должен быть локализирован (переведён на язык пользователя)
- Должен быть понятным и кратким
- Не должен быть пустой строкой
- Может содержать спецсимволы (кроме < и >)
Примеры:
- "Сохранить документ"
- "Экспортировать в PDF"
- "Параметры надстройки"
- "Об приложении"
Советы:
- Используйте глаголы для действий (Сохранить, Удалить)
- Используйте существительные для панелей (Параметры, Информация)
- Сохраняйте названия короткими
- Будьте конкретными (не просто "Опции", а "Параметры надстройки")
Example
{
id: 'button:save',
title: 'Сохранить',
type: 'button'
}
Inherited from
type
readonlytype:"button"
Маркер типа элемента управления.
Используется для идентификации элемента как кнопки в контейнере.
Remarks
- Всегда равен
'button'для этого интерфейса - Используется контейнерами (панель инструментов, боковые панели) для определения типа элемента
- Позволяет TypeScript правильно типизировать элемент
Default
'button'
Example
const button: Button = {
id: 'plugin:action',
title: 'Действие',
type: 'button', // Маркер типа
onClick: editorApi.createCallback(() => {})
};
variant?
readonlyoptionalvariant:"primary"|"secondary"|"link"
Внешний вид (стиль) кнопки.
Влияет на визуальное представление и выделение кнопки, однако контейнер может переопределить стиль в зависимости от своих требований.
Remarks
Возможные варианты:
| Вариант | Описание | Когда использовать |
|---|---|---|
primary | Основная кнопка, выделена визуально (обычно соответствует теме текущего редактора) | Главное действие (Сохранить, Отправить, Применить) |
secondary | Обычная кнопка, нейтральный стиль (используется по умолчанию) | Обычные действия (Копировать, Вставить, Удалить) |
link | Представление в виде гиперссылки (синий текст с подчеркиванием) | Вспомогательные действия (Помощь, Подробнее, Отмена) |
Влияние контейнера:
- Панель инструментов может игнорировать variant и использовать свой стиль
- Модальные окна часто переопределяют variant кнопок (OK/Cancel)
- Боковые панели обычно соблюдают variant
Визуальные примеры:
primary: ███ Сохранить ███ (выделенная, контрастная)
secondary: ░░░ Копировать ░░░ (обычная, нейтральная)
link: Помощь (синий текст, как ссылка)
Default
'secondary'
Example
Основная кнопка для важного действия
const submitButton: Button = {
id: 'plugin:submit',
title: 'Отправить',
type: 'button',
variant: 'primary',
onClick: editorApi.createCallback(() => {
// отправка данных
})
};
Ссылка-кнопка для вспомогательного действия
const helpButton: Button = {
id: 'plugin:help',
title: 'Нужна помощь?',
type: 'button',
variant: 'link',
onClick: editorApi.createCallback(() => ...)
};
Кнопки в диалоге (разные варианты)
const okButton: Button = {
id: 'plugin:ok',
title: 'OK',
type: 'button',
variant: 'primary', // Главное действие
onClick: editorApi.createCallback(() => {})
};
const cancelButton: Button = {
id: 'plugin:cancel',
title: 'Отмена',
type: 'button',
variant: 'secondary', // Вспомогательное действие
onClick: editorApi.createCallback(() => {})
};