Перейти к основному содержимому
Версия: Next

Interface: ButtonWithDropdown

Интерфейс для кнопки с ассоциированным выпадающим меню.

Это гибридный элемент управления, сочетающий функциональность обычной кнопки и выпадающего меню. Часто используется в панели инструментов и боковых панелях для группировки связанных действий.

Наследует функциональность от BaseControl для единообразного управления и добавляет поддержку выпадающего списка с вложенными кнопками.

Remarks

Иерархия интерфейсов:

ButtonWithDropdown (текущий интерфейс)
├── extends BaseControl
│ ├── id: string (обязательно)
│ ├── title: string (обязательно)
│ ├── order?: number (опционально)
│ └── groupingId?: string (опционально)
├── extends MaiHaveIcon
│ └── icon?: string (опционально)
├── extends MayBeDisabled
│ └── disabled?: boolean (опционально)
├── extends MayBeChecked
│ └── checked?: boolean (опционально)
├── onClick?: Callback (опционально, для основной кнопки)
└── items: Button[] (обязательно, для выпадающего меню)

Структура и поведение:

┌─────────────────────┬─────┐
│ Название кнопки │ ▼ │ ← ButtonWithDropdown
└─────────────────────┴─────┘
│ клик на кнопку │ клик на стрелку
│ (выполнить onClick) │ (открыть меню)
▼ ▼
Действие ┌──────────────┐
│ Действие 1 │
│ Действие 2 │
│ Действие 3 │
└──────────────┘

Режимы работы:

  1. Только выпадающее меню (без onClick)

    • Клик на кнопку открывает меню
    • Нет самостоятельного действия
    • Нет состояния checked
    • Стрелка и основная область работают одинаково
  2. Двухфункциональная кнопка (с onClick)

    • Клик на основную часть выполняет onClick
    • Поддержка отдельного состояния checked
    • Клик на стрелку открывает меню
    • Две разные функции в одном элементе

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

  • Для группировки связанных действий (экспорт в разные форматы)
  • Для выбора из вариантов одного действия
  • Для экономии места в панели инструментов
  • Когда есть основное действие + варианты этого действия

Отличие от других элементов:

  • Button — простая кнопка без меню
  • ButtonWithDropdown — кнопка с выпадающим меню (текущий)
  • Контекстное меню (ContextMenuItem) — появляется при правом клике

Example

Только выпадающее меню (без основного действия)

const exportDropdown: ButtonWithDropdown = {
id: 'plugin:export',
title: 'Экспортировать',
icon: 'Download',
type: 'button-with-dropdown',
items: [
{
id: 'plugin:export-pdf',
title: 'Экспортировать в PDF',
type: 'button',
onClick: editorApi.createCallback(async () => {
// экспорт в PDF
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в PDF...' });
})
},
{
id: 'plugin:export-html',
title: 'Экспортировать в HTML',
type: 'button',
onClick: editorApi.createCallback(async () => {
// экспорт в HTML
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в HTML...' });
})
},
{
id: 'plugin:export-docx',
title: 'Экспортировать в Word',
type: 'button',
onClick: editorApi.createCallback(async () => {
// экспорт в Word
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в Word...' });
})
}
]
};

Двухфункциональная кнопка (с основным действием)

const pasteDropdown: ButtonWithDropdown = {
id: 'plugin:paste',
title: 'Вставить',
icon: 'Paste',
type: 'button-with-dropdown',
// Клик на основную часть выполняет это действие
onClick: editorApi.createCallback(async () => {
await editorApi.document.clipboard.paste();
editorApi.ui.toasts.showToast({ id, content: 'Вставлено' });
}),
// Клик на стрелку открывает варианты вставки
items: [
{
id: 'plugin:paste-normal',
title: 'Обычная вставка',
type: 'button',
onClick: editorApi.createCallback(async () => {
await editorApi.document.clipboard.paste();
})
},
{
id: 'plugin:paste-special',
title: 'Специальная вставка',
type: 'button',
onClick: editorApi.createCallback(async () => {
// специальная вставка
})
},
{
id: 'plugin:paste-unformatted',
title: 'Вставить без форматирования',
type: 'button',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.clipboard.getPlainText?.();
if (text) {
await editorApi.document.insertContent(text);
}
})
}
]
};

Получение текста в разных форматах

const getTextDropdown: ButtonWithDropdown = {
id: 'plugin:get-text',
title: 'Get text',
icon: 'GetText',
type: 'button-with-dropdown',
groupingId: 'get-selection',
items: [
{
id: 'plugin:get-text-plain',
title: 'Get as text',
type: 'button',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
console.log('Текст:', text);
})
},
{
id: 'plugin:get-text-html',
title: 'Get as HTML',
type: 'button',
onClick: editorApi.createCallback(async () => {
const html = await editorApi.document.selection.getSelectionAsText('html');
console.log('HTML:', html);
})
}
]
};

Отключаемая кнопка с выпадающим меню

