@notectl/core 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +12 -10
  2. package/dist/chunks/{AttrRegistry-Ckj9eCHj.mjs → AttrRegistry-iNpjvcSG.mjs} +2 -2
  3. package/dist/chunks/{AttrRegistry-Ckj9eCHj.mjs.map → AttrRegistry-iNpjvcSG.mjs.map} +1 -1
  4. package/dist/chunks/AttributedMarkCommands-BY1BSYWM.mjs +2 -0
  5. package/dist/chunks/{AttributedMarkCommands-x7h4Xy7V.mjs.map → AttributedMarkCommands-BY1BSYWM.mjs.map} +1 -1
  6. package/dist/chunks/BlockInsertion-BJFhE0jA.mjs +2 -0
  7. package/dist/chunks/BlockInsertion-BJFhE0jA.mjs.map +1 -0
  8. package/dist/chunks/{ColorPickerPopup-CDUvkgcK.mjs → ColorPickerPopup-D6XjShhv.mjs} +2 -2
  9. package/dist/chunks/{ColorPickerPopup-CDUvkgcK.mjs.map → ColorPickerPopup-D6XjShhv.mjs.map} +1 -1
  10. package/dist/chunks/CommandHelpers-M6mPS6Ww.mjs +2 -0
  11. package/dist/chunks/CommandHelpers-M6mPS6Ww.mjs.map +1 -0
  12. package/dist/chunks/Commands-D_gMCnVa.mjs +2 -0
  13. package/dist/chunks/Commands-D_gMCnVa.mjs.map +1 -0
  14. package/dist/chunks/Document-3pNX7ear.mjs +2 -0
  15. package/dist/chunks/{Document-HC8s50qJ.mjs.map → Document-3pNX7ear.mjs.map} +1 -1
  16. package/dist/chunks/{DocumentParser-w70-Axud.mjs → DocumentParser-LvzDQOd1.mjs} +2 -2
  17. package/dist/chunks/{DocumentParser-w70-Axud.mjs.map → DocumentParser-LvzDQOd1.mjs.map} +1 -1
  18. package/dist/chunks/{HeadingPlugin-B-LF-AMM.mjs → HeadingPlugin-BmkeUXj8.mjs} +2 -2
  19. package/dist/chunks/{HeadingPlugin-B-LF-AMM.mjs.map → HeadingPlugin-BmkeUXj8.mjs.map} +1 -1
  20. package/dist/chunks/MarkCommands-CeCa4WSC.mjs +2 -0
  21. package/dist/chunks/{MarkCommands-CTuVDqnn.mjs.map → MarkCommands-CeCa4WSC.mjs.map} +1 -1
  22. package/dist/chunks/NavigationQueries-11qe4j9x.mjs +2 -0
  23. package/dist/chunks/NavigationQueries-11qe4j9x.mjs.map +1 -0
  24. package/dist/chunks/NodeResolver-z0ReCR34.mjs +2 -0
  25. package/dist/chunks/NodeResolver-z0ReCR34.mjs.map +1 -0
  26. package/dist/chunks/NodeSelectionCommands-CXrOcPtG.mjs +2 -0
  27. package/dist/chunks/NodeSelectionCommands-CXrOcPtG.mjs.map +1 -0
  28. package/dist/chunks/NotectlEditor-BJD7-FFx.mjs +4 -0
  29. package/dist/chunks/NotectlEditor-BJD7-FFx.mjs.map +1 -0
  30. package/dist/chunks/PopupManager-0b_Q0m7K.mjs +2 -0
  31. package/dist/chunks/PopupManager-0b_Q0m7K.mjs.map +1 -0
  32. package/dist/chunks/{RangeIterator-CprUbOWv.mjs → RangeIterator-XFN5FaYf.mjs} +2 -2
  33. package/dist/chunks/{RangeIterator-CprUbOWv.mjs.map → RangeIterator-XFN5FaYf.mjs.map} +1 -1
  34. package/dist/chunks/SelectionTransactions-DzIZxcuN.mjs +2 -0
  35. package/dist/chunks/{SelectionTransactions-DB3YDIEa.mjs.map → SelectionTransactions-DzIZxcuN.mjs.map} +1 -1
  36. package/dist/chunks/{TextDirectionLocale-BraFI9JF.mjs → TextDirectionLocale-CKz0ZrH_.mjs} +2 -2
  37. package/dist/chunks/{TextDirectionLocale-BraFI9JF.mjs.map → TextDirectionLocale-CKz0ZrH_.mjs.map} +1 -1
  38. package/dist/chunks/index-C-L4awHz.mjs +2 -0
  39. package/dist/chunks/index-C-L4awHz.mjs.map +1 -0
  40. package/dist/chunks/{index-D3BZFsAD.mjs → index-Cs9iqxhF.mjs} +2 -2
  41. package/dist/chunks/{index-D3BZFsAD.mjs.map → index-Cs9iqxhF.mjs.map} +1 -1
  42. package/dist/commands/BlockInsertion.d.ts.map +1 -1
  43. package/dist/commands/CommandHelpers.d.ts +13 -2
  44. package/dist/commands/CommandHelpers.d.ts.map +1 -1
  45. package/dist/commands/NodeSelectionCommands.d.ts +3 -8
  46. package/dist/commands/NodeSelectionCommands.d.ts.map +1 -1
  47. package/dist/editor/ContentSerializer.d.ts.map +1 -1
  48. package/dist/editor/EditorConfig.d.ts +50 -0
  49. package/dist/editor/EditorConfig.d.ts.map +1 -0
  50. package/dist/editor/EditorConfigController.d.ts +1 -1
  51. package/dist/editor/EditorConfigController.d.ts.map +1 -1
  52. package/dist/editor/EditorDOM.d.ts.map +1 -1
  53. package/dist/editor/EditorInitializer.d.ts +37 -0
  54. package/dist/editor/EditorInitializer.d.ts.map +1 -0
  55. package/dist/editor/EditorLifecycleCoordinator.d.ts +6 -1
  56. package/dist/editor/EditorLifecycleCoordinator.d.ts.map +1 -1
  57. package/dist/editor/NotectlEditor.d.ts +13 -51
  58. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  59. package/dist/editor/PluginBootstrapper.d.ts +1 -1
  60. package/dist/editor/PluginBootstrapper.d.ts.map +1 -1
  61. package/dist/full.mjs +1 -1
  62. package/dist/html.mjs +1 -1
  63. package/dist/input/ClipboardHandler.d.ts +5 -0
  64. package/dist/input/ClipboardHandler.d.ts.map +1 -1
  65. package/dist/input/HTMLParser.d.ts +9 -5
  66. package/dist/input/HTMLParser.d.ts.map +1 -1
  67. package/dist/input/InputHandler.d.ts +1 -0
  68. package/dist/input/InputHandler.d.ts.map +1 -1
  69. package/dist/input/PasteHTMLHandler.d.ts +25 -0
  70. package/dist/input/PasteHTMLHandler.d.ts.map +1 -0
  71. package/dist/input/PasteHandler.d.ts +2 -27
  72. package/dist/input/PasteHandler.d.ts.map +1 -1
  73. package/dist/input/PasteRichBlockHandler.d.ts +23 -0
  74. package/dist/input/PasteRichBlockHandler.d.ts.map +1 -0
  75. package/dist/input/SelectionDocument.d.ts +10 -0
  76. package/dist/input/SelectionDocument.d.ts.map +1 -0
  77. package/dist/model/RichBlockData.d.ts +12 -2
  78. package/dist/model/RichBlockData.d.ts.map +1 -1
  79. package/dist/notectl-core.mjs +1 -1
  80. package/dist/notectl-core.umd.js +1 -1
  81. package/dist/notectl-core.umd.js.map +1 -1
  82. package/dist/plugins/PluginContextFactory.d.ts +73 -0
  83. package/dist/plugins/PluginContextFactory.d.ts.map +1 -0
  84. package/dist/plugins/PluginManager.d.ts +5 -0
  85. package/dist/plugins/PluginManager.d.ts.map +1 -1
  86. package/dist/plugins/blockquote.mjs +1 -1
  87. package/dist/plugins/caret-navigation.mjs +1 -1
  88. package/dist/plugins/code-block.mjs +1 -1
  89. package/dist/plugins/font-size.mjs +1 -1
  90. package/dist/plugins/font.mjs +1 -1
  91. package/dist/plugins/gap-cursor.mjs +1 -1
  92. package/dist/plugins/hard-break.mjs +1 -1
  93. package/dist/plugins/heading.mjs +1 -1
  94. package/dist/plugins/highlight.mjs +1 -1
  95. package/dist/plugins/horizontal-rule.mjs +1 -1
  96. package/dist/plugins/image/ImageCommands.d.ts.map +1 -1
  97. package/dist/plugins/image.mjs +1 -1
  98. package/dist/plugins/image.mjs.map +1 -1
  99. package/dist/plugins/link.mjs +1 -1
  100. package/dist/plugins/list.mjs +1 -1
  101. package/dist/plugins/print.mjs +1 -1
  102. package/dist/plugins/shared/PopupManager.d.ts.map +1 -1
  103. package/dist/plugins/shared.mjs +1 -1
  104. package/dist/plugins/smart-paste.mjs +1 -1
  105. package/dist/plugins/strikethrough.mjs +1 -1
  106. package/dist/plugins/super-sub.mjs +1 -1
  107. package/dist/plugins/table/TableCommands.d.ts +1 -0
  108. package/dist/plugins/table/TableCommands.d.ts.map +1 -1
  109. package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
  110. package/dist/plugins/table/TableSelection.d.ts.map +1 -1
  111. package/dist/plugins/table.mjs +1 -1
  112. package/dist/plugins/table.mjs.map +1 -1
  113. package/dist/plugins/text-color.mjs +1 -1
  114. package/dist/plugins/text-direction-advanced.mjs +1 -1
  115. package/dist/plugins/text-direction.mjs +1 -1
  116. package/dist/plugins/text-formatting.mjs +1 -1
  117. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts +2 -0
  118. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts.map +1 -1
  119. package/dist/plugins/toolbar.mjs +1 -1
  120. package/dist/plugins/toolbar.mjs.map +1 -1
  121. package/dist/presets/full.mjs +1 -1
  122. package/dist/state/StepInversion.d.ts.map +1 -1
  123. package/dist/view/EditorView.d.ts +8 -58
  124. package/dist/view/EditorView.d.ts.map +1 -1
  125. package/dist/view/EditorViewEvents.d.ts +54 -0
  126. package/dist/view/EditorViewEvents.d.ts.map +1 -0
  127. package/dist/view/EditorViewNavigation.d.ts +47 -0
  128. package/dist/view/EditorViewNavigation.d.ts.map +1 -0
  129. package/dist/view/SelectionSync.d.ts.map +1 -1
  130. package/package.json +2 -2
  131. package/dist/chunks/AttributedMarkCommands-x7h4Xy7V.mjs +0 -2
  132. package/dist/chunks/BlockInsertion-zPxm6oa_.mjs +0 -2
  133. package/dist/chunks/BlockInsertion-zPxm6oa_.mjs.map +0 -1
  134. package/dist/chunks/Commands-DwXBBVGR.mjs +0 -2
  135. package/dist/chunks/Commands-DwXBBVGR.mjs.map +0 -1
  136. package/dist/chunks/Document-HC8s50qJ.mjs +0 -2
  137. package/dist/chunks/MarkCommands-CTuVDqnn.mjs +0 -2
  138. package/dist/chunks/NavigationQueries-DCOv4Ca5.mjs +0 -2
  139. package/dist/chunks/NavigationQueries-DCOv4Ca5.mjs.map +0 -1
  140. package/dist/chunks/NotectlEditor-DBBJkPCW.mjs +0 -3
  141. package/dist/chunks/NotectlEditor-DBBJkPCW.mjs.map +0 -1
  142. package/dist/chunks/PopupManager-Du3dYnsJ.mjs +0 -2
  143. package/dist/chunks/PopupManager-Du3dYnsJ.mjs.map +0 -1
  144. package/dist/chunks/SelectionTransactions-DB3YDIEa.mjs +0 -2
  145. package/dist/chunks/index-CVwf0cdH.mjs +0 -2
  146. package/dist/chunks/index-CVwf0cdH.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"toolbar.mjs","sources":["../../src/plugins/toolbar/ToolbarRegistry.ts","../../src/plugins/toolbar/ToolbarKeyboardNav.ts","../../src/plugins/toolbar/ToolbarLocale.ts","../../src/plugins/toolbar/ToolbarOverflowBehavior.ts","../../src/plugins/toolbar/ToolbarOverflowController.ts","../../src/plugins/toolbar/ToolbarRenderers.ts","../../src/plugins/toolbar/ToolbarPopupController.ts","../../src/plugins/toolbar/ToolbarTooltip.ts","../../src/plugins/toolbar/ToolbarPlugin.ts","../../src/editor/styles/toolbar.ts"],"sourcesContent":["/**\n * ToolbarRegistry: manages plugin-registered toolbar items\n * with per-plugin tracking for clean teardown.\n */\n\nimport type { ToolbarItem } from './ToolbarItem.js';\n\nexport class ToolbarRegistry {\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\n\tregisterToolbarItem(item: ToolbarItem, pluginId?: string): void {\n\t\tif (this._toolbarItems.has(item.id)) {\n\t\t\tthrow new Error(`ToolbarItem with id \"${item.id}\" is already registered.`);\n\t\t}\n\t\tthis._toolbarItems.set(item.id, item);\n\t\tif (pluginId) {\n\t\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\t\tids.push(item.id);\n\t\t\tthis._toolbarItemPluginMap.set(pluginId, ids);\n\t\t}\n\t}\n\n\tgetToolbarItemsByPlugin(pluginId: string): ToolbarItem[] {\n\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\tconst items: ToolbarItem[] = [];\n\t\tfor (const id of ids) {\n\t\t\tconst item = this._toolbarItems.get(id);\n\t\t\tif (item) items.push(item);\n\t\t}\n\t\treturn items;\n\t}\n\n\tgetToolbarItem(id: string): ToolbarItem | undefined {\n\t\treturn this._toolbarItems.get(id);\n\t}\n\n\tgetToolbarItems(): ToolbarItem[] {\n\t\treturn [...this._toolbarItems.values()];\n\t}\n\n\tremoveToolbarItem(id: string): void {\n\t\tthis._toolbarItems.delete(id);\n\t\tfor (const [pluginId, ids] of this._toolbarItemPluginMap) {\n\t\t\tconst idx = ids.indexOf(id);\n\t\t\tif (idx !== -1) {\n\t\t\t\tids.splice(idx, 1);\n\t\t\t\tif (ids.length === 0) this._toolbarItemPluginMap.delete(pluginId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t}\n}\n","/**\n * Keyboard navigation helpers for the toolbar (WAI-ARIA Toolbar pattern).\n * Also re-exports generic navigation helpers from `plugins/shared`.\n */\n\n/** Returns indices of all enabled buttons. */\nexport function getEnabledIndices(buttons: readonly HTMLButtonElement[]): number[] {\n\tconst result: number[] = [];\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) {\n\t\t\tresult.push(i);\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Finds the next enabled button index in the given direction (wraps around). */\nexport function findNextEnabled(\n\tbuttons: readonly HTMLButtonElement[],\n\tcurrent: number,\n\tdirection: 1 | -1,\n): number {\n\tconst len = buttons.length;\n\tif (len === 0) return -1;\n\n\tlet index = current;\n\tfor (let i = 0; i < len; i++) {\n\t\tindex = (index + direction + len) % len;\n\t\tif (!buttons[index]?.disabled) {\n\t\t\treturn index;\n\t\t}\n\t}\n\treturn current;\n}\n\n/** Finds the first enabled button index. */\nexport function findFirstEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\n/** Finds the last enabled button index. */\nexport function findLastEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = buttons.length - 1; i >= 0; i--) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\nexport {\n\tapplyRovingTabindex,\n\tfindNextDropdownItem,\n\tnavigateGrid,\n} from '../shared/KeyboardNav.js';\n\n/**\n * Resolves a horizontal navigation direction based on text direction.\n * In RTL, ArrowRight moves backward (-1) and ArrowLeft moves forward (1).\n */\nexport function resolveHorizontalDirection(\n\tkey: 'ArrowRight' | 'ArrowLeft',\n\tisRtl: boolean,\n): 1 | -1 {\n\tif (key === 'ArrowRight') return isRtl ? -1 : 1;\n\treturn isRtl ? 1 : -1;\n}\n","/** Locale interface and default English locale for the ToolbarPlugin. */\n\n// --- Locale Interface ---\n\nexport interface ToolbarLocale {\n\treadonly formattingOptionsAria: string;\n\treadonly moreToolsAria: string;\n\treadonly gridPickerLabel: (rows: number, cols: number) => string;\n}\n\n// --- Default English Locale ---\n\nexport const TOOLBAR_LOCALE_EN: ToolbarLocale = {\n\tformattingOptionsAria: 'Formatting options',\n\tmoreToolsAria: 'More tools',\n\tgridPickerLabel: (rows: number, cols: number) => `${rows} x ${cols}`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ToolbarLocale }>> = import.meta.glob<{\n\tdefault: ToolbarLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadToolbarLocale(lang: string): Promise<ToolbarLocale> {\n\tif (lang === 'en') return TOOLBAR_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return TOOLBAR_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn TOOLBAR_LOCALE_EN;\n\t}\n}\n","/**\n * Controls how the toolbar responds when items exceed the available width.\n *\n * @example\n * ```typescript\n * const editor = await createEditor({\n * toolbar: {\n * groups: [[BoldPlugin, ItalicPlugin], [HeadingPlugin]],\n * overflow: ToolbarOverflowBehavior.Flow,\n * },\n * });\n * ```\n */\nexport const ToolbarOverflowBehavior = {\n\t/** Items that don't fit are hidden behind a \"...\" dropdown button. Default. */\n\tBurgerMenu: 'burger-menu',\n\t/** Toolbar wraps to additional rows when items overflow. Pure CSS, no JS measurement. */\n\tFlow: 'flow',\n\t/** No responsive behavior; the toolbar clips at the container boundary. */\n\tNone: 'none',\n} as const;\n\nexport type ToolbarOverflowBehavior =\n\t(typeof ToolbarOverflowBehavior)[keyof typeof ToolbarOverflowBehavior];\n","/**\n * ToolbarOverflowController: manages responsive toolbar overflow.\n * Uses ResizeObserver to detect when items exceed available width,\n * hides overflow items, and shows a \"more\" dropdown button.\n * Delegates popup lifecycle to PopupManager when available.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { findNextDropdownItem } from '../shared/KeyboardNav.js';\nimport type { PopupHandle, PopupManager } from '../shared/PopupManager.js';\nimport { appendToRoot } from '../shared/PopupPositioning.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\n\n// --- Types ---\n\ninterface OverflowEntry {\n\treadonly element: HTMLButtonElement;\n\treadonly item: ToolbarItem;\n}\n\ntype OnOverflowChange = (\n\tvisibleButtons: readonly HTMLButtonElement[],\n\toverflowButton: HTMLButtonElement | null,\n) => void;\n\ntype OnItemActivated = (overflowButton: HTMLButtonElement, item: ToolbarItem) => void;\n\nexport interface OverflowControllerConfig {\n\treadonly toolbar: HTMLElement;\n\treadonly ariaLabel: string;\n\treadonly context: PluginContext;\n\treadonly onOverflowChange: OnOverflowChange;\n\treadonly onItemActivated: OnItemActivated;\n\treadonly getActiveElement: () => Element | null;\n\treadonly popupManager?: PopupManager;\n}\n\n// --- Constants ---\n\nconst OVERFLOW_BTN_WIDTH = 34;\nconst GAP = 2;\nconst HIDDEN_BTN_CLASS = 'notectl-toolbar-btn--overflow-hidden';\nconst HIDDEN_SEP_CLASS = 'notectl-toolbar-separator--overflow-hidden';\nconst HIDDEN_OVERFLOW_CLASS = 'notectl-toolbar-overflow-btn--hidden';\nconst ELLIPSIS_SVG =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\"><circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/></svg>';\n\n// --- Controller ---\n\nexport class ToolbarOverflowController {\n\tprivate readonly toolbar: HTMLElement;\n\tprivate readonly context: PluginContext;\n\tprivate readonly onOverflowChange: OnOverflowChange;\n\tprivate readonly onItemActivated: OnItemActivated;\n\tprivate readonly getActiveElement: () => Element | null;\n\tprivate readonly ariaLabel: string;\n\tprivate readonly popupManager: PopupManager | null;\n\n\tprivate entries: OverflowEntry[] = [];\n\tprivate overflowButton: HTMLButtonElement | null = null;\n\tprivate overflowDropdown: HTMLElement | null = null;\n\tprivate overflowHandle: PopupHandle | null = null;\n\tprivate overflowEntries: OverflowEntry[] = [];\n\tprivate resizeObserver: ResizeObserver | null = null;\n\tprivate closeHandler: ((e: MouseEvent) => void) | null = null;\n\n\tconstructor(config: OverflowControllerConfig) {\n\t\tthis.toolbar = config.toolbar;\n\t\tthis.ariaLabel = config.ariaLabel;\n\t\tthis.context = config.context;\n\t\tthis.onOverflowChange = config.onOverflowChange;\n\t\tthis.onItemActivated = config.onItemActivated;\n\t\tthis.getActiveElement = config.getActiveElement;\n\t\tthis.popupManager = config.popupManager ?? null;\n\n\t\tthis.resizeObserver = new ResizeObserver(() => this.recalculate());\n\t\tthis.resizeObserver.observe(this.toolbar);\n\t}\n\n\t/** Called after renderItems() — stores button references and recalculates. */\n\tupdate(buttons: readonly { element: HTMLButtonElement; item: ToolbarItem }[]): void {\n\t\tthis.entries = buttons.map((b) => ({ element: b.element, item: b.item }));\n\t\tthis.recalculate();\n\t}\n\n\t/** Measures toolbar and redistributes items between visible and overflow. */\n\trecalculate(): void {\n\t\tif (this.entries.length === 0) return;\n\n\t\tthis.closeDropdown();\n\t\tthis.resetVisibility();\n\t\tthis.ensureOverflowButton();\n\t\tthis.setOverflowButtonVisible(false);\n\n\t\t// Phase 1 — Measure (reads only): batch all layout reads before any writes\n\t\tconst availableWidth: number = this.measureAvailableWidth();\n\t\tconst children: HTMLElement[] = Array.from(this.toolbar.children) as HTMLElement[];\n\t\tconst childWidths: Map<HTMLElement, number> = this.measureChildWidths(children);\n\n\t\t// Phase 2 — Apply (writes only): use cached widths, no layout reads\n\t\tconst maxWidth: number = availableWidth - OVERFLOW_BTN_WIDTH - GAP;\n\t\tlet usedWidth = 0;\n\t\tlet overflowing = false;\n\t\tconst overflowList: OverflowEntry[] = [];\n\n\t\tfor (const child of children) {\n\t\t\tif (child === this.overflowButton) continue;\n\n\t\t\tif (child.classList.contains('notectl-toolbar-separator')) {\n\t\t\t\tif (overflowing) {\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst sepWidth: number = (childWidths.get(child) ?? 0) + GAP;\n\t\t\t\tif (usedWidth + sepWidth > maxWidth) {\n\t\t\t\t\toverflowing = true;\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t} else {\n\t\t\t\t\tusedWidth += sepWidth;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry: OverflowEntry | undefined = this.entries.find((oe) => oe.element === child);\n\t\t\tif (!entry) continue;\n\n\t\t\tif (overflowing) {\n\t\t\t\tentry.element.classList.add(HIDDEN_BTN_CLASS);\n\t\t\t\toverflowList.push(entry);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst btnWidth: number = (childWidths.get(child) ?? 0) + GAP;\n\t\t\tif (usedWidth + btnWidth > maxWidth) {\n\t\t\t\toverflowing = true;\n\t\t\t\tentry.element.classList.add(HIDDEN_BTN_CLASS);\n\t\t\t\toverflowList.push(entry);\n\t\t\t} else {\n\t\t\t\tusedWidth += btnWidth;\n\t\t\t}\n\t\t}\n\n\t\tthis.overflowEntries = overflowList;\n\t\tthis.hideTrailingSeparators();\n\t\tthis.setOverflowButtonVisible(overflowList.length > 0);\n\t\tthis.notifyChange();\n\t}\n\n\t/** Updates active/disabled states for items in the open overflow dropdown. */\n\tupdateItemStates(state: EditorState): void {\n\t\tif (!this.overflowDropdown) return;\n\n\t\tconst menuItems: HTMLButtonElement[] = Array.from(\n\t\t\tthis.overflowDropdown.querySelectorAll('.notectl-dropdown__item'),\n\t\t) as HTMLButtonElement[];\n\n\t\tfor (const menuItem of menuItems) {\n\t\t\tconst itemId: string | null = menuItem.getAttribute('data-toolbar-item');\n\t\t\tconst entry: OverflowEntry | undefined = this.overflowEntries.find(\n\t\t\t\t(oe) => oe.item.id === itemId,\n\t\t\t);\n\t\t\tif (!entry) continue;\n\n\t\t\tconst active: boolean = entry.item.isActive?.(state) ?? false;\n\t\t\tconst enabled: boolean = entry.item.isEnabled?.(state) ?? true;\n\t\t\tmenuItem.classList.toggle('notectl-dropdown__item--active', active);\n\t\t\tmenuItem.disabled = !enabled;\n\n\t\t\tif (entry.item.popupType === 'combobox') {\n\t\t\t\tconst labelEl: HTMLSpanElement | null = menuItem.querySelector(\n\t\t\t\t\t'.notectl-dropdown__item-label',\n\t\t\t\t);\n\t\t\t\tif (labelEl) {\n\t\t\t\t\tlabelEl.textContent = entry.item.getLabel(state);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entry.item.getIcon) {\n\t\t\t\tconst newIcon: string = entry.item.getIcon(state);\n\t\t\t\tconst iconEl: HTMLSpanElement | null = menuItem.querySelector(\n\t\t\t\t\t'.notectl-dropdown__item-icon',\n\t\t\t\t);\n\t\t\t\tif (iconEl && iconEl.innerHTML !== newIcon) {\n\t\t\t\t\ticonEl.innerHTML = newIcon;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Cleans up ResizeObserver, DOM elements, and event listeners. */\n\tdestroy(): void {\n\t\tthis.resizeObserver?.disconnect();\n\t\tthis.resizeObserver = null;\n\t\tthis.closeDropdown();\n\t\tthis.overflowButton?.remove();\n\t\tthis.overflowButton = null;\n\t\tthis.entries = [];\n\t\tthis.overflowEntries = [];\n\t}\n\n\t// --- Measurement ---\n\n\tprivate measureChildWidths(children: readonly HTMLElement[]): Map<HTMLElement, number> {\n\t\tconst widths: Map<HTMLElement, number> = new Map();\n\t\tfor (const child of children) {\n\t\t\tif (child === this.overflowButton) continue;\n\t\t\twidths.set(child, child.offsetWidth);\n\t\t}\n\t\treturn widths;\n\t}\n\n\tprivate measureAvailableWidth(): number {\n\t\tconst toolbarStyle: CSSStyleDeclaration = getComputedStyle(this.toolbar);\n\t\tconst paddingLeft: number = Number.parseFloat(toolbarStyle.paddingLeft) || 0;\n\t\tconst paddingRight: number = Number.parseFloat(toolbarStyle.paddingRight) || 0;\n\t\treturn this.toolbar.clientWidth - paddingLeft - paddingRight;\n\t}\n\n\tprivate resetVisibility(): void {\n\t\tfor (const entry of this.entries) {\n\t\t\tentry.element.classList.remove(HIDDEN_BTN_CLASS);\n\t\t}\n\t\tconst separators: HTMLElement[] = Array.from(\n\t\t\tthis.toolbar.querySelectorAll('.notectl-toolbar-separator'),\n\t\t) as HTMLElement[];\n\t\tfor (const sep of separators) {\n\t\t\tsep.classList.remove(HIDDEN_SEP_CLASS);\n\t\t}\n\t}\n\n\t// --- Overflow Button ---\n\n\tprivate setOverflowButtonVisible(visible: boolean): void {\n\t\tif (!this.overflowButton) return;\n\t\tthis.overflowButton.classList.toggle(HIDDEN_OVERFLOW_CLASS, !visible);\n\t\tif (!visible) {\n\t\t\tthis.overflowButton.removeAttribute('tabindex');\n\t\t}\n\t}\n\n\tprivate ensureOverflowButton(): void {\n\t\tif (this.overflowButton) return;\n\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = 'notectl-toolbar-overflow-btn';\n\t\tbtn.setAttribute('aria-label', this.ariaLabel);\n\t\tbtn.setAttribute('aria-haspopup', 'true');\n\t\tbtn.setAttribute('aria-expanded', 'false');\n\t\tbtn.innerHTML = ELLIPSIS_SVG;\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tthis.toggleDropdown();\n\t\t});\n\n\t\tthis.toolbar.appendChild(btn);\n\t\tthis.overflowButton = btn;\n\t}\n\n\t// --- Dropdown ---\n\n\tprivate toggleDropdown(): void {\n\t\tif (this.overflowDropdown) {\n\t\t\tthis.closeDropdown();\n\t\t} else {\n\t\t\tthis.openDropdown();\n\t\t}\n\t}\n\n\tprivate openDropdown(): void {\n\t\tif (!this.overflowButton || this.overflowEntries.length === 0) return;\n\n\t\tconst dropdown: HTMLDivElement = document.createElement('div');\n\t\tdropdown.className = 'notectl-toolbar-popup notectl-dropdown';\n\t\tdropdown.setAttribute('role', 'menu');\n\n\t\tthis.renderDropdownItems(dropdown, this.context.getState());\n\n\t\tif (this.popupManager) {\n\t\t\tthis.overflowHandle = this.popupManager.open({\n\t\t\t\tanchor: this.overflowButton,\n\t\t\t\tclassName: 'notectl-toolbar-popup notectl-dropdown',\n\t\t\t\tariaRole: 'menu',\n\t\t\t\tposition: 'below-end',\n\t\t\t\treferenceNode: this.overflowButton,\n\t\t\t\trestoreFocusTo: this.overflowButton,\n\t\t\t\tonClose: () => {\n\t\t\t\t\tthis.overflowHandle = null;\n\t\t\t\t\tthis.overflowDropdown = null;\n\t\t\t\t\tif (this.overflowButton) {\n\t\t\t\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tcontent: (popup: HTMLElement) => {\n\t\t\t\t\tthis.renderDropdownItems(popup, this.context.getState());\n\t\t\t\t\tthis.overflowDropdown = popup;\n\t\t\t\t\tpopup.addEventListener('keydown', (e: KeyboardEvent) => this.handleDropdownKeydown(e));\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'true');\n\t\t} else {\n\t\t\tthis.positionDropdown(dropdown);\n\t\t\tappendToRoot(dropdown, this.overflowButton);\n\t\t\tthis.overflowDropdown = dropdown;\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'true');\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tconst first: HTMLElement | null = dropdown.querySelector('[role=\"menuitem\"]');\n\t\t\t\tfirst?.focus();\n\t\t\t});\n\n\t\t\tdropdown.addEventListener('keydown', (e: KeyboardEvent) => this.handleDropdownKeydown(e));\n\t\t\tthis.registerCloseHandler();\n\t\t}\n\t}\n\n\tprivate renderDropdownItems(dropdown: HTMLElement, state: EditorState): void {\n\t\tlet lastGroup: string | null = null;\n\n\t\tfor (const entry of this.overflowEntries) {\n\t\t\tif (lastGroup !== null && entry.item.group !== lastGroup) {\n\t\t\t\tconst sep: HTMLDivElement = document.createElement('div');\n\t\t\t\tsep.className = 'notectl-dropdown__separator';\n\t\t\t\tsep.setAttribute('role', 'separator');\n\t\t\t\tdropdown.appendChild(sep);\n\t\t\t}\n\t\t\tlastGroup = entry.item.group;\n\n\t\t\tconst menuBtn: HTMLButtonElement = document.createElement('button');\n\t\t\tmenuBtn.type = 'button';\n\t\t\tmenuBtn.className = 'notectl-dropdown__item';\n\t\t\tmenuBtn.setAttribute('role', 'menuitem');\n\t\t\tmenuBtn.setAttribute('tabindex', '-1');\n\t\t\tmenuBtn.setAttribute('data-toolbar-item', entry.item.id);\n\n\t\t\tconst iconSpan: HTMLSpanElement = document.createElement('span');\n\t\t\ticonSpan.className = 'notectl-dropdown__item-icon';\n\t\t\tif (entry.item.popupType !== 'combobox') {\n\t\t\t\ticonSpan.innerHTML = entry.item.icon;\n\t\t\t}\n\t\t\tmenuBtn.appendChild(iconSpan);\n\n\t\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tlabelSpan.className = 'notectl-dropdown__item-label';\n\t\t\tlabelSpan.textContent =\n\t\t\t\tentry.item.popupType === 'combobox'\n\t\t\t\t\t? entry.item.getLabel(state)\n\t\t\t\t\t: (entry.item.tooltip ?? entry.item.label);\n\t\t\tmenuBtn.appendChild(labelSpan);\n\n\t\t\tmenuBtn.addEventListener('mousedown', (ev: MouseEvent) => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tev.stopPropagation();\n\t\t\t\tthis.activateOverflowItem(entry);\n\t\t\t});\n\n\t\t\tdropdown.appendChild(menuBtn);\n\t\t}\n\t}\n\n\tprivate positionDropdown(dropdown: HTMLElement): void {\n\t\tif (!this.overflowButton) return;\n\n\t\tconst rect: DOMRect = this.overflowButton.getBoundingClientRect();\n\t\tconst rtl: boolean = isRtlContext(this.toolbar);\n\n\t\tif (rtl) {\n\t\t\tsetStyleProperties(dropdown, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 2}px`,\n\t\t\t\tleft: `${rect.left}px`,\n\t\t\t\tright: 'auto',\n\t\t\t\tzIndex: '10000',\n\t\t\t});\n\t\t} else {\n\t\t\tconst rightEdge: number = window.innerWidth - rect.right;\n\t\t\tsetStyleProperties(dropdown, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 2}px`,\n\t\t\t\tright: `${rightEdge}px`,\n\t\t\t\tleft: 'auto',\n\t\t\t\tzIndex: '10000',\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerCloseHandler(): void {\n\t\tthis.closeHandler = (ev: MouseEvent) => {\n\t\t\tconst path: EventTarget[] = ev.composedPath();\n\t\t\tif (\n\t\t\t\tthis.overflowDropdown &&\n\t\t\t\t!path.includes(this.overflowDropdown) &&\n\t\t\t\tthis.overflowButton &&\n\t\t\t\t!path.includes(this.overflowButton)\n\t\t\t) {\n\t\t\t\tthis.closeDropdown();\n\t\t\t}\n\t\t};\n\t\tsetTimeout(() => {\n\t\t\tif (this.closeHandler) {\n\t\t\t\tdocument.addEventListener('mousedown', this.closeHandler);\n\t\t\t}\n\t\t}, 0);\n\t}\n\n\tprivate closeDropdown(): void {\n\t\tif (this.overflowHandle) {\n\t\t\tconst handle: PopupHandle = this.overflowHandle;\n\t\t\tthis.overflowHandle = null;\n\t\t\tthis.overflowDropdown = null;\n\t\t\thandle.close();\n\t\t\tif (this.overflowButton) {\n\t\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.overflowDropdown) {\n\t\t\tthis.overflowDropdown.remove();\n\t\t\tthis.overflowDropdown = null;\n\t\t}\n\t\tif (this.overflowButton) {\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t}\n\t\tif (this.closeHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.closeHandler);\n\t\t\tthis.closeHandler = null;\n\t\t}\n\t}\n\n\tprivate activateOverflowItem(entry: OverflowEntry): void {\n\t\tthis.closeDropdown();\n\t\tif (entry.item.popupType && this.overflowButton) {\n\t\t\tthis.onItemActivated(this.overflowButton, entry.item);\n\t\t} else {\n\t\t\tthis.context.executeCommand(entry.item.command);\n\t\t}\n\t}\n\n\t// --- Keyboard Navigation ---\n\n\tprivate handleDropdownKeydown(e: KeyboardEvent): void {\n\t\tif (!this.overflowDropdown) return;\n\n\t\tif (e.key === 'Escape' || e.key === 'Tab') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.closeDropdown();\n\t\t\tthis.overflowButton?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tthis.overflowDropdown.querySelectorAll('[role=\"menuitem\"]'),\n\t\t) as HTMLElement[];\n\t\tconst current: number = items.indexOf(this.getActiveElement() as HTMLElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(items, current, 1);\n\t\t\t\titems[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(items, current, -1);\n\t\t\t\titems[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focusedItem: HTMLElement | undefined = items[current];\n\t\t\t\tif (!focusedItem) break;\n\t\t\t\tconst itemId: string | null = focusedItem.getAttribute('data-toolbar-item');\n\t\t\t\tconst entry: OverflowEntry | undefined = this.overflowEntries.find(\n\t\t\t\t\t(oe) => oe.item.id === itemId,\n\t\t\t\t);\n\t\t\t\tif (entry) this.activateOverflowItem(entry);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Helpers ---\n\n\tprivate hideTrailingSeparators(): void {\n\t\tconst children: HTMLElement[] = Array.from(this.toolbar.children) as HTMLElement[];\n\t\tfor (let i = children.length - 1; i >= 0; i--) {\n\t\t\tconst child: HTMLElement | undefined = children[i];\n\t\t\tif (!child || child === this.overflowButton) continue;\n\t\t\tif (child.classList.contains('notectl-toolbar-separator')) {\n\t\t\t\tif (!child.classList.contains(HIDDEN_SEP_CLASS)) {\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t}\n\t\t\t} else if (!child.classList.contains(HIDDEN_BTN_CLASS)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate notifyChange(): void {\n\t\tconst visible: HTMLButtonElement[] = this.entries\n\t\t\t.filter((oe) => !oe.element.classList.contains(HIDDEN_BTN_CLASS))\n\t\t\t.map((oe) => oe.element);\n\t\tthis.onOverflowChange(visible, this.overflowEntries.length > 0 ? this.overflowButton : null);\n\t}\n}\n","/**\n * ToolbarRenderers: pure rendering functions for toolbar popup content.\n * Grid pickers, dropdown menus, and separator elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { DropdownConfig, GridPickerConfig } from './ToolbarItem.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale } from './ToolbarLocale.js';\n\nconst HIGHLIGHTED_CLASS = 'notectl-grid-picker__cell--highlighted';\n\n/**\n * Renders a grid picker into the given container.\n * Calls `onClose` after a cell is selected so the popup can be dismissed.\n */\nexport function renderGridPicker(\n\tcontainer: HTMLElement,\n\tconfig: GridPickerConfig,\n\tonClose: () => void,\n\tlocale: ToolbarLocale = TOOLBAR_LOCALE_EN,\n): void {\n\tcontainer.className += ' notectl-grid-picker';\n\n\tconst grid: HTMLDivElement = document.createElement('div');\n\tgrid.className = 'notectl-grid-picker__grid';\n\tgrid.setAttribute('role', 'grid');\n\tsetStyleProperties(grid, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: `repeat(${config.maxCols}, 1fr)`,\n\t\tgap: '2px',\n\t\tpadding: '8px',\n\t});\n\n\tconst label: HTMLDivElement = document.createElement('div');\n\tlabel.className = 'notectl-grid-picker__label';\n\tlabel.textContent = locale.gridPickerLabel(1, 1);\n\tsetStyleProperties(label, {\n\t\ttextAlign: 'center',\n\t\tpadding: '4px',\n\t\tfontSize: '12px',\n\t});\n\tlabel.setAttribute('aria-live', 'polite');\n\n\tfor (let r = 1; r <= config.maxRows; r++) {\n\t\tfor (let c = 1; c <= config.maxCols; c++) {\n\t\t\tconst cell: HTMLDivElement = document.createElement('div');\n\t\t\tcell.className = 'notectl-grid-picker__cell';\n\t\t\tcell.setAttribute('role', 'gridcell');\n\t\t\tcell.setAttribute('tabindex', '-1');\n\t\t\tcell.setAttribute('aria-label', locale.gridPickerLabel(r, c));\n\t\t\tsetStyleProperties(cell, {\n\t\t\t\twidth: '20px',\n\t\t\t\theight: '20px',\n\t\t\t\tborder: '1px solid #ccc',\n\t\t\t\tcursor: 'pointer',\n\t\t\t});\n\t\t\tcell.setAttribute('data-row', String(r));\n\t\t\tcell.setAttribute('data-col', String(c));\n\n\t\t\tcell.addEventListener('mouseenter', () => {\n\t\t\t\thighlightCells(grid, r, c);\n\t\t\t\tlabel.textContent = locale.gridPickerLabel(r, c);\n\t\t\t});\n\n\t\t\tcell.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t});\n\n\t\t\tcell.addEventListener('click', () => {\n\t\t\t\tconfig.onSelect(r, c);\n\t\t\t\tonClose();\n\t\t\t});\n\n\t\t\tgrid.appendChild(cell);\n\t\t}\n\t}\n\n\tcontainer.appendChild(grid);\n\tcontainer.appendChild(label);\n}\n\n/**\n * Highlights grid cells up to the given row/col and updates the label.\n * Used by both mouse hover and keyboard navigation.\n */\nexport function highlightCells(grid: HTMLElement, targetRow: number, targetCol: number): void {\n\tconst cells: NodeListOf<Element> = grid.querySelectorAll('.notectl-grid-picker__cell');\n\tfor (const cell of cells) {\n\t\tconst r: number = Number(cell.getAttribute('data-row'));\n\t\tconst c: number = Number(cell.getAttribute('data-col'));\n\t\tcell.classList.toggle(HIGHLIGHTED_CLASS, r <= targetRow && c <= targetCol);\n\t}\n}\n\n/**\n * Renders a dropdown menu into the given container.\n * Calls `onClose` after an item is activated so the popup can be dismissed.\n */\nexport function renderDropdown(\n\tcontainer: HTMLElement,\n\tconfig: DropdownConfig,\n\texecuteCommand: (command: string) => void,\n\tonClose: () => void,\n): void {\n\tcontainer.classList.add('notectl-dropdown');\n\tcontainer.setAttribute('role', 'menu');\n\n\tfor (const item of config.items) {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = 'notectl-dropdown__item';\n\t\tbtn.setAttribute('role', 'menuitem');\n\t\tbtn.setAttribute('tabindex', '-1');\n\n\t\tif (item.icon) {\n\t\t\tconst iconSpan: HTMLSpanElement = document.createElement('span');\n\t\t\ticonSpan.className = 'notectl-dropdown__item-icon';\n\t\t\ticonSpan.innerHTML = item.icon;\n\t\t\tbtn.appendChild(iconSpan);\n\t\t}\n\n\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\tlabelSpan.className = 'notectl-dropdown__item-label';\n\t\tlabelSpan.textContent = item.label;\n\t\tbtn.appendChild(labelSpan);\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t});\n\n\t\tbtn.addEventListener('click', () => {\n\t\t\texecuteCommand(item.command);\n\t\t\tonClose();\n\t\t});\n\n\t\tcontainer.appendChild(btn);\n\t}\n}\n\n/** Creates a toolbar group separator element. */\nexport function createSeparator(): HTMLSpanElement {\n\tconst sep: HTMLSpanElement = document.createElement('span');\n\tsep.className = 'notectl-toolbar-separator';\n\tsep.setAttribute('role', 'separator');\n\treturn sep;\n}\n","/**\n * ToolbarPopupController: manages popup lifecycle, positioning, keyboard\n * navigation, and auto-close for toolbar popups (grid pickers, dropdowns,\n * and custom popups). Delegates lifecycle to PopupManager.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { findNextDropdownItem, navigateGrid } from '../shared/KeyboardNav.js';\nimport type { PopupCloseOptions, PopupHandle, PopupManager } from '../shared/PopupManager.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale } from './ToolbarLocale.js';\nimport { highlightCells, renderDropdown, renderGridPicker } from './ToolbarRenderers.js';\n\nexport class ToolbarPopupController {\n\tprivate activePopup: HTMLElement | null = null;\n\tprivate activePopupButton: HTMLButtonElement | null = null;\n\tprivate activeHandle: PopupHandle | null = null;\n\tprivate readonly getActiveElement: () => Element | null;\n\tprivate readonly locale: ToolbarLocale;\n\tprivate popupManager: PopupManager | null = null;\n\n\tconstructor(getActiveElement: () => Element | null, locale: ToolbarLocale = TOOLBAR_LOCALE_EN) {\n\t\tthis.getActiveElement = getActiveElement;\n\t\tthis.locale = locale;\n\t}\n\n\t/** Injects the PopupManager instance (called after service registration). */\n\tsetPopupManager(manager: PopupManager): void {\n\t\tthis.popupManager = manager;\n\t}\n\n\t/** Whether a popup is currently open. */\n\tisOpen(): boolean {\n\t\treturn this.activePopup !== null;\n\t}\n\n\t/** Toggles a popup for the given toolbar button. */\n\ttoggle(button: HTMLButtonElement, item: ToolbarItem, context: PluginContext): void {\n\t\tif (this.activePopup) {\n\t\t\tthis.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.openViaManager(button, item, context);\n\t}\n\n\t/** Closes the active popup and cleans up event listeners. */\n\tclose(): void {\n\t\tif (this.activeHandle) {\n\t\t\t// Prevent onClose callback from re-entering\n\t\t\tconst handle: PopupHandle = this.activeHandle;\n\t\t\tthis.activeHandle = null;\n\t\t\tthis.clearButtonState();\n\t\t\thandle.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.clearButtonState();\n\t\tif (this.activePopup) {\n\t\t\tthis.activePopup.remove();\n\t\t\tthis.activePopup = null;\n\t\t}\n\t}\n\n\t/** Closes popup and restores focus to the trigger button. */\n\tcloseAndRestoreFocus(): void {\n\t\tconst triggerBtn: HTMLButtonElement | null = this.activePopupButton;\n\t\tthis.close();\n\t\ttriggerBtn?.focus();\n\t}\n\n\tdestroy(): void {\n\t\tthis.close();\n\t}\n\n\t// --- PopupManager path ---\n\n\tprivate openViaManager(\n\t\tbutton: HTMLButtonElement,\n\t\titem: ToolbarItem,\n\t\tcontext: PluginContext,\n\t): void {\n\t\tif (!this.popupManager) return;\n\n\t\tthis.activePopupButton = button;\n\t\tbutton.classList.add('notectl-toolbar-btn--popup-open');\n\t\tbutton.setAttribute('aria-expanded', 'true');\n\n\t\tthis.activeHandle = this.popupManager.open({\n\t\t\tanchor: button,\n\t\t\tclassName: 'notectl-toolbar-popup',\n\t\t\treferenceNode: button,\n\t\t\trestoreFocusTo: button,\n\t\t\tposition: 'below-start',\n\t\t\tonClose: () => {\n\t\t\t\t// Called when PopupManager closes the popup (click-outside, etc.)\n\t\t\t\tthis.activeHandle = null;\n\t\t\t\tthis.clearButtonState();\n\t\t\t\tthis.activePopup = null;\n\t\t\t},\n\t\t\tcontent: (popup: HTMLElement, close: (options?: PopupCloseOptions) => void) => {\n\t\t\t\tthis.activePopup = popup;\n\t\t\t\tthis.renderPopupContent(popup, item, context, close);\n\t\t\t\tpopup.addEventListener('keydown', (e: KeyboardEvent) => this.handlePopupKeydown(e));\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Shared rendering ---\n\n\tprivate renderPopupContent(\n\t\tpopup: HTMLElement,\n\t\titem: ToolbarItem,\n\t\tcontext: PluginContext,\n\t\tclose: (options?: PopupCloseOptions) => void,\n\t): void {\n\t\tconst closeAndFocusEditor = (): void => {\n\t\t\tclose({ restoreFocusTo: null });\n\t\t\tcontext.getContainer().focus();\n\t\t};\n\n\t\tswitch (item.popupType) {\n\t\t\tcase 'gridPicker':\n\t\t\t\trenderGridPicker(popup, item.popupConfig, closeAndFocusEditor, this.locale);\n\t\t\t\tbreak;\n\t\t\tcase 'dropdown':\n\t\t\t\trenderDropdown(\n\t\t\t\t\tpopup,\n\t\t\t\t\titem.popupConfig,\n\t\t\t\t\t(cmd: string) => context.executeCommand(cmd),\n\t\t\t\t\tcloseAndFocusEditor,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase 'custom':\n\t\t\t\titem.renderPopup(popup, context, close);\n\t\t\t\tbreak;\n\t\t\tcase 'combobox':\n\t\t\t\titem.renderPopup(popup, context, close);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// --- Button state ---\n\n\tprivate clearButtonState(): void {\n\t\tif (this.activePopupButton) {\n\t\t\tthis.activePopupButton.classList.remove('notectl-toolbar-btn--popup-open');\n\t\t\tthis.activePopupButton.setAttribute('aria-expanded', 'false');\n\t\t\tthis.activePopupButton = null;\n\t\t}\n\t}\n\n\t// --- Keyboard Navigation ---\n\n\tprivate handlePopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Tab') {\n\t\t\te.preventDefault();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tconst menuItems: NodeListOf<Element> = this.activePopup.querySelectorAll('[role=\"menuitem\"]');\n\t\tif (menuItems.length > 0) {\n\t\t\tthis.handleDropdownKeydown(e, menuItems);\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasGrid: boolean = this.activePopup.querySelector('.notectl-grid-picker__cell') !== null;\n\t\tif (hasGrid) {\n\t\t\tthis.handleGridKeydown(e);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.handleCustomPopupKeydown(e);\n\t}\n\n\tprivate handleDropdownKeydown(e: KeyboardEvent, items: NodeListOf<Element>): void {\n\t\tconst itemArr: HTMLElement[] = Array.from(items) as HTMLElement[];\n\t\tconst current: number = itemArr.indexOf(this.getActiveElement() as HTMLElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(itemArr, current, 1);\n\t\t\t\titemArr[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(itemArr, current, -1);\n\t\t\t\titemArr[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focused: HTMLElement | undefined = itemArr[current];\n\t\t\t\tif (focused) focused.click();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleGridKeydown(e: KeyboardEvent): void {\n\t\tconst focused: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst row: number = Number(focused?.getAttribute('data-row') ?? 1);\n\t\tconst col: number = Number(focused?.getAttribute('data-col') ?? 1);\n\n\t\tconst grid: Element | null =\n\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__grid') ?? null;\n\t\tif (!grid) return;\n\n\t\tconst lastCell: Element | null = grid.querySelector('.notectl-grid-picker__cell:last-child');\n\t\tconst maxCols: number = Number(lastCell?.getAttribute('data-col') ?? 1);\n\t\tconst maxRows: number = Number(lastCell?.getAttribute('data-row') ?? 1);\n\n\t\tif (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst [newRow, newCol]: [number, number] = navigateGrid(\n\t\t\t\trow,\n\t\t\t\tcol,\n\t\t\t\tmaxRows,\n\t\t\t\tmaxCols,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t\tthis.activePopup ? isRtlContext(this.activePopup) : false,\n\t\t\t);\n\t\t\tconst target: HTMLElement | null = grid.querySelector(\n\t\t\t\t`.notectl-grid-picker__cell[data-row=\"${newRow}\"][data-col=\"${newCol}\"]`,\n\t\t\t);\n\t\t\ttarget?.focus();\n\n\t\t\thighlightCells(grid as HTMLElement, newRow, newCol);\n\t\t\tconst label: Element | null =\n\t\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__label') ?? null;\n\t\t\tif (label) label.textContent = this.locale.gridPickerLabel(newRow, newCol);\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tfocused?.click();\n\t\t}\n\t}\n\n\tprivate handleCustomPopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\t\tconst buttons: HTMLButtonElement[] = Array.from(this.activePopup.querySelectorAll('button'));\n\t\tif (buttons.length === 0) return;\n\t\tconst active: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst currentIdx: number = buttons.indexOf(active as HTMLButtonElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(buttons, currentIdx, 1);\n\t\t\t\tbuttons[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(buttons, currentIdx, -1);\n\t\t\t\tbuttons[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (active) {\n\t\t\t\t\tactive.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * ToolbarTooltip: manages the tooltip lifecycle for toolbar buttons.\n * Shows a tooltip after a short delay when hovering or focusing a button,\n * hides it when the cursor leaves or focus moves away.\n */\n\nimport { setStyleProperties, setStyleProperty } from '../../style/StyleRuntime.js';\n\nconst TOOLTIP_DELAY_MS = 500;\n\nexport class ToolbarTooltip {\n\tprivate readonly element: HTMLElement;\n\tprivate timer: ReturnType<typeof setTimeout> | null = null;\n\tprivate target: HTMLButtonElement | null = null;\n\tprivate readonly isPopupActive: () => boolean;\n\n\tstatic readonly TOOLTIP_ID = 'notectl-toolbar-tooltip';\n\n\tconstructor(isPopupActive: () => boolean) {\n\t\tthis.isPopupActive = isPopupActive;\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.className = 'notectl-toolbar-tooltip';\n\t\tthis.element.id = ToolbarTooltip.TOOLTIP_ID;\n\t\tthis.element.setAttribute('role', 'tooltip');\n\t\tsetStyleProperty(this.element, 'display', 'none');\n\t}\n\n\tshow(button: HTMLButtonElement): void {\n\t\tthis.hide();\n\n\t\tif (this.isPopupActive() || button.disabled) return;\n\n\t\tconst text: string | null = button.getAttribute('data-tooltip');\n\t\tif (!text) return;\n\n\t\tthis.target = button;\n\n\t\tthis.timer = setTimeout(() => {\n\t\t\tif (this.isPopupActive()) return;\n\n\t\t\tthis.element.textContent = text;\n\t\t\tsetStyleProperty(this.element, 'display', '');\n\n\t\t\tconst root: Node = button.getRootNode();\n\t\t\tif (root instanceof ShadowRoot && !this.element.parentNode) {\n\t\t\t\troot.appendChild(this.element);\n\t\t\t} else if (!(root instanceof ShadowRoot) && !this.element.parentNode) {\n\t\t\t\tdocument.body.appendChild(this.element);\n\t\t\t}\n\n\t\t\tbutton.setAttribute('aria-describedby', ToolbarTooltip.TOOLTIP_ID);\n\n\t\t\tconst rect: DOMRect = button.getBoundingClientRect();\n\t\t\tsetStyleProperties(this.element, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 6}px`,\n\t\t\t\tleft: `${rect.left + rect.width / 2}px`,\n\t\t\t\ttransform: 'translateX(-50%)',\n\t\t\t});\n\t\t}, TOOLTIP_DELAY_MS);\n\t}\n\n\thide(): void {\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tif (this.target) {\n\t\t\tthis.target.removeAttribute('aria-describedby');\n\t\t\tthis.target = null;\n\t\t}\n\t\tsetStyleProperty(this.element, 'display', 'none');\n\t}\n\n\tdestroy(): void {\n\t\tthis.hide();\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * Toolbar plugin: renders toolbar items registered by other plugins.\n * Acts as a pure rendering engine — has no knowledge of specific features.\n * Supports buttons, dropdowns, grid pickers, and custom popups.\n * Implements WAI-ARIA Toolbar pattern with roving tabindex.\n */\n\nimport { TOOLBAR_CSS } from '../../editor/styles/toolbar.js';\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport { ServiceKey } from '../Plugin.js';\nimport type { Plugin, PluginConfig, PluginContext } from '../Plugin.js';\nimport { applyRovingTabindex } from '../shared/KeyboardNav.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { PopupManager, PopupServiceKey } from '../shared/PopupManager.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport {\n\tfindFirstEnabled,\n\tfindLastEnabled,\n\tfindNextEnabled,\n\tresolveHorizontalDirection,\n} from './ToolbarKeyboardNav.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale, loadToolbarLocale } from './ToolbarLocale.js';\nimport {\n\tToolbarOverflowBehavior,\n\ttype ToolbarOverflowBehavior as ToolbarOverflowBehaviorType,\n} from './ToolbarOverflowBehavior.js';\nimport { ToolbarOverflowController } from './ToolbarOverflowController.js';\nimport { ToolbarPopupController } from './ToolbarPopupController.js';\nimport { createSeparator } from './ToolbarRenderers.js';\nimport { ToolbarTooltip } from './ToolbarTooltip.js';\n\n// --- Layout Config ---\n\nexport interface ToolbarLayoutConfig {\n\treadonly groups: ReadonlyArray<ReadonlyArray<string>>;\n\t/**\n\t * Controls responsive overflow behavior when toolbar items exceed available width.\n\t * Defaults to `ToolbarOverflowBehavior.BurgerMenu`.\n\t */\n\treadonly overflow?: ToolbarOverflowBehaviorType;\n}\n\n// --- Typed Service API ---\n\nexport interface ToolbarServiceAPI {\n\t/** Re-reads isActive/isEnabled from state and updates all buttons. */\n\trefresh(): void;\n\t/** Closes the currently open popup, if any. */\n\tclosePopup(): void;\n}\n\nexport const ToolbarServiceKey = new ServiceKey<ToolbarServiceAPI>('toolbar');\n\n// --- Plugin ---\n\ninterface ToolbarButton {\n\telement: HTMLButtonElement;\n\titem: ToolbarItem;\n\tcomboLabelEl: HTMLSpanElement | null;\n}\n\nexport class ToolbarPlugin implements Plugin {\n\treadonly id = 'toolbar';\n\treadonly name = 'Toolbar';\n\treadonly priority = 10;\n\n\tprivate context: PluginContext | null = null;\n\tprivate toolbarElement: HTMLElement | null = null;\n\tprivate buttons: ToolbarButton[] = [];\n\tprivate readonly hiddenItems = new Set<string>();\n\tprivate readonly layoutConfig: ToolbarLayoutConfig | null;\n\tprivate overflowBehavior: ToolbarOverflowBehaviorType;\n\tprivate focusedIndex = 0;\n\tprivate tooltip: ToolbarTooltip | null = null;\n\tprivate popupController: ToolbarPopupController | null = null;\n\tprivate popupManager: PopupManager | null = null;\n\tprivate overflowController: ToolbarOverflowController | null = null;\n\tprivate visibleElements: HTMLButtonElement[] = [];\n\tprivate locale!: ToolbarLocale;\n\n\tconstructor(layoutConfig?: ToolbarLayoutConfig) {\n\t\tthis.layoutConfig = layoutConfig ?? null;\n\t\tthis.overflowBehavior = layoutConfig?.overflow ?? ToolbarOverflowBehavior.BurgerMenu;\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(context, undefined, TOOLBAR_LOCALE_EN, loadToolbarLocale);\n\t\tcontext.registerStyleSheet(TOOLBAR_CSS);\n\t\tthis.context = context;\n\n\t\tthis.popupManager = new PopupManager(context.getContainer());\n\t\tcontext.registerService(PopupServiceKey, this.popupManager);\n\n\t\tthis.popupController = new ToolbarPopupController(() => this.getActiveElement(), this.locale);\n\t\tthis.popupController.setPopupManager(this.popupManager);\n\t\tthis.tooltip = new ToolbarTooltip(() => this.popupController?.isOpen() ?? false);\n\n\t\tcontext.registerService(ToolbarServiceKey, {\n\t\t\trefresh: () => this.updateButtonStates(context.getState()),\n\t\t\tclosePopup: () => this.popupController?.close(),\n\t\t});\n\n\t\tthis.createToolbarElement();\n\t}\n\n\t/** Returns the current overflow behavior. */\n\tgetOverflowBehavior(): ToolbarOverflowBehaviorType {\n\t\treturn this.overflowBehavior;\n\t}\n\n\t/** Switches the overflow behavior at runtime. */\n\tsetOverflowBehavior(behavior: ToolbarOverflowBehaviorType): void {\n\t\tif (behavior === this.overflowBehavior) return;\n\n\t\tthis.overflowBehavior = behavior;\n\t\tthis.applyOverflowBehavior();\n\t\tthis.renderItems();\n\t}\n\n\tonReady(): void {\n\t\tthis.renderItems();\n\t}\n\n\tdestroy(): void {\n\t\tthis.overflowController?.destroy();\n\t\tthis.overflowController = null;\n\t\tthis.popupController?.destroy();\n\t\tthis.popupController = null;\n\t\tthis.popupManager?.destroy();\n\t\tthis.popupManager = null;\n\t\tthis.tooltip?.destroy();\n\t\tthis.tooltip = null;\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\tthis.toolbarElement = null;\n\t\t}\n\t\tthis.buttons = [];\n\t\tthis.visibleElements = [];\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateButtonStates(newState);\n\t}\n\n\tonReadOnlyChange(readonly: boolean): void {\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.hidden = readonly;\n\t\t}\n\t}\n\n\tonConfigure(config: PluginConfig): void {\n\t\tfor (const [key, value] of Object.entries(config)) {\n\t\t\tif (value === false) {\n\t\t\t\tthis.hiddenItems.add(key);\n\t\t\t} else {\n\t\t\t\tthis.hiddenItems.delete(key);\n\t\t\t}\n\t\t}\n\t\tthis.renderItems();\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate createToolbarElement(): void {\n\t\tif (!this.context) return;\n\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\tthis.toolbarElement = document.createElement('div');\n\t\tthis.toolbarElement.setAttribute('role', 'toolbar');\n\t\tthis.toolbarElement.setAttribute('aria-label', this.locale.formattingOptionsAria);\n\t\tthis.toolbarElement.setAttribute('data-notectl-no-print', '');\n\t\tthis.toolbarElement.className = 'notectl-toolbar';\n\n\t\tthis.toolbarElement.addEventListener('keydown', (e) => this.handleToolbarKeydown(e));\n\n\t\tthis.applyOverflowBehavior();\n\t\tcontainer.appendChild(this.toolbarElement);\n\t}\n\n\t/** Applies the current overflow behavior: creates/destroys the overflow controller and sets the data attribute. */\n\tprivate applyOverflowBehavior(): void {\n\t\tif (!this.toolbarElement || !this.context) return;\n\n\t\t// Tear down existing overflow controller\n\t\tthis.overflowController?.destroy();\n\t\tthis.overflowController = null;\n\n\t\tthis.toolbarElement.setAttribute('data-overflow', this.overflowBehavior);\n\n\t\tif (this.overflowBehavior === ToolbarOverflowBehavior.BurgerMenu) {\n\t\t\tthis.overflowController = new ToolbarOverflowController({\n\t\t\t\ttoolbar: this.toolbarElement,\n\t\t\t\tariaLabel: this.locale.moreToolsAria,\n\t\t\t\tcontext: this.context,\n\t\t\t\tpopupManager: this.popupManager ?? undefined,\n\t\t\t\tonOverflowChange: (visibleButtons, overflowBtn) => {\n\t\t\t\t\tthis.visibleElements = overflowBtn\n\t\t\t\t\t\t? [...visibleButtons, overflowBtn]\n\t\t\t\t\t\t: [...visibleButtons];\n\t\t\t\t\tthis.initRovingTabindex();\n\t\t\t\t},\n\t\t\t\tonItemActivated: (btn: HTMLButtonElement, item: ToolbarItem) => {\n\t\t\t\t\tthis.activateButton(btn, item);\n\t\t\t\t},\n\t\t\t\tgetActiveElement: () => this.getActiveElement(),\n\t\t\t});\n\t\t} else {\n\t\t\t// Flow and None modes: all buttons are visible for roving tabindex\n\t\t\tthis.visibleElements = [];\n\t\t}\n\t}\n\n\tprivate renderItems(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tfor (const btn of this.buttons) {\n\t\t\tbtn.element.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tfor (const sep of this.toolbarElement.querySelectorAll('.notectl-toolbar-separator')) {\n\t\t\tsep.remove();\n\t\t}\n\n\t\tif (this.layoutConfig) {\n\t\t\tthis.renderItemsByLayout();\n\t\t} else {\n\t\t\tthis.renderItemsByGroup();\n\t\t}\n\n\t\tif (this.buttons.length > 0 && !this.toolbarElement.parentElement) {\n\t\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\t\tcontainer.appendChild(this.toolbarElement);\n\t\t}\n\n\t\tthis.overflowController?.update(this.buttons);\n\t\tthis.initRovingTabindex();\n\t\tthis.updateButtonStates(this.context.getState());\n\t}\n\n\t// --- Roving Tabindex ---\n\n\tprivate getTabElements(): HTMLButtonElement[] {\n\t\treturn this.visibleElements.length > 0\n\t\t\t? this.visibleElements\n\t\t\t: this.buttons.map((b) => b.element);\n\t}\n\n\tprivate initRovingTabindex(): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tconst first: number = findFirstEnabled(elements);\n\t\tthis.focusedIndex = first >= 0 ? first : 0;\n\t\tapplyRovingTabindex(elements, this.focusedIndex);\n\t}\n\n\tprivate setRovingFocus(index: number): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tif (index < 0 || index >= elements.length) return;\n\t\tthis.focusedIndex = index;\n\t\tapplyRovingTabindex(elements, index);\n\t\telements[index]?.focus();\n\t}\n\n\t/** Returns the active element, respecting shadow DOM boundaries. */\n\tprivate getActiveElement(): Element | null {\n\t\tconst root: Node | undefined = this.toolbarElement?.getRootNode();\n\t\tif (root instanceof ShadowRoot) {\n\t\t\treturn root.activeElement;\n\t\t}\n\t\treturn document.activeElement;\n\t}\n\n\tprivate syncFocusedIndex(): void {\n\t\tconst active: Element | null = this.getActiveElement();\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tconst idx: number = elements.findIndex((el) => el === active);\n\t\tif (idx >= 0) {\n\t\t\tthis.focusedIndex = idx;\n\t\t}\n\t}\n\n\t// --- Toolbar Keyboard ---\n\n\tprivate handleToolbarKeydown(e: KeyboardEvent): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tif (elements.length === 0) return;\n\n\t\tthis.syncFocusedIndex();\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowRight':\n\t\t\tcase 'ArrowLeft': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst rtl: boolean = this.toolbarElement ? isRtlContext(this.toolbarElement) : false;\n\t\t\t\tconst dir: 1 | -1 = resolveHorizontalDirection(e.key, rtl);\n\t\t\t\tconst next: number = findNextEnabled(elements, this.focusedIndex, dir);\n\t\t\t\tthis.setRovingFocus(next);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst first: number = findFirstEnabled(elements);\n\t\t\t\tif (first >= 0) this.setRovingFocus(first);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst last: number = findLastEnabled(elements);\n\t\t\t\tif (last >= 0) this.setRovingFocus(last);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focused: HTMLButtonElement | undefined = elements[this.focusedIndex];\n\t\t\t\tconst btn: ToolbarButton | undefined = this.buttons.find((b) => b.element === focused);\n\t\t\t\tif (btn) this.activateButton(btn.element, btn.item);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Activates a toolbar button (shared between mouse click and keyboard). */\n\tprivate activateButton(btn: HTMLButtonElement, item: ToolbarItem): void {\n\t\tthis.tooltip?.hide();\n\t\tif (item.popupType && this.context) {\n\t\t\tthis.popupController?.toggle(btn, item, this.context);\n\t\t} else {\n\t\t\tthis.context?.executeCommand(item.command);\n\t\t}\n\t}\n\n\t// --- Layout Rendering ---\n\n\tprivate renderItemsByLayout(): void {\n\t\tif (!this.context || !this.toolbarElement || !this.layoutConfig) return;\n\n\t\tconst toolbarReg = this.context.getToolbarRegistry();\n\t\tlet firstGroup = true;\n\n\t\tfor (const groupPluginIds of this.layoutConfig.groups) {\n\t\t\tconst groupItems: ToolbarItem[] = [];\n\t\t\tfor (const pId of groupPluginIds) {\n\t\t\t\tconst items: ToolbarItem[] = toolbarReg\n\t\t\t\t\t.getToolbarItemsByPlugin(pId)\n\t\t\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\t\t\tgroupItems.push(...items);\n\t\t\t}\n\n\t\t\tif (groupItems.length === 0) continue;\n\n\t\t\tif (!firstGroup) {\n\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t}\n\t\t\tfirstGroup = false;\n\n\t\t\tfor (const item of groupItems) {\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\t\t\t}\n\t\t}\n\n\t\tif (this.buttons.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t}\n\n\tprivate renderItemsByGroup(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tconst toolbarRegistry = this.context.getToolbarRegistry();\n\t\tconst items: ToolbarItem[] = toolbarRegistry\n\t\t\t.getToolbarItems()\n\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\tif (items.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\treturn;\n\t\t}\n\n\t\tconst groups = new Map<string, ToolbarItem[]>();\n\t\tfor (const item of items) {\n\t\t\tconst list: ToolbarItem[] = groups.get(item.group) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroups.set(item.group, list);\n\t\t}\n\n\t\tlet firstGroup = true;\n\t\tfor (const [, groupItems] of groups) {\n\t\t\tif (!firstGroup) {\n\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t}\n\t\t\tfirstGroup = false;\n\n\t\t\tfor (const item of groupItems) {\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Button Creation ---\n\n\tprivate createButton(item: ToolbarItem): ToolbarButton {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = `notectl-toolbar-btn notectl-toolbar-btn--${item.id}`;\n\t\tbtn.setAttribute('aria-pressed', 'false');\n\t\tbtn.setAttribute('aria-label', item.label);\n\t\tbtn.setAttribute('data-toolbar-item', item.id);\n\t\tbtn.setAttribute('data-tooltip', item.tooltip ?? item.label);\n\n\t\tlet comboLabelEl: HTMLSpanElement | null = null;\n\n\t\tif (item.popupType === 'combobox') {\n\t\t\tbtn.setAttribute('role', 'combobox');\n\t\t\tbtn.setAttribute('aria-haspopup', 'listbox');\n\t\t\tbtn.setAttribute('aria-expanded', 'false');\n\n\t\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tlabelSpan.className = 'notectl-toolbar-combobox__label';\n\t\t\tconst state: EditorState | undefined = this.context?.getState();\n\t\t\tif (state) {\n\t\t\t\tlabelSpan.textContent = item.getLabel(state);\n\t\t\t}\n\t\t\tbtn.appendChild(labelSpan);\n\t\t\tcomboLabelEl = labelSpan;\n\n\t\t\tconst arrowSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tarrowSpan.className = 'notectl-toolbar-combobox__arrow';\n\t\t\tarrowSpan.setAttribute('aria-hidden', 'true');\n\t\t\tarrowSpan.textContent = '\\u25BE';\n\t\t\tbtn.appendChild(arrowSpan);\n\t\t} else {\n\t\t\tif (item.popupType) {\n\t\t\t\tbtn.setAttribute('aria-haspopup', 'true');\n\t\t\t\tbtn.setAttribute('aria-expanded', 'false');\n\t\t\t}\n\n\t\t\tconst span: HTMLSpanElement = document.createElement('span');\n\t\t\tspan.className = 'notectl-toolbar-btn__icon';\n\t\t\tspan.innerHTML = item.icon;\n\t\t\tbtn.appendChild(span);\n\t\t}\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tthis.activateButton(btn, item);\n\t\t});\n\n\t\tbtn.addEventListener('mouseenter', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('mouseleave', () => this.tooltip?.hide());\n\t\tbtn.addEventListener('focus', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('blur', () => this.tooltip?.hide());\n\n\t\treturn { element: btn, item, comboLabelEl };\n\t}\n\n\t// --- Button State Updates ---\n\n\tprivate updateButtonStates(state: EditorState): void {\n\t\tfor (const btn of this.buttons) {\n\t\t\tconst active: boolean = btn.item.isActive?.(state) ?? false;\n\t\t\tconst enabled: boolean = btn.item.isEnabled?.(state) ?? true;\n\t\t\tbtn.element.setAttribute('aria-pressed', String(active));\n\t\t\tbtn.element.classList.toggle('notectl-toolbar-btn--active', active);\n\t\t\tbtn.element.disabled = !enabled;\n\t\t\tif (!enabled) {\n\t\t\t\tbtn.element.setAttribute('aria-disabled', 'true');\n\t\t\t} else {\n\t\t\t\tbtn.element.removeAttribute('aria-disabled');\n\t\t\t}\n\t\t\tif (btn.comboLabelEl && btn.item.popupType === 'combobox') {\n\t\t\t\tbtn.comboLabelEl.textContent = btn.item.getLabel(state);\n\t\t\t}\n\t\t\tif (btn.item.getIcon) {\n\t\t\t\tconst newIcon: string = btn.item.getIcon(state);\n\t\t\t\tconst iconEl: HTMLSpanElement | null = btn.element.querySelector(\n\t\t\t\t\t'.notectl-toolbar-btn__icon',\n\t\t\t\t);\n\t\t\t\tif (iconEl && iconEl.innerHTML !== newIcon) {\n\t\t\t\t\ticonEl.innerHTML = newIcon;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.overflowController?.updateItemStates(state);\n\t}\n}\n","/** Toolbar styles — buttons, separators, tooltips, popups, dropdowns. */\nexport const TOOLBAR_CSS = `\n/* Toolbar */\n.notectl-plugin-container--top {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\tborder-bottom: 1px solid var(--notectl-border);\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n\tmin-height: 40px;\n}\n\n.notectl-toolbar {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n\tflex: 1;\n\tmin-width: 0;\n\tgap: 2px;\n\tpadding: 4px 8px;\n}\n\n.notectl-toolbar[hidden] {\n\tdisplay: none;\n}\n\n.notectl-toolbar-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-active-bg);\n\tborder-color: var(--notectl-primary-muted);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-toolbar-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n.notectl-toolbar-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:disabled:hover {\n\t\tbackground: transparent;\n\t\tborder-color: transparent;\n\t}\n}\n\n.notectl-toolbar-btn__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpointer-events: none;\n}\n\n.notectl-toolbar-btn__icon svg {\n\tdisplay: block;\n\twidth: 18px;\n\theight: 18px;\n\tfill: currentColor;\n}\n\n/* Tooltip (rendered as fixed-position element in shadow root) */\n.notectl-toolbar-tooltip {\n\tposition: fixed;\n\tpadding: 4px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 10001;\n\tline-height: 1.4;\n\tletter-spacing: 0.01em;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.notectl-toolbar-separator {\n\tdisplay: inline-block;\n\twidth: 1px;\n\theight: 20px;\n\tbackground: var(--notectl-border);\n\tmargin: 0 4px;\n\tvertical-align: middle;\n}\n\n/* Toolbar Popups */\n.notectl-toolbar-popup {\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbox-shadow: 0 4px 12px var(--notectl-shadow);\n\toverflow: hidden;\n}\n\n/* Grid Picker */\n.notectl-grid-picker__cell:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-grid-picker__cell--highlighted {\n\tbackground: var(--notectl-primary-muted);\n\tborder-color: var(--notectl-primary);\n}\n\n/* Dropdown */\n.notectl-dropdown {\n\tmin-width: 160px;\n\tpadding: 4px 0;\n}\n\n.notectl-dropdown__item {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\tfont-family: inherit;\n\twhite-space: nowrap;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-dropdown__item:focus-visible {\n\tbackground: var(--notectl-hover-bg);\n\toutline: none;\n}\n\n.notectl-dropdown__item-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-fg-muted);\n\tflex-shrink: 0;\n}\n\n.notectl-dropdown__item-label {\n\tflex: 1;\n}\n\n/* Overflow behavior: flow mode — toolbar wraps to additional rows */\n.notectl-toolbar[data-overflow=\"flow\"] {\n\tflex-wrap: wrap;\n\toverflow: visible;\n}\n\n/* Overflow behavior: none — toolbar clips without any responsive behavior */\n.notectl-toolbar[data-overflow=\"none\"] {\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n}\n\n/* Overflow: hidden items (burger-menu mode) */\n.notectl-toolbar-btn--overflow-hidden,\n.notectl-toolbar-separator--overflow-hidden {\n\tdisplay: none;\n}\n\n/* Overflow \"more\" button */\n.notectl-toolbar-overflow-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\tmargin-inline-start: auto;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-overflow-btn:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-overflow-btn--hidden {\n\tdisplay: none;\n}\n\n.notectl-toolbar-overflow-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n/* Dropdown item states shared by all dropdown menus (including overflow) */\n.notectl-dropdown__item:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:disabled:hover {\n\t\tbackground: none;\n\t}\n}\n\n.notectl-dropdown__item--active {\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-dropdown__item-icon svg {\n\tdisplay: block;\n\twidth: 16px;\n\theight: 16px;\n\tfill: currentColor;\n}\n\n.notectl-dropdown__separator {\n\theight: 1px;\n\tbackground: var(--notectl-border);\n\tmargin: 4px 0;\n}\n\n/* Combobox-style toolbar buttons (shared base for font, fontSize, heading, etc.) */\n.notectl-toolbar-btn[role=\"combobox\"] {\n\twidth: auto;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn[role=\"combobox\"]:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-fg-muted);\n\t}\n}\n\n.notectl-toolbar-btn[role=\"combobox\"].notectl-toolbar-btn--active {\n\tbackground: var(--notectl-bg);\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-combobox__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: start;\n\tline-height: 30px;\n}\n\n.notectl-toolbar-combobox__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Link Popup */\n.notectl-link-popup {\n\tpadding: 8px;\n\tmin-width: 200px;\n}\n\n.notectl-link-popup__input {\n\twidth: 100%;\n\tpadding: 4px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg);\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-link-popup__input:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-link-popup__button {\n\twidth: 100%;\n\tpadding: 6px 12px;\n\tcursor: pointer;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n\tcolor: var(--notectl-fg);\n\tfont-size: 13px;\n}\n\n.notectl-link-popup__button--apply {\n\tmargin-top: 4px;\n}\n\n@media (hover: hover) {\n\t.notectl-link-popup__button:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-link-popup__button:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n`;\n"],"names":["ToolbarRegistry","_toolbarItems","Map","_toolbarItemPluginMap","registerToolbarItem","item","pluginId","this","has","id","Error","set","ids","get","push","getToolbarItemsByPlugin","items","getToolbarItem","getToolbarItems","values","removeToolbarItem","delete","idx","indexOf","splice","length","clear","findFirstEnabled","buttons","i","disabled","TOOLBAR_LOCALE_EN","formattingOptionsAria","moreToolsAria","gridPickerLabel","rows","cols","localeModules","assign","import","async","loadToolbarLocale","lang","loader","default","ToolbarOverflowBehavior","BurgerMenu","Flow","None","HIDDEN_BTN_CLASS","HIDDEN_SEP_CLASS","ToolbarOverflowController","toolbar","context","onOverflowChange","onItemActivated","getActiveElement","ariaLabel","popupManager","entries","overflowButton","overflowDropdown","overflowHandle","overflowEntries","resizeObserver","closeHandler","constructor","config","ResizeObserver","recalculate","observe","update","map","b","element","closeDropdown","resetVisibility","ensureOverflowButton","setOverflowButtonVisible","availableWidth","measureAvailableWidth","children","Array","from","childWidths","measureChildWidths","maxWidth","usedWidth","overflowing","overflowList","child","classList","contains","add","sepWidth","entry","find","oe","btnWidth","hideTrailingSeparators","notifyChange","updateItemStates","state","menuItems","querySelectorAll","menuItem","itemId","getAttribute","active","isActive","enabled","isEnabled","toggle","popupType","labelEl","querySelector","textContent","getLabel","getIcon","newIcon","iconEl","innerHTML","destroy","disconnect","remove","widths","offsetWidth","toolbarStyle","getComputedStyle","paddingLeft","Number","parseFloat","paddingRight","clientWidth","separators","sep","visible","removeAttribute","btn","document","createElement","type","className","setAttribute","addEventListener","e","preventDefault","toggleDropdown","appendChild","openDropdown","dropdown","renderDropdownItems","getState","open","anchor","ariaRole","position","referenceNode","restoreFocusTo","onClose","content","popup","handleDropdownKeydown","positionDropdown","appendToRoot","requestAnimationFrame","first","focus","registerCloseHandler","lastGroup","group","menuBtn","iconSpan","icon","labelSpan","tooltip","label","ev","stopPropagation","activateOverflowItem","rect","getBoundingClientRect","isRtlContext","setStyleProperties","top","bottom","left","right","zIndex","rightEdge","window","innerWidth","path","composedPath","includes","setTimeout","handle","close","removeEventListener","executeCommand","command","key","current","next","findNextDropdownItem","prev","focusedItem","filter","highlightCells","grid","targetRow","targetCol","cells","cell","r","c","createSeparator","ToolbarPopupController","activePopup","activePopupButton","activeHandle","locale","setPopupManager","manager","isOpen","button","openViaManager","clearButtonState","closeAndRestoreFocus","triggerBtn","renderPopupContent","handlePopupKeydown","closeAndFocusEditor","getContainer","container","display","gridTemplateColumns","maxCols","gap","padding","textAlign","fontSize","maxRows","width","height","border","cursor","String","onSelect","renderGridPicker","popupConfig","cmd","renderDropdown","renderPopup","handleGridKeydown","handleCustomPopupKeydown","itemArr","focused","click","row","col","lastCell","newRow","newCol","navigateGrid","target","currentIdx","dispatchEvent","MouseEvent","bubbles","cancelable","ToolbarTooltip","timer","isPopupActive","static","TOOLTIP_ID","setStyleProperty","show","hide","text","root","getRootNode","ShadowRoot","parentNode","body","transform","clearTimeout","ToolbarServiceKey","ServiceKey","ToolbarPlugin","name","priority","toolbarElement","hiddenItems","Set","layoutConfig","overflowBehavior","focusedIndex","popupController","overflowController","visibleElements","overflow","init","resolveLocale","registerStyleSheet","PopupManager","registerService","PopupServiceKey","refresh","updateButtonStates","closePopup","createToolbarElement","getOverflowBehavior","setOverflowBehavior","behavior","applyOverflowBehavior","renderItems","onReady","onStateChange","_oldState","newState","_tr","onReadOnlyChange","readonly","hidden","onConfigure","value","Object","getPluginContainer","handleToolbarKeydown","visibleButtons","overflowBtn","initRovingTabindex","activateButton","renderItemsByLayout","renderItemsByGroup","parentElement","getTabElements","elements","applyRovingTabindex","setRovingFocus","index","activeElement","syncFocusedIndex","findIndex","el","isRtl","dir","direction","len","findNextEnabled","last","findLastEnabled","toolbarReg","getToolbarRegistry","firstGroup","groupPluginIds","groups","groupItems","pId","createButton","list","comboLabelEl","arrowSpan","span"],"mappings":"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"}
