@ixfx/components 0.4.3 → 0.5.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 (239) hide show
  1. package/bundle/index.d.ts +518 -1176
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +4861 -17274
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +1 -1
  6. package/dist/ac-text.d.ts +12 -7
  7. package/dist/ac-text.d.ts.map +1 -1
  8. package/dist/ac-text.js +2 -3
  9. package/dist/ac-text.js.map +1 -1
  10. package/dist/{button-C3fLMKUv.js → button-DxYee1ZH.js} +2 -2
  11. package/dist/{button-C3fLMKUv.js.map → button-DxYee1ZH.js.map} +1 -1
  12. package/dist/button.d.ts +1 -2
  13. package/dist/button.d.ts.map +1 -1
  14. package/dist/button.js +1 -2
  15. package/dist/checkbox.d.ts +0 -1
  16. package/dist/checkbox.d.ts.map +1 -1
  17. package/dist/checkbox.js +1 -1
  18. package/dist/checkbox.js.map +1 -1
  19. package/dist/{colour-picker-0sgAha1T.js → colour-picker-C3Ag4uh-.js} +15 -17
  20. package/dist/colour-picker-C3Ag4uh-.js.map +1 -0
  21. package/dist/colour-picker.d.ts +1 -1
  22. package/dist/colour-picker.js +1 -1
  23. package/dist/crumbs.d.ts +5 -2
  24. package/dist/crumbs.d.ts.map +1 -1
  25. package/dist/crumbs.js +45 -20
  26. package/dist/crumbs.js.map +1 -1
  27. package/dist/data-display.d.ts +1 -2
  28. package/dist/data-display.d.ts.map +1 -1
  29. package/dist/data-display.js +25 -23
  30. package/dist/data-display.js.map +1 -1
  31. package/dist/{data-provider-DgI909FP.js → data-provider-35TyWclX.js} +2 -2
  32. package/dist/data-provider-35TyWclX.js.map +1 -0
  33. package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
  34. package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
  35. package/dist/{defaults-C3b9OWJD.js → defaults-DcE8RQJc.js} +19 -1
  36. package/dist/defaults-DcE8RQJc.js.map +1 -0
  37. package/dist/editable-label.d.ts +1 -2
  38. package/dist/editable-label.d.ts.map +1 -1
  39. package/dist/editable-label.js +1 -1
  40. package/dist/editable-label.js.map +1 -1
  41. package/dist/{hex-editor-WZrjRtvL.js → hex-editor-Bk6rxhfg.js} +9 -11
  42. package/dist/hex-editor-Bk6rxhfg.js.map +1 -0
  43. package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
  44. package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
  45. package/dist/hex.d.ts +1 -1
  46. package/dist/hex.js +1 -1
  47. package/dist/highlight-B-eQrhhb.js.map +1 -1
  48. package/dist/{icon-Ndo40kNO.js → icon-B22XVlCt.js} +6 -4
  49. package/dist/{icon-Ndo40kNO.js.map → icon-B22XVlCt.js.map} +1 -1
  50. package/dist/{icon-Bd5BiU4b.d.ts → icon-DpA9x2Ve.d.ts} +2 -3
  51. package/dist/icon-DpA9x2Ve.d.ts.map +1 -0
  52. package/dist/icons.d.ts +2 -2
  53. package/dist/icons.js +2 -2
  54. package/dist/{incr-search-CeERfijK.js → incr-search-2pz21xtR.js} +9 -6
  55. package/dist/incr-search-2pz21xtR.js.map +1 -0
  56. package/dist/incr-search.d.ts +1 -1
  57. package/dist/incr-search.js +1 -1
  58. package/dist/{index-CowKi2mo.d.ts → index-BeuCXtiO.d.ts} +3 -4
  59. package/dist/index-BeuCXtiO.d.ts.map +1 -0
  60. package/dist/{index-D87kRcEs.d.ts → index-BtGFYfaK.d.ts} +2 -1
  61. package/dist/index-BtGFYfaK.d.ts.map +1 -0
  62. package/dist/{index-s_IhSnwc.d.ts → index-CoqtMSd9.d.ts} +6 -4
  63. package/dist/index-CoqtMSd9.d.ts.map +1 -0
  64. package/dist/{index-9fGVAg1d.d.ts → index-Cxwxtj6g.d.ts} +3 -3
  65. package/dist/index-Cxwxtj6g.d.ts.map +1 -0
  66. package/dist/index-D_ftz_IT.d.ts +184 -0
  67. package/dist/index-D_ftz_IT.d.ts.map +1 -0
  68. package/dist/{index-_RTQSKHi.d.ts → index-DfEkTGvT.d.ts} +11 -11
  69. package/dist/index-DfEkTGvT.d.ts.map +1 -0
  70. package/dist/index.d.ts +167 -29
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +712 -2970
  73. package/dist/index.js.map +1 -1
  74. package/dist/keyboard-B5xD7Fz-.js +36 -0
  75. package/dist/keyboard-B5xD7Fz-.js.map +1 -0
  76. package/dist/{labelled-input-base-ORb1rGq6.d.ts → labelled-input-base-DiTme1JO.d.ts} +1 -2
  77. package/dist/labelled-input-base-DiTme1JO.d.ts.map +1 -0
  78. package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
  79. package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
  80. package/dist/labelled-radial-input.d.ts +5 -4
  81. package/dist/labelled-radial-input.d.ts.map +1 -1
  82. package/dist/labelled-radial-input.js +7 -3
  83. package/dist/labelled-radial-input.js.map +1 -1
  84. package/dist/labelled-range-input.d.ts +1 -1
  85. package/dist/labelled-range-input.js +27 -3
  86. package/dist/labelled-range-input.js.map +1 -1
  87. package/dist/led.d.ts +1 -2
  88. package/dist/led.d.ts.map +1 -1
  89. package/dist/led.js +1 -1
  90. package/dist/led.js.map +1 -1
  91. package/dist/{menu-vjoiHZ13.js → menu-g6yd7ddN.js} +8 -9
  92. package/dist/menu-g6yd7ddN.js.map +1 -0
  93. package/dist/{menu-item-COx-Azgj.d.ts → menu-item-DSyf9f_L.d.ts} +4 -4
  94. package/dist/menu-item-DSyf9f_L.d.ts.map +1 -0
  95. package/dist/{menu-item-BrIuORYD.js → menu-item-NUKwJ4s5.js} +3 -4
  96. package/dist/{menu-item-BrIuORYD.js.map → menu-item-NUKwJ4s5.js.map} +1 -1
  97. package/dist/menu.d.ts +2 -2
  98. package/dist/menu.js +2 -2
  99. package/dist/miller.d.ts +8 -5
  100. package/dist/miller.d.ts.map +1 -1
  101. package/dist/miller.js +22 -24
  102. package/dist/miller.js.map +1 -1
  103. package/dist/narrowed-text.d.ts +7 -3
  104. package/dist/narrowed-text.d.ts.map +1 -1
  105. package/dist/narrowed-text.js +73 -47
  106. package/dist/narrowed-text.js.map +1 -1
  107. package/dist/panel.d.ts +1 -1
  108. package/dist/panel.d.ts.map +1 -1
  109. package/dist/panel.js +2 -2
  110. package/dist/panel.js.map +1 -1
  111. package/dist/plots.d.ts +2 -2
  112. package/dist/plots.js +1 -1
  113. package/dist/polar-pad.d.ts +15 -3
  114. package/dist/polar-pad.d.ts.map +1 -1
  115. package/dist/polar-pad.js +64 -11
  116. package/dist/polar-pad.js.map +1 -1
  117. package/dist/{radial-input-CpQPs1Mp.d.ts → radial-input-BhZeyyP-.d.ts} +6 -4
  118. package/dist/radial-input-BhZeyyP-.d.ts.map +1 -0
  119. package/dist/{radial-input-DZ7eQCcM.js → radial-input-DxCrt_NE.js} +41 -19
  120. package/dist/radial-input-DxCrt_NE.js.map +1 -0
  121. package/dist/radial-input.d.ts +1 -1
  122. package/dist/radial-input.js +1 -1
  123. package/dist/range-input.d.ts +15 -4
  124. package/dist/range-input.d.ts.map +1 -1
  125. package/dist/range-input.js +23 -2
  126. package/dist/range-input.js.map +1 -1
  127. package/dist/range.d.ts +15 -4
  128. package/dist/range.d.ts.map +1 -1
  129. package/dist/range.js +23 -2
  130. package/dist/range.js.map +1 -1
  131. package/dist/selecthorizontal.d.ts +1 -2
  132. package/dist/selecthorizontal.d.ts.map +1 -1
  133. package/dist/selecthorizontal.js +1 -1
  134. package/dist/selecthorizontal.js.map +1 -1
  135. package/dist/slider-input-DFpG23bS.js +1592 -0
  136. package/dist/slider-input-DFpG23bS.js.map +1 -0
  137. package/dist/slider-input-TidGhvXt.d.ts +160 -0
  138. package/dist/slider-input-TidGhvXt.d.ts.map +1 -0
  139. package/dist/slider-input.d.ts +2 -0
  140. package/dist/slider-input.js +2 -0
  141. package/dist/snap-container.d.ts +1 -2
  142. package/dist/snap-container.d.ts.map +1 -1
  143. package/dist/snap-container.js +6 -5
  144. package/dist/snap-container.js.map +1 -1
  145. package/dist/split-layout.d.ts +1 -2
  146. package/dist/split-layout.d.ts.map +1 -1
  147. package/dist/split-layout.js +6 -4
  148. package/dist/split-layout.js.map +1 -1
  149. package/dist/style.css +1 -1
  150. package/dist/swipe.d.ts +12 -2
  151. package/dist/swipe.d.ts.map +1 -1
  152. package/dist/swipe.js +22 -3
  153. package/dist/swipe.js.map +1 -1
  154. package/dist/{tab-list-DLzb-m-I.d.ts → tab-list-BohmbvqF.d.ts} +14 -5
  155. package/dist/tab-list-BohmbvqF.d.ts.map +1 -0
  156. package/dist/tab-list-DhkVhRQc.js +597 -0
  157. package/dist/tab-list-DhkVhRQc.js.map +1 -0
  158. package/dist/tabs.d.ts +2 -2
  159. package/dist/tabs.js +1 -208
  160. package/dist/{tickled-controller-BjYCzGrU.d.ts → tickled-controller-BF2Ea0DE.d.ts} +2 -31
  161. package/dist/tickled-controller-BF2Ea0DE.d.ts.map +1 -0
  162. package/dist/tickled-styles-fNDdqf6l.js.map +1 -1
  163. package/dist/{timeline-2OFtN4Ta.js → timeline-B2fgDL4U.js} +37 -1438
  164. package/dist/timeline-B2fgDL4U.js.map +1 -0
  165. package/dist/timeline.d.ts +1 -1
  166. package/dist/timeline.js +1 -1
  167. package/dist/{tooltip-RGVIwHrZ.d.ts → tooltip-BlvBUQxx.d.ts} +3 -3
  168. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
  169. package/dist/{tree-D84RUgFC.js → tree-BnvzhsAw.js} +8 -9
  170. package/dist/tree-BnvzhsAw.js.map +1 -0
  171. package/dist/{tree-component-BaCSPWg1.d.ts → tree-component-DCmmKZ4j.d.ts} +8 -124
  172. package/dist/tree-component-DCmmKZ4j.d.ts.map +1 -0
  173. package/dist/tree.d.ts +10 -4
  174. package/dist/tree.d.ts.map +1 -1
  175. package/dist/tree.js +1 -1
  176. package/dist/types-DO3gt5vg.d.ts +130 -0
  177. package/dist/types-DO3gt5vg.d.ts.map +1 -0
  178. package/dist/wheel-nudge-BlSCe_hD.js +86 -0
  179. package/dist/wheel-nudge-BlSCe_hD.js.map +1 -0
  180. package/dist/wheel-nudge-DgMTRYlh.d.ts +29 -0
  181. package/dist/wheel-nudge-DgMTRYlh.d.ts.map +1 -0
  182. package/dist/{xy-axis-BeWRMmbo.d.ts → xy-axis-5KhVTNoX.d.ts} +30 -7
  183. package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
  184. package/dist/xy-axis-CxHC8z5E.js +1849 -0
  185. package/dist/xy-axis-CxHC8z5E.js.map +1 -0
  186. package/dist/xy-pad.d.ts +13 -2
  187. package/dist/xy-pad.d.ts.map +1 -1
  188. package/dist/xy-pad.js +47 -6
  189. package/dist/xy-pad.js.map +1 -1
  190. package/docs-user/README.md +2 -0
  191. package/docs-user/button.md +48 -0
  192. package/docs-user/narrowed-text.md +33 -1
  193. package/docs-user/notifier.md +131 -0
  194. package/docs-user/plots.md +61 -1
  195. package/docs-user/radial-input.md +2 -2
  196. package/docs-user/slider-input.md +673 -0
  197. package/docs-user/tabs.md +12 -14
  198. package/docs-user/user-catalog.md +69 -4
  199. package/docs-user/vertical-list.md +75 -7
  200. package/package.json +23 -20
  201. package/dist/colour-C3MQIjFJ-vRCdr8W-.js +0 -3732
  202. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +0 -1
  203. package/dist/colour-picker-0sgAha1T.js.map +0 -1
  204. package/dist/data-provider-DgI909FP.js.map +0 -1
  205. package/dist/defaults-C3b9OWJD.js.map +0 -1
  206. package/dist/dist-CA13FvMn.js +0 -980
  207. package/dist/dist-CA13FvMn.js.map +0 -1
  208. package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
  209. package/dist/hex-editor-WZrjRtvL.js.map +0 -1
  210. package/dist/icon-Bd5BiU4b.d.ts.map +0 -1
  211. package/dist/incr-search-CeERfijK.js.map +0 -1
  212. package/dist/index-9fGVAg1d.d.ts.map +0 -1
  213. package/dist/index-CowKi2mo.d.ts.map +0 -1
  214. package/dist/index-D87kRcEs.d.ts.map +0 -1
  215. package/dist/index-DgXpCg_G.d.ts +0 -1244
  216. package/dist/index-DgXpCg_G.d.ts.map +0 -1
  217. package/dist/index-_RTQSKHi.d.ts.map +0 -1
  218. package/dist/index-s_IhSnwc.d.ts.map +0 -1
  219. package/dist/keyboard-CimiEskD.js +0 -20
  220. package/dist/keyboard-CimiEskD.js.map +0 -1
  221. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +0 -1
  222. package/dist/menu-item-COx-Azgj.d.ts.map +0 -1
  223. package/dist/menu-vjoiHZ13.js.map +0 -1
  224. package/dist/radial-input-CpQPs1Mp.d.ts.map +0 -1
  225. package/dist/radial-input-DZ7eQCcM.js.map +0 -1
  226. package/dist/tab-list-DLzb-m-I.d.ts.map +0 -1
  227. package/dist/tabs.js.map +0 -1
  228. package/dist/tickled-controller-BjYCzGrU.d.ts.map +0 -1
  229. package/dist/timeline-2OFtN4Ta.js.map +0 -1
  230. package/dist/tooltip-RGVIwHrZ.d.ts.map +0 -1
  231. package/dist/tree-D84RUgFC.js.map +0 -1
  232. package/dist/tree-component-BaCSPWg1.d.ts.map +0 -1
  233. package/dist/types-DSfbtHs3.d.ts +0 -8
  234. package/dist/types-DSfbtHs3.d.ts.map +0 -1
  235. package/dist/xy-axis-BeWRMmbo.d.ts.map +0 -1
  236. package/dist/xy-axis-no0OL_O1.js +0 -7893
  237. package/dist/xy-axis-no0OL_O1.js.map +0 -1
  238. /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
  239. /package/dist/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
package/dist/index.js CHANGED
@@ -1,52 +1,54 @@
1
1
  import { n as buildHighlightTargets, r as clearHighlights, t as applyHighlights } from "./highlight-B-eQrhhb.js";
2
2
  import { n as tickledStyles, r as TickledController, t as tickledItemStyles } from "./tickled-styles-fNDdqf6l.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-pNMOMx38.js";
4
- import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
4
+ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
5
  import { a as svgToDataUri, i as registerIcon, n as hasIcon, r as iconBus, t as getIcon } from "./registry-CkW7q09Q.js";
6
- import { t as IxfxIconElement } from "./icon-Ndo40kNO.js";
6
+ import { t as IxfxIconElement } from "./icon-B22XVlCt.js";
7
7
  import { AcTextElement } from "./ac-text.js";
8
- import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-CeERfijK.js";
9
- import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-C3b9OWJD.js";
8
+ import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-2pz21xtR.js";
9
+ import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-DcE8RQJc.js";
10
10
  import "./icons.js";
11
11
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
12
- import { n as buttonStyles, t as ButtonElement } from "./button-C3fLMKUv.js";
12
+ import { n as buttonStyles, t as ButtonElement } from "./button-DxYee1ZH.js";
13
13
  import { t as popupSurfaceStyles } from "./popup-DiWMxsWj.js";
14
- import "./menu-item-BrIuORYD.js";
14
+ import "./menu-item-NUKwJ4s5.js";
15
15
  import { Checkbox } from "./checkbox.js";
16
- import { _ as isEqualValueDefault, a as PlotDataSeries, c as parseColourScaleAttr, d as QueueMutable, f as isPrimitive, g as isEqualDefault, h as defaultComparer, i as PlotMultiAxis, l as readBaseColour, m as __exportAll, n as PlotSingleAxis, o as applyAgeModification, p as toStringAbbreviate, r as PlotHistogram, s as computeColour, t as PlotXyAxis, u as last, v as isEqualValueIgnoreOrder } from "./xy-axis-no0OL_O1.js";
17
- import { C as resultThrow, T as throwIfFailed, d as scaler, h as without, n as clamper, p as containsDuplicateInstances, y as nullUndefTest } from "./dist-CA13FvMn.js";
18
- import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-0sgAha1T.js";
16
+ import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-C3Ag4uh-.js";
19
17
  import { LabelledRangeInput } from "./labelled-range-input.js";
20
- import { t as collectDataResult } from "./data-provider-DgI909FP.js";
21
- import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-D84RUgFC.js";
18
+ import { t as collectDataResult } from "./data-provider-35TyWclX.js";
19
+ import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-BnvzhsAw.js";
22
20
  import { NarrowedTextElement } from "./narrowed-text.js";
23
21
  import { CrumbNavigationElement } from "./crumbs.js";
24
22
  import { DataDisplayComponent } from "./data-display.js";
25
23
  import { EditableLabel } from "./editable-label.js";
26
- import { t as resolveStep } from "./keyboard-CimiEskD.js";
24
+ import { t as resolveAxisStep } from "./keyboard-B5xD7Fz-.js";
25
+ import { t as WheelNudgeMixin } from "./wheel-nudge-BlSCe_hD.js";
27
26
  import { PanelElement } from "./panel.js";
28
- import { t as IxfxHexEditorElement } from "./hex-editor-WZrjRtvL.js";
29
- import { t as RadialInputElement } from "./radial-input-DZ7eQCcM.js";
27
+ import { t as IxfxHexEditorElement } from "./hex-editor-Bk6rxhfg.js";
28
+ import { t as RadialInputElement } from "./radial-input-DxCrt_NE.js";
30
29
  import { LabelledRadialInput } from "./labelled-radial-input.js";
31
30
  import { LedElement } from "./led.js";
32
- import { t as menu_exports } from "./menu-vjoiHZ13.js";
31
+ import { t as menu_exports } from "./menu-g6yd7ddN.js";
33
32
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
33
+ import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-CxHC8z5E.js";
34
34
  import { PolarPad } from "./polar-pad.js";
35
35
  import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
36
36
  import { RangeInput } from "./range-input.js";
37
37
  import { RangeElement } from "./range.js";
38
38
  import { SelectHorizontalElement } from "./selecthorizontal.js";
39
+ import { t as SliderInputElement } from "./slider-input-DFpG23bS.js";
39
40
  import { SnapContainer } from "./snap-container.js";
40
41
  import { SplitLayoutElement } from "./split-layout.js";
41
42
  import { SwipeElement } from "./swipe.js";
42
- import { TabListElement } from "./tabs.js";
43
- import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-2OFtN4Ta.js";
43
+ import { t as TabListElement } from "./tab-list-DhkVhRQc.js";
44
+ import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-B2fgDL4U.js";
44
45
  import { XyPad } from "./xy-pad.js";
45
- import { LitElement, css, html, nothing } from "lit";
46
+ import { LitElement, css, html, nothing, render } from "lit";
46
47
  import { eventOptions, property, query, queryAssignedElements, state } from "lit/decorators.js";
47
48
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
49
+ import { Trees } from "@ixfx/collections";
50
+ import { clamper, scaler } from "@ixfx/numbers";
48
51
  import { repeat } from "lit/directives/repeat.js";
49
- import { classMap } from "lit/directives/class-map.js";
50
52
  import { keyed } from "lit/directives/keyed.js";
51
53
  //#region src/common/data-controller.ts
52
54
  function isAsyncIterable(v) {
@@ -451,7 +453,6 @@ let AcTokenElement = class AcTokenElement extends LitElement {
451
453
  e.preventDefault();
452
454
  this.#closePopup();
453
455
  this._selectedTokenIndex = void 0;
454
- break;
455
456
  }
456
457
  }
457
458
  #onPaste;
@@ -569,9 +570,10 @@ let AcTokenElement = class AcTokenElement extends LitElement {
569
570
  });
570
571
  }
571
572
  #renderChip(item, index) {
573
+ const isSelected = this._selectedTokenIndex === index;
572
574
  return html`
573
575
  <span
574
- class="token-chip ${this._selectedTokenIndex === index ? `selected` : ``}"
576
+ class="token-chip ${isSelected ? `selected` : ``}"
575
577
  title=${item.subLabel ?? nothing}
576
578
  @pointerdown=${(e) => this.#onChipPointerDown(e, index)}
577
579
  >
@@ -999,9 +1001,11 @@ let RadioGroup = class RadioGroup extends LitElement {
999
1001
  min-width: min-content;
1000
1002
  box-sizing: border-box;
1001
1003
  /* Default to looking like a cohesive control group */
1002
- background: var(--surface-3, transparent);
1004
+ background: var(--surface-4, transparent);
1005
+ background: oklch(from var(--surface-4) l calc(c*0.2) h / 0.4);
1006
+
1003
1007
  border: var(--border, none);
1004
- border-radius: var(--radius-m, 4px);
1008
+ border-radius: var(--radius-xl, 8px);
1005
1009
  }
1006
1010
 
1007
1011
  * {
@@ -1031,6 +1035,7 @@ let RadioGroup = class RadioGroup extends LitElement {
1031
1035
  gap: var(--item-spacing, 0);
1032
1036
  overflow: hidden;
1033
1037
  border-radius: inherit;
1038
+ justify-content: center;
1034
1039
  }
1035
1040
 
1036
1041
  .radio-group.horizontal {
@@ -1072,13 +1077,13 @@ let RadioGroup = class RadioGroup extends LitElement {
1072
1077
 
1073
1078
  .radio-item:hover:not([disabled]) {
1074
1079
  opacity: 0.9;
1075
- background: var(--surface-4, rgba(255,255,255,0.05));
1080
+ background: color-mix(in oklch, var(--surface-4) 80%, transparent);
1076
1081
  }
1077
1082
 
1078
1083
  .radio-item.selected {
1079
1084
  font-weight: bold;
1080
1085
  color: var(--color-fg-accent, var(--surface-2-text));
1081
- background: var(--surface-6, rgba(255,255,255,0.1));
1086
+ background: var(--surface-5, rgba(255,255,255,0.1));
1082
1087
  }
1083
1088
 
1084
1089
  .radio-item[disabled] {
@@ -1540,2757 +1545,28 @@ let SplitButton = class SplitButton extends ButtonElement {
1540
1545
  align-items: stretch;
1541
1546
  }
1542
1547
  `
