@jimka/typescript-ui 0.5.0 → 0.6.0

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 (252) hide show
  1. package/dist/lib/{AbstractInput-B10DfLOf.js → AbstractInput-sRNPzWel.js} +2 -2
  2. package/dist/lib/{AbstractInput-B10DfLOf.js.map → AbstractInput-sRNPzWel.js.map} +1 -1
  3. package/dist/lib/Anchor-CwRhdP2J.js +2 -0
  4. package/dist/lib/Anchor-CwRhdP2J.js.map +1 -0
  5. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js +2 -0
  6. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js.map +1 -0
  7. package/dist/lib/Border-0DJFDiij.js +2 -0
  8. package/dist/lib/Border-0DJFDiij.js.map +1 -0
  9. package/dist/lib/Button-MpMIYBYJ.js +2 -0
  10. package/dist/lib/Button-MpMIYBYJ.js.map +1 -0
  11. package/dist/lib/{Card-CD3jxshU.js → Card-QYo27r5b.js} +2 -2
  12. package/dist/lib/{Card-CD3jxshU.js.map → Card-QYo27r5b.js.map} +1 -1
  13. package/dist/lib/Checkbox-D0JYK-wc.js +2 -0
  14. package/dist/lib/Checkbox-D0JYK-wc.js.map +1 -0
  15. package/dist/lib/CheckboxMenuRow-CesLhSnp.js +2 -0
  16. package/dist/lib/CheckboxMenuRow-CesLhSnp.js.map +1 -0
  17. package/dist/lib/{CodeEditor-BGlB232h.js → CodeEditor-N1FQodcF.js} +2 -2
  18. package/dist/lib/CodeEditor-N1FQodcF.js.map +1 -0
  19. package/dist/lib/ComboBox-Dx8Tk9yg.js +2 -0
  20. package/dist/lib/ComboBox-Dx8Tk9yg.js.map +1 -0
  21. package/dist/lib/Component-B0ShfPVi.js +2 -0
  22. package/dist/lib/Component-B0ShfPVi.js.map +1 -0
  23. package/dist/lib/Container-abY5Ww3W.js +2 -0
  24. package/dist/lib/{Container-C7RPLQEc.js.map → Container-abY5Ww3W.js.map} +1 -1
  25. package/dist/lib/{DOM-Ba8YRVel.js → DOM-C-Edb3tA.js} +2 -2
  26. package/dist/lib/DOM-C-Edb3tA.js.map +1 -0
  27. package/dist/lib/Dialog-cbA9V17e.js +2 -0
  28. package/dist/lib/Dialog-cbA9V17e.js.map +1 -0
  29. package/dist/lib/{FieldDecorator-HG65hEtk.js → FieldDecorator-BlYMfZ9L.js} +2 -2
  30. package/dist/lib/{FieldDecorator-HG65hEtk.js.map → FieldDecorator-BlYMfZ9L.js.map} +1 -1
  31. package/dist/lib/{Fit-Cg3dPyZg.js → Fit-BhlB-HAo.js} +2 -2
  32. package/dist/lib/{Fit-Cg3dPyZg.js.map → Fit-BhlB-HAo.js.map} +1 -1
  33. package/dist/lib/{FloatingPanel-D5buuVrQ.js → FloatingPanel-DkJXsZ2D.js} +2 -2
  34. package/dist/lib/{FloatingPanel-D5buuVrQ.js.map → FloatingPanel-DkJXsZ2D.js.map} +1 -1
  35. package/dist/lib/{Glyph-DeJF_zsR.js → Glyph-_VeBacS2.js} +2 -2
  36. package/dist/lib/{Glyph-DeJF_zsR.js.map → Glyph-_VeBacS2.js.map} +1 -1
  37. package/dist/lib/{Grid-BYBohJIA.js → Grid-Daiz7F5d.js} +2 -2
  38. package/dist/lib/Grid-Daiz7F5d.js.map +1 -0
  39. package/dist/lib/GridConstraints-C58LuTqM.js +2 -0
  40. package/dist/lib/{GridConstraints-Bts284FI.js.map → GridConstraints-C58LuTqM.js.map} +1 -1
  41. package/dist/lib/{Header-BIFJK9nR.js → Header-Dql3Zxc6.js} +2 -2
  42. package/dist/lib/{Header-BIFJK9nR.js.map → Header-Dql3Zxc6.js.map} +1 -1
  43. package/dist/lib/{IconText-Dsb1xS-E.js → IconText-PUjhTLlp.js} +2 -2
  44. package/dist/lib/{IconText-Dsb1xS-E.js.map → IconText-PUjhTLlp.js.map} +1 -1
  45. package/dist/lib/LayoutSerialization-CMxunLfV.js +2 -0
  46. package/dist/lib/LayoutSerialization-CMxunLfV.js.map +1 -0
  47. package/dist/lib/List-nx8220Fi.js +2 -0
  48. package/dist/lib/{List-BPd-IXZR.js.map → List-nx8220Fi.js.map} +1 -1
  49. package/dist/lib/MemoryStore-DhPoU-7X.js +2 -0
  50. package/dist/lib/MemoryStore-DhPoU-7X.js.map +1 -0
  51. package/dist/lib/Menu-Q0bpXXze.js +2 -0
  52. package/dist/lib/Menu-Q0bpXXze.js.map +1 -0
  53. package/dist/lib/{MenuButton-BR4KOFld.js → MenuButton-DCXi0tsP.js} +2 -2
  54. package/dist/lib/{MenuButton-BR4KOFld.js.map → MenuButton-DCXi0tsP.js.map} +1 -1
  55. package/dist/lib/OverlayFade-3pof2AJH.js +2 -0
  56. package/dist/lib/OverlayFade-3pof2AJH.js.map +1 -0
  57. package/dist/lib/{Panel-CpNQTLNF.js → Panel-Cy1pdlWO.js} +2 -2
  58. package/dist/lib/{Panel-CpNQTLNF.js.map → Panel-Cy1pdlWO.js.map} +1 -1
  59. package/dist/lib/{Position-PBVBW1JS.js → Position-BwtxouxK.js} +2 -2
  60. package/dist/lib/{Position-PBVBW1JS.js.map → Position-BwtxouxK.js.map} +1 -1
  61. package/dist/lib/{ProgressSpinner-lAsK26C-.js → ProgressSpinner-DK8xEQ9y.js} +2 -2
  62. package/dist/lib/{ProgressSpinner-lAsK26C-.js.map → ProgressSpinner-DK8xEQ9y.js.map} +1 -1
  63. package/dist/lib/RadioButton-BEwpqg1k.js +2 -0
  64. package/dist/lib/{RadioButton-CCcIaL54.js.map → RadioButton-BEwpqg1k.js.map} +1 -1
  65. package/dist/lib/RadioMenuRow-DP5qPyFR.js +2 -0
  66. package/dist/lib/RadioMenuRow-DP5qPyFR.js.map +1 -0
  67. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js → RovingTabIndex-pHEv5oLD.js} +2 -2
  68. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js.map → RovingTabIndex-pHEv5oLD.js.map} +1 -1
  69. package/dist/lib/Scrollbar-t8fFrUVQ.js +2 -0
  70. package/dist/lib/Scrollbar-t8fFrUVQ.js.map +1 -0
  71. package/dist/lib/{Slider-DZ9drUxn.js → Slider-CTbwR6HR.js} +2 -2
  72. package/dist/lib/{Slider-DZ9drUxn.js.map → Slider-CTbwR6HR.js.map} +1 -1
  73. package/dist/lib/{Spacer-SDhOMp2g.js → Spacer-srdN2d2b.js} +2 -2
  74. package/dist/lib/{Spacer-SDhOMp2g.js.map → Spacer-srdN2d2b.js.map} +1 -1
  75. package/dist/lib/TabButton-DLoMQzky.js +2 -0
  76. package/dist/lib/TabButton-DLoMQzky.js.map +1 -0
  77. package/dist/lib/TabCloseButton-CY7BGitY.js +2 -0
  78. package/dist/lib/TabCloseButton-CY7BGitY.js.map +1 -0
  79. package/dist/lib/{Text-CdHf3B-1.js → Text-CMKnK9uB.js} +2 -2
  80. package/dist/lib/{Text-CdHf3B-1.js.map → Text-CMKnK9uB.js.map} +1 -1
  81. package/dist/lib/{Tooltip-B_UF5bXD.js → Tooltip-CUOJOqQi.js} +3 -3
  82. package/dist/lib/Tooltip-CUOJOqQi.js.map +1 -0
  83. package/dist/lib/Tree-C64JNPWJ.js +2 -0
  84. package/dist/lib/Tree-C64JNPWJ.js.map +1 -0
  85. package/dist/lib/VBox-DfJPWXqc.js +2 -0
  86. package/dist/lib/VBox-DfJPWXqc.js.map +1 -0
  87. package/dist/lib/VirtualScroller-DTIn19o1.js +2 -0
  88. package/dist/lib/VirtualScroller-DTIn19o1.js.map +1 -0
  89. package/dist/lib/assets/StoreWorker-B5NwRM2I.js +2 -0
  90. package/dist/lib/assets/StoreWorker-B5NwRM2I.js.map +1 -0
  91. package/dist/lib/component/button.es.js +1 -1
  92. package/dist/lib/component/button.es.js.map +1 -1
  93. package/dist/lib/component/chart.es.js +1 -1
  94. package/dist/lib/component/container.es.js +1 -1
  95. package/dist/lib/component/container.es.js.map +1 -1
  96. package/dist/lib/component/diagram.es.js +1 -1
  97. package/dist/lib/component/diagram.es.js.map +1 -1
  98. package/dist/lib/component/display.es.js +1 -1
  99. package/dist/lib/component/display.es.js.map +1 -1
  100. package/dist/lib/component/editor.es.js +2 -2
  101. package/dist/lib/component/editor.es.js.map +1 -1
  102. package/dist/lib/component/input.es.js +1 -1
  103. package/dist/lib/component/input.es.js.map +1 -1
  104. package/dist/lib/component/list.es.js +1 -1
  105. package/dist/lib/component/list.es.js.map +1 -1
  106. package/dist/lib/component/menubar.es.js +1 -1
  107. package/dist/lib/component/menubar.es.js.map +1 -1
  108. package/dist/lib/component/table.es.js +6 -3
  109. package/dist/lib/component/table.es.js.map +1 -1
  110. package/dist/lib/component/tree.es.js +1 -1
  111. package/dist/lib/core.es.js +1 -1
  112. package/dist/lib/core.es.js.map +1 -1
  113. package/dist/lib/data.es.js +1 -1
  114. package/dist/lib/glyphs/solid/index.es.js +1 -1
  115. package/dist/lib/layout.es.js +1 -1
  116. package/dist/lib/layout.es.js.map +1 -1
  117. package/dist/lib/overlay.es.js +1 -1
  118. package/dist/lib/overlay.es.js.map +1 -1
  119. package/dist/lib/primitive.es.js +1 -1
  120. package/dist/lib/router.es.js +1 -1
  121. package/dist/lib/router.es.js.map +1 -1
  122. package/dist/lib/selectionsEqual-gMG7gCVI.js +2 -0
  123. package/dist/lib/selectionsEqual-gMG7gCVI.js.map +1 -0
  124. package/dist/lib/types/component/button/Button.d.ts +13 -0
  125. package/dist/lib/types/component/button/MenuButton.d.ts +1 -0
  126. package/dist/lib/types/component/button/PopupButton.d.ts +22 -0
  127. package/dist/lib/types/component/button/TabButton.d.ts +4 -0
  128. package/dist/lib/types/component/button/index.d.ts +2 -0
  129. package/dist/lib/types/component/container/CheckboxMenuRow.d.ts +33 -0
  130. package/dist/lib/types/component/container/CollapseButton.d.ts +11 -3
  131. package/dist/lib/types/component/container/MenuItem.d.ts +15 -5
  132. package/dist/lib/types/component/container/MenuRow.d.ts +24 -0
  133. package/dist/lib/types/component/container/MenuSeparator.d.ts +4 -2
  134. package/dist/lib/types/component/container/RadioMenuRow.d.ts +33 -0
  135. package/dist/lib/types/component/container/Scrollbar.d.ts +5 -0
  136. package/dist/lib/types/component/container/SplitGutter.d.ts +7 -2
  137. package/dist/lib/types/component/container/TabBar.d.ts +2 -0
  138. package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
  139. package/dist/lib/types/component/container/index.d.ts +6 -1
  140. package/dist/lib/types/component/display/WebGLCanvas.d.ts +1 -0
  141. package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +2 -0
  142. package/dist/lib/types/component/input/AbstractPickerField.d.ts +3 -2
  143. package/dist/lib/types/component/list/AbstractSelectableList.d.ts +1 -1
  144. package/dist/lib/types/component/list/MultiSelectList.d.ts +2 -1
  145. package/dist/lib/types/component/shared/VirtualRowView.d.ts +2 -0
  146. package/dist/lib/types/component/table/Body.d.ts +22 -1
  147. package/dist/lib/types/component/table/Column.d.ts +3 -1
  148. package/dist/lib/types/component/table/ColumnConfig.d.ts +2 -0
  149. package/dist/lib/types/component/table/ColumnFilter.d.ts +27 -0
  150. package/dist/lib/types/component/table/Header.d.ts +30 -3
  151. package/dist/lib/types/component/table/Row.d.ts +4 -0
  152. package/dist/lib/types/component/table/Table.d.ts +29 -0
  153. package/dist/lib/types/component/table/TableExporter.d.ts +4 -3
  154. package/dist/lib/types/component/table/TreeBody.d.ts +2 -1
  155. package/dist/lib/types/component/table/cell/CellText.d.ts +9 -0
  156. package/dist/lib/types/component/table/cell/Filter.d.ts +54 -0
  157. package/dist/lib/types/component/table/cell/FilterClauseBadge.d.ts +21 -0
  158. package/dist/lib/types/component/table/cell/GroupSeparator.d.ts +9 -0
  159. package/dist/lib/types/component/table/cell/Header.d.ts +1 -0
  160. package/dist/lib/types/component/table/cell/editor/CellEditor.d.ts +1 -0
  161. package/dist/lib/types/component/table/cell/renderer/CellRenderer.d.ts +1 -0
  162. package/dist/lib/types/component/table/cell/renderer/Combo.d.ts +2 -0
  163. package/dist/lib/types/component/table/cell/renderer/Date.d.ts +2 -0
  164. package/dist/lib/types/component/table/cell/renderer/DateTime.d.ts +2 -0
  165. package/dist/lib/types/component/table/cell/renderer/Filter.d.ts +16 -0
  166. package/dist/lib/types/component/table/cell/renderer/Glyph.d.ts +1 -0
  167. package/dist/lib/types/component/table/cell/renderer/Link.d.ts +2 -0
  168. package/dist/lib/types/component/table/cell/renderer/Number.d.ts +3 -1
  169. package/dist/lib/types/component/table/cell/renderer/String.d.ts +2 -0
  170. package/dist/lib/types/component/table/cell/renderer/Time.d.ts +2 -0
  171. package/dist/lib/types/component/table/cell/renderer/TreeCell.d.ts +1 -0
  172. package/dist/lib/types/component/table/index.d.ts +6 -0
  173. package/dist/lib/types/component/tree/Tree.d.ts +17 -1
  174. package/dist/lib/types/component/tree/index.d.ts +1 -1
  175. package/dist/lib/types/core/AnimatedDropdown.d.ts +0 -9
  176. package/dist/lib/types/core/Body.d.ts +4 -0
  177. package/dist/lib/types/core/ClassStyleRules.d.ts +1 -0
  178. package/dist/lib/types/core/DOM.d.ts +10 -0
  179. package/dist/lib/types/core/Event.d.ts +11 -2
  180. package/dist/lib/types/core/OverlayFade.d.ts +12 -0
  181. package/dist/lib/types/core/OverlayPosition.d.ts +6 -0
  182. package/dist/lib/types/core/Theme.d.ts +8 -0
  183. package/dist/lib/types/core/index.d.ts +5 -3
  184. package/dist/lib/types/data/AbstractStore.d.ts +3 -0
  185. package/dist/lib/types/data/FilterDescriptor.d.ts +13 -0
  186. package/dist/lib/types/data/index.d.ts +2 -1
  187. package/dist/lib/types/data/temporalText.d.ts +2 -0
  188. package/dist/lib/types/layout/BoxLayout.d.ts +6 -1
  189. package/dist/lib/types/layout/Grid.d.ts +1 -0
  190. package/dist/lib/types/layout/HFlow.d.ts +1 -1
  191. package/dist/lib/types/layout/Split.d.ts +10 -1
  192. package/dist/lib/types/layout/Tab.d.ts +7 -1
  193. package/dist/lib/types/layout/VFlow.d.ts +1 -1
  194. package/dist/lib/types/layout/index.d.ts +1 -1
  195. package/dist/lib/types/overlay/Dock.d.ts +1 -0
  196. package/dist/lib/types/overlay/Menu.d.ts +1 -1
  197. package/dist/lib/types/overlay/Popover.d.ts +3 -0
  198. package/dist/lib/types/overlay/PopupPanel.d.ts +17 -0
  199. package/dist/lib/types/overlay/Window.d.ts +2 -0
  200. package/dist/lib/types/overlay/index.d.ts +2 -0
  201. package/dist/lib/types/router/RoutePattern.d.ts +7 -0
  202. package/dist/lib/types/router/Router.d.ts +6 -2
  203. package/dist/lib/types/router/index.d.ts +1 -1
  204. package/dist/lib/validation.es.js +1 -1
  205. package/llms.txt +4 -0
  206. package/package.json +1 -1
  207. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js +0 -2
  208. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js.map +0 -1
  209. package/dist/lib/Anchor-BsblS5it.js +0 -2
  210. package/dist/lib/Anchor-BsblS5it.js.map +0 -1
  211. package/dist/lib/AnimatedDropdown-kL47HPGP.js +0 -2
  212. package/dist/lib/AnimatedDropdown-kL47HPGP.js.map +0 -1
  213. package/dist/lib/Border-CNS6aEXB.js +0 -2
  214. package/dist/lib/Border-CNS6aEXB.js.map +0 -1
  215. package/dist/lib/Button-T16zSZip.js +0 -2
  216. package/dist/lib/Button-T16zSZip.js.map +0 -1
  217. package/dist/lib/CodeEditor-BGlB232h.js.map +0 -1
  218. package/dist/lib/ComboBox-C9FYMuLv.js +0 -2
  219. package/dist/lib/ComboBox-C9FYMuLv.js.map +0 -1
  220. package/dist/lib/Component-w65rPK75.js +0 -2
  221. package/dist/lib/Component-w65rPK75.js.map +0 -1
  222. package/dist/lib/Container-C7RPLQEc.js +0 -2
  223. package/dist/lib/DOM-Ba8YRVel.js.map +0 -1
  224. package/dist/lib/DragManager-UvPHSoRm.js +0 -2
  225. package/dist/lib/DragManager-UvPHSoRm.js.map +0 -1
  226. package/dist/lib/Grid-BYBohJIA.js.map +0 -1
  227. package/dist/lib/GridConstraints-Bts284FI.js +0 -2
  228. package/dist/lib/LayoutSerialization-ySzY1h2l.js +0 -2
  229. package/dist/lib/LayoutSerialization-ySzY1h2l.js.map +0 -1
  230. package/dist/lib/LayoutSizes-DKDK1Cle.js +0 -2
  231. package/dist/lib/LayoutSizes-DKDK1Cle.js.map +0 -1
  232. package/dist/lib/List-BPd-IXZR.js +0 -2
  233. package/dist/lib/MemoryStore-BgP7-Uzn.js +0 -2
  234. package/dist/lib/MemoryStore-BgP7-Uzn.js.map +0 -1
  235. package/dist/lib/Menu-C0roOCY7.js +0 -2
  236. package/dist/lib/Menu-C0roOCY7.js.map +0 -1
  237. package/dist/lib/RadioButton-CCcIaL54.js +0 -2
  238. package/dist/lib/Scrollbar-C3ZZyZ1e.js +0 -2
  239. package/dist/lib/Scrollbar-C3ZZyZ1e.js.map +0 -1
  240. package/dist/lib/TabButton-DNo4ZgV8.js +0 -2
  241. package/dist/lib/TabButton-DNo4ZgV8.js.map +0 -1
  242. package/dist/lib/Tooltip-B_UF5bXD.js.map +0 -1
  243. package/dist/lib/Tree-C7qLbIYH.js +0 -2
  244. package/dist/lib/Tree-C7qLbIYH.js.map +0 -1
  245. package/dist/lib/VBox-32fxpkDl.js +0 -2
  246. package/dist/lib/VBox-32fxpkDl.js.map +0 -1
  247. package/dist/lib/VirtualScroller-cvFNMS7U.js +0 -2
  248. package/dist/lib/VirtualScroller-cvFNMS7U.js.map +0 -1
  249. package/dist/lib/assets/StoreWorker-CgOBYoai.js +0 -2
  250. package/dist/lib/assets/StoreWorker-CgOBYoai.js.map +0 -1
  251. package/dist/lib/selectionsEqual-BrTxPMmK.js +0 -2
  252. package/dist/lib/selectionsEqual-BrTxPMmK.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"menubar.es.js","names":[],"sources":["../../../src/typescript/lib/component/menubar/MenuBarButton.ts","../../../src/typescript/lib/component/menubar/MenuBar.ts","../../../src/typescript/lib/component/menubar/ToolBar.ts","../../../src/typescript/lib/component/menubar/ToolBarSeparator.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button, ButtonOptions } from \"~/component/button/Button.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link MenuBarButton}.\n *\n * @category Components\n */\nexport interface MenuBarButtonOptions extends ButtonOptions {\n}\n\n/** Horizontal padding inside the button, folded into the defaults bag below. */\nconst HORIZONTAL_PAD = 10;\n\n/**\n * User-overridable visual defaults forwarded to `super` via the third\n * constructor arg. The cascade in `Component`'s constructor merges these\n * over Button's own defaults and dispatches each setter once with the\n * final value, so any field the caller supplied wins.\n */\nconst _defaultMenuBarButtonOptions: Partial<MenuBarButtonOptions> = {\n backgroundColor: \"var(--ts-ui-menu-bar-btn-bg, transparent)\",\n foregroundColor: \"var(--ts-ui-menu-bar-btn-fg, inherit)\",\n cursor: \"pointer\",\n // chromeless suppresses Button's ridge border, drop shadow, gradient\n // background, and the pressed/hover treatments — the menubar wants a flat\n // label-shaped surface.\n chromeless: true,\n // Horizontal padding inside the button — replaces Button's 4-px insets\n // default.\n insets: new Insets(0, HORIZONTAL_PAD, 0, HORIZONTAL_PAD),\n};\n\n/** Pixel gap between the leading glyph and the label in the content row. */\nconst GLYPH_TEXT_GAP = 4;\n\n/**\n * Fixed row height shared by every `MenuBarButton` and by the parent\n * [`MenuBar`](/api/component/menubar/classes/MenuBar) container's `setMinSize`. Exported so the two stay in\n * lockstep — changing one without the other would let the bar grow taller\n * than its buttons.\n */\nexport const MENU_BAR_BUTTON_HEIGHT: number = 28;\n\n/**\n * A single top-level button in a [`MenuBar`](/api/component/menubar/classes/MenuBar) (e.g. \"File\", \"Edit\").\n *\n * Extends [`Button`](/api/component/button/classes/Button) with `chromeless: true`\n * so the menubar's flat label-style appearance dodges Button's ridge border,\n * drop shadow, and gradient defaults. Reuses Button's content-row machinery\n * for the optional leading glyph + label pair, re-anchored to the west edge.\n * Adds menubar-specific ARIA (`role=\"menuitem\"`, `aria-haspopup=\"menu\"`,\n * `aria-expanded`) and the sticky `setActive` highlight for the\n * dropdown-open state. The `:hover` rule rides Button's `styleRules` bag.\n *\n * Communicates open/close intent back to [`MenuBar`](/api/component/menubar/classes/MenuBar) via callbacks passed at\n * construction time.\n *\n * @category Components\n */\nclass MenuBarButton extends Button<MenuBarButtonOptions> {\n\n private readonly _onClickHandler: () => void;\n private readonly _onMouseOverHandler: () => void;\n\n /**\n * Constructs a `MenuBarButton`.\n *\n * @param text - The label shown in the bar (e.g. `\"File\"`).\n * @param onClick - Called when the user clicks this button.\n * @param onHover - Called when the mouse enters this button while a menu is open (quick-switch).\n * @param options - Optional configuration bag. `glyph` is inherited from\n * [`ButtonOptions`](/api/component/button/interfaces/ButtonOptions).\n */\n constructor(\n text: string,\n onClick: () => void,\n onHover: () => void,\n options?: MenuBarButtonOptions,\n subclassDefaults?: Partial<MenuBarButtonOptions>,\n ) {\n super(\n text,\n {\n ...options,\n // Menubar-specific :hover highlight rides Button's styleRules\n // bag so the cascade routes through createStyleRule's\n // dedupe-and-defer machinery. Merge with any caller-supplied\n // styleRules entries via the canonical array-spread idiom.\n styleRules: [\n ...(options?.styleRules ?? []),\n {\n suffix: \":hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-menu-bar-btn-hover-bg, rgba(30, 100, 200, 0.10))\",\n },\n },\n ],\n },\n { ..._defaultMenuBarButtonOptions, ...(subclassDefaults ?? {}) },\n );\n\n // Bump the HBox content-row spacing from Button's default (2) to the\n // menubar's GLYPH_TEXT_GAP (4).\n (this._content.getLayoutManager() as HBox).setComponentSpacing(GLYPH_TEXT_GAP);\n\n this.getAria().setRole(\"menuitem\");\n this.getAria().setHasPopup(\"menu\");\n this.getAria().setExpanded(false);\n\n this._onClickHandler = (): void => { onClick(); };\n this._onMouseOverHandler = (): void => { onHover(); };\n\n // Internal `Event.addListener(this, …)` calls — the class registers\n // listeners on itself, which is the allowed shape. The named-method\n // bypass rule only forbids *external* consumers from doing the same.\n Event.addListener(this, \"click\", this._onClickHandler);\n Event.addListener(this, \"mouseover\", this._onMouseOverHandler);\n }\n\n /**\n * Pins the button's height to {@link MENU_BAR_BUTTON_HEIGHT} while\n * inheriting Button's content-derived width.\n */\n protected override computePreferredSize(): { width: number; height: number } {\n const { width } = super.computePreferredSize();\n\n return { width, height: MENU_BAR_BUTTON_HEIGHT };\n }\n\n /**\n * Sets the active (dropdown-open) visual state.\n *\n * Active buttons show a persistent highlight background and report `aria-expanded=\"true\"`.\n *\n * @param active - `true` to show the open state, `false` to revert to the default.\n */\n setActive(active: boolean): this {\n this.setBackgroundColor(\n active\n ? \"var(--ts-ui-menu-bar-btn-hover-bg, rgba(30, 100, 200, 0.10))\"\n : \"var(--ts-ui-menu-bar-btn-bg, transparent)\"\n );\n this.getAria().setExpanded(active);\n\n // While this button's dropdown is open, silence its hover tooltip — the\n // title tooltip would otherwise pop over the open menu (and re-arm on a\n // quick-switch re-hover). Restored when the menu closes.\n this.setTooltipSuppressed(active);\n\n return this;\n }\n\n}\n\nconst MenuBarButtonCallable = callable(MenuBarButton);\ntype MenuBarButtonCallable = MenuBarButton;\nexport {\n MenuBarButton as _MenuBarButton,\n MenuBarButtonCallable as MenuBarButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { MenuBarButton, MENU_BAR_BUTTON_HEIGHT } from \"~/component/menubar/MenuBarButton.js\";\nimport { Menu } from \"~/overlay/Menu.js\";\nimport { MenuConfig } from \"~/component/container/MenuItem.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link MenuBar}.\n *\n * @category Components\n */\nexport interface MenuBarOptions extends ComponentOptions {\n /** Top-level menus to populate the bar with, equivalent to a tail `setMenus()`. */\n menus?: MenuConfig[];\n}\n\n// Default to the tool bar's background so menu bars and tool bars read as\n// one surface; the shipped themes set --ts-ui-menu-bar-bg to their\n// toolBar.background, and this untokened fallback matches ToolBar's own.\nconst _defaultMenuBarOptions: Partial<MenuBarOptions> = {\n backgroundColor: \"var(--ts-ui-menu-bar-bg, rgb(245, 245, 245))\",\n minSize: { width: 0, height: MENU_BAR_BUTTON_HEIGHT },\n};\n\n/**\n * A persistent horizontal menu bar that hosts top-level dropdown menus.\n *\n * `setMenus()` populates the bar with [`MenuBarButton`](/api/component/menubar/classes/MenuBarButton) children. Clicking a button\n * opens the corresponding [`Menu`](/api/overlay/classes/Menu) dropdown. While any dropdown is open,\n * hovering another button switches menus immediately (quick-switch mode), and\n * keyboard navigation (Arrow keys, Enter, Escape) is handled via a viewport-level\n * keydown listener.\n *\n * @example\n * ```typescript\n * const bar = new MenuBar();\n * bar.setMenus([\n * { label: 'File', items: [\n * { text: 'New', shortcut: 'Ctrl+N', action: () => newDoc() },\n * { separator: true },\n * { text: 'Quit', enabled: false },\n * ]},\n * { label: 'Edit', items: [\n * { text: 'Undo', shortcut: 'Ctrl+Z', action: () => undo() },\n * ]},\n * ]);\n * container.addComponent(bar);\n * ```\n *\n * @category Components\n */\nclass MenuBar extends Component {\n\n private readonly _buttons: MenuBarButton[] = [];\n private readonly _panels: Menu[] = [];\n private _openIndex: number = -1;\n private _quickSwitchActive: boolean = false;\n private _keydownListening: boolean = false;\n\n private readonly _onKeyDown: (e: KeyboardEvent) => Event.ListenerResult;\n\n /**\n * Constructs a `MenuBar`, optionally populated from `options.menus` (the\n * options-bag equivalent of a tail `setMenus()` call).\n *\n * @param options - Optional construction-time options; `menus` populates the bar.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: MenuBarOptions, subclassDefaults?: Partial<MenuBarOptions>) {\n super(options, { ..._defaultMenuBarOptions, ...(subclassDefaults ?? {}) });\n\n const hbox = new HBox();\n hbox.setComponentSpacing(0);\n hbox.setStretching(true);\n this.setLayoutManager(hbox);\n\n this.setElementCSSRule(\n \"borderBottom\",\n \"1px solid var(--ts-ui-menu-bar-border, rgb(220, 220, 220))\"\n );\n this.getAria().setRole(\"menubar\");\n this.getAria().setLabel(\"Main menu\");\n this.getAria().setTabIndex(0);\n\n this._onKeyDown = (e: KeyboardEvent) => {\n if (this._openIndex < 0) {\n return;\n }\n\n const panel = this._panels[this._openIndex];\n\n switch (e.key) {\n case \"Escape\":\n this.closeMenu();\n\n return { stop: true, prevent: true };\n\n case \"ArrowLeft\":\n this.openMenu((this._openIndex - 1 + this._panels.length) % this._panels.length);\n\n return { stop: true, prevent: true };\n\n case \"ArrowRight\":\n this.openMenu((this._openIndex + 1) % this._panels.length);\n\n return { stop: true, prevent: true };\n\n case \"ArrowDown\":\n if (panel.getFocusedIndex() < 0) {\n panel.focusItem(0);\n } else {\n panel.focusNext();\n }\n\n return { stop: true, prevent: true };\n\n case \"ArrowUp\":\n panel.focusPrev();\n\n return { stop: true, prevent: true };\n\n case \"Enter\":\n panel.activateFocused();\n\n return { stop: true, prevent: true };\n }\n\n return;\n };\n\n if (options?.menus) {\n this.setMenus(options.menus);\n }\n }\n\n /**\n * Replaces the current set of top-level menus.\n *\n * Disposes all existing [`MenuBarButton`](/api/component/menubar/classes/MenuBarButton) and [`Menu`](/api/overlay/classes/Menu) instances, then rebuilds\n * them from the given descriptors.\n *\n * @param menus - Ordered list of top-level menu descriptors.\n */\n setMenus(menus: MenuConfig[]): this {\n if (this._openIndex >= 0) {\n this.closeMenu();\n }\n\n for (const panel of this._panels) {\n panel.dispose();\n }\n\n this._buttons.length = 0;\n this._panels.length = 0;\n\n this.disposeAllComponents();\n\n for (let i = 0; i < menus.length; i++) {\n const menu = menus[i];\n const index = i;\n\n const button = new MenuBarButton(\n menu.label,\n () => {\n if (this._openIndex === index) {\n this.closeMenu();\n } else {\n this.openMenu(index);\n }\n },\n () => {\n if (this._quickSwitchActive && this._openIndex !== index) {\n this.openMenu(index);\n }\n },\n menu.glyph !== undefined ? { glyph: menu.glyph } : undefined\n );\n\n const panel = new Menu(menu.items, () => { this.closeMenu(); });\n\n this._buttons.push(button);\n this._panels.push(panel);\n this.addComponent(button);\n }\n\n return this;\n }\n\n /**\n * Disposes every top-level dropdown, then runs the inherited teardown.\n * `_panels` are LayerManager-mounted panels, never registered children\n * (see Menu.ts's class comment), so `super.destructor()`'s child\n * recursion cannot reach them. `_buttons` need no matching call — they\n * are registered via `addComponent` above, so the base recursion already\n * reaches them. `Component.dispose()` is idempotent, so a panel already\n * disposed by a `setMenus` call that ran just before teardown costs\n * nothing here.\n */\n protected destructor(): void {\n for (const panel of this._panels) {\n panel.dispose();\n }\n\n super.destructor();\n }\n\n /**\n * Programmatically opens the menu at the given index, closing any currently open menu first.\n *\n * @param index - Zero-based index into the menus array.\n */\n openMenu(index: number): this {\n if (index < 0 || index >= this._panels.length) {\n return this;\n }\n\n if (index === this._openIndex) {\n return this;\n }\n\n if (this._openIndex >= 0) {\n this._panels[this._openIndex].close();\n this._buttons[this._openIndex].setActive(false);\n }\n\n this._openIndex = index;\n this._quickSwitchActive = true;\n\n this._buttons[index].setActive(true);\n // Exclude only the opener button from the panel's outside-click dismissal\n // (so its own mousedown does not self-close before the click toggles it),\n // not the whole bar — otherwise a click on empty bar space would be\n // treated as inside and never close the menu.\n this._panels[index].setExcludedElement(this._buttons[index].getElement(true)!);\n this._panels[index].open(this._buttons[index].getElement(true)!);\n\n if (!this._keydownListening) {\n this._keydownListening = true;\n Event.addViewportListener(this, \"keydown\", this._onKeyDown);\n }\n\n return this;\n }\n\n /**\n * Closes the currently open menu, if any.\n */\n closeMenu(): this {\n if (this._openIndex < 0) {\n return this;\n }\n\n this._panels[this._openIndex].close();\n this._buttons[this._openIndex].setActive(false);\n\n this._openIndex = -1;\n this._quickSwitchActive = false;\n\n if (this._keydownListening) {\n this._keydownListening = false;\n Event.removeViewportListener(this, \"keydown\", this._onKeyDown);\n }\n\n return this;\n }\n\n /**\n * Returns the index of the currently open menu, or `-1` if none is open.\n *\n * @returns The open menu index, or -1.\n */\n getOpenIndex(): number {\n return this._openIndex;\n }\n}\n\nconst MenuBarCallable = callable(MenuBar);\ntype MenuBarCallable = MenuBar;\nexport {\n MenuBar as _MenuBar,\n MenuBarCallable as MenuBar\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button } from \"~/component/button/Button.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Container, ContainerOptions } from \"~/core/Container.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { VBox } from \"~/layout/VBox.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { RovingTabIndex } from \"~/core/RovingTabIndex.js\";\nimport { Menu } from \"~/overlay/Menu.js\";\nimport { MenuItemConfig } from \"~/component/container/MenuItem.js\";\nimport { Spacer } from \"~/component/container/Spacer.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { ellipsis_v } from \"~/glyphs/solid/ellipsis_v.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation, AxisEnd } from \"~/primitive/Axis.js\";\n\n// Register the overflow trigger's chevron eagerly at module load — same pattern\n// as SplitButton registering its caret_down — so the lazily-created \"more\"\n// affordance always resolves its glyph without the consumer pre-registering it.\nGlyph.register(ellipsis_v);\n\n/**\n * Overflow behaviour for a {@link ToolBar} whose children exceed its measured\n * extent. `\"clip\"` (the default) lets the children spill into the parent's\n * clipping region. `\"menu\"` hides the `Button` / `ToggleButton` children that\n * don't fit and surfaces them in a dropdown opened by a trailing chevron\n * affordance. Menu overflow is horizontal-only; vertical bars always clip.\n *\n * @category Components\n */\nexport type ToolBarOverflow = \"clip\" | \"menu\";\n\n/**\n * Construction-time options for {@link ToolBar}.\n *\n * @category Components\n */\nexport interface ToolBarOptions extends ContainerOptions {\n orientation?: AxisOrientation;\n compact?: boolean;\n overflow?: ToolBarOverflow;\n /**\n * Edge the `\"menu\"` overflow trigger sits on — `\"end\"` (default) or\n * `\"start\"`. No visible effect unless `overflow` is `\"menu\"`. Runtime\n * counterpart `setOverflowSide`.\n */\n overflowSide?: AxisEnd;\n /**\n * When `true` (the default), `Button` / `ToggleButton` children added to the\n * bar are switched to flat appearance for the classical toolbar look — no\n * resting frame, a light frame on hover, and a sunken inset frame on press.\n * Set `false` to keep raised buttons. Runtime counterpart `setFlat`.\n */\n flat?: boolean;\n}\n\n/**\n * Fallback inter-child spacing in pixels for the overflow reserve math only.\n * `_computeOverflowed` reserves a gap between children when measuring the\n * fit-set; it reads the live `getComponentSpacing()` and falls back to this\n * constant only when the layout manager isn't an `HBox`. The bar no longer\n * drives any gap itself (spacing defaults to 0), so this is purely the typed\n * fallback that keeps the overflow arithmetic well-defined.\n */\nconst TOOLBAR_GAP_DEFAULT: number = 4;\n\n/**\n * Registry glyph rendered on the overflow (\"more\") trigger button. Verified\n * present in the solid glyph set (`glyphs/solid/ellipsis_v.ts`); the vertical\n * ellipsis is the conventional overflow affordance for a horizontal bar.\n */\nconst OVERFLOW_TRIGGER_GLYPH: string = \"ellipsis-v\";\n\n/**\n * User-overridable defaults forwarded to `super` via the options bag.\n */\nconst _defaultToolBarOptions: Partial<ToolBarOptions> = {\n orientation: \"horizontal\",\n compact: true,\n overflow: \"clip\",\n overflowSide: \"end\",\n flat: true,\n backgroundColor: \"var(--ts-ui-toolbar-bg, rgb(245, 245, 245))\",\n};\n\n/**\n * A horizontal (or vertical) strip of related controls — e.g. Bold / Italic\n * / Underline in a text editor, or Cut / Copy / Paste in a file manager.\n *\n * `ToolBar` extends [`Container`](/api/core/classes/Container) and defaults to\n * compact mode (`compact: true`), so at construction it drops its own panel\n * insets to zero and renders its `Button` / `ToggleButton` children compact;\n * `setCompact(false)` restores the 4-pixel panel insets and the children's\n * default rendering. Layout defaults to a horizontal\n * [`HBox`](/api/layout/classes/HBox); pass `orientation: \"vertical\"` (or call\n * `setOrientation(\"vertical\")`) to swap to a [`VBox`](/api/layout/classes/VBox).\n *\n * Children can be any [`Component`](/api/core/classes/Component) — typically\n * [`Button`](/api/component/button/classes/Button),\n * [`ToggleButton`](/api/component/button/classes/ToggleButton),\n * [`ButtonGroup`](/api/overlay/classes/ButtonGroup) members,\n * [`ComboBox`](/api/component/input/classes/ComboBox), or {@link ToolBarSeparator}.\n * Focusable children (`tabindex >= 0`) are auto-registered with an internal\n * [`RovingTabIndex`](/api/core/classes/RovingTabIndex) so Arrow keys cycle\n * focus between them, matching the\n * [`ButtonGroup`](/api/overlay/classes/ButtonGroup) keyboard-nav pattern.\n *\n * @example\n * ```typescript\n * import { ToolBar, ToolBarSeparator } from '@jimka/typescript-ui/component/menubar';\n * import { Button } from '@jimka/typescript-ui/component/button';\n *\n * const bar = new ToolBar();\n * bar.addComponent(new Button('Cut'));\n * bar.addComponent(new Button('Copy'));\n * bar.addComponent(new Button('Paste'));\n * bar.addComponent(new ToolBarSeparator());\n * bar.addComponent(new Button('Find'));\n * ```\n *\n * @category Components\n */\nclass ToolBar<TOptions extends ToolBarOptions = ToolBarOptions> extends Container<TOptions> {\n\n declare private _orientation: AxisOrientation;\n declare private _compact: boolean;\n declare private _overflowMode: ToolBarOverflow;\n declare private _overflowSide: AxisEnd;\n declare private _flat: boolean;\n declare private _rovingTabIndex: RovingTabIndex;\n declare private _onKeyDown: (e: KeyboardEvent) => void;\n declare private _overflowButton: Button | null;\n declare private _overflowMenu: Menu | null;\n declare private _overflowSpacer: Spacer | null;\n\n /**\n * Constructs a `ToolBar`.\n *\n * @param options - Optional construction-time options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n *\n * @remarks The parameter is typed as the concrete {@link ToolBarOptions}\n * rather than the class's `TOptions` parameter so that passing an options\n * literal (e.g. `new ToolBar({ compact: true })`) cannot narrow `TOptions`\n * to that literal — which would type the instance as `ToolBar<{ compact:\n * true }>` and fail the weak-type assignability check when it is later used\n * as a base `Component` (e.g. `container.addComponent(toolbar)`). `TOptions`\n * stays at its `ToolBarOptions` default.\n */\n constructor(options?: ToolBarOptions, subclassDefaults?: Partial<ToolBarOptions>);\n constructor(options?: ToolBarOptions, subclassDefaults?: Partial<TOptions>) {\n super(\n options as TOptions,\n { ..._defaultToolBarOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n this.getAria().setRole(\"toolbar\");\n this.getAria().setTabIndex(0);\n\n this._onKeyDown = (e: KeyboardEvent) => {\n const isHoriz = this._orientation === \"horizontal\";\n const fwd = isHoriz ? \"ArrowRight\" : \"ArrowDown\";\n const back = isHoriz ? \"ArrowLeft\" : \"ArrowUp\";\n\n if (e.key === fwd) {\n e.preventDefault();\n this._rovingTabIndex.moveNext();\n } else if (e.key === back) {\n e.preventDefault();\n this._rovingTabIndex.movePrev();\n }\n };\n\n Event.addSubtreeListener(this, \"keydown\", this._onKeyDown);\n }\n\n /**\n * Applies a {@link ToolBarOptions} bag. Inherited `Container` fields cascade\n * through `super.applyOptions`; the `ToolBar`-specific fields\n * (orientation, compact, overflow) are dispatched here when set.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n // These fields all carry a class default and seed construction-time\n // backing state, so dispatch the caller value or the class default —\n // never leave the setter unfired (mirrors Panel.setAutoScroll).\n this.applyOrientation(options.orientation ?? this.getOrientation(), options);\n this.setCompact(options.compact ?? this.isCompact());\n // Dispatched before `overflow` so the trigger, created on entry to\n // `\"menu\"` mode, is positioned on the configured side from the start.\n this.setOverflowSide(options.overflowSide ?? this.getOverflowSide());\n this.setOverflow(options.overflow ?? this.getOverflow());\n this.setFlat(options.flat ?? this.isFlat());\n\n return this;\n }\n\n /**\n * Sets the layout direction. Horizontal toolbars pack children\n * left-to-right via [`HBox`](/api/layout/classes/HBox); vertical toolbars\n * pack them top-to-bottom via [`VBox`](/api/layout/classes/VBox). Child\n * spacing is preserved across the swap; the trailing-edge border flips\n * from bottom to right (or vice versa) to match the new direction.\n *\n * Existing {@link ToolBarSeparator} children are **not** auto-flipped —\n * see the architecture note in the plan.\n *\n * @param value - The new orientation.\n *\n * @returns This component, for method chaining.\n */\n setOrientation(value: AxisOrientation): this {\n this.applyOrientation(value);\n\n return this;\n }\n\n /**\n * Recomputes the layout manager, ARIA orientation, and trailing-edge border\n * for `value`. A no-op when `value` matches the current orientation.\n *\n * @param value - The new orientation.\n * @param options - Passed only from the constructor's `applyOptions`\n * dispatch; when its `border` is set, that value wins over the\n * orientation-derived border so a caller-supplied `border` option\n * survives construction. Every runtime caller (the public\n * {@link setOrientation}) omits it, so the border is always recomputed\n * from `value`.\n */\n private applyOrientation(value: AxisOrientation, options?: ToolBarOptions): void {\n if (value === this._orientation) {\n return;\n }\n\n const oldLM = this.getLayoutManager();\n // Default to flush (0) — the bar no longer drives a gap; child density\n // comes from the buttons' own compact insets. A consumer-set spacing on\n // an existing HBox/VBox is preserved across the orientation swap.\n const gap = (oldLM instanceof HBox || oldLM instanceof VBox)\n ? oldLM.getComponentSpacing()\n : 0;\n\n const newLM: HBox | VBox = value === \"horizontal\" ? new HBox() : new VBox();\n newLM.setComponentSpacing(gap);\n newLM.setStretching(true);\n\n this.setLayoutManager(newLM);\n this._orientation = value;\n\n this.getAria().setOrientation(value);\n\n if (options?.border !== undefined) {\n this.setBorder(options.border);\n return;\n }\n\n const ruleColor = \"var(--ts-ui-toolbar-border, rgb(220, 220, 220))\";\n\n if (value === \"horizontal\") {\n this.setBorder({ borderBottom: `1px solid ${ruleColor}` });\n } else {\n this.setBorder({ borderRight: `1px solid ${ruleColor}` });\n }\n }\n\n /**\n * Returns the current orientation.\n *\n * @returns `\"horizontal\"` or `\"vertical\"`.\n */\n getOrientation(): AxisOrientation {\n return this._orientation ?? this._defaultOptions.orientation!;\n }\n\n /**\n * Toggles compact mode. In compact mode the bar's own panel insets shrink\n * from `(4, 4, 4, 4)` to `(0, 0, 0, 0)` and every `Button` / `ToggleButton`\n * child is switched to compact rendering (tighter button insets), the same\n * way {@link setFlat} drives the flat appearance onto its button children.\n * Child spacing is left untouched — the bar packs its children flush and the\n * density comes from the buttons themselves.\n *\n * @param value - `true` to enable compact mode, `false` to restore defaults.\n *\n * @returns This component, for method chaining.\n */\n setCompact(value: boolean): this {\n if (value === this._compact) {\n return this;\n }\n\n this._compact = value;\n\n // Compact packs flush to its edges (zero inset) so a toolbar sits tight\n // against the surrounding chrome; the density between children still\n // comes from the buttons' own compact insets. Non-compact restores the\n // roomy 4px panel insets.\n const inset = value ? 0 : 4;\n\n this.setInsets(new Insets(inset, inset, inset, inset));\n\n for (const child of this.getComponents()) {\n if (child instanceof Button) {\n child.setCompact(value);\n }\n }\n\n this.doLayout();\n\n return this;\n }\n\n /**\n * Returns whether compact mode is currently active.\n *\n * @returns `true` if compact mode is enabled.\n */\n isCompact(): boolean {\n return this._compact ?? this._defaultOptions.compact!;\n }\n\n /**\n * Sets the overflow strategy. `\"clip\"` lets children spill into the parent's\n * clipping region. `\"menu\"` hides the `Button` / `ToggleButton` children\n * that don't fit and surfaces them in a dropdown opened by a trailing\n * chevron affordance; the trigger and its rebuild-mode\n * [`Menu`](/api/overlay/classes/Menu) are created lazily on first entry to\n * `\"menu\"` mode. Menu overflow applies to horizontal bars only — a vertical\n * bar always clips.\n *\n * @param value - `\"clip\"` or `\"menu\"`.\n *\n * @returns This component, for method chaining.\n */\n setOverflow(value: ToolBarOverflow): this {\n this._overflowMode = value;\n\n if (value === \"menu\" && this._overflowButton === undefined) {\n this._createOverflowAffordance();\n }\n\n this.doLayout();\n\n return this;\n }\n\n /**\n * Lazily builds the overflow trigger — a flat, glyph-only `Button` carrying\n * the chevron glyph — and the rebuild-mode `Menu` it opens. The trigger is\n * appended through `super.addComponent` so it bypasses the flatten-children\n * pass in {@link addComponent} and is excluded from the overflow set by\n * identity. It starts hidden; {@link doLayout} shows it only once at least\n * one button has overflowed.\n */\n private _createOverflowAffordance(): void {\n const trigger = new Button({ flat: true, glyph: OVERFLOW_TRIGGER_GLYPH });\n\n trigger.setDisplayed(false);\n trigger.getAria().setLabel(\"More\");\n trigger.getAria().setHasPopup(\"menu\");\n\n trigger.on(\"action\", () => { this._toggleOverflowMenu(); });\n\n this._overflowButton = trigger;\n this._overflowMenu = new Menu();\n // Flex spacer that pushes a right-side trigger to the bar's far edge; it\n // is only parented while the side is `\"right\"` (see _positionOverflowTrigger).\n this._overflowSpacer = Spacer.flex();\n\n super.addComponent(trigger);\n\n this._positionOverflowTrigger();\n }\n\n /**\n * Pins the overflow trigger to the configured edge. For `\"end\"` a flex\n * {@link Spacer} is parented just before the trigger so the chevron is\n * driven to the bar's trailing edge (rather than sitting flush against the\n * last visible button); the final child order is `[content…, spacer, trigger]`.\n * For `\"start\"` the spacer is detached and the trigger leads as the first\n * child. A no-op when no trigger exists yet. Re-run whenever content is added\n * (the trigger must stay at the edge) or the side changes; the trailing run\n * of buttons still overflows regardless of the trigger's side.\n */\n private _positionOverflowTrigger(): void {\n const trigger = this._overflowButton;\n const spacer = this._overflowSpacer;\n if (trigger === undefined || trigger === null || spacer === undefined || spacer === null) {\n return;\n }\n\n if (this._overflowSide === \"end\") {\n if (spacer.getParentComponent() !== this) {\n super.addComponent(spacer);\n }\n\n // Order the tail as [spacer, trigger]: move the trigger last, then\n // slot the spacer immediately before it. `moveComponent` recomputes\n // the index after splicing the moved child out, so the pre-move\n // length-relative targets land both at the end.\n this.moveComponent(trigger, this.getComponents().length - 1);\n this.moveComponent(spacer, this.getComponents().length - 2);\n } else {\n if (spacer.getParentComponent() === this) {\n this.removeComponent(spacer);\n }\n\n this.moveComponent(trigger, 0);\n }\n }\n\n /**\n * Returns the current overflow strategy.\n *\n * @returns `\"clip\"` or `\"menu\"`.\n */\n getOverflow(): ToolBarOverflow {\n return this._overflowMode ?? this._defaultOptions.overflow!;\n }\n\n /**\n * Sets which edge the `\"menu\"` overflow trigger sits on. `\"end\"` (the\n * default) trails the visible buttons; `\"start\"` leads them. Only the\n * trigger's position changes — the overflowing buttons are the trailing run\n * either way. No visible effect until `overflow` is `\"menu\"`.\n *\n * @param value - `\"start\"` or `\"end\"`.\n *\n * @returns This component, for method chaining.\n */\n setOverflowSide(value: AxisEnd): this {\n if (value === this._overflowSide) {\n return this;\n }\n\n this._overflowSide = value;\n\n this._positionOverflowTrigger();\n this.doLayout();\n\n return this;\n }\n\n /**\n * Returns the edge the overflow trigger sits on.\n *\n * @returns `\"start\"` or `\"end\"`.\n */\n getOverflowSide(): AxisEnd {\n return this._overflowSide ?? this._defaultOptions.overflowSide!;\n }\n\n /**\n * Toggles the classical flat appearance for the bar's `Button` /\n * `ToggleButton` children. When `true` (the default), each such child is\n * switched to flat mode — no resting frame, a light frame on hover, a sunken\n * inset frame on press, and a depressed look for a toggled-on\n * `ToggleButton`. Glyph-only flat buttons also tighten to compact squares.\n * Setting `false` reverts existing button children to raised chrome.\n *\n * Non-`Button` children (separators, combo boxes, spacers) are left\n * untouched. The flag also governs children added later through\n * {@link addComponent}.\n *\n * @param value - `true` to flatten button children, `false` to restore them.\n *\n * @returns This component, for method chaining.\n */\n setFlat(value: boolean): this {\n if (value === this._flat) {\n return this;\n }\n\n this._flat = value;\n\n for (const child of this.getComponents()) {\n if (child instanceof Button) {\n child.setFlat(value);\n }\n }\n\n return this;\n }\n\n /**\n * Returns whether the bar flattens its `Button` children.\n *\n * @returns `true` if flat mode is enabled.\n */\n isFlat(): boolean {\n return this._flat ?? this._defaultOptions.flat!;\n }\n\n /**\n * Appends a child component and, when its tab-index marks it focusable,\n * registers it with the internal roving-tabindex group so Arrow keys\n * cycle focus through it.\n *\n * @param component - The child component to add.\n *\n * @returns This component, for method chaining.\n */\n override addComponent(component: Component, constraints?: LayoutConstraints): this {\n super.addComponent(component, constraints);\n\n if (this._rovingTabIndex === undefined) {\n this._rovingTabIndex = new RovingTabIndex();\n }\n\n if (component.getAria().getTabIndex() !== -1) {\n this._rovingTabIndex.add(component);\n }\n\n if (this._flat && component instanceof Button) {\n component.setFlat(true);\n }\n\n if (this._compact && component instanceof Button) {\n component.setCompact(true);\n }\n\n // Keep the overflow trigger pinned to its edge: a content child appended\n // after the trigger (the trigger is created before the demo's buttons\n // for a construction-time `overflow: \"menu\"`) would otherwise leave the\n // chevron stranded mid-row. No-op when no trigger exists.\n this._positionOverflowTrigger();\n\n return this;\n }\n\n /**\n * Lays the bar out and, in `\"menu\"` overflow mode on a horizontal bar,\n * reflows the `Button` / `ToggleButton` children that no longer fit into the\n * trailing chevron dropdown. The base pass runs first so children report\n * their resolved preferred widths; the reflow then re-derives the fit-set\n * from scratch each pass, so widening the bar restores previously-hidden\n * buttons. Vertical bars and `\"clip\"` mode skip the reflow entirely.\n *\n * @returns This component, for method chaining.\n */\n override doLayout(): this {\n super.doLayout();\n\n if (this._overflowMode !== \"menu\" || this._orientation !== \"horizontal\") {\n return this;\n }\n\n if (this._overflowButton === undefined || this._overflowButton === null) {\n return this;\n }\n\n this._reflowOverflow(this._overflowButton);\n\n return this;\n }\n\n /**\n * Re-derives which `Button` / `ToggleButton` children overflow the bar's\n * inner width and toggles their `display` accordingly, reserving room for\n * the trigger whenever at least one button is hidden. Only mutates child\n * visibility when the fit-set actually changed, so the\n * `setDisplayed`-triggered re-layout converges instead of thrashing. The\n * trigger itself is shown only while ≥1 button is overflowed and is then\n * positioned for the dropdown anchor.\n *\n * @param trigger - The lazily-created overflow trigger button.\n */\n private _reflowOverflow(trigger: Button): void {\n const insets = this.getInsets();\n const inner = this.getWidth() - insets.getLeft() - insets.getRight();\n\n const lm = this.getLayoutManager();\n const gap = (lm instanceof HBox) ? lm.getComponentSpacing() : TOOLBAR_GAP_DEFAULT;\n\n const children = this.getComponents().filter(child => child !== trigger && child !== this._overflowSpacer);\n const overflowed = this._computeOverflowed(children, trigger, inner, gap);\n\n let changed = false;\n\n for (const child of children) {\n const shouldHide = overflowed.includes(child);\n\n if (child.isDisplayed() === shouldHide) {\n child.setDisplayed(!shouldHide);\n changed = true;\n }\n }\n\n const wantTrigger = overflowed.length > 0;\n\n if (trigger.isDisplayed() !== wantTrigger) {\n trigger.setDisplayed(wantTrigger);\n changed = true;\n }\n\n if (changed) {\n super.doLayout();\n }\n }\n\n /**\n * Walks the (non-trigger) children left-to-right, accumulating preferred\n * widths plus inter-child gaps, and returns the `Button` / `ToggleButton`\n * children that cross the inner width. When nothing overflows the result is\n * empty; otherwise the trigger's own width is reserved so the chevron has\n * room. Non-`Button` children that don't fit are left in place (clipped) —\n * only buttons have a well-defined menu-row representation.\n *\n * @param children - The bar's children, excluding the trigger.\n * @param trigger - The overflow trigger, measured for its reserved width.\n * @param inner - The bar's inner content width in pixels.\n * @param gap - The inter-child spacing in pixels.\n *\n * @returns The overflowed button children, in document order.\n */\n private _computeOverflowed(children: Component[], trigger: Button, inner: number, gap: number): Component[] {\n const widthOf = (child: Component): number => child.getPreferredSize()?.width ?? 0;\n\n let total = 0;\n\n for (let i = 0; i < children.length; i++) {\n total += widthOf(children[i]);\n\n if (i > 0) {\n total += gap;\n }\n }\n\n if (total <= inner) {\n return [];\n }\n\n const reserve = widthOf(trigger) + gap;\n const available = inner - reserve;\n\n const overflowed: Component[] = [];\n\n let used = 0;\n let crossed = false;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const next = used + widthOf(child) + (i > 0 ? gap : 0);\n\n if (next > available) {\n crossed = true;\n }\n\n // Once the width crosses the available extent, every following\n // Button overflows so the hidden set stays a contiguous trailing\n // run; non-Button children past the crossover stay put (clipped).\n if (crossed && child instanceof Button) {\n overflowed.push(child);\n } else {\n used = next;\n }\n }\n\n return overflowed;\n }\n\n /**\n * Disposes the overflow dropdown, then runs the inherited teardown.\n * `_overflowMenu` is a LayerManager-mounted panel, never a registered\n * child (see Menu.ts's class comment), so `super.destructor()`'s child\n * recursion cannot reach it. `_overflowButton` needs no matching call —\n * it is registered via `addComponent` (`_createOverflowAffordance`), so\n * the base recursion already reaches it.\n */\n protected destructor(): void {\n this._overflowMenu?.dispose();\n\n super.destructor();\n }\n\n /**\n * Builds one {@link MenuItemConfig} per currently-overflowed button and\n * toggles the rebuild-mode dropdown anchored under the trigger — opening it,\n * or closing it when the trigger is pressed again. Each row's `action`\n * re-fires the source button's `\"click\"` (the DOM event behind its\n * `\"action\"`) so the dropdown drives the original handler.\n */\n private _toggleOverflowMenu(): void {\n const trigger = this._overflowButton;\n const menu = this._overflowMenu;\n\n if (trigger === null || trigger === undefined || menu === null || menu === undefined) {\n return;\n }\n\n const configs: MenuItemConfig[] = [];\n\n for (const child of this.getComponents()) {\n if (child === trigger || child.isDisplayed() || !(child instanceof Button)) {\n continue;\n }\n\n const glyph = child.getGlyph()?.getGlyphName();\n\n configs.push({\n text: child.getText(),\n glyph: glyph,\n action: () => { child.click(); },\n });\n }\n\n const triggerEl = trigger.getElement();\n\n if (!triggerEl) {\n return;\n }\n\n const rect = DOM.source.getViewportRect(trigger);\n\n // toggleFor excludes the trigger from the menu's outside-click dismissal\n // and remembers it, so re-pressing the overflow button closes the menu\n // instead of the close-then-reopen flash a bare show() would produce.\n menu.toggleFor(triggerEl, rect, configs);\n }\n}\n\nconst ToolBarCallable = callable(ToolBar);\ntype ToolBarCallable<TOptions extends ToolBarOptions = ToolBarOptions> = ToolBar<TOptions>;\nexport {\n ToolBar as _ToolBar,\n ToolBarCallable as ToolBar\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation } from \"~/primitive/Axis.js\";\n\n/**\n * Construction-time options for {@link ToolBarSeparator}.\n *\n * @category Components\n */\nexport interface ToolBarSeparatorOptions extends ComponentOptions {\n orientation?: AxisOrientation;\n}\n\n/**\n * User-overridable default fill; a caller-supplied `backgroundColor` wins.\n */\nconst _defaultToolBarSeparatorOptions: Partial<ToolBarSeparatorOptions> = {\n backgroundColor: \"var(--ts-ui-toolbar-separator-color, rgb(220, 220, 220))\",\n};\n\n/**\n * A thin divider rule used inside a [`ToolBar`](/api/component/menubar/classes/ToolBar) to visually group\n * related controls. Defaults to a vertical rule (for horizontal toolbars);\n * pass `orientation: \"horizontal\"` for a vertical toolbar.\n *\n * Renders as a single bordered DOM element. The rule colour is theme-driven\n * via `--ts-ui-toolbar-separator-color`. Separators report `role=\"separator\"`\n * with a matching `aria-orientation`, and stay out of the keyboard tab order.\n *\n * @example\n * ```typescript\n * import { ToolBar, ToolBarSeparator } from '@jimka/typescript-ui/component/menubar';\n * const bar = new ToolBar();\n * bar.addComponent(new ToolBarSeparator());\n * ```\n *\n * @category Components\n */\nclass ToolBarSeparator extends Component<ToolBarSeparatorOptions> {\n\n /**\n * Pixel thickness of the rendered rule — a 1-pixel hairline. The breathing\n * room on either side of the rule comes from the parent toolbar's HBox /\n * VBox `componentSpacing` (theme token `--ts-ui-toolbar-gap`, default 4 px),\n * so the separator itself only carries the line. A wider THICKNESS would\n * stack on top of the parent's spacing and produce an asymmetric gap.\n */\n static readonly THICKNESS: number = 1;\n\n private readonly _orientation: AxisOrientation;\n\n /**\n * Constructs a `ToolBarSeparator`.\n *\n * @param options - Optional construction-time options. `options.orientation`\n * selects the rule direction; defaults to `\"vertical\"`.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(\n options?: ToolBarSeparatorOptions,\n subclassDefaults?: Partial<ToolBarSeparatorOptions>,\n ) {\n super(options, { ..._defaultToolBarSeparatorOptions, ...(subclassDefaults ?? {}) });\n\n this._orientation = options?.orientation ?? \"vertical\";\n\n if (this._orientation === \"vertical\") {\n // preferredSize.height = 0 keeps the separator out of the parent\n // HBox's row-height computation. The rendered height comes from\n // the parent's stretching=true branch, clamped to maxSize.height\n // (MAX_VALUE → containerSize.height). preferredSize.width = THICKNESS\n // makes the toolbar's own preferred width count the separator.\n this.setPreferredSize({ width: ToolBarSeparator.THICKNESS, height: 0 });\n this.setMaxSize({ width: ToolBarSeparator.THICKNESS, height: Number.MAX_VALUE });\n } else {\n this.setPreferredSize({ width: 0, height: ToolBarSeparator.THICKNESS });\n this.setMaxSize({ width: Number.MAX_VALUE, height: ToolBarSeparator.THICKNESS });\n }\n\n // The element IS the rule — a 1 px line filled with the theme colour.\n this.getAria().setRole(\"separator\");\n this.getAria().setOrientation(this._orientation);\n this.getAria().setTabIndex(-1);\n }\n\n /**\n * Returns the orientation passed at construction time.\n *\n * @returns The `ToolBarSeparator` orientation — `\"vertical\"` or `\"horizontal\"`.\n */\n getOrientation(): AxisOrientation {\n return this._orientation;\n }\n}\n\nconst ToolBarSeparatorCallable = callable(ToolBarSeparator);\ntype ToolBarSeparatorCallable = ToolBarSeparator;\nexport {\n ToolBarSeparator as _ToolBarSeparator,\n ToolBarSeparatorCallable as ToolBarSeparator\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"menubar.es.js","names":[],"sources":["../../../src/typescript/lib/component/menubar/MenuBarButton.ts","../../../src/typescript/lib/component/menubar/MenuBar.ts","../../../src/typescript/lib/component/menubar/ToolBar.ts","../../../src/typescript/lib/component/menubar/ToolBarSeparator.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button, ButtonOptions } from \"~/component/button/Button.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link MenuBarButton}.\n *\n * @category Components\n */\nexport interface MenuBarButtonOptions extends ButtonOptions {\n}\n\n/** Horizontal padding inside the button, folded into the defaults bag below. */\nconst HORIZONTAL_PAD = 10;\n\n/**\n * User-overridable visual defaults forwarded to `super` via the third\n * constructor arg. The cascade in `Component`'s constructor merges these\n * over Button's own defaults and dispatches each setter once with the\n * final value, so any field the caller supplied wins.\n */\nconst _defaultMenuBarButtonOptions: Partial<MenuBarButtonOptions> = {\n backgroundColor: \"var(--ts-ui-menu-bar-btn-bg, transparent)\",\n foregroundColor: \"var(--ts-ui-menu-bar-btn-fg, inherit)\",\n cursor: \"pointer\",\n // chromeless suppresses Button's ridge border, drop shadow, gradient\n // background, and the pressed/hover treatments — the menubar wants a flat\n // label-shaped surface.\n chromeless: true,\n // Horizontal padding inside the button — replaces Button's 4-px insets\n // default.\n insets: new Insets(0, HORIZONTAL_PAD, 0, HORIZONTAL_PAD),\n};\n\n/** Pixel gap between the leading glyph and the label in the content row. */\nconst GLYPH_TEXT_GAP = 4;\n\n/**\n * Fixed row height shared by every `MenuBarButton` and by the parent\n * [`MenuBar`](/api/component/menubar/classes/MenuBar) container's `setMinSize`. Exported so the two stay in\n * lockstep — changing one without the other would let the bar grow taller\n * than its buttons.\n */\nexport const MENU_BAR_BUTTON_HEIGHT: number = 28;\n\n/**\n * A single top-level button in a [`MenuBar`](/api/component/menubar/classes/MenuBar) (e.g. \"File\", \"Edit\").\n *\n * Extends [`Button`](/api/component/button/classes/Button) with `chromeless: true`\n * so the menubar's flat label-style appearance dodges Button's ridge border,\n * drop shadow, and gradient defaults. Reuses Button's content-row machinery\n * for the optional leading glyph + label pair, re-anchored to the west edge.\n * Adds menubar-specific ARIA (`role=\"menuitem\"`, `aria-haspopup=\"menu\"`,\n * `aria-expanded`) and the sticky `setActive` highlight for the\n * dropdown-open state. The `:hover` rule rides Button's `styleRules` bag.\n *\n * Communicates open/close intent back to [`MenuBar`](/api/component/menubar/classes/MenuBar) via callbacks passed at\n * construction time.\n *\n * @category Components\n */\nclass MenuBarButton extends Button<MenuBarButtonOptions> {\n\n private readonly _onClickHandler: () => void;\n private readonly _onMouseOverHandler: () => void;\n\n /**\n * Constructs a `MenuBarButton`.\n *\n * @param text - The label shown in the bar (e.g. `\"File\"`).\n * @param onClick - Called when the user clicks this button.\n * @param onHover - Called when the mouse enters this button while a menu is open (quick-switch).\n * @param options - Optional configuration bag. `glyph` is inherited from\n * [`ButtonOptions`](/api/component/button/interfaces/ButtonOptions).\n */\n constructor(\n text: string,\n onClick: () => void,\n onHover: () => void,\n options?: MenuBarButtonOptions,\n subclassDefaults?: Partial<MenuBarButtonOptions>,\n ) {\n super(\n text,\n {\n ...options,\n // Menubar-specific :hover highlight rides Button's styleRules\n // bag so the cascade routes through createStyleRule's\n // dedupe-and-defer machinery. Merge with any caller-supplied\n // styleRules entries via the canonical array-spread idiom.\n styleRules: [\n ...(options?.styleRules ?? []),\n {\n suffix: \":hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-menu-bar-btn-hover-bg, rgba(30, 100, 200, 0.10))\",\n },\n },\n ],\n },\n { ..._defaultMenuBarButtonOptions, ...(subclassDefaults ?? {}) },\n );\n\n // Bump the HBox content-row spacing from Button's default (2) to the\n // menubar's GLYPH_TEXT_GAP (4).\n (this._content.getLayoutManager() as HBox).setComponentSpacing(GLYPH_TEXT_GAP);\n\n this.getAria().setRole(\"menuitem\");\n this.getAria().setHasPopup(\"menu\");\n this.getAria().setExpanded(false);\n\n this._onClickHandler = (): void => { onClick(); };\n this._onMouseOverHandler = (): void => { onHover(); };\n\n // Internal `Event.addListener(this, …)` calls — the class registers\n // listeners on itself, which is the allowed shape. The named-method\n // bypass rule only forbids *external* consumers from doing the same.\n Event.addListener(this, \"click\", this._onClickHandler);\n Event.addListener(this, \"mouseover\", this._onMouseOverHandler);\n }\n\n /**\n * Pins the button's height to {@link MENU_BAR_BUTTON_HEIGHT} while\n * inheriting Button's content-derived width.\n */\n protected override computePreferredSize(): { width: number; height: number } {\n const { width } = super.computePreferredSize();\n\n return { width, height: MENU_BAR_BUTTON_HEIGHT };\n }\n\n /**\n * Sets the active (dropdown-open) visual state.\n *\n * Active buttons show a persistent highlight background and report `aria-expanded=\"true\"`.\n *\n * @param active - `true` to show the open state, `false` to revert to the default.\n */\n setActive(active: boolean): this {\n this.setBackgroundColor(\n active\n ? \"var(--ts-ui-menu-bar-btn-hover-bg, rgba(30, 100, 200, 0.10))\"\n : \"var(--ts-ui-menu-bar-btn-bg, transparent)\"\n );\n this.getAria().setExpanded(active);\n\n // While this button's dropdown is open, silence its hover tooltip — the\n // title tooltip would otherwise pop over the open menu (and re-arm on a\n // quick-switch re-hover). Restored when the menu closes.\n this.setTooltipSuppressed(active);\n\n return this;\n }\n\n}\n\nconst MenuBarButtonCallable = callable(MenuBarButton);\ntype MenuBarButtonCallable = MenuBarButton;\nexport {\n MenuBarButton as _MenuBarButton,\n MenuBarButtonCallable as MenuBarButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { MenuBarButton, MENU_BAR_BUTTON_HEIGHT } from \"~/component/menubar/MenuBarButton.js\";\nimport { Menu } from \"~/overlay/Menu.js\";\nimport { MenuConfig } from \"~/component/container/MenuItem.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link MenuBar}.\n *\n * @category Components\n */\nexport interface MenuBarOptions extends ComponentOptions {\n /** Top-level menus to populate the bar with, equivalent to a tail `setMenus()`. */\n menus?: MenuConfig[];\n}\n\n// Default to the tool bar's background so menu bars and tool bars read as\n// one surface; the shipped themes set --ts-ui-menu-bar-bg to their\n// toolBar.background, and this untokened fallback matches ToolBar's own.\nconst _defaultMenuBarOptions: Partial<MenuBarOptions> = {\n backgroundColor: \"var(--ts-ui-menu-bar-bg, rgb(245, 245, 245))\",\n minSize: { width: 0, height: MENU_BAR_BUTTON_HEIGHT },\n};\n\n/**\n * A persistent horizontal menu bar that hosts top-level dropdown menus.\n *\n * `setMenus()` populates the bar with [`MenuBarButton`](/api/component/menubar/classes/MenuBarButton) children. Clicking a button\n * opens the corresponding [`Menu`](/api/overlay/classes/Menu) dropdown. While any dropdown is open,\n * hovering another button switches menus immediately (quick-switch mode), and\n * keyboard navigation (Arrow keys, Enter, Escape) is handled via a viewport-level\n * keydown listener.\n *\n * @example\n * ```typescript\n * const bar = new MenuBar();\n * bar.setMenus([\n * { label: 'File', items: [\n * { text: 'New', shortcut: 'Ctrl+N', action: () => newDoc() },\n * { separator: true },\n * { text: 'Quit', enabled: false },\n * ]},\n * { label: 'Edit', items: [\n * { text: 'Undo', shortcut: 'Ctrl+Z', action: () => undo() },\n * ]},\n * ]);\n * container.addComponent(bar);\n * ```\n *\n * @category Components\n */\nclass MenuBar extends Component {\n\n private readonly _buttons: MenuBarButton[] = [];\n private readonly _panels: Menu[] = [];\n private _openIndex: number = -1;\n private _quickSwitchActive: boolean = false;\n private _keydownListening: boolean = false;\n\n private readonly _onKeyDown: (e: KeyboardEvent) => Event.ListenerResult;\n\n /**\n * Constructs a `MenuBar`, optionally populated from `options.menus` (the\n * options-bag equivalent of a tail `setMenus()` call).\n *\n * @param options - Optional construction-time options; `menus` populates the bar.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: MenuBarOptions, subclassDefaults?: Partial<MenuBarOptions>) {\n super(options, { ..._defaultMenuBarOptions, ...(subclassDefaults ?? {}) });\n\n const hbox = new HBox();\n hbox.setComponentSpacing(0);\n hbox.setStretching(true);\n this.setLayoutManager(hbox);\n\n this.setElementCSSRule(\n \"borderBottom\",\n \"1px solid var(--ts-ui-menu-bar-border, rgb(220, 220, 220))\"\n );\n this.getAria().setRole(\"menubar\");\n this.getAria().setLabel(\"Main menu\");\n this.getAria().setTabIndex(0);\n\n this._onKeyDown = (e: KeyboardEvent) => {\n if (this._openIndex < 0) {\n return;\n }\n\n const panel = this._panels[this._openIndex];\n\n // A focusable control inside a custom menu row holds real DOM\n // focus, so the key belongs to it, not to the bar's roving\n // navigation. Escape still closes the panel — LayerManager's own\n // keydown handler owns that. No config-built row is focusable, so\n // this never fires for a plain MenuItemConfig menu.\n const target = e.target === null ? null : DOM.source.intern(e.target);\n\n if (LayerManager.containsAcrossLayers(panel, target)) {\n return;\n }\n\n switch (e.key) {\n case \"Escape\":\n this.closeMenu();\n\n return { stop: true, prevent: true };\n\n case \"ArrowLeft\":\n this.openMenu((this._openIndex - 1 + this._panels.length) % this._panels.length);\n\n return { stop: true, prevent: true };\n\n case \"ArrowRight\":\n this.openMenu((this._openIndex + 1) % this._panels.length);\n\n return { stop: true, prevent: true };\n\n case \"ArrowDown\":\n if (panel.getFocusedIndex() < 0) {\n panel.focusItem(0);\n } else {\n panel.focusNext();\n }\n\n return { stop: true, prevent: true };\n\n case \"ArrowUp\":\n panel.focusPrev();\n\n return { stop: true, prevent: true };\n\n case \"Enter\":\n panel.activateFocused();\n\n return { stop: true, prevent: true };\n }\n\n return;\n };\n\n if (options?.menus) {\n this.setMenus(options.menus);\n }\n }\n\n /**\n * Replaces the current set of top-level menus.\n *\n * Disposes all existing [`MenuBarButton`](/api/component/menubar/classes/MenuBarButton) and [`Menu`](/api/overlay/classes/Menu) instances, then rebuilds\n * them from the given descriptors.\n *\n * @param menus - Ordered list of top-level menu descriptors.\n */\n setMenus(menus: MenuConfig[]): this {\n if (this._openIndex >= 0) {\n this.closeMenu();\n }\n\n for (const panel of this._panels) {\n panel.dispose();\n }\n\n this._buttons.length = 0;\n this._panels.length = 0;\n\n this.disposeAllComponents();\n\n for (let i = 0; i < menus.length; i++) {\n const menu = menus[i];\n const index = i;\n\n const button = new MenuBarButton(\n menu.label,\n () => {\n if (this._openIndex === index) {\n this.closeMenu();\n } else {\n this.openMenu(index);\n }\n },\n () => {\n if (this._quickSwitchActive && this._openIndex !== index) {\n this.openMenu(index);\n }\n },\n menu.glyph !== undefined ? { glyph: menu.glyph } : undefined\n );\n\n const panel = new Menu(menu.items, () => { this.closeMenu(); });\n\n this._buttons.push(button);\n this._panels.push(panel);\n this.addComponent(button);\n }\n\n return this;\n }\n\n /**\n * Disposes every top-level dropdown, then runs the inherited teardown.\n * `_panels` are LayerManager-mounted panels, never registered children\n * (see Menu.ts's class comment), so `super.destructor()`'s child\n * recursion cannot reach them. `_buttons` need no matching call — they\n * are registered via `addComponent` above, so the base recursion already\n * reaches them. `Component.dispose()` is idempotent, so a panel already\n * disposed by a `setMenus` call that ran just before teardown costs\n * nothing here.\n */\n protected destructor(): void {\n for (const panel of this._panels) {\n panel.dispose();\n }\n\n super.destructor();\n }\n\n /**\n * Programmatically opens the menu at the given index, closing any currently open menu first.\n *\n * @param index - Zero-based index into the menus array.\n */\n openMenu(index: number): this {\n if (index < 0 || index >= this._panels.length) {\n return this;\n }\n\n if (index === this._openIndex) {\n return this;\n }\n\n if (this._openIndex >= 0) {\n this._panels[this._openIndex].close();\n this._buttons[this._openIndex].setActive(false);\n }\n\n this._openIndex = index;\n this._quickSwitchActive = true;\n\n this._buttons[index].setActive(true);\n // Exclude only the opener button from the panel's outside-click dismissal\n // (so its own mousedown does not self-close before the click toggles it),\n // not the whole bar — otherwise a click on empty bar space would be\n // treated as inside and never close the menu.\n this._panels[index].setExcludedElement(this._buttons[index].getElement(true)!);\n this._panels[index].open(this._buttons[index].getElement(true)!);\n\n if (!this._keydownListening) {\n this._keydownListening = true;\n Event.addViewportListener(this, \"keydown\", this._onKeyDown);\n }\n\n return this;\n }\n\n /**\n * Closes the currently open menu, if any.\n */\n closeMenu(): this {\n if (this._openIndex < 0) {\n return this;\n }\n\n this._panels[this._openIndex].close();\n this._buttons[this._openIndex].setActive(false);\n\n this._openIndex = -1;\n this._quickSwitchActive = false;\n\n if (this._keydownListening) {\n this._keydownListening = false;\n Event.removeViewportListener(this, \"keydown\", this._onKeyDown);\n }\n\n return this;\n }\n\n /**\n * Returns the index of the currently open menu, or `-1` if none is open.\n *\n * @returns The open menu index, or -1.\n */\n getOpenIndex(): number {\n return this._openIndex;\n }\n}\n\nconst MenuBarCallable = callable(MenuBar);\ntype MenuBarCallable = MenuBar;\nexport {\n MenuBar as _MenuBar,\n MenuBarCallable as MenuBar\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button } from \"~/component/button/Button.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Container, ContainerOptions } from \"~/core/Container.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { VBox } from \"~/layout/VBox.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { RovingTabIndex } from \"~/core/RovingTabIndex.js\";\nimport { Menu } from \"~/overlay/Menu.js\";\nimport { MenuItemConfig } from \"~/component/container/MenuItem.js\";\nimport { Spacer } from \"~/component/container/Spacer.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { ellipsis_v } from \"~/glyphs/solid/ellipsis_v.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation, AxisEnd } from \"~/primitive/Axis.js\";\n\n// Register the overflow trigger's chevron eagerly at module load — same pattern\n// as SplitButton registering its caret_down — so the lazily-created \"more\"\n// affordance always resolves its glyph without the consumer pre-registering it.\nGlyph.register(ellipsis_v);\n\n/**\n * Overflow behaviour for a {@link ToolBar} whose children exceed its measured\n * extent. `\"clip\"` (the default) lets the children spill into the parent's\n * clipping region. `\"menu\"` hides the `Button` / `ToggleButton` children that\n * don't fit and surfaces them in a dropdown opened by a trailing chevron\n * affordance. Menu overflow is horizontal-only; vertical bars always clip.\n *\n * @category Components\n */\nexport type ToolBarOverflow = \"clip\" | \"menu\";\n\n/**\n * Construction-time options for {@link ToolBar}.\n *\n * @category Components\n */\nexport interface ToolBarOptions extends ContainerOptions {\n orientation?: AxisOrientation;\n compact?: boolean;\n overflow?: ToolBarOverflow;\n /**\n * Edge the `\"menu\"` overflow trigger sits on — `\"end\"` (default) or\n * `\"start\"`. No visible effect unless `overflow` is `\"menu\"`. Runtime\n * counterpart `setOverflowSide`.\n */\n overflowSide?: AxisEnd;\n /**\n * When `true` (the default), `Button` / `ToggleButton` children added to the\n * bar are switched to flat appearance for the classical toolbar look — no\n * resting frame, a light frame on hover, and a sunken inset frame on press.\n * Set `false` to keep raised buttons. Runtime counterpart `setFlat`.\n */\n flat?: boolean;\n}\n\n/**\n * Fallback inter-child spacing in pixels for the overflow reserve math only.\n * `_computeOverflowed` reserves a gap between children when measuring the\n * fit-set; it reads the live `getComponentSpacing()` and falls back to this\n * constant only when the layout manager isn't an `HBox`. The bar no longer\n * drives any gap itself (spacing defaults to 0), so this is purely the typed\n * fallback that keeps the overflow arithmetic well-defined.\n */\nconst TOOLBAR_GAP_DEFAULT: number = 4;\n\n/**\n * Registry glyph rendered on the overflow (\"more\") trigger button. Verified\n * present in the solid glyph set (`glyphs/solid/ellipsis_v.ts`); the vertical\n * ellipsis is the conventional overflow affordance for a horizontal bar.\n */\nconst OVERFLOW_TRIGGER_GLYPH: string = \"ellipsis-v\";\n\n/**\n * User-overridable defaults forwarded to `super` via the options bag.\n */\nconst _defaultToolBarOptions: Partial<ToolBarOptions> = {\n orientation: \"horizontal\",\n compact: true,\n overflow: \"clip\",\n overflowSide: \"end\",\n flat: true,\n backgroundColor: \"var(--ts-ui-toolbar-bg, rgb(245, 245, 245))\",\n};\n\n/**\n * A horizontal (or vertical) strip of related controls — e.g. Bold / Italic\n * / Underline in a text editor, or Cut / Copy / Paste in a file manager.\n *\n * `ToolBar` extends [`Container`](/api/core/classes/Container) and defaults to\n * compact mode (`compact: true`), so at construction it drops its own panel\n * insets to zero and renders its `Button` / `ToggleButton` children compact;\n * `setCompact(false)` restores the 4-pixel panel insets and the children's\n * default rendering. Layout defaults to a horizontal\n * [`HBox`](/api/layout/classes/HBox); pass `orientation: \"vertical\"` (or call\n * `setOrientation(\"vertical\")`) to swap to a [`VBox`](/api/layout/classes/VBox).\n *\n * Children can be any [`Component`](/api/core/classes/Component) — typically\n * [`Button`](/api/component/button/classes/Button),\n * [`ToggleButton`](/api/component/button/classes/ToggleButton),\n * [`ButtonGroup`](/api/overlay/classes/ButtonGroup) members,\n * [`ComboBox`](/api/component/input/classes/ComboBox), or {@link ToolBarSeparator}.\n * Focusable children (`tabindex >= 0`) are auto-registered with an internal\n * [`RovingTabIndex`](/api/core/classes/RovingTabIndex) so Arrow keys cycle\n * focus between them, matching the\n * [`ButtonGroup`](/api/overlay/classes/ButtonGroup) keyboard-nav pattern.\n *\n * @example\n * ```typescript\n * import { ToolBar, ToolBarSeparator } from '@jimka/typescript-ui/component/menubar';\n * import { Button } from '@jimka/typescript-ui/component/button';\n *\n * const bar = new ToolBar();\n * bar.addComponent(new Button('Cut'));\n * bar.addComponent(new Button('Copy'));\n * bar.addComponent(new Button('Paste'));\n * bar.addComponent(new ToolBarSeparator());\n * bar.addComponent(new Button('Find'));\n * ```\n *\n * @category Components\n */\nclass ToolBar<TOptions extends ToolBarOptions = ToolBarOptions> extends Container<TOptions> {\n\n declare private _orientation: AxisOrientation;\n declare private _compact: boolean;\n declare private _overflowMode: ToolBarOverflow;\n declare private _overflowSide: AxisEnd;\n declare private _flat: boolean;\n declare private _rovingTabIndex: RovingTabIndex;\n declare private _onKeyDown: (e: KeyboardEvent) => Event.ListenerResult;\n declare private _overflowButton: Button | null;\n declare private _overflowMenu: Menu | null;\n declare private _overflowSpacer: Spacer | null;\n\n /**\n * Constructs a `ToolBar`.\n *\n * @param options - Optional construction-time options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n *\n * @remarks The parameter is typed as the concrete {@link ToolBarOptions}\n * rather than the class's `TOptions` parameter so that passing an options\n * literal (e.g. `new ToolBar({ compact: true })`) cannot narrow `TOptions`\n * to that literal — which would type the instance as `ToolBar<{ compact:\n * true }>` and fail the weak-type assignability check when it is later used\n * as a base `Component` (e.g. `container.addComponent(toolbar)`). `TOptions`\n * stays at its `ToolBarOptions` default.\n */\n constructor(options?: ToolBarOptions, subclassDefaults?: Partial<ToolBarOptions>);\n constructor(options?: ToolBarOptions, subclassDefaults?: Partial<TOptions>) {\n super(\n options as TOptions,\n { ..._defaultToolBarOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n this.getAria().setRole(\"toolbar\");\n this.getAria().setTabIndex(0);\n\n this._onKeyDown = (e: KeyboardEvent): Event.ListenerResult => {\n const isHoriz = this._orientation === \"horizontal\";\n const fwd = isHoriz ? \"ArrowRight\" : \"ArrowDown\";\n const back = isHoriz ? \"ArrowLeft\" : \"ArrowUp\";\n\n if (e.key === fwd) {\n this._rovingTabIndex.moveNext();\n\n return { prevent: true };\n } else if (e.key === back) {\n this._rovingTabIndex.movePrev();\n\n return { prevent: true };\n }\n };\n\n Event.addSubtreeListener(this, \"keydown\", this._onKeyDown);\n }\n\n /**\n * Applies a {@link ToolBarOptions} bag. Inherited `Container` fields cascade\n * through `super.applyOptions`; the `ToolBar`-specific fields\n * (orientation, compact, overflow) are dispatched here when set.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n // These fields all carry a class default and seed construction-time\n // backing state, so dispatch the caller value or the class default —\n // never leave the setter unfired (mirrors Panel.setAutoScroll).\n this.applyOrientation(options.orientation ?? this.getOrientation(), options);\n this.setCompact(options.compact ?? this.isCompact());\n // Dispatched before `overflow` so the trigger, created on entry to\n // `\"menu\"` mode, is positioned on the configured side from the start.\n this.setOverflowSide(options.overflowSide ?? this.getOverflowSide());\n this.setOverflow(options.overflow ?? this.getOverflow());\n this.setFlat(options.flat ?? this.isFlat());\n\n return this;\n }\n\n /**\n * Sets the layout direction. Horizontal toolbars pack children\n * left-to-right via [`HBox`](/api/layout/classes/HBox); vertical toolbars\n * pack them top-to-bottom via [`VBox`](/api/layout/classes/VBox). Child\n * spacing is preserved across the swap; the trailing-edge border flips\n * from bottom to right (or vice versa) to match the new direction.\n *\n * Existing {@link ToolBarSeparator} children are **not** auto-flipped —\n * see the architecture note in the plan.\n *\n * @param value - The new orientation.\n *\n * @returns This component, for method chaining.\n */\n setOrientation(value: AxisOrientation): this {\n this.applyOrientation(value);\n\n return this;\n }\n\n /**\n * Recomputes the layout manager, ARIA orientation, and trailing-edge border\n * for `value`. A no-op when `value` matches the current orientation.\n *\n * @param value - The new orientation.\n * @param options - Passed only from the constructor's `applyOptions`\n * dispatch; when its `border` is set, that value wins over the\n * orientation-derived border so a caller-supplied `border` option\n * survives construction. Every runtime caller (the public\n * {@link setOrientation}) omits it, so the border is always recomputed\n * from `value`.\n */\n private applyOrientation(value: AxisOrientation, options?: ToolBarOptions): void {\n if (value === this._orientation) {\n return;\n }\n\n const oldLM = this.getLayoutManager();\n // Default to flush (0) — the bar no longer drives a gap; child density\n // comes from the buttons' own compact insets. A consumer-set spacing on\n // an existing HBox/VBox is preserved across the orientation swap.\n const gap = (oldLM instanceof HBox || oldLM instanceof VBox)\n ? oldLM.getComponentSpacing()\n : 0;\n\n const newLM: HBox | VBox = value === \"horizontal\" ? new HBox() : new VBox();\n newLM.setComponentSpacing(gap);\n newLM.setStretching(true);\n\n this.setLayoutManager(newLM);\n this._orientation = value;\n\n this.getAria().setOrientation(value);\n\n if (options?.border !== undefined) {\n this.setBorder(options.border);\n return;\n }\n\n const ruleColor = \"var(--ts-ui-toolbar-border, rgb(220, 220, 220))\";\n\n if (value === \"horizontal\") {\n this.setBorder({ borderBottom: `1px solid ${ruleColor}` });\n } else {\n this.setBorder({ borderRight: `1px solid ${ruleColor}` });\n }\n }\n\n /**\n * Returns the current orientation.\n *\n * @returns `\"horizontal\"` or `\"vertical\"`.\n */\n getOrientation(): AxisOrientation {\n return this._orientation ?? this._defaultOptions.orientation!;\n }\n\n /**\n * Toggles compact mode. In compact mode the bar's own panel insets shrink\n * from `(4, 4, 4, 4)` to `(0, 0, 0, 0)` and every `Button` / `ToggleButton`\n * child is switched to compact rendering (tighter button insets), the same\n * way {@link setFlat} drives the flat appearance onto its button children.\n * Child spacing is left untouched — the bar packs its children flush and the\n * density comes from the buttons themselves.\n *\n * @param value - `true` to enable compact mode, `false` to restore defaults.\n *\n * @returns This component, for method chaining.\n */\n setCompact(value: boolean): this {\n if (value === this._compact) {\n return this;\n }\n\n this._compact = value;\n\n // Compact packs flush to its edges (zero inset) so a toolbar sits tight\n // against the surrounding chrome; the density between children still\n // comes from the buttons' own compact insets. Non-compact restores the\n // roomy 4px panel insets.\n const inset = value ? 0 : 4;\n\n this.setInsets(new Insets(inset, inset, inset, inset));\n\n for (const child of this.getComponents()) {\n if (child instanceof Button) {\n child.setCompact(value);\n }\n }\n\n this.doLayout();\n\n return this;\n }\n\n /**\n * Returns whether compact mode is currently active.\n *\n * @returns `true` if compact mode is enabled.\n */\n isCompact(): boolean {\n return this._compact ?? this._defaultOptions.compact!;\n }\n\n /**\n * Sets the overflow strategy. `\"clip\"` lets children spill into the parent's\n * clipping region. `\"menu\"` hides the `Button` / `ToggleButton` children\n * that don't fit and surfaces them in a dropdown opened by a trailing\n * chevron affordance; the trigger and its rebuild-mode\n * [`Menu`](/api/overlay/classes/Menu) are created lazily on first entry to\n * `\"menu\"` mode. Menu overflow applies to horizontal bars only — a vertical\n * bar always clips.\n *\n * @param value - `\"clip\"` or `\"menu\"`.\n *\n * @returns This component, for method chaining.\n */\n setOverflow(value: ToolBarOverflow): this {\n this._overflowMode = value;\n\n if (value === \"menu\" && this._overflowButton === undefined) {\n this._createOverflowAffordance();\n }\n\n this.doLayout();\n\n return this;\n }\n\n /**\n * Lazily builds the overflow trigger — a flat, glyph-only `Button` carrying\n * the chevron glyph — and the rebuild-mode `Menu` it opens. The trigger is\n * appended through `super.addComponent` so it bypasses the flatten-children\n * pass in {@link addComponent} and is excluded from the overflow set by\n * identity. It starts hidden; {@link doLayout} shows it only once at least\n * one button has overflowed.\n */\n private _createOverflowAffordance(): void {\n const trigger = new Button({ flat: true, glyph: OVERFLOW_TRIGGER_GLYPH });\n\n trigger.setDisplayed(false);\n trigger.getAria().setLabel(\"More\");\n trigger.getAria().setHasPopup(\"menu\");\n\n trigger.on(\"action\", () => { this._toggleOverflowMenu(); });\n\n this._overflowButton = trigger;\n this._overflowMenu = new Menu();\n // Flex spacer that pushes a right-side trigger to the bar's far edge; it\n // is only parented while the side is `\"right\"` (see _positionOverflowTrigger).\n this._overflowSpacer = Spacer.flex();\n\n super.addComponent(trigger);\n\n this._positionOverflowTrigger();\n }\n\n /**\n * Pins the overflow trigger to the configured edge. For `\"end\"` a flex\n * {@link Spacer} is parented just before the trigger so the chevron is\n * driven to the bar's trailing edge (rather than sitting flush against the\n * last visible button); the final child order is `[content…, spacer, trigger]`.\n * For `\"start\"` the spacer is detached and the trigger leads as the first\n * child. A no-op when no trigger exists yet. Re-run whenever content is added\n * (the trigger must stay at the edge) or the side changes; the trailing run\n * of buttons still overflows regardless of the trigger's side.\n */\n private _positionOverflowTrigger(): void {\n const trigger = this._overflowButton;\n const spacer = this._overflowSpacer;\n if (trigger === undefined || trigger === null || spacer === undefined || spacer === null) {\n return;\n }\n\n if (this._overflowSide === \"end\") {\n if (spacer.getParentComponent() !== this) {\n super.addComponent(spacer);\n }\n\n // Order the tail as [spacer, trigger]: move the trigger last, then\n // slot the spacer immediately before it. `moveComponent` recomputes\n // the index after splicing the moved child out, so the pre-move\n // length-relative targets land both at the end.\n this.moveComponent(trigger, this.getComponents().length - 1);\n this.moveComponent(spacer, this.getComponents().length - 2);\n } else {\n if (spacer.getParentComponent() === this) {\n this.removeComponent(spacer);\n }\n\n this.moveComponent(trigger, 0);\n }\n }\n\n /**\n * Returns the current overflow strategy.\n *\n * @returns `\"clip\"` or `\"menu\"`.\n */\n getOverflow(): ToolBarOverflow {\n return this._overflowMode ?? this._defaultOptions.overflow!;\n }\n\n /**\n * Sets which edge the `\"menu\"` overflow trigger sits on. `\"end\"` (the\n * default) trails the visible buttons; `\"start\"` leads them. Only the\n * trigger's position changes — the overflowing buttons are the trailing run\n * either way. No visible effect until `overflow` is `\"menu\"`.\n *\n * @param value - `\"start\"` or `\"end\"`.\n *\n * @returns This component, for method chaining.\n */\n setOverflowSide(value: AxisEnd): this {\n if (value === this._overflowSide) {\n return this;\n }\n\n this._overflowSide = value;\n\n this._positionOverflowTrigger();\n this.doLayout();\n\n return this;\n }\n\n /**\n * Returns the edge the overflow trigger sits on.\n *\n * @returns `\"start\"` or `\"end\"`.\n */\n getOverflowSide(): AxisEnd {\n return this._overflowSide ?? this._defaultOptions.overflowSide!;\n }\n\n /**\n * Toggles the classical flat appearance for the bar's `Button` /\n * `ToggleButton` children. When `true` (the default), each such child is\n * switched to flat mode — no resting frame, a light frame on hover, a sunken\n * inset frame on press, and a depressed look for a toggled-on\n * `ToggleButton`. Glyph-only flat buttons also tighten to compact squares.\n * Setting `false` reverts existing button children to raised chrome.\n *\n * Non-`Button` children (separators, combo boxes, spacers) are left\n * untouched. The flag also governs children added later through\n * {@link addComponent}.\n *\n * @param value - `true` to flatten button children, `false` to restore them.\n *\n * @returns This component, for method chaining.\n */\n setFlat(value: boolean): this {\n if (value === this._flat) {\n return this;\n }\n\n this._flat = value;\n\n for (const child of this.getComponents()) {\n if (child instanceof Button) {\n child.setFlat(value);\n }\n }\n\n return this;\n }\n\n /**\n * Returns whether the bar flattens its `Button` children.\n *\n * @returns `true` if flat mode is enabled.\n */\n isFlat(): boolean {\n return this._flat ?? this._defaultOptions.flat!;\n }\n\n /**\n * Appends a child component and, when its tab-index marks it focusable,\n * registers it with the internal roving-tabindex group so Arrow keys\n * cycle focus through it.\n *\n * @param component - The child component to add.\n *\n * @returns This component, for method chaining.\n */\n override addComponent(component: Component, constraints?: LayoutConstraints): this {\n super.addComponent(component, constraints);\n\n if (this._rovingTabIndex === undefined) {\n this._rovingTabIndex = new RovingTabIndex();\n }\n\n if (component.getAria().getTabIndex() !== -1) {\n this._rovingTabIndex.add(component);\n }\n\n if (this._flat && component instanceof Button) {\n component.setFlat(true);\n }\n\n if (this._compact && component instanceof Button) {\n component.setCompact(true);\n }\n\n // Keep the overflow trigger pinned to its edge: a content child appended\n // after the trigger (the trigger is created before the demo's buttons\n // for a construction-time `overflow: \"menu\"`) would otherwise leave the\n // chevron stranded mid-row. No-op when no trigger exists.\n this._positionOverflowTrigger();\n\n return this;\n }\n\n /**\n * Lays the bar out and, in `\"menu\"` overflow mode on a horizontal bar,\n * reflows the `Button` / `ToggleButton` children that no longer fit into the\n * trailing chevron dropdown. The base pass runs first so children report\n * their resolved preferred widths; the reflow then re-derives the fit-set\n * from scratch each pass, so widening the bar restores previously-hidden\n * buttons. Vertical bars and `\"clip\"` mode skip the reflow entirely.\n *\n * @returns This component, for method chaining.\n */\n override doLayout(): this {\n super.doLayout();\n\n if (this._overflowMode !== \"menu\" || this._orientation !== \"horizontal\") {\n return this;\n }\n\n if (this._overflowButton === undefined || this._overflowButton === null) {\n return this;\n }\n\n this._reflowOverflow(this._overflowButton);\n\n return this;\n }\n\n /**\n * Re-derives which `Button` / `ToggleButton` children overflow the bar's\n * inner width and toggles their `display` accordingly, reserving room for\n * the trigger whenever at least one button is hidden. Only mutates child\n * visibility when the fit-set actually changed, so the\n * `setDisplayed`-triggered re-layout converges instead of thrashing. The\n * trigger itself is shown only while ≥1 button is overflowed and is then\n * positioned for the dropdown anchor.\n *\n * @param trigger - The lazily-created overflow trigger button.\n */\n private _reflowOverflow(trigger: Button): void {\n const insets = this.getInsets();\n const inner = this.getWidth() - insets.getLeft() - insets.getRight();\n\n const lm = this.getLayoutManager();\n const gap = (lm instanceof HBox) ? lm.getComponentSpacing() : TOOLBAR_GAP_DEFAULT;\n\n const children = this.getComponents().filter(child => child !== trigger && child !== this._overflowSpacer);\n const overflowed = this._computeOverflowed(children, trigger, inner, gap);\n\n let changed = false;\n\n for (const child of children) {\n const shouldHide = overflowed.includes(child);\n\n if (child.isDisplayed() === shouldHide) {\n child.setDisplayed(!shouldHide);\n changed = true;\n }\n }\n\n const wantTrigger = overflowed.length > 0;\n\n if (trigger.isDisplayed() !== wantTrigger) {\n trigger.setDisplayed(wantTrigger);\n changed = true;\n }\n\n if (changed) {\n super.doLayout();\n }\n }\n\n /**\n * Walks the (non-trigger) children left-to-right, accumulating preferred\n * widths plus inter-child gaps, and returns the `Button` / `ToggleButton`\n * children that cross the inner width. When nothing overflows the result is\n * empty; otherwise the trigger's own width is reserved so the chevron has\n * room. Non-`Button` children that don't fit are left in place (clipped) —\n * only buttons have a well-defined menu-row representation.\n *\n * @param children - The bar's children, excluding the trigger.\n * @param trigger - The overflow trigger, measured for its reserved width.\n * @param inner - The bar's inner content width in pixels.\n * @param gap - The inter-child spacing in pixels.\n *\n * @returns The overflowed button children, in document order.\n */\n private _computeOverflowed(children: Component[], trigger: Button, inner: number, gap: number): Component[] {\n const widthOf = (child: Component): number => child.getPreferredSize()?.width ?? 0;\n\n let total = 0;\n\n for (let i = 0; i < children.length; i++) {\n total += widthOf(children[i]);\n\n if (i > 0) {\n total += gap;\n }\n }\n\n if (total <= inner) {\n return [];\n }\n\n const reserve = widthOf(trigger) + gap;\n const available = inner - reserve;\n\n const overflowed: Component[] = [];\n\n let used = 0;\n let crossed = false;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const next = used + widthOf(child) + (i > 0 ? gap : 0);\n\n if (next > available) {\n crossed = true;\n }\n\n // Once the width crosses the available extent, every following\n // Button overflows so the hidden set stays a contiguous trailing\n // run; non-Button children past the crossover stay put (clipped).\n if (crossed && child instanceof Button) {\n overflowed.push(child);\n } else {\n used = next;\n }\n }\n\n return overflowed;\n }\n\n /**\n * Disposes the overflow dropdown, then runs the inherited teardown.\n * `_overflowMenu` is a LayerManager-mounted panel, never a registered\n * child (see Menu.ts's class comment), so `super.destructor()`'s child\n * recursion cannot reach it. `_overflowButton` needs no matching call —\n * it is registered via `addComponent` (`_createOverflowAffordance`), so\n * the base recursion already reaches it.\n */\n protected destructor(): void {\n this._overflowMenu?.dispose();\n\n super.destructor();\n }\n\n /**\n * Builds one {@link MenuItemConfig} per currently-overflowed button and\n * toggles the rebuild-mode dropdown anchored under the trigger — opening it,\n * or closing it when the trigger is pressed again. Each row's `action`\n * re-fires the source button's `\"click\"` (the DOM event behind its\n * `\"action\"`) so the dropdown drives the original handler.\n */\n private _toggleOverflowMenu(): void {\n const trigger = this._overflowButton;\n const menu = this._overflowMenu;\n\n if (trigger === null || trigger === undefined || menu === null || menu === undefined) {\n return;\n }\n\n const configs: MenuItemConfig[] = [];\n\n for (const child of this.getComponents()) {\n if (child === trigger || child.isDisplayed() || !(child instanceof Button)) {\n continue;\n }\n\n const glyph = child.getGlyph()?.getGlyphName();\n\n configs.push({\n text: child.getText(),\n glyph: glyph,\n action: () => { child.click(); },\n });\n }\n\n const triggerEl = trigger.getElement();\n\n if (!triggerEl) {\n return;\n }\n\n const rect = DOM.source.getViewportRect(trigger);\n\n // toggleFor excludes the trigger from the menu's outside-click dismissal\n // and remembers it, so re-pressing the overflow button closes the menu\n // instead of the close-then-reopen flash a bare show() would produce.\n menu.toggleFor(triggerEl, rect, configs);\n }\n}\n\nconst ToolBarCallable = callable(ToolBar);\ntype ToolBarCallable<TOptions extends ToolBarOptions = ToolBarOptions> = ToolBar<TOptions>;\nexport {\n ToolBar as _ToolBar,\n ToolBarCallable as ToolBar\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation } from \"~/primitive/Axis.js\";\n\n/**\n * Construction-time options for {@link ToolBarSeparator}.\n *\n * @category Components\n */\nexport interface ToolBarSeparatorOptions extends ComponentOptions {\n orientation?: AxisOrientation;\n}\n\n/**\n * User-overridable default fill; a caller-supplied `backgroundColor` wins.\n */\nconst _defaultToolBarSeparatorOptions: Partial<ToolBarSeparatorOptions> = {\n backgroundColor: \"var(--ts-ui-toolbar-separator-color, rgb(220, 220, 220))\",\n};\n\n/**\n * A thin divider rule used inside a [`ToolBar`](/api/component/menubar/classes/ToolBar) to visually group\n * related controls. Defaults to a vertical rule (for horizontal toolbars);\n * pass `orientation: \"horizontal\"` for a vertical toolbar.\n *\n * Renders as a single bordered DOM element. The rule colour is theme-driven\n * via `--ts-ui-toolbar-separator-color`. Separators report `role=\"separator\"`\n * with a matching `aria-orientation`, and stay out of the keyboard tab order.\n *\n * @example\n * ```typescript\n * import { ToolBar, ToolBarSeparator } from '@jimka/typescript-ui/component/menubar';\n * const bar = new ToolBar();\n * bar.addComponent(new ToolBarSeparator());\n * ```\n *\n * @category Components\n */\nclass ToolBarSeparator extends Component<ToolBarSeparatorOptions> {\n\n /**\n * Pixel thickness of the rendered rule — a 1-pixel hairline. The breathing\n * room on either side of the rule comes from the parent toolbar's HBox /\n * VBox `componentSpacing` (theme token `--ts-ui-toolbar-gap`, default 4 px),\n * so the separator itself only carries the line. A wider THICKNESS would\n * stack on top of the parent's spacing and produce an asymmetric gap.\n */\n static readonly THICKNESS: number = 1;\n\n private readonly _orientation: AxisOrientation;\n\n /**\n * Constructs a `ToolBarSeparator`.\n *\n * @param options - Optional construction-time options. `options.orientation`\n * selects the rule direction; defaults to `\"vertical\"`.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(\n options?: ToolBarSeparatorOptions,\n subclassDefaults?: Partial<ToolBarSeparatorOptions>,\n ) {\n super(options, { ..._defaultToolBarSeparatorOptions, ...(subclassDefaults ?? {}) });\n\n this._orientation = options?.orientation ?? \"vertical\";\n\n if (this._orientation === \"vertical\") {\n // preferredSize.height = 0 keeps the separator out of the parent\n // HBox's row-height computation. The rendered height comes from\n // the parent's stretching=true branch, clamped to maxSize.height\n // (MAX_VALUE → containerSize.height). preferredSize.width = THICKNESS\n // makes the toolbar's own preferred width count the separator.\n this.setPreferredSize({ width: ToolBarSeparator.THICKNESS, height: 0 });\n this.setMaxSize({ width: ToolBarSeparator.THICKNESS, height: Number.MAX_VALUE });\n } else {\n this.setPreferredSize({ width: 0, height: ToolBarSeparator.THICKNESS });\n this.setMaxSize({ width: Number.MAX_VALUE, height: ToolBarSeparator.THICKNESS });\n }\n\n // The element IS the rule — a 1 px line filled with the theme colour.\n this.getAria().setRole(\"separator\");\n this.getAria().setOrientation(this._orientation);\n this.getAria().setTabIndex(-1);\n }\n\n /**\n * Returns the orientation passed at construction time.\n *\n * @returns The `ToolBarSeparator` orientation — `\"vertical\"` or `\"horizontal\"`.\n */\n getOrientation(): AxisOrientation {\n return this._orientation;\n }\n}\n\nconst ToolBarSeparatorCallable = callable(ToolBarSeparator);\ntype ToolBarSeparatorCallable = ToolBarSeparator;\nexport {\n ToolBarSeparator as _ToolBarSeparator,\n ToolBarSeparatorCallable as ToolBarSeparator\n};\n"],"mappings":"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"}