@ixfx/components 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/bundle/index.d.ts +1086 -603
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +16153 -15296
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +14 -4
  6. package/dist/ac-text.d.ts.map +1 -1
  7. package/dist/ac-text.js +11 -6
  8. package/dist/ac-text.js.map +1 -1
  9. package/dist/{button-DMt5XWUK.js → button-C3fLMKUv.js} +4 -4
  10. package/dist/{button-DMt5XWUK.js.map → button-C3fLMKUv.js.map} +1 -1
  11. package/dist/button.d.ts +1 -1
  12. package/dist/button.d.ts.map +1 -1
  13. package/dist/button.js +1 -1
  14. package/dist/checkbox.d.ts +2 -2
  15. package/dist/checkbox.d.ts.map +1 -1
  16. package/dist/checkbox.js +14 -8
  17. package/dist/checkbox.js.map +1 -1
  18. package/dist/{colour-C3MQIjFJ-BLXg8W3U.js → colour-C3MQIjFJ-vRCdr8W-.js} +146 -552
  19. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +1 -0
  20. package/dist/{colour-picker-K6zu82lm.js → colour-picker-0sgAha1T.js} +14 -9
  21. package/dist/colour-picker-0sgAha1T.js.map +1 -0
  22. package/dist/colour-picker.d.ts +1 -1
  23. package/dist/colour-picker.js +1 -1
  24. package/dist/crumbs.d.ts +1 -1
  25. package/dist/crumbs.d.ts.map +1 -1
  26. package/dist/crumbs.js +11 -6
  27. package/dist/crumbs.js.map +1 -1
  28. package/dist/data-display.d.ts +9 -4
  29. package/dist/data-display.d.ts.map +1 -1
  30. package/dist/data-display.js +270 -43
  31. package/dist/data-display.js.map +1 -1
  32. package/dist/data-provider-DgI909FP.js +23 -0
  33. package/dist/data-provider-DgI909FP.js.map +1 -0
  34. package/dist/{decorate-D7rC1gLP.js → decorate-DdjvVHS-.js} +2 -2
  35. package/dist/{decorate-D7rC1gLP.js.map → decorate-DdjvVHS-.js.map} +1 -1
  36. package/dist/{defaults-C7elhuyJ.js → defaults-C3b9OWJD.js} +2 -2
  37. package/dist/{defaults-C7elhuyJ.js.map → defaults-C3b9OWJD.js.map} +1 -1
  38. package/dist/{dist-TAGYwaju.js → dist-CA13FvMn.js} +7 -66
  39. package/dist/dist-CA13FvMn.js.map +1 -0
  40. package/dist/editable-label.d.ts.map +1 -1
  41. package/dist/editable-label.js +3 -2
  42. package/dist/editable-label.js.map +1 -1
  43. package/dist/fallbacks-pNMOMx38.js +168 -0
  44. package/dist/fallbacks-pNMOMx38.js.map +1 -0
  45. package/dist/{hex-editor-DlfoA65y.d.ts → hex-editor-CMIxtNgT.d.ts} +1 -1
  46. package/dist/hex-editor-CMIxtNgT.d.ts.map +1 -0
  47. package/dist/{hex-editor-CsN_ySkH.js → hex-editor-WZrjRtvL.js} +3 -3
  48. package/dist/{hex-editor-CsN_ySkH.js.map → hex-editor-WZrjRtvL.js.map} +1 -1
  49. package/dist/hex.d.ts +1 -1
  50. package/dist/hex.js +1 -1
  51. package/dist/{highlight-TPbSHruI.js → highlight-B-eQrhhb.js} +1 -1
  52. package/dist/{highlight-TPbSHruI.js.map → highlight-B-eQrhhb.js.map} +1 -1
  53. package/dist/{icon-Dm_DHDz6.d.ts → icon-Bd5BiU4b.d.ts} +3 -3
  54. package/dist/icon-Bd5BiU4b.d.ts.map +1 -0
  55. package/dist/{icon-9NWTXtE1.js → icon-Ndo40kNO.js} +6 -5
  56. package/dist/icon-Ndo40kNO.js.map +1 -0
  57. package/dist/icons.d.ts +2 -2
  58. package/dist/icons.js +3 -3
  59. package/dist/{incr-search-DSKKsk6w.js → incr-search-CeERfijK.js} +2 -2
  60. package/dist/{incr-search-DSKKsk6w.js.map → incr-search-CeERfijK.js.map} +1 -1
  61. package/dist/incr-search.d.ts +1 -1
  62. package/dist/incr-search.js +2 -2
  63. package/dist/{index-hXFn14tM.d.ts → index-BMjri2-S.d.ts} +2 -2
  64. package/dist/{index-hXFn14tM.d.ts.map → index-BMjri2-S.d.ts.map} +1 -1
  65. package/dist/{index-DSlPeWLK.d.ts → index-CWpNcQKE.d.ts} +5 -5
  66. package/dist/index-CWpNcQKE.d.ts.map +1 -0
  67. package/dist/{index-DLkSKL4T.d.ts → index-CowKi2mo.d.ts} +1 -1
  68. package/dist/index-CowKi2mo.d.ts.map +1 -0
  69. package/dist/{index-B1hNR7Z9.d.ts → index-D87kRcEs.d.ts} +1 -1
  70. package/dist/{index-B1hNR7Z9.d.ts.map → index-D87kRcEs.d.ts.map} +1 -1
  71. package/dist/{index-CnL9krsH.d.ts → index-DgXpCg_G.d.ts} +32 -26
  72. package/dist/index-DgXpCg_G.d.ts.map +1 -0
  73. package/dist/{index-iZLld8Ca.d.ts → index-s_IhSnwc.d.ts} +2 -2
  74. package/dist/index-s_IhSnwc.d.ts.map +1 -0
  75. package/dist/index.d.ts +432 -121
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +2369 -1706
  78. package/dist/index.js.map +1 -1
  79. package/dist/interaction-D6efrBLo.js +1 -0
  80. package/dist/{keyboard-De_vOHLg.js → keyboard-CimiEskD.js} +1 -1
  81. package/dist/{keyboard-De_vOHLg.js.map → keyboard-CimiEskD.js.map} +1 -1
  82. package/dist/{labelled-input-base-CqPL5rKm.js → labelled-input-base-9K_w3oLj.js} +2 -2
  83. package/dist/{labelled-input-base-CqPL5rKm.js.map → labelled-input-base-9K_w3oLj.js.map} +1 -1
  84. package/dist/{labelled-input-base-BVvNeb5R.d.ts → labelled-input-base-ORb1rGq6.d.ts} +2 -2
  85. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +1 -0
  86. package/dist/labelled-radial-input.d.ts +3 -3
  87. package/dist/labelled-radial-input.d.ts.map +1 -1
  88. package/dist/labelled-radial-input.js +7 -6
  89. package/dist/labelled-radial-input.js.map +1 -1
  90. package/dist/labelled-range-input.d.ts +1 -1
  91. package/dist/labelled-range-input.js +2 -2
  92. package/dist/led.d.ts +1 -1
  93. package/dist/led.d.ts.map +1 -1
  94. package/dist/led.js +2 -2
  95. package/dist/led.js.map +1 -1
  96. package/dist/{menu-item-CKRfP0pN.js → menu-item-BrIuORYD.js} +20 -10
  97. package/dist/menu-item-BrIuORYD.js.map +1 -0
  98. package/dist/{menu-item-ClQF2DKN.d.ts → menu-item-COx-Azgj.d.ts} +1 -1
  99. package/dist/menu-item-COx-Azgj.d.ts.map +1 -0
  100. package/dist/{menu-DJJuCm-5.js → menu-vjoiHZ13.js} +30 -17
  101. package/dist/menu-vjoiHZ13.js.map +1 -0
  102. package/dist/menu.d.ts +2 -2
  103. package/dist/menu.js +2 -2
  104. package/dist/miller.d.ts +2 -2
  105. package/dist/miller.d.ts.map +1 -1
  106. package/dist/miller.js +18 -11
  107. package/dist/miller.js.map +1 -1
  108. package/dist/narrowed-text.d.ts.map +1 -1
  109. package/dist/narrowed-text.js +7 -5
  110. package/dist/narrowed-text.js.map +1 -1
  111. package/dist/panel.d.ts +1 -1
  112. package/dist/panel.d.ts.map +1 -1
  113. package/dist/panel.js +5 -4
  114. package/dist/panel.js.map +1 -1
  115. package/dist/plots.d.ts +2 -2
  116. package/dist/plots.js +2 -2
  117. package/dist/polar-pad.d.ts +1 -1
  118. package/dist/polar-pad.d.ts.map +1 -1
  119. package/dist/polar-pad.js +10 -4
  120. package/dist/polar-pad.js.map +1 -1
  121. package/dist/{popup-ImtS9KnS.js → popup-DiWMxsWj.js} +1 -1
  122. package/dist/{popup-ImtS9KnS.js.map → popup-DiWMxsWj.js.map} +1 -1
  123. package/dist/prominence-DlFShic3.js +104 -0
  124. package/dist/prominence-DlFShic3.js.map +1 -0
  125. package/dist/{radial-input-LUSBEycd.d.ts → radial-input-CpQPs1Mp.d.ts} +1 -1
  126. package/dist/radial-input-CpQPs1Mp.d.ts.map +1 -0
  127. package/dist/{radial-input-DZA6WaFu.js → radial-input-DZ7eQCcM.js} +11 -6
  128. package/dist/radial-input-DZ7eQCcM.js.map +1 -0
  129. package/dist/radial-input.d.ts +1 -1
  130. package/dist/radial-input.js +1 -1
  131. package/dist/range-input.d.ts +1 -1
  132. package/dist/range-input.d.ts.map +1 -1
  133. package/dist/range-input.js +9 -4
  134. package/dist/range-input.js.map +1 -1
  135. package/dist/range.d.ts +1 -1
  136. package/dist/range.d.ts.map +1 -1
  137. package/dist/range.js +5 -3
  138. package/dist/range.js.map +1 -1
  139. package/dist/{registry-Q2gYQCHM.js → registry-CkW7q09Q.js} +1 -1
  140. package/dist/{registry-Q2gYQCHM.js.map → registry-CkW7q09Q.js.map} +1 -1
  141. package/dist/selecthorizontal.d.ts +1 -1
  142. package/dist/selecthorizontal.d.ts.map +1 -1
  143. package/dist/selecthorizontal.js +4 -3
  144. package/dist/selecthorizontal.js.map +1 -1
  145. package/dist/snap-container.d.ts.map +1 -1
  146. package/dist/snap-container.js +1 -1
  147. package/dist/split-layout.d.ts +1 -1
  148. package/dist/split-layout.d.ts.map +1 -1
  149. package/dist/split-layout.js +6 -5
  150. package/dist/split-layout.js.map +1 -1
  151. package/dist/style.css +14 -4
  152. package/dist/swipe.d.ts.map +1 -1
  153. package/dist/swipe.js +9 -4
  154. package/dist/swipe.js.map +1 -1
  155. package/dist/{tab-list-BnqISNvO.d.ts → tab-list-DLzb-m-I.d.ts} +2 -2
  156. package/dist/tab-list-DLzb-m-I.d.ts.map +1 -0
  157. package/dist/tabs.d.ts +1 -1
  158. package/dist/tabs.js +10 -4
  159. package/dist/tabs.js.map +1 -1
  160. package/dist/{tickled-controller-Cq1Va0rR.d.ts → tickled-controller-BjYCzGrU.d.ts} +2 -2
  161. package/dist/tickled-controller-BjYCzGrU.d.ts.map +1 -0
  162. package/dist/{tickled-styles-Bg3QbcrD.js → tickled-styles-fNDdqf6l.js} +1 -17
  163. package/dist/{tickled-styles-Bg3QbcrD.js.map → tickled-styles-fNDdqf6l.js.map} +1 -1
  164. package/dist/{timeline-Bh0PhlKW.js → timeline-2OFtN4Ta.js} +2 -2
  165. package/dist/{timeline-Bh0PhlKW.js.map → timeline-2OFtN4Ta.js.map} +1 -1
  166. package/dist/timeline.d.ts +1 -1
  167. package/dist/timeline.js +1 -1
  168. package/dist/{tooltip-DMxmBNky.js → tooltip-CJt3WLmN.js} +1 -1
  169. package/dist/{tooltip-DMxmBNky.js.map → tooltip-CJt3WLmN.js.map} +1 -1
  170. package/dist/{tooltip-CwGfb4lp.d.ts → tooltip-RGVIwHrZ.d.ts} +1 -1
  171. package/dist/{tooltip-CwGfb4lp.d.ts.map → tooltip-RGVIwHrZ.d.ts.map} +1 -1
  172. package/dist/{tree-CvvKbO-f.js → tree-CJWpMUvD.js} +113 -103
  173. package/dist/tree-CJWpMUvD.js.map +1 -0
  174. package/dist/{tree-component-D8Bg48tt.d.ts → tree-component-BcO26Xvt.d.ts} +65 -3
  175. package/dist/tree-component-BcO26Xvt.d.ts.map +1 -0
  176. package/dist/tree.d.ts +15 -15
  177. package/dist/tree.d.ts.map +1 -1
  178. package/dist/tree.js +1 -1
  179. package/dist/{types-BKaqnpwx.d.ts → types-DSfbtHs3.d.ts} +1 -1
  180. package/dist/types-DSfbtHs3.d.ts.map +1 -0
  181. package/dist/{xy-axis-DL0tfJDr.js → xy-axis-CK64haaK.js} +1831 -359
  182. package/dist/xy-axis-CK64haaK.js.map +1 -0
  183. package/dist/{xy-axis-D9uwpGTT.d.ts → xy-axis-McdUpcYr.d.ts} +102 -3
  184. package/dist/xy-axis-McdUpcYr.d.ts.map +1 -0
  185. package/dist/xy-pad.d.ts +1 -1
  186. package/dist/xy-pad.d.ts.map +1 -1
  187. package/dist/xy-pad.js +11 -6
  188. package/dist/xy-pad.js.map +1 -1
  189. package/docs-user/README.md +45 -0
  190. package/docs-user/ac-text.md +67 -0
  191. package/docs-user/ac-token.md +187 -0
  192. package/docs-user/button.md +355 -0
  193. package/docs-user/checkbox.md +62 -0
  194. package/docs-user/colour-picker.md +237 -0
  195. package/docs-user/crumbs.md +66 -0
  196. package/docs-user/data-display.md +98 -0
  197. package/docs-user/editable-label.md +244 -0
  198. package/docs-user/grouped-item-lister.md +424 -0
  199. package/docs-user/icons.md +191 -0
  200. package/docs-user/incr-search.md +94 -0
  201. package/docs-user/labelled-radial-input.md +204 -0
  202. package/docs-user/labelled-range-input.md +194 -0
  203. package/docs-user/led.md +40 -0
  204. package/docs-user/menu.md +319 -0
  205. package/docs-user/miller.md +453 -0
  206. package/docs-user/narrowed-text.md +72 -0
  207. package/docs-user/panel.md +250 -0
  208. package/docs-user/plots.md +361 -0
  209. package/docs-user/polar-pad.md +228 -0
  210. package/docs-user/radial-input.md +559 -0
  211. package/docs-user/range-input.md +264 -0
  212. package/docs-user/range.md +12 -0
  213. package/docs-user/selecthorizontal.md +32 -0
  214. package/docs-user/snap-container.md +132 -0
  215. package/docs-user/split-layout.md +232 -0
  216. package/docs-user/swipe.md +44 -0
  217. package/docs-user/tabs.md +217 -0
  218. package/docs-user/timeline.md +116 -0
  219. package/docs-user/transitory-label.md +120 -0
  220. package/docs-user/tree.md +592 -0
  221. package/docs-user/user-catalog.md +165 -0
  222. package/docs-user/user-theming.md +379 -0
  223. package/docs-user/util.md +122 -0
  224. package/docs-user/vertical-list.md +351 -0
  225. package/docs-user/xy-pad.md +94 -0
  226. package/package.json +18 -17
  227. package/dist/colour-C3MQIjFJ-BLXg8W3U.js.map +0 -1
  228. package/dist/colour-picker-K6zu82lm.js.map +0 -1
  229. package/dist/dist-BX0OVIm7.js +0 -1290
  230. package/dist/dist-BX0OVIm7.js.map +0 -1
  231. package/dist/dist-TAGYwaju.js.map +0 -1
  232. package/dist/hex-editor-DlfoA65y.d.ts.map +0 -1
  233. package/dist/icon-9NWTXtE1.js.map +0 -1
  234. package/dist/icon-Dm_DHDz6.d.ts.map +0 -1
  235. package/dist/index-CnL9krsH.d.ts.map +0 -1
  236. package/dist/index-DLkSKL4T.d.ts.map +0 -1
  237. package/dist/index-DSlPeWLK.d.ts.map +0 -1
  238. package/dist/index-iZLld8Ca.d.ts.map +0 -1
  239. package/dist/interaction-DG7X1rhI.js +0 -1
  240. package/dist/labelled-input-base-BVvNeb5R.d.ts.map +0 -1
  241. package/dist/menu-DJJuCm-5.js.map +0 -1
  242. package/dist/menu-item-CKRfP0pN.js.map +0 -1
  243. package/dist/menu-item-ClQF2DKN.d.ts.map +0 -1
  244. package/dist/prominence--ic9uWBl.js +0 -98
  245. package/dist/prominence--ic9uWBl.js.map +0 -1
  246. package/dist/radial-input-DZA6WaFu.js.map +0 -1
  247. package/dist/radial-input-LUSBEycd.d.ts.map +0 -1
  248. package/dist/tab-list-BnqISNvO.d.ts.map +0 -1
  249. package/dist/tickled-controller-Cq1Va0rR.d.ts.map +0 -1
  250. package/dist/tree-CvvKbO-f.js.map +0 -1
  251. package/dist/tree-component-D8Bg48tt.d.ts.map +0 -1
  252. package/dist/types-BKaqnpwx.d.ts.map +0 -1
  253. package/dist/xy-axis-D9uwpGTT.d.ts.map +0 -1
  254. package/dist/xy-axis-DL0tfJDr.js.map +0 -1
  255. /package/bundle/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
  256. /package/dist/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
