@ixfx/components 0.3.2 → 0.4.1

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 (255) 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.map +1 -1
  12. package/dist/button.js +1 -1
  13. package/dist/checkbox.d.ts +2 -2
  14. package/dist/checkbox.d.ts.map +1 -1
  15. package/dist/checkbox.js +14 -8
  16. package/dist/checkbox.js.map +1 -1
  17. package/dist/{colour-C3MQIjFJ-BLXg8W3U.js → colour-C3MQIjFJ-vRCdr8W-.js} +146 -552
  18. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +1 -0
  19. package/dist/{colour-picker-K6zu82lm.js → colour-picker-0sgAha1T.js} +14 -9
  20. package/dist/colour-picker-0sgAha1T.js.map +1 -0
  21. package/dist/colour-picker.d.ts +1 -1
  22. package/dist/colour-picker.js +1 -1
  23. package/dist/crumbs.d.ts +1 -1
  24. package/dist/crumbs.d.ts.map +1 -1
  25. package/dist/crumbs.js +11 -6
  26. package/dist/crumbs.js.map +1 -1
  27. package/dist/data-display.d.ts +9 -4
  28. package/dist/data-display.d.ts.map +1 -1
  29. package/dist/data-display.js +270 -43
  30. package/dist/data-display.js.map +1 -1
  31. package/dist/data-provider-DgI909FP.js +23 -0
  32. package/dist/data-provider-DgI909FP.js.map +1 -0
  33. package/dist/{decorate-D7rC1gLP.js → decorate-DdjvVHS-.js} +2 -2
  34. package/dist/{decorate-D7rC1gLP.js.map → decorate-DdjvVHS-.js.map} +1 -1
  35. package/dist/{defaults-C7elhuyJ.js → defaults-C3b9OWJD.js} +2 -2
  36. package/dist/{defaults-C7elhuyJ.js.map → defaults-C3b9OWJD.js.map} +1 -1
  37. package/dist/{dist-TAGYwaju.js → dist-CA13FvMn.js} +7 -66
  38. package/dist/dist-CA13FvMn.js.map +1 -0
  39. package/dist/editable-label.d.ts.map +1 -1
  40. package/dist/editable-label.js +3 -2
  41. package/dist/editable-label.js.map +1 -1
  42. package/dist/fallbacks-pNMOMx38.js +168 -0
  43. package/dist/fallbacks-pNMOMx38.js.map +1 -0
  44. package/dist/{hex-editor-DlfoA65y.d.ts → hex-editor-CMIxtNgT.d.ts} +1 -1
  45. package/dist/hex-editor-CMIxtNgT.d.ts.map +1 -0
  46. package/dist/{hex-editor-CsN_ySkH.js → hex-editor-WZrjRtvL.js} +3 -3
  47. package/dist/{hex-editor-CsN_ySkH.js.map → hex-editor-WZrjRtvL.js.map} +1 -1
  48. package/dist/hex.d.ts +1 -1
  49. package/dist/hex.js +1 -1
  50. package/dist/{highlight-TPbSHruI.js → highlight-B-eQrhhb.js} +1 -1
  51. package/dist/{highlight-TPbSHruI.js.map → highlight-B-eQrhhb.js.map} +1 -1
  52. package/dist/{icon-9NWTXtE1.js → icon-Ndo40kNO.js} +6 -5
  53. package/dist/icon-Ndo40kNO.js.map +1 -0
  54. package/dist/{icon-Dm_DHDz6.d.ts → icon-epZd-JIO.d.ts} +2 -2
  55. package/dist/icon-epZd-JIO.d.ts.map +1 -0
  56. package/dist/icons.d.ts +2 -2
  57. package/dist/icons.js +3 -3
  58. package/dist/{incr-search-DSKKsk6w.js → incr-search-CeERfijK.js} +2 -2
  59. package/dist/{incr-search-DSKKsk6w.js.map → incr-search-CeERfijK.js.map} +1 -1
  60. package/dist/incr-search.d.ts +1 -1
  61. package/dist/incr-search.js +2 -2
  62. package/dist/{index-hXFn14tM.d.ts → index-BMjri2-S.d.ts} +2 -2
  63. package/dist/{index-hXFn14tM.d.ts.map → index-BMjri2-S.d.ts.map} +1 -1
  64. package/dist/{index-DSlPeWLK.d.ts → index-CWpNcQKE.d.ts} +5 -5
  65. package/dist/index-CWpNcQKE.d.ts.map +1 -0
  66. package/dist/{index-DLkSKL4T.d.ts → index-CowKi2mo.d.ts} +1 -1
  67. package/dist/index-CowKi2mo.d.ts.map +1 -0
  68. package/dist/{index-B1hNR7Z9.d.ts → index-D87kRcEs.d.ts} +1 -1
  69. package/dist/{index-B1hNR7Z9.d.ts.map → index-D87kRcEs.d.ts.map} +1 -1
  70. package/dist/{index-CnL9krsH.d.ts → index-DgXpCg_G.d.ts} +32 -26
  71. package/dist/index-DgXpCg_G.d.ts.map +1 -0
  72. package/dist/{index-iZLld8Ca.d.ts → index-JuEVfmr-.d.ts} +2 -2
  73. package/dist/index-JuEVfmr-.d.ts.map +1 -0
  74. package/dist/index.d.ts +432 -121
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2369 -1706
  77. package/dist/index.js.map +1 -1
  78. package/dist/interaction-D6efrBLo.js +1 -0
  79. package/dist/{keyboard-De_vOHLg.js → keyboard-CimiEskD.js} +1 -1
  80. package/dist/{keyboard-De_vOHLg.js.map → keyboard-CimiEskD.js.map} +1 -1
  81. package/dist/{labelled-input-base-CqPL5rKm.js → labelled-input-base-9K_w3oLj.js} +2 -2
  82. package/dist/{labelled-input-base-CqPL5rKm.js.map → labelled-input-base-9K_w3oLj.js.map} +1 -1
  83. package/dist/{labelled-input-base-BVvNeb5R.d.ts → labelled-input-base-Cz6qE6Dk.d.ts} +1 -1
  84. package/dist/labelled-input-base-Cz6qE6Dk.d.ts.map +1 -0
  85. package/dist/labelled-radial-input.d.ts +2 -2
  86. package/dist/labelled-radial-input.d.ts.map +1 -1
  87. package/dist/labelled-radial-input.js +7 -6
  88. package/dist/labelled-radial-input.js.map +1 -1
  89. package/dist/labelled-range-input.d.ts +1 -1
  90. package/dist/labelled-range-input.js +2 -2
  91. package/dist/led.d.ts +1 -1
  92. package/dist/led.d.ts.map +1 -1
  93. package/dist/led.js +2 -2
  94. package/dist/led.js.map +1 -1
  95. package/dist/{menu-item-CKRfP0pN.js → menu-item-BrIuORYD.js} +20 -10
  96. package/dist/menu-item-BrIuORYD.js.map +1 -0
  97. package/dist/{menu-item-ClQF2DKN.d.ts → menu-item-COx-Azgj.d.ts} +1 -1
  98. package/dist/menu-item-COx-Azgj.d.ts.map +1 -0
  99. package/dist/{menu-DJJuCm-5.js → menu-vjoiHZ13.js} +30 -17
  100. package/dist/menu-vjoiHZ13.js.map +1 -0
  101. package/dist/menu.d.ts +2 -2
  102. package/dist/menu.js +2 -2
  103. package/dist/miller.d.ts +2 -2
  104. package/dist/miller.d.ts.map +1 -1
  105. package/dist/miller.js +18 -11
  106. package/dist/miller.js.map +1 -1
  107. package/dist/narrowed-text.d.ts.map +1 -1
  108. package/dist/narrowed-text.js +7 -5
  109. package/dist/narrowed-text.js.map +1 -1
  110. package/dist/panel.d.ts +1 -1
  111. package/dist/panel.d.ts.map +1 -1
  112. package/dist/panel.js +5 -4
  113. package/dist/panel.js.map +1 -1
  114. package/dist/plots.d.ts +2 -2
  115. package/dist/plots.js +2 -2
  116. package/dist/polar-pad.d.ts +1 -1
  117. package/dist/polar-pad.d.ts.map +1 -1
  118. package/dist/polar-pad.js +10 -4
  119. package/dist/polar-pad.js.map +1 -1
  120. package/dist/{popup-ImtS9KnS.js → popup-DiWMxsWj.js} +1 -1
  121. package/dist/{popup-ImtS9KnS.js.map → popup-DiWMxsWj.js.map} +1 -1
  122. package/dist/prominence-DlFShic3.js +104 -0
  123. package/dist/prominence-DlFShic3.js.map +1 -0
  124. package/dist/{radial-input-LUSBEycd.d.ts → radial-input-CpQPs1Mp.d.ts} +1 -1
  125. package/dist/radial-input-CpQPs1Mp.d.ts.map +1 -0
  126. package/dist/{radial-input-DZA6WaFu.js → radial-input-DZ7eQCcM.js} +11 -6
  127. package/dist/radial-input-DZ7eQCcM.js.map +1 -0
  128. package/dist/radial-input.d.ts +1 -1
  129. package/dist/radial-input.js +1 -1
  130. package/dist/range-input.d.ts +1 -1
  131. package/dist/range-input.d.ts.map +1 -1
  132. package/dist/range-input.js +9 -4
  133. package/dist/range-input.js.map +1 -1
  134. package/dist/range.d.ts +1 -1
  135. package/dist/range.d.ts.map +1 -1
  136. package/dist/range.js +5 -3
  137. package/dist/range.js.map +1 -1
  138. package/dist/{registry-Q2gYQCHM.js → registry-CkW7q09Q.js} +1 -1
  139. package/dist/{registry-Q2gYQCHM.js.map → registry-CkW7q09Q.js.map} +1 -1
  140. package/dist/selecthorizontal.d.ts +1 -1
  141. package/dist/selecthorizontal.d.ts.map +1 -1
  142. package/dist/selecthorizontal.js +4 -3
  143. package/dist/selecthorizontal.js.map +1 -1
  144. package/dist/snap-container.d.ts.map +1 -1
  145. package/dist/snap-container.js +1 -1
  146. package/dist/split-layout.d.ts +1 -1
  147. package/dist/split-layout.d.ts.map +1 -1
  148. package/dist/split-layout.js +6 -5
  149. package/dist/split-layout.js.map +1 -1
  150. package/dist/style.css +14 -4
  151. package/dist/swipe.d.ts.map +1 -1
  152. package/dist/swipe.js +9 -4
  153. package/dist/swipe.js.map +1 -1
  154. package/dist/{tab-list-BnqISNvO.d.ts → tab-list-DLzb-m-I.d.ts} +2 -2
  155. package/dist/tab-list-DLzb-m-I.d.ts.map +1 -0
  156. package/dist/tabs.d.ts +1 -1
  157. package/dist/tabs.js +10 -4
  158. package/dist/tabs.js.map +1 -1
  159. package/dist/{tickled-controller-Cq1Va0rR.d.ts → tickled-controller-BjYCzGrU.d.ts} +2 -2
  160. package/dist/tickled-controller-BjYCzGrU.d.ts.map +1 -0
  161. package/dist/{tickled-styles-Bg3QbcrD.js → tickled-styles-fNDdqf6l.js} +1 -17
  162. package/dist/{tickled-styles-Bg3QbcrD.js.map → tickled-styles-fNDdqf6l.js.map} +1 -1
  163. package/dist/{timeline-Bh0PhlKW.js → timeline-2OFtN4Ta.js} +2 -2
  164. package/dist/{timeline-Bh0PhlKW.js.map → timeline-2OFtN4Ta.js.map} +1 -1
  165. package/dist/timeline.d.ts +1 -1
  166. package/dist/timeline.js +1 -1
  167. package/dist/{tooltip-DMxmBNky.js → tooltip-CJt3WLmN.js} +1 -1
  168. package/dist/{tooltip-DMxmBNky.js.map → tooltip-CJt3WLmN.js.map} +1 -1
  169. package/dist/{tooltip-CwGfb4lp.d.ts → tooltip-RGVIwHrZ.d.ts} +1 -1
  170. package/dist/{tooltip-CwGfb4lp.d.ts.map → tooltip-RGVIwHrZ.d.ts.map} +1 -1
  171. package/dist/{tree-CvvKbO-f.js → tree-CJWpMUvD.js} +113 -103
  172. package/dist/tree-CJWpMUvD.js.map +1 -0
  173. package/dist/{tree-component-D8Bg48tt.d.ts → tree-component-BcO26Xvt.d.ts} +65 -3
  174. package/dist/tree-component-BcO26Xvt.d.ts.map +1 -0
  175. package/dist/tree.d.ts +15 -15
  176. package/dist/tree.d.ts.map +1 -1
  177. package/dist/tree.js +1 -1
  178. package/dist/{types-BKaqnpwx.d.ts → types-DSfbtHs3.d.ts} +1 -1
  179. package/dist/types-DSfbtHs3.d.ts.map +1 -0
  180. package/dist/{xy-axis-DL0tfJDr.js → xy-axis-CK64haaK.js} +1831 -359
  181. package/dist/xy-axis-CK64haaK.js.map +1 -0
  182. package/dist/{xy-axis-D9uwpGTT.d.ts → xy-axis-McdUpcYr.d.ts} +102 -3
  183. package/dist/xy-axis-McdUpcYr.d.ts.map +1 -0
  184. package/dist/xy-pad.d.ts +1 -1
  185. package/dist/xy-pad.d.ts.map +1 -1
  186. package/dist/xy-pad.js +11 -6
  187. package/dist/xy-pad.js.map +1 -1
  188. package/docs-user/README.md +45 -0
  189. package/docs-user/ac-text.md +67 -0
  190. package/docs-user/ac-token.md +187 -0
  191. package/docs-user/button.md +355 -0
  192. package/docs-user/checkbox.md +62 -0
  193. package/docs-user/colour-picker.md +237 -0
  194. package/docs-user/crumbs.md +66 -0
  195. package/docs-user/data-display.md +98 -0
  196. package/docs-user/editable-label.md +244 -0
  197. package/docs-user/grouped-item-lister.md +424 -0
  198. package/docs-user/icons.md +191 -0
  199. package/docs-user/incr-search.md +94 -0
  200. package/docs-user/labelled-radial-input.md +204 -0
  201. package/docs-user/labelled-range-input.md +194 -0
  202. package/docs-user/led.md +40 -0
  203. package/docs-user/menu.md +319 -0
  204. package/docs-user/miller.md +453 -0
  205. package/docs-user/narrowed-text.md +72 -0
  206. package/docs-user/panel.md +250 -0
  207. package/docs-user/plots.md +361 -0
  208. package/docs-user/polar-pad.md +228 -0
  209. package/docs-user/radial-input.md +559 -0
  210. package/docs-user/range-input.md +264 -0
  211. package/docs-user/range.md +12 -0
  212. package/docs-user/selecthorizontal.md +32 -0
  213. package/docs-user/snap-container.md +132 -0
  214. package/docs-user/split-layout.md +232 -0
  215. package/docs-user/swipe.md +44 -0
  216. package/docs-user/tabs.md +217 -0
  217. package/docs-user/timeline.md +116 -0
  218. package/docs-user/transitory-label.md +120 -0
  219. package/docs-user/tree.md +592 -0
  220. package/docs-user/user-catalog.md +165 -0
  221. package/docs-user/user-theming.md +379 -0
  222. package/docs-user/util.md +122 -0
  223. package/docs-user/vertical-list.md +351 -0
  224. package/docs-user/xy-pad.md +94 -0
  225. package/package.json +19 -18
  226. package/dist/colour-C3MQIjFJ-BLXg8W3U.js.map +0 -1
  227. package/dist/colour-picker-K6zu82lm.js.map +0 -1
  228. package/dist/dist-BX0OVIm7.js +0 -1290
  229. package/dist/dist-BX0OVIm7.js.map +0 -1
  230. package/dist/dist-TAGYwaju.js.map +0 -1
  231. package/dist/hex-editor-DlfoA65y.d.ts.map +0 -1
  232. package/dist/icon-9NWTXtE1.js.map +0 -1
  233. package/dist/icon-Dm_DHDz6.d.ts.map +0 -1
  234. package/dist/index-CnL9krsH.d.ts.map +0 -1
  235. package/dist/index-DLkSKL4T.d.ts.map +0 -1
  236. package/dist/index-DSlPeWLK.d.ts.map +0 -1
  237. package/dist/index-iZLld8Ca.d.ts.map +0 -1
  238. package/dist/interaction-DG7X1rhI.js +0 -1
  239. package/dist/labelled-input-base-BVvNeb5R.d.ts.map +0 -1
  240. package/dist/menu-DJJuCm-5.js.map +0 -1
  241. package/dist/menu-item-CKRfP0pN.js.map +0 -1
  242. package/dist/menu-item-ClQF2DKN.d.ts.map +0 -1
  243. package/dist/prominence--ic9uWBl.js +0 -98
  244. package/dist/prominence--ic9uWBl.js.map +0 -1
  245. package/dist/radial-input-DZA6WaFu.js.map +0 -1
  246. package/dist/radial-input-LUSBEycd.d.ts.map +0 -1
  247. package/dist/tab-list-BnqISNvO.d.ts.map +0 -1
  248. package/dist/tickled-controller-Cq1Va0rR.d.ts.map +0 -1
  249. package/dist/tree-CvvKbO-f.js.map +0 -1
  250. package/dist/tree-component-D8Bg48tt.d.ts.map +0 -1
  251. package/dist/types-BKaqnpwx.d.ts.map +0 -1
  252. package/dist/xy-axis-D9uwpGTT.d.ts.map +0 -1
  253. package/dist/xy-axis-DL0tfJDr.js.map +0 -1
  254. /package/bundle/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
  255. /package/dist/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