const saveDropdown: ButtonWithDropdown = {
id: 'plugin:save-options',
title: 'Сохранить',
icon: 'Save',
type: 'button-with-dropdown',
disabled: false, // Может быть отключена
onClick: editorApi.createCallback(async () => {
// быстрое сохранение
editorApi.ui.toasts.showToast({ id, content: 'Сохранено' });
}),
// При этом выпадающее меню остается доступным
items: [
{
id: 'plugin:save-as',
title: 'Сохранить как...',
type: 'button',
onClick: editorApi.createCallback(async () => {
// сохранить как
})
},
{
id: 'plugin:save-all',
title: 'Сохранить всё',
type: 'button',
onClick: editorApi.createCallback(async () => {
// сохранить всё
})
}
]
};

Использование в панели инструментов

editorApi.ui.ribbon.addTab({
id: 'plugin:ribbon:tab',
title: 'My Plugin',
order: 27,
groups: [
{
id: 'plugin:group:export',
type: 'controls',
controls: [
{
id: 'plugin:export-dropdown',
title: 'Export',
icon: 'Download',
type: 'button-with-dropdown',
groupingId: 'export',
items: [
{
id: 'plugin:export-pdf',
title: 'Export to PDF',
type: 'button',
onClick: editorApi.createCallback(async () => {
// экспорт
})
},
{
id: 'plugin:export-html',
title: 'Export to HTML',
type: 'button',
onClick: editorApi.createCallback(async () => {
// экспорт
})
}
]
}
]
}
]
});

Кнопка с выпадающим меню и вариантами стиля

const actionDropdown: ButtonWithDropdown = {
id: 'plugin:action',
title: 'Действие',
icon: 'Settings',
type: 'button-with-dropdown',
onClick: editorApi.createCallback(() => {
editorApi.ui.toasts.showToast({ id, content: 'Выполнено основное действие' });
}),
items: [
{
id: 'plugin:action-1',
title: 'Вариант 1',
type: 'button',
variant: 'primary',
onClick: editorApi.createCallback(() => {
editorApi.ui.toasts.showToast({ id, content: 'Вариант 1' });
})
},
{
id: 'plugin:action-2',
title: 'Вариант 2',
type: 'button',
variant: 'secondary',
onClick: editorApi.createCallback(() => {
editorApi.ui.toasts.showToast({ id, content: 'Вариант 2' });
})
}
]
};

Рекомендации дизайна:

  • Используйте для группировки 2-5 связанных действий
  • Первое действие в меню должно быть типичным выбором
  • Если есть onClick, первое действие в меню может быть дублем основного действия
  • Используйте понятные иконки и названия
  • Группируйте по смыслу (экспорт, вставка, форматирование)

See

  • BaseControl — базовые свойства (id, title, order, groupingId)
  • MayHaveIcon — иконка для этого компонента
  • MayBeDisabled — состояние disabled
  • Button — элементы в выпадающем меню
  • Callback — тип обработчика события
  • RibbonApi — использование в панели инструментов

Extends

Properties

checked?

readonly optional checked: 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

MayBeChecked.checked


disabled?

readonly optional disabled: 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

MayBeDisabled.disabled


groupingId?

readonly optional groupingId: 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

BaseControl.groupingId


icon?

readonly optional icon: 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

HasIcon.icon


iconType?

readonly optional iconType: "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

HasIcon.iconType


id

readonly id: 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

BaseControl.id


items

readonly items: Button[]

Массив кнопок, отображаемых в выпадающем меню.

Содержит список элементов Button, которые будут доступны при открытии выпадающего меню.

Remarks

Характеристики items:

  • Минимум 1 кнопка в массиве
  • Максимум рекомендуется 5-7 кнопок (для удобства)
  • Все элементы должны быть типа Button
  • Кнопки отображаются в том же порядке, что в массиве
  • Каждая кнопка должна иметь свой onClick
  • Кнопки могут быть отключены через disabled

Рекомендации:

  • Первая кнопка — наиболее типичный выбор
  • Группируйте похожие действия рядом
  • Используйте понятные названия и иконки
  • Если много действий, подумайте о подменю

Структура Button в items:

  • id — уникальный идентификатор
  • title — текст кнопки
  • type: 'button' — обязательно 'button'
  • onClick — обработчик события
  • icon (опционально) — иконка
  • disabled (опционально) — отключение кнопки

Example

Простой выпадающий список

const dropdown: ButtonWithDropdown = {
id: 'plugin:format',
title: 'Format',
icon: 'Palette',
type: 'button-with-dropdown',
items: [
{
id: 'plugin:format-bold',
title: 'Bold',
type: 'button',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:format-italic',
title: 'Italic',
type: 'button',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:format-underline',
title: 'Underline',
type: 'button',
onClick: editorApi.createCallback(() => {})
}
]
};

Выпадающий список с иконками