@@ -0,0 +1,264 @@
1
+ # `<ixfx-range-input>`
2
+
3
+ A label-free, fully styled range slider wrapping `<input type="range">`. Supports horizontal and vertical orientations, CSS variable theming, gradient fills, custom thumb shapes, and an optional value tooltip.
4
+
5
+ ---
6
+
7
+ ## Basic usage
8
+
9
+ ```html
10
+ <ixfx-range-input value="0.5"></ixfx-range-input>
11
+ ```
12
+
13
+ ```js
14
+ const slider = document.querySelector('ixfx-range-input');
15
+ slider.addEventListener('input', e => console.log(e.detail.value));
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Attributes / properties
21
+
22
+ | Attribute / Property | Type | Default | Description |
23
+ |-----------------------|-----------------------------|----------------|--------------------------------------------------|
24
+ | `value` | `number` | `0` | Current value within `min`..`max` |
25
+ | `min` | `number` | `0` | Minimum value |
26
+ | `max` | `number` | `1` | Maximum value |
27
+ | `step` | `number` | `0.01` | Step increment |
28
+ | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Slider axis |
29
+ | `tooltip` | `boolean` | `false` | Show value tooltip on hover/focus |
30
+ | `tooltip-orientation` | `"top" \| "right"` | `"top"` | Tooltip position relative to thumb |
31
+ | `labelFormatter` | `(raw, scaled) => string` | — | JS property (not an attribute) — custom tooltip formatter. `raw` is the value within `min`..`max`; `scaled` is the normalised 0..1 position. |
32
+
33
+ ---
34
+
35
+ ## Events
36
+
37
+ Both events are `CustomEvent` instances with `{ bubbles: true, composed: true }`.
38
+
39
+ | Event | `detail` type | Description |
40
+ |----------|------------------------|----------------------------------------------------|
41
+ | `input` | `{ value: number }` | Fires continuously while dragging |
42
+ | `change` | `{ value: number }` | Fires once on release (same semantics as native) |
43
+
44
+ `value` in both events is the raw value within `min`..`max` (not normalised).
45
+
46
+ ---
47
+
48
+ ## Sizing
49
+
50
+ The component fills whatever dimensions you give it via `--width` / `--height`, or explicit CSS sizing.
51
+
52
+ | CSS variable | Default (horizontal) | Default (vertical) | Description |
53
+ |---|---|---|---|
54
+ | `--width` | `200px` | `2em` | Component width |
55
+ | `--height` | `2em` | `200px` | Component height |
56
+
57
+ ```html
58
+ <!-- Full-width, default height -->
59
+ <ixfx-range-input style="--width:100%"></ixfx-range-input>
60
+
61
+ <!-- Tall horizontal slider -->
62
+ <ixfx-range-input style="--width:100%; --height:4em"></ixfx-range-input>
63
+
64
+ <!-- Vertical, filling a flex container -->
65
+ <div style="height:160px; display:flex; align-items:stretch">
66
+ <ixfx-range-input orientation="vertical" style="--width:2em; --height:100%"></ixfx-range-input>
67
+ </div>
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Track CSS variables
73
+
74
+ | Variable | Default | Description |
75
+ |---------------------------------------------|-------------------------------|------------------------------------------|
76
+ | `--track-thickness` | `100%` | Track cross-axis size (% of component height in horizontal mode) |
77
+ | `--background-track` | `var(--surface-ll)` | Unfilled track background |
78
+ | `--background-track-hover` | `--background-track` | Unfilled track on hover |
79
+ | `--background-track-value` | `var(--surface-hh)` | Filled track color (supports gradients) |
80
+ | `--background-track-value-hover` | `var(--accent)` | Filled track on hover |
81
+ | `--background-track-value-active` | `var(--accent)` | Filled track while dragging |
82
+
83
+ ### Vertical-only overrides
84
+
85
+ When `orientation="vertical"` these take precedence over the horizontal vars (falling back to them when unset):
86
+
87
+ | Variable | Falls back to |
88
+ |--------------------------------------------------|--------------------------------------|
89
+ | `--background-track-vertical` | `--background-track` |
90
+ | `--background-track-value-vertical` | `--background-track-value` |
91
+ | `--background-track-value-hover-vertical` | `--background-track-value-hover` |
92
+ | `--background-track-value-active-vertical` | `--background-track-value-active` |
93
+
94
+ ---
95
+
96
+ ## Thumb CSS variables
97
+
98
+ | Variable | Default | Description |
99
+ |-----------------------|---------------------------|-------------------------------------------------|
100
+ | `--thumb-thickness` | `2em` | Thumb size along the track axis |
101
+ | `--thumb-size` | `--track-thickness` | Thumb size across the track axis |
102
+ | `--thumb-color` | `var(--surface-text)` | Thumb fill at rest |
103
+ | `--thumb-color-active`| `var(--accent)` | Thumb fill on hover / active |
104
+ | `--thumb-radius` | `0` | `border-radius` of the thumb |
105
+ | `--thumb-border` | `none` | `border` shorthand for the thumb |
106
+ | `--thumb-shadow` | `none` | `box-shadow` for the thumb |
107
+
108
+ ### Using container query units for thumb sizing
109
+
110
+ Because the component uses `container-type: size` internally, you can use `cqh` (1% of component height) and `cqw` (1% of component width) for reliable, dimension-agnostic sizing:
111
+
112
+ ```css
113
+ /* Thumb is always a square equal to the component height */
114
+ ixfx-range-input {
115
+ --thumb-thickness: 100cqh;
116
+ --thumb-size: 100cqh;
117
+ }
118
+
119
+ /* Thumb is 80% of component height */
120
+ ixfx-range-input {
121
+ --thumb-thickness: 80cqh;
122
+ --thumb-size: 80cqh;
123
+ }
124
+ ```
125
+
126
+ For vertical sliders, use `cqw` (component width) to size the thumb relative to the narrow dimension:
127
+
128
+ ```css
129
+ ixfx-range-input[orientation="vertical"] {
130
+ --thumb-thickness: 100cqw;
131
+ --thumb-size: 100cqw;
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Tooltip
138
+
139
+ Add the `tooltip` attribute to show the current value above the thumb on hover/focus.
140
+
141
+ ```html
142
+ <!-- Default: shows value rounded to 2 decimal places -->
143
+ <ixfx-range-input tooltip value="0.5"></ixfx-range-input>
144
+
145
+ <!-- Integer range: step=1 → no decimal places shown -->
146
+ <ixfx-range-input tooltip min="0" max="100" step="1" value="42"></ixfx-range-input>
147
+
148
+ <!-- Vertical slider: show tooltip to the right of the thumb -->
149
+ <ixfx-range-input orientation="vertical" tooltip tooltip-orientation="right" value="0.6"></ixfx-range-input>
150
+ ```
151
+
152
+ ### Custom tooltip formatter
153
+
154
+ Assign a function to the `labelFormatter` JS property:
155
+
156
+ ```js
157
+ const slider = document.querySelector('ixfx-range-input');
158
+ slider.labelFormatter = (rawValue, scaledValue) =>
159
+ `${Math.round(scaledValue * 100)}%`;
160
+ ```
161
+
162
+ - `rawValue` — the value within `min`..`max`
163
+ - `scaledValue` — normalised 0..1 position
164
+
165
+ ---
166
+
167
+ ## Examples
168
+
169
+ ### Accent colour override
170
+
171
+ ```css
172
+ .my-slider {
173
+ --background-track-value: hsl(280 60% 35%);
174
+ --background-track-value-hover: hsl(280 80% 55%);
175
+ --background-track-value-active: hsl(280 80% 55%);
176
+ --thumb-color-active: hsl(280 80% 65%);
177
+ }
178
+ ```
179
+
180
+ ```html
181
+ <ixfx-range-input class="my-slider" value="0.5" style="--width:100%"></ixfx-range-input>
182
+ ```
183
+
184
+ ### Gradient fill
185
+
186
+ The filled-track area uses a CSS mask, so any gradient set on `--background-track-value` shows through only up to the current value position.
187
+
188
+ ```css
189
+ .gradient-fire {
190
+ --background-track-value: linear-gradient(to right, hsl(50 100% 45%), hsl(15 90% 50%));
191
+ --background-track-value-hover: linear-gradient(to right, hsl(55 100% 55%), hsl(15 100% 60%));
192
+ --background-track-value-active: linear-gradient(to right, hsl(55 100% 55%), hsl(15 100% 60%));
193
+ }
194
+ ```
195
+
196
+ ### Pill thumb
197
+
198
+ ```css
199
+ .pill {
200
+ --thumb-radius: 999px;
201
+ --thumb-thickness: 20px;
202
+ --thumb-size: 200cqh;
203
+ }
204
+ ```
205
+
206
+ ### Circle dot thumb
207
+
208
+ ```css
209
+ .dot {
210
+ --thumb-thickness: 100cqh;
211
+ --thumb-size: 100cqh;
212
+ --thumb-radius: 50%;
213
+ }
214
+ ```
215
+
216
+ ### Ghost (outlined) thumb
217
+
218
+ ```css
219
+ .ghost {
220
+ --thumb-color: transparent;
221
+ --thumb-color-active: transparent;
222
+ --thumb-border: 2px solid var(--accent);
223
+ --thumb-radius: 3px;
224
+ --thumb-shadow: 0 0 6px var(--accent);
225
+ }
226
+ ```
227
+
228
+ ### Orientation-specific colours
229
+
230
+ Both orientations can share one CSS class, with the vertical variant overriding only what it needs:
231
+
232
+ ```css
233
+ .dual-color {
234
+ --background-track-value: hsl(210 70% 40%); /* horizontal → blue */
235
+ --background-track-value-vertical: hsl(30 70% 45%); /* vertical → orange */
236
+ }
237
+ ```
238
+
239
+ ```html
240
+ <ixfx-range-input class="dual-color" value="0.6" style="--width:100%"></ixfx-range-input>
241
+ <ixfx-range-input class="dual-color" orientation="vertical" value="0.6"></ixfx-range-input>
242
+ ```
243
+
244
+ ### Listening to events
245
+
246
+ ```js
247
+ const slider = document.querySelector('ixfx-range-input');
248
+
249
+ // Fires on every move
250
+ slider.addEventListener('input', ({ detail }) => {
251
+ console.log('moving:', detail.value);
252
+ });
253
+
254
+ // Fires once on release
255
+ slider.addEventListener('change', ({ detail }) => {
256
+ console.log('settled:', detail.value);
257
+ });
258
+ ```
259
+
260
+ ### Setting value programmatically
261
+
262
+ ```js
263
+ slider.value = 0.75;
264
+ ```
@@ -0,0 +1,12 @@
1
+ # Range elements
2
+
3
+ ## Styling
4
+
5
+ Range: Coloured bar that suggests values
6
+ --range-background: (AccentColor)
7
+ --range-thickness: (1em)
8
+ --thumb-background: (ButtonFace)
9
+ Tooltip
10
+
11
+ --tooltip-background: (ButtonFace)
12
+ --tooltip-color: (ButtonText)
@@ -0,0 +1,32 @@
1
+ # `ixfx-selecthorizontal-element`
2
+
3
+ A horizontally scrolling container with snap points for child elements. Useful for scrollable lists of items that should snap into alignment.
4
+
5
+ ```html
6
+ <ixfx-selecthorizontal-element>
7
+ <div>Item 1</div>
8
+ <div>Item 2</div>
9
+ <div>Item 3</div>
10
+ </ixfx-selecthorizontal-element>
11
+ ```
12
+
13
+ ### Properties / attributes
14
+
15
+ | Attribute / Property | Type | Default | Description |
16
+ |----------------------|----------|---------|----------------------------|
17
+ | `editMode` | `boolean`| `false` | (Reserved for future use) |
18
+
19
+ ### CSS custom properties
20
+
21
+ Inherits border styling from global `--border` and `--accent` variables applied to slotted children.
22
+
23
+ ### CSS parts
24
+
25
+ The component styles slotted elements with scroll snapping behavior.
26
+
27
+ ### Usage notes
28
+
29
+ - Children should have `data-value` attribute for identification
30
+ - Component handles `slotchange` events to update available items
31
+ - Uses `scroll-snap-type: x mandatory` for snap alignment
32
+ - Hidden scrollbar via `scrollbar-width: none`
@@ -0,0 +1,132 @@
1
+ # `ixfx-snap-container`
2
+
3
+ A container that positions its child element at configurable snap positions along an axis. The child can be dragged, clicked to snap, or controlled via keyboard.
4
+
5
+ ```html
6
+ <ixfx-snap-container snap-positions="3" orientation="horizontal">
7
+ <button>Drag me</button>
8
+ </ixfx-snap-container>
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Properties / attributes
14
+
15
+ | Attribute / Property | Type | Default | Description |
16
+ |------------------------|-------------------------------|-------------|--------------------------------------------------------------------|
17
+ | `orientation` | `'horizontal'` \| `'vertical'` | `'horizontal'` | Axis along which snapping occurs. Horizontal uses x-axis; vertical uses y-axis |
18
+ | `snap-positions` | number | `3` | Number of snap positions |
19
+ | `snap-logic` | `'centre'` \| `'balanced'` | `'balanced'` | How snap positions are distributed (see [Snap logic](#snap-logic)) |
20
+ | `click-snap` | `'closest'` \| `'step'` | `'closest'` | How clicking in empty space snaps (see [Click snap modes](#click-snap-modes)) |
21
+ | `snap` | number | `0` | Current snap index (0-based) |
22
+
23
+ ---
24
+
25
+ ## Snap logic
26
+
27
+ ### `balanced` (default)
28
+
29
+ First snap position aligns with container's left/top edge. Last snap position aligns with container's right/bottom edge. Middle positions are evenly distributed.
30
+
31
+ ```
32
+ Position 0 ─┬── Position 1 ─┬── Position 2 ─┬── Position 3 ─┬── Position 4
33
+ │ │ │ │
34
+ ────────────┼────────────────┼────────────────┼────────────────┼────────────
35
+ Left edge │ evenly │ evenly │ evenly │ Right edge
36
+ │ spaced │ spaced │ spaced │
37
+ ```
38
+
39
+ ### `centre`
40
+
41
+ All snap positions are evenly distributed, ignoring edge alignment.
42
+
43
+ ```
44
+ Position 0 ─┬── Position 1 ─┬── Position 2 ─┬── Position 3 ─┬── Position 4
45
+ │ │ │ │
46
+ ────────────┼────────────────┼────────────────┼────────────────┼────────────
47
+ │ │ centred │ │
48
+ │ │ │ │
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Click snap modes
54
+
55
+ ### `closest` (default)
56
+
57
+ Clicking anywhere in the container (not on the child) moves the child to the nearest snap position to the click point.
58
+
59
+ ### `step`
60
+
61
+ Clicking to the **right** of the child's center moves it one position right. Clicking to the **left** moves it one position left. Similarly for vertical orientation (up/down).
62
+
63
+ This is useful for incremental navigation without dragging.
64
+
65
+ ---
66
+
67
+ ## Events
68
+
69
+ | Event | Detail | Description |
70
+ |---------------|-------------------------------------|------------------------------------------|
71
+ | `snap-change` | `{ previousSnap, newSnap }` | Fired when snap index changes |
72
+ | `snap-input` | `{ index }` | Fired continuously during drag operation |
73
+
74
+ Both events bubble and are composed.
75
+
76
+ ```js
77
+ container.addEventListener('snap-change', (e) => {
78
+ console.log(`Moved from ${e.detail.previousSnap} to ${e.detail.newSnap}`);
79
+ });
80
+ ```
81
+
82
+ ---
83
+
84
+ ## CSS custom properties
85
+
86
+ | Property | Default | Description |
87
+ |------------------------|------------|--------------------------------------------------|
88
+ | `--transition-duration`| `200ms` | Duration of snap transitions |
89
+
90
+ The child element also receives a `--snap-index` custom property reflecting its current position:
91
+
92
+ ```css
93
+ child {
94
+ background: hsl(calc(var(--snap-index) * 60), 70%, 50%);
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Keyboard navigation
101
+
102
+ When the container or its child has focus:
103
+
104
+ | Orientation | Key | Action |
105
+ |---------------|-----------|-------------------------------|
106
+ | horizontal | LEFT | Move to previous snap position|
107
+ | horizontal | RIGHT | Move to next snap position |
108
+ | vertical | UP | Move to previous snap position|
109
+ | vertical | DOWN | Move to next snap position |
110
+
111
+ ---
112
+
113
+ ## Programmatic control
114
+
115
+ All properties are writable at runtime:
116
+
117
+ ```js
118
+ const container = document.querySelector('ixfx-snap-container');
119
+
120
+ container.snap = 2; // Jump to position 2
121
+ container.snapPositions = 5; // Change to 5 positions
122
+ container.orientation = 'vertical'; // Switch to vertical
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Usage notes
128
+
129
+ - The child element should have a fixed or intrinsic size
130
+ - The container has `overflow: hidden` and positions the child absolutely
131
+ - Drag requires moving at least 10px before snapping engages
132
+ - In `step` mode, clicking when already at the boundary (0 or max) does nothing
@@ -0,0 +1,232 @@
1
+ # Split Layout
2
+
3
+ A Lit web component that lays out two elements within a container with a resize handle to adjust their proportions.
4
+
5
+ ---
6
+
7
+ ## `ixfx-split-layout`
8
+
9
+ ### Attributes
10
+
11
+ | Attribute | Type | Default | Description |
12
+ |-----------|------|---------|-------------|
13
+ | `layout` | `vertical` \| `horizontal` | `vertical` | Split orientation. `vertical` creates left/right panels, `horizontal` creates top/bottom panels. |
14
+ | `sizeA` | `String` | `""` | CSS size for panel A (slot `a`). Can use relative (`50%`) or absolute (`100px`) values. Empty string defaults to `auto`. |
15
+ | `sizeB` | `String` | `""` | CSS size for panel B (slot `b`). Same format as `sizeA`. |
16
+ | `fixedA` | `Boolean` | `false` | If `true`, `sizeA` is calculated in pixels rather than percentage of whole. |
17
+ | `fixedB` | `Boolean` | `false` | If `true`, `sizeB` is calculated in pixels rather than percentage of whole. |
18
+ | `collapsible` | `Boolean` | `false` | If `true`, panels can be collapsed by dragging the handle to the edge. The other panel expands to fill the space. |
19
+ | `minSizeA` | `String` | `""` | Minimum size for panel A (e.g., `"100px"` or `"20%"`). Empty means no minimum. |
20
+ | `maxSizeA` | `String` | `""` | Maximum size for panel A. Empty means no maximum. |
21
+ | `minSizeB` | `String` | `""` | Minimum size for panel B. |
22
+ | `maxSizeB` | `String` | `""` | Maximum size for panel B. |
23
+
24
+ ### Properties
25
+
26
+ | Property | Type | Description |
27
+ |----------|------|-------------|
28
+ | `collapsedA` | `Boolean` (reflects attribute) | `true` if panel A is currently collapsed. |
29
+ | `collapsedB` | `Boolean` (reflects attribute) | `true` if panel B is currently collapsed. |
30
+
31
+ ### CSS Variables
32
+
33
+ | Variable | Default | Description |
34
+ |----------|---------|-------------|
35
+ | `--handle-size` | `2px` | Width/height of the resize handle |
36
+ | `--handle-colour` | `var(--surface-5)` | Colour of the resize handle |
37
+ | `--handle-hover-colour` | `var(--surface-6)` | Colour of handle when hovering |
38
+ | `--handle-active-colour` | `var(--accent)` | Colour of handle when being dragged |
39
+
40
+ ### Events
41
+
42
+ | Event | Detail | Description |
43
+ |-------|--------|-------------|
44
+ | `ixfx-split-collapsed` | `{ panel: 'A' \| 'B', collapsed: boolean }` | Fired when a panel is collapsed or uncollapsed via drag. |
45
+
46
+ ---
47
+
48
+ ## Basic Usage
49
+
50
+ ### Vertical Split (Left/Right)
51
+
52
+ ```html
53
+ <ixfx-split-layout layout="vertical" style="width: 100%; height: 400px;">
54
+ <div slot="a" style="background: var(--surface-3);">Left Panel</div>
55
+ <div slot="b" style="background: var(--surface-5);">Right Panel</div>
56
+ </ixfx-split-layout>
57
+ ```
58
+
59
+ ### Horizontal Split (Top/Bottom)
60
+
61
+ ```html
62
+ <ixfx-split-layout layout="horizontal" style="width: 100%; height: 400px;">
63
+ <div slot="a" style="background: var(--surface-3);">Top Panel</div>
64
+ <div slot="b" style="background: var(--surface-5);">Bottom Panel</div>
65
+ </ixfx-split-layout>
66
+ ```
67
+
68
+ ### With Fixed Panel
69
+
70
+ ```html
71
+ <!-- Left panel fixed at 200px, right panel takes remaining space -->
72
+ <ixfx-split-layout fixedA layout="vertical" style="width: 100%; height: 400px;">
73
+ <div slot="a" style="background: var(--surface-3);">Left Panel (200px)</div>
74
+ <div slot="b" style="background: var(--surface-5);">Right Panel (flexible)</div>
75
+ </ixfx-split-layout>
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Collapsible Panels
81
+
82
+ When `collapsible` is set, dragging a resize handle to the edge collapses that panel. The other panel expands to fill the space. Dragging away from the edge uncollapses the panel.
83
+
84
+ ```html
85
+ <ixfx-split-layout collapsible layout="horizontal" style="width: 100%; height: 400px;">
86
+ <div slot="a" style="background: var(--surface-3);">Top Panel</div>
87
+ <div slot="b" style="background: var(--surface-5);">Bottom Panel</div>
88
+ </ixfx-split-layout>
89
+ ```
90
+
91
+ ### Collapse Events
92
+
93
+ ```javascript
94
+ const split = document.querySelector('ixfx-split-layout[collapsible]');
95
+
96
+ split.addEventListener('ixfx-split-collapsed', ({ detail }) => {
97
+ console.log(`Panel ${detail.panel} is now ${detail.collapsed ? 'collapsed' : 'uncollapsed'}`);
98
+ });
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Min/Max Size Constraints
104
+
105
+ Use `minSizeA`, `maxSizeA`, `minSizeB`, and `maxSizeB` to constrain panel sizes:
106
+
107
+ ```html
108
+ <ixfx-split-layout
109
+ minSizeA="100px"
110
+ maxSizeA="70%"
111
+ minSizeB="50px"
112
+ layout="horizontal"
113
+ style="width: 100%; height: 400px;">
114
+ <div slot="a" style="background: var(--surface-3);">Top Panel</div>
115
+ <div slot="b" style="background: var(--surface-5);">Bottom Panel</div>
116
+ </ixfx-split-layout>
117
+ ```
118
+
119
+ **Constraint rules:**
120
+ - **Min constraints take precedence**: If both panels' minimums exceed 100% combined, they're scaled proportionally
121
+ - **Max constraints are secondary**: If a max constraint conflicts with a min constraint, the max is ignored to satisfy the min
122
+ - **The constrained panel gets clamped**: The other panel receives the remaining space
123
+
124
+ ---
125
+
126
+ ## Nested Splits with Two-Way Corner Resize
127
+
128
+ When a `ixfx-split-layout` is nested inside slot A of an outer split, a corner zone appears at the intersection of the two resize handles. This enables simultaneous resize of both splits.
129
+
130
+ ```
131
+ ┌─────────────────┬────────────┐
132
+ │ │ │
133
+ │ ┌─────────────┤ │
134
+ │ │ Editor │ │
135
+ │ │ │ │
136
+ │ ├─────────────┤ Sidebar │
137
+ │ │ Terminal │ │
138
+ │ │ │ │
139
+ │ └─────────────┘ │
140
+ └─────────────────┴────────────┘
141
+
142
+ Corner Zone
143
+ (drag here for two-way resize)
144
+ ```
145
+
146
+ ### Structure
147
+
148
+ ```html
149
+ <ixfx-split-layout layout="vertical" style="width: 100%; height: 400px;">
150
+ <!-- Nested split is a direct child of slot A -->
151
+ <ixfx-split-layout slot="a" layout="horizontal" style="width: 100%; height: 100%;">
152
+ <div slot="a" style="background: var(--surface);">Editor</div>
153
+ <div slot="b" style="background: var(--surface-3);">Terminal</div>
154
+ </ixfx-split-layout>
155
+ <div slot="b" style="background: var(--surface-5);">Sidebar</div>
156
+ </ixfx-split-layout>
157
+ ```
158
+
159
+ **Note**: For the corner zone to appear, the nested split must be a direct child of slot A (no wrapper elements between the split and slot A).
160
+
161
+ ### Corner Zone Behavior
162
+
163
+ - **Visual indicator**: A small magenta circle (12px) appears at the intersection point
164
+ - **Cursor change**: Shows `nwse-resize` cursor when hovering over the corner zone (for vertical-outer/horizontal-inner splits)
165
+ - **Two-way resize**: Dragging the corner zone adjusts both the outer vertical split and the inner horizontal split simultaneously
166
+ - **Position tracking**: The corner zone follows the resize handles as they move, staying at their intersection
167
+
168
+ ---
169
+
170
+ ## CSS Customisation
171
+
172
+ ### Handle Styling
173
+
174
+ ```css
175
+ ixfx-split-layout {
176
+ --handle-size: 4px;
177
+ --handle-colour: var(--surface-4);
178
+ --handle-hover-colour: var(--surface-6);
179
+ --handle-active-colour: var(--accent);
180
+ }
181
+ ```
182
+
183
+ ### Hide Collapsed Panels Completely
184
+
185
+ ```css
186
+ ixfx-split-layout[data-collapsed-a] slot[name="a"] {
187
+ display: none;
188
+ }
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Programmatic Control
194
+
195
+ ### Setting Sizes
196
+
197
+ ```javascript
198
+ const split = document.querySelector('ixfx-split-layout');
199
+
200
+ // Set to 30% / 70%
201
+ split.sizeA = '30%';
202
+ split.sizeB = '70%';
203
+
204
+ // Set to fixed pixel widths
205
+ split.fixedA = true;
206
+ split.sizeA = '200px'; // Panel A is 200px
207
+ // Panel B automatically gets remaining space
208
+
209
+ // Collapse a panel programmatically
210
+ split.collapsedA = true;
211
+ split.collapsedB = false;
212
+ ```
213
+
214
+ ### Reading State
215
+
216
+ ```javascript
217
+ console.log('Panel A size:', split.sizeA);
218
+ console.log('Panel B size:', split.sizeB);
219
+ console.log('Is A collapsed?', split.collapsedA);
220
+ console.log('Is B collapsed?', split.collapsedB);
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Implementation Notes
226
+
227
+ - Uses Shadow DOM for style encapsulation
228
+ - Slots use `display: block` and `overflow: hidden` by default
229
+ - When no size is specified for a panel, it defaults to `auto` (fill remaining space)
230
+ - When both sizes are empty, both default to `50%`
231
+ - The resize handle is `flex-shrink: 0` to prevent it from collapsing
232
+ - Nested splits detect their parent through slot assignment and automatically enable corner resize