1
+ {"version":3,"file":"toolbar.mjs","sources":["../../src/plugins/toolbar/ToolbarRegistry.ts","../../src/plugins/toolbar/ToolbarKeyboardNav.ts","../../src/plugins/toolbar/ToolbarLocale.ts","../../src/plugins/toolbar/ToolbarOverflowBehavior.ts","../../src/plugins/toolbar/ToolbarOverflowController.ts","../../src/plugins/toolbar/ToolbarRenderers.ts","../../src/plugins/toolbar/ToolbarPopupController.ts","../../src/plugins/toolbar/ToolbarTooltip.ts","../../src/plugins/toolbar/ToolbarPlugin.ts","../../src/editor/styles/toolbar.ts"],"sourcesContent":["/**\n * ToolbarRegistry: manages plugin-registered toolbar items\n * with per-plugin tracking for clean teardown.\n */\n\nimport type { ToolbarItem } from './ToolbarItem.js';\n\nexport class ToolbarRegistry {\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\n\tregisterToolbarItem(item: ToolbarItem, pluginId?: string): void {\n\t\tif (this._toolbarItems.has(item.id)) {\n\t\t\tthrow new Error(`ToolbarItem with id \"${item.id}\" is already registered.`);\n\t\t}\n\t\tthis._toolbarItems.set(item.id, item);\n\t\tif (pluginId) {\n\t\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\t\tids.push(item.id);\n\t\t\tthis._toolbarItemPluginMap.set(pluginId, ids);\n\t\t}\n\t}\n\n\tgetToolbarItemsByPlugin(pluginId: string): ToolbarItem[] {\n\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\tconst items: ToolbarItem[] = [];\n\t\tfor (const id of ids) {\n\t\t\tconst item = this._toolbarItems.get(id);\n\t\t\tif (item) items.push(item);\n\t\t}\n\t\treturn items;\n\t}\n\n\tgetToolbarItem(id: string): ToolbarItem | undefined {\n\t\treturn this._toolbarItems.get(id);\n\t}\n\n\tgetToolbarItems(): ToolbarItem[] {\n\t\treturn [...this._toolbarItems.values()];\n\t}\n\n\tremoveToolbarItem(id: string): void {\n\t\tthis._toolbarItems.delete(id);\n\t\tfor (const [pluginId, ids] of this._toolbarItemPluginMap) {\n\t\t\tconst idx = ids.indexOf(id);\n\t\t\tif (idx !== -1) {\n\t\t\t\tids.splice(idx, 1);\n\t\t\t\tif (ids.length === 0) this._toolbarItemPluginMap.delete(pluginId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t}\n}\n","/**\n * Keyboard navigation helpers for the toolbar (WAI-ARIA Toolbar pattern).\n * Also re-exports generic navigation helpers from `plugins/shared`.\n */\n\n/** Returns indices of all enabled buttons. */\nexport function getEnabledIndices(buttons: readonly HTMLButtonElement[]): number[] {\n\tconst result: number[] = [];\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) {\n\t\t\tresult.push(i);\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Finds the next enabled button index in the given direction (wraps around). */\nexport function findNextEnabled(\n\tbuttons: readonly HTMLButtonElement[],\n\tcurrent: number,\n\tdirection: 1 | -1,\n): number {\n\tconst len = buttons.length;\n\tif (len === 0) return -1;\n\n\tlet index = current;\n\tfor (let i = 0; i < len; i++) {\n\t\tindex = (index + direction + len) % len;\n\t\tif (!buttons[index]?.disabled) {\n\t\t\treturn index;\n\t\t}\n\t}\n\treturn current;\n}\n\n/** Finds the first enabled button index. */\nexport function findFirstEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\n/** Finds the last enabled button index. */\nexport function findLastEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = buttons.length - 1; i >= 0; i--) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\nexport {\n\tapplyRovingTabindex,\n\tfindNextDropdownItem,\n\tnavigateGrid,\n} from '../shared/KeyboardNav.js';\n\n/**\n * Resolves a horizontal navigation direction based on text direction.\n * In RTL, ArrowRight moves backward (-1) and ArrowLeft moves forward (1).\n */\nexport function resolveHorizontalDirection(\n\tkey: 'ArrowRight' | 'ArrowLeft',\n\tisRtl: boolean,\n): 1 | -1 {\n\tif (key === 'ArrowRight') return isRtl ? -1 : 1;\n\treturn isRtl ? 1 : -1;\n}\n","/** Locale interface and default English locale for the ToolbarPlugin. */\n\n// --- Locale Interface ---\n\nexport interface ToolbarLocale {\n\treadonly formattingOptionsAria: string;\n\treadonly moreToolsAria: string;\n\treadonly gridPickerLabel: (rows: number, cols: number) => string;\n}\n\n// --- Default English Locale ---\n\nexport const TOOLBAR_LOCALE_EN: ToolbarLocale = {\n\tformattingOptionsAria: 'Formatting options',\n\tmoreToolsAria: 'More tools',\n\tgridPickerLabel: (rows: number, cols: number) => `${rows} x ${cols}`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ToolbarLocale }>> = import.meta.glob<{\n\tdefault: ToolbarLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadToolbarLocale(lang: string): Promise<ToolbarLocale> {\n\tif (lang === 'en') return TOOLBAR_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return TOOLBAR_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn TOOLBAR_LOCALE_EN;\n\t}\n}\n","/**\n * Controls how the toolbar responds when items exceed the available width.\n *\n * @example\n * ```typescript\n * const editor = await createEditor({\n * toolbar: {\n * groups: [[BoldPlugin, ItalicPlugin], [HeadingPlugin]],\n * overflow: ToolbarOverflowBehavior.Flow,\n * },\n * });\n * ```\n */\nexport const ToolbarOverflowBehavior = {\n\t/** Items that don't fit are hidden behind a \"...\" dropdown button. Default. */\n\tBurgerMenu: 'burger-menu',\n\t/** Toolbar wraps to additional rows when items overflow. Pure CSS, no JS measurement. */\n\tFlow: 'flow',\n\t/** No responsive behavior; the toolbar clips at the container boundary. */\n\tNone: 'none',\n} as const;\n\nexport type ToolbarOverflowBehavior =\n\t(typeof ToolbarOverflowBehavior)[keyof typeof ToolbarOverflowBehavior];\n","/**\n * ToolbarOverflowController: manages responsive toolbar overflow.\n * Uses ResizeObserver to detect when items exceed available width,\n * hides overflow items, and shows a \"more\" dropdown button.\n * Delegates popup lifecycle to PopupManager when available.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { findNextDropdownItem } from '../shared/KeyboardNav.js';\nimport type { PopupHandle, PopupManager } from '../shared/PopupManager.js';\nimport { appendToRoot } from '../shared/PopupPositioning.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\n\n// --- Types ---\n\ninterface OverflowEntry {\n\treadonly element: HTMLButtonElement;\n\treadonly item: ToolbarItem;\n}\n\ntype OnOverflowChange = (\n\tvisibleButtons: readonly HTMLButtonElement[],\n\toverflowButton: HTMLButtonElement | null,\n) => void;\n\ntype OnItemActivated = (overflowButton: HTMLButtonElement, item: ToolbarItem) => void;\n\nexport interface OverflowControllerConfig {\n\treadonly toolbar: HTMLElement;\n\treadonly ariaLabel: string;\n\treadonly context: PluginContext;\n\treadonly onOverflowChange: OnOverflowChange;\n\treadonly onItemActivated: OnItemActivated;\n\treadonly getActiveElement: () => Element | null;\n\treadonly popupManager?: PopupManager;\n}\n\n// --- Constants ---\n\nconst OVERFLOW_BTN_WIDTH = 34;\nconst GAP = 2;\nconst HIDDEN_BTN_CLASS = 'notectl-toolbar-btn--overflow-hidden';\nconst HIDDEN_SEP_CLASS = 'notectl-toolbar-separator--overflow-hidden';\nconst HIDDEN_OVERFLOW_CLASS = 'notectl-toolbar-overflow-btn--hidden';\nconst ELLIPSIS_SVG =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\"><circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/></svg>';\n\n// --- Controller ---\n\nexport class ToolbarOverflowController {\n\tprivate readonly toolbar: HTMLElement;\n\tprivate readonly context: PluginContext;\n\tprivate readonly onOverflowChange: OnOverflowChange;\n\tprivate readonly onItemActivated: OnItemActivated;\n\tprivate readonly getActiveElement: () => Element | null;\n\tprivate readonly ariaLabel: string;\n\tprivate readonly popupManager: PopupManager | null;\n\n\tprivate entries: OverflowEntry[] = [];\n\tprivate overflowButton: HTMLButtonElement | null = null;\n\tprivate overflowDropdown: HTMLElement | null = null;\n\tprivate overflowHandle: PopupHandle | null = null;\n\tprivate overflowEntries: OverflowEntry[] = [];\n\tprivate resizeObserver: ResizeObserver | null = null;\n\tprivate closeHandler: ((e: MouseEvent) => void) | null = null;\n\tprivate closeHandlerTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate closeHandlerAttached = false;\n\n\tconstructor(config: OverflowControllerConfig) {\n\t\tthis.toolbar = config.toolbar;\n\t\tthis.ariaLabel = config.ariaLabel;\n\t\tthis.context = config.context;\n\t\tthis.onOverflowChange = config.onOverflowChange;\n\t\tthis.onItemActivated = config.onItemActivated;\n\t\tthis.getActiveElement = config.getActiveElement;\n\t\tthis.popupManager = config.popupManager ?? null;\n\n\t\tthis.resizeObserver = new ResizeObserver(() => this.recalculate());\n\t\tthis.resizeObserver.observe(this.toolbar);\n\t}\n\n\t/** Called after renderItems() — stores button references and recalculates. */\n\tupdate(buttons: readonly { element: HTMLButtonElement; item: ToolbarItem }[]): void {\n\t\tthis.entries = buttons.map((b) => ({ element: b.element, item: b.item }));\n\t\tthis.recalculate();\n\t}\n\n\t/** Measures toolbar and redistributes items between visible and overflow. */\n\trecalculate(): void {\n\t\tif (this.entries.length === 0) return;\n\n\t\tthis.closeDropdown();\n\t\tthis.resetVisibility();\n\t\tthis.ensureOverflowButton();\n\t\tthis.setOverflowButtonVisible(false);\n\n\t\t// Phase 1 — Measure (reads only): batch all layout reads before any writes\n\t\tconst availableWidth: number = this.measureAvailableWidth();\n\t\tconst children: HTMLElement[] = Array.from(this.toolbar.children) as HTMLElement[];\n\t\tconst childWidths: Map<HTMLElement, number> = this.measureChildWidths(children);\n\n\t\t// Phase 2 — Apply (writes only): use cached widths, no layout reads\n\t\tconst maxWidth: number = availableWidth - OVERFLOW_BTN_WIDTH - GAP;\n\t\tlet usedWidth = 0;\n\t\tlet overflowing = false;\n\t\tconst overflowList: OverflowEntry[] = [];\n\n\t\tfor (const child of children) {\n\t\t\tif (child === this.overflowButton) continue;\n\n\t\t\tif (child.classList.contains('notectl-toolbar-separator')) {\n\t\t\t\tif (overflowing) {\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst sepWidth: number = (childWidths.get(child) ?? 0) + GAP;\n\t\t\t\tif (usedWidth + sepWidth > maxWidth) {\n\t\t\t\t\toverflowing = true;\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t} else {\n\t\t\t\t\tusedWidth += sepWidth;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry: OverflowEntry | undefined = this.entries.find((oe) => oe.element === child);\n\t\t\tif (!entry) continue;\n\n\t\t\tif (overflowing) {\n\t\t\t\tentry.element.classList.add(HIDDEN_BTN_CLASS);\n\t\t\t\toverflowList.push(entry);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst btnWidth: number = (childWidths.get(child) ?? 0) + GAP;\n\t\t\tif (usedWidth + btnWidth > maxWidth) {\n\t\t\t\toverflowing = true;\n\t\t\t\tentry.element.classList.add(HIDDEN_BTN_CLASS);\n\t\t\t\toverflowList.push(entry);\n\t\t\t} else {\n\t\t\t\tusedWidth += btnWidth;\n\t\t\t}\n\t\t}\n\n\t\tthis.overflowEntries = overflowList;\n\t\tthis.hideTrailingSeparators();\n\t\tthis.setOverflowButtonVisible(overflowList.length > 0);\n\t\tthis.notifyChange();\n\t}\n\n\t/** Updates active/disabled states for items in the open overflow dropdown. */\n\tupdateItemStates(state: EditorState): void {\n\t\tif (!this.overflowDropdown) return;\n\n\t\tconst menuItems: HTMLButtonElement[] = Array.from(\n\t\t\tthis.overflowDropdown.querySelectorAll('.notectl-dropdown__item'),\n\t\t) as HTMLButtonElement[];\n\n\t\tfor (const menuItem of menuItems) {\n\t\t\tconst itemId: string | null = menuItem.getAttribute('data-toolbar-item');\n\t\t\tconst entry: OverflowEntry | undefined = this.overflowEntries.find(\n\t\t\t\t(oe) => oe.item.id === itemId,\n\t\t\t);\n\t\t\tif (!entry) continue;\n\n\t\t\tconst active: boolean = entry.item.isActive?.(state) ?? false;\n\t\t\tconst enabled: boolean = entry.item.isEnabled?.(state) ?? true;\n\t\t\tmenuItem.classList.toggle('notectl-dropdown__item--active', active);\n\t\t\tmenuItem.disabled = !enabled;\n\n\t\t\tif (entry.item.popupType === 'combobox') {\n\t\t\t\tconst labelEl: HTMLSpanElement | null = menuItem.querySelector(\n\t\t\t\t\t'.notectl-dropdown__item-label',\n\t\t\t\t);\n\t\t\t\tif (labelEl) {\n\t\t\t\t\tlabelEl.textContent = entry.item.getLabel(state);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entry.item.getIcon) {\n\t\t\t\tconst newIcon: string = entry.item.getIcon(state);\n\t\t\t\tconst iconEl: HTMLSpanElement | null = menuItem.querySelector(\n\t\t\t\t\t'.notectl-dropdown__item-icon',\n\t\t\t\t);\n\t\t\t\tif (iconEl && iconEl.innerHTML !== newIcon) {\n\t\t\t\t\ticonEl.innerHTML = newIcon;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Cleans up ResizeObserver, DOM elements, and event listeners. */\n\tdestroy(): void {\n\t\tthis.resizeObserver?.disconnect();\n\t\tthis.resizeObserver = null;\n\t\tthis.closeDropdown();\n\t\tthis.overflowButton?.remove();\n\t\tthis.overflowButton = null;\n\t\tthis.entries = [];\n\t\tthis.overflowEntries = [];\n\t}\n\n\t// --- Measurement ---\n\n\tprivate measureChildWidths(children: readonly HTMLElement[]): Map<HTMLElement, number> {\n\t\tconst widths: Map<HTMLElement, number> = new Map();\n\t\tfor (const child of children) {\n\t\t\tif (child === this.overflowButton) continue;\n\t\t\twidths.set(child, child.offsetWidth);\n\t\t}\n\t\treturn widths;\n\t}\n\n\tprivate measureAvailableWidth(): number {\n\t\tconst toolbarStyle: CSSStyleDeclaration = getComputedStyle(this.toolbar);\n\t\tconst paddingLeft: number = Number.parseFloat(toolbarStyle.paddingLeft) || 0;\n\t\tconst paddingRight: number = Number.parseFloat(toolbarStyle.paddingRight) || 0;\n\t\treturn this.toolbar.clientWidth - paddingLeft - paddingRight;\n\t}\n\n\tprivate resetVisibility(): void {\n\t\tfor (const entry of this.entries) {\n\t\t\tentry.element.classList.remove(HIDDEN_BTN_CLASS);\n\t\t}\n\t\tconst separators: HTMLElement[] = Array.from(\n\t\t\tthis.toolbar.querySelectorAll('.notectl-toolbar-separator'),\n\t\t) as HTMLElement[];\n\t\tfor (const sep of separators) {\n\t\t\tsep.classList.remove(HIDDEN_SEP_CLASS);\n\t\t}\n\t}\n\n\t// --- Overflow Button ---\n\n\tprivate setOverflowButtonVisible(visible: boolean): void {\n\t\tif (!this.overflowButton) return;\n\t\tthis.overflowButton.classList.toggle(HIDDEN_OVERFLOW_CLASS, !visible);\n\t\tif (!visible) {\n\t\t\tthis.overflowButton.removeAttribute('tabindex');\n\t\t}\n\t}\n\n\tprivate ensureOverflowButton(): void {\n\t\tif (this.overflowButton) return;\n\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = 'notectl-toolbar-overflow-btn';\n\t\tbtn.setAttribute('aria-label', this.ariaLabel);\n\t\tbtn.setAttribute('aria-haspopup', 'true');\n\t\tbtn.setAttribute('aria-expanded', 'false');\n\t\tbtn.innerHTML = ELLIPSIS_SVG;\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tthis.toggleDropdown();\n\t\t});\n\n\t\tthis.toolbar.appendChild(btn);\n\t\tthis.overflowButton = btn;\n\t}\n\n\t// --- Dropdown ---\n\n\tprivate toggleDropdown(): void {\n\t\tif (this.overflowDropdown) {\n\t\t\tthis.closeDropdown();\n\t\t} else {\n\t\t\tthis.openDropdown();\n\t\t}\n\t}\n\n\tprivate openDropdown(): void {\n\t\tif (!this.overflowButton || this.overflowEntries.length === 0) return;\n\n\t\tconst dropdown: HTMLDivElement = document.createElement('div');\n\t\tdropdown.className = 'notectl-toolbar-popup notectl-dropdown';\n\t\tdropdown.setAttribute('role', 'menu');\n\n\t\tthis.renderDropdownItems(dropdown, this.context.getState());\n\n\t\tif (this.popupManager) {\n\t\t\tthis.overflowHandle = this.popupManager.open({\n\t\t\t\tanchor: this.overflowButton,\n\t\t\t\tclassName: 'notectl-toolbar-popup notectl-dropdown',\n\t\t\t\tariaRole: 'menu',\n\t\t\t\tposition: 'below-end',\n\t\t\t\treferenceNode: this.overflowButton,\n\t\t\t\trestoreFocusTo: this.overflowButton,\n\t\t\t\tonClose: () => {\n\t\t\t\t\tthis.overflowHandle = null;\n\t\t\t\t\tthis.overflowDropdown = null;\n\t\t\t\t\tif (this.overflowButton) {\n\t\t\t\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tcontent: (popup: HTMLElement) => {\n\t\t\t\t\tthis.renderDropdownItems(popup, this.context.getState());\n\t\t\t\t\tthis.overflowDropdown = popup;\n\t\t\t\t\tpopup.addEventListener('keydown', (e: KeyboardEvent) => this.handleDropdownKeydown(e));\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'true');\n\t\t} else {\n\t\t\tthis.positionDropdown(dropdown);\n\t\t\tappendToRoot(dropdown, this.overflowButton);\n\t\t\tthis.overflowDropdown = dropdown;\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'true');\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tconst first: HTMLElement | null = dropdown.querySelector('[role=\"menuitem\"]');\n\t\t\t\tfirst?.focus();\n\t\t\t});\n\n\t\t\tdropdown.addEventListener('keydown', (e: KeyboardEvent) => this.handleDropdownKeydown(e));\n\t\t\tthis.registerCloseHandler();\n\t\t}\n\t}\n\n\tprivate renderDropdownItems(dropdown: HTMLElement, state: EditorState): void {\n\t\tlet lastGroup: string | null = null;\n\n\t\tfor (const entry of this.overflowEntries) {\n\t\t\tif (lastGroup !== null && entry.item.group !== lastGroup) {\n\t\t\t\tconst sep: HTMLDivElement = document.createElement('div');\n\t\t\t\tsep.className = 'notectl-dropdown__separator';\n\t\t\t\tsep.setAttribute('role', 'separator');\n\t\t\t\tdropdown.appendChild(sep);\n\t\t\t}\n\t\t\tlastGroup = entry.item.group;\n\n\t\t\tconst menuBtn: HTMLButtonElement = document.createElement('button');\n\t\t\tmenuBtn.type = 'button';\n\t\t\tmenuBtn.className = 'notectl-dropdown__item';\n\t\t\tmenuBtn.setAttribute('role', 'menuitem');\n\t\t\tmenuBtn.setAttribute('tabindex', '-1');\n\t\t\tmenuBtn.setAttribute('data-toolbar-item', entry.item.id);\n\n\t\t\tconst iconSpan: HTMLSpanElement = document.createElement('span');\n\t\t\ticonSpan.className = 'notectl-dropdown__item-icon';\n\t\t\tif (entry.item.popupType !== 'combobox') {\n\t\t\t\ticonSpan.innerHTML = entry.item.icon;\n\t\t\t}\n\t\t\tmenuBtn.appendChild(iconSpan);\n\n\t\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tlabelSpan.className = 'notectl-dropdown__item-label';\n\t\t\tlabelSpan.textContent =\n\t\t\t\tentry.item.popupType === 'combobox'\n\t\t\t\t\t? entry.item.getLabel(state)\n\t\t\t\t\t: (entry.item.tooltip ?? entry.item.label);\n\t\t\tmenuBtn.appendChild(labelSpan);\n\n\t\t\tmenuBtn.addEventListener('mousedown', (ev: MouseEvent) => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tev.stopPropagation();\n\t\t\t\tthis.activateOverflowItem(entry);\n\t\t\t});\n\n\t\t\tdropdown.appendChild(menuBtn);\n\t\t}\n\t}\n\n\tprivate positionDropdown(dropdown: HTMLElement): void {\n\t\tif (!this.overflowButton) return;\n\n\t\tconst rect: DOMRect = this.overflowButton.getBoundingClientRect();\n\t\tconst rtl: boolean = isRtlContext(this.toolbar);\n\n\t\tif (rtl) {\n\t\t\tsetStyleProperties(dropdown, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 2}px`,\n\t\t\t\tleft: `${rect.left}px`,\n\t\t\t\tright: 'auto',\n\t\t\t\tzIndex: '10000',\n\t\t\t});\n\t\t} else {\n\t\t\tconst rightEdge: number = window.innerWidth - rect.right;\n\t\t\tsetStyleProperties(dropdown, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 2}px`,\n\t\t\t\tright: `${rightEdge}px`,\n\t\t\t\tleft: 'auto',\n\t\t\t\tzIndex: '10000',\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerCloseHandler(): void {\n\t\tthis.closeHandler = (ev: MouseEvent) => {\n\t\t\tconst path: EventTarget[] = ev.composedPath();\n\t\t\tif (\n\t\t\t\tthis.overflowDropdown &&\n\t\t\t\t!path.includes(this.overflowDropdown) &&\n\t\t\t\tthis.overflowButton &&\n\t\t\t\t!path.includes(this.overflowButton)\n\t\t\t) {\n\t\t\t\tthis.closeDropdown();\n\t\t\t}\n\t\t};\n\t\tthis.closeHandlerTimer = setTimeout(() => {\n\t\t\tthis.closeHandlerTimer = null;\n\t\t\tif (!this.closeHandler || !this.overflowDropdown) return;\n\t\t\tdocument.addEventListener('mousedown', this.closeHandler);\n\t\t\tthis.closeHandlerAttached = true;\n\t\t}, 0);\n\t}\n\n\tprivate closeDropdown(): void {\n\t\tif (this.overflowHandle) {\n\t\t\tconst handle: PopupHandle = this.overflowHandle;\n\t\t\tthis.overflowHandle = null;\n\t\t\tthis.overflowDropdown = null;\n\t\t\thandle.close();\n\t\t\tif (this.overflowButton) {\n\t\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.overflowDropdown) {\n\t\t\tthis.overflowDropdown.remove();\n\t\t\tthis.overflowDropdown = null;\n\t\t}\n\t\tif (this.overflowButton) {\n\t\t\tthis.overflowButton.setAttribute('aria-expanded', 'false');\n\t\t}\n\t\tif (this.closeHandler) {\n\t\t\tif (this.closeHandlerTimer !== null) {\n\t\t\t\tclearTimeout(this.closeHandlerTimer);\n\t\t\t\tthis.closeHandlerTimer = null;\n\t\t\t}\n\t\t\tif (this.closeHandlerAttached) {\n\t\t\t\tdocument.removeEventListener('mousedown', this.closeHandler);\n\t\t\t\tthis.closeHandlerAttached = false;\n\t\t\t}\n\t\t\tthis.closeHandler = null;\n\t\t}\n\t}\n\n\tprivate activateOverflowItem(entry: OverflowEntry): void {\n\t\tthis.closeDropdown();\n\t\tif (entry.item.popupType && this.overflowButton) {\n\t\t\tthis.onItemActivated(this.overflowButton, entry.item);\n\t\t} else {\n\t\t\tthis.context.executeCommand(entry.item.command);\n\t\t}\n\t}\n\n\t// --- Keyboard Navigation ---\n\n\tprivate handleDropdownKeydown(e: KeyboardEvent): void {\n\t\tif (!this.overflowDropdown) return;\n\n\t\tif (e.key === 'Escape' || e.key === 'Tab') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.closeDropdown();\n\t\t\tthis.overflowButton?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tthis.overflowDropdown.querySelectorAll('[role=\"menuitem\"]'),\n\t\t) as HTMLElement[];\n\t\tconst current: number = items.indexOf(this.getActiveElement() as HTMLElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(items, current, 1);\n\t\t\t\titems[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(items, current, -1);\n\t\t\t\titems[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focusedItem: HTMLElement | undefined = items[current];\n\t\t\t\tif (!focusedItem) break;\n\t\t\t\tconst itemId: string | null = focusedItem.getAttribute('data-toolbar-item');\n\t\t\t\tconst entry: OverflowEntry | undefined = this.overflowEntries.find(\n\t\t\t\t\t(oe) => oe.item.id === itemId,\n\t\t\t\t);\n\t\t\t\tif (entry) this.activateOverflowItem(entry);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Helpers ---\n\n\tprivate hideTrailingSeparators(): void {\n\t\tconst children: HTMLElement[] = Array.from(this.toolbar.children) as HTMLElement[];\n\t\tfor (let i = children.length - 1; i >= 0; i--) {\n\t\t\tconst child: HTMLElement | undefined = children[i];\n\t\t\tif (!child || child === this.overflowButton) continue;\n\t\t\tif (child.classList.contains('notectl-toolbar-separator')) {\n\t\t\t\tif (!child.classList.contains(HIDDEN_SEP_CLASS)) {\n\t\t\t\t\tchild.classList.add(HIDDEN_SEP_CLASS);\n\t\t\t\t}\n\t\t\t} else if (!child.classList.contains(HIDDEN_BTN_CLASS)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate notifyChange(): void {\n\t\tconst visible: HTMLButtonElement[] = this.entries\n\t\t\t.filter((oe) => !oe.element.classList.contains(HIDDEN_BTN_CLASS))\n\t\t\t.map((oe) => oe.element);\n\t\tthis.onOverflowChange(visible, this.overflowEntries.length > 0 ? this.overflowButton : null);\n\t}\n}\n","/**\n * ToolbarRenderers: pure rendering functions for toolbar popup content.\n * Grid pickers, dropdown menus, and separator elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { DropdownConfig, GridPickerConfig } from './ToolbarItem.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale } from './ToolbarLocale.js';\n\nconst HIGHLIGHTED_CLASS = 'notectl-grid-picker__cell--highlighted';\n\n/**\n * Renders a grid picker into the given container.\n * Calls `onClose` after a cell is selected so the popup can be dismissed.\n */\nexport function renderGridPicker(\n\tcontainer: HTMLElement,\n\tconfig: GridPickerConfig,\n\tonClose: () => void,\n\tlocale: ToolbarLocale = TOOLBAR_LOCALE_EN,\n): void {\n\tcontainer.className += ' notectl-grid-picker';\n\n\tconst grid: HTMLDivElement = document.createElement('div');\n\tgrid.className = 'notectl-grid-picker__grid';\n\tgrid.setAttribute('role', 'grid');\n\tsetStyleProperties(grid, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: `repeat(${config.maxCols}, 1fr)`,\n\t\tgap: '2px',\n\t\tpadding: '8px',\n\t});\n\n\tconst label: HTMLDivElement = document.createElement('div');\n\tlabel.className = 'notectl-grid-picker__label';\n\tlabel.textContent = locale.gridPickerLabel(1, 1);\n\tsetStyleProperties(label, {\n\t\ttextAlign: 'center',\n\t\tpadding: '4px',\n\t\tfontSize: '12px',\n\t});\n\tlabel.setAttribute('aria-live', 'polite');\n\n\tfor (let r = 1; r <= config.maxRows; r++) {\n\t\tfor (let c = 1; c <= config.maxCols; c++) {\n\t\t\tconst cell: HTMLDivElement = document.createElement('div');\n\t\t\tcell.className = 'notectl-grid-picker__cell';\n\t\t\tcell.setAttribute('role', 'gridcell');\n\t\t\tcell.setAttribute('tabindex', '-1');\n\t\t\tcell.setAttribute('aria-label', locale.gridPickerLabel(r, c));\n\t\t\tsetStyleProperties(cell, {\n\t\t\t\twidth: '20px',\n\t\t\t\theight: '20px',\n\t\t\t\tborder: '1px solid #ccc',\n\t\t\t\tcursor: 'pointer',\n\t\t\t});\n\t\t\tcell.setAttribute('data-row', String(r));\n\t\t\tcell.setAttribute('data-col', String(c));\n\n\t\t\tcell.addEventListener('mouseenter', () => {\n\t\t\t\thighlightCells(grid, r, c);\n\t\t\t\tlabel.textContent = locale.gridPickerLabel(r, c);\n\t\t\t});\n\n\t\t\tcell.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t});\n\n\t\t\tcell.addEventListener('click', () => {\n\t\t\t\tconfig.onSelect(r, c);\n\t\t\t\tonClose();\n\t\t\t});\n\n\t\t\tgrid.appendChild(cell);\n\t\t}\n\t}\n\n\tcontainer.appendChild(grid);\n\tcontainer.appendChild(label);\n}\n\n/**\n * Highlights grid cells up to the given row/col and updates the label.\n * Used by both mouse hover and keyboard navigation.\n */\nexport function highlightCells(grid: HTMLElement, targetRow: number, targetCol: number): void {\n\tconst cells: NodeListOf<Element> = grid.querySelectorAll('.notectl-grid-picker__cell');\n\tfor (const cell of cells) {\n\t\tconst r: number = Number(cell.getAttribute('data-row'));\n\t\tconst c: number = Number(cell.getAttribute('data-col'));\n\t\tcell.classList.toggle(HIGHLIGHTED_CLASS, r <= targetRow && c <= targetCol);\n\t}\n}\n\n/**\n * Renders a dropdown menu into the given container.\n * Calls `onClose` after an item is activated so the popup can be dismissed.\n */\nexport function renderDropdown(\n\tcontainer: HTMLElement,\n\tconfig: DropdownConfig,\n\texecuteCommand: (command: string) => void,\n\tonClose: () => void,\n): void {\n\tcontainer.classList.add('notectl-dropdown');\n\tcontainer.setAttribute('role', 'menu');\n\n\tfor (const item of config.items) {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = 'notectl-dropdown__item';\n\t\tbtn.setAttribute('role', 'menuitem');\n\t\tbtn.setAttribute('tabindex', '-1');\n\n\t\tif (item.icon) {\n\t\t\tconst iconSpan: HTMLSpanElement = document.createElement('span');\n\t\t\ticonSpan.className = 'notectl-dropdown__item-icon';\n\t\t\ticonSpan.innerHTML = item.icon;\n\t\t\tbtn.appendChild(iconSpan);\n\t\t}\n\n\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\tlabelSpan.className = 'notectl-dropdown__item-label';\n\t\tlabelSpan.textContent = item.label;\n\t\tbtn.appendChild(labelSpan);\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t});\n\n\t\tbtn.addEventListener('click', () => {\n\t\t\texecuteCommand(item.command);\n\t\t\tonClose();\n\t\t});\n\n\t\tcontainer.appendChild(btn);\n\t}\n}\n\n/** Creates a toolbar group separator element. */\nexport function createSeparator(): HTMLSpanElement {\n\tconst sep: HTMLSpanElement = document.createElement('span');\n\tsep.className = 'notectl-toolbar-separator';\n\tsep.setAttribute('role', 'separator');\n\treturn sep;\n}\n","/**\n * ToolbarPopupController: manages popup lifecycle, positioning, keyboard\n * navigation, and auto-close for toolbar popups (grid pickers, dropdowns,\n * and custom popups). Delegates lifecycle to PopupManager.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { findNextDropdownItem, navigateGrid } from '../shared/KeyboardNav.js';\nimport type { PopupCloseOptions, PopupHandle, PopupManager } from '../shared/PopupManager.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale } from './ToolbarLocale.js';\nimport { highlightCells, renderDropdown, renderGridPicker } from './ToolbarRenderers.js';\n\nexport class ToolbarPopupController {\n\tprivate activePopup: HTMLElement | null = null;\n\tprivate activePopupButton: HTMLButtonElement | null = null;\n\tprivate activeHandle: PopupHandle | null = null;\n\tprivate readonly getActiveElement: () => Element | null;\n\tprivate readonly locale: ToolbarLocale;\n\tprivate popupManager: PopupManager | null = null;\n\n\tconstructor(getActiveElement: () => Element | null, locale: ToolbarLocale = TOOLBAR_LOCALE_EN) {\n\t\tthis.getActiveElement = getActiveElement;\n\t\tthis.locale = locale;\n\t}\n\n\t/** Injects the PopupManager instance (called after service registration). */\n\tsetPopupManager(manager: PopupManager): void {\n\t\tthis.popupManager = manager;\n\t}\n\n\t/** Whether a popup is currently open. */\n\tisOpen(): boolean {\n\t\treturn this.activePopup !== null;\n\t}\n\n\t/** Toggles a popup for the given toolbar button. */\n\ttoggle(button: HTMLButtonElement, item: ToolbarItem, context: PluginContext): void {\n\t\tif (this.activePopup) {\n\t\t\tthis.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.openViaManager(button, item, context);\n\t}\n\n\t/** Closes the active popup and cleans up event listeners. */\n\tclose(): void {\n\t\tif (this.activeHandle) {\n\t\t\t// Prevent onClose callback from re-entering\n\t\t\tconst handle: PopupHandle = this.activeHandle;\n\t\t\tthis.activeHandle = null;\n\t\t\tthis.clearButtonState();\n\t\t\thandle.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.clearButtonState();\n\t\tif (this.activePopup) {\n\t\t\tthis.activePopup.remove();\n\t\t\tthis.activePopup = null;\n\t\t}\n\t}\n\n\t/** Closes popup and restores focus to the trigger button. */\n\tcloseAndRestoreFocus(): void {\n\t\tconst triggerBtn: HTMLButtonElement | null = this.activePopupButton;\n\t\tthis.close();\n\t\ttriggerBtn?.focus();\n\t}\n\n\tdestroy(): void {\n\t\tthis.close();\n\t}\n\n\t// --- PopupManager path ---\n\n\tprivate openViaManager(\n\t\tbutton: HTMLButtonElement,\n\t\titem: ToolbarItem,\n\t\tcontext: PluginContext,\n\t): void {\n\t\tif (!this.popupManager) return;\n\n\t\tthis.activePopupButton = button;\n\t\tbutton.classList.add('notectl-toolbar-btn--popup-open');\n\t\tbutton.setAttribute('aria-expanded', 'true');\n\n\t\tthis.activeHandle = this.popupManager.open({\n\t\t\tanchor: button,\n\t\t\tclassName: 'notectl-toolbar-popup',\n\t\t\treferenceNode: button,\n\t\t\trestoreFocusTo: button,\n\t\t\tposition: 'below-start',\n\t\t\tonClose: () => {\n\t\t\t\t// Called when PopupManager closes the popup (click-outside, etc.)\n\t\t\t\tthis.activeHandle = null;\n\t\t\t\tthis.clearButtonState();\n\t\t\t\tthis.activePopup = null;\n\t\t\t},\n\t\t\tcontent: (popup: HTMLElement, close: (options?: PopupCloseOptions) => void) => {\n\t\t\t\tthis.activePopup = popup;\n\t\t\t\tthis.renderPopupContent(popup, item, context, close);\n\t\t\t\tpopup.addEventListener('keydown', (e: KeyboardEvent) => this.handlePopupKeydown(e));\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Shared rendering ---\n\n\tprivate renderPopupContent(\n\t\tpopup: HTMLElement,\n\t\titem: ToolbarItem,\n\t\tcontext: PluginContext,\n\t\tclose: (options?: PopupCloseOptions) => void,\n\t): void {\n\t\tconst closeAndFocusEditor = (): void => {\n\t\t\tclose({ restoreFocusTo: null });\n\t\t\tcontext.getContainer().focus();\n\t\t};\n\n\t\tswitch (item.popupType) {\n\t\t\tcase 'gridPicker':\n\t\t\t\trenderGridPicker(popup, item.popupConfig, closeAndFocusEditor, this.locale);\n\t\t\t\tbreak;\n\t\t\tcase 'dropdown':\n\t\t\t\trenderDropdown(\n\t\t\t\t\tpopup,\n\t\t\t\t\titem.popupConfig,\n\t\t\t\t\t(cmd: string) => context.executeCommand(cmd),\n\t\t\t\t\tcloseAndFocusEditor,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase 'custom':\n\t\t\t\titem.renderPopup(popup, context, close);\n\t\t\t\tbreak;\n\t\t\tcase 'combobox':\n\t\t\t\titem.renderPopup(popup, context, close);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// --- Button state ---\n\n\tprivate clearButtonState(): void {\n\t\tif (this.activePopupButton) {\n\t\t\tthis.activePopupButton.classList.remove('notectl-toolbar-btn--popup-open');\n\t\t\tthis.activePopupButton.setAttribute('aria-expanded', 'false');\n\t\t\tthis.activePopupButton = null;\n\t\t}\n\t}\n\n\t// --- Keyboard Navigation ---\n\n\tprivate handlePopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Tab') {\n\t\t\te.preventDefault();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tconst menuItems: NodeListOf<Element> = this.activePopup.querySelectorAll('[role=\"menuitem\"]');\n\t\tif (menuItems.length > 0) {\n\t\t\tthis.handleDropdownKeydown(e, menuItems);\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasGrid: boolean = this.activePopup.querySelector('.notectl-grid-picker__cell') !== null;\n\t\tif (hasGrid) {\n\t\t\tthis.handleGridKeydown(e);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.handleCustomPopupKeydown(e);\n\t}\n\n\tprivate handleDropdownKeydown(e: KeyboardEvent, items: NodeListOf<Element>): void {\n\t\tconst itemArr: HTMLElement[] = Array.from(items) as HTMLElement[];\n\t\tconst current: number = itemArr.indexOf(this.getActiveElement() as HTMLElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(itemArr, current, 1);\n\t\t\t\titemArr[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(itemArr, current, -1);\n\t\t\t\titemArr[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focused: HTMLElement | undefined = itemArr[current];\n\t\t\t\tif (focused) focused.click();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleGridKeydown(e: KeyboardEvent): void {\n\t\tconst focused: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst row: number = Number(focused?.getAttribute('data-row') ?? 1);\n\t\tconst col: number = Number(focused?.getAttribute('data-col') ?? 1);\n\n\t\tconst grid: Element | null =\n\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__grid') ?? null;\n\t\tif (!grid) return;\n\n\t\tconst lastCell: Element | null = grid.querySelector('.notectl-grid-picker__cell:last-child');\n\t\tconst maxCols: number = Number(lastCell?.getAttribute('data-col') ?? 1);\n\t\tconst maxRows: number = Number(lastCell?.getAttribute('data-row') ?? 1);\n\n\t\tif (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst [newRow, newCol]: [number, number] = navigateGrid(\n\t\t\t\trow,\n\t\t\t\tcol,\n\t\t\t\tmaxRows,\n\t\t\t\tmaxCols,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t\tthis.activePopup ? isRtlContext(this.activePopup) : false,\n\t\t\t);\n\t\t\tconst target: HTMLElement | null = grid.querySelector(\n\t\t\t\t`.notectl-grid-picker__cell[data-row=\"${newRow}\"][data-col=\"${newCol}\"]`,\n\t\t\t);\n\t\t\ttarget?.focus();\n\n\t\t\thighlightCells(grid as HTMLElement, newRow, newCol);\n\t\t\tconst label: Element | null =\n\t\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__label') ?? null;\n\t\t\tif (label) label.textContent = this.locale.gridPickerLabel(newRow, newCol);\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tfocused?.click();\n\t\t}\n\t}\n\n\tprivate handleCustomPopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\t\tconst buttons: HTMLButtonElement[] = Array.from(this.activePopup.querySelectorAll('button'));\n\t\tif (buttons.length === 0) return;\n\t\tconst active: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst currentIdx: number = buttons.indexOf(active as HTMLButtonElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(buttons, currentIdx, 1);\n\t\t\t\tbuttons[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(buttons, currentIdx, -1);\n\t\t\t\tbuttons[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (active) {\n\t\t\t\t\tactive.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * ToolbarTooltip: manages the tooltip lifecycle for toolbar buttons.\n * Shows a tooltip after a short delay when hovering or focusing a button,\n * hides it when the cursor leaves or focus moves away.\n */\n\nimport { setStyleProperties, setStyleProperty } from '../../style/StyleRuntime.js';\n\nconst TOOLTIP_DELAY_MS = 500;\n\nexport class ToolbarTooltip {\n\tprivate readonly element: HTMLElement;\n\tprivate timer: ReturnType<typeof setTimeout> | null = null;\n\tprivate target: HTMLButtonElement | null = null;\n\tprivate readonly isPopupActive: () => boolean;\n\n\tstatic readonly TOOLTIP_ID = 'notectl-toolbar-tooltip';\n\n\tconstructor(isPopupActive: () => boolean) {\n\t\tthis.isPopupActive = isPopupActive;\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.className = 'notectl-toolbar-tooltip';\n\t\tthis.element.id = ToolbarTooltip.TOOLTIP_ID;\n\t\tthis.element.setAttribute('role', 'tooltip');\n\t\tsetStyleProperty(this.element, 'display', 'none');\n\t}\n\n\tshow(button: HTMLButtonElement): void {\n\t\tthis.hide();\n\n\t\tif (this.isPopupActive() || button.disabled) return;\n\n\t\tconst text: string | null = button.getAttribute('data-tooltip');\n\t\tif (!text) return;\n\n\t\tthis.target = button;\n\n\t\tthis.timer = setTimeout(() => {\n\t\t\tif (this.isPopupActive()) return;\n\n\t\t\tthis.element.textContent = text;\n\t\t\tsetStyleProperty(this.element, 'display', '');\n\n\t\t\tconst root: Node = button.getRootNode();\n\t\t\tif (root instanceof ShadowRoot && !this.element.parentNode) {\n\t\t\t\troot.appendChild(this.element);\n\t\t\t} else if (!(root instanceof ShadowRoot) && !this.element.parentNode) {\n\t\t\t\tdocument.body.appendChild(this.element);\n\t\t\t}\n\n\t\t\tbutton.setAttribute('aria-describedby', ToolbarTooltip.TOOLTIP_ID);\n\n\t\t\tconst rect: DOMRect = button.getBoundingClientRect();\n\t\t\tsetStyleProperties(this.element, {\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: `${rect.bottom + 6}px`,\n\t\t\t\tleft: `${rect.left + rect.width / 2}px`,\n\t\t\t\ttransform: 'translateX(-50%)',\n\t\t\t});\n\t\t}, TOOLTIP_DELAY_MS);\n\t}\n\n\thide(): void {\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tif (this.target) {\n\t\t\tthis.target.removeAttribute('aria-describedby');\n\t\t\tthis.target = null;\n\t\t}\n\t\tsetStyleProperty(this.element, 'display', 'none');\n\t}\n\n\tdestroy(): void {\n\t\tthis.hide();\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * Toolbar plugin: renders toolbar items registered by other plugins.\n * Acts as a pure rendering engine — has no knowledge of specific features.\n * Supports buttons, dropdowns, grid pickers, and custom popups.\n * Implements WAI-ARIA Toolbar pattern with roving tabindex.\n */\n\nimport { TOOLBAR_CSS } from '../../editor/styles/toolbar.js';\nimport { isRtlContext } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport { ServiceKey } from '../Plugin.js';\nimport type { Plugin, PluginConfig, PluginContext } from '../Plugin.js';\nimport { applyRovingTabindex } from '../shared/KeyboardNav.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { PopupManager, PopupServiceKey } from '../shared/PopupManager.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport {\n\tfindFirstEnabled,\n\tfindLastEnabled,\n\tfindNextEnabled,\n\tresolveHorizontalDirection,\n} from './ToolbarKeyboardNav.js';\nimport { TOOLBAR_LOCALE_EN, type ToolbarLocale, loadToolbarLocale } from './ToolbarLocale.js';\nimport {\n\tToolbarOverflowBehavior,\n\ttype ToolbarOverflowBehavior as ToolbarOverflowBehaviorType,\n} from './ToolbarOverflowBehavior.js';\nimport { ToolbarOverflowController } from './ToolbarOverflowController.js';\nimport { ToolbarPopupController } from './ToolbarPopupController.js';\nimport { createSeparator } from './ToolbarRenderers.js';\nimport { ToolbarTooltip } from './ToolbarTooltip.js';\n\n// --- Layout Config ---\n\nexport interface ToolbarLayoutConfig {\n\treadonly groups: ReadonlyArray<ReadonlyArray<string>>;\n\t/**\n\t * Controls responsive overflow behavior when toolbar items exceed available width.\n\t * Defaults to `ToolbarOverflowBehavior.BurgerMenu`.\n\t */\n\treadonly overflow?: ToolbarOverflowBehaviorType;\n}\n\n// --- Typed Service API ---\n\nexport interface ToolbarServiceAPI {\n\t/** Re-reads isActive/isEnabled from state and updates all buttons. */\n\trefresh(): void;\n\t/** Closes the currently open popup, if any. */\n\tclosePopup(): void;\n}\n\nexport const ToolbarServiceKey = new ServiceKey<ToolbarServiceAPI>('toolbar');\n\n// --- Plugin ---\n\ninterface ToolbarButton {\n\telement: HTMLButtonElement;\n\titem: ToolbarItem;\n\tcomboLabelEl: HTMLSpanElement | null;\n}\n\nexport class ToolbarPlugin implements Plugin {\n\treadonly id = 'toolbar';\n\treadonly name = 'Toolbar';\n\treadonly priority = 10;\n\n\tprivate context: PluginContext | null = null;\n\tprivate toolbarElement: HTMLElement | null = null;\n\tprivate buttons: ToolbarButton[] = [];\n\tprivate readonly hiddenItems = new Set<string>();\n\tprivate readonly layoutConfig: ToolbarLayoutConfig | null;\n\tprivate overflowBehavior: ToolbarOverflowBehaviorType;\n\tprivate focusedIndex = 0;\n\tprivate tooltip: ToolbarTooltip | null = null;\n\tprivate popupController: ToolbarPopupController | null = null;\n\tprivate popupManager: PopupManager | null = null;\n\tprivate overflowController: ToolbarOverflowController | null = null;\n\tprivate visibleElements: HTMLButtonElement[] = [];\n\tprivate locale!: ToolbarLocale;\n\n\tconstructor(layoutConfig?: ToolbarLayoutConfig) {\n\t\tthis.layoutConfig = layoutConfig ?? null;\n\t\tthis.overflowBehavior = layoutConfig?.overflow ?? ToolbarOverflowBehavior.BurgerMenu;\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(context, undefined, TOOLBAR_LOCALE_EN, loadToolbarLocale);\n\t\tcontext.registerStyleSheet(TOOLBAR_CSS);\n\t\tthis.context = context;\n\n\t\tthis.popupManager = new PopupManager(context.getContainer());\n\t\tcontext.registerService(PopupServiceKey, this.popupManager);\n\n\t\tthis.popupController = new ToolbarPopupController(() => this.getActiveElement(), this.locale);\n\t\tthis.popupController.setPopupManager(this.popupManager);\n\t\tthis.tooltip = new ToolbarTooltip(() => this.popupController?.isOpen() ?? false);\n\n\t\tcontext.registerService(ToolbarServiceKey, {\n\t\t\trefresh: () => this.updateButtonStates(context.getState()),\n\t\t\tclosePopup: () => this.popupController?.close(),\n\t\t});\n\n\t\tthis.createToolbarElement();\n\t}\n\n\t/** Returns the current overflow behavior. */\n\tgetOverflowBehavior(): ToolbarOverflowBehaviorType {\n\t\treturn this.overflowBehavior;\n\t}\n\n\t/** Switches the overflow behavior at runtime. */\n\tsetOverflowBehavior(behavior: ToolbarOverflowBehaviorType): void {\n\t\tif (behavior === this.overflowBehavior) return;\n\n\t\tthis.overflowBehavior = behavior;\n\t\tthis.applyOverflowBehavior();\n\t\tthis.renderItems();\n\t}\n\n\tonReady(): void {\n\t\tthis.renderItems();\n\t}\n\n\tdestroy(): void {\n\t\tthis.overflowController?.destroy();\n\t\tthis.overflowController = null;\n\t\tthis.popupController?.destroy();\n\t\tthis.popupController = null;\n\t\tthis.popupManager?.destroy();\n\t\tthis.popupManager = null;\n\t\tthis.tooltip?.destroy();\n\t\tthis.tooltip = null;\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\tthis.toolbarElement = null;\n\t\t}\n\t\tthis.buttons = [];\n\t\tthis.visibleElements = [];\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateButtonStates(newState);\n\t}\n\n\tonReadOnlyChange(readonly: boolean): void {\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.hidden = readonly;\n\t\t}\n\t}\n\n\tonConfigure(config: PluginConfig): void {\n\t\tfor (const [key, value] of Object.entries(config)) {\n\t\t\tif (value === false) {\n\t\t\t\tthis.hiddenItems.add(key);\n\t\t\t} else {\n\t\t\t\tthis.hiddenItems.delete(key);\n\t\t\t}\n\t\t}\n\t\tthis.renderItems();\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate createToolbarElement(): void {\n\t\tif (!this.context) return;\n\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\tthis.toolbarElement = document.createElement('div');\n\t\tthis.toolbarElement.setAttribute('role', 'toolbar');\n\t\tthis.toolbarElement.setAttribute('aria-label', this.locale.formattingOptionsAria);\n\t\tthis.toolbarElement.setAttribute('data-notectl-no-print', '');\n\t\tthis.toolbarElement.className = 'notectl-toolbar';\n\n\t\tthis.toolbarElement.addEventListener('keydown', (e) => this.handleToolbarKeydown(e));\n\n\t\tthis.applyOverflowBehavior();\n\t\tcontainer.appendChild(this.toolbarElement);\n\t}\n\n\t/** Applies the current overflow behavior: creates/destroys the overflow controller and sets the data attribute. */\n\tprivate applyOverflowBehavior(): void {\n\t\tif (!this.toolbarElement || !this.context) return;\n\n\t\t// Tear down existing overflow controller\n\t\tthis.overflowController?.destroy();\n\t\tthis.overflowController = null;\n\n\t\tthis.toolbarElement.setAttribute('data-overflow', this.overflowBehavior);\n\n\t\tif (this.overflowBehavior === ToolbarOverflowBehavior.BurgerMenu) {\n\t\t\tthis.overflowController = new ToolbarOverflowController({\n\t\t\t\ttoolbar: this.toolbarElement,\n\t\t\t\tariaLabel: this.locale.moreToolsAria,\n\t\t\t\tcontext: this.context,\n\t\t\t\tpopupManager: this.popupManager ?? undefined,\n\t\t\t\tonOverflowChange: (visibleButtons, overflowBtn) => {\n\t\t\t\t\tthis.visibleElements = overflowBtn\n\t\t\t\t\t\t? [...visibleButtons, overflowBtn]\n\t\t\t\t\t\t: [...visibleButtons];\n\t\t\t\t\tthis.initRovingTabindex();\n\t\t\t\t},\n\t\t\t\tonItemActivated: (btn: HTMLButtonElement, item: ToolbarItem) => {\n\t\t\t\t\tthis.activateButton(btn, item);\n\t\t\t\t},\n\t\t\t\tgetActiveElement: () => this.getActiveElement(),\n\t\t\t});\n\t\t} else {\n\t\t\t// Flow and None modes: all buttons are visible for roving tabindex\n\t\t\tthis.visibleElements = [];\n\t\t}\n\t}\n\n\tprivate renderItems(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tfor (const btn of this.buttons) {\n\t\t\tbtn.element.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tfor (const sep of this.toolbarElement.querySelectorAll('.notectl-toolbar-separator')) {\n\t\t\tsep.remove();\n\t\t}\n\n\t\tif (this.layoutConfig) {\n\t\t\tthis.renderItemsByLayout();\n\t\t} else {\n\t\t\tthis.renderItemsByGroup();\n\t\t}\n\n\t\tif (this.buttons.length > 0 && !this.toolbarElement.parentElement) {\n\t\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\t\tcontainer.appendChild(this.toolbarElement);\n\t\t}\n\n\t\tthis.overflowController?.update(this.buttons);\n\t\tthis.initRovingTabindex();\n\t\tthis.updateButtonStates(this.context.getState());\n\t}\n\n\t// --- Roving Tabindex ---\n\n\tprivate getTabElements(): HTMLButtonElement[] {\n\t\treturn this.visibleElements.length > 0\n\t\t\t? this.visibleElements\n\t\t\t: this.buttons.map((b) => b.element);\n\t}\n\n\tprivate initRovingTabindex(): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tconst first: number = findFirstEnabled(elements);\n\t\tthis.focusedIndex = first >= 0 ? first : 0;\n\t\tapplyRovingTabindex(elements, this.focusedIndex);\n\t}\n\n\tprivate setRovingFocus(index: number): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tif (index < 0 || index >= elements.length) return;\n\t\tthis.focusedIndex = index;\n\t\tapplyRovingTabindex(elements, index);\n\t\telements[index]?.focus();\n\t}\n\n\t/** Returns the active element, respecting shadow DOM boundaries. */\n\tprivate getActiveElement(): Element | null {\n\t\tconst root: Node | undefined = this.toolbarElement?.getRootNode();\n\t\tif (root instanceof ShadowRoot) {\n\t\t\treturn root.activeElement;\n\t\t}\n\t\treturn document.activeElement;\n\t}\n\n\tprivate syncFocusedIndex(): void {\n\t\tconst active: Element | null = this.getActiveElement();\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tconst idx: number = elements.findIndex((el) => el === active);\n\t\tif (idx >= 0) {\n\t\t\tthis.focusedIndex = idx;\n\t\t}\n\t}\n\n\t// --- Toolbar Keyboard ---\n\n\tprivate handleToolbarKeydown(e: KeyboardEvent): void {\n\t\tconst elements: HTMLButtonElement[] = this.getTabElements();\n\t\tif (elements.length === 0) return;\n\n\t\tthis.syncFocusedIndex();\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowRight':\n\t\t\tcase 'ArrowLeft': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst rtl: boolean = this.toolbarElement ? isRtlContext(this.toolbarElement) : false;\n\t\t\t\tconst dir: 1 | -1 = resolveHorizontalDirection(e.key, rtl);\n\t\t\t\tconst next: number = findNextEnabled(elements, this.focusedIndex, dir);\n\t\t\t\tthis.setRovingFocus(next);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst first: number = findFirstEnabled(elements);\n\t\t\t\tif (first >= 0) this.setRovingFocus(first);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst last: number = findLastEnabled(elements);\n\t\t\t\tif (last >= 0) this.setRovingFocus(last);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focused: HTMLButtonElement | undefined = elements[this.focusedIndex];\n\t\t\t\tconst btn: ToolbarButton | undefined = this.buttons.find((b) => b.element === focused);\n\t\t\t\tif (btn) this.activateButton(btn.element, btn.item);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Activates a toolbar button (shared between mouse click and keyboard). */\n\tprivate activateButton(btn: HTMLButtonElement, item: ToolbarItem): void {\n\t\tthis.tooltip?.hide();\n\t\tif (item.popupType && this.context) {\n\t\t\tthis.popupController?.toggle(btn, item, this.context);\n\t\t} else {\n\t\t\tthis.context?.executeCommand(item.command);\n\t\t}\n\t}\n\n\t// --- Layout Rendering ---\n\n\tprivate renderItemsByLayout(): void {\n\t\tif (!this.context || !this.toolbarElement || !this.layoutConfig) return;\n\n\t\tconst toolbarReg = this.context.getToolbarRegistry();\n\t\tlet firstGroup = true;\n\n\t\tfor (const groupPluginIds of this.layoutConfig.groups) {\n\t\t\tconst groupItems: ToolbarItem[] = [];\n\t\t\tfor (const pId of groupPluginIds) {\n\t\t\t\tconst items: ToolbarItem[] = toolbarReg\n\t\t\t\t\t.getToolbarItemsByPlugin(pId)\n\t\t\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\t\t\tgroupItems.push(...items);\n\t\t\t}\n\n\t\t\tif (groupItems.length === 0) continue;\n\n\t\t\tif (!firstGroup) {\n\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t}\n\t\t\tfirstGroup = false;\n\n\t\t\tfor (const item of groupItems) {\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\t\t\t}\n\t\t}\n\n\t\tif (this.buttons.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t}\n\n\tprivate renderItemsByGroup(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tconst toolbarRegistry = this.context.getToolbarRegistry();\n\t\tconst items: ToolbarItem[] = toolbarRegistry\n\t\t\t.getToolbarItems()\n\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\tif (items.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\treturn;\n\t\t}\n\n\t\tconst groups = new Map<string, ToolbarItem[]>();\n\t\tfor (const item of items) {\n\t\t\tconst list: ToolbarItem[] = groups.get(item.group) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroups.set(item.group, list);\n\t\t}\n\n\t\tlet firstGroup = true;\n\t\tfor (const [, groupItems] of groups) {\n\t\t\tif (!firstGroup) {\n\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t}\n\t\t\tfirstGroup = false;\n\n\t\t\tfor (const item of groupItems) {\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Button Creation ---\n\n\tprivate createButton(item: ToolbarItem): ToolbarButton {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = `notectl-toolbar-btn notectl-toolbar-btn--${item.id}`;\n\t\tbtn.setAttribute('aria-pressed', 'false');\n\t\tbtn.setAttribute('aria-label', item.label);\n\t\tbtn.setAttribute('data-toolbar-item', item.id);\n\t\tbtn.setAttribute('data-tooltip', item.tooltip ?? item.label);\n\n\t\tlet comboLabelEl: HTMLSpanElement | null = null;\n\n\t\tif (item.popupType === 'combobox') {\n\t\t\tbtn.setAttribute('role', 'combobox');\n\t\t\tbtn.setAttribute('aria-haspopup', 'listbox');\n\t\t\tbtn.setAttribute('aria-expanded', 'false');\n\n\t\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tlabelSpan.className = 'notectl-toolbar-combobox__label';\n\t\t\tconst state: EditorState | undefined = this.context?.getState();\n\t\t\tif (state) {\n\t\t\t\tlabelSpan.textContent = item.getLabel(state);\n\t\t\t}\n\t\t\tbtn.appendChild(labelSpan);\n\t\t\tcomboLabelEl = labelSpan;\n\n\t\t\tconst arrowSpan: HTMLSpanElement = document.createElement('span');\n\t\t\tarrowSpan.className = 'notectl-toolbar-combobox__arrow';\n\t\t\tarrowSpan.setAttribute('aria-hidden', 'true');\n\t\t\tarrowSpan.textContent = '\\u25BE';\n\t\t\tbtn.appendChild(arrowSpan);\n\t\t} else {\n\t\t\tif (item.popupType) {\n\t\t\t\tbtn.setAttribute('aria-haspopup', 'true');\n\t\t\t\tbtn.setAttribute('aria-expanded', 'false');\n\t\t\t}\n\n\t\t\tconst span: HTMLSpanElement = document.createElement('span');\n\t\t\tspan.className = 'notectl-toolbar-btn__icon';\n\t\t\tspan.innerHTML = item.icon;\n\t\t\tbtn.appendChild(span);\n\t\t}\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tthis.activateButton(btn, item);\n\t\t});\n\n\t\tbtn.addEventListener('mouseenter', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('mouseleave', () => this.tooltip?.hide());\n\t\tbtn.addEventListener('focus', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('blur', () => this.tooltip?.hide());\n\n\t\treturn { element: btn, item, comboLabelEl };\n\t}\n\n\t// --- Button State Updates ---\n\n\tprivate updateButtonStates(state: EditorState): void {\n\t\tfor (const btn of this.buttons) {\n\t\t\tconst active: boolean = btn.item.isActive?.(state) ?? false;\n\t\t\tconst enabled: boolean = btn.item.isEnabled?.(state) ?? true;\n\t\t\tbtn.element.setAttribute('aria-pressed', String(active));\n\t\t\tbtn.element.classList.toggle('notectl-toolbar-btn--active', active);\n\t\t\tbtn.element.disabled = !enabled;\n\t\t\tif (!enabled) {\n\t\t\t\tbtn.element.setAttribute('aria-disabled', 'true');\n\t\t\t} else {\n\t\t\t\tbtn.element.removeAttribute('aria-disabled');\n\t\t\t}\n\t\t\tif (btn.comboLabelEl && btn.item.popupType === 'combobox') {\n\t\t\t\tbtn.comboLabelEl.textContent = btn.item.getLabel(state);\n\t\t\t}\n\t\t\tif (btn.item.getIcon) {\n\t\t\t\tconst newIcon: string = btn.item.getIcon(state);\n\t\t\t\tconst iconEl: HTMLSpanElement | null = btn.element.querySelector(\n\t\t\t\t\t'.notectl-toolbar-btn__icon',\n\t\t\t\t);\n\t\t\t\tif (iconEl && iconEl.innerHTML !== newIcon) {\n\t\t\t\t\ticonEl.innerHTML = newIcon;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.overflowController?.updateItemStates(state);\n\t}\n}\n","/** Toolbar styles — buttons, separators, tooltips, popups, dropdowns. */\nexport const TOOLBAR_CSS = `\n/* Toolbar */\n.notectl-plugin-container--top {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\tborder-bottom: 1px solid var(--notectl-border);\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n\tmin-height: 40px;\n}\n\n.notectl-toolbar {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n\tflex: 1;\n\tmin-width: 0;\n\tgap: 2px;\n\tpadding: 4px 8px;\n}\n\n.notectl-toolbar[hidden] {\n\tdisplay: none;\n}\n\n.notectl-toolbar-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-active-bg);\n\tborder-color: var(--notectl-primary-muted);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-toolbar-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n.notectl-toolbar-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:disabled:hover {\n\t\tbackground: transparent;\n\t\tborder-color: transparent;\n\t}\n}\n\n.notectl-toolbar-btn__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpointer-events: none;\n}\n\n.notectl-toolbar-btn__icon svg {\n\tdisplay: block;\n\twidth: 18px;\n\theight: 18px;\n\tfill: currentColor;\n}\n\n/* Tooltip (rendered as fixed-position element in shadow root) */\n.notectl-toolbar-tooltip {\n\tposition: fixed;\n\tpadding: 4px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 10001;\n\tline-height: 1.4;\n\tletter-spacing: 0.01em;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.notectl-toolbar-separator {\n\tdisplay: inline-block;\n\twidth: 1px;\n\theight: 20px;\n\tbackground: var(--notectl-border);\n\tmargin: 0 4px;\n\tvertical-align: middle;\n}\n\n/* Toolbar Popups */\n.notectl-toolbar-popup {\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbox-shadow: 0 4px 12px var(--notectl-shadow);\n\toverflow: hidden;\n}\n\n/* Grid Picker */\n.notectl-grid-picker__cell:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-grid-picker__cell--highlighted {\n\tbackground: var(--notectl-primary-muted);\n\tborder-color: var(--notectl-primary);\n}\n\n/* Dropdown */\n.notectl-dropdown {\n\tmin-width: 160px;\n\tpadding: 4px 0;\n}\n\n.notectl-dropdown__item {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\tfont-family: inherit;\n\twhite-space: nowrap;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-dropdown__item:focus-visible {\n\tbackground: var(--notectl-hover-bg);\n\toutline: none;\n}\n\n.notectl-dropdown__item-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-fg-muted);\n\tflex-shrink: 0;\n}\n\n.notectl-dropdown__item-label {\n\tflex: 1;\n}\n\n/* Overflow behavior: flow mode — toolbar wraps to additional rows */\n.notectl-toolbar[data-overflow=\"flow\"] {\n\tflex-wrap: wrap;\n\toverflow: visible;\n}\n\n/* Overflow behavior: none — toolbar clips without any responsive behavior */\n.notectl-toolbar[data-overflow=\"none\"] {\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n}\n\n/* Overflow: hidden items (burger-menu mode) */\n.notectl-toolbar-btn--overflow-hidden,\n.notectl-toolbar-separator--overflow-hidden {\n\tdisplay: none;\n}\n\n/* Overflow \"more\" button */\n.notectl-toolbar-overflow-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\tmargin-inline-start: auto;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-overflow-btn:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-overflow-btn--hidden {\n\tdisplay: none;\n}\n\n.notectl-toolbar-overflow-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n/* Dropdown item states shared by all dropdown menus (including overflow) */\n.notectl-dropdown__item:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:disabled:hover {\n\t\tbackground: none;\n\t}\n}\n\n.notectl-dropdown__item--active {\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-dropdown__item-icon svg {\n\tdisplay: block;\n\twidth: 16px;\n\theight: 16px;\n\tfill: currentColor;\n}\n\n.notectl-dropdown__separator {\n\theight: 1px;\n\tbackground: var(--notectl-border);\n\tmargin: 4px 0;\n}\n\n/* Combobox-style toolbar buttons (shared base for font, fontSize, heading, etc.) */\n.notectl-toolbar-btn[role=\"combobox\"] {\n\twidth: auto;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn[role=\"combobox\"]:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-fg-muted);\n\t}\n}\n\n.notectl-toolbar-btn[role=\"combobox\"].notectl-toolbar-btn--active {\n\tbackground: var(--notectl-bg);\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-combobox__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: start;\n\tline-height: 30px;\n}\n\n.notectl-toolbar-combobox__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Link Popup */\n.notectl-link-popup {\n\tpadding: 8px;\n\tmin-width: 200px;\n}\n\n.notectl-link-popup__input {\n\twidth: 100%;\n\tpadding: 4px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg);\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-link-popup__input:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-link-popup__button {\n\twidth: 100%;\n\tpadding: 6px 12px;\n\tcursor: pointer;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n\tcolor: var(--notectl-fg);\n\tfont-size: 13px;\n}\n\n.notectl-link-popup__button--apply {\n\tmargin-top: 4px;\n}\n\n@media (hover: hover) {\n\t.notectl-link-popup__button:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-link-popup__button:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n`;\n"],"names":["ToolbarRegistry","_toolbarItems","Map","_toolbarItemPluginMap","registerToolbarItem","item","pluginId","this","has","id","Error","set","ids","get","push","getToolbarItemsByPlugin","items","getToolbarItem","getToolbarItems","values","removeToolbarItem","delete","idx","indexOf","splice","length","clear","findFirstEnabled","buttons","i","disabled","TOOLBAR_LOCALE_EN","formattingOptionsAria","moreToolsAria","gridPickerLabel","rows","cols","localeModules","assign","import","async","loadToolbarLocale","lang","loader","default","ToolbarOverflowBehavior","BurgerMenu","Flow","None","HIDDEN_BTN_CLASS","HIDDEN_SEP_CLASS","ToolbarOverflowController","toolbar","context","onOverflowChange","onItemActivated","getActiveElement","ariaLabel","popupManager","entries","overflowButton","overflowDropdown","overflowHandle","overflowEntries","resizeObserver","closeHandler","closeHandlerTimer","closeHandlerAttached","constructor","config","ResizeObserver","recalculate","observe","update","map","b","element","closeDropdown","resetVisibility","ensureOverflowButton","setOverflowButtonVisible","availableWidth","measureAvailableWidth","children","Array","from","childWidths","measureChildWidths","maxWidth","usedWidth","overflowing","overflowList","child","classList","contains","add","sepWidth","entry","find","oe","btnWidth","hideTrailingSeparators","notifyChange","updateItemStates","state","menuItems","querySelectorAll","menuItem","itemId","getAttribute","active","isActive","enabled","isEnabled","toggle","popupType","labelEl","querySelector","textContent","getLabel","getIcon","newIcon","iconEl","innerHTML","destroy","disconnect","remove","widths","offsetWidth","toolbarStyle","getComputedStyle","paddingLeft","Number","parseFloat","paddingRight","clientWidth","separators","sep","visible","removeAttribute","btn","document","createElement","type","className","setAttribute","addEventListener","e","preventDefault","toggleDropdown","appendChild","openDropdown","dropdown","renderDropdownItems","getState","open","anchor","ariaRole","position","referenceNode","restoreFocusTo","onClose","content","popup","handleDropdownKeydown","positionDropdown","appendToRoot","requestAnimationFrame","first","focus","registerCloseHandler","lastGroup","group","menuBtn","iconSpan","icon","labelSpan","tooltip","label","ev","stopPropagation","activateOverflowItem","rect","getBoundingClientRect","isRtlContext","setStyleProperties","top","bottom","left","right","zIndex","rightEdge","window","innerWidth","path","composedPath","includes","setTimeout","handle","close","clearTimeout","removeEventListener","executeCommand","command","key","current","next","findNextDropdownItem","prev","focusedItem","filter","highlightCells","grid","targetRow","targetCol","cells","cell","r","c","createSeparator","ToolbarPopupController","activePopup","activePopupButton","activeHandle","locale","setPopupManager","manager","isOpen","button","openViaManager","clearButtonState","closeAndRestoreFocus","triggerBtn","renderPopupContent","handlePopupKeydown","closeAndFocusEditor","getContainer","container","display","gridTemplateColumns","maxCols","gap","padding","textAlign","fontSize","maxRows","width","height","border","cursor","String","onSelect","renderGridPicker","popupConfig","cmd","renderDropdown","renderPopup","handleGridKeydown","handleCustomPopupKeydown","itemArr","focused","click","row","col","lastCell","newRow","newCol","navigateGrid","target","currentIdx","dispatchEvent","MouseEvent","bubbles","cancelable","ToolbarTooltip","timer","isPopupActive","static","TOOLTIP_ID","setStyleProperty","show","hide","text","root","getRootNode","ShadowRoot","parentNode","body","transform","ToolbarServiceKey","ServiceKey","ToolbarPlugin","name","priority","toolbarElement","hiddenItems","Set","layoutConfig","overflowBehavior","focusedIndex","popupController","overflowController","visibleElements","overflow","init","resolveLocale","registerStyleSheet","PopupManager","registerService","PopupServiceKey","refresh","updateButtonStates","closePopup","createToolbarElement","getOverflowBehavior","setOverflowBehavior","behavior","applyOverflowBehavior","renderItems","onReady","onStateChange","_oldState","newState","_tr","onReadOnlyChange","readonly","hidden","onConfigure","value","Object","getPluginContainer","handleToolbarKeydown","visibleButtons","overflowBtn","initRovingTabindex","activateButton","renderItemsByLayout","renderItemsByGroup","parentElement","getTabElements","elements","applyRovingTabindex","setRovingFocus","index","activeElement","syncFocusedIndex","findIndex","el","isRtl","dir","direction","len","findNextEnabled","last","findLastEnabled","toolbarReg","getToolbarRegistry","firstGroup","groupPluginIds","groups","groupItems","pId","createButton","list","comboLabelEl","arrowSpan","span"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{AlignmentPlugin as i}from"../plugins/alignment.mjs";import{BlockquotePlugin as o}from"../plugins/blockquote.mjs";import{CodeBlockPlugin as t}from"../plugins/code-block.mjs";import{FontSizePlugin as m}from"../plugins/font-size.mjs";import{FontPlugin as n}from"../plugins/font.mjs";import{HardBreakPlugin as r}from"../plugins/hard-break.mjs";import{a as s}from"../chunks/HeadingPlugin-B-LF-AMM.mjs";import{HighlightPlugin as e}from"../plugins/highlight.mjs";import{HorizontalRulePlugin as p}from"../plugins/horizontal-rule.mjs";import{ImagePlugin as l}from"../plugins/image.mjs";import{LinkPlugin as g}from"../plugins/link.mjs";import{ListPlugin as u}from"../plugins/list.mjs";import{PrintPlugin as f}from"../plugins/print.mjs";import{SmartPastePlugin as a}from"../plugins/smart-paste.mjs";import{StrikethroughPlugin as j}from"../plugins/strikethrough.mjs";import{SuperSubPlugin as w}from"../plugins/super-sub.mjs";import{TablePlugin as h}from"../plugins/table.mjs";import{TextColorPlugin as c}from"../plugins/text-color.mjs";import{TextDirectionPlugin as k}from"../plugins/text-direction.mjs";import{TextFormattingPlugin as b}from"../plugins/text-formatting.mjs";function x(x){return{toolbar:[[new n({fonts:[],...x?.font}),new m(x?.fontSize)],[new b(x?.textFormatting),new j(x?.strikethrough),new w(x?.superSub)],[new c(x?.textColor),new e(x?.highlight)],[new s(x?.heading),new o(x?.blockquote),new t(x?.codeBlock)],[new i(x?.alignment),new k(x?.textDirection)],[new u(x?.list)],[new g(x?.link),new h(x?.table),new p(x?.horizontalRule),new l(x?.image)],[new f(x?.print)]],plugins:[new r,new a(x?.smartPaste)]}}export{x as createFullPreset};
1
+ import{AlignmentPlugin as i}from"../plugins/alignment.mjs";import{BlockquotePlugin as o}from"../plugins/blockquote.mjs";import{CodeBlockPlugin as t}from"../plugins/code-block.mjs";import{FontSizePlugin as m}from"../plugins/font-size.mjs";import{FontPlugin as n}from"../plugins/font.mjs";import{HardBreakPlugin as r}from"../plugins/hard-break.mjs";import{a as s}from"../chunks/HeadingPlugin-BmkeUXj8.mjs";import{HighlightPlugin as e}from"../plugins/highlight.mjs";import{HorizontalRulePlugin as p}from"../plugins/horizontal-rule.mjs";import{ImagePlugin as l}from"../plugins/image.mjs";import{LinkPlugin as g}from"../plugins/link.mjs";import{ListPlugin as u}from"../plugins/list.mjs";import{PrintPlugin as f}from"../plugins/print.mjs";import{SmartPastePlugin as a}from"../plugins/smart-paste.mjs";import{StrikethroughPlugin as j}from"../plugins/strikethrough.mjs";import{SuperSubPlugin as w}from"../plugins/super-sub.mjs";import{TablePlugin as h}from"../plugins/table.mjs";import{TextColorPlugin as c}from"../plugins/text-color.mjs";import{TextDirectionPlugin as k}from"../plugins/text-direction.mjs";import{TextFormattingPlugin as b}from"../plugins/text-formatting.mjs";function x(x){return{toolbar:[[new n({fonts:[],...x?.font}),new m(x?.fontSize)],[new b(x?.textFormatting),new j(x?.strikethrough),new w(x?.superSub)],[new c(x?.textColor),new e(x?.highlight)],[new s(x?.heading),new o(x?.blockquote),new t(x?.codeBlock)],[new i(x?.alignment),new k(x?.textDirection)],[new u(x?.list)],[new g(x?.link),new h(x?.table),new p(x?.horizontalRule),new l(x?.image)],[new f(x?.print)]],plugins:[new r,new a(x?.smartPaste)]}}export{x as createFullPreset};
2
2
  //# sourceMappingURL=full.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"StepInversion.d.ts","sourceRoot":"","sources":["../../src/state/StepInversion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AASpD,sCAAsC;AACtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAwH3C;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,GAAG,WAAW,CAW9D"}
1
+ {"version":3,"file":"StepInversion.d.ts","sourceRoot":"","sources":["../../src/state/StepInversion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AASpD,sCAAsC;AACtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAwH3C;AAWD,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,GAAG,WAAW,CAW9D"}
@@ -25,37 +25,27 @@ export declare class EditorView {
25
25
  private readonly contentElement;
26
26
  readonly history: HistoryManager;
27
27
  private readonly stateChangeCallbacks;
28
- private readonly handleSelectionChange;
29
- private readonly handleMousedown;
30
- private readonly handleDragover;
31
- private readonly handleDrop;
32
- private readonly handleCompositionStartForWrapper;
33
- private readonly handleCompositionEndForWrapper;
34
28
  private isUpdating;
35
- private pendingNodeSelectionClear;
36
- private pendingGapCursorClear;
37
29
  private readonly schemaRegistry?;
38
- private readonly keymapRegistry?;
39
- private readonly fileHandlerRegistry?;
40
30
  private readonly nodeViewRegistry?;
41
31
  private readonly nodeViews;
42
32
  private decorations;
43
33
  private readonly getDecorations?;
44
34
  private readonly isReadOnly;
45
- private navigationKeymap;
46
35
  private readonly compositionState;
47
36
  private readonly cursorWrapper;
48
- private goalColumn;
49
- private preserveGoalColumn;
37
+ private readonly navigation;
38
+ private readonly events;
50
39
  constructor(contentElement: HTMLElement, options: EditorViewOptions);
51
40
  /** Returns the current editor state. */
52
41
  getState(): EditorState;
53
42
  /**
54
- * Central update cycle: sets state, collects decorations, reconciles DOM,
55
- * syncs selection, and notifies listeners. Guarded against re-entrancy.
43
+ * Central update cycle: sets state, collects decorations, reconciles
44
+ * DOM, syncs selection, and notifies listeners.
45
+ * Guarded against re-entrancy.
56
46
  */
57
47
  private applyUpdate;
58
- /** Dispatches a transaction, updates state, reconciles DOM, syncs selection. */
48
+ /** Dispatches a transaction, updates state, reconciles DOM. */
59
49
  dispatch(tr: Transaction): void;
60
50
  /** Performs undo. */
61
51
  undo(): void;
@@ -65,51 +55,11 @@ export declare class EditorView {
65
55
  onStateChange(callback: StateChangeCallback): () => void;
66
56
  /** Replaces the editor state without destroying handlers or history. */
67
57
  replaceState(newState: EditorState): void;
68
- /** Syncs the DOM selection to the editor state. */
69
- private syncSelectionFromDOM;
70
- /** Handles mousedown on selectable/void blocks to create NodeSelection. */
71
- private onMousedown;
72
- /**
73
- * When the user clicks in empty space below all rendered blocks,
74
- * appends a new paragraph after the last block and focuses it.
75
- */
76
- private handleClickBelowContent;
77
- /** Allows file drop by preventing default on dragover when files are present. */
78
- private onDragover;
79
- /** Handles file drop by delegating to registered file handlers. */
80
- private onDrop;
81
- /** Converts screen coordinates to an editor Position. */
82
- private getPositionFromPoint;
83
- /** Handles DOM selection changes (clicks, arrow keys). */
84
- private onSelectionChange;
58
+ /** Syncs the DOM selection into editor state. */
59
+ syncSelection(): void;
85
60
  /** Reconciles DOM and syncs selection, updating decoration state. */
86
61
  private reconcileAndSync;
87
62
  private reconcileOptions;
88
- /** Registers arrow-key keymaps with navigation priority for cross-block movement. */
89
- private registerNavigationKeymaps;
90
- /** Handles a navigation arrow key: cross-block movement if at textblock boundary. */
91
- private handleNavigationArrow;
92
- /** Handles horizontal arrow navigation: InlineNode skip + cross-block. */
93
- private handleHorizontalArrow;
94
- /**
95
- * Maps visual horizontal arrow intent (left/right key) to logical movement
96
- * direction in offset space for the current block direction.
97
- */
98
- private resolveLogicalHorizontalDirection;
99
- /** Handles vertical arrow navigation with goalColumn preservation. */
100
- private handleVerticalArrow;
101
- /**
102
- * Validates the DOM cursor position after an InlineNode skip.
103
- *
104
- * Chrome can place the cursor inside a `contenteditable="false"` element
105
- * (phantom position), and Firefox may lose the cursor entirely next to such
106
- * elements. This read-back roundtrip detects drift between the model
107
- * selection and the actual DOM selection. If they diverge, we force
108
- * `syncSelectionToDOM()` a second time to correct the position.
109
- */
110
- private validateSelectionAfterInlineSkip;
111
- /** Syncs the DOM selection into editor state. Exposed for external callers. */
112
- syncSelection(): void;
113
63
  /** Cleans up all event listeners and handlers. */
114
64
  destroy(): void;
115
65
  }