@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
@@ -1 +0,0 @@
1
- {"version":3,"file":"Tree-C7qLbIYH.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\";\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/** 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 /**\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 };\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};\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 _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}; every other option is\n * inherited from {@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 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 * 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._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 * 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.\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 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: 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 expandNode(node: TreeNode): this {\n if (!this._expandedNodes.has(node)) {\n this._onToggle(node);\n }\n\n return this;\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 * Collapse and already-resolved expansion commit synchronously. A lazy node\n * declared with `loadChildren` that has not loaded yet defers its expansion\n * to {@link _loadAndExpand}, which only commits once the loader resolves.\n */\n private _onToggle(node: TreeNode): void {\n if (this._expandedNodes.has(node)) {\n this._expandedNodes.delete(node);\n this._reflattenAndRender();\n\n return;\n }\n\n const needsLoad = node.loadChildren !== undefined\n && !this._loadedNodes.has(node)\n && !(node.children && node.children.length);\n\n if (!needsLoad) {\n this._expandedNodes.add(node);\n this._reflattenAndRender();\n\n return;\n }\n\n if (this._loadingNodes.has(node)) {\n return;\n }\n\n void this._loadAndExpand(node);\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 private async _loadAndExpand(node: TreeNode): Promise<void> {\n this._loadingNodes.add(node);\n this._reflattenAndRender();\n\n try {\n const children = await node.loadChildren!();\n\n if (!this._loadingNodes.has(node)) {\n return;\n }\n\n node.children = children;\n this._loadedNodes.add(node);\n this._expandedNodes.add(node);\n } catch (error) {\n if (!this._loadingNodes.has(node)) {\n return;\n }\n\n this.emit(\"loaderror\", node, error);\n } finally {\n this._loadingNodes.delete(node);\n this._reflattenAndRender();\n }\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): void {\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 e.preventDefault();\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 return;\n }\n\n const { node } = flatRows[focusIdx];\n const hasChildren = this._isExpandable(node);\n\n if (!hasChildren) {\n return;\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;\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\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 * @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\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): 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 rowEl = row.getElement();\n if (!rowEl || (!DOM.source.contains(rowEl, target) && target !== rowEl)) {\n continue;\n }\n\n e.preventDefault();\n this.emit(\"contextmenu\", node, e);\n\n return;\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.\n *\n * @param e - The dblclick event whose target is inside the tree's subtree.\n */\n private _handleDblClick(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 rowEl = row.getElement();\n if (!rowEl || (!DOM.source.contains(rowEl, target) && target !== rowEl)) {\n continue;\n }\n\n e.preventDefault();\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. Leaf nodes have nothing to expand, so\n // their `\"dblclick\"` stays a pure activation 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)) {\n this._onToggle(node);\n }\n\n return;\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\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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"}
@@ -1,2 +0,0 @@
1
- import{a as e,o as t}from"./Position-PBVBW1JS.js";import{f as n,h as r,m as i,p as a}from"./Component-w65rPK75.js";var BoxLayout=class extends n{_spacing=5;_stretching=!1;_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.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._stretching||!1}setStretching(e){return this._stretching=!!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}}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.isStretching())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{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{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);r?d.push({component:t,...this.resolveBounds(t,r.offset,c,r.extent,o,i.BOTH)}):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);d?_.push({component:a,...this.resolveBounds(a,d.offset,g,d.extent,u[n],i.BOTH)}):_.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-32fxpkDl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"VBox-32fxpkDl.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 * 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 stretching?: boolean;\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 _stretching: boolean = false;\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.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 isStretching(): boolean {\n return this._stretching || false;\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 setStretching(stretching: boolean): this {\n this._stretching = !!stretching;\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 * 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 * each box's default cross placement (HBox baseline, VBox WEST origin) is\n * more specific than geometric centring.\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` while stretching\n * (baseline alignment is disabled) or when no child reports a baseline.\n */\n getContentBaseline(): number | null {\n if (this.isStretching()) {\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 {\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 {\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 {\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 {\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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"}
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-Ba8YRVel.js";import{l as t}from"./Position-PBVBW1JS.js";import{S as n,_ as r,g as i}from"./Component-w65rPK75.js";import{i as a,n as o,r as s,t as c}from"./Scrollbar-C3ZZyZ1e.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,a){this._owner=t,this._onScroll=a;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:o()}}),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`,e=>this.onWheel(e),{passive:!1}),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`,a(this._scrollY)),this.setShadowEdge(`bottom`,`--ts-ss-bottom`,a(r-this._scrollY)),this.setShadowEdge(`left`,`--ts-ss-left`,a(this._scrollX)),this.setShadowEdge(`right`,`--ts-ss-right`,a(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]:s(i)}}))}onWheel(e){if(r(e)){if(e.preventDefault(),e.shiftKey&&e.deltaY!==0&&e.deltaX===0){this._smooth.scrollBy(e.deltaY,0);return}this._smooth.scrollBy(e.deltaX,e.deltaY)}}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-cvFNMS7U.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"VirtualScroller-cvFNMS7U.js","names":[],"sources":["../../src/typescript/lib/component/container/VirtualScroller.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { SmoothScroller, consumeWheel } from \"~/core/SmoothScroller.js\";\nimport { Scrollbar } from \"~/component/container/Scrollbar.js\";\nimport { scrollShadowBoxShadow, scrollShadowEdgeValue, scrollShadowRamp } from \"~/core/ScrollShadow.js\";\n\n/** Per-edge scroll-shadow strength cache, quantised to a whole percent (0–100). */\ntype ScrollShadowEdges = { top: number; bottom: number; left: number; right: number };\n\n// VirtualScroller is a plain helper, not a Component: it owns and lays out raw\n// `clipBox` / `rowsContainer` `HTMLElement`s it creates directly, so the\n// Component style setters don't apply and direct `.style` writes are correct.\n\n/**\n * Callback fired by {@link VirtualScroller} whenever the scroll position\n * changes via user input (wheel, touch, momentum, scrollbar). The owner\n * should re-render its visible window in response.\n *\n * @category Components\n */\nexport type VirtualScrollerOnScroll = () => void;\n\n/**\n * Shared scroll machinery for transform-based virtual lists (e.g. table body,\n * tree). Owns the rows-container element, two custom {@link Scrollbar} overlays\n * (vertical + horizontal), and the wheel/touch handlers with 2-axis fling\n * momentum.\n *\n * The owner component:\n * 1. Constructs a VirtualScroller from its `init()` with the owner element and\n * a callback that re-renders the visible window.\n * 2. Appends pool rows into {@link getRowsContainer}.\n * 3. Reads {@link getScrollX} / {@link getScrollY} to determine the visible window.\n * 4. Calls {@link clampToContent} at the start of `renderWindow` (so scroll\n * positions are sane before being used).\n * 5. Calls {@link layoutScrollbars} at the end of `renderWindow` with the\n * current content sizes; the scroller applies the final clamp and positions\n * the scrollbars.\n *\n * @category Components\n */\nexport class VirtualScroller {\n\n private _owner : Component;\n private _onScroll : VirtualScrollerOnScroll;\n private _clipBox : Handle;\n private _rowsContainer : Handle;\n private _scrollbarV : Scrollbar;\n private _scrollbarH : Scrollbar;\n private _scrollX : number = 0;\n private _scrollY : number = 0;\n private _contentWidth : number = 0;\n private _contentHeight : number = 0;\n private _smooth : SmoothScroller;\n private _shadowOverlay : Handle;\n private _shadowEdges : ScrollShadowEdges = { top: 0, bottom: 0, left: 0, right: 0 };\n\n /**\n * Constructs a VirtualScroller and attaches it to the owner element.\n *\n * @param owner - The component being scrolled (used for `getContentBounds`).\n * @param element - The owner's root DOM element. Must already exist; call\n * this from the owner's `init()` after `super.init(element)`.\n * @param onScroll - Callback invoked when scroll position changes via\n * user input.\n */\n constructor(owner: Component, element: Handle, onScroll: VirtualScrollerOnScroll) {\n this._owner = owner;\n this._onScroll = onScroll;\n\n // Two-element wrapper: the outer `clipBox` carries `overflow:hidden`\n // sized to the effective viewport so the Scrollbar widgets — positioned\n // by `layoutScrollbars` at the far edge of the owner's content box —\n // sit in their own reserved band rather than overlaying the rightmost\n // column / bottom row. The inner `rowsContainer` carries the scroll\n // transform; the transform cannot sit on the same element as\n // `overflow:hidden` because CSS clipping happens in the element's own\n // LOCAL coordinate system before its transform applies — splitting\n // the two roles lets the transform shift the rows around inside a\n // stable clip.\n const clipBox = DOM.sink.createElement(\"div\");\n DOM.sink.apply(clipBox, { style: { position: \"absolute\", top: \"0\", left: \"0\", width: \"100%\", height: \"100%\", overflow: \"hidden\" } });\n DOM.sink.appendChild(element, clipBox);\n this._clipBox = clipBox;\n\n const container = DOM.sink.createElement(\"div\");\n DOM.sink.apply(container, { style: { position: \"absolute\", top: \"0\", left: \"0\", width: \"100%\", transform: \"translate3d(0, 0, 0)\", willChange: \"transform\" } });\n DOM.sink.appendChild(clipBox, container);\n this._rowsContainer = container;\n\n // Position-aware edge shadows, matching the native-scroll `Panel` cue.\n // The overlay is a sibling of `rowsContainer` inside the `clipBox`, so it\n // is clipped to the effective viewport and — being outside the scrolled\n // `rowsContainer` — is not shifted by the scroll transform; sizing it to\n // 100% tracks the clip box that `layoutScrollbars` resizes to the\n // effective viewport. It paints above the rows (appended last) and is\n // inert to the pointer. Each edge is a `box-shadow` layer gated by a\n // custom property; `updateShadows` flips the property per scroll/resize.\n const shadowOverlay = DOM.sink.createElement(\"div\");\n DOM.sink.apply(shadowOverlay, { style: {\n position: \"absolute\",\n top: \"0\",\n left: \"0\",\n width: \"100%\",\n height: \"100%\",\n pointerEvents: \"none\",\n boxShadow: scrollShadowBoxShadow(),\n } });\n DOM.sink.appendChild(clipBox, shadowOverlay);\n this._shadowOverlay = shadowOverlay;\n\n // Drives wheel-initiated scrolling through an eased RAF loop. The seam\n // delegates to the existing setScrollX/Y (which clamp, write the\n // transform, and fire onScroll, so the virtual window re-renders every\n // frame) and clamps targets against the same effective-viewport bounds.\n this._smooth = new SmoothScroller({\n read: (axis) => axis === \"x\" ? this._scrollX : this._scrollY,\n write: (axis, value) => axis === \"x\" ? this.setScrollX(value) : this.setScrollY(value),\n clamp: (axis, value) => this.clampAxis(axis, value),\n });\n\n this._scrollbarV = new Scrollbar(\"vertical\");\n DOM.sink.appendChild(element, this._scrollbarV.getElement(true)!);\n this._scrollbarV.on(\"scroll\", (p: number) => {\n this._smooth.reset();\n this.setScrollY(p);\n });\n\n this._scrollbarH = new Scrollbar(\"horizontal\");\n DOM.sink.appendChild(element, this._scrollbarH.getElement(true)!);\n this._scrollbarH.on(\"scroll\", (p: number) => {\n this._smooth.reset();\n this.setScrollX(p);\n });\n\n this._owner.setTouchAction(\"none\");\n\n // Subtree because wheel events fire on whichever descendant of the\n // owner the pointer is over (a row, a cell, …) — not the owner root.\n // passive: false so onWheel can preventDefault the native page scroll.\n Event.addSubtreeListener(\n this._owner,\n \"wheel\",\n (e: WheelEvent) => this.onWheel(e),\n { passive: false }\n );\n\n this.attachTouchHandlers();\n }\n\n /**\n * Disposes the two `Scrollbar` overlays this scroller owns. They are\n * appended straight onto the owner's element rather than registered as its\n * children, so the owner's `destructor()` recursion cannot reach them and\n * their per-instance stylesheet rules would otherwise survive teardown.\n * Called from `VirtualRowView.destructor()`.\n */\n dispose(): void {\n this._scrollbarV.dispose();\n this._scrollbarH.dispose();\n }\n\n /**\n * Returns the two created container handles (clip box and rows container).\n * The owning component tracks these via `trackHandle` so they are released\n * with the owner — on its destructor or, for a discarded owner, on GC — and\n * not left pinned in the registry. The scroller is not a `Component`, so it\n * cannot track its own handles.\n *\n * @returns The scroller's owned element handles.\n */\n ownedHandles(): readonly Handle[] {\n return [this._clipBox, this._rowsContainer, this._shadowOverlay];\n }\n\n /**\n * Returns the rows-container element. Owners append pool rows here so\n * they participate in the transform-based scroll.\n *\n * @returns The rows-container DOM element.\n */\n getRowsContainer(): Handle {\n return this._rowsContainer;\n }\n\n /**\n * Returns the current vertical scroll position in pixels.\n *\n * @returns The current `scrollY`.\n */\n getScrollY(): number {\n return this._scrollY;\n }\n\n /**\n * Returns the current horizontal scroll position in pixels.\n *\n * @returns The current `scrollX`.\n */\n getScrollX(): number {\n return this._scrollX;\n }\n\n /**\n * Sets the vertical scroll position. Clamped against the last-known\n * content height and the *effective* viewport height (the owner's\n * content-box height minus the horizontal scrollbar's reservation when\n * that bar is visible),\n * so the maximum reachable scroll position matches what the vertical\n * scrollbar's thumb tops out at. Triggers the owner's `onScroll` callback\n * if the position changed.\n *\n * @param y - The new scroll position in pixels.\n */\n setScrollY(y: number): this {\n const maxScroll = Math.max(0, this._contentHeight - this.effectiveViewportH());\n const next = Util.clamp(y, 0, maxScroll);\n\n if (next === this._scrollY) {\n return this;\n }\n\n this._scrollY = next;\n this.updateTransform();\n this._onScroll();\n\n return this;\n }\n\n /**\n * Sets the horizontal scroll position. Clamped against the last-known\n * content width and the *effective* viewport width (the owner's\n * content-box width minus the vertical scrollbar's reservation when that\n * bar is visible),\n * so the maximum reachable scroll position matches what the horizontal\n * scrollbar's thumb tops out at. Triggers the owner's `onScroll` callback\n * if the position changed.\n *\n * @param x - The new scroll position in pixels.\n */\n setScrollX(x: number): this {\n const maxScroll = Math.max(0, this._contentWidth - this.effectiveViewportW());\n const next = Util.clamp(x, 0, maxScroll);\n\n if (next === this._scrollX) {\n return this;\n }\n\n this._scrollX = next;\n this.updateTransform();\n this._onScroll();\n\n return this;\n }\n\n /**\n * Clamps a requested position for one axis to its `[0, max]` range, using\n * the same effective-viewport bounds as `setScrollX/Y` so the eased wheel\n * target converges exactly where the scrollbar thumb tops out.\n *\n * @param axis - The axis to clamp (`\"x\"` or `\"y\"`).\n * @param value - The requested position in pixels.\n *\n * @returns The clamped position in pixels.\n */\n private clampAxis(axis: \"x\" | \"y\", value: number): number {\n const max = axis === \"x\"\n ? Math.max(0, this._contentWidth - this.effectiveViewportW())\n : Math.max(0, this._contentHeight - this.effectiveViewportH());\n\n return Util.clamp(value, 0, max);\n }\n\n /**\n * Aborts any in-flight eased wheel animation and re-seeds it from the live\n * position. Call before a programmatic scroll jump (e.g. `scrollToRecord`)\n * so a lingering ease can't snap the position back afterward.\n */\n resetWheelEase(): void {\n this._smooth.reset();\n }\n\n /**\n * Decides whether each scrollbar should be visible given the current\n * content size, accounting for the mutual dependency between the two\n * axes — if one bar is visible, its track-width reservation shrinks\n * the cross-axis viewport, which can in turn force the other bar to\n * become visible. Two iterations are sufficient: each pass can only\n * promote one flag from false to true.\n *\n * The effective viewport is measured in the owner's content box, not its\n * outer box, so a bordered or padded owner reports the space actually\n * visible to rows.\n */\n private computeScrollbarVisibility(contentWidth: number, contentHeight: number): { vVisible: boolean, hVisible: boolean, effW: number, effH: number } {\n const box = this._owner.getContentBounds()\n ?? { x: 0, y: 0, width: this._owner.getWidth() || 0, height: this._owner.getHeight() || 0 };\n\n // `box.{width,height}` derive from the owner's committed `_width`/\n // `_height`, which are declared `NaN` and stay so until the owner is\n // first sized. The `?? …` fallback above covers the no-element case,\n // not that one — an element-bearing but unsized owner still yields a\n // non-null box whose extents are NaN — so `|| 0` stays, the same\n // coercion the outer-box reads it replaced already used.\n const outerH = box.height || 0;\n const outerW = box.width || 0;\n const trackW = this._scrollbarV.getTrackWidth();\n\n let vVisible = false;\n let hVisible = false;\n for (let i = 0; i < 2; i++) {\n const effH: number = outerH - (hVisible ? trackW : 0);\n const effW: number = outerW - (vVisible ? trackW : 0);\n\n vVisible = contentHeight > effH;\n hVisible = contentWidth > effW;\n }\n\n const effH = outerH - (hVisible ? trackW : 0);\n const effW = outerW - (vVisible ? trackW : 0);\n\n return { vVisible, hVisible, effW, effH };\n }\n\n /**\n * Effective vertical viewport — the owner's content-box height minus the\n * horizontal scrollbar's track-width reservation when that bar would be\n * visible.\n * Single source of truth so the clamps in `setScrollY` agree with what\n * the vertical scrollbar's `setMetrics` is fed.\n */\n private effectiveViewportH(): number {\n return this.computeScrollbarVisibility(this._contentWidth, this._contentHeight).effH;\n }\n\n /**\n * Effective horizontal viewport — see {@link effectiveViewportH}.\n */\n private effectiveViewportW(): number {\n return this.computeScrollbarVisibility(this._contentWidth, this._contentHeight).effW;\n }\n\n /**\n * Effective viewport width for the last-known content metrics — the owner's\n * content-box width minus the vertical scrollbar's track reservation when\n * that bar is visible. Owners that size fill-width rows (e.g. the\n * [`Tree`](/api/component/tree/classes/Tree)) base their row width on this so\n * content does not run under the vertical bar, which would otherwise force a\n * spurious horizontal bar for the reserved band. Reads the current\n * `_contentWidth` / `_contentHeight`; callers refresh those via\n * {@link clampToContent} at the top of their render pass before querying.\n * The public face of `effectiveViewportW` (same value; that stays the\n * internal clamp helper).\n *\n * @returns The effective viewport width in pixels.\n */\n getViewportWidth(): number {\n return this.effectiveViewportW();\n }\n\n /**\n * Clamps the current `scrollX` / `scrollY` against the new content size\n * and the *effective* viewport on each axis (which subtracts the\n * cross-axis scrollbar's track-width when that bar is visible). Call at\n * the start of `renderWindow` so scrollX/Y are within range before being\n * used for window calculations — important when content has shrunk since\n * the last frame. Uses the same effective-viewport reasoning as\n * `setScrollX/Y` so the clamps agree and scrollX/Y aren't pulled back to\n * a smaller bound than the scrollbar's own `setMetrics` expects (which\n * would leave the thumb stopping short of the end-arrow). Does not fire\n * `onScroll`.\n *\n * @param contentWidth - The total scrollable content width in pixels.\n * @param contentHeight - The total scrollable content height in pixels.\n */\n clampToContent(contentWidth: number, contentHeight: number): void {\n this._contentWidth = contentWidth;\n this._contentHeight = contentHeight;\n\n const maxY = Math.max(0, contentHeight - this.effectiveViewportH());\n const maxX = Math.max(0, contentWidth - this.effectiveViewportW());\n\n let changed = false;\n if (this._scrollY > maxY) {\n this._scrollY = maxY;\n changed = true;\n }\n if (this._scrollX > maxX) {\n this._scrollX = maxX;\n changed = true;\n }\n if (changed) {\n this.updateTransform();\n }\n }\n\n /**\n * Tight clamp using effective viewports (each axis subtracts the\n * cross-axis scrollbar's track width when it is visible), then positions\n * the scrollbars and pushes metrics. Call at end of `renderWindow`.\n *\n * Both bars and the clip box are placed in the owner's content box: a\n * child's containing block is already the owner's padding box, so\n * placing them against the outer box would run the far edge past where\n * `overflow: hidden` clips, by both border sides.\n *\n * @param contentWidth - The total scrollable content width in pixels.\n * @param contentHeight - The total scrollable content height in pixels.\n */\n layoutScrollbars(contentWidth: number, contentHeight: number): void {\n this._contentWidth = contentWidth;\n this._contentHeight = contentHeight;\n\n const box = this._owner.getContentBounds()\n ?? { x: 0, y: 0, width: this._owner.getWidth() || 0, height: this._owner.getHeight() || 0 };\n\n const trackW = this._scrollbarV.getTrackWidth();\n\n const { effW, effH } = this.computeScrollbarVisibility(contentWidth, contentHeight);\n\n const maxY = Math.max(0, contentHeight - effH);\n const maxX = Math.max(0, contentWidth - effW);\n if (this._scrollY > maxY || this._scrollX > maxX) {\n if (this._scrollY > maxY) this._scrollY = maxY;\n if (this._scrollX > maxX) this._scrollX = maxX;\n this.updateTransform();\n }\n\n this._scrollbarV.setX(box.x + Math.max(0, box.width - trackW));\n this._scrollbarV.setY(box.y);\n this._scrollbarV.setHeight(effH);\n this._scrollbarV.setMetrics(effH, contentHeight, this._scrollY);\n\n this._scrollbarH.setX(box.x);\n this._scrollbarH.setY(box.y + Math.max(0, box.height - trackW));\n this._scrollbarH.setWidth(effW);\n this._scrollbarH.setMetrics(effW, contentWidth, this._scrollX);\n\n // Resize the clip box to the effective viewport so cells translated\n // by the horizontal scroll can't bleed under the vertical scrollbar\n // (and rows beyond the bottom can't bleed under the horizontal\n // scrollbar). When neither bar is visible this collapses to the\n // full owner content box, matching the previous `width/height: 100%`\n // behaviour for a borderless, unpadded owner.\n DOM.sink.apply(this._clipBox, { style: { left: box.x + \"px\", top: box.y + \"px\", width: effW + \"px\", height: effH + \"px\" } });\n\n // Content size / viewport may have changed without the scroll position\n // moving (so `updateTransform` did not run above) — refresh the shadow\n // edges against the new extremes.\n this.updateShadows();\n }\n\n /**\n * Writes the current `scrollX` / `scrollY` into the rows-container\n * transform.\n */\n private updateTransform(): void {\n DOM.sink.apply(this._rowsContainer, { style: { transform: `translate3d(${-this._scrollX}px, ${-this._scrollY}px, 0)` } });\n this.updateShadows();\n }\n\n /**\n * Recomputes each scroll-shadow edge's strength from the current scroll\n * position, content size, and effective viewport, then lights only the\n * edges that have hidden content past them. Cheap on a no-op scroll: an\n * edge whose quantised strength is unchanged skips the DOM write (see\n * {@link setShadowEdge}). Called on every scroll ({@link updateTransform})\n * and whenever the content/viewport metrics change ({@link layoutScrollbars}).\n */\n private updateShadows(): void {\n const { effW, effH } = this.computeScrollbarVisibility(this._contentWidth, this._contentHeight);\n\n const maxX = Math.max(0, this._contentWidth - effW);\n const maxY = Math.max(0, this._contentHeight - effH);\n\n this.setShadowEdge(\"top\", \"--ts-ss-top\", scrollShadowRamp(this._scrollY));\n this.setShadowEdge(\"bottom\", \"--ts-ss-bottom\", scrollShadowRamp(maxY - this._scrollY));\n this.setShadowEdge(\"left\", \"--ts-ss-left\", scrollShadowRamp(this._scrollX));\n this.setShadowEdge(\"right\", \"--ts-ss-right\", scrollShadowRamp(maxX - this._scrollX));\n }\n\n /**\n * Sets a single edge's shadow strength by scaling the theme shadow colour\n * toward transparent. Strength is quantised to a whole percent so an\n * in-ramp scroll only repaints when the visible strength actually changes;\n * at zero the property is unset so the `box-shadow` layer falls back to\n * `transparent`.\n *\n * @param edge - The edge whose cached strength this updates.\n * @param property - The overlay custom property backing that edge's shadow.\n * @param strength - The target strength in the range 0–1.\n */\n private setShadowEdge(edge: keyof ScrollShadowEdges, property: string, strength: number): void {\n const percent = Math.round(strength * 100); // quantise: 0–1 → 0–100%\n\n if (this._shadowEdges[edge] === percent) {\n return;\n }\n\n this._shadowEdges[edge] = percent;\n DOM.sink.apply(this._shadowOverlay, { style: { [property]: scrollShadowEdgeValue(percent) } });\n }\n\n /**\n * Eases wheel input into the scroll position through the {@link SmoothScroller}.\n * Shift+wheel without an explicit deltaX is treated as horizontal scroll.\n * Claims the event so an ancestor scroll container doesn't also scroll it.\n *\n * @param e - The wheel event.\n */\n private onWheel(e: WheelEvent): void {\n if (!consumeWheel(e)) {\n return;\n }\n\n e.preventDefault();\n\n if (e.shiftKey && e.deltaY !== 0 && e.deltaX === 0) {\n this._smooth.scrollBy(e.deltaY, 0);\n\n return;\n }\n\n this._smooth.scrollBy(e.deltaX, e.deltaY);\n }\n\n /**\n * Installs the touch handlers: 1:1 finger drag scrolls both axes, and on\n * release a 2D fling momentum decays per frame until it falls below\n * threshold or hits a scroll boundary.\n */\n private attachTouchHandlers(): void {\n let touchActive = false;\n let touchStartY = 0;\n let touchStartX = 0;\n let touchStartScrollY = 0;\n let touchStartScrollX = 0;\n let touchSamples : Array<{ time: number, x: number, y: number }> = [];\n let momentumRaf : number | null = null;\n\n const cancelMomentum = (): void => {\n if (momentumRaf !== null) {\n DOM.sink.cancelAnimationFrame(momentumRaf);\n momentumRaf = null;\n }\n };\n\n // Subtree because touch events fire on descendants of the owner\n // (rows / cells) — not the owner root.\n Event.addSubtreeListener(this._owner, \"touchstart\", (e: TouchEvent) => {\n if (e.touches.length !== 1) {\n return;\n }\n cancelMomentum();\n this._smooth.reset();\n touchActive = true;\n touchStartY = e.touches[0].clientY;\n touchStartX = e.touches[0].clientX;\n touchStartScrollY = this._scrollY;\n touchStartScrollX = this._scrollX;\n touchSamples = [{ time: performance.now(), x: touchStartX, y: touchStartY }];\n });\n\n Event.addSubtreeListener(this._owner, \"touchmove\", (e: TouchEvent) => {\n if (!touchActive || e.touches.length !== 1) {\n return;\n }\n const y = e.touches[0].clientY;\n const x = e.touches[0].clientX;\n const now = performance.now();\n\n touchSamples.push({ time: now, x: x, y: y });\n while (touchSamples.length > 1 && touchSamples[0].time < now - 150) {\n touchSamples.shift();\n }\n\n this.setScrollY(touchStartScrollY + (touchStartY - y));\n this.setScrollX(touchStartScrollX + (touchStartX - x));\n });\n\n const startMomentum = (): void => {\n if (touchSamples.length < 2) {\n return;\n }\n\n const last = touchSamples[touchSamples.length - 1];\n\n const PAUSE_THRESHOLD = 50;\n if (performance.now() - last.time > PAUSE_THRESHOLD) {\n return;\n }\n\n const VELOCITY_WINDOW = 80;\n const cutoff = last.time - VELOCITY_WINDOW;\n let firstIdx = touchSamples.length - 1;\n while (firstIdx > 0 && touchSamples[firstIdx - 1].time >= cutoff) {\n firstIdx--;\n }\n const first = touchSamples[firstIdx];\n const dt = last.time - first.time;\n if (dt <= 0) {\n return;\n }\n\n let velocityY = (first.y - last.y) / dt;\n let velocityX = (first.x - last.x) / dt;\n\n const MIN_VELOCITY = 0.1;\n const FRICTION = 0.95;\n const STOP_VELOCITY = 0.02;\n\n const initialSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);\n if (initialSpeed < MIN_VELOCITY) {\n return;\n }\n\n let lastT = performance.now();\n const step = (): void => {\n const now = performance.now();\n const frame = now - lastT;\n lastT = now;\n\n const decay = Math.pow(FRICTION, frame / 16.667);\n velocityY *= decay;\n velocityX *= decay;\n\n const speed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);\n if (speed < STOP_VELOCITY) {\n momentumRaf = null;\n return;\n }\n\n const beforeY = this._scrollY;\n const beforeX = this._scrollX;\n this.setScrollY(this._scrollY + velocityY * frame);\n this.setScrollX(this._scrollX + velocityX * frame);\n if (this._scrollY === beforeY) {\n velocityY = 0;\n }\n if (this._scrollX === beforeX) {\n velocityX = 0;\n }\n if (velocityY === 0 && velocityX === 0) {\n momentumRaf = null;\n return;\n }\n\n momentumRaf = DOM.sink.requestAnimationFrame(step);\n };\n\n momentumRaf = DOM.sink.requestAnimationFrame(step);\n };\n\n Event.addSubtreeListener(this._owner, \"touchend\", () => {\n if (!touchActive) {\n return;\n }\n touchActive = false;\n startMomentum();\n });\n\n Event.addSubtreeListener(this._owner, \"touchcancel\", () => {\n touchActive = false;\n cancelMomentum();\n });\n }\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- (function(){function e(e,t){return e&&typeof e.get==`function`?e.get(t):e?e[t]:void 0}function t(n,r){switch(r.type){case`eq`:return e(n,r.field)===r.value;case`neq`:return e(n,r.field)!==r.value;case`contains`:{let t=e(n,r.field);if(t==null)return!1;let i=r.caseSensitive?String(t):String(t).toLowerCase(),a=r.caseSensitive?r.value:r.value.toLowerCase();return i.indexOf(a)!==-1}case`startsWith`:{let t=e(n,r.field);if(t==null)return!1;let i=r.caseSensitive?String(t):String(t).toLowerCase(),a=r.caseSensitive?r.value:r.value.toLowerCase();return i.indexOf(a)===0}case`gt`:return e(n,r.field)>r.value;case`gte`:return e(n,r.field)>=r.value;case`lt`:return e(n,r.field)<r.value;case`lte`:return e(n,r.field)<=r.value;case`in`:return r.values.indexOf(e(n,r.field))!==-1;case`and`:for(let e of r.filters)if(!t(n,e))return!1;return!0;case`or`:for(let e of r.filters)if(t(n,e))return!0;return!1;case`not`:return!t(n,r.filter)}}function n(e,t){return e<t?-1:+(e>t)}function r(e,t,r){return e==null&&t==null?0:e==null?1:t==null?-1:r===`string`||r===void 0&&typeof e==`string`&&typeof t==`string`?e.localeCompare(t):(r===`date`||r===`datetime`||r===`time`)&&e instanceof Date&&t instanceof Date?n(e.getTime(),t.getTime()):n(e,t)}let i=new Map;function a(e,t,n,i,a){t.sort((t,o)=>{let s=e[t]?e[t][n]:void 0,c=e[o]?e[o][n]:void 0,l=r(s,c,a);return s==null||c==null||i===`asc`?l:-l})}self.onmessage=e=>{let n=e.data;try{if(n.type===`snapshot`){i.set(n.storeId,n.records),self.postMessage({requestId:n.requestId});return}let e=i.get(n.storeId);if(!e){self.postMessage({requestId:n.requestId,error:`No snapshot for storeId `+n.storeId});return}let r=[];for(let t=0;t<e.length;t++)r.push(t);n.filter&&(r=r.filter(r=>t(e[r],n.filter))),n.sort&&a(e,r,n.sort.field,n.sort.direction,n.sort.fieldType),self.postMessage({requestId:n.requestId,indices:r})}catch(e){self.postMessage({requestId:n.requestId,error:String(e?.message??e)})}}})();
2
- //# sourceMappingURL=StoreWorker-CgOBYoai.js.map