@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckboxMenuRow-CesLhSnp.js","names":[],"sources":["../../src/typescript/lib/core/WheelTrap.ts","../../src/typescript/lib/overlay/DragFeedback.ts","../../src/typescript/lib/overlay/DragGhost.ts","../../src/typescript/lib/overlay/ReorderIndicator.ts","../../src/typescript/lib/overlay/DragManager.ts","../../src/typescript/lib/component/container/CheckboxMenuRow.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport type { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { consumeWheel } from \"~/core/SmoothScroller.js\";\n\n/**\n * Components that currently have the wheel trap installed. Used purely for\n * idempotency — the listener itself ({@link swallowUnconsumedWheel}) captures\n * nothing per component, so one shared reference serves every overlay. Keyed\n * weakly, mirroring how the layer registry keys per-layer state, so a closed\n * overlay's entry is collectable without an explicit purge.\n */\nconst _trapped = new WeakSet<Component>();\n\n/**\n * Subtree `wheel` handler shared by every trapped overlay: claims the event via\n * the framework's wheel once-marker and, when the claim succeeds (no inner\n * scroller took it first), `preventDefault()`s it so the native wheel never\n * reaches a scrollable ancestor behind the overlay.\n *\n * @param e - The wheel event reaching the overlay as the outermost ancestor.\n */\nfunction swallowUnconsumedWheel(e: WheelEvent): Event.ListenerResult {\n if (consumeWheel(e)) {\n return { prevent: true };\n }\n}\n\n/**\n * Registers a non-passive subtree `wheel` listener on `component` that\n * `preventDefault()`s any wheel the event reaches it unconsumed — trapping\n * wheels an inner scroller did not claim so they cannot fall through to content\n * behind a floating overlay. Idempotent per component.\n *\n * @param component - The overlay to install the trap on. Must already be mounted,\n * since the subtree listener resolves the component's element.\n *\n * @remarks Subtree events dispatch descendant-first, so any inner scroll\n * container under the pointer claims the wheel first and the overlay's handler,\n * firing last as the outermost ancestor, sees it already consumed and does\n * nothing — inner scroll proceeds untouched. The listener is `{ passive: false }`\n * to match the only other `wheel` registration (the inner scroll pipeline) and\n * because `preventDefault()` is a no-op on a passive listener.\n */\nexport function trapWheel(component: Component): void {\n if (_trapped.has(component)) {\n return;\n }\n\n _trapped.add(component);\n Event.addSubtreeListener(component, \"wheel\", { passive: false, handler: swallowUnconsumedWheel });\n}\n\n/**\n * Removes the trap installed by {@link trapWheel}. Safe to call when none was\n * installed.\n *\n * @param component - The overlay whose trap should be removed.\n */\nexport function untrapWheel(component: Component): void {\n if (!_trapped.has(component)) {\n return;\n }\n\n _trapped.delete(component);\n Event.removeSubtreeListener(component, \"wheel\", swallowUnconsumedWheel);\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 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 Event.addViewportListener(source, \"selectstart\", onSelectStart);\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 * Suppresses the browser's own text-selection gesture for the duration of a\n * drag session, which would otherwise run alongside it now that table cell\n * text is selectable — the drag is mouse-driven (mousedown/mousemove), not\n * HTML5 drag-and-drop, so nothing else stops a selection from painting in\n * parallel. `preventDefault()` on `mousemove` does not by itself stop the\n * browser from extending a selection (verified live: the selection still\n * grew with every `mousemove` observably prevented), so the suppression has\n * to target `selectstart` itself. Registered and torn down alongside the\n * mousemove/mouseup viewport listeners, so it is live only while a session\n * exists — including the brief press-to-release window of a plain click\n * that never crosses the drag threshold, where losing the (invisible)\n * collapsed-caret placement a real `selectstart` would otherwise produce\n * has no observable effect on a non-editable table cell.\n *\n * @returns Always suppresses the event while installed.\n */\nfunction onSelectStart(): Event.ListenerResult {\n return { stop: true, prevent: true };\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 { stop: true, prevent: 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 { stop: true, prevent: 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 { stop: true, prevent: true };\n }\n\n if (session.currentTarget !== target.component) {\n leaveCurrentTarget(session, detail);\n enterNewTarget(session, target, detail);\n\n return { stop: true, prevent: 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 { stop: true, prevent: 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 { stop: true, prevent: 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 Event.removeViewportListener(session.source, \"selectstart\", onSelectStart);\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","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { ComponentOptions } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Checkbox } from \"~/component/input/Checkbox.js\";\nimport { MenuItem } from \"~/component/container/MenuItem.js\";\nimport { MenuRow } from \"~/component/container/MenuRow.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/** Events exposed by {@link CheckboxMenuRow}. */\nexport type CheckboxMenuRowEvent = \"action\";\n\n// Dim applied to a disabled row, matching the framework's other composite\n// disabled controls (Button.setEnabled, NumberSpinner.applyEnabled).\nconst DISABLED_OPACITY = 0.5;\n\n/**\n * Construction-time options for {@link CheckboxMenuRow}.\n *\n * @category Components\n */\nexport interface CheckboxMenuRowOptions extends ComponentOptions {\n /** Row label, rendered beside the checkbox graphic. */\n text?: string;\n /** Initial checked state. Defaults to `false`. */\n checked?: boolean;\n /** Defaults to `true`. Disabled rows are dimmed and non-interactive. */\n enabled?: boolean;\n /**\n * Construction-time listener bag; `action` fires after each toggle.\n */\n listeners?: { action?: () => void };\n}\n\n/**\n * A [`Menu`](/api/overlay/classes/Menu) row hosting a real\n * [`Checkbox`](/api/component/input/classes/Checkbox), for a multi-select menu.\n *\n * Built via `{ row: () => new CheckboxMenuRow({ text, checked }) }` on a\n * `MenuItemConfig`. Toggles on a click anywhere in the row or on Enter (via\n * {@link activate}) and leaves the menu open — unlike a plain `MenuItem`,\n * activating it never closes the panel. `isNavigable()` reports `true`, so\n * the menu's roving arrow-key highlight lands on it like any other row.\n *\n * @category Components\n */\nclass CheckboxMenuRow extends MenuRow<CheckboxMenuRowOptions> {\n\n private _checkbox: Checkbox;\n // The title offset the owning Menu pushed in, or null when this row is\n // standalone — in which case doLayout falls back to MenuItem.TEXT_INSET.\n private _iconStart: number | null = null;\n // The check-column width the owning Menu pushed in, alongside _iconStart —\n // needed to tell whether _iconStart was widened for a sibling's icon (see\n // doLayout's `iconColumnReserved`).\n private _checkZone: number | null = null;\n\n private readonly _onMouseOver: () => void;\n private readonly _onMouseOut: () => void;\n private readonly _onClick: () => void;\n\n /**\n * Constructs a CheckboxMenuRow.\n *\n * @param options - Optional construction-time options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: CheckboxMenuRowOptions, subclassDefaults?: Partial<CheckboxMenuRowOptions>) {\n super(options, subclassDefaults);\n\n // `text` / `checked` are read from the raw constructor argument, not\n // `this._options`: neither field has a matching setter for\n // `applyOptions` to dispatch through (there is no live `setText`, and\n // `setChecked` below writes straight to `_checkbox`, which cannot\n // exist yet during the `super()` cascade), so `this._options` is\n // never populated for them — `_checkbox` itself is the state cache\n // for `checked` from this point on.\n this._checkbox = new Checkbox({\n label: options?.text ?? \"\",\n selected: options?.checked ?? false,\n enabled: options?.enabled ?? true,\n });\n // Pointer-inert child so a click anywhere in the row hits the row\n // element and toggles — the same arrangement MenuItem uses for its\n // five labels and SelectableListRow uses for its renderer. The row's\n // own `click` listener is exact-target, so the Checkbox's internal\n // synthetic click (fired from setSelected on its own element) cannot\n // re-enter it.\n this._checkbox.setPointerEvents(\"none\");\n this.addComponent(this._checkbox);\n\n if (options?.enabled === false) {\n // Pointer-inert, not merely guarded: a consumer's `on(\"action\", …)`\n // handler is a second click listener on this row, which no guard\n // inside `activate()` can suppress. Keeping the click off the row\n // is what makes a disabled row truly non-interactive.\n this.setPointerEvents(\"none\");\n this.setOpacity(DISABLED_OPACITY);\n }\n\n this._onMouseOver = () => {\n this.setFocused(true);\n };\n\n this._onMouseOut = () => {\n this.setFocused(false);\n };\n\n this._onClick = () => {\n this.activate();\n };\n\n Event.addListener(this, \"mouseover\", this._onMouseOver);\n Event.addListener(this, \"mouseout\", this._onMouseOut);\n Event.addListener(this, \"click\", this._onClick);\n\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Returns the row's current checked state.\n *\n * @returns Whether the checkbox is currently checked.\n */\n isChecked(): boolean {\n return this._checkbox.isSelected();\n }\n\n /**\n * Sets the checked state.\n *\n * @param value - `true` to check, `false` to uncheck.\n * @returns This row, for method chaining.\n */\n setChecked(value: boolean): this {\n this._checkbox.setSelected(value);\n\n return this;\n }\n\n /**\n * Returns `true` — a `CheckboxMenuRow` behaves like a menu item, so the\n * menu's roving highlight lands on it and Enter activates it.\n *\n * @returns `true`.\n */\n isNavigable(): boolean {\n return true;\n }\n\n /**\n * Overrides {@link MenuRow.isEnabled}, reading the inner `Checkbox`'s\n * own enabled state — the cache for this row's `enabled` option, just as\n * it already is for `checked`.\n *\n * @returns Whether this row is interactive.\n */\n isEnabled(): boolean {\n return this._checkbox.isEnabled();\n }\n\n /**\n * Flips the checkbox. Called by a click on the row or by\n * `Menu.activateFocused()` on Enter. A no-op when the row is disabled.\n */\n activate(): void {\n if (!this.isEnabled()) {\n return;\n }\n\n this.setChecked(!this.isChecked());\n }\n\n /**\n * Returns the row's own content width — the checkbox's natural width\n * plus right padding, excluding any left inset of its own (`Menu` adds\n * the shared `iconStart` uniformly; see {@link MenuRow.getContentWidth}).\n * Read by `Menu.layOutColumns` **before** {@link setColumns} runs, so\n * this must never depend on the injected `iconStart` value itself.\n *\n * @returns The row's preferred content width in pixels.\n */\n getContentWidth(): number {\n const width = Math.ceil(this._checkbox.getPreferredSize()?.width ?? 0);\n\n return width + MenuItem.RIGHT_PAD;\n }\n\n /**\n * Stores the menu-computed left offset so the checkbox lines up with the\n * `MenuItem`s around it. `titleColumn` is unused — this row has no shared\n * title column of its own.\n *\n * @param checkZone - Width reserved for the menu's leading checkmark column.\n * @param iconStart - The left offset (in pixels) to align the checkbox to.\n * @param _titleColumn - Unused.\n */\n setColumns(checkZone: number, iconStart: number, _titleColumn: number): void {\n this._checkZone = checkZone;\n this._iconStart = iconStart;\n this.scheduleLayout();\n }\n\n /**\n * Positions the checkbox within the row's content box, vertically\n * centred, at the injected `iconStart` (or `MenuItem.TEXT_INSET` when\n * this row was never given one).\n *\n * When a sibling row reserves an icon column, `iconStart` is pushed out\n * to align with icon rows' *title text* — past their icon — which would\n * otherwise indent this row's checkbox behind an icon-sized gap of empty\n * space. Aligning with the icon's own position instead (`checkZone + 4`,\n * matching {@link MenuItem}'s icon inset) keeps the checkbox flush with\n * where a sibling's icon renders, since the checkbox plays the same\n * visual role. With no icon column, `iconStart` already collapses to\n * `checkZone + MenuItem.TEXT_INSET`, so this leaves a plain\n * checkbox-only menu's layout unchanged.\n *\n * @returns This row, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const box = this.getContentBounds();\n\n if (!box) {\n return this;\n }\n\n const size = this._checkbox.getPreferredSize() ?? { width: 0, height: 0 };\n const checkZone = this._checkZone ?? 0;\n const iconColumnReserved = this._iconStart !== null && this._iconStart - checkZone === MenuItem.ICON_ZONE;\n const left = iconColumnReserved ? checkZone + 4 : (this._iconStart ?? MenuItem.TEXT_INSET);\n const top = Math.max(0, Math.floor((box.height - size.height) / 2));\n\n this._checkbox.setX(box.x + left);\n this._checkbox.setY(box.y + top);\n this._checkbox.setWidth(Math.max(0, box.width - left - MenuItem.RIGHT_PAD));\n this._checkbox.setHeight(size.height);\n\n return this;\n }\n\n /**\n * Registers a listener for this row's `\"action\"` event — fired after\n * each toggle (click or {@link activate}). A typed semantic shorthand\n * over {@link Event.addListener} (the underlying DOM event is `\"click\"`).\n *\n * @param event - The event name. Only `\"action\"` is accepted.\n * @param listener - The callback to invoke after each toggle.\n * @returns This row, for method chaining.\n */\n on(event: \"action\", listener: () => void): this;\n on(_event: \"action\", listener: () => void): this {\n Event.addListener(this, \"click\", listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered `\"action\"` listener.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n * @returns This row, for method chaining.\n */\n off(event: \"action\", listener: () => void): this;\n off(_event: \"action\", listener: () => void): this {\n Event.removeListener(this, \"click\", listener);\n\n return this;\n }\n}\n\nconst CheckboxMenuRowCallable = callable(CheckboxMenuRow);\ntype CheckboxMenuRowCallable = CheckboxMenuRow;\nexport {\n CheckboxMenuRow as _CheckboxMenuRow,\n CheckboxMenuRowCallable as CheckboxMenuRow\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./rolldown-runtime-O8uOSEUP.js";import{t}from"./DOM-Ba8YRVel.js";import{h as n,r,t as i,v as a}from"./Component-w65rPK75.js";import{t as o}from"./ListenerBag-WPdKuuds.js";import{t as s}from"./LanguageRegistry-CcVnbKuh.js";import{EditorView as c,drawSelection as l,highlightActiveLine as u,highlightActiveLineGutter as d,keymap as f,lineNumbers as p}from"@codemirror/view";import{Compartment as m,EditorState as h}from"@codemirror/state";import{defaultKeymap as g,history as _,historyKeymap as v,indentWithTab as y}from"@codemirror/commands";import{HighlightStyle as b,bracketMatching as x,indentOnInput as S,indentRange as C,syntaxHighlighting as w}from"@codemirror/language";import{tags as T}from"@lezer/highlight";var E=`#2563eb`,D=`#16a34a`,O=`#6b7280`,k=`#d97706`,A=`#7c3aed`,j=`#0891b2`,M=`#be185d`;function codeEditorTheme(e){return[c.theme({"&":{height:`100%`,color:`var(--ts-ui-text-color, #1a1a1a)`,backgroundColor:`var(--ts-ui-input-bg, #ffffff)`},".cm-content":{fontFamily:`var(--ts-ui-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)`,caretColor:`var(--ts-ui-indicator-focus, #2563eb)`,cursor:`text`},".cm-gutters":{color:`var(--ts-ui-text-color, #1a1a1a)`,backgroundColor:`var(--ts-ui-input-bg, #ffffff)`,borderRight:`1px solid var(--ts-ui-border-color, rgba(127, 127, 127, 0.4))`},"&.cm-focused .cm-cursor":{borderLeftColor:`var(--ts-ui-indicator-focus, #2563eb)`},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground":{backgroundColor:`var(--ts-ui-indicator-selection, rgba(37, 99, 235, 0.25))`},".cm-activeLine, .cm-activeLineGutter":{backgroundColor:`rgba(127, 127, 127, 0.08)`}},{dark:e}),w(b.define([{tag:T.keyword,color:E},{tag:[T.string,T.special(T.string)],color:D},{tag:T.comment,color:O,fontStyle:`italic`},{tag:[T.number,T.bool,T.null],color:k},{tag:[T.definition(T.variableName),T.function(T.variableName)],color:A},{tag:T.typeName,color:j},{tag:[T.propertyName,T.attributeName],color:M},{tag:T.tagName,color:E},{tag:[T.heading,T.heading1,T.heading2,T.heading3,T.heading4,T.heading5,T.heading6],color:E,fontWeight:`bold`},{tag:T.strong,fontWeight:`bold`},{tag:T.emphasis,fontStyle:`italic`},{tag:T.monospace,color:D},{tag:[T.link,T.url],color:E,textDecoration:`underline`},{tag:[T.quote,T.contentSeparator],color:O},{tag:T.processingInstruction,color:O}]))]}var N=e({CodeEditor:()=>V,_CodeEditor:()=>CodeEditor}),P={overflow:`auto`},F=`.cm-scroller`,I=`.cm-content`,L=1,R=300,z=.16,B=`var(--ts-ui-validation-error-border, #dc2626)`;function buildReadOnlyExtension(e){return h.readOnly.of(e)}var CodeEditor=class extends i{_view=null;_flashOverlay=null;_flashAnimation=null;_langCompartment=new m;_readOnlyCompartment=new m;_themeCompartment=new m;_listeners=new o;_unsubscribeTheme;_scrollElement=null;_contentElement=null;_lastSyncedShape=null;_lastHbarReserve=0;constructor(e,t,n){super(t,{...P,...n??{}}),e!==void 0&&this._options.value===void 0&&(this._options.value=e),this._unsubscribeTheme=r.onThemeChange(()=>this.onThemeChange()),this.applyListeners(t?.listeners),this.onFirstLayout(()=>this.mount())}applyOptions(e){return super.applyOptions(e),e.value!==void 0&&(this._options.value=e.value),e.language!==void 0&&(this._options.language=e.language),e.readOnly!==void 0&&(this._options.readOnly=e.readOnly),e.autoHeightMaxRows!==void 0&&(this._options.autoHeightMaxRows=e.autoHeightMaxRows),this}getValue(){return this._view?this._view.state.doc.toString():this._options.value??``}setValue(e){return this._options.value=e,this._view&&this._view.dispatch({changes:{from:0,to:this._view.state.doc.length,insert:e}}),this}getLanguage(){return this._options.language??null}setLanguage(e){if(this._options.language=e??void 0,!this._view)return this;if(!e)return this._view.dispatch({effects:this._langCompartment.reconfigure([])}),this;let t=s(e);return t&&t.loadExtension().then(t=>{this._view&&this.getLanguage()===e&&this._view.dispatch({effects:this._langCompartment.reconfigure(t)})}),this}getReadOnly(){return this._options.readOnly??!1}setReadOnly(e){return this._options.readOnly=e,this._view&&this._view.dispatch({effects:this._readOnlyCompartment.reconfigure(buildReadOnlyExtension(e))}),this}getAutoHeightMaxRows(){return this._options.autoHeightMaxRows??null}focus(e=!1){return this._view?(this._view.focus(),this):super.focus(e)}moveCursorToEnd(){if(this._view){let e=this._view.state.doc.length;this._view.dispatch({selection:{anchor:e},scrollIntoView:!0})}return this}async format(){let e=this.getLanguage(),t=e?s(e):void 0;if(!t?.loadFormatter){this.reindentFallback();return}let n=await(await t.loadFormatter())(this.getValue(),this._view?this._view.state.selection.main.head:0);this._options.value=n.formatted,this._view&&this._view.dispatch({changes:{from:0,to:this._view.state.doc.length,insert:n.formatted},selection:{anchor:Math.min(n.cursorOffset,n.formatted.length)}})}reindentFallback(){this._view&&this._view.dispatch({changes:C(this._view.state,0,this._view.state.doc.length)})}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?[t]:[])}destructor(){this._flashAnimation?.cancel(),this._flashAnimation=null,this._unsubscribeTheme(),this._scrollElement=null,this._contentElement=null,this._view?.destroy(),this._view=null,super.destructor()}getScrollElement(){return this._scrollElement??super.getScrollElement()}mount(){if(this._view)return;let e=this.getElement();if(!e)return;let n=r.getTheme().colorScheme===`dark`,i=[_(),f.of([...g,...v,y]),l(),p(),u(),d(),S(),x(),this._readOnlyCompartment.of(buildReadOnlyExtension(this.getReadOnly())),this._themeCompartment.of(codeEditorTheme(n)),this._langCompartment.of([]),c.updateListener.of(e=>{e.docChanged&&(this._options.value=e.state.doc.toString(),this.emit(`change`,{value:this._options.value})),(e.heightChanged||e.geometryChanged)&&this.syncAutoHeight(e.selectionSet&&!e.docChanged)}),c.domEventHandlers({beforeinput:()=>this.onEditIntent(),paste:()=>this.onEditIntent(),drop:()=>this.onEditIntent()})],a=h.create({doc:this._options.value??``,extensions:i});this._view=t.sink.mountView(e,e=>new c({parent:e,state:a})),this._view&&(this.mountFlashOverlay(e),this._scrollElement=t.source.querySelector(e,F),this._scrollElement&&(this._contentElement=t.source.querySelector(this._scrollElement,I)),this._scrollElement&&this.getAutoHeightMaxRows()!==null&&t.sink.apply(this._scrollElement,{style:{paddingBottom:`1px`,scrollbarGutter:`stable`}}));let o=this.getLanguage();o&&this.setLanguage(o),this.syncAutoHeight()}syncAutoHeight(e=!1){let n=this.getAutoHeightMaxRows();if(!this._view||n===null||!this._scrollElement)return;let r=t.source.getScrollMetrics(this._scrollElement),i=this._view.documentPadding.top+this._view.documentPadding.bottom,a=(r.scrollHeight-i)/this._view.state.doc.lines*n+i,o=Math.min(r.scrollHeight,a);if(e&&o>this.getHeight())return;let s=[this._view.state.doc.lines,this._view.state.doc.length,r.clientWidth],c=this._lastSyncedShape===null||s.some((e,t)=>e!==this._lastSyncedShape[t]);this._lastSyncedShape=s;let l=this.getHeight(),u=r.clientHeight;if(c&&(this.setHeight(o),u=t.source.getScrollMetrics(this._scrollElement).clientHeight,r.scrollHeight<=a&&this._contentElement)){let e=t.source.getElementRect(this._contentElement).height,n=t.source.getElementRect(this._scrollElement).height-L;o+=Math.max(0,e-n)}let d=t.source.getOffsetSize(this._scrollElement);this._lastHbarReserve=Math.max(0,d.offsetHeight-u);let f=o+this._lastHbarReserve;f!==l&&(f>l&&!c||f<l&&!c&&l-f<1||(this.setHeight(f),this.emit(`heightchange`,{height:f})))}mountFlashOverlay(e){let n=this.trackHandle(t.sink.createElement(`div`));t.sink.apply(n,{style:{position:`absolute`,inset:`0`,pointerEvents:`none`,zIndex:`300`,backgroundColor:B,opacity:`0`}}),t.sink.appendChild(e,n),this._flashOverlay=n}onThemeChange(){if(!this._view)return;let e=r.getTheme().colorScheme===`dark`;this._view.dispatch({effects:this._themeCompartment.reconfigure(codeEditorTheme(e))})}onEditIntent(){return this.getReadOnly()&&this.signalReadOnlyEdit(),!1}signalReadOnlyEdit(){this.emit(`readonlyedit`),this.flashReadOnly()}flashReadOnly(){this._flashOverlay&&(this._flashAnimation?.cancel(),this._flashAnimation=a.play(this._flashOverlay,{from:{opacity:String(z)},to:{opacity:`0`},durationMs:R,properties:[`opacity`]}))}},V=n(CodeEditor);export{N as n,V as t};
2
- //# sourceMappingURL=CodeEditor-BGlB232h.js.map
1
+ import{t as e}from"./rolldown-runtime-O8uOSEUP.js";import{t}from"./DOM-C-Edb3tA.js";import{h as n,r,t as i,v as a}from"./Component-B0ShfPVi.js";import{t as o}from"./ListenerBag-WPdKuuds.js";import{t as s}from"./LanguageRegistry-CcVnbKuh.js";import{EditorView as c,drawSelection as l,highlightActiveLine as u,highlightActiveLineGutter as d,keymap as f,lineNumbers as p}from"@codemirror/view";import{Compartment as m,EditorState as h}from"@codemirror/state";import{defaultKeymap as g,history as _,historyKeymap as v,indentWithTab as y}from"@codemirror/commands";import{HighlightStyle as b,bracketMatching as x,indentOnInput as S,indentRange as C,syntaxHighlighting as w}from"@codemirror/language";import{tags as T}from"@lezer/highlight";var E=`#2563eb`,D=`#16a34a`,O=`#6b7280`,k=`#d97706`,A=`#7c3aed`,j=`#0891b2`,M=`#be185d`;function codeEditorTheme(e){return[c.theme({"&":{height:`100%`,color:`var(--ts-ui-text-color, #1a1a1a)`,backgroundColor:`var(--ts-ui-input-bg, #ffffff)`},".cm-content":{fontFamily:`var(--ts-ui-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)`,caretColor:`var(--ts-ui-indicator-focus, #2563eb)`,cursor:`text`},".cm-gutters":{color:`var(--ts-ui-text-color, #1a1a1a)`,backgroundColor:`var(--ts-ui-input-bg, #ffffff)`,borderRight:`1px solid var(--ts-ui-border-color, rgba(127, 127, 127, 0.4))`},"&.cm-focused .cm-cursor":{borderLeftColor:`var(--ts-ui-indicator-focus, #2563eb)`},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground":{backgroundColor:`var(--ts-ui-indicator-selection, rgba(37, 99, 235, 0.25))`},".cm-activeLine, .cm-activeLineGutter":{backgroundColor:`rgba(127, 127, 127, 0.08)`}},{dark:e}),w(b.define([{tag:T.keyword,color:E},{tag:[T.string,T.special(T.string)],color:D},{tag:T.comment,color:O,fontStyle:`italic`},{tag:[T.number,T.bool,T.null],color:k},{tag:[T.definition(T.variableName),T.function(T.variableName)],color:A},{tag:T.typeName,color:j},{tag:[T.propertyName,T.attributeName],color:M},{tag:T.tagName,color:E},{tag:[T.heading,T.heading1,T.heading2,T.heading3,T.heading4,T.heading5,T.heading6],color:E,fontWeight:`bold`},{tag:T.strong,fontWeight:`bold`},{tag:T.emphasis,fontStyle:`italic`},{tag:T.monospace,color:D},{tag:[T.link,T.url],color:E,textDecoration:`underline`},{tag:[T.quote,T.contentSeparator],color:O},{tag:T.processingInstruction,color:O}]))]}var N=e({CodeEditor:()=>V,_CodeEditor:()=>CodeEditor}),P={overflow:`auto`},F=`.cm-scroller`,I=`.cm-content`,L=1,R=300,z=.16,B=`var(--ts-ui-validation-error-border, #dc2626)`;function buildReadOnlyExtension(e){return h.readOnly.of(e)}var CodeEditor=class extends i{_view=null;_flashOverlay=null;_flashAnimation=null;_langCompartment=new m;_readOnlyCompartment=new m;_themeCompartment=new m;_listeners=new o;_unsubscribeTheme;_scrollElement=null;_contentElement=null;_lastSyncedShape=null;_lastHbarReserve=0;constructor(e,t,n){super(t,{...P,...n??{}}),e!==void 0&&this._options.value===void 0&&(this._options.value=e),this._unsubscribeTheme=r.onThemeChange(()=>this.onThemeChange()),this.applyListeners(t?.listeners),this.onFirstLayout(()=>this.mount())}applyOptions(e){return super.applyOptions(e),e.value!==void 0&&(this._options.value=e.value),e.language!==void 0&&(this._options.language=e.language),e.readOnly!==void 0&&(this._options.readOnly=e.readOnly),e.autoHeightMaxRows!==void 0&&(this._options.autoHeightMaxRows=e.autoHeightMaxRows),this}getValue(){return this._view?this._view.state.doc.toString():this._options.value??``}setValue(e){return this._options.value=e,this._view&&this._view.dispatch({changes:{from:0,to:this._view.state.doc.length,insert:e}}),this}getLanguage(){return this._options.language??null}setLanguage(e){if(this._options.language=e??void 0,!this._view)return this;if(!e)return this._view.dispatch({effects:this._langCompartment.reconfigure([])}),this;let t=s(e);return t&&t.loadExtension().then(t=>{this._view&&this.getLanguage()===e&&this._view.dispatch({effects:this._langCompartment.reconfigure(t)})}),this}getReadOnly(){return this._options.readOnly??!1}setReadOnly(e){return this._options.readOnly=e,this._view&&this._view.dispatch({effects:this._readOnlyCompartment.reconfigure(buildReadOnlyExtension(e))}),this}getAutoHeightMaxRows(){return this._options.autoHeightMaxRows??null}focus(e=!1){return this._view?(this._view.focus(),this):super.focus(e)}moveCursorToEnd(){if(this._view){let e=this._view.state.doc.length;this._view.dispatch({selection:{anchor:e},scrollIntoView:!0})}return this}async format(){let e=this.getLanguage(),t=e?s(e):void 0;if(!t?.loadFormatter){this.reindentFallback();return}let n=await(await t.loadFormatter())(this.getValue(),this._view?this._view.state.selection.main.head:0);this._options.value=n.formatted,this._view&&this._view.dispatch({changes:{from:0,to:this._view.state.doc.length,insert:n.formatted},selection:{anchor:Math.min(n.cursorOffset,n.formatted.length)}})}reindentFallback(){this._view&&this._view.dispatch({changes:C(this._view.state,0,this._view.state.doc.length)})}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?[t]:[])}destructor(){this._flashAnimation?.cancel(),this._flashAnimation=null,this._unsubscribeTheme(),this._scrollElement=null,this._contentElement=null,this._view?.destroy(),this._view=null,super.destructor()}getScrollElement(){return this._scrollElement??super.getScrollElement()}mount(){if(this._view)return;let e=this.getElement();if(!e)return;let n=r.getTheme().colorScheme===`dark`,i=[_(),f.of([...g,...v,y]),l(),p(),u(),d(),S(),x(),this._readOnlyCompartment.of(buildReadOnlyExtension(this.getReadOnly())),this._themeCompartment.of(codeEditorTheme(n)),this._langCompartment.of([]),c.updateListener.of(e=>{e.docChanged&&(this._options.value=e.state.doc.toString(),this.emit(`change`,{value:this._options.value})),(e.heightChanged||e.geometryChanged)&&this.syncAutoHeight(e.selectionSet&&!e.docChanged)}),c.domEventHandlers({beforeinput:()=>this.onEditIntent(),paste:()=>this.onEditIntent(),drop:()=>this.onEditIntent()})],a=h.create({doc:this._options.value??``,extensions:i});this._view=t.sink.mountView(e,e=>new c({parent:e,state:a})),this._view&&(this.mountFlashOverlay(e),this._scrollElement=t.source.querySelector(e,F),this._scrollElement&&(this._contentElement=t.source.querySelector(this._scrollElement,I)),this._scrollElement&&this.getAutoHeightMaxRows()!==null&&t.sink.apply(this._scrollElement,{style:{paddingBottom:`1px`,scrollbarGutter:`stable`}}));let o=this.getLanguage();o&&this.setLanguage(o),this.syncAutoHeight()}syncAutoHeight(e=!1){let n=this.getAutoHeightMaxRows();if(!this._view||n===null||!this._scrollElement)return;let r=t.source.getScrollMetrics(this._scrollElement),i=this._view.documentPadding.top+this._view.documentPadding.bottom,a=(r.scrollHeight-i)/this._view.state.doc.lines*n+i,o=Math.min(r.scrollHeight,a);if(e&&o>this.getHeight())return;let s=[this._view.state.doc.lines,this._view.state.doc.length,r.clientWidth],c=this._lastSyncedShape===null||s.some((e,t)=>e!==this._lastSyncedShape[t]);this._lastSyncedShape=s;let l=this.getHeight(),u=r.clientHeight;if(c){if(this.setHeight(o),u=t.source.getScrollMetrics(this._scrollElement).clientHeight,r.scrollHeight<=a&&this._contentElement){let e=t.source.getElementRect(this._contentElement).height,n=t.source.getElementRect(this._scrollElement).height-L;o+=Math.max(0,e-n)}}else{let e=l-this._lastHbarReserve;o<e&&e-o>=1&&(o=e)}let d=t.source.getOffsetSize(this._scrollElement);this._lastHbarReserve=Math.max(0,d.offsetHeight-u);let f=o+this._lastHbarReserve;f!==l&&(f>l&&!c||f<l&&!c&&l-f<1||(this.setHeight(f),this.emit(`heightchange`,{height:f})))}mountFlashOverlay(e){let n=this.trackHandle(t.sink.createElement(`div`));t.sink.apply(n,{style:{position:`absolute`,inset:`0`,pointerEvents:`none`,zIndex:`300`,backgroundColor:B,opacity:`0`}}),t.sink.appendChild(e,n),this._flashOverlay=n}onThemeChange(){if(!this._view)return;let e=r.getTheme().colorScheme===`dark`;this._view.dispatch({effects:this._themeCompartment.reconfigure(codeEditorTheme(e))})}onEditIntent(){return this.getReadOnly()&&this.signalReadOnlyEdit(),!1}signalReadOnlyEdit(){this.emit(`readonlyedit`),this.flashReadOnly()}flashReadOnly(){this._flashOverlay&&(this._flashAnimation?.cancel(),this._flashAnimation=a.play(this._flashOverlay,{from:{opacity:String(z)},to:{opacity:`0`},durationMs:R,properties:[`opacity`]}))}},V=n(CodeEditor);export{N as n,V as t};
2
+ //# sourceMappingURL=CodeEditor-N1FQodcF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeEditor-N1FQodcF.js","names":[],"sources":["../../src/typescript/lib/component/editor/theme.ts","../../src/typescript/lib/component/editor/CodeEditor.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { EditorView } from \"@codemirror/view\";\nimport { HighlightStyle, syntaxHighlighting } from \"@codemirror/language\";\nimport { tags } from \"@lezer/highlight\";\nimport type { Extension } from \"@codemirror/state\";\n\n// The syntax palette has no dedicated project theme tokens (the framework\n// defines chrome/surface/accent tokens, not a per-token-kind syntax scheme),\n// so it is a fixed, IDE-conventional colour set chosen for light/dark\n// legibility rather than derived from CSS variables — mirroring how\n// `Markdown`'s code-block wash is a neutral constant rather than a token.\nconst SYNTAX_KEYWORD = \"#2563eb\"; // matches the framework's single accent hue\nconst SYNTAX_STRING = \"#16a34a\"; // green — conventional \"string\" colour\nconst SYNTAX_COMMENT = \"#6b7280\"; // muted grey — de-emphasises comments\nconst SYNTAX_LITERAL = \"#d97706\"; // amber — numbers/booleans/null\nconst SYNTAX_FUNCTION = \"#7c3aed\"; // violet — function/variable definitions\nconst SYNTAX_TYPE = \"#0891b2\"; // teal — type names\nconst SYNTAX_PROPERTY = \"#be185d\"; // pink — object/attribute property names\n\n/**\n * Builds the editor's theme extension: the chrome (background, gutters,\n * cursor, selection) via `EditorView.theme`, plus syntax-highlighting colours\n * via a `HighlightStyle`.\n *\n * The chrome reads the project's CSS custom-property tokens directly\n * (`--ts-ui-input-bg`, `--ts-ui-text-color`, `--ts-ui-font-mono`,\n * `--ts-ui-border-color`, `--ts-ui-indicator-focus`,\n * `--ts-ui-indicator-selection`), each with a light/dark-safe fallback, so a\n * `ThemeManager.setTheme` toggle recolours the editor with no rebuild — only\n * the underlying CSS variables change.\n *\n * @param dark - Whether the dark theme flag (`--ts-ui-color-scheme: dark`) is\n * currently active, forwarded to `EditorView.theme`'s `dark` option so\n * CodeMirror's own dark-mode heuristics (default scrollbar styling, base\n * theme selection) agree with the project's active theme.\n * @returns The combined chrome + syntax-highlighting extension.\n */\nexport function codeEditorTheme(dark: boolean): Extension {\n const chrome = EditorView.theme({\n \"&\": {\n height: \"100%\",\n color: \"var(--ts-ui-text-color, #1a1a1a)\",\n backgroundColor: \"var(--ts-ui-input-bg, #ffffff)\",\n },\n \".cm-content\": {\n fontFamily: \"var(--ts-ui-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)\",\n caretColor: \"var(--ts-ui-indicator-focus, #2563eb)\",\n cursor: \"text\",\n },\n \".cm-gutters\": {\n color: \"var(--ts-ui-text-color, #1a1a1a)\",\n backgroundColor: \"var(--ts-ui-input-bg, #ffffff)\",\n borderRight: \"1px solid var(--ts-ui-border-color, rgba(127, 127, 127, 0.4))\",\n },\n \"&.cm-focused .cm-cursor\": {\n borderLeftColor: \"var(--ts-ui-indicator-focus, #2563eb)\",\n },\n \"&.cm-focused .cm-selectionBackground, .cm-selectionBackground\": {\n backgroundColor: \"var(--ts-ui-indicator-selection, rgba(37, 99, 235, 0.25))\",\n },\n \".cm-activeLine, .cm-activeLineGutter\": {\n backgroundColor: \"rgba(127, 127, 127, 0.08)\",\n },\n }, { dark });\n\n const highlight = syntaxHighlighting(HighlightStyle.define([\n { tag: tags.keyword, color: SYNTAX_KEYWORD },\n { tag: [tags.string, tags.special(tags.string)], color: SYNTAX_STRING },\n { tag: tags.comment, color: SYNTAX_COMMENT, fontStyle: \"italic\" },\n { tag: [tags.number, tags.bool, tags.null], color: SYNTAX_LITERAL },\n { tag: [tags.definition(tags.variableName), tags.function(tags.variableName)], color: SYNTAX_FUNCTION },\n { tag: tags.typeName, color: SYNTAX_TYPE },\n { tag: [tags.propertyName, tags.attributeName], color: SYNTAX_PROPERTY },\n { tag: tags.tagName, color: SYNTAX_KEYWORD },\n // Markdown constructs (the `markdown` language, e.g. the MarkdownEditor\n // source surface). The parser tags these; without a style here they\n // would render as plain text. Headings/links reuse the accent hue; bold\n // and italic carry weight/slant rather than colour so prose stays\n // readable; the markup marks (`#`, `**`, `` ` ``, `>`, `-`) and quotes\n // are muted so the content reads over the syntax.\n { tag: [tags.heading, tags.heading1, tags.heading2, tags.heading3,\n tags.heading4, tags.heading5, tags.heading6], color: SYNTAX_KEYWORD, fontWeight: \"bold\" },\n { tag: tags.strong, fontWeight: \"bold\" },\n { tag: tags.emphasis, fontStyle: \"italic\" },\n { tag: tags.monospace, color: SYNTAX_STRING },\n { tag: [tags.link, tags.url], color: SYNTAX_KEYWORD, textDecoration: \"underline\" },\n { tag: [tags.quote, tags.contentSeparator], color: SYNTAX_COMMENT },\n { tag: tags.processingInstruction, color: SYNTAX_COMMENT },\n ]));\n\n return [chrome, highlight];\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Animation } from \"~/core/Animation.js\";\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { ThemeManager } from \"~/core/Theme.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { EditorView, keymap, drawSelection, lineNumbers, highlightActiveLine, highlightActiveLineGutter } from \"@codemirror/view\";\nimport { EditorState, Compartment } from \"@codemirror/state\";\nimport type { Extension } from \"@codemirror/state\";\nimport { history, defaultKeymap, historyKeymap, indentWithTab } from \"@codemirror/commands\";\nimport { indentOnInput, bracketMatching, indentRange } from \"@codemirror/language\";\nimport { getLanguage } from \"~/component/editor/LanguageRegistry.js\";\nimport { codeEditorTheme } from \"~/component/editor/theme.js\";\n\n/**\n * Payload of {@link CodeEditor}'s `\"change\"` event: the document text after\n * the edit that triggered it.\n *\n * @category Components\n */\nexport interface CodeEditorChange {\n value: string;\n}\n\n/**\n * Payload of {@link CodeEditor}'s `\"heightchange\"` event: the editor's new\n * height in pixels.\n *\n * @category Components\n */\nexport interface CodeEditorHeightChange {\n height: number;\n}\n\n/**\n * The events {@link CodeEditor} exposes through its custom `on` / `off` surface:\n *\n * - `\"change\"` — the document text changed (payload {@link CodeEditorChange}).\n * - `\"readonlyedit\"` — a user edit was rejected because the editor is read-only\n * (no payload); see {@link CodeEditor.on}.\n * - `\"heightchange\"` — {@link CodeEditorOptions.autoHeightMaxRows} is set and the\n * editor's own computed height changed (payload {@link CodeEditorHeightChange}).\n */\ntype CodeEditorEvent = \"change\" | \"readonlyedit\" | \"heightchange\";\n\n/**\n * Construction-time options for {@link CodeEditor}.\n *\n * @category Components\n */\nexport interface CodeEditorOptions extends ComponentOptions {\n /** Initial document text (also accepted as the positional first argument). */\n value?: string;\n /** Registered language id (e.g. `\"javascript\"`, `\"json\"`, `\"sql\"`). Unset renders plain text. */\n language?: string;\n /** Whether the editor rejects edits. Default `false`. */\n readOnly?: boolean;\n /**\n * Row count the editor grows to fit before its own vertical scrollbar\n * takes over. Unset (the default): today's behaviour — a fixed height\n * the caller controls via `setHeight`/`preferredSize`, filling its host.\n */\n autoHeightMaxRows?: number;\n /** Construction-time listener bag; the events are `\"change\"`, `\"readonlyedit\"`, and `\"heightchange\"`. */\n listeners?: { change?: (payload: CodeEditorChange) => void; readonlyedit?: () => void; heightchange?: (payload: CodeEditorHeightChange) => void };\n}\n\n/**\n * User-overridable defaults forwarded to `super` via the options bag. The\n * cascade in `Component`'s constructor dispatches each setter once with the\n * final value, so any field the caller supplied wins.\n */\nconst _defaultCodeEditorOptions: Partial<CodeEditorOptions> = {\n // Override Component's `overflow: \"hidden\"` default so the framework's\n // eased wheel scroller attaches: `applyStyle` reads the effective overflow\n // and installs the controller from it (see `Component.applyOverflowStyles`\n // -> `refreshWheelScrolling`), which then drives whatever\n // `getScrollElement` resolves to — CodeMirror's `.cm-scroller` once the\n // view is mounted. Inert as a style: `.cm-editor` is `height: 100%` and the\n // flash overlay is `inset: 0`, so the editor's own box has no overflow to\n // scroll and never paints a native bar of its own. This mirrors how an\n // overlay-mode `Panel` keeps `overflow: auto` on a panel element that can\n // likewise never scroll.\n overflow: \"auto\",\n};\n\n/** CodeMirror's scrolling viewport element, inside the mounted view. */\nconst CM_SCROLLER_SELECTOR = \".cm-scroller\";\n\n/** CodeMirror's content element, inside `.cm-scroller`. */\nconst CM_CONTENT_SELECTOR = \".cm-content\";\n\n// Padding-bottom applied once to an auto-height editor's `.cm-scroller`\n// (see the `_scrollElement` resolution in `mount`) so a sub-pixel content\n// overhang can never leave the scroller a fraction of a pixel short and\n// paint a permanent, non-functional vertical scrollbar. `.cm-scroller`'s\n// `scrollHeight` is a whole number but the content it measures is not, so\n// committing the reported extent verbatim discards up to a pixel of real\n// content. This must be a fixed, one-time style, not part of the height\n// `syncAutoHeight` (re)computes on every call: `.cm-content`'s own\n// `min-height: 100%` means its rendered height — and so `.cm-scroller`'s\n// `scrollHeight`, which can never report less than the scroller's own\n// `clientHeight` — floors at whatever height was last committed, so adding\n// this slop to the committed height itself fed straight back into the next\n// measurement and ratcheted the editor's height upward forever. Mirrors\n// ScrollStrip.arrowReserve's `+1` slop against the same rounding noise.\nconst SUBPIXEL_HEIGHT_SLOP_PX = 1;\n\n// `syncAutoHeight` trusts a height GROWTH only on the call where the\n// document/width shape genuinely changed (a real edit or resize) — never\n// again against the same shape, no matter how plausible the reading looks.\n// Committing a height changes `.cm-scroller`'s real `clientHeight`;\n// CodeMirror's own `ViewState.measure()` (@codemirror/view) runs on its own\n// schedule and compares that live value against its cached copy on every\n// pass, reporting a fresh `geometryChanged` update whenever they differ —\n// which they always do, immediately after any commit. That re-invokes\n// `syncAutoHeight` with no genuine content or width change. On a real\n// (non-integer) device-pixel ratio the re-measurement does not reliably read\n// back the exact value just committed (unlike the mount-time case\n// `SUBPIXEL_HEIGHT_SLOP_PX` handles, which converges): it can read\n// fractionally MORE, live-observed climbing by tens of pixels roughly every\n// 100ms, forever, with the editor merely visible and no further interaction.\n// A one-growth-of-slack budget was tried first, on the theory that an\n// initial pre-layout guess might need exactly one accurate follow-up once\n// CodeMirror's real layout became available. Live testing across several\n// unrelated blocks (Dialog, Drawer, LineChart, Button) refuted that: the\n// \"follow-up\" fired on essentially every multi-line editor regardless of\n// whether real settling was needed, each time adding a line or two of dead\n// space with nothing behind it — the same self-referential echo the\n// unbounded case shows, just bounded to a single step instead of climbing\n// forever. There is no reliable signal that distinguishes a genuine\n// follow-up correction from this echo, so none is trusted; a block whose\n// first, always-free commit undershoots true content is a distinct bug (the\n// initial measurement itself, not this guard) to fix at the source.\n\n/** Duration of the read-only rejection flash, in milliseconds. */\nconst READONLY_FLASH_MS = 300;\n\n/** Peak opacity of the read-only rejection wash — a subtle tint that keeps the text readable. */\nconst READONLY_FLASH_PEAK_OPACITY = 0.16;\n\n/**\n * Fill of the read-only rejection wash: the project's validation-error token,\n * with a light/dark-safe fallback, so the tint follows a `ThemeManager.setTheme`\n * toggle with no rebuild (the CSS variable resolves live).\n */\nconst READONLY_FLASH_COLOR = \"var(--ts-ui-validation-error-border, #dc2626)\";\n\n/**\n * Builds the readOnly-state extension: `EditorState.readOnly` blocks every\n * edit (including programmatic ones) while leaving the content DOM editable, so\n * the caret, cursor navigation, and text selection / copy all keep working —\n * the standard read-only experience. (`EditorView.editable.of(false)` would\n * additionally strip selection by making CodeMirror stop managing a caret in\n * the content, so it is deliberately *not* used here.)\n *\n * @param readOnly - Whether the editor should reject edits.\n * @returns The extension for the readOnly compartment.\n */\nfunction buildReadOnlyExtension(readOnly: boolean): Extension {\n return EditorState.readOnly.of(readOnly);\n}\n\n/**\n * A syntax-highlighting, formatting code editor wrapping CodeMirror 6.\n *\n * @remarks\n * `CodeEditor` deliberately omits IntelliSense (no autocomplete, no lint, no\n * language service) — its scope is highlighting plus one-command formatting.\n * CodeMirror's `EditorView` is a *foreign live widget*: it takes a real parent\n * element and mutates a whole DOM region it owns directly, exactly like the\n * `CanvasRenderingContext2D` a [`Canvas`](/api/component/display/classes/Canvas)\n * obtains from the seam. So `CodeEditor` is **live-only** — under the modelled\n * test sink it mounts nothing, and every editor operation guards on a `null`\n * view, matching `Canvas` / `WebGLCanvas`.\n *\n * The editor mounts once, in the component's first connected + sized layout\n * (`onFirstLayout`) — CodeMirror needs a real, sized parent to measure its\n * internal scroller correctly. It fills the assigned box and scrolls\n * internally; give it a sized host (a `Fit` panel or an explicit\n * `preferredSize`), the same as `Canvas`.\n *\n * Highlighting grammars and formatters load lazily, per language, through the\n * registry in `LanguageRegistry.ts` (`registerLanguage` / `getLanguage` /\n * `listLanguages`) — see that module and `languages.ts` for the five built-in\n * languages (JavaScript/TypeScript, JSON, HTML, SQL, Markdown).\n *\n * @example\n * ```typescript\n * import { CodeEditor } from '@jimka/typescript-ui/component/editor';\n *\n * const editor = new CodeEditor('const x = 1;', { language: 'javascript' });\n * panel.addComponent(editor);\n * await editor.format();\n * ```\n *\n * @category Components\n */\nclass CodeEditor extends Component<CodeEditorOptions> {\n\n /** The live CodeMirror view; `null` until mounted (or forever, offline). */\n private _view: EditorView | null = null;\n\n /** Overlay flashed on a rejected read-only edit; `null` until mounted (or forever, offline). */\n private _flashOverlay: Handle | null = null;\n\n // In-flight read-only flash, cancelled on teardown so its fallback timer\n // cannot fire against the overlay's released element handle.\n private _flashAnimation: Animation.CancelHandle | null = null;\n\n /** Reconfigured by {@link CodeEditor.setLanguage} to swap the active grammar. */\n private readonly _langCompartment: Compartment = new Compartment();\n\n /** Reconfigured by {@link CodeEditor.setReadOnly}. */\n private readonly _readOnlyCompartment: Compartment = new Compartment();\n\n /** Reconfigured on a theme change to recolour the editor. */\n private readonly _themeCompartment: Compartment = new Compartment();\n\n /** Custom-event fan-out for `\"change\"`. */\n private readonly _listeners: ListenerBag<CodeEditorEvent> = new ListenerBag<CodeEditorEvent>();\n\n /** Handle to detach the {@link ThemeManager.onThemeChange} listener on {@link CodeEditor.dispose}. */\n private readonly _unsubscribeTheme: () => void;\n\n /**\n * Handle for CodeMirror's own scrolling viewport, resolved once the view\n * mounts; `null` until then (or forever, offline). Backs\n * {@link CodeEditor.getScrollElement}.\n */\n private _scrollElement: Handle | null = null;\n\n /**\n * Handle for CodeMirror's own content element (`.cm-content`, inside\n * `.cm-scroller`), resolved once the view mounts; `null` until then (or\n * forever, offline). Used by {@link CodeEditor.syncAutoHeight} to read\n * its true, fractional rendered content height — `scrollHeight` /\n * `clientHeight` are integer DOM properties that can round away a\n * sub-pixel shortfall this element's own `getBoundingClientRect` still\n * shows.\n */\n private _contentElement: Handle | null = null;\n\n /**\n * `[lines, docLength, clientWidth]` as of the last call to\n * `syncAutoHeight`, or `null` before the first call. Used to tell a\n * genuine content/width change from a self-triggered geometry echo — a\n * growth is trusted only when this differs from the previous call, and\n * so is a content shrink of a pixel or more (a smaller, sub-pixel\n * content shrink is rounding noise regardless of this tuple).\n */\n private _lastSyncedShape: readonly [number, number, number] | null = null;\n\n /**\n * Horizontal-scrollbar height reserve, re-measured on every call to\n * `syncAutoHeight` (rendered content width — and so a real scrollbar's\n * presence — can change without the document/width shape itself\n * changing, e.g. once an async language grammar finishes loading and\n * re-flows the text). Cached here only so a later call can fold it into\n * `desired` without re-deriving it. See\n * {@link CodeEditor.syncAutoHeight}'s `@remarks` for why it's measured\n * this way at all.\n */\n private _lastHbarReserve = 0;\n\n /**\n * Constructs a code editor.\n *\n * @param value - Initial document text (optional; defaults to \"\").\n * @param options - Optional construction options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(value?: string, options?: CodeEditorOptions, subclassDefaults?: Partial<CodeEditorOptions>) {\n super(options, { ..._defaultCodeEditorOptions, ...(subclassDefaults ?? {}) });\n\n // Positional argument: cache it only when the caller didn't also pass\n // `options.value` (which the super-time cascade already stored).\n if (value !== undefined && this._options.value === undefined) {\n this._options.value = value;\n }\n\n this._unsubscribeTheme = ThemeManager.onThemeChange(() => this.onThemeChange());\n\n this.applyListeners(options?.listeners);\n\n this.onFirstLayout(() => this.mount());\n }\n\n /**\n * Caches the `value` / `language` / `readOnly` fields onto `_options` after\n * inherited Component fields cascade through `super.applyOptions`. No view\n * exists yet at this point (the editor mounts later, in `onFirstLayout`), so\n * these are pure caches, applied to the freshly-created `EditorState` and\n * compartments in `mount()`.\n *\n * @param options - The options bag carrying the values to apply.\n * @returns This component, for method chaining.\n */\n protected applyOptions(options: CodeEditorOptions): this {\n super.applyOptions(options);\n\n if (options.value !== undefined) this._options.value = options.value;\n if (options.language !== undefined) this._options.language = options.language;\n if (options.readOnly !== undefined) this._options.readOnly = options.readOnly;\n if (options.autoHeightMaxRows !== undefined) this._options.autoHeightMaxRows = options.autoHeightMaxRows;\n\n return this;\n }\n\n /**\n * Returns the current document text: read live from the view when mounted,\n * else the cached pre-mount / offline value.\n *\n * @returns The document text, or `\"\"` when unset.\n */\n getValue(): string {\n if (this._view) {\n return this._view.state.doc.toString();\n }\n\n return this._options.value ?? \"\";\n }\n\n /**\n * Replaces the whole document. Caches the value; when a view is mounted,\n * also dispatches a full-document replace transaction.\n *\n * @param value - The new document text.\n * @returns This component, for method chaining.\n */\n setValue(value: string): this {\n this._options.value = value;\n\n if (this._view) {\n this._view.dispatch({\n changes: { from: 0, to: this._view.state.doc.length, insert: value },\n });\n }\n\n return this;\n }\n\n /**\n * Returns the active language id.\n *\n * @returns The registered language id, or `null` when unset.\n */\n getLanguage(): string | null {\n return this._options.language ?? null;\n }\n\n /**\n * Sets (or clears) the active language. Caches the id; when a view is\n * mounted and the id names a registered language, kicks off the grammar's\n * lazy `loadExtension()` and reconfigures the grammar compartment once it\n * resolves — guarded against a stale resolution by re-checking the active\n * language id, so a rapid double-swap applies only the latest.\n *\n * @param id - A registered language id, or `null` to clear highlighting.\n * @returns This component, for method chaining.\n */\n setLanguage(id: string | null): this {\n this._options.language = id ?? undefined;\n\n if (!this._view) {\n return this;\n }\n\n if (!id) {\n this._view.dispatch({ effects: this._langCompartment.reconfigure([]) });\n\n return this;\n }\n\n const def = getLanguage(id);\n\n if (!def) {\n return this;\n }\n\n void def.loadExtension().then((extension) => {\n if (this._view && this.getLanguage() === id) {\n this._view.dispatch({ effects: this._langCompartment.reconfigure(extension) });\n }\n });\n\n return this;\n }\n\n /**\n * Returns whether the editor currently rejects edits.\n *\n * @returns The readOnly state.\n */\n getReadOnly(): boolean {\n return this._options.readOnly ?? false;\n }\n\n /**\n * Sets whether the editor rejects edits. Caches the state; when a view is\n * mounted, also reconfigures the readOnly compartment.\n *\n * @param readOnly - Whether the editor should reject edits.\n * @returns This component, for method chaining.\n */\n setReadOnly(readOnly: boolean): this {\n this._options.readOnly = readOnly;\n\n if (this._view) {\n this._view.dispatch({ effects: this._readOnlyCompartment.reconfigure(buildReadOnlyExtension(readOnly)) });\n }\n\n return this;\n }\n\n /**\n * Returns the row-count cap this editor grows to before its own vertical\n * scrollbar takes over.\n *\n * @returns The configured {@link CodeEditorOptions.autoHeightMaxRows}, or\n * `null` when unset (today's fixed-height, fill-parent contract).\n */\n getAutoHeightMaxRows(): number | null {\n return this._options.autoHeightMaxRows ?? null;\n }\n\n /**\n * Moves keyboard focus into the editor.\n *\n * @remarks Overrides {@link core!Component.focus} because a `CodeEditor`'s own\n * element is a plain, non-focusable host `<div>` — CodeMirror owns the real\n * focusable target (its `contentDOM`), so the base `element.focus()` would be\n * a no-op. When mounted this hands focus to the live view; offline / before\n * mount it falls back to the base behaviour (also a no-op, matching every\n * other editor operation's null-view guard). The current selection / caret is\n * left untouched — pair with {@link CodeEditor.moveCursorToEnd} to also move it.\n *\n * @param preventScroll - Forwarded to the base fallback; CodeMirror's own\n * `focus()` takes no scroll option, so it is honoured only offline.\n * @returns This component, for method chaining.\n */\n focus(preventScroll: boolean = false): this {\n if (this._view) {\n this._view.focus();\n\n return this;\n }\n\n return super.focus(preventScroll);\n }\n\n /**\n * Places the caret at the end of the document (after the last character),\n * collapsing any selection, and scrolls it into view.\n *\n * @remarks A selection-only transaction — it changes no text, so it emits no\n * `\"change\"`. No-op before the view is mounted (offline / pre-mount), like\n * every other view operation. Pair with {@link CodeEditor.focus} to land the\n * caret ready for typing (e.g. on a freshly opened, pre-seeded editor).\n *\n * @returns This component, for method chaining.\n */\n moveCursorToEnd(): this {\n if (this._view) {\n const end = this._view.state.doc.length;\n\n this._view.dispatch({ selection: { anchor: end }, scrollIntoView: true });\n }\n\n return this;\n }\n\n /**\n * Formats the document via the active language's formatter, or re-indents\n * it (CodeMirror's own indentation service) when the language has none.\n *\n * @remarks If the formatter throws (invalid syntax), the rejection\n * propagates and the document is left **untouched** — the full-document\n * replace only runs after the formatter resolves successfully, so a\n * throwing formatter never reaches it. The cursor is preserved through\n * Prettier's `formatWithCursor` mapping, or clamped to the new document\n * length for a formatter with no cursor map (sql-formatter).\n *\n * @returns A promise that resolves once formatting completes, or rejects\n * with the formatter's error.\n */\n async format(): Promise<void> {\n const id = this.getLanguage();\n const def = id ? getLanguage(id) : undefined;\n\n if (!def?.loadFormatter) {\n this.reindentFallback();\n\n return;\n }\n\n const formatter = await def.loadFormatter();\n const source = this.getValue();\n const cursorOffset = this._view ? this._view.state.selection.main.head : 0;\n\n const result = await formatter(source, cursorOffset);\n\n this._options.value = result.formatted;\n\n if (this._view) {\n this._view.dispatch({\n changes: { from: 0, to: this._view.state.doc.length, insert: result.formatted },\n selection: { anchor: Math.min(result.cursorOffset, result.formatted.length) },\n });\n }\n }\n\n /**\n * The `format()` fallback for a language with no formatter: re-indents the\n * whole document via CodeMirror's own indentation service. Factored out\n * from `format()` so the dispatch decision (formatter vs. this fallback) is\n * unit-testable by spying on this method — the actual re-indent needs a\n * live view (guarded below) and is otherwise manual-verify only.\n */\n private reindentFallback(): void {\n if (this._view) {\n this._view.dispatch({ changes: indentRange(this._view.state, 0, this._view.state.doc.length) });\n }\n }\n\n /**\n * Registers a listener for the `\"change\"` event, fired whenever the\n * document changes (including via {@link CodeEditor.format} / {@link CodeEditor.setValue}).\n *\n * @param event - Must be `\"change\"`.\n * @param listener - Invoked with the new document text.\n * @returns This component, for method chaining.\n */\n on(event: \"change\", listener: (payload: CodeEditorChange) => void): this;\n /**\n * Registers a listener for the `\"readonlyedit\"` event, fired when a user\n * edit (typing, paste, drop) is rejected because the editor is read-only.\n *\n * @param event - Must be `\"readonlyedit\"`.\n * @param listener - Invoked with no arguments on each rejected edit.\n * @returns This component, for method chaining.\n */\n on(event: \"readonlyedit\", listener: () => void): this;\n /**\n * Registers a listener for the `\"heightchange\"` event, fired when\n * {@link CodeEditorOptions.autoHeightMaxRows} is set and the editor's own\n * computed height changes.\n *\n * @param event - Must be `\"heightchange\"`.\n * @param listener - Invoked with the editor's new height.\n * @returns This component, for method chaining.\n */\n on(event: \"heightchange\", listener: (payload: CodeEditorHeightChange) => void): this;\n on(event: CodeEditorEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered `\"change\"` listener.\n *\n * @param event - Must be `\"change\"`.\n * @param listener - The exact callback reference to remove.\n * @returns This component, for method chaining.\n */\n off(event: \"change\", listener: (payload: CodeEditorChange) => void): this;\n /**\n * Removes a previously registered `\"readonlyedit\"` listener.\n *\n * @param event - Must be `\"readonlyedit\"`.\n * @param listener - The exact callback reference to remove.\n * @returns This component, for method chaining.\n */\n off(event: \"readonlyedit\", listener: () => void): this;\n /**\n * Removes a previously registered `\"heightchange\"` listener.\n *\n * @param event - Must be `\"heightchange\"`.\n * @param listener - The exact callback reference to remove.\n * @returns This component, for method chaining.\n */\n off(event: \"heightchange\", listener: (payload: CodeEditorHeightChange) => void): this;\n off(event: CodeEditorEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fans an event out to its registered listeners.\n *\n * @param event - The event name.\n * @param payload - The event payload (`\"change\"`/`\"heightchange\"`; `\"readonlyedit\"` has none).\n */\n protected emit(event: \"change\", payload: CodeEditorChange): void;\n protected emit(event: \"readonlyedit\"): void;\n protected emit(event: \"heightchange\", payload: CodeEditorHeightChange): void;\n protected emit(event: CodeEditorEvent, payload?: CodeEditorChange | CodeEditorHeightChange): void {\n this._listeners.fire(event, ...(payload ? [payload] : []));\n }\n\n /**\n * Detaches the theme-change listener and destroys the live CodeMirror\n * view, then defers to the base class for the rest of teardown. Call\n * before discarding a dynamically-built `CodeEditor`, mirroring\n * `Markdown.destructor`.\n */\n protected destructor(): void {\n // Before `super.destructor()` releases the overlay's element handle,\n // which the flash's fallback timer would otherwise write to.\n this._flashAnimation?.cancel();\n this._flashAnimation = null;\n\n this._unsubscribeTheme();\n\n // Before the view is destroyed below, so any later scroll read (the\n // base destructor's own teardown, a queued layout) resolves through the\n // base element rather than a handle whose node CodeMirror has removed.\n this._scrollElement = null;\n this._contentElement = null;\n\n // Nulled after destroy so a second destructor() pass on this same\n // instance (dispose() is documented idempotent — a harmless no-op —\n // but CodeMirror's own EditorView.destroy() is not guarded against a\n // repeat call) finds `_view` already null and no-ops via the `?.`\n // above. Cheap insurance on a path the offline test harness cannot\n // reach: it never constructs a live `EditorView`.\n this._view?.destroy();\n this._view = null;\n\n super.destructor();\n }\n\n /**\n * Routes every framework scroll read/write onto CodeMirror's own scrolling\n * viewport (`.cm-scroller`) rather than the editor's outer box, so the\n * eased wheel scroller, the scroll-offset cache, and\n * {@link CodeEditor.getMaxScrollTop} all act on the element that actually\n * moves.\n *\n * @returns CodeMirror's scroller handle once mounted, else the editor's own\n * element.\n *\n * @remarks Falls back to the base element before the view mounts (and\n * forever offline, where the view never mounts): the outer box has no\n * overflow, so every scroll read reports zero extent and the wheel handler\n * leaves the gesture unclaimed — the correct answer while there is nothing\n * to scroll.\n */\n protected getScrollElement(): Handle | undefined {\n return this._scrollElement ?? super.getScrollElement();\n }\n\n /**\n * Builds the `EditorState` and mounts the CodeMirror view through the DOM\n * seam's `mountView` escape. Idempotent (guards on an existing view).\n * Offline / before the element exists, `DOM.sink.mountView` returns `null`,\n * so `_view` stays `null` and every editor operation continues to no-op.\n */\n private mount(): void {\n if (this._view) {\n return;\n }\n\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n const dark = ThemeManager.getTheme().colorScheme === \"dark\";\n\n const extensions: Extension[] = [\n history(),\n // `indentWithTab` is deliberately absent from `defaultKeymap`,\n // because binding Tab traps it inside the editor and a keyboard\n // user can no longer Tab out. A code editor that does not indent\n // on Tab is the worse trade, and `defaultKeymap` already carries\n // the escape hatch: Ctrl-m (Alt-Shift-m on macOS) toggles\n // CodeMirror's tab-focus mode, after which Tab moves focus again.\n // Listed last so its Tab / Shift-Tab bindings take precedence.\n keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab]),\n drawSelection(),\n lineNumbers(),\n highlightActiveLine(),\n highlightActiveLineGutter(),\n indentOnInput(),\n bracketMatching(),\n this._readOnlyCompartment.of(buildReadOnlyExtension(this.getReadOnly())),\n this._themeCompartment.of(codeEditorTheme(dark)),\n this._langCompartment.of([]),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n this._options.value = update.state.doc.toString();\n this.emit(\"change\", { value: this._options.value });\n }\n\n if (update.heightChanged || update.geometryChanged) {\n this.syncAutoHeight(update.selectionSet && !update.docChanged);\n }\n }),\n EditorView.domEventHandlers({\n // A user edit while read-only is blocked by `EditorState.readOnly`\n // at the input layer — it never becomes a transaction, so it emits\n // no \"change\". These hooks surface the rejection as feedback:\n // typing / IME / delete fire `beforeinput`, while paste and drop are\n // prevented before `beforeinput` runs, so each needs its own hook.\n beforeinput: () => this.onEditIntent(),\n paste: () => this.onEditIntent(),\n drop: () => this.onEditIntent(),\n }),\n ];\n\n const state = EditorState.create({ doc: this._options.value ?? \"\", extensions });\n\n this._view = DOM.sink.mountView(element, (parent) => new EditorView({ parent, state }));\n\n if (this._view) {\n this.mountFlashOverlay(element);\n\n // Hand the framework's scroll plumbing CodeMirror's own viewport\n // (see getScrollElement). Resolved through the seam rather than\n // from `_view.scrollDOM`, so no raw element crosses the boundary;\n // the handle is interned weakly, so the live DOM keeps owning it\n // and it must not be tracked as one of this component's own.\n this._scrollElement = DOM.source.querySelector(element, CM_SCROLLER_SELECTOR);\n\n // Resolved from `_scrollElement` (not `element`) so the query is\n // scoped to this editor's own scroller, matching how `_scrollElement`\n // itself is resolved.\n if (this._scrollElement) {\n this._contentElement = DOM.source.querySelector(this._scrollElement, CM_CONTENT_SELECTOR);\n }\n\n // Auto-height mode only: two fixed, one-time styles, never\n // recomputed, so neither can feed back into a later measurement.\n if (this._scrollElement && this.getAutoHeightMaxRows() !== null) {\n DOM.sink.apply(this._scrollElement, {\n style: {\n // A one-time padding-bottom absorbs the sub-pixel\n // content overhang `syncAutoHeight` cannot safely\n // absorb itself — see SUBPIXEL_HEIGHT_SLOP_PX.\n // Recomputing it every call fed back into the next\n // `scrollHeight` read instead (`.cm-content`'s\n // `min-height: 100%` floors its own rendered height\n // at whatever `.cm-scroller`'s clientHeight last was),\n // ratcheting the height upward forever.\n paddingBottom: SUBPIXEL_HEIGHT_SLOP_PX + \"px\",\n // `syncAutoHeight` reserves room for a horizontal\n // scrollbar by comparing `scrollWidth` against\n // `.cm-scroller`'s own `clientWidth` — but that\n // `clientWidth` shrinks whenever `.cm-scroller` is\n // itself showing a *vertical* scrollbar (the native\n // scrollbar eats horizontal space). For a document\n // whose longest line sits within one scrollbar-width\n // of that boundary, this is circular: committing the\n // taller (reserved) height removes the vertical\n // scrollbar, which widens `clientWidth`, which drops\n // the horizontal reserve, which commits the shorter\n // height, which brings the vertical scrollbar back —\n // forever. `scrollbar-gutter: stable` reserves the\n // vertical scrollbar's track unconditionally, so\n // `clientWidth` no longer depends on whether a\n // vertical scrollbar is currently showing, breaking\n // the cycle at its source.\n scrollbarGutter: \"stable\",\n },\n });\n }\n }\n\n const language = this.getLanguage();\n\n if (language) {\n this.setLanguage(language);\n }\n\n // CM6's constructor-time initial update is not documented to\n // reliably invoke `updateListener`, so this call seeds the first\n // measurement explicitly rather than assuming it does.\n this.syncAutoHeight();\n }\n\n /**\n * Computes this editor's desired height when {@link CodeEditorOptions.autoHeightMaxRows}\n * is set — the real rendered content height, plus the horizontal scrollbar's\n * measured thickness when `.cm-scroller` is showing one, capped at the row\n * limit — and applies it via `setHeight()`, emitting `\"heightchange\"` when\n * the value actually moves. No-op offline (no `_view`, or `_scrollElement`\n * hasn't resolved) and when `autoHeightMaxRows` is unset (today's\n * fixed-height contract).\n *\n * @remarks Reads `.cm-scroller`'s live `scrollHeight`/`scrollWidth`/\n * `clientWidth` via `DOM.source.getScrollMetrics` rather than CodeMirror's\n * own `contentHeight`/`defaultLineHeight` getters. CodeMirror defers its own\n * internal line-height refresh while its view is scrolled outside the\n * browser's visible viewport (`ViewState.measure`'s `inView` gate, a\n * performance optimisation for large documents), so those getters can keep\n * reporting CodeMirror's pre-measurement default indefinitely for a fenced\n * block that upgrades below the page fold. `.cm-scroller`'s native scroll\n * metrics force a real reflow on every read and are accurate regardless of\n * that gate, since CodeMirror always renders a short document's line DOM\n * eagerly at construction. The row cap's per-row pixel height is derived\n * the same way — from the live line count, not `defaultLineHeight`.\n *\n * `.cm-scroller` carries a one-time `SUBPIXEL_HEIGHT_SLOP_PX` padding-\n * bottom (applied once, in `mount`) rather than this method adding it to\n * the height it computes — see that constant's comment for why the slop\n * cannot live here without ratcheting the editor's height upward on every\n * call.\n *\n * A height change this method applies is itself a geometry change\n * CodeMirror's own internal measurement reacts to independently of this\n * component, so a growth — and, symmetrically, a content shrink of a\n * pixel or more — is trusted only on the call where the document/width\n * shape genuinely changed — see the comment above `_lastSyncedShape`'s\n * declaration for why no growth, and no such shrink, against an\n * unchanged shape is trusted, however plausible either looks.\n *\n * @param pureSelectionChange - True when the caller's `updateListener`\n * update carries a selection change but no document change. A cursor\n * move alone can never legitimately need more vertical space (a\n * monospace grid layout has no reflow to trigger), so a growth request\n * arriving this way is rejected outright, even on a call that would\n * otherwise read as a shape change — live-confirmed via a direct\n * mutation-log comparison: a click moving the cursor to a *different*\n * line reassigns `cm-activeLine` / `cm-activeLineGutter` and rewrites\n * `.cm-content`'s own style, CodeMirror's heavier internal refresh,\n * while a same-line reposition (or a single-line document, structurally\n * incapable of having a different line to click) never does.\n */\n private syncAutoHeight(pureSelectionChange = false): void {\n const maxRows = this.getAutoHeightMaxRows();\n\n if (!this._view || maxRows === null || !this._scrollElement) {\n return;\n }\n\n const metrics = DOM.source.getScrollMetrics(this._scrollElement);\n\n const padding = this._view.documentPadding.top + this._view.documentPadding.bottom;\n const perLineHeight = (metrics.scrollHeight - padding) / this._view.state.doc.lines;\n const capPx = perLineHeight * maxRows + padding;\n\n let contentDesired = Math.min(metrics.scrollHeight, capPx);\n\n if (pureSelectionChange && contentDesired > this.getHeight()) {\n return;\n }\n\n const shape = [this._view.state.doc.lines, this._view.state.doc.length, metrics.clientWidth] as const;\n const shapeChanged = this._lastSyncedShape === null || shape.some((v, i) => v !== this._lastSyncedShape![i]);\n\n this._lastSyncedShape = shape;\n\n // Captured before this call's own commits (the intermediate one\n // below, when shapeChanged), so the convergence/growth checks after\n // it compare against the height this call STARTED with rather than\n // one it already changed mid-call.\n const previousHeight = this.getHeight();\n\n // `.cm-scroller`'s one-time `scrollbar-gutter: stable` (see `mount`)\n // reserves a vertical scrollbar's worth of width unconditionally,\n // narrowing `clientWidth` regardless of whether a vertical scrollbar\n // ever actually renders — so whether a REAL horizontal scrollbar\n // renders cannot be predicted from `scrollWidth` vs. `clientWidth`\n // (with or without a scrollbar-width fudge factor): live measurement\n // found two blocks both with `scrollWidth > clientWidth` (7px and\n // 15px over) where only the second actually rendered one. The fix is\n // to measure the box's own rendered state directly instead of\n // predicting it — `offsetHeight` includes a real horizontal\n // scrollbar's thickness, `clientHeight` excludes it, so their\n // difference (floored at zero) is exactly the space it's costing.\n //\n // Measured on EVERY call, not just a shape change: a real\n // scrollbar's presence depends on rendered content width, which can\n // change WITHOUT the shape tuple above changing — live-confirmed via\n // a block whose language grammar loads asynchronously\n // (`setLanguage`'s `loadExtension().then(...)`, well after `mount`'s\n // synchronous initial measurement): a real, visible horizontal\n // scrollbar present at that initial measurement resolved on its own\n // once highlighting settled and re-flowed the text, but the shape\n // tuple (line count, doc length, container width) never changed, so\n // a reserve cached only on shape changes never got revisited and the\n // dead space it added stayed forever. Re-measuring costs one more\n // forced-layout read per call, same class as the several already\n // happening here, and is safe to trust unconditionally in a way a\n // content-height GROWTH is not: the box's own height is fed back\n // into `.cm-content`'s `min-height: 100%`, which is what makes a\n // height growth self-reinforcing, but a scrollbar's thickness is\n // independent of this element's height, so re-reading it here can't\n // manufacture its own feedback loop. Any resulting increase in the\n // committed height still passes through the same shape-gated growth\n // check below as always; a decrease passes through the same\n // sub-pixel-noise-guarded shrink check.\n //\n // On the call that first establishes a new shape, `.cm-scroller` is\n // still whatever height it had BEFORE (this component's own pre-sync\n // default on the very first call ever, or the previous shape's\n // height on a later one) — live-confirmed wrong: a block correctly\n // showing no scrollbar once content-sized measured a false 15px\n // reserve read against that stale height, and since no growth\n // against an unchanged shape is ever trusted (see above), the wrong\n // reading then locked in permanently. So on a shape change the\n // content-only height is committed FIRST, forcing a real layout pass\n // (a plain synchronous property read already forces one; the box\n // itself needs an actual write, not just a read, since the\n // scrollbar's presence is being measured against ITS height), and\n // the reserve is measured against that — all still within this one\n // call, so nothing paints in between. On a later call against an\n // unchanged shape the box is already content-sized from that\n // earlier commit, so `metrics.clientHeight` (read once, at the top\n // of this method, before any commit this call might make) is\n // already an accurate reference — no second commit needed.\n let settledClientHeight = metrics.clientHeight;\n\n if (shapeChanged) {\n this.setHeight(contentDesired);\n\n const settled = DOM.source.getScrollMetrics(this._scrollElement);\n\n settledClientHeight = settled.clientHeight;\n\n // The pre-commit `metrics.scrollHeight` above, and `settled`\n // here, are both integer DOM properties — browsers round or\n // floor them, which can hide a genuine sub-pixel shortfall\n // entirely: live-confirmed via a raw DOM snapshot where\n // CodeMirror's own gutter carried an inline `min-height:\n // 223.504px` (its internal, full-precision content measurement)\n // against a rounded 224px commit that STILL left a hair of real,\n // non-zero scroll range — yet `scrollHeight`/`clientHeight` both\n // read back as the same rounded 224, showing no gap at all. The\n // fractional `getBoundingClientRect`-based rect on `.cm-content`\n // itself doesn't round this away, so it's compared directly\n // against `.cm-scroller`'s own fractional content-box height\n // (its rect height minus the fixed padding-bottom applied in\n // `mount` — `.cm-content`'s `min-height: 100%` resolves against\n // that content box, not the padding-inclusive border box).\n // Skipped when this call's height came from the row cap, not\n // real content: a capped block is EXPECTED to keep overflowing\n // past its committed height — that's what drives its own\n // intentional internal scroll — so \"correcting\" it here would\n // defeat the cap.\n if (metrics.scrollHeight <= capPx && this._contentElement) {\n const contentRectHeight = DOM.source.getElementRect(this._contentElement).height;\n const scrollerContentBoxHeight = DOM.source.getElementRect(this._scrollElement).height - SUBPIXEL_HEIGHT_SLOP_PX;\n\n contentDesired += Math.max(0, contentRectHeight - scrollerContentBoxHeight);\n }\n } else {\n // A content shrink this call did NOT earn through a genuine shape\n // change is the same self-triggered geometry echo the growth guard\n // below already distrusts (see the comment above `_lastSyncedShape`,\n // and the growth check a few lines down): CodeMirror's own internal\n // remeasure pass can report a `scrollHeight` reading that drifts away\n // from what this method already committed -- on a real device-pixel\n // ratio it can read fractionally MORE, forever, on the growth side\n // (see the comment above); live-confirmed to drift the other way too:\n // a chain of such echoes, each shrinking `contentDesired` by more than\n // the sub-pixel noise floor below, walks the committed height down\n // with nothing to stop it short of zero -- even though the document\n // never changed. Only a genuine shape change re-establishes trust in\n // a smaller reading; a re-entrant call holds the content component at\n // its last-trusted value instead. The hbar-reserve component measured\n // below is unaffected -- it is re-measured, and trusted, on every\n // call regardless of shape, since (per the comment above its own\n // computation) it cannot manufacture this kind of feedback loop on\n // its own.\n const previousContentHeight = previousHeight - this._lastHbarReserve;\n\n if (contentDesired < previousContentHeight && previousContentHeight - contentDesired >= 1) {\n contentDesired = previousContentHeight;\n }\n }\n\n const offsetSize = DOM.source.getOffsetSize(this._scrollElement);\n\n this._lastHbarReserve = Math.max(0, offsetSize.offsetHeight - settledClientHeight);\n\n const desired = contentDesired + this._lastHbarReserve;\n\n if (desired === previousHeight) {\n return;\n }\n\n if (desired > previousHeight && !shapeChanged) {\n return;\n }\n\n // A residual shrink against an UNCHANGED shape, smaller than one\n // pixel, can only be integer-rounding noise, never genuine content:\n // a content shrink of a pixel or more against an unchanged shape is\n // already held at its last-trusted value by the guard above, so\n // whatever reaches this point is either a sub-pixel content reading\n // or a change in the independently-trusted hbar reserve.\n // `metrics.scrollHeight` above is an integer DOM property — on a\n // later call against a shape whose height this method already\n // corrected upward by a fraction of a pixel (see the fractional\n // undershoot correction above), it reads back that already-correct\n // height rounded DOWN, which is strictly LESS than what this method\n // itself committed. Live-confirmed: unguarded, that read straight\n // back through as a \"genuine\" shrink every time, silently reverting\n // the correction on the very next geometryChanged event —\n // CodeMirror's own settling fires one almost immediately — so the\n // fix never held past its own first call.\n if (desired < previousHeight && !shapeChanged && previousHeight - desired < 1) {\n return;\n }\n\n this.setHeight(desired);\n this.emit(\"heightchange\", { height: desired });\n }\n\n /**\n * Creates the read-only rejection wash: a pointer-transparent overlay that\n * fills the editor box and sits above CodeMirror's content, appended after\n * the view so it paints on top. It rests at `opacity: 0`; {@link CodeEditor.flashReadOnly}\n * pulses it. Tracked as an owned handle, so the component's teardown releases it.\n *\n * @param host - The mounted editor element the overlay fills.\n */\n private mountFlashOverlay(host: Handle): void {\n const overlay = this.trackHandle(DOM.sink.createElement(\"div\"));\n\n DOM.sink.apply(overlay, {\n style: {\n position: \"absolute\",\n inset: \"0\",\n pointerEvents: \"none\",\n // Above CodeMirror's sticky line-number gutter (z-index 200) so the\n // wash covers the gutter too; `.cm-editor` forms no stacking context,\n // so the gutter would otherwise paint over a lower overlay.\n zIndex: \"300\",\n backgroundColor: READONLY_FLASH_COLOR,\n opacity: \"0\",\n },\n });\n DOM.sink.appendChild(host, overlay);\n\n this._flashOverlay = overlay;\n }\n\n /**\n * Reconfigures the theme compartment when the project theme changes, so\n * the editor's chrome + syntax colours follow a `ThemeManager.setTheme`\n * toggle with no rebuild. No-ops before the view exists.\n */\n private onThemeChange(): void {\n if (!this._view) {\n return;\n }\n\n const dark = ThemeManager.getTheme().colorScheme === \"dark\";\n\n this._view.dispatch({ effects: this._themeCompartment.reconfigure(codeEditorTheme(dark)) });\n }\n\n /**\n * DOM-event hook for the read-only rejection feedback, wired to\n * `beforeinput` / `paste` / `drop` in {@link CodeEditor.mount}. When the\n * editor is read-only it surfaces the attempt via\n * {@link CodeEditor.signalReadOnlyEdit}; it never consumes the event, so\n * CodeMirror's own `EditorState.readOnly` handling still blocks the edit.\n *\n * @returns Always `false` (event left unhandled).\n */\n private onEditIntent(): boolean {\n if (this.getReadOnly()) {\n this.signalReadOnlyEdit();\n }\n\n return false;\n }\n\n /**\n * Emits the `\"readonlyedit\"` event and plays the rejection flash — a\n * programmatic hook plus a built-in visual cue that an edit was refused\n * because the editor is read-only.\n */\n private signalReadOnlyEdit(): void {\n this.emit(\"readonlyedit\");\n this.flashReadOnly();\n }\n\n /**\n * Flashes a brief error-coloured wash over the editor as feedback for a\n * rejected edit: fades the overlay from a subtle tint back to transparent.\n * No-op before the overlay is mounted (offline / pre-mount), and — via\n * {@link Animation.play} — honours `prefers-reduced-motion`: under reduced\n * motion the `\"readonlyedit\"` event still fires but nothing animates.\n *\n * A full-box wash is used rather than a border/ring cue because the editor\n * is often large and mostly empty, so an edge flash sits far from where the\n * eye is (the caret) and reads as nothing; the wash covers the content the\n * user is looking at while staying faint enough to keep the text legible.\n */\n private flashReadOnly(): void {\n if (!this._flashOverlay) {\n return;\n }\n\n this._flashAnimation?.cancel();\n this._flashAnimation = Animation.play(this._flashOverlay, {\n from: { opacity: String(READONLY_FLASH_PEAK_OPACITY) },\n to: { opacity: \"0\" },\n durationMs: READONLY_FLASH_MS,\n properties: [\"opacity\"],\n });\n }\n}\n\nconst CodeEditorCallable = callable(CodeEditor);\ntype CodeEditorCallable = CodeEditor;\nexport {\n CodeEditor as _CodeEditor,\n CodeEditorCallable as CodeEditor,\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./DOM-C-Edb3tA.js";import{l as t,n,o as r}from"./Position-BwtxouxK.js";import{S as i,b as a,h as o,t as s}from"./Component-B0ShfPVi.js";import{n as c}from"./Scrollbar-t8fFrUVQ.js";import{t as l}from"./Glyph-_VeBacS2.js";import{t as u}from"./Panel-Cy1pdlWO.js";import{t as d}from"./AnimatedDropdown-H3Rh-YMZ.js";import{t as f}from"./Fit-BhlB-HAo.js";import{t as p}from"./Text-CMKnK9uB.js";import{t as m}from"./AbstractInput-sRNPzWel.js";import{n as h,r as g}from"./VBox-DfJPWXqc.js";import{t as _}from"./LayoutConstraints-LIHYYd2F.js";import{t as v}from"./Button-MpMIYBYJ.js";import{t as y}from"./Grid-Daiz7F5d.js";import{chevron_left as b}from"./glyphs/solid/chevron_left.es.js";import{chevron_right as x}from"./glyphs/solid/chevron_right.es.js";import{clock as S}from"./glyphs/solid/clock.es.js";import{r as C,t as w}from"./List-nx8220Fi.js";import{chevron_down as T}from"./glyphs/solid/chevron_down.es.js";var E=`var(--ts-ui-link-color, rgb(21, 101, 192))`;new a({scope:`selector`,name:`.Link`,styles:{textDecoration:`underline`}}),new a({scope:`selector`,name:`.Link:focus-visible`,styles:{outline:`2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))`,outlineOffset:`1px`}});var D={tag:`a`,foregroundColor:E,cursor:`pointer`,interactive:!0},Link=class extends p{constructor(e,t,n){super(e,t,{...D,...n??{}}),i.addListener(this,`keydown`,this.handleKeyDown),this.applyListeners(t?.listeners)}applyOptions(e){return super.applyOptions(e),this.setInteractive(e.interactive??this.isInteractive()),this}isInteractive(){return this._options.interactive??this._defaultOptions.interactive??!0}setInteractive(e){return this._options.interactive=e,e?this.getAria().setRole(`link`).setTabIndex(0):this.getAria().clearRole().setTabIndex(null),this}on(e,t){return i.addListener(this,`click`,t),this}off(e,t){return i.removeListener(this,`click`,t),this}click(){return i.fireEvent(this,`click`),this}handleKeyDown(e){if(this.isInteractive()&&e.key===`Enter`)return this.click(),{prevent:!0}}},O=o(Link);new a({scope:`selector`,name:`.TextField:focus, .TextArea:focus, .PasswordField:focus`,styles:{outline:`none`,boxShadow:`inset 0 0 0 2px var(--ts-ui-indicator-focus, rgb(30, 100, 200))`}});var k={tag:`input`,backgroundColor:`var(--ts-ui-input-bg, rgb(255, 255, 255))`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`},TextInput=class extends m{constructor(e,t){super(e,{...k,...t??{}}),this.setElementCSSRules({fontFamily:`var(--ts-ui-font-family, sans-serif)`,fontSize:`var(--ts-ui-font-size, 14px)`,lineHeight:`calc(1em + var(--ts-ui-line-padding, 2px))`}),i.addListener(this,`input`,this.onInput)}onInput(){let t=this.getElement();this.setText(t?e.source.getValue(t):``),this.notifyChange(this.getValue())}applyOptions(e){return super.applyOptions(e),e.text!==void 0&&this.setText(e.text),e.textAlign!==void 0&&this.setTextAlign(e.textAlign),e.placeholder!==void 0&&this.setPlaceholder(e.placeholder),e.readOnly!==void 0&&this.setReadOnly(e.readOnly),e.enabled!==void 0&&this.setEnabled(e.enabled),e.maxLength!==void 0&&this.setMaxLength(e.maxLength),e.inputMode!==void 0&&this.setInputMode(e.inputMode),e.autoComplete!==void 0&&this.setAutoComplete(e.autoComplete),this}on(e,t){return e===`action`?(i.addListener(this,`input`,t),this):e===`keydown`?(i.addListener(this,`keydown`,t),this):super.on(e,t)}off(e,t){return e===`action`?(i.removeListener(this,`input`,t),this):e===`keydown`?(i.removeListener(this,`keydown`,t),this):super.off(e,t)}setType(e){return this._options.type=e,this.setElementAttribute(`type`,e),this}setName(e){return super.setName(e),e==null?this.removeElementAttribute(`name`):this.setElementAttribute(`name`,e),this}clearName(){return this._options.name===void 0?this:(this._options.name=void 0,this.removeElementAttribute(`name`),this)}getInputMode(){return this._options.inputMode??null}setInputMode(e){return this._options.inputMode===e?this:(this._options.inputMode=e,this.setElementAttribute(`inputmode`,e),this)}clearInputMode(){return this._options.inputMode===void 0?this:(this._options.inputMode=void 0,this.removeElementAttribute(`inputmode`),this)}getAutoComplete(){return this._options.autoComplete??null}setAutoComplete(e){return this._options.autoComplete===e?this:(this._options.autoComplete=e,this.setElementAttribute(`autocomplete`,e),this)}clearAutoComplete(){return this._options.autoComplete===void 0?this:(this._options.autoComplete=void 0,this.removeElementAttribute(`autocomplete`),this)}getBaseline(){return this.wrapInnerBaseline(t.measureTextBaseline())}getTextAlign(){return this._options.textAlign??null}setTextAlign(e){return this._options.textAlign=e,this.setElementCSSRule(`textAlign`,e),this}clearTextAlign(){return this.setTextAlign(null)}getText(){return this._options.text??``}setText(t){this._options.text=t||``;let n=this.getElement();return n&&e.sink.setValue(n,this._options.text),this}getValue(){return this.getText()}setValue(e){return this.setText(e)}getPlaceholder(){return this._options.placeholder??null}setPlaceholder(e){return this._options.placeholder=e,this.setElementAttribute(`placeholder`,e),this}clearPlaceholder(){return this._options.placeholder===void 0?this:(this._options.placeholder=void 0,this.removeElementAttribute(`placeholder`),this)}getMaxLength(){return this._options.maxLength??null}setMaxLength(e){return this._options.maxLength=e,this.setElementAttribute(`maxlength`,String(e)),this}clearMaxLength(){return this._options.maxLength===void 0?this:(this._options.maxLength=void 0,this.removeElementAttribute(`maxlength`),this)}select(t,n){let r=this.getElement();if(!r)return this;(!t||t<0)&&(t=0);let i=this._options.text??``;return(!n||n>i.length)&&(n=i.length+1),e.sink.setSelectionRange(r,t,n),this}applyEnabled(e){this.setDisabledAttribute(!e)}applyReadOnly(e){e?this.setElementAttribute(`readonly`,``):this.removeElementAttribute(`readonly`)}getElement(e=!1){return super.getElement(e)}init(t){super.init(t);let n=t||this.getElement();return this._options.type!==void 0&&e.sink.apply(n,{setAttr:{type:this._options.type}}),this._options.name!=null&&e.sink.apply(n,{setAttr:{name:this._options.name}}),this._options.placeholder!==void 0&&e.sink.apply(n,{setAttr:{placeholder:this._options.placeholder}}),this._options.readOnly&&e.sink.apply(n,{setAttr:{readonly:``}}),this._options.maxLength!==void 0&&e.sink.apply(n,{setAttr:{maxlength:String(this._options.maxLength)}}),this._options.inputMode!==void 0&&e.sink.apply(n,{setAttr:{inputmode:this._options.inputMode}}),this._options.autoComplete!==void 0&&e.sink.apply(n,{setAttr:{autocomplete:this._options.autoComplete}}),this}render(){let t=super.render();return e.sink.setValue(t,this._options.text??``),t}},A=o(TextInput),j={cursor:`text`,border:`none`,outline:`none`},PickerInput=class extends A{constructor(){super(void 0,j)}},M=o(PickerInput),PickerButton=class extends v{constructor(){super({chromeless:!0,insets:new n(0,4,0,4)})}},N=o(PickerButton),P={content:`''`,position:`absolute`,inset:`0`,border:`2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))`,borderRadius:`inherit`,boxSizing:`border-box`,pointerEvents:`none`,zIndex:`1`};function registerFocusWithinRing(e){let t=e.split(`,`).map(e=>e.trim()+`:focus-within::after`).join(`, `);new a({scope:`selector`,name:t,styles:P})}registerFocusWithinRing(`.DateField, .TimeField, .DateTimeField`);var F=24,I={cursor:`text`,padding:new n(3,3,3,3),backgroundColor:`var(--ts-ui-input-bg, rgb(255, 255, 255))`,foregroundColor:`var(--ts-ui-text-color, black)`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`},AbstractPickerField=class extends m{_input;_button;_dropdown=null;_value=null;_invalid=!1;_showSeconds=!1;constructor(e,t){super(e,{...I,...t??{}}),this._input=new M,this._input.setType(`text`),this._input.setInputMode(`none`),this._input.setAutoComplete(`off`),this._input.setPadding(new n(0,3,0,3)),this._button=new N,this.addComponent(this._input),this.addComponent(this._button),this.updateHeight(),this.subscribeTheme(()=>this.updateHeight()),i.addListener(this._input,`input`,()=>this.onInput()),i.addListener(this._input,`blur`,()=>this.onBlur()),i.addListener(this._input,`keydown`,e=>this.onKeyDown(e)),this._button.on(`action`,()=>this.onButtonClick()),this._button.addPointerDownListener(e=>this.onButtonPointerDown(e)),this._options.enabled!==void 0&&this.applyEnabled(this._options.enabled),this._options.readOnly!==void 0&&this.applyReadOnly(this._options.readOnly)}getDefaultBorder(){return I.border}applyOptions(e){return super.applyOptions(e),e.dropdownAnimated!==void 0&&this.setDropdownAnimated(e.dropdownAnimated),this}doLayout(){super.doLayout();let e=this.getContentBounds();if(!e)return this;let t=Math.max(0,e.width-F);return this._input.setX(e.x),this._input.setY(e.y),this._input.setWidth(t),this._input.setHeight(e.height),this._button.setX(e.x+t),this._button.setY(e.y),this._button.setWidth(F),this._button.setHeight(e.height),this._button.doLayout(),this}updateHeight(){let e=t.singleLineBoxHeight(this.getInsets(),this.getPadding(),this.getBorderSize()),n=this.getPreferredSizeConstraint()?.width??this.getPreferredWidth();this.setPreferredSize({width:n,height:e});let r=this.getMaxSizeConstraint()?.width??2**53-1;this.setMaxSize({width:r,height:e});let i=this.getMinSizeConstraint()?.width??0;this.setMinSize({width:i,height:e})}setValue(e){return this._value=e,this._input?.setText(e?this.formatValue(e):``),this}getValue(){return this._value}getBaseline(){return this.wrapInnerBaseline(this._input.getBaseline())}setDropdownAnimated(e){return this._options.dropdownAnimated=e,this._dropdown&&this._dropdown.setAnimated(e),this}isDropdownAnimated(){return this._options.dropdownAnimated??!0}applyEnabled(e){this._input.setEnabled(e)}applyReadOnly(e){this._input.setReadOnly(e)}onButtonClick(){this._dropdown?.isOpen()?this.closeDropdown():(this._input.focus(),this.openDropdown())}onButtonPointerDown(e){return{prevent:!0}}onInput(){let e=this._input.getText();if(!e){this._value=null,this.setInvalid(!1),this.notifyChange(null);return}let t=this.parseRaw(e);t===null?this.setInvalid(!0):(this._value=t,this.setInvalid(!1),this.notifyChange(t))}onBlur(){this._invalid&&(this._input.setText(``),this._value=null,this.setInvalid(!1))}setInvalid(e){this._invalid!==e&&(this._invalid=e,e?this.setBorder({border:`1px solid var(--ts-ui-validation-error-border)`}):this.setBorder(this.getDefaultBorder()))}onKeyDown(e){if(this._dropdown&&this._dropdown.isOpen()&&this._dropdown.handleKey(e))return{prevent:!0};if(e.key===`ArrowDown`)return this.openDropdown(),{prevent:!0};e.key===`Escape`&&this.closeDropdown()}ensureDropdown(){if(!this._dropdown){this._dropdown=this.createDropdown();let e=this._options.dropdownAnimated;e!==void 0&&this._dropdown.setAnimated(e)}return this._dropdown}openDropdown(){let e=this.ensureDropdown();e.isOpen()||(e.setCloseHandler(()=>this.closeDropdown()),e.setAnchorElement(this.getElement(!0)??null),e.showAt(this._input.getElement(!0),this._value))}closeDropdown(){this._dropdown&&this._dropdown.isOpen()&&this._dropdown.hideAnimated()}},L={cursor:`text`,padding:new n(3,3,3,3),backgroundColor:`var(--ts-ui-input-bg, rgb(255, 255, 255))`,foregroundColor:`var(--ts-ui-text-color, black)`},TextField=class extends A{constructor(e,t){super(e,{...L,...t??{}}),this.updateHeight(),this.subscribeTheme(()=>this.updateHeight()),this.setType(`text`)}updateHeight(){let e=t.singleLineBoxHeight(this.getInsets(),this.getPadding(),this.getBorderSize()),n=this.getPreferredSizeConstraint()?.width??200;this.setPreferredSize({width:n,height:e});let r=this.getMaxSizeConstraint()?.width??2**53-1;this.setMaxSize({width:r,height:e});let i=this.getMinSizeConstraint()?.width??0;this.setMinSize({width:i,height:e})}setBorder(e){super.setBorder(e);let n=t.singleLineBoxHeight(this.getInsets(),this.getPadding(),this.getBorderSize()),i=this.getPreferredSize(),a=this.getMinSize(),o=this.getMaxSize();return i&&this.setPreferredSize({width:i.width,height:n}),a&&this.setMinSize({width:a.width,height:n}),o&&!r(o.height)&&this.setMaxSize({width:o.width,height:n}),this}},R=o(TextField);new a({scope:`class`,name:`PickerColumnHeader`,styles:{opacity:`0.7`}}),new a({scope:`class`,name:`PickerCell`,styles:{borderRadius:`3px`}}),new a({scope:`selector`,name:`.PickerCell:hover`,styles:{backgroundColor:`var(--ts-ui-autocomplete-item-hover-bg, rgba(30, 100, 200, 0.08))`}}),new a({scope:`selector`,name:`.PickerCell.disabled`,styles:{pointerEvents:`none`,color:`var(--ts-ui-autocomplete-item-disabled-color, rgb(170, 170, 170))`,backgroundColor:`var(--ts-ui-picker-cell-disabled-bg, transparent)`}});var PickerColumnHeader=class extends p{constructor(e){super(e,{textAlign:`center`,fontSize:12})}},PickerCellList=class extends u{constructor(){super({layoutManager:new h({spacing:0,stretching:!0}),autoScroll:`y`,insets:new n(0,0,0,0)})}getMinSize(){let e=super.getMinSize();return e&&{width:e.width,height:0}}},PickerCell=class extends p{_selected=!1;_disabled=!1;_onClick;constructor(e,t){super(e,{textAlign:`center`,preferredSize:{width:0,height:22}}),this._onClick=t,this.setLineHeight(22),this.setCursor(`pointer`),i.addListener(this,`pointerdown`,{prevent:!0,handler:this.handlePointerDown}),i.addListener(this,`click`,this.handleClick)}handlePointerDown(e){}handleClick(){this._disabled||this._onClick()}setSelected(e){return this._selected===e?this:(this._selected=e,e?(this.setBackgroundColor(`var(--ts-ui-autocomplete-item-highlight-bg, rgba(30, 100, 200, 0.18))`),this.setFontWeight(`bold`)):(this.clearBackgroundColor(),this.setFontWeight(`normal`)),this)}isSelected(){return this._selected}setDisabled(t){if(this._disabled===t)return this;this._disabled=t,this.setCursor(t?`default`:`pointer`);let n=this.getElement();return n&&e.sink.apply(n,{toggleClass:{disabled:t}}),this}isDisabled(){return this._disabled}render(){let t=super.render();return this._disabled&&e.sink.apply(t,{addClass:[`disabled`]}),t}},PickerColumn=class extends s{_cellList;constructor(e){if(super(),this.setLayoutManager(new h({spacing:2,stretching:!0})),e!==null){let t=new PickerColumnHeader(e);t.setPreferredSize({width:0,height:18}),this.addComponent(t)}this._cellList=new PickerCellList;let t=new _;t.weight=1,this.addComponent(this._cellList,t)}addCell(e){return this._cellList.addComponent(e),this}clearCells(){return this._cellList.disposeAllComponents(),this}getCellList(){return this._cellList}scrollSelectedIntoView(){let n=this._cellList.getElement();if(!n)return this;let r=this._cellList.getComponents(),i=null;for(let e of r)if(e instanceof PickerCell&&e.isSelected()){i=e;break}if(!i)return this;let a=i.getElement();if(!a)return this;let o=e.source.getOffsetSize(a),s=e.source.getScrollMetrics(n),c=o.offsetTop,l=o.offsetHeight,u=s.clientHeight,d=c-(u-l)/2,f=s.scrollHeight-u,p=t.clamp(d,0,f);return e.sink.apply(n,{scrollTop:p}),this}setSelectedValue(e){for(let t of this._cellList.getComponents())t instanceof PickerCell&&t.setSelected(t.getText().valueOf()===e);return this}};l.register(b),l.register(x),new a({scope:`class`,name:`PickerDay`,styles:{borderRadius:`3px`}}),new a({scope:`selector`,name:`.PickerDay:hover`,styles:{backgroundColor:`var(--ts-ui-autocomplete-item-hover-bg, rgba(30, 100, 200, 0.08))`}}),new a({scope:`selector`,name:`.PickerDay.disabled`,styles:{pointerEvents:`none`,color:`var(--ts-ui-autocomplete-item-disabled-color, rgb(170, 170, 170))`,backgroundColor:`var(--ts-ui-picker-cell-disabled-bg, transparent)`}}),new a({scope:`class`,name:`PickerNavButton`,styles:{borderRadius:`3px`,color:`var(--ts-ui-picker-nav-fg, var(--ts-ui-text-color))`}}),new a({scope:`selector`,name:`.PickerNavButton:hover`,styles:{backgroundColor:`var(--ts-ui-picker-nav-hover-bg, rgba(30, 100, 200, 0.08))`}});var PickerDayHeader=class extends p{constructor(e){super(e,{textAlign:`center`,fontSize:12,preferredSize:{width:0,height:20}}),this.setLineHeight(20)}},PickerBlankCell=class extends s{constructor(){super({preferredSize:{width:0,height:24}})}},PickerNavButton=class extends s{constructor(e,t){super({preferredSize:{width:24,height:24}}),this.setLayoutManager(new f),this.setCursor(`pointer`),this.getAria().setRole(`button`);let n=new l(e);n.setPointerEvents(`none`),n.setPreferredSize({width:12,height:12}),this.addComponent(n),i.addListener(this,`pointerdown`,{prevent:!0,handler:this.onPointerDown}),i.addListener(this,`click`,()=>t())}onPointerDown(){}render(){let t=super.render();return e.sink.apply(t,{addClass:[`PickerNavButton`]}),t}},PickerMonthLabel=class extends p{constructor(e){super(``,{textAlign:`center`,fontWeight:`bold`}),this.setLineHeight(24),this.setCursor(`pointer`),this.getAria().setRole(`button`),this.getAria().setExpanded(!1),this.getAria().setTabIndex(0),i.addListener(this,`pointerdown`,{prevent:!0,handler:this.onPointerDown}),i.addListener(this,`click`,()=>e())}onPointerDown(){}render(){let t=super.render();return e.sink.apply(t,{addClass:[`PickerNavButton`]}),t}},PickerDay=class extends p{_date;_selected=!1;_disabled=!1;_onClick;constructor(e,t){super(String(e.getDate()),{textAlign:`center`,preferredSize:{width:0,height:24}}),this._date=e,this._onClick=t,this.setLineHeight(24),this.setCursor(`pointer`),i.addListener(this,`pointerdown`,{prevent:!0,handler:this.onPointerDown}),i.addListener(this,`click`,()=>this.onClick())}getDate(){return this._date}onPointerDown(e){}onClick(){this._disabled||this._onClick(this._date)}setSelected(e){return this._selected===e?this:(this._selected=e,e?(this.setBackgroundColor(`var(--ts-ui-autocomplete-item-highlight-bg, rgba(30, 100, 200, 0.18))`),this.setFontWeight(`bold`)):(this.clearBackgroundColor(),this.setFontWeight(`normal`)),this)}isSelected(){return this._selected}setDisabled(t){if(this._disabled===t)return this;this._disabled=t,this.setCursor(t?`default`:`pointer`);let n=this.getElement();return n&&e.sink.apply(n,{toggleClass:{disabled:t}}),this}isDisabled(){return this._disabled}render(){let t=super.render();return e.sink.apply(t,{addClass:[`PickerDay`]}),this._disabled&&e.sink.apply(t,{addClass:[`disabled`]}),t}};function dayStart(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),0,0,0,0)}function dayEnd(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),23,59,59,999)}var AbstractCalendarDropdown=class extends d{_onSelect;_value=null;_monthAnchor=new Date;_yearScrollOpen=!1;_root;_headerRow;_prevButton;_nextButton;_monthLabel;_weekdayRow;_dayGrid;_yearColumn=null;_highlightedDayIdx=-1;_highlightedYear=-1;_yearTypeBuffer=``;_yearTypeTimer=null;constructor(e,t,r){super(t,{zIndex:10050,layoutManager:new f,backgroundColor:`var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`,shadow:`var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))`,insets:new n(6,6,6,6),...r??{}}),this._onSelect=e,this.getAria().setRole(`group`),this.setContain(`layout`),this._root=new s,this._root.setLayoutManager(new h({spacing:4,stretching:!0})),this._headerRow=new s({preferredSize:{width:0,height:24}}),this._headerRow.setLayoutManager(new g({spacing:2,stretching:!0})),this._prevButton=new PickerNavButton(`chevron-left`,()=>this.prevMonth()),this._nextButton=new PickerNavButton(`chevron-right`,()=>this.nextMonth()),this._monthLabel=new PickerMonthLabel(()=>this.toggleYearScroller());let a=new _;a.weight=1,this._headerRow.addComponent(this._prevButton),this._headerRow.addComponent(this._monthLabel,a),this._headerRow.addComponent(this._nextButton),this._root.addComponent(this._headerRow),this._weekdayRow=new s({preferredSize:{width:0,height:20}}),this._weekdayRow.setLayoutManager(new y({columns:7,spacing:2}));for(let e of[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`])this._weekdayRow.addComponent(new PickerDayHeader(e));this._root.addComponent(this._weekdayRow),this._dayGrid=new s({preferredSize:{width:0,height:154}}),this._dayGrid.setLayoutManager(new y({columns:7,spacing:2})),this._root.addComponent(this._dayGrid),this.addComponent(this._root),this.buildExtraRootChildren(),i.addSubtreeListener(this,`pointerdown`,e=>this.onPointerDown(e))}applyOptions(e){return super.applyOptions(e),e.minDate!==void 0&&(this._options.minDate=e.minDate),e.maxDate!==void 0&&(this._options.maxDate=e.maxDate),this}onPointerDown(t){if(!(e.source.isNode(t.target)&&e.source.getTagName(e.source.intern(t.target))===`INPUT`)&&!c(t))return{prevent:!0}}showAt(t,n){this._value=n?new Date(n.getTime()):null;let r=this._value??new Date;this._monthAnchor=new Date(r.getFullYear(),r.getMonth(),1),this._highlightedDayIdx=-1,this._highlightedYear=-1,this.resetYearTypeBuffer(),this._yearScrollOpen&&this.closeYearScroller(),this.pauseLayout(),this.rebuild(),this.resumeLayout();let i=this.computePanelHeight();return this.setWidth(this.getPanelWidth()),this.setHeight(i),this.doLayout(),this.placeAnchored(e.source.getElementRect(t)),this.showAnimated(),this}hideAnimated(){return super.hideAnimated(),this.resetYearTypeBuffer(),this}computePanelHeight(){let e=this.getPerimeterSize(),t=206+this.getExtraInnerHeight();return e.top+e.bottom+t}rebuild(){this.buildDayGrid(),this.rebuildExtraRowsAfterValueChange()}buildDayGrid(){this._dayGrid.disposeAllComponents(),this._highlightedDayIdx=-1;let e=this._monthAnchor.getFullYear(),t=this._monthAnchor.getMonth();this._monthLabel.setText(this._monthAnchor.toLocaleDateString(void 0,{month:`long`,year:`numeric`}));let n=new Date(e,t,1).getDay(),r=new Date(e,t+1,0).getDate();for(let e=0;e<n;e++)this._dayGrid.addComponent(new PickerBlankCell);for(let n=1;n<=r;n++){let r=new Date(e,t,n),i=new PickerDay(r,e=>this.onDateSelected(e));this.isDateInRange(r)||i.setDisabled(!0),this.isValueOnDay(r)&&i.setSelected(!0),this._dayGrid.addComponent(i)}let i=42-n-r;for(let e=0;e<i;e++)this._dayGrid.addComponent(new PickerBlankCell)}isValueOnDay(e){return this._value?this._value.getFullYear()===e.getFullYear()&&this._value.getMonth()===e.getMonth()&&this._value.getDate()===e.getDate():!1}isDateInRange(e){let t=this._options.minDate??null,n=this._options.maxDate??null;return!(t&&e.getTime()<dayStart(t).getTime()||n&&e.getTime()>dayEnd(n).getTime())}hasAnyInRange(e){let t=e.getFullYear(),n=e.getMonth(),r=new Date(t,n+1,0).getDate(),i=new Date(t,n,1),a=new Date(t,n,r),o=this._options.minDate??null,s=this._options.maxDate??null;return!(o&&dayEnd(a).getTime()<dayStart(o).getTime()||s&&dayStart(i).getTime()>dayEnd(s).getTime())}onDateSelected(e){this.applyDateSelection(e),this._monthAnchor=new Date(e.getFullYear(),e.getMonth(),1),this.notifyValueChanged(),this.rebuild(),this.doLayout()}notifyValueChanged(){this._value&&this._onSelect(new Date(this._value.getTime()))}prevMonth(){let e=new Date(this._monthAnchor.getFullYear(),this._monthAnchor.getMonth()-1,1);this.hasAnyInRange(e)&&(this._monthAnchor=e,this._yearScrollOpen?(this.updateMonthLabel(),this.refreshYearSelection()):(this.buildDayGrid(),this.doLayout()))}nextMonth(){let e=new Date(this._monthAnchor.getFullYear(),this._monthAnchor.getMonth()+1,1);this.hasAnyInRange(e)&&(this._monthAnchor=e,this._yearScrollOpen?(this.updateMonthLabel(),this.refreshYearSelection()):(this.buildDayGrid(),this.doLayout()))}updateMonthLabel(){this._monthLabel.setText(this._monthAnchor.toLocaleDateString(void 0,{month:`long`,year:`numeric`}))}toggleYearScroller(){this._yearScrollOpen?this.closeYearScroller():this.openYearScroller()}openYearScroller(){this._yearColumn||(this._yearColumn=new PickerColumn(null),this._yearColumn.setPreferredSize({width:0,height:154}),this._yearColumn.getAria().setRole(`listbox`)),this.buildYearScroller(),this._root.removeComponent(this._dayGrid),this._root.insertComponent(this._yearColumn,2),this._yearScrollOpen=!0,this._monthLabel.getAria().setExpanded(!0),this.doLayout(),this._yearColumn.scrollSelectedIntoView()}closeYearScroller(){this._yearColumn&&this._root.removeComponent(this._yearColumn),this._root.insertComponent(this._dayGrid,2),this._yearScrollOpen=!1,this._monthLabel.getAria().setExpanded(!1),this.resetYearTypeBuffer(),this.buildDayGrid(),this.doLayout()}buildYearScroller(){if(!this._yearColumn)return;this._yearColumn.clearCells(),this._highlightedYear=-1;let e=new Date,t=this._options.minDate?.getFullYear()??e.getFullYear()-120,n=this._options.maxDate?.getFullYear()??e.getFullYear()+50,r=this._monthAnchor.getFullYear();for(let e=t;e<=n;e++){let t=e,n=new PickerCell(String(t),()=>this.onYearSelected(t));t===r&&n.setSelected(!0),this._yearColumn.addCell(n)}}refreshYearSelection(){if(!this._yearColumn)return;let e=this._monthAnchor.getFullYear();for(let t of this._yearColumn.getCellList().getComponents())t instanceof PickerCell&&t.setSelected(t.getText().valueOf()===String(e))}onYearSelected(e){this._monthAnchor=new Date(e,this._monthAnchor.getMonth(),1),this.applyYearSelection(e),this.closeYearScroller()}resetYearTypeBuffer(){this._yearTypeBuffer=``,this._yearTypeTimer!==null&&(clearTimeout(this._yearTypeTimer),this._yearTypeTimer=null)}handleKey(e){return this.isOpen()?this._yearScrollOpen?this.handleKeyInYearScroller(e):this.handleKeyInDayGrid(e):!1}handleKeyInDayGrid(e){switch(e.key){case`ArrowLeft`:return this.moveHighlightedDay(-1);case`ArrowRight`:return this.moveHighlightedDay(1);case`ArrowUp`:return this.moveHighlightedDay(-7);case`ArrowDown`:return this.moveHighlightedDay(7);case`PageUp`:return this.prevMonth(),!0;case`PageDown`:return this.nextMonth(),!0;case`Home`:return this.highlightFirstDayOfMonth();case`End`:return this.highlightLastDayOfMonth();case`Enter`:case` `:return this.commitHighlightedDay();default:return!1}}getDayGridChildren(){return this._dayGrid.getComponents()}moveHighlightedDay(e){let t=this.getDayGridChildren(),n=[];for(let e=0;e<t.length;e++){let r=t[e];r instanceof PickerDay&&!r.isDisabled()&&n.push({idx:e,cell:r})}if(n.length===0)return!0;let r=-1;for(let e=0;e<n.length;e++)if(n[e].idx===this._highlightedDayIdx){r=e;break}if(r<0){r=0;for(let e=0;e<n.length;e++)if(n[e].cell.isSelected()){r=e;break}}let i=Math.max(0,Math.min(n.length-1,r+e));return this.setHighlightedDay(n[i].idx),!0}setHighlightedDay(e){let t=this.getDayGridChildren();if(this._highlightedDayIdx>=0&&this._highlightedDayIdx<t.length){let e=t[this._highlightedDayIdx];e instanceof PickerDay&&!this.matchesSelection(e)&&e.setSelected(!1)}if(e<0||e>=t.length){this._highlightedDayIdx=-1;return}let n=t[e];n instanceof PickerDay&&(n.setSelected(!0),this._highlightedDayIdx=e)}matchesSelection(e){return this.isValueOnDay(e.getDate())}highlightFirstDayOfMonth(){let e=this.getDayGridChildren();for(let t=0;t<e.length;t++){let n=e[t];if(n instanceof PickerDay&&!n.isDisabled())return this.setHighlightedDay(t),!0}return!0}highlightLastDayOfMonth(){let e=this.getDayGridChildren();for(let t=e.length-1;t>=0;t--){let n=e[t];if(n instanceof PickerDay&&!n.isDisabled())return this.setHighlightedDay(t),!0}return!0}commitHighlightedDay(){if(this._highlightedDayIdx<0)return!1;let e=this.getDayGridChildren()[this._highlightedDayIdx];return e instanceof PickerDay&&!e.isDisabled()&&(this.onDateSelected(e.getDate()),!0)}handleKeyInYearScroller(e){if(/^[0-9]$/.test(e.key))return this.appendYearDigit(e.key);switch(e.key){case`ArrowLeft`:case`ArrowUp`:return this.moveHighlightedYear(-1);case`ArrowRight`:case`ArrowDown`:return this.moveHighlightedYear(1);case`PageUp`:return this.moveHighlightedYear(-10);case`PageDown`:return this.moveHighlightedYear(10);case`Home`:return this.highlightFirstYear();case`End`:return this.highlightLastYear();case`Enter`:case` `:return this.commitHighlightedYear();case`Escape`:return this.closeYearScroller(),!0;default:return!1}}getYearCells(){if(!this._yearColumn)return[];let e=[];for(let t of this._yearColumn.getCellList().getComponents())t instanceof PickerCell&&e.push(t);return e}moveHighlightedYear(e){let t=this.getYearCells();if(t.length===0)return!0;let n=this.findHighlightedYearPos(t),r=Math.max(0,Math.min(t.length-1,n+e));return this.applyYearHighlight(t,r),!0}findHighlightedYearPos(e){if(this._highlightedYear<0){for(let t=0;t<e.length;t++)if(e[t].isSelected())return t;return 0}for(let t=0;t<e.length;t++)if(e[t].getText().valueOf()===String(this._highlightedYear))return t;return 0}applyYearHighlight(e,t){let n=this._monthAnchor.getFullYear();for(let t of e)t.setSelected(t.getText().valueOf()===String(n));e[t].setSelected(!0),this._highlightedYear=parseInt(e[t].getText().valueOf(),10),this._yearColumn&&this._yearColumn.scrollSelectedIntoView()}highlightFirstYear(){let e=this.getYearCells();return e.length===0||this.applyYearHighlight(e,0),!0}highlightLastYear(){let e=this.getYearCells();return e.length===0||this.applyYearHighlight(e,e.length-1),!0}commitHighlightedYear(){let e=this._highlightedYear>=0?this._highlightedYear:this._monthAnchor.getFullYear();return this.onYearSelected(e),!0}appendYearDigit(e){this._yearTypeBuffer.length>=4&&(this._yearTypeBuffer=``),this._yearTypeBuffer+=e,this._yearTypeTimer!==null&&clearTimeout(this._yearTypeTimer),this._yearTypeTimer=setTimeout(()=>this.resetYearTypeBuffer(),800);let t=this.getYearCells(),n=this._yearTypeBuffer,r=-1;for(let e=0;e<t.length;e++)if(t[e].getText().valueOf().startsWith(n)){r=e;break}return r>=0&&this.applyYearHighlight(t,r),n.length===4&&this.resetYearTypeBuffer(),!0}getExtraInnerHeight(){return 0}buildExtraRootChildren(){}rebuildExtraRowsAfterValueChange(){}applyDateSelection(e){this._value=new Date(e.getFullYear(),e.getMonth(),e.getDate(),0,0,0,0)}applyYearSelection(e){}},z=240,DatePickerDropdown=class extends AbstractCalendarDropdown{constructor(e,t){super(e,t)}getPanelWidth(){return z}onDateSelected(e){this.applyDateSelection(e),this._monthAnchor=new Date(e.getFullYear(),e.getMonth(),1),this.notifyValueChanged()}},B=o(DatePickerDropdown),TimeColumns=class extends s{_onChange;_showSeconds;_hours=-1;_minutes=-1;_seconds=-1;_hourColumn;_minuteColumn;_secondColumn;constructor(e,t){super({preferredSize:{width:0,height:176}}),this._onChange=e,this._showSeconds=t?.showSeconds??!1,this.setLayoutManager(new g({spacing:4,stretching:!0}));let n=new _;n.weight=1,this._hourColumn=this.buildColumn(`Hour`,24,1,e=>this.onUnitSelected(`hours`,e)),this._minuteColumn=this.buildColumn(`Min`,60,5,e=>this.onUnitSelected(`minutes`,e)),this.addComponent(this._hourColumn,n),this.addComponent(this._minuteColumn,n),this._showSeconds?(this._secondColumn=this.buildColumn(`Sec`,60,5,e=>this.onUnitSelected(`seconds`,e)),this.addComponent(this._secondColumn,n)):this._secondColumn=null}setTime(e){return e?(this._hours=e.getHours(),this._minutes=e.getMinutes(),this._seconds=this._showSeconds?e.getSeconds():0):(this._hours=-1,this._minutes=-1,this._seconds=-1),this.refreshColumns(),this}buildColumn(e,t,n,r){let i=new PickerColumn(e);for(let e=0;e<t;e+=n){let t=e,n=new PickerCell(String(t).padStart(2,`0`),()=>r(t));i.addCell(n)}return i}onUnitSelected(e,t){e===`hours`?this._hours=t:e===`minutes`?this._minutes=t:this._seconds=t,this._hours<0&&(this._hours=0),this._minutes<0&&(this._minutes=0),this._seconds<0&&(this._seconds=0),this.refreshColumns(),this._onChange(this._hours,this._minutes,this._showSeconds?this._seconds:0)}refreshColumns(){this._hourColumn.setSelectedValue(this.cellLabel(this._hours)),this._minuteColumn.setSelectedValue(this.cellLabel(this._minutes)),this._secondColumn?.setSelectedValue(this.cellLabel(this._seconds))}cellLabel(e){return e<0?null:String(e).padStart(2,`0`)}},V=140,H=200,U=220,TimePickerDropdown=class extends d{_showSeconds;_timeColumns;constructor(e,t){super(t,{zIndex:10050,layoutManager:new f,backgroundColor:`var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`,shadow:`var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))`,insets:new n(4,4,4,4)}),this._showSeconds=t?.showSeconds??!1,this.getAria().setRole(`group`),this.setContain(`layout`),this._timeColumns=new TimeColumns(e,{showSeconds:this._showSeconds}),this.addComponent(this._timeColumns),i.addSubtreeListener(this,`pointerdown`,e=>this.onPointerDown(e))}onPointerDown(e){if(!c(e))return{prevent:!0}}showAt(t,n){return this._timeColumns.setTime(n),this.setWidth(this._showSeconds?H:V),this.setHeight(U),this.placeAnchored(e.source.getElementRect(t)),this.showAnimated(),this.doLayout(),this}},W=o(TimePickerDropdown);l.register(S);var TimeField=class extends AbstractPickerField{constructor(e){super(e),this._button.setGlyph(`clock`),this._options.showSeconds!==void 0&&(this._showSeconds=this._options.showSeconds),this._options.value!==void 0&&this.setValue(this._options.value)}applyOptions(e){return super.applyOptions(e),e.showSeconds!==void 0&&(this._options.showSeconds=e.showSeconds),e.value!==void 0&&(this._options.value=e.value),this}formatValue(e){let t=String(e.getHours()).padStart(2,`0`),n=String(e.getMinutes()).padStart(2,`0`);return this._showSeconds?`${t}:${n}:${String(e.getSeconds()).padStart(2,`0`)}`:`${t}:${n}`}parseRaw(e){let[t,n,r]=e.split(`:`),i=Number(t),a=Number(n),o=r===void 0?0:Number(r);if(n===void 0||n===``||!(!isNaN(i)&&i>=0&&i<24)||!(!isNaN(a)&&a>=0&&a<60)||!(!isNaN(o)&&o>=0&&o<60))return null;let s=new Date;return s.setHours(i,a,o,0),s}createDropdown(){return new W((e,t,n)=>this.onTimeSelected(e,t,n),{showSeconds:this._showSeconds})}onTimeSelected(e,t,n){let r=new Date;r.setHours(e,t,n,0),this.onDropdownSelected(r)}onDropdownSelected(e){this.setValue(e),i.fireEvent(this._input,`input`)}getPreferredWidth(){return 140}},G=o(TimeField),K=240,DateTimePickerDropdown=class extends AbstractCalendarDropdown{constructor(e,t){super(e,t)}applyOptions(e){return super.applyOptions(e),e.showSeconds!==void 0&&(this._options.showSeconds=e.showSeconds),this}buildExtraRootChildren(){this._timeField=new G({showSeconds:this.isShowingSeconds()}),this._timeField.on(`change`,e=>this.onTimeFieldChange(e)),this._root.addComponent(this._timeField)}rebuildExtraRowsAfterValueChange(){this._timeField.setValue(this._value)}onTimeFieldChange(e){if(!e)return;let t=this._value??this.todayMidnight();t.setHours(e.getHours(),e.getMinutes(),this.isShowingSeconds()?e.getSeconds():0,0),this._value=t,this.notifyValueChanged()}applyDateSelection(e){this._value?this._value.setFullYear(e.getFullYear(),e.getMonth(),e.getDate()):this._value=new Date(e.getFullYear(),e.getMonth(),e.getDate(),0,0,0,0)}applyYearSelection(e){this._value&&(this._value.setFullYear(e),this.notifyValueChanged())}getPanelWidth(){return K}getExtraInnerHeight(){return 4+(this._timeField.getPreferredSize()?.height??0)}isShowingSeconds(){return this._options.showSeconds??!1}todayMidnight(){let e=new Date;return new Date(e.getFullYear(),e.getMonth(),e.getDate(),0,0,0,0)}},q=o(DateTimePickerDropdown);l.register(T);var J={tag:`div`,backgroundColor:`var(--ts-ui-input-bg, rgb(255, 255, 255))`,foregroundColor:`var(--ts-ui-text-color, black)`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`,cursor:`pointer`,insets:new n(3,6,3,6)},Y=200,X=22,Z=16,Q=200,ComboBoxDropdown=class extends d{_list;_minWidth=Q;constructor(e){super(void 0,{layoutManager:new f,backgroundColor:`var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))`,border:`var(--ts-ui-input-border)`,borderRadius:`var(--ts-ui-border-radius, 4px)`,shadow:`var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))`}),this.setContain(`layout`),this._list=new w,this._list.setBorder(`none`),this._list.setBorderRadius(`0`),this._list.setFocusOnRowClick(!1),this.addComponent(this._list),this._list.on(`action`,()=>e(this._list.getSelectedIndex()))}handleKey(e){return this._list.handleKey(e)}showAt(t,n,r){this.pauseLayout(),this._list.setItemsArray(n),this._list.setSelectedIndex(r,!1),this.resumeLayout();let i=this.getPerimeterSize(),a=i.top+i.bottom,o=i.left+i.right,s=n.length*X+a,c=Math.min(s,Y),l=e.source.getElementRect(t),u=this.measureWidestLabel(n)+Z+o,d=l.width,f=Math.max(l.width,this._minWidth),p=Math.min(Math.max(u,d),f,e.source.getViewportSize().width);return this.setWidth(p),this.setHeight(c),this.placeAnchored(l),this.showAnimated(),this.doLayout(),this}setMinWidth(e){return this._minWidth=e,this}getMinWidth(){return this._minWidth}getList(){return this._list}measureWidestLabel(e){let n=0;for(let r of e){let e=t.measureTextWidth(r.label);e>n&&(n=e)}return n}};new a({scope:`class`,name:`ComboBox`,styles:{userSelect:`none`,whiteSpace:`nowrap`}}),new a({scope:`class`,name:`ComboBoxLabel`,styles:{overflow:`hidden`,textOverflow:`ellipsis`}}),new a({scope:`selector`,name:`.ComboBoxDropdown .List:focus::after`,styles:{content:`none`}});var ComboBoxLabel=class extends s{_lineHeight=null;_renderer;constructor(e){super({tag:`span`}),this.setPointerEvents(`none`),this._renderer=e()}setItem(e,t){return this._renderer.update({item:e,index:t}),this}setRenderer(t){let n=this.getElement();if(n){let t=this._renderer.getElement();t&&e.source.getParentNode(t)===n&&e.sink.removeChild(n,t)}return this._renderer=t,n&&e.sink.appendChild(n,this._renderer.getElement(!0)),this}setLineHeight(e){return this._lineHeight=typeof e==`number`?e+`px`:e,this.setElementCSSRule(`lineHeight`,this._lineHeight),this}getLineHeight(){return this._lineHeight}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._renderer.getElement(!0)),this}doLayout(){super.doLayout();let e=this.getContentBounds();return e?(this._renderer.setAutoCommitStyle(!1),this._renderer.setX(e.x),this._renderer.setY(e.y),this._renderer.setWidth(e.width),this._renderer.setHeight(e.height),this._renderer.setAutoCommitStyle(!0),this._renderer.layoutChildren(e.width,e.height),this):this}},ComboBoxCaret=class extends s{_glyph=new l(`chevron-down`);_size;constructor(){super({tag:`span`}),this._size=t.lineHeightPx({linePadding:!1}),this.setMinSize({width:this._size,height:this._size}),this.setMaxSize({width:this._size,height:this._size}),this.setPointerEvents(`none`),this._glyph.setPreferredSize({width:this._size,height:this._size}),this._glyph.setPointerEvents(`none`),this.addComponent(this._glyph)}getCaretSize(){return this._size}getGlyph(){return this._glyph}},ComboBox=class extends m{_dropdown;_label;_caret;_pendingValue=null;_boundStore=null;_onStoreRefresh;constructor(e,t){super(e,{...J,...t??{}}),this.getAria().setRole(`combobox`),this.getAria().setExpanded(!1),this.getAria().setTabIndex(0),this._label=new ComboBoxLabel(this._options.rendererFactory??(()=>new C)),this._caret=new ComboBoxCaret,this.addComponent(this._label),this.addComponent(this._caret),this._dropdown=new ComboBoxDropdown(e=>this.onRowSelected(e)),this._options.dropdownAnimated!==void 0&&this._dropdown.setAnimated(this._options.dropdownAnimated),this._options.dropdownMinWidth!==void 0&&this._dropdown.setMinWidth(this._options.dropdownMinWidth),this._options.rendererFactory!==void 0&&this._dropdown.getList().setRendererFactory(this._options.rendererFactory),this.refreshLabel(),this.updateHeight(),this.subscribeTheme(()=>this.updateHeight()),i.addListener(this,`click`,()=>this.toggleDropdown()),i.addListener(this,`keydown`,e=>this.onKeyDown(e)),this._dropdown.setCloseHandler(()=>this.closeDropdown()),this._onStoreRefresh=()=>this.onStoreRefresh(),this._options.store!==void 0&&this._options.displayField!==void 0&&this.setStore(this._options.store,this._options.displayField,this._options.valueField,this._options.glyphField),this._options.items!==void 0&&this.setItems(this._options.items),this._options.selectedIndex!==void 0&&this.setSelectedIndex(this._options.selectedIndex,!1),this._options.value!==void 0&&this.setValue(this._options.value),this._options.selectedItem!==void 0&&this.setValue(this._options.selectedItem),this._options.enabled!==void 0&&this.applyEnabled(this._options.enabled),this._options.readOnly!==void 0&&this.applyReadOnly(this._options.readOnly)}applyOptions(e){return super.applyOptions(e),e.items!==void 0&&(this._options.items=e.items),e.store!==void 0&&(this._options.store=e.store),e.displayField!==void 0&&(this._options.displayField=e.displayField),e.valueField!==void 0&&(this._options.valueField=e.valueField),e.glyphField!==void 0&&(this._options.glyphField=e.glyphField),e.rendererFactory!==void 0&&(this._options.rendererFactory=e.rendererFactory),e.selectedIndex!==void 0&&(this._options.selectedIndex=e.selectedIndex),e.value!==void 0&&(this._options.value=e.value),e.selectedItem!==void 0&&(this._options.selectedItem=e.selectedItem),e.dropdownAnimated!==void 0&&(this._options.dropdownAnimated=e.dropdownAnimated),e.dropdownMinWidth!==void 0&&this.setDropdownMinWidth(e.dropdownMinWidth),this}updateHeight(){let e=t.singleLineBoxHeight(this.getInsets(),this.getPadding(),this.getBorderSize()),n=this.getPreferredSizeConstraint()?.width??200;this.setPreferredSize({width:n,height:e});let r=this.getMaxSizeConstraint()?.width??2**53-1;this.setMaxSize({width:r,height:e});let i=this.getMinSizeConstraint()?.width??0;this.setMinSize({width:i,height:e})}doLayout(){super.doLayout();let e=this.getContentBounds();if(!e)return this;let t=this._caret.getCaretSize(),n=Math.max(0,e.width-t-6),r=e.x+n+6,i=e.y+Math.max(0,(e.height-t)/2);return this._label.setX(e.x),this._label.setY(e.y),this._label.setWidth(n),this._label.setHeight(e.height),this._label.setLineHeight(e.height),this._label.doLayout(),this._caret.setX(r),this._caret.setY(i),this._caret.setWidth(t),this._caret.setHeight(t),this}getBaseline(){return this.wrapInnerBaseline(t.measureTextBaseline())}openDropdown(){return this._dropdown.isOpen()||this.toggleDropdown(),this}toggleDropdown(){if(this._dropdown.isOpen()){this.closeDropdown();return}let e=this.getElement(!0),t=this._dropdown.getList();this._dropdown.setAnchorElement(e),this._dropdown.showAt(e,t.getItems(),t.getSelectedIndex()),this.getAria().setExpanded(!0),this.setCaretOpen(!0)}setCaretOpen(e){let t=this._caret.getGlyph(),n=this._dropdown.isAnimated()?this._dropdown.getDurationMs():0;t.setTransition(`transform ${n}ms ease`),t.setTransform(e?`rotate(180deg)`:`rotate(0deg)`)}closeDropdown(){this._dropdown.isOpen()&&(this._dropdown.hideAnimated(),this.getAria().setExpanded(!1),this.setCaretOpen(!1))}onKeyDown(e){if(this._dropdown.isOpen())return this._dropdown.handleKey(e)?{prevent:!0}:e.key===`Escape`?(this.closeDropdown(),{prevent:!0}):void 0;switch(e.key){case`ArrowDown`:case`ArrowUp`:case`Enter`:case` `:return this.toggleDropdown(),{prevent:!0}}}onRowSelected(e){this.setSelectedIndex(e,!0),this.closeDropdown()}computeSelectedItem(){let e=this._dropdown.getList(),t=e.getSelectedIndex(),n=e.getItems();return t>=0&&t<n.length?{item:n[t],index:t}:{item:{key:``,label:``},index:-1}}refreshLabel(){let{item:e,index:t}=this.computeSelectedItem();this._label.setItem(e,t)}on(e,t){return super.on(e===`action`?`change`:e,t)}off(e,t){return super.off(e===`action`?`change`:e,t)}setValue(e){return this._pendingValue=e,this._dropdown.getList().setValue(e),this.refreshLabel(),this}getValue(){return this._dropdown.getList().getValue()||(this._pendingValue??``)}getSelectedIndex(){return this._dropdown.getList().getSelectedIndex()}setSelectedIndex(e,t=!0){return this._dropdown.getList().setSelectedIndex(e,!1),this._pendingValue=null,this.refreshLabel(),t&&this.notifyChange(this.getValue()),this}getItems(){return this._dropdown.getList().getItems()}setItems(e){return this._dropdown.getList().setItems(e),this.reapplyPendingValue(),this.autoSelectFirstIfEmpty(),this.refreshLabel(),this}addItem(e){return this._dropdown.getList().addItem(e),this.reapplyPendingValue(),this.autoSelectFirstIfEmpty(),this.refreshLabel(),this}setStore(e,t,n,r){return this._options.store=e,this._options.displayField=t,this._options.valueField=n,this._options.glyphField=r,this._boundStore&&[`load`,`add`,`remove`,`datachange`].forEach(e=>this._boundStore.off(e,this._onStoreRefresh)),this._dropdown.getList().setStore(e,t,n,r),this._boundStore=e,[`load`,`add`,`remove`,`datachange`].forEach(t=>e.on(t,this._onStoreRefresh)),this.reapplyPendingValue(),this.autoSelectFirstIfEmpty(),this.refreshLabel(),this}getStore(){return this._dropdown.getList().getStore()}setRendererFactory(e){return this._options.rendererFactory=e,this._dropdown.getList().setRendererFactory(e),this._label.setRenderer(e()),this.refreshLabel(),this}getRendererFactory(){return this._dropdown.getList().getRendererFactory()}getSelectedRecord(){return this._dropdown.getList().getSelectedRecord()}reapplyPendingValue(){if(this._pendingValue===null)return;let e=this._dropdown.getList();e.setValue(this._pendingValue),e.getSelectedIndex()>=0&&(this._pendingValue=null)}autoSelectFirstIfEmpty(){let e=this._dropdown.getList();e.getSelectedIndex()<0&&e.getItems().length>0&&e.setSelectedIndex(0,!1)}onStoreRefresh(){this.reapplyPendingValue(),this.autoSelectFirstIfEmpty(),this.refreshLabel()}setDropdownAnimated(e){return this._options.dropdownAnimated=e,this._dropdown.setAnimated(e),this}isDropdownAnimated(){return this._options.dropdownAnimated??!0}setDropdownMinWidth(e){return this._options.dropdownMinWidth=e,this._dropdown.setMinWidth(e),this}getDropdownMinWidth(){return this._options.dropdownMinWidth??Q}applyEnabled(e){this.getAria().setDisabled(!e),this.getAria().setTabIndex(e?0:-1),this.setCursor(e?`pointer`:`default`),e||this.closeDropdown()}applyReadOnly(e){this.getAria().setReadOnly(e)}},$=o(ComboBox);export{B as a,PickerColumn as c,registerFocusWithinRing as d,N as f,O as h,W as i,R as l,A as m,q as n,PickerCell as o,M as p,G as r,PickerCellList as s,$ as t,AbstractPickerField as u};
2
+ //# sourceMappingURL=ComboBox-Dx8Tk9yg.js.map