Перейти к основному содержимому
Версия: 26.1.0 (в разработке)

Type Alias: ContextMenuItemWithDropdown

ContextMenuItemWithDropdown = BaseContextMenuItem & object

Элемент контекстного меню с вложенным выпадающим списком (каскадное меню).

Представляет собой пункт меню, при наведении или клике на который открывается подменю с дополнительными опциями. Используется для организации связанных действий.

Наследует все свойства от BaseContextMenuItem и добавляет массив вложенных элементов items.

Type declaration

items

items: ContextMenuItem[]

Массив вложенных элементов второго уровня (подменю).

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

Remarks

Допустимые типы вложенных элементов:

  • SimpleContextMenuItem — простые пункты меню
  • ContextMenuItemWithDropdown — вложенные подменю (до 2 уровней)
  • ContextMenuItemWithGroup — пункты с groupingId
  • ContextMenuItem — объединённый тип всех вышеперечисленных

Ограничения:

  • Минимум 1 элемент в массиве
  • Максимум 5-7 элементов для удобства
  • Максимум 2 уровня вложенности (для UX)
  • Элементы могут содержать shownInScopes и disabledInScopes

Порядок элементов:

  • Элементы отображаются в том же порядке, что и в массиве
  • Порядок можно изменять, переупорядочивая элементы в items
  • Пункты с одинаковым groupingId автоматически группируются

Наследование условий видимости:

  • Если родительский пункт скрыт (shownInScopes не совпадает), то и подменю скрыто
  • Если родительский пункт отключен (disabledInScopes совпадает), то и подменю недоступно
  • Вложенные элементы могут иметь свои shownInScopes и disabledInScopes

Производительность:

  • Подменю загружается лениво (только при открытии)
  • Не влияет на производительность основного меню
  • Рекомендуется не использовать более 3 уровней вложенности

Example

Простой массив подменю

const dropdown: ContextMenuItemWithDropdown = {
id: 'plugin:export',
title: 'Экспортировать',
items: [
{
id: 'plugin:export-pdf',
title: 'PDF',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:export-html',
title: 'HTML',
onClick: editorApi.createCallback(() => {})
}
]
};

Подменю с вложенным подменю (2 уровня)

const dropdown: ContextMenuItemWithDropdown = {
id: 'plugin:main',
title: 'Главное меню',
items: [
{
id: 'plugin:action',
title: 'Действие',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:submenu',
title: 'Подменю',
items: [ // Вложенное подменю
{
id: 'plugin:subaction',
title: 'Поддействие',
onClick: editorApi.createCallback(() => {})
}
]
}
]
};

Подменю с условной видимостью

const dropdown: ContextMenuItemWithDropdown = {
id: 'plugin:text-actions',
title: 'Действия с текстом',
shownInScopes: [{ scope: 'text' }], // Видимо только над текстом
items: [
{
id: 'plugin:uppercase',
title: 'ВЕРХНИЙ РЕГИСТР',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.toUpperCase());
}
})
},
{
id: 'plugin:lowercase',
title: 'нижний регистр',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.toLowerCase());
}
})
}
]
};

Подменю с groupingId

const dropdown: ContextMenuItemWithDropdown = {
id: 'plugin:analysis',
title: 'Анализ',
icon: 'BarChart',
items: [
{
id: 'plugin:word-count',
title: 'Количество слов',
groupingId: 'plugin_stats',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:char-count',
title: 'Количество символов',
groupingId: 'plugin_stats',
onClick: editorApi.createCallback(() => {})
},
{
id: 'plugin:readability',
title: 'Читаемость',
groupingId: 'plugin_quality',
onClick: editorApi.createCallback(() => {})
}
]
};

See

Remarks

Иерархия типов:

ContextMenuItemWithDropdown (текущий тип)
└── extends BaseContextMenuItem
├── extends BaseControl
│ ├── id: string (обязательно)
│ ├── title: string (обязательно)
│ └── ...
└── extends MayHaveIcon
└── icon?: string (опционально)
└── items: ContextMenuItem[] (обязательно)

Ключевые отличия от других типов:

  • SimpleContextMenuItem — простой пункт без подменю
  • ContextMenuItemWithDropdown — пункт с выпадающим подменю (текущий)
  • ContextMenuItemWithGroup — пункт с groupingId для группировки

Структура вложенного подменю:

  • Может содержать SimpleContextMenuItem (обычные пункты)
  • Может содержать ContextMenuItemWithDropdown (вложенные подменю, до 2 уровней)
  • Может содержать ContextMenuItemWithGroup (пункты с groupingId)
  • Максимум вложенности: 2 уровня (для удобства)

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

  • Для группировки связанных действий (Экспорт, Трансформация, Анализ)
  • Когда действий много и нужна хорошая организация
  • Для создания иерархической структуры меню
  • Когда нужна структура "Действие → Способ/Тип"

Поведение при отображении:

  • Пункт отображается с указателем (стрелка) обозначающим наличие подменю
  • При наведении мышки или клике открывается подменю
  • Подменю закрывается при клике вне меню
  • На мобильных устройствах: требуется клик для открытия подменю

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

  • Максимум 1-2 уровня вложенности
  • Максимум 5-7 пунктов в подменю
  • Используйте понятные названия категорий
  • Добавляйте иконки для быстрого распознавания

Example

Простое выпадающее меню с 2 пунктами