const dropdown: ButtonWithDropdown = {
id: 'plugin:align',
title: 'Align',
icon: 'AlignLeft',
type: 'button-with-dropdown',
items: [
{
id: 'plugin:align-left',
title: 'Align Left',
icon: 'AlignLeft',
type: 'button',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:align-center',
title: 'Align Center',
icon: 'AlignCenter',
type: 'button',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:align-right',
title: 'Align Right',
icon: 'AlignRight',
type: 'button',
onClick: editorApi.createCallback(() => {})
}
]
};

Выпадающий список с некоторыми отключенными кнопками

const dropdown: ButtonWithDropdown = {
id: 'plugin:options',
title: 'Options',
icon: 'Settings',
type: 'button-with-dropdown',
items: [
{
id: 'plugin:option-1',
title: 'Option 1',
type: 'button',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:option-2',
title: 'Option 2',
type: 'button',
disabled: true, // Отключена - недоступна
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:option-3',
title: 'Option 3',
type: 'button',
onClick: editorApi.createCallback(() => {})
}
]
};

See

  • Button — простые кнопки в меню
  • Callback — для обработчиков в кнопках

onClick?

readonly optional onClick: Callback

Обработчик события для непосредственного взаимодействия с основной частью кнопки.

Опциональный обработчик, который определяет поведение при клике на основную кнопку.

Remarks

Режимы работы:

1. Без onClick (только выпадающее меню):

  • Клик на кнопку открывает/закрывает выпадающее меню
  • Клик на стрелку также открывает/закрывает меню
  • Нет дополнительного действия при клике на основную область
  • Используется для простого выбора из списка

2. С onClick (двухфункциональная кнопка):

  • Клик на основную часть выполняет onClick
  • Клик на стрелку открывает/закрывает меню
  • Кнопка имеет две разные функции
  • Используется когда есть основное действие + варианты

Поведение:

  • Если не указан, кнопка работает только как меню
  • При клике на основную область выполняется onClick (если указан)
  • При клике на стрелку открывается меню независимо от onClick
  • Обработчик может быть синхронным или асинхронным

Default

undefined (режим: только меню)

Example

Только выпадающее меню (без onClick)

const dropdown: ButtonWithDropdown = {
id: 'plugin:export',
title: 'Export',
icon: 'Download',
type: 'button-with-dropdown',
// onClick не указан - кнопка только открывает меню
items: [
{
id: 'plugin:export-pdf',
title: 'PDF',
type: 'button',
onClick: editorApi.createCallback(() => {})
}
]
};

Двухфункциональная кнопка (с onClick)

const dropdown: ButtonWithDropdown = {
id: 'plugin:paste',
title: 'Paste',
icon: 'Paste',
type: 'button-with-dropdown',
// onClick указан - клик на кнопку вставляет, клик на стрелку открывает варианты
onClick: editorApi.createCallback(async () => {
await editorApi.document.clipboard.paste();
}),
items: [
{
id: 'plugin:paste-special',
title: 'Paste Special',
type: 'button',
onClick: editorApi.createCallback(async () => {
// специальная вставка
})
}
]
};

Асинхронный onClick

const dropdown: ButtonWithDropdown = {
id: 'plugin:save',
title: 'Save',
icon: 'Save',
type: 'button-with-dropdown',
onClick: editorApi.createCallback(async () => {
editorApi.ui.toasts.showToast({ id, content: 'Saving...' });
await saveDocument();
editorApi.ui.toasts.showToast({ id, content: 'Saved' });
}),
items: [
{
id: 'plugin:save-as',
title: 'Save As...',
type: 'button',
onClick: editorApi.createCallback(() => {})
}
]
};

See


title

readonly title: string

Название/заголовок элемента пользовательского интерфейса.

Remarks

Требования:

  • Должен быть локализирован (переведён на язык пользователя)
  • Должен быть понятным и кратким
  • Не должен быть пустой строкой
  • Может содержать спецсимволы (кроме < и >)

Примеры:

  • "Сохранить документ"
  • "Экспортировать в PDF"
  • "Параметры надстройки"
  • "Об приложении"

Советы:

  • Используйте глаголы для действий (Сохранить, Удалить)
  • Используйте существительные для панелей (Параметры, Информация)
  • Сохраняйте названия короткими
  • Будьте конкретными (не просто "Опции", а "Параметры надстройки")

Example

{
id: 'button:save',
title: 'Сохранить',
type: 'button'
}

Inherited from

BaseControl.title


type

readonly type: "button-with-dropdown"

Маркер типа элемента управления.

Используется для идентификации элемента как кнопки с выпадающим меню в контейнере.

Remarks

  • Всегда равен 'button-with-dropdown' для этого интерфейса
  • Используется контейнерами для определения типа элемента
  • Позволяет TypeScript правильно типизировать элемент

Default

'button-with-dropdown'

Example

const dropdown: ButtonWithDropdown = {
id: 'plugin:dropdown',
title: 'Действие',
icon: 'Menu',
type: 'button-with-dropdown', // Маркер типа
items: []
};