@ixfx/components 0.4.3 → 0.4.4

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 (225) hide show
  1. package/bundle/index.d.ts +395 -1176
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +7699 -20648
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +12 -7
  6. package/dist/ac-text.d.ts.map +1 -1
  7. package/dist/ac-text.js +2 -3
  8. package/dist/ac-text.js.map +1 -1
  9. package/dist/{button-C3fLMKUv.js → button-DxYee1ZH.js} +2 -2
  10. package/dist/{button-C3fLMKUv.js.map → button-DxYee1ZH.js.map} +1 -1
  11. package/dist/button.d.ts +1 -2
  12. package/dist/button.d.ts.map +1 -1
  13. package/dist/button.js +1 -2
  14. package/dist/checkbox.d.ts +0 -1
  15. package/dist/checkbox.d.ts.map +1 -1
  16. package/dist/checkbox.js +1 -1
  17. package/dist/checkbox.js.map +1 -1
  18. package/dist/{colour-picker-0sgAha1T.js → colour-picker-BacNRabo.js} +14 -16
  19. package/dist/colour-picker-BacNRabo.js.map +1 -0
  20. package/dist/colour-picker.d.ts +1 -1
  21. package/dist/colour-picker.js +1 -1
  22. package/dist/crumbs.d.ts +5 -2
  23. package/dist/crumbs.d.ts.map +1 -1
  24. package/dist/crumbs.js +45 -20
  25. package/dist/crumbs.js.map +1 -1
  26. package/dist/data-display.d.ts +1 -2
  27. package/dist/data-display.d.ts.map +1 -1
  28. package/dist/data-display.js +25 -23
  29. package/dist/data-display.js.map +1 -1
  30. package/dist/{data-provider-DgI909FP.js → data-provider-35TyWclX.js} +2 -2
  31. package/dist/data-provider-35TyWclX.js.map +1 -0
  32. package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
  33. package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
  34. package/dist/editable-label.d.ts +1 -2
  35. package/dist/editable-label.d.ts.map +1 -1
  36. package/dist/editable-label.js +1 -1
  37. package/dist/editable-label.js.map +1 -1
  38. package/dist/{hex-editor-WZrjRtvL.js → hex-editor-Bk6rxhfg.js} +9 -11
  39. package/dist/hex-editor-Bk6rxhfg.js.map +1 -0
  40. package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
  41. package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
  42. package/dist/hex.d.ts +1 -1
  43. package/dist/hex.js +1 -1
  44. package/dist/highlight-B-eQrhhb.js.map +1 -1
  45. package/dist/{icon-Ndo40kNO.js → icon-B22XVlCt.js} +6 -4
  46. package/dist/{icon-Ndo40kNO.js.map → icon-B22XVlCt.js.map} +1 -1
  47. package/dist/{icon-Bd5BiU4b.d.ts → icon-DpA9x2Ve.d.ts} +2 -3
  48. package/dist/icon-DpA9x2Ve.d.ts.map +1 -0
  49. package/dist/icons.d.ts +2 -2
  50. package/dist/icons.js +1 -1
  51. package/dist/{incr-search-CeERfijK.js → incr-search-2pz21xtR.js} +9 -6
  52. package/dist/incr-search-2pz21xtR.js.map +1 -0
  53. package/dist/incr-search.d.ts +1 -1
  54. package/dist/incr-search.js +1 -1
  55. package/dist/{index-CowKi2mo.d.ts → index-BeuCXtiO.d.ts} +3 -4
  56. package/dist/index-BeuCXtiO.d.ts.map +1 -0
  57. package/dist/{index-D87kRcEs.d.ts → index-BtGFYfaK.d.ts} +2 -1
  58. package/dist/index-BtGFYfaK.d.ts.map +1 -0
  59. package/dist/{index-s_IhSnwc.d.ts → index-CoqtMSd9.d.ts} +6 -4
  60. package/dist/index-CoqtMSd9.d.ts.map +1 -0
  61. package/dist/{index-9fGVAg1d.d.ts → index-Cxwxtj6g.d.ts} +3 -3
  62. package/dist/index-Cxwxtj6g.d.ts.map +1 -0
  63. package/dist/index-D_ftz_IT.d.ts +184 -0
  64. package/dist/index-D_ftz_IT.d.ts.map +1 -0
  65. package/dist/{index-_RTQSKHi.d.ts → index-DfEkTGvT.d.ts} +11 -11
  66. package/dist/index-DfEkTGvT.d.ts.map +1 -0
  67. package/dist/index.d.ts +44 -29
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +304 -3075
  70. package/dist/index.js.map +1 -1
  71. package/dist/keyboard-B5xD7Fz-.js +36 -0
  72. package/dist/keyboard-B5xD7Fz-.js.map +1 -0
  73. package/dist/{labelled-input-base-ORb1rGq6.d.ts → labelled-input-base-DiTme1JO.d.ts} +1 -2
  74. package/dist/labelled-input-base-DiTme1JO.d.ts.map +1 -0
  75. package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
  76. package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
  77. package/dist/labelled-radial-input.d.ts +5 -4
  78. package/dist/labelled-radial-input.d.ts.map +1 -1
  79. package/dist/labelled-radial-input.js +7 -3
  80. package/dist/labelled-radial-input.js.map +1 -1
  81. package/dist/labelled-range-input.d.ts +1 -1
  82. package/dist/labelled-range-input.js +27 -3
  83. package/dist/labelled-range-input.js.map +1 -1
  84. package/dist/led.d.ts +1 -2
  85. package/dist/led.d.ts.map +1 -1
  86. package/dist/led.js +1 -1
  87. package/dist/led.js.map +1 -1
  88. package/dist/{menu-vjoiHZ13.js → menu-g6yd7ddN.js} +8 -9
  89. package/dist/menu-g6yd7ddN.js.map +1 -0
  90. package/dist/{menu-item-COx-Azgj.d.ts → menu-item-DSyf9f_L.d.ts} +4 -4
  91. package/dist/menu-item-DSyf9f_L.d.ts.map +1 -0
  92. package/dist/{menu-item-BrIuORYD.js → menu-item-NUKwJ4s5.js} +3 -4
  93. package/dist/{menu-item-BrIuORYD.js.map → menu-item-NUKwJ4s5.js.map} +1 -1
  94. package/dist/menu.d.ts +2 -2
  95. package/dist/menu.js +2 -2
  96. package/dist/miller.d.ts +8 -5
  97. package/dist/miller.d.ts.map +1 -1
  98. package/dist/miller.js +22 -24
  99. package/dist/miller.js.map +1 -1
  100. package/dist/narrowed-text.d.ts +7 -3
  101. package/dist/narrowed-text.d.ts.map +1 -1
  102. package/dist/narrowed-text.js +73 -47
  103. package/dist/narrowed-text.js.map +1 -1
  104. package/dist/panel.d.ts +1 -1
  105. package/dist/panel.d.ts.map +1 -1
  106. package/dist/panel.js +2 -2
  107. package/dist/panel.js.map +1 -1
  108. package/dist/plots.d.ts +2 -2
  109. package/dist/plots.js +1 -1
  110. package/dist/polar-pad.d.ts +15 -3
  111. package/dist/polar-pad.d.ts.map +1 -1
  112. package/dist/polar-pad.js +64 -11
  113. package/dist/polar-pad.js.map +1 -1
  114. package/dist/{radial-input-CpQPs1Mp.d.ts → radial-input-DXMN55Nz.d.ts} +6 -4
  115. package/dist/radial-input-DXMN55Nz.d.ts.map +1 -0
  116. package/dist/{radial-input-DZ7eQCcM.js → radial-input-DxCrt_NE.js} +41 -19
  117. package/dist/radial-input-DxCrt_NE.js.map +1 -0
  118. package/dist/radial-input.d.ts +1 -1
  119. package/dist/radial-input.js +1 -1
  120. package/dist/range-input.d.ts +15 -4
  121. package/dist/range-input.d.ts.map +1 -1
  122. package/dist/range-input.js +23 -2
  123. package/dist/range-input.js.map +1 -1
  124. package/dist/range.d.ts +15 -4
  125. package/dist/range.d.ts.map +1 -1
  126. package/dist/range.js +23 -2
  127. package/dist/range.js.map +1 -1
  128. package/dist/selecthorizontal.d.ts +1 -2
  129. package/dist/selecthorizontal.d.ts.map +1 -1
  130. package/dist/selecthorizontal.js +1 -1
  131. package/dist/selecthorizontal.js.map +1 -1
  132. package/dist/slider-input-DFpG23bS.js +1592 -0
  133. package/dist/slider-input-DFpG23bS.js.map +1 -0
  134. package/dist/slider-input-XppH3vcy.d.ts +160 -0
  135. package/dist/slider-input-XppH3vcy.d.ts.map +1 -0
  136. package/dist/slider-input.d.ts +2 -0
  137. package/dist/slider-input.js +2 -0
  138. package/dist/snap-container.d.ts +1 -2
  139. package/dist/snap-container.d.ts.map +1 -1
  140. package/dist/snap-container.js +6 -5
  141. package/dist/snap-container.js.map +1 -1
  142. package/dist/split-layout.d.ts +1 -2
  143. package/dist/split-layout.d.ts.map +1 -1
  144. package/dist/split-layout.js +6 -4
  145. package/dist/split-layout.js.map +1 -1
  146. package/dist/swipe.d.ts +12 -2
  147. package/dist/swipe.d.ts.map +1 -1
  148. package/dist/swipe.js +22 -3
  149. package/dist/swipe.js.map +1 -1
  150. package/dist/{tab-list-DLzb-m-I.d.ts → tab-list-BohmbvqF.d.ts} +14 -5
  151. package/dist/tab-list-BohmbvqF.d.ts.map +1 -0
  152. package/dist/tab-list-DzknpdSo.js +592 -0
  153. package/dist/tab-list-DzknpdSo.js.map +1 -0
  154. package/dist/tabs.d.ts +2 -2
  155. package/dist/tabs.js +1 -208
  156. package/dist/{tickled-controller-BjYCzGrU.d.ts → tickled-controller-BF2Ea0DE.d.ts} +2 -31
  157. package/dist/tickled-controller-BF2Ea0DE.d.ts.map +1 -0
  158. package/dist/tickled-styles-fNDdqf6l.js.map +1 -1
  159. package/dist/{timeline-2OFtN4Ta.js → timeline-B2fgDL4U.js} +37 -1438
  160. package/dist/timeline-B2fgDL4U.js.map +1 -0
  161. package/dist/timeline.d.ts +1 -1
  162. package/dist/timeline.js +1 -1
  163. package/dist/{tooltip-RGVIwHrZ.d.ts → tooltip-BlvBUQxx.d.ts} +3 -3
  164. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
  165. package/dist/{tree-D84RUgFC.js → tree-BnvzhsAw.js} +8 -9
  166. package/dist/tree-BnvzhsAw.js.map +1 -0
  167. package/dist/{tree-component-BaCSPWg1.d.ts → tree-component-DCmmKZ4j.d.ts} +8 -124
  168. package/dist/tree-component-DCmmKZ4j.d.ts.map +1 -0
  169. package/dist/tree.d.ts +10 -4
  170. package/dist/tree.d.ts.map +1 -1
  171. package/dist/tree.js +1 -1
  172. package/dist/types-DO3gt5vg.d.ts +130 -0
  173. package/dist/types-DO3gt5vg.d.ts.map +1 -0
  174. package/dist/wheel-nudge-BlSCe_hD.js +86 -0
  175. package/dist/wheel-nudge-BlSCe_hD.js.map +1 -0
  176. package/dist/wheel-nudge-DGrNzWuE.d.ts +29 -0
  177. package/dist/wheel-nudge-DGrNzWuE.d.ts.map +1 -0
  178. package/dist/{xy-axis-BeWRMmbo.d.ts → xy-axis-5KhVTNoX.d.ts} +30 -7
  179. package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
  180. package/dist/xy-axis-CxHC8z5E.js +1849 -0
  181. package/dist/xy-axis-CxHC8z5E.js.map +1 -0
  182. package/dist/xy-pad.d.ts +13 -2
  183. package/dist/xy-pad.d.ts.map +1 -1
  184. package/dist/xy-pad.js +47 -6
  185. package/dist/xy-pad.js.map +1 -1
  186. package/docs-user/radial-input.md +2 -2
  187. package/package.json +21 -20
  188. package/dist/colour-C3MQIjFJ-vRCdr8W-.js +0 -3732
  189. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +0 -1
  190. package/dist/colour-picker-0sgAha1T.js.map +0 -1
  191. package/dist/data-provider-DgI909FP.js.map +0 -1
  192. package/dist/dist-CA13FvMn.js +0 -980
  193. package/dist/dist-CA13FvMn.js.map +0 -1
  194. package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
  195. package/dist/hex-editor-WZrjRtvL.js.map +0 -1
  196. package/dist/icon-Bd5BiU4b.d.ts.map +0 -1
  197. package/dist/incr-search-CeERfijK.js.map +0 -1
  198. package/dist/index-9fGVAg1d.d.ts.map +0 -1
  199. package/dist/index-CowKi2mo.d.ts.map +0 -1
  200. package/dist/index-D87kRcEs.d.ts.map +0 -1
  201. package/dist/index-DgXpCg_G.d.ts +0 -1244
  202. package/dist/index-DgXpCg_G.d.ts.map +0 -1
  203. package/dist/index-_RTQSKHi.d.ts.map +0 -1
  204. package/dist/index-s_IhSnwc.d.ts.map +0 -1
  205. package/dist/keyboard-CimiEskD.js +0 -20
  206. package/dist/keyboard-CimiEskD.js.map +0 -1
  207. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +0 -1
  208. package/dist/menu-item-COx-Azgj.d.ts.map +0 -1
  209. package/dist/menu-vjoiHZ13.js.map +0 -1
  210. package/dist/radial-input-CpQPs1Mp.d.ts.map +0 -1
  211. package/dist/radial-input-DZ7eQCcM.js.map +0 -1
  212. package/dist/tab-list-DLzb-m-I.d.ts.map +0 -1
  213. package/dist/tabs.js.map +0 -1
  214. package/dist/tickled-controller-BjYCzGrU.d.ts.map +0 -1
  215. package/dist/timeline-2OFtN4Ta.js.map +0 -1
  216. package/dist/tooltip-RGVIwHrZ.d.ts.map +0 -1
  217. package/dist/tree-D84RUgFC.js.map +0 -1
  218. package/dist/tree-component-BaCSPWg1.d.ts.map +0 -1
  219. package/dist/types-DSfbtHs3.d.ts +0 -8
  220. package/dist/types-DSfbtHs3.d.ts.map +0 -1
  221. package/dist/xy-axis-BeWRMmbo.d.ts.map +0 -1
  222. package/dist/xy-axis-no0OL_O1.js +0 -7893
  223. package/dist/xy-axis-no0OL_O1.js.map +0 -1
  224. /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
  225. /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";
