@jimka/typescript-ui 0.4.1 → 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 (292) hide show
  1. package/dist/lib/{AbstractInput-BxfrmD2W.js → AbstractInput-sRNPzWel.js} +2 -2
  2. package/dist/lib/{AbstractInput-BxfrmD2W.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/AnchorConstraints-Bfkt8019.js +2 -0
  6. package/dist/lib/AnchorConstraints-Bfkt8019.js.map +1 -0
  7. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js +2 -0
  8. package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js.map +1 -0
  9. package/dist/lib/Border-0DJFDiij.js +2 -0
  10. package/dist/lib/Border-0DJFDiij.js.map +1 -0
  11. package/dist/lib/Button-MpMIYBYJ.js +2 -0
  12. package/dist/lib/Button-MpMIYBYJ.js.map +1 -0
  13. package/dist/lib/{Card-a4dzYrbX.js → Card-QYo27r5b.js} +2 -2
  14. package/dist/lib/{Card-a4dzYrbX.js.map → Card-QYo27r5b.js.map} +1 -1
  15. package/dist/lib/Checkbox-D0JYK-wc.js +2 -0
  16. package/dist/lib/Checkbox-D0JYK-wc.js.map +1 -0
  17. package/dist/lib/CheckboxMenuRow-CesLhSnp.js +2 -0
  18. package/dist/lib/CheckboxMenuRow-CesLhSnp.js.map +1 -0
  19. package/dist/lib/CodeEditor-N1FQodcF.js +2 -0
  20. package/dist/lib/CodeEditor-N1FQodcF.js.map +1 -0
  21. package/dist/lib/ComboBox-Dx8Tk9yg.js +2 -0
  22. package/dist/lib/ComboBox-Dx8Tk9yg.js.map +1 -0
  23. package/dist/lib/Component-B0ShfPVi.js +2 -0
  24. package/dist/lib/Component-B0ShfPVi.js.map +1 -0
  25. package/dist/lib/Container-abY5Ww3W.js +2 -0
  26. package/dist/lib/{Container-0bsG2Q8Z.js.map → Container-abY5Ww3W.js.map} +1 -1
  27. package/dist/lib/DOM-C-Edb3tA.js +2 -0
  28. package/dist/lib/DOM-C-Edb3tA.js.map +1 -0
  29. package/dist/lib/Dialog-cbA9V17e.js +2 -0
  30. package/dist/lib/Dialog-cbA9V17e.js.map +1 -0
  31. package/dist/lib/{FieldDecorator-Bpx8J8n9.js → FieldDecorator-BlYMfZ9L.js} +2 -2
  32. package/dist/lib/{FieldDecorator-Bpx8J8n9.js.map → FieldDecorator-BlYMfZ9L.js.map} +1 -1
  33. package/dist/lib/{Fit-CL1m1nIZ.js → Fit-BhlB-HAo.js} +2 -2
  34. package/dist/lib/{Fit-CL1m1nIZ.js.map → Fit-BhlB-HAo.js.map} +1 -1
  35. package/dist/lib/FloatingPanel-DkJXsZ2D.js +2 -0
  36. package/dist/lib/FloatingPanel-DkJXsZ2D.js.map +1 -0
  37. package/dist/lib/{Glyph-wN7bk7mg.js → Glyph-_VeBacS2.js} +2 -2
  38. package/dist/lib/{Glyph-wN7bk7mg.js.map → Glyph-_VeBacS2.js.map} +1 -1
  39. package/dist/lib/{Grid-DHHmaB-Y.js → Grid-Daiz7F5d.js} +2 -2
  40. package/dist/lib/Grid-Daiz7F5d.js.map +1 -0
  41. package/dist/lib/GridConstraints-C58LuTqM.js +2 -0
  42. package/dist/lib/{GridConstraints-DVc1BmlP.js.map → GridConstraints-C58LuTqM.js.map} +1 -1
  43. package/dist/lib/{Header-2hKwQo_u.js → Header-Dql3Zxc6.js} +2 -2
  44. package/dist/lib/{Header-2hKwQo_u.js.map → Header-Dql3Zxc6.js.map} +1 -1
  45. package/dist/lib/{IconText-DC7Xe34b.js → IconText-PUjhTLlp.js} +2 -2
  46. package/dist/lib/{IconText-DC7Xe34b.js.map → IconText-PUjhTLlp.js.map} +1 -1
  47. package/dist/lib/LanguageRegistry-CcVnbKuh.js +2 -0
  48. package/dist/lib/LanguageRegistry-CcVnbKuh.js.map +1 -0
  49. package/dist/lib/LayoutSerialization-CMxunLfV.js +2 -0
  50. package/dist/lib/LayoutSerialization-CMxunLfV.js.map +1 -0
  51. package/dist/lib/List-nx8220Fi.js +2 -0
  52. package/dist/lib/{List-CG4NvwuV.js.map → List-nx8220Fi.js.map} +1 -1
  53. package/dist/lib/MemoryStore-DhPoU-7X.js +2 -0
  54. package/dist/lib/MemoryStore-DhPoU-7X.js.map +1 -0
  55. package/dist/lib/Menu-Q0bpXXze.js +2 -0
  56. package/dist/lib/Menu-Q0bpXXze.js.map +1 -0
  57. package/dist/lib/{MenuButton-wy_0RskC.js → MenuButton-DCXi0tsP.js} +2 -2
  58. package/dist/lib/{MenuButton-wy_0RskC.js.map → MenuButton-DCXi0tsP.js.map} +1 -1
  59. package/dist/lib/OverlayFade-3pof2AJH.js +2 -0
  60. package/dist/lib/OverlayFade-3pof2AJH.js.map +1 -0
  61. package/dist/lib/Panel-Cy1pdlWO.js +2 -0
  62. package/dist/lib/{Panel-Rd9zkNXx.js.map → Panel-Cy1pdlWO.js.map} +1 -1
  63. package/dist/lib/{Position-Ck_KD4cR.js → Position-BwtxouxK.js} +2 -2
  64. package/dist/lib/{Position-Ck_KD4cR.js.map → Position-BwtxouxK.js.map} +1 -1
  65. package/dist/lib/{ProgressSpinner-yt-VXyCb.js → ProgressSpinner-DK8xEQ9y.js} +2 -2
  66. package/dist/lib/{ProgressSpinner-yt-VXyCb.js.map → ProgressSpinner-DK8xEQ9y.js.map} +1 -1
  67. package/dist/lib/RadioButton-BEwpqg1k.js +2 -0
  68. package/dist/lib/RadioButton-BEwpqg1k.js.map +1 -0
  69. package/dist/lib/RadioMenuRow-DP5qPyFR.js +2 -0
  70. package/dist/lib/RadioMenuRow-DP5qPyFR.js.map +1 -0
  71. package/dist/lib/{RovingTabIndex-DFJyoveq.js → RovingTabIndex-pHEv5oLD.js} +2 -2
  72. package/dist/lib/{RovingTabIndex-DFJyoveq.js.map → RovingTabIndex-pHEv5oLD.js.map} +1 -1
  73. package/dist/lib/Scrollbar-t8fFrUVQ.js +2 -0
  74. package/dist/lib/Scrollbar-t8fFrUVQ.js.map +1 -0
  75. package/dist/lib/Slider-CTbwR6HR.js +2 -0
  76. package/dist/lib/Slider-CTbwR6HR.js.map +1 -0
  77. package/dist/lib/{Spacer-qalSEJ5i.js → Spacer-srdN2d2b.js} +2 -2
  78. package/dist/lib/{Spacer-qalSEJ5i.js.map → Spacer-srdN2d2b.js.map} +1 -1
  79. package/dist/lib/TabButton-DLoMQzky.js +2 -0
  80. package/dist/lib/TabButton-DLoMQzky.js.map +1 -0
  81. package/dist/lib/TabCloseButton-CY7BGitY.js +2 -0
  82. package/dist/lib/TabCloseButton-CY7BGitY.js.map +1 -0
  83. package/dist/lib/Text-CMKnK9uB.js +2 -0
  84. package/dist/lib/Text-CMKnK9uB.js.map +1 -0
  85. package/dist/lib/{Tooltip-Dro4DOZs.js → Tooltip-CUOJOqQi.js} +3 -3
  86. package/dist/lib/Tooltip-CUOJOqQi.js.map +1 -0
  87. package/dist/lib/Tree-C64JNPWJ.js +2 -0
  88. package/dist/lib/Tree-C64JNPWJ.js.map +1 -0
  89. package/dist/lib/VBox-DfJPWXqc.js +2 -0
  90. package/dist/lib/VBox-DfJPWXqc.js.map +1 -0
  91. package/dist/lib/{Validator-Du8PqS5i.js → Validator-Cjs1EU5Q.js} +2 -2
  92. package/dist/lib/{Validator-Du8PqS5i.js.map → Validator-Cjs1EU5Q.js.map} +1 -1
  93. package/dist/lib/VirtualScroller-DTIn19o1.js +2 -0
  94. package/dist/lib/VirtualScroller-DTIn19o1.js.map +1 -0
  95. package/dist/lib/assets/StoreWorker-B5NwRM2I.js +2 -0
  96. package/dist/lib/assets/StoreWorker-B5NwRM2I.js.map +1 -0
  97. package/dist/lib/component/button.es.js +1 -1
  98. package/dist/lib/component/button.es.js.map +1 -1
  99. package/dist/lib/component/chart.es.js +1 -1
  100. package/dist/lib/component/chart.es.js.map +1 -1
  101. package/dist/lib/component/container.es.js +1 -1
  102. package/dist/lib/component/container.es.js.map +1 -1
  103. package/dist/lib/component/diagram.es.js +1 -1
  104. package/dist/lib/component/diagram.es.js.map +1 -1
  105. package/dist/lib/component/display.es.js +1 -1
  106. package/dist/lib/component/display.es.js.map +1 -1
  107. package/dist/lib/component/editor.es.js +3 -3
  108. package/dist/lib/component/editor.es.js.map +1 -1
  109. package/dist/lib/component/input.es.js +1 -1
  110. package/dist/lib/component/input.es.js.map +1 -1
  111. package/dist/lib/component/list.es.js +1 -1
  112. package/dist/lib/component/list.es.js.map +1 -1
  113. package/dist/lib/component/menubar.es.js +1 -1
  114. package/dist/lib/component/menubar.es.js.map +1 -1
  115. package/dist/lib/component/table.es.js +6 -3
  116. package/dist/lib/component/table.es.js.map +1 -1
  117. package/dist/lib/component/tree.es.js +1 -1
  118. package/dist/lib/component/tree.es.js.map +1 -1
  119. package/dist/lib/core.es.js +1 -1
  120. package/dist/lib/core.es.js.map +1 -1
  121. package/dist/lib/data.es.js +1 -1
  122. package/dist/lib/glyphs/solid/index.es.js +1 -1
  123. package/dist/lib/languages-Dl8qdL8a.js +2 -0
  124. package/dist/lib/languages-Dl8qdL8a.js.map +1 -0
  125. package/dist/lib/layout.es.js +1 -1
  126. package/dist/lib/layout.es.js.map +1 -1
  127. package/dist/lib/overlay.es.js +1 -1
  128. package/dist/lib/overlay.es.js.map +1 -1
  129. package/dist/lib/primitive.es.js +1 -1
  130. package/dist/lib/router.es.js +1 -1
  131. package/dist/lib/router.es.js.map +1 -1
  132. package/dist/lib/selectionsEqual-gMG7gCVI.js +2 -0
  133. package/dist/lib/selectionsEqual-gMG7gCVI.js.map +1 -0
  134. package/dist/lib/types/component/button/Button.d.ts +13 -0
  135. package/dist/lib/types/component/button/MenuButton.d.ts +1 -0
  136. package/dist/lib/types/component/button/PopupButton.d.ts +22 -0
  137. package/dist/lib/types/component/button/TabButton.d.ts +5 -1
  138. package/dist/lib/types/component/button/ToggleButton.d.ts +1 -1
  139. package/dist/lib/types/component/button/index.d.ts +2 -0
  140. package/dist/lib/types/component/chart/ChartLegend.d.ts +1 -1
  141. package/dist/lib/types/component/container/CheckboxMenuRow.d.ts +33 -0
  142. package/dist/lib/types/component/container/CollapseButton.d.ts +11 -3
  143. package/dist/lib/types/component/container/FloatingPanel.d.ts +23 -0
  144. package/dist/lib/types/component/container/MenuItem.d.ts +15 -5
  145. package/dist/lib/types/component/container/MenuRow.d.ts +24 -0
  146. package/dist/lib/types/component/container/MenuSeparator.d.ts +4 -2
  147. package/dist/lib/types/component/container/RadioMenuRow.d.ts +33 -0
  148. package/dist/lib/types/component/container/ScrollStrip.d.ts +1 -1
  149. package/dist/lib/types/component/container/Scrollbar.d.ts +6 -3
  150. package/dist/lib/types/component/container/SplitGutter.d.ts +7 -2
  151. package/dist/lib/types/component/container/TabBar.d.ts +3 -1
  152. package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
  153. package/dist/lib/types/component/container/index.d.ts +8 -1
  154. package/dist/lib/types/component/diagram/DiagramGroupNode.d.ts +1 -1
  155. package/dist/lib/types/component/display/Markdown.d.ts +42 -1
  156. package/dist/lib/types/component/display/MarkdownMinimap.d.ts +38 -0
  157. package/dist/lib/types/component/display/MarkdownViewer.d.ts +60 -0
  158. package/dist/lib/types/component/display/WebGLCanvas.d.ts +1 -0
  159. package/dist/lib/types/component/display/index.d.ts +6 -0
  160. package/dist/lib/types/component/editor/CodeEditor.d.ts +13 -0
  161. package/dist/lib/types/component/editor/index.d.ts +1 -1
  162. package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +2 -0
  163. package/dist/lib/types/component/input/AbstractPickerField.d.ts +3 -2
  164. package/dist/lib/types/component/input/Checkbox.d.ts +1 -1
  165. package/dist/lib/types/component/input/RadioButton.d.ts +1 -1
  166. package/dist/lib/types/component/input/Slider.d.ts +1 -1
  167. package/dist/lib/types/component/input/Text.d.ts +0 -2
  168. package/dist/lib/types/component/input/Toggle.d.ts +1 -1
  169. package/dist/lib/types/component/list/AbstractSelectableList.d.ts +1 -1
  170. package/dist/lib/types/component/list/MultiSelectList.d.ts +2 -1
  171. package/dist/lib/types/component/menubar/MenuBar.d.ts +1 -1
  172. package/dist/lib/types/component/menubar/ToolBar.d.ts +1 -0
  173. package/dist/lib/types/component/shared/VirtualRowView.d.ts +2 -0
  174. package/dist/lib/types/component/table/Body.d.ts +23 -1
  175. package/dist/lib/types/component/table/Column.d.ts +3 -1
  176. package/dist/lib/types/component/table/ColumnConfig.d.ts +2 -0
  177. package/dist/lib/types/component/table/ColumnFilter.d.ts +27 -0
  178. package/dist/lib/types/component/table/Header.d.ts +30 -3
  179. package/dist/lib/types/component/table/Row.d.ts +4 -0
  180. package/dist/lib/types/component/table/Table.d.ts +29 -0
  181. package/dist/lib/types/component/table/TableExporter.d.ts +4 -3
  182. package/dist/lib/types/component/table/TreeBody.d.ts +2 -1
  183. package/dist/lib/types/component/table/cell/CellText.d.ts +9 -0
  184. package/dist/lib/types/component/table/cell/Filter.d.ts +54 -0
  185. package/dist/lib/types/component/table/cell/FilterClauseBadge.d.ts +21 -0
  186. package/dist/lib/types/component/table/cell/GroupSeparator.d.ts +9 -0
  187. package/dist/lib/types/component/table/cell/Header.d.ts +1 -0
  188. package/dist/lib/types/component/table/cell/SortPriorityBadge.d.ts +1 -1
  189. package/dist/lib/types/component/table/cell/editor/CellEditor.d.ts +1 -0
  190. package/dist/lib/types/component/table/cell/editor/CellEditorPool.d.ts +1 -0
  191. package/dist/lib/types/component/table/cell/editor/Date.d.ts +1 -0
  192. package/dist/lib/types/component/table/cell/editor/DateTime.d.ts +1 -0
  193. package/dist/lib/types/component/table/cell/editor/Time.d.ts +1 -0
  194. package/dist/lib/types/component/table/cell/renderer/CellRenderer.d.ts +1 -0
  195. package/dist/lib/types/component/table/cell/renderer/Combo.d.ts +2 -0
  196. package/dist/lib/types/component/table/cell/renderer/Date.d.ts +2 -0
  197. package/dist/lib/types/component/table/cell/renderer/DateTime.d.ts +2 -0
  198. package/dist/lib/types/component/table/cell/renderer/Filter.d.ts +16 -0
  199. package/dist/lib/types/component/table/cell/renderer/Glyph.d.ts +1 -0
  200. package/dist/lib/types/component/table/cell/renderer/Link.d.ts +2 -0
  201. package/dist/lib/types/component/table/cell/renderer/Number.d.ts +3 -1
  202. package/dist/lib/types/component/table/cell/renderer/String.d.ts +2 -0
  203. package/dist/lib/types/component/table/cell/renderer/Time.d.ts +2 -0
  204. package/dist/lib/types/component/table/cell/renderer/TreeCell.d.ts +1 -0
  205. package/dist/lib/types/component/table/index.d.ts +6 -0
  206. package/dist/lib/types/component/tree/Tree.d.ts +26 -2
  207. package/dist/lib/types/component/tree/index.d.ts +1 -1
  208. package/dist/lib/types/component/tree/renderer/Label.d.ts +1 -1
  209. package/dist/lib/types/core/AnimatedDropdown.d.ts +0 -9
  210. package/dist/lib/types/core/Body.d.ts +4 -0
  211. package/dist/lib/types/core/ClassStyleRules.d.ts +1 -0
  212. package/dist/lib/types/core/Component.d.ts +5 -0
  213. package/dist/lib/types/core/DOM.d.ts +10 -0
  214. package/dist/lib/types/core/Event.d.ts +11 -2
  215. package/dist/lib/types/core/OverlayFade.d.ts +12 -0
  216. package/dist/lib/types/core/OverlayPosition.d.ts +6 -0
  217. package/dist/lib/types/core/Theme.d.ts +12 -2
  218. package/dist/lib/types/core/index.d.ts +5 -3
  219. package/dist/lib/types/data/AbstractStore.d.ts +3 -0
  220. package/dist/lib/types/data/FilterDescriptor.d.ts +13 -0
  221. package/dist/lib/types/data/index.d.ts +2 -1
  222. package/dist/lib/types/data/temporalText.d.ts +2 -0
  223. package/dist/lib/types/layout/BoxLayout.d.ts +6 -1
  224. package/dist/lib/types/layout/Grid.d.ts +1 -0
  225. package/dist/lib/types/layout/HFlow.d.ts +1 -1
  226. package/dist/lib/types/layout/LayoutManager.d.ts +8 -0
  227. package/dist/lib/types/layout/Split.d.ts +10 -1
  228. package/dist/lib/types/layout/Tab.d.ts +7 -1
  229. package/dist/lib/types/layout/VFlow.d.ts +1 -1
  230. package/dist/lib/types/layout/index.d.ts +1 -1
  231. package/dist/lib/types/overlay/Dock.d.ts +1 -0
  232. package/dist/lib/types/overlay/Menu.d.ts +1 -1
  233. package/dist/lib/types/overlay/Popover.d.ts +3 -0
  234. package/dist/lib/types/overlay/PopupPanel.d.ts +17 -0
  235. package/dist/lib/types/overlay/Window.d.ts +2 -0
  236. package/dist/lib/types/overlay/index.d.ts +2 -0
  237. package/dist/lib/types/router/RoutePattern.d.ts +7 -0
  238. package/dist/lib/types/router/Router.d.ts +6 -2
  239. package/dist/lib/types/router/index.d.ts +1 -1
  240. package/dist/lib/validation.es.js +1 -1
  241. package/llms.txt +7 -0
  242. package/package.json +15 -15
  243. package/dist/lib/AbstractBooleanInput-DE5NNJT0.js +0 -2
  244. package/dist/lib/AbstractBooleanInput-DE5NNJT0.js.map +0 -1
  245. package/dist/lib/AnchorConstraints-DdDYSDkf.js +0 -2
  246. package/dist/lib/AnchorConstraints-DdDYSDkf.js.map +0 -1
  247. package/dist/lib/AnimatedDropdown-QLNasu_Y.js +0 -2
  248. package/dist/lib/AnimatedDropdown-QLNasu_Y.js.map +0 -1
  249. package/dist/lib/Border-CKKUk5G9.js +0 -2
  250. package/dist/lib/Border-CKKUk5G9.js.map +0 -1
  251. package/dist/lib/Button-MZDYJOMC.js +0 -2
  252. package/dist/lib/Button-MZDYJOMC.js.map +0 -1
  253. package/dist/lib/ComboBox-C04SfXAR.js +0 -2
  254. package/dist/lib/ComboBox-C04SfXAR.js.map +0 -1
  255. package/dist/lib/Component-fRQvgaEY.js +0 -2
  256. package/dist/lib/Component-fRQvgaEY.js.map +0 -1
  257. package/dist/lib/Container-0bsG2Q8Z.js +0 -2
  258. package/dist/lib/DOM-67StIm5G.js +0 -2
  259. package/dist/lib/DOM-67StIm5G.js.map +0 -1
  260. package/dist/lib/DragManager-DRor_-1x.js +0 -2
  261. package/dist/lib/DragManager-DRor_-1x.js.map +0 -1
  262. package/dist/lib/Grid-DHHmaB-Y.js.map +0 -1
  263. package/dist/lib/GridConstraints-DVc1BmlP.js +0 -2
  264. package/dist/lib/LayoutSerialization-D5bBas4W.js +0 -2
  265. package/dist/lib/LayoutSerialization-D5bBas4W.js.map +0 -1
  266. package/dist/lib/LayoutSizes-qNaURyiw.js +0 -2
  267. package/dist/lib/LayoutSizes-qNaURyiw.js.map +0 -1
  268. package/dist/lib/List-CG4NvwuV.js +0 -2
  269. package/dist/lib/MemoryStore-DT6iWWco.js +0 -2
  270. package/dist/lib/MemoryStore-DT6iWWco.js.map +0 -1
  271. package/dist/lib/Menu-CrZy2u0g.js +0 -2
  272. package/dist/lib/Menu-CrZy2u0g.js.map +0 -1
  273. package/dist/lib/Panel-Rd9zkNXx.js +0 -2
  274. package/dist/lib/RadioButton-D23rId-V.js +0 -2
  275. package/dist/lib/RadioButton-D23rId-V.js.map +0 -1
  276. package/dist/lib/Scrollbar-SOj9psiP.js +0 -2
  277. package/dist/lib/Scrollbar-SOj9psiP.js.map +0 -1
  278. package/dist/lib/Slider-DBnAZ-F7.js +0 -2
  279. package/dist/lib/Slider-DBnAZ-F7.js.map +0 -1
  280. package/dist/lib/TabButton-DKECTTk1.js +0 -2
  281. package/dist/lib/TabButton-DKECTTk1.js.map +0 -1
  282. package/dist/lib/Text-KB5LksJl.js +0 -2
  283. package/dist/lib/Text-KB5LksJl.js.map +0 -1
  284. package/dist/lib/Tooltip-Dro4DOZs.js.map +0 -1
  285. package/dist/lib/VBox-P3WFGkPc.js +0 -2
  286. package/dist/lib/VBox-P3WFGkPc.js.map +0 -1
  287. package/dist/lib/VirtualScroller-Bv4KXGKW.js +0 -2
  288. package/dist/lib/VirtualScroller-Bv4KXGKW.js.map +0 -1
  289. package/dist/lib/assets/StoreWorker-CgOBYoai.js +0 -2
  290. package/dist/lib/assets/StoreWorker-CgOBYoai.js.map +0 -1
  291. package/dist/lib/selectionsEqual-Ci3_uflt.js +0 -2
  292. package/dist/lib/selectionsEqual-Ci3_uflt.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"core.es.js","names":[],"sources":["../../src/typescript/lib/core/themes/ClassicTheme.ts","../../src/typescript/lib/core/themes/DarkTheme.ts","../../src/typescript/lib/core/Form.ts","../../src/typescript/lib/core/Favicon.ts","../../src/typescript/lib/core/Body.ts","../../src/typescript/lib/core/FocusHistory.ts","../../src/typescript/lib/core/Binding.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Classic light theme using white backgrounds, black text, and gradient\n * buttons. The original default look, retained as an opt-in alternative now\n * that {@link ModernTheme} is the preselected theme.\n *\n * Authored as `defineTheme(BaseTheme, …)`: it declares only its palette (and\n * `colorScheme`); every structural token is inherited from {@link BaseTheme}.\n * Classic carries no structural override — its `tab.underBorderFullWidth`\n * already matches the base value.\n *\n * @category Theme\n */\nexport const ClassicTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'light',\n text : { color: 'rgb(0, 0, 0)' },\n body : { background: 'rgb(255, 255, 255)' },\n border : { color: 'black' },\n button : {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : 'rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n description: {\n foreground: 'rgb(110, 110, 110)',\n },\n pressed : {\n foreground: 'rgb(150, 150, 150)',\n background: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.30)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.25)',\n },\n flat : {\n hover : {\n background: 'rgba(0, 0, 0, 0.06)',\n border : '1px solid rgb(200, 200, 200)',\n },\n pressed: {\n background: 'rgba(0, 0, 0, 0.10)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.25)',\n border : '1px solid rgb(180, 180, 180)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(200, 200, 200)',\n shadow : '2px 2px 1px inset grey',\n },\n },\n input : {\n background : 'rgb(255, 255, 255)',\n border : '1px solid rgb(160, 160, 160)',\n borderHover: '1px solid rgb(120, 120, 120)',\n },\n form : {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(160, 160, 160)',\n color : 'rgb(40, 40, 40)',\n disabledBackground: 'rgb(240, 240, 240)',\n disabledColor : 'rgb(170, 170, 170)',\n focusRing : 'rgb(30, 100, 200)',\n toggle : {\n trackOffBackground: 'rgb(200, 200, 200)',\n trackOnBackground : 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n slider : {\n trackBackground : 'rgb(220, 220, 220)',\n trackActiveBackground: 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n checkbox: {\n background : 'rgb(255, 255, 255)',\n selectedBackground : 'rgb(30, 100, 200)',\n indeterminateBackground: 'rgb(160, 160, 160)',\n checkColor : 'rgb(255, 255, 255)',\n },\n radio : {\n background : 'rgb(255, 255, 255)',\n selectedBackground: 'rgb(30, 100, 200)',\n dotColor : 'rgb(255, 255, 255)',\n },\n },\n gutter: { background: '#AAAAAA' },\n collapse: {\n strip: { background: '#AAAAAA', size: '18px' },\n button: { color: 'rgb(100,100,100)' },\n },\n accordion: {\n border : '1px solid rgb(190,190,190)',\n header : {\n background: 'linear-gradient(rgb(230,230,230),rgb(210,210,210))',\n border : '1px solid rgb(190,190,190)',\n color : 'inherit',\n },\n panel : { border: 'rgb(210,210,210)' },\n indicator: { color: 'rgb(100,100,100)' },\n },\n tab : {\n toolbar: { background: '#eee', border: '#e1e1e8' },\n button : {\n background: 'linear-gradient(rgb(208, 208, 216), rgb(185, 185, 196))',\n border : 'none',\n hover : { background: 'linear-gradient(rgb(220, 220, 227), rgb(198, 198, 208))', border: 'none' },\n selected : { background: 'linear-gradient(rgb(255, 255, 255), rgb(235, 235, 240))', border: 'none' },\n },\n indicator: { color: '#1a73e8' },\n },\n window: {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.4)',\n snapGlow : '0 0 0 2px rgba(30, 100, 200, 0.7)',\n control : {\n background : 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : '1px solid rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n hoverBackground : 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n activeBackground: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n },\n header : { background: '#eee' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border: 'black',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.15)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.6)',\n new : 'rgba(70, 200, 70, 0.15)',\n dirty : 'rgba(255, 165, 0, 0.15)',\n stripe : 'rgba(0, 0, 0, 0.035)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(0, 0, 0, 0.04)',\n requiredEmptyOutlineColor : 'rgba(220, 60, 60, 0.6)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.6)',\n },\n resizeHandle: {\n color : 'rgba(0, 0, 0, 0.2)',\n },\n sortBadge: {\n background: 'rgba(0, 0, 0, 0.15)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(30, 100, 200, 0.10)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n },\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n statusBar: {\n background: 'rgb(245, 245, 245)',\n color : 'rgb(60, 60, 60)',\n border : 'rgb(220, 220, 220)',\n },\n toolBar: {\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n separatorColor: 'rgb(220, 220, 220)',\n },\n tooltip: {\n background: 'rgb(255, 255, 240)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(180, 180, 100)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.2)',\n },\n popover: {\n background: 'rgb(255, 255, 255)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.18)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n info : { background: 'rgba(210, 224, 244, 0.75)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(210, 240, 220, 0.75)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(248, 232, 204, 0.75)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(244, 214, 214, 0.75)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(200, 50, 50)',\n tooltip: {\n background: 'rgb(180, 30, 30)',\n color : 'rgb(255, 255, 255)',\n border : 'rgb(140, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0,0,0,0.15)',\n item: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n highlightBackground: 'rgba(30, 100, 200, 0.18)',\n highlightColor : 'inherit',\n disabledColor : 'rgb(170, 170, 170)',\n },\n },\n // Defaults mirror `autoComplete` numerically because both surfaces present\n // selectable rows; a theme that customises one gets the other matching\n // automatically. `row.separator` defaults to `transparent` so the visual\n // matches the prior native `<select>` (no row hairlines); themes can opt\n // in to a denser look by overriding to a `1px solid rgba(...)` colour.\n list: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n row: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.18)',\n selectedColor : 'inherit',\n focusRing : 'rgb(30, 100, 200)',\n disabledColor : 'rgb(170, 170, 170)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(30, 100, 200)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Picker tokens stay numerically in step with `autoComplete.item.*` — they\n // share the {@link PickerCell} class — so a theme that customises one\n // gets the other matching automatically.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(30, 100, 200, 0.08)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.45)' },\n border : 'rgb(220, 220, 220)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.35)',\n confirm : 'rgb(30, 180, 80)',\n cancel : 'rgb(200, 50, 50)',\n info : { background: 'rgba(30, 100, 200, 0.15)', foreground: 'rgb(30, 100, 200)' },\n affirm : { background: 'rgba(30, 180, 80, 0.15)', foreground: 'rgb(30, 180, 80)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.25)',\n border : 'rgb(220, 220, 220)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.18)',\n handle: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.16)',\n },\n },\n spinner: {\n dividerColor: 'rgb(180, 180, 180)',\n },\n progressBar: {\n track : { background: 'rgb(220, 220, 220)' },\n fill : { background: 'rgb(30, 100, 200)' },\n indeterminate: { background: 'rgb(30, 100, 200)' },\n },\n progressSpinner: {\n color : 'rgb(30, 100, 200)',\n backdrop: 'rgba(255, 255, 255, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(200, 200, 200, 0.9)',\n border : 'rgb(150, 150, 150)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.25)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.12)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.10)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(30, 100, 200)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : 'rgba(80, 140, 240, 0.40)',\n activeBackground : 'rgba(80, 140, 240, 0.28)',\n invalidBackground: 'rgba(200, 50, 50, 0.28)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.06)',\n border : '2px dashed rgba(80, 140, 240, 0.40)',\n activeBackground: 'rgba(80, 140, 240, 0.18)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.80)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito colour-blind-safe categorical palette, tuned for a light\n // background (Classic is a light scheme). Neutral grey axis/grid/label; the\n // selection ring reuses the theme's blue accent.\n chart: {\n series: [\n '#0072B2', // blue\n '#E69F00', // orange\n '#009E73', // green\n '#D55E00', // vermilion\n '#CC79A7', // purple\n '#56B4E9', // sky\n '#8C6D1F', // gold\n '#555555', // grey\n ],\n axis : 'rgb(120, 120, 120)',\n grid : 'rgb(220, 220, 220)',\n label : 'rgb(80, 80, 80)',\n selection: '#1a73e8',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Dark-mode theme using dark backgrounds and light text.\n *\n * Authored as `defineTheme(BaseTheme, …)`: beyond its palette and\n * `colorScheme: 'dark'`, its only structural divergence is\n * `tab.underBorderFullWidth: false` (the base value is `true`). Every other\n * structural token is inherited from {@link BaseTheme}.\n *\n * @category Theme\n */\nexport const DarkTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'dark',\n text : { color: 'rgb(220, 220, 220)' },\n body : { background: 'rgb(30, 30, 30)' },\n border : { color: 'rgb(90, 90, 90)' },\n button : {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border : 'rgb(80, 80, 80)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.5)',\n description: {\n foreground: 'rgb(160, 160, 160)',\n },\n pressed : {\n foreground: 'rgb(180, 180, 180)',\n background: 'linear-gradient(rgb(35, 35, 35), rgb(48, 48, 48))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.6)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(90, 90, 90), rgb(65, 65, 65))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.55)',\n },\n flat : {\n hover : {\n background: 'rgba(255, 255, 255, 0.08)',\n border : '1px solid rgb(90, 90, 90)',\n },\n pressed: {\n background: 'rgba(255, 255, 255, 0.12)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.55)',\n border : '1px solid rgb(70, 70, 70)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(35, 35, 35)',\n shadow : '2px 2px 1px inset #333',\n },\n },\n input : {\n background : 'rgb(40, 40, 40)',\n border : '1px solid rgb(110, 110, 110)',\n borderHover: '1px solid rgb(150, 150, 150)',\n },\n form : {\n background : 'rgb(40, 40, 40)',\n border : 'rgb(110, 110, 110)',\n color : 'rgb(230, 230, 230)',\n disabledBackground: 'rgb(60, 60, 60)',\n disabledColor : 'rgb(120, 120, 120)',\n focusRing : 'rgb(120, 170, 240)',\n toggle : {\n trackOffBackground: 'rgb(70, 70, 70)',\n trackOnBackground : 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n slider : {\n trackBackground : 'rgb(70, 70, 70)',\n trackActiveBackground: 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n checkbox: {\n background : 'rgb(40, 40, 40)',\n selectedBackground : 'rgb(120, 170, 240)',\n indeterminateBackground: 'rgb(100, 100, 100)',\n checkColor : 'rgb(20, 20, 20)',\n },\n radio : {\n background : 'rgb(40, 40, 40)',\n selectedBackground: 'rgb(120, 170, 240)',\n dotColor : 'rgb(20, 20, 20)',\n },\n },\n gutter: { background: '#555' },\n collapse: {\n strip: { background: '#555', size: '18px' },\n button: { color: 'rgb(160,160,160)' },\n },\n accordion: {\n border : '1px solid rgb(80,80,80)',\n header : {\n background: 'linear-gradient(rgb(60,60,60),rgb(45,45,45))',\n border : '1px solid rgb(80,80,80)',\n color : 'inherit',\n },\n panel : { border: 'rgb(70,70,70)' },\n indicator: { color: 'rgb(160,160,160)' },\n },\n tab : {\n underBorderFullWidth: false,\n toolbar: { background: '#2a2a2a', border: '#444' },\n button : {\n background: '#3a3a3a',\n border : 'none',\n hover : { background: '#454545', border: 'none' },\n selected : { background: 'rgb(30, 30, 30)', border: 'none' },\n },\n indicator: { color: '#4a9eff' },\n },\n window : {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.6)',\n snapGlow : '0 0 0 2px rgba(80, 150, 240, 0.8)',\n control : {\n background : 'rgb(30, 30, 30)',\n border : '1px solid transparent',\n shadow : 'none',\n hoverBackground : 'rgb(55, 55, 55)',\n activeBackground: 'rgb(45, 45, 45)',\n },\n header : { background: '#2a2a2a' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border: '#555',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.25)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.8)',\n new : 'rgba(70, 200, 70, 0.2)',\n dirty : 'rgba(255, 165, 0, 0.2)',\n stripe : 'rgba(255, 255, 255, 0.045)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(255, 255, 255, 0.04)',\n requiredEmptyOutlineColor : 'rgba(255, 90, 90, 0.8)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.8)',\n },\n resizeHandle: {\n color : 'rgba(255, 255, 255, 0.25)',\n },\n sortBadge: {\n background: 'rgba(255, 255, 255, 0.2)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(100, 140, 220, 0.15)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n },\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n statusBar: {\n background: 'rgb(45, 45, 45)',\n color : 'rgb(200, 200, 200)',\n border : 'rgb(70, 70, 70)',\n },\n toolBar: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n separatorColor: 'rgb(70, 70, 70)',\n },\n tooltip: {\n background: 'rgb(60, 60, 45)',\n color : 'rgb(220, 220, 180)',\n border : 'rgb(120, 110, 70)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.5)',\n },\n popover: {\n background: 'rgb(50, 50, 55)',\n color : 'rgb(230, 230, 235)',\n border : 'rgb(90, 90, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.55)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.4)',\n info : { background: 'rgba(30, 100, 200, 0.4)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(30, 180, 80, 0.4)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(220, 140, 0, 0.4)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(200, 50, 50, 0.4)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(220, 80, 80)',\n tooltip: {\n background: 'rgb(160, 30, 30)',\n color : 'rgb(255, 220, 220)',\n border : 'rgb(120, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0,0,0,0.5)',\n item: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n highlightBackground: 'rgba(100, 140, 220, 0.28)',\n highlightColor : 'rgb(220, 220, 255)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n },\n // Dark defaults track `autoComplete` for the same hover/selected hues so\n // the row chrome stays consistent across the two popover surfaces.\n list: {\n background: 'rgb(40, 40, 40)',\n border : 'rgb(80, 80, 80)',\n row: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n selectedBackground: 'rgba(100, 140, 220, 0.28)',\n selectedColor : 'rgb(220, 220, 255)',\n focusRing : 'rgb(120, 170, 240)',\n disabledColor : 'rgb(100, 100, 100)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(120, 170, 240)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Dark picker tokens follow the dark `autoComplete.item.*` hue family for\n // chevron-hover consistency with cell hover.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(120, 170, 255, 0.12)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.65)' },\n border : 'rgb(70, 70, 70)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.6)',\n confirm : 'rgb(80, 200, 110)',\n cancel : 'rgb(220, 90, 90)',\n info : { background: 'rgba(30, 100, 200, 0.25)', foreground: 'rgb(60, 130, 220)' },\n affirm : { background: 'rgba(80, 200, 110, 0.25)', foreground: 'rgb(80, 200, 110)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.55)',\n border : 'rgb(70, 70, 70)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(70, 70, 70)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.45)',\n handle: {\n hoverBackground : 'rgba(120, 170, 240, 0.12)',\n selectedBackground: 'rgba(120, 170, 240, 0.22)',\n },\n },\n spinner: {\n dividerColor: 'rgb(80, 80, 80)',\n },\n progressBar: {\n track : { background: 'rgb(55, 55, 55)' },\n fill : { background: 'rgb(60, 130, 220)' },\n indeterminate: { background: 'rgb(60, 130, 220)' },\n },\n progressSpinner: {\n color : 'rgb(60, 130, 220)',\n backdrop: 'rgba(20, 20, 20, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(60, 60, 60, 0.9)',\n border : 'rgb(100, 100, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.6)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.2)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.18)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(80, 140, 240)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.12)',\n border : 'rgba(80, 140, 240, 0.45)',\n activeBackground : 'rgba(80, 140, 240, 0.32)',\n invalidBackground: 'rgba(200, 50, 50, 0.32)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : '2px dashed rgba(80, 140, 240, 0.45)',\n activeBackground: 'rgba(80, 140, 240, 0.24)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.85)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito-derived categorical palette, brightened for adequate contrast on\n // a dark background. Light-grey axis/label with a dim grid; the selection\n // ring reuses the theme's blue accent (matching the focus indicator).\n chart: {\n series: [\n '#56B4E9', // sky\n '#E69F00', // orange\n '#00C08B', // green\n '#FF7F4D', // vermilion\n '#E48FC1', // purple\n '#0091D5', // blue\n '#F0E442', // yellow\n '#AAAAAA', // grey\n ],\n axis : 'rgb(176, 176, 176)',\n grid : 'rgb(58, 58, 58)',\n label : 'rgb(192, 192, 192)',\n selection: '#4a9eff',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Panel, PanelOptions } from \"~/core/Panel.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Form}.\n *\n * @category Core\n */\nexport interface FormOptions extends PanelOptions {\n /**\n * Called after a native form submission is requested — via the submit\n * button, Enter in a field, or `requestSubmit()`. The framework has already\n * called `preventDefault()` on the submit event, so the page will not\n * navigate; the handler owns what submission means.\n */\n onSubmit?: (form: Form) => void;\n}\n\n/**\n * A {@link Panel} that bakes the semantic `<form>` tag and wires the native\n * `submit` event to a single `onSubmit` callback.\n *\n * Use `Form` as the content surface for a group of fields that should submit\n * together — it inherits `Panel`'s 4-pixel insets and `autoScroll` stack, so a\n * tall form in a short area scrolls rather than inflating to content size.\n * Trigger a submission from an external control (e.g. a footer button outside\n * the form) via {@link Form.requestSubmit}, which reaches the browser's native\n * `HTMLFormElement.requestSubmit()` — firing the cancelable `submit` event and\n * running constraint validation — through the `DOM.sink` seam, mirroring how\n * {@link Component.focus} reaches the native `focus()`.\n *\n * @example\n * ```typescript\n * const form = new Form({\n * onSubmit: (f) => console.log('submitted'),\n * });\n * // ...\n * submitButton.on(\"action\", () => form.requestSubmit());\n * ```\n *\n * @category Core\n */\nclass Form<TOptions extends FormOptions = FormOptions> extends Panel<TOptions> {\n\n private _onSubmit: ((form: Form) => void) | null = null;\n\n /**\n * @param options - Optional. Construction-time options applied to the form.\n */\n constructor(options?: TOptions) {\n super(options, { tag: \"form\" } as Partial<TOptions>);\n\n // Wire after super() returns: Event.addListener needs the fully\n // constructed component, and this is the deferred-dispatch site the\n // super-cascade trap requires (never applyOptions).\n this._onSubmit = options?.onSubmit ?? null;\n Event.addListener(this, \"submit\", this.handleSubmit);\n }\n\n /**\n * Handles the native `submit` event: prevents the browser's default\n * navigation and forwards to the `onSubmit` callback, if any.\n *\n * @param e - The native submit event.\n */\n private handleSubmit(e: SubmitEvent): void {\n e.preventDefault();\n this._onSubmit?.(this);\n }\n\n /**\n * Requests a native form submission, firing the cancelable `submit` event\n * and running the browser's constraint validation (unlike `.submit()`,\n * which skips both). No-op if the form is not yet rendered.\n */\n requestSubmit(): void {\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n DOM.sink.requestSubmit(element);\n }\n}\n\nconst FormCallable = callable(Form);\ntype FormCallable<TOptions extends FormOptions = FormOptions> = Form<TOptions>;\nexport {\n Form as _Form,\n FormCallable as Form,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM, type Handle } from \"~/core/DOM.js\";\n\n/**\n * The library's built-in mark: the framework's `Border` layout drawn literally\n * as a north bar, a west sidebar and a centre pane on a rounded plate.\n *\n * Geometry, on a 32-unit viewBox so every dimension is a whole number and each\n * unit is half a pixel in a 16px browser tab: the plate is the full 32×32 with\n * a 6-unit corner radius, and clips the three regions so they inherit its\n * rounded corners. The north bar is `0,0 32×10` (full width, as `Border` docks\n * north); the west sidebar `0,12 10×20`; the centre pane `12,12 20×20`. The\n * 2-unit gaps between them are the field showing through — the regions carry\n * no stroke, so nothing in the mark is thinner than a solid 10-unit block.\n *\n * Colours are fixed rather than read from the active theme, and the SVG carries\n * its own `prefers-color-scheme` rule so the mark suits light *and* dark\n * browser chrome without any framework wiring. Light mode is plain black on\n * white — the highest-contrast pairing, which is what holds the 1px gaps\n * together once a browser downsamples the mark to tab size. The dark palette is\n * lifted from `DarkTheme`: `#505050` is its `button.border` and `#78AAF0` its\n * `input.focusRing`, the framework's accent hue.\n *\n * Declared with single quotes because the string is full of double quotes.\n *\n * @internal Exported for the encoding round-trip test only; not part of the\n * public API (the `core` barrel does not re-export it).\n */\nexport const MARK_SVG = '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><style>.pane{fill:#FFFFFF}.region{fill:#000000}@media(prefers-color-scheme:dark){.pane{fill:#505050}.region{fill:#78AAF0}}</style><clipPath id=\"plate\"><rect width=\"32\" height=\"32\" rx=\"6\"/></clipPath><g clip-path=\"url(#plate)\"><rect class=\"pane\" width=\"32\" height=\"32\"/><rect class=\"region\" width=\"32\" height=\"10\"/><rect class=\"region\" y=\"12\" width=\"10\" height=\"20\"/><rect class=\"region\" x=\"12\" y=\"12\" width=\"20\" height=\"20\"/></g></svg>';\n\n/**\n * The library's built-in mark as a ready-to-use `data:` URI — what\n * {@link Favicon.install} writes when no other icon is supplied.\n *\n * Encoded with `encodeURIComponent` rather than a hand-written escape list.\n * Getting that list wrong fails silently: an unescaped `#` would truncate the\n * URI at `url(#plate)`, dropping the clip path and rendering a blank tab icon\n * with no error anywhere.\n *\n * @category Core\n */\nexport const DEFAULT_FAVICON = `data:image/svg+xml,${encodeURIComponent(MARK_SVG)}`;\n\n/**\n * Matches `rel=\"icon\"` and `rel=\"shortcut icon\"` — `~=` is the\n * whitespace-separated word match, so a `rel` of `\"shortcut icon\"` contains the\n * word `icon` and matches. `apple-touch-icon` and `mask-icon` are single words\n * and deliberately do not: neither sets the browser-tab icon, so a page\n * carrying only one of them still has no tab icon worth preserving.\n */\nconst ICON_LINK_SELECTOR = 'link[rel~=\"icon\"]';\n\n/**\n * Installs the browser-tab icon by appending a `<link rel=\"icon\">` to `<head>`.\n *\n * Apps do not normally call this: `Body.init` installs {@link DEFAULT_FAVICON}\n * on mount, and the `favicon` option on that call is the ordinary way to supply\n * a different one or to suppress injection. Call it directly only when mounting\n * without `Body.init`.\n *\n * An icon the document already declares always wins — see {@link Favicon.install}.\n *\n * @category Core\n */\nexport class Favicon {\n\n /**\n * The link this class injected, or `null` when it has not injected one.\n * Held so a later install swaps the `href` instead of stacking a second\n * `<link>` — the browser would honour the last one, but the page would\n * accumulate a link per call.\n */\n private static _link: Handle | null = null;\n\n /**\n * Appends a `<link rel=\"icon\">` to `<head>`, unless the document already\n * declares an icon link of its own — an app's `<link rel=\"icon\">` written\n * in its `index.html` is never replaced. Module scripts run after the\n * document is parsed, so such a link is always visible by the time this\n * runs.\n *\n * Calling it again replaces the `href` on the link it previously injected\n * rather than appending a second one.\n *\n * @param href - The icon URL or `data:` URI. Defaults to the library's\n * built-in mark.\n *\n * @returns `true` when the icon was installed, `false` when the document's\n * own icon link was left in place.\n */\n static install(href: string = DEFAULT_FAVICON): boolean {\n if (Favicon._link !== null) {\n DOM.sink.apply(Favicon._link, { setAttr: { href } });\n\n return true;\n }\n\n const head = DOM.source.getHead();\n\n if (DOM.source.querySelector(head, ICON_LINK_SELECTOR) !== null) {\n return false;\n }\n\n const link = DOM.sink.createElement(\"link\");\n\n DOM.sink.apply(link, { setAttr: { rel: \"icon\", href } });\n DOM.sink.appendChild(head, link);\n\n Favicon._link = link;\n\n return true;\n }\n\n /**\n * Forgets the injected link, so the next {@link Favicon.install} appends a\n * fresh one instead of writing through the handle it is holding.\n *\n * @internal Test-only. A handle minted before `DOM.reset()` does not\n * resolve against the registry that replaces it, so a suite that resets the\n * DOM between cases must reset this too.\n */\n static _reset(): void {\n Favicon._link = null;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Favicon, DEFAULT_FAVICON } from \"~/core/Favicon.js\";\nimport { ThemeManager, ModernTheme } from \"~/core/Theme.js\";\n\n/**\n * Options for the singleton {@link Body}.\n *\n * @category Core\n */\nexport interface BodyOptions extends ComponentOptions {\n /**\n * Browser-tab icon. A URL or `data:` URI installs that icon; `false`\n * suppresses injection entirely. Omitted, the library's built-in mark is\n * used. In every case a `<link rel=\"icon\">` already present in the page's\n * HTML wins and nothing is injected.\n */\n favicon?: string | false;\n}\n\n/**\n * A {@link Component} that wraps the page's `<body>` element.\n *\n * Mount a top-level layout in one call:\n * ```\n * Body.init({ layoutManager: Fit(), components: [shell] });\n * ```\n *\n * Once mounted, reach the singleton again with `Body.getInstance()` — to add a\n * further child, read the layout manager, or attach a listener.\n *\n * @category Core\n */\nexport class Body extends Component<BodyOptions> {\n\n private static readonly INSTANCE: Body = new Body();\n\n /**\n * Returns the singleton Body instance — the accessor for reaching the body\n * *after* it is mounted: adding a further child, reading its layout\n * manager, or attaching a listener. To mount a top-level layout in one\n * call, use `Body.init` instead.\n *\n * @returns The single shared Body component for this page.\n */\n static getInstance() {\n return this.INSTANCE;\n }\n\n /**\n * Applies an options bag to the singleton Body and returns it — the\n * ergonomic entry point for mounting a top-level layout in one call:\n * `Body.init({ layoutManager: Fit(), components: [shell] })`. Only the\n * supplied fields are dispatched (it delegates to\n * `Component.applyOptions`), so the body's viewport-size tracking and\n * theme set up at construction are preserved.\n *\n * Also installs the browser-tab icon, unless the page already declares a\n * `<link rel=\"icon\">` of its own or `options.favicon` is `false`.\n *\n * @param options - Component options to apply (layout manager, children, …).\n *\n * @returns The singleton Body instance, for chaining.\n *\n * @remarks Re-binds the style and attribute buffers to the current body\n * element before dispatching `options` — see\n * `Component.reattachElementBuffers`. The singleton is constructed once\n * per page load, so this only matters when the underlying DOM has been\n * swapped since construction (a test harness); it is a no-op rebind\n * otherwise.\n */\n static init(options: BodyOptions = {}): Body {\n this.INSTANCE.reattachElementBuffers();\n this.INSTANCE.applyOptions(options);\n\n // The built-in default is dispatched here rather than from\n // applyOptions, which also runs during the singleton's construction at\n // module import — too early for a caller to have opted out, and before\n // a test harness has swapped the DOM seams.\n if (options.favicon === undefined) {\n this.INSTANCE.setFavicon(DEFAULT_FAVICON);\n }\n\n return this.INSTANCE;\n }\n\n /** @inheritDoc */\n protected applyOptions(options: BodyOptions): this {\n super.applyOptions(options);\n\n if (options.favicon !== undefined) this.setFavicon(options.favicon);\n\n return this;\n }\n\n /**\n * Installs the browser-tab icon, or suppresses it.\n *\n * A `<link rel=\"icon\">` the page's own HTML declares always wins, so this\n * writes nothing when one is present. `false` suppresses injection; it does\n * not remove an icon already installed.\n *\n * @param favicon - The icon URL or `data:` URI, or `false` for none.\n *\n * @returns This component, for method chaining.\n */\n setFavicon(favicon: string | false): this {\n this._options.favicon = favicon;\n\n if (favicon !== false) {\n Favicon.install(favicon);\n }\n\n return this;\n }\n\n /**\n * Returns the browser-tab icon this body was configured with.\n *\n * @returns The configured URL or `data:` URI, `false` when injection is\n * suppressed, or the library's built-in mark when nothing was configured.\n */\n getFavicon(): string | false {\n return this._options.favicon ?? DEFAULT_FAVICON;\n }\n\n private constructor() {\n super({ tag: \"body\" });\n\n this.init();\n\n this.setBackgroundColor(\"var(--ts-ui-body-bg, rgb(241, 241, 241))\");\n\n ThemeManager.setTheme(ModernTheme);\n }\n\n /**\n * Returns the document body element.\n *\n * @returns The `<body>` HTMLElement.\n */\n getElement() {\n return DOM.source.getBody();\n }\n\n /**\n * Initializes the body size from the viewport and registers a resize listener to keep it in sync.\n *\n * @returns This component, for method chaining.\n */\n protected init(): this {\n super.init();\n\n this.setSize(DOM.source.getViewportSize());\n this.clearInsets();\n\n Event.addViewportListener(this, \"resize\", this._onViewportResize);\n this.subscribeTheme(this._onThemeReflow);\n\n return this;\n }\n\n /**\n * Bound viewport-resize handler. Reads the current viewport extent on\n * each fire (DOM `resize` events carry no payload) and writes it\n * through the typed setter.\n */\n private _onViewportResize = (): void => {\n this.setSize(DOM.source.getViewportSize());\n };\n\n /**\n * Bound theme-change handler. Schedules a layout pass so every `Text` in\n * the page re-measures lazily against the new theme's metrics — replaces\n * the per-`Text` theme subscription this component's children used to\n * hold individually.\n */\n private _onThemeReflow = (): void => {\n this.scheduleLayout();\n };\n\n /**\n * Overrides {@link Component.clampsToContentSize} to `false`: the body *is*\n * the viewport, so its size must track {@link Util.getViewportSize} exactly\n * and let oversized content overflow (the page scrolls / a child `Panel`\n * scrolls internally) rather than inflating the body up to its\n * content-derived minimum. With the `Component` default (`true`),\n * {@link Component.setSize} ran the viewport extent through\n * {@link Component.clampHeight}, which floored it to `getMinSize()` — the\n * tall content's minimum — so once that minimum was measured the body could\n * never shrink back below its content when the viewport shrank.\n *\n * @returns `false`, so size clamping uses the body's own explicit\n * constraints only, not its content-derived ones.\n */\n protected clampsToContentSize(): boolean {\n return false;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\n\n/**\n * A physical-key chord. `code` is a `KeyboardEvent.code` value (layout-independent).\n *\n * @category Core\n */\nexport interface FocusHistoryKeyCombo {\n code: string;\n ctrl?: boolean;\n alt?: boolean;\n shift?: boolean;\n meta?: boolean;\n}\n\n/**\n * Options for {@link FocusHistory.enable} / {@link FocusHistory.configure}.\n *\n * @category Core\n */\nexport interface FocusHistoryOptions {\n /** Max entries retained; oldest dropped past this. Default 50. */\n maxSize?: number;\n /** Back accelerator. Default `Alt+[` (`{ code: \"BracketLeft\", alt: true }`). */\n back?: FocusHistoryKeyCombo;\n /** Forward accelerator. Default `Alt+]` (`{ code: \"BracketRight\", alt: true }`). */\n forward?: FocusHistoryKeyCombo;\n}\n\n/**\n * The sole custom event name fired by {@link FocusHistory}.\n *\n * @category Core\n */\nexport type FocusHistoryEvent = \"change\";\n\n/**\n * Payload of the `\"change\"` event: the navigability of the trail after the change.\n *\n * @category Core\n */\nexport interface FocusHistoryChange {\n canGoBack: boolean;\n canGoForward: boolean;\n}\n\n// 50: a working session's focus trail rarely exceeds a few dozen stops; caps\n// memory at 50 handle numbers while leaving generous back-depth.\nconst DEFAULT_MAX_ENTRIES: number = 50;\n// Alt+[ / Alt+]: editor-style \"navigate back/forward\"; no default browser\n// action (unlike Alt+Left/Right = browser history); layout-independent via code.\nconst DEFAULT_BACK_COMBO: FocusHistoryKeyCombo = { code: \"BracketLeft\", alt: true };\nconst DEFAULT_FORWARD_COMBO: FocusHistoryKeyCombo = { code: \"BracketRight\", alt: true };\n\n// Sentinel used to register the service's viewport listeners — see\n// LayerManager's identical `_listenerOwner` pattern. `FocusHistory` has no DOM\n// element of its own, so a stable, otherwise-unused `Component` owns them.\nconst _owner: Component = new Component();\nconst _listeners = new ListenerBag<FocusHistoryEvent>();\n\n// Chronological trail, oldest first. Entries are bare `Handle`s (not\n// `Component`s) because focus frequently lands on an element with no 1:1\n// component (an input inside a Text, a raw button).\nlet _entries: Handle[] = [];\n// Current position in `_entries`; -1 when the trail is empty.\nlet _index: number = -1;\nlet _enabled: boolean = false;\n// Re-entrancy guard: true for the duration of a service-driven `DOM.sink.focus`\n// call, so the synchronous `focusin` it triggers is not recorded as a new move.\nlet _navigating: boolean = false;\nlet _maxSize: number = DEFAULT_MAX_ENTRIES;\nlet _back: FocusHistoryKeyCombo = DEFAULT_BACK_COMBO;\nlet _forward: FocusHistoryKeyCombo = DEFAULT_FORWARD_COMBO;\n\n/**\n * Whether `handle` still resolves to a connected element. A GC-collected weak\n * handle throws on resolve inside the DOM seam; that is treated as stale too.\n */\nfunction isLive(handle: Handle): boolean {\n try {\n return DOM.source.isConnected(handle);\n } catch {\n return false;\n }\n}\n\n/**\n * Drops every stale (no-longer-connected) entry from the trail, keeping\n * `_index` pointed at the nearest surviving entry at or before its old\n * position (or -1 if nothing survived there). Run before every navigation\n * and every `canGo*` query so those never act on a dead entry.\n */\nfunction pruneStale(): void {\n const kept: Handle[] = [];\n let newIndex = -1;\n\n for (let i = 0; i < _entries.length; i++) {\n const handle = _entries[i];\n\n if (isLive(handle)) {\n kept.push(handle);\n\n if (i <= _index) {\n newIndex = kept.length - 1;\n }\n }\n }\n\n _entries = kept;\n _index = newIndex;\n}\n\n/** Computes the current navigability and notifies `\"change\"` listeners. */\nfunction fireChange(): void {\n const change: FocusHistoryChange = {\n canGoBack: _index > 0,\n canGoForward: _index < _entries.length - 1,\n };\n\n _listeners.fire(\"change\", change);\n}\n\n/**\n * Appends `handle` to the trail (deduping a repeat of the current entry and\n * truncating any forward branch), advances `_index`, and fires `\"change\"`.\n */\nfunction record(handle: Handle): void {\n if (_index >= 0 && _entries[_index] === handle) {\n return;\n }\n\n _entries.length = _index + 1;\n _entries.push(handle);\n\n while (_entries.length > _maxSize) {\n _entries.shift();\n }\n\n _index = _entries.length - 1;\n fireChange();\n}\n\n/** Re-focuses `handle` under the re-entrancy guard, then fires `\"change\"`. */\nfunction focusEntry(handle: Handle): void {\n _navigating = true;\n DOM.sink.focus(handle);\n _navigating = false;\n fireChange();\n}\n\n/**\n * Prunes stale entries, then moves `_index` by `direction` and re-focuses the\n * entry there, if one exists.\n *\n * @returns True if focus moved.\n */\nfunction navigate(direction: -1 | 1): boolean {\n pruneStale();\n\n const target = _index + direction;\n\n if (target < 0 || target >= _entries.length) {\n return false;\n }\n\n _index = target;\n focusEntry(_entries[_index]);\n\n return true;\n}\n\n/** Whether a `KeyboardEvent` matches a configured combo. */\nfunction matchesCombo(e: KeyboardEvent, combo: FocusHistoryKeyCombo): boolean {\n return e.code === combo.code &&\n e.altKey === !!combo.alt && e.ctrlKey === !!combo.ctrl &&\n e.shiftKey === !!combo.shift && e.metaKey === !!combo.meta;\n}\n\n/** Document `focusin` handler: records the newly-focused element. */\nfunction onFocusIn(e: FocusEvent): void {\n if (!_enabled || _navigating) {\n return;\n }\n\n if (!DOM.source.isElement(e.target)) {\n return;\n }\n\n record(DOM.source.intern(e.target));\n}\n\n/**\n * Document `keydown` handler: drives `back()`/`forward()` on the configured\n * combos, suppressed while a modal layer is on top so the accelerator does\n * not fight the modal's own focus trap.\n *\n * @returns `{ stop: true, prevent: true }` when the key matches a navigation combo\n * and no modal layer is suppressing it; nothing otherwise, so every other key\n * keeps propagating.\n */\nfunction onKeyDown(e: KeyboardEvent): Event.ListenerResult {\n if (!_enabled) {\n return;\n }\n\n const direction: -1 | 1 | 0 = matchesCombo(e, _back) ? -1 : matchesCombo(e, _forward) ? 1 : 0;\n\n if (direction === 0) {\n return;\n }\n\n const top = LayerManager.getTopLayer();\n\n if (top && top.getDismissMode() === \"modal\") {\n return;\n }\n\n navigate(direction);\n\n return { stop: true, prevent: true };\n}\n\n/**\n * Global focus-trail navigation service: records the chronological order in\n * which elements receive keyboard focus across the document and drives an\n * accelerator that walks the trail backward and forward, like browser\n * back/forward but for keyboard focus. Opt-in — call {@link enable} to start\n * recording; nothing auto-starts it.\n *\n * @category Core\n */\nexport namespace FocusHistory {\n /**\n * Installs the `focusin` + `keydown` listeners, seeds the trail with the\n * current active element (if any), and begins recording. Idempotent —\n * calling it again while already enabled only applies `options`.\n *\n * @param options - Optional `maxSize` / combo overrides, applied via\n * {@link configure} before enabling.\n */\n export function enable(options?: FocusHistoryOptions): void {\n if (options) {\n configure(options);\n }\n\n if (_enabled) {\n return;\n }\n\n _enabled = true;\n\n Event.addViewportListener(_owner, \"focusin\", onFocusIn);\n Event.addViewportListener(_owner, \"keydown\", onKeyDown);\n\n const active = DOM.source.getActiveElement();\n\n if (active !== null) {\n record(active);\n }\n }\n\n /**\n * Removes the listeners and stops recording. Preserves the trail —\n * re-enabling resumes from where it left off. Idempotent.\n */\n export function disable(): void {\n if (!_enabled) {\n return;\n }\n\n _enabled = false;\n _navigating = false;\n\n Event.removeViewportListener(_owner, \"focusin\", onFocusIn);\n Event.removeViewportListener(_owner, \"keydown\", onKeyDown);\n }\n\n /** Whether the service is currently observing. */\n export function isEnabled(): boolean {\n return _enabled;\n }\n\n /**\n * Updates `maxSize` / combos without toggling enablement. Only the\n * supplied fields change.\n *\n * @param options - The fields to update.\n */\n export function configure(options: FocusHistoryOptions): void {\n if (options.maxSize !== undefined) {\n _maxSize = options.maxSize;\n }\n\n if (options.back !== undefined) {\n _back = options.back;\n }\n\n if (options.forward !== undefined) {\n _forward = options.forward;\n }\n }\n\n /**\n * Re-focuses the previous live entry, skipping and dropping any stale\n * ones encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function back(): boolean {\n return navigate(-1);\n }\n\n /**\n * Re-focuses the next live entry, skipping and dropping any stale ones\n * encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function forward(): boolean {\n return navigate(1);\n }\n\n /**\n * Whether a live entry exists before the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoBack(): boolean {\n pruneStale();\n\n return _index > 0;\n }\n\n /**\n * Whether a live entry exists after the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoForward(): boolean {\n pruneStale();\n\n return _index < _entries.length - 1;\n }\n\n /** Empties the trail and fires `\"change\"` with both flags false. */\n export function clear(): void {\n _entries = [];\n _index = -1;\n fireChange();\n }\n\n /**\n * Subscribes to trail-navigability changes, fired after every recorded\n * focus move and after every `back()` / `forward()` navigation.\n *\n * @param event - Always `\"change\"`.\n * @param listener - Invoked with the trail's navigability after the change.\n */\n export function on(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.add(event, listener);\n }\n\n /**\n * Unsubscribes a `\"change\"` listener.\n *\n * @param event - Always `\"change\"`.\n * @param listener - The exact callback reference passed to {@link on}.\n */\n export function off(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.remove(event, listener);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from '~/core/BaseObject.js';\nimport { ModelRecord } from '~/data/ModelRecord.js';\nimport { Bindable, BindingAccessors } from '~/core/Bindable.js';\nimport { Component } from '~/core/Component.js';\nimport { ListenerBag } from '~/core/ListenerBag.js';\nimport { ValidationRule, FieldValidationConfig } from '~/validation/ValidationRule.js';\nimport { FieldDecorator } from '~/validation/FieldDecorator.js';\nimport { applyRule } from '~/validation/Validator.js';\n\n/**\n * String-literal union of events emitted by {@link Binding}.\n *\n * @category Data\n */\nexport type BindingEvent = \"change\" | \"commit\" | \"reject\" | \"beforerecord\";\n\ninterface BoundEntry {\n accessors: BindingAccessors<any>;\n active: boolean;\n}\n\n/**\n * Listener consulted before a record change takes effect.\n *\n * Receives the *next* record (or `null`) and returns `false` to cancel the\n * change. Any other return value (`true`, `undefined`, …) allows it.\n *\n * @category Data\n */\nexport type BeforeRecordListener = (next: ModelRecord | null) => boolean;\n\n/**\n * Synchronises a {@link ModelRecord} with a set of UI components.\n *\n * Components are registered with {@link bind}, either as {@link Bindable} implementors\n * (short form) or via explicit accessor callbacks (long form). Once a record is loaded\n * via {@link setRecord}, every bound component is populated from the record's fields.\n * Conversely, whenever a component's value changes, the record is updated automatically.\n *\n * @example Short form — component implements Bindable\n * ```typescript\n * const binding = new Binding()\n * .bind('name', nameField)\n * .bind('active', activeCheckbox)\n * .bind('role', roleCombo);\n *\n * binding.setRecord(record);\n * ```\n *\n * @example Long form — explicit accessors for any component\n * ```typescript\n * const binding = new Binding()\n * .bind('name', myWidget, {\n * get: () => myWidget.getValue(),\n * set: (v) => myWidget.setValue(v),\n * listen: (fn) => myWidget.on(\"change\", fn),\n * });\n * ```\n *\n * @category Data\n */\nexport class Binding extends BaseObject {\n\n private _record: ModelRecord | null = null;\n private _entries: Map<string, BoundEntry> = new Map();\n private _listeners: ListenerBag<BindingEvent> = new ListenerBag<BindingEvent>();\n private _validationConfigs: Map<string, FieldValidationConfig> = new Map();\n private _globalValidateOnChange: boolean = false;\n private _loading: boolean = false;\n\n // ── Registration ────────────────────────────────────────────────────────\n\n /**\n * Registers a field binding using a component that implements {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - A component implementing the {@link Bindable} interface.\n */\n bind<T>(fieldName: string, component: Bindable<T>): this;\n\n /**\n * Registers a field binding using explicit accessor callbacks.\n * Use this overload for components that do not implement {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - Any object (used only as a placeholder for the overload).\n * @param accessors - Getter, setter, and change-listener callbacks.\n */\n bind<T>(fieldName: string, component: object, accessors: BindingAccessors<T>): this;\n\n bind<T>(fieldName: string, component: Bindable<T> | object, accessors?: BindingAccessors<T>): this {\n this.unbind(fieldName);\n\n const acc: BindingAccessors<any> = accessors ?? {\n get: () => (component as Bindable<T>).getValue(),\n set: (v: T) => (component as Bindable<T>).setValue(v),\n listen: (fn) => (component as Bindable<T>).on(\"binding\", fn),\n };\n\n const entry: BoundEntry = { accessors: acc, active: true };\n this._entries.set(fieldName, entry);\n\n acc.listen(() => {\n if (this._loading) {\n return;\n }\n\n if (!entry.active || !this._record) {\n return;\n }\n\n const value = acc.get();\n this._record.set(fieldName, value);\n\n this.emit(\"change\", fieldName, value);\n\n this._validateFieldIfLive(fieldName);\n });\n\n if (this._record) {\n acc.set(this._record.get(fieldName));\n }\n\n return this;\n }\n\n /**\n * Removes the binding for the given field.\n * The change listener previously attached to the component becomes a no-op.\n *\n * @param fieldName - The field whose binding should be removed.\n */\n unbind(fieldName: string): this {\n const entry = this._entries.get(fieldName);\n if (entry) {\n entry.active = false;\n\n this._entries.delete(fieldName);\n }\n\n return this;\n }\n\n // ── Record management ────────────────────────────────────────────────────\n\n /**\n * Loads a record into the binding. All registered components are immediately\n * populated with the corresponding field values. Pass `null` to clear the binding.\n *\n * Before any state mutation, every `on(\"beforerecord\", fn)` listener is\n * consulted; if any returns `false` the\n * call is a complete no-op (no validation reset, no field population) and\n * `this` is returned unchanged.\n *\n * @param record - The record to bind, or `null` to detach.\n */\n setRecord(record: ModelRecord | null): this {\n for (const fn of this._listeners.get(\"beforerecord\") as BeforeRecordListener[]) {\n if (fn(record) === false) {\n return this;\n }\n }\n\n this._record = record;\n\n this.clearValidation();\n\n if (!record) {\n return this;\n }\n\n this._loading = true;\n\n try {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(record.get(fieldName));\n }\n } finally {\n this._loading = false;\n }\n\n for (const [fieldName] of this._validationConfigs) {\n this._validateFieldIfLive(fieldName);\n }\n\n return this;\n }\n\n /**\n * Returns the currently bound record, or `null` if none is loaded.\n */\n getRecord(): ModelRecord | null {\n return this._record;\n }\n\n // ── Commit / reject ──────────────────────────────────────────────────────\n\n /**\n * Commits the current record, clearing its dirty and new flags.\n * Fires all registered commit listeners.\n */\n commit(): this {\n this._record?.commit();\n\n this.emit(\"commit\");\n\n return this;\n }\n\n /**\n * Rejects all changes on the current record and re-syncs every component\n * from the reverted field values. Fires all registered reject listeners.\n * Also clears any active validation error decorations.\n */\n reject(): void {\n this._record?.reject();\n\n if (this._record) {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(this._record.get(fieldName));\n }\n }\n\n this.clearValidation();\n\n this.emit(\"reject\");\n }\n\n // ── Listeners ────────────────────────────────────────────────────────────\n\n /**\n * Registers a listener for one of this binding's events.\n *\n * @param event - `\"change\"` fires whenever any bound component changes a\n * field value, receiving `(fieldName, value)`. `\"commit\"` fires after\n * {@link commit}. `\"reject\"` fires after {@link reject}.\n * `\"beforerecord\"` is consulted before {@link setRecord} mutates state;\n * returning `false` vetoes the call as a complete no-op.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This binding, for method chaining.\n *\n * @remarks `\"beforerecord\"` veto semantics: iteration stops on the first\n * `false`; if any listener vetoes, {@link setRecord} returns without\n * modifying any state. Returning `true` — or anything other than\n * `false`, including `undefined` — allows the change. Async\n * confirmation must be handled at the call site — {@link setRecord}\n * stays synchronous. A listener that itself calls {@link setRecord}\n * re-enters the same veto loop, which is supported but discouraged.\n * `null` is a valid `next` value (it represents a clear); a listener\n * that only wants to guard non-clear switches must short-circuit\n * `next === null` itself.\n */\n on(event: \"change\", listener: (fieldName: string, value: unknown) => void): this;\n on(event: \"commit\", listener: () => void): this;\n on(event: \"reject\", listener: () => void): this;\n on(event: \"beforerecord\", listener: BeforeRecordListener): this;\n on(event: BindingEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This binding, for method chaining.\n */\n off(event: BindingEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order. Internal use only — external callers route\n * dispatch through {@link commit} / {@link reject} / {@link setRecord}.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"change\", fieldName: string, value: unknown): void;\n protected emit(event: \"commit\"): void;\n protected emit(event: \"reject\"): void;\n protected emit(event: BindingEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n // ── Validation ───────────────────────────────────────────────────────────\n\n /**\n * Attaches one or more validation rules to a bound field.\n *\n * @param fieldName - The field name registered with {@link bind}.\n * @param component - The Component instance to wrap with a {@link FieldDecorator} on error.\n * @param rules - One or more {@link ValidationRule} objects to apply to this field.\n *\n * @returns this, for chaining.\n */\n addValidation(fieldName: string, component: Component, rules: ValidationRule | ValidationRule[]): this {\n const ruleArray = Array.isArray(rules) ? rules : [rules];\n\n this._validationConfigs.set(fieldName, {\n rules : ruleArray,\n component,\n validateOnChange: false,\n decorator : null,\n });\n\n return this;\n }\n\n /**\n * Removes all validation rules for a field and clears any existing error decoration.\n *\n * @param fieldName - The field whose validation should be removed.\n *\n * @returns this, for chaining.\n */\n removeValidation(fieldName: string): this {\n const config = this._validationConfigs.get(fieldName);\n\n if (config?.decorator) {\n config.decorator.clearError();\n }\n\n this._validationConfigs.delete(fieldName);\n\n return this;\n }\n\n /**\n * Runs all registered validation rules against the current field values.\n * Applies or clears {@link FieldDecorator} error state for each validated field.\n *\n * @returns true if all fields pass; false if any field fails.\n */\n validate(): boolean {\n let allValid = true;\n\n for (const [fieldName] of this._validationConfigs) {\n const valid = this._validateField(fieldName);\n\n if (!valid) {\n allValid = false;\n }\n }\n\n return allValid;\n }\n\n /**\n * Enables or disables live validation (validation on every field change).\n *\n * @param enabled - true to validate on every change event; false for explicit-only.\n */\n setValidateOnChange(enabled: boolean): this {\n this._globalValidateOnChange = enabled;\n\n return this;\n }\n\n /**\n * Returns whether live validation is globally enabled.\n *\n * @returns true if live validation is active.\n */\n getValidateOnChange(): boolean {\n return this._globalValidateOnChange;\n }\n\n /**\n * Clears all error decorations without re-running rules.\n * Called automatically by {@link reject}.\n */\n clearValidation(): this {\n for (const [, config] of this._validationConfigs) {\n if (config.decorator) {\n config.decorator.clearError();\n }\n }\n\n return this;\n }\n\n /**\n * Validates a single field and updates its decorator.\n *\n * @param fieldName - The field to validate.\n *\n * @returns true if the field passes all rules.\n */\n private _validateField(fieldName: string): boolean {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return true;\n }\n\n const entry = this._entries.get(fieldName);\n const value = entry ? entry.accessors.get() : undefined;\n\n for (const rule of config.rules) {\n const result = applyRule(rule, value);\n\n if (result.valid) {\n continue;\n }\n\n if (!config.decorator) {\n const parent = config.component.getParentComponent();\n\n if (parent) {\n config.decorator = new FieldDecorator(config.component, parent);\n }\n }\n\n config.decorator?.showError(result.message);\n\n return false;\n }\n\n config.decorator?.clearError();\n\n return true;\n }\n\n /**\n * Calls {@link _validateField} only if live validation is active for this field.\n *\n * @param fieldName - The field to conditionally validate.\n */\n private _validateFieldIfLive(fieldName: string): void {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return;\n }\n\n const live = config.validateOnChange || this._globalValidateOnChange;\n\n if (live) {\n this._validateField(fieldName);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"core.es.js","names":[],"sources":["../../src/typescript/lib/core/themes/ClassicTheme.ts","../../src/typescript/lib/core/themes/DarkTheme.ts","../../src/typescript/lib/core/Form.ts","../../src/typescript/lib/core/Favicon.ts","../../src/typescript/lib/core/Body.ts","../../src/typescript/lib/core/FocusHistory.ts","../../src/typescript/lib/core/Binding.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Classic light theme using white backgrounds, black text, and gradient\n * buttons. The original default look, retained as an opt-in alternative now\n * that {@link ModernTheme} is the preselected theme.\n *\n * Authored as `defineTheme(BaseTheme, …)`: it declares only its palette (and\n * `colorScheme`); every structural token is inherited from {@link BaseTheme}.\n * Classic carries no structural override — its `tab.underBorderFullWidth`\n * already matches the base value.\n *\n * @category Theme\n */\nexport const ClassicTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'light',\n text : { color: 'rgb(0, 0, 0)' },\n body : { background: 'rgb(255, 255, 255)' },\n border : { color: 'black' },\n button : {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : 'rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n description: {\n foreground: 'rgb(110, 110, 110)',\n },\n pressed : {\n foreground: 'rgb(150, 150, 150)',\n background: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.30)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.25)',\n },\n flat : {\n hover : {\n background: 'rgba(0, 0, 0, 0.06)',\n border : '1px solid rgb(200, 200, 200)',\n },\n pressed: {\n background: 'rgba(0, 0, 0, 0.10)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.25)',\n border : '1px solid rgb(180, 180, 180)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(200, 200, 200)',\n shadow : '2px 2px 1px inset grey',\n },\n },\n input : {\n background : 'rgb(255, 255, 255)',\n border : '1px solid rgb(160, 160, 160)',\n borderHover: '1px solid rgb(120, 120, 120)',\n },\n form : {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(160, 160, 160)',\n color : 'rgb(40, 40, 40)',\n disabledBackground: 'rgb(240, 240, 240)',\n disabledColor : 'rgb(170, 170, 170)',\n focusRing : 'rgb(30, 100, 200)',\n toggle : {\n trackOffBackground: 'rgb(200, 200, 200)',\n trackOnBackground : 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n slider : {\n trackBackground : 'rgb(220, 220, 220)',\n trackActiveBackground: 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n checkbox: {\n background : 'rgb(255, 255, 255)',\n selectedBackground : 'rgb(30, 100, 200)',\n indeterminateBackground: 'rgb(160, 160, 160)',\n checkColor : 'rgb(255, 255, 255)',\n },\n radio : {\n background : 'rgb(255, 255, 255)',\n selectedBackground: 'rgb(30, 100, 200)',\n dotColor : 'rgb(255, 255, 255)',\n },\n },\n gutter: { background: '#AAAAAA' },\n collapse: {\n strip: { background: '#AAAAAA', size: '18px' },\n button: { color: 'rgb(100,100,100)' },\n },\n accordion: {\n border : '1px solid rgb(190,190,190)',\n header : {\n background: 'linear-gradient(rgb(230,230,230),rgb(210,210,210))',\n border : '1px solid rgb(190,190,190)',\n color : 'inherit',\n },\n panel : { border: 'rgb(210,210,210)' },\n indicator: { color: 'rgb(100,100,100)' },\n },\n tab : {\n toolbar: { background: '#eee', border: '#e1e1e8' },\n button : {\n background: 'linear-gradient(rgb(208, 208, 216), rgb(185, 185, 196))',\n border : 'none',\n hover : { background: 'linear-gradient(rgb(220, 220, 227), rgb(198, 198, 208))', border: 'none' },\n selected : { background: 'linear-gradient(rgb(255, 255, 255), rgb(235, 235, 240))', border: 'none' },\n },\n indicator: { color: '#1a73e8' },\n },\n window: {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.4)',\n snapGlow : '0 0 0 2px rgba(30, 100, 200, 0.7)',\n control : {\n background : 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : '1px solid rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n hoverBackground : 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n activeBackground: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n },\n header : { background: '#eee' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border: 'black',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.15)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.6)',\n new : 'rgba(70, 200, 70, 0.15)',\n dirty : 'rgba(255, 165, 0, 0.15)',\n stripe : 'rgba(0, 0, 0, 0.035)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(0, 0, 0, 0.04)',\n requiredEmptyOutlineColor : 'rgba(220, 60, 60, 0.6)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.6)',\n },\n filterRow: {\n background: 'rgba(255, 200, 0, 0.2)',\n },\n resizeHandle: {\n color : 'rgba(0, 0, 0, 0.2)',\n },\n sortBadge: {\n background: 'rgba(0, 0, 0, 0.15)',\n color : 'inherit',\n },\n // Solid (not translucent) and independent of `color: inherit` — this\n // badge sits on the operator button's own glyph (`fill: currentColor`),\n // so inheriting `color` risks the digit rendering the same shade as\n // the glyph beneath/around it. The theme's own blue accent (matching\n // the focus ring — see the chart palette comment below) on white\n // gives a guaranteed ~5.7:1 contrast ratio, independent of whatever\n // sits behind it.\n filterClauseBadge: {\n background: 'rgb(30, 100, 200)',\n color : 'rgb(255, 255, 255)',\n },\n },\n contextMenu: {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(30, 100, 200, 0.10)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n },\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n statusBar: {\n background: 'rgb(245, 245, 245)',\n color : 'rgb(60, 60, 60)',\n border : 'rgb(220, 220, 220)',\n },\n toolBar: {\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n separatorColor: 'rgb(220, 220, 220)',\n },\n tooltip: {\n background: 'rgb(255, 255, 240)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(180, 180, 100)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.2)',\n },\n popover: {\n background: 'rgb(255, 255, 255)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.18)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n info : { background: 'rgba(210, 224, 244, 0.75)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(210, 240, 220, 0.75)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(248, 232, 204, 0.75)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(244, 214, 214, 0.75)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(200, 50, 50)',\n tooltip: {\n background: 'rgb(180, 30, 30)',\n color : 'rgb(255, 255, 255)',\n border : 'rgb(140, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0,0,0,0.15)',\n item: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n highlightBackground: 'rgba(30, 100, 200, 0.18)',\n highlightColor : 'inherit',\n disabledColor : 'rgb(170, 170, 170)',\n },\n },\n // Defaults mirror `autoComplete` numerically because both surfaces present\n // selectable rows; a theme that customises one gets the other matching\n // automatically. `row.separator` defaults to `transparent` so the visual\n // matches the prior native `<select>` (no row hairlines); themes can opt\n // in to a denser look by overriding to a `1px solid rgba(...)` colour.\n list: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n row: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.18)',\n selectedColor : 'inherit',\n focusRing : 'rgb(30, 100, 200)',\n disabledColor : 'rgb(170, 170, 170)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(30, 100, 200)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Picker tokens stay numerically in step with `autoComplete.item.*` — they\n // share the {@link PickerCell} class — so a theme that customises one\n // gets the other matching automatically.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(30, 100, 200, 0.08)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.45)' },\n border : 'rgb(220, 220, 220)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.35)',\n confirm : 'rgb(30, 180, 80)',\n cancel : 'rgb(200, 50, 50)',\n info : { background: 'rgba(30, 100, 200, 0.15)', foreground: 'rgb(30, 100, 200)' },\n affirm : { background: 'rgba(30, 180, 80, 0.15)', foreground: 'rgb(30, 180, 80)' },\n },\n drawer: {\n shadow : '4px 0 24px rgba(0, 0, 0, 0.25)',\n border : 'rgb(220, 220, 220)',\n },\n rail: {\n border : 'rgb(200, 200, 200)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.18)',\n handle: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.16)',\n },\n },\n spinner: {\n dividerColor: 'rgb(180, 180, 180)',\n },\n progressBar: {\n track : { background: 'rgb(220, 220, 220)' },\n fill : { background: 'rgb(30, 100, 200)' },\n indeterminate: { background: 'rgb(30, 100, 200)' },\n },\n progressSpinner: {\n color : 'rgb(30, 100, 200)',\n backdrop: 'rgba(255, 255, 255, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(200, 200, 200, 0.9)',\n border : 'rgb(150, 150, 150)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.25)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.12)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.10)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(30, 100, 200)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : 'rgba(80, 140, 240, 0.40)',\n activeBackground : 'rgba(80, 140, 240, 0.28)',\n invalidBackground: 'rgba(200, 50, 50, 0.28)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.06)',\n border : '2px dashed rgba(80, 140, 240, 0.40)',\n activeBackground: 'rgba(80, 140, 240, 0.18)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.80)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito colour-blind-safe categorical palette, tuned for a light\n // background (Classic is a light scheme). Neutral grey axis/grid/label; the\n // selection ring reuses the theme's blue accent.\n chart: {\n series: [\n '#0072B2', // blue\n '#E69F00', // orange\n '#009E73', // green\n '#D55E00', // vermilion\n '#CC79A7', // purple\n '#56B4E9', // sky\n '#8C6D1F', // gold\n '#555555', // grey\n ],\n axis : 'rgb(120, 120, 120)',\n grid : 'rgb(220, 220, 220)',\n label : 'rgb(80, 80, 80)',\n selection: '#1a73e8',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Dark-mode theme using dark backgrounds and light text.\n *\n * Authored as `defineTheme(BaseTheme, …)`: beyond its palette and\n * `colorScheme: 'dark'`, its only structural divergence is\n * `tab.underBorderFullWidth: false` (the base value is `true`). Every other\n * structural token is inherited from {@link BaseTheme}.\n *\n * @category Theme\n */\nexport const DarkTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'dark',\n text : { color: 'rgb(220, 220, 220)' },\n body : { background: 'rgb(30, 30, 30)' },\n border : { color: 'rgb(90, 90, 90)' },\n button : {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border : 'rgb(80, 80, 80)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.5)',\n description: {\n foreground: 'rgb(160, 160, 160)',\n },\n pressed : {\n foreground: 'rgb(180, 180, 180)',\n background: 'linear-gradient(rgb(35, 35, 35), rgb(48, 48, 48))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.6)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(90, 90, 90), rgb(65, 65, 65))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.55)',\n },\n flat : {\n hover : {\n background: 'rgba(255, 255, 255, 0.08)',\n border : '1px solid rgb(90, 90, 90)',\n },\n pressed: {\n background: 'rgba(255, 255, 255, 0.12)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.55)',\n border : '1px solid rgb(70, 70, 70)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(35, 35, 35)',\n shadow : '2px 2px 1px inset #333',\n },\n },\n input : {\n background : 'rgb(40, 40, 40)',\n border : '1px solid rgb(110, 110, 110)',\n borderHover: '1px solid rgb(150, 150, 150)',\n },\n form : {\n background : 'rgb(40, 40, 40)',\n border : 'rgb(110, 110, 110)',\n color : 'rgb(230, 230, 230)',\n disabledBackground: 'rgb(60, 60, 60)',\n disabledColor : 'rgb(120, 120, 120)',\n focusRing : 'rgb(120, 170, 240)',\n toggle : {\n trackOffBackground: 'rgb(70, 70, 70)',\n trackOnBackground : 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n slider : {\n trackBackground : 'rgb(70, 70, 70)',\n trackActiveBackground: 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n checkbox: {\n background : 'rgb(40, 40, 40)',\n selectedBackground : 'rgb(120, 170, 240)',\n indeterminateBackground: 'rgb(100, 100, 100)',\n checkColor : 'rgb(20, 20, 20)',\n },\n radio : {\n background : 'rgb(40, 40, 40)',\n selectedBackground: 'rgb(120, 170, 240)',\n dotColor : 'rgb(20, 20, 20)',\n },\n },\n gutter: { background: '#555' },\n collapse: {\n strip: { background: '#555', size: '18px' },\n button: { color: 'rgb(160,160,160)' },\n },\n accordion: {\n border : '1px solid rgb(80,80,80)',\n header : {\n background: 'linear-gradient(rgb(60,60,60),rgb(45,45,45))',\n border : '1px solid rgb(80,80,80)',\n color : 'inherit',\n },\n panel : { border: 'rgb(70,70,70)' },\n indicator: { color: 'rgb(160,160,160)' },\n },\n tab : {\n underBorderFullWidth: false,\n toolbar: { background: '#2a2a2a', border: '#444' },\n button : {\n background: '#3a3a3a',\n border : 'none',\n hover : { background: '#454545', border: 'none' },\n selected : { background: 'rgb(30, 30, 30)', border: 'none' },\n },\n indicator: { color: '#4a9eff' },\n },\n window : {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.6)',\n snapGlow : '0 0 0 2px rgba(80, 150, 240, 0.8)',\n control : {\n background : 'rgb(30, 30, 30)',\n border : '1px solid transparent',\n shadow : 'none',\n hoverBackground : 'rgb(55, 55, 55)',\n activeBackground: 'rgb(45, 45, 45)',\n },\n header : { background: '#2a2a2a' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border: '#555',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.25)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.8)',\n new : 'rgba(70, 200, 70, 0.2)',\n dirty : 'rgba(255, 165, 0, 0.2)',\n stripe : 'rgba(255, 255, 255, 0.045)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(255, 255, 255, 0.04)',\n requiredEmptyOutlineColor : 'rgba(255, 90, 90, 0.8)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.8)',\n },\n filterRow: {\n background: 'rgba(255, 200, 0, 0.28)',\n },\n resizeHandle: {\n color : 'rgba(255, 255, 255, 0.25)',\n },\n sortBadge: {\n background: 'rgba(255, 255, 255, 0.2)',\n color : 'inherit',\n },\n // Solid (not translucent) and independent of `color: inherit` — this\n // badge sits on the operator button's own glyph (`fill: currentColor`),\n // so inheriting `color` risks the digit rendering the same shade as\n // the glyph beneath/around it. The theme's own (brightened) blue\n // accent (matching the focus ring — see the chart palette comment\n // below) needs a dark, not white, digit for real contrast: white on\n // this lighter blue is only ~2.4:1, while the body's own dark\n // background tone on it is ~7:1.\n filterClauseBadge: {\n background: 'rgb(120, 170, 240)',\n color : 'rgb(30, 30, 30)',\n },\n },\n contextMenu: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(100, 140, 220, 0.15)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n },\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n statusBar: {\n background: 'rgb(45, 45, 45)',\n color : 'rgb(200, 200, 200)',\n border : 'rgb(70, 70, 70)',\n },\n toolBar: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n separatorColor: 'rgb(70, 70, 70)',\n },\n tooltip: {\n background: 'rgb(60, 60, 45)',\n color : 'rgb(220, 220, 180)',\n border : 'rgb(120, 110, 70)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.5)',\n },\n popover: {\n background: 'rgb(50, 50, 55)',\n color : 'rgb(230, 230, 235)',\n border : 'rgb(90, 90, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.55)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.4)',\n info : { background: 'rgba(30, 100, 200, 0.4)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(30, 180, 80, 0.4)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(220, 140, 0, 0.4)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(200, 50, 50, 0.4)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(220, 80, 80)',\n tooltip: {\n background: 'rgb(160, 30, 30)',\n color : 'rgb(255, 220, 220)',\n border : 'rgb(120, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0,0,0,0.5)',\n item: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n highlightBackground: 'rgba(100, 140, 220, 0.28)',\n highlightColor : 'rgb(220, 220, 255)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n },\n // Dark defaults track `autoComplete` for the same hover/selected hues so\n // the row chrome stays consistent across the two popover surfaces.\n list: {\n background: 'rgb(40, 40, 40)',\n border : 'rgb(80, 80, 80)',\n row: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n selectedBackground: 'rgba(100, 140, 220, 0.28)',\n selectedColor : 'rgb(220, 220, 255)',\n focusRing : 'rgb(120, 170, 240)',\n disabledColor : 'rgb(100, 100, 100)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(120, 170, 240)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Dark picker tokens follow the dark `autoComplete.item.*` hue family for\n // chevron-hover consistency with cell hover.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(120, 170, 255, 0.12)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.65)' },\n border : 'rgb(70, 70, 70)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.6)',\n confirm : 'rgb(80, 200, 110)',\n cancel : 'rgb(220, 90, 90)',\n info : { background: 'rgba(30, 100, 200, 0.25)', foreground: 'rgb(60, 130, 220)' },\n affirm : { background: 'rgba(80, 200, 110, 0.25)', foreground: 'rgb(80, 200, 110)' },\n },\n drawer: {\n shadow : '4px 0 24px rgba(0, 0, 0, 0.55)',\n border : 'rgb(70, 70, 70)',\n },\n rail: {\n border : 'rgb(70, 70, 70)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.45)',\n handle: {\n hoverBackground : 'rgba(120, 170, 240, 0.12)',\n selectedBackground: 'rgba(120, 170, 240, 0.22)',\n },\n },\n spinner: {\n dividerColor: 'rgb(80, 80, 80)',\n },\n progressBar: {\n track : { background: 'rgb(55, 55, 55)' },\n fill : { background: 'rgb(60, 130, 220)' },\n indeterminate: { background: 'rgb(60, 130, 220)' },\n },\n progressSpinner: {\n color : 'rgb(60, 130, 220)',\n backdrop: 'rgba(20, 20, 20, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(60, 60, 60, 0.9)',\n border : 'rgb(100, 100, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.6)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.2)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.18)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(80, 140, 240)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.12)',\n border : 'rgba(80, 140, 240, 0.45)',\n activeBackground : 'rgba(80, 140, 240, 0.32)',\n invalidBackground: 'rgba(200, 50, 50, 0.32)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : '2px dashed rgba(80, 140, 240, 0.45)',\n activeBackground: 'rgba(80, 140, 240, 0.24)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.85)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito-derived categorical palette, brightened for adequate contrast on\n // a dark background. Light-grey axis/label with a dim grid; the selection\n // ring reuses the theme's blue accent (matching the focus indicator).\n chart: {\n series: [\n '#56B4E9', // sky\n '#E69F00', // orange\n '#00C08B', // green\n '#FF7F4D', // vermilion\n '#E48FC1', // purple\n '#0091D5', // blue\n '#F0E442', // yellow\n '#AAAAAA', // grey\n ],\n axis : 'rgb(176, 176, 176)',\n grid : 'rgb(58, 58, 58)',\n label : 'rgb(192, 192, 192)',\n selection: '#4a9eff',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Panel, PanelOptions } from \"~/core/Panel.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Form}.\n *\n * @category Core\n */\nexport interface FormOptions extends PanelOptions {\n /**\n * Called after a native form submission is requested — via the submit\n * button, Enter in a field, or `requestSubmit()`. The framework has already\n * called `preventDefault()` on the submit event, so the page will not\n * navigate; the handler owns what submission means.\n */\n onSubmit?: (form: Form) => void;\n}\n\n/**\n * A {@link Panel} that bakes the semantic `<form>` tag and wires the native\n * `submit` event to a single `onSubmit` callback.\n *\n * Use `Form` as the content surface for a group of fields that should submit\n * together — it inherits `Panel`'s 4-pixel insets and `autoScroll` stack, so a\n * tall form in a short area scrolls rather than inflating to content size.\n * Trigger a submission from an external control (e.g. a footer button outside\n * the form) via {@link Form.requestSubmit}, which reaches the browser's native\n * `HTMLFormElement.requestSubmit()` — firing the cancelable `submit` event and\n * running constraint validation — through the `DOM.sink` seam, mirroring how\n * {@link Component.focus} reaches the native `focus()`.\n *\n * @example\n * ```typescript\n * const form = new Form({\n * onSubmit: (f) => console.log('submitted'),\n * });\n * // ...\n * submitButton.on(\"action\", () => form.requestSubmit());\n * ```\n *\n * @category Core\n */\nclass Form<TOptions extends FormOptions = FormOptions> extends Panel<TOptions> {\n\n private _onSubmit: ((form: Form) => void) | null = null;\n\n /**\n * @param options - Optional. Construction-time options applied to the form.\n */\n constructor(options?: TOptions) {\n super(options, { tag: \"form\" } as Partial<TOptions>);\n\n // Wire after super() returns: Event.addListener needs the fully\n // constructed component, and this is the deferred-dispatch site the\n // super-cascade trap requires (never applyOptions).\n this._onSubmit = options?.onSubmit ?? null;\n Event.addListener(this, \"submit\", this.handleSubmit);\n }\n\n /**\n * Handles the native `submit` event: prevents the browser's default\n * navigation and forwards to the `onSubmit` callback, if any.\n *\n * @param e - The native submit event.\n */\n private handleSubmit(e: SubmitEvent): void {\n e.preventDefault();\n this._onSubmit?.(this);\n }\n\n /**\n * Requests a native form submission, firing the cancelable `submit` event\n * and running the browser's constraint validation (unlike `.submit()`,\n * which skips both). No-op if the form is not yet rendered.\n */\n requestSubmit(): void {\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n DOM.sink.requestSubmit(element);\n }\n}\n\nconst FormCallable = callable(Form);\ntype FormCallable<TOptions extends FormOptions = FormOptions> = Form<TOptions>;\nexport {\n Form as _Form,\n FormCallable as Form,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM, type Handle } from \"~/core/DOM.js\";\n\n/**\n * The library's built-in mark: the framework's `Border` layout drawn literally\n * as a north bar, a west sidebar and a centre pane on a rounded plate.\n *\n * Geometry, on a 32-unit viewBox so every dimension is a whole number and each\n * unit is half a pixel in a 16px browser tab: the plate is the full 32×32 with\n * a 6-unit corner radius, and clips the three regions so they inherit its\n * rounded corners. The north bar is `0,0 32×10` (full width, as `Border` docks\n * north); the west sidebar `0,12 10×20`; the centre pane `12,12 20×20`. The\n * 2-unit gaps between them are the field showing through — the regions carry\n * no stroke, so nothing in the mark is thinner than a solid 10-unit block.\n *\n * Colours are fixed rather than read from the active theme, and the SVG carries\n * its own `prefers-color-scheme` rule so the mark suits light *and* dark\n * browser chrome without any framework wiring. Light mode is plain black on\n * white — the highest-contrast pairing, which is what holds the 1px gaps\n * together once a browser downsamples the mark to tab size. The dark palette is\n * lifted from `DarkTheme`: `#505050` is its `button.border` and `#78AAF0` its\n * `input.focusRing`, the framework's accent hue.\n *\n * Declared with single quotes because the string is full of double quotes.\n *\n * @internal Exported for the encoding round-trip test only; not part of the\n * public API (the `core` barrel does not re-export it).\n */\nexport const MARK_SVG = '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><style>.pane{fill:#FFFFFF}.region{fill:#000000}@media(prefers-color-scheme:dark){.pane{fill:#505050}.region{fill:#78AAF0}}</style><clipPath id=\"plate\"><rect width=\"32\" height=\"32\" rx=\"6\"/></clipPath><g clip-path=\"url(#plate)\"><rect class=\"pane\" width=\"32\" height=\"32\"/><rect class=\"region\" width=\"32\" height=\"10\"/><rect class=\"region\" y=\"12\" width=\"10\" height=\"20\"/><rect class=\"region\" x=\"12\" y=\"12\" width=\"20\" height=\"20\"/></g></svg>';\n\n/**\n * The library's built-in mark as a ready-to-use `data:` URI — what\n * {@link Favicon.install} writes when no other icon is supplied.\n *\n * Encoded with `encodeURIComponent` rather than a hand-written escape list.\n * Getting that list wrong fails silently: an unescaped `#` would truncate the\n * URI at `url(#plate)`, dropping the clip path and rendering a blank tab icon\n * with no error anywhere.\n *\n * @category Core\n */\nexport const DEFAULT_FAVICON = `data:image/svg+xml,${encodeURIComponent(MARK_SVG)}`;\n\n/**\n * Matches `rel=\"icon\"` and `rel=\"shortcut icon\"` — `~=` is the\n * whitespace-separated word match, so a `rel` of `\"shortcut icon\"` contains the\n * word `icon` and matches. `apple-touch-icon` and `mask-icon` are single words\n * and deliberately do not: neither sets the browser-tab icon, so a page\n * carrying only one of them still has no tab icon worth preserving.\n */\nconst ICON_LINK_SELECTOR = 'link[rel~=\"icon\"]';\n\n/**\n * Installs the browser-tab icon by appending a `<link rel=\"icon\">` to `<head>`.\n *\n * Apps do not normally call this: `Body.init` installs {@link DEFAULT_FAVICON}\n * on mount, and the `favicon` option on that call is the ordinary way to supply\n * a different one or to suppress injection. Call it directly only when mounting\n * without `Body.init`.\n *\n * An icon the document already declares always wins — see {@link Favicon.install}.\n *\n * @category Core\n */\nexport class Favicon {\n\n /**\n * The link this class injected, or `null` when it has not injected one.\n * Held so a later install swaps the `href` instead of stacking a second\n * `<link>` — the browser would honour the last one, but the page would\n * accumulate a link per call.\n */\n private static _link: Handle | null = null;\n\n /**\n * Appends a `<link rel=\"icon\">` to `<head>`, unless the document already\n * declares an icon link of its own — an app's `<link rel=\"icon\">` written\n * in its `index.html` is never replaced. Module scripts run after the\n * document is parsed, so such a link is always visible by the time this\n * runs.\n *\n * Calling it again replaces the `href` on the link it previously injected\n * rather than appending a second one.\n *\n * @param href - The icon URL or `data:` URI. Defaults to the library's\n * built-in mark.\n *\n * @returns `true` when the icon was installed, `false` when the document's\n * own icon link was left in place.\n */\n static install(href: string = DEFAULT_FAVICON): boolean {\n if (Favicon._link !== null) {\n DOM.sink.apply(Favicon._link, { setAttr: { href } });\n\n return true;\n }\n\n const head = DOM.source.getHead();\n\n if (DOM.source.querySelector(head, ICON_LINK_SELECTOR) !== null) {\n return false;\n }\n\n const link = DOM.sink.createElement(\"link\");\n\n DOM.sink.apply(link, { setAttr: { rel: \"icon\", href } });\n DOM.sink.appendChild(head, link);\n\n Favicon._link = link;\n\n return true;\n }\n\n /**\n * Forgets the injected link, so the next {@link Favicon.install} appends a\n * fresh one instead of writing through the handle it is holding.\n *\n * @internal Test-only. A handle minted before `DOM.reset()` does not\n * resolve against the registry that replaces it, so a suite that resets the\n * DOM between cases must reset this too.\n */\n static _reset(): void {\n Favicon._link = null;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Favicon, DEFAULT_FAVICON } from \"~/core/Favicon.js\";\nimport { ThemeManager, ModernTheme } from \"~/core/Theme.js\";\n\n/**\n * Options for the singleton {@link Body}.\n *\n * @category Core\n */\nexport interface BodyOptions extends ComponentOptions {\n /**\n * Browser-tab icon. A URL or `data:` URI installs that icon; `false`\n * suppresses injection entirely. Omitted, the library's built-in mark is\n * used. In every case a `<link rel=\"icon\">` already present in the page's\n * HTML wins and nothing is injected.\n */\n favicon?: string | false;\n\n /**\n * Whether the browser's own right-click menu is allowed. Defaults to\n * `false` — `Body.init` suppresses the native menu page-wide, so only\n * menus the library or the app opens on `contextmenu` ever appear.\n * `true` restores the browser's menu everywhere.\n */\n nativeContextMenu?: boolean;\n}\n\n/**\n * A {@link Component} that wraps the page's `<body>` element.\n *\n * Mount a top-level layout in one call:\n * ```\n * Body.init({ layoutManager: Fit(), components: [shell] });\n * ```\n *\n * Once mounted, reach the singleton again with `Body.getInstance()` — to add a\n * further child, read the layout manager, or attach a listener.\n *\n * @category Core\n */\nexport class Body extends Component<BodyOptions> {\n\n private static readonly INSTANCE: Body = new Body();\n\n /**\n * Returns the singleton Body instance — the accessor for reaching the body\n * *after* it is mounted: adding a further child, reading its layout\n * manager, or attaching a listener. To mount a top-level layout in one\n * call, use `Body.init` instead.\n *\n * @returns The single shared Body component for this page.\n */\n static getInstance() {\n return this.INSTANCE;\n }\n\n /**\n * Applies an options bag to the singleton Body and returns it — the\n * ergonomic entry point for mounting a top-level layout in one call:\n * `Body.init({ layoutManager: Fit(), components: [shell] })`. Only the\n * supplied fields are dispatched (it delegates to\n * `Component.applyOptions`), so the body's viewport-size tracking and\n * theme set up at construction are preserved.\n *\n * Also installs the browser-tab icon, unless the page already declares a\n * `<link rel=\"icon\">` of its own or `options.favicon` is `false`, and\n * suppresses the browser's native right-click menu page-wide, unless\n * `options.nativeContextMenu` is `true`.\n *\n * @param options - Component options to apply (layout manager, children, …).\n *\n * @returns The singleton Body instance, for chaining.\n *\n * @remarks Re-binds the style and attribute buffers to the current body\n * element before dispatching `options` — see\n * `Component.reattachElementBuffers`. The singleton is constructed once\n * per page load, so this only matters when the underlying DOM has been\n * swapped since construction (a test harness); it is a no-op rebind\n * otherwise.\n */\n static init(options: BodyOptions = {}): Body {\n this.INSTANCE.reattachElementBuffers();\n this.INSTANCE.applyOptions(options);\n\n // The built-in default is dispatched here rather than from\n // applyOptions, which also runs during the singleton's construction at\n // module import — too early for a caller to have opted out, and before\n // a test harness has swapped the DOM seams.\n if (options.favicon === undefined) {\n this.INSTANCE.setFavicon(DEFAULT_FAVICON);\n }\n\n // Same reasoning as the favicon default above: dispatched here rather\n // than from applyOptions, which also runs during the singleton's\n // construction at module import — too early for a caller to have\n // opted out, and before a test harness has swapped the DOM seams.\n if (options.nativeContextMenu === undefined) {\n this.INSTANCE.setNativeContextMenu(false);\n }\n\n return this.INSTANCE;\n }\n\n /** @inheritDoc */\n protected applyOptions(options: BodyOptions): this {\n super.applyOptions(options);\n\n if (options.favicon !== undefined) this.setFavicon(options.favicon);\n if (options.nativeContextMenu !== undefined) this.setNativeContextMenu(options.nativeContextMenu);\n\n return this;\n }\n\n /**\n * Installs the browser-tab icon, or suppresses it.\n *\n * A `<link rel=\"icon\">` the page's own HTML declares always wins, so this\n * writes nothing when one is present. `false` suppresses injection; it does\n * not remove an icon already installed.\n *\n * @param favicon - The icon URL or `data:` URI, or `false` for none.\n *\n * @returns This component, for method chaining.\n */\n setFavicon(favicon: string | false): this {\n this._options.favicon = favicon;\n\n if (favicon !== false) {\n Favicon.install(favicon);\n }\n\n return this;\n }\n\n /**\n * Returns the browser-tab icon this body was configured with.\n *\n * @returns The configured URL or `data:` URI, `false` when injection is\n * suppressed, or the library's built-in mark when nothing was configured.\n */\n getFavicon(): string | false {\n return this._options.favicon ?? DEFAULT_FAVICON;\n }\n\n /**\n * Allows or suppresses the browser's native right-click menu page-wide.\n *\n * @param allowed - `true` lets the browser's own menu open on\n * `contextmenu`; `false` suppresses it everywhere.\n *\n * @returns This component, for method chaining.\n */\n setNativeContextMenu(allowed: boolean): this {\n // The listener is registered exactly when the option reads `false`;\n // `undefined` means \"not configured yet\", so nothing is registered.\n const listening = this._options.nativeContextMenu === false;\n\n this._options.nativeContextMenu = allowed;\n\n if (!allowed && !listening) {\n Event.addViewportListener(this, \"contextmenu\", this.onContextMenu);\n } else if (allowed && listening) {\n Event.removeViewportListener(this, \"contextmenu\", this.onContextMenu);\n }\n\n return this;\n }\n\n /**\n * Returns whether the browser's native right-click menu is allowed.\n *\n * @returns `true` when the native menu is allowed, `false` when it is\n * suppressed (the default).\n */\n getNativeContextMenu(): boolean {\n return this._options.nativeContextMenu ?? false;\n }\n\n private constructor() {\n super({ tag: \"body\" });\n\n this.init();\n\n this.setBackgroundColor(\"var(--ts-ui-body-bg, rgb(241, 241, 241))\");\n\n ThemeManager.setTheme(ModernTheme);\n }\n\n /**\n * Returns the document body element.\n *\n * @returns The `<body>` HTMLElement.\n */\n getElement() {\n return DOM.source.getBody();\n }\n\n /**\n * Initializes the body size from the viewport and registers a resize listener to keep it in sync.\n *\n * @returns This component, for method chaining.\n */\n protected init(): this {\n super.init();\n\n this.setSize(DOM.source.getViewportSize());\n this.clearInsets();\n\n Event.addViewportListener(this, \"resize\", this._onViewportResize);\n this.subscribeTheme(this._onThemeReflow);\n\n return this;\n }\n\n /**\n * Bound viewport-resize handler. Reads the current viewport extent on\n * each fire (DOM `resize` events carry no payload) and writes it\n * through the typed setter.\n */\n private _onViewportResize = (): void => {\n this.setSize(DOM.source.getViewportSize());\n };\n\n /**\n * Viewport `contextmenu` handler registered by {@link setNativeContextMenu}\n * while the native menu is suppressed. Returns a disposition rather than\n * calling `preventDefault()` itself, and deliberately never returns a stop\n * disposition: a `contextmenu` event is also routed to any component's\n * own handler (e.g. `Tree`, `DiagramView`) through `Event`'s other\n * window-capture listener, and this handler must not cut that walk short.\n * A plain prototype method, not an arrow field, so it exists before the\n * constructor runs and has a stable identity `removeViewportListener` can\n * find (see `Markdown.handleViewportChange` for the same reasoning).\n *\n * @returns `{ prevent: true }`, suppressing the browser's own menu.\n */\n private onContextMenu(): Event.ListenerResult {\n return { prevent: true };\n }\n\n /**\n * Bound theme-change handler. Schedules a layout pass so every `Text` in\n * the page re-measures lazily against the new theme's metrics — replaces\n * the per-`Text` theme subscription this component's children used to\n * hold individually.\n */\n private _onThemeReflow = (): void => {\n this.scheduleLayout();\n };\n\n /**\n * Overrides {@link Component.clampsToContentSize} to `false`: the body *is*\n * the viewport, so its size must track {@link Util.getViewportSize} exactly\n * and let oversized content overflow (the page scrolls / a child `Panel`\n * scrolls internally) rather than inflating the body up to its\n * content-derived minimum. With the `Component` default (`true`),\n * {@link Component.setSize} ran the viewport extent through\n * {@link Component.clampHeight}, which floored it to `getMinSize()` — the\n * tall content's minimum — so once that minimum was measured the body could\n * never shrink back below its content when the viewport shrank.\n *\n * @returns `false`, so size clamping uses the body's own explicit\n * constraints only, not its content-derived ones.\n */\n protected clampsToContentSize(): boolean {\n return false;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\n\n/**\n * A physical-key chord. `code` is a `KeyboardEvent.code` value (layout-independent).\n *\n * @category Core\n */\nexport interface FocusHistoryKeyCombo {\n code: string;\n ctrl?: boolean;\n alt?: boolean;\n shift?: boolean;\n meta?: boolean;\n}\n\n/**\n * Options for {@link FocusHistory.enable} / {@link FocusHistory.configure}.\n *\n * @category Core\n */\nexport interface FocusHistoryOptions {\n /** Max entries retained; oldest dropped past this. Default 50. */\n maxSize?: number;\n /** Back accelerator. Default `Alt+[` (`{ code: \"BracketLeft\", alt: true }`). */\n back?: FocusHistoryKeyCombo;\n /** Forward accelerator. Default `Alt+]` (`{ code: \"BracketRight\", alt: true }`). */\n forward?: FocusHistoryKeyCombo;\n}\n\n/**\n * The sole custom event name fired by {@link FocusHistory}.\n *\n * @category Core\n */\nexport type FocusHistoryEvent = \"change\";\n\n/**\n * Payload of the `\"change\"` event: the navigability of the trail after the change.\n *\n * @category Core\n */\nexport interface FocusHistoryChange {\n canGoBack: boolean;\n canGoForward: boolean;\n}\n\n// 50: a working session's focus trail rarely exceeds a few dozen stops; caps\n// memory at 50 handle numbers while leaving generous back-depth.\nconst DEFAULT_MAX_ENTRIES: number = 50;\n// Alt+[ / Alt+]: editor-style \"navigate back/forward\"; no default browser\n// action (unlike Alt+Left/Right = browser history); layout-independent via code.\nconst DEFAULT_BACK_COMBO: FocusHistoryKeyCombo = { code: \"BracketLeft\", alt: true };\nconst DEFAULT_FORWARD_COMBO: FocusHistoryKeyCombo = { code: \"BracketRight\", alt: true };\n\n// Sentinel used to register the service's viewport listeners — see\n// LayerManager's identical `_listenerOwner` pattern. `FocusHistory` has no DOM\n// element of its own, so a stable, otherwise-unused `Component` owns them.\nconst _owner: Component = new Component();\nconst _listeners = new ListenerBag<FocusHistoryEvent>();\n\n// Chronological trail, oldest first. Entries are bare `Handle`s (not\n// `Component`s) because focus frequently lands on an element with no 1:1\n// component (an input inside a Text, a raw button).\nlet _entries: Handle[] = [];\n// Current position in `_entries`; -1 when the trail is empty.\nlet _index: number = -1;\nlet _enabled: boolean = false;\n// Re-entrancy guard: true for the duration of a service-driven `DOM.sink.focus`\n// call, so the synchronous `focusin` it triggers is not recorded as a new move.\nlet _navigating: boolean = false;\nlet _maxSize: number = DEFAULT_MAX_ENTRIES;\nlet _back: FocusHistoryKeyCombo = DEFAULT_BACK_COMBO;\nlet _forward: FocusHistoryKeyCombo = DEFAULT_FORWARD_COMBO;\n\n/**\n * Whether `handle` still resolves to a connected element. A GC-collected weak\n * handle throws on resolve inside the DOM seam; that is treated as stale too.\n */\nfunction isLive(handle: Handle): boolean {\n try {\n return DOM.source.isConnected(handle);\n } catch {\n return false;\n }\n}\n\n/**\n * Drops every stale (no-longer-connected) entry from the trail, keeping\n * `_index` pointed at the nearest surviving entry at or before its old\n * position (or -1 if nothing survived there). Run before every navigation\n * and every `canGo*` query so those never act on a dead entry.\n */\nfunction pruneStale(): void {\n const kept: Handle[] = [];\n let newIndex = -1;\n\n for (let i = 0; i < _entries.length; i++) {\n const handle = _entries[i];\n\n if (isLive(handle)) {\n kept.push(handle);\n\n if (i <= _index) {\n newIndex = kept.length - 1;\n }\n }\n }\n\n _entries = kept;\n _index = newIndex;\n}\n\n/** Computes the current navigability and notifies `\"change\"` listeners. */\nfunction fireChange(): void {\n const change: FocusHistoryChange = {\n canGoBack: _index > 0,\n canGoForward: _index < _entries.length - 1,\n };\n\n _listeners.fire(\"change\", change);\n}\n\n/**\n * Appends `handle` to the trail (deduping a repeat of the current entry and\n * truncating any forward branch), advances `_index`, and fires `\"change\"`.\n */\nfunction record(handle: Handle): void {\n if (_index >= 0 && _entries[_index] === handle) {\n return;\n }\n\n _entries.length = _index + 1;\n _entries.push(handle);\n\n while (_entries.length > _maxSize) {\n _entries.shift();\n }\n\n _index = _entries.length - 1;\n fireChange();\n}\n\n/** Re-focuses `handle` under the re-entrancy guard, then fires `\"change\"`. */\nfunction focusEntry(handle: Handle): void {\n _navigating = true;\n DOM.sink.focus(handle);\n _navigating = false;\n fireChange();\n}\n\n/**\n * Prunes stale entries, then moves `_index` by `direction` and re-focuses the\n * entry there, if one exists.\n *\n * @returns True if focus moved.\n */\nfunction navigate(direction: -1 | 1): boolean {\n pruneStale();\n\n const target = _index + direction;\n\n if (target < 0 || target >= _entries.length) {\n return false;\n }\n\n _index = target;\n focusEntry(_entries[_index]);\n\n return true;\n}\n\n/** Whether a `KeyboardEvent` matches a configured combo. */\nfunction matchesCombo(e: KeyboardEvent, combo: FocusHistoryKeyCombo): boolean {\n return e.code === combo.code &&\n e.altKey === !!combo.alt && e.ctrlKey === !!combo.ctrl &&\n e.shiftKey === !!combo.shift && e.metaKey === !!combo.meta;\n}\n\n/** Document `focusin` handler: records the newly-focused element. */\nfunction onFocusIn(e: FocusEvent): void {\n if (!_enabled || _navigating) {\n return;\n }\n\n if (!DOM.source.isElement(e.target)) {\n return;\n }\n\n record(DOM.source.intern(e.target));\n}\n\n/**\n * Document `keydown` handler: drives `back()`/`forward()` on the configured\n * combos, suppressed while a modal layer is on top so the accelerator does\n * not fight the modal's own focus trap.\n *\n * @returns `{ stop: true, prevent: true }` when the key matches a navigation combo\n * and no modal layer is suppressing it; nothing otherwise, so every other key\n * keeps propagating.\n */\nfunction onKeyDown(e: KeyboardEvent): Event.ListenerResult {\n if (!_enabled) {\n return;\n }\n\n const direction: -1 | 1 | 0 = matchesCombo(e, _back) ? -1 : matchesCombo(e, _forward) ? 1 : 0;\n\n if (direction === 0) {\n return;\n }\n\n const top = LayerManager.getTopLayer();\n\n if (top && top.getDismissMode() === \"modal\") {\n return;\n }\n\n navigate(direction);\n\n return { stop: true, prevent: true };\n}\n\n/**\n * Global focus-trail navigation service: records the chronological order in\n * which elements receive keyboard focus across the document and drives an\n * accelerator that walks the trail backward and forward, like browser\n * back/forward but for keyboard focus. Opt-in — call {@link enable} to start\n * recording; nothing auto-starts it.\n *\n * @category Core\n */\nexport namespace FocusHistory {\n /**\n * Installs the `focusin` + `keydown` listeners, seeds the trail with the\n * current active element (if any), and begins recording. Idempotent —\n * calling it again while already enabled only applies `options`.\n *\n * @param options - Optional `maxSize` / combo overrides, applied via\n * {@link configure} before enabling.\n */\n export function enable(options?: FocusHistoryOptions): void {\n if (options) {\n configure(options);\n }\n\n if (_enabled) {\n return;\n }\n\n _enabled = true;\n\n Event.addViewportListener(_owner, \"focusin\", onFocusIn);\n Event.addViewportListener(_owner, \"keydown\", onKeyDown);\n\n const active = DOM.source.getActiveElement();\n\n if (active !== null) {\n record(active);\n }\n }\n\n /**\n * Removes the listeners and stops recording. Preserves the trail —\n * re-enabling resumes from where it left off. Idempotent.\n */\n export function disable(): void {\n if (!_enabled) {\n return;\n }\n\n _enabled = false;\n _navigating = false;\n\n Event.removeViewportListener(_owner, \"focusin\", onFocusIn);\n Event.removeViewportListener(_owner, \"keydown\", onKeyDown);\n }\n\n /** Whether the service is currently observing. */\n export function isEnabled(): boolean {\n return _enabled;\n }\n\n /**\n * Updates `maxSize` / combos without toggling enablement. Only the\n * supplied fields change.\n *\n * @param options - The fields to update.\n */\n export function configure(options: FocusHistoryOptions): void {\n if (options.maxSize !== undefined) {\n _maxSize = options.maxSize;\n }\n\n if (options.back !== undefined) {\n _back = options.back;\n }\n\n if (options.forward !== undefined) {\n _forward = options.forward;\n }\n }\n\n /**\n * Re-focuses the previous live entry, skipping and dropping any stale\n * ones encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function back(): boolean {\n return navigate(-1);\n }\n\n /**\n * Re-focuses the next live entry, skipping and dropping any stale ones\n * encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function forward(): boolean {\n return navigate(1);\n }\n\n /**\n * Whether a live entry exists before the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoBack(): boolean {\n pruneStale();\n\n return _index > 0;\n }\n\n /**\n * Whether a live entry exists after the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoForward(): boolean {\n pruneStale();\n\n return _index < _entries.length - 1;\n }\n\n /** Empties the trail and fires `\"change\"` with both flags false. */\n export function clear(): void {\n _entries = [];\n _index = -1;\n fireChange();\n }\n\n /**\n * Subscribes to trail-navigability changes, fired after every recorded\n * focus move and after every `back()` / `forward()` navigation.\n *\n * @param event - Always `\"change\"`.\n * @param listener - Invoked with the trail's navigability after the change.\n */\n export function on(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.add(event, listener);\n }\n\n /**\n * Unsubscribes a `\"change\"` listener.\n *\n * @param event - Always `\"change\"`.\n * @param listener - The exact callback reference passed to {@link on}.\n */\n export function off(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.remove(event, listener);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from '~/core/BaseObject.js';\nimport { ModelRecord } from '~/data/ModelRecord.js';\nimport { Bindable, BindingAccessors } from '~/core/Bindable.js';\nimport { Component } from '~/core/Component.js';\nimport { ListenerBag } from '~/core/ListenerBag.js';\nimport { ValidationRule, FieldValidationConfig } from '~/validation/ValidationRule.js';\nimport { FieldDecorator } from '~/validation/FieldDecorator.js';\nimport { applyRule } from '~/validation/Validator.js';\n\n/**\n * String-literal union of events emitted by {@link Binding}.\n *\n * @category Data\n */\nexport type BindingEvent = \"change\" | \"commit\" | \"reject\" | \"beforerecord\";\n\ninterface BoundEntry {\n accessors: BindingAccessors<any>;\n active: boolean;\n}\n\n/**\n * Listener consulted before a record change takes effect.\n *\n * Receives the *next* record (or `null`) and returns `false` to cancel the\n * change. Any other return value (`true`, `undefined`, …) allows it.\n *\n * @category Data\n */\nexport type BeforeRecordListener = (next: ModelRecord | null) => boolean;\n\n/**\n * Synchronises a {@link ModelRecord} with a set of UI components.\n *\n * Components are registered with {@link bind}, either as {@link Bindable} implementors\n * (short form) or via explicit accessor callbacks (long form). Once a record is loaded\n * via {@link setRecord}, every bound component is populated from the record's fields.\n * Conversely, whenever a component's value changes, the record is updated automatically.\n *\n * @example Short form — component implements Bindable\n * ```typescript\n * const binding = new Binding()\n * .bind('name', nameField)\n * .bind('active', activeCheckbox)\n * .bind('role', roleCombo);\n *\n * binding.setRecord(record);\n * ```\n *\n * @example Long form — explicit accessors for any component\n * ```typescript\n * const binding = new Binding()\n * .bind('name', myWidget, {\n * get: () => myWidget.getValue(),\n * set: (v) => myWidget.setValue(v),\n * listen: (fn) => myWidget.on(\"change\", fn),\n * });\n * ```\n *\n * @category Data\n */\nexport class Binding extends BaseObject {\n\n private _record: ModelRecord | null = null;\n private _entries: Map<string, BoundEntry> = new Map();\n private _listeners: ListenerBag<BindingEvent> = new ListenerBag<BindingEvent>();\n private _validationConfigs: Map<string, FieldValidationConfig> = new Map();\n private _globalValidateOnChange: boolean = false;\n private _loading: boolean = false;\n\n // ── Registration ────────────────────────────────────────────────────────\n\n /**\n * Registers a field binding using a component that implements {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - A component implementing the {@link Bindable} interface.\n */\n bind<T>(fieldName: string, component: Bindable<T>): this;\n\n /**\n * Registers a field binding using explicit accessor callbacks.\n * Use this overload for components that do not implement {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - Any object (used only as a placeholder for the overload).\n * @param accessors - Getter, setter, and change-listener callbacks.\n */\n bind<T>(fieldName: string, component: object, accessors: BindingAccessors<T>): this;\n\n bind<T>(fieldName: string, component: Bindable<T> | object, accessors?: BindingAccessors<T>): this {\n this.unbind(fieldName);\n\n const acc: BindingAccessors<any> = accessors ?? {\n get: () => (component as Bindable<T>).getValue(),\n set: (v: T) => (component as Bindable<T>).setValue(v),\n listen: (fn) => (component as Bindable<T>).on(\"binding\", fn),\n };\n\n const entry: BoundEntry = { accessors: acc, active: true };\n this._entries.set(fieldName, entry);\n\n acc.listen(() => {\n if (this._loading) {\n return;\n }\n\n if (!entry.active || !this._record) {\n return;\n }\n\n const value = acc.get();\n this._record.set(fieldName, value);\n\n this.emit(\"change\", fieldName, value);\n\n this._validateFieldIfLive(fieldName);\n });\n\n if (this._record) {\n acc.set(this._record.get(fieldName));\n }\n\n return this;\n }\n\n /**\n * Removes the binding for the given field.\n * The change listener previously attached to the component becomes a no-op.\n *\n * @param fieldName - The field whose binding should be removed.\n */\n unbind(fieldName: string): this {\n const entry = this._entries.get(fieldName);\n if (entry) {\n entry.active = false;\n\n this._entries.delete(fieldName);\n }\n\n return this;\n }\n\n // ── Record management ────────────────────────────────────────────────────\n\n /**\n * Loads a record into the binding. All registered components are immediately\n * populated with the corresponding field values. Pass `null` to clear the binding.\n *\n * Before any state mutation, every `on(\"beforerecord\", fn)` listener is\n * consulted; if any returns `false` the\n * call is a complete no-op (no validation reset, no field population) and\n * `this` is returned unchanged.\n *\n * @param record - The record to bind, or `null` to detach.\n */\n setRecord(record: ModelRecord | null): this {\n for (const fn of this._listeners.get(\"beforerecord\") as BeforeRecordListener[]) {\n if (fn(record) === false) {\n return this;\n }\n }\n\n this._record = record;\n\n this.clearValidation();\n\n if (!record) {\n return this;\n }\n\n this._loading = true;\n\n try {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(record.get(fieldName));\n }\n } finally {\n this._loading = false;\n }\n\n for (const [fieldName] of this._validationConfigs) {\n this._validateFieldIfLive(fieldName);\n }\n\n return this;\n }\n\n /**\n * Returns the currently bound record, or `null` if none is loaded.\n */\n getRecord(): ModelRecord | null {\n return this._record;\n }\n\n // ── Commit / reject ──────────────────────────────────────────────────────\n\n /**\n * Commits the current record, clearing its dirty and new flags.\n * Fires all registered commit listeners.\n */\n commit(): this {\n this._record?.commit();\n\n this.emit(\"commit\");\n\n return this;\n }\n\n /**\n * Rejects all changes on the current record and re-syncs every component\n * from the reverted field values. Fires all registered reject listeners.\n * Also clears any active validation error decorations.\n */\n reject(): void {\n this._record?.reject();\n\n if (this._record) {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(this._record.get(fieldName));\n }\n }\n\n this.clearValidation();\n\n this.emit(\"reject\");\n }\n\n // ── Listeners ────────────────────────────────────────────────────────────\n\n /**\n * Registers a listener for one of this binding's events.\n *\n * @param event - `\"change\"` fires whenever any bound component changes a\n * field value, receiving `(fieldName, value)`. `\"commit\"` fires after\n * {@link commit}. `\"reject\"` fires after {@link reject}.\n * `\"beforerecord\"` is consulted before {@link setRecord} mutates state;\n * returning `false` vetoes the call as a complete no-op.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This binding, for method chaining.\n *\n * @remarks `\"beforerecord\"` veto semantics: iteration stops on the first\n * `false`; if any listener vetoes, {@link setRecord} returns without\n * modifying any state. Returning `true` — or anything other than\n * `false`, including `undefined` — allows the change. Async\n * confirmation must be handled at the call site — {@link setRecord}\n * stays synchronous. A listener that itself calls {@link setRecord}\n * re-enters the same veto loop, which is supported but discouraged.\n * `null` is a valid `next` value (it represents a clear); a listener\n * that only wants to guard non-clear switches must short-circuit\n * `next === null` itself.\n */\n on(event: \"change\", listener: (fieldName: string, value: unknown) => void): this;\n on(event: \"commit\", listener: () => void): this;\n on(event: \"reject\", listener: () => void): this;\n on(event: \"beforerecord\", listener: BeforeRecordListener): this;\n on(event: BindingEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This binding, for method chaining.\n */\n off(event: BindingEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order. Internal use only — external callers route\n * dispatch through {@link commit} / {@link reject} / {@link setRecord}.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"change\", fieldName: string, value: unknown): void;\n protected emit(event: \"commit\"): void;\n protected emit(event: \"reject\"): void;\n protected emit(event: BindingEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n // ── Validation ───────────────────────────────────────────────────────────\n\n /**\n * Attaches one or more validation rules to a bound field.\n *\n * @param fieldName - The field name registered with {@link bind}.\n * @param component - The Component instance to wrap with a {@link FieldDecorator} on error.\n * @param rules - One or more {@link ValidationRule} objects to apply to this field.\n *\n * @returns this, for chaining.\n */\n addValidation(fieldName: string, component: Component, rules: ValidationRule | ValidationRule[]): this {\n const ruleArray = Array.isArray(rules) ? rules : [rules];\n\n this._validationConfigs.set(fieldName, {\n rules : ruleArray,\n component,\n validateOnChange: false,\n decorator : null,\n });\n\n return this;\n }\n\n /**\n * Removes all validation rules for a field and clears any existing error decoration.\n *\n * @param fieldName - The field whose validation should be removed.\n *\n * @returns this, for chaining.\n */\n removeValidation(fieldName: string): this {\n const config = this._validationConfigs.get(fieldName);\n\n if (config?.decorator) {\n config.decorator.clearError();\n }\n\n this._validationConfigs.delete(fieldName);\n\n return this;\n }\n\n /**\n * Runs all registered validation rules against the current field values.\n * Applies or clears {@link FieldDecorator} error state for each validated field.\n *\n * @returns true if all fields pass; false if any field fails.\n */\n validate(): boolean {\n let allValid = true;\n\n for (const [fieldName] of this._validationConfigs) {\n const valid = this._validateField(fieldName);\n\n if (!valid) {\n allValid = false;\n }\n }\n\n return allValid;\n }\n\n /**\n * Enables or disables live validation (validation on every field change).\n *\n * @param enabled - true to validate on every change event; false for explicit-only.\n */\n setValidateOnChange(enabled: boolean): this {\n this._globalValidateOnChange = enabled;\n\n return this;\n }\n\n /**\n * Returns whether live validation is globally enabled.\n *\n * @returns true if live validation is active.\n */\n getValidateOnChange(): boolean {\n return this._globalValidateOnChange;\n }\n\n /**\n * Clears all error decorations without re-running rules.\n * Called automatically by {@link reject}.\n */\n clearValidation(): this {\n for (const [, config] of this._validationConfigs) {\n if (config.decorator) {\n config.decorator.clearError();\n }\n }\n\n return this;\n }\n\n /**\n * Validates a single field and updates its decorator.\n *\n * @param fieldName - The field to validate.\n *\n * @returns true if the field passes all rules.\n */\n private _validateField(fieldName: string): boolean {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return true;\n }\n\n const entry = this._entries.get(fieldName);\n const value = entry ? entry.accessors.get() : undefined;\n\n for (const rule of config.rules) {\n const result = applyRule(rule, value);\n\n if (result.valid) {\n continue;\n }\n\n if (!config.decorator) {\n const parent = config.component.getParentComponent();\n\n if (parent) {\n config.decorator = new FieldDecorator(config.component, parent);\n }\n }\n\n config.decorator?.showError(result.message);\n\n return false;\n }\n\n config.decorator?.clearError();\n\n return true;\n }\n\n /**\n * Calls {@link _validateField} only if live validation is active for this field.\n *\n * @param fieldName - The field to conditionally validate.\n */\n private _validateFieldIfLive(fieldName: string): void {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return;\n }\n\n const live = config.validateOnChange || this._globalValidateOnChange;\n\n if (live) {\n this._validateField(fieldName);\n }\n }\n}\n"],"mappings":"6rBAkBA,IAAa,EAAsB,EAAY,EAAW,CACtD,YAAa,QACb,KAAa,CAAE,MAAO,cAAe,EACrC,KAAa,CAAE,WAAY,oBAAqB,EAChD,OAAa,CAAE,MAAO,OAAQ,EAC9B,OAAa,CACT,WAAY,0DACZ,OAAY,qBACZ,OAAY,mCACZ,YAAa,CACT,WAAY,oBAChB,EACA,QAAY,CACR,WAAY,qBACZ,WAAY,0DACZ,OAAY,qCAChB,EACA,MAAY,CACR,WAAY,UACZ,WAAY,0DACZ,OAAY,mCAChB,EACA,KAAY,CACR,MAAS,CACL,WAAY,sBACZ,OAAY,8BAChB,EACA,QAAS,CACL,WAAY,sBACZ,OAAY,wCACZ,OAAY,8BAChB,CACJ,CACJ,EACA,OAAc,CACV,SAAU,CACN,WAAY,qBACZ,OAAY,wBAChB,CACJ,EACA,MAAQ,CACJ,WAAa,qBACb,OAAa,+BACb,YAAa,8BACjB,EACA,KAAQ,CACJ,WAAoB,qBACpB,OAAoB,qBACpB,MAAoB,kBACpB,mBAAoB,qBACpB,cAAoB,qBACpB,UAAoB,oBACpB,OAAU,CACN,mBAAoB,qBACpB,kBAAoB,oBACpB,gBAAoB,oBACxB,EACA,OAAU,CACN,gBAAuB,qBACvB,sBAAuB,oBACvB,gBAAuB,oBAC3B,EACA,SAAU,CACN,WAAyB,qBACzB,mBAAyB,oBACzB,wBAAyB,qBACzB,WAAyB,oBAC7B,EACA,MAAU,CACN,WAAoB,qBACpB,mBAAoB,oBACpB,SAAoB,oBACxB,CACJ,EACA,OAAQ,CAAE,WAAY,SAAU,EAChC,SAAU,CACN,MAAQ,CAAE,WAAY,UAAW,KAAM,MAAO,EAC9C,OAAQ,CAAE,MAAO,kBAAmB,CACxC,EACA,UAAW,CACP,OAAW,6BACX,OAAW,CACP,WAAY,qDACZ,OAAY,6BACZ,MAAY,SAChB,EACA,MAAW,CAAE,OAAQ,kBAAmB,EACxC,UAAW,CAAE,MAAO,kBAAmB,CAC3C,EACA,IAAQ,CACJ,QAAS,CAAE,WAAY,OAAY,OAAQ,SAAU,EACrD,OAAS,CACL,WAAY,0DACZ,OAAY,OACZ,MAAY,CAAE,WAAY,0DAA2D,OAAQ,MAAO,EACpG,SAAY,CAAE,WAAY,0DAA2D,OAAQ,MAAO,CACxG,EACA,UAAW,CAAE,MAAO,SAAU,CAClC,EACA,OAAQ,CACJ,OAAc,iCACd,SAAc,oCACd,QAAc,CACV,WAAkB,0DAClB,OAAkB,+BAClB,OAAkB,mCAClB,gBAAkB,0DAClB,iBAAkB,yDACtB,EACA,OAAc,CAAE,WAAY,MAAO,CACvC,EACA,MAAQ,CACJ,OAAQ,CACJ,WAAY,0DACZ,OAAQ,QACR,MAAQ,CAAE,MAAO,cAAe,CACpC,EACA,IAAQ,CACJ,SAAgB,2BAChB,eAAgB,0CAChB,IAAgB,0BAChB,MAAgB,0BAChB,OAAgB,sBACpB,EACA,KAAQ,CACJ,WAA4B,cAC5B,mBAA4B,sBAC5B,0BAA4B,yBAC5B,MAA4B,UAC5B,OAA4B,OAC5B,kBAA4B,yBAChC,EACA,UAAW,CACP,WAAY,wBAChB,EACA,aAAc,CACV,MAAQ,oBACZ,EACA,UAAW,CACP,WAAY,sBACZ,MAAY,SAChB,EAQA,kBAAmB,CACf,WAAY,oBACZ,MAAY,oBAChB,CACJ,EACA,YAAa,CACT,WAAgB,qBAChB,OAAgB,qBAChB,OAAgB,kCAChB,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,oBACrB,EACA,eAAgB,oBACpB,EACA,QAAS,CAEL,WAAgB,qBAChB,OAAgB,qBAChB,OAAgB,CACZ,WAAiB,cACjB,gBAAiB,2BACjB,WAAiB,SACrB,EACA,MAAgB,CACZ,WAAY,qBACZ,OAAY,qBACZ,OAAY,iCAChB,EACA,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,qBACjB,cAAiB,oBACrB,EACA,eAAgB,oBACpB,EACA,UAAW,CACP,WAAY,qBACZ,MAAY,kBACZ,OAAY,oBAChB,EACA,QAAS,CACL,WAAgB,qBAChB,OAAgB,qBAChB,eAAgB,oBACpB,EACA,QAAS,CACL,WAAY,qBACZ,MAAY,eACZ,OAAY,qBACZ,OAAY,gCAChB,EACA,QAAS,CACL,WAAY,qBACZ,MAAY,eACZ,OAAY,qBACZ,OAAY,kCAChB,EACA,aAAc,CACV,OAAS,kCACT,KAAS,CAAE,WAAY,4BAA8B,OAAQ,mBAAqB,EAClF,QAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,EAClF,QAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,EAClF,MAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,CACtF,EACA,WAAY,CACR,MAAO,CACH,OAAS,mBACT,QAAS,CACL,WAAY,mBACZ,MAAY,qBACZ,OAAY,kBAChB,CACJ,CACJ,EACA,aAAc,CACV,WAAY,qBACZ,OAAY,qBACZ,OAAY,+BACZ,KAAM,CACF,gBAAqB,2BACrB,oBAAqB,2BACrB,eAAqB,UACrB,cAAqB,oBACzB,CACJ,EAMA,KAAM,CACF,WAAY,qBACZ,OAAY,qBACZ,IAAK,CACD,gBAAoB,2BACpB,mBAAoB,2BACpB,cAAoB,UACpB,UAAoB,oBACpB,cAAoB,qBACpB,UAAoB,aACxB,CACJ,EACA,UAAW,CACP,MAAW,oBACX,UAAW,+BACf,EAIA,OAAQ,CACJ,cAAwB,0BACxB,mBAAwB,2BACxB,uBAAwB,aAC5B,EACA,OAAQ,CACJ,SAAU,CAAE,WAAY,qBAAsB,EAC9C,OAAU,qBACV,OAAU,mCACV,QAAU,mBACV,OAAU,mBACV,KAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,EACpF,OAAU,CAAE,WAAY,0BAA4B,WAAY,kBAAoB,CACxF,EACA,OAAQ,CACJ,OAAY,iCACZ,OAAY,oBAChB,EACA,KAAM,CACF,OAAY,qBACZ,OAAY,iCACZ,OAAQ,CACJ,gBAAoB,2BACpB,mBAAoB,0BACxB,CACJ,EACA,QAAS,CACL,aAAc,oBAClB,EACA,YAAa,CACT,MAAe,CAAE,WAAY,oBAAqB,EAClD,KAAe,CAAE,WAAY,mBAAoB,EACjD,cAAe,CAAE,WAAY,mBAAoB,CACrD,EACA,gBAAiB,CACb,MAAU,oBACV,SAAU,0BACd,EACA,KAAM,CACF,MAAO,CACH,WAAY,2BACZ,OAAY,qBACZ,OAAY,kCAChB,EACA,SAAU,CACN,MAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAoB,EAC9E,QAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAmB,CACjF,EACA,iBAAkB,CACd,MAAO,mBACX,EACA,SAAU,CACN,WAAmB,2BACnB,OAAmB,2BACnB,iBAAmB,2BACnB,kBAAmB,yBACvB,CACJ,EACA,aAAc,CACV,WAAkB,2BAClB,OAAkB,sCAClB,iBAAkB,2BAClB,aAAkB,qCACtB,EACA,OAAQ,CACJ,YAAa,kBACjB,EAIA,MAAO,CACH,OAAQ,CACJ,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACJ,EACA,KAAW,qBACX,KAAW,qBACX,MAAW,kBACX,UAAW,SACf,CACJ,CAAC,EC3VY,EAAmB,EAAY,EAAW,CACnD,YAAa,OACb,KAAa,CAAE,MAAO,oBAAqB,EAC3C,KAAa,CAAE,WAAY,iBAAkB,EAC7C,OAAa,CAAE,MAAO,iBAAkB,EACxC,OAAa,CACT,WAAY,oDACZ,OAAY,kBACZ,OAAY,mCACZ,YAAa,CACT,WAAY,oBAChB,EACA,QAAY,CACR,WAAY,qBACZ,WAAY,oDACZ,OAAY,oCAChB,EACA,MAAY,CACR,WAAY,UACZ,WAAY,oDACZ,OAAY,mCAChB,EACA,KAAY,CACR,MAAS,CACL,WAAY,4BACZ,OAAY,2BAChB,EACA,QAAS,CACL,WAAY,4BACZ,OAAY,wCACZ,OAAY,2BAChB,CACJ,CACJ,EACA,OAAc,CACV,SAAU,CACN,WAAY,kBACZ,OAAY,wBAChB,CACJ,EACA,MAAQ,CACJ,WAAa,kBACb,OAAa,+BACb,YAAa,8BACjB,EACA,KAAQ,CACJ,WAAoB,kBACpB,OAAoB,qBACpB,MAAoB,qBACpB,mBAAoB,kBACpB,cAAoB,qBACpB,UAAoB,qBACpB,OAAU,CACN,mBAAoB,kBACpB,kBAAoB,qBACpB,gBAAoB,oBACxB,EACA,OAAU,CACN,gBAAuB,kBACvB,sBAAuB,qBACvB,gBAAuB,oBAC3B,EACA,SAAU,CACN,WAAyB,kBACzB,mBAAyB,qBACzB,wBAAyB,qBACzB,WAAyB,iBAC7B,EACA,MAAU,CACN,WAAoB,kBACpB,mBAAoB,qBACpB,SAAoB,iBACxB,CACJ,EACA,OAAQ,CAAE,WAAY,MAAO,EAC7B,SAAU,CACN,MAAQ,CAAE,WAAY,OAAQ,KAAM,MAAO,EAC3C,OAAQ,CAAE,MAAO,kBAAmB,CACxC,EACA,UAAW,CACP,OAAW,0BACX,OAAW,CACP,WAAY,+CACZ,OAAY,0BACZ,MAAY,SAChB,EACA,MAAW,CAAE,OAAQ,eAAgB,EACrC,UAAW,CAAE,MAAO,kBAAmB,CAC3C,EACA,IAAQ,CACJ,qBAAsB,GACtB,QAAS,CAAE,WAAY,UAAW,OAAQ,MAAO,EACjD,OAAS,CACL,WAAY,UACZ,OAAY,OACZ,MAAY,CAAE,WAAY,UAAoB,OAAQ,MAAO,EAC7D,SAAY,CAAE,WAAY,kBAAmB,OAAQ,MAAO,CAChE,EACA,UAAW,CAAE,MAAO,SAAU,CAClC,EACA,OAAY,CACR,OAAc,iCACd,SAAc,oCACd,QAAc,CACV,WAAkB,kBAClB,OAAkB,wBAClB,OAAkB,OAClB,gBAAkB,kBAClB,iBAAkB,iBACtB,EACA,OAAc,CAAE,WAAY,SAAU,CAC1C,EACA,MAAY,CACR,OAAQ,CACJ,WAAY,oDACZ,OAAQ,OACR,MAAQ,CAAE,MAAO,cAAe,CACpC,EACA,IAAQ,CACJ,SAAgB,2BAChB,eAAgB,0CAChB,IAAgB,yBAChB,MAAgB,yBAChB,OAAgB,4BACpB,EACA,KAAQ,CACJ,WAA4B,cAC5B,mBAA4B,4BAC5B,0BAA4B,yBAC5B,MAA4B,UAC5B,OAA4B,OAC5B,kBAA4B,yBAChC,EACA,UAAW,CACP,WAAY,yBAChB,EACA,aAAc,CACV,MAAQ,2BACZ,EACA,UAAW,CACP,WAAY,2BACZ,MAAY,SAChB,EASA,kBAAmB,CACf,WAAY,qBACZ,MAAY,iBAChB,CACJ,EACA,YAAa,CACT,WAAgB,kBAChB,OAAgB,kBAChB,OAAgB,iCAChB,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,oBACrB,EACA,eAAgB,iBACpB,EACA,QAAS,CAEL,WAAgB,kBAChB,OAAgB,kBAChB,OAAgB,CACZ,WAAiB,cACjB,gBAAiB,4BACjB,WAAiB,SACrB,EACA,MAAgB,CACZ,WAAY,kBACZ,OAAY,kBACZ,OAAY,gCAChB,EACA,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,qBACjB,cAAiB,oBACrB,EACA,eAAgB,iBACpB,EACA,UAAW,CACP,WAAY,kBACZ,MAAY,qBACZ,OAAY,iBAChB,EACA,QAAS,CACL,WAAgB,kBAChB,OAAgB,kBAChB,eAAgB,iBACpB,EACA,QAAS,CACL,WAAY,kBACZ,MAAY,qBACZ,OAAY,oBACZ,OAAY,gCAChB,EACA,QAAS,CACL,WAAY,kBACZ,MAAY,qBACZ,OAAY,mBACZ,OAAY,kCAChB,EACA,aAAc,CACV,OAAS,iCACT,KAAS,CAAE,WAAY,0BAA4B,OAAQ,mBAAqB,EAChF,QAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,EAChF,QAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,EAChF,MAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,CACpF,EACA,WAAY,CACR,MAAO,CACH,OAAS,mBACT,QAAS,CACL,WAAY,mBACZ,MAAY,qBACZ,OAAY,kBAChB,CACJ,CACJ,EACA,aAAc,CACV,WAAY,kBACZ,OAAY,kBACZ,OAAY,8BACZ,KAAM,CACF,gBAAqB,4BACrB,oBAAqB,4BACrB,eAAqB,qBACrB,cAAqB,oBACzB,CACJ,EAGA,KAAM,CACF,WAAY,kBACZ,OAAY,kBACZ,IAAK,CACD,gBAAoB,4BACpB,mBAAoB,4BACpB,cAAoB,qBACpB,UAAoB,qBACpB,cAAoB,qBACpB,UAAoB,aACxB,CACJ,EACA,UAAW,CACP,MAAW,qBACX,UAAW,+BACf,EAGA,OAAQ,CACJ,cAAwB,0BACxB,mBAAwB,4BACxB,uBAAwB,aAC5B,EACA,OAAQ,CACJ,SAAU,CAAE,WAAY,qBAAsB,EAC9C,OAAU,kBACV,OAAU,kCACV,QAAU,oBACV,OAAU,mBACV,KAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,EACpF,OAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,CACxF,EACA,OAAQ,CACJ,OAAY,iCACZ,OAAY,iBAChB,EACA,KAAM,CACF,OAAY,kBACZ,OAAY,iCACZ,OAAQ,CACJ,gBAAoB,4BACpB,mBAAoB,2BACxB,CACJ,EACA,QAAS,CACL,aAAc,iBAClB,EACA,YAAa,CACT,MAAe,CAAE,WAAY,iBAAkB,EAC/C,KAAe,CAAE,WAAY,mBAAoB,EACjD,cAAe,CAAE,WAAY,mBAAoB,CACrD,EACA,gBAAiB,CACb,MAAU,oBACV,SAAU,uBACd,EACA,KAAM,CACF,MAAO,CACH,WAAY,wBACZ,OAAY,qBACZ,OAAY,iCAChB,EACA,SAAU,CACN,MAAS,CAAE,WAAY,yBAA2B,OAAQ,kBAAoB,EAC9E,QAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAmB,CACjF,EACA,iBAAkB,CACd,MAAO,mBACX,EACA,SAAU,CACN,WAAmB,2BACnB,OAAmB,2BACnB,iBAAmB,2BACnB,kBAAmB,yBACvB,CACJ,EACA,aAAc,CACV,WAAkB,2BAClB,OAAkB,sCAClB,iBAAkB,2BAClB,aAAkB,qCACtB,EACA,OAAQ,CACJ,YAAa,kBACjB,EAIA,MAAO,CACH,OAAQ,CACJ,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACJ,EACA,KAAW,qBACX,KAAW,kBACX,MAAW,qBACX,UAAW,SACf,CACJ,CAAC,ECzTK,KAAN,cAA+D,CAAgB,CAE3E,UAAmD,KAKnD,YAAY,EAAoB,CAC5B,MAAM,EAAS,CAAE,IAAK,MAAO,CAAsB,EAKnD,KAAK,UAAY,GAAS,UAAY,KACtC,EAAM,YAAY,KAAM,SAAU,KAAK,YAAY,CACvD,CAQA,aAAqB,EAAsB,CACvC,EAAE,eAAe,EACjB,KAAK,YAAY,IAAI,CACzB,CAOA,eAAsB,CAClB,IAAM,EAAU,KAAK,WAAW,EAE3B,GAIL,EAAI,KAAK,cAAc,CAAO,CAClC,CACJ,EAEM,EAAe,EAAS,IAAI,EChDrB,EAAkB,qzBASzB,EAAqB,oBAcd,EAAb,MAAa,OAAQ,CAQjB,OAAe,MAAuB,KAkBtC,OAAO,QAAQ,EAAe,EAA0B,CACpD,GAAI,QAAQ,QAAU,KAGlB,OAFA,EAAI,KAAK,MAAM,QAAQ,MAAO,CAAE,QAAS,CAAE,MAAK,CAAE,CAAC,EAE5C,GAGX,IAAM,EAAO,EAAI,OAAO,QAAQ,EAEhC,GAAI,EAAI,OAAO,cAAc,EAAM,CAAkB,IAAM,KACvD,MAAO,GAGX,IAAM,EAAO,EAAI,KAAK,cAAc,MAAM,EAO1C,OALA,EAAI,KAAK,MAAM,EAAM,CAAE,QAAS,CAAE,IAAK,OAAQ,MAAK,CAAE,CAAC,EACvD,EAAI,KAAK,YAAY,EAAM,CAAI,EAE/B,QAAQ,MAAQ,EAET,EACX,CAUA,OAAO,QAAe,CAClB,QAAQ,MAAQ,IACpB,CACJ,ECjFa,EAAb,MAAa,aAAa,CAAuB,CAE7C,OAAwB,SAAiB,IAAI,KAU7C,OAAO,aAAc,CACjB,OAAO,KAAK,QAChB,CA0BA,OAAO,KAAK,EAAuB,CAAC,EAAS,CAoBzC,OAnBA,KAAK,SAAS,uBAAuB,EACrC,KAAK,SAAS,aAAa,CAAO,EAM9B,EAAQ,UAAY,IAAA,IACpB,KAAK,SAAS,WAAW,CAAe,EAOxC,EAAQ,oBAAsB,IAAA,IAC9B,KAAK,SAAS,qBAAqB,EAAK,EAGrC,KAAK,QAChB,CAGA,aAAuB,EAA4B,CAM/C,OALA,MAAM,aAAa,CAAO,EAEtB,EAAQ,UAAY,IAAA,IAAW,KAAK,WAAW,EAAQ,OAAO,EAC9D,EAAQ,oBAAsB,IAAA,IAAW,KAAK,qBAAqB,EAAQ,iBAAiB,EAEzF,IACX,CAaA,WAAW,EAA+B,CAOtC,MANA,MAAK,SAAS,QAAU,EAEpB,IAAY,IACZ,EAAQ,QAAQ,CAAO,EAGpB,IACX,CAQA,YAA6B,CACzB,OAAO,KAAK,SAAS,SAAW,CACpC,CAUA,qBAAqB,EAAwB,CAGzC,IAAM,EAAY,KAAK,SAAS,oBAAsB,GAUtD,MARA,MAAK,SAAS,kBAAoB,EAE9B,CAAC,GAAW,CAAC,EACb,EAAM,oBAAoB,KAAM,cAAe,KAAK,aAAa,EAC1D,GAAW,GAClB,EAAM,uBAAuB,KAAM,cAAe,KAAK,aAAa,EAGjE,IACX,CAQA,sBAAgC,CAC5B,OAAO,KAAK,SAAS,mBAAqB,EAC9C,CAEA,aAAsB,CAClB,MAAM,CAAE,IAAK,MAAO,CAAC,EAErB,KAAK,KAAK,EAEV,KAAK,mBAAmB,0CAA0C,EAElE,EAAa,SAAS,CAAW,CACrC,CAOA,YAAa,CACT,OAAO,EAAI,OAAO,QAAQ,CAC9B,CAOA,MAAuB,CASnB,OARA,MAAM,KAAK,EAEX,KAAK,QAAQ,EAAI,OAAO,gBAAgB,CAAC,EACzC,KAAK,YAAY,EAEjB,EAAM,oBAAoB,KAAM,SAAU,KAAK,iBAAiB,EAChE,KAAK,eAAe,KAAK,cAAc,EAEhC,IACX,CAOA,sBAAwC,CACpC,KAAK,QAAQ,EAAI,OAAO,gBAAgB,CAAC,CAC7C,EAeA,eAA8C,CAC1C,MAAO,CAAE,QAAS,EAAK,CAC3B,CAQA,mBAAqC,CACjC,KAAK,eAAe,CACxB,EAgBA,qBAAyC,CACrC,MAAO,EACX,CACJ,ECxNM,EAA8B,GAG9B,EAA8C,CAAE,KAAM,cAAgB,IAAK,EAAK,EAChF,EAA8C,CAAE,KAAM,eAAgB,IAAK,EAAK,EAKhF,EAAoB,IAAI,EACxB,EAAa,IAAI,EAKnB,EAAqB,CAAC,EAEtB,EAAiB,GACjB,EAAoB,GAGpB,EAAuB,GACvB,EAAmB,EACnB,EAAiC,EACjC,EAAiC,EAMrC,SAAS,OAAO,EAAyB,CACrC,GAAI,CACA,OAAO,EAAI,OAAO,YAAY,CAAM,CACxC,MAAQ,CACJ,MAAO,EACX,CACJ,CAQA,SAAS,YAAmB,CACxB,IAAM,EAAiB,CAAC,EACpB,EAAW,GAEf,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACtC,IAAM,EAAS,EAAS,GAEpB,OAAO,CAAM,IACb,EAAK,KAAK,CAAM,EAEZ,GAAK,IACL,EAAW,EAAK,OAAS,GAGrC,CAEA,EAAW,EACX,EAAS,CACb,CAGA,SAAS,YAAmB,CACxB,IAAM,EAA6B,CAC/B,UAAc,EAAS,EACvB,aAAc,EAAS,EAAS,OAAS,CAC7C,EAEA,EAAW,KAAK,SAAU,CAAM,CACpC,CAMA,SAAS,OAAO,EAAsB,CAC9B,QAAU,GAAK,EAAS,KAAY,GAOxC,KAHA,EAAS,OAAS,EAAS,EAC3B,EAAS,KAAK,CAAM,EAEb,EAAS,OAAS,GACrB,EAAS,MAAM,EAGnB,EAAS,EAAS,OAAS,EAC3B,WAAW,CAJQ,CAKvB,CAGA,SAAS,WAAW,EAAsB,CACtC,EAAc,GACd,EAAI,KAAK,MAAM,CAAM,EACrB,EAAc,GACd,WAAW,CACf,CAQA,SAAS,SAAS,EAA4B,CAC1C,WAAW,EAEX,IAAM,EAAS,EAAS,EASxB,OAPI,EAAS,GAAK,GAAU,EAAS,OAC1B,IAGX,EAAS,EACT,WAAW,EAAS,EAAO,EAEpB,GACX,CAGA,SAAS,aAAa,EAAkB,EAAsC,CAC1E,OAAO,EAAE,OAAS,EAAM,MACpB,EAAE,SAAW,CAAC,CAAC,EAAM,KAAO,EAAE,UAAY,CAAC,CAAC,EAAM,MAClD,EAAE,WAAa,CAAC,CAAC,EAAM,OAAS,EAAE,UAAY,CAAC,CAAC,EAAM,IAC9D,CAGA,SAAS,UAAU,EAAqB,CAChC,CAAC,GAAY,GAIZ,EAAI,OAAO,UAAU,EAAE,MAAM,GAIlC,OAAO,EAAI,OAAO,OAAO,EAAE,MAAM,CAAC,CACtC,CAWA,SAAS,UAAU,EAAwC,CACvD,GAAI,CAAC,EACD,OAGJ,IAAM,EAAwB,aAAa,EAAG,CAAK,EAAI,GAAK,gBAAa,EAAG,CAAQ,EAEpF,GAAI,IAAc,EACd,OAGJ,IAAM,EAAM,EAAa,YAAY,EAEjC,QAAO,EAAI,eAAe,IAAM,SAMpC,OAFA,SAAS,CAAS,EAEX,CAAE,KAAM,GAAM,QAAS,EAAK,CACvC,CAWO,IAAU,GAAV,SAAA,EAAA,CASI,SAAS,OAAO,EAAqC,CAKxD,GAJI,GACA,UAAU,CAAO,EAGjB,EACA,OAGJ,EAAW,GAEX,EAAM,oBAAoB,EAAQ,UAAW,SAAS,EACtD,EAAM,oBAAoB,EAAQ,UAAW,SAAS,EAEtD,IAAM,EAAS,EAAI,OAAO,iBAAiB,EAEvC,IAAW,MACX,OAAO,CAAM,CAErB,iBAMO,SAAS,SAAgB,CACvB,IAIL,EAAW,GACX,EAAc,GAEd,EAAM,uBAAuB,EAAQ,UAAW,SAAS,EACzD,EAAM,uBAAuB,EAAQ,UAAW,SAAS,EAC7D,mBAGO,SAAS,WAAqB,CACjC,OAAO,CACX,uBAQO,SAAS,UAAU,EAAoC,CACtD,EAAQ,UAAY,IAAA,KACpB,EAAW,EAAQ,SAGnB,EAAQ,OAAS,IAAA,KACjB,EAAQ,EAAQ,MAGhB,EAAQ,UAAY,IAAA,KACpB,EAAW,EAAQ,QAE3B,uBAQO,SAAS,MAAgB,CAC5B,OAAO,SAAS,EAAE,CACtB,aAQO,SAAS,SAAmB,CAC/B,OAAO,SAAS,CAAC,CACrB,mBAMO,SAAS,WAAqB,CAGjC,OAFA,WAAW,EAEJ,EAAS,CACpB,uBAMO,SAAS,cAAwB,CAGpC,OAFA,WAAW,EAEJ,EAAS,EAAS,OAAS,CACtC,6BAGO,SAAS,OAAc,CAC1B,EAAW,CAAC,EACZ,EAAS,GACT,WAAW,CACf,eASO,SAAS,GAAG,EAAiB,EAAsD,CACtF,EAAW,IAAI,EAAO,CAAQ,CAClC,SAQO,SAAS,IAAI,EAAiB,EAAsD,CACvF,EAAW,OAAO,EAAO,CAAQ,CACrC,UACH,EAAA,CAAA,AAAA,IAAA,CAAA,CAAD,ECzTA,IAAa,QAAb,cAA6B,CAAW,CAEpC,QAAsC,KACtC,SAA4C,IAAI,IAChD,WAAgD,IAAI,EACpD,mBAAiE,IAAI,IACrE,wBAA2C,GAC3C,SAA4B,GAsB5B,KAAQ,EAAmB,EAAiC,EAAuC,CAC/F,KAAK,OAAO,CAAS,EAErB,IAAM,EAA6B,GAAa,CAC5C,QAAe,EAA0B,SAAS,EAClD,IAAS,GAAU,EAA0B,SAAS,CAAC,EACvD,OAAS,GAAQ,EAA0B,GAAG,UAAW,CAAE,CAC/D,EAEM,EAAoB,CAAE,UAAW,EAAK,OAAQ,EAAK,EAwBzD,OAvBA,KAAK,SAAS,IAAI,EAAW,CAAK,EAElC,EAAI,WAAa,CAKb,GAJI,KAAK,UAIL,CAAC,EAAM,QAAU,CAAC,KAAK,QACvB,OAGJ,IAAM,EAAQ,EAAI,IAAI,EACtB,KAAK,QAAQ,IAAI,EAAW,CAAK,EAEjC,KAAK,KAAK,SAAU,EAAW,CAAK,EAEpC,KAAK,qBAAqB,CAAS,CACvC,CAAC,EAEG,KAAK,SACL,EAAI,IAAI,KAAK,QAAQ,IAAI,CAAS,CAAC,EAGhC,IACX,CAQA,OAAO,EAAyB,CAC5B,IAAM,EAAQ,KAAK,SAAS,IAAI,CAAS,EAOzC,OANI,IACA,EAAM,OAAS,GAEf,KAAK,SAAS,OAAO,CAAS,GAG3B,IACX,CAeA,UAAU,EAAkC,CACxC,IAAK,IAAM,KAAM,KAAK,WAAW,IAAI,cAAc,EAC/C,GAAI,EAAG,CAAM,IAAM,GACf,OAAO,KAQf,GAJA,KAAK,QAAU,EAEf,KAAK,gBAAgB,EAEjB,CAAC,EACD,OAAO,KAGX,KAAK,SAAW,GAEhB,GAAI,CACA,IAAK,GAAM,CAAC,EAAW,KAAU,KAAK,SAClC,EAAM,UAAU,IAAI,EAAO,IAAI,CAAS,CAAC,CAEjD,QAAU,CACN,KAAK,SAAW,EACpB,CAEA,IAAK,GAAM,CAAC,KAAc,KAAK,mBAC3B,KAAK,qBAAqB,CAAS,EAGvC,OAAO,IACX,CAKA,WAAgC,CAC5B,OAAO,KAAK,OAChB,CAQA,QAAe,CAKX,OAJA,KAAK,SAAS,OAAO,EAErB,KAAK,KAAK,QAAQ,EAEX,IACX,CAOA,QAAe,CAGX,GAFA,KAAK,SAAS,OAAO,EAEjB,KAAK,QACL,IAAK,GAAM,CAAC,EAAW,KAAU,KAAK,SAClC,EAAM,UAAU,IAAI,KAAK,QAAQ,IAAI,CAAS,CAAC,EAIvD,KAAK,gBAAgB,EAErB,KAAK,KAAK,QAAQ,CACtB,CA+BA,GAAG,EAAuB,EAA0B,CAGhD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAWA,IAAI,EAAqB,EAA0B,CAG/C,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAaA,KAAe,EAAqB,GAAG,EAA0B,CAC7D,KAAK,WAAW,KAAK,EAAO,GAAG,CAAO,CAC1C,CAaA,cAAc,EAAmB,EAAsB,EAAgD,CACnG,IAAM,EAAY,MAAM,QAAQ,CAAK,EAAI,EAAQ,CAAC,CAAK,EASvD,OAPA,KAAK,mBAAmB,IAAI,EAAW,CACnC,MAAkB,EAClB,YACA,iBAAkB,GAClB,UAAkB,IACtB,CAAC,EAEM,IACX,CASA,iBAAiB,EAAyB,CACtC,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAQpD,OANI,GAAQ,WACR,EAAO,UAAU,WAAW,EAGhC,KAAK,mBAAmB,OAAO,CAAS,EAEjC,IACX,CAQA,UAAoB,CAChB,IAAI,EAAW,GAEf,IAAK,GAAM,CAAC,KAAc,KAAK,mBACb,KAAK,eAAe,CAE7B,IACD,EAAW,IAInB,OAAO,CACX,CAOA,oBAAoB,EAAwB,CAGxC,MAFA,MAAK,wBAA0B,EAExB,IACX,CAOA,qBAA+B,CAC3B,OAAO,KAAK,uBAChB,CAMA,iBAAwB,CACpB,IAAK,GAAM,EAAG,KAAW,KAAK,mBACtB,EAAO,WACP,EAAO,UAAU,WAAW,EAIpC,OAAO,IACX,CASA,eAAuB,EAA4B,CAC/C,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAEpD,GAAI,CAAC,EACD,MAAO,GAGX,IAAM,EAAQ,KAAK,SAAS,IAAI,CAAS,EACnC,EAAQ,EAAQ,EAAM,UAAU,IAAI,EAAI,IAAA,GAE9C,IAAK,IAAM,KAAQ,EAAO,MAAO,CAC7B,IAAM,EAAS,EAAU,EAAM,CAAK,EAEhC,MAAO,MAIX,IAAI,CAAC,EAAO,UAAW,CACnB,IAAM,EAAS,EAAO,UAAU,mBAAmB,EAE/C,IACA,EAAO,UAAY,IAAI,EAAe,EAAO,UAAW,CAAM,EAEtE,CAIA,OAFA,EAAO,WAAW,UAAU,EAAO,OAAO,EAEnC,EAJP,CAKJ,CAIA,OAFA,EAAO,WAAW,WAAW,EAEtB,EACX,CAOA,qBAA6B,EAAyB,CAClD,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAE/C,IAIQ,EAAO,kBAAoB,KAAK,0BAGzC,KAAK,eAAe,CAAS,CAErC,CACJ"}
@@ -1,2 +1,2 @@
1
- import{a as e,c as t,d as n,f as r,i,l as a,n as o,o as s,r as c,s as l,t as u,u as d}from"./MemoryStore-DT6iWWco.js";var AjaxError=class extends Error{status;statusText;body;operation;url;constructor(e,t,n,r){super(`AjaxProxy: ${e} failed with status ${n.status}`),this.name=`AjaxError`,this.status=n.status,this.statusText=n.statusText,this.body=r,this.operation=e,this.url=t}},f=`data`,p=`total`,JsonReader=class{_root;_rootProperty;_totalProperty;_mode;constructor(e){this._root=e?.root,this._rootProperty=e?.rootProperty??f,this._totalProperty=e?.totalProperty??p,this._mode=e?.mode??`auto`}read(e,t){if(this._mode===`detect`){let t=this._root?e?.[this._root]:e;return Array.isArray(t)?this.readArray(e):this.readEnvelope(e)}return this._mode===`envelope`||this._mode===`auto`&&t?this.readEnvelope(e):this.readArray(e)}readEnvelope(e){let t=this._root?e[this._root]:e;if(typeof t!=`object`||!t)throw Error(`AjaxProxy: paginated response is not an envelope object — if the server returns a top-level array, set mode:'array'`);let n=t[this._rootProperty],r=t[this._totalProperty];if(!Array.isArray(n))throw Error(`AjaxProxy: paginated response 'data' is not an array`);return{records:n,total:typeof r==`number`?r:void 0,success:typeof t.success==`boolean`?t.success:void 0,message:typeof t.message==`string`?t.message:void 0}}readArray(e){if(this._root){let t=e[this._root];if(!Array.isArray(t))throw Error(`AjaxProxy: root '${this._root}' did not resolve to an array`);return{records:t}}if(!Array.isArray(e))throw Error(`AjaxProxy: response is not an array and no root was specified — if the server returns a { data, total } envelope, set mode:'detect' (or mode:'envelope' / a rootProperty), or enable pagination with setPageSize()`);return{records:e}}},JsonWriter=class{_mode;constructor(e){this._mode=e?.mode??`full`}writeRecord(e,t){return JSON.stringify(this.dataFor(e,t))}writeRecords(e,t){return JSON.stringify(e.map(e=>this.dataFor(e,t)))}dataFor(e,t){return this._mode===`dirty`&&t===`update`?e.getChangedData():e.getData()}},AjaxProxy=class extends c{_url;_root;_method;_createMethod;_updateMethod;_headers;_reader;_writer;_lastTotalCount=void 0;constructor(e){super(),this._url=e.url,this._root=e.root,this._method=e.method??`GET`,this._createMethod=e.createMethod??`POST`,this._updateMethod=e.updateMethod??`PUT`,this._headers=e.headers??{},this._reader=e.reader??new JsonReader({root:e.root,mode:e.readMode}),this._writer=e.writer??new JsonWriter({mode:e.writeMode}),e.batch===!1&&this.disableBatch()}disableBatch(){let e=this;e.createBatch=void 0,e.updateBatch=void 0,e.destroyBatch=void 0}async read(e){let t=e!=null&&(e.page!=null||e.pageSize!=null),n=this.buildReadUrl(e),r=await fetch(n,{method:this._method,headers:this._headers,signal:e?.signal});r.ok||await this.throwHttpError(r,`read`,n);let i=await r.json(),a=this._reader.read(i,t);return this._lastTotalCount=a.total,a.records}buildReadUrl(e){if(e==null)return this._url;let t=new URLSearchParams;e.page!=null&&t.set(`page`,String(e.page)),e.pageSize!=null&&t.set(`pageSize`,String(e.pageSize)),e.sorters!=null&&e.sorters.length>0&&t.set(`sort`,JSON.stringify(e.sorters)),e.filters!=null&&e.filters.length>0&&t.set(`filter`,JSON.stringify(e.filters));let n=t.toString();if(n===``)return this._url;let r=this._url.includes(`?`)?`&`:`?`;return this._url+r+n}getLastTotalCount(){return this._lastTotalCount}async create(e){let t=await fetch(this._url,{method:this._createMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecord(e,`create`)});t.ok||await this.throwHttpError(t,`create`,this._url);let n=await t.json();return this._root?n[this._root]:n}async update(e){let t=await fetch(`${this._url}/${e.getId()}`,{method:this._updateMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecord(e,`update`)});t.ok||await this.throwHttpError(t,`update`,`${this._url}/${e.getId()}`);let n=await t.json();return this._root?n[this._root]:n}async destroy(e){let t=await fetch(`${this._url}/${e.getId()}`,{method:`DELETE`,headers:this._headers});t.ok||await this.throwHttpError(t,`destroy`,`${this._url}/${e.getId()}`)}async createBatch(e){let t=await fetch(this._url,{method:this._createMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e,`create`)});return t.ok||await this.throwHttpError(t,`create`,this._url),this.readBatchResponse(t)}async updateBatch(e){let t=await fetch(this._url,{method:this._updateMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e,`update`)});return t.ok||await this.throwHttpError(t,`update`,this._url),this.readBatchResponse(t)}async destroyBatch(e){let t=await fetch(this._url,{method:`DELETE`,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e)});t.ok||await this.throwHttpError(t,`destroy`,this._url)}async readBatchResponse(e){let t=await e.json();return this._root?t[this._root]:t}async throwHttpError(e,t,n){let r;try{r=await e.json()}catch{try{r=await e.text()}catch{r=void 0}}throw new AjaxError(t,n,e,r)}},AjaxStore=class extends n{model;proxy;constructor(e,t){if(super(),e instanceof i){if(!t)throw Error(`AjaxStore requires an AjaxProxyOptions argument when constructed with a Model.`);this.model=e,this.proxy=new AjaxProxy(t)}else this.model=e.model,this.proxy=new AjaxProxy(e.proxy),this.applyOptions(e)}},TreeNode=class{_store;_record;_parent;_children=[];_depth;_leaf=!1;_loaded=!0;constructor(e,t,n,r){this._store=e,this._record=t,this._parent=n,this._depth=r}getRecord(){return this._record}getId(){return this._record?this._record.get(this._store.getIdField()):void 0}getParent(){return this._parent}getChildren(){return this._children}getDepth(){return this._depth}isExpanded(){return this._store.isExpanded(this)}isLeaf(){return this._leaf}isLoaded(){return this._loaded}setChildren(e){this._children=e}setLeaf(e){this._leaf=e}setLoaded(e){this._loaded=e}},TreeStore=class extends n{model;proxy;_idField;_parentField;_leafField;_hasChildrenField;_childrenKey;_root;_nodesById=new Map;_childRecords=new Map;_expandedIds=new Set;_loadingIds=new Set;_loadedIds=new Set;_visibleNodes=[];constructor(e){super(),this.model=e.model,this.proxy=e.proxy,this._parentField=e.parentField,this._idField=e.idField??this.model.getPrimaryKeyField()?.getName()??`id`,this._leafField=e.leafField,this._hasChildrenField=e.hasChildrenField,this._childrenKey=e.childrenKey,this._root=new TreeNode(this,null,null,-1),this.applyOptions(e)}getIdField(){return this._idField}getParentField(){return this._parentField}loadData(e){super.loadData(this._childrenKey?this.flattenNested(e):e)}applyView(){let e=super.applyView();return this.rebuildNodeIndex(),this.flatten(),e.then(()=>{this.rebuildNodeIndex(),this.flatten()})}flattenNested(e){let t=this.model.getField(this._idField)?.getMapping()??this._idField,n=this.model.getField(this._parentField)?.getMapping()??this._parentField,r=[],walk=(e,i)=>{for(let a of e){let e=a[this._childrenKey],o={...a};delete o[this._childrenKey],i!=null&&o[n]==null&&(o[n]=i),r.push(o),Array.isArray(e)&&e.length>0&&walk(e,o[t])}};return walk(e,null),r}rebuildNodeIndex(){let e=this.getRecords();this.bucketChildRecords(e),this._nodesById.clear(),this._root.setChildren(this.buildChildNodes(null,this._root,0))}bucketChildRecords(e){this._childRecords.clear();let t=new Set;for(let n of e)t.add(n.get(this._idField));for(let n of e){let e=n.get(this._parentField),r=e!=null&&t.has(e)?e:null,i=this._childRecords.get(r);i?i.push(n):this._childRecords.set(r,[n])}}buildChildNodes(e,t,n){return(this._childRecords.get(e)??[]).map(e=>{let r=e.get(this._idField),i=new TreeNode(this,e,t,n);return i.setLeaf(this.resolveLeaf(e,r)),i.setLoaded(this.resolveLoaded(r)),this._nodesById.set(r,i),i.setChildren(this.buildChildNodes(r,i,n+1)),i})}resolveLoaded(e){if(!this._hasChildrenField||this._loadedIds.has(e))return!0;let t=this._childRecords.get(e);return!!t&&t.length>0}resolveLeaf(e,t){if(this._leafField)return e.get(this._leafField)===!0;if(this._hasChildrenField)return e.get(this._hasChildrenField)!==!0;let n=this._childRecords.get(t);return!n||n.length===0}flatten(){let e=[],recurse=t=>{for(let n of t)e.push(n),this._expandedIds.has(n.getId())&&recurse(n.getChildren())};recurse(this._root.getChildren()),this._visibleNodes=e}getRootNode(){return this._root}getNodeById(e){return this._nodesById.get(e)}getNodeForRecord(e){return this._nodesById.get(e.get(this._idField))}getChildren(e){return e.getChildren()}getParent(e){return e.getParent()}getDepth(e){return e.getDepth()}eachNode(e){let recurse=t=>{for(let n of t)e(n),recurse(n.getChildren())};recurse(this._root.getChildren())}getVisibleNodes(){return this._visibleNodes.slice()}getVisibleCount(){return this._visibleNodes.length}async expand(e){let t=e.getId();this._expandedIds.has(t)||e.isLeaf()||!e.isLoaded()&&this.proxy&&!await this.loadChildren(t)||(this._expandedIds.add(t),this.flatten(),this.emit(`expand`,{node:e}))}async loadChildren(e){if(e==null||this._loadingIds.has(e))return!1;this._loadingIds.add(e);try{let t={filters:[{type:`eq`,field:this._parentField,value:e}]},n=await this.proxy.read(t);this._loadedIds.add(e),this.appendRecords(n.map(e=>this.model.createRecord(e)));let r=this.getNodeById(e);return r&&this.emit(`append`,{parent:r,nodes:r.getChildren()}),!0}finally{this._loadingIds.delete(e)}}collapse(e){let t=e.getId();this._expandedIds.has(t)&&(this._expandedIds.delete(t),this.flatten(),this.emit(`collapse`,{node:e}))}toggle(e){return this._expandedIds.has(e.getId())?(this.collapse(e),Promise.resolve()):this.expand(e)}isExpanded(e){return this._expandedIds.has(e.getId())}expandToDepth(e){this.eachNode(t=>{!t.isLeaf()&&t.getDepth()<=e&&this._expandedIds.add(t.getId())}),this.flatten()}collapseAll(){this._expandedIds.clear(),this.flatten()}on(e,t){return super.on(e,t)}off(e,t){return super.off(e,t)}emit(e,t){super.emit(e,t)}onTree(e,t){return this.on(e,t)}},WebStorageProxy=class extends c{_key;_storage;constructor(e){super(),this._key=e.key,this._storage=e.storage===`session`?sessionStorage:localStorage,e.data!==void 0&&this._storage.getItem(this._key)===null&&this.writeAll(e.data)}read(e){return Promise.resolve(this.readAll())}create(e){let t=this.readAll(),n={...e.getData()},r=e.getModel().getPrimaryKeyField()?.getName();return r!==void 0&&e.getId()===void 0&&(n[r]=this.nextId(t,r)),t.push(n),this.writeAll(t),Promise.resolve(n)}update(e){let t=this.readAll(),n={...e.getData()},r=e.getModel().getPrimaryKeyField()?.getName();if(r!==void 0){let i=e.getId(),a=t.findIndex(e=>e[r]===i);a!==-1&&(t[a]=n,this.writeAll(t))}return Promise.resolve(n)}destroy(e){let t=this.readAll(),n=e.getModel().getPrimaryKeyField()?.getName();if(n!==void 0){let r=e.getId(),i=t.findIndex(e=>e[n]===r);i!==-1&&(t.splice(i,1),this.writeAll(t))}return Promise.resolve()}readAll(){let e=this._storage.getItem(this._key);if(e===null)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}writeAll(e){this._storage.setItem(this._key,JSON.stringify(e))}nextId(e,t){let n=0;for(let r of e){let e=r[t];typeof e==`number`&&e>n&&(n=e)}return n+1}};export{e as AbstractModel,n as AbstractStore,AjaxError,AjaxProxy,AjaxStore,s as Association,l as BelongsToAssociation,r as Field,t as HasManyAssociation,JsonReader,JsonWriter,o as MemoryProxy,u as MemoryStore,i as Model,a as ModelRecord,c as Proxy,d as Store,TreeNode,TreeStore,WebStorageProxy};
1
+ import{a as e,c as t,d as n,i as r,l as i,n as a,o,p as s,r as c,s as l,t as u,u as d}from"./MemoryStore-DhPoU-7X.js";var AjaxError=class extends Error{status;statusText;body;operation;url;constructor(e,t,n,r){super(`AjaxProxy: ${e} failed with status ${n.status}`),this.name=`AjaxError`,this.status=n.status,this.statusText=n.statusText,this.body=r,this.operation=e,this.url=t}},f=`data`,p=`total`,JsonReader=class{_root;_rootProperty;_totalProperty;_mode;constructor(e){this._root=e?.root,this._rootProperty=e?.rootProperty??f,this._totalProperty=e?.totalProperty??p,this._mode=e?.mode??`auto`}read(e,t){if(this._mode===`detect`){let t=this._root?e?.[this._root]:e;return Array.isArray(t)?this.readArray(e):this.readEnvelope(e)}return this._mode===`envelope`||this._mode===`auto`&&t?this.readEnvelope(e):this.readArray(e)}readEnvelope(e){let t=this._root?e[this._root]:e;if(typeof t!=`object`||!t)throw Error(`AjaxProxy: paginated response is not an envelope object — if the server returns a top-level array, set mode:'array'`);let n=t[this._rootProperty],r=t[this._totalProperty];if(!Array.isArray(n))throw Error(`AjaxProxy: paginated response 'data' is not an array`);return{records:n,total:typeof r==`number`?r:void 0,success:typeof t.success==`boolean`?t.success:void 0,message:typeof t.message==`string`?t.message:void 0}}readArray(e){if(this._root){let t=e[this._root];if(!Array.isArray(t))throw Error(`AjaxProxy: root '${this._root}' did not resolve to an array`);return{records:t}}if(!Array.isArray(e))throw Error(`AjaxProxy: response is not an array and no root was specified — if the server returns a { data, total } envelope, set mode:'detect' (or mode:'envelope' / a rootProperty), or enable pagination with setPageSize()`);return{records:e}}},JsonWriter=class{_mode;constructor(e){this._mode=e?.mode??`full`}writeRecord(e,t){return JSON.stringify(this.dataFor(e,t))}writeRecords(e,t){return JSON.stringify(e.map(e=>this.dataFor(e,t)))}dataFor(e,t){return this._mode===`dirty`&&t===`update`?e.getChangedData():e.getData()}},AjaxProxy=class extends c{_url;_root;_method;_createMethod;_updateMethod;_headers;_reader;_writer;_lastTotalCount=void 0;constructor(e){super(),this._url=e.url,this._root=e.root,this._method=e.method??`GET`,this._createMethod=e.createMethod??`POST`,this._updateMethod=e.updateMethod??`PUT`,this._headers=e.headers??{},this._reader=e.reader??new JsonReader({root:e.root,mode:e.readMode}),this._writer=e.writer??new JsonWriter({mode:e.writeMode}),e.batch===!1&&this.disableBatch()}disableBatch(){let e=this;e.createBatch=void 0,e.updateBatch=void 0,e.destroyBatch=void 0}async read(e){let t=e!=null&&(e.page!=null||e.pageSize!=null),n=this.buildReadUrl(e),r=await fetch(n,{method:this._method,headers:this._headers,signal:e?.signal});r.ok||await this.throwHttpError(r,`read`,n);let i=await r.json(),a=this._reader.read(i,t);return this._lastTotalCount=a.total,a.records}buildReadUrl(e){if(e==null)return this._url;let t=new URLSearchParams;e.page!=null&&t.set(`page`,String(e.page)),e.pageSize!=null&&t.set(`pageSize`,String(e.pageSize)),e.sorters!=null&&e.sorters.length>0&&t.set(`sort`,JSON.stringify(e.sorters)),e.filters!=null&&e.filters.length>0&&t.set(`filter`,JSON.stringify(e.filters));let n=t.toString();if(n===``)return this._url;let r=this._url.includes(`?`)?`&`:`?`;return this._url+r+n}getLastTotalCount(){return this._lastTotalCount}async create(e){let t=await fetch(this._url,{method:this._createMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecord(e,`create`)});t.ok||await this.throwHttpError(t,`create`,this._url);let n=await t.json();return this._root?n[this._root]:n}async update(e){let t=await fetch(`${this._url}/${e.getId()}`,{method:this._updateMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecord(e,`update`)});t.ok||await this.throwHttpError(t,`update`,`${this._url}/${e.getId()}`);let n=await t.json();return this._root?n[this._root]:n}async destroy(e){let t=await fetch(`${this._url}/${e.getId()}`,{method:`DELETE`,headers:this._headers});t.ok||await this.throwHttpError(t,`destroy`,`${this._url}/${e.getId()}`)}async createBatch(e){let t=await fetch(this._url,{method:this._createMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e,`create`)});return t.ok||await this.throwHttpError(t,`create`,this._url),this.readBatchResponse(t)}async updateBatch(e){let t=await fetch(this._url,{method:this._updateMethod,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e,`update`)});return t.ok||await this.throwHttpError(t,`update`,this._url),this.readBatchResponse(t)}async destroyBatch(e){let t=await fetch(this._url,{method:`DELETE`,headers:{"Content-Type":`application/json`,...this._headers},body:this._writer.writeRecords(e)});t.ok||await this.throwHttpError(t,`destroy`,this._url)}async readBatchResponse(e){let t=await e.json();return this._root?t[this._root]:t}async throwHttpError(e,t,n){let r;try{r=await e.json()}catch{try{r=await e.text()}catch{r=void 0}}throw new AjaxError(t,n,e,r)}},AjaxStore=class extends n{model;proxy;constructor(e,t){if(super(),e instanceof r){if(!t)throw Error(`AjaxStore requires an AjaxProxyOptions argument when constructed with a Model.`);this.model=e,this.proxy=new AjaxProxy(t)}else this.model=e.model,this.proxy=new AjaxProxy(e.proxy),this.applyOptions(e)}},TreeNode=class{_store;_record;_parent;_children=[];_depth;_leaf=!1;_loaded=!0;constructor(e,t,n,r){this._store=e,this._record=t,this._parent=n,this._depth=r}getRecord(){return this._record}getId(){return this._record?this._record.get(this._store.getIdField()):void 0}getParent(){return this._parent}getChildren(){return this._children}getDepth(){return this._depth}isExpanded(){return this._store.isExpanded(this)}isLeaf(){return this._leaf}isLoaded(){return this._loaded}setChildren(e){this._children=e}setLeaf(e){this._leaf=e}setLoaded(e){this._loaded=e}},TreeStore=class extends n{model;proxy;_idField;_parentField;_leafField;_hasChildrenField;_childrenKey;_root;_nodesById=new Map;_childRecords=new Map;_expandedIds=new Set;_loadingIds=new Set;_loadedIds=new Set;_visibleNodes=[];constructor(e){super(),this.model=e.model,this.proxy=e.proxy,this._parentField=e.parentField,this._idField=e.idField??this.model.getPrimaryKeyField()?.getName()??`id`,this._leafField=e.leafField,this._hasChildrenField=e.hasChildrenField,this._childrenKey=e.childrenKey,this._root=new TreeNode(this,null,null,-1),this.applyOptions(e)}getIdField(){return this._idField}getParentField(){return this._parentField}loadData(e){super.loadData(this._childrenKey?this.flattenNested(e):e)}applyView(){let e=super.applyView();return this.rebuildNodeIndex(),this.flatten(),e.then(()=>{this.rebuildNodeIndex(),this.flatten()})}flattenNested(e){let t=this.model.getField(this._idField)?.getMapping()??this._idField,n=this.model.getField(this._parentField)?.getMapping()??this._parentField,r=[],walk=(e,i)=>{for(let a of e){let e=a[this._childrenKey],o={...a};delete o[this._childrenKey],i!=null&&o[n]==null&&(o[n]=i),r.push(o),Array.isArray(e)&&e.length>0&&walk(e,o[t])}};return walk(e,null),r}rebuildNodeIndex(){let e=this.getRecords();this.bucketChildRecords(e),this._nodesById.clear(),this._root.setChildren(this.buildChildNodes(null,this._root,0))}bucketChildRecords(e){this._childRecords.clear();let t=new Set;for(let n of e)t.add(n.get(this._idField));for(let n of e){let e=n.get(this._parentField),r=e!=null&&t.has(e)?e:null,i=this._childRecords.get(r);i?i.push(n):this._childRecords.set(r,[n])}}buildChildNodes(e,t,n){return(this._childRecords.get(e)??[]).map(e=>{let r=e.get(this._idField),i=new TreeNode(this,e,t,n);return i.setLeaf(this.resolveLeaf(e,r)),i.setLoaded(this.resolveLoaded(r)),this._nodesById.set(r,i),i.setChildren(this.buildChildNodes(r,i,n+1)),i})}resolveLoaded(e){if(!this._hasChildrenField||this._loadedIds.has(e))return!0;let t=this._childRecords.get(e);return!!t&&t.length>0}resolveLeaf(e,t){if(this._leafField)return e.get(this._leafField)===!0;if(this._hasChildrenField)return e.get(this._hasChildrenField)!==!0;let n=this._childRecords.get(t);return!n||n.length===0}flatten(){let e=[],recurse=t=>{for(let n of t)e.push(n),this._expandedIds.has(n.getId())&&recurse(n.getChildren())};recurse(this._root.getChildren()),this._visibleNodes=e}getRootNode(){return this._root}getNodeById(e){return this._nodesById.get(e)}getNodeForRecord(e){return this._nodesById.get(e.get(this._idField))}getChildren(e){return e.getChildren()}getParent(e){return e.getParent()}getDepth(e){return e.getDepth()}eachNode(e){let recurse=t=>{for(let n of t)e(n),recurse(n.getChildren())};recurse(this._root.getChildren())}getVisibleNodes(){return this._visibleNodes.slice()}getVisibleCount(){return this._visibleNodes.length}async expand(e){let t=e.getId();this._expandedIds.has(t)||e.isLeaf()||!e.isLoaded()&&this.proxy&&!await this.loadChildren(t)||(this._expandedIds.add(t),this.flatten(),this.emit(`expand`,{node:e}))}async loadChildren(e){if(e==null||this._loadingIds.has(e))return!1;this._loadingIds.add(e);try{let t={filters:[{type:`eq`,field:this._parentField,value:e}]},n=await this.proxy.read(t);this._loadedIds.add(e),this.appendRecords(n.map(e=>this.model.createRecord(e)));let r=this.getNodeById(e);return r&&this.emit(`append`,{parent:r,nodes:r.getChildren()}),!0}finally{this._loadingIds.delete(e)}}collapse(e){let t=e.getId();this._expandedIds.has(t)&&(this._expandedIds.delete(t),this.flatten(),this.emit(`collapse`,{node:e}))}toggle(e){return this._expandedIds.has(e.getId())?(this.collapse(e),Promise.resolve()):this.expand(e)}isExpanded(e){return this._expandedIds.has(e.getId())}expandToDepth(e){this.eachNode(t=>{!t.isLeaf()&&t.getDepth()<=e&&this._expandedIds.add(t.getId())}),this.flatten()}collapseAll(){this._expandedIds.clear(),this.flatten()}on(e,t){return super.on(e,t)}off(e,t){return super.off(e,t)}emit(e,t){super.emit(e,t)}onTree(e,t){return this.on(e,t)}},WebStorageProxy=class extends c{_key;_storage;constructor(e){super(),this._key=e.key,this._storage=e.storage===`session`?sessionStorage:localStorage,e.data!==void 0&&this._storage.getItem(this._key)===null&&this.writeAll(e.data)}read(e){return Promise.resolve(this.readAll())}create(e){let t=this.readAll(),n={...e.getData()},r=e.getModel().getPrimaryKeyField()?.getName();return r!==void 0&&e.getId()===void 0&&(n[r]=this.nextId(t,r)),t.push(n),this.writeAll(t),Promise.resolve(n)}update(e){let t=this.readAll(),n={...e.getData()},r=e.getModel().getPrimaryKeyField()?.getName();if(r!==void 0){let i=e.getId(),a=t.findIndex(e=>e[r]===i);a!==-1&&(t[a]=n,this.writeAll(t))}return Promise.resolve(n)}destroy(e){let t=this.readAll(),n=e.getModel().getPrimaryKeyField()?.getName();if(n!==void 0){let r=e.getId(),i=t.findIndex(e=>e[n]===r);i!==-1&&(t.splice(i,1),this.writeAll(t))}return Promise.resolve()}readAll(){let e=this._storage.getItem(this._key);if(e===null)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}writeAll(e){this._storage.setItem(this._key,JSON.stringify(e))}nextId(e,t){let n=0;for(let r of e){let e=r[t];typeof e==`number`&&e>n&&(n=e)}return n+1}};export{e as AbstractModel,n as AbstractStore,AjaxError,AjaxProxy,AjaxStore,o as Association,l as BelongsToAssociation,s as Field,t as HasManyAssociation,JsonReader,JsonWriter,a as MemoryProxy,u as MemoryStore,r as Model,i as ModelRecord,c as Proxy,d as Store,TreeNode,TreeStore,WebStorageProxy};
2
2
  //# sourceMappingURL=data.es.js.map