@jimka/typescript-ui 0.5.0 → 0.7.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 (293) hide show
  1. package/dist/lib/{AbstractInput-B10DfLOf.js → AbstractInput-W2PLJV5_.js} +2 -2
  2. package/dist/lib/{AbstractInput-B10DfLOf.js.map → AbstractInput-W2PLJV5_.js.map} +1 -1
  3. package/dist/lib/Anchor-iZhsvMlT.js +2 -0
  4. package/dist/lib/Anchor-iZhsvMlT.js.map +1 -0
  5. package/dist/lib/AnimatedDropdown-D0RhVgv3.js +2 -0
  6. package/dist/lib/AnimatedDropdown-D0RhVgv3.js.map +1 -0
  7. package/dist/lib/Border-6GsTNV-2.js +2 -0
  8. package/dist/lib/Border-6GsTNV-2.js.map +1 -0
  9. package/dist/lib/Button-CnFAiQuV.js +2 -0
  10. package/dist/lib/Button-CnFAiQuV.js.map +1 -0
  11. package/dist/lib/{Card-CD3jxshU.js → Card-C20k2YHU.js} +2 -2
  12. package/dist/lib/{Card-CD3jxshU.js.map → Card-C20k2YHU.js.map} +1 -1
  13. package/dist/lib/Checkbox-CM1z8keM.js +2 -0
  14. package/dist/lib/Checkbox-CM1z8keM.js.map +1 -0
  15. package/dist/lib/CheckboxMenuRow-C1h4LPHR.js +2 -0
  16. package/dist/lib/CheckboxMenuRow-C1h4LPHR.js.map +1 -0
  17. package/dist/lib/{CodeEditor-BGlB232h.js → CodeEditor-CTL2WjF8.js} +2 -2
  18. package/dist/lib/CodeEditor-CTL2WjF8.js.map +1 -0
  19. package/dist/lib/ComboBox-PZ5YPL0X.js +2 -0
  20. package/dist/lib/ComboBox-PZ5YPL0X.js.map +1 -0
  21. package/dist/lib/Component-D99-15Zt.js +2 -0
  22. package/dist/lib/Component-D99-15Zt.js.map +1 -0
  23. package/dist/lib/Container-FWRjgF6T.js +2 -0
  24. package/dist/lib/{Container-C7RPLQEc.js.map → Container-FWRjgF6T.js.map} +1 -1
  25. package/dist/lib/DOM-Cjh7_7TF.js +2 -0
  26. package/dist/lib/DOM-Cjh7_7TF.js.map +1 -0
  27. package/dist/lib/Dialog-DN78RaVH.js +2 -0
  28. package/dist/lib/Dialog-DN78RaVH.js.map +1 -0
  29. package/dist/lib/{FieldDecorator-HG65hEtk.js → FieldDecorator-DyPX8CFh.js} +2 -2
  30. package/dist/lib/{FieldDecorator-HG65hEtk.js.map → FieldDecorator-DyPX8CFh.js.map} +1 -1
  31. package/dist/lib/{Fit-Cg3dPyZg.js → Fit-CaPMj7Up.js} +2 -2
  32. package/dist/lib/{Fit-Cg3dPyZg.js.map → Fit-CaPMj7Up.js.map} +1 -1
  33. package/dist/lib/{FloatingPanel-D5buuVrQ.js → FloatingPanel-Dsy_vJxi.js} +2 -2
  34. package/dist/lib/{FloatingPanel-D5buuVrQ.js.map → FloatingPanel-Dsy_vJxi.js.map} +1 -1
  35. package/dist/lib/Glyph-DiEpD3gy.js +2 -0
  36. package/dist/lib/Glyph-DiEpD3gy.js.map +1 -0
  37. package/dist/lib/{Grid-BYBohJIA.js → Grid-ft_UUpj8.js} +2 -2
  38. package/dist/lib/Grid-ft_UUpj8.js.map +1 -0
  39. package/dist/lib/GridConstraints-CvZ0Nzaw.js +2 -0
  40. package/dist/lib/{GridConstraints-Bts284FI.js.map → GridConstraints-CvZ0Nzaw.js.map} +1 -1
  41. package/dist/lib/{Header-BIFJK9nR.js → Header-Osm3IjDw.js} +2 -2
  42. package/dist/lib/{Header-BIFJK9nR.js.map → Header-Osm3IjDw.js.map} +1 -1
  43. package/dist/lib/{IconText-Dsb1xS-E.js → IconText-BBaYJ2Fx.js} +2 -2
  44. package/dist/lib/{IconText-Dsb1xS-E.js.map → IconText-BBaYJ2Fx.js.map} +1 -1
  45. package/dist/lib/LayoutSerialization-BC64__O7.js +2 -0
  46. package/dist/lib/LayoutSerialization-BC64__O7.js.map +1 -0
  47. package/dist/lib/List-CQbZK_pT.js +2 -0
  48. package/dist/lib/List-CQbZK_pT.js.map +1 -0
  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-CwHluLGT.js +2 -0
  52. package/dist/lib/Menu-CwHluLGT.js.map +1 -0
  53. package/dist/lib/{MenuButton-BR4KOFld.js → MenuButton-BqCT-1yv.js} +2 -2
  54. package/dist/lib/{MenuButton-BR4KOFld.js.map → MenuButton-BqCT-1yv.js.map} +1 -1
  55. package/dist/lib/OverlayFade-CuEXgimf.js +2 -0
  56. package/dist/lib/OverlayFade-CuEXgimf.js.map +1 -0
  57. package/dist/lib/{Panel-CpNQTLNF.js → Panel-CtViePqY.js} +2 -2
  58. package/dist/lib/{Panel-CpNQTLNF.js.map → Panel-CtViePqY.js.map} +1 -1
  59. package/dist/lib/{Position-PBVBW1JS.js → Position-BIEU1Eze.js} +2 -2
  60. package/dist/lib/Position-BIEU1Eze.js.map +1 -0
  61. package/dist/lib/{ProgressSpinner-lAsK26C-.js → ProgressSpinner-BuBvC1FY.js} +2 -2
  62. package/dist/lib/{ProgressSpinner-lAsK26C-.js.map → ProgressSpinner-BuBvC1FY.js.map} +1 -1
  63. package/dist/lib/RadioButton-Df5J-H6m.js +2 -0
  64. package/dist/lib/RadioButton-Df5J-H6m.js.map +1 -0
  65. package/dist/lib/RadioMenuRow-Cfv0x6Qj.js +2 -0
  66. package/dist/lib/RadioMenuRow-Cfv0x6Qj.js.map +1 -0
  67. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js → RovingTabIndex--w28AnXc.js} +2 -2
  68. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js.map → RovingTabIndex--w28AnXc.js.map} +1 -1
  69. package/dist/lib/Scrollbar-DcnueNJd.js +2 -0
  70. package/dist/lib/Scrollbar-DcnueNJd.js.map +1 -0
  71. package/dist/lib/SelectableText-DZNxjKXR.js +2 -0
  72. package/dist/lib/SelectableText-DZNxjKXR.js.map +1 -0
  73. package/dist/lib/{Slider-DZ9drUxn.js → Slider-DNfd8Lxz.js} +2 -2
  74. package/dist/lib/{Slider-DZ9drUxn.js.map → Slider-DNfd8Lxz.js.map} +1 -1
  75. package/dist/lib/{Spacer-SDhOMp2g.js → Spacer-BznfGbwG.js} +2 -2
  76. package/dist/lib/{Spacer-SDhOMp2g.js.map → Spacer-BznfGbwG.js.map} +1 -1
  77. package/dist/lib/TabButton-CAACsMov.js +2 -0
  78. package/dist/lib/TabButton-CAACsMov.js.map +1 -0
  79. package/dist/lib/TabCloseButton-CCiqsX3y.js +2 -0
  80. package/dist/lib/TabCloseButton-CCiqsX3y.js.map +1 -0
  81. package/dist/lib/Text-O-FWa5Cy.js +2 -0
  82. package/dist/lib/Text-O-FWa5Cy.js.map +1 -0
  83. package/dist/lib/Tooltip-CyICVu15.js +3 -0
  84. package/dist/lib/Tooltip-CyICVu15.js.map +1 -0
  85. package/dist/lib/Tree-CSEguhlk.js +2 -0
  86. package/dist/lib/Tree-CSEguhlk.js.map +1 -0
  87. package/dist/lib/VBox-DVe4UXwX.js +2 -0
  88. package/dist/lib/VBox-DVe4UXwX.js.map +1 -0
  89. package/dist/lib/VirtualScroller-ggPTCQb0.js +2 -0
  90. package/dist/lib/VirtualScroller-ggPTCQb0.js.map +1 -0
  91. package/dist/lib/assets/StoreWorker-B5NwRM2I.js +2 -0
  92. package/dist/lib/assets/StoreWorker-B5NwRM2I.js.map +1 -0
  93. package/dist/lib/component/button.es.js +1 -1
  94. package/dist/lib/component/button.es.js.map +1 -1
  95. package/dist/lib/component/chart.es.js +1 -1
  96. package/dist/lib/component/chart.es.js.map +1 -1
  97. package/dist/lib/component/container.es.js +1 -1
  98. package/dist/lib/component/container.es.js.map +1 -1
  99. package/dist/lib/component/diagram.es.js +1 -1
  100. package/dist/lib/component/diagram.es.js.map +1 -1
  101. package/dist/lib/component/display.es.js +1 -1
  102. package/dist/lib/component/display.es.js.map +1 -1
  103. package/dist/lib/component/editor.es.js +2 -2
  104. package/dist/lib/component/editor.es.js.map +1 -1
  105. package/dist/lib/component/input.es.js +1 -1
  106. package/dist/lib/component/input.es.js.map +1 -1
  107. package/dist/lib/component/list.es.js +1 -1
  108. package/dist/lib/component/list.es.js.map +1 -1
  109. package/dist/lib/component/menubar.es.js +1 -1
  110. package/dist/lib/component/menubar.es.js.map +1 -1
  111. package/dist/lib/component/table.es.js +6 -3
  112. package/dist/lib/component/table.es.js.map +1 -1
  113. package/dist/lib/component/tree.es.js +1 -1
  114. package/dist/lib/core.es.js +1 -1
  115. package/dist/lib/core.es.js.map +1 -1
  116. package/dist/lib/data.es.js +1 -1
  117. package/dist/lib/glyphs/solid/index.es.js +1 -1
  118. package/dist/lib/layout.es.js +1 -1
  119. package/dist/lib/layout.es.js.map +1 -1
  120. package/dist/lib/overlay.es.js +1 -1
  121. package/dist/lib/overlay.es.js.map +1 -1
  122. package/dist/lib/primitive.es.js +1 -1
  123. package/dist/lib/router.es.js +1 -1
  124. package/dist/lib/router.es.js.map +1 -1
  125. package/dist/lib/selectionsEqual-C7MrKMQr.js +2 -0
  126. package/dist/lib/selectionsEqual-C7MrKMQr.js.map +1 -0
  127. package/dist/lib/types/component/button/Button.d.ts +22 -0
  128. package/dist/lib/types/component/button/MenuButton.d.ts +1 -0
  129. package/dist/lib/types/component/button/PopupButton.d.ts +22 -0
  130. package/dist/lib/types/component/button/TabButton.d.ts +9 -0
  131. package/dist/lib/types/component/button/ToggleButton.d.ts +3 -0
  132. package/dist/lib/types/component/button/index.d.ts +2 -0
  133. package/dist/lib/types/component/chart/AbstractChart.d.ts +2 -0
  134. package/dist/lib/types/component/container/CheckboxMenuRow.d.ts +33 -0
  135. package/dist/lib/types/component/container/CollapseButton.d.ts +11 -3
  136. package/dist/lib/types/component/container/MenuItem.d.ts +15 -5
  137. package/dist/lib/types/component/container/MenuRow.d.ts +24 -0
  138. package/dist/lib/types/component/container/MenuSeparator.d.ts +4 -2
  139. package/dist/lib/types/component/container/RadioMenuRow.d.ts +33 -0
  140. package/dist/lib/types/component/container/Scrollbar.d.ts +5 -0
  141. package/dist/lib/types/component/container/SplitGutter.d.ts +7 -2
  142. package/dist/lib/types/component/container/TabBar.d.ts +2 -0
  143. package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
  144. package/dist/lib/types/component/container/index.d.ts +6 -1
  145. package/dist/lib/types/component/display/Markdown.d.ts +2 -1
  146. package/dist/lib/types/component/display/WebGLCanvas.d.ts +1 -0
  147. package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +4 -0
  148. package/dist/lib/types/component/input/AbstractPickerField.d.ts +5 -2
  149. package/dist/lib/types/component/input/AutoCompleteDropdown.d.ts +2 -0
  150. package/dist/lib/types/component/input/ComboBox.d.ts +3 -1
  151. package/dist/lib/types/component/input/Link.d.ts +2 -0
  152. package/dist/lib/types/component/input/PasswordField.d.ts +2 -0
  153. package/dist/lib/types/component/input/PickerInput.d.ts +2 -0
  154. package/dist/lib/types/component/input/SelectableText.d.ts +11 -0
  155. package/dist/lib/types/component/input/SpinButton.d.ts +2 -0
  156. package/dist/lib/types/component/input/Text.d.ts +16 -2
  157. package/dist/lib/types/component/input/TextArea.d.ts +2 -0
  158. package/dist/lib/types/component/input/TextField.d.ts +2 -0
  159. package/dist/lib/types/component/input/TextInput.d.ts +2 -0
  160. package/dist/lib/types/component/input/TimePickerDropdown.d.ts +3 -1
  161. package/dist/lib/types/component/input/UsernameField.d.ts +2 -0
  162. package/dist/lib/types/component/input/index.d.ts +2 -0
  163. package/dist/lib/types/component/list/AbstractSelectableList.d.ts +5 -3
  164. package/dist/lib/types/component/list/MultiSelectList.d.ts +2 -1
  165. package/dist/lib/types/component/shared/VirtualRowView.d.ts +2 -0
  166. package/dist/lib/types/component/table/Body.d.ts +52 -5
  167. package/dist/lib/types/component/table/Column.d.ts +3 -1
  168. package/dist/lib/types/component/table/ColumnConfig.d.ts +2 -0
  169. package/dist/lib/types/component/table/ColumnFilter.d.ts +27 -0
  170. package/dist/lib/types/component/table/Header.d.ts +31 -4
  171. package/dist/lib/types/component/table/Row.d.ts +24 -2
  172. package/dist/lib/types/component/table/Table.d.ts +31 -0
  173. package/dist/lib/types/component/table/TableExporter.d.ts +7 -3
  174. package/dist/lib/types/component/table/TablePanel.d.ts +1 -0
  175. package/dist/lib/types/component/table/TreeBody.d.ts +2 -1
  176. package/dist/lib/types/component/table/TreeTablePanel.d.ts +1 -0
  177. package/dist/lib/types/component/table/cell/Cell.d.ts +7 -2
  178. package/dist/lib/types/component/table/cell/CellText.d.ts +9 -0
  179. package/dist/lib/types/component/table/cell/Default.d.ts +1 -1
  180. package/dist/lib/types/component/table/cell/Filter.d.ts +54 -0
  181. package/dist/lib/types/component/table/cell/FilterClauseBadge.d.ts +21 -0
  182. package/dist/lib/types/component/table/cell/GroupSeparator.d.ts +9 -0
  183. package/dist/lib/types/component/table/cell/Header.d.ts +4 -0
  184. package/dist/lib/types/component/table/cell/ResizeHandle.d.ts +1 -1
  185. package/dist/lib/types/component/table/cell/editor/CellEditor.d.ts +1 -0
  186. package/dist/lib/types/component/table/cell/renderer/CellRenderer.d.ts +3 -2
  187. package/dist/lib/types/component/table/cell/renderer/Combo.d.ts +2 -0
  188. package/dist/lib/types/component/table/cell/renderer/Date.d.ts +2 -0
  189. package/dist/lib/types/component/table/cell/renderer/DateTime.d.ts +2 -0
  190. package/dist/lib/types/component/table/cell/renderer/Filter.d.ts +16 -0
  191. package/dist/lib/types/component/table/cell/renderer/Glyph.d.ts +1 -0
  192. package/dist/lib/types/component/table/cell/renderer/Link.d.ts +2 -0
  193. package/dist/lib/types/component/table/cell/renderer/Number.d.ts +3 -1
  194. package/dist/lib/types/component/table/cell/renderer/String.d.ts +5 -1
  195. package/dist/lib/types/component/table/cell/renderer/Time.d.ts +2 -0
  196. package/dist/lib/types/component/table/cell/renderer/TreeCell.d.ts +1 -0
  197. package/dist/lib/types/component/table/index.d.ts +7 -1
  198. package/dist/lib/types/component/tree/Tree.d.ts +17 -1
  199. package/dist/lib/types/component/tree/index.d.ts +1 -1
  200. package/dist/lib/types/core/AnimatedDropdown.d.ts +2 -9
  201. package/dist/lib/types/core/Body.d.ts +4 -0
  202. package/dist/lib/types/core/ClassStyleRules.d.ts +47 -3
  203. package/dist/lib/types/core/Component.d.ts +30 -2
  204. package/dist/lib/types/core/DOM.d.ts +15 -1
  205. package/dist/lib/types/core/Event.d.ts +11 -2
  206. package/dist/lib/types/core/LayerManager.d.ts +1 -0
  207. package/dist/lib/types/core/OverlayFade.d.ts +12 -0
  208. package/dist/lib/types/core/OverlayPosition.d.ts +6 -0
  209. package/dist/lib/types/core/StyleTarget.d.ts +2 -0
  210. package/dist/lib/types/core/Theme.d.ts +9 -0
  211. package/dist/lib/types/core/Util.d.ts +4 -0
  212. package/dist/lib/types/core/index.d.ts +6 -4
  213. package/dist/lib/types/data/AbstractStore.d.ts +3 -0
  214. package/dist/lib/types/data/FilterDescriptor.d.ts +13 -0
  215. package/dist/lib/types/data/index.d.ts +2 -1
  216. package/dist/lib/types/data/temporalText.d.ts +2 -0
  217. package/dist/lib/types/layout/BoxLayout.d.ts +6 -1
  218. package/dist/lib/types/layout/Grid.d.ts +1 -0
  219. package/dist/lib/types/layout/HFlow.d.ts +1 -1
  220. package/dist/lib/types/layout/Split.d.ts +10 -1
  221. package/dist/lib/types/layout/Tab.d.ts +7 -1
  222. package/dist/lib/types/layout/Table.d.ts +2 -0
  223. package/dist/lib/types/layout/VFlow.d.ts +1 -1
  224. package/dist/lib/types/layout/index.d.ts +1 -1
  225. package/dist/lib/types/overlay/AbstractWindow.d.ts +3 -0
  226. package/dist/lib/types/overlay/Dock.d.ts +1 -0
  227. package/dist/lib/types/overlay/Menu.d.ts +1 -1
  228. package/dist/lib/types/overlay/Popover.d.ts +3 -0
  229. package/dist/lib/types/overlay/PopupPanel.d.ts +19 -0
  230. package/dist/lib/types/overlay/Window.d.ts +2 -0
  231. package/dist/lib/types/overlay/index.d.ts +2 -0
  232. package/dist/lib/types/router/RoutePattern.d.ts +7 -0
  233. package/dist/lib/types/router/Router.d.ts +6 -2
  234. package/dist/lib/types/router/index.d.ts +1 -1
  235. package/dist/lib/validation.es.js +1 -1
  236. package/llms.txt +4 -0
  237. package/package.json +1 -1
  238. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js +0 -2
  239. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js.map +0 -1
  240. package/dist/lib/Anchor-BsblS5it.js +0 -2
  241. package/dist/lib/Anchor-BsblS5it.js.map +0 -1
  242. package/dist/lib/AnimatedDropdown-kL47HPGP.js +0 -2
  243. package/dist/lib/AnimatedDropdown-kL47HPGP.js.map +0 -1
  244. package/dist/lib/Border-CNS6aEXB.js +0 -2
  245. package/dist/lib/Border-CNS6aEXB.js.map +0 -1
  246. package/dist/lib/Button-T16zSZip.js +0 -2
  247. package/dist/lib/Button-T16zSZip.js.map +0 -1
  248. package/dist/lib/CodeEditor-BGlB232h.js.map +0 -1
  249. package/dist/lib/ComboBox-C9FYMuLv.js +0 -2
  250. package/dist/lib/ComboBox-C9FYMuLv.js.map +0 -1
  251. package/dist/lib/Component-w65rPK75.js +0 -2
  252. package/dist/lib/Component-w65rPK75.js.map +0 -1
  253. package/dist/lib/Container-C7RPLQEc.js +0 -2
  254. package/dist/lib/DOM-Ba8YRVel.js +0 -2
  255. package/dist/lib/DOM-Ba8YRVel.js.map +0 -1
  256. package/dist/lib/DragManager-UvPHSoRm.js +0 -2
  257. package/dist/lib/DragManager-UvPHSoRm.js.map +0 -1
  258. package/dist/lib/Glyph-DeJF_zsR.js +0 -2
  259. package/dist/lib/Glyph-DeJF_zsR.js.map +0 -1
  260. package/dist/lib/Grid-BYBohJIA.js.map +0 -1
  261. package/dist/lib/GridConstraints-Bts284FI.js +0 -2
  262. package/dist/lib/LayoutSerialization-ySzY1h2l.js +0 -2
  263. package/dist/lib/LayoutSerialization-ySzY1h2l.js.map +0 -1
  264. package/dist/lib/LayoutSizes-DKDK1Cle.js +0 -2
  265. package/dist/lib/LayoutSizes-DKDK1Cle.js.map +0 -1
  266. package/dist/lib/List-BPd-IXZR.js +0 -2
  267. package/dist/lib/List-BPd-IXZR.js.map +0 -1
  268. package/dist/lib/MemoryStore-BgP7-Uzn.js +0 -2
  269. package/dist/lib/MemoryStore-BgP7-Uzn.js.map +0 -1
  270. package/dist/lib/Menu-C0roOCY7.js +0 -2
  271. package/dist/lib/Menu-C0roOCY7.js.map +0 -1
  272. package/dist/lib/Position-PBVBW1JS.js.map +0 -1
  273. package/dist/lib/RadioButton-CCcIaL54.js +0 -2
  274. package/dist/lib/RadioButton-CCcIaL54.js.map +0 -1
  275. package/dist/lib/Scrollbar-C3ZZyZ1e.js +0 -2
  276. package/dist/lib/Scrollbar-C3ZZyZ1e.js.map +0 -1
  277. package/dist/lib/TabButton-DNo4ZgV8.js +0 -2
  278. package/dist/lib/TabButton-DNo4ZgV8.js.map +0 -1
  279. package/dist/lib/Text-CdHf3B-1.js +0 -2
  280. package/dist/lib/Text-CdHf3B-1.js.map +0 -1
  281. package/dist/lib/Tooltip-B_UF5bXD.js +0 -3
  282. package/dist/lib/Tooltip-B_UF5bXD.js.map +0 -1
  283. package/dist/lib/Tree-C7qLbIYH.js +0 -2
  284. package/dist/lib/Tree-C7qLbIYH.js.map +0 -1
  285. package/dist/lib/VBox-32fxpkDl.js +0 -2
  286. package/dist/lib/VBox-32fxpkDl.js.map +0 -1
  287. package/dist/lib/VirtualScroller-cvFNMS7U.js +0 -2
  288. package/dist/lib/VirtualScroller-cvFNMS7U.js.map +0 -1
  289. package/dist/lib/assets/StoreWorker-CgOBYoai.js +0 -2
  290. package/dist/lib/assets/StoreWorker-CgOBYoai.js.map +0 -1
  291. package/dist/lib/selectionsEqual-BrTxPMmK.js +0 -2
  292. package/dist/lib/selectionsEqual-BrTxPMmK.js.map +0 -1
  293. package/dist/lib/types/component/table/CellGeometry.d.ts +0 -6
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./DOM-Cjh7_7TF.js";import{S as t,h as n,t as r}from"./Component-D99-15Zt.js";import{t as i}from"./ListenerBag-WPdKuuds.js";import{t as a}from"./Glyph-DiEpD3gy.js";import{t as o}from"./Text-O-FWa5Cy.js";import{t as s}from"./ProgressSpinner-BuBvC1FY.js";import{caret_down as c}from"./glyphs/solid/caret_down.es.js";import{n as l,t as u}from"./selectionsEqual-C7MrKMQr.js";import{caret_right as d}from"./glyphs/solid/caret_right.es.js";var TreeNodeRenderer=class extends r{constructor(){super()}},LabelTreeNodeRenderer=class extends TreeNodeRenderer{_label;constructor(){super(),this.clearInsets(),this._label=new o(void 0,{truncate:!0}),this._label.clearInsets(),this._label.setAutoMeasure(!1)}getLabel(){return this._label}update(e){this._label.setText(e.node.label),this._label.measure()}getContentWidth(){return this._label.getPreferredSize()?.width??0}layoutChildren(e,t){let n=this.getContentBounds()??{x:0,y:0,height:t},r=Math.min(this.getContentWidth(),e);this._label.setAutoCommitStyle(!1),this._label.setX(n.x),this._label.setY(n.y),this._label.setWidth(r),this._label.setHeight(n.height),this._label.setLineHeight(n.height),this._label.setAutoCommitStyle(!0)}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._label.getElement(!0)),this}};a.register(c,d);var TreeRow=class extends r{_toggle=null;_spinner=null;_renderer;_node=null;_depth=0;constructor(e=()=>new LabelTreeNodeRenderer){super(),this.getAria().setRole(`treeitem`),this._renderer=e()}getToggle(){return this._toggle}getRenderer(){return this._renderer}setRenderer(t){let n=this.getElement();if(n){let r=this._renderer.getElement();r&&e.source.getParentNode(r)===n&&e.sink.removeChild(n,r),e.sink.appendChild(n,t.getElement(!0))}return this._renderer=t,this}getNode(){return this._node}getDepth(){return this._depth}setRowData(t,n,r,i,o,c,l,u){if(this._node=t,this._depth=n,this._toggle){let t=this.getElement();t&&e.sink.removeChild(t,this._toggle.getElement(!0)),this._toggle=null}if(this._spinner){let t=this.getElement();t&&e.sink.removeChild(t,this._spinner.getElement(!0)),this._spinner=null}if(u){let t=new s;this._spinner=t;let n=this.getElement();n&&e.sink.appendChild(n,t.getElement(!0))}else if(r){let t=new a(i?`caret-down`:`caret-right`);t.setCursor(`pointer`),t.clearInsets(),t.getAria().setHidden(!0),this._toggle=t;let n=this.getElement();n&&e.sink.appendChild(n,t.getElement(!0))}return this._renderer.update({node:t,depth:n,expanded:i,selected:l,hasChildren:r}),this.getAria().setLevel(n+1),this.getAria().setExpanded(r?i:null),this.getAria().setSetSize(o),this.getAria().setPosInSet(c),this}layoutChildren(e,t){let n=this.getContentBounds()??{x:0,y:0,width:this.getWidth()||0,height:e},r=n.x+this._depth*t;if(this._toggle){let e=this._toggle.getPreferredSize()?.height??n.height;this._toggle.setAutoCommitStyle(!1),this._toggle.setX(r),this._toggle.setY(n.y+Math.max(0,(n.height-e)/2)),this._toggle.setWidth(20),this._toggle.setHeight(e),this._toggle.setAutoCommitStyle(!0)}this._spinner&&(this._spinner.setAutoCommitStyle(!1),this._spinner.setX(r),this._spinner.setY(n.y),this._spinner.setWidth(20),this._spinner.setHeight(n.height),this._spinner.setAutoCommitStyle(!0),this._spinner.doLayout());let i=r+20,a=Math.max(0,n.x+n.width-i);this._renderer.setAutoCommitStyle(!1),this._renderer.setX(i),this._renderer.setY(n.y),this._renderer.setWidth(a),this._renderer.setHeight(n.height),this._renderer.setAutoCommitStyle(!0),this._renderer.layoutChildren(a,n.height)}getContentWidth(e){let t=this._depth*e,n=this._renderer.getContentWidth();return t+20+n}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._renderer.getElement(!0)),this}},f=n(TreeRow),p=16,m=24,h=200,g=`var(--ts-ui-table-row-selected, rgba(30, 100, 200, 0.15))`,_={backgroundColor:`var(--ts-ui-input-bg, rgb(255, 255, 255))`,overflow:`hidden`,maxSize:{width:2**53-1,height:2**53-1},rowOverflow:`scroll`,expandTrigger:`dblclick`},Tree=class extends l{_nodes=[];_expandedNodes=new Set;_flatRows=[];_lastRowWidth=0;_maxContentWidth=0;_selectedNodes=new Set;_loadingNodes=new Set;_loadedNodes=new Set;_pendingExpansions=new Map;_anchorNode=null;_focusNode=null;_listeners=new i;_rendererFactory=()=>new LabelTreeNodeRenderer;constructor(e,t){super(e,{..._,...t??{}}),this.getAria().setRole(`tree`),this.getAria().setTabIndex(0),this.getAria().setMultiselectable(!0),this.subscribeTheme(()=>this.onThemeReflow()),this.applyListeners(e?.listeners)}applyOptions(e){return super.applyOptions(e),e.rowOverflow!==void 0&&this.setRowOverflow(e.rowOverflow),e.expandTrigger!==void 0&&this.setExpandTrigger(e.expandTrigger),this}getRowOverflow(){return this._options.rowOverflow??this._defaultOptions.rowOverflow??`scroll`}setRowOverflow(e){return this._options.rowOverflow=e,this}getExpandTrigger(){return this._options.expandTrigger??this._defaultOptions.expandTrigger??`dblclick`}setExpandTrigger(e){return this._options.expandTrigger=e,this}getPreferredSize(){return this.getPreferredSizeConstraint()===null?{width:h,height:this._flatRows.length*this.getRowHeight()}:super.getPreferredSize()}setNodes(e){return this._nodes=e,this._expandedNodes.clear(),this._selectedNodes.clear(),this._loadingNodes.clear(),this._loadedNodes.clear(),this._pendingExpansions.clear(),this._anchorNode=null,this._focusNode=null,this._flatten(),this.getElement()&&(this._boundIndices.fill(-1),this.invalidateGeom(),this.renderWindow()),this}expandAll(){let addExpandable=e=>{for(let t of e)t.children&&t.children.length>0&&(this._expandedNodes.add(t),addExpandable(t.children))};return addExpandable(this._nodes),this._reflattenAndRender(),this}getRowHeight(){return m}createPoolRow(){return new f(this._rendererFactory)}getNodes(){return this._nodes}getSelectedNode(){return this._anchorNode}getSelectedNodes(){return Array.from(this._selectedNodes)}getExpandedNodes(){return Array.from(this._expandedNodes)}selectNode(e){let t=this._flatRows.findIndex(t=>t.node===e);return t<0?this:(this._selectedNodes.clear(),this._selectedNodes.add(e),this._anchorNode=e,this._focusNode=e,this._updateSelectionStyle(),this._scrollIntoView(t),this.renderWindow(),this._updateActiveDescendant(),this)}async revealByPredicate(e){let t=await this._findPath(this._nodes,e,[]);if(t===null)return null;for(let e=0;e<t.length-1;e++)this._expandedNodes.add(t[e]);this._reflattenAndRender();let n=t[t.length-1],r=this._flatRows.findIndex(e=>e.node===n);return r>=0&&this._scrollIntoView(r),n}async _findPath(e,t,n){for(let r of e){let e=[...n,r];if(t(r.data,r))return e;let i=await this._ensureChildrenLoaded(r);if(i.length>0){let n=await this._findPath(i,t,e);if(n!==null)return n}}return null}async _ensureChildrenLoaded(e){if(e.children&&e.children.length>0)return e.children;if(e.loadChildren!==void 0&&!this._loadedNodes.has(e))try{let t=await e.loadChildren();return e.children=t,this._loadedNodes.add(e),t}catch{return[]}return e.children??[]}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}setRendererFactory(e){this._rendererFactory=e;for(let t of this._rowPool)t.setRenderer(e());return this._boundIndices.fill(-1),this.invalidateGeom(),this.getElement()&&this.renderWindow(),this}getRendererFactory(){return this._rendererFactory}_isExpandable(e){return!!(e.children&&e.children.length>0)||e.hasChildren===!0}_flatten(){this._flatRows=[],this._maxContentWidth=0;let recurse=(e,t)=>{let n=e.length;for(let r=0;r<e.length;r++){let i=e[r];this._flatRows.push({node:i,depth:t,siblingCount:n,posInSet:r+1}),this._isExpandable(i)&&this._expandedNodes.has(i)&&i.children&&recurse(i.children,t+1)}};recurse(this._nodes,0)}_reflattenAndRender(){this._flatten(),this._boundIndices.fill(-1),this.invalidateGeom(),this.renderWindow()}expandNode(e){return this._expandedNodes.has(e)||this._expand(e),this}async expandNodeAsync(e){return this._expandedNodes.has(e)?!0:this._expand(e)}_onToggle(e){if(this._expandedNodes.has(e)){this._collapse(e);return}this._expand(e)}_expand(e){return e.loadChildren!==void 0&&!this._loadedNodes.has(e)&&!(e.children&&e.children.length)?this._expandLazy(e):(this._expandedNodes.add(e),this._reflattenAndRender(),this.emit(`expand`,e),Promise.resolve(!0))}_collapse(e){this._expandedNodes.delete(e),this._reflattenAndRender(),this.emit(`collapse`,e)}_expandLazy(e){let t=this._pendingExpansions.get(e);if(t!==void 0)return t;let n=this._loadAndExpand(e);return this._pendingExpansions.set(e,n),n.then(()=>{this._pendingExpansions.get(e)===n&&this._pendingExpansions.delete(e)}),n}async _loadAndExpand(e){this._loadingNodes.add(e),this._reflattenAndRender();let t=!1;try{let n=await e.loadChildren();if(!this._loadingNodes.has(e))return!1;e.children=n,this._loadedNodes.add(e),this._expandedNodes.add(e),t=!0}catch(t){if(!this._loadingNodes.has(e))return!1;this.emit(`loaderror`,e,t)}finally{this._loadingNodes.delete(e),this._reflattenAndRender()}return t&&this.emit(`expand`,e),t}_notifySelectionChange(e){u(e,this._selectedNodes)||this.emit(`selection`,this.getSelectedNodes())}_rangeSelect(e,t){let n=Math.min(e,t),r=Math.max(e,t);this._selectedNodes.clear();for(let e=n;e<=r;e++)this._selectedNodes.add(this._flatRows[e].node)}_selectAtIndex(e){if(e<0||e>=this._flatRows.length)return;let t=this._flatRows[e].node,n=new Set(this._selectedNodes);this._selectedNodes.clear(),this._selectedNodes.add(t),this._anchorNode=t,this._focusNode=t,this._updateSelectionStyle(),this._scrollIntoView(e),this.renderWindow(),this._updateActiveDescendant(),this._notifySelectionChange(n)}_extendSelectionTo(e){if(e<0||e>=this._flatRows.length)return;let t=new Set(this._selectedNodes),n=this._anchorNode?this._flatRows.findIndex(e=>e.node===this._anchorNode):e;this._rangeSelect(n<0?e:n,e),this._focusNode=this._flatRows[e].node,this._updateSelectionStyle(),this._scrollIntoView(e),this.renderWindow(),this._updateActiveDescendant(),this._notifySelectionChange(t)}_scrollIntoView(e){this.scrollRowIntoView(e)}_onKeyDown(e){if(!new Set([`ArrowDown`,`ArrowUp`,`ArrowLeft`,`ArrowRight`,`Home`,`End`]).has(e.key))return;let t=this._flatRows;if(t.length===0)return;let n=this._focusNode?t.findIndex(e=>e.node===this._focusNode):-1;if(e.key===`ArrowDown`){let r=n<0?0:Math.min(n+1,t.length-1);e.shiftKey?this._extendSelectionTo(r):this._selectAtIndex(r)}else if(e.key===`ArrowUp`){let t=n<0?0:Math.max(n-1,0);e.shiftKey?this._extendSelectionTo(t):this._selectAtIndex(t)}else if(e.key===`Home`)e.shiftKey?this._extendSelectionTo(0):this._selectAtIndex(0);else if(e.key===`End`){let n=t.length-1;e.shiftKey?this._extendSelectionTo(n):this._selectAtIndex(n)}else if(e.key===`ArrowRight`){if(n<0)return this._selectAtIndex(0),{prevent:!0};let{node:e}=t[n];if(!this._isExpandable(e))return{prevent:!0};this._expandedNodes.has(e)?this._selectAtIndex(n+1):this._onToggle(e)}else if(e.key===`ArrowLeft`){if(n<0)return{prevent:!0};let{node:e,depth:r}=t[n];if(this._isExpandable(e)&&this._expandedNodes.has(e)){this._onToggle(e);let t=this._flatRows.findIndex(t=>t.node===e);t>=0&&this._scrollIntoView(t)}else if(r>0){for(let e=n-1;e>=0;e--)if(t[e].depth===r-1){this._selectAtIndex(e);break}}}return{prevent:!0}}_handleClick(t){let n=t.target===null?null:e.source.intern(t.target);for(let r of this._rowPool){let i=r.getNode();if(!i)continue;let a=r.getToggle();if(a){let t=a.getElement();if(t&&(n===t||e.source.contains(t,n))){this._onToggle(i);return}}let o=r.getElement();if(!o||!e.source.contains(o,n)&&n!==o)continue;let s=this._flatRows.findIndex(e=>e.node===i);if(t.shiftKey&&this._anchorNode)this._extendSelectionTo(s);else if(t.ctrlKey||t.metaKey){let e=new Set(this._selectedNodes);this._selectedNodes.has(i)?this._selectedNodes.delete(i):this._selectedNodes.add(i),this._anchorNode=i,this._focusNode=i,this._updateSelectionStyle(),this._notifySelectionChange(e)}else this._selectAtIndex(s),this.getExpandTrigger()===`click`&&this._isExpandable(i)&&this._onToggle(i);return}}_handleContextMenu(t){let n=t.target===null?null:e.source.intern(t.target);for(let r of this._rowPool){let i=r.getNode();if(!i)continue;let a=r.getElement();if(!(!a||!e.source.contains(a,n)&&n!==a))return this.emit(`contextmenu`,i,t),{prevent:!0}}}_handleDblClick(t){let n=t.target===null?null:e.source.intern(t.target);for(let t of this._rowPool){let r=t.getNode();if(!r)continue;let i=t.getElement();if(!i||!e.source.contains(i,n)&&n!==i)continue;this.emit(`dblclick`,r);let a=t.getToggle(),o=a?a.getElement():void 0;return!(o&&(n===o||e.source.contains(o,n)))&&this._isExpandable(r)&&this.getExpandTrigger()===`dblclick`&&this._onToggle(r),{prevent:!0}}}_updateSelectionStyle(){for(let t of this._rowPool){let n=t.getElement();if(!n)continue;let r=t.getNode(),i=r!==null&&this._selectedNodes.has(r),a=r!==null&&r===this._focusNode;i?e.sink.apply(n,{style:{"background-color":g}}):e.sink.apply(n,{style:{"background-color":null}}),a?e.sink.apply(n,{style:{outline:`2px solid var(--ts-ui-focus-ring, rgba(30, 100, 200, 0.6))`,"outline-offset":`-2px`}}):e.sink.apply(n,{style:{outline:null,"outline-offset":null}}),t.getAria().setSelected(i)}}_updateActiveDescendant(){if(!this._focusNode){this.getAria().setActiveDescendant(``);return}for(let e of this._rowPool)if(e.getNode()===this._focusNode){this.getAria().setActiveDescendant(e.getId());return}this.getAria().setActiveDescendant(``)}onThemeReflow(){this._maxContentWidth=0,super.onThemeReflow()}renderWindow(){if(!this.getElement()||!this._scroller||this.deferRenderWhileFirstLayoutHeld())return;let e=this._scroller,t=this._flatRows.length,n=t*m;e.clampToContent(this._lastRowWidth,n);let r=this.getHeight()||0,i=this.computeVisibleWindow(e.getScrollY(),r,t),a=this.computePoolTarget(i.windowSize,r,t);this.growRowPool(a),this.alignPoolWindow(i.firstRow);let{reboundFlags:o,maxContentWidth:s}=this._bindAndMeasure(i.firstRow,i.windowSize);s>this._maxContentWidth&&(this._maxContentWidth=s);let c=this.getRowOverflow()===`clip`?e.getViewportWidth():Math.max(e.getViewportWidth(),this._maxContentWidth);c!==this._lastRowWidth&&(this._lastRowWidth=c,this.invalidateGeom()),this._positionRows(i.firstRow,i.windowSize,c,o),this.hideExcessPoolRows(i.windowSize),this._updateSelectionStyle(),e.layoutScrollbars(c,n),this.finishResumedRender()&&this._updateActiveDescendant()}_bindAndMeasure(e,t){let n=Array(t),r=0;for(let i=0;i<t;i++){let t=this._rowPool[i],a=e+i,o=this._flatRows[a],s=this._isExpandable(o.node),c=this._expandedNodes.has(o.node),l=this._loadingNodes.has(o.node),u=this._boundIndices[i]!==a;if(u){let e=this._selectedNodes.has(o.node);t.setRowData(o.node,o.depth,s,c,o.siblingCount,o.posInSet,e,l),this._boundIndices[i]=a}n[i]=u;let d=t.getContentWidth(p);d>r&&(r=d)}return{reboundFlags:n,maxContentWidth:r}}_positionRows(e,t,n,r){for(let i=0;i<t;i++){let t=this._rowPool[i],a=e+i,o=r[i],s=this.positionRow(i,a*m,n);(o||s)&&t.layoutChildren(m,p)}}init(e){super.init(e);let n=e||this.getElement();return n?(this.initScroller(n),t.addSubtreeListener(this,`click`,this._handleClick),t.addSubtreeListener(this,`contextmenu`,this._handleContextMenu),t.addSubtreeListener(this,`dblclick`,this._handleDblClick),t.addListener(this,`keydown`,this._onKeyDown),this.renderWindow(),this):this}doLayout(){return this.isLayoutPaused()?this:(super.doLayout(),this.renderWindowIfDeferred()||this.renderWindow(),this)}},v=n(Tree);export{LabelTreeNodeRenderer as n,TreeNodeRenderer as r,v as t};
2
+ //# sourceMappingURL=Tree-CSEguhlk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tree-CSEguhlk.js","names":[],"sources":["../../src/typescript/lib/component/tree/TreeNodeRenderer.ts","../../src/typescript/lib/component/tree/renderer/Label.ts","../../src/typescript/lib/component/tree/TreeRow.ts","../../src/typescript/lib/component/tree/Tree.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { TreeNodeRenderContext } from \"~/component/tree/TreeNodeRenderContext.js\";\n\n/**\n * Abstract base class for tree node renderers.\n *\n * @remarks\n * A `TreeNodeRenderer` controls the content area of a single\n * [`TreeRow`](/api/component/tree/classes/TreeRow) — that is, everything to\n * the right of the expand/collapse toggle. The owning [`Tree`](/api/component/tree/classes/Tree)\n * holds a renderer factory; each pool slot calls that factory once at\n * construction and rebinds via {@link update} when the slot is remapped to a\n * different node or its selection/expansion state changes.\n *\n * The toggle remains under `TreeRow`'s control because click detection routes\n * through it; renderers never see toggle clicks.\n *\n * Subclasses must implement {@link update}, {@link getContentWidth}, and\n * {@link layoutChildren}. See [`LabelTreeNodeRenderer`](/api/component/tree/classes/LabelTreeNodeRenderer)\n * for the canonical default.\n *\n * @category Components\n */\nexport abstract class TreeNodeRenderer extends Component {\n\n constructor() {\n super();\n }\n\n /**\n * Rebinds this renderer to new node data.\n *\n * @param context - The bound-node state for this render pass.\n *\n * @remarks\n * Called every time the owning pool slot is mapped to a different node, or\n * when an expansion-state change forces a full re-bind. Plain selection\n * style changes (background highlight, focus ring) are handled by the\n * `Tree` directly on the row element and do not flow through `update()`.\n */\n abstract update(context: TreeNodeRenderContext): void;\n\n /**\n * Returns the natural pixel width this renderer would render at given the\n * current bound node.\n *\n * @returns Content width in pixels.\n *\n * @remarks\n * Used by [`Tree`](/api/component/tree/classes/Tree) to compute the\n * horizontal scroll extent. Renderers that auto-measure their children\n * should return the sum of those measured widths.\n */\n abstract getContentWidth(): number;\n\n /**\n * Positions this renderer's internal children inside its content box.\n *\n * @param width - The horizontal extent of the renderer in pixels.\n * @param height - The vertical extent of the renderer in pixels.\n *\n * @remarks\n * Called by `TreeRow.layoutChildren` after the renderer's own size has\n * been set via `setX`/`setY`/`setWidth`/`setHeight`.\n *\n * The `width` and `height` arguments are this renderer's **outer** box, so\n * an implementation must not place children against them directly: take the\n * rectangle from [`getContentBounds()`](/api/core/classes/Component), which\n * subtracts any border and padding the renderer carries, and fall back to\n * the arguments only when it returns `null` (no element yet). A child's\n * containing block is already this renderer's padding box, so one placed\n * at `(0, 0)` sized to `width` / `height` starts inside the border and\n * overruns the opposite edge by its width, where the `overflow: hidden`\n * every component carries clips it.\n */\n abstract layoutChildren(width: number, height: number): void;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { TreeNodeRenderer } from \"~/component/tree/TreeNodeRenderer.js\";\nimport { TreeNodeRenderContext } from \"~/component/tree/TreeNodeRenderContext.js\";\n\n/**\n * The default [`TreeNodeRenderer`](/api/component/tree/classes/TreeNodeRenderer) —\n * a single `<span>` carrying the node's label.\n *\n * @remarks\n * Used as the implicit factory by [`Tree`](/api/component/tree/classes/Tree)\n * when no custom renderer is set. The internal `Text` runs with\n * `autoMeasure(false)`; an explicit `measure()` call after each `setText`\n * caches the natural width for `getContentWidth()` to read on the next layout\n * pass.\n *\n * @example\n * ```typescript\n * tree.setRendererFactory(() => new LabelTreeNodeRenderer());\n * ```\n *\n * @category Components\n */\nexport class LabelTreeNodeRenderer extends TreeNodeRenderer {\n\n private _label: Text;\n\n /**\n * Constructs a label renderer with an empty text node. The label is\n * populated on the first {@link update} call.\n */\n constructor() {\n super();\n this.clearInsets();\n\n this._label = new Text(undefined, { truncate: true });\n this._label.clearInsets();\n this._label.setAutoMeasure(false);\n }\n\n /**\n * Returns the underlying label component so consumers can tweak font /\n * colour properties at construction time.\n *\n * @returns The internal [`Text`](/api/component/input/classes/Text) instance.\n */\n getLabel(): Text {\n return this._label;\n }\n\n /**\n * Updates the rendered label text and re-measures.\n *\n * @param context - The bound-node state for this render pass.\n */\n update(context: TreeNodeRenderContext): void {\n this._label.setText(context.node.label);\n this._label.measure();\n }\n\n /**\n * Returns the cached natural width of the rendered label.\n *\n * @returns Label width in pixels.\n */\n getContentWidth(): number {\n return this._label.getPreferredSize()?.width ?? 0;\n }\n\n /**\n * Sizes the label to fill the renderer's allocated box and centres its\n * line-box vertically by matching `line-height` to the row height.\n *\n * The label goes inside this renderer's content box, so a border or padding\n * on the renderer shrinks it rather than being painted over.\n *\n * @param width - The row's available width in pixels. The label clamps to\n * this when it is narrower than the label's own natural width — its box\n * is otherwise always exactly as wide as its content (`getContentWidth`),\n * so `text-overflow: ellipsis` would never actually have room to trigger.\n * In `Tree`'s default `rowOverflow: \"scroll\"` mode this is a no-op: rows\n * already grow to fit the widest label (`Tree`'s `_maxContentWidth`), so\n * `width` is never narrower than `getContentWidth()` there. It only\n * clamps when `rowOverflow: \"clip\"` caps the row at the viewport width.\n * @param height - The vertical extent of the row in pixels. Used only while\n * the renderer has no element yet and the content box is unavailable.\n */\n layoutChildren(width: number, height: number): void {\n const box = this.getContentBounds() ?? { x: 0, y: 0, height };\n const labelWidth = Math.min(this.getContentWidth(), width);\n\n this._label.setAutoCommitStyle(false);\n this._label.setX(box.x);\n this._label.setY(box.y);\n this._label.setWidth(labelWidth);\n this._label.setHeight(box.height);\n this._label.setLineHeight(box.height);\n this._label.setAutoCommitStyle(true);\n }\n\n /**\n * Appends the label sub-component element to the renderer's DOM element.\n *\n * @param element - Optional element passed by the rendering pipeline; falls back to getElement().\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (!el) {\n return this;\n }\n\n DOM.sink.appendChild(el, this._label.getElement(true)!);\n\n return this;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { ProgressSpinner } from \"~/component/display/ProgressSpinner.js\";\nimport { TreeNode } from \"~/component/tree/TreeNode.js\";\nimport { TreeNodeRenderer } from \"~/component/tree/TreeNodeRenderer.js\";\nimport { LabelTreeNodeRenderer } from \"~/component/tree/renderer/Label.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { caret_down } from \"~/glyphs/solid/caret_down.js\";\nimport { caret_right } from \"~/glyphs/solid/caret_right.js\";\n\nGlyph.register(caret_down, caret_right);\n\n/** Width in pixels reserved for the expand/collapse toggle icon. */\nexport const TOGGLE_WIDTH = 20;\n\n/**\n * A single visible row in the {@link Tree} virtual-scroll pool.\n *\n * Each pool slot holds one {@link TreeNode} at a time. The {@link Tree} calls\n * {@link setRowData} to rebind a slot to a different node and\n * {@link layoutChildren} to reposition the toggle and renderer after the row's\n * own dimensions are updated.\n *\n * @remarks\n * The toggle ([`Glyph`](/api/component/display/classes/Glyph)) and content\n * renderer are appended directly to the row's DOM element in `init()` rather\n * than via `addComponent`, so their preferred-size change notifications do not\n * propagate up to the Tree and trigger unnecessary layout passes. Leaf rows\n * have no toggle; non-leaf rows swap in a fresh `caret-down` / `caret-right`\n * glyph on each state change rather than mutating a single character. The row\n * content area (everything to the right of the toggle) is owned by a\n * [`TreeNodeRenderer`](/api/component/tree/classes/TreeNodeRenderer) supplied\n * via the constructor factory.\n */\nclass TreeRow extends Component {\n\n private _toggle: Glyph | null = null;\n private _spinner: ProgressSpinner | null = null;\n private _renderer: TreeNodeRenderer;\n private _node: TreeNode | null = null;\n private _depth: number = 0;\n\n constructor(rendererFactory: () => TreeNodeRenderer = () => new LabelTreeNodeRenderer()) {\n super();\n\n this.getAria().setRole(\"treeitem\");\n\n this._renderer = rendererFactory();\n }\n\n /**\n * Returns the toggle icon glyph, or null when the bound node is a leaf.\n *\n * @returns The toggle [`Glyph`](/api/component/display/classes/Glyph) instance, or null.\n */\n getToggle(): Glyph | null {\n return this._toggle;\n }\n\n /**\n * Returns the renderer currently bound to this pool row.\n *\n * @returns The active [`TreeNodeRenderer`](/api/component/tree/classes/TreeNodeRenderer).\n */\n getRenderer(): TreeNodeRenderer {\n return this._renderer;\n }\n\n /**\n * Replaces this row's content renderer, swapping the underlying DOM\n * element in place.\n *\n * @param renderer - The new renderer instance to install.\n * @returns This row, for method chaining.\n *\n * @remarks\n * The new renderer's element is appended to the row immediately. The\n * caller is expected to follow up with `setRowData` (typically via the\n * Tree's next render pass) so the renderer receives an `update()` before\n * being laid out.\n */\n setRenderer(renderer: TreeNodeRenderer): this {\n const el = this.getElement();\n\n if (el) {\n const oldEl = this._renderer.getElement();\n if (oldEl && DOM.source.getParentNode(oldEl) === el) {\n DOM.sink.removeChild(el, oldEl);\n }\n\n DOM.sink.appendChild(el, renderer.getElement(true)!);\n }\n\n this._renderer = renderer;\n\n return this;\n }\n\n /**\n * Returns the tree node currently bound to this pool row.\n *\n * @returns The bound {@link TreeNode}, or null if the slot is unbound.\n */\n getNode(): TreeNode | null {\n return this._node;\n }\n\n /**\n * Returns the depth of the currently bound node.\n *\n * @returns The zero-based depth level.\n */\n getDepth(): number {\n return this._depth;\n }\n\n /**\n * Binds this pool slot to a new node, updating the toggle icon, content\n * renderer, and ARIA positional attributes.\n *\n * @param node - The tree node to display.\n * @param depth - The zero-based nesting depth (controls indentation).\n * @param hasChildren - Whether the node has child nodes (determines toggle visibility).\n * @param expanded - Whether the node is currently expanded.\n * @param siblingCount - Total number of siblings at this level under the same parent.\n * @param posInSet - 1-based position of this node among its siblings.\n * @param selected - Whether the node is currently selected.\n * @param loading - Whether this node's lazy children are currently loading;\n * when true a spinner replaces the toggle caret.\n */\n setRowData(node: TreeNode, depth: number, hasChildren: boolean, expanded: boolean, siblingCount: number, posInSet: number, selected: boolean, loading: boolean): this {\n this._node = node;\n this._depth = depth;\n\n if (this._toggle) {\n const el = this.getElement();\n if (el) {\n DOM.sink.removeChild(el, this._toggle.getElement(true)!);\n }\n this._toggle = null;\n }\n\n if (this._spinner) {\n const el = this.getElement();\n if (el) {\n DOM.sink.removeChild(el, this._spinner.getElement(true)!);\n }\n this._spinner = null;\n }\n\n if (loading) {\n // No explicit size: the spinner tracks the theme font-size so it\n // reads as the same visual weight as the caret glyph it replaces,\n // and `layoutChildren` fits it into the TOGGLE_WIDTH box.\n const spinner = new ProgressSpinner();\n this._spinner = spinner;\n\n const el = this.getElement();\n if (el) {\n DOM.sink.appendChild(el, spinner.getElement(true)!);\n }\n } else if (hasChildren) {\n const toggle = new Glyph(expanded ? \"caret-down\" : \"caret-right\");\n toggle.setCursor(\"pointer\");\n toggle.clearInsets();\n toggle.getAria().setHidden(true);\n this._toggle = toggle;\n\n const el = this.getElement();\n if (el) {\n DOM.sink.appendChild(el, toggle.getElement(true)!);\n }\n }\n\n this._renderer.update({ node, depth, expanded, selected, hasChildren });\n\n this.getAria().setLevel(depth + 1);\n this.getAria().setExpanded(hasChildren ? expanded : null);\n this.getAria().setSetSize(siblingCount);\n this.getAria().setPosInSet(posInSet);\n\n return this;\n }\n\n /**\n * Positions the toggle and renderer sub-components inside the row's content\n * box — the rectangle {@link Component.getContentBounds} returns, which a\n * border or padding on the row shrinks. Placing them against the row's outer\n * box instead makes the renderer overflow on both axes, and the row's\n * `overflow: hidden` clips it.\n *\n * @param rowHeight - The current height of this row in pixels. Used only\n * while the row has no element yet and the content box is unavailable;\n * otherwise the children's height comes from the content box, which is\n * this same height less the row's own border and padding.\n * @param indentPx - Pixels of indentation per depth level.\n */\n layoutChildren(rowHeight: number, indentPx: number): void {\n const box = this.getContentBounds()\n ?? { x: 0, y: 0, width: this.getWidth() || 0, height: rowHeight };\n\n const indent = box.x + this._depth * indentPx;\n\n if (this._toggle) {\n // The caret is a rigid SVG Glyph (min/max pinned to its 16×16\n // preferredSize), so it cannot fill the taller row — centre it\n // geometrically instead of relying on line-height (a no-op for SVG).\n const glyphHeight = this._toggle.getPreferredSize()?.height ?? box.height;\n this._toggle.setAutoCommitStyle(false);\n this._toggle.setX(indent);\n this._toggle.setY(box.y + Math.max(0, (box.height - glyphHeight) / 2));\n this._toggle.setWidth(TOGGLE_WIDTH);\n this._toggle.setHeight(glyphHeight);\n this._toggle.setAutoCommitStyle(true);\n }\n\n if (this._spinner) {\n this._spinner.setAutoCommitStyle(false);\n this._spinner.setX(indent);\n this._spinner.setY(box.y);\n this._spinner.setWidth(TOGGLE_WIDTH);\n this._spinner.setHeight(box.height);\n this._spinner.setAutoCommitStyle(true);\n\n // The spinner owns its inner arc, which only positions itself when\n // its own doLayout runs; the row appends it directly rather than via\n // addComponent, so drive that layout here once the box is sized.\n this._spinner.doLayout();\n }\n\n const labelX = indent + TOGGLE_WIDTH;\n const labelBoxW = Math.max(0, box.x + box.width - labelX);\n\n this._renderer.setAutoCommitStyle(false);\n this._renderer.setX(labelX);\n this._renderer.setY(box.y);\n this._renderer.setWidth(labelBoxW);\n this._renderer.setHeight(box.height);\n this._renderer.setAutoCommitStyle(true);\n\n this._renderer.layoutChildren(labelBoxW, box.height);\n }\n\n /**\n * Returns the natural pixel width needed to display this row's full content\n * (indent + toggle + renderer content) without horizontal clipping.\n *\n * @param indentPx - Pixels of indentation per depth level.\n */\n getContentWidth(indentPx: number): number {\n const indent = this._depth * indentPx;\n const contentW = this._renderer.getContentWidth();\n\n return indent + TOGGLE_WIDTH + contentW;\n }\n\n /**\n * Appends the renderer sub-component element to the row's DOM element.\n * The toggle glyph (if any) is appended on demand by `setRowData`.\n *\n * @param element - Optional element passed by the rendering pipeline; falls back to getElement().\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (!el) {\n return this;\n }\n\n DOM.sink.appendChild(el, this._renderer.getElement(true)!);\n\n return this;\n }\n}\n\nconst TreeRowCallable = callable(TreeRow);\ntype TreeRowCallable = TreeRow;\nexport {\n TreeRow as _TreeRow,\n TreeRowCallable as TreeRow\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport type { Size } from \"~/primitive/Size.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { VirtualRowView } from \"~/component/shared/VirtualRowView.js\";\nimport { selectionsEqual } from \"~/component/shared/selectionsEqual.js\";\nimport { TreeNode } from \"~/component/tree/TreeNode.js\";\nimport { TreeRow } from \"~/component/tree/TreeRow.js\";\nimport { TreeNodeRenderer } from \"~/component/tree/TreeNodeRenderer.js\";\nimport { LabelTreeNodeRenderer } from \"~/component/tree/renderer/Label.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * String-literal union of the events emitted by {@link Tree}.\n *\n * @category Components\n */\nexport type TreeEvent = \"selection\" | \"loaderror\" | \"contextmenu\" | \"dblclick\" | \"expand\" | \"collapse\";\n\n/**\n * How a row wider than the viewport is handled.\n *\n * - `\"scroll\"` (the default) — every row grows to the widest label seen so\n * far and the horizontal scrollbar reveals the rest. Appropriate when a\n * label's full text matters (e.g. a file path).\n * - `\"clip\"` — every row caps at the viewport width and a row-node renderer\n * that honours it (e.g. {@link LabelTreeNodeRenderer}) truncates with an\n * ellipsis instead. Appropriate for a TOC-style outline, where reading a\n * label matters more than its exact text and scrolling sideways to read\n * one would be worse than truncating it.\n *\n * @category Components\n */\nexport type TreeRowOverflow = \"scroll\" | \"clip\";\n\n/** Which click gesture on a row's body expands or collapses it. Default `\"dblclick\"`. */\nexport type TreeExpandTrigger = \"dblclick\" | \"click\";\n\n/** Pixels of indentation added per depth level. */\nconst INDENT_PX = 16;\n\n/** Fixed height in pixels for every visible row. */\nconst ROW_HEIGHT = 24;\n\n/** Default preferred width when the caller sets no explicit `preferredSize`. */\nconst DEFAULT_PREFERRED_WIDTH = 200;\n\n/** CSS background applied to the selected row. */\nconst SELECTED_BG = \"var(--ts-ui-table-row-selected, rgba(30, 100, 200, 0.15))\";\n\n/**\n * A pre-flattened entry in the visible subtree used by the virtual scroll.\n */\ninterface FlatRow {\n node: TreeNode;\n depth: number;\n siblingCount: number;\n posInSet: number;\n}\n\n/**\n * Construction-time options for {@link Tree}. Root nodes are set via\n * `setNodes()` and the renderer factory via `setRendererFactory()`; this\n * interface only carries the event-listener bag and the inherited\n * {@link ComponentOptions}.\n *\n * @category Components\n */\nexport interface TreeOptions extends ComponentOptions {\n /** How a row wider than the viewport is handled. Default `\"scroll\"`. See {@link TreeRowOverflow}. */\n rowOverflow?: TreeRowOverflow;\n\n /** Which click gesture on a row's body expands/collapses it. Default `\"dblclick\"`. See {@link TreeExpandTrigger}. */\n expandTrigger?: TreeExpandTrigger;\n\n /**\n * Multi-event listener bag dispatched to {@link Tree.on} at\n * construction time.\n */\n listeners?: {\n selection?: (nodes: TreeNode[]) => void;\n loaderror?: (node: TreeNode, error: unknown) => void;\n contextmenu?: (node: TreeNode, event: MouseEvent) => void;\n dblclick?: (node: TreeNode) => void;\n expand?: (node: TreeNode) => void;\n collapse?: (node: TreeNode) => void;\n };\n}\n\n/** User-overridable default fill; a caller-supplied `backgroundColor` wins. */\nconst _defaultTreeOptions: Partial<TreeOptions> = {\n backgroundColor: \"var(--ts-ui-input-bg, rgb(255, 255, 255))\",\n overflow: \"hidden\",\n maxSize: { width: Number.MAX_SAFE_INTEGER, height: Number.MAX_SAFE_INTEGER },\n rowOverflow: \"scroll\",\n expandTrigger: \"dblclick\",\n};\n\n/**\n * A hierarchical data view with collapsible nodes and virtual scrolling.\n *\n * Pass root nodes via {@link Tree.setNodes}. The tree flattens the currently\n * visible subtree into a single scrollable list and recycles a fixed pool of\n * internal row components — rebinding rows only when their data index changes,\n * mirroring the approach used in `table/Body.ts`.\n *\n * Scrolling is delegated to a `VirtualScroller` that owns the\n * rows-container transform, two custom scrollbar overlays, and the wheel/touch\n * handlers with fling momentum.\n *\n * @example\n * ```typescript\n * const tree = new Tree();\n * tree.setNodes([\n * { label: \"Fruits\", children: [\n * { label: \"Apple\" },\n * { label: \"Banana\" },\n * ]},\n * { label: \"Vegetables\" },\n * ]);\n * container.addComponent(tree);\n * ```\n *\n * @category Components\n */\nclass Tree extends VirtualRowView<TreeRow, TreeOptions> {\n\n private _nodes : TreeNode[] = [];\n private _expandedNodes : Set<TreeNode> = new Set();\n private _flatRows : FlatRow[] = [];\n private _lastRowWidth : number = 0;\n // Widest row content measured so far across the current flattened set. Only\n // the *visible* window is measured each frame, so tracking a running maximum\n // keeps the horizontal content width — and thus the H scrollbar — stable as\n // different-width rows scroll through the window, instead of jittering with\n // whatever happens to be on screen. Reset in `_flatten` when the row set is\n // rebuilt, so a narrower dataset (or a collapsed wide branch) re-derives it.\n private _maxContentWidth : number = 0;\n private _selectedNodes : Set<TreeNode> = new Set();\n private _loadingNodes : Set<TreeNode> = new Set();\n private _loadedNodes : Set<TreeNode> = new Set();\n private _pendingExpansions : Map<TreeNode, Promise<boolean>> = new Map();\n private _anchorNode : TreeNode | null = null;\n private _focusNode : TreeNode | null = null;\n private _listeners : ListenerBag<TreeEvent> = new ListenerBag<TreeEvent>();\n private _rendererFactory : () => TreeNodeRenderer = () => new LabelTreeNodeRenderer();\n\n constructor(options?: TreeOptions, subclassDefaults?: Partial<TreeOptions>) {\n super(options, { ..._defaultTreeOptions, ...(subclassDefaults ?? {}) });\n\n this.getAria().setRole(\"tree\");\n this.getAria().setTabIndex(0);\n this.getAria().setMultiselectable(true);\n\n this.subscribeTheme(() => this.onThemeReflow());\n\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Dispatches {@link TreeOptions.rowOverflow} and\n * {@link TreeOptions.expandTrigger}; every other option is inherited from\n * {@link Component}.\n *\n * @param options - The options bag carrying the values to apply.\n * @returns This tree, for method chaining.\n */\n protected applyOptions(options: TreeOptions): this {\n super.applyOptions(options);\n\n if (options.rowOverflow !== undefined) {\n this.setRowOverflow(options.rowOverflow);\n }\n\n if (options.expandTrigger !== undefined) {\n this.setExpandTrigger(options.expandTrigger);\n }\n\n return this;\n }\n\n /**\n * How a row wider than the viewport is handled.\n *\n * @returns The cached {@link TreeOptions.rowOverflow}, or the class default when never set.\n */\n getRowOverflow(): TreeRowOverflow {\n return this._options.rowOverflow ?? this._defaultOptions.rowOverflow ?? \"scroll\";\n }\n\n /**\n * Sets how a row wider than the viewport is handled.\n *\n * @param rowOverflow - `\"scroll\"` grows rows to fit the widest label and\n * scrolls; `\"clip\"` caps rows at the viewport width and truncates. See\n * {@link TreeRowOverflow}.\n * @returns This tree, for method chaining.\n */\n setRowOverflow(rowOverflow: TreeRowOverflow): this {\n this._options.rowOverflow = rowOverflow;\n\n return this;\n }\n\n /**\n * Which click gesture on a row's body expands or collapses it.\n *\n * @returns The cached {@link TreeOptions.expandTrigger}, or the class default when never set.\n */\n getExpandTrigger(): TreeExpandTrigger {\n return this._options.expandTrigger ?? this._defaultOptions.expandTrigger ?? \"dblclick\";\n }\n\n /**\n * Sets which click gesture on a row's body expands or collapses it.\n *\n * @param expandTrigger - `\"dblclick\"` requires a double-click on the row\n * body to toggle it, the file-explorer convention; `\"click\"` toggles it\n * on a plain single click, the IDE-sidebar convention. The caret always\n * toggles on a single click regardless of this setting. See\n * {@link TreeExpandTrigger}.\n * @returns This tree, for method chaining.\n */\n setExpandTrigger(expandTrigger: TreeExpandTrigger): this {\n this._options.expandTrigger = expandTrigger;\n\n return this;\n }\n\n /**\n * Reports a height derived from the current flattened row count as the\n * preferred height when the caller has set no explicit `preferredSize`,\n * mirroring `Markdown.getPreferredSize`'s own measured-content override —\n * so a `Tree` sized by its preferred size (e.g. a corner-pinned `Anchor`\n * child, not stretched) grows and shrinks with its actual content instead\n * of reporting a fixed guess. Width keeps the class default; an explicit\n * `preferredSize` constraint wins outright.\n *\n * @returns The preferred `{width, height}`.\n */\n getPreferredSize(): Size | null {\n if (this.getPreferredSizeConstraint() !== null) {\n return super.getPreferredSize();\n }\n\n return { width: DEFAULT_PREFERRED_WIDTH, height: this._flatRows.length * this.getRowHeight() };\n }\n\n /**\n * Replaces the root nodes, collapses all nodes, clears selection, and re-renders.\n *\n * @param nodes - The new array of root {@link TreeNode} objects.\n */\n setNodes(nodes: TreeNode[]): this {\n this._nodes = nodes;\n this._expandedNodes.clear();\n this._selectedNodes.clear();\n this._loadingNodes.clear();\n this._loadedNodes.clear();\n this._pendingExpansions.clear();\n this._anchorNode = null;\n this._focusNode = null;\n this._flatten();\n\n if (this.getElement()) {\n this._boundIndices.fill(-1);\n this.invalidateGeom();\n this.renderWindow();\n }\n\n return this;\n }\n\n /**\n * Expands every node that has (already-loaded) children, so the whole tree\n * is flattened and visible. Does not load lazy branches and does not change\n * the selection or emit any event.\n *\n * @returns This tree, for method chaining.\n */\n expandAll(): this {\n const addExpandable = (nodes: TreeNode[]): void => {\n for (const node of nodes) {\n if (node.children && node.children.length > 0) {\n this._expandedNodes.add(node);\n addExpandable(node.children);\n }\n }\n };\n\n addExpandable(this._nodes);\n this._reflattenAndRender();\n\n return this;\n }\n\n /** Returns the fixed row height every tree row is laid out at. */\n protected getRowHeight(): number {\n return ROW_HEIGHT;\n }\n\n /**\n * Constructs one pool row backed by the current renderer factory. The\n * base's `growRowPool` owns the append + parallel-array bookkeeping.\n *\n * @returns The new, un-appended pool row.\n */\n protected createPoolRow(): TreeRow {\n return new TreeRow(this._rendererFactory);\n }\n\n /**\n * Returns the root nodes currently displayed by the tree.\n *\n * @returns The array of root {@link TreeNode} objects.\n */\n getNodes(): TreeNode[] {\n return this._nodes;\n }\n\n /**\n * Returns the anchor node of the current selection (the last node selected by a plain click or\n * arrow key without Shift), or null if there is no selection.\n *\n * @returns The anchor {@link TreeNode}, or null.\n */\n getSelectedNode(): TreeNode | null {\n return this._anchorNode;\n }\n\n /**\n * Returns all currently selected nodes in no guaranteed order.\n *\n * @returns An array of selected {@link TreeNode} instances.\n */\n getSelectedNodes(): TreeNode[] {\n return Array.from(this._selectedNodes);\n }\n\n /**\n * Returns every currently expanded node, in no guaranteed order.\n *\n * @returns A snapshot array of expanded {@link TreeNode} instances.\n *\n * @remarks\n * `expandAll` and `revealByPredicate` fill the expanded set without\n * emitting `\"expand\"`, so this getter is how a caller reads the state\n * after either.\n */\n getExpandedNodes(): TreeNode[] {\n return Array.from(this._expandedNodes);\n }\n\n /**\n * Programmatically selects a single node, replacing any existing selection\n * and scrolling it into view.\n *\n * Unlike a user click this does **not** emit the `\"selection\"` event: it is a\n * state setter for syncing the tree to an external source of truth (e.g. the\n * active dock tab), so it must not re-trigger selection-driven side effects.\n * No-op when the node is not in the currently visible (flattened) set — e.g.\n * an ancestor is collapsed.\n *\n * @param node - A node currently held by this tree.\n *\n * @returns This tree, for method chaining.\n */\n selectNode(node: TreeNode): this {\n const index = this._flatRows.findIndex(r => r.node === node);\n if (index < 0) {\n return this;\n }\n\n this._selectedNodes.clear();\n this._selectedNodes.add(node);\n this._anchorNode = node;\n this._focusNode = node;\n\n this._updateSelectionStyle();\n this._scrollIntoView(index);\n this.renderWindow();\n this._updateActiveDescendant();\n\n return this;\n }\n\n /**\n * Finds the first node whose payload satisfies `predicate`, expanding every\n * ancestor on the path (loading lazy branches as needed) so the node becomes\n * visible, then scrolls it into view. Returns the node, or `null` when no\n * node matches.\n *\n * Unlike {@link selectNode} — which no-ops when the target sits under a\n * collapsed or not-yet-loaded ancestor — this walks the whole tree,\n * awaiting each lazy branch's `loadChildren` on the way down, so it can\n * reveal a node the user has never manually expanded to. Because it may\n * load every branch it visits, it is O(nodes) and issues one `loadChildren`\n * per unloaded branch it descends; call it for a deliberate \"jump to this\n * object\" action, not on a hot path.\n *\n * Revealing is not selecting: this method does not change the selection or\n * emit `\"selection\"`. Select the returned node with {@link selectNode} if the\n * reveal should also highlight it. It likewise expands ancestors without\n * emitting `\"expand\"` — read {@link getExpandedNodes} afterwards.\n *\n * The search is depth-first in root-then-child order and stops at the first\n * match. A lazy branch whose `loadChildren` rejects is skipped (its subtree\n * is treated as empty) and the walk continues; the failure is not surfaced\n * here (no `\"loaderror\"` is emitted for a reveal-driven load).\n *\n * @param predicate - Tested against each node's `data` payload (and the node\n * itself); return `true` for the node to reveal.\n *\n * @returns A promise resolving to the revealed {@link TreeNode}, or `null`.\n */\n async revealByPredicate(predicate: (data: unknown, node: TreeNode) => boolean): Promise<TreeNode | null> {\n const path = await this._findPath(this._nodes, predicate, []);\n if (path === null) {\n return null;\n }\n\n // Expand every ancestor (all but the target itself) so the target's row\n // enters the flattened set; the target's own children stay as they are.\n for (let i = 0; i < path.length - 1; i++) {\n this._expandedNodes.add(path[i]);\n }\n this._reflattenAndRender();\n\n const target = path[path.length - 1];\n const index = this._flatRows.findIndex(r => r.node === target);\n if (index >= 0) {\n this._scrollIntoView(index);\n }\n\n return target;\n }\n\n /**\n * Depth-first search for the first node satisfying `predicate`, returning\n * the full root-to-match path (inclusive) or `null`. Awaits and caches each\n * visited branch's lazy children so the walk can descend into unloaded\n * subtrees.\n *\n * @param nodes - The sibling nodes to search at this level.\n * @param predicate - The match test (see {@link revealByPredicate}).\n * @param prefix - The ancestor path leading to `nodes`.\n *\n * @returns The path from a root to the matching node, or `null`.\n */\n private async _findPath(\n nodes: TreeNode[],\n predicate: (data: unknown, node: TreeNode) => boolean,\n prefix: TreeNode[],\n ): Promise<TreeNode[] | null> {\n for (const node of nodes) {\n const here = [...prefix, node];\n\n if (predicate(node.data, node)) {\n return here;\n }\n\n const children = await this._ensureChildrenLoaded(node);\n if (children.length > 0) {\n const found = await this._findPath(children, predicate, here);\n if (found !== null) {\n return found;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Returns a node's children, loading and caching them from `loadChildren`\n * first when the node is lazy and unloaded. Mirrors {@link _loadAndExpand}'s\n * cache writes (`children` + `_loadedNodes`) but does not expand the node —\n * a reveal only expands the ancestors on the path to its match. A rejected\n * load is swallowed and treated as an empty subtree.\n *\n * @param node - The node whose children are needed.\n *\n * @returns The node's children (possibly empty).\n */\n private async _ensureChildrenLoaded(node: TreeNode): Promise<TreeNode[]> {\n if (node.children && node.children.length > 0) {\n return node.children;\n }\n\n if (node.loadChildren !== undefined && !this._loadedNodes.has(node)) {\n try {\n const children = await node.loadChildren();\n\n node.children = children;\n this._loadedNodes.add(node);\n\n return children;\n } catch {\n return [];\n }\n }\n\n return node.children ?? [];\n }\n\n /**\n * Registers a listener for one of this tree's events.\n *\n * @param event - `\"selection\"` fires whenever the selection changes,\n * receiving the full array of selected {@link TreeNode} instances.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"selection\", listener: (nodes: TreeNode[]) => void): this;\n\n /**\n * Registers a listener for a lazy node's failed child load.\n *\n * @param event - `\"loaderror\"` fires when a node's `loadChildren` rejects;\n * the node stays collapsed and unloaded so toggling again retries.\n * @param listener - Receives the {@link TreeNode} whose load failed and the\n * rejection reason.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"loaderror\", listener: (node: TreeNode, error: unknown) => void): this;\n\n /**\n * Registers a listener for a right-click on a node.\n *\n * @param event - `\"contextmenu\"` fires when a node row is right-clicked,\n * receiving the {@link TreeNode} under the cursor and the originating\n * `MouseEvent` (its `clientX`/`clientY` position a context menu). The\n * default browser menu is suppressed and the tree's selection is left\n * unchanged, so a right-click never opens a node the way a left-click does.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"contextmenu\", listener: (node: TreeNode, event: MouseEvent) => void): this;\n\n /**\n * Registers a listener for a double-click (activation) on a node.\n *\n * @param event - `\"dblclick\"` fires when a node row is double-clicked,\n * receiving the {@link TreeNode} under the cursor. The first click of the\n * pair still emits `\"selection\"` as usual, so `\"dblclick\"` is an\n * activation signal layered on top of selection — consumers typically use\n * `\"selection\"` to preview a node and `\"dblclick\"` to open it.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"dblclick\", listener: (node: TreeNode) => void): this;\n\n /**\n * Registers a listener for a node's expansion committing.\n *\n * @param event - `\"expand\"` fires after the expansion has committed and\n * the rows have been rebuilt — for an unloaded lazy node, after its\n * `loadChildren` resolved and the children were attached, not when the\n * toggle was first requested. It never fires from `setNodes`,\n * `expandAll`, or `revealByPredicate`; a rejected lazy load fires only\n * `\"loaderror\"` instead.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"expand\", listener: (node: TreeNode) => void): this;\n\n /**\n * Registers a listener for a node leaving the expanded set.\n *\n * @param event - `\"collapse\"` fires after the node has left the expanded\n * set and the rows have been rebuilt. It never fires from `setNodes`,\n * `expandAll`, or `revealByPredicate`.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This tree, for method chaining.\n */\n on(event: \"collapse\", listener: (node: TreeNode) => void): this;\n on(event: TreeEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This tree, for method chaining.\n */\n off(event: TreeEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"selection\", nodes: TreeNode[]): void;\n protected emit(event: \"loaderror\", node: TreeNode, error: unknown): void;\n protected emit(event: \"contextmenu\", node: TreeNode, event_: MouseEvent): void;\n protected emit(event: \"dblclick\", node: TreeNode): void;\n protected emit(event: \"expand\", node: TreeNode): void;\n protected emit(event: \"collapse\", node: TreeNode): void;\n protected emit(event: TreeEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Sets the renderer factory used to create one\n * [`TreeNodeRenderer`](/api/component/tree/classes/TreeNodeRenderer)\n * instance per pool slot.\n *\n * @param factory - Zero-argument function returning a new\n * [`TreeNodeRenderer`](/api/component/tree/classes/TreeNodeRenderer).\n * Defaults to `() => new LabelTreeNodeRenderer()`.\n * @returns This tree, for method chaining.\n *\n * @remarks\n * If pool rows already exist, each one's renderer is replaced in place via\n * `TreeRow.setRenderer(factory())`. The DOM pool itself is preserved.\n * Bindings are cleared so the next render pass rebinds and updates the\n * new renderers.\n */\n setRendererFactory(factory: () => TreeNodeRenderer): this {\n this._rendererFactory = factory;\n\n for (const row of this._rowPool) {\n row.setRenderer(factory());\n }\n\n this._boundIndices.fill(-1);\n this.invalidateGeom();\n\n if (this.getElement()) {\n this.renderWindow();\n }\n\n return this;\n }\n\n /**\n * Returns the renderer factory currently in use.\n *\n * @returns The zero-argument factory function.\n */\n getRendererFactory(): () => TreeNodeRenderer {\n return this._rendererFactory;\n }\n\n /**\n * Reports whether a node renders an expand/collapse caret.\n *\n * @param node - The node to test.\n * @returns True when the node already carries children, or is a lazy node\n * declared with `hasChildren: true`.\n *\n * @remarks\n * Centralising the predicate keeps the caret, ARIA, and flatten decisions\n * from drifting apart. An eager node with an empty `children` array is not\n * expandable; a lazy node is expandable before its children exist.\n */\n private _isExpandable(node: TreeNode): boolean {\n return !!(node.children && node.children.length > 0) || node.hasChildren === true;\n }\n\n /**\n * Rebuilds the flat visible-row list from the current root nodes and expanded set,\n * computing `siblingCount` and `posInSet` (1-based) for each entry.\n */\n private _flatten(): void {\n this._flatRows = [];\n\n // The visible set is changing, so the widest-row running maximum no\n // longer describes it — reset it and let the next render pass re-derive\n // the content width from the new rows (a collapsed wide branch or a\n // narrower dataset must be able to shrink the horizontal extent).\n this._maxContentWidth = 0;\n\n const recurse = (nodes: TreeNode[], depth: number): void => {\n const siblingCount = nodes.length;\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n this._flatRows.push({ node, depth, siblingCount, posInSet: i + 1 });\n\n if (this._isExpandable(node) && this._expandedNodes.has(node) && node.children) {\n recurse(node.children, depth + 1);\n }\n }\n };\n\n recurse(this._nodes, 0);\n }\n\n /**\n * Re-flattens the visible subtree and forces a full rebind of the pool so\n * every row reflects the current expanded/loading state.\n *\n * @remarks\n * Called from the collapse path, the synchronous expand path, and the async\n * load path — anywhere the flattened-row set or a node's loading affordance\n * changes.\n */\n private _reflattenAndRender(): void {\n this._flatten();\n this._boundIndices.fill(-1);\n this.invalidateGeom();\n this.renderWindow();\n }\n\n /**\n * Expands `node` if it is not already expanded — the same commit path as\n * clicking its collapsed caret (loading its children first when it is an\n * unloaded lazy node), without requiring a prior click. No-ops if `node`\n * is already expanded. Useful for defaulting specific sections open after\n * {@link setNodes}, which always starts every node collapsed.\n *\n * @param node - The node to expand.\n *\n * @returns This tree, for method chaining.\n *\n * @see Use {@link expandNodeAsync} instead when the caller needs to know\n * when a lazy expansion finished.\n */\n expandNode(node: TreeNode): this {\n if (!this._expandedNodes.has(node)) {\n void this._expand(node);\n }\n\n return this;\n }\n\n /**\n * Expands `node` and resolves once the expansion has committed.\n *\n * @param node - The node to expand.\n *\n * @returns A promise resolving to `true` when the node ends up expanded —\n * including when it already was — or `false` when a lazy load rejected\n * and the node stayed collapsed.\n *\n * @remarks\n * A second call for a node whose lazy load is already in flight joins\n * that load instead of starting another, and both callers resolve with\n * its outcome. Emits `\"expand\"` on a real transition, the same as\n * {@link expandNode}.\n */\n async expandNodeAsync(node: TreeNode): Promise<boolean> {\n if (this._expandedNodes.has(node)) {\n return true;\n }\n\n return this._expand(node);\n }\n\n /**\n * Toggles the expanded state of a node, re-flattens, and re-renders.\n *\n * @param node - The node whose expanded state should be toggled.\n *\n * @remarks\n * Delegates to {@link _collapse} for an expanded node and {@link _expand}\n * for a collapsed one — the same commit path (and lazy-load join\n * behaviour, via {@link _expandLazy}) used by every other caller.\n */\n private _onToggle(node: TreeNode): void {\n if (this._expandedNodes.has(node)) {\n this._collapse(node);\n\n return;\n }\n\n void this._expand(node);\n }\n\n /**\n * Commits `node`'s expansion, loading a lazy node's children first.\n *\n * @param node - The node to expand.\n *\n * @returns A promise resolving to `true` once the expansion has committed,\n * or `false` when a lazy load failed or was orphaned.\n *\n * @remarks\n * An already-loaded node commits synchronously — the returned promise is\n * already resolved by the time this returns, so a caller that ignores it\n * still sees the expansion in the same tick.\n */\n private _expand(node: TreeNode): Promise<boolean> {\n const needsLoad = node.loadChildren !== undefined\n && !this._loadedNodes.has(node)\n && !(node.children && node.children.length);\n\n if (needsLoad) {\n return this._expandLazy(node);\n }\n\n this._expandedNodes.add(node);\n this._reflattenAndRender();\n this.emit(\"expand\", node);\n\n return Promise.resolve(true);\n }\n\n /**\n * Removes `node` from the expanded set, re-renders, then reports the change.\n *\n * @param node - The node to collapse.\n */\n private _collapse(node: TreeNode): void {\n this._expandedNodes.delete(node);\n this._reflattenAndRender();\n this.emit(\"collapse\", node);\n }\n\n /**\n * Starts a lazy node's load-and-expand, or joins the one already running for\n * that node so a second caller never triggers a second `loadChildren`.\n *\n * @param node - The lazy node to expand.\n *\n * @returns The (possibly shared) promise resolving once the load settles.\n */\n private _expandLazy(node: TreeNode): Promise<boolean> {\n const inFlight = this._pendingExpansions.get(node);\n\n if (inFlight !== undefined) {\n return inFlight;\n }\n\n const pending = this._loadAndExpand(node);\n\n this._pendingExpansions.set(node, pending);\n\n // Identity-checked so a `setNodes` that cleared the map mid-flight, followed\n // by a fresh load for the same node object, is not un-registered by the\n // orphaned load's own cleanup.\n void pending.then(() => {\n if (this._pendingExpansions.get(node) === pending) {\n this._pendingExpansions.delete(node);\n }\n });\n\n return pending;\n }\n\n /**\n * Loads a lazy node's children, then commits its expansion.\n *\n * @param node - The lazy node to load and expand.\n *\n * @remarks\n * Marks the node loading (driving its spinner affordance), awaits\n * `loadChildren`, and on success writes `children`, records the node as\n * loaded and expanded. A rejection emits `\"loaderror\"` and leaves the node\n * collapsed and unloaded so toggling again retries. An empty resolved array\n * is treated as success: the node renders as an expanded, empty parent.\n *\n * If `setNodes` swaps the dataset while the loader is in flight, it clears\n * `_loadingNodes`, so a still-present membership check after the await tells\n * us the node is still live; an orphaned resolve commits nothing.\n *\n * The `\"expand\"` emission is the last thing this method does, after the\n * re-render, so a listener sees the loaded children already flattened.\n *\n * @returns `true` when the node's expansion committed, `false` when the\n * load failed or was orphaned by a `setNodes` swap.\n */\n private async _loadAndExpand(node: TreeNode): Promise<boolean> {\n this._loadingNodes.add(node);\n this._reflattenAndRender();\n\n let expanded = false;\n\n try {\n const children = await node.loadChildren!();\n\n if (!this._loadingNodes.has(node)) {\n return false;\n }\n\n node.children = children;\n this._loadedNodes.add(node);\n this._expandedNodes.add(node);\n expanded = true;\n } catch (error) {\n if (!this._loadingNodes.has(node)) {\n return false;\n }\n\n this.emit(\"loaderror\", node, error);\n } finally {\n this._loadingNodes.delete(node);\n this._reflattenAndRender();\n }\n\n if (expanded) {\n this.emit(\"expand\", node);\n }\n\n return expanded;\n }\n\n /**\n * Fires `\"selection\"` with the current selection, unless it has the same\n * membership as `before` — in which case the gesture that ran did not\n * actually change what was selected, and the event is skipped.\n *\n * @param before - The selection as it stood immediately before the\n * mutating gesture ran.\n */\n private _notifySelectionChange(before: ReadonlySet<TreeNode>): void {\n if (selectionsEqual(before, this._selectedNodes)) {\n return;\n }\n\n this.emit(\"selection\", this.getSelectedNodes());\n }\n\n /**\n * Fills `_selectedNodes` with every node in `_flatRows` between `anchorIdx` and `focusIdx` (inclusive).\n *\n * @param anchorIdx - One end of the range.\n * @param focusIdx - The other end of the range (may be less than `anchorIdx`).\n */\n private _rangeSelect(anchorIdx: number, focusIdx: number): void {\n const lo = Math.min(anchorIdx, focusIdx);\n const hi = Math.max(anchorIdx, focusIdx);\n\n this._selectedNodes.clear();\n\n for (let i = lo; i <= hi; i++) {\n this._selectedNodes.add(this._flatRows[i].node);\n }\n }\n\n /**\n * Replaces the selection with the single node at `index`, resets the anchor and focus, and scrolls it into view.\n *\n * @param index - Zero-based index into `_flatRows`.\n */\n private _selectAtIndex(index: number): void {\n if (index < 0 || index >= this._flatRows.length) {\n return;\n }\n\n const node = this._flatRows[index].node;\n const before = new Set(this._selectedNodes);\n\n this._selectedNodes.clear();\n this._selectedNodes.add(node);\n this._anchorNode = node;\n this._focusNode = node;\n\n this._updateSelectionStyle();\n this._scrollIntoView(index);\n this.renderWindow();\n this._updateActiveDescendant();\n this._notifySelectionChange(before);\n }\n\n /**\n * Extends the range selection from `_anchorNode` to `index`, moving only the focus end.\n *\n * @param index - Zero-based index into `_flatRows` for the new focus position.\n */\n private _extendSelectionTo(index: number): void {\n if (index < 0 || index >= this._flatRows.length) {\n return;\n }\n\n const before = new Set(this._selectedNodes);\n\n const anchorIdx = this._anchorNode\n ? this._flatRows.findIndex(r => r.node === this._anchorNode)\n : index;\n\n this._rangeSelect(anchorIdx < 0 ? index : anchorIdx, index);\n this._focusNode = this._flatRows[index].node;\n\n this._updateSelectionStyle();\n this._scrollIntoView(index);\n this.renderWindow();\n this._updateActiveDescendant();\n this._notifySelectionChange(before);\n }\n\n /**\n * Scrolls the tree element so the row at `index` is fully visible, without\n * moving if it already is. Delegates to the shared base implementation.\n *\n * @param index - Zero-based index into `_flatRows`.\n */\n private _scrollIntoView(index: number): void {\n this.scrollRowIntoView(index);\n }\n\n /**\n * Handles keyboard navigation for the tree widget.\n *\n * @remarks\n * Implements the WAI-ARIA tree keyboard interaction pattern:\n * - `ArrowDown` / `ArrowUp` — move to next/previous visible row (plain) or extend range (Shift)\n * - `ArrowRight` — expand a collapsed node, or move into an already-expanded node's first child\n * - `ArrowLeft` — collapse an expanded node, or move to its parent\n * - `Home` / `End` — jump to first/last visible row (plain) or extend range to edge (Shift)\n *\n * @param e - The keyboard event fired on the tree element.\n */\n private _onKeyDown(e: KeyboardEvent): Event.ListenerResult {\n const navigable = new Set(['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Home', 'End']);\n if (!navigable.has(e.key)) {\n return;\n }\n\n const flatRows = this._flatRows;\n if (flatRows.length === 0) {\n return;\n }\n\n // For Shift+Arrow the moving end is the focus node, not the anchor\n const focusIdx = this._focusNode\n ? flatRows.findIndex(r => r.node === this._focusNode)\n : -1;\n\n if (e.key === 'ArrowDown') {\n const next = focusIdx < 0 ? 0 : Math.min(focusIdx + 1, flatRows.length - 1);\n e.shiftKey ? this._extendSelectionTo(next) : this._selectAtIndex(next);\n\n } else if (e.key === 'ArrowUp') {\n const prev = focusIdx < 0 ? 0 : Math.max(focusIdx - 1, 0);\n e.shiftKey ? this._extendSelectionTo(prev) : this._selectAtIndex(prev);\n\n } else if (e.key === 'Home') {\n e.shiftKey ? this._extendSelectionTo(0) : this._selectAtIndex(0);\n\n } else if (e.key === 'End') {\n const last = flatRows.length - 1;\n e.shiftKey ? this._extendSelectionTo(last) : this._selectAtIndex(last);\n\n } else if (e.key === 'ArrowRight') {\n if (focusIdx < 0) {\n this._selectAtIndex(0);\n\n return { prevent: true };\n }\n\n const { node } = flatRows[focusIdx];\n const hasChildren = this._isExpandable(node);\n\n if (!hasChildren) {\n return { prevent: true };\n }\n\n if (this._expandedNodes.has(node)) {\n // Already expanded — move focus into the first child\n this._selectAtIndex(focusIdx + 1);\n } else {\n // Collapsed — expand without moving focus\n this._onToggle(node);\n }\n\n } else if (e.key === 'ArrowLeft') {\n if (focusIdx < 0) {\n return { prevent: true };\n }\n\n const { node, depth } = flatRows[focusIdx];\n const hasChildren = this._isExpandable(node);\n\n if (hasChildren && this._expandedNodes.has(node)) {\n // Expanded — collapse and stay on the same node\n this._onToggle(node);\n const newIdx = this._flatRows.findIndex(r => r.node === node);\n if (newIdx >= 0) {\n this._scrollIntoView(newIdx);\n }\n } else if (depth > 0) {\n // Collapsed or leaf — move to parent (nearest ancestor with depth - 1)\n for (let i = focusIdx - 1; i >= 0; i--) {\n if (flatRows[i].depth === depth - 1) {\n this._selectAtIndex(i);\n break;\n }\n }\n }\n }\n\n return { prevent: true };\n }\n\n /**\n * Dispatches clicks to either toggle expand/collapse or select a row.\n *\n * @remarks\n * Supports three selection modes via modifier keys:\n * - Plain click: replace selection with the clicked node\n * - Ctrl/Cmd+click: toggle the clicked node without disturbing others\n * - Shift+click: range-select from the anchor to the clicked node\n *\n * When {@link getExpandTrigger} is `\"click\"`, a plain click (no\n * modifiers) on an expandable row's body also toggles its expansion\n * after selection is applied; Ctrl/Cmd-click and an anchored Shift-click\n * never toggle; the caret always toggles regardless of this setting.\n *\n * @param e - The click event whose target is inside the tree's DOM subtree.\n */\n private _handleClick(e: MouseEvent): void {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n\n for (const row of this._rowPool) {\n const node = row.getNode();\n if (!node) {\n continue;\n }\n\n const toggle = row.getToggle();\n if (toggle) {\n const toggleEl = toggle.getElement();\n if (toggleEl && (target === toggleEl || DOM.source.contains(toggleEl, target))) {\n this._onToggle(node);\n return;\n }\n }\n\n const rowEl = row.getElement();\n if (!rowEl || (!DOM.source.contains(rowEl, target) && target !== rowEl)) {\n continue;\n }\n\n const clickedIdx = this._flatRows.findIndex(r => r.node === node);\n\n if (e.shiftKey && this._anchorNode) {\n this._extendSelectionTo(clickedIdx);\n } else if (e.ctrlKey || e.metaKey) {\n const before = new Set(this._selectedNodes);\n\n if (this._selectedNodes.has(node)) {\n this._selectedNodes.delete(node);\n } else {\n this._selectedNodes.add(node);\n }\n\n this._anchorNode = node;\n this._focusNode = node;\n this._updateSelectionStyle();\n this._notifySelectionChange(before);\n } else {\n this._selectAtIndex(clickedIdx);\n\n if (this.getExpandTrigger() === \"click\" && this._isExpandable(node)) {\n this._onToggle(node);\n }\n }\n\n return;\n }\n }\n\n /**\n * Resolves the node under a right-click and emits the `\"contextmenu\"` event.\n *\n * @remarks\n * Mirrors {@link _handleClick}'s row-matching but deliberately does not change\n * the selection: a right-click positions a context menu over a node without\n * triggering the selection-driven side effects (e.g. opening the node) that a\n * left-click would. When a node row is hit the browser's native menu is\n * suppressed via `preventDefault` and `\"contextmenu\"` fires with the node and\n * the originating event; a right-click on empty space is left to the browser.\n *\n * @param e - The contextmenu event whose target is inside the tree's subtree.\n */\n private _handleContextMenu(e: MouseEvent): Event.ListenerResult {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n\n for (const row of this._rowPool) {\n const node = row.getNode();\n if (!node) {\n continue;\n }\n\n const rowEl = row.getElement();\n if (!rowEl || (!DOM.source.contains(rowEl, target) && target !== rowEl)) {\n continue;\n }\n\n this.emit(\"contextmenu\", node, e);\n\n return { prevent: true };\n }\n }\n\n /**\n * Resolves the node under a double-click and emits the `\"dblclick\"` event.\n *\n * @remarks\n * Mirrors {@link _handleContextMenu}'s row-matching. The first click of the\n * pair has already run through {@link _handleClick} and set the selection, so\n * this only layers an activation signal on top — it does not re-select.\n * `preventDefault` suppresses the browser's double-click text selection of the\n * row label. When {@link getExpandTrigger} is `\"click\"`, the row-body toggle\n * below is skipped too, for the same reason the caret's is — each click of\n * the pair already toggled it via {@link _handleClick}.\n *\n * @param e - The dblclick event whose target is inside the tree's subtree.\n */\n private _handleDblClick(e: MouseEvent): Event.ListenerResult {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n\n for (const row of this._rowPool) {\n const node = row.getNode();\n if (!node) {\n continue;\n }\n\n const rowEl = row.getElement();\n if (!rowEl || (!DOM.source.contains(rowEl, target) && target !== rowEl)) {\n continue;\n }\n\n this.emit(\"dblclick\", node);\n\n // Double-clicking a parent row toggles its expansion, the\n // file-explorer convention. A double-click on the toggle caret is\n // skipped: `_handleClick` already fired `_onToggle` on each of the\n // two clicks, so its net state is unchanged and toggling again here\n // would flip it a third time. The row body is skipped the same way\n // when `expandTrigger` is `\"click\"` — there too, each of the two\n // clicks already toggled it via `_handleClick`. Leaf nodes have\n // nothing to expand, so their `\"dblclick\"` stays a pure activation\n // signal.\n const toggle = row.getToggle();\n const toggleEl = toggle ? toggle.getElement() : undefined;\n const onToggle = !!toggleEl\n && (target === toggleEl || DOM.source.contains(toggleEl, target));\n\n if (!onToggle && this._isExpandable(node) && this.getExpandTrigger() === \"dblclick\") {\n this._onToggle(node);\n }\n\n return { prevent: true };\n }\n }\n\n /**\n * Applies or removes the selection highlight, focus ring, and aria-selected on all bound pool rows.\n */\n private _updateSelectionStyle(): void {\n for (const row of this._rowPool) {\n const rowEl = row.getElement();\n\n if (!rowEl) {\n continue;\n }\n\n const node = row.getNode();\n const isSelected = node !== null && this._selectedNodes.has(node!);\n const isFocused = node !== null && node === this._focusNode;\n\n // Per-node ephemeral selection/focus styling on a pooled row re-bound\n // to a different node on every render. Routing this through cached\n // Component setters would persist it into _options and replay it onto\n // the next node bound to this reused row, so write/remove the inline\n // styles directly instead.\n if (isSelected) {\n DOM.sink.apply(rowEl, { style: { \"background-color\": SELECTED_BG } });\n } else {\n DOM.sink.apply(rowEl, { style: { \"background-color\": null } });\n }\n\n if (isFocused) {\n DOM.sink.apply(rowEl, { style: { \"outline\": \"2px solid var(--ts-ui-focus-ring, rgba(30, 100, 200, 0.6))\", \"outline-offset\": \"-2px\" } });\n } else {\n DOM.sink.apply(rowEl, { style: { \"outline\": null, \"outline-offset\": null } });\n }\n\n row.getAria().setSelected(isSelected);\n }\n }\n\n /**\n * Sets `aria-activedescendant` on the tree container to the pool row bound to `_focusNode`.\n *\n * @remarks Must be called after `renderWindow()` so the pool slot is guaranteed in the DOM.\n */\n private _updateActiveDescendant(): void {\n if (!this._focusNode) {\n this.getAria().setActiveDescendant(\"\");\n\n return;\n }\n\n for (const row of this._rowPool) {\n if (row.getNode() === this._focusNode) {\n this.getAria().setActiveDescendant(row.getId());\n\n return;\n }\n }\n\n this.getAria().setActiveDescendant(\"\");\n }\n\n /**\n * Drops the running content-width maximum before the shared re-bind pass.\n *\n * @remarks The maximum is deliberately monotonic within a flattened set so\n * the horizontal scrollbar does not jitter as rows scroll in and out (it is\n * otherwise reset only in `_flatten`). A metrics reflow invalidates the\n * measurements it was accumulated from, so keeping it would pin the content\n * width to the old font — leaving a phantom scroll range when the new face\n * is narrower, and never widening past the stale value.\n */\n protected onThemeReflow(): void {\n this._maxContentWidth = 0;\n\n super.onThemeReflow();\n }\n\n /**\n * Recomputes the visible row window, rebinds changed pool slots, and hides excess rows.\n */\n protected renderWindow(): void {\n const element = this.getElement();\n if (!element || !this._scroller) {\n return;\n }\n\n if (this.deferRenderWhileFirstLayoutHeld()) {\n return;\n }\n\n const scroller = this._scroller;\n\n const totalRows = this._flatRows.length;\n const totalHeight = totalRows * ROW_HEIGHT;\n\n // Loose clamp using the last-known content width (the actual contentW\n // for this frame is computed below from the first row-bind pass).\n scroller.clampToContent(this._lastRowWidth, totalHeight);\n\n const visibleHeight = this.getHeight() || 0;\n const win = this.computeVisibleWindow(scroller.getScrollY(), visibleHeight, totalRows);\n\n const poolTarget = this.computePoolTarget(win.windowSize, visibleHeight, totalRows);\n this.growRowPool(poolTarget);\n this.alignPoolWindow(win.firstRow);\n\n const { reboundFlags, maxContentWidth } =\n this._bindAndMeasure(win.firstRow, win.windowSize);\n\n // Only the visible window was measured, so fold the widest row seen this\n // frame into the running maximum for the current flattened set (reset in\n // `_flatten`). The content width then only grows as wider rows are\n // discovered and never shrinks when they scroll away, so the horizontal\n // scrollbar stays stable instead of jittering with the visible rows.\n if (maxContentWidth > this._maxContentWidth) {\n this._maxContentWidth = maxContentWidth;\n }\n\n // Fill to the effective viewport width (owner width minus the vertical\n // scrollbar's reservation when that bar is visible), not the raw owner\n // width. Sizing rows to the full width would push their trailing edge\n // under the vertical bar, and handing that full width to\n // `layoutScrollbars` as the content width forces a spurious horizontal\n // bar for the reserved band. `clampToContent` above has already refreshed\n // the scroller's content metrics this pass.\n //\n // `rowOverflow: \"clip\"` never grows past the viewport at all — every\n // row (and so every renderer) is capped there instead, trading the\n // horizontal scrollbar for truncation (see `LabelTreeNodeRenderer`).\n const rowWidth = this.getRowOverflow() === \"clip\"\n ? scroller.getViewportWidth()\n : Math.max(scroller.getViewportWidth(), this._maxContentWidth);\n if (rowWidth !== this._lastRowWidth) {\n this._lastRowWidth = rowWidth;\n this.invalidateGeom();\n }\n\n this._positionRows(win.firstRow, win.windowSize, rowWidth, reboundFlags);\n this.hideExcessPoolRows(win.windowSize);\n\n this._updateSelectionStyle();\n\n scroller.layoutScrollbars(rowWidth, totalHeight);\n\n // A pass the startup font gate deferred skipped whatever its caller did\n // after asking for it — including the active-descendant refresh, which\n // could not name a row that did not exist yet. Redo it now the rows do.\n if (this.finishResumedRender()) {\n this._updateActiveDescendant();\n }\n }\n\n /**\n * First pass: binds visible pool slots to their flattened rows (when\n * rebound) and computes the maximum content width across visible rows so\n * the second pass knows how wide each row should be.\n *\n * @param firstRow - The first data index covered by the visible window.\n * @param windowSize - The number of rows in the window.\n * @returns Per-slot rebind flags (parallel to the window) and the widest\n * content width seen, both consumed by {@link _positionRows}.\n */\n private _bindAndMeasure(firstRow: number, windowSize: number): { reboundFlags: boolean[], maxContentWidth: number } {\n const reboundFlags: boolean[] = new Array(windowSize);\n let maxContentWidth = 0;\n\n for (let i = 0; i < windowSize; i++) {\n const row = this._rowPool[i];\n const dataIndex = firstRow + i;\n const flatRow = this._flatRows[dataIndex];\n const hasChildren = this._isExpandable(flatRow.node);\n const expanded = this._expandedNodes.has(flatRow.node);\n const loading = this._loadingNodes.has(flatRow.node);\n const wasRebound = this._boundIndices[i] !== dataIndex;\n\n if (wasRebound) {\n const selected = this._selectedNodes.has(flatRow.node);\n row.setRowData(flatRow.node, flatRow.depth, hasChildren, expanded, flatRow.siblingCount, flatRow.posInSet, selected, loading);\n this._boundIndices[i] = dataIndex;\n }\n\n reboundFlags[i] = wasRebound;\n\n const cw = row.getContentWidth(INDENT_PX);\n if (cw > maxContentWidth) {\n maxContentWidth = cw;\n }\n }\n\n return { reboundFlags, maxContentWidth };\n }\n\n /**\n * Second pass: positions visible rows at `dataIndex * ROW_HEIGHT`, sizes\n * them to `rowWidth`, marks them displayed, and re-lays out their children\n * only when the row was rebound or its geometry changed.\n *\n * @param firstRow - The first data index covered by the visible window.\n * @param windowSize - The number of rows in the window.\n * @param rowWidth - The horizontal extent of each row in pixels.\n * @param reboundFlags - The per-slot rebind flags produced by {@link _bindAndMeasure}.\n */\n private _positionRows(firstRow: number, windowSize: number, rowWidth: number, reboundFlags: boolean[]): void {\n for (let i = 0; i < windowSize; i++) {\n const row = this._rowPool[i];\n const dataIndex = firstRow + i;\n const wasRebound = reboundFlags[i];\n\n const geomChanged = this.positionRow(i, dataIndex * ROW_HEIGHT, rowWidth);\n\n if (wasRebound || geomChanged) {\n row.layoutChildren(ROW_HEIGHT, INDENT_PX);\n }\n }\n }\n\n /**\n * Constructs the `VirtualScroller` and wires click and keyboard listeners.\n *\n * @param element - Optional element passed by the rendering pipeline; falls back to getElement().\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (!el) {\n return this;\n }\n\n this.initScroller(el);\n\n Event.addSubtreeListener(this, \"click\", this._handleClick);\n Event.addSubtreeListener(this, \"contextmenu\", this._handleContextMenu);\n Event.addSubtreeListener(this, \"dblclick\", this._handleDblClick);\n Event.addListener(this, \"keydown\", this._onKeyDown);\n\n this.renderWindow();\n\n return this;\n }\n\n /**\n * Calls the layout manager and then refreshes the virtual-scroll viewport.\n *\n * @returns This component, for method chaining.\n *\n * @remarks\n * Overrides [`Component.doLayout`](/api/core/classes/Component#doLayout) so that layout-manager-driven size changes\n * (e.g. from a parent Tab or Split) automatically update the rendered row window.\n */\n doLayout(): this {\n if (this.isLayoutPaused()) {\n return this;\n }\n\n super.doLayout();\n\n // A pass the startup font gate deferred already renders the window, so\n // running the unconditional one as well would render twice on the frame\n // the gate opens.\n if (!this.renderWindowIfDeferred()) {\n this.renderWindow();\n }\n\n return this;\n }\n}\n\nconst TreeCallable = callable(Tree);\ntype TreeCallable = Tree;\nexport {\n Tree as _Tree,\n TreeCallable as Tree\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{a as e,o as t}from"./Position-BIEU1Eze.js";import{f as n,h as r,m as i,p as a}from"./Component-D99-15Zt.js";var BoxLayout=class extends n{_spacing=5;_itemAlign=`baseline`;_mode=`preferred`;_overflowSizing=`preferred`;_justify=`start`;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.mode!==void 0&&this.setMode(e.mode),e.spacing!==void 0&&this.setComponentSpacing(e.spacing),e.stretching!==void 0&&this.setStretching(e.stretching),e.itemAlign!==void 0&&this.setItemAlign(e.itemAlign),e.overflowSizing!==void 0&&this.setOverflowSizing(e.overflowSizing),e.justify!==void 0&&this.setJustify(e.justify)}getComponentSpacing(){return this._spacing||0}setComponentSpacing(e){return this._spacing=e||0,this}isStretching(){return this._itemAlign===`stretch`}setStretching(e){return this.setItemAlign(e?`stretch`:`baseline`)}getItemAlign(){return this._itemAlign}setItemAlign(e){return this._itemAlign=e,this}getMode(){return this._mode}setMode(e){return this._mode=e,this}getOverflowSizing(){return this._overflowSizing}setOverflowSizing(e){return this._overflowSizing=e,this}getJustify(){return this._justify}setJustify(e){return this._justify=e,this}aggregateMaxSize(n){let r=this.getContainer();if(!r)return null;let i=r.getPerimeterSize(),a=r.getLaidOutComponents(),o=n?i.left+i.right:i.top+i.bottom,s=n?i.top+i.bottom:i.left+i.right,c=o,l=0,u=!1,d=!1,f=0;for(let e of a){let r=e.getMaxSize();if(!r){u=!0,d=!0;continue}let i=n?r.width:r.height,a=n?r.height:r.width;t(i)?u=!0:this._mode===`equal`?f=Math.max(f,i):c+=i,t(a)?d=!0:l=Math.max(l,a)}this._mode===`equal`?c+=a.length*f+this._spacing*Math.max(0,a.length-1):c+=this._spacing*Math.max(0,a.length-1),l+=s;let p=u?e:c,m=d?e:l;return{width:n?p:m,height:n?m:p}}computeShrink(e,t,n,r){if(e<=n||r)return{remaining:Math.max(0,n-e),shrinkRatio:0};let i=e-n,a=e-t;return{remaining:0,shrinkRatio:a>0?Math.min(1,i/a):1}}justifyOffsets(e,t,n){let r=Math.max(0,t-e);return r===0||this._justify===`start`?{lead:0,gap:0}:this._justify===`center`?{lead:r/2,gap:0}:this._justify===`end`?{lead:r,gap:0}:this._justify===`between`?{lead:0,gap:n>1?r/(n-1):0}:{lead:n>0?r/(2*n):0,gap:n>0?r/n:0}}crossItemOffset(e,t){return this._itemAlign===`center`?Math.max(0,(t-e)/2):this._itemAlign===`end`?Math.max(0,t-e):0}crossPlacement(e,t,n,r,a){let o=this.getLayoutConstraints(e),s=o?.fill??null,c=o?.anchor??null;if(a?s===i.VERTICAL||s===i.BOTH:s===i.HORIZONTAL||s===i.BOTH)return{offset:t,extent:n};let l=this.crossAnchorEdge(c,a);if(l===null)return null;let u=Math.min(r,n);return{offset:l===`lead`?t:t+(n-u),extent:u}}crossAnchorEdge(e,t){return e===null?null:t?e===a.NORTH||e===a.NORTHWEST||e===a.NORTHEAST?`lead`:e===a.SOUTH||e===a.SOUTHWEST||e===a.SOUTHEAST?`trail`:null:e===a.WEST||e===a.NORTHWEST||e===a.SOUTHWEST?`lead`:e===a.EAST||e===a.NORTHEAST||e===a.SOUTHEAST?`trail`:null}},HBox=class extends BoxLayout{_defaultComponentWidth=100;getContentBaseline(){if(this._itemAlign!==`baseline`)return null;let e=this.getContainer();if(!e)return null;let t=[],n=[];for(let r of e.getLaidOutComponents()){let e=r.getPreferredSize();t.push(e?e.height:0),n.push(r.getBaseline())}return this.computeRowMetrics(t,n).rowAscent}getPreferredSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=t.left+t.right,i=[],a=[];if(this._mode===`equal`){let e=0;for(let t in n){let r=n[t],o=r.getPreferredSize();o&&(e=Math.max(e,o.width),i.push(o.height),a.push(r.getBaseline()))}r+=n.length*(e+this._spacing)-this._spacing}else{for(let e in n){let t=n[e],o=t.getPreferredSize();o&&(r+=o.width,i.push(o.height),a.push(t.getBaseline()))}r+=this._spacing*(n.length-1)}let o=this.computeRowHeight(i,a);return o+=t.top+t.bottom,{width:r,height:o}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=t.left+t.right,i=[],a=[];if(this._mode===`equal`){let e=0;for(let t in n){let r=n[t],o=r.getMinSize();o&&(e=Math.max(e,o.width),i.push(o.height),a.push(r.getBaseline()))}r+=n.length*(e+this._spacing)-this._spacing}else{for(let e in n){let t=n[e],o=t.getMinSize();o&&(r+=o.width,i.push(o.height),a.push(t.getBaseline()))}r+=this._spacing*(n.length-1)}let o=this.computeRowHeight(i,a);return o+=t.top+t.bottom,{width:r,height:o}}getMaxSize(){return this.aggregateMaxSize(!0)}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=e.getLaidOutComponents();if(t.length===0)return{width:0,height:0};let n=0;if(this._mode===`equal`){let e=0;for(let r of t){let t=r.getMinSize();t&&(e=Math.max(e,t.width),n=Math.max(n,t.height))}return{width:t.length*(e+this._spacing)-this._spacing,height:n}}let r=this._spacing*(t.length-1);for(let e of t){let t=e.getMinSize();t&&(r+=t.width,n=Math.max(n,t.height))}return{width:r,height:n}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getLaidOutComponents(),r=e.getContentInsets(),i=this.getComponentSpacing(),a=this.inflateForOverflow(t),o;o=this._mode===`equal`?this.layoutEqualMode(n,t,a,r,i):this.layoutPreferredMode(n,a,r,i),this.commitPlacements(o),this.reserveContentFrame()}layoutEqualMode(e,t,n,r,a){let o=this.computeEqualCellWidth(e,t.width,a);if(this.isStretching()){let t=r.getTop(),s=r.getLeft(),c=[];for(let r of e)c.push({component:r,...this.resolveBounds(r,s,t,o,n.height,i.BOTH)}),s+=o+a;return c}let s=[],c=[];for(let t of e){let e=t.getPreferredSize();s.push(e?e.height:0),c.push(t.getBaseline())}let{rowAscent:l,rowDescent:u}=this.computeRowMetrics(s,c),d=r.getTop(),f=n.height,p=r.getLeft(),m=[];for(let t=0;t<e.length;t+=1){let n=e[t],h=this.crossPlacement(n,d,f,s[t],!0);if(h)m.push({component:n,...this.resolveBounds(n,p,h.offset,o,h.extent,i.BOTH)});else if(this._itemAlign===`start`||this._itemAlign===`center`||this._itemAlign===`end`){let e=d+this.crossItemOffset(s[t],f);m.push({component:n,...this.resolveBounds(n,p,e,o,s[t],i.BOTH)})}else{let e=this.rowChildY(r.getTop(),s[t],c[t],l,u);m.push({component:n,...this.resolveBounds(n,p,e,o,s[t],i.BOTH)})}p+=o+a}return m}computeEqualCellWidth(e,t,n){let r=0,i=0;for(let t of e){let e=t.getMinSize();e&&(r=Math.max(r,e.width));let n=t.getPreferredSize();n&&(i=Math.max(i,n.width))}let a=(t-n*(e.length-1))/e.length;return a>=r?a:this.isOverflowingX()&&this._overflowSizing===`preferred`?Math.max(r,i):r}layoutPreferredMode(e,t,n,r){let{totalWeight:a,fixedPreferred:o,fixedMin:s}=this.measureFixedWidths(e,r),{remaining:c,shrinkRatio:l}=this.computeShrink(o,s,t.width,this.isOverflowingX()),u=[],d=[],f=[];for(let n of e){let e=this.getLayoutConstraints(n)?.weight??0,r=n.getPreferredSize(),i=n.getMinSize(),o=n.getMaxSize();u.push(this.resolveChildWidth(r,i,o,e,a,c,l));let s;s=!r||this.isStretching()?t.height:Math.min(r.height,t.height),o&&(s=Math.min(s,o.height)),d.push(s),f.push(n.getBaseline())}let{rowAscent:p,rowDescent:m}=this.isStretching()?{rowAscent:null,rowDescent:0}:this.computeRowMetrics(d,f),h=0,g=0;if(a===0){let i=r*(e.length-1);for(let e of u)i+=e;let a=t.width-(n.getLeft()+n.getRight());({lead:h,gap:g}=this.justifyOffsets(i,a,e.length))}let _=n.getTop(),v=t.height-(n.getTop()+n.getBottom()),y=n.getLeft()+h,b=[];for(let t=0;t<e.length;t+=1){let a=e[t],o=a.getPreferredSize(),s=a.getMaxSize(),c=o?Math.min(o.height,v):v;s&&(c=Math.min(c,s.height));let l=this.crossPlacement(a,_,v,c,!0);if(l)b.push({component:a,...this.resolveBounds(a,y,l.offset,u[t],l.extent,i.BOTH)});else if(this._itemAlign===`start`||this._itemAlign===`center`||this._itemAlign===`end`){let e=_+this.crossItemOffset(d[t],v);b.push({component:a,...this.resolveBounds(a,y,e,u[t],d[t],i.BOTH)})}else{let e=this.rowChildY(n.getTop(),d[t],f[t],p,m);b.push({component:a,...this.resolveBounds(a,y,e,u[t],d[t],i.BOTH)})}y+=u[t],y+=r+g}return b}measureFixedWidths(e,t){let n=0,r=t*(e.length-1),i=t*(e.length-1);for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0;if(e>0)n+=e;else{let e=t.getPreferredSize(),n=t.getMinSize();r+=this.preferredChildWidth(e,n),i+=n?n.width:0}}return{totalWeight:n,fixedPreferred:r,fixedMin:i}}preferredChildWidth(e,t){let n=(e?e.width:void 0)??(t&&t.width>0?t.width:void 0)??this._defaultComponentWidth;return t?Math.max(n,t.width):n}resolveChildWidth(e,t,n,r,i,a,o){let s;if(r>0&&i>0)s=r/i*a;else{let n=this.preferredChildWidth(e,t);s=n-o*(n-(t?t.width:0))}return n&&(s=Math.min(s,n.width)),t&&(s=Math.max(s,t.width)),s}rowChildY(e,t,n,r,i){return r===null?e:n===null?e+this.nullChildY(t,r,i):e+(r-n)}},o=r(HBox),VBox=class extends BoxLayout{_defaultComponentHeight=100;getContentBaseline(){let e=this.getContainer();if(!e)return null;let t=e.getLaidOutComponents();return t.length===0?null:t[0].getBaseline()}getPreferredSize(){let n=this.getContainer();if(!n)return null;let r=n.getPerimeterSize(),i=n.getLaidOutComponents();if(this._mode===`equal`){let e=0,t=0;for(let n in i){let r=i[n].getPreferredSize();r&&(e=Math.max(e,r.width),t=Math.max(t,r.height))}return{width:e+r.left+r.right,height:i.length*(t+this._spacing)-this._spacing+r.top+r.bottom}}let a=e,o=r.top+r.bottom;for(let e in i){let n=i[e].getPreferredSize();n&&(a=t(a)?Math.min(a,n.width):Math.max(a,n.width),o+=n.height)}return a+=r.left+r.right,o+=this._spacing*(i.length-1),{width:a,height:o}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents();if(this._mode===`equal`){let e=0,r=0;for(let t in n){let i=n[t].getMinSize();i&&(e=Math.max(e,i.width),r=Math.max(r,i.height))}return{width:e+t.left+t.right,height:n.length*(r+this._spacing)-this._spacing+t.top+t.bottom}}let r=0,i=t.top+t.bottom;for(let e in n){let t=n[e].getMinSize();t&&(r=Math.max(r,t.width),i+=t.height)}return r+=t.left+t.right,i+=this._spacing*(n.length-1),{width:r,height:i}}getMaxSize(){return this.aggregateMaxSize(!1)}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=e.getLaidOutComponents();if(t.length===0)return{width:0,height:0};let n=0;if(this._mode===`equal`){let e=0;for(let r of t){let t=r.getMinSize();t&&(n=Math.max(n,t.width),e=Math.max(e,t.height))}return{width:n,height:t.length*(e+this._spacing)-this._spacing}}let r=this._spacing*(t.length-1);for(let e of t){let t=e.getMinSize();t&&(n=Math.max(n,t.width),r+=t.height)}return{width:n,height:r}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getLaidOutComponents(),r=e.getContentInsets(),i=this.getComponentSpacing(),a=this.inflateForOverflow(t),o;o=this._mode===`equal`?this.layoutEqualMode(n,t,a,r,i):this.layoutPreferredMode(n,a,r,i),this.commitPlacements(o),this.reserveContentFrame()}layoutEqualMode(e,t,n,r,a){let o=this.computeEqualCellHeight(e,t.height,a),s=r.getLeft(),c=r.getTop();if(this.isStretching()){let t=n.width,r=[];for(let n of e)r.push({component:n,...this.resolveBounds(n,s,c,t,o,i.BOTH)}),c+=o+a;return r}let l=r.getLeft(),u=n.width,d=[];for(let t of e){let e=t.getPreferredSize(),n=e?e.width:0,r=this.crossPlacement(t,l,u,n,!1);if(r)d.push({component:t,...this.resolveBounds(t,r.offset,c,r.extent,o,i.BOTH)});else if(this._itemAlign===`start`||this._itemAlign===`center`||this._itemAlign===`end`){let e=l+this.crossItemOffset(n,u);d.push({component:t,...this.resolveBounds(t,e,c,n,o,i.BOTH)})}else d.push({component:t,...this.resolveBounds(t,s,c,n,o,i.BOTH)});c+=o+a}return d}computeEqualCellHeight(e,t,n){let r=0,i=0;for(let t of e){let e=t.getMinSize();e&&(r=Math.max(r,e.height));let n=t.getPreferredSize();n&&(i=Math.max(i,n.height))}let a=(t-n*(e.length-1))/e.length;return a>=r?a:this.isOverflowingY()&&this._overflowSizing===`preferred`?Math.max(r,i):r}layoutPreferredMode(e,t,n,r){let{totalWeight:a,fixedPreferred:o,fixedMin:s}=this.measureFixedHeights(e,r),{remaining:c,shrinkRatio:l}=this.computeShrink(o,s,t.height,this.isOverflowingY()),u=[];for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0,n=t.getPreferredSize(),r=t.getMinSize(),i=t.getMaxSize();u.push(this.resolveChildHeight(n,r,i,e,a,c,l))}let d=0,f=0;if(a===0){let i=r*(e.length-1);for(let e of u)i+=e;let a=t.height-(n.getTop()+n.getBottom());({lead:d,gap:f}=this.justifyOffsets(i,a,e.length))}let p=n.getLeft(),m=t.width-(n.getLeft()+n.getRight()),h=n.getLeft(),g=n.getTop()+d,_=[];for(let n=0;n<e.length;n+=1){let a=e[n],o=a.getPreferredSize(),s=a.getMaxSize(),c;c=!o||this.isStretching()?t.width:Math.min(o.width,t.width),s&&(c=Math.min(c,s.width));let l=o?Math.min(o.width,m):m;s&&(l=Math.min(l,s.width));let d=this.crossPlacement(a,p,m,l,!1);if(d)_.push({component:a,...this.resolveBounds(a,d.offset,g,d.extent,u[n],i.BOTH)});else if(this._itemAlign===`start`||this._itemAlign===`center`||this._itemAlign===`end`){let e=p+this.crossItemOffset(l,m);_.push({component:a,...this.resolveBounds(a,e,g,l,u[n],i.BOTH)})}else _.push({component:a,...this.resolveBounds(a,h,g,c,u[n],i.BOTH)});g+=u[n],g+=r+f}return _}measureFixedHeights(e,t){let n=0,r=t*(e.length-1),i=t*(e.length-1);for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0;if(e>0)n+=e;else{let e=t.getPreferredSize(),n=t.getMinSize();r+=this.preferredChildHeight(e,n),i+=n?n.height:0}}return{totalWeight:n,fixedPreferred:r,fixedMin:i}}preferredChildHeight(e,t){let n=(e?e.height:void 0)??(t&&t.height>0?t.height:void 0)??this._defaultComponentHeight;return t?Math.max(n,t.height):n}resolveChildHeight(e,t,n,r,i,a,o){let s;if(r>0&&i>0)s=r/i*a;else{let n=this.preferredChildHeight(e,t);s=n-o*(n-(t?t.height:0))}return n&&(s=Math.min(s,n.height)),t&&(s=Math.max(s,t.height)),s}},s=r(VBox);export{BoxLayout as i,s as n,o as r,VBox as t};
2
+ //# sourceMappingURL=VBox-DVe4UXwX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VBox-DVe4UXwX.js","names":[],"sources":["../../src/typescript/lib/layout/BoxLayout.ts","../../src/typescript/lib/layout/HBox.ts","../../src/typescript/lib/layout/VBox.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { AnchorType } from \"~/layout/AnchorType.js\";\nimport type { AxisPosition, AxisSpread } from \"~/primitive/Axis.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Size, UNBOUNDED, isUnbounded } from \"~/primitive/Size.js\";\n\n/**\n * Sizing strategy along an {@link HBox} or {@link VBox}'s main axis.\n *\n * - `\"preferred\"` — each child gets its preferred width (height for VBox);\n * `weight`-constrained children split the remaining space; an overflow\n * shrinks non-weighted children proportionally toward their min sizes.\n * - `\"equal\"` — children split the container's inner extent equally; the\n * per-cell floor is `max(child.minSize.width)` (height for VBox);\n * `weight` constraints are ignored.\n *\n * @category Layouts\n */\nexport type BoxMode = \"preferred\" | \"equal\";\n\n/**\n * How an `\"equal\"`-mode {@link HBox}/{@link VBox} sizes its cells when the\n * row/column overflows the host's inner extent and the host has opted into\n * scrolling (`Panel.setAutoScroll`).\n *\n * - `\"preferred\"` (the default) — every cell takes the widest/tallest child's\n * preferred extent, so cells keep their preferred size and the host scrolls.\n * - `\"min\"` — every cell stays at the min floor (`max(child.minSize)`), so the\n * row/column scrolls at the minimum cell size instead of growing.\n *\n * Has no effect outside `\"equal\"` mode, nor when the cells fit (the equal share\n * clears the min floor), nor when the host does not scroll (cells always clamp\n * to the min floor and the host's `overflow: hidden` clips the surplus).\n *\n * @category Layouts\n */\nexport type BoxOverflowSizing = \"preferred\" | \"min\";\n\n/**\n * How a `\"preferred\"`-mode {@link HBox}/{@link VBox} distributes the leftover\n * main-axis space when its children are shorter than the inner main extent and\n * no `weight` cells consume the slack. Mirrors CSS `justify-content`.\n *\n * A single line makes exactly one main-axis slack decision, so the two shared\n * axis concepts fuse into this one field: the {@link AxisPosition} half\n * (`\"start\"`/`\"center\"`/`\"end\"`) positions the whole child block as a unit,\n * while the {@link AxisSpread} half (`\"between\"`/`\"around\"`) spreads the slack\n * into the inter-child gaps. `justifyOffsets` reflects the split — position\n * values yield a leading offset (`lead`, `gap: 0`) and spread values yield an\n * inter-child `gap`. `\"start\"` is the shared identity of both halves, so the\n * union collapses to these five distinct values.\n *\n * - `\"start\"` (the default) — children pack at the leading edge; the slack sits\n * at the trailing edge.\n * - `\"center\"` — the child block is centred; equal slack on both ends.\n * - `\"end\"` — children pack at the trailing edge; the slack sits at the leading\n * edge.\n * - `\"between\"` — the first child sits at the leading edge, the last at the\n * trailing edge, and the slack is split evenly into the gaps between them.\n * - `\"around\"` — every child gets equal space around it: a half-unit before the\n * first and after the last, a full unit between neighbours.\n *\n * Has no effect outside `\"preferred\"` mode, nor when `weight` cells absorb the\n * slack, nor when the content fills or overflows the inner extent (the row\n * clamps to `\"start\"` so the leading child is never pushed out of view).\n *\n * @category Layouts\n */\nexport type BoxJustify = AxisPosition | AxisSpread;\n\n/**\n * Cross-axis alignment of a child within an {@link HBox} row / {@link VBox}\n * column, when the child sets no explicit per-child cross intent (fill/anchor\n * align-self). Mirrors {@link FlowLayout}'s `FlowItemAlign`, with the extra\n * `\"stretch\"` a box can do.\n *\n * - `\"start\"` — leading cross-edge (HBox top, VBox left).\n * - `\"center\"` — centred in the cross band.\n * - `\"end\"` — trailing cross-edge (HBox bottom, VBox right).\n * - `\"baseline\"` — HBox: shared text baseline (the default). VBox has no cross\n * text baseline, so it degrades to `\"start\"`.\n * - `\"stretch\"` — fill the cross band (equivalent to the deprecated\n * `stretching`).\n *\n * @category Layouts\n */\nexport type BoxItemAlign = \"start\" | \"center\" | \"end\" | \"baseline\" | \"stretch\";\n\n/**\n * Construction-time options shared by {@link HBox} and {@link VBox}.\n *\n * @remarks `mode` selects the sizing strategy along the box's main axis.\n * `\"preferred\"` (the default) honours each child's preferred main-axis extent\n * and supports `weight` cells. `\"equal\"` divides the container's main axis\n * equally and ignores `weight`. `mode` is independent of `stretching`, which\n * governs the cross axis: `stretching` defaults to `false` in both modes, so\n * `\"equal\"` divides the main axis but leaves children at their preferred\n * cross-axis extent unless `stretching: true` is passed.\n *\n * @category Layouts\n */\nexport interface BoxLayoutOptions extends LayoutManagerOptions {\n spacing?: number;\n /** @deprecated Use `itemAlign` — `stretching: true` ≡ `itemAlign: \"stretch\"`. */\n stretching?: boolean;\n itemAlign?: BoxItemAlign;\n mode?: BoxMode;\n overflowSizing?: BoxOverflowSizing;\n justify?: BoxJustify;\n}\n\n/**\n * Abstract base for the single-axis box layouts {@link HBox} and {@link VBox}.\n * Holds the axis-agnostic configuration plumbing — spacing, stretching, sizing\n * mode, and overflow sizing — and dispatches a {@link BoxLayoutOptions} bag.\n * The geometric algorithms (`getPreferredSize`, `getMinSize`, `getMaxSize`,\n * `computeTotalMinSize`, `doLayout`) are mirror-image per axis and stay\n * concrete on each subclass.\n *\n * @category Layouts\n */\nexport abstract class BoxLayout extends LayoutManager {\n\n // `protected`, not `private`: the subclasses' geometric methods\n // (getPreferredSize/getMinSize/getMaxSize/computeTotalMinSize/doLayout)\n // read these fields directly, so they must be visible to HBox/VBox.\n protected _spacing: number = 5;\n protected _itemAlign: BoxItemAlign = \"baseline\";\n protected _mode: BoxMode = \"preferred\";\n protected _overflowSizing: BoxOverflowSizing = \"preferred\";\n protected _justify: BoxJustify = \"start\";\n\n constructor(options?: BoxLayoutOptions) {\n // LayoutManager's constructor takes no options; applied via applyOptions below.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link BoxLayoutOptions} bag, dispatching mode, spacing, and\n * stretching after the inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @remarks `mode` and `stretching` are independent axes: `mode` governs the\n * main-axis sizing strategy, `stretching` governs whether children fill the\n * cross axis. Neither defaults from the other — `stretching` is `false`\n * unless the options bag passes it explicitly, in both `\"preferred\"` and\n * `\"equal\"` mode.\n */\n protected applyOptions(options: BoxLayoutOptions): void {\n super.applyOptions(options);\n\n if (options.mode !== undefined) {\n this.setMode(options.mode);\n }\n\n if (options.spacing !== undefined) {\n this.setComponentSpacing(options.spacing);\n }\n\n if (options.stretching !== undefined) {\n this.setStretching(options.stretching);\n }\n\n if (options.itemAlign !== undefined) {\n this.setItemAlign(options.itemAlign);\n }\n\n if (options.overflowSizing !== undefined) {\n this.setOverflowSizing(options.overflowSizing);\n }\n\n if (options.justify !== undefined) {\n this.setJustify(options.justify);\n }\n }\n\n /**\n * Returns the pixel spacing between child components.\n *\n * @returns The current spacing in pixels.\n */\n getComponentSpacing(): number {\n return this._spacing || 0;\n }\n\n /**\n * Sets the pixel spacing between child components.\n *\n * @param spacing - Spacing in pixels.\n *\n * @returns This layout manager, for method chaining.\n */\n setComponentSpacing(spacing: number): this {\n this._spacing = spacing || 0;\n\n return this;\n }\n\n /**\n * Returns whether children stretch to fill the container's cross axis.\n *\n * @returns `true` if stretching is enabled.\n *\n * @deprecated Use `getItemAlign() === \"stretch\"`.\n */\n isStretching(): boolean {\n return this._itemAlign === \"stretch\";\n }\n\n /**\n * Sets whether children stretch to fill the container's cross axis.\n *\n * @param stretching - Pass `true` to enable cross-axis stretching.\n *\n * @returns This layout manager, for method chaining.\n *\n * @deprecated Use `setItemAlign(\"stretch\" | \"baseline\")`.\n */\n setStretching(stretching: boolean): this {\n return this.setItemAlign(stretching ? \"stretch\" : \"baseline\");\n }\n\n /**\n * Returns how a child is aligned within the cross axis when it sets no\n * explicit per-child cross intent (fill/anchor align-self).\n *\n * @returns The current {@link BoxItemAlign}.\n */\n getItemAlign(): BoxItemAlign {\n return this._itemAlign;\n }\n\n /**\n * Sets how a child is aligned within the cross axis when it sets no\n * explicit per-child cross intent (fill/anchor align-self).\n *\n * @param itemAlign - `\"start\"`/`\"center\"`/`\"end\"` pin to or centre within\n * the cross band, `\"baseline\"` (the default) aligns HBox rows on their\n * shared text baseline (degrading to `\"start\"` on VBox), and `\"stretch\"`\n * fills the cross band. See {@link BoxItemAlign}.\n *\n * @returns This layout manager, for method chaining.\n */\n setItemAlign(itemAlign: BoxItemAlign): this {\n this._itemAlign = itemAlign;\n\n return this;\n }\n\n /**\n * Returns the current sizing mode along the main axis.\n *\n * @returns Either `\"preferred\"` or `\"equal\"`.\n */\n getMode(): BoxMode {\n return this._mode;\n }\n\n /**\n * Sets the sizing mode along the main axis.\n *\n * @param mode - `\"preferred\"` honours each child's preferred main-axis\n * extent; `\"equal\"` divides the container's main axis equally among\n * children.\n *\n * @returns This layout manager, for method chaining.\n */\n setMode(mode: BoxMode): this {\n this._mode = mode;\n\n return this;\n }\n\n /**\n * Returns the cell-sizing strategy used when an `\"equal\"`-mode row/column\n * overflows a scrolling host.\n *\n * @returns Either `\"preferred\"` or `\"min\"`.\n */\n getOverflowSizing(): BoxOverflowSizing {\n return this._overflowSizing;\n }\n\n /**\n * Sets the cell-sizing strategy used when an `\"equal\"`-mode row/column\n * overflows a scrolling host.\n *\n * @param overflowSizing - `\"preferred\"` grows every cell to the largest\n * child's preferred extent and scrolls; `\"min\"` keeps cells at the min\n * floor and scrolls at the minimum cell size. See {@link BoxOverflowSizing}.\n *\n * @returns This layout manager, for method chaining.\n */\n setOverflowSizing(overflowSizing: BoxOverflowSizing): this {\n this._overflowSizing = overflowSizing;\n\n return this;\n }\n\n /**\n * Returns how leftover main-axis space is distributed in `\"preferred\"` mode.\n *\n * @returns The current {@link BoxJustify} mode.\n */\n getJustify(): BoxJustify {\n return this._justify;\n }\n\n /**\n * Sets how leftover main-axis space is distributed in `\"preferred\"` mode.\n *\n * @param justify - `\"start\"` packs children at the leading edge (the\n * default), `\"center\"`/`\"end\"` shift the block, and `\"between\"`/`\"around\"`\n * spread the slack into the inter-child gaps. See {@link BoxJustify}.\n *\n * @returns This layout manager, for method chaining.\n */\n setJustify(justify: BoxJustify): this {\n this._justify = justify;\n\n return this;\n }\n\n /**\n * Aggregates the children's maximum sizes per the box contract: main axis =\n * sum of child maxima (+ spacing; in `\"equal\"` mode count * widest-child-max),\n * cross axis = max of child maxima, a null or unbounded child max making that\n * axis unbounded. Saturated to {@link UNBOUNDED}. Includes the container\n * perimeter.\n *\n * @param horizontal - `true` for {@link HBox} (main = width), `false` for\n * {@link VBox} (main = height).\n * @returns The aggregated maximum `{width, height}`, or `null` if no\n * container is attached.\n */\n protected aggregateMaxSize(horizontal: boolean): Size | null {\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const perimeterSize = container.getPerimeterSize();\n const components = container.getLaidOutComponents();\n\n const mainStart = horizontal ? perimeterSize.left + perimeterSize.right : perimeterSize.top + perimeterSize.bottom;\n const crossExtra = horizontal ? perimeterSize.top + perimeterSize.bottom : perimeterSize.left + perimeterSize.right;\n\n let main = mainStart;\n let cross = 0;\n let mainUnbounded = false;\n let crossUnbounded = false;\n let maxChildMain = 0;\n\n for (const component of components) {\n const size = component.getMaxSize();\n\n if (!size) {\n mainUnbounded = true;\n crossUnbounded = true;\n continue;\n }\n\n const mainExtent = horizontal ? size.width : size.height;\n const crossExtent = horizontal ? size.height : size.width;\n\n if (isUnbounded(mainExtent)) {\n mainUnbounded = true;\n } else if (this._mode === \"equal\") {\n maxChildMain = Math.max(maxChildMain, mainExtent);\n } else {\n main += mainExtent;\n }\n\n if (isUnbounded(crossExtent)) {\n crossUnbounded = true;\n } else {\n cross = Math.max(cross, crossExtent);\n }\n }\n\n if (this._mode === \"equal\") {\n main += components.length * maxChildMain + this._spacing * Math.max(0, components.length - 1);\n } else {\n main += this._spacing * Math.max(0, components.length - 1);\n }\n\n cross += crossExtra;\n\n const mainValue = mainUnbounded ? UNBOUNDED : main;\n const crossValue = crossUnbounded ? UNBOUNDED : cross;\n\n return {\n width: horizontal ? mainValue : crossValue,\n height: horizontal ? crossValue : mainValue\n };\n }\n\n /**\n * Resolves how much main-axis space the weight cells share and how hard the\n * non-weighted children must shrink. When the non-weighted children's\n * preferred extents fit (or the host scrolls on this axis), nothing shrinks\n * and the leftover is the weight remainder. Otherwise the children shrink\n * proportionally toward their min extents so the last child's far edge lands\n * inside the container.\n *\n * @param fixedPreferred - Summed preferred main-axis extent of the\n * non-weighted children, including inter-child spacing.\n * @param fixedMin - Summed minimum main-axis extent of the same children,\n * including spacing.\n * @param available - The working container's inner extent on the main axis.\n * @param overflowing - Whether the host has opted into scrolling on this\n * axis; when `true` the shrink is skipped so the host's CSS overflow\n * engages instead.\n * @returns `remaining` — the main-axis space left for weight cells — and\n * `shrinkRatio` — `0` (no shrink) through `1` (shrink fully to min).\n */\n protected computeShrink(fixedPreferred: number, fixedMin: number, available: number, overflowing: boolean): { remaining: number; shrinkRatio: number } {\n if (fixedPreferred <= available || overflowing) {\n return { remaining: Math.max(0, available - fixedPreferred), shrinkRatio: 0 };\n }\n\n const excess = fixedPreferred - available;\n const shrinkable = fixedPreferred - fixedMin;\n\n return { remaining: 0, shrinkRatio: shrinkable > 0 ? Math.min(1, excess / shrinkable) : 1 };\n }\n\n /**\n * Distributes the trailing main-axis slack per {@link BoxJustify}, returning\n * a leading offset and an extra inter-child gap. The subclass adds `lead` to\n * the placement cursor's start and `gap` to the inter-child spacing. A row\n * that fills or overflows the inner extent (`residual === 0`) and the\n * `\"start\"` fast path both return `{ lead: 0, gap: 0 }`, leaving placement\n * byte-identical to the un-justified loop. Generalises\n * {@link FlowLayout.alignLead}, which only produces a leading offset, by also\n * spreading slack into the gaps for `\"between\"`/`\"around\"`.\n *\n * @param contentMain - Summed placed child main-extents plus inter-child\n * spacing — the block's total main extent.\n * @param innerMain - The container's inner extent along the main axis.\n * @param count - The number of children sharing the axis.\n * @returns `lead` — pixels added before the first child — and `gap` — pixels\n * added to the spacing after each child. Both are non-negative.\n */\n protected justifyOffsets(contentMain: number, innerMain: number, count: number): { lead: number; gap: number } {\n const residual = Math.max(0, innerMain - contentMain);\n\n if (residual === 0 || this._justify === \"start\") {\n return { lead: 0, gap: 0 };\n }\n\n if (this._justify === \"center\") {\n return { lead: residual / 2, gap: 0 };\n }\n\n if (this._justify === \"end\") {\n return { lead: residual, gap: 0 };\n }\n\n if (this._justify === \"between\") {\n return { lead: 0, gap: count > 1 ? residual / (count - 1) : 0 };\n }\n\n // \"around\"\n return { lead: count > 0 ? residual / (2 * count) : 0, gap: count > 0 ? residual / count : 0 };\n }\n\n /**\n * Computes the leading cross-axis offset for the `\"start\"`/`\"center\"`/\n * `\"end\"` {@link BoxItemAlign} fallback — consulted only when a child sets\n * no explicit per-child cross intent and `itemAlign` is not `\"baseline\"` or\n * `\"stretch\"` (those keep their own, unchanged, placement paths). Mirrors\n * {@link FlowLayout.crossOffset}'s `center`/`end` arms.\n *\n * @param childCross - The child's own cross extent.\n * @param crossExtent - The full cross band extent.\n * @returns The leading offset in pixels — `0` for `\"start\"`, and never negative.\n */\n protected crossItemOffset(childCross: number, crossExtent: number): number {\n if (this._itemAlign === \"center\") {\n return Math.max(0, (crossExtent - childCross) / 2);\n }\n\n if (this._itemAlign === \"end\") {\n return Math.max(0, crossExtent - childCross);\n }\n\n return 0; // \"start\"\n }\n\n /**\n * Resolves a child's cross-axis offset and extent within the full cross\n * band, honouring an explicit per-child cross `fill`/`anchor` (align-self).\n * A cross-axis `fill` (`VERTICAL`/`BOTH` in an {@link HBox}, `HORIZONTAL`/\n * `BOTH` in a {@link VBox}) stretches the child to the whole band; a\n * cross-axis `anchor` edge (NORTH/SOUTH for HBox, WEST/EAST for VBox, plus\n * the corners carrying that component) pins the child's natural cross extent\n * to the leading or trailing edge. The main-axis `anchor` component and\n * `CENTER` are deliberately inert — the box owns main-axis sequencing, and\n * when `itemAlign` is `\"baseline\"` (the default) each box's default cross\n * placement (HBox baseline, VBox WEST origin) is more specific than\n * geometric centring; other `itemAlign` values choose the cross offset in\n * the caller.\n *\n * @param component - The child whose constraints supply the cross intent.\n * @param crossLead - The band's leading edge (`insets.top` for HBox,\n * `insets.left` for VBox).\n * @param crossExtent - The full cross band extent.\n * @param naturalCross - The child's preferred cross extent, already capped to\n * the band and the child's maximum; the anchored child sits at this extent.\n * @param horizontal - `true` for {@link HBox} (cross axis is vertical),\n * `false` for {@link VBox} (cross axis is horizontal).\n * @returns `{ offset, extent }` when the child sets an explicit cross intent,\n * or `null` to signal the caller to keep its default cross placement.\n */\n protected crossPlacement(component: Component, crossLead: number, crossExtent: number, naturalCross: number, horizontal: boolean): { offset: number; extent: number } | null {\n const constraints = this.getLayoutConstraints(component);\n const fill = constraints?.fill ?? null;\n const anchor = constraints?.anchor ?? null;\n\n const crossFill = horizontal\n ? (fill === FillType.VERTICAL || fill === FillType.BOTH)\n : (fill === FillType.HORIZONTAL || fill === FillType.BOTH);\n\n if (crossFill) {\n return { offset: crossLead, extent: crossExtent };\n }\n\n const edge = this.crossAnchorEdge(anchor, horizontal);\n\n if (edge === null) {\n return null;\n }\n\n const extent = Math.min(naturalCross, crossExtent);\n const offset = edge === \"lead\"\n ? crossLead\n : crossLead + (crossExtent - extent);\n\n return { offset, extent };\n }\n\n /**\n * Projects a child's `anchor` onto the cross axis as a leading/trailing edge.\n * CENTER and pure main-axis anchors carry no cross component and return\n * `null`, leaving the caller on its default cross placement.\n *\n * @param anchor - The child's anchor constraint, or `null`.\n * @param horizontal - `true` for {@link HBox} (cross = vertical: NORTH=lead,\n * SOUTH=trail), `false` for {@link VBox} (cross = horizontal: WEST=lead,\n * EAST=trail).\n * @returns `\"lead\"`/`\"trail\"` for an anchor with a cross component, else `null`.\n */\n private crossAnchorEdge(anchor: AnchorType | null, horizontal: boolean): \"lead\" | \"trail\" | null {\n if (anchor === null) {\n return null;\n }\n\n if (horizontal) {\n if (anchor === AnchorType.NORTH || anchor === AnchorType.NORTHWEST || anchor === AnchorType.NORTHEAST) {\n return \"lead\";\n }\n\n if (anchor === AnchorType.SOUTH || anchor === AnchorType.SOUTHWEST || anchor === AnchorType.SOUTHEAST) {\n return \"trail\";\n }\n\n return null;\n }\n\n if (anchor === AnchorType.WEST || anchor === AnchorType.NORTHWEST || anchor === AnchorType.SOUTHWEST) {\n return \"lead\";\n }\n\n if (anchor === AnchorType.EAST || anchor === AnchorType.NORTHEAST || anchor === AnchorType.SOUTHEAST) {\n return \"trail\";\n }\n\n return null;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BoxLayout, BoxLayoutOptions } from \"~/layout/BoxLayout.js\";\nimport type { ResolvedPlacement } from \"~/layout/LayoutManager.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link HBox}.\n *\n * @remarks `mode` selects the sizing strategy along the horizontal axis.\n * `\"preferred\"` (the default) honours each child's preferred width and\n * supports `weight` cells. `\"equal\"` divides the container width equally\n * and ignores `weight`. `mode` is independent of `stretching` (the cross-axis\n * fill): `stretching` defaults to `false` in both modes, so `\"equal\"` divides\n * the width but leaves children at their preferred height unless\n * `stretching: true` is passed.\n *\n * @category Layouts\n */\nexport interface HBoxOptions extends BoxLayoutOptions {}\n\n/**\n * A layout manager that places children in a single horizontal row. The\n * `mode` option selects between preferred-width sequencing (with weight-cell\n * support) and equal-width division of the container.\n *\n * @category Layouts\n */\nclass HBox extends BoxLayout {\n\n private _defaultComponentWidth: number = 100;\n\n /**\n * Returns the row's baseline (the maximum child text baseline) measured from\n * the container's content-top, so a baseline-aware parent aligns this HBox\n * container by the same baseline its own children align to — rather than\n * auto-centring the whole container.\n *\n * @returns The inner baseline offset in pixels, or `null` when `itemAlign`\n * is not `\"baseline\"` (a centred/edge-aligned or stretched row exposes no\n * shared baseline) or when no child reports a baseline.\n */\n getContentBaseline(): number | null {\n if (this._itemAlign !== \"baseline\") {\n return null;\n }\n\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const heights: number[] = [];\n const baselines: Array<number | null> = [];\n\n for (const component of container.getLaidOutComponents()) {\n const size = component.getPreferredSize();\n heights.push(size ? size.height : 0);\n baselines.push(component.getBaseline());\n }\n\n return this.computeRowMetrics(heights, baselines).rowAscent;\n }\n\n /**\n * Returns the preferred size. In `\"preferred\"` mode this is the sum\n * of child widths plus spacing. In `\"equal\"` mode it is\n * `count * (maxChildWidth + spacing) - spacing`. Row height in both\n * modes is the baseline-aware row height of the children.\n *\n * @returns The preferred `{width, height}`, or `null` if no container is attached.\n */\n getPreferredSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n let components = container.getLaidOutComponents();\n let width = perimeterSize.left + perimeterSize.right;\n\n const heights: number[] = [];\n const baselines: Array<number | null> = [];\n\n if (this._mode === \"equal\") {\n let maxChildWidth = 0;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getPreferredSize();\n\n if (size) {\n maxChildWidth = Math.max(maxChildWidth, size.width);\n heights.push(size.height);\n baselines.push(component.getBaseline());\n }\n }\n\n width += components.length * (maxChildWidth + this._spacing) - this._spacing;\n } else {\n for (let idx in components) {\n let component = components[idx];\n let size = component.getPreferredSize();\n\n if (size) {\n width += size.width;\n heights.push(size.height);\n baselines.push(component.getBaseline());\n }\n }\n\n width += this._spacing * (components.length - 1);\n }\n\n let height = this.computeRowHeight(heights, baselines);\n\n height += perimeterSize.top + perimeterSize.bottom;\n\n return {\n width: width,\n height: height\n };\n }\n\n /**\n * Returns the minimum size. In `\"preferred\"` mode this is the sum of\n * child min widths plus spacing. In `\"equal\"` mode it is\n * `count * (maxChildMinWidth + spacing) - spacing`. Row height in\n * both modes is the baseline-aware row height of the children's\n * minimums.\n *\n * @returns The minimum `{width, height}`, or `null` if no container is attached.\n */\n getMinSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n let components = container.getLaidOutComponents();\n let width = perimeterSize.left + perimeterSize.right;\n\n const heights: number[] = [];\n const baselines: Array<number | null> = [];\n\n if (this._mode === \"equal\") {\n let maxChildMinWidth = 0;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getMinSize();\n\n if (size) {\n maxChildMinWidth = Math.max(maxChildMinWidth, size.width);\n heights.push(size.height);\n baselines.push(component.getBaseline());\n }\n }\n\n width += components.length * (maxChildMinWidth + this._spacing) - this._spacing;\n } else {\n for (let idx in components) {\n let component = components[idx];\n let size = component.getMinSize();\n\n if (size) {\n width += size.width;\n heights.push(size.height);\n baselines.push(component.getBaseline());\n }\n }\n\n width += this._spacing * (components.length - 1);\n }\n\n let height = this.computeRowHeight(heights, baselines);\n\n height += perimeterSize.top + perimeterSize.bottom;\n\n return {\n width: width,\n height: height\n };\n }\n\n /**\n * Returns the maximum size the row can usefully occupy. Along the main axis\n * (width) it sums the children's *maximum* widths plus spacing; in `\"equal\"`\n * mode it is `count * maxChildMaxWidth` plus spacing, since every cell shares\n * the widest child's allowance. The cross axis (height) takes the *largest*\n * child maximum — the tallest a child permits the row to grow to. A child\n * whose maximum is `null` or at the unbounded sentinel makes that axis\n * unbounded.\n *\n * @returns The maximum `{width, height}`, or `null` if no container is attached.\n */\n getMaxSize(): Size | null {\n return this.aggregateMaxSize(true);\n }\n\n /**\n * Computes the children's combined minSize along this manager's geometry.\n * In `\"preferred\"` mode width is the sum of per-child `minSize.width`\n * plus spacing. In `\"equal\"` mode width is\n * `count * maxChildMinWidth + spacing*(n-1)` (HBox distributes width\n * equally so the per-cell floor is the max of every child's min width).\n * Height in both modes is the max per-child `minSize.height`. Used by\n * `doLayout` to inflate the working size when the host has opted into\n * `setOverflowing` on the corresponding axis.\n *\n * @returns The total min-size; `{ width: 0, height: 0 }` when the\n * container is absent or has no children.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n const components = container.getLaidOutComponents();\n if (components.length === 0) {\n return { width: 0, height: 0 };\n }\n\n let height = 0;\n\n if (this._mode === \"equal\") {\n let maxWidth = 0;\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n maxWidth = Math.max(maxWidth, min.width);\n height = Math.max(height, min.height);\n }\n }\n\n return {\n width: components.length * (maxWidth + this._spacing) - this._spacing,\n height,\n };\n }\n\n let width = this._spacing * (components.length - 1);\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n width += min.width;\n height = Math.max(height, min.height);\n }\n }\n\n return { width, height };\n }\n\n /**\n * Lays out the children left-to-right, dispatching to `layoutEqualMode` or\n * `layoutPreferredMode` per the sizing mode after inflating the working\n * size for any scroll-enabled axis.\n */\n doLayout(): void {\n const container = this.getContainer();\n if (!container) {\n return;\n }\n\n const innerSize = container.getInnerSize();\n if (!innerSize) {\n return;\n }\n\n const components = container.getLaidOutComponents();\n const containerInsets = container.getContentInsets();\n const spacing = this.getComponentSpacing();\n\n // Universal scroll: when the host has opted into per-axis overflow, lay\n // out against the children's combined minSize so trailing children land\n // past the viewport and the host's CSS `overflow: auto` scrolls.\n // `innerSize` stays the real viewport for equal mode's overflow test.\n const containerSize = this.inflateForOverflow(innerSize);\n\n let placements: ResolvedPlacement[];\n\n if (this._mode === \"equal\") {\n placements = this.layoutEqualMode(components, innerSize, containerSize, containerInsets, spacing);\n } else {\n placements = this.layoutPreferredMode(components, containerSize, containerInsets, spacing);\n }\n\n this.commitPlacements(placements);\n\n this.reserveContentFrame();\n }\n\n /**\n * Places children in equal-width cells. Every cell takes the same width\n * (see {@link HBox.computeEqualCellWidth}); when stretching, cells fill the\n * container height, otherwise children keep their preferred height and are\n * baseline-aligned within the row.\n *\n * @param components - The children to place, in order.\n * @param innerSize - The host's real inner size (pre-inflation), used to\n * measure the equal share against the true viewport.\n * @param containerSize - The working size, possibly inflated for overflow.\n * @param insets - The container's content insets.\n * @param spacing - Inter-child spacing in pixels.\n * @returns The resolved placements, ready for {@link LayoutManager.commitPlacements}.\n */\n private layoutEqualMode(components: Component[], innerSize: Size, containerSize: Size, insets: Insets, spacing: number): ResolvedPlacement[] {\n const cellWidth = this.computeEqualCellWidth(components, innerSize.width, spacing);\n\n if (this.isStretching()) {\n const y = insets.getTop();\n let x = insets.getLeft();\n const placements: ResolvedPlacement[] = [];\n\n for (const component of components) {\n placements.push({ component, ...this.resolveBounds(component, x, y, cellWidth, containerSize.height, FillType.BOTH) });\n\n x += cellWidth + spacing;\n }\n\n return placements;\n }\n\n const heights: number[] = [];\n const baselines: Array<number | null> = [];\n\n for (const component of components) {\n const size = component.getPreferredSize();\n\n heights.push(size ? size.height : 0);\n baselines.push(component.getBaseline());\n }\n\n const { rowAscent, rowDescent } = this.computeRowMetrics(heights, baselines);\n\n // Match the equal-stretch band exactly: the stretch branch fills\n // containerSize.height from insets.top with no bottom-inset subtraction,\n // so an EAST/fill align-self child reaches the same trailing edge.\n const crossLead = insets.getTop();\n const crossExtent = containerSize.height;\n\n let x = insets.getLeft();\n const placements: ResolvedPlacement[] = [];\n\n for (let idx = 0; idx < components.length; idx += 1) {\n const component = components[idx];\n\n const cross = this.crossPlacement(component, crossLead, crossExtent, heights[idx], true);\n\n if (cross) {\n placements.push({ component, ...this.resolveBounds(component, x, cross.offset, cellWidth, cross.extent, FillType.BOTH) });\n } else if (this._itemAlign === \"start\" || this._itemAlign === \"center\" || this._itemAlign === \"end\") {\n const y = crossLead + this.crossItemOffset(heights[idx], crossExtent);\n\n placements.push({ component, ...this.resolveBounds(component, x, y, cellWidth, heights[idx], FillType.BOTH) });\n } else {\n const y = this.rowChildY(insets.getTop(), heights[idx], baselines[idx], rowAscent, rowDescent);\n\n placements.push({ component, ...this.resolveBounds(component, x, y, cellWidth, heights[idx], FillType.BOTH) });\n }\n\n x += cellWidth + spacing;\n }\n\n return placements;\n }\n\n /**\n * Computes the shared cell width for equal mode: the equal share of the\n * inner width, floored at the widest child's min width.\n *\n * @param components - The children sharing the row.\n * @param innerWidth - The host's real inner width (pre-inflation).\n * @param spacing - Inter-child spacing in pixels.\n * @returns The width every equal-mode cell receives.\n *\n * @remarks Three cases drive the floor: (1) the share clears the widest\n * child's min width → the row fits, divide equally; (2) the share is below\n * the min floor, the host scrolls on this axis, and `overflowSizing` is\n * `\"preferred\"` → every cell takes the widest child's preferred width so\n * cells regain preferred size instead of sticking at min while scrolling;\n * (3) otherwise → clamp to the min floor (a non-scrolling host's\n * `overflow: hidden` clips the surplus).\n */\n private computeEqualCellWidth(components: Component[], innerWidth: number, spacing: number): number {\n let maxChildMinWidth = 0;\n let maxChildPreferredWidth = 0;\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n maxChildMinWidth = Math.max(maxChildMinWidth, min.width);\n }\n\n const pref = component.getPreferredSize();\n if (pref) {\n maxChildPreferredWidth = Math.max(maxChildPreferredWidth, pref.width);\n }\n }\n\n const equalShare = (innerWidth - spacing * (components.length - 1)) / components.length;\n\n if (equalShare >= maxChildMinWidth) {\n return equalShare;\n }\n\n if (this.isOverflowingX() && this._overflowSizing === \"preferred\") {\n return Math.max(maxChildMinWidth, maxChildPreferredWidth);\n }\n\n return maxChildMinWidth;\n }\n\n /**\n * Places children at their preferred widths. Weight cells split the space\n * left after the non-weighted children; when the row overflows, the\n * non-weighted children shrink proportionally toward their min widths.\n * Children keep their preferred height (or fill the row height when\n * stretching) and are baseline-aligned unless stretching.\n *\n * @param components - The children to place, in order.\n * @param containerSize - The working size, possibly inflated for overflow.\n * @param insets - The container's content insets.\n * @param spacing - Inter-child spacing in pixels.\n * @returns The resolved placements, ready for {@link LayoutManager.commitPlacements}.\n */\n private layoutPreferredMode(components: Component[], containerSize: Size, insets: Insets, spacing: number): ResolvedPlacement[] {\n const { totalWeight, fixedPreferred, fixedMin } = this.measureFixedWidths(components, spacing);\n\n const { remaining: remainingWidth, shrinkRatio } = this.computeShrink(\n fixedPreferred,\n fixedMin,\n containerSize.width,\n this.isOverflowingX()\n );\n\n const widths: number[] = [];\n const heights: number[] = [];\n const baselines: Array<number | null> = [];\n\n for (const component of components) {\n const weight = this.getLayoutConstraints(component)?.weight ?? 0;\n const size = component.getPreferredSize();\n const minSize = component.getMinSize();\n const maxSize = component.getMaxSize();\n\n widths.push(this.resolveChildWidth(size, minSize, maxSize, weight, totalWeight, remainingWidth, shrinkRatio));\n\n // Cross-axis (height): give the child the row's available height —\n // the full inner height when stretching or sizeless, otherwise its\n // preferred height capped to the row. Cap to the child's maximum, but\n // do NOT floor to its minimum: enforcing the minimum here would\n // dogmatically inflate a child back up to its content size even when\n // the row is shorter, defeating a scrolling/clipping child. The\n // child's own setHeight → clampHeight applies its minimum (its\n // content minimum for a general component, or nothing for a Panel,\n // which fits its allocation and scrolls). When the host opts into\n // vertical scroll, `containerSize` is already inflated to the content\n // extent upstream, so `min(pref, containerSize)` still yields the full\n // height without a floor here.\n let height: number;\n\n if (!size || this.isStretching()) {\n height = containerSize.height;\n } else {\n height = Math.min(size.height, containerSize.height);\n }\n\n if (maxSize) {\n height = Math.min(height, maxSize.height);\n }\n\n heights.push(height);\n\n baselines.push(component.getBaseline());\n }\n\n // Stretching forces every child to fill the row vertically, which makes\n // baseline alignment meaningless — fall back to top-alignment. rowAscent\n // is driven only by text-bearing children; tall null-baseline children\n // (a List, TextArea, etc.) must NOT drag the baseline down or every text\n // label in the row would be pushed off the top.\n const { rowAscent, rowDescent } = this.isStretching()\n ? { rowAscent: null, rowDescent: 0 }\n : this.computeRowMetrics(heights, baselines);\n\n // Sum the placed main extents to find the trailing slack, then ask the\n // shared helper how to distribute it. Weight cells already consume all\n // slack, so justify is a no-op when any are present.\n let lead = 0;\n let gap = 0;\n\n if (totalWeight === 0) {\n let contentWidth = spacing * (components.length - 1);\n\n for (const w of widths) {\n contentWidth += w;\n }\n\n const innerWidth = containerSize.width - (insets.getLeft() + insets.getRight());\n\n ({ lead, gap } = this.justifyOffsets(contentWidth, innerWidth, components.length));\n }\n\n // Cross band for per-child align-self: the same vertical band the\n // stretch path fills, trimmed by both insets.\n const crossLead = insets.getTop();\n const crossExtent = containerSize.height - (insets.getTop() + insets.getBottom());\n\n let x = insets.getLeft() + lead;\n const placements: ResolvedPlacement[] = [];\n\n for (let idx = 0; idx < components.length; idx += 1) {\n const component = components[idx];\n\n // Align-self sizes from the child's *preferred* height (capped to the\n // band + max), independent of the stretch-inflated heights[idx], so an\n // anchored child shrinks-and-anchors even under global stretching.\n const pref = component.getPreferredSize();\n const maxSize = component.getMaxSize();\n let naturalCross = pref ? Math.min(pref.height, crossExtent) : crossExtent;\n\n if (maxSize) {\n naturalCross = Math.min(naturalCross, maxSize.height);\n }\n\n const cross = this.crossPlacement(component, crossLead, crossExtent, naturalCross, true);\n\n if (cross) {\n placements.push({ component, ...this.resolveBounds(component, x, cross.offset, widths[idx], cross.extent, FillType.BOTH) });\n } else if (this._itemAlign === \"start\" || this._itemAlign === \"center\" || this._itemAlign === \"end\") {\n const y = crossLead + this.crossItemOffset(heights[idx], crossExtent);\n\n placements.push({ component, ...this.resolveBounds(component, x, y, widths[idx], heights[idx], FillType.BOTH) });\n } else {\n const y = this.rowChildY(insets.getTop(), heights[idx], baselines[idx], rowAscent, rowDescent);\n\n placements.push({ component, ...this.resolveBounds(component, x, y, widths[idx], heights[idx], FillType.BOTH) });\n }\n\n // Advance by the resolved width, not getWidth(): the gap is measured\n // against the same extent contentWidth summed, so a placeComponent\n // clamp must not skew the trailing edge.\n x += widths[idx];\n x += spacing + gap;\n }\n\n return placements;\n }\n\n /**\n * Sums the non-weighted children's preferred and minimum widths (each\n * including inter-child spacing) and the total weight of the weight cells.\n *\n * @param components - The children sharing the row.\n * @param spacing - Inter-child spacing in pixels.\n * @returns `totalWeight` of the weight cells, plus the `fixedPreferred` and\n * `fixedMin` width totals of the non-weighted children.\n */\n private measureFixedWidths(components: Component[], spacing: number): { totalWeight: number; fixedPreferred: number; fixedMin: number } {\n let totalWeight = 0;\n let fixedPreferred = spacing * (components.length - 1);\n let fixedMin = spacing * (components.length - 1);\n\n for (const component of components) {\n const weight = this.getLayoutConstraints(component)?.weight ?? 0;\n\n if (weight > 0) {\n totalWeight += weight;\n } else {\n const size = component.getPreferredSize();\n const minSize = component.getMinSize();\n\n fixedPreferred += this.preferredChildWidth(size, minSize);\n fixedMin += minSize ? minSize.width : 0;\n }\n }\n\n return { totalWeight, fixedPreferred, fixedMin };\n }\n\n /**\n * Resolves a non-weighted child's preferred width, falling back through min\n * width to `_defaultComponentWidth`.\n *\n * @param size - The child's preferred size, or `null`.\n * @param minSize - The child's minimum size, or `null`.\n * @returns The width the child contributes before shrinking.\n *\n * @remarks Nullish-coalesce, not `||`: a component with an explicit\n * preferred width of 0 (e.g. an empty `Text` label) must contribute 0, not\n * fall through to `_defaultComponentWidth` and inflate the row's fixed total\n * past the container, which would force the shrink path to squeeze every\n * non-weighted child (including glyphs) toward its min size. The\n * `minSize.width > 0` guard prevents `LayoutManager._defaultMinSize =\n * {0,0}` from short-circuiting the chain into a 0 width (which would land a\n * layout-managed Table on width 0 even though no preferred size was set).\n *\n * The result is floored at the child's own min width: a child placed at\n * `max(preferred, min)` (see {@link HBox.resolveChildWidth}) must reserve\n * that same width in the fixed total, or a child reporting `preferred < min`\n * (a `min ≤ preferred` invariant violation) would be under-reserved and push\n * the weighted cells out, overflowing the row.\n */\n private preferredChildWidth(size: Size | null, minSize: Size | null): number {\n const preferred = (size ? size.width : undefined)\n ?? (minSize && minSize.width > 0 ? minSize.width : undefined)\n ?? this._defaultComponentWidth;\n\n return minSize ? Math.max(preferred, minSize.width) : preferred;\n }\n\n /**\n * Resolves a child's final width within the row, clamped to its min/max —\n * the minimum wins when the two conflict. Weight cells take a share of\n * `remainingWidth`; non-weighted children take their preferred width\n * reduced by the shrink ratio toward their min width.\n *\n * @param size - The child's preferred size, or `null`.\n * @param minSize - The child's minimum size, or `null`.\n * @param maxSize - The child's maximum size, or `null`.\n * @param weight - The child's weight constraint (0 when non-weighted).\n * @param totalWeight - The summed weight of all weight cells.\n * @param remainingWidth - The space available to weight cells.\n * @param shrinkRatio - How far (0–1) non-weighted children shrink to min.\n * @returns The child's width.\n */\n private resolveChildWidth(size: Size | null, minSize: Size | null, maxSize: Size | null, weight: number, totalWeight: number, remainingWidth: number, shrinkRatio: number): number {\n let width: number;\n\n if (weight > 0 && totalWeight > 0) {\n width = (weight / totalWeight) * remainingWidth;\n } else {\n const pref = this.preferredChildWidth(size, minSize);\n const min = minSize ? minSize.width : 0;\n\n width = pref - shrinkRatio * (pref - min);\n }\n\n if (maxSize) {\n width = Math.min(width, maxSize.width);\n }\n\n if (minSize) {\n width = Math.max(width, minSize.width);\n }\n\n return width;\n }\n\n /**\n * Computes a child's y within the row, aligning text-bearing children on the\n * shared baseline and centring null-baseline children in the text line.\n *\n * @param top - The row's content-top (inside the insets).\n * @param height - The child's height.\n * @param baseline - The child's baseline, or `null` for graphical/replaced children.\n * @param rowAscent - The row's text baseline, or `null` when no child reports one.\n * @param rowDescent - The row's text descent.\n * @returns The child's y position.\n */\n private rowChildY(top: number, height: number, baseline: number | null, rowAscent: number | null, rowDescent: number): number {\n if (rowAscent === null) {\n return top;\n }\n\n if (baseline !== null) {\n return top + (rowAscent - baseline);\n }\n\n return top + this.nullChildY(height, rowAscent, rowDescent);\n }\n}\n\nconst HBoxCallable = callable(HBox);\ntype HBoxCallable = HBox;\nexport {\n HBox as _HBox,\n HBoxCallable as HBox\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Size, UNBOUNDED, isUnbounded } from \"~/primitive/Size.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { BoxLayout, BoxLayoutOptions } from \"~/layout/BoxLayout.js\";\nimport type { ResolvedPlacement } from \"~/layout/LayoutManager.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link VBox}.\n *\n * @remarks `mode` selects the sizing strategy along the vertical axis.\n * `\"preferred\"` (the default) honours each child's preferred height and\n * supports `weight` cells. `\"equal\"` divides the container height equally\n * and ignores `weight`. `mode` is independent of `stretching` (the cross-axis\n * fill): `stretching` defaults to `false` in both modes, so `\"equal\"` divides\n * the height but leaves children at their preferred width unless\n * `stretching: true` is passed.\n *\n * @category Layouts\n */\nexport interface VBoxOptions extends BoxLayoutOptions {}\n\n/**\n * A layout manager that places children in a single vertical column. The\n * `mode` option selects between preferred-height sequencing (with weight-cell\n * support) and equal-height division of the container.\n *\n * @category Layouts\n */\nclass VBox extends BoxLayout {\n\n private _defaultComponentHeight: number = 100;\n\n /**\n * Returns the column's baseline — the first laid-out child's baseline,\n * measured from the container's content-top — so a baseline-aware parent\n * aligns this VBox container by its first row's text baseline rather than\n * auto-centring the whole container.\n *\n * @returns The first child's baseline offset in pixels, or `null` when there\n * is no container, no laid-out children, or the first child reports no\n * baseline of its own.\n *\n * @remarks Forwards the **first** child's baseline verbatim — unlike\n * {@link HBox}, which takes the maximum baseline across the row's children.\n * A column has a single well-defined first row, so forwarding it (including\n * a `null` when that first row is graphical) is the most predictable\n * contract. The first child stacks at the container's content-top in every\n * mode, so its own baseline is already content-relative — `Component`'s\n * `getBaseline` then adds the container's chrome. Unlike `HBox`, this is not\n * disabled while stretching: VBox `stretching` fills the cross (width) axis\n * and leaves each child's height and intrinsic baseline untouched.\n */\n getContentBaseline(): number | null {\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const components = container.getLaidOutComponents();\n if (components.length === 0) {\n return null;\n }\n\n return components[0].getBaseline();\n }\n\n /**\n * Returns the preferred size. In `\"preferred\"` mode this is the widest\n * child width and the sum of child heights plus spacing. In `\"equal\"`\n * mode height is `count * (maxChildHeight + spacing) - spacing`.\n *\n * @returns The preferred `{width, height}`, or `null` if no container is attached.\n */\n getPreferredSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n let components = container.getLaidOutComponents();\n\n if (this._mode === \"equal\") {\n let innerWidth = 0;\n let innerHeight = 0;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getPreferredSize();\n\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight = Math.max(innerHeight, size.height);\n }\n }\n\n const width = innerWidth + perimeterSize.left + perimeterSize.right;\n const height = components.length * (innerHeight + this._spacing) - this._spacing\n + perimeterSize.top + perimeterSize.bottom;\n\n return { width, height };\n }\n\n let width = UNBOUNDED;\n let height = perimeterSize.top + perimeterSize.bottom;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getPreferredSize();\n\n if (size) {\n width = isUnbounded(width) ? Math.min(width, size.width) : Math.max(width, size.width);\n height += size.height;\n }\n }\n\n width += perimeterSize.left + perimeterSize.right;\n height += this._spacing * (components.length - 1);\n\n return {\n width: width,\n height: height\n };\n }\n\n /**\n * Returns the minimum size. In `\"preferred\"` mode this is the widest\n * child minimum width and the sum of child minimum heights plus\n * spacing. In `\"equal\"` mode height is\n * `count * (maxChildMinHeight + spacing) - spacing`.\n *\n * @returns The minimum `{width, height}`, or `null` if no container is attached.\n */\n getMinSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n let components = container.getLaidOutComponents();\n\n if (this._mode === \"equal\") {\n let innerWidth = 0;\n let innerHeight = 0;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getMinSize();\n\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight = Math.max(innerHeight, size.height);\n }\n }\n\n const width = innerWidth + perimeterSize.left + perimeterSize.right;\n const height = components.length * (innerHeight + this._spacing) - this._spacing\n + perimeterSize.top + perimeterSize.bottom;\n\n return { width, height };\n }\n\n let width = 0;\n let height = perimeterSize.top + perimeterSize.bottom;\n\n for (let idx in components) {\n let component = components[idx];\n let size = component.getMinSize();\n\n if (size) {\n width = Math.max(width, size.width);\n height += size.height;\n }\n }\n\n width += perimeterSize.left + perimeterSize.right;\n height += this._spacing * (components.length - 1);\n\n return {\n width: width,\n height: height\n };\n }\n\n /**\n * Returns the maximum size the column can usefully occupy. Along the main\n * axis (height) it sums the children's *maximum* heights plus spacing; in\n * `\"equal\"` mode it is `count * maxChildMaxHeight` plus spacing, since every\n * cell shares the tallest child's allowance. The cross axis (width) takes\n * the *largest* child maximum — the widest a child permits the column to\n * grow to. A child whose maximum is `null` or at the unbounded sentinel\n * makes that axis unbounded.\n *\n * @returns The maximum `{width, height}`, or `null` if no container is attached.\n */\n getMaxSize(): Size | null {\n return this.aggregateMaxSize(false);\n }\n\n /**\n * Computes the children's combined minSize along this manager's geometry.\n * In `\"preferred\"` mode height is the sum of per-child `minSize.height`\n * plus spacing. In `\"equal\"` mode height is\n * `count * maxChildMinHeight + spacing*(n-1)` (VBox distributes height\n * equally so the per-cell floor is the max of every child's min height).\n * Width in both modes is the max per-child `minSize.width`. Used by\n * `doLayout` to inflate the working size when the host has opted into\n * `setOverflowing` on the corresponding axis.\n *\n * @returns The total min-size; `{ width: 0, height: 0 }` when the\n * container is absent or has no children.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n const components = container.getLaidOutComponents();\n if (components.length === 0) {\n return { width: 0, height: 0 };\n }\n\n let width = 0;\n\n if (this._mode === \"equal\") {\n let maxHeight = 0;\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n width = Math.max(width, min.width);\n maxHeight = Math.max(maxHeight, min.height);\n }\n }\n\n return {\n width,\n height: components.length * (maxHeight + this._spacing) - this._spacing,\n };\n }\n\n let height = this._spacing * (components.length - 1);\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n width = Math.max(width, min.width);\n height += min.height;\n }\n }\n\n return { width, height };\n }\n\n /**\n * Lays out the children top-to-bottom, dispatching to `layoutEqualMode` or\n * `layoutPreferredMode` per the sizing mode after inflating the working\n * size for any scroll-enabled axis.\n */\n doLayout(): void {\n const container = this.getContainer();\n if (!container) {\n return;\n }\n\n const innerSize = container.getInnerSize();\n if (!innerSize) {\n return;\n }\n\n const components = container.getLaidOutComponents();\n const containerInsets = container.getContentInsets();\n const spacing = this.getComponentSpacing();\n\n // Universal scroll: when the host has opted into per-axis overflow, lay\n // out against the children's combined minSize so trailing children land\n // past the viewport and the host's CSS `overflow: auto` scrolls.\n // `innerSize` stays the real viewport for equal mode's overflow test.\n const containerSize = this.inflateForOverflow(innerSize);\n\n let placements: ResolvedPlacement[];\n\n if (this._mode === \"equal\") {\n placements = this.layoutEqualMode(components, innerSize, containerSize, containerInsets, spacing);\n } else {\n placements = this.layoutPreferredMode(components, containerSize, containerInsets, spacing);\n }\n\n this.commitPlacements(placements);\n\n this.reserveContentFrame();\n }\n\n /**\n * Places children in equal-height cells stacked top-to-bottom. Every cell\n * takes the same height (see {@link VBox.computeEqualCellHeight}); when\n * stretching, cells fill the container width, otherwise children keep their\n * preferred width and are left-aligned within the column.\n *\n * @param components - The children to place, in order.\n * @param innerSize - The host's real inner size (pre-inflation), used to\n * measure the equal share against the true viewport.\n * @param containerSize - The working size, possibly inflated for overflow.\n * @param insets - The container's content insets.\n * @param spacing - Inter-child spacing in pixels.\n * @returns The resolved placements, ready for {@link LayoutManager.commitPlacements}.\n */\n private layoutEqualMode(components: Component[], innerSize: Size, containerSize: Size, insets: Insets, spacing: number): ResolvedPlacement[] {\n const cellHeight = this.computeEqualCellHeight(components, innerSize.height, spacing);\n\n const x = insets.getLeft();\n let y = insets.getTop();\n\n if (this.isStretching()) {\n const cellWidth = containerSize.width;\n const placements: ResolvedPlacement[] = [];\n\n for (const component of components) {\n placements.push({ component, ...this.resolveBounds(component, x, y, cellWidth, cellHeight, FillType.BOTH) });\n\n y += cellHeight + spacing;\n }\n\n return placements;\n }\n\n // Match the equal-stretch band exactly: the stretch branch fills\n // containerSize.width from insets.left with no right-inset subtraction,\n // so an EAST/fill align-self child reaches the same trailing edge.\n const crossLead = insets.getLeft();\n const crossExtent = containerSize.width;\n const placements: ResolvedPlacement[] = [];\n\n for (const component of components) {\n const size = component.getPreferredSize();\n const width = size ? size.width : 0;\n\n const cross = this.crossPlacement(component, crossLead, crossExtent, width, false);\n\n if (cross) {\n placements.push({ component, ...this.resolveBounds(component, cross.offset, y, cross.extent, cellHeight, FillType.BOTH) });\n } else if (this._itemAlign === \"start\" || this._itemAlign === \"center\" || this._itemAlign === \"end\") {\n const cx = crossLead + this.crossItemOffset(width, crossExtent);\n\n placements.push({ component, ...this.resolveBounds(component, cx, y, width, cellHeight, FillType.BOTH) });\n } else {\n placements.push({ component, ...this.resolveBounds(component, x, y, width, cellHeight, FillType.BOTH) });\n }\n\n y += cellHeight + spacing;\n }\n\n return placements;\n }\n\n /**\n * Computes the shared cell height for equal mode: the equal share of the\n * inner height, floored at the tallest child's min height.\n *\n * @param components - The children sharing the column.\n * @param innerHeight - The host's real inner height (pre-inflation).\n * @param spacing - Inter-child spacing in pixels.\n * @returns The height every equal-mode cell receives.\n *\n * @remarks Three cases drive the floor: (1) the share clears the tallest\n * child's min height → the column fits, divide equally; (2) the share is\n * below the min floor, the host scrolls on this axis, and `overflowSizing`\n * is `\"preferred\"` → every cell takes the tallest child's preferred height\n * so cells regain preferred size instead of sticking at min while\n * scrolling; (3) otherwise → clamp to the min floor (a non-scrolling host's\n * `overflow: hidden` clips the surplus).\n */\n private computeEqualCellHeight(components: Component[], innerHeight: number, spacing: number): number {\n let maxChildMinHeight = 0;\n let maxChildPreferredHeight = 0;\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n maxChildMinHeight = Math.max(maxChildMinHeight, min.height);\n }\n\n const pref = component.getPreferredSize();\n if (pref) {\n maxChildPreferredHeight = Math.max(maxChildPreferredHeight, pref.height);\n }\n }\n\n const equalShare = (innerHeight - spacing * (components.length - 1)) / components.length;\n\n if (equalShare >= maxChildMinHeight) {\n return equalShare;\n }\n\n if (this.isOverflowingY() && this._overflowSizing === \"preferred\") {\n return Math.max(maxChildMinHeight, maxChildPreferredHeight);\n }\n\n return maxChildMinHeight;\n }\n\n /**\n * Places children at their preferred heights stacked top-to-bottom. Weight\n * cells split the space left after the non-weighted children; when the\n * column overflows, the non-weighted children shrink proportionally toward\n * their min heights. Children keep their preferred width, or fill the\n * container width when stretching.\n *\n * @param components - The children to place, in order.\n * @param containerSize - The working size, possibly inflated for overflow.\n * @param insets - The container's content insets.\n * @param spacing - Inter-child spacing in pixels.\n * @returns The resolved placements, ready for {@link LayoutManager.commitPlacements}.\n */\n private layoutPreferredMode(components: Component[], containerSize: Size, insets: Insets, spacing: number): ResolvedPlacement[] {\n const { totalWeight, fixedPreferred, fixedMin } = this.measureFixedHeights(components, spacing);\n\n const { remaining: remainingHeight, shrinkRatio } = this.computeShrink(\n fixedPreferred,\n fixedMin,\n containerSize.height,\n this.isOverflowingY()\n );\n\n // Pre-pass: resolve each child's height into an array so the trailing\n // slack can be measured before placement (mirrors HBox's widths[]).\n const heights: number[] = [];\n\n for (const component of components) {\n const weight = this.getLayoutConstraints(component)?.weight ?? 0;\n const size = component.getPreferredSize();\n const minSize = component.getMinSize();\n const maxSize = component.getMaxSize();\n\n heights.push(this.resolveChildHeight(size, minSize, maxSize, weight, totalWeight, remainingHeight, shrinkRatio));\n }\n\n // Sum the placed main extents to find the trailing slack, then ask the\n // shared helper how to distribute it. Weight cells already consume all\n // slack, so justify is a no-op when any are present.\n let lead = 0;\n let gap = 0;\n\n if (totalWeight === 0) {\n let contentHeight = spacing * (components.length - 1);\n\n for (const h of heights) {\n contentHeight += h;\n }\n\n const innerHeight = containerSize.height - (insets.getTop() + insets.getBottom());\n\n ({ lead, gap } = this.justifyOffsets(contentHeight, innerHeight, components.length));\n }\n\n // Cross band for per-child align-self: the horizontal band trimmed by\n // both insets. The default path keeps reading containerSize.width\n // (un-trimmed) to stay byte-identical with today's body.\n const crossLead = insets.getLeft();\n const crossExtent = containerSize.width - (insets.getLeft() + insets.getRight());\n\n const x = insets.getLeft();\n let y = insets.getTop() + lead;\n const placements: ResolvedPlacement[] = [];\n\n for (let idx = 0; idx < components.length; idx += 1) {\n const component = components[idx];\n const size = component.getPreferredSize();\n const maxSize = component.getMaxSize();\n\n // Cross-axis (width): give the child the column's available width —\n // the full inner width when stretching or sizeless, otherwise its\n // preferred width capped to the column. Cap to the child's maximum,\n // but do NOT floor to its minimum: enforcing the minimum here would\n // dogmatically inflate a child back up to its content size even when\n // the column is narrower, defeating a scrolling/clipping child. The\n // child's own setWidth → clampWidth applies its minimum (its content\n // minimum for a general component, or nothing for a Panel, which fits\n // its allocation and scrolls). When the host opts into horizontal\n // scroll, `containerSize` is already inflated to the content extent\n // upstream, so `min(pref, containerSize)` still yields the full width\n // without a floor here.\n let defaultWidth: number;\n\n if (!size || this.isStretching()) {\n defaultWidth = containerSize.width;\n } else {\n defaultWidth = Math.min(size.width, containerSize.width);\n }\n\n if (maxSize) {\n defaultWidth = Math.min(defaultWidth, maxSize.width);\n }\n\n // Align-self sizes from the child's *preferred* width (capped to the\n // band + max), independent of global stretching, so an anchored child\n // shrinks-and-anchors even when the column is stretching.\n let naturalWidth = size ? Math.min(size.width, crossExtent) : crossExtent;\n\n if (maxSize) {\n naturalWidth = Math.min(naturalWidth, maxSize.width);\n }\n\n const cross = this.crossPlacement(component, crossLead, crossExtent, naturalWidth, false);\n\n if (cross) {\n placements.push({ component, ...this.resolveBounds(component, cross.offset, y, cross.extent, heights[idx], FillType.BOTH) });\n } else if (this._itemAlign === \"start\" || this._itemAlign === \"center\" || this._itemAlign === \"end\") {\n const cx = crossLead + this.crossItemOffset(naturalWidth, crossExtent);\n\n placements.push({ component, ...this.resolveBounds(component, cx, y, naturalWidth, heights[idx], FillType.BOTH) });\n } else {\n placements.push({ component, ...this.resolveBounds(component, x, y, defaultWidth, heights[idx], FillType.BOTH) });\n }\n\n // Advance by the resolved height, not getHeight(): the gap is\n // measured against the same extent contentHeight summed, so a\n // placeComponent clamp must not skew the trailing edge.\n y += heights[idx];\n y += spacing + gap;\n }\n\n return placements;\n }\n\n /**\n * Sums the non-weighted children's preferred and minimum heights (each\n * including inter-child spacing) and the total weight of the weight cells.\n *\n * @param components - The children sharing the column.\n * @param spacing - Inter-child spacing in pixels.\n * @returns `totalWeight` of the weight cells, plus the `fixedPreferred` and\n * `fixedMin` height totals of the non-weighted children.\n */\n private measureFixedHeights(components: Component[], spacing: number): { totalWeight: number; fixedPreferred: number; fixedMin: number } {\n let totalWeight = 0;\n let fixedPreferred = spacing * (components.length - 1);\n let fixedMin = spacing * (components.length - 1);\n\n for (const component of components) {\n const weight = this.getLayoutConstraints(component)?.weight ?? 0;\n\n if (weight > 0) {\n totalWeight += weight;\n } else {\n const size = component.getPreferredSize();\n const minSize = component.getMinSize();\n\n fixedPreferred += this.preferredChildHeight(size, minSize);\n fixedMin += minSize ? minSize.height : 0;\n }\n }\n\n return { totalWeight, fixedPreferred, fixedMin };\n }\n\n /**\n * Resolves a non-weighted child's preferred height, falling back through min\n * height to `_defaultComponentHeight`.\n *\n * @param size - The child's preferred size, or `null`.\n * @param minSize - The child's minimum size, or `null`.\n * @returns The height the child contributes before shrinking.\n *\n * @remarks Nullish-coalesce, not `||`: a component with an explicit\n * preferred height of 0 must contribute 0, not fall through to\n * `_defaultComponentHeight`. The `minSize.height > 0` guard prevents\n * `LayoutManager._defaultMinSize = {0,0}` from short-circuiting the chain\n * into a 0 height (which would land a layout-managed Table on a 0 height\n * even though no preferred size was set).\n *\n * The result is floored at the child's own min height: a child placed at\n * `max(preferred, min)` (see {@link VBox.resolveChildHeight}) must reserve\n * that same height in the fixed total, or a child reporting `preferred < min`\n * (a `min ≤ preferred` invariant violation) would be under-reserved and push\n * the weighted cells out, overflowing the column.\n */\n private preferredChildHeight(size: Size | null, minSize: Size | null): number {\n const preferred = (size ? size.height : undefined)\n ?? (minSize && minSize.height > 0 ? minSize.height : undefined)\n ?? this._defaultComponentHeight;\n\n return minSize ? Math.max(preferred, minSize.height) : preferred;\n }\n\n /**\n * Resolves a child's final height within the column, clamped to its\n * min/max — the minimum wins when the two conflict. Weight cells take a\n * share of `remainingHeight`; non-weighted children take their preferred\n * height reduced by the shrink ratio toward their min height.\n *\n * @param size - The child's preferred size, or `null`.\n * @param minSize - The child's minimum size, or `null`.\n * @param maxSize - The child's maximum size, or `null`.\n * @param weight - The child's weight constraint (0 when non-weighted).\n * @param totalWeight - The summed weight of all weight cells.\n * @param remainingHeight - The space available to weight cells.\n * @param shrinkRatio - How far (0–1) non-weighted children shrink to min.\n * @returns The child's height.\n */\n private resolveChildHeight(size: Size | null, minSize: Size | null, maxSize: Size | null, weight: number, totalWeight: number, remainingHeight: number, shrinkRatio: number): number {\n let height: number;\n\n if (weight > 0 && totalWeight > 0) {\n height = (weight / totalWeight) * remainingHeight;\n } else {\n const pref = this.preferredChildHeight(size, minSize);\n const min = minSize ? minSize.height : 0;\n\n height = pref - shrinkRatio * (pref - min);\n }\n\n if (maxSize) {\n height = Math.min(height, maxSize.height);\n }\n\n if (minSize) {\n height = Math.max(height, minSize.height);\n }\n\n return height;\n }\n}\n\nconst VBoxCallable = callable(VBox);\ntype VBoxCallable = VBox;\nexport {\n VBox as _VBox,\n VBoxCallable as VBox\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./DOM-Cjh7_7TF.js";import{l as t}from"./Position-BIEU1Eze.js";import{S as n,_ as r,g as i}from"./Component-D99-15Zt.js";import{a,o,s,t as c}from"./Scrollbar-DcnueNJd.js";var VirtualScroller=class{_owner;_onScroll;_clipBox;_rowsContainer;_scrollbarV;_scrollbarH;_scrollX=0;_scrollY=0;_contentWidth=0;_contentHeight=0;_smooth;_shadowOverlay;_shadowEdges={top:0,bottom:0,left:0,right:0};constructor(t,r,o){this._owner=t,this._onScroll=o;let s=e.sink.createElement(`div`);e.sink.apply(s,{style:{position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,overflow:`hidden`}}),e.sink.appendChild(r,s),this._clipBox=s;let l=e.sink.createElement(`div`);e.sink.apply(l,{style:{position:`absolute`,top:`0`,left:`0`,width:`100%`,transform:`translate3d(0, 0, 0)`,willChange:`transform`}}),e.sink.appendChild(s,l),this._rowsContainer=l;let u=e.sink.createElement(`div`);e.sink.apply(u,{style:{position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,pointerEvents:`none`,boxShadow:a()}}),e.sink.appendChild(s,u),this._shadowOverlay=u,this._smooth=new i({read:e=>e===`x`?this._scrollX:this._scrollY,write:(e,t)=>e===`x`?this.setScrollX(t):this.setScrollY(t),clamp:(e,t)=>this.clampAxis(e,t)}),this._scrollbarV=new c(`vertical`),e.sink.appendChild(r,this._scrollbarV.getElement(!0)),this._scrollbarV.on(`scroll`,e=>{this._smooth.reset(),this.setScrollY(e)}),this._scrollbarH=new c(`horizontal`),e.sink.appendChild(r,this._scrollbarH.getElement(!0)),this._scrollbarH.on(`scroll`,e=>{this._smooth.reset(),this.setScrollX(e)}),this._owner.setTouchAction(`none`),n.addSubtreeListener(this._owner,`wheel`,{passive:!1,handler:e=>this.onWheel(e)}),this.attachTouchHandlers()}dispose(){this._scrollbarV.dispose(),this._scrollbarH.dispose()}ownedHandles(){return[this._clipBox,this._rowsContainer,this._shadowOverlay]}getRowsContainer(){return this._rowsContainer}getScrollY(){return this._scrollY}getScrollX(){return this._scrollX}setScrollY(e){let n=Math.max(0,this._contentHeight-this.effectiveViewportH()),r=t.clamp(e,0,n);return r===this._scrollY?this:(this._scrollY=r,this.updateTransform(),this._onScroll(),this)}setScrollX(e){let n=Math.max(0,this._contentWidth-this.effectiveViewportW()),r=t.clamp(e,0,n);return r===this._scrollX?this:(this._scrollX=r,this.updateTransform(),this._onScroll(),this)}clampAxis(e,n){let r=e===`x`?Math.max(0,this._contentWidth-this.effectiveViewportW()):Math.max(0,this._contentHeight-this.effectiveViewportH());return t.clamp(n,0,r)}resetWheelEase(){this._smooth.reset()}computeScrollbarVisibility(e,t){let n=this._owner.getContentBounds()??{x:0,y:0,width:this._owner.getWidth()||0,height:this._owner.getHeight()||0},r=n.height||0,i=n.width||0,a=this._scrollbarV.getTrackWidth(),o=!1,s=!1;for(let n=0;n<2;n++){let n=r-(s?a:0),c=i-(o?a:0);o=t>n,s=e>c}let c=r-(s?a:0),l=i-(o?a:0);return{vVisible:o,hVisible:s,effW:l,effH:c}}effectiveViewportH(){return this.computeScrollbarVisibility(this._contentWidth,this._contentHeight).effH}effectiveViewportW(){return this.computeScrollbarVisibility(this._contentWidth,this._contentHeight).effW}getViewportWidth(){return this.effectiveViewportW()}clampToContent(e,t){this._contentWidth=e,this._contentHeight=t;let n=Math.max(0,t-this.effectiveViewportH()),r=Math.max(0,e-this.effectiveViewportW()),i=!1;this._scrollY>n&&(this._scrollY=n,i=!0),this._scrollX>r&&(this._scrollX=r,i=!0),i&&this.updateTransform()}layoutScrollbars(t,n){this._contentWidth=t,this._contentHeight=n;let r=this._owner.getContentBounds()??{x:0,y:0,width:this._owner.getWidth()||0,height:this._owner.getHeight()||0},i=this._scrollbarV.getTrackWidth(),{effW:a,effH:o}=this.computeScrollbarVisibility(t,n),s=Math.max(0,n-o),c=Math.max(0,t-a);(this._scrollY>s||this._scrollX>c)&&(this._scrollY>s&&(this._scrollY=s),this._scrollX>c&&(this._scrollX=c),this.updateTransform()),this._scrollbarV.setX(r.x+Math.max(0,r.width-i)),this._scrollbarV.setY(r.y),this._scrollbarV.setHeight(o),this._scrollbarV.setMetrics(o,n,this._scrollY),this._scrollbarH.setX(r.x),this._scrollbarH.setY(r.y+Math.max(0,r.height-i)),this._scrollbarH.setWidth(a),this._scrollbarH.setMetrics(a,t,this._scrollX),e.sink.apply(this._clipBox,{style:{left:r.x+`px`,top:r.y+`px`,width:a+`px`,height:o+`px`}}),this.updateShadows()}updateTransform(){e.sink.apply(this._rowsContainer,{style:{transform:`translate3d(${-this._scrollX}px, ${-this._scrollY}px, 0)`}}),this.updateShadows()}updateShadows(){let{effW:e,effH:t}=this.computeScrollbarVisibility(this._contentWidth,this._contentHeight),n=Math.max(0,this._contentWidth-e),r=Math.max(0,this._contentHeight-t);this.setShadowEdge(`top`,`--ts-ss-top`,s(this._scrollY)),this.setShadowEdge(`bottom`,`--ts-ss-bottom`,s(r-this._scrollY)),this.setShadowEdge(`left`,`--ts-ss-left`,s(this._scrollX)),this.setShadowEdge(`right`,`--ts-ss-right`,s(n-this._scrollX))}setShadowEdge(t,n,r){let i=Math.round(r*100);this._shadowEdges[t]!==i&&(this._shadowEdges[t]=i,e.sink.apply(this._shadowOverlay,{style:{[n]:o(i)}}))}onWheel(e){if(r(e))return e.shiftKey&&e.deltaY!==0&&e.deltaX===0?(this._smooth.scrollBy(e.deltaY,0),{prevent:!0}):(this._smooth.scrollBy(e.deltaX,e.deltaY),{prevent:!0})}attachTouchHandlers(){let t=!1,r=0,i=0,a=0,o=0,s=[],c=null,cancelMomentum=()=>{c!==null&&(e.sink.cancelAnimationFrame(c),c=null)};n.addSubtreeListener(this._owner,`touchstart`,e=>{e.touches.length===1&&(cancelMomentum(),this._smooth.reset(),t=!0,r=e.touches[0].clientY,i=e.touches[0].clientX,a=this._scrollY,o=this._scrollX,s=[{time:performance.now(),x:i,y:r}])}),n.addSubtreeListener(this._owner,`touchmove`,e=>{if(!t||e.touches.length!==1)return;let n=e.touches[0].clientY,c=e.touches[0].clientX,l=performance.now();for(s.push({time:l,x:c,y:n});s.length>1&&s[0].time<l-150;)s.shift();this.setScrollY(a+(r-n)),this.setScrollX(o+(i-c))});let startMomentum=()=>{if(s.length<2)return;let t=s[s.length-1];if(performance.now()-t.time>50)return;let n=t.time-80,r=s.length-1;for(;r>0&&s[r-1].time>=n;)r--;let i=s[r],a=t.time-i.time;if(a<=0)return;let o=(i.y-t.y)/a,l=(i.x-t.x)/a;if(Math.sqrt(l*l+o*o)<.1)return;let u=performance.now(),step=()=>{let t=performance.now(),n=t-u;u=t;let r=.95**(n/16.667);if(o*=r,l*=r,Math.sqrt(l*l+o*o)<.02){c=null;return}let i=this._scrollY,a=this._scrollX;if(this.setScrollY(this._scrollY+o*n),this.setScrollX(this._scrollX+l*n),this._scrollY===i&&(o=0),this._scrollX===a&&(l=0),o===0&&l===0){c=null;return}c=e.sink.requestAnimationFrame(step)};c=e.sink.requestAnimationFrame(step)};n.addSubtreeListener(this._owner,`touchend`,()=>{t&&(t=!1,startMomentum())}),n.addSubtreeListener(this._owner,`touchcancel`,()=>{t=!1,cancelMomentum()})}};export{VirtualScroller as t};
2
+ //# sourceMappingURL=VirtualScroller-ggPTCQb0.js.map