@@ -0,0 +1,355 @@
1
+ # Button components
2
+
3
+ Three related button components:
4
+
5
+ - **`ixfx-button`** — a styled, icon-capable replacement for `<button>`
6
+ - **`ixfx-split-button`** — a button paired with a dropdown caret; supports a static popup menu, a switcher mode, and programmatic item control
7
+ - **`ixfx-radio-group`** — a group of radio-style selectable items; also supports single toggle mode
8
+
9
+ ---
10
+
11
+ ## `ixfx-button`
12
+
13
+ ```html
14
+ <ixfx-button>Save</ixfx-button>
15
+ <ixfx-button icon="check">Commit</ixfx-button>
16
+ <ixfx-button icon="check" hide-label>Commit</ixfx-button>
17
+ <ixfx-button disabled>Unavailable</ixfx-button>
18
+ ```
19
+
20
+ ### Properties / attributes
21
+
22
+ | Attribute / Property | Type | Default | Description |
23
+ |---------------------|---------|---------|----------------------------------------------------|
24
+ | `disabled` | boolean | `false` | Disables the button |
25
+ | `icon` | string | — | Registered icon name **or** raw `<svg>` string |
26
+ | `hide-icon` | boolean | `false` | Hides the icon even when `icon` is set |
27
+ | `hide-label` | boolean | `false` | Hides the text label (useful for icon-only buttons)|
28
+
29
+ ### Slots
30
+
31
+ | Slot | Description |
32
+ |---------|--------------------------|
33
+ | default | Button label text / HTML |
34
+
35
+ ### Events
36
+
37
+ `ixfx-button` does not fire custom events. Listen for the standard `click` on the element.
38
+
39
+ ```js
40
+ document.querySelector('ixfx-button').addEventListener('click', () => { ... });
41
+ ```
42
+
43
+ ### Icons
44
+
45
+ Icon names resolve against the icon registry. Built-in names: `check`, `chevron-down`, `chevron-right`, `close`, `caret-right`. Register custom icons with `registerIcon(name, svgString)` from `src/icons/registry.ts`.
46
+
47
+ You can also pass a raw SVG string directly to `icon`:
48
+
49
+ ```js
50
+ btn.icon = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="..."/></svg>';
51
+ ```
52
+
53
+ ### CSS custom properties
54
+
55
+ | Property | Default | Description |
56
+ |---------------------|----------|-------------------------|
57
+ | `--surface-3` | `#ccc` | Button background |
58
+ | `--surface-3-text` | `#000` | Button text / icon fill |
59
+ | `--accent` | `#666` | Hover border colour |
60
+ | `--border` | `1px solid #999` | Border |
61
+ | `--radius-xl` | `8px` | Border radius |
62
+ | `--space-m` | `8px` | Vertical padding |
63
+ | `--space-l` | `12px` | Horizontal padding |
64
+ | `--text-m` | `14px` | Font size |
65
+ | `--transition` | `0.2s` | Hover/active transition |
66
+ | `--disabled-opacity`| `0.5` | Opacity when disabled |
67
+
68
+ ---
69
+
70
+ ## `ixfx-radio-group`
71
+
72
+ A group of radio-style selectable items, useful for selecting one option from a list. Also supports a **single toggle mode** when no `<option>` children are provided.
73
+
74
+ ```html
75
+ <ixfx-radio-group name="waveform" value="sine">
76
+ <option value="sine">Sine</option>
77
+ <option value="square">Square</option>
78
+ <option value="sawtooth">Saw</option>
79
+ <option value="triangle">Tri</option>
80
+ </ixfx-radio-group>
81
+ ```
82
+
83
+ ### Single toggle mode
84
+
85
+ When no `<option>` elements are provided and text content is present, the component renders as a toggle button:
86
+
87
+ ```html
88
+ <ixfx-radio-group name="toggle" checked>Enable Feature</ixfx-radio-group>
89
+ <ixfx-radio-group name="state" value="active" value-off="inactive" checked>Active/Inactive</ixfx-radio-group>
90
+ <ixfx-radio-group name="confirm" icon-name="check" icon-name-off="close" checked>On/Off</ixfx-radio-group>
91
+ ```
92
+
93
+ ### Properties / attributes
94
+
95
+ | Attribute / Property | Type | Default | Description |
96
+ |---------------------|-----------------------------------|--------------|----------------------------------------------------------------|
97
+ | `value` | string | `''` | Currently selected value |
98
+ | `checked` | boolean | `false` | For toggle mode: whether it is checked |
99
+ | `orientation` | `'horizontal'` \| `'vertical'` | `'horizontal'` | Layout direction |
100
+ | `mode` | `'compact'` \| `'max'` | `'compact'` | `compact`: items size to fit content. `max`: items stretch to fill container |
101
+ | `name` | string | `''` | Radio group name (used for native radio behavior) |
102
+ | `value-off` | string | `''` | Value when toggle is in off state |
103
+ | `icon-name` | string | `''` | Icon name (from registry) shown when toggle is on / item selected |
104
+ | `icon-name-off` | string | `''` | Icon name shown when toggle is off |
105
+ | `hide-labels` | boolean | `false` | Hides item labels |
106
+ | `items` | `RadioItem[]` | `[]` | Programmatically set items (alternative to `<option>` children) |
107
+
108
+ ### Slots
109
+
110
+ | Slot | Description |
111
+ |-----------|--------------------------------------------------|
112
+ | default | Text content for toggle mode |
113
+ | (children)| `<option>` elements defining radio items |
114
+
115
+ ### Events
116
+
117
+ | Event | Detail | Description |
118
+ |----------|---------------------------------------------|-------------------------------------|
119
+ | `change` | `{ checked: boolean, value: string \| undefined }` | Fired when selection changes |
120
+
121
+ ```js
122
+ document.querySelector('ixfx-radio-group').addEventListener('change', e => {
123
+ console.log(e.detail.value); // e.g. 'sine'
124
+ console.log(e.detail.checked); // true
125
+ });
126
+ ```
127
+
128
+ ### Programmatic control
129
+
130
+ ```js
131
+ const group = document.querySelector('ixfx-radio-group');
132
+
133
+ // Get/set selected value
134
+ group.value = 'square';
135
+
136
+ // For toggle mode
137
+ group.checked = true;
138
+
139
+ // Update items programmatically
140
+ group.items = [
141
+ { value: 'alpha', label: 'Alpha' },
142
+ { value: 'beta', label: 'Beta', disabled: true },
143
+ { value: 'gamma', label: 'Gamma', iconName: 'check' },
144
+ ];
145
+ ```
146
+
147
+ ### CSS custom properties
148
+
149
+ | Property | Default | Description |
150
+ |------------------------|--------------------------------|------------------------------------------|
151
+ | `--surface-3` | `transparent` | Background |
152
+ | `--border` | `none` | Border |
153
+ | `--radius-m` | `4px` | Border radius |
154
+ | `--item-spacing` | `0` | Gap between items |
155
+ | `--icon-label-spacing` | `0.5rem` | Gap between icon and label |
156
+ | `--icon-size` | `1.2rem` | Icon dimensions |
157
+ | `--compact-padding` | `0.5rem` | Padding in compact mode |
158
+ | `--space-m` | `0.5rem` | Vertical item padding |
159
+ | `--space-l` | `1rem` | Horizontal item padding |
160
+
161
+ ### TypeScript types
162
+
163
+ ```ts
164
+ import type { RadioGroupChangeDetail, RadioItem, RadioGroupMode } from 'ixfxfun-components';
165
+ ```
166
+
167
+ ---
168
+
169
+ ## `ixfx-split-button`
170
+
171
+ A button split into a **primary action area** (left) and a **caret** (right) that opens a popup menu. Extends `ixfx-button` so all button properties and CSS variables apply.
172
+
173
+ ```html
174
+ <ixfx-split-button>
175
+ Save
176
+ <ixfx-menu-container slot="menu">
177
+ <ixfx-menu-item command="save-draft" label="Save as Draft"></ixfx-menu-item>
178
+ <ixfx-menu-item command="save-copy" label="Save a Copy"></ixfx-menu-item>
179
+ <ixfx-menu-separator></ixfx-menu-separator>
180
+ <ixfx-menu-item command="export" label="Export…"></ixfx-menu-item>
181
+ </ixfx-menu-container>
182
+ </ixfx-split-button>
183
+ ```
184
+
185
+ ### Properties / attributes
186
+
187
+ Inherits all `ixfx-button` properties, plus:
188
+
189
+ | Attribute / Property | Type | Default | Description |
190
+ |---------------------|-----------------|-------------|-----------------------------------------------------------------|
191
+ | `mode` | `'default'` \| `'switcher'` | `'default'` | See [Modes](#modes) |
192
+ | `default-value` | string | `''` | Command to pre-select in switcher mode |
193
+ | `items` | `PopupItem[]` | — | Directly set popup items (ignored when `itemsProvider` is set) |
194
+ | `itemsProvider` | `() => PopupItem[] \| Promise<PopupItem[]>` | — | Called on each caret click; return value replaces all other item sources |
195
+ | `registry` | `CommandRegistry` | — | Optional command registry forwarded to `ixfx-menu-trigger` |
196
+ | `keyboardManager` | `KeyboardManager` | — | Optional keyboard manager forwarded to `ixfx-menu-trigger` |
197
+
198
+ ### Slots
199
+
200
+ | Slot | Description |
201
+ |-----------|-------------------------------------------------------------------------------|
202
+ | default | Primary button label |
203
+ | `menu` | `<ixfx-menu-container>` + items for the popup (default mode); or `<ixfx-menu-item>` elements as the data source in switcher mode |
204
+
205
+ ### Events
206
+
207
+ | Event | Detail | Description |
208
+ |----------------|------------------------------|-----------------------------------------------------------------------------|
209
+ | `menu-command` | `{ command: string }` | Fired when a menu item is selected, or when the primary button is clicked in switcher mode |
210
+
211
+ ```js
212
+ element.addEventListener('menu-command', e => {
213
+ console.log(e.detail.command); // e.g. 'save-draft'
214
+ });
215
+ ```
216
+
217
+ The primary area does **not** fire `click` with a command — handle `menu-command` for both modes.
218
+
219
+ ---
220
+
221
+ ### Modes
222
+
223
+ #### `default` mode (the default)
224
+
225
+ Left side fires a plain `click`. Right caret opens the popup.
226
+
227
+ ```html
228
+ <ixfx-split-button icon="check">
229
+ Commit
230
+ <ixfx-menu-container slot="menu">
231
+ <ixfx-menu-item command="commit-push" label="Commit & Push"></ixfx-menu-item>
232
+ <ixfx-menu-item command="commit-only" label="Commit Only"></ixfx-menu-item>
233
+ <ixfx-menu-item command="amend" label="Amend Last Commit"></ixfx-menu-item>
234
+ </ixfx-menu-container>
235
+ </ixfx-split-button>
236
+ ```
237
+
238
+ #### `switcher` mode
239
+
240
+ Selecting from the popup **replaces** the primary action and fires `menu-command` immediately. The replaced item returns to the popup. The caret shows a right-facing chevron to signal "this changes what the button does".
241
+
242
+ ```html
243
+ <ixfx-split-button mode="switcher" default-value="save">
244
+ <ixfx-menu-item slot="menu" command="save" label="Save"></ixfx-menu-item>
245
+ <ixfx-menu-item slot="menu" command="save-draft" label="Save as Draft"></ixfx-menu-item>
246
+ <ixfx-menu-item slot="menu" command="export" label="Export…"></ixfx-menu-item>
247
+ </ixfx-split-button>
248
+ ```
249
+
250
+ Icons on switcher items flow through to the primary button:
251
+
252
+ ```html
253
+ <ixfx-split-button mode="switcher" default-value="commit-push">
254
+ <ixfx-menu-item slot="menu" command="commit-push" label="Commit & Push" icon-name="check"></ixfx-menu-item>
255
+ <ixfx-menu-item slot="menu" command="commit-only" label="Commit Only" icon-name="check"></ixfx-menu-item>
256
+ <ixfx-menu-item slot="menu" command="amend" label="Amend" ></ixfx-menu-item>
257
+ </ixfx-split-button>
258
+ ```
259
+
260
+ ---
261
+
262
+ ### Programmatic control
263
+
264
+ All properties are writable at runtime. Changes trigger re-render automatically.
265
+
266
+ #### Set popup items directly
267
+
268
+ ```js
269
+ import type { PopupItem } from 'ixfxfun-components';
270
+
271
+ const btn = document.querySelector('ixfx-split-button');
272
+
273
+ btn.items = [
274
+ { command: 'staging', label: 'Deploy to Staging', icon: 'check' },
275
+ { command: 'prod', label: 'Deploy to Production' },
276
+ { command: 'preview', label: 'Preview build' },
277
+ ];
278
+ ```
279
+
280
+ `items` works in both `default` and `switcher` modes. In switcher mode the first item (or `default-value` if matched) becomes the active selection.
281
+
282
+ #### Dynamic / async items via callback
283
+
284
+ ```js
285
+ btn.itemsProvider = async () => {
286
+ const data = await fetch('/api/deploy-targets').then(r => r.json());
287
+ return data.map(t => ({ command: t.id, label: t.name }));
288
+ };
289
+ ```
290
+
291
+ The popup shows a "Loading…" placeholder while the promise resolves. `itemsProvider` takes priority over `items` and declarative slot content.
292
+
293
+ #### Change mode at runtime
294
+
295
+ ```js
296
+ btn.mode = 'switcher'; // or 'default'
297
+ ```
298
+
299
+ When switching to `switcher` and `items` is set, items are re-applied for the new mode automatically.
300
+
301
+ #### Select a command in switcher mode
302
+
303
+ ```js
304
+ const found = btn.selectCommand('staging'); // returns false if command not in items
305
+ ```
306
+
307
+ This changes the primary button label/icon immediately without opening the popup and without firing `menu-command`.
308
+
309
+ #### Change label and icon
310
+
311
+ ```js
312
+ btn.textContent = 'Publish'; // updates the default slot
313
+ btn.icon = 'check';
314
+ btn.hideLabel = true;
315
+ btn.disabled = true;
316
+ ```
317
+
318
+ ---
319
+
320
+ ### Responsive behaviour
321
+
322
+ When the primary area is too narrow to show its label, the component automatically collapses to icon + caret only. It restores the label as soon as space allows. No configuration needed — driven by a `ResizeObserver` comparing `scrollWidth` vs `offsetWidth`.
323
+
324
+ To force icon-only at all times, set `hide-label`:
325
+
326
+ ```html
327
+ <ixfx-split-button icon="check" hide-label>Commit</ixfx-split-button>
328
+ ```
329
+
330
+ ---
331
+
332
+ ### CSS parts
333
+
334
+ | Part | Element |
335
+ |-----------|---------------------------|
336
+ | `primary` | The left primary `<button>` |
337
+ | `caret` | The right caret `<button>` |
338
+
339
+ ```css
340
+ ixfx-split-button::part(primary) { font-weight: bold; }
341
+ ixfx-split-button::part(caret) { background: hotpink; }
342
+ ```
343
+
344
+ ---
345
+
346
+ ### TypeScript types
347
+
348
+ ```ts
349
+ import type {
350
+ PopupItem, // { command, label, icon?, disabled? }
351
+ SwitcherItem, // { command, label, icon }
352
+ ItemsProvider, // () => PopupItem[] | Promise<PopupItem[]>
353
+ SplitButtonMode, // 'default' | 'switcher'
354
+ } from 'ixfxfun-components';
355
+ ```
@@ -0,0 +1,62 @@
1
+ # `ixfx-checkbox`
2
+
3
+ A custom checkbox with a diagonal line indicator and indeterminate state support. Uses shadow DOM with CSS variables for full appearance customization.
4
+
5
+ ```html
6
+ <ixfx-checkbox label="Accept terms"></ixfx-checkbox>
7
+ <ixfx-checkbox checked label="Enabled"></ixfx-checkbox>
8
+ <ixfx-checkbox disabled label="Disabled"></ixfx-checkbox>
9
+ <ixfx-checkbox indeterminate label="Pending"></ixfx-checkbox>
10
+ ```
11
+
12
+ ### Properties / attributes
13
+
14
+ | Attribute / Property | Type | Default | Description |
15
+ |----------------------|-----------|---------|--------------------------------------|
16
+ | `checked` | `boolean` | `false` | Checked state (diagonal line) |
17
+ | `indeterminate` | `boolean` | `false` | Indeterminate state (horizontal bar) |
18
+ | `disabled` | `boolean` | `false` | Disabled state |
19
+ | `label` | `string` | `''` | Text label beside the box |
20
+ | `name` | `string` | `''` | Form field name |
21
+ | `value` | `string` | `''` | Form field value |
22
+
23
+ ### Events
24
+
25
+ | Event | Detail | Description |
26
+ |----------|---------------------------|------------------------------|
27
+ | `change` | `{ checked: boolean }` | Fired when checked state changes |
28
+
29
+ ```js
30
+ document.querySelector('ixfx-checkbox').addEventListener('change', e => {
31
+ console.log(e.detail.checked);
32
+ });
33
+ ```
34
+
35
+ ### CSS custom properties
36
+
37
+ | Property | Default | Description |
38
+ |---------------------------|-----------------------------------|---------------------------------|
39
+ | `--box-size` | `18px` | Box width/height |
40
+ | `--box-border-width` | `2px` | Box border thickness |
41
+ | `--box-border-color` | `var(--surface-4)` | Box border color |
42
+ | `--box-bg-unchecked` | `color-mix(...surface-3, surface-2)` | Background when unchecked |
43
+ | `--box-bg-checked` | `color-mix(...surface-3, surface-2)` | Background when checked |
44
+ | `--check-line-color` | `var(--accent)` | Diagonal / horizontal line color |
45
+ | `--check-line-width` | `6px` | Line thickness |
46
+ | `--box-opacity-unchecked` | `0.5` | Opacity when unchecked |
47
+ | `--box-opacity-checked` | `1` | Opacity when checked |
48
+ | `--box-opacity-hover` | `var(--prominence-tickled-opacity)` | Opacity on hover |
49
+ | `--box-opacity-disabled` | `var(--prominence-disabled-opacity)` | Opacity when disabled |
50
+ | `--label-gap` | `var(--space-m)` | Gap between box and label |
51
+ | `--label-fg` | `var(--surface-3-text)` | Label text color |
52
+ | `--label-active` | `var(--surface-2-text)` | Label color when box clicked |
53
+ | `--label-hover` | `var(--surface-2-text)` | Label color on hover |
54
+ | `--label-opacity` | `1` | Label opacity |
55
+ | `--label-opacity-unchecked` | `1` | Label opacity when unchecked |
56
+ | `--transition-duration` | `var(--transition)` | Animation duration |
57
+
58
+ ### TypeScript types
59
+
60
+ ```ts
61
+ import type { CheckboxChangeDetail } from 'ixfxfun-components';
62
+ ```
@@ -0,0 +1,237 @@
1
+ # Colour Picker Components
2
+
3
+ Two components for picking OKLCH colours. Use `ixfx-colour-picker` when you need a full inline picker; use `ixfx-colour-picker-popup` when you need a compact swatch that opens a picker in a popover.
4
+
5
+ Both work in OKLCH colour space, which gives perceptually uniform gradients across all three channels.
6
+
7
+ ---
8
+
9
+ ## `<ixfx-colour-picker>`
10
+
11
+ A full inline picker with gradient-rendered sliders for Hue, Lightness, and Chroma (and optionally Opacity). Includes a colour preview swatch. Layout adapts automatically — portrait (stacked), landscape (preview beside sliders), and a compact narrow-height mode.
12
+
13
+ ### Basic usage
14
+
15
+ ```html
16
+ <ixfx-colour-picker></ixfx-colour-picker>
17
+
18
+ <script>
19
+ const picker = document.querySelector('ixfx-colour-picker');
20
+ picker.addEventListener('input', e => {
21
+ console.log(e.detail); // { l, c, h, a }
22
+ console.log(picker.value); // "oklch(0.7 0.15 180)"
23
+ });
24
+ </script>
25
+ ```
26
+
27
+ ### Attributes
28
+
29
+ | Attribute | Type | Default | Description |
30
+ |------------------|---------|---------|-------------|
31
+ | `l` | number | `0.7` | Lightness (0–1) |
32
+ | `c` | number | `0.15` | Chroma (0–0.4) |
33
+ | `h` | number | `180` | Hue (0–360) |
34
+ | `a` | number | `1` | Opacity (0–1). Only relevant when `show-a` is set. |
35
+ | `value` | string | — | Set initial colour from any CSS colour string (e.g. `"#ff0"`, `"hsl(120 50% 50%)"`) |
36
+ | `hide-preview` | boolean | `false` | Hide the colour preview swatch |
37
+ | `hide-h` | boolean | `false` | Hide the Hue slider |
38
+ | `hide-l` | boolean | `false` | Hide the Lightness slider |
39
+ | `hide-c` | boolean | `false` | Hide the Chroma slider |
40
+ | `show-a` | boolean | `false` | Show the Opacity slider |
41
+ | `horizontal` | boolean | `false` | Force horizontal layout (preview left, sliders right) |
42
+ | `sliders-vertical` | boolean | `false` | Render sliders as side-by-side vertical bars |
43
+ | `hide-tooltips` | boolean | `false` | Suppress hover tooltips on slider labels |
44
+ | `range-l` | string | `"0-1"` | Restrict Lightness slider range, e.g. `"0.2-0.9"` |
45
+ | `range-c` | string | `"0-0.4"` | Restrict Chroma slider range |
46
+ | `range-h` | string | `"0-360"` | Restrict Hue slider range |
47
+ | `range-a` | string | `"0-1"` | Restrict Opacity slider range |
48
+
49
+ ### Properties
50
+
51
+ All attributes above are also settable as JS properties (camelCase where applicable: `hidePreview`, `hideH`, `hideL`, `hideC`, `showA`, `horizontal`, `slidersVertical`, `hideTooltips`).
52
+
53
+ Range setters accept a `[min, max]` tuple and can also be set via the attributes above:
54
+
55
+ ```js
56
+ picker.rangeH = [0, 180]; // restrict hue to cool colours
57
+ picker.rangeL = [0.2, 0.8]; // exclude near-black and near-white
58
+ ```
59
+
60
+ ### Getters
61
+
62
+ | Getter | Returns | Description |
63
+ |---------|---------|-------------|
64
+ | `value` | `string` | Current colour as a CSS `oklch()` string, e.g. `"oklch(0.7 0.15 180)"` |
65
+ | `rangeL` | `[number, number]` | Active lightness range |
66
+ | `rangeC` | `[number, number]` | Active chroma range |
67
+ | `rangeH` | `[number, number]` | Active hue range |
68
+ | `rangeA` | `[number, number]` | Active opacity range |
69
+
70
+ ### Methods
71
+
72
+ #### `setColour(colour)`
73
+
74
+ Set the colour programmatically from any ixfx-compatible colour format. Also updates the double-click reset target for all sliders.
75
+
76
+ ```js
77
+ picker.setColour('hsl(200, 80%, 50%)');
78
+ picker.setColour('#e74c3c');
79
+ picker.setColour({ l: 0.6, c: 0.2, h: 260 }); // OKLCH object
80
+ ```
81
+
82
+ Accepts any format that ixfx's `Colour.convert()` understands.
83
+
84
+ ### Events
85
+
86
+ Both events carry `CustomEvent<{ l: number, c: number, h: number, a: number }>` and bubble + compose.
87
+
88
+ | Event | When |
89
+ |----------|------|
90
+ | `input` | Every slider move (continuous, high frequency) |
91
+ | `change` | When slider interaction ends (committed value) |
92
+
93
+ ```js
94
+ picker.addEventListener('input', e => {
95
+ document.body.style.background = picker.value;
96
+ });
97
+
98
+ picker.addEventListener('change', e => {
99
+ saveColour(e.detail); // { l, c, h, a }
100
+ });
101
+ ```
102
+
103
+ ### CSS custom properties
104
+
105
+ | Property | Default | Description |
106
+ |----------|---------|-------------|
107
+ | `--picker-alt-width` | `240px` | Component width |
108
+ | `--picker-alt-height` | `240px` | Component height |
109
+ | `--picker-alt-min-slider-height` | `2.5em` | Minimum height per slider |
110
+
111
+ Standard theme variables (`--surface`, `--surface-ll`, `--radius-m`, `--space-s`, `--accent`) are used where available.
112
+
113
+ ### Layout behaviour
114
+
115
+ The component uses CSS container queries on its own size, so you can size it freely:
116
+
117
+ ```css
118
+ ixfx-colour-picker {
119
+ width: 100%;
120
+ height: 300px;
121
+ }
122
+ ```
123
+
124
+ - **Portrait / square**: preview swatch on top, sliders below (stacked column)
125
+ - **Landscape** (aspect ratio > 1): preview swatch on left, sliders on right
126
+ - **Short** (height < 150px): switches to landscape regardless of width
127
+ - **`sliders-vertical`**: sliders become narrow side-by-side vertical bars (good for wide, short layouts)
128
+
129
+ ---
130
+
131
+ ## `<ixfx-colour-picker-popup>`
132
+
133
+ A compact inline swatch button. Clicking it opens a full `ixfx-colour-picker` in a native popover anchored to the swatch. The picker is lazy — it is not added to the DOM until the swatch is clicked for the first time.
134
+
135
+ ### Basic usage
136
+
137
+ ```html
138
+ <label>
139
+ Background colour
140
+ <ixfx-colour-picker-popup></ixfx-colour-picker-popup>
141
+ </label>
142
+
143
+ <script>
144
+ const popup = document.querySelector('ixfx-colour-picker-popup');
145
+ popup.addEventListener('change', e => {
146
+ document.body.style.background = popup.value;
147
+ });
148
+ </script>
149
+ ```
150
+
151
+ ### Modes
152
+
153
+ #### Fluid mode (default)
154
+
155
+ Every slider move updates `l/c/h/a` on the popup and fires `input`. The swatch updates live. `change` fires when the slider interaction ends.
156
+
157
+ #### Confirm mode
158
+
159
+ Slider changes are held in a pending state. Nothing is committed until the user clicks the confirm (✓) button, which fires `change` and closes the popover. Dismissing the popover without confirming (light-dismiss / clicking outside) reverts the picker to the last committed values.
160
+
161
+ ```html
162
+ <ixfx-colour-picker-popup mode="confirm"></ixfx-colour-picker-popup>
163
+ ```
164
+
165
+ ### Attributes
166
+
167
+ | Attribute | Type | Default | Description |
168
+ |----------------|---------|------------|-------------|
169
+ | `mode` | string | `"fluid"` | `"fluid"` or `"confirm"` |
170
+ | `l` | number | `0.7` | Committed lightness (0–1) |
171
+ | `c` | number | `0.15` | Committed chroma (0–0.4) |
172
+ | `h` | number | `180` | Committed hue (0–360) |
173
+ | `a` | number | `1` | Committed opacity (0–1) |
174
+ | `size` | string | `"medium"` | Popover picker size: `"small"` \| `"medium"` \| `"large"` \| `"huge"` |
175
+ | `show-preview` | boolean | `false` | Show the colour preview inside the picker (fluid mode hides it by default since the swatch already shows the live colour) |
176
+ | `hide-h` | boolean | `false` | Hide the Hue slider inside the picker |
177
+ | `hide-l` | boolean | `false` | Hide the Lightness slider inside the picker |
178
+ | `hide-c` | boolean | `false` | Hide the Chroma slider inside the picker |
179
+ | `show-a` | boolean | `false` | Show the Opacity slider inside the picker |
180
+ | `horizontal` | boolean | `false` | Force horizontal layout inside the picker |
181
+
182
+ Picker sizes (width × height):
183
+
184
+ | `size` | Dimensions |
185
+ |-----------|------------|
186
+ | `small` | 130 × 100 px |
187
+ | `medium` | 100 × 155 px (default) |
188
+ | `large` | 200 × 180 px |
189
+ | `huge` | 290 × 240 px |
190
+
191
+ ### Getters
192
+
193
+ | Getter | Returns | Description |
194
+ |---------|----------|-------------|
195
+ | `value` | `string` | Committed colour as a CSS `oklch()` string |
196
+
197
+ ### Methods
198
+
199
+ #### `setColour(colour)`
200
+
201
+ Set the committed colour from any ixfx-compatible format. The swatch updates immediately. The inner picker reflects the new colour the next time the popover opens.
202
+
203
+ ```js
204
+ popup.setColour('#3498db');
205
+ popup.setColour({ l: 0.5, c: 0.25, h: 30 });
206
+ ```
207
+
208
+ ### Events
209
+
210
+ | Event | Mode | When |
211
+ |----------|---------|------|
212
+ | `input` | fluid | Every slider move |
213
+ | `change` | fluid | Slider interaction ends |
214
+ | `change` | confirm | Confirm button clicked |
215
+
216
+ Both carry `CustomEvent<{ l: number, c: number, h: number, a: number }>`, bubble, and compose.
217
+
218
+ ### CSS custom properties
219
+
220
+ | Property | Default | Description |
221
+ |----------|---------|-------------|
222
+ | `--cp-popup-swatch-size` | `1.5em` | Width and height of the swatch button |
223
+
224
+ The popover panel uses standard theme variables for background, border, radius, and shadow (`--surface`, `--border`, `--radius-l`, `--shadow-l`, `--space-s`).
225
+
226
+ ---
227
+
228
+ ## Shared event detail type
229
+
230
+ ```ts
231
+ type ColourPickerEventDetail = {
232
+ l: number; // Lightness 0–1
233
+ c: number; // Chroma 0–0.4
234
+ h: number; // Hue 0–360
235
+ a?: number; // Opacity 0–1 (defaults to 1)
236
+ };
237
+ ```