@jimka/typescript-ui 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/dist/lib/{AbstractInput-B10DfLOf.js → AbstractInput-sRNPzWel.js} +2 -2
  2. package/dist/lib/{AbstractInput-B10DfLOf.js.map → AbstractInput-sRNPzWel.js.map} +1 -1
  3. package/dist/lib/Anchor-CwRhdP2J.js +2 -0
  4. package/dist/lib/Anchor-CwRhdP2J.js.map +1 -0
  5. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js +2 -0
  6. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js.map +1 -0
  7. package/dist/lib/Border-0DJFDiij.js +2 -0
  8. package/dist/lib/Border-0DJFDiij.js.map +1 -0
  9. package/dist/lib/Button-MpMIYBYJ.js +2 -0
  10. package/dist/lib/Button-MpMIYBYJ.js.map +1 -0
  11. package/dist/lib/{Card-CD3jxshU.js → Card-QYo27r5b.js} +2 -2
  12. package/dist/lib/{Card-CD3jxshU.js.map → Card-QYo27r5b.js.map} +1 -1
  13. package/dist/lib/Checkbox-D0JYK-wc.js +2 -0
  14. package/dist/lib/Checkbox-D0JYK-wc.js.map +1 -0
  15. package/dist/lib/CheckboxMenuRow-CesLhSnp.js +2 -0
  16. package/dist/lib/CheckboxMenuRow-CesLhSnp.js.map +1 -0
  17. package/dist/lib/{CodeEditor-BGlB232h.js → CodeEditor-N1FQodcF.js} +2 -2
  18. package/dist/lib/CodeEditor-N1FQodcF.js.map +1 -0
  19. package/dist/lib/ComboBox-Dx8Tk9yg.js +2 -0
  20. package/dist/lib/ComboBox-Dx8Tk9yg.js.map +1 -0
  21. package/dist/lib/Component-B0ShfPVi.js +2 -0
  22. package/dist/lib/Component-B0ShfPVi.js.map +1 -0
  23. package/dist/lib/Container-abY5Ww3W.js +2 -0
  24. package/dist/lib/{Container-C7RPLQEc.js.map → Container-abY5Ww3W.js.map} +1 -1
  25. package/dist/lib/{DOM-Ba8YRVel.js → DOM-C-Edb3tA.js} +2 -2
  26. package/dist/lib/DOM-C-Edb3tA.js.map +1 -0
  27. package/dist/lib/Dialog-cbA9V17e.js +2 -0
  28. package/dist/lib/Dialog-cbA9V17e.js.map +1 -0
  29. package/dist/lib/{FieldDecorator-HG65hEtk.js → FieldDecorator-BlYMfZ9L.js} +2 -2
  30. package/dist/lib/{FieldDecorator-HG65hEtk.js.map → FieldDecorator-BlYMfZ9L.js.map} +1 -1
  31. package/dist/lib/{Fit-Cg3dPyZg.js → Fit-BhlB-HAo.js} +2 -2
  32. package/dist/lib/{Fit-Cg3dPyZg.js.map → Fit-BhlB-HAo.js.map} +1 -1
  33. package/dist/lib/{FloatingPanel-D5buuVrQ.js → FloatingPanel-DkJXsZ2D.js} +2 -2
  34. package/dist/lib/{FloatingPanel-D5buuVrQ.js.map → FloatingPanel-DkJXsZ2D.js.map} +1 -1
  35. package/dist/lib/{Glyph-DeJF_zsR.js → Glyph-_VeBacS2.js} +2 -2
  36. package/dist/lib/{Glyph-DeJF_zsR.js.map → Glyph-_VeBacS2.js.map} +1 -1
  37. package/dist/lib/{Grid-BYBohJIA.js → Grid-Daiz7F5d.js} +2 -2
  38. package/dist/lib/Grid-Daiz7F5d.js.map +1 -0
  39. package/dist/lib/GridConstraints-C58LuTqM.js +2 -0
  40. package/dist/lib/{GridConstraints-Bts284FI.js.map → GridConstraints-C58LuTqM.js.map} +1 -1
  41. package/dist/lib/{Header-BIFJK9nR.js → Header-Dql3Zxc6.js} +2 -2
  42. package/dist/lib/{Header-BIFJK9nR.js.map → Header-Dql3Zxc6.js.map} +1 -1
  43. package/dist/lib/{IconText-Dsb1xS-E.js → IconText-PUjhTLlp.js} +2 -2
  44. package/dist/lib/{IconText-Dsb1xS-E.js.map → IconText-PUjhTLlp.js.map} +1 -1
  45. package/dist/lib/LayoutSerialization-CMxunLfV.js +2 -0
  46. package/dist/lib/LayoutSerialization-CMxunLfV.js.map +1 -0
  47. package/dist/lib/List-nx8220Fi.js +2 -0
  48. package/dist/lib/{List-BPd-IXZR.js.map → List-nx8220Fi.js.map} +1 -1
  49. package/dist/lib/MemoryStore-DhPoU-7X.js +2 -0
  50. package/dist/lib/MemoryStore-DhPoU-7X.js.map +1 -0
  51. package/dist/lib/Menu-Q0bpXXze.js +2 -0
  52. package/dist/lib/Menu-Q0bpXXze.js.map +1 -0
  53. package/dist/lib/{MenuButton-BR4KOFld.js → MenuButton-DCXi0tsP.js} +2 -2
  54. package/dist/lib/{MenuButton-BR4KOFld.js.map → MenuButton-DCXi0tsP.js.map} +1 -1
  55. package/dist/lib/OverlayFade-3pof2AJH.js +2 -0
  56. package/dist/lib/OverlayFade-3pof2AJH.js.map +1 -0
  57. package/dist/lib/{Panel-CpNQTLNF.js → Panel-Cy1pdlWO.js} +2 -2
  58. package/dist/lib/{Panel-CpNQTLNF.js.map → Panel-Cy1pdlWO.js.map} +1 -1
  59. package/dist/lib/{Position-PBVBW1JS.js → Position-BwtxouxK.js} +2 -2
  60. package/dist/lib/{Position-PBVBW1JS.js.map → Position-BwtxouxK.js.map} +1 -1
  61. package/dist/lib/{ProgressSpinner-lAsK26C-.js → ProgressSpinner-DK8xEQ9y.js} +2 -2
  62. package/dist/lib/{ProgressSpinner-lAsK26C-.js.map → ProgressSpinner-DK8xEQ9y.js.map} +1 -1
  63. package/dist/lib/RadioButton-BEwpqg1k.js +2 -0
  64. package/dist/lib/{RadioButton-CCcIaL54.js.map → RadioButton-BEwpqg1k.js.map} +1 -1
  65. package/dist/lib/RadioMenuRow-DP5qPyFR.js +2 -0
  66. package/dist/lib/RadioMenuRow-DP5qPyFR.js.map +1 -0
  67. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js → RovingTabIndex-pHEv5oLD.js} +2 -2
  68. package/dist/lib/{RovingTabIndex-C2Vzq0IX.js.map → RovingTabIndex-pHEv5oLD.js.map} +1 -1
  69. package/dist/lib/Scrollbar-t8fFrUVQ.js +2 -0
  70. package/dist/lib/Scrollbar-t8fFrUVQ.js.map +1 -0
  71. package/dist/lib/{Slider-DZ9drUxn.js → Slider-CTbwR6HR.js} +2 -2
  72. package/dist/lib/{Slider-DZ9drUxn.js.map → Slider-CTbwR6HR.js.map} +1 -1
  73. package/dist/lib/{Spacer-SDhOMp2g.js → Spacer-srdN2d2b.js} +2 -2
  74. package/dist/lib/{Spacer-SDhOMp2g.js.map → Spacer-srdN2d2b.js.map} +1 -1
  75. package/dist/lib/TabButton-DLoMQzky.js +2 -0
  76. package/dist/lib/TabButton-DLoMQzky.js.map +1 -0
  77. package/dist/lib/TabCloseButton-CY7BGitY.js +2 -0
  78. package/dist/lib/TabCloseButton-CY7BGitY.js.map +1 -0
  79. package/dist/lib/{Text-CdHf3B-1.js → Text-CMKnK9uB.js} +2 -2
  80. package/dist/lib/{Text-CdHf3B-1.js.map → Text-CMKnK9uB.js.map} +1 -1
  81. package/dist/lib/{Tooltip-B_UF5bXD.js → Tooltip-CUOJOqQi.js} +3 -3
  82. package/dist/lib/Tooltip-CUOJOqQi.js.map +1 -0
  83. package/dist/lib/Tree-C64JNPWJ.js +2 -0
  84. package/dist/lib/Tree-C64JNPWJ.js.map +1 -0
  85. package/dist/lib/VBox-DfJPWXqc.js +2 -0
  86. package/dist/lib/VBox-DfJPWXqc.js.map +1 -0
  87. package/dist/lib/VirtualScroller-DTIn19o1.js +2 -0
  88. package/dist/lib/VirtualScroller-DTIn19o1.js.map +1 -0
  89. package/dist/lib/assets/StoreWorker-B5NwRM2I.js +2 -0
  90. package/dist/lib/assets/StoreWorker-B5NwRM2I.js.map +1 -0
  91. package/dist/lib/component/button.es.js +1 -1
  92. package/dist/lib/component/button.es.js.map +1 -1
  93. package/dist/lib/component/chart.es.js +1 -1
  94. package/dist/lib/component/container.es.js +1 -1
  95. package/dist/lib/component/container.es.js.map +1 -1
  96. package/dist/lib/component/diagram.es.js +1 -1
  97. package/dist/lib/component/diagram.es.js.map +1 -1
  98. package/dist/lib/component/display.es.js +1 -1
  99. package/dist/lib/component/display.es.js.map +1 -1
  100. package/dist/lib/component/editor.es.js +2 -2
  101. package/dist/lib/component/editor.es.js.map +1 -1
  102. package/dist/lib/component/input.es.js +1 -1
  103. package/dist/lib/component/input.es.js.map +1 -1
  104. package/dist/lib/component/list.es.js +1 -1
  105. package/dist/lib/component/list.es.js.map +1 -1
  106. package/dist/lib/component/menubar.es.js +1 -1
  107. package/dist/lib/component/menubar.es.js.map +1 -1
  108. package/dist/lib/component/table.es.js +6 -3
  109. package/dist/lib/component/table.es.js.map +1 -1
  110. package/dist/lib/component/tree.es.js +1 -1
  111. package/dist/lib/core.es.js +1 -1
  112. package/dist/lib/core.es.js.map +1 -1
  113. package/dist/lib/data.es.js +1 -1
  114. package/dist/lib/glyphs/solid/index.es.js +1 -1
  115. package/dist/lib/layout.es.js +1 -1
  116. package/dist/lib/layout.es.js.map +1 -1
  117. package/dist/lib/overlay.es.js +1 -1
  118. package/dist/lib/overlay.es.js.map +1 -1
  119. package/dist/lib/primitive.es.js +1 -1
  120. package/dist/lib/router.es.js +1 -1
  121. package/dist/lib/router.es.js.map +1 -1
  122. package/dist/lib/selectionsEqual-gMG7gCVI.js +2 -0
  123. package/dist/lib/selectionsEqual-gMG7gCVI.js.map +1 -0
  124. package/dist/lib/types/component/button/Button.d.ts +13 -0
  125. package/dist/lib/types/component/button/MenuButton.d.ts +1 -0
  126. package/dist/lib/types/component/button/PopupButton.d.ts +22 -0
  127. package/dist/lib/types/component/button/TabButton.d.ts +4 -0
  128. package/dist/lib/types/component/button/index.d.ts +2 -0
  129. package/dist/lib/types/component/container/CheckboxMenuRow.d.ts +33 -0
  130. package/dist/lib/types/component/container/CollapseButton.d.ts +11 -3
  131. package/dist/lib/types/component/container/MenuItem.d.ts +15 -5
  132. package/dist/lib/types/component/container/MenuRow.d.ts +24 -0
  133. package/dist/lib/types/component/container/MenuSeparator.d.ts +4 -2
  134. package/dist/lib/types/component/container/RadioMenuRow.d.ts +33 -0
  135. package/dist/lib/types/component/container/Scrollbar.d.ts +5 -0
  136. package/dist/lib/types/component/container/SplitGutter.d.ts +7 -2
  137. package/dist/lib/types/component/container/TabBar.d.ts +2 -0
  138. package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
  139. package/dist/lib/types/component/container/index.d.ts +6 -1
  140. package/dist/lib/types/component/display/WebGLCanvas.d.ts +1 -0
  141. package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +2 -0
  142. package/dist/lib/types/component/input/AbstractPickerField.d.ts +3 -2
  143. package/dist/lib/types/component/list/AbstractSelectableList.d.ts +1 -1
  144. package/dist/lib/types/component/list/MultiSelectList.d.ts +2 -1
  145. package/dist/lib/types/component/shared/VirtualRowView.d.ts +2 -0
  146. package/dist/lib/types/component/table/Body.d.ts +22 -1
  147. package/dist/lib/types/component/table/Column.d.ts +3 -1
  148. package/dist/lib/types/component/table/ColumnConfig.d.ts +2 -0
  149. package/dist/lib/types/component/table/ColumnFilter.d.ts +27 -0
  150. package/dist/lib/types/component/table/Header.d.ts +30 -3
  151. package/dist/lib/types/component/table/Row.d.ts +4 -0
  152. package/dist/lib/types/component/table/Table.d.ts +29 -0
  153. package/dist/lib/types/component/table/TableExporter.d.ts +4 -3
  154. package/dist/lib/types/component/table/TreeBody.d.ts +2 -1
  155. package/dist/lib/types/component/table/cell/CellText.d.ts +9 -0
  156. package/dist/lib/types/component/table/cell/Filter.d.ts +54 -0
  157. package/dist/lib/types/component/table/cell/FilterClauseBadge.d.ts +21 -0
  158. package/dist/lib/types/component/table/cell/GroupSeparator.d.ts +9 -0
  159. package/dist/lib/types/component/table/cell/Header.d.ts +1 -0
  160. package/dist/lib/types/component/table/cell/editor/CellEditor.d.ts +1 -0
  161. package/dist/lib/types/component/table/cell/renderer/CellRenderer.d.ts +1 -0
  162. package/dist/lib/types/component/table/cell/renderer/Combo.d.ts +2 -0
  163. package/dist/lib/types/component/table/cell/renderer/Date.d.ts +2 -0
  164. package/dist/lib/types/component/table/cell/renderer/DateTime.d.ts +2 -0
  165. package/dist/lib/types/component/table/cell/renderer/Filter.d.ts +16 -0
  166. package/dist/lib/types/component/table/cell/renderer/Glyph.d.ts +1 -0
  167. package/dist/lib/types/component/table/cell/renderer/Link.d.ts +2 -0
  168. package/dist/lib/types/component/table/cell/renderer/Number.d.ts +3 -1
  169. package/dist/lib/types/component/table/cell/renderer/String.d.ts +2 -0
  170. package/dist/lib/types/component/table/cell/renderer/Time.d.ts +2 -0
  171. package/dist/lib/types/component/table/cell/renderer/TreeCell.d.ts +1 -0
  172. package/dist/lib/types/component/table/index.d.ts +6 -0
  173. package/dist/lib/types/component/tree/Tree.d.ts +17 -1
  174. package/dist/lib/types/component/tree/index.d.ts +1 -1
  175. package/dist/lib/types/core/AnimatedDropdown.d.ts +0 -9
  176. package/dist/lib/types/core/Body.d.ts +4 -0
  177. package/dist/lib/types/core/ClassStyleRules.d.ts +1 -0
  178. package/dist/lib/types/core/DOM.d.ts +10 -0
  179. package/dist/lib/types/core/Event.d.ts +11 -2
  180. package/dist/lib/types/core/OverlayFade.d.ts +12 -0
  181. package/dist/lib/types/core/OverlayPosition.d.ts +6 -0
  182. package/dist/lib/types/core/Theme.d.ts +8 -0
  183. package/dist/lib/types/core/index.d.ts +5 -3
  184. package/dist/lib/types/data/AbstractStore.d.ts +3 -0
  185. package/dist/lib/types/data/FilterDescriptor.d.ts +13 -0
  186. package/dist/lib/types/data/index.d.ts +2 -1
  187. package/dist/lib/types/data/temporalText.d.ts +2 -0
  188. package/dist/lib/types/layout/BoxLayout.d.ts +6 -1
  189. package/dist/lib/types/layout/Grid.d.ts +1 -0
  190. package/dist/lib/types/layout/HFlow.d.ts +1 -1
  191. package/dist/lib/types/layout/Split.d.ts +10 -1
  192. package/dist/lib/types/layout/Tab.d.ts +7 -1
  193. package/dist/lib/types/layout/VFlow.d.ts +1 -1
  194. package/dist/lib/types/layout/index.d.ts +1 -1
  195. package/dist/lib/types/overlay/Dock.d.ts +1 -0
  196. package/dist/lib/types/overlay/Menu.d.ts +1 -1
  197. package/dist/lib/types/overlay/Popover.d.ts +3 -0
  198. package/dist/lib/types/overlay/PopupPanel.d.ts +17 -0
  199. package/dist/lib/types/overlay/Window.d.ts +2 -0
  200. package/dist/lib/types/overlay/index.d.ts +2 -0
  201. package/dist/lib/types/router/RoutePattern.d.ts +7 -0
  202. package/dist/lib/types/router/Router.d.ts +6 -2
  203. package/dist/lib/types/router/index.d.ts +1 -1
  204. package/dist/lib/validation.es.js +1 -1
  205. package/llms.txt +4 -0
  206. package/package.json +1 -1
  207. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js +0 -2
  208. package/dist/lib/AbstractBooleanInput-CbW7ZrDT.js.map +0 -1
  209. package/dist/lib/Anchor-BsblS5it.js +0 -2
  210. package/dist/lib/Anchor-BsblS5it.js.map +0 -1
  211. package/dist/lib/AnimatedDropdown-kL47HPGP.js +0 -2
  212. package/dist/lib/AnimatedDropdown-kL47HPGP.js.map +0 -1
  213. package/dist/lib/Border-CNS6aEXB.js +0 -2
  214. package/dist/lib/Border-CNS6aEXB.js.map +0 -1
  215. package/dist/lib/Button-T16zSZip.js +0 -2
  216. package/dist/lib/Button-T16zSZip.js.map +0 -1
  217. package/dist/lib/CodeEditor-BGlB232h.js.map +0 -1
  218. package/dist/lib/ComboBox-C9FYMuLv.js +0 -2
  219. package/dist/lib/ComboBox-C9FYMuLv.js.map +0 -1
  220. package/dist/lib/Component-w65rPK75.js +0 -2
  221. package/dist/lib/Component-w65rPK75.js.map +0 -1
  222. package/dist/lib/Container-C7RPLQEc.js +0 -2
  223. package/dist/lib/DOM-Ba8YRVel.js.map +0 -1
  224. package/dist/lib/DragManager-UvPHSoRm.js +0 -2
  225. package/dist/lib/DragManager-UvPHSoRm.js.map +0 -1
  226. package/dist/lib/Grid-BYBohJIA.js.map +0 -1
  227. package/dist/lib/GridConstraints-Bts284FI.js +0 -2
  228. package/dist/lib/LayoutSerialization-ySzY1h2l.js +0 -2
  229. package/dist/lib/LayoutSerialization-ySzY1h2l.js.map +0 -1
  230. package/dist/lib/LayoutSizes-DKDK1Cle.js +0 -2
  231. package/dist/lib/LayoutSizes-DKDK1Cle.js.map +0 -1
  232. package/dist/lib/List-BPd-IXZR.js +0 -2
  233. package/dist/lib/MemoryStore-BgP7-Uzn.js +0 -2
  234. package/dist/lib/MemoryStore-BgP7-Uzn.js.map +0 -1
  235. package/dist/lib/Menu-C0roOCY7.js +0 -2
  236. package/dist/lib/Menu-C0roOCY7.js.map +0 -1
  237. package/dist/lib/RadioButton-CCcIaL54.js +0 -2
  238. package/dist/lib/Scrollbar-C3ZZyZ1e.js +0 -2
  239. package/dist/lib/Scrollbar-C3ZZyZ1e.js.map +0 -1
  240. package/dist/lib/TabButton-DNo4ZgV8.js +0 -2
  241. package/dist/lib/TabButton-DNo4ZgV8.js.map +0 -1
  242. package/dist/lib/Tooltip-B_UF5bXD.js.map +0 -1
  243. package/dist/lib/Tree-C7qLbIYH.js +0 -2
  244. package/dist/lib/Tree-C7qLbIYH.js.map +0 -1
  245. package/dist/lib/VBox-32fxpkDl.js +0 -2
  246. package/dist/lib/VBox-32fxpkDl.js.map +0 -1
  247. package/dist/lib/VirtualScroller-cvFNMS7U.js +0 -2
  248. package/dist/lib/VirtualScroller-cvFNMS7U.js.map +0 -1
  249. package/dist/lib/assets/StoreWorker-CgOBYoai.js +0 -2
  250. package/dist/lib/assets/StoreWorker-CgOBYoai.js.map +0 -1
  251. package/dist/lib/selectionsEqual-BrTxPMmK.js +0 -2
  252. package/dist/lib/selectionsEqual-BrTxPMmK.js.map +0 -1