8
+ import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-2pz21xtR.js";
9
9
  import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-C3b9OWJD.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-BacNRabo.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-DzknpdSo.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
46
  import { LitElement, css, html, nothing } 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
  >
@@ -1410,2887 +1412,158 @@ let SplitButton = class SplitButton extends ButtonElement {
1410
1412
  @keydown=${this._handlePrimaryKeyDown}
1411
1413
  @click=${this._handleSwitcherPrimaryClick}
1412
1414
  >
1413
- ${primaryIcon}${primaryLabel}
1414
- </button>
1415
- <ixfx-menu-trigger .registry=${this.registry} .keyboardManager=${this.keyboardManager}>
1416
- ${this._renderCaret(`chevron-right`, `Choose action`)}
1417
- <ixfx-menu-container slot="menu">
1418
- ${popupItems}
1419
- </ixfx-menu-container>
1420
- </ixfx-menu-trigger>
1421
- </div>
1422
- `;
1423
- }
1424
- static {
1425
- this.styles = [
1426
- themeFallbacks,
1427
- prominenceStyles,
1428
- buttonStyles,
1429
- css`
1430
- :host {
1431
- display: inline-flex;
1432
- max-width: 100%;
1433
- vertical-align: middle;
1434
- }
1435
-
1436
- slot.switcher-data {
1437
- display: none;
1438
- }
1439
-
1440
- .split {
1441
- display: inline-flex;
1442
- width: 100%;
1443
- background: var(--surface-3, #ccc);
1444
- color: var(--surface-3-text, #000);
1445
- border: var(--border, 1px solid #999);
1446
- border-radius: var(--radius-xl, 8px);
1447
- corner-shape: superellipse(1);
1448
- box-shadow:
1449
- inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-4) 30%, transparent),
1450
- inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 20%, transparent),
1451
- 2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 30%, transparent);
1452
- overflow: hidden;
1453
- transition: background var(--transition, 0.2s), border-color var(--transition, 0.2s);
1454
- }
1455
-
1456
- /* Switcher: accent the caret separator to signal "this changes the default" */
1457
- .split.switcher button.caret {
1458
- border-inline-start-color: var(--accent, #666);
1459
- opacity: 0.7;
1460
- }
1461
-
1462
- .split.switcher button.caret:hover:not(:disabled) {
1463
- opacity: 1;
1464
- }
1465
-
1466
- /* Caret is dimmed when there is no popup content */
1467
- button.caret[data-empty] {
1468
- opacity: 0.3;
1469
- pointer-events: none;
1470
- }
1471
-
1472
- .split:has(button:hover:not(:disabled)) {
1473
- border-color: var(--accent, #666);
1474
- box-shadow:
1475
- inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-5) 70%, transparent),
1476
- inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 60%, transparent),
1477
- 2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 90%, transparent);
1478
- }
1479
-
1480
- .split:has(button:active:not(:disabled)) {
1481
- transform: translateY(1px);
1482
- box-shadow: inset 1px 1px 0px 0.5px color-mix(in oklch, var(--surface-1), transparent);
1483
- }
1484
-
1485
- button.primary,
1486
- button.caret {
1487
- border: none;
1488
- border-radius: 0;
1489
- background: none;
1490
- box-shadow: none;
1491
- color: inherit;
1492
- margin: 0;
1493
- cursor: pointer;
1494
- display: inline-flex;
1495
- align-items: center;
1496
- justify-content: center;
1497
- transition: background var(--transition, 0.2s), opacity var(--transition, 0.2s);
1498
- }
1499
-
1500
- button.primary {
1501
- flex: 1;
1502
- padding: var(--space-m, 8px) var(--space-l, 12px);
1503
- gap: 0.5em;
1504
- overflow: hidden;
1505
- white-space: nowrap;
1506
- }
1507
-
1508
- button.caret {
1509
- padding: var(--space-m, 8px) var(--space-s, 6px);
1510
- border-inline-start: var(--border, 1px solid #999);
1511
- flex-shrink: 0;
1512
- }
1513
-
1514
- button.primary:hover:not(:disabled),
1515
- button.caret:hover:not(:disabled) {
1516
- background: color-mix(in oklch, var(--surface-4) 80%, transparent);
1517
- }
1518
-
1519
- button.primary:active:not(:disabled),
1520
- button.caret:active:not(:disabled) {
1521
- background: var(--surface-2, #aaa);
1522
- transform: none;
1523
- box-shadow: none;
1524
- }
1525
-
1526
- button.primary:disabled,
1527
- button.caret:disabled {
1528
- opacity: 0.5;
1529
- cursor: not-allowed;
1530
- }
1531
-
1532
- button.primary:focus-visible,
1533
- button.caret:focus-visible {
1534
- outline: 2px solid var(--accent, #666);
1535
- outline-offset: -2px;
1536
- }
1537
-
1538
- ixfx-menu-trigger {
1539
- display: inline-flex;
1540
- align-items: stretch;
1541
- }
1542
- `
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;
1415
+ ${primaryIcon}${primaryLabel}
1416
+ </button>
1417
+ <ixfx-menu-trigger .registry=${this.registry} .keyboardManager=${this.keyboardManager}>
1418
+ ${this._renderCaret(`chevron-right`, `Choose action`)}
1419
+ <ixfx-menu-container slot="menu">
1420
+ ${popupItems}
1421
+ </ixfx-menu-container>
1422
+ </ixfx-menu-trigger>
1423
+ </div>
1424
+ `;
4154
1425
  }
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;
1426
+ static {
1427
+ this.styles = [
1428
+ themeFallbacks,
1429
+ prominenceStyles,
1430
+ buttonStyles,
1431
+ css`
1432
+ :host {
1433
+ display: inline-flex;
1434
+ max-width: 100%;
1435
+ vertical-align: middle;
1436
+ }
1437
+
1438
+ slot.switcher-data {
1439
+ display: none;
1440
+ }
1441
+
1442
+ .split {
1443
+ display: inline-flex;
1444
+ width: 100%;
1445
+ background: var(--surface-3, #ccc);
1446
+ color: var(--surface-3-text, #000);
1447
+ border: var(--border, 1px solid #999);
1448
+ border-radius: var(--radius-xl, 8px);
1449
+ corner-shape: superellipse(1);
1450
+ box-shadow:
1451
+ inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-4) 30%, transparent),
1452
+ inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 20%, transparent),
1453
+ 2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 30%, transparent);
1454
+ overflow: hidden;
1455
+ transition: background var(--transition, 0.2s), border-color var(--transition, 0.2s);
1456
+ }
1457
+
1458
+ /* Switcher: accent the caret separator to signal "this changes the default" */
1459
+ .split.switcher button.caret {
1460
+ border-inline-start-color: var(--accent, #666);
1461
+ opacity: 0.7;
1462
+ }
1463
+
1464
+ .split.switcher button.caret:hover:not(:disabled) {
1465
+ opacity: 1;
1466
+ }
1467
+
1468
+ /* Caret is dimmed when there is no popup content */
1469
+ button.caret[data-empty] {
1470
+ opacity: 0.3;
1471
+ pointer-events: none;
1472
+ }
1473
+
1474
+ .split:has(button:hover:not(:disabled)) {
1475
+ border-color: var(--accent, #666);
1476
+ box-shadow:
1477
+ inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-5) 70%, transparent),
1478
+ inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 60%, transparent),
1479
+ 2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 90%, transparent);
1480
+ }
1481
+
1482
+ .split:has(button:active:not(:disabled)) {
1483
+ transform: translateY(1px);
1484
+ box-shadow: inset 1px 1px 0px 0.5px color-mix(in oklch, var(--surface-1), transparent);
1485
+ }
1486
+
1487
+ button.primary,
1488
+ button.caret {
1489
+ border: none;
1490
+ border-radius: 0;
1491
+ background: none;
1492
+ box-shadow: none;
1493
+ color: inherit;
1494
+ margin: 0;
1495
+ cursor: pointer;
1496
+ display: inline-flex;
1497
+ align-items: center;
1498
+ justify-content: center;
1499
+ transition: background var(--transition, 0.2s), opacity var(--transition, 0.2s);
1500
+ }
1501
+
1502
+ button.primary {
1503
+ flex: 1;
1504
+ padding: var(--space-m, 8px) var(--space-l, 12px);
1505
+ gap: 0.5em;
1506
+ overflow: hidden;
1507
+ white-space: nowrap;
1508
+ }
1509
+
1510
+ button.caret {
1511
+ padding: var(--space-m, 8px) var(--space-s, 6px);
1512
+ border-inline-start: var(--border, 1px solid #999);
1513
+ flex-shrink: 0;
1514
+ }
1515
+
1516
+ button.primary:hover:not(:disabled),
1517
+ button.caret:hover:not(:disabled) {
1518
+ background: color-mix(in oklch, var(--surface-4) 80%, transparent);
1519
+ }
1520
+
1521
+ button.primary:active:not(:disabled),
1522
+ button.caret:active:not(:disabled) {
1523
+ background: var(--surface-2, #aaa);
1524
+ transform: none;
1525
+ box-shadow: none;
1526
+ }
1527
+
1528
+ button.primary:disabled,
1529
+ button.caret:disabled {
1530
+ opacity: 0.5;
1531
+ cursor: not-allowed;
1532
+ }
1533
+
1534
+ button.primary:focus-visible,
1535
+ button.caret:focus-visible {
1536
+ outline: 2px solid var(--accent, #666);
1537
+ outline-offset: -2px;
1538
+ }
1539
+
1540
+ ixfx-menu-trigger {
1541
+ display: inline-flex;
1542
+ align-items: stretch;
1543
+ }
1544
+ `
1545
+ ];
4281
1546
  }
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
1547
  };
1548
+ __decorate([property({ attribute: false })], SplitButton.prototype, "registry", void 0);
1549
+ __decorate([property({ attribute: false })], SplitButton.prototype, "keyboardManager", void 0);
1550
+ __decorate([property({ type: String })], SplitButton.prototype, "mode", void 0);
1551
+ __decorate([property({
1552
+ type: String,
1553
+ attribute: `default-value`
1554
+ })], SplitButton.prototype, "defaultValue", void 0);
1555
+ __decorate([property({ attribute: false })], SplitButton.prototype, "itemsProvider", void 0);
1556
+ __decorate([property({ attribute: false })], SplitButton.prototype, "items", void 0);
1557
+ __decorate([query(`ixfx-menu-trigger`)], SplitButton.prototype, "_menuTrigger", void 0);
1558
+ __decorate([state()], SplitButton.prototype, "_compact", void 0);
1559
+ __decorate([state()], SplitButton.prototype, "_selectedCommand", void 0);
1560
+ __decorate([state()], SplitButton.prototype, "_selectedLabel", void 0);
1561
+ __decorate([state()], SplitButton.prototype, "_selectedIcon", void 0);
1562
+ __decorate([state()], SplitButton.prototype, "_switcherItems", void 0);
1563
+ __decorate([state()], SplitButton.prototype, "_dynamicItems", void 0);
1564
+ __decorate([state()], SplitButton.prototype, "_loadingItems", void 0);
1565
+ __decorate([state()], SplitButton.prototype, "_menuHasItems", void 0);
1566
+ SplitButton = __decorate([safeCustomElement(`ixfx-split-button`)], SplitButton);
4294
1567
  //#endregion
4295
1568
  //#region src/crumbs/crumb-path-controller.ts
4296
1569
  var CrumbPathController = class {
@@ -4301,7 +1574,7 @@ var CrumbPathController = class {
4301
1574
  constructor(options = {}) {
4302
1575
  this.#separator = options.separator ?? `/`;
4303
1576
  this.#onQuery = options.onQuery;
4304
- this.#pathed = new tree_exports.Pathed.Pathed({ separator: this.#separator });
1577
+ this.#pathed = new Trees.Pathed.Pathed({ separator: this.#separator });
4305
1578
  if (options.paths) this.addPaths(options.paths);
4306
1579
  }
4307
1580
  get separator() {
@@ -4410,7 +1683,6 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4410
1683
  case `Escape`:
4411
1684
  e.preventDefault();
4412
1685
  this.#closeDropdown();
4413
- break;
4414
1686
  }
4415
1687
  };
4416
1688
  this.#onHostKeyDown = (e) => {
@@ -4749,9 +2021,11 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4749
2021
  #onHostKeyDown;
4750
2022
  render() {
4751
2023
  const segments = this.#getSegments();
4752
- if (this._editing) return html`
2024
+ if (this._editing) {
2025
+ const editValue = this.path;
2026
+ return html`
4753
2027
  <ixfx-ac-text
4754
- .value=${this.path}
2028
+ .value=${editValue}
4755
2029
  .tabSuffix=${this.separator}
4756
2030
  .completionProvider=${this.#makeCompletionProvider()}
4757
2031
  @change=${this.#onAcChange}
@@ -4759,6 +2033,7 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4759
2033
  @keydown=${this.#onAcKeyDown}
4760
2034
  ></ixfx-ac-text>
4761
2035
  `;
2036
+ }
4762
2037
  const rootSegments = this.#getRootSegments();
4763
2038
  const leadingCaret = this.siblingLookup && rootSegments.length === 0 ? html`
4764
2039
  <div class="caret ${this._openIdx === -1 ? `open` : ``} ${this._confirmedLeafIndices.has(``) ? `disabled` : ``}"
@@ -4986,7 +2261,7 @@ CrumbPathElement = __decorate([safeCustomElement(`ixfx-crumb-path`)], CrumbPathE
4986
2261
  //#endregion
4987
2262
  //#region src/editable-label/editable-number.ts
4988
2263
  const DRAG_THRESHOLD_PX = 3;
4989
- let EditableNumber = class EditableNumber extends EditableLabel {
2264
+ let EditableNumber = class EditableNumber extends WheelNudgeMixin(EditableLabel) {
4990
2265
  #dragStartY;
4991
2266
  #dragStartValue;
4992
2267
  #dragging;
@@ -5239,14 +2514,15 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5239
2514
  this.style.setProperty(`--value`, String(normalized));
5240
2515
  let valueStart = 0;
5241
2516
  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`) {
2517
+ if (this.linearStyle === `bipolar`) {
2518
+ if (normalized <= .5) {
2519
+ valueStart = normalized;
2520
+ valueEnd = .5;
2521
+ } else {
2522
+ valueStart = .5;
2523
+ valueEnd = normalized;
2524
+ }
2525
+ } else if (this.linearStyle === `unipolar`) {
5250
2526
  valueStart = .5 - normalized * .5;
5251
2527
  valueEnd = .5 + normalized * .5;
5252
2528
  }
@@ -5288,8 +2564,7 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5288
2564
  _handleArrowKey(e) {
5289
2565
  const range = (this.max ?? 100) - (this.min ?? 0);
5290
2566
  if (range === 0) return false;
5291
- const shiftDivisor = e.shiftKey ? 10 : 1;
5292
- const effectiveStep = resolveStep(range, void 0, this.step) / shiftDivisor;
2567
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, e.shiftKey);
5293
2568
  let delta = 0;
5294
2569
  let handled = false;
5295
2570
  switch (e.key) {
@@ -5310,33 +2585,49 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5310
2585
  case `End`:
5311
2586
  delta = (this.max ?? 0) - this._parseValue();
5312
2587
  handled = true;
5313
- break;
5314
2588
  }
5315
2589
  if (handled) {
5316
2590
  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
- });
2591
+ this._applyDelta(delta);
5336
2592
  return true;
5337
2593
  }
5338
2594
  return false;
5339
2595
  }
2596
+ /**
2597
+ * Apply a signed delta to the current value, clamp/snap/format, and fire
2598
+ * `input`/`change`. Shared between arrow-key handler and the wheel handler.
2599
+ */
2600
+ _applyDelta(delta) {
2601
+ const prev = this.value;
2602
+ const current = this._parseValue();
2603
+ const newValue = this._clamp(this._snap(current + delta));
2604
+ const newValueStr = this.step !== void 0 ? this._formatNumber(newValue) : newValue.toFixed(this.precision);
2605
+ this.value = newValueStr;
2606
+ this._requestDisplayUpdate();
2607
+ this._updateValueCss(this._normalizedValue(newValue));
2608
+ if (newValueStr !== prev) this.dispatchEvent(new CustomEvent(`input`, {
2609
+ detail: { value: newValueStr },
2610
+ bubbles: true,
2611
+ composed: true
2612
+ }));
2613
+ requestAnimationFrame(() => {
2614
+ if (this.value !== prev) this.dispatchEvent(new CustomEvent(`change`, {
2615
+ detail: { value: this.value },
2616
+ bubbles: true,
2617
+ composed: true
2618
+ }));
2619
+ });
2620
+ }
2621
+ _shouldHandleWheel() {
2622
+ if (this._editing) return false;
2623
+ return super._shouldHandleWheel();
2624
+ }
2625
+ _applyWheelDelta(direction, event) {
2626
+ const range = (this.max ?? 100) - (this.min ?? 0);
2627
+ if (range === 0) return;
2628
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
2629
+ this._applyDelta(direction * effectiveStep);
2630
+ }
5340
2631
  _parseValue() {
5341
2632
  return Number.parseFloat(this.value) || 0;
5342
2633
  }
@@ -5359,6 +2650,11 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5359
2650
  return n;
5360
2651
  }
5361
2652
  _snap(n) {
2653
+ if (this.stops && this.stops > 1) {
2654
+ const min = this.min ?? 0;
2655
+ const stopStep = ((this.max ?? 100) - min) / this.stops;
2656
+ return Math.round((n - min) / stopStep) * stopStep + min;
2657
+ }
5362
2658
  if (!this.step) return n;
5363
2659
  return Math.round(n / this.step) * this.step;
5364
2660
  }
@@ -5549,6 +2845,7 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5549
2845
  __decorate([property({ type: Number })], EditableNumber.prototype, "min", void 0);
5550
2846
  __decorate([property({ type: Number })], EditableNumber.prototype, "max", void 0);
5551
2847
  __decorate([property({ type: Number })], EditableNumber.prototype, "step", void 0);
2848
+ __decorate([property({ type: Number })], EditableNumber.prototype, "stops", void 0);
5552
2849
  __decorate([property({
5553
2850
  type: Number,
5554
2851
  attribute: `drag-sensitivity`
@@ -5971,9 +3268,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
5971
3268
  }
5972
3269
  break;
5973
3270
  }
5974
- case `Escape`:
5975
- this._clearSelection();
5976
- break;
3271
+ case `Escape`: this._clearSelection();
5977
3272
  }
5978
3273
  };
5979
3274
  this._onClick = (e) => {
@@ -6142,7 +3437,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6142
3437
  _replaceSelection(item) {
6143
3438
  if (this.selectionMode === `none`) return;
6144
3439
  const previous = this._selectedItems;
6145
- const next = new Set([item]);
3440
+ const next = /* @__PURE__ */ new Set([item]);
6146
3441
  this._selectedItems = next;
6147
3442
  this.#selectionAnchor = item;
6148
3443
  this._syncItemStates();
@@ -6229,7 +3524,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
6229
3524
  } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
6230
3525
  else this._replaceSelection(item);
6231
3526
  break;
6232
- case `checked`: break;
3527
+ case `checked`:
6233
3528
  }
6234
3529
  }
6235
3530
  _handleSpaceKey(item) {
@@ -6867,11 +4162,13 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
6867
4162
  }
6868
4163
  a = newA;
6869
4164
  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}'`);
4165
+ } else if (which === `a`) {
4166
+ if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
4167
+ else a = v;
4168
+ } else if (which === `b`) {
4169
+ if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
4170
+ else b = v;
4171
+ } else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
6875
4172
  this.setPoles(a, b);
6876
4173
  }
6877
4174
  setPoles(a, b) {
@@ -6930,63 +4227,65 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
6930
4227
  const currentPos = isVertical ? current.offset.y : current.offset.x;
6931
4228
  const amt = (isVertical ? startPos - currentPos : currentPos - startPos) / valuePerPix;
6932
4229
  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;
4230
+ if (draggingWhich === `a`) {
4231
+ if (resizeMode === `bipolar`) {
4232
+ const calcA = startA + amt;
4233
+ const calcB = startB - amt;
4234
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4235
+ setPoles(calcA, calcB);
4236
+ } else if (resizeMode === `bipolar-flex`) {
4237
+ let calcA = startA + amt;
4238
+ let calcB = startB;
4239
+ if (startB <= min) calcB = min;
4240
+ else if (startB >= max) calcB = max;
4241
+ else {
4242
+ calcA = startA + amt;
4243
+ calcB = startB - amt;
4244
+ }
4245
+ if (calcA < min) calcA = min;
4246
+ if (calcA > max) calcA = max;
4247
+ if (calcB < min) calcB = min;
4248
+ if (calcB > max) calcB = max;
4249
+ if (calcA > calcB) return;
4250
+ setPoles(calcA, calcB);
4251
+ } else {
4252
+ let constrainedAmt = amt;
4253
+ if (startA + amt < min) constrainedAmt = min - startA;
4254
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4255
+ const finalA = startA + constrainedAmt;
4256
+ const finalB = startB + constrainedAmt;
4257
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6946
4258
  }
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;
4259
+ } else if (draggingWhich === `b`) {
4260
+ if (resizeMode === `bipolar`) {
4261
+ const calcA = startA - amt;
4262
+ const calcB = startB + amt;
4263
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4264
+ setPoles(calcA, calcB);
4265
+ } else if (resizeMode === `bipolar-flex`) {
4266
+ let calcA = startA;
4267
+ let calcB = startB + amt;
4268
+ if (startA <= min) calcA = min;
4269
+ else if (startA >= max) calcA = max;
4270
+ else {
4271
+ calcA = startA - amt;
4272
+ calcB = startB + amt;
4273
+ }
4274
+ if (calcA < min) calcA = min;
4275
+ if (calcA > max) calcA = max;
4276
+ if (calcB < min) calcB = min;
4277
+ if (calcB > max) calcB = max;
4278
+ if (calcA > calcB) return;
4279
+ setPoles(calcA, calcB);
4280
+ } else {
4281
+ let constrainedAmt = amt;
4282
+ if (startA + amt < min) constrainedAmt = min - startA;
4283
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4284
+ const finalA = startA + constrainedAmt;
4285
+ const finalB = startB + constrainedAmt;
4286
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6974
4287
  }
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`) {
4288
+ } else if (resizeMode === `bipolar`) {
6990
4289
  const calcA = startA + amt;
6991
4290
  const calcB = startB + amt;
6992
4291
  if (calcA < min || calcB > max) return;
@@ -7366,13 +4665,18 @@ let TabListItemElement = class TabListItemElement extends LitElement {
7366
4665
  }
7367
4666
 
7368
4667
  .toolbar {
7369
- display: none;
4668
+ /* Always laid out (display: flex) so the tab's width doesn't shift when
4669
+ the toolbar appears on selection. visibility: hidden keeps the
4670
+ toolbar from receiving pointer events or painting, while preserving
4671
+ the space its contents take up. */
4672
+ display: flex;
7370
4673
  align-items: center;
7371
4674
  gap: var(--space-xs);
4675
+ visibility: hidden;
7372
4676
  }
7373
4677
 
7374
4678
  :host([selected]) .toolbar {
7375
- display: flex;
4679
+ visibility: visible;
7376
4680
  }
7377
4681
 
7378
4682
  slot[name="toolbar"] {
@@ -7795,86 +5099,11 @@ function monitorIndeterminate(targetElOrQuery, watchedElsOrQueries) {
7795
5099
  };
7796
5100
  }
7797
5101
  //#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
5102
  //#region src/index.ts
7874
5103
  function init() {
7875
5104
  console.log(`Init`);
7876
5105
  }
7877
5106
  //#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 };
5107
+ 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, 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, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
7879
5108
 
7880
5109
  //# sourceMappingURL=index.js.map