const dropdownMenu: ContextMenuItemWithDropdown = {
id: 'plugin:text-case',
title: 'Регистр текста',
icon: 'TextCase',
items: [
{
id: 'plugin:uppercase',
title: 'ВЕРХНИЙ РЕГИСТР',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.toUpperCase());
}
})
},
{
id: 'plugin:lowercase',
title: 'нижний регистр',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.toLowerCase());
}
})
}
]
};

editorApi.ui.contextMenu.addItems([dropdownMenu]);

Выпадающее меню "Экспортировать"

const exportMenu: ContextMenuItemWithDropdown = {
id: 'plugin:export',
title: 'Экспортировать',
icon: 'Download',
items: [
{
id: 'plugin:export-pdf',
title: 'Экспортировать в PDF',
onClick: editorApi.createCallback(async () => {
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в PDF...' });
// экспорт в PDF
})
},
{
id: 'plugin:export-html',
title: 'Экспортировать в HTML',
onClick: editorApi.createCallback(async () => {
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в HTML...' });
// экспорт в HTML
})
},
{
id: 'plugin:export-markdown',
title: 'Экспортировать в Markdown',
onClick: editorApi.createCallback(async () => {
editorApi.ui.toasts.showToast({ id, content: 'Экспорт в Markdown...' });
// экспорт в Markdown
})
}
]
};

editorApi.ui.contextMenu.addItems([exportMenu]);

Выпадающее меню с условной видимостью

const conditionalMenu: ContextMenuItemWithDropdown = {
id: 'plugin:text-transform',
title: 'Трансформировать текст',
icon: 'TextTransform',
shownInScopes: [
{ scope: 'text' },
{ scope: 'selection' }
],
items: [
{
id: 'plugin:trim',
title: 'Убрать пробелы',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.trim());
}
})
},
{
id: 'plugin:remove-newlines',
title: 'Убрать переводы строк',
onClick: editorApi.createCallback(async () => {
const text = await editorApi.document.selection.getSelectionAsText();
if (text) {
await editorApi.document.insertContent(text.replace(/\n/g, ' '));
}
})
}
]
};

Выпадающее меню "Вставить"

const insertMenu: ContextMenuItemWithDropdown = {
id: 'plugin:insert',
title: 'Вставить',
icon: 'Plus',
groupingId: 'plugin_insert',
items: [
{
id: 'plugin:insert-date',
title: 'Дату',
onClick: editorApi.createCallback(async () => {
const today = new Date().toLocaleDateString('ru-RU');
await editorApi.document.insertContent(today);
})
},
{
id: 'plugin:insert-time',
title: 'Время',
onClick: editorApi.createCallback(async () => {
const now = new Date().toLocaleTimeString('ru-RU');
await editorApi.document.insertContent(now);
})
},
{
id: 'plugin:insert-timestamp',
title: 'Дату и время',
onClick: editorApi.createCallback(async () => {
const timestamp = new Date().toLocaleString('ru-RU');
await editorApi.document.insertContent(timestamp);
})
}
]
};

Вложенное подменю (2 уровня)

const nestedMenu: ContextMenuItemWithDropdown = {
id: 'plugin:formatting',
title: 'Форматирование',
icon: 'Format',
items: [
{
id: 'plugin:style-bold',
title: 'Жирный',
onClick: editorApi.createCallback(async () => {
await editorApi.document.insertContent('<b>текст</b>', 'html');
})
},
{
id: 'plugin:style-italic',
title: 'Курсив',
onClick: editorApi.createCallback(async () => {
await editorApi.document.insertContent('<i>текст</i>', 'html');
})
},
// Вложенное подменю (до 2-3 уровней)
{
id: 'plugin:colors',
title: 'Цвет текста',
items: [
{
id: 'plugin:color-red',
title: 'Красный',
onClick: editorApi.createCallback(async () => {
await editorApi.document.insertContent(
'<span style="color: red;">текст</span>',
'html'
);
})
},
{
id: 'plugin:color-blue',
title: 'Синий',
onClick: editorApi.createCallback(async () => {
await editorApi.document.insertContent(
'<span style="color: blue;">текст</span>',
'html'
);
})
}
]
}
]
};

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

export default {
onInit: (editorApi) => {
editorApi.ui.contextMenu.addItems([
{
id: 'plugin:main-menu',
title: 'Моя надстройка',
icon: 'Plugin',
groupingId: 'plugin_main',
items: [
{
id: 'plugin:action-1',
title: 'Действие 1',
onClick: editorApi.createCallback(() => {
console.log('Действие 1');
})
},
{
id: 'plugin:action-2',
title: 'Действие 2',
onClick: editorApi.createCallback(() => {
console.log('Действие 2');
})
},
{
id: 'plugin:submenu',
title: 'Подменю',
items: [
{
id: 'plugin:subaction-1',
title: 'Поддействие 1',
onClick: editorApi.createCallback(() => {
console.log('Поддействие 1');
})
},
{
id: 'plugin:subaction-2',
title: 'Поддействие 2',
onClick: editorApi.createCallback(() => {
console.log('Поддействие 2');
})
}
]
}
]
}
]);
},

onDestroy: (editorApi) => {
editorApi.ui.contextMenu.removeItems([
'plugin:main-menu'
]);
}
}

See

  • BaseContextMenuItem — наследуемые свойства
  • SimpleContextMenuItem — простой пункт без подменю
  • ContextMenuItemWithGroup — для пунктов с группировкой
  • ContextMenuItem — объединение всех типов элементов меню
  • ContextMenuApi — API управления контекстным меню