@@ -1,2 +0,0 @@
1
- import{h as e,t}from"./Component-w65rPK75.js";var Container=class extends t{clampsToContentSize(){return!1}},n=e(Container);export{n as t};
2
- //# sourceMappingURL=Container-C7RPLQEc.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DOM-Ba8YRVel.js","names":[],"sources":["../../src/typescript/lib/core/DOM.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport type { TextMeasureOptions, TextMetrics } from \"~/core/Util.js\";\nimport type { Size } from \"~/primitive/Size.js\";\nimport type { Component } from \"~/core/Component.js\";\n\n// Production measurement caches. These live here because the irreducible\n// browser-measurement leaf (the off-screen probe, the canvas metrics context,\n// the scrollbar-width probe) is the production side of the read seam — the lone\n// place the framework touches the real DOM for measurement.\nlet _metricsCtx: CanvasRenderingContext2D | null = null;\nlet _scrollBarWidth: number = -1;\n\n/**\n * Applies a set of camelCase inline-style properties to an element, used by the\n * off-screen measurement probes below. Raw `style` access is intentional — this\n * is inside the seam's production implementation.\n */\nfunction _applyProbeStyles(element: HTMLElement, styles: Record<string, string>): void {\n for (const key of Object.keys(styles)) {\n (element.style as any)[key] = styles[key];\n }\n}\n\n/**\n * Plain serialisable rectangle in viewport coordinates. Deliberately *not* a\n * live [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect):\n * the read seam returns plain data so the same call can be answered by a\n * geometry model (offline tests) or, in future, across a worker boundary.\n *\n * @remarks The `top` / `left` / `right` / `bottom` edges mirror `DOMRect`'s\n * derived fields so existing anchor-positioning call sites read this as a\n * drop-in for the rect they used to get from `getBoundingClientRect()`. A live\n * `DOMRect` is structurally assignable to a `Rect`.\n *\n * @category Core\n */\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n left: number;\n right: number;\n bottom: number;\n}\n\n/**\n * Plain box-model snapshot — an element's native scroll offsets together with\n * its scrollable content size and visible viewport size, read in one shot.\n * Deliberately *not* a live element: like {@link Rect}, the read seam returns\n * plain data so the same call can be answered offline or across a worker\n * boundary.\n *\n * @category Core\n */\nexport interface ScrollMetrics {\n scrollTop: number;\n scrollLeft: number;\n scrollWidth: number;\n scrollHeight: number;\n clientWidth: number;\n clientHeight: number;\n}\n\n/**\n * Plain offset-box snapshot — an element's top edge and height relative to its\n * `offsetParent`. Plain data for the same reason as {@link ScrollMetrics}.\n *\n * @category Core\n */\nexport interface OffsetSize {\n offsetTop: number;\n offsetHeight: number;\n}\n\n/**\n * Plain snapshot of a media element's playback state, read in one shot through\n * {@link DOMSource.getMediaState}. Deliberately *not* a live element: like\n * {@link ScrollMetrics}, the read seam returns plain data so the same call can\n * be answered by a media model (offline tests) or across a worker boundary.\n *\n * @category Core\n */\nexport interface MediaState {\n /** Current playback position in seconds. */\n currentTime: number;\n /** Total media duration in seconds (`NaN` before metadata loads). */\n duration: number;\n /** Whether playback is currently paused. */\n paused: boolean;\n /** Whether playback has reached the end of the media. */\n ended: boolean;\n /** Current audio volume in `[0, 1]`. */\n volume: number;\n /** Whether audio is muted. */\n muted: boolean;\n /** Current playback speed multiplier (`1` is normal speed). */\n playbackRate: number;\n}\n\n/**\n * Opaque, serialisable element reference. A branded `number`, so a raw number\n * cannot be passed where a handle is expected and the reference forwards across\n * a worker boundary as plain data. The live `Node` it stands for never escapes\n * the seam — every sink/source method resolves the handle internally.\n *\n * @category Core\n */\nexport type Handle = number & { readonly __handleBrand: unique symbol };\n\n/**\n * A timer id as returned by the host's `setTimeout`. Node and the browser\n * disagree on the concrete type (`Timeout` object vs `number`), so the seam\n * carries whichever the host produces rather than committing to one.\n *\n * @category Core\n */\nexport type TimerId = ReturnType<typeof setTimeout>;\n\n/**\n * A batch of mutations applied to a single element with one handle resolve.\n * Every field is plain serialisable data — no live element, no function — so a\n * worker transport forwards an entire patch as one `postMessage`.\n *\n * Application order is fixed: styles first, then class removals before\n * additions (so a `removeClass` + `addClass` of the same name lands \"on\"),\n * attribute removals before sets, then dataset / text / scroll.\n *\n * @category Core\n */\nexport interface ElementPatch {\n /** Inline style writes. `null` removes the property. camelCase or `--custom`. */\n style?: Readonly<Record<string, string | null>>;\n /** Classes to remove (applied before {@link ElementPatch.addClass}). */\n removeClass?: readonly string[];\n /** Classes to add. */\n addClass?: readonly string[];\n /** Classes to force on/off. */\n toggleClass?: Readonly<Record<string, boolean>>;\n /** Attributes to remove (applied before {@link ElementPatch.setAttr}). */\n removeAttr?: readonly string[];\n /** Attributes to set. */\n setAttr?: Readonly<Record<string, string>>;\n /** `data-*` writes (camelCase keys). */\n dataset?: Readonly<Record<string, string>>;\n /** Text content. */\n text?: string;\n /** Native horizontal scroll offset. */\n scrollLeft?: number;\n /** Native vertical scroll offset. */\n scrollTop?: number;\n}\n\n/**\n * Canonicalising handle registry — the lone holder of live DOM references in\n * the handle design. Maps a handle to its node (forward) and a node back to its\n * handle (reverse) so a node is never assigned two handles; that reverse map is\n * what makes handle equality mirror element equality.\n *\n * Two minting modes draw the leak-safety line. {@link HandleRegistry.retain} is\n * for nodes the framework owns (it created them): a strong forward entry,\n * released explicitly at the element's dispose site. {@link HandleRegistry.intern}\n * is for browser-supplied nodes the live DOM already owns: a weak forward entry\n * (`WeakRef`) plus a finalizer that drops the handle once the node is collected,\n * so interning can never pin a dead node.\n *\n * Module-private: only the production sink and source touch it.\n */\nclass HandleRegistry {\n private readonly _forward = new Map<Handle, Node | WeakRef<Node>>();\n private readonly _reverse = new WeakMap<Node, Handle>();\n private _next = 1;\n\n /** Drops the forward entry when a weakly-interned node is garbage-collected. */\n private readonly _finalizer = new FinalizationRegistry<Handle>((handle) => {\n this._forward.delete(handle);\n });\n\n /**\n * Mints a canonical handle for a node the framework owns (a created,\n * possibly-detached element). Strongly held so a detached node survives\n * until it is mounted or explicitly released.\n *\n * @param node - The owned node.\n * @returns Its canonical handle (stable across repeated calls).\n */\n retain(node: Node): Handle {\n const existing = this._reverse.get(node);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const handle = this._mint(node);\n\n this._forward.set(handle, node);\n\n return handle;\n }\n\n /**\n * Mints a canonical handle for a node supplied by the browser (an event\n * target, a `querySelector` result, the active element). The live DOM owns\n * it, so the registry holds only a weak reference plus a finalizer — no leak\n * even if the handle is never released.\n *\n * @param node - The browser-supplied node.\n * @returns Its canonical handle (stable while the node is alive).\n */\n intern(node: Node): Handle {\n const existing = this._reverse.get(node);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const handle = this._mint(node);\n\n this._forward.set(handle, new WeakRef(node));\n this._finalizer.register(node, handle);\n\n return handle;\n }\n\n /**\n * Resolves a handle to its node. Throws on a released or collected handle —\n * a use-after-free becomes a loud failure instead of the silent no-op a\n * stale element pointer would give.\n *\n * @param handle - The handle to resolve.\n * @returns The live node.\n */\n resolve(handle: Handle): Node {\n const entry = this._forward.get(handle);\n\n if (entry === undefined) {\n throw new Error(`DOM handle ${handle} is not registered (released or never minted).`);\n }\n\n const node = entry instanceof WeakRef ? entry.deref() : entry;\n\n if (node === undefined) {\n throw new Error(`DOM handle ${handle} refers to a collected node.`);\n }\n\n return node;\n }\n\n /**\n * Releases an owned handle at its element's dispose site. Idempotent. A\n * missed release on a retained (strong) handle pins a detached element\n * forever, so the migration must place this at every created-element\n * teardown.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void {\n const entry = this._forward.get(handle);\n\n if (entry === undefined) {\n return;\n }\n\n const node = entry instanceof WeakRef ? entry.deref() : entry;\n\n if (node) {\n this._reverse.delete(node);\n }\n\n this._forward.delete(handle);\n }\n\n /** Live forward-map size — a test hook that verifies release / GC eviction. */\n get size(): number {\n return this._forward.size;\n }\n\n private _mint(node: Node): Handle {\n const handle = this._next as Handle;\n\n this._next += 1;\n this._reverse.set(node, handle);\n\n return handle;\n }\n}\n\n/** The shared production registry. Rebuilt together with the seams by {@link DOM.reset}. */\nlet _registry = new HandleRegistry();\n\n/** Forward-map size of the shared production registry; for tests only. @internal */\nexport function _handleRegistrySize(): number {\n return _registry.size;\n}\n\n/**\n * The single terminal style write, shared by the inline-style and patch paths.\n * A hyphenated key is either a custom property (`--foo`) or a standard\n * kebab-case name (`background-color`); both go through `setProperty` /\n * `removeProperty`. Only camelCase keys work through the indexed accessor.\n */\nfunction writeDeclaration(style: CSSStyleDeclaration, key: string, value: string | null): void {\n if (key.includes(\"-\")) {\n if (value === null) {\n style.removeProperty(key);\n } else {\n style.setProperty(key, value);\n }\n } else if (value === null) {\n (style as unknown as Record<string, string>)[key] = \"\";\n } else {\n (style as unknown as Record<string, string>)[key] = value;\n }\n}\n\n/**\n * Module-private, never appended to the document: a detached element whose\n * inline style is a real `CSSStyleDeclaration`. Writing to it costs nothing at\n * the document level, so a bag can be merged property-by-property here and\n * land on the shared sheet as one mutation.\n */\nlet _scratch: CSSStyleDeclaration | null = null;\n\nfunction scratchDeclaration(): CSSStyleDeclaration | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n return _scratch ??= document.createElement(\"div\").style;\n}\n\n/**\n * Applies an {@link ElementPatch} to a resolved element — the terminal raw-DOM\n * write for the batched {@link DOMSink.apply} path. Fixed order: styles, class\n * removals before additions, attribute removals before sets, then dataset /\n * text / scroll.\n */\nfunction applyPatchTo(element: HTMLElement, patch: ElementPatch): void {\n if (patch.style) {\n for (const key of Object.keys(patch.style)) {\n writeDeclaration(element.style, key, patch.style[key]);\n }\n }\n\n if (patch.removeClass) {\n for (const name of patch.removeClass) {\n element.classList.remove(name);\n }\n }\n\n if (patch.addClass) {\n for (const name of patch.addClass) {\n // Skip empty tokens: `classList.add(\"\")` throws a SyntaxError. A\n // stray empty class name (e.g. an anonymous class whose\n // `constructor.name` is \"\") must not abort the whole patch.\n if (name) {\n element.classList.add(name);\n }\n }\n }\n\n if (patch.toggleClass) {\n for (const name of Object.keys(patch.toggleClass)) {\n element.classList.toggle(name, patch.toggleClass[name]);\n }\n }\n\n if (patch.removeAttr) {\n for (const key of patch.removeAttr) {\n element.removeAttribute(key);\n }\n }\n\n if (patch.setAttr) {\n for (const key of Object.keys(patch.setAttr)) {\n element.setAttribute(key, patch.setAttr[key]);\n }\n }\n\n if (patch.dataset) {\n for (const key of Object.keys(patch.dataset)) {\n element.dataset[key] = patch.dataset[key];\n }\n }\n\n if (patch.text !== undefined) {\n element.textContent = patch.text;\n }\n\n if (patch.scrollLeft !== undefined) {\n element.scrollLeft = patch.scrollLeft;\n }\n\n if (patch.scrollTop !== undefined) {\n element.scrollTop = patch.scrollTop;\n }\n}\n\n/**\n * Fluent accumulator over an {@link ElementPatch}. Each method appends to the\n * pending patch; {@link PatchBuilder.commit} flushes it as one batched write.\n * The fluent form is sugar for cold call sites — the batched {@link DOMSink.apply}\n * is the real primitive — and it allocates one builder per edit.\n *\n * @category Core\n */\nexport class PatchBuilder {\n private readonly _patch: {\n style?: Record<string, string | null>;\n addClass?: string[];\n setAttr?: Record<string, string>;\n text?: string;\n } = {};\n\n /**\n * @param _commit - Flush callback that performs the single handle resolve.\n */\n constructor(private readonly _commit: (patch: ElementPatch) => void) {}\n\n /**\n * Queues an inline-style write (`null` removes).\n *\n * @param key - The CSS property name (camelCase, or `--custom-property`).\n * @param value - The value to set, or null to remove the property.\n * @returns This builder.\n */\n style(key: string, value: string | null): this {\n (this._patch.style ??= {})[key] = value;\n\n return this;\n }\n\n /**\n * Queues a class addition.\n *\n * @param name - The class name.\n * @returns This builder.\n */\n addClass(name: string): this {\n (this._patch.addClass ??= []).push(name);\n\n return this;\n }\n\n /**\n * Queues an attribute set.\n *\n * @param key - The attribute name.\n * @param value - The attribute value.\n * @returns This builder.\n */\n attr(key: string, value: string): this {\n (this._patch.setAttr ??= {})[key] = value;\n\n return this;\n }\n\n /**\n * Queues a text-content write.\n *\n * @param value - The text content.\n * @returns This builder.\n */\n text(value: string): this {\n this._patch.text = value;\n\n return this;\n }\n\n /** Flushes the accumulated patch through one batched write (one resolve). */\n commit(): void {\n this._commit(this._patch);\n }\n}\n\n/**\n * Terminal DOM-write primitive. Every structural mutation and inline-style\n * write in the framework funnels through this seam instead of touching\n * `element.style` / `element.classList` / `appendChild` directly. The\n * production implementation ({@link ProductionDOMSink}) is a thin pass-through;\n * test implementations record the writes without touching a DOM.\n *\n * @remarks Methods are one-way (no return value drives control flow), so a\n * future worker transport can forward each as a `postMessage`.\n *\n * @category Core\n */\nexport interface DOMSink {\n /**\n * Applies a batch of mutations to one element with a single handle resolve.\n * The hot-path primitive that replaces the ten per-write data setters\n * (`setStyle`, `addClass`, `removeClass`, `toggleClass`, `setAttribute`,\n * `removeAttribute`, `setDataset`, `setTextContent`, `setScrollLeft`,\n * `setScrollTop`): a layout commit (width + height + classes + an attribute)\n * costs one `Map.get`, not one per write.\n *\n * @param handle - The target element handle.\n * @param patch - The batch of mutations.\n */\n apply(handle: Handle, patch: ElementPatch): void;\n\n /**\n * Fluent convenience that accumulates a patch and flushes it through a\n * single {@link apply}. For cold call sites — it allocates one builder per\n * edit.\n *\n * @param handle - The target element handle.\n * @returns A builder whose `commit()` performs the single resolve.\n */\n edit(handle: Handle): PatchBuilder;\n\n /**\n * Releases an owned (retained) handle at its element's dispose site.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void;\n\n /**\n * Writes a bag of style properties onto a `CSSStyleRule`'s declaration as\n * one sheet mutation. A `CSSStyleRule` has no element, so it gets its own\n * method — mirroring how {@link apply}'s `style` patch serves both the\n * single and the bulk element-style path.\n *\n * @param rule - The target `CSSStyleRule`.\n * @param styles - Camel-cased property keys mapped to string values (or\n * null to remove the property).\n */\n setRuleStyles(rule: CSSStyleRule, styles: Record<string, string | null>): void;\n\n /**\n * Finds, or inserts, the framework's shared-stylesheet `CSSStyleRule` for a\n * selector, so callers never walk a `CSSStyleSheet` directly. The returned\n * rule is handed to {@link setRuleStyles}.\n *\n * @param selector - The CSS selector text.\n * @returns The existing or newly-inserted rule.\n */\n ensureStyleRule(selector: string): CSSStyleRule;\n\n /**\n * Removes the shared-stylesheet `CSSStyleRule` for a selector, if present.\n * The inverse of {@link ensureStyleRule}. A no-op when no rule matches.\n *\n * @param selector - The CSS selector text of the rule to remove.\n */\n deleteStyleRule(selector: string): void;\n\n /**\n * Inserts a `@keyframes` block into the shared stylesheet if one with the\n * given name does not already exist (idempotent).\n *\n * @param name - The animation name (no `@keyframes` prefix).\n * @param body - The keyframe body (the text between the braces).\n */\n ensureKeyframes(name: string, body: string): void;\n\n /**\n * Creates a detached HTML element, retained behind a handle until released.\n *\n * @param tag - The element tag name.\n * @returns The new element's handle.\n */\n createElement(tag: string): Handle;\n\n /**\n * Creates a detached namespaced element (SVG sprite / glyph construction),\n * retained behind a handle until released.\n *\n * @param ns - The element namespace URI.\n * @param tag - The element tag name.\n * @returns The new element's handle.\n */\n createElementNS(ns: string, tag: string): Handle;\n\n /**\n * Appends a child to a parent.\n *\n * @param parent - The parent handle.\n * @param child - The child handle to append.\n */\n appendChild(parent: Handle, child: Handle): void;\n\n /**\n * Removes a child from a parent.\n *\n * @param parent - The parent handle.\n * @param child - The child handle to remove.\n */\n removeChild(parent: Handle, child: Handle): void;\n\n /**\n * Detaches an element from its parent.\n *\n * @param handle - The element to remove.\n */\n removeElement(handle: Handle): void;\n\n /**\n * Moves browser focus to an element.\n *\n * @param handle - The element to focus.\n * @param options - Focus options; `preventScroll` suppresses the native\n * scroll-into-view so a host that owns its own scroll offset is not fought.\n */\n focus(handle: Handle, options?: { preventScroll?: boolean }): void;\n\n /**\n * Requests a native form submission on a `<form>` element, firing the\n * cancelable `submit` event and running constraint validation.\n *\n * @param handle - The form element to submit.\n */\n requestSubmit(handle: Handle): void;\n\n /**\n * Removes browser focus from an element.\n *\n * @param handle - The element to blur.\n */\n blur(handle: Handle): void;\n\n /**\n * Writes the value of a form control.\n *\n * @param handle - The target form control.\n * @param value - The value to set.\n */\n setValue(handle: Handle, value: string): void;\n\n /**\n * Sets the text-selection range of a form control.\n *\n * @param handle - The target form control.\n * @param start - The selection start offset.\n * @param end - The selection end offset.\n */\n setSelectionRange(handle: Handle, start: number, end: number): void;\n\n /**\n * Assigns `location.hash`, pushing a history entry.\n *\n * @param hash - The new hash, including its leading `\"#\"`.\n */\n setLocationHash(hash: string): void;\n\n /**\n * Replaces the current history entry with one carrying `hash`, instead of\n * pushing a new one.\n *\n * @param hash - The new hash, including its leading `\"#\"`.\n */\n replaceLocationHash(hash: string): void;\n\n /**\n * `history.pushState` with `url`, pushing a history entry. Fires no\n * event — the caller is responsible for applying the new route.\n *\n * @param url - The new path (and optional query/fragment) to push.\n */\n pushHistoryPath(url: string): void;\n\n /**\n * `history.replaceState` with `url`, replacing the current history\n * entry. Fires no event — the caller is responsible for applying the new\n * route.\n *\n * @param url - The new path (and optional query/fragment) to write.\n */\n replaceHistoryPath(url: string): void;\n\n /**\n * Registers a native event listener on a target. The framework's\n * {@link Event} class is the component-level routing layer; this seam covers\n * the low-level native hook it (and a few primitives) sits on.\n *\n * @param target - The event target handle (element, window, media-query list).\n * @param type - The event type.\n * @param handler - The listener.\n * @param options - Optional capture/passive/once options.\n */\n addListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | AddEventListenerOptions): void;\n\n /**\n * Removes a native event listener previously registered with {@link addListener}.\n *\n * @param target - The event target handle.\n * @param type - The event type.\n * @param handler - The listener to remove.\n * @param options - Optional capture options matching the registration.\n */\n removeListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | EventListenerOptions): void;\n\n /**\n * Dispatches an event on a target.\n *\n * @param target - The event target handle.\n * @param event - The event to dispatch.\n */\n dispatchEvent(target: Handle, event: Event): void;\n\n /**\n * Builds and dispatches a custom event of `type` with the given init on a\n * target. The framework's sole construction site for fired custom events:\n * the production sink mints a native `CustomEvent`, while the modelled sink\n * builds a plain sentinel event, so production code never names the global\n * `CustomEvent` constructor. `init` is a `CustomEventInit`, so `init.detail`\n * surfaces as the event's `detail` exactly as the inline `new CustomEvent`\n * it replaces did.\n *\n * @param target - The event target handle.\n * @param type - The event type (e.g. `\"keydown\"`).\n * @param init - Optional `CustomEventInit` (carries `detail`).\n */\n dispatchCustomEvent(target: Handle, type: string, init?: CustomEventInit): void;\n\n /**\n * Schedules a callback for the next animation frame.\n *\n * @param callback - The frame callback.\n * @returns The request handle, for {@link cancelAnimationFrame}.\n */\n requestAnimationFrame(callback: FrameRequestCallback): number;\n\n /**\n * Cancels a previously scheduled animation-frame callback.\n *\n * @param handle - The handle returned by {@link requestAnimationFrame}.\n */\n cancelAnimationFrame(handle: number): void;\n\n /**\n * Schedules `callback` to run after `delayMs`.\n *\n * @param callback - The timer callback.\n * @param delayMs - Delay before the callback runs, in milliseconds.\n * @returns The timer id, for {@link clearTimeout}.\n */\n setTimeout(callback: () => void, delayMs: number): TimerId;\n\n /**\n * Cancels a timer scheduled through {@link setTimeout}. A timer that has\n * already fired, or an id already cleared, is ignored.\n *\n * @param id - The id returned by {@link setTimeout}.\n */\n clearTimeout(id: TimerId): void;\n\n /**\n * Cancels every timer this sink scheduled that has not yet fired. Called by\n * `DOM.reset()` so a torn-down environment cannot be reached by a callback\n * scheduled against the previous one.\n */\n clearAllTimeouts(): void;\n\n /**\n * Sets an element's `id`.\n *\n * @param handle - The target element.\n * @param id - The id to set.\n */\n setId(handle: Handle, id: string): void;\n\n /**\n * Inserts a node before a reference child of a parent.\n *\n * @param parent - The parent handle.\n * @param node - The node to insert.\n * @param reference - The child to insert before, or null to append.\n */\n insertBefore(parent: Handle, node: Handle, reference: Handle | null): void;\n\n /**\n * Creates an empty document fragment for batched insertion, retained behind\n * a handle until released.\n *\n * @returns The new fragment's handle.\n */\n createDocumentFragment(): Handle;\n\n /**\n * Synthesises a click on an element (file-input open, download anchor).\n *\n * @param handle - The element to click.\n */\n click(handle: Handle): void;\n\n /**\n * Routes subsequent pointer events for a pointer id to an element.\n *\n * @param handle - The capturing element.\n * @param pointerId - The pointer id to capture.\n */\n setPointerCapture(handle: Handle, pointerId: number): void;\n\n /**\n * Releases a pointer capture previously set on an element.\n *\n * @param handle - The element holding the capture.\n * @param pointerId - The pointer id to release.\n */\n releasePointerCapture(handle: Handle, pointerId: number): void;\n\n /**\n * Obtains a drawing context from a `<canvas>` element. Generic over\n * `contextId` (`\"2d\"`, `\"webgl\"`, `\"webgl2\"`) so a single seam entry serves\n * both the raster and WebGL components, each narrowing the returned union\n * itself.\n *\n * @remarks Unlike every other sink method this returns a live object rather\n * than a forwardable one-way write: a rendering context cannot cross a worker\n * boundary, so a modelled sink returns `null` and the caller no-ops offline.\n * This is the single, named escape from the seam's one-way contract — the\n * reason a canvas is a live-only component.\n *\n * @param handle - The `<canvas>` element handle.\n * @param contextId - The context identifier (`\"2d\"`, `\"webgl\"`, …).\n * @param options - Optional context attributes (e.g. `{ alpha: false }`).\n * @returns The rendering context, or `null` when unavailable (offline, or the\n * element does not support the requested context).\n */\n getContext(handle: Handle, contextId: string, options?: unknown): RenderingContext | null;\n\n /**\n * Resolves `handle` to its real element and hands it to `factory`, which\n * mounts a foreign live widget (a third-party library that takes a parent\n * element and mutates a whole DOM region it owns) into it — the second\n * named escape from the seam's one-way contract, after {@link getContext}.\n *\n * @remarks Like `getContext`, this returns a live object rather than a\n * forwardable one-way write: the mounted widget instance cannot cross a\n * worker boundary, so a modelled sink returns `null` and the caller no-ops\n * offline. This is the reason a component built on `mountView` (e.g.\n * `CodeEditor` on CodeMirror's `EditorView`) is live-only. `factory`'s\n * parameter is deliberately left unannotated at call sites outside this\n * seam — its type is inferred from this signature — so no call site names\n * a DOM element type and trips `no-raw-dom`'s *hold* clause.\n *\n * @param handle - The element handle to mount the foreign widget into.\n * @param factory - Builds and returns the foreign widget given the\n * resolved parent element.\n * @returns Whatever `factory` returns, or `null` offline / when the handle\n * does not resolve.\n */\n mountView<T>(handle: Handle, factory: (parent: HTMLElement) => T): T | null;\n\n /**\n * Starts (or resumes) playback of a media element. Wraps the `play()` IDL\n * method, whose returned promise is intentionally dropped — playback state is\n * observed through media events, not the promise.\n *\n * @param handle - The `<video>` / `<audio>` element handle.\n */\n mediaPlay(handle: Handle): void;\n\n /**\n * Pauses playback of a media element.\n *\n * @param handle - The media element handle.\n */\n mediaPause(handle: Handle): void;\n\n /**\n * Seeks a media element to a playback position.\n *\n * @param handle - The media element handle.\n * @param seconds - The target position in seconds.\n */\n setCurrentTime(handle: Handle, seconds: number): void;\n\n /**\n * Sets a media element's audio volume.\n *\n * @param handle - The media element handle.\n * @param value - The volume in `[0, 1]`.\n */\n setVolume(handle: Handle, value: number): void;\n\n /**\n * Sets a media element's muted state (the IDL property, which the boolean\n * attribute alone cannot toggle after load).\n *\n * @param handle - The media element handle.\n * @param muted - Whether audio is muted.\n */\n setMuted(handle: Handle, muted: boolean): void;\n\n /**\n * Sets a media element's playback speed multiplier.\n *\n * @param handle - The media element handle.\n * @param rate - The playback rate (`1` is normal speed).\n */\n setPlaybackRate(handle: Handle, rate: number): void;\n\n /**\n * Requests that an element enter fullscreen. Must be called from a user\n * gesture handler; the returned promise is dropped — the transition is\n * observed through the `fullscreenchange` event.\n *\n * @param handle - The element to display fullscreen.\n */\n requestFullscreen(handle: Handle): void;\n\n /**\n * Exits fullscreen for the document. No-op when nothing is fullscreen.\n */\n exitFullscreen(): void;\n}\n\n/**\n * Read seam. Geometry is keyed on the owning {@link Component} (so a model can\n * reproduce it from committed state); text metrics, theme variables, and\n * environment constants funnel through the remaining methods. The production\n * implementation ({@link ProductionDOMSource}) reads the live DOM; test\n * implementations answer from a geometry model and a baked metrics table.\n *\n * @category Core\n */\nexport interface DOMSource {\n /**\n * Converts a raw browser node arriving at an event boundary into a (weak)\n * handle. The one place a raw target legitimately enters the seam from\n * outside — the event system hands it `evnt.target`, and the handle is\n * interned so no call site downstream holds the raw node.\n *\n * @param target - The browser-supplied event target.\n * @returns Its canonical handle.\n */\n intern(target: EventTarget): Handle;\n\n /**\n * Whether a raw value arriving at an event boundary is a DOM node. Replaces\n * call-site `value instanceof Node` guards (which name a global constructor)\n * so an `EventTarget | null` field can be narrowed before {@link intern}.\n *\n * @param value - The raw value to test (typically `e.relatedTarget` / `e.target`).\n * @returns `true` when the value is a node; production matches `instanceof Node`.\n * The `EventTarget` type guard lets a nullable event field narrow for\n * the subsequent {@link intern}.\n */\n isNode(value: unknown): value is EventTarget;\n\n /**\n * Whether a raw value is a DOM element — {@link isNode} narrowed to elements.\n * Replaces call-site `value instanceof Element`.\n *\n * @param value - The raw value to test.\n * @returns `true` when the value is an element; production matches `instanceof Element`.\n */\n isElement(value: unknown): value is EventTarget;\n\n /**\n * Escapes a string for safe use inside a CSS selector. Replaces call-site\n * `CSS.escape`, which names a global the offline harness does not ship.\n *\n * @param value - The raw string (e.g. a glyph id).\n * @returns The escaped string; production uses `CSS.escape`.\n */\n escapeSelector(value: string): string;\n\n /**\n * Returns the viewport-space rectangle of a component's root element.\n *\n * @param component - The component to measure.\n * @returns The component's bounding rectangle as plain data.\n */\n getViewportRect(component: Component): Rect;\n\n /**\n * Returns the viewport-space rectangle of an arbitrary element. Escape\n * hatch for non-component nodes (anchor elements, ancestor scroll boxes).\n *\n * @param handle - The element to measure.\n * @returns The element's bounding rectangle as plain data.\n */\n getElementRect(handle: Handle): Rect;\n\n /**\n * Measures the rendered size and baseline of a text string.\n *\n * @param text - The string to measure.\n * @param options - Font properties; default to the active theme variables.\n * @returns The measured `{width, height, baseline}` in pixels.\n */\n measureText(text: string, options?: TextMeasureOptions): TextMetrics;\n\n /**\n * Measures many strings under one font in a single document reflow.\n *\n * @param texts - The strings to measure.\n * @param options - Font properties; default to the active theme variables.\n * @returns One width per input, in input order; an empty input list\n * touches the DOM not at all and returns an empty array.\n */\n measureTextWidths(texts: string[], options?: TextMeasureOptions): number[];\n\n /**\n * Resolves a CSS `font-size` value (possibly a `calc()`/`var()`) to a pixel\n * number by evaluating it on an off-screen probe.\n *\n * @param fontSizeCSS - A CSS font-size value.\n * @returns The resolved size in pixels (14 when unresolvable).\n */\n resolveFontSizePx(fontSizeCSS: string): number;\n\n /**\n * Returns the active font's vertical metrics in pixels.\n *\n * @returns The font `{ascent, descent, capTop}` in pixels.\n */\n measureFontMetrics(): { ascent: number; descent: number; capTop: number };\n\n /**\n * Resolves a theme CSS variable (e.g. `--ts-ui-font-size`) to its value.\n *\n * @param name - The CSS custom-property name, including the leading `--`.\n * @returns The resolved value, trimmed; empty string when unset.\n */\n getThemeVar(name: string): string;\n\n /**\n * Returns the current viewport size in pixels.\n *\n * @returns The viewport `{width, height}`.\n */\n getViewportSize(): Size;\n\n /**\n * Returns the native scrollbar width in pixels.\n *\n * @returns The scrollbar width.\n */\n getScrollBarWidth(): number;\n\n /**\n * Returns the display's device-pixel ratio — the factor by which a\n * `<canvas>` backing store must be scaled above its CSS size to stay crisp\n * on a HiDPI display. Reads the flagged `window.devicePixelRatio` global\n * behind the seam; a modelled source reports `1` so offline backing-store\n * math stays deterministic.\n *\n * @returns The device-pixel ratio (`1` or greater); `1` when unavailable.\n */\n getDevicePixelRatio(): number;\n\n /**\n * Whether this is a modelled (no-browser) source. Lets the few\n * irreducibly-browser reads short-circuit to a fallback offline.\n *\n * @returns `true` for a modelled source, `false` for production.\n */\n isModelled(): boolean;\n\n /**\n * Reads an element's native horizontal scroll offset (browser-clamped).\n *\n * @param handle - The element to read.\n * @returns The current `scrollLeft` in pixels.\n */\n getScrollLeft(handle: Handle): number;\n\n /**\n * Reads an element's native vertical scroll offset (browser-clamped).\n *\n * @param handle - The element to read.\n * @returns The current `scrollTop` in pixels.\n */\n getScrollTop(handle: Handle): number;\n\n /**\n * Reads an element's scroll offsets, scrollable content size, and visible\n * viewport size in one shot.\n *\n * @param handle - The element to measure.\n * @returns The element's {@link ScrollMetrics} as plain data.\n */\n getScrollMetrics(handle: Handle): ScrollMetrics;\n\n /**\n * Reads an element's offset-box top edge and height.\n *\n * @param handle - The element to measure.\n * @returns The element's {@link OffsetSize} as plain data.\n */\n getOffsetSize(handle: Handle): OffsetSize;\n\n /**\n * Whether an element is currently attached to a document.\n *\n * @param handle - The element to test.\n * @returns `true` when the element is connected.\n */\n isConnected(handle: Handle): boolean;\n\n /**\n * Reads the value of a form control.\n *\n * @param handle - The form control to read.\n * @returns The control's current value.\n */\n getValue(handle: Handle): string;\n\n /**\n * Returns the element that currently has focus, or null.\n *\n * @returns The active element handle, or null when nothing is focused.\n */\n getActiveElement(): Handle | null;\n\n /**\n * Evaluates a media query, returning its current match state and a\n * change-subscription hook. The live `MediaQueryList` never escapes the seam.\n *\n * @param query - The media-query string.\n * @returns The match state and a `change` subscription.\n */\n matchMedia(query: string): MediaQueryResult;\n\n /**\n * Whether an event target is the global `window` (identity check that keeps\n * the raw global out of call sites).\n *\n * @param target - The target handle to test, or null.\n * @returns `true` when the target is `window`.\n */\n isWindow(target: Handle | null): boolean;\n\n /**\n * Returns the global `window` interned to a handle, so window-level\n * listeners can be registered without a call site naming the raw global.\n *\n * @returns The `window` handle.\n */\n getWindow(): Handle;\n\n /**\n * The current `location.hash`, boxed so the raw global never escapes the\n * seam.\n *\n * @returns The hash including its leading `\"#\"`, or `\"\"` when empty.\n */\n getLocationHash(): string;\n\n /**\n * The current `location.pathname`, boxed so the raw global never escapes\n * the seam.\n *\n * @returns The path, always starting with `\"/\"`.\n */\n getLocationPathname(): string;\n\n /**\n * Whether a node is the ancestor of (or equal to) another node.\n *\n * @param ancestor - The candidate ancestor handle.\n * @param node - The node handle to test, or null.\n * @returns `true` when `ancestor` contains `node`.\n */\n contains(ancestor: Handle, node: Handle | null): boolean;\n\n /**\n * Finds the first descendant of `root` matching a selector.\n *\n * @param root - The subtree root handle.\n * @param selector - The CSS selector.\n * @returns The first match handle, or null.\n */\n querySelector(root: Handle, selector: string): Handle | null;\n\n /**\n * Finds all descendants of `root` matching a selector, as a plain array.\n *\n * @param root - The subtree root handle.\n * @param selector - The CSS selector.\n * @returns The match handles (a snapshot array, never a live `NodeList`).\n */\n querySelectorAll(root: Handle, selector: string): Handle[];\n\n /**\n * Whether an element itself matches a selector. The self-test counterpart to\n * {@link DOMSource.querySelector}, which only sees descendants — needed when\n * a component's own root element is the candidate (a `TextField` renders as\n * the `<input>` itself, with no focusable descendant to find).\n *\n * @param handle - The element to test.\n * @param selector - The CSS selector.\n * @returns `true` when the element matches.\n */\n matches(handle: Handle, selector: string): boolean;\n\n /**\n * Returns an element's parent element, or null.\n *\n * @param handle - The element to read.\n * @returns The parent element handle, or null.\n */\n getParentElement(handle: Handle): Handle | null;\n\n /**\n * Returns a node's parent node, or null.\n *\n * @param handle - The node to read.\n * @returns The parent node handle, or null.\n */\n getParentNode(handle: Handle): Handle | null;\n\n /**\n * Returns a node's first child, or null.\n *\n * @param handle - The node to read.\n * @returns The first child handle, or null.\n */\n getFirstChild(handle: Handle): Handle | null;\n\n /**\n * Returns an element's resolved border widths as computed-style strings\n * (e.g. `\"1px\"`), one per side.\n *\n * @param handle - The element to measure.\n * @returns The four border-width strings.\n */\n getBorderWidths(handle: Handle): { top: string; right: string; bottom: string; left: string };\n\n /**\n * Returns an element's resolved `overflow` / `overflow-x` / `overflow-y`\n * computed-style strings.\n *\n * @param handle - The element to read.\n * @returns The three overflow strings.\n */\n getComputedOverflow(handle: Handle): { overflow: string; overflowX: string; overflowY: string };\n\n /**\n * Reads a single inline style property off an element.\n *\n * @param handle - The element to read.\n * @param key - The CSS property name (camelCase, or `--custom-property`).\n * @returns The inline value (empty string when unset).\n */\n getInlineStyle(handle: Handle, key: string): string;\n\n /**\n * Returns the document's root `<html>` element — the mount point for\n * top-layer overlays.\n *\n * @returns The document element handle.\n */\n getDocumentElement(): Handle;\n\n /**\n * Returns the document `<body>` element.\n *\n * @returns The body element handle.\n */\n getBody(): Handle;\n\n /**\n * Returns the document `<head>` element.\n *\n * @returns The head element handle.\n */\n getHead(): Handle;\n\n /**\n * Registers a callback fired each time the document's web fonts finish a\n * batch of loading. Text whose preferred size was measured against a\n * fallback font before a `font-display: swap` web font swapped in must\n * re-measure once the real font is available, or its stale\n * (fallback-derived) size clips the now-wider glyphs. Offline sources\n * measure against baked fonts with no async swap, so they never invoke it.\n *\n * @param callback - Invoked whenever a batch of font loads settles; never\n * invoked on a document that loads no web fonts at all, since no\n * measurement can go stale there. Implementations must not fire it merely\n * because the font set is momentarily idle — see the production\n * implementation for why that is the trap this contract exists to avoid.\n */\n onFontsReady(callback: () => void): void;\n\n /**\n * Starts downloading and activating `family` now, rather than leaving the\n * fetch to be triggered by the first text that renders in it.\n *\n * An `@font-face` rule on its own downloads nothing: the browser fetches\n * and activates a face only once rendered content actually uses it, which\n * puts that work *after* the whole first layout instead of alongside it.\n * Starting it as soon as the rules are installed lets the face arrive while\n * the component tree is still being built.\n *\n * @param family - The `font-family` name to start loading, as it appears in\n * the `@font-face` rule.\n *\n * @returns `true` when an asynchronous load was actually started, so the\n * caller can expect {@link onFontsReady} to follow; `false` when this\n * source cannot load fonts asynchronously at all — an engine with no CSS\n * Font Loading API, or an offline source measuring against baked fonts.\n * A caller that defers work until the font settles must not defer on\n * `false`, or it would be waiting for a callback that never comes.\n *\n * @remarks Best-effort and fire-and-forget: a failed load is not an error\n * (the `font-display: swap` fallback stands, and {@link onFontsReady}\n * still settles the measurements).\n */\n startFontLoad(family: string): boolean;\n\n /**\n * Looks up an element by its `id`.\n *\n * @param id - The element id (no `#` prefix).\n * @returns The matching element handle, or null.\n */\n getElementById(id: string): Handle | null;\n\n /**\n * Reads an element's `id`.\n *\n * @param handle - The element to read.\n * @returns The element's id (empty string when unset).\n */\n getId(handle: Handle): string;\n\n /**\n * Reads a `data-*` attribute via the element's dataset.\n *\n * @param handle - The element to read.\n * @param key - The dataset key (camelCase).\n * @returns The value, or undefined when unset.\n */\n getDataset(handle: Handle, key: string): string | undefined;\n\n /**\n * Reads an element's tag name (uppercase).\n *\n * @param handle - The element to read.\n * @returns The tag name.\n */\n getTagName(handle: Handle): string;\n\n /**\n * Whether an element has a given attribute.\n *\n * @param handle - The element to test.\n * @param key - The attribute name.\n * @returns `true` when the attribute is present.\n */\n hasAttribute(handle: Handle, key: string): boolean;\n\n /**\n * Reads an attribute value.\n *\n * @param handle - The element to read.\n * @param key - The attribute name.\n * @returns The value, or null when unset.\n */\n getAttribute(handle: Handle, key: string): string | null;\n\n /**\n * Reads an image's intrinsic pixel size.\n *\n * @param handle - The image element.\n * @returns The natural `{width, height}` in pixels.\n */\n getNaturalSize(handle: Handle): { width: number; height: number };\n\n /**\n * Reads a media element's playback state in one shot as plain data.\n *\n * @param handle - The `<video>` / `<audio>` element handle.\n * @returns The element's {@link MediaState}.\n */\n getMediaState(handle: Handle): MediaState;\n\n /**\n * Returns the element currently displayed fullscreen, or `null` when nothing\n * is. Reads `document.fullscreenElement` behind the seam so no call site\n * names the global.\n *\n * @returns The fullscreen element handle, or `null`.\n */\n getFullscreenElement(): Handle | null;\n\n /**\n * Reads the selected files of a file input.\n *\n * @param handle - The file-input element.\n * @returns The selected `FileList`, or null.\n */\n getFiles(handle: Handle): FileList | null;\n\n /**\n * Whether an element currently holds a given pointer capture.\n *\n * @param handle - The element to test.\n * @param pointerId - The pointer id.\n * @returns `true` when the element captures the pointer.\n */\n hasPointerCapture(handle: Handle, pointerId: number): boolean;\n\n /**\n * Returns the stack of elements at a viewport point (hit-testing).\n *\n * @param x - The viewport x coordinate.\n * @param y - The viewport y coordinate.\n * @returns The element handles at the point, topmost first.\n */\n elementsFromPoint(x: number, y: number): Handle[];\n}\n\n/**\n * Seam-friendly result of {@link DOMSource.matchMedia}: the current match state\n * plus a change subscription, so the live `MediaQueryList` stays behind the seam.\n *\n * @category Core\n */\nexport interface MediaQueryResult {\n /** Whether the query currently matches. */\n matches: boolean;\n /**\n * Subscribes to match-state changes.\n *\n * @param handler - Called on each `change` of the query.\n */\n addChangeListener(handler: (event: MediaQueryListEvent) => void): void;\n}\n\n/**\n * Boxes a live `DOMRect` into a plain {@link Rect}, preserving every edge.\n */\nfunction toRect(domRect: DOMRect): Rect {\n return {\n x: domRect.x,\n y: domRect.y,\n width: domRect.width,\n height: domRect.height,\n top: domRect.top,\n left: domRect.left,\n right: domRect.right,\n bottom: domRect.bottom\n };\n}\n\n/**\n * Production {@link DOMSink}: every method is a one-line pass-through to the\n * native DOM, behaving bit-for-bit like the pre-seam direct writes.\n *\n * @category Core\n */\nexport class ProductionDOMSink implements DOMSink {\n /**\n * Timers scheduled through this sink that have not yet fired. Tracked so\n * `DOM.reset()` can disarm them: a pending `setTimeout` lives in the host's\n * scheduler, so discarding the sink object leaves it running.\n */\n private readonly _timers = new Set<TimerId>();\n\n /** Selector → rule for the sheet in `_indexedSheet`. Empty until first use. */\n private _ruleIndex: Map<string, CSSStyleRule> = new Map();\n\n /** The sheet `_ruleIndex` describes; `null` before the first build. */\n private _indexedSheet: CSSStyleSheet | null = null;\n\n /**\n * Applies a batch of mutations to one element with a single handle resolve.\n * The hot-path primitive — a layout commit (width + height + classes + an\n * attribute) costs one `Map.get`, not one per write.\n *\n * @param handle - The target element handle.\n * @param patch - The batch of mutations.\n */\n apply(handle: Handle, patch: ElementPatch): void {\n applyPatchTo(_registry.resolve(handle) as HTMLElement, patch);\n }\n\n /**\n * Fluent convenience that accumulates a patch and flushes it through a\n * single {@link ProductionDOMSink.apply}. For cold call sites — it allocates\n * one builder per edit.\n *\n * @param handle - The target element handle.\n * @returns A builder whose `commit()` performs the single resolve.\n */\n edit(handle: Handle): PatchBuilder {\n return new PatchBuilder((patch) => this.apply(handle, patch));\n }\n\n /**\n * Releases an owned (retained) handle at its element's dispose site.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void {\n _registry.release(handle);\n }\n\n /** @inheritDoc */\n setRuleStyles(rule: CSSStyleRule, styles: Record<string, string | null>): void {\n const keys = Object.keys(styles);\n\n if (keys.length === 0) {\n return;\n }\n\n const scratch = keys.length === 1 ? null : scratchDeclaration();\n\n // One declaration is already one mutation, and the headless path (no\n // document, so no scratch element) falls back to the same direct writes.\n if (!scratch) {\n for (const key of keys) {\n writeDeclaration(rule.style, key, styles[key]);\n }\n\n return;\n }\n\n scratch.cssText = rule.style.cssText;\n\n for (const key of keys) {\n writeDeclaration(scratch, key, styles[key]);\n }\n\n rule.style.cssText = scratch.cssText;\n }\n\n /** @inheritDoc */\n ensureStyleRule(selector: string): CSSStyleRule {\n const sheet = this.mainSheet();\n const index = this.ruleIndex(sheet);\n const cached = index.get(selector);\n\n if (cached) {\n return cached;\n }\n\n const insertedAt = sheet.insertRule(selector + \"{}\", sheet.cssRules.length);\n const rule = sheet.cssRules[insertedAt] as CSSStyleRule;\n\n index.set(selector, rule);\n\n return rule;\n }\n\n /** @inheritDoc */\n deleteStyleRule(selector: string): void {\n // Best-effort cleanup reached from the component GC finalizer, which runs\n // decoupled from the DOM lifecycle: at GC time this production sink may be\n // active in a headless environment (the node test env, or after a\n // DOM.reset()). With no document there is no shared sheet and nothing to\n // delete, so no-op rather than dereference `document` in `mainSheet()`.\n if (typeof document === \"undefined\") {\n return;\n }\n\n const sheet = this.mainSheet();\n const index = this.ruleIndex(sheet);\n const rule = index.get(selector);\n\n if (!rule) {\n return;\n }\n\n index.delete(selector);\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n if (sheet.cssRules[idx] === rule) {\n sheet.deleteRule(idx);\n return;\n }\n }\n }\n\n /** @inheritDoc */\n ensureKeyframes(name: string, body: string): void {\n const sheet = this.mainSheet();\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n const rule = sheet.cssRules[idx] as CSSKeyframesRule;\n\n if (rule.type === CSSRule.KEYFRAMES_RULE && rule.name === name) {\n return;\n }\n }\n\n sheet.insertRule('@keyframes ' + name + ' { ' + body + ' }', sheet.cssRules.length);\n }\n\n /**\n * Returns the selector → rule index for `sheet`, building it with one walk\n * of `cssRules` the first time this sheet is seen and reusing it on every\n * later call while `sheet` stays the same object. Building from the live\n * sheet — rather than starting empty — is what keeps a fresh sink (e.g.\n * after `DOM.reset()`, which replaces the sink but not the `<style\n * id=\"Base\">` element) honest about rules a previous sink already left on\n * it. Assumes a single writer: a second `ProductionDOMSink` concurrently\n * writing the same sheet would keep its own index and not see this one's\n * inserts.\n *\n * @param sheet - The sheet to index.\n */\n private ruleIndex(sheet: CSSStyleSheet): Map<string, CSSStyleRule> {\n if (this._indexedSheet === sheet) {\n return this._ruleIndex;\n }\n\n const index = new Map<string, CSSStyleRule>();\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n const rule = sheet.cssRules[idx];\n\n if (rule.type === CSSRule.STYLE_RULE) {\n index.set((rule as CSSStyleRule).selectorText, rule as CSSStyleRule);\n }\n }\n\n this._ruleIndex = index;\n this._indexedSheet = sheet;\n\n return index;\n }\n\n /**\n * Returns the framework's shared `<style id=\"Base\">` stylesheet, creating\n * the `<head>` and `<style>` element on first call. The lone place the\n * framework touches a `CSSStyleSheet` — relocated here from `StyleTarget`\n * so the stylesheet plumbing lives behind the seam.\n */\n private mainSheet(): CSSStyleSheet {\n let head = document.getElementsByTagName(\"head\")[0] as HTMLHeadElement;\n\n if (!head) {\n head = document.createElement(\"head\");\n document.appendChild(head);\n }\n\n let style: HTMLStyleElement | null = null;\n const styles = head.getElementsByTagName(\"style\");\n\n for (let idx = 0; idx < styles.length; idx += 1) {\n if (styles[idx].id === \"Base\") {\n style = styles[idx];\n }\n }\n\n if (!style) {\n style = document.createElement(\"style\");\n style.id = \"Base\";\n head.appendChild(style);\n }\n\n return style.sheet as CSSStyleSheet;\n }\n\n /** @inheritDoc */\n createElement(tag: string): Handle {\n return _registry.retain(document.createElement(tag));\n }\n\n /** @inheritDoc */\n createElementNS(ns: string, tag: string): Handle {\n return _registry.retain(document.createElementNS(ns, tag));\n }\n\n /** @inheritDoc */\n appendChild(parent: Handle, child: Handle): void {\n _registry.resolve(parent).appendChild(_registry.resolve(child));\n }\n\n /** @inheritDoc */\n removeChild(parent: Handle, child: Handle): void {\n _registry.resolve(parent).removeChild(_registry.resolve(child));\n }\n\n /** @inheritDoc */\n removeElement(handle: Handle): void {\n (_registry.resolve(handle) as Element).remove();\n }\n\n /** @inheritDoc */\n focus(handle: Handle, options?: { preventScroll?: boolean }): void {\n (_registry.resolve(handle) as HTMLElement).focus(options);\n }\n\n /** @inheritDoc */\n requestSubmit(handle: Handle): void {\n (_registry.resolve(handle) as HTMLFormElement).requestSubmit();\n }\n\n /** @inheritDoc */\n blur(handle: Handle): void {\n (_registry.resolve(handle) as HTMLElement).blur();\n }\n\n /** @inheritDoc */\n setValue(handle: Handle, value: string): void {\n (_registry.resolve(handle) as HTMLInputElement).value = value;\n }\n\n /** @inheritDoc */\n setSelectionRange(handle: Handle, start: number, end: number): void {\n (_registry.resolve(handle) as HTMLInputElement).setSelectionRange(start, end);\n }\n\n /** @inheritDoc */\n setLocationHash(hash: string): void {\n location.hash = hash;\n }\n\n /** @inheritDoc */\n replaceLocationHash(hash: string): void {\n const href = location.href;\n const hashIndex = href.indexOf('#');\n const base = hashIndex === -1 ? href : href.slice(0, hashIndex);\n\n location.replace(base + hash);\n }\n\n /** @inheritDoc */\n pushHistoryPath(url: string): void {\n history.pushState(null, \"\", url);\n }\n\n /** @inheritDoc */\n replaceHistoryPath(url: string): void {\n history.replaceState(null, \"\", url);\n }\n\n /** @inheritDoc */\n addListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | AddEventListenerOptions): void {\n _registry.resolve(target).addEventListener(type, handler as EventListener, options);\n }\n\n /** @inheritDoc */\n removeListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | EventListenerOptions): void {\n _registry.resolve(target).removeEventListener(type, handler as EventListener, options);\n }\n\n /** @inheritDoc */\n dispatchEvent(target: Handle, event: Event): void {\n _registry.resolve(target).dispatchEvent(event);\n }\n\n /** @inheritDoc */\n dispatchCustomEvent(target: Handle, type: string, init?: CustomEventInit): void {\n _registry.resolve(target).dispatchEvent(new CustomEvent(type, init));\n }\n\n /** @inheritDoc */\n requestAnimationFrame(callback: FrameRequestCallback): number {\n return requestAnimationFrame(callback);\n }\n\n /** @inheritDoc */\n cancelAnimationFrame(handle: number): void {\n cancelAnimationFrame(handle);\n }\n\n /** @inheritDoc */\n setTimeout(callback: () => void, delayMs: number): TimerId {\n const id = setTimeout(() => {\n this._timers.delete(id);\n callback();\n }, delayMs);\n\n this._timers.add(id);\n\n return id;\n }\n\n /** @inheritDoc */\n clearTimeout(id: TimerId): void {\n this._timers.delete(id);\n clearTimeout(id);\n }\n\n /** @inheritDoc */\n clearAllTimeouts(): void {\n for (const id of this._timers) {\n clearTimeout(id);\n }\n\n this._timers.clear();\n }\n\n /** @inheritDoc */\n setId(handle: Handle, id: string): void {\n (_registry.resolve(handle) as Element).id = id;\n }\n\n /** @inheritDoc */\n insertBefore(parent: Handle, node: Handle, reference: Handle | null): void {\n _registry.resolve(parent).insertBefore(\n _registry.resolve(node),\n reference === null ? null : _registry.resolve(reference)\n );\n }\n\n /** @inheritDoc */\n createDocumentFragment(): Handle {\n return _registry.retain(document.createDocumentFragment());\n }\n\n /** @inheritDoc */\n click(handle: Handle): void {\n (_registry.resolve(handle) as HTMLElement).click();\n }\n\n /** @inheritDoc */\n setPointerCapture(handle: Handle, pointerId: number): void {\n (_registry.resolve(handle) as Element).setPointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n releasePointerCapture(handle: Handle, pointerId: number): void {\n (_registry.resolve(handle) as Element).releasePointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n getContext(handle: Handle, contextId: string, options?: unknown): RenderingContext | null {\n return (_registry.resolve(handle) as HTMLCanvasElement).getContext(contextId, options);\n }\n\n /** @inheritDoc */\n mountView<T>(handle: Handle, factory: (parent: HTMLElement) => T): T | null {\n return factory(_registry.resolve(handle) as HTMLElement);\n }\n\n /** @inheritDoc */\n mediaPlay(handle: Handle): void {\n // The play() promise rejects on an autoplay-policy block; playback state\n // is observed through media events, so the promise is intentionally void.\n void (_registry.resolve(handle) as HTMLMediaElement).play().catch(() => {});\n }\n\n /** @inheritDoc */\n mediaPause(handle: Handle): void {\n (_registry.resolve(handle) as HTMLMediaElement).pause();\n }\n\n /** @inheritDoc */\n setCurrentTime(handle: Handle, seconds: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).currentTime = seconds;\n }\n\n /** @inheritDoc */\n setVolume(handle: Handle, value: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).volume = value;\n }\n\n /** @inheritDoc */\n setMuted(handle: Handle, muted: boolean): void {\n (_registry.resolve(handle) as HTMLMediaElement).muted = muted;\n }\n\n /** @inheritDoc */\n setPlaybackRate(handle: Handle, rate: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).playbackRate = rate;\n }\n\n /** @inheritDoc */\n requestFullscreen(handle: Handle): void {\n // The transition is observed through fullscreenchange; a rejected request\n // (no user gesture) is swallowed rather than surfaced as an unhandled reject.\n void (_registry.resolve(handle) as HTMLElement).requestFullscreen().catch(() => {});\n }\n\n /** @inheritDoc */\n exitFullscreen(): void {\n if (document.fullscreenElement) {\n void document.exitFullscreen().catch(() => {});\n }\n }\n}\n\n/**\n * Production {@link DOMSource}: reads the live DOM and delegates text\n * measurement to the existing {@link Util} canvas/probe code.\n *\n * @category Core\n */\nexport class ProductionDOMSource implements DOMSource {\n /**\n * Converts a raw browser node arriving at an event boundary into a (weak)\n * handle. The one place a raw target legitimately enters the seam from\n * outside — the event system hands it `evnt.target`, and the handle is\n * interned so no call site downstream holds the raw node.\n *\n * @param target - The browser-supplied event target.\n * @returns Its canonical handle.\n */\n intern(target: EventTarget): Handle {\n return _registry.intern(target as Node);\n }\n\n /** @inheritDoc */\n isNode(value: unknown): value is EventTarget {\n return value instanceof Node;\n }\n\n /** @inheritDoc */\n isElement(value: unknown): value is EventTarget {\n return value instanceof Element;\n }\n\n /** @inheritDoc */\n escapeSelector(value: string): string {\n // Real browsers always ship `CSS.escape`; guard for environments that\n // don't (jsdom, some SSR contexts) with an equivalent backslash escape\n // of every non-identifier character.\n if (typeof CSS !== \"undefined\" && typeof CSS.escape === \"function\") {\n return CSS.escape(value);\n }\n\n return value.replace(/[^\\w-]/g, ch => \"\\\\\" + ch);\n }\n\n /** @inheritDoc */\n getViewportRect(component: Component): Rect {\n return toRect((_registry.resolve(component.getElement()!) as HTMLElement).getBoundingClientRect());\n }\n\n /** @inheritDoc */\n getElementRect(handle: Handle): Rect {\n return toRect((_registry.resolve(handle) as Element).getBoundingClientRect());\n }\n\n /** @inheritDoc */\n measureText(text: string, options: TextMeasureOptions = {}): TextMetrics {\n const {\n fontFamily = \"var(--ts-ui-font-family, system-ui, sans-serif)\",\n fontSize = \"var(--ts-ui-font-size, 14px)\",\n fontWeight = \"normal\",\n fontStyle = \"normal\",\n fontVariant = \"normal\",\n fontStretch = \"normal\",\n lineHeight = \"calc(1em + var(--ts-ui-line-padding, 2px))\",\n maxWidth,\n } = options;\n\n const probe = document.createElement(\"span\");\n\n _applyProbeStyles(probe, {\n position: \"fixed\",\n visibility: \"hidden\",\n // With a wrap width the probe must honour `\\n` and soft-wrap so the\n // measured height covers every visual line; otherwise stay on a\n // single `nowrap` line for the natural-size measurement.\n whiteSpace: maxWidth === undefined ? \"nowrap\" : \"pre-wrap\",\n width: maxWidth === undefined ? \"\" : `${maxWidth}px`,\n fontFamily, fontSize, fontWeight, fontStyle, fontVariant, fontStretch, lineHeight,\n });\n\n probe.textContent = text;\n\n const ref = document.createElement(\"span\");\n\n _applyProbeStyles(ref, {\n display: \"inline-block\",\n width: \"0\",\n height: \"0\",\n verticalAlign: \"baseline\",\n });\n\n probe.appendChild(ref);\n document.body.appendChild(probe);\n\n const probeRect = probe.getBoundingClientRect();\n const refRect = ref.getBoundingClientRect();\n\n document.body.removeChild(probe);\n\n return {\n width: Math.ceil(probeRect.width),\n height: Math.ceil(probeRect.height),\n baseline: Math.round(refRect.top - probeRect.top),\n };\n }\n\n /** @inheritDoc */\n measureTextWidths(texts: string[], options: TextMeasureOptions = {}): number[] {\n if (texts.length === 0) {\n return [];\n }\n\n const {\n fontFamily = \"var(--ts-ui-font-family, system-ui, sans-serif)\",\n fontSize = \"var(--ts-ui-font-size, 14px)\",\n fontWeight = \"normal\",\n fontStyle = \"normal\",\n fontVariant = \"normal\",\n fontStretch = \"normal\",\n } = options;\n\n const wrapper = document.createElement(\"div\");\n\n _applyProbeStyles(wrapper, { position: \"fixed\", visibility: \"hidden\", whiteSpace: \"nowrap\" });\n\n const probes = texts.map(text => {\n const probe = document.createElement(\"span\");\n\n _applyProbeStyles(probe, {\n display: \"inline-block\", whiteSpace: \"nowrap\",\n fontFamily, fontSize, fontWeight, fontStyle, fontVariant, fontStretch,\n });\n\n probe.textContent = text;\n wrapper.appendChild(probe);\n\n return probe;\n });\n\n document.body.appendChild(wrapper);\n\n // One layout flush: the first read forces it, and nothing mutates the\n // DOM between reads, so the rest are served from the same computed layout.\n const widths = probes.map(p => Math.ceil(p.getBoundingClientRect().width));\n\n document.body.removeChild(wrapper);\n\n return widths;\n }\n\n /** @inheritDoc */\n resolveFontSizePx(fontSizeCSS: string): number {\n const probe = document.createElement(\"span\");\n\n _applyProbeStyles(probe, { position: \"fixed\", visibility: \"hidden\", fontSize: fontSizeCSS });\n\n document.body.appendChild(probe);\n const px = parseFloat(getComputedStyle(probe).fontSize);\n document.body.removeChild(probe);\n\n return isNaN(px) ? 14 : px; // 14 mirrors the base font fallback\n }\n\n /** @inheritDoc */\n measureFontMetrics(): { ascent: number; descent: number; capTop: number } {\n if (_metricsCtx === null) {\n _metricsCtx = document.createElement(\"canvas\").getContext(\"2d\");\n }\n\n const ctx = _metricsCtx as CanvasRenderingContext2D;\n\n // 14px / system-ui mirror the `--ts-ui-font-*` defaults shipped by the\n // themes; they only apply when the computed value is empty (pre-apply).\n const family = this.getThemeVar(\"--ts-ui-font-family\") || \"system-ui, sans-serif\";\n const size = this.getThemeVar(\"--ts-ui-font-size\") || \"14px\";\n\n ctx.font = `normal normal ${size} ${family}`;\n\n const m = ctx.measureText(\"X\");\n\n const hasFontBox = typeof m.fontBoundingBoxAscent === \"number\";\n const ascent = hasFontBox ? m.fontBoundingBoxAscent : m.actualBoundingBoxAscent;\n const descent = hasFontBox ? m.fontBoundingBoxDescent : m.actualBoundingBoxDescent;\n\n return { ascent, descent, capTop: m.actualBoundingBoxAscent };\n }\n\n /** @inheritDoc */\n getThemeVar(name: string): string {\n return getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n }\n\n /** @inheritDoc */\n getViewportSize(): Size {\n const width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\n const height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\n\n return { width, height };\n }\n\n /** @inheritDoc */\n getScrollBarWidth(): number {\n if (_scrollBarWidth >= 0) {\n return _scrollBarWidth;\n }\n\n const outer = document.createElement(\"div\");\n\n _applyProbeStyles(outer, {\n position: \"absolute\",\n top: \"-1000px\",\n left: \"-1000px\",\n width: \"100px\",\n height: \"50px\",\n overflow: \"hidden\",\n });\n\n const inner = document.createElement(\"div\");\n\n _applyProbeStyles(inner, { width: \"100%\", height: \"200px\" });\n\n outer.appendChild(inner);\n document.body.appendChild(outer);\n\n const widthNoScroll = inner.offsetWidth;\n\n _applyProbeStyles(outer, { overflow: \"auto\" });\n\n const widthScroll = inner.offsetWidth;\n\n document.body.removeChild(outer);\n\n _scrollBarWidth = widthNoScroll - widthScroll;\n\n return _scrollBarWidth;\n }\n\n /** @inheritDoc */\n getDevicePixelRatio(): number {\n return window.devicePixelRatio || 1;\n }\n\n /** @inheritDoc */\n isModelled(): boolean {\n return false;\n }\n\n /** @inheritDoc */\n getScrollLeft(handle: Handle): number {\n return (_registry.resolve(handle) as Element).scrollLeft;\n }\n\n /** @inheritDoc */\n getScrollTop(handle: Handle): number {\n return (_registry.resolve(handle) as Element).scrollTop;\n }\n\n /** @inheritDoc */\n getScrollMetrics(handle: Handle): ScrollMetrics {\n const element = _registry.resolve(handle) as Element;\n\n return {\n scrollTop: element.scrollTop,\n scrollLeft: element.scrollLeft,\n scrollWidth: element.scrollWidth,\n scrollHeight: element.scrollHeight,\n clientWidth: element.clientWidth,\n clientHeight: element.clientHeight\n };\n }\n\n /** @inheritDoc */\n getOffsetSize(handle: Handle): OffsetSize {\n const el = _registry.resolve(handle) as HTMLElement;\n\n return {\n offsetTop: el.offsetTop,\n offsetHeight: el.offsetHeight\n };\n }\n\n /** @inheritDoc */\n isConnected(handle: Handle): boolean {\n return (_registry.resolve(handle) as Element).isConnected;\n }\n\n /** @inheritDoc */\n getValue(handle: Handle): string {\n return (_registry.resolve(handle) as HTMLInputElement).value;\n }\n\n /** @inheritDoc */\n getActiveElement(): Handle | null {\n const active = document.activeElement;\n\n return active === null ? null : _registry.intern(active);\n }\n\n /** @inheritDoc */\n matchMedia(query: string): MediaQueryResult {\n // Non-browser environments (SSR, workers, bare Node) have no\n // `matchMedia`; degrade to an inert result so callers need no\n // environment guard of their own — the capability check lives here, in\n // the seam, rather than leaking a raw `window` probe into call sites.\n if (typeof matchMedia !== \"function\") {\n return { matches: false, addChangeListener: (): void => {} };\n }\n\n const mql = matchMedia(query);\n\n return {\n matches: mql.matches,\n addChangeListener(handler: (event: MediaQueryListEvent) => void): void {\n mql.addEventListener(\"change\", handler);\n }\n };\n }\n\n /** @inheritDoc */\n isWindow(target: Handle | null): boolean {\n return target !== null && _registry.resolve(target) === (window as unknown as Node);\n }\n\n /** @inheritDoc */\n getWindow(): Handle {\n return _registry.intern(window as unknown as Node);\n }\n\n /** @inheritDoc */\n getLocationHash(): string {\n return location.hash;\n }\n\n /** @inheritDoc */\n getLocationPathname(): string {\n return location.pathname;\n }\n\n /** @inheritDoc */\n contains(ancestor: Handle, node: Handle | null): boolean {\n return _registry.resolve(ancestor).contains(node === null ? null : _registry.resolve(node));\n }\n\n /** @inheritDoc */\n querySelector(root: Handle, selector: string): Handle | null {\n const found = (_registry.resolve(root) as ParentNode).querySelector(selector);\n\n return found === null ? null : _registry.intern(found);\n }\n\n /** @inheritDoc */\n querySelectorAll(root: Handle, selector: string): Handle[] {\n return Array.from((_registry.resolve(root) as ParentNode).querySelectorAll(selector), (node) => _registry.intern(node));\n }\n\n /** @inheritDoc */\n matches(handle: Handle, selector: string): boolean {\n return (_registry.resolve(handle) as Element).matches(selector);\n }\n\n /** @inheritDoc */\n getParentElement(handle: Handle): Handle | null {\n const parent = (_registry.resolve(handle) as Element).parentElement;\n\n return parent === null ? null : _registry.intern(parent);\n }\n\n /** @inheritDoc */\n getParentNode(handle: Handle): Handle | null {\n const parent = _registry.resolve(handle).parentNode;\n\n return parent === null ? null : _registry.intern(parent);\n }\n\n /** @inheritDoc */\n getFirstChild(handle: Handle): Handle | null {\n const child = _registry.resolve(handle).firstChild;\n\n return child === null ? null : _registry.intern(child);\n }\n\n /** @inheritDoc */\n getBorderWidths(handle: Handle): { top: string; right: string; bottom: string; left: string } {\n const cs = getComputedStyle(_registry.resolve(handle) as Element);\n\n return {\n top: cs.borderTopWidth,\n right: cs.borderRightWidth,\n bottom: cs.borderBottomWidth,\n left: cs.borderLeftWidth\n };\n }\n\n /** @inheritDoc */\n getComputedOverflow(handle: Handle): { overflow: string; overflowX: string; overflowY: string } {\n const cs = getComputedStyle(_registry.resolve(handle) as Element);\n\n return {\n overflow: cs.overflow,\n overflowX: cs.overflowX,\n overflowY: cs.overflowY\n };\n }\n\n /** @inheritDoc */\n getInlineStyle(handle: Handle, key: string): string {\n const style = (_registry.resolve(handle) as HTMLElement).style;\n\n if (key.includes(\"-\")) {\n return style.getPropertyValue(key);\n }\n\n return (style as any)[key];\n }\n\n /** @inheritDoc */\n getDocumentElement(): Handle {\n return _registry.intern(document.documentElement);\n }\n\n /** @inheritDoc */\n getBody(): Handle {\n return _registry.intern(document.body);\n }\n\n /** @inheritDoc */\n getHead(): Handle {\n return _registry.intern(document.head);\n }\n\n /** @inheritDoc */\n onFontsReady(callback: () => void): void {\n const fonts = document.fonts;\n\n // Older engines without the CSS Font Loading API: the fallback\n // measurement is the only one we get, so leave it standing.\n if (!fonts) {\n return;\n }\n\n // `loadingdone`, deliberately not `fonts.ready`: `ready` is a snapshot\n // of the set's *current* state, and the set is idle at the moment the\n // framework subscribes — `ensureFontLoaded` injected the `@font-face`\n // rules microseconds earlier and no text has been laid out with them\n // yet, so the browser has not begun fetching. A lone `ready.then`\n // therefore resolves on the very next microtask, hundreds of ms before\n // the real face arrives, and re-measures against the same fallback it\n // exists to replace. `loadingdone` fires once each batch of faces\n // settles (loaded or errored), so it catches the swap-in itself — and\n // any later batch, such as a second subset or a lazily used family.\n fonts.addEventListener('loadingdone', () => callback());\n }\n\n /** @inheritDoc */\n startFontLoad(family: string): boolean {\n const fonts = document.fonts;\n\n if (!fonts) {\n return false;\n }\n\n // `load` matches faces by the CSS font shorthand and by the characters\n // its second argument needs; the default (a single space) selects the\n // subset covering the Basic Latin range, which is the one virtually all\n // UI text renders from. Any further subset stays lazy and is picked up\n // by the `loadingdone` batch it settles in.\n //\n // The size in the shorthand is required syntax, not a constraint: one\n // variable face covers every size and the 200-800 weight range, so this\n // activates the same file the first laid-out text would have. A\n // rejection means the face is unavailable, which the `swap` fallback\n // already covers — swallow it rather than surfacing an unhandled\n // rejection for a purely opportunistic fetch.\n fonts.load(`14px \"${family}\"`).catch(() => {});\n\n return true;\n }\n\n /** @inheritDoc */\n getElementById(id: string): Handle | null {\n const found = document.getElementById(id);\n\n return found === null ? null : _registry.intern(found);\n }\n\n /** @inheritDoc */\n getId(handle: Handle): string {\n return (_registry.resolve(handle) as Element).id;\n }\n\n /** @inheritDoc */\n getDataset(handle: Handle, key: string): string | undefined {\n return (_registry.resolve(handle) as HTMLElement).dataset[key];\n }\n\n /** @inheritDoc */\n getTagName(handle: Handle): string {\n return (_registry.resolve(handle) as Element).tagName;\n }\n\n /** @inheritDoc */\n hasAttribute(handle: Handle, key: string): boolean {\n return (_registry.resolve(handle) as Element).hasAttribute(key);\n }\n\n /** @inheritDoc */\n getAttribute(handle: Handle, key: string): string | null {\n return (_registry.resolve(handle) as Element).getAttribute(key);\n }\n\n /** @inheritDoc */\n getNaturalSize(handle: Handle): { width: number; height: number } {\n const image = _registry.resolve(handle) as HTMLImageElement;\n\n return { width: image.naturalWidth, height: image.naturalHeight };\n }\n\n /** @inheritDoc */\n getMediaState(handle: Handle): MediaState {\n const media = _registry.resolve(handle) as HTMLMediaElement;\n\n return {\n currentTime: media.currentTime,\n duration: media.duration,\n paused: media.paused,\n ended: media.ended,\n volume: media.volume,\n muted: media.muted,\n playbackRate: media.playbackRate,\n };\n }\n\n /** @inheritDoc */\n getFullscreenElement(): Handle | null {\n const element = document.fullscreenElement;\n\n return element ? _registry.intern(element) : null;\n }\n\n /** @inheritDoc */\n getFiles(handle: Handle): FileList | null {\n return (_registry.resolve(handle) as HTMLInputElement).files;\n }\n\n /** @inheritDoc */\n hasPointerCapture(handle: Handle, pointerId: number): boolean {\n return (_registry.resolve(handle) as Element).hasPointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n elementsFromPoint(x: number, y: number): Handle[] {\n return Array.from(document.elementsFromPoint(x, y), (node) => _registry.intern(node));\n }\n}\n\n/**\n * The shape of the global {@link DOM} swap point.\n *\n * @category Core\n */\nexport interface DOMSeams {\n /** The active write seam. Defaults to a {@link ProductionDOMSink}. */\n sink: DOMSink;\n /** The active read seam. Defaults to a {@link ProductionDOMSource}. */\n source: DOMSource;\n /**\n * Swaps in test implementations. Omitted seams keep their current value.\n *\n * @param impls - The sink and/or source to install.\n */\n install(impls: { sink?: DOMSink; source?: DOMSource }): void;\n /** Restores the production implementations. */\n reset(): void;\n}\n\n/**\n * Global swap point for the DOM seams, mirroring `ThemeManager`'s active-theme\n * singleton. Production code reads {@link DOM.sink} / {@link DOM.source}; test\n * setup swaps them via {@link DOM.install} and restores via {@link DOM.reset}.\n *\n * @remarks A mutable-property `const` object rather than a `namespace` with\n * `export let`: the latter is not supported by the Oxc transformer the Vite\n * build uses. The binding is stable; the `sink` / `source` properties are the\n * swappable state.\n *\n * @category Core\n */\nexport const DOM: DOMSeams = {\n sink: new ProductionDOMSink(),\n source: new ProductionDOMSource(),\n\n install(impls: { sink?: DOMSink; source?: DOMSource }): void {\n if (impls.sink) {\n DOM.sink = impls.sink;\n }\n\n if (impls.source) {\n DOM.source = impls.source;\n }\n },\n\n reset(): void {\n // Disarm before anything is rebuilt. A pending timer lives in the host\n // scheduler and reads the *current* seams when it fires, so one left\n // armed here would run against the fresh registry with a handle minted\n // against the old one — the use-after-free `resolve` throws on.\n DOM.sink.clearAllTimeouts();\n\n // Rebuild the shared registry alongside the seams so a test never\n // resolves a handle minted against the previous DOM.\n _registry = new HandleRegistry();\n DOM.sink = new ProductionDOMSink();\n DOM.source = new ProductionDOMSource();\n },\n};\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-Ba8YRVel.js";import{t}from"./Position-PBVBW1JS.js";import{S as n,h as r,t as i}from"./Component-w65rPK75.js";import{a}from"./Tooltip-B_UF5bXD.js";import{t as o}from"./Text-CdHf3B-1.js";var s=a.Band.Window-1,DragFeedback=class extends i{_valid=!0;constructor(){super(),this.setPosition(t.ABSOLUTE),this.setZIndex(s),this.setPointerEvents(`none`),this.applyTintForValidity()}isValid(){return this._valid}setValid(e){this._valid!==e&&(this._valid=e,this.applyTintForValidity())}attachTo(t,n){let r=this.getElement(!0);if(n&&n!==t){this.setX(t.getX()),this.setY(t.getY()),this.setWidth(t.getWidth()),this.setHeight(t.getHeight());let i=n.getElement(!0);e.source.getParentElement(r)!==i&&e.sink.appendChild(i,r);return}this.setX(0),this.setY(0),this.setWidth(t.getWidth()),this.setHeight(t.getHeight());let i=t.getElement(!0);e.source.getParentElement(r)!==i&&e.sink.appendChild(i,r)}detach(){this.removeElement()}applyTintForValidity(){let e=this._valid?`valid`:`invalid`;this.setBackgroundColor(`var(--ts-ui-drag-feedback-${e}-bg)`),this.setBorder({border:`2px solid var(--ts-ui-drag-feedback-${e}-border)`})}},c=r(DragFeedback),l=10200,u=160,d=28,f=6,DragGhost=class extends i{_label=null;constructor(e,n,r){super(),this.setPosition(t.FIXED),this.setZIndex(l),this.setPointerEvents(`none`),this.setWidth(n??u),this.setHeight(r??d),this.setBackgroundColor(`var(--ts-ui-drag-ghost-bg)`),this.setBorder({border:`1px solid var(--ts-ui-drag-ghost-border)`}),this.setShadow(`var(--ts-ui-drag-ghost-shadow)`),this.setBorderRadius(`var(--ts-ui-border-radius, 4px)`),this.setOpacity(.85),e!==void 0&&(this._label=new o(e),this._label.setPointerEvents(`none`),this.addComponent(this._label))}moveTo(e,t){this.setX(e),this.setY(t)}show(){let t=this.getElement(!0);this.scheduleLayout(),e.sink.appendChild(e.source.getDocumentElement(),t)}hide(){this.removeElement()}doLayout(){super.doLayout();let e=this.getContentBounds();return this._label&&e&&(this._label.setX(e.x+f),this._label.setY(e.y+f),this._label.setWidth(e.width-12),this._label.setHeight(e.height-12)),this}},p=r(DragGhost),m=a.Band.Window-1,h=2,g=1,ReorderIndicator=class extends i{constructor(){super(),this.setPosition(t.ABSOLUTE),this.setZIndex(m),this.setPointerEvents(`none`),this.setHeight(h),this.setBackgroundColor(`var(--ts-ui-drag-reorder-color)`)}setInsertionY(e){this.setY(e-g)}attachTo(t){let n=t.getElement(!0),r=this.getElement(!0);this.setX(0),this.setWidth(t.getWidth()),e.source.getParentElement(r)!==n&&e.sink.appendChild(n,r)}detach(){this.removeElement()}},_=r(ReorderIndicator),v=new Map,y=1e3,b=12,x=12,S=new Map,C=new Map,w=null,T;(function(e){function makeDragSource(e,t){return S.set(e.getId(),{component:e,options:t}),e.addMouseDownSubtreeListener(onSourceMouseDown),tearDownDragSource.bind(null,e)}e.makeDragSource=makeDragSource;function makeDropTarget(e,t){return C.set(e.getId(),{component:e,options:t}),tearDownDropTarget.bind(null,e)}e.makeDropTarget=makeDropTarget;function isDragging(){return w!==null&&w.committed}e.isDragging=isDragging;function cancel(){w!==null&&endSession(!1,0,0)}e.cancel=cancel})(T||={});function resolveDragData(e){return typeof e.dragData==`function`?e.dragData():e.dragData}function tearDownDragSource(e){e.removeMouseDownSubtreeListener(onSourceMouseDown),S.delete(e.getId())}function tearDownDropTarget(e){C.delete(e.getId())}function onSourceMouseDown(t){if(w!==null||t.button!==0)return;let r=S.get(this.getId());if(!r)return;let i=r.component,a=r.options;w={source:i,sourceOptions:a,dragData:resolveDragData(a),startX:t.clientX,startY:t.clientY,committed:!1,ghost:null,feedback:null,indicator:null,currentTarget:null,previousBodyCursor:e.source.getInlineStyle(e.source.getBody(),`cursor`)},n.addViewportListener(i,`mousemove`,onMouseMove),n.addViewportListener(i,`mouseup`,onMouseUp)}function commitSession(t){t.committed=!0;let n=t.sourceOptions.ghostFactory?t.sourceOptions.ghostFactory(t.source,t.dragData):new p;if(t.ghost=n,t.feedback=new c,t.indicator=new _,typeof n.show==`function`)n.show();else{let t=n.getElement(!0);e.sink.appendChild(e.source.getDocumentElement(),t)}t.sourceOptions.cursor&&e.sink.apply(e.source.getBody(),{style:{cursor:t.sourceOptions.cursor}})}function buildDetail(e,t,n){return{dragData:e.dragData,sourceId:e.source.getId(),clientX:t,clientY:n}}function pickDropTarget(t,n){let r=e.source.elementsFromPoint(t,n);for(let t of r){let n=C.get(e.source.getId(t));if(n)return n}return null}function leaveCurrentTarget(e,t){if(e.currentTarget===null)return;let n=C.get(e.currentTarget.getId());n&&n.options.onDragLeave&&n.options.onDragLeave(t),e.feedback&&e.feedback.detach(),e.indicator&&e.indicator.detach(),e.currentTarget=null}function enterNewTarget(e,t,n){let r=t.options.accepts(n);if(e.feedback&&!t.options.suppressValidityTint&&(e.feedback.setValid(r),e.feedback.attachTo(t.component,t.options.feedbackHost)),!r){e.currentTarget=t.component;return}let i=t.options.onDragOver?.(n);typeof i==`number`&&e.indicator?(e.indicator.attachTo(t.component),e.indicator.setInsertionY(i)):e.indicator&&e.indicator.detach(),e.currentTarget=t.component}function onMouseMove(e){if(w===null)return;let t=w;if(!t.committed){let r=e.clientX-t.startX,i=e.clientY-t.startY;if(r*r+i*i<16)return!0;let a=buildDetail(t,e.clientX,e.clientY);if(t.sourceOptions.onDragStart?.(a)===!1)return endSession(!1,e.clientX,e.clientY),!0;commitSession(t),n.fireEvent(t.source,`dragstart`,{detail:a})}if(t.ghost){let n=t.ghost;typeof n.moveTo==`function`?n.moveTo(e.clientX+b,e.clientY+x):(t.ghost.setX(e.clientX+b),t.ghost.setY(e.clientY+x))}let r=buildDetail(t,e.clientX,e.clientY),i=pickDropTarget(e.clientX,e.clientY);if(i===null)return leaveCurrentTarget(t,r),!0;if(t.currentTarget!==i.component)return leaveCurrentTarget(t,r),enterNewTarget(t,i,r),!0;let a=i.options.accepts(r);if(t.feedback&&!i.options.suppressValidityTint&&t.feedback.setValid(a),!a)return t.indicator&&t.indicator.detach(),!0;let o=i.options.onDragOver?.(r);return typeof o==`number`&&t.indicator?(t.indicator.attachTo(i.component),t.indicator.setInsertionY(o)):t.indicator&&t.indicator.detach(),!0}function onMouseUp(e){if(w===null)return;let t=w,r=buildDetail(t,e.clientX,e.clientY),i=!1;if(t.committed&&t.currentTarget!==null){let e=C.get(t.currentTarget.getId());e&&(e.options.accepts(r)&&e.options.onDrop?.(r)!==!1&&n.fireEvent(t.source,`drop`,{detail:r}),i=!0)}return endSession(i,e.clientX,e.clientY),!0}function endSession(t,r,i){if(w===null)return;let a=w;if(n.removeViewportListener(a.source,`mousemove`,onMouseMove),n.removeViewportListener(a.source,`mouseup`,onMouseUp),a.feedback&&a.feedback.dispose(),a.indicator&&a.indicator.dispose(),a.ghost){if(a.sourceOptions.ghostFactory){let e=a.ghost;typeof e.hide==`function`?e.hide():a.ghost.removeElement()}else a.ghost.dispose()}if(a.sourceOptions.cursor&&e.sink.apply(e.source.getBody(),{style:{cursor:a.previousBodyCursor}}),a.committed){let e=buildDetail(a,r,i);n.fireEvent(a.source,`dragend`,{detail:e}),a.sourceOptions.onDragEnd?.(e,t)}w=null}export{p as a,_ as i,y as n,c as o,v as r,T as t};
2
- //# sourceMappingURL=DragManager-UvPHSoRm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DragManager-UvPHSoRm.js","names":[],"sources":["../../src/typescript/lib/overlay/DragFeedback.ts","../../src/typescript/lib/overlay/DragGhost.ts","../../src/typescript/lib/overlay/ReorderIndicator.ts","../../src/typescript/lib/overlay/DragManager.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Z-order for the drop-target validity tint. The tint highlights a drop target,\n * which lives in ordinary app content — so it must sit **below** the lowest\n * {@link LayerManager} band (the {@link Window} band) or it paints over a\n * floating window, while still sitting above the target's own content (app\n * z-indexes top out near 3). The app tree establishes no isolating stacking\n * context, so a higher value escapes to the root context and beats windows —\n * which is exactly the bug `Band.Window - 1` avoids. Shared rationale with\n * {@link ReorderIndicator}; the drag ghost sits above both at the root.\n */\nconst Z_INDEX = LayerManager.Band.Window - 1;\n\n/**\n * A validity tint overlay drawn on top of the row currently being hovered\n * during an active drag. The colour swaps between the `valid` and\n * `invalid` theme tokens via {@link setValid}; the geometry is mirrored\n * onto a drop target via {@link attachTo}.\n *\n * Owned by [`DragManager`](/api/overlay/variables/DragManager) — application\n * code does not instantiate this directly.\n *\n * @category Core\n */\nclass DragFeedback extends Component {\n\n private _valid: boolean = true;\n\n /**\n * Constructs a drag-feedback overlay. The overlay is not attached\n * until {@link attachTo} is called.\n */\n constructor() {\n super();\n\n this.setPosition(Position.ABSOLUTE);\n this.setZIndex(Z_INDEX);\n this.setPointerEvents(\"none\");\n\n this.applyTintForValidity();\n }\n\n /**\n * Returns whether the overlay is currently showing the \"valid drop\"\n * tint.\n *\n * @returns `true` for the valid tint, `false` for the invalid tint.\n */\n isValid(): boolean {\n return this._valid;\n }\n\n /**\n * Switches the overlay between the `valid` and `invalid` theme\n * tokens. Idempotent — repeated calls with the same value are a\n * no-op.\n *\n * @param valid - `true` to show the valid tint, `false` for invalid.\n */\n setValid(valid: boolean): void {\n if (this._valid === valid) {\n return;\n }\n\n this._valid = valid;\n\n this.applyTintForValidity();\n }\n\n /**\n * Sizes this overlay to cover the drop target and appends it to the DOM.\n *\n * With no `host`, the tint is a child of the target, covering its body. When\n * a `host` is given, the tint instead lives in that (non-scrolling) layer,\n * sized to the target's box within it — so a target that scrolls its own\n * content (a Tab strip's clip frame) gets a tint over the *viewport* that\n * stays put instead of riding the scroll.\n *\n * @param target - The drop target whose box the tint should cover.\n * @param host - Optional non-scrolling layer to host the tint (see\n * {@link DropTargetOptions.feedbackHost}). Defaults to the target.\n */\n attachTo(target: Component, host?: Component): void {\n const myEl = this.getElement(true)!;\n\n if (host && host !== target) {\n // Overlay the target's box from within the host layer.\n this.setX(target.getX());\n this.setY(target.getY());\n this.setWidth(target.getWidth());\n this.setHeight(target.getHeight());\n\n const hostEl = host.getElement(true)!;\n if (DOM.source.getParentElement(myEl) !== hostEl) {\n DOM.sink.appendChild(hostEl, myEl);\n }\n\n return;\n }\n\n // Cover the target's own body as a child of it.\n this.setX(0);\n this.setY(0);\n this.setWidth(target.getWidth());\n this.setHeight(target.getHeight());\n\n const targetEl = target.getElement(true)!;\n if (DOM.source.getParentElement(myEl) !== targetEl) {\n DOM.sink.appendChild(targetEl, myEl);\n }\n }\n\n /**\n * Removes the overlay element from the DOM.\n */\n detach(): void {\n this.removeElement();\n }\n\n /**\n * Writes the background and border CSS variables that correspond to\n * the cached validity state. Called from the constructor and from\n * {@link setValid} on transitions.\n */\n private applyTintForValidity(): void {\n const suffix = this._valid ? \"valid\" : \"invalid\";\n\n this.setBackgroundColor(`var(--ts-ui-drag-feedback-${suffix}-bg)`);\n this.setBorder({ border: `2px solid var(--ts-ui-drag-feedback-${suffix}-border)` });\n }\n}\n\nconst DragFeedbackCallable = callable(DragFeedback);\ntype DragFeedbackCallable = DragFeedback;\nexport {\n DragFeedback as _DragFeedback,\n DragFeedbackCallable as DragFeedback,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Z-order ceiling for the drag ghost. The follow-the-cursor preview rides above\n * everything during a drag — appended at the document root, above the\n * LayerManager bands — so it is never occluded by a floating window or by the\n * per-target highlights ([`DragFeedback`](/api/overlay/classes/DragFeedback) /\n * [`ReorderIndicator`](/api/overlay/classes/ReorderIndicator)), which deliberately\n * sit *below* the window band instead.\n */\nconst Z_INDEX = 10200;\n\n/**\n * Default ghost width when the caller omits an explicit size. Picked to\n * comfortably surround a one-line label without measuring text.\n */\nconst DEFAULT_WIDTH = 160;\n\n/** Default ghost height — one row's worth of vertical room. */\nconst DEFAULT_HEIGHT = 28;\n\n/**\n * Inner padding around the optional ghost label so text doesn't crowd the\n * border at the framework's default font size.\n */\nconst LABEL_INSET = 6;\n\n/**\n * A floating drag preview that follows the pointer during an active drag\n * session, drawn above every other overlay. Created and owned by\n * [`DragManager`](/api/overlay/variables/DragManager); application code does\n * not instantiate this directly.\n *\n * The ghost is `Position.FIXED` (one of the documented overlay carve-outs\n * in `ARCHITECTURE.md` §Positioning) and renders with\n * `pointer-events: none` so the manager's\n * `document.elementsFromPoint` hit-test always returns the row underneath.\n *\n * @category Core\n */\nclass DragGhost extends Component {\n\n private _label: Text | null = null;\n\n /**\n * Constructs a drag ghost. The caller positions it via\n * {@link moveTo} and toggles visibility through {@link show} /\n * {@link hide}.\n *\n * @param label - Optional text drawn inside the ghost.\n * @param width - Optional width in pixels (defaults to 160).\n * @param height - Optional height in pixels (defaults to 28).\n */\n constructor(label?: string, width?: number, height?: number) {\n super();\n\n this.setPosition(Position.FIXED);\n this.setZIndex(Z_INDEX);\n this.setPointerEvents(\"none\");\n this.setWidth(width ?? DEFAULT_WIDTH);\n this.setHeight(height ?? DEFAULT_HEIGHT);\n\n this.setBackgroundColor(\"var(--ts-ui-drag-ghost-bg)\");\n this.setBorder({ border: \"1px solid var(--ts-ui-drag-ghost-border)\" });\n this.setShadow(\"var(--ts-ui-drag-ghost-shadow)\");\n this.setBorderRadius(\"var(--ts-ui-border-radius, 4px)\");\n this.setOpacity(Number(\"0.85\"));\n\n if (label !== undefined) {\n this._label = new Text(label);\n this._label.setPointerEvents(\"none\");\n this.addComponent(this._label);\n }\n }\n\n /**\n * Repositions the ghost so its top-left corner sits at\n * `(clientX, clientY)`. `DragManager` calls this on every `mousemove`\n * during an active drag.\n *\n * @param clientX - The viewport X (already offset from the cursor by the manager).\n * @param clientY - The viewport Y (already offset from the cursor by the manager).\n */\n moveTo(clientX: number, clientY: number): void {\n this.setX(clientX);\n this.setY(clientY);\n }\n\n /**\n * Appends the ghost to `<html>` and schedules a layout pass. Used by\n * `DragManager` when a drag commits past the movement threshold.\n */\n show(): void {\n const el = this.getElement(true)!;\n\n this.scheduleLayout();\n DOM.sink.appendChild(DOM.source.getDocumentElement(), el);\n }\n\n /**\n * Removes the ghost element from the DOM. Used by `DragManager` on\n * mouseup / cancel.\n */\n hide(): void {\n this.removeElement();\n }\n\n /**\n * Lays out the optional label inside the ghost's content box.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const box = this.getContentBounds();\n\n if (this._label && box) {\n this._label.setX(box.x + LABEL_INSET);\n this._label.setY(box.y + LABEL_INSET);\n this._label.setWidth(box.width - LABEL_INSET * 2);\n this._label.setHeight(box.height - LABEL_INSET * 2);\n }\n\n return this;\n }\n}\n\nconst DragGhostCallable = callable(DragGhost);\ntype DragGhostCallable = DragGhost;\nexport {\n DragGhost as _DragGhost,\n DragGhostCallable as DragGhost,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Z-order shared with {@link DragFeedback}: just **below** the lowest\n * {@link LayerManager} band (the {@link Window} band) so this drop-target\n * insertion line — drawn over app content that establishes no isolating\n * stacking context — never paints over a floating window, while still sitting\n * above the target's own content. The drag ghost sits above both at the root.\n */\nconst Z_INDEX = LayerManager.Band.Window - 1;\n\n/** Height of the insertion-line bar in pixels. */\nconst BAR_HEIGHT = 2;\n\n/**\n * Half the bar height — subtracted in {@link ReorderIndicator.setInsertionY}\n * so the 2 px bar is centred on the insertion line.\n */\nconst BAR_HALF = 1;\n\n/**\n * A 2 px horizontal bar drawn between rows to mark the insertion line\n * during an active drag-reorder gesture.\n *\n * Reserved for future sibling-reorder work — drop-on-directory does not\n * use this overlay. The class ships now so the public API surface and\n * theme tokens stabilise alongside\n * [`DragGhost`](/api/overlay/classes/DragGhost) and\n * [`DragFeedback`](/api/overlay/classes/DragFeedback); the row-DnD wiring\n * in [`TreeTable`](/api/component/table/classes/TreeTable) only attaches\n * the feedback tint.\n *\n * @category Core\n */\nclass ReorderIndicator extends Component {\n\n /**\n * Constructs a reorder indicator. The bar is not attached until\n * {@link attachTo} is called.\n */\n constructor() {\n super();\n\n this.setPosition(Position.ABSOLUTE);\n this.setZIndex(Z_INDEX);\n this.setPointerEvents(\"none\");\n this.setHeight(BAR_HEIGHT);\n\n this.setBackgroundColor(\"var(--ts-ui-drag-reorder-color)\");\n }\n\n /**\n * Centres the bar on the given y-coordinate within the attached\n * target. The `- BAR_HALF` shift accounts for the 2 px bar height.\n *\n * @param y - Insertion-line y, measured from the target's top edge.\n */\n setInsertionY(y: number): void {\n this.setY(y - BAR_HALF);\n }\n\n /**\n * Mirrors the target's width onto the bar and appends the bar\n * element to the target.\n *\n * @param target - The drop target whose top-left coordinate space\n * the bar is positioned within.\n */\n attachTo(target: Component): void {\n const targetEl = target.getElement(true)!;\n const myEl = this.getElement(true)!;\n\n this.setX(0);\n this.setWidth(target.getWidth());\n\n if (DOM.source.getParentElement(myEl) === targetEl) {\n return;\n }\n\n DOM.sink.appendChild(targetEl, myEl);\n }\n\n /**\n * Removes the bar element from the DOM.\n */\n detach(): void {\n this.removeElement();\n }\n}\n\nconst ReorderIndicatorCallable = callable(ReorderIndicator);\ntype ReorderIndicatorCallable = ReorderIndicator;\nexport {\n ReorderIndicator as _ReorderIndicator,\n ReorderIndicatorCallable as ReorderIndicator,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { DragFeedback } from \"~/overlay/DragFeedback.js\";\nimport { DragGhost } from \"~/overlay/DragGhost.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ReorderIndicator } from \"~/overlay/ReorderIndicator.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Arbitrary, caller-defined payload attached to a drag source — the\n * shape is consumer-domain and the manager never inspects fields.\n *\n * @category Core\n */\nexport type DragData = Record<string, unknown>;\n\n/**\n * Payload delivered to every named drag-source / drop-target callback\n * and to every fired DOM event. Field names are stable across\n * `dragstart`, `dragover`, `dragleave`, `drop`, `dragend`.\n *\n * @category Core\n */\nexport interface DragEventDetail {\n /** The source's resolved drag data — read from the source options at session start. */\n dragData : DragData;\n /** The source component's id (`getId()`), useful for cycle / self-drop checks. */\n sourceId : string;\n /** Viewport-relative pointer X at the moment the event was raised. */\n clientX : number;\n /** Viewport-relative pointer Y at the moment the event was raised. */\n clientY : number;\n}\n\n/**\n * Drag-data payload attached to every tab-header drag — the cross-container\n * contract shared by the within-strip reorder path, tab tear-off / re-dock, the\n * Ctrl-drag window re-dock, and the downstream edge-split / dock-manager work.\n * A drop target reads it off {@link DragEventDetail}'s `dragData`. Because\n * {@link DragData} is a plain record it cannot carry a live component reference,\n * so `componentId` keys into the module-level `tabDragRegistry` to resolve the\n * dragged content.\n *\n * @category Core\n */\nexport interface TabDragData {\n /** Discriminator a drop target tests in its `accepts` predicate. */\n tabDrag: true;\n /** The source strip's stable id — distinguishes reorder-within from dock-from-elsewhere. */\n sourceTabId: string;\n /** The dragged content component's id — the key into `tabDragRegistry`. */\n componentId: string;\n /** The tab label — used for the drag ghost and the tear-off window title. */\n label: string;\n}\n\n/**\n * Resolves a {@link TabDragData} `componentId` back to the live content\n * component being dragged. Written when a header drag starts and cleared when it\n * ends, so a drop target — the same strip, another strip, or a torn-off\n * {@link DragData}-carrying window — can move the real component rather than\n * only learning its id. Shared by-import across `Tab` and `Window`; one\n * instance, so a source-side write is visible to the destination-side read.\n */\nexport const tabDragRegistry: Map<string, Component> = new Map<string, Component>();\n\n/**\n * Dwell, in milliseconds, before a tab held over a drop target spring-loads a\n * raise of that target's host window — surfacing a backgrounded float so the user\n * can aim the drop. Shared by the two dock drop surfaces so a region body\n * ([`DockRegion`](/api/layout/classes/DockRegion)) and a tab bar\n * ([`TabBar`](/api/component/container/classes/TabBar)) raise on the same cadence.\n *\n * Long enough that brushing a drag across a background window in transit does not\n * raise it, short enough that a deliberate hover surfaces the target. Set above a\n * `MenuItem` submenu's 150ms hover delay because raising a whole window is a\n * heavier, more disruptive action than opening a submenu, so it should demand a\n * clearly deliberate pause.\n */\nexport const SPRING_RAISE_DELAY_MS = 1000;\n\n/**\n * Construction-time options accepted by {@link DragManager.makeDragSource}.\n *\n * @category Core\n */\nexport interface DragSourceOptions {\n /** Static or factory-produced payload attached to the session. */\n dragData : DragData | (() => DragData);\n /**\n * Optional veto callback fired the moment the threshold is crossed.\n * Return `false` to abort the drag before any overlay is shown.\n */\n onDragStart? : (detail: DragEventDetail) => boolean | void;\n /**\n * Optional ghost factory. The returned component is used in place of\n * the manager's default ghost (which carries no label and matches the\n * source's size). The component must be detached when returned.\n */\n ghostFactory?: (source: Component, data: DragData) => Component;\n /** CSS cursor applied to `<body>` while the drag is active. */\n cursor? : string;\n /**\n * Fired once the gesture ends, after any `onDrop`. `dropped` is `true` when\n * the release was handled by a registered drop target — whether the target\n * accepted the drop or refused it — and `false` only on a release over empty\n * space. Lets a source distinguish a release that landed on a target from a\n * fall-through to empty space (e.g. tab tear-off), the signal the `\"dragend\"`\n * DOM event alone cannot carry.\n */\n onDragEnd? : (detail: DragEventDetail, dropped: boolean) => void;\n}\n\n/**\n * Construction-time options accepted by {@link DragManager.makeDropTarget}.\n *\n * @category Core\n */\nexport interface DropTargetOptions {\n /**\n * Validity predicate. Returns `true` when the dragged source may\n * drop on this target; the visual feedback tint mirrors the result.\n */\n accepts : (detail: DragEventDetail) => boolean;\n /**\n * Optional hover callback. Return a number to position the\n * [`ReorderIndicator`](/api/overlay/classes/ReorderIndicator) at the\n * given y inside the target; return `null` / `undefined` for no\n * reorder line.\n */\n onDragOver? : (detail: DragEventDetail) => number | null | void;\n /** Optional leave callback (cursor exits target's box). */\n onDragLeave? : (detail: DragEventDetail) => void;\n /** Optional drop callback — return `false` to suppress the `drop` event. */\n onDrop? : (detail: DragEventDetail) => boolean | void;\n /**\n * Suppresses the whole-target validity tint\n * ([`DragFeedback`](/api/overlay/classes/DragFeedback)) for this target. Pass it\n * when the target paints its own positional validity feedback (e.g. a\n * [`DockRegion`](/api/layout/classes/DockRegion) colours the drop *zone*\n * blue/red in `onDragOver`) so the two don't stack into a tinted frame *and*\n * a tinted zone. `accepts` still governs whether `onDragOver`/`onDrop` fire.\n */\n suppressValidityTint?: boolean;\n /**\n * Optional non-scrolling layer to host the validity tint, sized to the\n * target's box within it. Pass it when the target scrolls its own content\n * (e.g. a Tab strip's clip frame) so the tint overlays the *viewport* and\n * stays put instead of riding the scroll. Defaults to the target itself.\n */\n feedbackHost?: Component;\n}\n\ninterface DragSourceRecord {\n component: Component;\n options: DragSourceOptions;\n}\n\ninterface DropTargetRecord {\n component: Component;\n options: DropTargetOptions;\n}\n\ninterface DragSession {\n source: Component;\n sourceOptions: DragSourceOptions;\n dragData: DragData;\n startX: number;\n startY: number;\n committed: boolean;\n ghost: Component | null;\n feedback: DragFeedback | null;\n indicator: ReorderIndicator | null;\n currentTarget: Component | null;\n previousBodyCursor: string;\n}\n\n/**\n * Distance the cursor must travel between `mousedown` and `mousemove`\n * before the press-and-drag commits to a drag. The 4 px slop matches\n * the standard HIG threshold on Windows and macOS — anything shorter\n * fires a drag on plain clicks; anything longer feels unresponsive.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * Diagonal offsets applied to the ghost's top-left corner so the cursor\n * stays clear of the preview. Matches Finder / VS Code placement.\n */\nconst GHOST_OFFSET_X = 12;\nconst GHOST_OFFSET_Y = 12;\n\nconst dragSources = new Map<string, DragSourceRecord>();\nconst dropTargets = new Map<string, DropTargetRecord>();\nlet activeSession: DragSession | null = null;\n\n/**\n * Process-wide drag-and-drop coordinator. Maintains the global source /\n * target registry, owns the single active drag session, and\n * positions the three overlay components\n * ([`DragGhost`](/api/overlay/classes/DragGhost),\n * [`DragFeedback`](/api/overlay/classes/DragFeedback),\n * [`ReorderIndicator`](/api/overlay/classes/ReorderIndicator)) above the\n * page during a drag.\n *\n * Consumers register through the two factory functions and receive a\n * teardown closure to unwire when the source / target component goes\n * away. The manager itself fires no events directly — every callback\n * lives on the option bag the caller passed to the factory.\n *\n * @example\n * ```typescript\n * const tearDownSrc = DragManager.makeDragSource(row, {\n * dragData: () => ({ recordId: row.getRecord()?.get('id') }),\n * });\n * const tearDownTgt = DragManager.makeDropTarget(folder, {\n * accepts: (d) => d.dragData.recordId !== folder.getRecord()?.get('id'),\n * onDrop: (d) => moveRecord(d.dragData.recordId, folder),\n * });\n * ```\n *\n * @category Core\n */\nexport namespace DragManager {\n\n /**\n * Registers a component as a drag source. The component's mousedown\n * event begins a pending drag session that commits once the cursor\n * travels past the 4 px movement threshold.\n *\n * @param component - The source component.\n * @param options - Drag source configuration.\n *\n * @returns A teardown function that removes the source registration\n * and the mousedown listener.\n */\n export function makeDragSource(component: Component, options: DragSourceOptions): () => void {\n dragSources.set(component.getId(), { component, options });\n component.addMouseDownSubtreeListener(onSourceMouseDown);\n\n return tearDownDragSource.bind(null, component);\n }\n\n /**\n * Registers a component as a drop target. The component is queried\n * for `accepts` during every `mousemove` while a drag is active and\n * receives the configured callbacks at the appropriate phases.\n *\n * @param component - The drop target.\n * @param options - Drop target configuration.\n *\n * @returns A teardown function that removes the target registration.\n */\n export function makeDropTarget(component: Component, options: DropTargetOptions): () => void {\n dropTargets.set(component.getId(), { component, options });\n\n return tearDownDropTarget.bind(null, component);\n }\n\n /**\n * Returns whether a drag is currently in progress (committed past\n * the 4 px movement threshold).\n *\n * @returns `true` while the ghost is visible; `false` otherwise.\n */\n export function isDragging(): boolean {\n return activeSession !== null && activeSession.committed;\n }\n\n /**\n * Aborts an in-flight drag. Mirrors a `mouseup` outside any drop\n * target — no drop callback fires; the session tears down.\n */\n export function cancel(): void {\n if (activeSession === null) {\n return;\n }\n\n endSession(false, 0, 0);\n }\n}\n\n/**\n * Resolves the source's drag-data payload — accepts either a literal or\n * a factory function on every drag start so callers can carry per-row\n * state without re-registering the source.\n */\nfunction resolveDragData(options: DragSourceOptions): DragData {\n return typeof options.dragData === \"function\" ? options.dragData() : options.dragData;\n}\n\n/**\n * Removes the per-component mousedown listener and drops the source\n * record. Bound to `(component)` by `makeDragSource` so the returned\n * teardown closure stays a stable named-function reference.\n */\nfunction tearDownDragSource(component: Component): void {\n component.removeMouseDownSubtreeListener(onSourceMouseDown);\n dragSources.delete(component.getId());\n}\n\n/**\n * Drops the target record. Bound to `(component)` by\n * `makeDropTarget` so the returned teardown closure stays a stable\n * named-function reference.\n */\nfunction tearDownDropTarget(component: Component): void {\n dropTargets.delete(component.getId());\n}\n\n/**\n * Records the pending press and arms the viewport-level move / up\n * listeners. Nothing visual happens until the cursor crosses the\n * threshold.\n *\n * Registered as a subtree mousedown listener on every drag source, so\n * a press on any descendant of the source bubbles up the subtree\n * walker and the framework's Event router applies `component` as\n * `this` for the matching source — the lookup that identifies which\n * source was pressed.\n */\nfunction onSourceMouseDown(this: Component, e: MouseEvent): void {\n if (activeSession !== null) {\n return;\n }\n\n if (e.button !== 0) {\n return;\n }\n\n const record = dragSources.get(this.getId());\n\n if (!record) {\n return;\n }\n\n const source = record.component;\n const options = record.options;\n\n activeSession = {\n source,\n sourceOptions: options,\n dragData: resolveDragData(options),\n startX: e.clientX,\n startY: e.clientY,\n committed: false,\n ghost: null,\n feedback: null,\n indicator: null,\n currentTarget: null,\n previousBodyCursor: DOM.source.getInlineStyle(DOM.source.getBody(), \"cursor\"),\n };\n\n // Viewport listeners route through Event.baseViewportListener, which stops\n // mouseup propagation at window capture phase whenever any viewport\n // listener for the type exists. A raw document-level mouseup binding would\n // race SpinButton-class registrants that already pre-empt mouseup at\n // capture and never fire.\n Event.addViewportListener(source, \"mousemove\", onMouseMove);\n Event.addViewportListener(source, \"mouseup\", onMouseUp);\n}\n\n/**\n * Builds the session's three overlay components and writes the page-\n * wide cursor. Called once on the first mousemove that crosses the\n * threshold.\n */\nfunction commitSession(session: DragSession): void {\n session.committed = true;\n\n const ghost = session.sourceOptions.ghostFactory\n ? session.sourceOptions.ghostFactory(session.source, session.dragData)\n : new DragGhost();\n\n session.ghost = ghost;\n session.feedback = new DragFeedback();\n session.indicator = new ReorderIndicator();\n\n if (typeof (ghost as unknown as { show?: () => void }).show === \"function\") {\n (ghost as unknown as { show: () => void }).show();\n } else {\n const el = ghost.getElement(true)!;\n\n DOM.sink.appendChild(DOM.source.getDocumentElement(), el);\n }\n\n if (session.sourceOptions.cursor) {\n DOM.sink.apply(DOM.source.getBody(), { style: { cursor: session.sourceOptions.cursor } });\n }\n}\n\n/**\n * Builds the immutable detail payload threaded through every\n * source / target callback for the current pointer position.\n */\nfunction buildDetail(session: DragSession, clientX: number, clientY: number): DragEventDetail {\n return {\n dragData: session.dragData,\n sourceId: session.source.getId(),\n clientX,\n clientY,\n };\n}\n\n/**\n * Hit-tests under the ghost (which is pointer-events-none) and returns\n * the registered drop target whose element is the first match in the\n * z-stack, or `null` when no registered target sits under the cursor.\n */\nfunction pickDropTarget(clientX: number, clientY: number): DropTargetRecord | null {\n const stack = DOM.source.elementsFromPoint(clientX, clientY);\n\n for (const el of stack) {\n const record = dropTargets.get(DOM.source.getId(el));\n\n if (record) {\n return record;\n }\n }\n\n return null;\n}\n\n/**\n * Detaches the validity tint from the previous target and fires its\n * `onDragLeave`. No-op when there is no previous target.\n */\nfunction leaveCurrentTarget(session: DragSession, detail: DragEventDetail): void {\n if (session.currentTarget === null) {\n return;\n }\n\n const prev = dropTargets.get(session.currentTarget.getId());\n\n if (prev && prev.options.onDragLeave) {\n prev.options.onDragLeave(detail);\n }\n\n if (session.feedback) {\n session.feedback.detach();\n }\n\n if (session.indicator) {\n session.indicator.detach();\n }\n\n session.currentTarget = null;\n}\n\n/**\n * Attaches the validity tint to the new target, calls `onDragOver`\n * once, and positions the reorder indicator if the callback returned a\n * y value.\n */\nfunction enterNewTarget(session: DragSession, target: DropTargetRecord, detail: DragEventDetail): void {\n const accepted = target.options.accepts(detail);\n\n if (session.feedback && !target.options.suppressValidityTint) {\n session.feedback.setValid(accepted);\n session.feedback.attachTo(target.component, target.options.feedbackHost);\n }\n\n if (!accepted) {\n session.currentTarget = target.component;\n\n return;\n }\n\n const hint = target.options.onDragOver?.(detail);\n\n if (typeof hint === \"number\" && session.indicator) {\n session.indicator.attachTo(target.component);\n session.indicator.setInsertionY(hint);\n } else if (session.indicator) {\n session.indicator.detach();\n }\n\n session.currentTarget = target.component;\n}\n\n/**\n * Drives the active session forward each frame: commits past the\n * threshold, moves the ghost, hands target changes to the\n * enter / leave helpers, and re-runs `onDragOver` while the cursor stays\n * inside the same target.\n *\n * @returns `true` while a drag session is live, consuming the move so nothing else\n * tracks the pointer; nothing when there is no session, so the move keeps propagating.\n */\nfunction onMouseMove(e: MouseEvent): Event.ListenerResult {\n if (activeSession === null) {\n return;\n }\n\n const session = activeSession;\n\n if (!session.committed) {\n const dx = e.clientX - session.startX;\n const dy = e.clientY - session.startY;\n\n if (dx * dx + dy * dy < DRAG_THRESHOLD * DRAG_THRESHOLD) {\n return true;\n }\n\n const startDetail = buildDetail(session, e.clientX, e.clientY);\n\n if (session.sourceOptions.onDragStart?.(startDetail) === false) {\n endSession(false, e.clientX, e.clientY);\n\n return true;\n }\n\n commitSession(session);\n Event.fireEvent(session.source, \"dragstart\", { detail: startDetail });\n }\n\n if (session.ghost) {\n const dragGhost = session.ghost as unknown as { moveTo?: (x: number, y: number) => void };\n\n if (typeof dragGhost.moveTo === \"function\") {\n dragGhost.moveTo(e.clientX + GHOST_OFFSET_X, e.clientY + GHOST_OFFSET_Y);\n } else {\n session.ghost.setX(e.clientX + GHOST_OFFSET_X);\n session.ghost.setY(e.clientY + GHOST_OFFSET_Y);\n }\n }\n\n const detail = buildDetail(session, e.clientX, e.clientY);\n const target = pickDropTarget(e.clientX, e.clientY);\n\n if (target === null) {\n leaveCurrentTarget(session, detail);\n\n return true;\n }\n\n if (session.currentTarget !== target.component) {\n leaveCurrentTarget(session, detail);\n enterNewTarget(session, target, detail);\n\n return true;\n }\n\n // Same target as last frame — re-check accepts so the feedback\n // tint stays accurate (the validity of a drop can change as the\n // cursor moves within the same target, e.g. crossing into a\n // descendant region the source isn't allowed to land on). Skip\n // onDragOver / reorder indicator entirely while the drop is\n // rejected.\n const accepted = target.options.accepts(detail);\n\n if (session.feedback && !target.options.suppressValidityTint) {\n session.feedback.setValid(accepted);\n }\n\n if (!accepted) {\n if (session.indicator) {\n session.indicator.detach();\n }\n\n return true;\n }\n\n const hint = target.options.onDragOver?.(detail);\n\n if (typeof hint === \"number\" && session.indicator) {\n session.indicator.attachTo(target.component);\n session.indicator.setInsertionY(hint);\n } else if (session.indicator) {\n session.indicator.detach();\n }\n\n return true;\n}\n\n/**\n * Commits the drop (if any) and tears down the session.\n *\n * @returns `true` when a drag session was live, consuming the release that ends it;\n * nothing when there is no session, so the release keeps propagating.\n */\nfunction onMouseUp(e: MouseEvent): Event.ListenerResult {\n if (activeSession === null) {\n return;\n }\n\n const session = activeSession;\n const detail = buildDetail(session, e.clientX, e.clientY);\n let dropped = false;\n\n if (session.committed && session.currentTarget !== null) {\n const target = dropTargets.get(session.currentTarget.getId());\n\n if (target) {\n // Released over a registered drop target. Dispatch the drop only\n // when the target accepts; either way the release was *handled* by a\n // target rather than falling through to empty space, so report\n // `dropped` so the source skips its empty-space fallback — e.g. a Tab\n // header snaps back instead of tearing off into a window when the\n // target refused it (a rejected self-dock is a no-op, not a detach).\n if (target.options.accepts(detail)) {\n const onDropResult = target.options.onDrop?.(detail);\n\n if (onDropResult !== false) {\n Event.fireEvent(session.source, \"drop\", { detail });\n }\n }\n\n dropped = true;\n }\n }\n\n endSession(dropped, e.clientX, e.clientY);\n\n return true;\n}\n\n/**\n * Removes overlays, unwires viewport listeners, restores the body\n * cursor, and fires `dragend` when the session committed.\n */\nfunction endSession(dropped: boolean, clientX: number, clientY: number): void {\n if (activeSession === null) {\n return;\n }\n\n const session = activeSession;\n\n Event.removeViewportListener(session.source, \"mousemove\", onMouseMove);\n Event.removeViewportListener(session.source, \"mouseup\", onMouseUp);\n\n // The drag chrome is built fresh for every committed gesture in\n // `commitSession` and held only on the session record — none of it is\n // registered through `addComponent`, so `Component.destructor()`'s child\n // recursion can never reach it. Disposing, rather than only detaching,\n // is what reclaims each one's per-instance stylesheet rule before the\n // session reference is dropped; detaching alone grew the shared sheet by\n // one rule per drag, without bound.\n if (session.feedback) {\n session.feedback.dispose();\n }\n\n if (session.indicator) {\n session.indicator.dispose();\n }\n\n if (session.ghost) {\n if (session.sourceOptions.ghostFactory) {\n // A ghost from the caller's factory belongs to the caller, which\n // may hand back the same component on every gesture — so it is\n // detached, never disposed.\n const dragGhost = session.ghost as unknown as { hide?: () => void };\n\n if (typeof dragGhost.hide === \"function\") {\n dragGhost.hide();\n } else {\n session.ghost.removeElement();\n }\n } else {\n session.ghost.dispose();\n }\n }\n\n if (session.sourceOptions.cursor) {\n DOM.sink.apply(DOM.source.getBody(), { style: { cursor: session.previousBodyCursor } });\n }\n\n if (session.committed) {\n const detail = buildDetail(session, clientX, clientY);\n\n Event.fireEvent(session.source, \"dragend\", { detail });\n session.sourceOptions.onDragEnd?.(detail, dropped);\n }\n\n activeSession = null;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Grid-BYBohJIA.js","names":[],"sources":["../../src/typescript/lib/layout/Grid.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 { GridTrack } from \"~/layout/GridTrack.js\";\nimport { GridConstraints } from \"~/layout/GridConstraints.js\";\nimport { Size, UNBOUNDED, isUnbounded, saturate } from \"~/primitive/Size.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Grid}.\n *\n * @category Layouts\n */\nexport interface GridOptions extends LayoutManagerOptions {\n rows?: number;\n columns?: number;\n spacing?: number;\n\n /** Grid-wide fill applied to children that don't set their own `fill`. Default {@link FillType.BOTH}. */\n defaultFill?: FillType;\n\n /** Grid-wide anchor applied to non-filling children that don't set their own `anchor`. Default {@link AnchorType.CENTER}. */\n defaultAnchor?: AnchorType;\n\n /** When `true`, children are baseline-aligned per row (column/row tracks still apply; children use preferred height). Default `false`. */\n baselineAlign?: boolean;\n\n /** Per-column sizing tracks; see {@link GridTrack}. */\n columnTracks?: GridTrack[];\n\n /** Per-row sizing tracks; see {@link GridTrack}. */\n rowTracks?: GridTrack[];\n}\n\n/**\n * A layout manager that tiles children in a uniform grid of equal-sized cells.\n * Row and column counts can be configured explicitly or left at `0` for auto-calculation.\n *\n * @category Layouts\n */\nclass Grid extends LayoutManager {\n\n private _rows: number = 0;\n private _columns: number = 0;\n private _spacing: number = 5;\n private _defaultFill: FillType = FillType.BOTH;\n private _defaultAnchor: AnchorType = AnchorType.CENTER;\n private _baselineAlign: boolean = false;\n private _columnTracks: GridTrack[] = [];\n private _rowTracks: GridTrack[] = [];\n\n constructor(options?: GridOptions) {\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 GridOptions} bag, dispatching grid dimensions, spacing,\n * default fill/anchor, and baseline alignment after the inherited\n * LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: GridOptions): void {\n super.applyOptions(options);\n\n if (options.rows !== undefined) {\n this.setRows(options.rows);\n }\n\n if (options.columns !== undefined) {\n this.setColumns(options.columns);\n }\n\n if (options.spacing !== undefined) {\n this.setComponentSpacing(options.spacing);\n }\n\n if (options.defaultFill !== undefined) {\n this.setDefaultFill(options.defaultFill);\n }\n\n if (options.defaultAnchor !== undefined) {\n this.setDefaultAnchor(options.defaultAnchor);\n }\n\n if (options.baselineAlign !== undefined) {\n this.setBaselineAlign(options.baselineAlign);\n }\n\n if (options.columnTracks !== undefined) {\n this.setColumnTracks(options.columnTracks);\n }\n\n if (options.rowTracks !== undefined) {\n this.setRowTracks(options.rowTracks);\n }\n }\n\n /**\n * Returns the grid-wide default fill applied to children that don't set\n * their own `fill` constraint.\n *\n * @returns The default {@link FillType} (initially {@link FillType.BOTH}).\n */\n getDefaultFill(): FillType {\n return this._defaultFill;\n }\n\n /**\n * Sets the grid-wide default fill. Each child overrides this with its own\n * {@link GridConstraints} `fill`; otherwise this value drives whether the\n * child fills its cell.\n *\n * @param fill - The default fill strategy for children without their own `fill`.\n */\n setDefaultFill(fill: FillType): this {\n this._defaultFill = fill;\n\n return this;\n }\n\n /**\n * Returns the grid-wide default anchor applied to non-filling children that\n * don't set their own `anchor` constraint.\n *\n * @returns The default {@link AnchorType} (initially {@link AnchorType.CENTER}).\n */\n getDefaultAnchor(): AnchorType {\n return this._defaultAnchor;\n }\n\n /**\n * Sets the grid-wide default anchor. Each child overrides this with its own\n * {@link GridConstraints} `anchor`; otherwise this value positions a\n * non-filling child within its cell.\n *\n * @param anchor - The default anchor for children without their own `anchor`.\n */\n setDefaultAnchor(anchor: AnchorType): this {\n this._defaultAnchor = anchor;\n\n return this;\n }\n\n /**\n * Returns whether children are baseline-aligned per row.\n *\n * @returns `true` if per-row baseline alignment is enabled.\n */\n isBaselineAlign(): boolean {\n return this._baselineAlign;\n }\n\n /**\n * Sets whether children are baseline-aligned per row. When `true`, the\n * column/row tracks still size each cell (so a `\"content\"` column hugs its\n * content), each row uses the natural heights of its children, and\n * components are baseline-aligned within the row, mirroring\n * [`HBox`](/api/layout/classes/HBox)'s baseline-aware placement. Orthogonal\n * to {@link Grid.setDefaultFill} — baseline alignment owns the vertical axis\n * while fill/anchor still drive the horizontal axis.\n *\n * @param baselineAlign - Pass `true` to enable per-row baseline alignment.\n */\n setBaselineAlign(baselineAlign: boolean): this {\n this._baselineAlign = baselineAlign;\n\n return this;\n }\n\n /**\n * Returns the configured number of rows, or `0` if the grid auto-calculates row count.\n *\n * @returns The row count.\n */\n getRows() {\n return this._rows;\n }\n\n /**\n * Sets the number of rows. Pass `0` to let the grid auto-calculate.\n *\n * @param rows - The desired row count, or `0` for automatic.\n */\n setRows(rows: number) : this {\n this._rows = rows;\n\n return this;\n }\n\n /**\n * Returns the gap, in pixels, between adjacent cells (horizontally and vertically).\n *\n * @returns The current spacing in pixels.\n */\n getComponentSpacing() {\n return this._spacing || 0;\n }\n\n /**\n * Sets the gap, in pixels, between adjacent cells. Applied both horizontally\n * (between columns) and vertically (between rows).\n *\n * @param spacing - Spacing in pixels. Falsy values are treated as `0`.\n */\n setComponentSpacing(spacing: number) : this {\n this._spacing = spacing || 0;\n\n return this;\n }\n\n /**\n * Returns the configured number of columns, or `0` if the grid auto-calculates column count.\n *\n * @returns The column count.\n */\n getColumns() {\n return this._columns;\n }\n\n /**\n * Sets the number of columns. Pass `0` to let the grid auto-calculate.\n *\n * @param columns - The desired column count, or `0` for automatic.\n */\n setColumns(columns: number) : this {\n this._columns = columns;\n\n return this;\n }\n\n /**\n * Returns the per-column sizing tracks.\n *\n * @returns The configured column tracks; empty when columns size uniformly.\n */\n getColumnTracks(): GridTrack[] {\n return this._columnTracks;\n }\n\n /**\n * Sets the per-column sizing tracks. When fewer tracks are supplied than the\n * grid has columns, the missing tracks default to `{ mode: \"weight\", value: 1 }`.\n *\n * @param tracks - The column tracks; see {@link GridTrack}.\n */\n setColumnTracks(tracks: GridTrack[]): this {\n this._columnTracks = tracks;\n\n return this;\n }\n\n /**\n * Returns the per-row sizing tracks.\n *\n * @returns The configured row tracks; empty when rows size uniformly.\n */\n getRowTracks(): GridTrack[] {\n return this._rowTracks;\n }\n\n /**\n * Sets the per-row sizing tracks. When fewer tracks are supplied than the\n * grid has rows, the missing tracks default to `{ mode: \"weight\", value: 1 }`.\n *\n * @param tracks - The row tracks; see {@link GridTrack}.\n */\n setRowTracks(tracks: GridTrack[]): this {\n this._rowTracks = tracks;\n\n return this;\n }\n\n /**\n * Returns the computed cell count for the current component list as `{width: rows, height: columns}`.\n *\n * @returns An object with `width` (row count) and `height` (column count), or `undefined` if no container is attached.\n *\n * @remarks The property names `width` and `height` are repurposed here to\n * carry column and row counts rather than pixel dimensions —\n * `result.width` is the column count, `result.height` is the row count.\n */\n getColRowCount() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n let components = container.getLaidOutComponents();\n let componentCount = components.length;\n\n let rows = 0;\n let columns = 0;\n\n if (!this._rows && !this._columns) {\n columns = Math.floor(Math.sqrt(componentCount));\n rows = Math.ceil(componentCount / columns);\n } else if (this._rows && this._columns) {\n rows = this._rows;\n columns = this._columns;\n } else if (this._columns) {\n columns = this._columns;\n rows = Math.ceil(componentCount / columns);\n } else {\n rows = this._rows;\n columns = Math.ceil(componentCount / rows);\n }\n\n return {\n width: columns,\n height: rows\n };\n }\n\n /**\n * Returns the preferred size. With tracks declared, this is the sum of the\n * per-track preferred extents (fixed tracks their value, content *and*\n * weight tracks their measured content — wide/tall enough to show every\n * cell at its natural size) plus spacing. Track-less grids keep the uniform\n * `maxChildPreferred * count` estimate.\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\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let components = container.getLaidOutComponents();\n\n let maxCellWidth = 0;\n let maxCellHeight = 0;\n\n for (const component of components) {\n let size = component.getPreferredSize();\n\n if (size) {\n maxCellWidth = Math.max(maxCellWidth, size.width);\n maxCellHeight = Math.max(maxCellHeight, size.height);\n }\n }\n\n let colRowCount = this.getColRowCount();\n let cols = colRowCount ? colRowCount.width : 1;\n let rows = colRowCount ? colRowCount.height : 1;\n let spacing = this.getComponentSpacing();\n\n const content = this.measureContent(components, cols, rows);\n\n let innerWidth = this._columnTracks.length > 0\n ? this.trackAxisExtent(this._columnTracks, cols, content.columns, true)\n : maxCellWidth * cols;\n\n let innerHeight = this._rowTracks.length > 0\n ? this.trackAxisExtent(this._rowTracks, rows, content.rows, true)\n : maxCellHeight * rows;\n\n innerWidth += Math.max(0, cols - 1) * spacing;\n innerHeight += Math.max(0, rows - 1) * spacing;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Returns the minimum size. With tracks declared, this is the sum of the\n * per-track minima (fixed tracks their value, content tracks their measured\n * content, weight tracks `0`) plus spacing — matching what `doLayout`\n * actually lays out, so a host no longer over-reserves space the way the\n * uniform `maxChildMin * count` estimate did. Track-less grids keep that\n * uniform estimate.\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\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let components = container.getLaidOutComponents();\n\n let maxCellWidth = 0;\n let maxCellHeight = 0;\n\n for (const component of components) {\n let size = component.getMinSize();\n\n if (size) {\n maxCellWidth = Math.max(maxCellWidth, size.width);\n maxCellHeight = Math.max(maxCellHeight, size.height);\n }\n }\n\n let colRowCount = this.getColRowCount();\n let cols = colRowCount ? colRowCount.width : 1;\n let rows = colRowCount ? colRowCount.height : 1;\n let spacing = this.getComponentSpacing();\n\n const content = this.measureContent(components, cols, rows);\n\n let innerWidth = this._columnTracks.length > 0\n ? this.trackAxisExtent(this._columnTracks, cols, content.columns, false)\n : maxCellWidth * cols;\n\n let innerHeight = this._rowTracks.length > 0\n ? this.trackAxisExtent(this._rowTracks, rows, content.rows, false)\n : maxCellHeight * rows;\n\n innerWidth += Math.max(0, cols - 1) * spacing;\n innerHeight += Math.max(0, rows - 1) * spacing;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Returns the maximum size the grid can usefully occupy: the sum of the\n * per-track maxima plus inter-cell spacing and the container perimeter. A\n * `fixed` track contributes its pixel value, a `content` track its measured\n * content, and a `weight` track is unbounded — so any weight track makes the\n * whole axis unbounded (the grid can absorb arbitrary slack there). With no\n * tracks on an axis the fallback is `cols * maxChildMax` (the uniform-cell\n * estimate), where a child's `null`/sentinel maximum counts as unbounded.\n *\n * @returns The maximum `{width, height}`, or `null` if no container is attached.\n */\n getMaxSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let components = container.getLaidOutComponents();\n\n let colRowCount = this.getColRowCount();\n let cols = colRowCount ? colRowCount.width : 1;\n let rows = colRowCount ? colRowCount.height : 1;\n let spacing = this.getComponentSpacing();\n\n const content = this.measureContent(components, cols, rows);\n\n const innerWidth = this._columnTracks.length > 0\n ? this.trackAxisMax(this._columnTracks, cols, content.columns)\n : cols * this.maxChildExtent(components, true);\n\n const innerHeight = this._rowTracks.length > 0\n ? this.trackAxisMax(this._rowTracks, rows, content.rows)\n : rows * this.maxChildExtent(components, false);\n\n return {\n width: saturate(innerWidth + Math.max(0, cols - 1) * spacing + outerWidth),\n height: saturate(innerHeight + Math.max(0, rows - 1) * spacing + outerHeight)\n };\n }\n\n /**\n * Sums the per-track maxima along one axis: a `fixed` track contributes its\n * pixel value, a `content` track its measured content size, and a `weight`\n * track is unbounded — the first weight track saturates the axis to the\n * unbounded sentinel, since a flex track can grow without limit. A\n * missing track defaults to `weight`, matching {@link trackAxisExtent}.\n *\n * @param tracks - The declared tracks for this axis.\n * @param count - The number of columns (or rows) to size.\n * @param contentSizes - Measured content maxima per track.\n * @returns The summed maximum extent for the axis, excluding spacing.\n */\n private trackAxisMax(tracks: GridTrack[], count: number, contentSizes: number[]): number {\n let total = 0;\n\n for (let i = 0; i < count; i += 1) {\n const track = tracks[i] ?? { mode: \"weight\" as const, value: 1 };\n\n if (track.mode === \"fixed\") {\n total += track.value ?? 0;\n } else if (track.mode === \"content\") {\n total += contentSizes[i] ?? 0;\n } else {\n return UNBOUNDED;\n }\n }\n\n return total;\n }\n\n /**\n * Returns the largest per-child maximum extent across all children on one\n * axis, for the uniform-cell (no-track) fallback. A child whose maximum is\n * `null` or at the unbounded sentinel makes the whole axis unbounded, so the\n * result saturates to the unbounded sentinel.\n *\n * @param components - The grid's children.\n * @param horizontal - `true` to read each child's max width, `false` for height.\n * @returns The largest child maximum, or the unbounded sentinel when any\n * child is unbounded.\n */\n private maxChildExtent(components: Component[], horizontal: boolean): number {\n let largest = 0;\n\n for (const component of components) {\n const max = component.getMaxSize();\n\n if (!max) {\n return UNBOUNDED;\n }\n\n const extent = horizontal ? max.width : max.height;\n\n if (isUnbounded(extent)) {\n return UNBOUNDED;\n }\n\n largest = Math.max(largest, extent);\n }\n\n return largest;\n }\n\n /**\n * Computes the children's combined minSize along this manager's geometry:\n * width is `cols * maxChildMinWidth + (cols-1) * spacing`; height is\n * `rows * maxChildMinHeight + (rows-1) * spacing`. Used by `doLayout` to\n * inflate the working size when the host has opted into `setOverflowing`.\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 const colRowCount = this.getColRowCount();\n const cols = colRowCount ? colRowCount.width : 1;\n const rows = colRowCount ? colRowCount.height : 1;\n const spacing = this.getComponentSpacing();\n\n let maxCellWidth = 0;\n let maxCellHeight = 0;\n\n for (const component of components) {\n const min = component.getMinSize();\n if (min) {\n maxCellWidth = Math.max(maxCellWidth, min.width);\n maxCellHeight = Math.max(maxCellHeight, min.height);\n }\n }\n\n const content = this.measureContent(components, cols, rows);\n\n // When tracks are declared, the axis minimum is the sum of per-track\n // minima — a `fixed` track needs its fixed value, a `content` track its\n // measured content, and a `weight` track nothing (it flexes to fill\n // slack and clips oversized children, so it imposes no intrinsic floor).\n // This keeps a child that the grid is meant to *clip* (e.g. an oversized\n // child in a fixed column) from inflating the whole grid's min width.\n // With no tracks on an axis, fall back to the uniform `maxChild*count`\n // estimate so non-track grids still drive universal scroll unchanged.\n const widthMin = this._columnTracks.length > 0\n ? this.trackAxisExtent(this._columnTracks, cols, content.columns, false)\n : cols * maxCellWidth;\n\n const heightMin = this._rowTracks.length > 0\n ? this.trackAxisExtent(this._rowTracks, rows, content.rows, false)\n : rows * maxCellHeight;\n\n return {\n width: widthMin + Math.max(0, cols - 1) * spacing,\n height: heightMin + Math.max(0, rows - 1) * spacing,\n };\n }\n\n /**\n * Sums the per-track extents along one axis: a `fixed` track contributes its\n * pixel value and a `content` track its measured content size. A `weight`\n * track contributes its measured content when `includeWeightContent` is\n * `true` (the *preferred* extent — wide enough to show its content at\n * natural size) and `0` otherwise (the *minimum* extent — a flex track can\n * shrink to nothing). A missing track (when the list is shorter than\n * `count`) defaults to `weight`, matching `resolveTracks`' weight default.\n *\n * @param tracks - The declared tracks for this axis.\n * @param count - The number of columns (or rows) to size.\n * @param contentSizes - Measured content maxima per track.\n * @param includeWeightContent - Whether weight tracks contribute their\n * measured content (preferred extent) rather than `0` (minimum extent).\n * @returns The summed extent for the axis, excluding spacing.\n */\n private trackAxisExtent(tracks: GridTrack[], count: number, contentSizes: number[], includeWeightContent: boolean): number {\n let total = 0;\n\n for (let i = 0; i < count; i += 1) {\n const track = tracks[i] ?? { mode: \"weight\" as const, value: 1 };\n\n if (track.mode === \"fixed\") {\n total += track.value ?? 0;\n } else if (track.mode === \"content\") {\n total += contentSizes[i] ?? 0;\n } else if (includeWeightContent) {\n total += contentSizes[i] ?? 0;\n }\n }\n\n return total;\n }\n\n /**\n * Tiles all children in a grid of equal-sized cells, left-to-right then top-to-bottom.\n *\n * @remarks Each cell is sized by the column/row tracks; how a child sits\n * inside its cell is driven by the child's own `fill`/`anchor`\n * ([`GridConstraints`](/api/layout/classes/GridConstraints)) falling back to\n * the grid's {@link Grid.setDefaultFill}/{@link Grid.setDefaultAnchor}\n * (default {@link FillType.BOTH}, so children fill their cells out of the\n * box). When {@link Grid.setBaselineAlign} is enabled, the column/row tracks\n * still size each cell (a `\"content\"` column hugs its content), each row\n * uses the natural heights of its children, and components are\n * baseline-aligned within their row, mirroring\n * [`HBox`](/api/layout/classes/HBox)'s baseline-aware placement. Baseline\n * mode auto-flows by `colSpan`; explicit `col`/`row` and `rowSpan > 1` are\n * not supported.\n */\n doLayout() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n let components = container.getLaidOutComponents();\n let containerInsets = container.getContentInsets();\n let containerSize = container.getInnerSize();\n if (!containerSize) {\n return;\n }\n\n let colRowCount = this.getColRowCount();\n let cols = colRowCount ? colRowCount.width : 1;\n let rows = colRowCount ? colRowCount.height : 1;\n let spacing = this.getComponentSpacing();\n\n // Universal scroll: see HBox.doLayout for the rationale. Inflates the\n // working size to the children's combined minSize on the axes the\n // host has marked as overflowing.\n containerSize = this.inflateForOverflow(containerSize);\n\n if (!this._baselineAlign) {\n this.layoutOccupancy(components, cols, rows, containerSize, containerInsets, spacing);\n\n return;\n }\n\n // Baseline mode honours the same per-track column/row sizing as the\n // occupancy path — so a \"content\" column hugs its titles instead of\n // taking a uniform 1/cols share — plus colSpan auto-flow, then\n // baseline-aligns each row's children within the row (mirroring HBox).\n // Explicit col/row placement and rowSpan > 1 are not supported here.\n const content = this.measureContent(components, cols, rows);\n const colExtents = this.resolveTracks(this._columnTracks, cols, containerSize.width, spacing, content.columns);\n const rowExtents = this.resolveTracks(this._rowTracks, rows, containerSize.height, spacing, content.rows);\n\n type BaselineCell = {\n component: Component;\n col: number;\n colSpan: number;\n height: number;\n baseline: number | null;\n };\n\n const perRow: BaselineCell[][] = Array.from({ length: rows }, () => []);\n\n let flowCol = 0;\n let flowRow = 0;\n\n for (const component of components) {\n if (flowRow >= rows) {\n break;\n }\n\n const cons = this.getLayoutConstraints(component) as GridConstraints | undefined;\n const colSpan = Util.clamp(cons?.colSpan ?? 1, 1, cols);\n const size = component.getPreferredSize();\n\n perRow[flowRow].push({\n component,\n col: flowCol,\n colSpan,\n height: size ? size.height : 0,\n baseline: component.getBaseline(),\n });\n\n flowCol += colSpan;\n\n if (flowCol >= cols) {\n flowCol = 0;\n flowRow += 1;\n }\n }\n\n let y = containerInsets.getTop();\n\n for (let row = 0; row < rows; row += 1) {\n const rowCells = perRow[row];\n\n const { rowAscent, rowDescent } = this.computeRowMetrics(\n rowCells.map(cell => cell.height),\n rowCells.map(cell => cell.baseline),\n );\n\n for (const cell of rowCells) {\n let x = containerInsets.getLeft();\n for (let i = 0; i < cell.col; i += 1) {\n x += (colExtents[i] ?? 0) + spacing;\n }\n\n let width = (cell.colSpan - 1) * spacing;\n for (let i = cell.col; i < cell.col + cell.colSpan; i += 1) {\n width += colExtents[i] ?? 0;\n }\n\n let cellY: number;\n\n if (rowAscent !== null) {\n cellY = cell.baseline !== null\n ? y + (rowAscent - cell.baseline)\n : y + this.nullChildY(cell.height, rowAscent, rowDescent);\n } else {\n cellY = y;\n }\n\n this.placeComponent(\n cell.component,\n x,\n cellY,\n width,\n cell.height,\n this._defaultFill,\n this._defaultAnchor\n );\n }\n\n const baselineHeight = rowAscent !== null ? rowAscent + rowDescent : 0;\n\n y += Math.max(rowExtents[row] ?? 0, baselineHeight) + spacing;\n }\n }\n\n /**\n * Resolves a track list into per-track pixel extents along one axis.\n *\n * @param tracks - The declared tracks; missing tracks (when shorter than\n * `count`) default to `{ mode: \"weight\", value: 1 }`.\n * @param count - The number of columns (or rows) to size.\n * @param available - The inner extent of the container along this axis.\n * @param spacing - The inter-cell gap, in pixels.\n * @param contentSizes - Measured content maxima per track, used for `\"content\"` tracks.\n * @returns A `number[count]` of pixel extents.\n *\n * @remarks Fixed tracks keep their `value`; content tracks keep their measured\n * size; the remaining space is split among weight tracks in proportion to their\n * weights. When no weight track exists the remaining space is left unused.\n */\n private resolveTracks(tracks: GridTrack[], count: number, available: number, spacing: number, contentSizes: number[]): number[] {\n const inner = available - Math.max(0, count - 1) * spacing;\n\n const resolved: number[] = new Array(count).fill(0);\n\n let fixedSum = 0;\n let contentSum = 0;\n let weightSum = 0;\n\n for (let i = 0; i < count; i += 1) {\n const track = tracks[i] ?? { mode: \"weight\" as const, value: 1 };\n\n if (track.mode === \"fixed\") {\n resolved[i] = track.value ?? 0;\n fixedSum += resolved[i];\n } else if (track.mode === \"content\") {\n resolved[i] = contentSizes[i] ?? 0;\n contentSum += resolved[i];\n } else {\n weightSum += Math.max(0, track.value ?? 1);\n }\n }\n\n const remaining = Math.max(0, inner - fixedSum - contentSum);\n\n if (weightSum > 0) {\n for (let i = 0; i < count; i += 1) {\n const track = tracks[i] ?? { mode: \"weight\" as const, value: 1 };\n\n if (track.mode === \"weight\") {\n resolved[i] = remaining * (Math.max(0, track.value ?? 1) / weightSum);\n }\n }\n }\n\n return resolved;\n }\n\n /**\n * Measures the content maxima of single-track-spanning children, per column\n * and per row, for `\"content\"` track sizing.\n *\n * @param components - The container's children.\n * @param cols - The column count.\n * @param rows - The row count.\n * @returns `{ columns, rows }` arrays of per-track content maxima.\n *\n * @remarks Each child contributes `max(preferred, min)` so a child that only\n * set a min size still widens (or heightens) its track. A child contributes to\n * a column only when its `colSpan` is `1`, and to a row only when its `rowSpan`\n * is `1` — multi-track spanners are not distributed in v1. Because content\n * measurement is independent of cell placement, the maxima are folded by\n * explicit-or-flow position when known, else by document-order column/row.\n */\n private measureContent(components: Component[], cols: number, rows: number): { columns: number[]; rows: number[] } {\n const columns: number[] = new Array(cols).fill(0);\n const rowSizes: number[] = new Array(rows).fill(0);\n\n // Baseline mode only: per-row preferred heights + baselines, so the row\n // content size can fold in the baseline spread `doLayout` reserves (see\n // below). Left empty when `baselineAlign` is off.\n const rowHeights: number[][] = this._baselineAlign ? Array.from({ length: rows }, () => []) : [];\n const rowBaselines: Array<Array<number | null>> = this._baselineAlign ? Array.from({ length: rows }, () => []) : [];\n\n let flowCol = 0;\n let flowRow = 0;\n\n for (const component of components) {\n const cons = this.getLayoutConstraints(component) as GridConstraints | undefined;\n const preferred = component.getPreferredSize();\n const min = component.getMinSize();\n\n const w = Math.max(preferred ? preferred.width : 0, min ? min.width : 0);\n const h = Math.max(preferred ? preferred.height : 0, min ? min.height : 0);\n\n const colSpan = Math.max(1, cons?.colSpan ?? 1);\n const rowSpan = Math.max(1, cons?.rowSpan ?? 1);\n\n let c: number;\n let r: number;\n\n if (cons && (cons.col != null || cons.row != null)) {\n c = Util.clamp(cons.col ?? 0, 0, Math.max(0, cols - 1));\n r = Util.clamp(cons.row ?? 0, 0, Math.max(0, rows - 1));\n } else {\n c = flowCol;\n r = flowRow;\n\n flowCol += colSpan;\n\n if (flowCol >= cols) {\n flowCol = 0;\n flowRow += rowSpan;\n }\n }\n\n if (colSpan === 1 && c < cols) {\n columns[c] = Math.max(columns[c], w);\n }\n\n if (rowSpan === 1 && r < rows) {\n rowSizes[r] = Math.max(rowSizes[r], h);\n\n if (this._baselineAlign) {\n // Pair the preferred height with the baseline, exactly as\n // `doLayout` does — the cell's placed height and baseline\n // together set the row's ascent/descent.\n rowHeights[r].push(preferred ? preferred.height : 0);\n rowBaselines[r].push(component.getBaseline());\n }\n }\n }\n\n // A baseline-aligned row is `max(tallestCell, rowAscent + rowDescent)`\n // (see `doLayout`): cells on mismatched baselines need the highest ascent\n // plus the deepest descent, which can exceed the tallest cell. Fold that\n // spread into the measured row size so `getPreferredSize` / `getMinSize`\n // reserve what `doLayout` actually lays out, rather than under-reporting\n // and letting the content overflow the box the parent sized from it.\n if (this._baselineAlign) {\n for (let r = 0; r < rows; r += 1) {\n const { rowAscent, rowDescent } = this.computeRowMetrics(rowHeights[r], rowBaselines[r]);\n\n if (rowAscent !== null) {\n rowSizes[r] = Math.max(rowSizes[r], rowAscent + rowDescent);\n }\n }\n }\n\n return { columns, rows: rowSizes };\n }\n\n /**\n * Tiles children using the occupancy-grid algorithm: explicitly-placed\n * children are reserved first, then the remaining children auto-flow into the\n * free cells, with per-track sizing and per-cell clip-vs-place.\n *\n * @param components - The container's children.\n * @param cols - The column count.\n * @param rows - The row count.\n * @param containerSize - The container's (possibly overflow-inflated) inner size.\n * @param insets - The container's insets, supplying the cell origin offset.\n * @param spacing - The inter-cell gap, in pixels.\n */\n private layoutOccupancy(components: Component[], cols: number, rows: number, containerSize: Size, insets: Insets, spacing: number): void {\n const content = this.measureContent(components, cols, rows);\n\n const colExtents = this.resolveTracks(this._columnTracks, cols, containerSize.width, spacing, content.columns);\n const rowExtents = this.resolveTracks(this._rowTracks, rows, containerSize.height, spacing, content.rows);\n\n const occupancy: boolean[][] = [];\n\n for (let r = 0; r < rows; r += 1) {\n occupancy.push(new Array(cols).fill(false));\n }\n\n const owners: Array<Array<string | null>> = [];\n\n for (let r = 0; r < rows; r += 1) {\n owners.push(new Array(cols).fill(null));\n }\n\n const placeAt = (component: Component, r: number, c: number, rowSpan: number, colSpan: number): void => {\n let x = insets.getLeft();\n\n for (let i = 0; i < c; i += 1) {\n x += colExtents[i] + spacing;\n }\n\n let y = insets.getTop();\n\n for (let i = 0; i < r; i += 1) {\n y += rowExtents[i] + spacing;\n }\n\n let w = (colSpan - 1) * spacing;\n\n for (let i = c; i < c + colSpan; i += 1) {\n w += colExtents[i] ?? 0;\n }\n\n let h = (rowSpan - 1) * spacing;\n\n for (let i = r; i < r + rowSpan; i += 1) {\n h += rowExtents[i] ?? 0;\n }\n\n const min = component.getMinSize();\n\n if (min && (min.width > w || min.height > h)) {\n // The child's own `min-width` / `min-height` keep its box from\n // shrinking to the cell on the overflowing axis, so clip it with\n // a cell-sized frame. Honour the grid's fill/anchor on whichever\n // axis the child *does* fit — `resolveBounds` yields the\n // fill/anchor-placed box — and override only the overflowing axis\n // to the child's natural extent (its preferred size, falling back\n // to min) so the content renders at full size up to the clip edge\n // rather than at a cramped preferred that drops fill. The frame is\n // anchored at the cell; the child commits at the resolved offset\n // within it (0 on an overflowing axis, since `resolveBounds`\n // applies no anchor displacement when the child exceeds the cell).\n const resolved = this.resolveBounds(component, x, y, w, h, this._defaultFill, this._defaultAnchor);\n const pref = component.getPreferredSize();\n\n const childWidth = min.width > w ? (pref ? pref.width : min.width) : resolved.width;\n const childHeight = min.height > h ? (pref ? pref.height : min.height) : resolved.height;\n\n component.setClipFrame(x, y, w, h);\n this.commitBounds(component, resolved.x - x, resolved.y - y, childWidth, childHeight);\n } else {\n // The child fits: resolve its bounds honouring its own\n // fill/anchor over the grid defaults, then commit the result so\n // a non-filling child shrinks and anchors within its cell.\n const resolved = this.resolveBounds(component, x, y, w, h, this._defaultFill, this._defaultAnchor);\n\n component.clearClipFrame();\n this.commitBounds(component, resolved.x, resolved.y, resolved.width, resolved.height);\n }\n };\n\n // Pass 1 — reserve explicitly-positioned children.\n for (const component of components) {\n const cons = this.getLayoutConstraints(component) as GridConstraints | undefined;\n\n if (!cons || (cons.col == null && cons.row == null)) {\n continue;\n }\n\n const c = Util.clamp(cons.col ?? 0, 0, Math.max(0, cols - 1));\n const r = Util.clamp(cons.row ?? 0, 0, Math.max(0, rows - 1));\n const colSpan = Util.clamp(cons.colSpan ?? 1, 1, cols - c);\n const rowSpan = Util.clamp(cons.rowSpan ?? 1, 1, rows - r);\n\n for (let rr = r; rr < r + rowSpan; rr += 1) {\n for (let cc = c; cc < c + colSpan; cc += 1) {\n if (occupancy[rr][cc]) {\n console.warn(`Grid: ${component.getId()} overlaps ${owners[rr][cc]} at cell (${rr},${cc})`);\n }\n\n occupancy[rr][cc] = true;\n owners[rr][cc] = component.getId();\n }\n }\n\n placeAt(component, r, c, rowSpan, colSpan);\n }\n\n // Pass 2 — auto-flow the remaining children into free cells.\n for (const component of components) {\n const cons = this.getLayoutConstraints(component) as GridConstraints | undefined;\n\n if (cons && (cons.col != null || cons.row != null)) {\n continue;\n }\n\n const colSpan = Util.clamp(cons?.colSpan ?? 1, 1, cols);\n const rowSpan = Util.clamp(cons?.rowSpan ?? 1, 1, rows);\n\n const slot = this.findFreeCell(occupancy, rows, cols, rowSpan, colSpan);\n\n if (!slot) {\n continue;\n }\n\n for (let rr = slot.r; rr < slot.r + rowSpan; rr += 1) {\n for (let cc = slot.c; cc < slot.c + colSpan; cc += 1) {\n occupancy[rr][cc] = true;\n owners[rr][cc] = component.getId();\n }\n }\n\n placeAt(component, slot.r, slot.c, rowSpan, colSpan);\n }\n }\n\n /**\n * Scans the occupancy grid in row-major order for the first top-left cell\n * whose `rowSpan`×`colSpan` block is entirely free.\n *\n * @param occupancy - The `boolean[rows][cols]` occupancy map.\n * @param rows - The row count.\n * @param cols - The column count.\n * @param rowSpan - The block height to fit.\n * @param colSpan - The block width to fit.\n * @returns The free block's top-left `{ r, c }`, or `null` if none fits.\n */\n private findFreeCell(occupancy: boolean[][], rows: number, cols: number, rowSpan: number, colSpan: number): { r: number; c: number } | null {\n for (let r = 0; r + rowSpan <= rows; r += 1) {\n for (let c = 0; c + colSpan <= cols; c += 1) {\n let free = true;\n\n for (let rr = r; rr < r + rowSpan && free; rr += 1) {\n for (let cc = c; cc < c + colSpan; cc += 1) {\n if (occupancy[rr][cc]) {\n free = false;\n\n break;\n }\n }\n }\n\n if (free) {\n return { r, c };\n }\n }\n }\n\n return null;\n }\n}\n\nconst GridCallable = callable(Grid);\ntype GridCallable = Grid;\nexport {\n Grid as _Grid,\n GridCallable as Grid\n};\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-Ba8YRVel.js";import{a as t,l as n,n as r}from"./Position-PBVBW1JS.js";import{S as i,b as a,f as o,h as s,p as c,t as l,v as u}from"./Component-w65rPK75.js";import{t as d}from"./ListenerBag-WPdKuuds.js";import{r as f}from"./VBox-32fxpkDl.js";import{i as p,n as m,t as h}from"./LayoutSizes-DKDK1Cle.js";import{n as g}from"./Border-CNS6aEXB.js";import{t as _}from"./LayoutConstraints-LIHYYd2F.js";import{t as v}from"./Button-T16zSZip.js";import{n as y,r as b}from"./DragChain-CYGuT7OA.js";var x=14,S=`▶`,C=null;function ensureAccordionIndicatorClassRule(){C||=new a({scope:`class`,name:`AccordionIndicator`,styles:{textAlign:`center`,pointerEvents:`none`,fontSize:`10px`,color:`var(--ts-ui-accordion-indicator-color, rgb(100,100,100))`,transition:`transform 200ms ease`}})}var AccordionIndicator=class extends l{_lineHeight=null;constructor(e){ensureAccordionIndicatorClassRule(),super({tag:`span`,preferredSize:{width:x,height:x},...e??{}}),this._expanded??=!1,this._character??=S,this.createStyleRule(`.expanded`).set(`transform`,`rotate(90deg)`)}setLineHeight(e){return this._lineHeight===e?this:(this._lineHeight=e,this.setElementCSSRule(`lineHeight`,e+`px`),this)}setHeight(e){return super.setHeight(e),this.setLineHeight(e),this}applyOptions(e){return super.applyOptions(e),e.expanded!==void 0&&this.setExpanded(e.expanded),e.character!==void 0&&this.setCharacter(e.character),this}getCharacter(){return this._character??S}setCharacter(t){this._character=t;let n=this.getElement();return n&&e.sink.apply(n,{text:t}),this}render(){let t=super.render();return e.sink.apply(t,{text:this._character??S}),this._expanded&&e.sink.apply(t,{addClass:[`expanded`]}),t}getExpanded(){return this._expanded}setExpanded(t){this._expanded=t;let n=this.getElement();return n&&e.sink.apply(n,{toggleClass:{expanded:t}}),this}clearExpanded(){return this.setExpanded(!1)}setAnimationTiming(e,t){return this.setTransition(`transform ${e}ms ${t}`),this}},w=s(AccordionIndicator),T=8,E=10,D=4,O=6,k=6,A=2,AccordionHeader=class extends l{_tools=[];_chevronSide=`end`;constructor(e,t){super({tag:`div`,...t}),this._indicator=new w({character:t?.chevronGlyph}),this._title=new v(e,{chromeless:!0,anchor:c.WEST,glyph:t?.glyph}),this._toolGroup=new l,this._toolGroup.setLayoutManager(new f({spacing:D,stretching:!0})),this._toolGroup.setBackgroundColor(`transparent`),this.setLayoutManager(new f({spacing:D,stretching:!0}));let n=new _;n.weight=1,this.addComponent(this._title,n),this.addComponent(this._toolGroup),this._chevronSide=t?.chevronSide??`end`,this.placeIndicator(),this.setExpanded(t?.expanded??!1),this.setCompact(t?.compact??!1)}setCompact(e){let t=e?O:T,n=e?k:E;return this.setInsets(new r(0,n,0,t)),this.getLayoutManager().setComponentSpacing(e?A:D),this._title?.setCompact(e),this.scheduleLayout(),this}placeIndicator(){this.getComponents().includes(this._indicator)&&this.removeComponent(this._indicator),this._chevronSide===`start`?this.insertComponent(this._indicator,0):this.addComponent(this._indicator)}getTitleButton(){return this._title}setExpanded(e){return this._indicator?.setExpanded(e),this._title?.getAria().setExpanded(e),this}isExpanded(){return this._indicator?.getExpanded()??!1}setChevronSide(e){return this._chevronSide===e?this:(this._chevronSide=e,this.placeIndicator(),this.scheduleLayout(),this)}getChevronSide(){return this._chevronSide}setChevronGlyph(e){return this._indicator?.setCharacter(e),this}addTool(e){return e instanceof v&&e.setFlat(!0),this._tools.includes(e)?this:(this._tools.push(e),this._toolGroup.addComponent(e),this.scheduleLayout(),this)}removeTool(e){let t=this._tools.indexOf(e);return t===-1?this:(this._tools.splice(t,1),this._toolGroup.removeComponent(e),this.scheduleLayout(),this)}setToolsRevealed(e){return this._toolGroup.setDisplayed(e),this}setAnimationTiming(e,t){return this._indicator?.setAnimationTiming(e,t),this}},j=s(AccordionHeader),M=`cubic-bezier(0.4, 0, 0.6, 1)`,N=22,P=6,F=`var(--ts-ui-accordion-header-bg, rgb(243,244,246))`,I=`var(--ts-ui-accordion-header-border, 1px solid rgb(214,217,222))`,L=`var(--ts-ui-accordion-header-color, inherit)`,R=`var(--ts-ui-accordion-border, 1px solid rgb(214,217,222))`,Accordion=class extends o{_headers=[];_panelWrappers=[];_openState=[];_singleOpen=!1;_headerHeight=28;_headerHeightExplicit=!1;_compact=!1;_animationDuration=200;_chevronSide=`end`;_chevronGlyph=null;_spacing=0;_themed=!0;_fillHeight=!1;_tools=[];_toolsVisibility=`hover`;_hoveredHeader=-1;_listeners=new d;_resizable=!1;_resizeSizes=new Map;_pendingSectionSizes=null;_resizeFactor=1;_resizePinned=new Set;_resizeGutters=[];_gutterPairs=[];_dragUpper=null;_dragLower=null;_dragLastPointer=0;_dragOpenIndices=[];_dragGutterUpperPos=0;_toggleAnimations=0;_shrinkAnimations=new Map;_wrapperAnimations=new Map;_boundOnGutterDragEnd=()=>this.onGutterDragEnd();constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){if(super.applyOptions(e),e.headerHeight!==void 0&&this.setHeaderHeight(e.headerHeight),e.animationDuration!==void 0&&this.setAnimationDuration(e.animationDuration),e.chevronSide!==void 0&&this.setChevronSide(e.chevronSide),e.toolsVisibility!==void 0&&this.setToolsVisibility(e.toolsVisibility),e.compact!==void 0&&this.setCompact(e.compact),e.chevronGlyph!==void 0&&this.setChevronGlyph(e.chevronGlyph),e.spacing!==void 0&&this.setSpacing(e.spacing),e.themed!==void 0&&this.setThemed(e.themed),e.fillHeight!==void 0&&this.setFillHeight(e.fillHeight),e.resizable!==void 0&&this.setResizable(e.resizable),e.sectionSizes!==void 0&&(this._pendingSectionSizes=e.sectionSizes.map(e=>({...e}))),e.listeners!==void 0){let t=e.listeners;for(let e of Object.keys(t)){let n=t[e];n!==void 0&&this.on(e,n)}}e.singleOpen!==void 0&&this.setSingleOpen(e.singleOpen)}isSingleOpen(){return this._singleOpen}setSingleOpen(e){if(this._singleOpen=e,!e)return this;let t=!1;for(let e=0;e<this._openState.length;e++)this._openState[e]&&(t?(this.primeWrapper(e),this._openState[e]=!1,this._headers[e].setExpanded(!1),this.emit(`sectiontoggle`,e,!1)):t=!0);return this.relayoutHost(),this}getHeaderHeight(){return this._headerHeight}setHeaderHeight(e){return this._headerHeight=e,this._headerHeightExplicit=!0,this}effectiveHeaderHeight(){return this._compact&&!this._headerHeightExplicit?N:this._headerHeight}isCompact(){return this._compact}setCompact(e){this._compact=e;for(let t of this._headers)t.setCompact(e);return this.relayoutHost(),this}getAnimationDuration(){return this._animationDuration}setAnimationDuration(e){return this._animationDuration=e,this}getChevronSide(){return this._chevronSide}setChevronSide(e){this._chevronSide=e;for(let t of this._headers)t.setChevronSide(e);return this.getContainer()?.scheduleLayout(),this}getChevronGlyph(){return this._chevronGlyph}setChevronGlyph(e){this._chevronGlyph=e;for(let t of this._headers)t.setChevronGlyph(e);return this.getContainer()?.scheduleLayout(),this}getSpacing(){return this._spacing}setSpacing(e){return this._spacing=e,this.relayoutHost(),this}isFillHeight(){return this._fillHeight}setFillHeight(e){return this._fillHeight=e,this.getContainer()?.scheduleLayout(),this}isResizable(){return this._resizable}setResizable(e){return this._resizable=e,this.getContainer()?.scheduleLayout(),this}isThemed(){return this._themed}setThemed(e){this._themed=e,this.applyContainerTheming();for(let e=0;e<this._headers.length;e++)this.applySectionTheming(e);return this.getContainer()?.scheduleLayout(),this}applyContainerTheming(){let e=this.getContainer();e&&(this._themed?e.setBorder({border:R}):e.clearBorder())}applySectionTheming(e){let t=this._headers[e];if(t){if(!this._themed){t.clearBackground(),t.clearForegroundColor(),t.clearBorder();return}t.setBackground(F),t.setForegroundColor(L),t.setBorder({border:`none`,borderBottom:I})}}getToolsVisibility(){return this._toolsVisibility}setToolsVisibility(e){this._toolsVisibility=e;for(let t of this._headers)t.setToolsRevealed(e===`always`);return this}addTool(e){return this._tools.includes(e)?this:(this._tools.push(e),this._hoveredHeader!==-1&&this._headers[this._hoveredHeader]?.addTool(e),this.getContainer()?.scheduleLayout(),this)}removeTool(e){let t=this._tools.indexOf(e);return t===-1?this:(this._tools.splice(t,1),this._hoveredHeader!==-1&&this._headers[this._hoveredHeader]?.removeTool(e),this.getContainer()?.scheduleLayout(),this)}revealHeaderTools(e){let t=this._headers[e];if(t){for(let e of this._tools)t.addTool(e);this._toolsVisibility===`hover`&&t.setToolsRevealed(!0)}}hideHeaderTools(e){let t=this._headers[e];if(t){for(let e of this._tools)t.removeTool(e);this._toolsVisibility===`hover`&&t.setToolsRevealed(!1)}}onHeaderHoverEnter(t,n){let r=this._headers[t]?.getElement();r&&e.source.isNode(n.relatedTarget)&&e.source.contains(r,e.source.intern(n.relatedTarget))||this._hoveredHeader!==t&&(this._hoveredHeader!==-1&&this.hideHeaderTools(this._hoveredHeader),this._hoveredHeader=t,this.revealHeaderTools(t))}onHeaderHoverLeave(t,n){let r=this._headers[t]?.getElement();r&&e.source.isNode(n.relatedTarget)&&e.source.contains(r,e.source.intern(n.relatedTarget))||this._hoveredHeader===t&&(this.hideHeaderTools(t),this._hoveredHeader=-1)}relayoutHost(){let e=this.getContainer();e?.scheduleLayout(),e?.notifyIntrinsicSizeChanged()}openSection(e){if(e<0||e>=this._openState.length)return this;if(this._singleOpen)for(let t=0;t<this._openState.length;t++)t!==e&&this._openState[t]&&(this.primeWrapper(t),this._openState[t]=!1,this._headers[t].setExpanded(!1),this.emit(`sectiontoggle`,t,!1));return this.primeWrapper(e),this._openState[e]=!0,this._headers[e].setExpanded(!0),this.emit(`sectiontoggle`,e,!0),this.relayoutHost(),this}closeSection(e){return e<0||e>=this._openState.length?this:(this.primeWrapper(e),this._openState[e]=!1,this._headers[e].setExpanded(!1),this.emit(`sectiontoggle`,e,!1),this.relayoutHost(),this)}expandAll(){if(this._singleOpen)return this.openSection(0),this;for(let e=0;e<this._openState.length;e++)this.openSection(e);return this}collapseAll(){for(let e=0;e<this._openState.length;e++)this.closeSection(e);return this}isSectionOpen(e){return this._openState[e]??!1}sectionSizeUnits(e){return e.map(e=>this.effectiveWeight(e)===0?`px`:`ratio`)}getSectionSizes(){let e=this.getContainer();if(!e)return[];let t=e.getComponents();if(t.length===0)return[];let n=this.sectionSizeUnits(t);return this._pendingSectionSizes!==null&&m(this._pendingSectionSizes,n)?this._pendingSectionSizes.map(e=>({...e})):p(n,t.map(e=>this._resizeSizes.get(e)??0))}applySectionSizes(e){return this._pendingSectionSizes=e.map(e=>({...e})),this.getContainer()?.scheduleLayout(),this}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}attach(e){return super.attach(e),this}detach(){let t=this.getContainer();for(let e of this._shrinkAnimations.values())e.cancel();this._shrinkAnimations.clear();for(let e of this._wrapperAnimations.values())e.cancel();this._wrapperAnimations.clear(),this._toggleAnimations>0&&(this._toggleAnimations=0,this.setSectionTransitions(!1),t?.setTransition(null)),this._dragUpper&&this.onGutterDragEnd();for(let n=0;n<this._headers.length;n++){let r=(t?t.getComponents():[])[n];r&&t&&e.sink.appendChild(t.getElement(),r.getElement());let i=r?this.getLayoutConstraints(r)?.tools??[]:[];for(let e of[...this._tools,...i])this._headers[n].removeTool(e);this._headers[n].dispose(),this._panelWrappers[n].dispose()}this._headers=[],this._panelWrappers=[],this._openState=[];for(let t of this._resizeGutters)e.sink.removeElement(t.getElement()),t.dispose();return this._resizeGutters=[],this._resizeSizes.clear(),this._gutterPairs=[],super.detach(),this}getPreferredSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getComponents(),r=t.top+t.bottom,i=0,a=0;for(let e=0;e<n.length;e++)if(n[e].isDisplayed()&&(a>0&&(r+=this._spacing),a+=1,r+=this.effectiveHeaderHeight(),e<this._openState.length?this._openState[e]:this.getLayoutConstraints(n[e])?.initiallyOpen??!1)){let t=n[e].getPreferredSize();t&&(r+=t.height,t.width>i&&(i=t.width))}return{width:i+t.left+t.right,height:r}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getComponents(),r=t.top+t.bottom,i=0,a=0;for(let e=0;e<n.length;e++)if(n[e].isDisplayed()&&(a>0&&(r+=this._spacing),a+=1,r+=this.effectiveHeaderHeight(),e<this._openState.length?this._openState[e]:this.getLayoutConstraints(n[e])?.initiallyOpen??!1)){let t=n[e].getMinSize();t&&(r+=t.height,t.width>i&&(i=t.width))}return{width:i+t.left+t.right,height:r}}getMaxSize(){return{width:t,height:t}}createSection(t,n){let r=this.getContainer(),a=this.getLayoutConstraints(t),o=a?.label??t.getId(),s=a?.initiallyOpen??!1,c=new j(o,{chevronSide:this._chevronSide,glyph:a?.glyph??void 0,compact:this._compact,chevronGlyph:this._chevronGlyph??void 0});c.setAnimationTiming(this._animationDuration,M),c.setTransition(`none`);let u=c.getTitleButton();u.on(`action`,()=>this.onHeaderClicked(n)),i.addListener(c,`click`,()=>this.onHeaderClicked(n)),i.addListener(u,`keydown`,e=>this.onHeaderKeyDown(e,n)),i.addSubtreeListener(c,`mouseover`,e=>this.onHeaderHoverEnter(n,e)),i.addSubtreeListener(c,`mouseout`,e=>this.onHeaderHoverLeave(n,e));let d=new l;d.setOverflow(`hidden`),d.setContain(`layout paint`),d.setTransition(`none`),e.sink.appendChild(r.getElement(),c.getElement(!0)),e.sink.appendChild(r.getElement(),d.getElement(!0)),e.sink.appendChild(d.getElement(),t.getElement()),t.setTransition(`none`),this._openState.push(s),this._headers.push(c),this._panelWrappers.push(d),c.setExpanded(s),u.getAria().setControls(d.getId()),d.getAria().setRole(`region`),d.getAria().setLabelledBy(u.getId());for(let e of a?.tools??[])c.addTool(e);this._toolsVisibility===`hover`&&c.setToolsRevealed(!1),this.applySectionTheming(n)}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=0;for(let n of e.getComponents()){if(!n.isDisplayed())continue;let e=n.getMinSize();e&&(t=Math.max(t,e.width))}return{width:t,height:0}}placeSection(e,t,n,r,i,a,o){let s=this._headers[e],c=this._panelWrappers[e],l=this.effectiveHeaderHeight();s.setX(o),s.setY(n),s.setWidth(a),s.setHeight(l),s.doLayout();let u=n+l;return c.setX(o),c.setY(u),c.setWidth(a),c.setHeight(r),t.setX(0),t.setY(0),t.setWidth(a),t.setHeight(i),u+r}doLayout(){let e=this.getContainer();if(!e||!e.getElement())return;let t=e.getComponents();for(let e=this._headers.length;e<t.length;e++)this.createSection(t[e],e);this.applyContainerTheming();let n=e.getInnerSize(),r=e.getContentInsets(),i=n?n.width:0;if(this.isOverflowingX()){let e=this.computeTotalMinSize();i=Math.max(i,e.width)}let a=this.computeShrinkRatio(t,n),o=this.computeFill(t,n,a),s=this.computeResizableHeights(t,n,a,o);this.layoutSections(t,i,r.getLeft(),r.getTop(),s!==null,(e,n)=>{if(n)return s?.get(e)??this.openContentHeight(t[e],a)+(o.get(e)??0);let r=t[e].getPreferredSize();return r?r.height:100},!0,!0)}layoutSections(e,t,n,r,i,a,o,s){let c=r,l=0,d=null,f=0,p=0;for(let r=0;r<e.length;r++){let m=e[r],h=this._headers[r],g=this._panelWrappers[r],_=this._openState[r];if(!m.isDisplayed()){h.setDisplayed(!1),g.setDisplayed(!1);continue}h.setDisplayed(!0),g.setDisplayed(!0),l>0&&(c+=this._spacing),l+=1;let v=a(r,_),y=_?v:0;_&&i&&d!==null&&(this.placeGutter(p,f,t,n),this._gutterPairs[p]={upper:d,lower:m},p+=1);let b=m.getHeight(),x=_&&o&&!u.isReducedMotion()&&v<b,S=this.placeSection(r,m,c,y,v,t,n);(s||v!==b)&&(x?(this._shrinkAnimations.get(r)?.cancel(),this._shrinkAnimations.set(r,u.afterTransition({component:g,property:`height`,durationMs:this._animationDuration,fallbackBufferMs:40,onComplete:()=>{this._shrinkAnimations.delete(r),m.doLayout()}}))):m.doLayout()),_&&i&&(d=m,f=S),c=S}this._gutterPairs.length=p;for(let e=p;e<this._resizeGutters.length;e++)this._resizeGutters[e].setVisible(!1)}getOrCreateResizeGutter(t){let n=this._resizeGutters[t];if(n)return n;let r=this.getContainer(),i=new g(`vertical`,{collapsible:!1,expandedBackground:`transparent`});return i.setTransition(`none`),i.on(`dragstart`,e=>this.onGutterDragStart(t,e)),i.on(`drag`,e=>this.onGutterDrag(t,e)),e.sink.appendChild(r.getElement(),i.getElement(!0)),this._resizeGutters.push(i),i}placeGutter(e,t,n,r){let i=this.getOrCreateResizeGutter(e);i.setX(r),i.setY(t-P),i.setWidth(n),i.setHeight(P),i.setVisible(!0)}onGutterDragStart(e,t){let n=this._gutterPairs[e];if(!n)return;let r=this.getContainer()?.getComponents()??[];this._dragOpenIndices=[];for(let e=0;e<r.length;e++)r[e].isDisplayed()&&this._openState[e]&&this._dragOpenIndices.push(e);if(this._dragGutterUpperPos=this._dragOpenIndices.indexOf(r.indexOf(n.upper)),this._dragGutterUpperPos===-1)return;this._dragUpper=n.upper,this._dragLower=n.lower,this._dragLastPointer=t;let a=this.getContainer();a&&(i.addViewportListener(a,`mouseup`,this._boundOnGutterDragEnd),i.addViewportListener(a,`touchend`,this._boundOnGutterDragEnd),i.addViewportListener(a,`touchcancel`,this._boundOnGutterDragEnd))}onGutterDrag(e,t){let n=this._gutterPairs[e],r=this.getContainer();if(!n||n.upper!==this._dragUpper||n.lower!==this._dragLower||!r)return;let i=r.getComponents(),a=this._dragOpenIndices,o=this._dragGutterUpperPos,s=t-this._dragLastPointer,c=a.map(e=>i[e].getHeight()),l=a.map(e=>{let t=i[e].getMinSize();return t?t.height:0}),u=a.map(e=>{let t=i[e].getMaxSize();return t?t.height:1/0}),d=[],f=[];for(let e=o;e>=0;e--)d.push(e);for(let e=o+1;e<a.length;e++)f.push(e);let p=s>=0?d:f,m=s>=0?f:d,h=y(p,c,1,l,u),g=y(m,c,-1,l,u),_=Math.max(0,Math.min(Math.abs(s),h,g));this._dragLastPointer+=Math.sign(s)*_;let v=c.slice();b(p,c,_,1,l,u,v),b(m,c,_,-1,l,u,v);let x=new Map;for(let e=0;e<a.length;e++){let t=i[a[e]],n=this._resizePinned.has(t)?1:this._resizeFactor;x.set(a[e],v[e]),this._resizeSizes.set(t,v[e]/n)}let S=r.getContentInsets(),C=this._panelWrappers[a[0]].getWidth();this.layoutSections(i,C,S.getLeft(),S.getTop(),!0,(e,t)=>t?x.get(e)??i[e].getHeight():i[e].getHeight(),!1,!1)}onGutterDragEnd(){let e=this._dragUpper!==null,t=this.getContainer();return t&&(i.removeViewportListener(t,`mouseup`,this._boundOnGutterDragEnd),i.removeViewportListener(t,`touchend`,this._boundOnGutterDragEnd),i.removeViewportListener(t,`touchcancel`,this._boundOnGutterDragEnd)),this._dragUpper=null,this._dragLower=null,e&&this.emit(`sectionresize`,this.getSectionSizes()),!0}computeShrinkRatio(e,t){if(!t)return 0;let n=0,r=0,i=0,a=0;for(let t=0;t<e.length;t++){if(!e[t].isDisplayed()||(a>0&&(n+=this._spacing),a+=1,n+=this.effectiveHeaderHeight(),!this._openState[t]))continue;let o=e[t].getPreferredSize(),s=e[t].getMinSize();r+=o?o.height:100,i+=s?s.height:0}let o=n+r,s=n+i,c=t.height;if(o<=c||s>c)return 0;let l=o-s;return l>0?(o-c)/l:0}openContentHeight(e,t){let n=e.getPreferredSize(),r=n?n.height:100,i=e.getMinSize(),a=i?i.height:0,o=r-t*(r-a),s=e.getMaxSize(),c=s?Math.min(o,s.height):o;return Math.max(c,a)}computeFill(e,t,n){let r=new Map;if(!t)return r;let i=0,a=0,o=[],s=0;for(let t=0;t<e.length;t++)if(e[t].isDisplayed()&&(a>0&&(i+=this._spacing),a+=1,i+=this.effectiveHeaderHeight(),this._openState[t])){let r=this.openContentHeight(e[t],n);i+=r;let a=this.effectiveWeight(e[t]);a>0&&(o.push({index:t,weight:a,headroom:this.fillHeadroom(e[t],r)}),s+=a)}let c=t.height-i;return c<=0||s<=0?r:this.distributeFillWithinMax(o,c)}effectiveWeight(e){let t=this.getLayoutConstraints(e)?.weight??0;return t>0?t:+!!this._fillHeight}resizePinnedSections(e,t,n){let r=[],i=0,a=0;for(let n of t)this.effectiveWeight(e[n])>0?i+=1:(r.push(n),a+=this.clampSectionHeight(e[n],this._resizeSizes.get(e[n])??0));return i===0||a>n?[]:r}clampSectionHeight(e,t){let r=e.getMinSize(),i=e.getMaxSize();return n.clamp(t,r?r.height:0,i?i.height:1/0)}fillHeadroom(e,t){let n=e.getMaxSize();return n?Math.max(0,n.height-t):1/0}distributeFillWithinMax(e,t){let n=new Map,r=new Set(e),i=t;for(;;){let e=0;for(let t of r)e+=t.weight;if(e<=0)break;let t=i/e,a=!1;for(let e of r)if(e.weight*t>e.headroom){n.set(e.index,e.headroom),i-=e.headroom,r.delete(e),a=!0;break}if(!a){for(let e of r)n.set(e.index,e.weight*t);break}if(r.size===0)break}return n}computeResizableHeights(e,t,n,r){if(!this._resizable||!t)return null;for(let t of[...this._resizeSizes.keys()])e.includes(t)||this._resizeSizes.delete(t);let i=0,a=0,o=[];for(let t=0;t<e.length;t++)e[t].isDisplayed()&&(a>0&&(i+=this._spacing),a+=1,i+=this.effectiveHeaderHeight(),this._openState[t]&&o.push(t));if(o.length===0)return null;let s=t.height-i;this.applyPendingSectionSizes(e,s);for(let t of o){let i=e[t];this._resizeSizes.has(i)||this._resizeSizes.set(i,this.openContentHeight(i,n)+(r.get(t)??0))}return this.distributeWithinConstraints(e,o,s)}applyPendingSectionSizes(e,t){let n=this._pendingSectionSizes;if(n===null)return;this._pendingSectionSizes=null;let r=this.sectionSizeUnits(e);if(!m(n,r))return;let i=h(n,t);for(let t=0;t<e.length;t+=1)i[t]>0?this._resizeSizes.set(e[t],i[t]):this._resizeSizes.delete(e[t])}distributeWithinConstraints(e,t,n){let r=new Map,i=new Set(t),a=n,o=1;this._resizePinned.clear();for(let o of this.resizePinnedSections(e,t,n)){let t=this.clampSectionHeight(e[o],this._resizeSizes.get(e[o])??0);r.set(o,t),a-=t,i.delete(o),this._resizePinned.add(e[o])}for(;;){let t=0;for(let n of i)t+=this._resizeSizes.get(e[n])??0;o=t>0?a/t:0;let n=!1;for(let t of i){let s=e[t],c=(this._resizeSizes.get(s)??0)*o,l=s.getMinSize(),u=s.getMaxSize(),d=l?l.height:0,f=u?u.height:1/0;if(c<d){r.set(t,d),a-=d,i.delete(t),n=!0;break}if(c>f){r.set(t,f),a-=f,i.delete(t),n=!0;break}}if(!n){for(let t of i)r.set(t,(this._resizeSizes.get(e[t])??0)*o);break}if(i.size===0)break}return this._resizeFactor=o>0?o:1,r}onHeaderKeyDown(e,t){let n=this._headers.length;if(n===0)return;let r;switch(e.key){case`ArrowDown`:r=(t+1)%n;break;case`ArrowUp`:r=(t-1+n)%n;break;case`Home`:r=0;break;case`End`:r=n-1;break;default:return}e.preventDefault(),this._headers[r].getTitleButton().focus()}onHeaderClicked(e){let t=this._openState[e];if(this._singleOpen&&!t)for(let t=0;t<this._openState.length;t++)t!==e&&this._openState[t]&&(this.primeWrapper(t),this._openState[t]=!1,this._headers[t].setExpanded(!1),this.emit(`sectiontoggle`,t,!1));let n=!t;this.primeWrapper(e),this._openState[e]=n,this._headers[e].setExpanded(n),this.emit(`sectiontoggle`,e,n),this.relayoutHost()}primeWrapper(t){if(u.isReducedMotion())return;let n=this._panelWrappers[t],r=this.getContainer();this.setSectionTransitions(!0),r?.setTransition(`height ${this._animationDuration}ms ${M}`),n.setWillChange(`height`);let i=r?.getElement();i&&e.source.getElementRect(i);let a=this._wrapperAnimations.get(t);a?(a.cancel(),this._wrapperAnimations.delete(t)):this._toggleAnimations+=1,this._wrapperAnimations.set(t,u.afterTransition({component:n,property:`height`,durationMs:this._animationDuration,fallbackBufferMs:40,onComplete:()=>{this._wrapperAnimations.delete(t),n.setWillChange(null),--this._toggleAnimations,this._toggleAnimations<=0&&(this._toggleAnimations=0,this.setSectionTransitions(!1),r?.setTransition(null),this.relayoutHost())}}))}setSectionTransitions(e){let t=this.getContainer()?.getComponents()??[];for(let n=0;n<this._headers.length;n++)this._headers[n].setTransition(e?this.buildHeaderTransition():`none`),this._panelWrappers[n].setTransition(e?this.buildWrapperTransition():`none`),t[n]?.setTransition(e?this.buildContentTransition():`none`);for(let t of this._resizeGutters)t.setTransition(e?this.buildHeaderTransition():`none`)}buildHeaderTransition(){return`top ${this._animationDuration}ms ${M}`}buildWrapperTransition(){return`height ${this._animationDuration}ms ${M}, top ${this._animationDuration}ms ${M}`}buildContentTransition(){return`height ${this._animationDuration}ms ${M}`}},z=s(Accordion),AccordionConstraints=class extends _{label;initiallyOpen;tools;constructor(e,t,n,r){super(),this.label=e,this.initiallyOpen=t,this.glyph=n??null,this.tools=r}},GridConstraints=class extends _{col;row;rowSpan;colSpan;constructor(){super()}};export{w as a,j as i,AccordionConstraints as n,z as r,GridConstraints as t};
2
- //# sourceMappingURL=GridConstraints-Bts284FI.js.map