1543
- ];
1544
- }
1545
- };
1546
- __decorate([property({ attribute: false })], SplitButton.prototype, "registry", void 0);
1547
- __decorate([property({ attribute: false })], SplitButton.prototype, "keyboardManager", void 0);
1548
- __decorate([property({ type: String })], SplitButton.prototype, "mode", void 0);
1549
- __decorate([property({
1550
- type: String,
1551
- attribute: `default-value`
1552
- })], SplitButton.prototype, "defaultValue", void 0);
1553
- __decorate([property({ attribute: false })], SplitButton.prototype, "itemsProvider", void 0);
1554
- __decorate([property({ attribute: false })], SplitButton.prototype, "items", void 0);
1555
- __decorate([query(`ixfx-menu-trigger`)], SplitButton.prototype, "_menuTrigger", void 0);
1556
- __decorate([state()], SplitButton.prototype, "_compact", void 0);
1557
- __decorate([state()], SplitButton.prototype, "_selectedCommand", void 0);
1558
- __decorate([state()], SplitButton.prototype, "_selectedLabel", void 0);
1559
- __decorate([state()], SplitButton.prototype, "_selectedIcon", void 0);
1560
- __decorate([state()], SplitButton.prototype, "_switcherItems", void 0);
1561
- __decorate([state()], SplitButton.prototype, "_dynamicItems", void 0);
1562
- __decorate([state()], SplitButton.prototype, "_loadingItems", void 0);
1563
- __decorate([state()], SplitButton.prototype, "_menuHasItems", void 0);
1564
- SplitButton = __decorate([safeCustomElement(`ixfx-split-button`)], SplitButton);
1565
- //#endregion
1566
- //#region node_modules/.pnpm/@ixfx+collections@0.56.13/node_modules/@ixfx/collections/dist/StackMutable-B9Qm32K8.js
1567
- const trimStack = (opts, stack, toAdd) => {
1568
- const potentialLength = stack.length + toAdd.length;
1569
- const policy = opts.discardPolicy ?? `additions`;
1570
- const capacity = opts.capacity ?? potentialLength;
1571
- const toRemove = potentialLength - capacity;
1572
- if (opts.debug) console.log(`Stack.push: stackLen: ${stack.length} potentialLen: ${potentialLength} toRemove: ${toRemove} policy: ${policy}`);
1573
- switch (policy) {
1574
- case `additions`:
1575
- if (opts.debug) console.log(`Stack.push:DiscardAdditions: stackLen: ${stack.length} slice: ${potentialLength - capacity} toAddLen: ${toAdd.length}`);
1576
- if (stack.length === opts.capacity) return stack;
1577
- else return [...stack, ...toAdd.slice(0, toAdd.length - toRemove)];
1578
- case `newer`: {
1579
- if (toAdd.length >= capacity) return toAdd.slice(toAdd.length - capacity);
1580
- const keepFromOld = capacity - toAdd.length;
1581
- return [...stack.slice(0, keepFromOld), ...toAdd];
1582
- }
1583
- case `older`: return [...stack, ...toAdd].slice(toRemove);
1584
- default: throw new Error(`Unknown discard policy ${policy}`);
1585
- }
1586
- };
1587
- const push = (opts, stack, ...toAdd) => {
1588
- const potentialLength = stack.length + toAdd.length;
1589
- return opts.capacity && potentialLength > opts.capacity ? trimStack(opts, stack, toAdd) : [...stack, ...toAdd];
1590
- };
1591
- const pop = (opts, stack) => {
1592
- if (stack.length === 0) throw new Error(`Stack is empty`);
1593
- return stack.slice(0, -1);
1594
- };
1595
- /**
1596
- * Peek at the top of the stack (end of array)
1597
- *
1598
- * @typeParam V - Type of stored items
1599
- * @param {StackOpts} opts
1600
- * @param {V[]} stack
1601
- * @returns {(V | undefined)}
1602
- */
1603
- const peek = (opts, stack) => stack.at(-1);
1604
- const isEmpty = (opts, stack) => stack.length === 0;
1605
- const isFull = (opts, stack) => {
1606
- if (opts.capacity) return stack.length >= opts.capacity;
1607
- return false;
1608
- };
1609
- /**
1610
- * Creates a stack. Mutable. Use {@link StackImmutable} for an immutable alternative.
1611
- *
1612
- * @example Basic usage
1613
- * ```js
1614
- * // Create
1615
- * const s = new StackMutable();
1616
- * // Add one or more items
1617
- * s.push(1, 2, 3, 4);
1618
- *
1619
- * // See what's on top
1620
- * s.peek; // 4
1621
- *
1622
- * // Remove the top-most, and return it
1623
- * s.pop(); // 4
1624
- *
1625
- * // Now there's a new top-most element
1626
- * s.peek; // 3
1627
- * ```
1628
- */
1629
- var StackMutable = class {
1630
- opts;
1631
- data;
1632
- /**
1633
- * Create a new StackMutable.
1634
- *
1635
- * @param opts Options
1636
- * @param data Initial data to use
1637
- */
1638
- constructor(opts = {}, data = []) {
1639
- this.opts = opts;
1640
- this.data = data;
1641
- }
1642
- /**
1643
- * Push data onto the stack.
1644
- * If `toAdd` is empty, nothing happens
1645
- * @param toAdd Data to add
1646
- * @returns Length of stack
1647
- */
1648
- push(...toAdd) {
1649
- if (toAdd.length === 0) return this.data.length;
1650
- this.data = push(this.opts, this.data, ...toAdd);
1651
- return this.data.length;
1652
- }
1653
- /**
1654
- * Iterate from bottom to top. Note that `forEachFromTop` iterates from top to bottom, so this is the reverse.
1655
- * @param fn
1656
- */
1657
- forEach(fn) {
1658
- this.data.forEach(fn);
1659
- }
1660
- /**
1661
- * Iterate from top to bottom. Note that `forEach` iterates from bottom to top, so this is the reverse.
1662
- * @param fn
1663
- */
1664
- forEachFromTop(fn) {
1665
- [...this.data].reverse().forEach(fn);
1666
- }
1667
- /**
1668
- * Pop the top-most item from the stack, and return it. If the stack is empty, returns _undefined_.
1669
- * @returns
1670
- */
1671
- pop() {
1672
- const v = peek(this.opts, this.data);
1673
- this.data = pop(this.opts, this.data);
1674
- return v;
1675
- }
1676
- /**
1677
- * Returns _true_ if the stack is empty, _false_ otherwise.
1678
- */
1679
- get isEmpty() {
1680
- return isEmpty(this.opts, this.data);
1681
- }
1682
- /**
1683
- * Returns _true_ if the stack is full, _false_ otherwise. Note that a stack is only full if a `maxSize` option was provided at construction time.
1684
- */
1685
- get isFull() {
1686
- return isFull(this.opts, this.data);
1687
- }
1688
- /**
1689
- * Returns the top-most item on the stack, without modifying the stack. If the stack is empty, returns _undefined_.
1690
- */
1691
- get peek() {
1692
- return peek(this.opts, this.data);
1693
- }
1694
- /**
1695
- * Returns the number of items currently on the stack.
1696
- */
1697
- get length() {
1698
- return this.data.length;
1699
- }
1700
- };
1701
- //#endregion
1702
- //#region node_modules/.pnpm/@ixfx+collections@0.56.13/node_modules/@ixfx/collections/dist/tree-C6jGRTgK.js
1703
- const compare$1 = (a, b, eq = isEqualValueIgnoreOrder, parent) => {
1704
- const valueEqual = valueOrIdentityEqual(a, b, eq);
1705
- const childrenCompare = compareChildren(a, b, eq);
1706
- const diff = {
1707
- valueChanged: !valueEqual,
1708
- a,
1709
- b,
1710
- added: childrenCompare.added,
1711
- removed: childrenCompare.removed,
1712
- childChanged: false
1713
- };
1714
- const diffNode = {
1715
- value: diff,
1716
- childrenStore: [],
1717
- parent
1718
- };
1719
- const childrenDiff = childrenCompare.identical.map((c) => compare$1(c[0], c[1], eq, diffNode));
1720
- const someChildChange = hasChange(diff) || childrenDiff.some((v) => hasChange(v.value));
1721
- setChildren(diffNode, childrenDiff);
1722
- diffNode.toString = () => toString$1(diffNode, 0);
1723
- diffNode.value.childChanged = someChildChange;
1724
- throwTreeTest(diffNode);
1725
- return diffNode;
1726
- };
1727
- const hasChange = (vv) => {
1728
- if (vv === void 0) return false;
1729
- if (vv.valueChanged) return true;
1730
- if (vv.childChanged) return true;
1731
- if (vv.added.length > 0) return true;
1732
- if (vv.removed.length > 0) return true;
1733
- return false;
1734
- };
1735
- const compareChildren = (a, b, eq = isEqualValueIgnoreOrder) => {
1736
- const childrenOfA = [...a.children()];
1737
- const childrenOfB = [...b.children()];
1738
- const identical = [];
1739
- const removed = [];
1740
- for (const childA of childrenOfA) {
1741
- let foundIndex = -1;
1742
- for (const [index, childOfB] of childrenOfB.entries()) if (valueOrIdentityEqual(childA, childOfB, eq)) {
1743
- identical.push([childA, childOfB]);
1744
- foundIndex = index;
1745
- break;
1746
- }
1747
- if (foundIndex === -1) removed.push(childA);
1748
- else childrenOfB.splice(foundIndex, 1);
1749
- }
1750
- return {
1751
- added: [...childrenOfB],
1752
- identical,
1753
- removed
1754
- };
1755
- };
1756
- const valueOrIdentityEqual = (a, b, eq) => {
1757
- if (a.getIdentity() === b.getIdentity()) return true;
1758
- if (eq(a.getValue(), b.getValue())) return true;
1759
- return false;
1760
- };
1761
- const toStringSingle = (n) => {
1762
- return JSON.stringify(n.getValue());
1763
- };
1764
- const toString$1 = (n, indent = 0) => {
1765
- if (n === void 0) return `(undefined)`;
1766
- let t = toStringDiff(n.value, indent);
1767
- for (const c of n.childrenStore) t += toString$1(c, indent + 2);
1768
- return t;
1769
- };
1770
- const toStringDiff = (n, indent) => {
1771
- const spaces = ` `.repeat(indent);
1772
- if (n === void 0) return `${spaces}(undefined)`;
1773
- const t = [];
1774
- t.push(`a: ${toStringSingle(n.a)} b: ${toStringSingle(n.b)}`);
1775
- if (n.valueChanged) t.push(`Value changed. Child changed: ${n.childChanged}`);
1776
- else t.push(`Value unchanged. Child changed: ${n.childChanged}`);
1777
- if (n.added.length > 0) {
1778
- t.push(`Added:`);
1779
- for (const c of n.added) t.push(` - ` + toStringSingle(c));
1780
- }
1781
- if (n.removed.length > 0) {
1782
- t.push(`Removed: ${n.removed.length}`);
1783
- for (const c of n.removed) t.push(` - ` + toStringSingle(c));
1784
- }
1785
- t.push(`----\n`);
1786
- return t.map((line) => spaces + line).join(`\n`);
1787
- };
1788
- var tree_mutable_exports = /* @__PURE__ */ __exportAll({
1789
- add: () => add,
1790
- addValue: () => addValue,
1791
- asDynamicTraversable: () => asDynamicTraversable$1,
1792
- breadthFirst: () => breadthFirst$2,
1793
- children: () => children$2,
1794
- childrenLength: () => childrenLength$1,
1795
- childrenValues: () => childrenValues,
1796
- compare: () => compare,
1797
- computeMaxDepth: () => computeMaxDepth,
1798
- createNode: () => createNode$1,
1799
- depthFirst: () => depthFirst$3,
1800
- findAnyChildByValue: () => findAnyChildByValue$2,
1801
- findChildByValue: () => findChildByValue$1,
1802
- findParentsValue: () => findParentsValue,
1803
- followValue: () => followValue$1,
1804
- fromPlainObject: () => fromPlainObject,
1805
- getRoot: () => getRoot,
1806
- hasAnyChild: () => hasAnyChild$1,
1807
- hasAnyParent: () => hasAnyParent$1,
1808
- hasChild: () => hasChild$1,
1809
- hasParent: () => hasParent$1,
1810
- nodeDepth: () => nodeDepth,
1811
- parents: () => parents$1,
1812
- parentsValues: () => parentsValues,
1813
- queryByValue: () => queryByValue,
1814
- queryParentsValue: () => queryParentsValue,
1815
- remove: () => remove$1,
1816
- removeValuelessNodesFromChild: () => removeValuelessNodesFromChild,
1817
- root: () => root$2,
1818
- rootWrapped: () => rootWrapped$1,
1819
- setChildren: () => setChildren,
1820
- siblings: () => siblings$2,
1821
- stripParentage: () => stripParentage,
1822
- throwTreeTest: () => throwTreeTest,
1823
- toStringDeep: () => toStringDeep$4,
1824
- treeTest: () => treeTest,
1825
- value: () => value,
1826
- wrap: () => wrap$1
1827
- });
1828
- /**
1829
- * Compares two nodes.
1830
- *
1831
- * By default uses `isEqualValueIgnoreOrder` to compare nodes. This means
1832
- * values of nodes will be compared, ignoring the order of fields.
1833
- * @param a
1834
- * @param b
1835
- * @param eq Comparison function. Uses `isEqualValueIgnoreOrder` by default.
1836
- * @returns Compare results
1837
- */
1838
- function compare(a, b, eq) {
1839
- return compare$1(asDynamicTraversable$1(a), asDynamicTraversable$1(b), eq);
1840
- }
1841
- /**
1842
- * Converts {@link Trees.TreeNode} to {@link Trees.SimplifiedNode}, removing the 'parent' fields.
1843
- * This can be useful because if you have the whole tree, the parent field
1844
- * is redundant and because it makes circular references can make dumping to console etc more troublesome.
1845
- *
1846
- * Recursive: strips parentage of all children and so on too.
1847
- * @param node
1848
- */
1849
- function stripParentage(node) {
1850
- return {
1851
- value: node.value,
1852
- childrenStore: node.childrenStore.map((c) => stripParentage(c))
1853
- };
1854
- }
1855
- const unwrapped = (node) => `wraps` in node ? node.wraps : node;
1856
- const wrapped = (node) => `wraps` in node ? node : wrap$1(node);
1857
- /**
1858
- * Wraps node `n` for a more object-oriented means of access.
1859
- * It will wrap child nodes on demand. For this reason, WrappedNode object
1860
- * identity is not stable
1861
- * @param n Node to wrap
1862
- */
1863
- function wrap$1(n) {
1864
- return {
1865
- *children() {
1866
- for (const c of n.childrenStore) yield wrap$1(c);
1867
- },
1868
- getValue: () => n.value,
1869
- getIdentity: () => n,
1870
- *queryValue(value) {
1871
- for (const v of queryByValue(value, unwrapped(n))) yield wrap$1(v);
1872
- },
1873
- *queryParentsValue(child, value, eq) {
1874
- for (const v of queryParentsValue(unwrapped(child), value, eq)) yield wrap$1(v);
1875
- },
1876
- *parentsValues(child) {
1877
- yield* parentsValues(unwrapped(child));
1878
- },
1879
- findParentsValue(child, value, eq) {
1880
- const n = findParentsValue(child, value, eq);
1881
- if (n !== void 0) return wrap$1(n);
1882
- },
1883
- getParent: () => n.parent === void 0 ? void 0 : wrap$1(n.parent),
1884
- hasParent: (parent) => {
1885
- return hasParent$1(n, unwrapped(parent));
1886
- },
1887
- hasAnyParent: (parent) => {
1888
- return hasAnyParent$1(n, unwrapped(parent));
1889
- },
1890
- hasChild: (child) => {
1891
- return hasChild$1(unwrapped(child), n);
1892
- },
1893
- hasAnyChild: (child) => {
1894
- return hasAnyChild$1(unwrapped(child), n);
1895
- },
1896
- remove: () => {
1897
- remove$1(n);
1898
- },
1899
- addValue: (value) => {
1900
- return wrap$1(addValue(value, n));
1901
- },
1902
- add: (child) => {
1903
- add(unwrapped(child), n);
1904
- return wrapped(child);
1905
- },
1906
- wraps: n
1907
- };
1908
- }
1909
- /**
1910
- * Removes `child` from the tree structure it is in.
1911
- * It removes `child` from its parent. Any sub-children of `child` still remain connected.
1912
- * @param child
1913
- */
1914
- function remove$1(child) {
1915
- const p = child.parent;
1916
- if (p === void 0) return false;
1917
- child.parent = void 0;
1918
- const count = p.childrenStore.length;
1919
- p.childrenStore = without(p.childrenStore, child);
1920
- return count !== p.childrenStore.length;
1921
- }
1922
- /**
1923
- * Starting from a child node, work backwards, removing it and ancestors that have no value
1924
- *
1925
- * If `child` is an only child, it will recursively call the same function on the parent.
1926
- * @param child Child to start from
1927
- */
1928
- function removeValuelessNodesFromChild(child) {
1929
- if (typeof child.value !== `undefined`) return false;
1930
- const parent = child.parent;
1931
- if (!parent) return false;
1932
- const sibs = [...siblings$2(child)];
1933
- remove$1(child);
1934
- if (sibs.length === 0) return removeValuelessNodesFromChild(parent);
1935
- return true;
1936
- }
1937
- /**
1938
- * Enumeate all siblings of `child`. This won't include `child` itself.
1939
- * If `child` is not part of a tree (ie has no parent) no values are yielded.
1940
- */
1941
- function* siblings$2(child, eq = isEqualDefault) {
1942
- const parent = child.parent;
1943
- if (typeof parent === `undefined`) return;
1944
- for (const c of parent.childrenStore) {
1945
- if (eq(c, child)) continue;
1946
- yield c;
1947
- }
1948
- }
1949
- /**
1950
- * Depth-first iteration of the children of `node`
1951
- * @param node
1952
- */
1953
- function* depthFirst$3(node) {
1954
- if (!root$2) return;
1955
- const stack = new StackMutable();
1956
- stack.push(...node.childrenStore);
1957
- let entry = stack.pop();
1958
- while (entry) {
1959
- yield entry;
1960
- if (entry) stack.push(...entry.childrenStore);
1961
- if (stack.isEmpty) break;
1962
- entry = stack.pop();
1963
- }
1964
- }
1965
- /**
1966
- * Breadth-first iteration of the children of `node`
1967
- * @param node
1968
- */
1969
- function* breadthFirst$2(node) {
1970
- if (!node) return;
1971
- const queue = new QueueMutable();
1972
- queue.enqueue(...node.childrenStore);
1973
- let entry = queue.dequeue();
1974
- while (entry) {
1975
- yield entry;
1976
- if (entry) queue.enqueue(...entry.childrenStore);
1977
- if (queue.isEmpty) break;
1978
- entry = queue.dequeue();
1979
- }
1980
- }
1981
- /**
1982
- * Validates the tree from `root` downwards.
1983
- * @param root
1984
- * @param seen
1985
- */
1986
- function treeTest(root, seen = []) {
1987
- if (root.parent === root) return [
1988
- false,
1989
- `Root has itself as parent`,
1990
- root
1991
- ];
1992
- if (seen.includes(root)) return [
1993
- false,
1994
- `Same node instance is appearing further in tree`,
1995
- root
1996
- ];
1997
- seen.push(root);
1998
- if (containsDuplicateInstances(root.childrenStore)) return [
1999
- false,
2000
- `Children list contains duplicates`,
2001
- root
2002
- ];
2003
- for (const c of root.childrenStore) {
2004
- if (c.parent !== root) return [
2005
- false,
2006
- `Member of childrenStore does not have .parent set`,
2007
- c
2008
- ];
2009
- if (hasAnyChild$1(root, c)) return [
2010
- false,
2011
- `Child has parent as its own child`,
2012
- c
2013
- ];
2014
- const v = treeTest(c, seen);
2015
- if (!v[0]) return v;
2016
- }
2017
- return [
2018
- true,
2019
- ``,
2020
- root
2021
- ];
2022
- }
2023
- /**
2024
- * Throws an exception if `root` fails tree validation
2025
- * @param root
2026
- */
2027
- function throwTreeTest(root) {
2028
- const v = treeTest(root);
2029
- if (v[0]) return;
2030
- throw new Error(`${v[1]} Node: ${toStringAbbreviate(v[2].value, 30)}`, { cause: v[2] });
2031
- }
2032
- /**
2033
- * Iterate over direct children of `root`, yielding {@link TreeNode} instances.
2034
- * Use {@link childrenValues} to iterate over child values
2035
- * @param root
2036
- */
2037
- function* children$2(root) {
2038
- for (const c of root.childrenStore) yield c;
2039
- }
2040
- /**
2041
- * Iterate over the value of direct children of `root`.
2042
- * Use {@link children} if you want to iterate over {@link TreeNode} instances instead.
2043
- * @param root
2044
- */
2045
- function* childrenValues(root) {
2046
- for (const c of root.childrenStore) if (typeof c.value !== `undefined`) yield c.value;
2047
- }
2048
- /**
2049
- * Iterate over all parents of `child`. First result is the immediate parent.
2050
- * @param child
2051
- */
2052
- function* parents$1(child) {
2053
- let p = child.parent;
2054
- while (p) {
2055
- yield p;
2056
- p = p.parent;
2057
- }
2058
- }
2059
- /**
2060
- * Returns the depth of `node`. A root node (ie. with no parents) has a depth of 0.
2061
- * @param node
2062
- */
2063
- function nodeDepth(node) {
2064
- return [...parents$1(node)].length;
2065
- }
2066
- /**
2067
- * Returns _true_ if `child` is an immediate child of `parent`.
2068
- * @param child
2069
- * @param parent
2070
- * @param eq Equality function to compare nodes. Uses `isEqualDefault` by default, which compares by reference.
2071
- */
2072
- function hasChild$1(child, parent, eq = isEqualDefault) {
2073
- for (const c of parent.childrenStore) if (eq(c, child)) return true;
2074
- return false;
2075
- }
2076
- /**
2077
- * Returns the first immediate child of `parent` that matches `value`.
2078
- *
2079
- * Use {@link queryByValue} if you want all matching children.
2080
- * @param value
2081
- * @param parent
2082
- * @param eq
2083
- */
2084
- function findChildByValue$1(value, parent, eq = isEqualDefault) {
2085
- for (const c of parent.childrenStore) if (eq(value, c.value)) return c;
2086
- }
2087
- /**
2088
- * Yield all immediate children of `parent` that match `value`.
2089
- *
2090
- * Use {@link findChildByValue} if you only want the first matching child.
2091
- * @param value
2092
- * @param parent
2093
- * @param eq
2094
- */
2095
- function* queryByValue(value, parent, eq = isEqualDefault) {
2096
- for (const c of parent.childrenStore) if (eq(value, c.value)) yield c;
2097
- }
2098
- /**
2099
- * Returns _true_ if `prospectiveChild` is some child node of `parent`,
2100
- * anywhere in the tree structure.
2101
- *
2102
- * Use {@link hasChild} to only check immediate children.
2103
- * @param prospectiveChild
2104
- * @param parent
2105
- */
2106
- function hasAnyChild$1(prospectiveChild, parent) {
2107
- for (const c of breadthFirst$2(parent)) if (c === prospectiveChild) return true;
2108
- return false;
2109
- }
2110
- /**
2111
- * Using a breadth-first search, return the first child of `parent` that has `value`.
2112
- * @param value Value being sought
2113
- * @param parent Parent node
2114
- * @param eq Equality function to compare values. Uses `isEqualDefault` by default, which compares by reference.
2115
- */
2116
- function findAnyChildByValue$2(value, parent, eq = isEqualDefault) {
2117
- for (const c of breadthFirst$2(parent)) if (eq(c.value, value)) return c;
2118
- }
2119
- /**
2120
- * Traverses up a node to find the root.
2121
- * @param node
2122
- */
2123
- function getRoot(node) {
2124
- if (node.parent) return getRoot(node.parent);
2125
- return node;
2126
- }
2127
- /**
2128
- * Returns _true_ if `prospectiveParent` is any ancestor
2129
- * parent of `child`.
2130
- *
2131
- * Use {@link hasParent} to only check immediate parent.
2132
- * @param child
2133
- * @param prospectiveParent
2134
- */
2135
- function hasAnyParent$1(child, prospectiveParent) {
2136
- for (const p of parents$1(child)) if (p === prospectiveParent) return true;
2137
- return false;
2138
- }
2139
- /**
2140
- * Yields the node value of each parent of `child`.
2141
- * _undefined_ values are not returned.
2142
- *
2143
- * Use {@link queryParentsValue} to search for a particular value
2144
- * @param child
2145
- */
2146
- function* parentsValues(child) {
2147
- for (const p of parents$1(child)) if (typeof p.value !== `undefined`) yield p.value;
2148
- return false;
2149
- }
2150
- /**
2151
- * Yields all parents of `child` that have a given value.
2152
- * Use {@link findParentsValue} to find the first match only.
2153
- * @param child
2154
- * @param value
2155
- * @param eq
2156
- */
2157
- function* queryParentsValue(child, value, eq = isEqualDefault) {
2158
- for (const p of parents$1(child)) if (typeof p.value !== `undefined`) {
2159
- if (eq(p.value, value)) yield p;
2160
- }
2161
- return false;
2162
- }
2163
- /**
2164
- * Returns the first parent that has a given value.
2165
- * @param child
2166
- * @param value
2167
- * @param eq
2168
- */
2169
- function findParentsValue(child, value, eq = isEqualDefault) {
2170
- return [...queryParentsValue(child, value, eq)][0];
2171
- }
2172
- /**
2173
- * Returns _true_ if `prospectiveParent` is the immediate
2174
- * parent of `child`.
2175
- *
2176
- * Use {@link hasAnyParent} to check for any ancestor parent.
2177
- * @param child
2178
- * @param prospectiveParent
2179
- */
2180
- function hasParent$1(child, prospectiveParent) {
2181
- return child.parent === prospectiveParent;
2182
- }
2183
- /**
2184
- * Computes the maximum depth of the tree.
2185
- * That is, how many steps down from `node` it can go.
2186
- * If a tree is: root -> childA -> subChildB
2187
- * ```js
2188
- * // Yields 2, since there are at max two steps down from root
2189
- * computeMaxDepth(root);
2190
- * ```
2191
- * @param node
2192
- */
2193
- function computeMaxDepth(node) {
2194
- return computeMaxDepthImpl(node, 0);
2195
- }
2196
- function computeMaxDepthImpl(node, startingDepth = 0) {
2197
- let depth = startingDepth;
2198
- for (const c of node.childrenStore) depth = Math.max(depth, computeMaxDepthImpl(c, startingDepth + 1));
2199
- return depth;
2200
- }
2201
- /**
2202
- * Adds a child node to `parent`.
2203
- * If `child` already has a parent, it is removed from that parent.
2204
- * @param child
2205
- * @param parent
2206
- * @throws Error if adding a child would break tree structure
2207
- */
2208
- function add(child, parent) {
2209
- throwAttemptedChild(child, parent);
2210
- const p = child.parent;
2211
- parent.childrenStore = [...parent.childrenStore, child];
2212
- child.parent = parent;
2213
- if (p) p.childrenStore = without(p.childrenStore, child);
2214
- }
2215
- /**
2216
- * Adds a new child node based on a value
2217
- */
2218
- function addValue(value, parent) {
2219
- return createNode$1(value, parent);
2220
- }
2221
- /**
2222
- * Creates the root for a tree, with an optional `value`.
2223
- * Use {@link rootWrapped} if you want a more object-oriented mode of access.
2224
- * @param value
2225
- */
2226
- function root$2(value) {
2227
- return createNode$1(value);
2228
- }
2229
- function fromPlainObject(value, label = ``, parent, seen = []) {
2230
- const entries = Object.entries(value);
2231
- parent = parent === void 0 ? root$2() : addValue({
2232
- label,
2233
- value
2234
- }, parent);
2235
- for (const entry of entries) {
2236
- const value = entry[1];
2237
- if (seen.includes(value)) continue;
2238
- seen.push(value);
2239
- if (typeof entry[1] === `object`) fromPlainObject(value, entry[0], parent, seen);
2240
- else addValue({
2241
- label: entry[0],
2242
- value
2243
- }, parent);
2244
- }
2245
- return parent;
2246
- }
2247
- /**
2248
- * Creates a tree, returning it as a {@link WrappedNode} for object-oriented access.
2249
- * Use {@link Trees.Mutable.root} alternatively.
2250
- * @param value
2251
- */
2252
- function rootWrapped$1(value) {
2253
- return wrap$1(createNode$1(value));
2254
- }
2255
- /**
2256
- * Creates a `TreeNode` instance with a given value and parent.
2257
- * Parent node, if specified, has its `childrenStore` property changed to include new child.
2258
- * @param value
2259
- * @param parent
2260
- */
2261
- function createNode$1(value, parent) {
2262
- const n = {
2263
- childrenStore: [],
2264
- parent,
2265
- value
2266
- };
2267
- if (parent !== void 0) parent.childrenStore = [...parent.childrenStore, n];
2268
- return n;
2269
- }
2270
- function childrenLength$1(node) {
2271
- return node.childrenStore.length;
2272
- }
2273
- function value(node) {
2274
- return node.value;
2275
- }
2276
- /**
2277
- * Projects `node` as a dynamic traversable.
2278
- * Dynamic in the sense that it creates the traversable project for nodes on demand.
2279
- * A consequence is that node identities are not stable.
2280
- * @param node
2281
- */
2282
- function asDynamicTraversable$1(node) {
2283
- return {
2284
- *children() {
2285
- for (const c of node.childrenStore) yield asDynamicTraversable$1(c);
2286
- },
2287
- getParent() {
2288
- if (node.parent === void 0) return;
2289
- return asDynamicTraversable$1(node.parent);
2290
- },
2291
- getValue() {
2292
- return node.value;
2293
- },
2294
- getIdentity() {
2295
- return node;
2296
- }
2297
- };
2298
- }
2299
- /**
2300
- * Throws an error if:
2301
- * 1. `child` is the same node as `parent`
2302
- * 2. `child` is already an immediate child of `parent`
2303
- * 3. `child` is an ancestor parent of `parent`
2304
- * 4. `child` has `parent` as its own child
2305
- * @param c
2306
- * @param parent
2307
- */
2308
- function throwAttemptedChild(c, parent) {
2309
- if (parent === c) throw new Error(`Cannot add self as child`);
2310
- if (c.parent === parent) return;
2311
- if (hasAnyParent$1(parent, c)) throw new Error(`Child contains parent (1)`, { cause: c });
2312
- if (hasAnyParent$1(c, parent)) throw new Error(`Parent already contains child`, { cause: c });
2313
- if (hasAnyChild$1(parent, c)) throw new Error(`Child contains parent (2)`, { cause: c });
2314
- }
2315
- /**
2316
- * Sets the children of `parent` to a list of `children`.
2317
- *
2318
- * Any previous children are disconnected from this parent.
2319
- * All new children have their parent set to `parent`.
2320
- *
2321
- * There is some validation to ensure that adding the children doesn't break the tree.
2322
- */
2323
- function setChildren(parent, children) {
2324
- for (const c of children) throwAttemptedChild(c, parent);
2325
- parent.childrenStore = [...children];
2326
- for (const c of children) c.parent = parent;
2327
- }
2328
- function toStringDeep$4(node, indent = 0) {
2329
- const t = `${` `.repeat(indent)} + ${node.value ? JSON.stringify(node.value) : `-`}`;
2330
- return node.childrenStore.length > 0 ? `${t}\n${node.childrenStore.map((d) => toStringDeep$4(d, indent + 1)).join(`\n`)}` : t;
2331
- }
2332
- function* followValue$1(root, continuePredicate, depth = 1) {
2333
- for (const c of root.childrenStore) {
2334
- const value = c.value;
2335
- if (value === void 0) continue;
2336
- if (continuePredicate(value, depth)) {
2337
- yield c.value;
2338
- yield* followValue$1(c, continuePredicate, depth + 1);
2339
- }
2340
- }
2341
- }
2342
- var traverse_object_exports = /* @__PURE__ */ __exportAll({
2343
- asDynamicTraversable: () => asDynamicTraversable,
2344
- children: () => children$1,
2345
- create: () => create$1,
2346
- createSimplified: () => createSimplified,
2347
- createWrapped: () => createWrapped,
2348
- depthFirst: () => depthFirst$2,
2349
- getByPath: () => getByPath,
2350
- prettyPrint: () => prettyPrint,
2351
- prettyPrintEntries: () => prettyPrintEntries,
2352
- toStringDeep: () => toStringDeep$3,
2353
- traceByPath: () => traceByPath
2354
- });
2355
- /**
2356
- * Helper function to get a 'friendly' string representation of an array of {@link TraverseObjectEntry}.
2357
- * @param entries
2358
- * @returns
2359
- */
2360
- function prettyPrintEntries(entries) {
2361
- if (entries.length === 0) return `(empty)`;
2362
- let t = ``;
2363
- for (const [index, entry] of entries.entries()) {
2364
- t += ` `.repeat(index);
2365
- t += entry.name + ` = ` + JSON.stringify(entry.leafValue) + `\n`;
2366
- }
2367
- return t;
2368
- }
2369
- /**
2370
- * Returns a human-friendly debug string for a tree-like structure
2371
- * ```js
2372
- * console.log(Trees.prettyPrint(obj));
2373
- * ```
2374
- * @param indent
2375
- * @param node
2376
- * @param options
2377
- * @returns
2378
- */
2379
- const prettyPrint = (node, indent = 0, options = {}) => {
2380
- resultThrow(nullUndefTest(node, `node`));
2381
- const entry = getNamedEntry(node, options.name ?? `node`);
2382
- const t = `${` `.repeat(indent)} + name: ${entry.name} value: ${JSON.stringify(entry.leafValue)}`;
2383
- const childrenAsArray = [...children$1(node, options)];
2384
- return childrenAsArray.length > 0 ? t + `\n` + childrenAsArray.map((d) => prettyPrint(d.leafValue, indent + 1, {
2385
- ...options,
2386
- name: d.name
2387
- })).join(`\n`) : t;
2388
- };
2389
- /**
2390
- * Returns a debug string representation of the node (recursive)
2391
- * @param node
2392
- * @param indent
2393
- * @returns
2394
- */
2395
- const toStringDeep$3 = (node, indent = 0) => {
2396
- let t = ` `.repeat(indent) + ` ${node.value?.name}`;
2397
- if (node.value !== void 0) {
2398
- if (`sourceValue` in node.value && `leafValue` in node.value) {
2399
- let sourceValue = toStringAbbreviate(node.value.sourceValue, 20);
2400
- const leafValue = toStringAbbreviate(node.value.leafValue, 20);
2401
- sourceValue = sourceValue === leafValue ? `` : `source: ` + sourceValue;
2402
- t += ` = ${leafValue} ${sourceValue}`;
2403
- } else if (`sourceValue` in node.value && node.value.sourceValue !== void 0) t += ` = ${node.value.sourceValue}`;
2404
- if (`ancestors` in node.value) t += ` (ancestors: ${node.value.ancestors.join(`, `)})`;
2405
- }
2406
- t += `\n`;
2407
- for (const c of node.childrenStore) t += toStringDeep$3(c, indent + 1);
2408
- return t;
2409
- };
2410
- /**
2411
- * Yields the direct (ie. non-recursive) children of a tree-like object as a pairing
2412
- * of node name and value. Supports basic objects, Maps and arrays.
2413
- *
2414
- * To iterate recursively, consider {@link depthFirst}
2415
- *
2416
- * Each child is returned in an {@link TraverseObjectEntry} structure:
2417
- * ```typescript
2418
- * type Entry = Readonly<{
2419
- * // Property name
2420
- * name: string,
2421
- * // Value of property, as if you called `object[propertyName]`
2422
- * sourceValue: any,
2423
- * // Branch nodes will have _undefined_, leaf nodes will contain the value
2424
- * leafValue: any
2425
- * }>;
2426
- * ```
2427
- *
2428
- * For example, iterating over a flat object:
2429
- * ```js
2430
- * const verySimpleObject = { field: `hello`, flag: true }
2431
- * const kids = [ ...children(verySimpleObject) ];
2432
- * // Yields:
2433
- * // [ { name: "field", sourceValue: `hello`, leafValue: `hello` },
2434
- * // { name: "flag", sourceValue: true, leafValue: true } ]
2435
- * ```
2436
- *
2437
- * For objects containing objects:
2438
- * ```js
2439
- * const lessSimpleObject = { field: `hello`, flag: true, colour: { `red`, opacity: 0.5 } }
2440
- * const kids = [ ...children(verySimpleObject) ];
2441
- * // Yields as before, plus:
2442
- * // { name: "colour", sourceValue: { name: 'red', opacity: 0.5 }, leafValue: undefined }
2443
- * ```
2444
- *
2445
- * Note that 'sourceValue' always contains the property value, as if you
2446
- * access it via `object[propName]`. 'leafValue' only contains the value if it's a leaf
2447
- * node.
2448
- *
2449
- * Arrays are assigned a name based on index.
2450
- * @example Arrays
2451
- * ```js
2452
- * const colours = [ { r: 1, g: 0, b: 0 }, { r: 0, g: 1, b: 0 }, { r: 0, g: 0, b: 1 } ];
2453
- * // Children:
2454
- * // [
2455
- * // { name: "array[0]", value: {r:1,g:0,b:0} },
2456
- * // { name: "array[1]", value: {r:0,g:1,b:0} },
2457
- * // { name: "array[2]", value: {r:0,g:0,b:1} },
2458
- * // ]
2459
- * ```
2460
- *
2461
- * Pass in `options.name` (eg 'colours') to have names generated as 'colours[0]', etc.
2462
- * Options can also be used to filter children. By default all direct children are returned.
2463
- * @param node
2464
- * @param options
2465
- */
2466
- function* children$1(node, options = {}) {
2467
- resultThrow(nullUndefTest(node, `node`));
2468
- const filteringOption = options.filter ?? `none`;
2469
- const filterByValue = (v) => {
2470
- if (filteringOption === `none`) return [true, isPrimitive(v)];
2471
- else if (filteringOption === `leaves` && isPrimitive(v)) return [true, true];
2472
- else if (filteringOption === `branches` && !isPrimitive(v)) return [true, false];
2473
- return [false, isPrimitive(v)];
2474
- };
2475
- if (Array.isArray(node)) for (const [index, element] of node.entries()) {
2476
- const f = filterByValue(element);
2477
- if (f[0]) yield {
2478
- name: index.toString(),
2479
- _kind: `entry`,
2480
- sourceValue: element,
2481
- leafValue: f[1] ? element : void 0
2482
- };
2483
- }
2484
- else if (typeof node === `object`) {
2485
- const entriesIter = `entries` in node ? node.entries() : Object.entries(node);
2486
- for (const [name, value] of entriesIter) {
2487
- const [filter, isPrimitive] = filterByValue(value);
2488
- if (filter) yield {
2489
- name,
2490
- _kind: `entry`,
2491
- sourceValue: value,
2492
- leafValue: isPrimitive ? value : void 0
2493
- };
2494
- }
2495
- }
2496
- }
2497
- function* depthFirst$2(node, options = {}, ancestors = []) {
2498
- for (const c of children$1(node, options)) {
2499
- yield {
2500
- ...c,
2501
- ancestors: [...ancestors],
2502
- _kind: `entry-ancestors`
2503
- };
2504
- yield* depthFirst$2(c.sourceValue, options, [...ancestors, c.name]);
2505
- }
2506
- }
2507
- /**
2508
- * Finds a given direct child by name
2509
- * @param name
2510
- * @param node
2511
- * @returns
2512
- */
2513
- function childByName(name, node) {
2514
- for (const d of children$1(node)) if (d.name === name) return d;
2515
- }
2516
- /**
2517
- * Returns the closest matching entry, tracing `path` in an array, Map or simple object.
2518
- * Returns an entry with _undefined_ value at the point where tracing stopped.
2519
- * Use {@link traceByPath} to step through all the segments.
2520
- *
2521
- * ```js
2522
- * const people = {
2523
- * jane: {
2524
- * address: {
2525
- * postcode: 1000,
2526
- * street: 'West St',
2527
- * city: 'Blahville'
2528
- * },
2529
- * colour: 'red'
2530
- * }
2531
- * }
2532
- * Trees.getByPath('jane.address.postcode', people); // '.' default separator
2533
- * // ['postcode', 1000]
2534
- * Trees.getByPath('jane.address.country.state', people);
2535
- * // ['country', undefined] - since full path could not be resolved.
2536
- * ```
2537
- * @param path Path, eg `jane.address.postcode`
2538
- * @param node Node to look within
2539
- * @param options Options for parsing path. By default '.' is used as a separator
2540
- * @returns
2541
- */
2542
- function getByPath(path, node, options = {}) {
2543
- const v = last(traceByPath(path, node, options));
2544
- if (!v) throw new Error(`Could not trace path: ${path} `);
2545
- return v;
2546
- }
2547
- /**
2548
- * Enumerates over children of `node` towards the node named in `path`.
2549
- * This is useful if you want to get the interim steps to the target node.
2550
- *
2551
- * Use {@link getByPath} if you don't care about interim steps.
2552
- *
2553
- * ```js
2554
- * const people = {
2555
- * jane: {
2556
- * address: {
2557
- * postcode: 1000,
2558
- * street: 'West St',
2559
- * city: 'Blahville'
2560
- * },
2561
- * colour: 'red'
2562
- * }
2563
- * }
2564
- * for (const p of Trees.traceByPath('jane.address.street', people)) {
2565
- * // { name: "jane", value: { address: { postcode: 1000,street: 'West St', city: 'Blahville' }, colour: 'red'} },
2566
- * // { name: "address", value: { postcode: 1000, street: 'West St', city: 'Blahville' } },
2567
- * // { name: "street", value: "West St" } }
2568
- * }
2569
- * ```
2570
- *
2571
- * Results stop when the path can't be followed any further.
2572
- * The last entry will have a name of the last sought path segment, and _undefined_ as its value.
2573
- *
2574
- * @param path Path to traverse
2575
- * @param node Starting node
2576
- * @param options Options for path traversal logic
2577
- * @returns
2578
- */
2579
- function* traceByPath(path, node, options = {}) {
2580
- resultThrow(nullUndefTest(path, `path`), nullUndefTest(node, `node`));
2581
- const separator = options.separator ?? `.`;
2582
- const pathSplit = path.split(separator);
2583
- const ancestors = [];
2584
- for (const p of pathSplit) {
2585
- const entry = childByName(p, node);
2586
- if (!entry) {
2587
- yield {
2588
- name: p,
2589
- sourceValue: void 0,
2590
- leafValue: void 0,
2591
- ancestors,
2592
- _kind: `entry-ancestors`
2593
- };
2594
- return;
2595
- }
2596
- node = entry.sourceValue;
2597
- yield {
2598
- ...entry,
2599
- ancestors: [...ancestors],
2600
- _kind: `entry-ancestors`
2601
- };
2602
- ancestors.push(p);
2603
- }
2604
- }
2605
- /**
2606
- * Returns a projection of `node` as a dynamic traversable.
2607
- * This means that the tree structure is dynamically created as last-minute as possible.
2608
- *
2609
- * The type when calling `getValue()` is {@link TraverseObjectEntryStatic}:
2610
- * ```typescript
2611
- * type EntryStatic = Readonly<{
2612
- * name: string,
2613
- * value: any
2614
- * ancestors: string[]
2615
- * }>
2616
- * ```
2617
- *
2618
- * Note that the object identity of TraversableTree return results is not stable.
2619
- * This is because they are created on-the-fly by reading fields of `node`.
2620
- *
2621
- * ```js
2622
- * const c1 = [ ...asDynamicTraversable(someObject).children() ];
2623
- * const c2 = [ ...asDynamicTraversable(someObject).children() ];
2624
- *
2625
- * // Object identity is not the same
2626
- * c1[ 0 ] === c1[ 0 ]; // false
2627
- *
2628
- * // ...even though its referring to the same value
2629
- * c1[ 0 ].getValue() === c1[ 0 ].getValue(); // true
2630
- * ```
2631
- *
2632
- * Instead .getIdentity() to get a stable identity:
2633
- * ```js
2634
- * c1[ 0 ].getIdentity() === c2[ 0 ].getIdentity(); // true
2635
- * ```
2636
- *
2637
- * @example
2638
- * ```js
2639
- * const myObj = { name: `Pedro`, size: 45, colour: `orange` };
2640
- * const root = Trees.FromObject.asDynamicTraversable(myObj);
2641
- * for (const v of Trees.Traverse.breadthFirst(root)) {
2642
- * // v.getValue() yields:
2643
- * // { name: 'name', sourceValue: 'Pedro' ...},
2644
- * // { name: 'size', sourceValue: 45 ... }
2645
- * // ...
2646
- * }
2647
- * ```
2648
- * @param node Object to read
2649
- * @param options Options when creating traversable
2650
- * @param ancestors Do not use
2651
- * @param parent Do not use
2652
- * @returns
2653
- */
2654
- const asDynamicTraversable = (node, options = {}, ancestors = [], parent) => {
2655
- const name = options.name ?? `object`;
2656
- const t = {
2657
- *children() {
2658
- for (const { name: childName, sourceValue, leafValue } of children$1(node, options)) yield asDynamicTraversable(sourceValue, {
2659
- ...options,
2660
- name: childName
2661
- }, [...ancestors, name], t);
2662
- },
2663
- getParent() {
2664
- return parent;
2665
- },
2666
- getValue() {
2667
- return {
2668
- name,
2669
- sourceValue: node,
2670
- ancestors,
2671
- _kind: `entry-static`
2672
- };
2673
- },
2674
- getIdentity() {
2675
- return node;
2676
- }
2677
- };
2678
- return t;
2679
- };
2680
- /**
2681
- * Reads all fields and sub-fields of `node`, returning as a 'wrapped' tree structure.
2682
- * Is a snapshot of `node`, and won't update if it mutates.
2683
- * @param node
2684
- * @param options
2685
- * @returns
2686
- */
2687
- const createWrapped = (node, options) => {
2688
- return wrap$1(create$1(node, options));
2689
- };
2690
- /**
2691
- * Reads all fields and sub-fields of `node`, returning as a basic tree structure.
2692
- * The structure is a snapshot of the object. If the object changes afterwards, the tree will
2693
- * remain the same.
2694
- *
2695
- * Alternatively, consider {@link asDynamicTraversable} which reads the object dynamically.
2696
- * @example
2697
- * ```js
2698
- * const myObj = { name: `Pedro`, size: 45, colour: `orange` };
2699
- * const root = Trees.FromObject.create(myObj);
2700
- * for (const v of Trees.Traverse.breadthFirst(root)) {
2701
- * // v.getValue() yields:
2702
- * // { name: 'name', sourceValue: 'Pedro' ...},
2703
- * // { name: 'size', sourceValue: 45 ... }
2704
- * // ...
2705
- * }
2706
- * ```
2707
- * @param node
2708
- * @param options
2709
- * @returns
2710
- */
2711
- const create$1 = (node, options = {}) => {
2712
- return createImpl(node, (options.valuesAtLeaves ?? false ? (v) => {
2713
- if (isPrimitive(v)) return v;
2714
- } : (v) => v)(node), options, []);
2715
- };
2716
- const createImpl = (sourceValue, leafValue, options = {}, ancestors) => {
2717
- const defaultName = options.name ?? `object_ci`;
2718
- const r = root$2({
2719
- name: defaultName,
2720
- sourceValue: leafValue,
2721
- ancestors: [...ancestors],
2722
- _kind: `entry-static`
2723
- });
2724
- ancestors = [...ancestors, defaultName];
2725
- for (const c of children$1(sourceValue, options)) {
2726
- const v = options.valuesAtLeaves ? c.leafValue : c.sourceValue;
2727
- add(createImpl(c.sourceValue, v, {
2728
- ...options,
2729
- name: c.name
2730
- }, ancestors), r);
2731
- }
2732
- return r;
2733
- };
2734
- /**
2735
- * Returns a copy of `node` with its (and all its childrens') parent information removed.
2736
- *
2737
- * Under the hood:
2738
- * ```js
2739
- * TreeArrayBacked.stripParentage(create(node, options));
2740
- * ```
2741
- * @param node
2742
- * @param options
2743
- * @returns
2744
- */
2745
- const createSimplified = (node, options = {}) => {
2746
- return stripParentage(create$1(node, options));
2747
- };
2748
- /**
2749
- * Generates a name for a node.
2750
- * Uses the 'name' property if it exists, otherwise uses `defaultName`
2751
- * @param node
2752
- * @param defaultName
2753
- * @returns
2754
- */
2755
- function getNamedEntry(node, defaultName = ``) {
2756
- if (`name` in node && `leafValue` in node && `sourceValue` in node) return {
2757
- name: node.name,
2758
- _kind: `entry`,
2759
- leafValue: node.leafValue,
2760
- sourceValue: node.sourceValue
2761
- };
2762
- if (`name` in node) return {
2763
- name: node.name,
2764
- leafValue: node,
2765
- sourceValue: node,
2766
- _kind: `entry`
2767
- };
2768
- return {
2769
- name: defaultName,
2770
- leafValue: node,
2771
- sourceValue: node,
2772
- _kind: `entry`
2773
- };
2774
- }
2775
- function isSingleValue(v) {
2776
- if (`value` in v) return true;
2777
- return false;
2778
- }
2779
- function isMultiValue(v) {
2780
- if (`values` in v) return Array.isArray(v.values);
2781
- return false;
2782
- }
2783
- var pathed_exports = /* @__PURE__ */ __exportAll({
2784
- Pathed: () => Pathed,
2785
- addValueByPath: () => addValueByPath,
2786
- children: () => children,
2787
- childrenLengthByPath: () => childrenLengthByPath,
2788
- clearValuesByPath: () => clearValuesByPath,
2789
- findAnyChildByValue: () => findAnyChildByValue$1,
2790
- hasValue: () => hasValue,
2791
- parent: () => parent,
2792
- parentValues: () => parentValues,
2793
- removeValueByPath: () => removeValueByPath,
2794
- siblings: () => siblings$1,
2795
- siblingsValues: () => siblingsValues,
2796
- toStringDeep: () => toStringDeep$2,
2797
- valueByPath: () => valueByPath,
2798
- valuesByPath: () => valuesByPath
2799
- });
2800
- /**
2801
- * Creates a wrapper for working with 'pathed' trees.
2802
- * An example is a filesystem.
2803
- *
2804
- * ```js
2805
- * const t = new Pathed();
2806
- * // Store a value. Path implies a structure of
2807
- * // c -> users -> admin
2808
- * // ...which is automatically created
2809
- * t.add({x:10}, `c.users.admin`);
2810
- *
2811
- * t.add({x:20}, `c.users.guest`);
2812
- * // Tree will now be:
2813
- * // c-> users -> admin
2814
- * // -> guest
2815
- *
2816
- * t.getValue(`c.users.guest`); // { x:20 }
2817
- * ```
2818
- *
2819
- * By default only a single value can be stored at a path.
2820
- * Set options to allow this:
2821
- * ```js
2822
- * const t = new Pathed({ duplicates: `allow` });
2823
- * t.add({x:10}, `c.users.admin`);
2824
- * t.add({x:20}, `c.users.admin`);
2825
- * t.getValue(`c.users.admin`); // Throws an error because there are multiple values
2826
- * t.getValues(`c.users.admin`); // [ {x:10}, {x:20 } ]
2827
- * ```
2828
- * @param pathOpts
2829
- * @returns
2830
- */
2831
- var Pathed = class {
2832
- #root;
2833
- #pathOpts;
2834
- /**
2835
- * Create, using default options
2836
- * @param pathOpts
2837
- */
2838
- constructor(pathOpts = {}) {
2839
- this.#pathOpts = {
2840
- separator: `.`,
2841
- startsWithSeparator: false,
2842
- duplicates: `overwrite`,
2843
- ...pathOpts
2844
- };
2845
- }
2846
- /**
2847
- * Adds a value at the string path, automatically creating intermediate nodes as needed.
2848
- * By default, if a value already exists at the path, it will be overwritten. Set options to change this.
2849
- * @param value Value to associate with path
2850
- * @param path Path
2851
- */
2852
- add(value, path) {
2853
- throwIfFailed(this.validate(path));
2854
- const n = addValueByPath(value, path, this.#pathOpts, this.#root);
2855
- if (this.#root === void 0) this.#root = getRoot(n);
2856
- }
2857
- validate(path) {
2858
- if (this.#pathOpts.startsWithSeparator && !path.startsWith(this.#pathOpts.separator)) return {
2859
- success: false,
2860
- error: `Path must start with separator when 'startsWithSeparator' is enabled. Got: ${path}`
2861
- };
2862
- return {
2863
- success: true,
2864
- value: path
2865
- };
2866
- }
2867
- /**
2868
- * Returns a string representation of tree
2869
- * @returns Returns a string representation of tree
2870
- */
2871
- prettyPrint() {
2872
- if (this.#root === void 0) return `(empty)`;
2873
- return toStringDeep$4(this.#root);
2874
- }
2875
- /**
2876
- * Removes the value at the given path, returning _true_
2877
- * if there was a value. This will delete tree nodes if they become empty
2878
- * @param path
2879
- * @returns _true_ if value was removed
2880
- */
2881
- remove(path) {
2882
- throwIfFailed(this.validate(path));
2883
- if (this.#root === void 0) return false;
2884
- return removeValueByPath(path, this.#root, this.#pathOpts);
2885
- }
2886
- /**
2887
- * Returns _true_ if we have a value at `path`
2888
- * @param path
2889
- * @returns _true_ if value exists at path
2890
- */
2891
- hasPath(path) {
2892
- throwIfFailed(this.validate(path));
2893
- if (this.#root === void 0) return false;
2894
- return findChildByPath(path, this.#root, this.#pathOpts) !== void 0;
2895
- }
2896
- /**
2897
- * Returns a tree node for a given path, or _undefined_
2898
- * if path does not exist.
2899
- *
2900
- * Use {@link getValue} to get the value at a node instead.
2901
- * @param path
2902
- * @returns The tree node for the given path, or _undefined_ if not found
2903
- */
2904
- getNode(path) {
2905
- throwIfFailed(this.validate(path));
2906
- if (this.#root === void 0) return;
2907
- return findChildByPath(path, this.#root, this.#pathOpts);
2908
- }
2909
- /**
2910
- * Returns the value at the path, or _undefined_ if path is not found.
2911
- * Use {@link getNode} to get the tree node instead.
2912
- * @param path
2913
- * @returns The value at the path, or _undefined_ if path is not found
2914
- */
2915
- getValue(path) {
2916
- throwIfFailed(this.validate(path));
2917
- if (this.#root === void 0) return;
2918
- return valueByPath(path, this.#root, this.#pathOpts);
2919
- }
2920
- /**
2921
- * Gets the containing path to `node`. If _includeNode_ is true, we also include the
2922
- * node's own label.
2923
- */
2924
- getPath(node, includeNode) {
2925
- if (this.#root === void 0) return ``;
2926
- const segments = [];
2927
- if (includeNode && node.value) segments.push(node.value?.label);
2928
- for (const p of parentValues(node)) segments.unshift(p.label);
2929
- let path = segments.join(this.#pathOpts.separator);
2930
- if (this.#pathOpts.startsWithSeparator) {
2931
- if (!path.startsWith(this.#pathOpts.separator)) path = this.#pathOpts.separator + path;
2932
- if (!path.endsWith(this.#pathOpts.separator) && (node.childrenStore.length > 0 || !includeNode)) path += this.#pathOpts.separator;
2933
- }
2934
- return path;
2935
- }
2936
- /**
2937
- * Gets the number of children at a given path.
2938
- * Returns NaN if path does not exist or has no children.
2939
- * @param path
2940
- * @returns The number of children at the path, or NaN if path is not found
2941
- */
2942
- childrenLength(path) {
2943
- throwIfFailed(this.validate(path));
2944
- if (this.#root === void 0) return NaN;
2945
- const c = findChildByPath(path, this.#root, this.#pathOpts);
2946
- if (c === void 0) return NaN;
2947
- return c.childrenStore.length;
2948
- }
2949
- /**
2950
- * Get all the values stored at a path, if multiple values are allowed. Returns an empty array if path does not exist or has no value.
2951
- * @param path
2952
- * @returns An array of values at the path, or an empty array if path is not found
2953
- */
2954
- getValues(path) {
2955
- throwIfFailed(this.validate(path));
2956
- if (this.#root === void 0) return void 0;
2957
- return valuesByPath(path, this.#root, this.#pathOpts);
2958
- }
2959
- /**
2960
- * Removes all values at the given path, but leaves the structure of the tree intact. Returns _true_ if there was a value to clear.
2961
- * @param path
2962
- * @returns _true_ if there was a value to clear at the path
2963
- */
2964
- clearValues(path) {
2965
- throwIfFailed(this.validate(path));
2966
- if (this.#root === void 0) return false;
2967
- return clearValuesByPath(path, this.#root, this.#pathOpts);
2968
- }
2969
- /**
2970
- * Iterate all children of this path
2971
- */
2972
- *children(path) {
2973
- throwIfFailed(this.validate(path));
2974
- if (this.#root === void 0) return;
2975
- yield* children(path, this.#root, this.#pathOpts);
2976
- }
2977
- /**
2978
- * Iterate all siblings of this path
2979
- */
2980
- *siblings(path) {
2981
- throwIfFailed(this.validate(path));
2982
- if (this.#root === void 0) return;
2983
- yield* siblings$1(path, this.#root, this.#pathOpts);
2984
- }
2985
- /**
2986
- * Iterate all siblings of this path
2987
- */
2988
- *siblingsValues(path) {
2989
- throwIfFailed(this.validate(path));
2990
- if (this.#root === void 0) return;
2991
- yield* siblingsValues(path, this.#root, this.#pathOpts);
2992
- }
2993
- /**
2994
- * Returns the parent node of `path`, or _undefined_ if not found or at root.
2995
- */
2996
- parent(path) {
2997
- throwIfFailed(this.validate(path));
2998
- if (this.#root === void 0) return;
2999
- return parent(path, this.#root, this.#pathOpts);
3000
- }
3001
- get separator() {
3002
- return this.#pathOpts.separator;
3003
- }
3004
- /**
3005
- * Returns the root tree node.
3006
- * @returns The root tree node, or _undefined_ if tree is empty
3007
- */
3008
- get root() {
3009
- return this.#root;
3010
- }
3011
- };
3012
- /**
3013
- * Adds a value by a string path, with '.' as a the default delimiter
3014
- * Automatically generates intermediate nodes.
3015
- *
3016
- * ```js
3017
- * const root = addValueByPath({}, 'c');
3018
- * addValueByPath({x:'blah'}, 'c.users.admin', root);
3019
- * ```
3020
- *
3021
- * Creates the structure:
3022
- * ```
3023
- * c value: { } label: c
3024
- * + users value: undefined label: users
3025
- * + admin value: { x: 'blah' } label: admin
3026
- * ```
3027
- *
3028
- * By default, multiple values under same key are overwritten, with the most recent winning.
3029
- * @param value Value to add
3030
- * @param path Path to add at
3031
- * @param node Node to insert
3032
- * @param pathOpts Options
3033
- */
3034
- function addValueByPath(value, path, pathOpts, node) {
3035
- const separator = pathOpts.separator;
3036
- const duplicatePath = pathOpts.duplicates;
3037
- const split = path.split(separator);
3038
- let count = 0;
3039
- for (const p of split) {
3040
- const lastEntry = count === split.length - 1;
3041
- const found = findChildByLabel(p, node);
3042
- if (found === void 0) node = createNode$1({
3043
- value: lastEntry ? value : void 0,
3044
- label: p
3045
- }, node);
3046
- else {
3047
- node = found;
3048
- if (lastEntry) switch (duplicatePath) {
3049
- case `ignore`: break;
3050
- case `allow`: {
3051
- const existing = getValuesFromNode(node);
3052
- node.value = {
3053
- values: [...existing, value],
3054
- label: p
3055
- };
3056
- break;
3057
- }
3058
- case `overwrite`:
3059
- node.value = {
3060
- value,
3061
- label: p
3062
- };
3063
- break;
3064
- }
3065
- else node = found;
3066
- }
3067
- count++;
3068
- }
3069
- if (node === void 0) throw new Error(`Could not create tree`);
3070
- return node;
3071
- }
3072
- /**
3073
- * Removes the value at the given path, returning _true_ if there was something to remove.
3074
- * @param node
3075
- * @returns _true_ if something removed
3076
- */
3077
- function isLabelledNodeEmpty(node) {
3078
- if (node.value === void 0) return true;
3079
- if (`values` in node.value) return node.value.values.length === 0;
3080
- if (`value` in node.value) return node.value.value === void 0;
3081
- return true;
3082
- }
3083
- function pruneLabelledBranch(node) {
3084
- if (node.childrenStore.length > 0) return;
3085
- if (!isLabelledNodeEmpty(node)) return;
3086
- const parent = node.parent;
3087
- if (!parent) return;
3088
- remove$1(node);
3089
- pruneLabelledBranch(parent);
3090
- }
3091
- function removeValueByPath(path, root, pathOpts) {
3092
- if (root === void 0) return false;
3093
- const c = findChildByPath(path, root, pathOpts);
3094
- if (c === void 0) return false;
3095
- c.value = void 0;
3096
- pruneLabelledBranch(c);
3097
- return true;
3098
- }
3099
- function clearValuesByPath(path, root, pathOpts) {
3100
- if (root === void 0) return false;
3101
- const c = findChildByPath(path, root, pathOpts);
3102
- if (c === void 0) return false;
3103
- c.value = {
3104
- label: c.value?.label ?? ``,
3105
- value: void 0
3106
- };
3107
- return true;
3108
- }
3109
- /**
3110
- * Return the length of children of `path`, or NaN if path not found.
3111
- */
3112
- function childrenLengthByPath(path, searchStart, pathOpts) {
3113
- if (searchStart === void 0) return NaN;
3114
- const c = findChildByPath(path, searchStart, pathOpts);
3115
- if (c === void 0) return NaN;
3116
- return c.childrenStore.length;
3117
- }
3118
- /**
3119
- * Iterate over all the children of `path`
3120
- */
3121
- function* children(path, searchStart, pathOpts) {
3122
- if (searchStart === void 0) return;
3123
- const c = findChildByPath(path, searchStart, pathOpts);
3124
- if (c === void 0) return;
3125
- for (const ch of c.childrenStore) yield ch;
3126
- }
3127
- /**
3128
- * Iterate over all the siblings of `path`, excluding the node at `path` itself.
3129
- * Yields LabelledNode instances, which allow you to traverse tree. If all you care about is the values, use {@link siblingsValues} instead.
3130
- */
3131
- function* siblings$1(path, searchStart, pathOpts) {
3132
- if (searchStart === void 0) return;
3133
- const c = findChildByPath(path, searchStart, pathOpts);
3134
- if (c === void 0) return;
3135
- const parent = c.parent;
3136
- if (parent === void 0) return;
3137
- for (const ch of parent.childrenStore) {
3138
- if (ch === c) continue;
3139
- if (typeof ch === `undefined`) throw new TypeError(`Unexpected undefined child node`);
3140
- yield ch;
3141
- }
3142
- }
3143
- /**
3144
- * Iterate over the values of all the siblings of `path`, excluding the node at `path` itself. If you need to traverse tree, use {@link siblings} instead.
3145
- * @param path
3146
- * @param searchStart
3147
- * @param pathOpts
3148
- */
3149
- function* siblingsValues(path, searchStart, pathOpts) {
3150
- for (const s of siblings$1(path, searchStart, pathOpts)) {
3151
- if (s.value === void 0) continue;
3152
- yield s.value;
3153
- }
3154
- }
3155
- /**
3156
- * Return the parent node of `path`, or undefined if not found or at root.
3157
- */
3158
- function parent(path, searchStart, pathOpts) {
3159
- if (searchStart === void 0) return;
3160
- const c = findChildByPath(path, searchStart, pathOpts);
3161
- if (c === void 0) return;
3162
- return c.parent;
3163
- }
3164
- function* parentValues(start) {
3165
- for (const p of parents$1(start)) {
3166
- if (p.value === void 0) continue;
3167
- yield p.value;
3168
- }
3169
- }
3170
- /**
3171
- * Searches direct children, returning the node that has the given `label`
3172
- * @param label
3173
- * @param node
3174
- * @returns Child node, or _undefined_
3175
- */
3176
- function findChildByLabel(label, node) {
3177
- if (node === void 0) return void 0;
3178
- if (label === void 0) throw new Error(`Parameter 'label' cannot be undefined`);
3179
- if (node.value?.label === label) return node;
3180
- for (const c of node.childrenStore) if (c.value?.label === label) return c;
3181
- }
3182
- /**
3183
- * Searches children, returning the node that has the given `value`.
3184
- * @param value Value
3185
- * @param node Node to start search from
3186
- * @param maxDepth Maximum depth, defaults to full recursion
3187
- * @param eq Equality function
3188
- * @returns Child, or _undefined_ if not found
3189
- */
3190
- function findAnyChildByValue$1(value, node, maxDepth = Number.MAX_SAFE_INTEGER, eq = isEqualValueDefault) {
3191
- if (typeof node === `undefined`) throw new TypeError(`Param 'node' is undefined`);
3192
- if (maxDepth <= 0) return;
3193
- if (typeof value === `undefined`) throw new Error(`Param 'value' cannot be undefined`);
3194
- for (const c of node.childrenStore) if (hasValue(value, c, eq)) return c;
3195
- for (const c of node.childrenStore) {
3196
- const result = findAnyChildByValue$1(value, c, maxDepth - 1, eq);
3197
- if (typeof result !== `undefined`) return result;
3198
- }
3199
- }
3200
- function hasValue(value, node, eq = isEqualDefault) {
3201
- if (typeof node.value === `undefined`) return false;
3202
- if (isSingleValue(node.value)) {
3203
- if (eq(node.value.value, value)) return true;
3204
- } else if (isMultiValue(node.value)) {
3205
- for (const v of node.value.values) if (eq(v, value)) return true;
3206
- }
3207
- return false;
3208
- }
3209
- function valueByPath(path, node, pathOpts = {}) {
3210
- const values = valuesByPath(path, node, pathOpts);
3211
- if (typeof values === `undefined`) return;
3212
- if (values.length === 0) return void 0;
3213
- if (values.length > 1) throw new Error(`Multiple values at path. Use getValues instead`);
3214
- return values[0];
3215
- }
3216
- function getValuesFromNode(node) {
3217
- if (node.value === void 0) return [];
3218
- if (`values` in node.value) return node.value.values;
3219
- if (`value` in node.value) {
3220
- if (node.value.value === void 0) return [];
3221
- return [node.value.value];
3222
- }
3223
- return [];
3224
- }
3225
- function findChildByPath(path, searchStart, pathOpts) {
3226
- if (path.endsWith(pathOpts.separator) && pathOpts.startsWithSeparator) path = path.slice(0, -pathOpts.separator.length);
3227
- const split = path.split(pathOpts.separator);
3228
- let c = searchStart;
3229
- for (const p of split) {
3230
- c = findChildByLabel(p, c);
3231
- if (c === void 0) return;
3232
- }
3233
- return c;
3234
- }
3235
- function valuesByPath(path, searchStart, pathOpts = {}) {
3236
- const separator = pathOpts.separator ?? `.`;
3237
- const split = path.split(separator);
3238
- let c = searchStart;
3239
- for (const p of split) {
3240
- c = findChildByLabel(p, c);
3241
- if (c === void 0) return;
3242
- }
3243
- return getValuesFromNode(c);
3244
- }
3245
- function formatInspectValue(v) {
3246
- if (v === void 0) return `undefined`;
3247
- if (v === null) return `null`;
3248
- if (typeof v === `string`) return `"${v}"`;
3249
- if (typeof v === `number` || typeof v === `boolean`) return String(v);
3250
- if (Array.isArray(v)) {
3251
- if (v.length === 0) return `[]`;
3252
- return `[ ${v.map(formatInspectValue).join(`, `)} ]`;
3253
- }
3254
- if (typeof v === `object`) return `{ ${Object.entries(v).map(([k, val]) => `${k}: ${formatInspectValue(val)}`).join(`, `)} }`;
3255
- return String(v);
3256
- }
3257
- /**
3258
- * Returns a string representation of a LabelledNode tree.
3259
- * Format: `{ label: "x", value: ..., children: [...] }`
3260
- */
3261
- function toStringDeep$2(node) {
3262
- const label = node.value?.label ?? `?`;
3263
- const innerValue = node.value === void 0 ? void 0 : `values` in node.value ? node.value.values : `value` in node.value ? node.value.value : void 0;
3264
- const children = node.childrenStore.map((c) => toStringDeep$2(c));
3265
- const childrenStr = children.length === 0 ? `[]` : `[ ${children.join(`, `)} ]`;
3266
- return `{ label: "${label}", value: ${formatInspectValue(innerValue)}, children: ${childrenStr} }`;
3267
- }
3268
- var traversable_tree_exports = /* @__PURE__ */ __exportAll({
3269
- breadthFirst: () => breadthFirst$1,
3270
- childrenLength: () => childrenLength,
3271
- couldAddChild: () => couldAddChild,
3272
- depthFirst: () => depthFirst$1,
3273
- find: () => find$2,
3274
- findAnyChildByValue: () => findAnyChildByValue,
3275
- findAnyParentByValue: () => findAnyParentByValue,
3276
- findByValue: () => findByValue,
3277
- findChildByValue: () => findChildByValue,
3278
- findParentByValue: () => findParentByValue,
3279
- followValue: () => followValue,
3280
- hasAnyChild: () => hasAnyChild,
3281
- hasAnyChildValue: () => hasAnyChildValue,
3282
- hasAnyParent: () => hasAnyParent,
3283
- hasAnyParentValue: () => hasAnyParentValue,
3284
- hasChild: () => hasChild,
3285
- hasChildValue: () => hasChildValue,
3286
- hasParent: () => hasParent,
3287
- hasParentValue: () => hasParentValue,
3288
- parents: () => parents,
3289
- siblings: () => siblings,
3290
- toString: () => toString,
3291
- toStringDeep: () => toStringDeep$1
3292
- });
3293
- /**
3294
- * Returns the number of children of `tree`.
3295
- * Under the hood is just `[ ...tree.children() ].length`
3296
- * @param tree
3297
- * @returns
3298
- */
3299
- const childrenLength = (tree) => {
3300
- return [...tree.children()].length;
3301
- };
3302
- /**
3303
- * Returns _true_ if `child` is parented at any level (grand-parented etc) by `possibleParent`
3304
- * @param child Child being sought
3305
- * @param possibleParent Possible parent of child
3306
- * @param eq Equality comparison function {@link isEqualDefault} used by default
3307
- * @returns
3308
- */
3309
- const hasAnyParent = (child, possibleParent, eq) => {
3310
- return hasParent(child, possibleParent, eq, Number.MAX_SAFE_INTEGER);
3311
- };
3312
- /**
3313
- * Returns _true_ if `child` is parented at any level (grand-parented etc) by a parent with value `possibleParentValue`
3314
- * @param child Child being sought
3315
- * @param possibleParentValue Value of possible parent of child
3316
- * @param eq Equality comparison function {@link isEqualDefault} used by default
3317
- * @throws TypeError if `child` is undefined
3318
- * @returns
3319
- */
3320
- const hasAnyParentValue = (child, possibleParentValue, eq) => {
3321
- if (typeof child === `undefined`) throw new TypeError(`Param 'child' is undefined`);
3322
- return hasParentValue(child, possibleParentValue, eq, Number.MAX_SAFE_INTEGER);
3323
- };
3324
- /**
3325
- * Returns any parent of `child` that has value `possibleParentValue`. Returns _undefined_ if not found.
3326
- * @param child Child being sought
3327
- * @param possibleParentValue Value of possible parent of child
3328
- * @param eq Equality comparison function {@link isEqualDefault} used by default
3329
- * @returns
3330
- */
3331
- const findAnyParentByValue = (child, possibleParentValue, eq) => {
3332
- return findParentByValue(child, possibleParentValue, eq, Number.MAX_SAFE_INTEGER);
3333
- };
3334
- /**
3335
- * Returns _true_ if `child` exists within `possibleParent`. By default it only looks at the immediate
3336
- * parent (maxDepth: 0). Use Number.MAX_SAFE_INTEGER for searching recursively upwards (or {@link hasAnyParent})
3337
- * @param child Child being sought
3338
- * @param possibleParent Possible parent of child
3339
- * @param maxDepth Max depth of traversal. Default of 0 only looks for immediate parent.
3340
- * @param eq Equality comparison function. {@link isEqualDefault} used by default.
3341
- * @returns
3342
- */
3343
- const hasParent = (child, possibleParent, eq = isEqualDefault, maxDepth = 0) => {
3344
- if (maxDepth < 0) return false;
3345
- const isChildTrav = isTraversable(child);
3346
- const isParentTrav = isTraversable(possibleParent);
3347
- const p = isChildTrav ? child.getParent() : child.parent;
3348
- if (typeof p === `undefined`) return false;
3349
- if (eq(p, possibleParent)) return true;
3350
- if (eq(isChildTrav ? p.getIdentity() : p.value, isParentTrav ? possibleParent.getIdentity() : possibleParent.value)) return true;
3351
- return hasParent(p, possibleParent, eq, maxDepth - 1);
3352
- };
3353
- /**
3354
- * Checks if a child node has a parent with a certain value
3355
- * Note: by default only checks immediate parent. Set maxDepth to a large value to recurse
3356
- *
3357
- * Uses `getValue()` on the parent if that function exists.
3358
- * @param child Node to start looking from
3359
- * @param possibleParentValue Value to seek
3360
- * @param eq Equality checker
3361
- * @param maxDepth Defaults to 0, so it only checks immediate parent
3362
- * @returns
3363
- */
3364
- const hasParentValue = (child, possibleParentValue, eq = isEqualDefault, maxDepth = 0) => {
3365
- if (child === void 0) throw new Error(`Param 'child' is undefined`);
3366
- if (maxDepth < 0) return false;
3367
- const p = `getParent` in child ? child.getParent() : child.parent;
3368
- if (p === void 0) return false;
3369
- if (eq(`getValue` in p ? p.getValue() : p.value, possibleParentValue)) return true;
3370
- return hasParentValue(p, possibleParentValue, eq, maxDepth - 1);
3371
- };
3372
- /**
3373
- * Returns any parent of `child` that has value `possibleParentValue`. Returns _undefined_ if not found.
3374
- * @param child Child being sought
3375
- * @param possibleParentValue Value of possible parent of child
3376
- * @param eq Equality comparison function {@link isEqualDefault} used by default
3377
- * @param maxDepth Maximum depth of traversal. Default of 0 only looks for immediate parent.
3378
- * @returns
3379
- */
3380
- const findParentByValue = (child, possibleParentValue, eq = isEqualDefault, maxDepth = 0) => {
3381
- if (maxDepth < 0) return;
3382
- const p = `getParent` in child ? child.getParent() : child.parent;
3383
- if (p === void 0) return;
3384
- if (eq(`getValue` in p ? p.getValue() : p.value, possibleParentValue)) return p;
3385
- return findParentByValue(p, possibleParentValue, eq, maxDepth - 1);
3386
- };
3387
- /**
3388
- * Returns _true_ if `prospectiveChild` can be legally added to `parent`.
3389
- * _False_ is returned if:
3390
- * * `parent` and `prospectiveChild` are equal
3391
- * * `parent` already contains `prospectiveChild`
3392
- * * `prospectiveChild` has `parent` as its own child
3393
- *
3394
- * Throws an error if `parent` or `prospectiveChild` is null/undefined.
3395
- * @param parent Parent to add to
3396
- * @param prospectiveChild Prospective child
3397
- * @param eq Equality function
3398
- */
3399
- const couldAddChild = (parent, prospectiveChild, eq = isEqualDefault) => {
3400
- if (eq(parent, prospectiveChild)) throw new Error(`Child equals parent`);
3401
- if (hasAnyChild(parent, prospectiveChild, eq)) throw new Error(`Circular. Parent already has child`);
3402
- if (hasAnyChild(prospectiveChild, parent, eq)) throw new Error(`Prospective child has parent as child relation`);
3403
- };
3404
- /**
3405
- * Returns _true_ if _possibleChild_ is contained within _parent_ tree.
3406
- * That is, it is any sub-child.
3407
- * @param parent Parent tree
3408
- * @param possibleChild Sought child
3409
- * @param eq Equality function, or {@link isEqualDefault} if undefined.
3410
- * @returns
3411
- */
3412
- const hasAnyChild = (parent, possibleChild, eq = isEqualDefault) => {
3413
- return hasChild(parent, possibleChild, eq, Number.MAX_SAFE_INTEGER);
3414
- };
3415
- /**
3416
- * Returns _true_ if `parent` has any child with value `possibleChildValue`. It explores
3417
- * at children at any depth from `parent`.
3418
- * @param parent
3419
- * @param possibleChildValue
3420
- * @param eq
3421
- * @returns
3422
- */
3423
- const hasAnyChildValue = (parent, possibleChildValue, eq = isEqualDefault) => {
3424
- return hasChildValue(parent, possibleChildValue, eq, Number.MAX_SAFE_INTEGER);
3425
- };
3426
- /**
3427
- * Returns _true_ if _possibleChild_ is contained within _maxDepth_ children
3428
- * of _parent_ node. By default only looks at immediate children (maxDepth = 0).
3429
- *
3430
- * ```js
3431
- * // Just check parentNode for childNode
3432
- * Trees.hasChild(parentNode, childNode);
3433
- * // See if parentNode or parentNode's parents have childNode
3434
- * Trees.hasChild(parentNode, childNode, 1);
3435
- * // Use custom equality function, in this case comparing on name field
3436
- * Trees.hasChild(parentNode, childNode, 0, (a, b) => a.name === b.name);
3437
- * ```
3438
- * @param parent Parent tree
3439
- * @param possibleChild Sought child
3440
- * @param maxDepth Maximum depth. 0 for immediate children, Number.MAX_SAFE_INTEGER for boundless
3441
- * @param eq Equality function, or {@link isEqualDefault} if undefined.
3442
- * @returns
3443
- */
3444
- const hasChild = (parent, possibleChild, eq = isEqualDefault, maxDepth = 0) => {
3445
- if (maxDepth < 0) return false;
3446
- if (eq(parent, possibleChild)) return true;
3447
- const pId = `getIdentity` in parent ? parent.getIdentity() : parent.value;
3448
- const pcId = `getIdentity` in possibleChild ? possibleChild.getIdentity() : possibleChild.value;
3449
- if (eq(pId, pcId)) return true;
3450
- for (const c of breadthFirst$1(parent, maxDepth)) {
3451
- const cId = `getIdentity` in c ? c.getIdentity() : c.value;
3452
- if (eq(c, possibleChild)) return true;
3453
- if (eq(cId, pcId)) return true;
3454
- }
3455
- return false;
3456
- };
3457
- /**
3458
- * Returns _true_ if `parent` has any child with value `possibleChildValue`. It explores
3459
- * at children up to `maxDepth` from `parent`. By default only looks at immediate children (maxDepth = 0).
3460
- * @param parent
3461
- * @param possibleValue
3462
- * @param eq
3463
- * @param maxDepth
3464
- * @returns
3465
- */
3466
- const hasChildValue = (parent, possibleValue, eq = isEqualDefault, maxDepth = 0) => {
3467
- if (maxDepth < 0) return false;
3468
- if (eq(parent.getValue(), possibleValue)) return true;
3469
- for (const c of breadthFirst$1(parent, maxDepth)) if (eq(c.getValue(), possibleValue)) return true;
3470
- return false;
3471
- };
3472
- /**
3473
- * Iterates over siblings of `node`.
3474
- *
3475
- * Other iteration options:
3476
- * * {@link breadthFirst}: Children, breadth-first
3477
- * * {@link depthFirst}: Children, depth-first
3478
- * * {@link parents}: Chain of parents, starting with immediate parent
3479
- * * {@link siblings}: Nodes with same parent
3480
- * @param node Node to begin from
3481
- * @returns
3482
- */
3483
- function* siblings(node) {
3484
- const p = node.getParent();
3485
- if (p === void 0) return;
3486
- for (const s of p.children()) {
3487
- if (s === node) continue;
3488
- yield s;
3489
- }
3490
- }
3491
- /**
3492
- * Iterates over parents of `node`, starting with immediate parent
3493
- *
3494
- * Other iteration options:
3495
- * * {@link breadthFirst}: Children, breadth-first
3496
- * * {@link depthFirst}: Children, depth-first
3497
- * * {@link parents}: Chain of parents, starting with immediate parent
3498
- * * {@link siblings}: Nodes with same parent
3499
- * @param node Node to begin from
3500
- * @returns
3501
- */
3502
- function* parents(node) {
3503
- if (isTraversable(node)) {
3504
- let p = node.getParent();
3505
- while (p !== void 0) {
3506
- yield p;
3507
- p = p.getParent();
3508
- }
3509
- } else {
3510
- let p = node.parent;
3511
- while (p !== void 0) {
3512
- yield p;
3513
- p = p.parent;
3514
- }
3515
- }
3516
- }
3517
- /**
3518
- * Descends `parent`, breadth-first, looking for a particular value.
3519
- * Returns _undefined_ if not found.
3520
- * @param parent
3521
- * @param possibleValue
3522
- * @param eq
3523
- * @returns
3524
- */
3525
- function findAnyChildByValue(parent, possibleValue, eq = isEqualDefault) {
3526
- return findChildByValue(parent, possibleValue, eq, Number.MAX_SAFE_INTEGER);
3527
- }
3528
- /**
3529
- * Searches breadth-first for `possibleValue` under and including `parent`.
3530
- * `maxDepth` sets he maximum level to which the tree is searched.
3531
- * @param parent
3532
- * @param possibleValue
3533
- * @param eq
3534
- * @param maxDepth
3535
- * @returns
3536
- */
3537
- function findChildByValue(parent, possibleValue, eq = isEqualDefault, maxDepth = 0) {
3538
- if (maxDepth < 0) return;
3539
- const isTraver = isTraversable(parent);
3540
- if (isTraver) {
3541
- if (eq(parent.getValue(), possibleValue)) return parent;
3542
- } else if (eq(parent.value, possibleValue)) return parent;
3543
- for (const d of breadthFirst$1(parent, maxDepth)) if (isTraver) {
3544
- if (eq(d.getValue(), possibleValue)) return d;
3545
- } else if (eq(d.value, possibleValue)) return d;
3546
- }
3547
- /**
3548
- * Iterates over children of `root`, depth-first.
3549
- *
3550
- * Other iteration options:
3551
- * * {@link breadthFirst}: Children, breadth-first
3552
- * * {@link depthFirst}: Children, depth-first
3553
- * * {@link parents}: Chain of parents, starting with immediate parent
3554
- * * {@link siblings}: Nodes with same parent
3555
- * @param root Root node
3556
- * @returns
3557
- */
3558
- function* depthFirst$1(root) {
3559
- if (!root) return;
3560
- const stack = new StackMutable();
3561
- let entry = root;
3562
- while (entry) {
3563
- const entries = isTraversable(entry) ? [...entry.children()] : [...entry.childrenStore];
3564
- stack.push(...entries);
3565
- if (stack.isEmpty) break;
3566
- entry = stack.pop();
3567
- if (entry) yield entry;
3568
- }
3569
- }
3570
- /**
3571
- * Iterates over the children of `root`, breadth-first
3572
- *
3573
- * Other iteration options:
3574
- * * {@link breadthFirst}: Children, breadth-first
3575
- * * {@link depthFirst}: Children, depth-first
3576
- * * {@link parents}: Chain of parents, starting with immediate parent
3577
- * * {@link siblings}: Nodes with same parent
3578
- *
3579
- * @example Traversing over a simple object
3580
- * ```js
3581
- * const myObj = { name: `Pedro`, size: 45, colour: `orange` };
3582
- * const root = Trees.FromObject.asDynamicTraversable(myObj);
3583
- * for (const v of Trees.Traverse.breadthFirst(root)) {
3584
- * // v.getValue() yields:
3585
- * // { name: 'name', sourceValue: 'Pedro' ...},
3586
- * // { name: 'size', sourceValue: 45 ... }
3587
- * // ...
3588
- * }
3589
- * ```
3590
- * @param root Root node
3591
- * @param depth How many levels to traverse
3592
- * @returns
3593
- */
3594
- function* breadthFirst$1(root, depth = Number.MAX_SAFE_INTEGER) {
3595
- if (!root) return;
3596
- const queue = isTraversable(root) ? new QueueMutable() : new QueueMutable();
3597
- let entry = root;
3598
- while (entry) {
3599
- if (depth < 0) return;
3600
- if (entry !== void 0) {
3601
- const kids = `childrenStore` in entry ? entry.childrenStore : entry.children();
3602
- for (const c of kids) {
3603
- yield c;
3604
- queue.enqueue(c);
3605
- }
3606
- }
3607
- entry = queue.dequeue();
3608
- depth--;
3609
- }
3610
- }
3611
- /**
3612
- * Applies `predicate` to `root` and all its child nodes, returning the node where
3613
- * `predicate` yields _true_.
3614
- * Use {@link findByValue} to find a node by its value
3615
- * @param root
3616
- * @param predicate
3617
- * @param order Iterate children by breadth or depth. Default 'breadth'
3618
- * @returns
3619
- */
3620
- function find$2(root, predicate, order = `breadth`) {
3621
- if (predicate(root)) return root;
3622
- const iter = order === `breadth` ? breadthFirst$1 : depthFirst$1;
3623
- for (const c of iter(root)) if (predicate(c)) return c;
3624
- }
3625
- /**
3626
- * Applies `predicate` to `root` and all its child nodes, returning the node value for
3627
- * `predicate` yields _true_.
3628
- * Use {@link find} to filter by nodes rather than values
3629
- *
3630
- * ```js
3631
- * const n = findByValue(root, (v) => v.name === 'Bob');
3632
- * ```
3633
- * @param root
3634
- * @param predicate
3635
- * @param order Iterate children by breadth or depth. Default 'breadth'
3636
- * @returns
3637
- */
3638
- function findByValue(root, predicate, order = `breadth`) {
3639
- if (predicate(root.getValue())) return root;
3640
- const iter = order === `breadth` ? breadthFirst$1 : depthFirst$1;
3641
- for (const c of iter(root)) if (predicate(c.getValue())) return c;
3642
- }
3643
- /**
3644
- * Search through children in a path-like manner.
3645
- *
3646
- * It finds the first child of `root` that matches `continuePredicate`.
3647
- * The function gets passed a depth of 1 to begin with. It recurses, looking for the next sub-child, etc.
3648
- *
3649
- * If it can't find a child, it stops.
3650
- *
3651
- * This is different to 'find' functions, which exhaustively search all possible child nodes, regardless of position in tree.
3652
- *
3653
- * ```js
3654
- * const path = 'a.aa.aaa'.split('.');
3655
- * const pred = (nodeValue, depth) => {
3656
- * if (nodeValue === path[0]) {
3657
- * path.shift(); // Remove first element
3658
- * return true;
3659
- * }
3660
- * return false;
3661
- * }
3662
- *
3663
- * // Assuming we have a tree of string values:
3664
- * // a
3665
- * // - aa
3666
- * // - aaa
3667
- * // - ab
3668
- * // b
3669
- * // - ba
3670
- * for (const c of follow(tree, pred)) {
3671
- * // Returns nodes: a, aa and then aaa
3672
- * }
3673
- * ```
3674
- * @param root
3675
- * @param continuePredicate
3676
- * @param depth
3677
- */
3678
- function* followValue(root, continuePredicate, depth = 1) {
3679
- for (const c of root.children()) if (continuePredicate(c.getValue(), depth)) {
3680
- yield c.getValue();
3681
- yield* followValue(c, continuePredicate, depth + 1);
3682
- }
3683
- }
3684
- function toStringDeep$1(node, depth = 0) {
3685
- if (node === void 0) return `(undefined)`;
3686
- if (node === null) return `(null)`;
3687
- const v = node.getValue();
3688
- let type = typeof v;
3689
- if (Array.isArray(v)) type = `array`;
3690
- let t = ` `.repeat(depth) + `value: ${JSON.stringify(v)} (${type})\n`;
3691
- for (const n of node.children()) t += toStringDeep$1(n, depth + 1);
3692
- return t;
3693
- }
3694
- function toString(...nodes) {
3695
- let t = ``;
3696
- for (const node of nodes) {
3697
- const v = node.getValue();
3698
- const vString = toStringAbbreviate(v);
3699
- const children = [...node.children()];
3700
- const parent = node.getParent();
3701
- let type = typeof v;
3702
- if (Array.isArray(v)) type = `array`;
3703
- t += `value: ${vString} (${type}) kids: ${children.length} parented: ${parent ? `y` : `n`}\n`;
3704
- }
3705
- return t;
3706
- }
3707
- var binary_tree_exports = /* @__PURE__ */ __exportAll({
3708
- addLeft: () => addLeft,
3709
- addRight: () => addRight,
3710
- balanceFactor: () => balanceFactor,
3711
- breadthFirst: () => breadthFirst,
3712
- createNode: () => createNode,
3713
- depthFirst: () => depthFirst,
3714
- find: () => find$1,
3715
- fromArray: () => fromArray$1,
3716
- getLeft: () => getLeft,
3717
- getRight: () => getRight,
3718
- grandparent: () => grandparent,
3719
- hasLeft: () => hasLeft,
3720
- hasRight: () => hasRight,
3721
- height: () => height,
3722
- inOrder: () => inOrder$1,
3723
- isLeaf: () => isLeaf,
3724
- isParentLeftChild: () => isParentLeftChild,
3725
- isParentRightChild: () => isParentRightChild,
3726
- leftSubtreeHeightFn: () => leftSubtreeHeightFn,
3727
- parentChildSide: () => parentChildSide,
3728
- postOrder: () => postOrder$1,
3729
- preOrder: () => preOrder$1,
3730
- removeNode: () => removeNode,
3731
- rightSubtreeHeightFn: () => rightSubtreeHeightFn,
3732
- root: () => root$1,
3733
- rootWrapped: () => rootWrapped,
3734
- setLeft: () => setLeft,
3735
- setRight: () => setRight,
3736
- sibling: () => sibling,
3737
- toArray: () => toArray,
3738
- toStringDeep: () => toStringDeep,
3739
- uncle: () => uncle,
3740
- wrap: () => wrap
3741
- });
3742
- const getLeftChild = (node) => {
3743
- return node.childrenStore[0];
3744
- };
3745
- const getRightChild = (node) => {
3746
- return node.childrenStore[1];
3747
- };
3748
- const getLeft = (node) => {
3749
- return getLeftChild(node);
3750
- };
3751
- const getRight = (node) => {
3752
- return getRightChild(node);
3753
- };
3754
- const hasLeft = (node) => {
3755
- return getLeftChild(node) !== void 0;
3756
- };
3757
- const hasRight = (node) => {
3758
- return getRightChild(node) !== void 0;
3759
- };
3760
- const isLeaf = (node) => {
3761
- return !hasLeft(node) && !hasRight(node);
3762
- };
3763
- const setLeft = (parent, child) => {
3764
- const existingLeft = getLeftChild(parent);
3765
- if (existingLeft) existingLeft.parent = void 0;
3766
- const children = [...parent.childrenStore];
3767
- if (child === void 0 && children.length <= 1) {
3768
- parent.childrenStore = [];
3769
- return;
3770
- } else if (child === void 0) {
3771
- children[0] = void 0;
3772
- parent.childrenStore = children;
3773
- return;
3774
- }
3775
- if (children.length === 0) children.push(child);
3776
- else children[0] = child;
3777
- parent.childrenStore = children;
3778
- child.parent = parent;
3779
- };
3780
- const setRight = (parent, child) => {
3781
- const existingRight = getRightChild(parent);
3782
- if (existingRight) existingRight.parent = void 0;
3783
- const children = [...parent.childrenStore];
3784
- if (child === void 0) {
3785
- if (children.length >= 2) {
3786
- children[1] = void 0;
3787
- if (children[0] === void 0) parent.childrenStore = [];
3788
- else parent.childrenStore = children;
3789
- }
3790
- return;
3791
- }
3792
- if (children.length === 0) children.push(void 0, child);
3793
- else if (children.length === 1) children.push(child);
3794
- else children[1] = child;
3795
- parent.childrenStore = children;
3796
- child.parent = parent;
3797
- };
3798
- const removeNode = (node) => {
3799
- const p = node.parent;
3800
- if (!p) return;
3801
- if (p.childrenStore[0] === node) setLeft(p, void 0);
3802
- else if (p.childrenStore[1] === node) setRight(p, void 0);
3803
- };
3804
- const sibling = (node) => {
3805
- const parent = node.parent;
3806
- if (!parent) return void 0;
3807
- const left = getLeftChild(parent);
3808
- const right = getRightChild(parent);
3809
- if (left === node) return right;
3810
- if (right === node) return left;
3811
- };
3812
- const uncle = (node) => {
3813
- const parent = node.parent;
3814
- if (!parent) return void 0;
3815
- return sibling(parent);
3816
- };
3817
- const grandparent = (node) => {
3818
- const parent = node.parent;
3819
- if (!parent) return void 0;
3820
- return parent.parent;
3821
- };
3822
- const isParentLeftChild = (node) => {
3823
- const parent = node.parent;
3824
- if (!parent) return false;
3825
- return getLeftChild(parent) === node;
3826
- };
3827
- const isParentRightChild = (node) => {
3828
- const parent = node.parent;
3829
- if (!parent) return false;
3830
- return getRightChild(parent) === node;
3831
- };
3832
- const parentChildSide = (node) => {
3833
- if (!node.parent) return `neutral`;
3834
- return isParentLeftChild(node) ? `left` : `right`;
3835
- };
3836
- const leftSubtreeHeight = (node) => {
3837
- const left = getLeftChild(node);
3838
- return left ? subtreeHeight(left) + 1 : 0;
3839
- };
3840
- const rightSubtreeHeight = (node) => {
3841
- const right = getRightChild(node);
3842
- return right ? subtreeHeight(right) + 1 : 0;
3843
- };
3844
- const subtreeHeight = (node) => {
3845
- return Math.max(leftSubtreeHeight(node), rightSubtreeHeight(node));
3846
- };
3847
- const height = (node) => {
3848
- return subtreeHeight(node);
3849
- };
3850
- const balanceFactor = (node) => {
3851
- return leftSubtreeHeight(node) - rightSubtreeHeight(node);
3852
- };
3853
- const leftSubtreeHeightFn = leftSubtreeHeight;
3854
- const rightSubtreeHeightFn = rightSubtreeHeight;
3855
- const addLeft = (value, parent) => {
3856
- const existingLeft = getLeftChild(parent);
3857
- if (existingLeft) existingLeft.parent = void 0;
3858
- const child = {
3859
- value,
3860
- parent,
3861
- childrenStore: []
3862
- };
3863
- const children = [...parent.childrenStore];
3864
- if (children.length === 0) children.push(child);
3865
- else if (children.length === 1) children[0] = child;
3866
- else children[0] = child;
3867
- parent.childrenStore = children;
3868
- return child;
3869
- };
3870
- const addRight = (value, parent) => {
3871
- const existingRight = getRightChild(parent);
3872
- if (existingRight) existingRight.parent = void 0;
3873
- const child = {
3874
- value,
3875
- parent,
3876
- childrenStore: []
3877
- };
3878
- const children = [...parent.childrenStore];
3879
- if (children.length === 0) {
3880
- children.push(void 0);
3881
- children.push(child);
3882
- } else if (children.length === 1) children.push(child);
3883
- else children[1] = child;
3884
- parent.childrenStore = children;
3885
- return child;
3886
- };
3887
- const root$1 = (value) => {
3888
- return root$2(value);
3889
- };
3890
- const createNode = (value, parent) => {
3891
- return createNode$1(value, parent);
3892
- };
3893
- const unwrapNode = (node) => {
3894
- return `node` in node ? node.node : node;
3895
- };
3896
- const wrapNode = (node) => {
3897
- return wrap(node);
3898
- };
3899
- const wrap = (node) => {
3900
- return {
3901
- node,
3902
- get left() {
3903
- const left = getLeftChild(node);
3904
- return left ? wrapNode(left) : void 0;
3905
- },
3906
- get right() {
3907
- const right = getRightChild(node);
3908
- return right ? wrapNode(right) : void 0;
3909
- },
3910
- set left(value) {
3911
- setLeft(node, value ? unwrapNode(value) : void 0);
3912
- },
3913
- set right(value) {
3914
- setRight(node, value ? unwrapNode(value) : void 0);
3915
- },
3916
- get parentChildSide() {
3917
- return parentChildSide(node);
3918
- },
3919
- get isParentLeftChild() {
3920
- return isParentLeftChild(node);
3921
- },
3922
- get isParentRightChild() {
3923
- return isParentRightChild(node);
3924
- },
3925
- get isLeaf() {
3926
- return isLeaf(node);
3927
- },
3928
- get sibling() {
3929
- const sib = sibling(node);
3930
- return sib ? wrapNode(sib) : void 0;
3931
- },
3932
- get uncle() {
3933
- const unc = uncle(node);
3934
- return unc ? wrapNode(unc) : void 0;
3935
- },
3936
- get grandparent() {
3937
- const gp = grandparent(node);
3938
- return gp ? wrapNode(gp) : void 0;
3939
- },
3940
- get leftSubtreeHeight() {
3941
- return leftSubtreeHeight(node);
3942
- },
3943
- get rightSubtreeHeight() {
3944
- return rightSubtreeHeight(node);
3945
- },
3946
- get height() {
3947
- return height(node);
3948
- },
3949
- get balanceFactor() {
3950
- return balanceFactor(node);
3951
- },
3952
- has(value) {
3953
- return find$1(node, value) !== void 0;
3954
- },
3955
- addLeft(value) {
3956
- return wrapNode(addLeft(value, node));
3957
- },
3958
- addRight(value) {
3959
- return wrapNode(addRight(value, node));
3960
- },
3961
- setLeft(nodeOrWrapped) {
3962
- setLeft(node, unwrapNode(nodeOrWrapped));
3963
- },
3964
- setRight(nodeOrWrapped) {
3965
- setRight(node, unwrapNode(nodeOrWrapped));
3966
- },
3967
- remove() {
3968
- removeNode(node);
3969
- }
3970
- };
3971
- };
3972
- const rootWrapped = (value) => {
3973
- return wrap(root$2(value));
3974
- };
3975
- const find$1 = (root, value) => {
3976
- for (const n of breadthFirst(root)) if (n.value === value) return n;
3977
- };
3978
- function* inOrder$1(node) {
3979
- const left = getLeftChild(node);
3980
- if (left) yield* inOrder$1(left);
3981
- yield node;
3982
- const right = getRightChild(node);
3983
- if (right) yield* inOrder$1(right);
3984
- }
3985
- function* preOrder$1(node) {
3986
- yield node;
3987
- const left = getLeftChild(node);
3988
- if (left) yield* preOrder$1(left);
3989
- const right = getRightChild(node);
3990
- if (right) yield* preOrder$1(right);
3991
- }
3992
- function* postOrder$1(node) {
3993
- const left = getLeftChild(node);
3994
- if (left) yield* postOrder$1(left);
3995
- const right = getRightChild(node);
3996
- if (right) yield* postOrder$1(right);
3997
- yield node;
3998
- }
3999
- function* depthFirst(node) {
4000
- const left = getLeftChild(node);
4001
- const right = getRightChild(node);
4002
- if (left) yield* depthFirst(left);
4003
- if (right) yield* depthFirst(right);
4004
- yield node;
4005
- }
4006
- function* breadthFirst(node) {
4007
- yield node;
4008
- const queue = [];
4009
- queue.push(...node.childrenStore.filter((c) => c !== void 0 && c.value !== void 0));
4010
- while (queue.length > 0) {
4011
- const current = queue.shift();
4012
- yield current;
4013
- queue.push(...current.childrenStore.filter((c) => c !== void 0 && c.value !== void 0));
4014
- }
4015
- }
4016
- const fromArray$1 = (array) => {
4017
- if (array.length === 0) return void 0;
4018
- const rootNode = root$2(array[0]);
4019
- const insert = (index, parent) => {
4020
- const leftIdx = 2 * index + 1;
4021
- const rightIdx = 2 * index + 2;
4022
- if (leftIdx < array.length) {
4023
- addLeft(array[leftIdx], parent);
4024
- insert(leftIdx, getLeftChild(parent));
4025
- }
4026
- if (rightIdx < array.length) {
4027
- addRight(array[rightIdx], parent);
4028
- insert(rightIdx, getRightChild(parent));
4029
- }
4030
- };
4031
- insert(0, rootNode);
4032
- return rootNode;
4033
- };
4034
- const toArray = (root) => {
4035
- const result = [];
4036
- for (const node of breadthFirst(root)) if (node.value !== void 0) result.push(node.value);
4037
- return result;
4038
- };
4039
- const toStringDeep = (node, indent = 0) => {
4040
- const v = node.value !== void 0 ? JSON.stringify(node.value) : `-`;
4041
- const prefix = ` `.repeat(indent);
4042
- const left = getLeftChild(node);
4043
- const right = getRightChild(node);
4044
- let result = `${prefix}${v}`;
4045
- if (left || right) {
4046
- result += `\n`;
4047
- if (left) {
4048
- result += `${prefix} L: ${toStringDeep(left, indent + 1)}`;
4049
- if (right) result += `\n`;
4050
- }
4051
- if (right) result += `${prefix} R: ${toStringDeep(right, indent + 1)}`;
4052
- }
4053
- return result;
4054
- };
4055
- var binary_search_tree_exports = /* @__PURE__ */ __exportAll({
4056
- Bst: () => Bst,
4057
- create: () => create,
4058
- find: () => find,
4059
- fromArray: () => fromArray,
4060
- has: () => has,
4061
- inOrder: () => inOrder,
4062
- insert: () => insert,
4063
- max: () => max,
4064
- min: () => min,
4065
- postOrder: () => postOrder,
4066
- preOrder: () => preOrder,
4067
- remove: () => remove,
4068
- root: () => root,
4069
- valuesInOrder: () => valuesInOrder
4070
- });
4071
- var Bst = class {
4072
- root;
4073
- comparer;
4074
- constructor(comparer = defaultComparer) {
4075
- this.comparer = comparer;
4076
- this.root = root$1();
4077
- }
4078
- insert(value) {
4079
- this.root = insert(this.root, value, this.comparer);
4080
- return this.root;
4081
- }
4082
- has(value) {
4083
- return has(this.root, value, this.comparer);
4084
- }
4085
- find(value) {
4086
- return find(this.root, value, this.comparer);
4087
- }
4088
- remove(value) {
4089
- const result = remove(this.root, value, this.comparer);
4090
- if (result) this.root = result;
4091
- return result !== void 0;
4092
- }
4093
- min() {
4094
- return min(this.root);
4095
- }
4096
- max() {
4097
- return max(this.root);
4098
- }
4099
- inOrder() {
4100
- return inOrder(this.root);
4101
- }
4102
- preOrder() {
4103
- return preOrder(this.root);
4104
- }
4105
- postOrder() {
4106
- return postOrder(this.root);
4107
- }
4108
- valuesInOrder() {
4109
- return valuesInOrder(this.root);
4110
- }
4111
- toArrayInOrder() {
4112
- return Array.from(this.valuesInOrder());
4113
- }
4114
- };
4115
- const insert = (root, value, compare = defaultComparer) => {
4116
- if (root.value === void 0) {
4117
- root.value = value;
4118
- return root;
4119
- }
4120
- let current = root;
4121
- while (true) {
4122
- const cmp = compare(value, current.value);
4123
- if (cmp < 0) {
4124
- const left = getLeft(current);
4125
- if (left) current = left;
4126
- else {
4127
- addLeft(value, current);
4128
- break;
4129
- }
4130
- } else if (cmp > 0) {
4131
- const right = getRight(current);
4132
- if (right) current = right;
4133
- else {
4134
- addRight(value, current);
4135
- break;
4136
- }
4137
- } else break;
4138
- }
4139
- return root;
4140
- };
4141
- const has = (root, value, compare = defaultComparer) => {
4142
- return find(root, value, compare) !== void 0;
4143
- };
4144
- const find = (root, value, compare = defaultComparer) => {
4145
- if (!root || root.value === void 0) return void 0;
4146
- const cmp = compare(value, root.value);
4147
- if (cmp === 0) return root;
4148
- else if (cmp < 0) {
4149
- const left = getLeft(root);
4150
- return left ? find(left, value, compare) : void 0;
4151
- } else {
4152
- const right = getRight(root);
4153
- return right ? find(right, value, compare) : void 0;
4154
- }
4155
- };
4156
- const min = (root) => {
4157
- if (!root || root.value === void 0) return void 0;
4158
- let current = root;
4159
- while (getLeft(current)) current = getLeft(current);
4160
- return current;
4161
- };
4162
- const max = (root) => {
4163
- if (!root || root.value === void 0) return void 0;
4164
- let current = root;
4165
- while (getRight(current)) current = getRight(current);
4166
- return current;
4167
- };
4168
- const remove = (root, value, compare = defaultComparer) => {
4169
- if (!root || root.value === void 0) return void 0;
4170
- const nodeToRemove = find(root, value, compare);
4171
- if (!nodeToRemove) return;
4172
- const left = getLeft(nodeToRemove);
4173
- const right = getRight(nodeToRemove);
4174
- if (!left && !right) if (nodeToRemove === root) {
4175
- root.value = void 0;
4176
- root.childrenStore = [];
4177
- } else removeNode(nodeToRemove);
4178
- else if (!left) if (nodeToRemove === root) {
4179
- root.value = right.value;
4180
- root.childrenStore = right.childrenStore;
4181
- for (const child of root.childrenStore) if (child) child.parent = root;
4182
- } else {
4183
- const parent = nodeToRemove.parent;
4184
- if (getLeft(parent) === nodeToRemove) setLeft(parent, right);
4185
- else setRight(parent, right);
4186
- }
4187
- else if (!right) if (nodeToRemove === root) {
4188
- root.value = left.value;
4189
- root.childrenStore = left.childrenStore;
4190
- for (const child of root.childrenStore) if (child) child.parent = root;
4191
- } else {
4192
- const parent = nodeToRemove.parent;
4193
- if (getLeft(parent) === nodeToRemove) setLeft(parent, left);
4194
- else setRight(parent, left);
4195
- }
4196
- else {
4197
- const successor = min(right);
4198
- nodeToRemove.value = successor.value;
4199
- const succParent = successor.parent;
4200
- const succRight = getRight(successor);
4201
- if (getLeft(succParent) === successor) setLeft(succParent, succRight);
4202
- else setRight(succParent, succRight);
4203
- }
4204
- return root;
4205
- };
4206
- function* inOrder(node) {
4207
- if (!node) return;
4208
- const left = getLeft(node);
4209
- if (left) yield* inOrder(left);
4210
- yield node;
4211
- const right = getRight(node);
4212
- if (right) yield* inOrder(right);
4213
- }
4214
- function* preOrder(node) {
4215
- if (!node) return;
4216
- yield node;
4217
- const left = getLeft(node);
4218
- if (left) yield* preOrder(left);
4219
- const right = getRight(node);
4220
- if (right) yield* preOrder(right);
4221
- }
4222
- function* postOrder(node) {
4223
- if (!node) return;
4224
- const left = getLeft(node);
4225
- if (left) yield* postOrder(left);
4226
- const right = getRight(node);
4227
- if (right) yield* postOrder(right);
4228
- yield node;
4229
- }
4230
- function* valuesInOrder(node) {
4231
- for (const n of inOrder(node)) if (n.value !== void 0) yield n.value;
4232
- }
4233
- const create = (comparer) => {
4234
- return new Bst(comparer);
4235
- };
4236
- const fromArray = (array, comparer = defaultComparer) => {
4237
- const bst = new Bst(comparer);
4238
- for (const value of array) bst.insert(value);
4239
- return bst;
4240
- };
4241
- const root = () => {
4242
- return root$1();
4243
- };
4244
- var tree_exports = /* @__PURE__ */ __exportAll({
4245
- BinarySearchTree: () => binary_search_tree_exports,
4246
- BinaryTree: () => binary_tree_exports,
4247
- FromObject: () => traverse_object_exports,
4248
- Mutable: () => tree_mutable_exports,
4249
- Pathed: () => pathed_exports,
4250
- Traverse: () => traversable_tree_exports,
4251
- compare: () => compare$1,
4252
- isMultiValue: () => isMultiValue,
4253
- isSingleValue: () => isSingleValue,
4254
- isTraversable: () => isTraversable,
4255
- isTreeNode: () => isTreeNode,
4256
- toTraversable: () => toTraversable
4257
- });
4258
- /**
4259
- * Makes a 'traversable' to move around a {@link TreeNode},
4260
- * an existing {@link TraversableTree} or a plain object.
4261
- *
4262
- * @param node
4263
- * @returns
4264
- */
4265
- const toTraversable = (node) => {
4266
- if (isTraversable(node)) return node;
4267
- if (isTreeNode(node)) return asDynamicTraversable$1(node);
4268
- if (typeof node === `object`) return asDynamicTraversable(node);
4269
- throw new Error(`Parameter 'node' not convertible`);
4270
- };
4271
- /**
4272
- * Checks whether `node` is of type {@link TreeNode}.
4273
- *
4274
- * Checks for: parent, childrenStore and value defined on `node`.
4275
- * @param node
4276
- * @returns
4277
- */
4278
- const isTreeNode = (node) => {
4279
- if (`parent` in node && `childrenStore` in node && `value` in node) {
4280
- if (Array.isArray(node.childrenStore)) return true;
1548
+ ];
4281
1549
  }
4282
- return false;
4283
- };
4284
- /**
4285
- * Checks if `node` is of type {@link TraversableTree}.
4286
- *
4287
- * Checks by looking for: children, getParent, getValue and getIdentity defined on `node`.
4288
- * @param node
4289
- * @returns
4290
- */
4291
- const isTraversable = (node) => {
4292
- return `children` in node && `getParent` in node && `getValue` in node && `getIdentity` in node;
4293
1550
  };
1551
+ __decorate([property({ attribute: false })], SplitButton.prototype, "registry", void 0);
1552
+ __decorate([property({ attribute: false })], SplitButton.prototype, "keyboardManager", void 0);
1553
+ __decorate([property({ type: String })], SplitButton.prototype, "mode", void 0);
1554
+ __decorate([property({
1555
+ type: String,
1556
+ attribute: `default-value`
1557
+ })], SplitButton.prototype, "defaultValue", void 0);
1558
+ __decorate([property({ attribute: false })], SplitButton.prototype, "itemsProvider", void 0);
1559
+ __decorate([property({ attribute: false })], SplitButton.prototype, "items", void 0);
1560
+ __decorate([query(`ixfx-menu-trigger`)], SplitButton.prototype, "_menuTrigger", void 0);
1561
+ __decorate([state()], SplitButton.prototype, "_compact", void 0);
1562
+ __decorate([state()], SplitButton.prototype, "_selectedCommand", void 0);
1563
+ __decorate([state()], SplitButton.prototype, "_selectedLabel", void 0);
1564
+ __decorate([state()], SplitButton.prototype, "_selectedIcon", void 0);
1565
+ __decorate([state()], SplitButton.prototype, "_switcherItems", void 0);
1566
+ __decorate([state()], SplitButton.prototype, "_dynamicItems", void 0);
1567
+ __decorate([state()], SplitButton.prototype, "_loadingItems", void 0);
1568
+ __decorate([state()], SplitButton.prototype, "_menuHasItems", void 0);
1569
+ SplitButton = __decorate([safeCustomElement(`ixfx-split-button`)], SplitButton);
4294
1570
  //#endregion
4295
1571
  //#region src/crumbs/crumb-path-controller.ts
4296
1572
  var CrumbPathController = class {
@@ -4301,7 +1577,7 @@ var CrumbPathController = class {
4301
1577
  constructor(options = {}) {
4302
1578
  this.#separator = options.separator ?? `/`;
4303
1579
  this.#onQuery = options.onQuery;
4304
- this.#pathed = new tree_exports.Pathed.Pathed({ separator: this.#separator });
1580
+ this.#pathed = new Trees.Pathed.Pathed({ separator: this.#separator });
4305
1581
  if (options.paths) this.addPaths(options.paths);
4306
1582
  }
4307
1583
  get separator() {
@@ -4410,7 +1686,6 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4410
1686
  case `Escape`:
4411
1687
  e.preventDefault();
4412
1688
  this.#closeDropdown();
4413
- break;
4414
1689
  }
4415
1690
  };
4416
1691
  this.#onHostKeyDown = (e) => {
@@ -4749,9 +2024,11 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4749
2024
  #onHostKeyDown;
4750
2025
  render() {
4751
2026
  const segments = this.#getSegments();
4752
- if (this._editing) return html`
2027
+ if (this._editing) {
2028
+ const editValue = this.path;
2029
+ return html`
4753
2030
  <ixfx-ac-text
4754
- .value=${this.path}
2031
+ .value=${editValue}
4755
2032
  .tabSuffix=${this.separator}
4756
2033
  .completionProvider=${this.#makeCompletionProvider()}
4757
2034
  @change=${this.#onAcChange}
@@ -4759,6 +2036,7 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4759
2036
  @keydown=${this.#onAcKeyDown}
4760
2037
  ></ixfx-ac-text>
4761
2038
  `;
2039
+ }
4762
2040
  const rootSegments = this.#getRootSegments();
4763
2041
  const leadingCaret = this.siblingLookup && rootSegments.length === 0 ? html`
4764
2042
  <div class="caret ${this._openIdx === -1 ? `open` : ``} ${this._confirmedLeafIndices.has(``) ? `disabled` : ``}"
@@ -4986,7 +2264,7 @@ CrumbPathElement = __decorate([safeCustomElement(`ixfx-crumb-path`)], CrumbPathE
4986
2264
  //#endregion
4987
2265
  //#region src/editable-label/editable-number.ts
4988
2266
  const DRAG_THRESHOLD_PX = 3;
4989
- let EditableNumber = class EditableNumber extends EditableLabel {
2267
+ let EditableNumber = class EditableNumber extends WheelNudgeMixin(EditableLabel) {
4990
2268
  #dragStartY;
4991
2269
  #dragStartValue;
4992
2270
  #dragging;
@@ -5239,14 +2517,15 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5239
2517
  this.style.setProperty(`--value`, String(normalized));
5240
2518
  let valueStart = 0;
5241
2519
  let valueEnd = normalized;
5242
- if (this.linearStyle === `bipolar`) if (normalized <= .5) {
5243
- valueStart = normalized;
5244
- valueEnd = .5;
5245
- } else {
5246
- valueStart = .5;
5247
- valueEnd = normalized;
5248
- }
5249
- else if (this.linearStyle === `unipolar`) {
2520
+ if (this.linearStyle === `bipolar`) {
2521
+ if (normalized <= .5) {
2522
+ valueStart = normalized;
2523
+ valueEnd = .5;
2524
+ } else {
2525
+ valueStart = .5;
2526
+ valueEnd = normalized;
2527
+ }
2528
+ } else if (this.linearStyle === `unipolar`) {
5250
2529
  valueStart = .5 - normalized * .5;
5251
2530
  valueEnd = .5 + normalized * .5;
5252
2531
  }
@@ -5288,8 +2567,7 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5288
2567
  _handleArrowKey(e) {
5289
2568
  const range = (this.max ?? 100) - (this.min ?? 0);
5290
2569
  if (range === 0) return false;
5291
- const shiftDivisor = e.shiftKey ? 10 : 1;
5292
- const effectiveStep = resolveStep(range, void 0, this.step) / shiftDivisor;
2570
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, e.shiftKey);
5293
2571
  let delta = 0;
5294
2572
  let handled = false;
5295
2573
  switch (e.key) {
@@ -5310,33 +2588,49 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5310
2588
  case `End`:
5311
2589
  delta = (this.max ?? 0) - this._parseValue();
5312
2590
  handled = true;
5313
- break;
5314
2591
  }
5315
2592
  if (handled) {
5316
2593
  e.preventDefault();
5317
- const prev = this.value;
5318
- const current = this._parseValue();
5319
- const newValue = this._clamp(this._snap(current + delta));
5320
- const newValueStr = this.step !== void 0 ? this._formatNumber(newValue) : newValue.toFixed(this.precision);
5321
- this.value = newValueStr;
5322
- this._requestDisplayUpdate();
5323
- this._updateValueCss(this._normalizedValue(newValue));
5324
- if (newValueStr !== prev) this.dispatchEvent(new CustomEvent(`input`, {
5325
- detail: { value: newValueStr },
5326
- bubbles: true,
5327
- composed: true
5328
- }));
5329
- requestAnimationFrame(() => {
5330
- if (this.value !== prev) this.dispatchEvent(new CustomEvent(`change`, {
5331
- detail: { value: this.value },
5332
- bubbles: true,
5333
- composed: true
5334
- }));
5335
- });
2594
+ this._applyDelta(delta);
5336
2595
  return true;
5337
2596
  }
5338
2597
  return false;
5339
2598
  }
2599
+ /**
2600
+ * Apply a signed delta to the current value, clamp/snap/format, and fire
2601
+ * `input`/`change`. Shared between arrow-key handler and the wheel handler.
2602
+ */
2603
+ _applyDelta(delta) {
2604
+ const prev = this.value;
2605
+ const current = this._parseValue();
2606
+ const newValue = this._clamp(this._snap(current + delta));
2607
+ const newValueStr = this.step !== void 0 ? this._formatNumber(newValue) : newValue.toFixed(this.precision);
2608
+ this.value = newValueStr;
2609
+ this._requestDisplayUpdate();
2610
+ this._updateValueCss(this._normalizedValue(newValue));
2611
+ if (newValueStr !== prev) this.dispatchEvent(new CustomEvent(`input`, {
2612
+ detail: { value: newValueStr },
2613
+ bubbles: true,
2614
+ composed: true
2615
+ }));
2616
+ requestAnimationFrame(() => {
2617
+ if (this.value !== prev) this.dispatchEvent(new CustomEvent(`change`, {
2618
+ detail: { value: this.value },
2619
+ bubbles: true,
2620
+ composed: true
2621
+ }));
2622
+ });
2623
+ }
2624
+ _shouldHandleWheel() {
2625
+ if (this._editing) return false;
2626
+ return super._shouldHandleWheel();
2627
+ }
2628
+ _applyWheelDelta(direction, event) {
2629
+ const range = (this.max ?? 100) - (this.min ?? 0);
2630
+ if (range === 0) return;
2631
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
2632
+ this._applyDelta(direction * effectiveStep);
2633
+ }
5340
2634
  _parseValue() {
5341
2635
  return Number.parseFloat(this.value) || 0;
5342
2636
  }
@@ -5359,6 +2653,11 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5359
2653
  return n;
5360
2654
  }
5361
2655
  _snap(n) {
2656
+ if (this.stops && this.stops > 1) {
2657
+ const min = this.min ?? 0;
2658
+ const stopStep = ((this.max ?? 100) - min) / this.stops;
2659
+ return Math.round((n - min) / stopStep) * stopStep + min;
2660
+ }
5362
2661
  if (!this.step) return n;
5363
2662
  return Math.round(n / this.step) * this.step;
5364
2663
  }
@@ -5549,6 +2848,7 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5549
2848
  __decorate([property({ type: Number })], EditableNumber.prototype, "min", void 0);
5550
2849
  __decorate([property({ type: Number })], EditableNumber.prototype, "max", void 0);
5551
2850
  __decorate([property({ type: Number })], EditableNumber.prototype, "step", void 0);
2851
+ __decorate([property({ type: Number })], EditableNumber.prototype, "stops", void 0);
5552
2852
  __decorate([property({
5553
2853
  type: Number,
5554
2854
  attribute: `drag-sensitivity`
@@ -5971,9 +3271,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
5971
3271
  }
5972
3272
  break;
5973
3273
  }
5974
- case `Escape`:
5975
- this._clearSelection();
5976
- break;
3274
+ case `Escape`: this._clearSelection();
5977
3275
  }
5978
3276
  };
5979
3277
  this._onClick = (e) => {
@@ -6061,7 +3359,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6061
3359
  this._selectedItems = remapped;
6062
3360
  }
6063
3361
  this._syncItemStates();
6064
- }
3362
+ } else if (changed.has(`checkboxRenderer`) && this.interactionMode === `checked`) this._syncCheckboxes();
6065
3363
  }
6066
3364
  /** The most recently selected item, or `undefined` if nothing is selected. */
6067
3365
  get selectedItem() {
@@ -6142,7 +3440,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6142
3440
  _replaceSelection(item) {
6143
3441
  if (this.selectionMode === `none`) return;
6144
3442
  const previous = this._selectedItems;
6145
- const next = new Set([item]);
3443
+ const next = /* @__PURE__ */ new Set([item]);
6146
3444
  this._selectedItems = next;
6147
3445
  this.#selectionAnchor = item;
6148
3446
  this._syncItemStates();
@@ -6229,7 +3527,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6229
3527
  } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
6230
3528
  else this._replaceSelection(item);
6231
3529
  break;
6232
- case `checked`: break;
3530
+ case `checked`:
6233
3531
  }
6234
3532
  }
6235
3533
  _handleSpaceKey(item) {
@@ -6257,6 +3555,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6257
3555
  }
6258
3556
  _syncCheckboxes() {
6259
3557
  const inCheckedMode = this.interactionMode === `checked`;
3558
+ const wantsCustom = typeof this.checkboxRenderer === `function`;
6260
3559
  if (inCheckedMode) for (const inner of Array.from(this.children)) {
6261
3560
  if (!inner.hasAttribute(`data-list-item`)) continue;
6262
3561
  if (inner.parentElement !== this) continue;
@@ -6281,24 +3580,70 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6281
3580
  this.#customWrappers.clear();
6282
3581
  }
6283
3582
  for (const el of this.querySelectorAll(`li`)) {
6284
- let cb = el.querySelector(`input.ixfx-list-checkbox`);
6285
- if (inCheckedMode) {
6286
- if (!cb) {
6287
- cb = document.createElement(`input`);
6288
- cb.type = `checkbox`;
6289
- cb.className = `ixfx-list-checkbox`;
6290
- cb.style.cssText = `flex-shrink:0;margin:0 6px 0 0;cursor:pointer;accent-color:var(--accent,#60a5fa);pointer-events:auto`;
6291
- cb.tabIndex = -1;
6292
- cb.addEventListener(`click`, (e) => {
6293
- e.stopPropagation();
6294
- this._toggleItem(el);
6295
- });
6296
- el.prepend(cb);
6297
- }
6298
- cb.checked = this._selectedItems.has(el);
6299
- } else if (cb) cb.remove();
3583
+ const existing = el.querySelector(`.ixfx-list-checkbox`);
3584
+ if (!inCheckedMode) {
3585
+ if (existing) existing.remove();
3586
+ continue;
3587
+ }
3588
+ const existingIsCustom = existing?.classList.contains(`ixfx-list-checkbox-custom`) ?? false;
3589
+ if (existing && existingIsCustom !== wantsCustom) existing.remove();
3590
+ let cb = el.querySelector(`.ixfx-list-checkbox`);
3591
+ if (!cb) {
3592
+ cb = wantsCustom ? this._createCustomCheckbox(el) : this._createNativeCheckboxCell(el);
3593
+ el.prepend(cb);
3594
+ }
3595
+ const checked = this._selectedItems.has(el);
3596
+ if (wantsCustom) {
3597
+ cb.setAttribute(`aria-checked`, String(checked));
3598
+ cb.toggleAttribute(`data-checked`, checked);
3599
+ if (this.checkboxRenderer) render(this.checkboxRenderer(checked), cb);
3600
+ } else {
3601
+ const input = cb.querySelector(`input.ixfx-list-checkbox`);
3602
+ if (input) input.checked = checked;
3603
+ }
6300
3604
  }
6301
3605
  }
3606
+ /**
3607
+ * Native checkbox cell: a span that stretches to the row's full cross-axis
3608
+ * (so the entire column height is a click target) with a real `<input>`
3609
+ * centred inside. The span owns the click; the input is purely visual and
3610
+ * has `pointer-events:none` so a single click produces one toggle.
3611
+ */
3612
+ _createNativeCheckboxCell(el) {
3613
+ const cell = document.createElement(`span`);
3614
+ cell.className = `ixfx-list-checkbox ixfx-list-checkbox-native`;
3615
+ cell.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:18px;margin:0 6px 0 0;cursor:pointer;pointer-events:auto`;
3616
+ cell.tabIndex = -1;
3617
+ cell.setAttribute(`role`, `checkbox`);
3618
+ cell.setAttribute(`part`, `checkbox`);
3619
+ cell.addEventListener(`click`, (e) => {
3620
+ e.stopPropagation();
3621
+ this._toggleItem(el);
3622
+ });
3623
+ const input = document.createElement(`input`);
3624
+ input.type = `checkbox`;
3625
+ input.className = `ixfx-list-checkbox`;
3626
+ input.style.cssText = `pointer-events:none;cursor:pointer;margin:0`;
3627
+ cell.appendChild(input);
3628
+ return cell;
3629
+ }
3630
+ /**
3631
+ * Custom checkbox cell: same shape as the native cell (a stretching span)
3632
+ * so behaviour is identical. The renderer's content goes inside.
3633
+ */
3634
+ _createCustomCheckbox(el) {
3635
+ const span = document.createElement(`span`);
3636
+ span.className = `ixfx-list-checkbox ixfx-list-checkbox-custom`;
3637
+ span.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:24px;margin:0 6px 0 0;cursor:pointer;pointer-events:auto`;
3638
+ span.tabIndex = -1;
3639
+ span.setAttribute(`role`, `checkbox`);
3640
+ span.setAttribute(`part`, `checkbox`);
3641
+ span.addEventListener(`click`, (e) => {
3642
+ e.stopPropagation();
3643
+ this._toggleItem(el);
3644
+ });
3645
+ return span;
3646
+ }
6302
3647
  _findListItem(path) {
6303
3648
  for (const target of path) {
6304
3649
  if (!(target instanceof Element)) continue;
@@ -6360,8 +3705,14 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6360
3705
  padding: 0;
6361
3706
  width: 100%;
6362
3707
  height: 100%;
3708
+ overflow-x: hidden;
6363
3709
  overflow-y: auto;
6364
3710
  box-sizing: border-box;
3711
+ /* Scrollbar theming: end users override these CSS variables to control
3712
+ the native scrollbar (scrollbar-width, scrollbar-gutter, scrollbar-color). */
3713
+ scrollbar-width: var(--list-scrollbar-width, auto);
3714
+ scrollbar-gutter: var(--list-scrollbar-gutter, auto);
3715
+ scrollbar-color: var(--list-scrollbar-color, auto);
6365
3716
  }
6366
3717
 
6367
3718
  ::slotted([hidden]) {
@@ -6391,6 +3742,25 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6391
3742
  outline: 1px solid transparent;
6392
3743
  }
6393
3744
 
3745
+ /* In checked mode, only the checkbox column is clickable; the row body
3746
+ gets a default cursor so it doesn't suggest otherwise. */
3747
+ :host([interaction-mode="checked"]) ::slotted(li),
3748
+ :host([interaction-mode="checked"]) ::slotted([data-list-item]) {
3749
+ cursor: default;
3750
+ }
3751
+
3752
+ /* Wrapper inserted around custom [data-list-item] elements in checked mode.
3753
+ Provides the flex layout so the injected checkbox can stretch to the
3754
+ row's full height via align-self:stretch. */
3755
+ .ixfx-custom-row {
3756
+ display: flex;
3757
+ align-items: center;
3758
+ min-height: var(--list-item-height, 28px);
3759
+ box-sizing: border-box;
3760
+ cursor: default;
3761
+ user-select: none;
3762
+ }
3763
+
6394
3764
  ::slotted([data-tickled]) {
6395
3765
  background: var(--item-bg-tickled);
6396
3766
  outline: var(--item-border-tickled);
@@ -6498,6 +3868,7 @@ __decorate([property({
6498
3868
  attribute: `interaction-mode`
6499
3869
  })], VerticalListElement.prototype, "interactionMode", void 0);
6500
3870
  __decorate([property({ attribute: false })], VerticalListElement.prototype, "filterPredicate", void 0);
3871
+ __decorate([property({ attribute: false })], VerticalListElement.prototype, "checkboxRenderer", void 0);
6501
3872
  __decorate([state()], VerticalListElement.prototype, "_selectedItems", void 0);
6502
3873
  __decorate([state()], VerticalListElement.prototype, "_searchVisible", void 0);
6503
3874
  __decorate([state()], VerticalListElement.prototype, "_searchQuery", void 0);
@@ -6633,6 +4004,441 @@ function createVerticalListAdapter(renderItem, options) {
6633
4004
  return adapter;
6634
4005
  }
6635
4006
  //#endregion
4007
+ //#region src/notifier/notification-pill.ts
4008
+ let NotificationPillElement = class NotificationPillElement extends LitElement {
4009
+ constructor(..._args) {
4010
+ super(..._args);
4011
+ this.notificationType = `info`;
4012
+ this.message = ``;
4013
+ this.dismissing = false;
4014
+ this.notificationId = ``;
4015
+ }
4016
+ #handleClick() {
4017
+ this.#emitTap();
4018
+ }
4019
+ #handleKeyDown(e) {
4020
+ if (e.key === `Enter` || e.key === ` `) {
4021
+ e.preventDefault();
4022
+ this.#emitTap();
4023
+ }
4024
+ }
4025
+ #emitTap() {
4026
+ this.dispatchEvent(new CustomEvent(`pill-tap`, {
4027
+ detail: { id: this.notificationId },
4028
+ bubbles: true,
4029
+ composed: true
4030
+ }));
4031
+ }
4032
+ #renderIcon() {
4033
+ if (!this.icon) return nothing;
4034
+ if (this.icon.startsWith(`<svg`)) return html`<span class="pill-icon">${unsafeHTML(this.icon)}</span>`;
4035
+ if (!getIcon(this.icon)) return nothing;
4036
+ return html`<ixfx-icon class="pill-icon" name="${this.icon}"></ixfx-icon>`;
4037
+ }
4038
+ render() {
4039
+ return html`
4040
+ <button
4041
+ type="button"
4042
+ class="pill"
4043
+ notification-type="${this.notificationType}"
4044
+ @click=${this.#handleClick}
4045
+ @keydown=${this.#handleKeyDown}
4046
+ aria-label="${this.message}"
4047
+ >
4048
+ ${this.#renderIcon()}
4049
+ <span class="pill-message">${this.message}</span>
4050
+ </button>
4051
+ `;
4052
+ }
4053
+ static {
4054
+ this.styles = [themeFallbacks, css`
4055
+ :host {
4056
+ display: block;
4057
+ }
4058
+
4059
+ .pill {
4060
+ appearance: none;
4061
+ cursor: pointer;
4062
+ font-family: var(--font-family, inherit);
4063
+ font-size: var(--text-m, 12px);
4064
+ padding: var(--space-s, 4px) var(--space-m, 8px);
4065
+ border-radius: var(--radius-l, 6px);
4066
+ border: 1px solid var(--surface-6, #666);
4067
+ display: inline-flex;
4068
+ align-items: center;
4069
+ gap: var(--space-s, 4px);
4070
+ max-width: 300px;
4071
+ box-shadow: var(--shadow-m);
4072
+ transition: opacity 0.2s ease-out, transform 0.2s ease-out;
4073
+ pointer-events: auto;
4074
+ }
4075
+
4076
+ :host([dismissing]) .pill {
4077
+ opacity: 0;
4078
+ transform: translateX(20px);
4079
+ }
4080
+
4081
+ .pill[notification-type="info"] {
4082
+ background: var(--surface-5, #555);
4083
+ color: var(--surface-5-text, #fff);
4084
+ }
4085
+
4086
+ .pill[notification-type="warning"] {
4087
+ background: color-mix(in oklch, oklch(65% 0.18 70) 30%, var(--surface-5));
4088
+ border-color: oklch(65% 0.18 70);
4089
+ color: var(--surface-5-text, #fff);
4090
+ }
4091
+
4092
+ .pill[notification-type="error"] {
4093
+ background: var(--error, #c00);
4094
+ border-color: var(--error, #c00);
4095
+ color: var(--error-text, #fff);
4096
+ }
4097
+
4098
+ .pill-icon {
4099
+ display: inline-flex;
4100
+ align-items: center;
4101
+ flex-shrink: 0;
4102
+ }
4103
+
4104
+ .pill-icon ixfx-icon {
4105
+ font-size: var(--text-m, 12px);
4106
+ }
4107
+
4108
+ .pill-message {
4109
+ white-space: nowrap;
4110
+ overflow: hidden;
4111
+ text-overflow: ellipsis;
4112
+ }
4113
+
4114
+ .pill:focus-visible {
4115
+ outline: 2px solid var(--accent, #4a9);
4116
+ outline-offset: 2px;
4117
+ }
4118
+
4119
+ @media (prefers-reduced-motion: reduce) {
4120
+ .pill {
4121
+ transition: opacity 0.1s ease-out;
4122
+ transform: none !important;
4123
+ }
4124
+ }
4125
+ `];
4126
+ }
4127
+ };
4128
+ __decorate([property({
4129
+ type: String,
4130
+ attribute: `notification-type`
4131
+ })], NotificationPillElement.prototype, "notificationType", void 0);
4132
+ __decorate([property({ type: String })], NotificationPillElement.prototype, "message", void 0);
4133
+ __decorate([property({ type: String })], NotificationPillElement.prototype, "icon", void 0);
4134
+ __decorate([property({
4135
+ type: Boolean,
4136
+ reflect: true
4137
+ })], NotificationPillElement.prototype, "dismissing", void 0);
4138
+ __decorate([property({
4139
+ type: String,
4140
+ attribute: `notification-id`
4141
+ })], NotificationPillElement.prototype, "notificationId", void 0);
4142
+ NotificationPillElement = __decorate([safeCustomElement(`ixfx-notification-pill`)], NotificationPillElement);
4143
+ //#endregion
4144
+ //#region src/notifier/pill-renderer.ts
4145
+ const ROW_SPACING = 8;
4146
+ const DEFAULT_ROW_HEIGHT = 40;
4147
+ const STACK_OFFSET_STEP = 4;
4148
+ const STACK_OPACITY_BASE = .7;
4149
+ const STACK_OPACITY_DECAY = .15;
4150
+ const STACK_OPACITY_MIN = .2;
4151
+ function edgesOf(position) {
4152
+ return {
4153
+ vertical: position.startsWith(`top`) ? `top` : `bottom`,
4154
+ horizontal: position.endsWith(`-left`) ? `left` : position.endsWith(`-right`) ? `right` : `middle`
4155
+ };
4156
+ }
4157
+ function anchorStyles(position, safeArea) {
4158
+ const { vertical, horizontal } = edgesOf(position);
4159
+ const vMargin = `calc(var(--space-l, 12px) + ${(vertical === `top` ? safeArea.top : safeArea.bottom) ?? 0}px)`;
4160
+ let css = `position: fixed; `;
4161
+ css += vertical === `top` ? `top: ${vMargin}; bottom: auto; ` : `bottom: ${vMargin}; top: auto; `;
4162
+ if (horizontal === `left`) {
4163
+ const hMargin = `calc(var(--space-l, 12px) + ${safeArea.left ?? 0}px)`;
4164
+ css += `left: ${hMargin}; right: auto;`;
4165
+ } else if (horizontal === `right`) {
4166
+ const hMargin = `calc(var(--space-l, 12px) + ${safeArea.right ?? 0}px)`;
4167
+ css += `right: ${hMargin}; left: auto;`;
4168
+ } else css += `left: 50%; right: auto;`;
4169
+ return css;
4170
+ }
4171
+ /** Entry-animation starting transform: pills slide in from the edge they're anchored to. */
4172
+ function entryTransform(edges) {
4173
+ const dy = edges.vertical === `top` ? -20 : 20;
4174
+ if (edges.horizontal === `middle`) return `translateX(-50%) translate(0, ${dy}px)`;
4175
+ return `translate(${edges.horizontal === `left` ? -20 : 20}px, ${dy}px)`;
4176
+ }
4177
+ function restingTransform(edges, dx, dy) {
4178
+ if (edges.horizontal === `middle`) return `translateX(-50%) translate(${dx}px, ${dy}px)`;
4179
+ return `translate(${dx}px, ${dy}px)`;
4180
+ }
4181
+ function createPillRenderer(options = {}) {
4182
+ const position = options.position ?? `top-right`;
4183
+ const queueDisplay = options.queueDisplay ?? `list`;
4184
+ const safeArea = options.safeArea ?? {};
4185
+ const edges = edgesOf(position);
4186
+ let container = null;
4187
+ let hooks = null;
4188
+ const pills = /* @__PURE__ */ new Map();
4189
+ let rowHeight = DEFAULT_ROW_HEIGHT;
4190
+ let measured = false;
4191
+ function ensureContainer() {
4192
+ if (container) return container;
4193
+ container = document.createElement(`div`);
4194
+ container.className = `ixfx-notification-container`;
4195
+ container.setAttribute(`role`, `region`);
4196
+ container.setAttribute(`aria-label`, `Notifications`);
4197
+ document.body.appendChild(container);
4198
+ return container;
4199
+ }
4200
+ function updateAttributes(el, notification) {
4201
+ el.setAttribute(`notification-type`, notification.type);
4202
+ el.setAttribute(`message`, notification.message);
4203
+ if (notification.icon) el.setAttribute(`icon`, notification.icon);
4204
+ else el.removeAttribute(`icon`);
4205
+ }
4206
+ function createPillElement(notification) {
4207
+ const el = document.createElement(`ixfx-notification-pill`);
4208
+ el.setAttribute(`notification-id`, notification.id);
4209
+ el.style.cssText = anchorStyles(position, safeArea);
4210
+ updateAttributes(el, notification);
4211
+ el.style.opacity = `0`;
4212
+ el.style.transform = entryTransform(edges);
4213
+ el.addEventListener(`pill-tap`, (e) => {
4214
+ const customEvent = e;
4215
+ hooks?.onTap(customEvent.detail.id);
4216
+ });
4217
+ return el;
4218
+ }
4219
+ function measureRowHeight(el) {
4220
+ if (measured) return;
4221
+ requestAnimationFrame(() => {
4222
+ const height = el.getBoundingClientRect().height;
4223
+ if (height > 0) {
4224
+ rowHeight = height;
4225
+ measured = true;
4226
+ }
4227
+ });
4228
+ }
4229
+ /** Positions every currently-visible pill for its rank in `order` (index 0 = front/oldest). */
4230
+ function applyLayout(order) {
4231
+ const total = order.length;
4232
+ order.forEach((notification, index) => {
4233
+ const entry = pills.get(notification.id);
4234
+ if (!entry) return;
4235
+ const el = entry.element;
4236
+ let dx = 0;
4237
+ let dy = 0;
4238
+ let opacity = 1;
4239
+ let pointerEvents = `auto`;
4240
+ let filter = `none`;
4241
+ if (queueDisplay === `list`) {
4242
+ const step = index * (rowHeight + ROW_SPACING);
4243
+ dy = edges.vertical === `top` ? step : -step;
4244
+ } else {
4245
+ const step = index * STACK_OFFSET_STEP;
4246
+ dy = edges.vertical === `top` ? step : -step;
4247
+ dx = edges.horizontal === `left` ? step : edges.horizontal === `right` ? -step : 0;
4248
+ if (index > 0) {
4249
+ const hintIndex = index - 1;
4250
+ opacity = Math.max(STACK_OPACITY_MIN, STACK_OPACITY_BASE - hintIndex * STACK_OPACITY_DECAY);
4251
+ pointerEvents = `none`;
4252
+ filter = `saturate(0.6)`;
4253
+ }
4254
+ }
4255
+ el.style.transition = `opacity 0.2s ease-out, transform 0.2s ease-out`;
4256
+ el.style.opacity = `${opacity}`;
4257
+ el.style.zIndex = `${total - index}`;
4258
+ el.style.pointerEvents = pointerEvents;
4259
+ el.style.filter = filter;
4260
+ el.style.transform = restingTransform(edges, dx, dy);
4261
+ });
4262
+ }
4263
+ function dismiss(id) {
4264
+ const entry = pills.get(id);
4265
+ if (!entry) return;
4266
+ const el = entry.element;
4267
+ el.setAttribute(`dismissing`, `true`);
4268
+ const cleanup = () => {
4269
+ el.removeEventListener(`transitionend`, cleanup);
4270
+ el.remove();
4271
+ pills.delete(id);
4272
+ if (container && pills.size === 0) {
4273
+ container.remove();
4274
+ container = null;
4275
+ measured = false;
4276
+ rowHeight = DEFAULT_ROW_HEIGHT;
4277
+ }
4278
+ };
4279
+ el.addEventListener(`transitionend`, cleanup);
4280
+ setTimeout(cleanup, 300);
4281
+ }
4282
+ function setNotifications(notifications, _queueSize) {
4283
+ const cont = ensureContainer();
4284
+ const idsToKeep = new Set(notifications.map((n) => n.id));
4285
+ for (const notification of notifications) {
4286
+ const existing = pills.get(notification.id);
4287
+ if (existing) {
4288
+ existing.notification = notification;
4289
+ updateAttributes(existing.element, notification);
4290
+ continue;
4291
+ }
4292
+ const el = createPillElement(notification);
4293
+ pills.set(notification.id, {
4294
+ element: el,
4295
+ notification
4296
+ });
4297
+ cont.appendChild(el);
4298
+ measureRowHeight(el);
4299
+ }
4300
+ for (const [id] of pills) if (!idsToKeep.has(id)) dismiss(id);
4301
+ requestAnimationFrame(() => applyLayout(notifications));
4302
+ }
4303
+ return {
4304
+ attach(newHooks) {
4305
+ hooks = newHooks;
4306
+ },
4307
+ detach() {
4308
+ for (const [id] of pills) dismiss(id);
4309
+ if (container) {
4310
+ container.remove();
4311
+ container = null;
4312
+ }
4313
+ },
4314
+ setNotifications
4315
+ };
4316
+ }
4317
+ //#endregion
4318
+ //#region src/notifier/manager.ts
4319
+ const options = {
4320
+ renderer: void 0,
4321
+ timeout: 4e3,
4322
+ timeoutError: 8e3,
4323
+ queue: true,
4324
+ queueSize: 3,
4325
+ tapBehaviour: `dismiss`,
4326
+ tapHandlerDefault: void 0
4327
+ };
4328
+ /** Rank-ordered, index 0 = oldest/first (next to be evicted or timed out). Length never exceeds queueSize (or 1 when queuing is disabled). */
4329
+ const visible = [];
4330
+ let renderer = null;
4331
+ let defaultRenderer = null;
4332
+ function getDefaultRenderer() {
4333
+ defaultRenderer ??= createPillRenderer({ position: `top-right` });
4334
+ return defaultRenderer;
4335
+ }
4336
+ function getRenderer() {
4337
+ return renderer ?? getDefaultRenderer();
4338
+ }
4339
+ function syncRenderer() {
4340
+ getRenderer().setNotifications([...visible], options.queueSize);
4341
+ }
4342
+ function clearTimer(managed) {
4343
+ if (managed.timer !== null) {
4344
+ clearTimeout(managed.timer);
4345
+ managed.timer = null;
4346
+ }
4347
+ }
4348
+ /**
4349
+ * A message shown alone takes the full timeout. A message that joined a
4350
+ * non-empty queue at arrival time is permanently "wasQueued" and gets
4351
+ * 1/queueSize of the timeout once it reaches the front. The timer for a
4352
+ * given message is only ever started once - when it first becomes front.
4353
+ */
4354
+ function startTimer(managed) {
4355
+ const base = managed.type === `error` ? options.timeoutError : options.timeout;
4356
+ const duration = managed.wasQueued ? base / options.queueSize : base;
4357
+ managed.timer = window.setTimeout(() => dismiss(managed.id), duration);
4358
+ }
4359
+ function ensureFrontTimer() {
4360
+ const front = visible[0];
4361
+ if (front && front.timer === null) startTimer(front);
4362
+ }
4363
+ const NotificationManager = {
4364
+ configure(opts) {
4365
+ if (opts.renderer !== void 0) {
4366
+ renderer?.detach?.();
4367
+ renderer = opts.renderer;
4368
+ renderer.attach({ onTap(id) {
4369
+ const notification = visible.find((n) => n.id === id);
4370
+ if (!notification) return;
4371
+ if (notification.onTap) notification.onTap(id);
4372
+ else options.tapHandlerDefault?.(notification);
4373
+ if (options.tapBehaviour === `dismiss`) dismiss(id);
4374
+ } });
4375
+ syncRenderer();
4376
+ }
4377
+ if (opts.timeout !== void 0) options.timeout = opts.timeout;
4378
+ if (opts.timeoutError !== void 0) options.timeoutError = opts.timeoutError;
4379
+ if (opts.queue !== void 0) options.queue = opts.queue;
4380
+ if (opts.queueSize !== void 0) {
4381
+ options.queueSize = Math.max(1, opts.queueSize);
4382
+ while (visible.length > options.queueSize) clearTimer(visible.shift());
4383
+ ensureFrontTimer();
4384
+ syncRenderer();
4385
+ }
4386
+ if (opts.tapBehaviour !== void 0) options.tapBehaviour = opts.tapBehaviour;
4387
+ if (opts.tapHandlerDefault !== void 0) options.tapHandlerDefault = opts.tapHandlerDefault;
4388
+ },
4389
+ notify(content) {
4390
+ const id = crypto.randomUUID();
4391
+ const now = Date.now();
4392
+ const icon = content.icon ?? (content.type === `error` ? `error` : void 0);
4393
+ const managed = {
4394
+ ...content,
4395
+ icon,
4396
+ id,
4397
+ createdAt: now,
4398
+ updatedAt: now,
4399
+ timer: null,
4400
+ wasQueued: false
4401
+ };
4402
+ if (options.queue) {
4403
+ if (visible.length >= options.queueSize) clearTimer(visible.shift());
4404
+ managed.wasQueued = visible.length > 0;
4405
+ visible.push(managed);
4406
+ } else {
4407
+ while (visible.length > 0) clearTimer(visible.pop());
4408
+ visible.push(managed);
4409
+ }
4410
+ ensureFrontTimer();
4411
+ syncRenderer();
4412
+ return id;
4413
+ },
4414
+ update(id, content) {
4415
+ const managed = visible.find((n) => n.id === id);
4416
+ if (!managed) return;
4417
+ Object.assign(managed, content);
4418
+ managed.updatedAt = Date.now();
4419
+ if (visible[0] === managed) {
4420
+ clearTimer(managed);
4421
+ startTimer(managed);
4422
+ }
4423
+ syncRenderer();
4424
+ },
4425
+ dismiss(id) {
4426
+ dismiss(id);
4427
+ },
4428
+ dismissAll() {
4429
+ for (const m of visible) clearTimer(m);
4430
+ visible.length = 0;
4431
+ syncRenderer();
4432
+ }
4433
+ };
4434
+ function dismiss(id) {
4435
+ const idx = visible.findIndex((m) => m.id === id);
4436
+ if (idx === -1) return;
4437
+ clearTimer(visible.splice(idx, 1)[0]);
4438
+ ensureFrontTimer();
4439
+ syncRenderer();
4440
+ }
4441
+ //#endregion
6636
4442
  //#region src/panel/panel-group.ts
6637
4443
  let PanelGroupElement = class PanelGroupElement extends LitElement {
6638
4444
  constructor(..._args) {
@@ -6867,11 +4673,13 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
6867
4673
  }
6868
4674
  a = newA;
6869
4675
  b = newB;
6870
- } else if (which === `a`) if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
6871
- else a = v;
6872
- else if (which === `b`) if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
6873
- else b = v;
6874
- else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
4676
+ } else if (which === `a`) {
4677
+ if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
4678
+ else a = v;
4679
+ } else if (which === `b`) {
4680
+ if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
4681
+ else b = v;
4682
+ } else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
6875
4683
  this.setPoles(a, b);
6876
4684
  }
6877
4685
  setPoles(a, b) {
@@ -6930,63 +4738,65 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
6930
4738
  const currentPos = isVertical ? current.offset.y : current.offset.x;
6931
4739
  const amt = (isVertical ? startPos - currentPos : currentPos - startPos) / valuePerPix;
6932
4740
  polesChanged = true;
6933
- if (draggingWhich === `a`) if (resizeMode === `bipolar`) {
6934
- const calcA = startA + amt;
6935
- const calcB = startB - amt;
6936
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
6937
- setPoles(calcA, calcB);
6938
- } else if (resizeMode === `bipolar-flex`) {
6939
- let calcA = startA + amt;
6940
- let calcB = startB;
6941
- if (startB <= min) calcB = min;
6942
- else if (startB >= max) calcB = max;
6943
- else {
6944
- calcA = startA + amt;
6945
- calcB = startB - amt;
4741
+ if (draggingWhich === `a`) {
4742
+ if (resizeMode === `bipolar`) {
4743
+ const calcA = startA + amt;
4744
+ const calcB = startB - amt;
4745
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4746
+ setPoles(calcA, calcB);
4747
+ } else if (resizeMode === `bipolar-flex`) {
4748
+ let calcA = startA + amt;
4749
+ let calcB = startB;
4750
+ if (startB <= min) calcB = min;
4751
+ else if (startB >= max) calcB = max;
4752
+ else {
4753
+ calcA = startA + amt;
4754
+ calcB = startB - amt;
4755
+ }
4756
+ if (calcA < min) calcA = min;
4757
+ if (calcA > max) calcA = max;
4758
+ if (calcB < min) calcB = min;
4759
+ if (calcB > max) calcB = max;
4760
+ if (calcA > calcB) return;
4761
+ setPoles(calcA, calcB);
4762
+ } else {
4763
+ let constrainedAmt = amt;
4764
+ if (startA + amt < min) constrainedAmt = min - startA;
4765
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4766
+ const finalA = startA + constrainedAmt;
4767
+ const finalB = startB + constrainedAmt;
4768
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6946
4769
  }
6947
- if (calcA < min) calcA = min;
6948
- if (calcA > max) calcA = max;
6949
- if (calcB < min) calcB = min;
6950
- if (calcB > max) calcB = max;
6951
- if (calcA > calcB) return;
6952
- setPoles(calcA, calcB);
6953
- } else {
6954
- let constrainedAmt = amt;
6955
- if (startA + amt < min) constrainedAmt = min - startA;
6956
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
6957
- const finalA = startA + constrainedAmt;
6958
- const finalB = startB + constrainedAmt;
6959
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6960
- }
6961
- else if (draggingWhich === `b`) if (resizeMode === `bipolar`) {
6962
- const calcA = startA - amt;
6963
- const calcB = startB + amt;
6964
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
6965
- setPoles(calcA, calcB);
6966
- } else if (resizeMode === `bipolar-flex`) {
6967
- let calcA = startA;
6968
- let calcB = startB + amt;
6969
- if (startA <= min) calcA = min;
6970
- else if (startA >= max) calcA = max;
6971
- else {
6972
- calcA = startA - amt;
6973
- calcB = startB + amt;
4770
+ } else if (draggingWhich === `b`) {
4771
+ if (resizeMode === `bipolar`) {
4772
+ const calcA = startA - amt;
4773
+ const calcB = startB + amt;
4774
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4775
+ setPoles(calcA, calcB);
4776
+ } else if (resizeMode === `bipolar-flex`) {
4777
+ let calcA = startA;
4778
+ let calcB = startB + amt;
4779
+ if (startA <= min) calcA = min;
4780
+ else if (startA >= max) calcA = max;
4781
+ else {
4782
+ calcA = startA - amt;
4783
+ calcB = startB + amt;
4784
+ }
4785
+ if (calcA < min) calcA = min;
4786
+ if (calcA > max) calcA = max;
4787
+ if (calcB < min) calcB = min;
4788
+ if (calcB > max) calcB = max;
4789
+ if (calcA > calcB) return;
4790
+ setPoles(calcA, calcB);
4791
+ } else {
4792
+ let constrainedAmt = amt;
4793
+ if (startA + amt < min) constrainedAmt = min - startA;
4794
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4795
+ const finalA = startA + constrainedAmt;
4796
+ const finalB = startB + constrainedAmt;
4797
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6974
4798
  }
6975
- if (calcA < min) calcA = min;
6976
- if (calcA > max) calcA = max;
6977
- if (calcB < min) calcB = min;
6978
- if (calcB > max) calcB = max;
6979
- if (calcA > calcB) return;
6980
- setPoles(calcA, calcB);
6981
- } else {
6982
- let constrainedAmt = amt;
6983
- if (startA + amt < min) constrainedAmt = min - startA;
6984
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
6985
- const finalA = startA + constrainedAmt;
6986
- const finalB = startB + constrainedAmt;
6987
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6988
- }
6989
- else if (resizeMode === `bipolar`) {
4799
+ } else if (resizeMode === `bipolar`) {
6990
4800
  const calcA = startA + amt;
6991
4801
  const calcB = startB + amt;
6992
4802
  if (calcA < min || calcB > max) return;
@@ -7317,7 +5127,7 @@ let TabListItemElement = class TabListItemElement extends LitElement {
7317
5127
  prominenceStyles,
7318
5128
  css`
7319
5129
  :host {
7320
- --selected-colour: var(--accent);
5130
+ --selected-colour: var(--surface-2-text);
7321
5131
  --selected-border-width: 1px;
7322
5132
  --padding: var(--space-m);
7323
5133
  display: inline-flex;
@@ -7343,6 +5153,8 @@ let TabListItemElement = class TabListItemElement extends LitElement {
7343
5153
  border-bottom-color: var(--indicator-color-bottom, transparent);
7344
5154
  border-left-color: var(--indicator-color-left, transparent);
7345
5155
  border-right-color: var(--indicator-color-right, transparent);
5156
+ background: var(--surface-5);
5157
+ font-weight: bold;
7346
5158
  }
7347
5159
 
7348
5160
  .label {
@@ -7366,13 +5178,18 @@ let TabListItemElement = class TabListItemElement extends LitElement {
7366
5178
  }
7367
5179
 
7368
5180
  .toolbar {
7369
- display: none;
5181
+ /* Always laid out (display: flex) so the tab's width doesn't shift when
5182
+ the toolbar appears on selection. visibility: hidden keeps the
5183
+ toolbar from receiving pointer events or painting, while preserving
5184
+ the space its contents take up. */
5185
+ display: flex;
7370
5186
  align-items: center;
7371
5187
  gap: var(--space-xs);
5188
+ visibility: hidden;
7372
5189
  }
7373
5190
 
7374
5191
  :host([selected]) .toolbar {
7375
- display: flex;
5192
+ visibility: visible;
7376
5193
  }
7377
5194
 
7378
5195
  slot[name="toolbar"] {
@@ -7795,86 +5612,11 @@ function monitorIndeterminate(targetElOrQuery, watchedElsOrQueries) {
7795
5612
  };
7796
5613
  }
7797
5614
  //#endregion
7798
- //#region src/util/is-numeric.ts
7799
- function isNumeric(str) {
7800
- if (typeof str === `number`) return true;
7801
- if (typeof str !== `string`) return false;
7802
- const trimmed = str.trim();
7803
- return trimmed !== `` && !Number.isNaN(Number(trimmed));
7804
- }
7805
- //#endregion
7806
- //#region src/util/tooltip.ts
7807
- var _TooltipElement;
7808
- let TooltipElement = class TooltipElement extends LitElement {
7809
- static {
7810
- _TooltipElement = this;
7811
- }
7812
- constructor(..._args) {
7813
- super(..._args);
7814
- this.valueFormatTooltip = _TooltipElement.defaultFormatter;
7815
- this.orientation = `top`;
7816
- this.anchor = `--tooltip`;
7817
- }
7818
- static {
7819
- this.numberFormatter = (v) => Math.floor(v).toString();
7820
- }
7821
- static {
7822
- this.defaultFormatter = (v) => {
7823
- if (typeof v === `number`) {
7824
- if (Number.isInteger(v)) return v.toString();
7825
- return v.toFixed(2);
7826
- } else if (typeof v === `string`) return v;
7827
- else return JSON.stringify(v);
7828
- };
7829
- }
7830
- #renderIcon() {
7831
- if (!this.icon) return nothing;
7832
- if (this.icon.startsWith(`<svg`)) return html`<span class="tooltip-icon" style="display:inline-flex;align-items:center;margin-right:0.25em">${unsafeHTML(this.icon)}</span>`;
7833
- if (!getIcon(this.icon)) return nothing;
7834
- return html`<ixfx-icon class="tooltip-icon" style="margin-right:0.25em" name="${this.icon}"></ixfx-icon>`;
7835
- }
7836
- render() {
7837
- const classes = {
7838
- "tooltip": true,
7839
- "tooltip-orientation-top": this.orientation === `top`,
7840
- "tooltip-orientation-bottom": this.orientation === `bottom`,
7841
- "tooltip-orientation-right": this.orientation === `right`,
7842
- "tooltip-orientation-left": this.orientation === `left`,
7843
- "tooltip-type-text": true,
7844
- "tooltip-type-number": false,
7845
- "tooltip-style-bubble": true
7846
- };
7847
- let value = ``;
7848
- switch (typeof this.value) {
7849
- case `number`:
7850
- classes[`tooltip-type-number`] = true;
7851
- value = this.valueFormatTooltip(this.value);
7852
- break;
7853
- case `string`:
7854
- if (isNumeric(this.value)) {
7855
- classes[`tooltip-type-number`] = true;
7856
- value = this.valueFormatTooltip(Number.parseFloat(this.value));
7857
- } else value = this.value;
7858
- break;
7859
- default: value = JSON.stringify(this.value);
7860
- }
7861
- return html`<output style="--anchor-id: ${this.anchor}" class=${classMap(classes)}>${this.#renderIcon()}${value}</output>`;
7862
- }
7863
- createRenderRoot() {
7864
- return this;
7865
- }
7866
- };
7867
- __decorate([property({ type: String })], TooltipElement.prototype, "orientation", void 0);
7868
- __decorate([property({ type: String })], TooltipElement.prototype, "anchor", void 0);
7869
- __decorate([property()], TooltipElement.prototype, "value", void 0);
7870
- __decorate([property({ type: String })], TooltipElement.prototype, "icon", void 0);
7871
- TooltipElement = _TooltipElement = __decorate([safeCustomElement(`ixfx-tooltip`)], TooltipElement);
7872
- //#endregion
7873
5615
  //#region src/index.ts
7874
5616
  function init() {
7875
5617
  console.log(`Init`);
7876
5618
  }
7877
5619
  //#endregion
7878
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
5620
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SliderInputElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
7879
5621
 
7880
5622
  //# sourceMappingURL=index.js.map