@fusion.dev/helix-headless 0.142.1 → 0.144.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 (285) hide show
  1. package/custom-elements.json +25381 -1202
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  11. package/dist/area-chart/root/area-chart-root.js +39 -11
  12. package/dist/avatar/group/avatar-group.d.ts +24 -3
  13. package/dist/avatar/group/avatar-group.js +34 -2
  14. package/dist/avatar/root/avatar-root.d.ts +17 -1
  15. package/dist/avatar/root/avatar-root.js +31 -10
  16. package/dist/badge/root/badge-root.d.ts +12 -0
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
  19. package/dist/bar-chart/root/bar-chart-root.js +58 -21
  20. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  21. package/dist/blockquote/root/blockquote-root.js +6 -4
  22. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  24. package/dist/button/root/button-root.d.ts +84 -1
  25. package/dist/button/root/button-root.js +81 -3
  26. package/dist/callout/root/callout-root.d.ts +32 -6
  27. package/dist/callout/root/callout-root.js +26 -7
  28. package/dist/canvas/root/canvas-root.d.ts +1 -0
  29. package/dist/canvas/root/canvas-root.js +10 -1
  30. package/dist/card/root/card-root.d.ts +30 -1
  31. package/dist/card/root/card-root.js +38 -5
  32. package/dist/carousel/root/carousel-root.d.ts +47 -5
  33. package/dist/carousel/root/carousel-root.js +53 -21
  34. package/dist/chat/composer/chat-composer.d.ts +13 -11
  35. package/dist/chat/composer/chat-composer.js +6 -12
  36. package/dist/chat/message/chat-message.js +8 -1
  37. package/dist/chat/root/chat-root.d.ts +1 -0
  38. package/dist/chat/root/chat-root.js +2 -1
  39. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  40. package/dist/checkbox/root/checkbox-root.js +9 -3
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
  42. package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
  43. package/dist/code/root/code-root.d.ts +1 -1
  44. package/dist/code-block/lines.d.ts +13 -0
  45. package/dist/code-block/lines.js +2 -0
  46. package/dist/code-block/root/code-block-root.d.ts +49 -0
  47. package/dist/code-block/root/code-block-root.js +44 -3
  48. package/dist/color-input/root/color-input-root.d.ts +60 -2
  49. package/dist/color-input/root/color-input-root.js +55 -7
  50. package/dist/color-picker/channels.d.ts +26 -0
  51. package/dist/color-picker/channels.js +84 -0
  52. package/dist/color-picker/root/color-picker-root.d.ts +118 -12
  53. package/dist/color-picker/root/color-picker-root.js +183 -13
  54. package/dist/combobox/root/combobox-root.d.ts +126 -3
  55. package/dist/combobox/root/combobox-root.js +224 -21
  56. package/dist/command/root/command-root.d.ts +47 -10
  57. package/dist/command/root/command-root.js +45 -4
  58. package/dist/copy-button/from.d.ts +22 -0
  59. package/dist/copy-button/from.js +28 -0
  60. package/dist/copy-button/root/copy-button-root.d.ts +48 -7
  61. package/dist/copy-button/root/copy-button-root.js +54 -8
  62. package/dist/data-table/root/data-table-root.d.ts +164 -10
  63. package/dist/data-table/root/data-table-root.js +488 -57
  64. package/dist/date-input/root/date-input-root.d.ts +123 -9
  65. package/dist/date-input/root/date-input-root.js +147 -45
  66. package/dist/date-picker/root/date-picker-root.d.ts +229 -18
  67. package/dist/date-picker/root/date-picker-root.js +342 -46
  68. package/dist/dialog/description.d.ts +9 -0
  69. package/dist/dialog/description.js +14 -0
  70. package/dist/dialog/root/dialog-root.d.ts +101 -10
  71. package/dist/dialog/root/dialog-root.js +83 -4
  72. package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
  73. package/dist/donut-chart/root/donut-chart-root.js +48 -13
  74. package/dist/drawer/root/drawer-root.d.ts +93 -7
  75. package/dist/drawer/root/drawer-root.js +126 -5
  76. package/dist/drawer/swipe-start.d.ts +9 -0
  77. package/dist/drawer/swipe-start.js +12 -0
  78. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  79. package/dist/drilldown/item/drilldown-item.js +6 -2
  80. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  81. package/dist/drilldown/root/drilldown-root.js +26 -10
  82. package/dist/element-events.generated.js +42 -13
  83. package/dist/empty/root/empty-root.d.ts +1 -1
  84. package/dist/file-input/root/file-input-root.d.ts +65 -1
  85. package/dist/file-input/root/file-input-root.js +76 -12
  86. package/dist/file-input/screen.d.ts +35 -0
  87. package/dist/file-input/screen.js +49 -0
  88. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  89. package/dist/filter-input/menu/filter-menu.js +8 -0
  90. package/dist/filter-input/root/filter-input-root.d.ts +43 -6
  91. package/dist/filter-input/root/filter-input-root.js +89 -10
  92. package/dist/filter-input/suggest.d.ts +17 -0
  93. package/dist/filter-input/suggest.js +23 -0
  94. package/dist/format-date/options.d.ts +33 -0
  95. package/dist/format-date/options.js +42 -0
  96. package/dist/format-date/root/format-date-root.d.ts +62 -3
  97. package/dist/format-date/root/format-date-root.js +78 -37
  98. package/dist/graph/root/graph-root.d.ts +24 -3
  99. package/dist/graph/root/graph-root.js +66 -12
  100. package/dist/heatmap/root/buckets.d.ts +2 -1
  101. package/dist/heatmap/root/buckets.js +5 -1
  102. package/dist/heatmap/root/heatmap-root.d.ts +47 -9
  103. package/dist/heatmap/root/heatmap-root.js +46 -18
  104. package/dist/icon/index.d.ts +2 -0
  105. package/dist/icon/index.js +2 -0
  106. package/dist/icon/registry.d.ts +37 -0
  107. package/dist/icon/registry.js +83 -0
  108. package/dist/icon/root/icon-root.d.ts +53 -6
  109. package/dist/icon/root/icon-root.js +72 -4
  110. package/dist/icon/root/index.d.ts +2 -0
  111. package/dist/icon/root/index.js +2 -0
  112. package/dist/icon/set.d.ts +1 -0
  113. package/dist/icon/set.js +3 -0
  114. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  115. package/dist/image/root/image-root.d.ts +23 -2
  116. package/dist/image/root/image-root.js +23 -4
  117. package/dist/input/root/input-root.d.ts +62 -9
  118. package/dist/input/root/input-root.js +61 -5
  119. package/dist/kbd/root/kbd-root.d.ts +26 -11
  120. package/dist/kbd/root/kbd-root.js +35 -38
  121. package/dist/kbd/shortcut.d.ts +18 -0
  122. package/dist/kbd/shortcut.js +35 -0
  123. package/dist/legend/hidden-series.d.ts +8 -0
  124. package/dist/legend/hidden-series.js +13 -0
  125. package/dist/legend/root/legend-root.d.ts +63 -0
  126. package/dist/legend/root/legend-root.js +61 -7
  127. package/dist/lightbox/item/lightbox-item.d.ts +17 -1
  128. package/dist/lightbox/item/lightbox-item.js +10 -1
  129. package/dist/lightbox/root/lightbox-root.d.ts +77 -6
  130. package/dist/lightbox/root/lightbox-root.js +116 -5
  131. package/dist/line-chart/root/line-chart-root.d.ts +29 -4
  132. package/dist/line-chart/root/line-chart-root.js +58 -17
  133. package/dist/list/item/list-item.d.ts +11 -5
  134. package/dist/list/item/list-item.js +5 -6
  135. package/dist/listbox/range.d.ts +17 -0
  136. package/dist/listbox/range.js +5 -0
  137. package/dist/listbox/root/listbox-root.d.ts +184 -4
  138. package/dist/listbox/root/listbox-root.js +229 -23
  139. package/dist/loader/busy.d.ts +17 -0
  140. package/dist/loader/busy.js +24 -0
  141. package/dist/loader/root/loader-root.d.ts +37 -0
  142. package/dist/loader/root/loader-root.js +52 -3
  143. package/dist/map/root/map-root.d.ts +19 -4
  144. package/dist/map/root/map-root.js +36 -7
  145. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  146. package/dist/megamenu/root/megamenu-root.js +10 -1
  147. package/dist/menu/item/menu-item.d.ts +41 -12
  148. package/dist/menu/item/menu-item.js +46 -3
  149. package/dist/menu/root/menu-root.d.ts +32 -2
  150. package/dist/menu/root/menu-root.js +48 -8
  151. package/dist/meter/root/meter-root.d.ts +13 -0
  152. package/dist/meter/root/meter-root.js +24 -5
  153. package/dist/navigation/root/navigation-root.d.ts +10 -2
  154. package/dist/navigation/root/navigation-root.js +13 -2
  155. package/dist/notifications/feed-keys.d.ts +10 -0
  156. package/dist/notifications/feed-keys.js +14 -0
  157. package/dist/notifications/group/notification-group.d.ts +1 -0
  158. package/dist/notifications/notification/notification.d.ts +29 -0
  159. package/dist/notifications/notification/notification.js +51 -3
  160. package/dist/notifications/root/notifications-root.d.ts +49 -0
  161. package/dist/notifications/root/notifications-root.js +76 -2
  162. package/dist/number-input/root/number-input-root.d.ts +109 -7
  163. package/dist/number-input/root/number-input-root.js +109 -21
  164. package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
  165. package/dist/object-inspector/root/object-inspector-root.js +92 -12
  166. package/dist/option/root/option-root.d.ts +58 -6
  167. package/dist/option/root/option-root.js +35 -5
  168. package/dist/outline/root/outline-root.d.ts +13 -2
  169. package/dist/outline/root/outline-root.js +4 -2
  170. package/dist/pagination/root/pagination-root.d.ts +19 -1
  171. package/dist/pagination/root/pagination-root.js +49 -9
  172. package/dist/pagination/size/pagination-size.d.ts +13 -3
  173. package/dist/pagination/size/pagination-size.js +7 -0
  174. package/dist/pin-input/format.d.ts +7 -0
  175. package/dist/pin-input/format.js +16 -0
  176. package/dist/pin-input/root/pin-input-root.d.ts +37 -0
  177. package/dist/pin-input/root/pin-input-root.js +48 -7
  178. package/dist/popover/root/popover-root.d.ts +78 -3
  179. package/dist/popover/root/popover-root.js +74 -5
  180. package/dist/progress/root/progress-root.d.ts +23 -1
  181. package/dist/progress/root/progress-root.js +40 -10
  182. package/dist/qr-code/export.d.ts +31 -0
  183. package/dist/qr-code/export.js +10 -0
  184. package/dist/qr-code/root/qr-code-root.d.ts +45 -0
  185. package/dist/qr-code/root/qr-code-root.js +78 -3
  186. package/dist/radio/group/radio-group.d.ts +64 -0
  187. package/dist/radio/group/radio-group.js +66 -12
  188. package/dist/radio/root/radio-root.d.ts +8 -5
  189. package/dist/radio/root/radio-root.js +1 -2
  190. package/dist/rating/root/rating-root.d.ts +49 -1
  191. package/dist/rating/root/rating-root.js +69 -10
  192. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  193. package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
  194. package/dist/select/root/select-root.d.ts +93 -3
  195. package/dist/select/root/select-root.js +111 -13
  196. package/dist/skeleton/root/skeleton-root.d.ts +39 -3
  197. package/dist/skeleton/root/skeleton-root.js +33 -4
  198. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  199. package/dist/skip-link/root/skip-link-root.js +15 -1
  200. package/dist/slider/root/slider-root.d.ts +59 -2
  201. package/dist/slider/root/slider-root.js +82 -8
  202. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  203. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  204. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  205. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  206. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  207. package/dist/splitter/root/splitter-root.d.ts +28 -6
  208. package/dist/splitter/root/splitter-root.js +35 -1
  209. package/dist/stat/root/stat-root.d.ts +9 -1
  210. package/dist/stat/root/stat-root.js +15 -2
  211. package/dist/steps/root/steps-root.js +1 -1
  212. package/dist/steps/step/step.d.ts +1 -0
  213. package/dist/steps/step/step.js +1 -1
  214. package/dist/switch/root/switch-root.d.ts +14 -2
  215. package/dist/switch/root/switch-root.js +7 -1
  216. package/dist/table/cell/table-cell.d.ts +24 -4
  217. package/dist/table/cell/table-cell.js +21 -1
  218. package/dist/table/column/table-column.d.ts +32 -6
  219. package/dist/table/column/table-column.js +36 -6
  220. package/dist/table/root/table-root.d.ts +94 -3
  221. package/dist/table/root/table-root.js +128 -5
  222. package/dist/table/row/table-row.d.ts +7 -0
  223. package/dist/table/row/table-row.js +9 -1
  224. package/dist/tabs/root/tabs-root.d.ts +6 -1
  225. package/dist/tabs/root/tabs-root.js +6 -2
  226. package/dist/tag/group/tag-group.d.ts +107 -0
  227. package/dist/tag/group/tag-group.js +157 -0
  228. package/dist/tag/index.d.ts +1 -0
  229. package/dist/tag/index.js +1 -0
  230. package/dist/tag/root/tag-root.d.ts +83 -1
  231. package/dist/tag/root/tag-root.js +87 -17
  232. package/dist/tag/selection.d.ts +10 -0
  233. package/dist/tag/selection.js +12 -0
  234. package/dist/textarea/grow.d.ts +22 -0
  235. package/dist/textarea/grow.js +20 -0
  236. package/dist/textarea/root/textarea-root.d.ts +13 -0
  237. package/dist/textarea/root/textarea-root.js +10 -2
  238. package/dist/time-input/root/time-input-root.d.ts +71 -6
  239. package/dist/time-input/root/time-input-root.js +110 -44
  240. package/dist/time-picker/root/time-picker-root.d.ts +155 -26
  241. package/dist/time-picker/root/time-picker-root.js +192 -63
  242. package/dist/toast/hotkey.d.ts +22 -0
  243. package/dist/toast/hotkey.js +23 -0
  244. package/dist/toast/item/toast-item.d.ts +16 -1
  245. package/dist/toast/item/toast-item.js +41 -13
  246. package/dist/toast/root/toast-root.d.ts +105 -8
  247. package/dist/toast/root/toast-root.js +209 -4
  248. package/dist/toggle/group/toggle-group.d.ts +95 -16
  249. package/dist/toggle/group/toggle-group.js +99 -13
  250. package/dist/toggle/root/toggle-root.d.ts +26 -11
  251. package/dist/toggle/root/toggle-root.js +14 -6
  252. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  253. package/dist/toolbar/root/toolbar-root.js +99 -16
  254. package/dist/tooltip/focus-target.d.ts +6 -0
  255. package/dist/tooltip/focus-target.js +9 -0
  256. package/dist/tooltip/root/tooltip-root.d.ts +73 -15
  257. package/dist/tooltip/root/tooltip-root.js +96 -7
  258. package/dist/tour/naming.d.ts +30 -0
  259. package/dist/tour/naming.js +10 -0
  260. package/dist/tour/root/tour-root.d.ts +67 -3
  261. package/dist/tour/root/tour-root.js +105 -17
  262. package/dist/tour/stop/tour-stop.d.ts +65 -3
  263. package/dist/tour/stop/tour-stop.js +61 -11
  264. package/dist/tour/wait.d.ts +11 -0
  265. package/dist/tour/wait.js +19 -0
  266. package/dist/tree/item/tree-item.d.ts +21 -5
  267. package/dist/tree/item/tree-item.js +14 -4
  268. package/dist/tree/root/tree-root.d.ts +29 -5
  269. package/dist/tree/root/tree-root.js +64 -8
  270. package/dist/trend/root/trend-root.d.ts +36 -1
  271. package/dist/trend/root/trend-root.js +41 -15
  272. package/dist/video/root/keys.d.ts +5 -0
  273. package/dist/video/root/keys.js +13 -1
  274. package/dist/video/root/video-root.d.ts +19 -0
  275. package/dist/video/root/video-root.js +48 -4
  276. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  277. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  278. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  279. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  280. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  281. package/lint.json +1 -1
  282. package/package.json +5 -5
  283. package/types/jsx.d.ts +9140 -1149
  284. package/types/svelte.d.ts +1 -0
  285. package/types/vue.d.ts +2089 -267
@@ -0,0 +1,37 @@
1
+ import type { HelixIcon } from '@fusion.dev/helix-icons';
2
+ /** What a library gives for a name: a glyph, a glyph later, or nothing. */
3
+ export type IconResolver = (name: string) => HelixIcon | Promise<HelixIcon | undefined> | undefined;
4
+ /**
5
+ * Makes glyphs resolvable by name: a record of names to glyphs, such as the
6
+ * whole set, or a list of glyphs, each under its own `name`.
7
+ *
8
+ * A name registered again takes the newer glyph.
9
+ */
10
+ export declare const registerIcons: (glyphs: Record<string, HelixIcon> | readonly HelixIcon[]) => void;
11
+ /**
12
+ * Resolves names written `prefix:name` through a library of your own, such as
13
+ * another icon set or glyphs fetched from a server.
14
+ *
15
+ * The resolver may answer at once or with a promise; an element waiting on a
16
+ * promise draws the glyph when it arrives and fires `load`. Each written name
17
+ * is asked once, and a prefix registered again is asked afresh.
18
+ */
19
+ export declare const registerIconLibrary: (prefix: string, resolve: IconResolver) => void;
20
+ /**
21
+ * Calls `watcher` whenever a glyph or a library is registered, so an element
22
+ * drawn before its glyph was registered can look again. Returns the function
23
+ * that stops it.
24
+ */
25
+ export declare const watchIcons: (watcher: () => void) => (() => void);
26
+ /** The registered glyph of this name, or `undefined`. */
27
+ export declare const registeredIcon: (name: string) => HelixIcon | undefined;
28
+ /**
29
+ * The glyph for a name: a registered one at once, or what the library its
30
+ * prefix names gives, which may be a promise. `undefined` where nothing
31
+ * answers.
32
+ *
33
+ * A registered name wins over a library, so a page can override one glyph of
34
+ * a library by registering it under the same written name. A library that
35
+ * fails answers nothing.
36
+ */
37
+ export declare const resolveIcon: (name: string) => HelixIcon | Promise<HelixIcon | undefined> | undefined;
@@ -0,0 +1,83 @@
1
+ const KEY = Symbol.for('helix.icon-registry');
2
+ const changed = (held) => {
3
+ for (const watcher of held.watchers) {
4
+ watcher();
5
+ }
6
+ };
7
+ const registry = () => {
8
+ const held = globalThis;
9
+ let found = held[KEY];
10
+ if (!found) {
11
+ found = { answers: new Map(), glyphs: new Map(), libraries: new Map(), watchers: new Set() };
12
+ held[KEY] = found;
13
+ }
14
+ return found;
15
+ };
16
+ export const registerIcons = (glyphs) => {
17
+ const held = registry();
18
+ const into = held.glyphs;
19
+ const entries = Array.isArray(glyphs)
20
+ ? glyphs.map((glyph) => [glyph.name, glyph])
21
+ : Object.entries(glyphs);
22
+ for (const [name, glyph] of entries) {
23
+ into.set(name, glyph);
24
+ }
25
+ changed(held);
26
+ };
27
+ export const registerIconLibrary = (prefix, resolve) => {
28
+ const held = registry();
29
+ held.libraries.set(prefix, resolve);
30
+ for (const name of held.answers.keys()) {
31
+ if (name.startsWith(`${prefix}:`)) {
32
+ held.answers.delete(name);
33
+ }
34
+ }
35
+ changed(held);
36
+ };
37
+ export const watchIcons = (watcher) => {
38
+ const held = registry();
39
+ held.watchers.add(watcher);
40
+ return () => {
41
+ held.watchers.delete(watcher);
42
+ };
43
+ };
44
+ export const registeredIcon = (name) => registry().glyphs.get(name);
45
+ export const resolveIcon = (name) => {
46
+ const registered = registeredIcon(name);
47
+ if (registered || name === '') {
48
+ return registered;
49
+ }
50
+ const split = name.indexOf(':');
51
+ if (split <= 0) {
52
+ return undefined;
53
+ }
54
+ const held = registry();
55
+ if (held.answers.has(name)) {
56
+ return held.answers.get(name);
57
+ }
58
+ const library = held.libraries.get(name.slice(0, split));
59
+ if (!library) {
60
+ return undefined;
61
+ }
62
+ const answer = asked(library, name.slice(split + 1));
63
+ if (answer instanceof Promise) {
64
+ const settled = answer.then((glyph) => glyph, () => undefined);
65
+ held.answers.set(name, settled);
66
+ void settled.then((glyph) => {
67
+ if (held.answers.get(name) === settled) {
68
+ held.answers.set(name, glyph);
69
+ }
70
+ });
71
+ return settled;
72
+ }
73
+ held.answers.set(name, answer);
74
+ return answer;
75
+ };
76
+ const asked = (library, name) => {
77
+ try {
78
+ return library(name);
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ };
@@ -1,6 +1,6 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type HelixIcon } from '@fusion.dev/helix-icons';
3
- import { nothing, type TemplateResult } from 'lit';
2
+ import type { HelixIcon } from '@fusion.dev/helix-icons';
3
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
4
4
  /**
5
5
  * @summary A named icon from the Helix set.
6
6
  *
@@ -18,11 +18,22 @@ import { nothing, type TemplateResult } from 'lit';
18
18
  * a dark background. Shapes that set their own `fill` or `stroke` are
19
19
  * unaffected.
20
20
  *
21
- * A name with no match renders nothing.
21
+ * **A name is looked up in a registry.** The family's entry registers the
22
+ * whole set, so any name in it draws. The element's own entry,
23
+ * `@fusion.dev/helix-headless/icon/root`, registers none: a page that imports
24
+ * it and calls `registerIcons` with the glyphs it names ships those and no
25
+ * others. `registerIconLibrary` resolves names under a prefix of your own,
26
+ * such as `lucide:camera`, at once or later, and the element fires `load` when
27
+ * a glyph that came later is drawn. A glyph registered after the element
28
+ * rendered is drawn then.
29
+ *
30
+ * A name with no match renders nothing, and the element fires `error`, so a
31
+ * typo in a name can be heard.
22
32
  *
23
33
  * An icon is decorative by default and hidden from assistive technology. Set
24
34
  * `label` only when the icon is the only carrier of meaning, such as in a
25
- * button with no text.
35
+ * button with no text. An `aria-label` on the element works too: the element
36
+ * is then an image with that name.
26
37
  *
27
38
  * @since 0.1.0
28
39
  * @status stable
@@ -30,6 +41,9 @@ import { nothing, type TemplateResult } from 'lit';
30
41
  * @aliases Glyph, Symbol
31
42
  * @documentation https://fusion.dev/helix/components/icon
32
43
  *
44
+ * @event {Event} error - `name` matches no registered icon and no library answers it, so nothing is drawn.
45
+ * @event {Event} load - A glyph a library gave later for `name` is drawn.
46
+ *
33
47
  * @csspart svg - The rendered SVG.
34
48
  */
35
49
  export declare class HelixHeadlessIcon extends HelixElement {
@@ -69,10 +83,43 @@ export declare class HelixHeadlessIcon extends HelixElement {
69
83
  * so it is what markup can carry, and resolving one means an index of the
70
84
  * whole set that no bundler can shake: 15 kB for a consumer who renders one
71
85
  * mark. An attribute is the only thing an HTML author can write, and that is
72
- * worth the index; a consumer who would rather not pay it hands over the
73
- * value instead.
86
+ * worth the index; a consumer who would rather not pay it imports the
87
+ * element from `icon/root` and registers the glyphs it names, or hands over
88
+ * the value instead.
89
+ *
90
+ * A name written `prefix:name` asks the library registered under that
91
+ * prefix.
74
92
  */
75
93
  name: string;
94
+ /**
95
+ * Hears an `aria-label` written on the element, which no property mirrors.
96
+ *
97
+ * Lit observes the attributes of its own properties only, and `ariaLabel`
98
+ * belongs to the platform.
99
+ */
100
+ static get observedAttributes(): string[];
101
+ /**
102
+ * Called by the browser when an observed attribute changes. A new
103
+ * `aria-label` asks for an update, because the element takes the image role
104
+ * while one names it.
105
+ */
106
+ attributeChangedCallback(name: string, old: string | null, value: string | null): void;
107
+ /** The name the last `error` was fired for, so it fires once per name. */
108
+ private missed;
109
+ /** The glyph this render draws, from `icon` or the registry. */
110
+ private drawn;
111
+ /** A library is still answering for `name`, so it is not missing yet. */
112
+ private waiting;
113
+ /** The name whose late glyph arrived and has not been announced with `load`. */
114
+ private arrived;
115
+ /** Stops listening to the registry. */
116
+ private unwatch;
117
+ connectedCallback(): void;
118
+ disconnectedCallback(): void;
119
+ /** What the registry gives for `name` now, starting the wait for a late glyph. */
120
+ private lookup;
121
+ protected willUpdate(changed: PropertyValues): void;
122
+ protected updated(changed: PropertyValues): void;
76
123
  protected render(): TemplateResult | typeof nothing;
77
124
  }
78
125
  declare global {
@@ -4,21 +4,89 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
- import { icons } from '@fusion.dev/helix-icons';
7
+ import { customElement, HelixElement, hostAria, reportRuntime } from '@fusion.dev/helix-core';
9
8
  import { html, nothing } from 'lit';
10
9
  import { property } from 'lit/decorators.js';
11
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
11
+ import { resolveIcon, watchIcons } from '../registry.js';
12
12
  let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.label = '';
16
16
  this.mirror = false;
17
17
  this.name = '';
18
+ this.missed = '';
19
+ this.waiting = false;
20
+ this.arrived = '';
21
+ }
22
+ static get observedAttributes() {
23
+ return [...super.observedAttributes, 'aria-label'];
24
+ }
25
+ attributeChangedCallback(name, old, value) {
26
+ super.attributeChangedCallback(name, old, value);
27
+ if (name === 'aria-label') {
28
+ this.requestUpdate();
29
+ }
30
+ }
31
+ connectedCallback() {
32
+ super.connectedCallback();
33
+ this.unwatch = watchIcons(() => {
34
+ if (this.icon === undefined && this.name !== '') {
35
+ this.requestUpdate();
36
+ }
37
+ });
38
+ }
39
+ disconnectedCallback() {
40
+ super.disconnectedCallback();
41
+ this.unwatch?.();
42
+ this.unwatch = undefined;
43
+ }
44
+ lookup() {
45
+ const found = this.name === '' ? undefined : resolveIcon(this.name);
46
+ this.waiting = found instanceof Promise;
47
+ if (!(found instanceof Promise)) {
48
+ return found;
49
+ }
50
+ const name = this.name;
51
+ void found.then(() => {
52
+ if (this.name === name && this.isConnected) {
53
+ this.arrived = name;
54
+ this.requestUpdate();
55
+ }
56
+ });
57
+ return undefined;
58
+ }
59
+ willUpdate(changed) {
60
+ super.willUpdate(changed);
61
+ const named = this.label === '' && (this.getAttribute?.('aria-label') ?? '') !== '';
62
+ hostAria(this.internals, { role: named ? 'img' : '' });
63
+ this.drawn = this.icon ?? this.lookup();
64
+ }
65
+ updated(changed) {
66
+ super.updated(changed);
67
+ if (this.arrived === this.name && this.drawn !== undefined) {
68
+ this.dispatchEvent(new Event('load', { bubbles: false, cancelable: false, composed: false }));
69
+ }
70
+ this.arrived = '';
71
+ if (this.drawn === undefined && this.name !== '' && !this.waiting) {
72
+ if (this.missed !== this.name) {
73
+ this.missed = this.name;
74
+ this.dispatchEvent(new Event('error', { bubbles: false, cancelable: false, composed: false }));
75
+ reportRuntime({
76
+ kind: 'unknown-icon',
77
+ message: `<${this.localName} name="${this.name}"> names no registered icon, so it draws ` +
78
+ 'nothing. Check the name, register the glyph with `registerIcons`, or import it ' +
79
+ 'and pass it as `icon`.',
80
+ tag: this.localName,
81
+ });
82
+ }
83
+ }
84
+ else {
85
+ this.missed = '';
86
+ }
18
87
  }
19
88
  render() {
20
- const named = Object.hasOwn(icons, this.name) ? icons[this.name] : undefined;
21
- const icon = this.icon ?? named;
89
+ const icon = this.drawn;
22
90
  if (!icon) {
23
91
  return nothing;
24
92
  }
@@ -0,0 +1,2 @@
1
+ export { type IconResolver, registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
2
+ export * from './icon-root.js';
@@ -0,0 +1,2 @@
1
+ export { registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
2
+ export * from './icon-root.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { icons } from '@fusion.dev/helix-icons';
2
+ import { registerIcons } from './registry.js';
3
+ registerIcons(icons);
@@ -25,7 +25,7 @@ import { HelixHeadlessButton } from '../../button/root/button-root.js';
25
25
  *
26
26
  * @slot - The icon.
27
27
  *
28
- * @csspart button - The inner button or anchor.
28
+ * @csspart button - The inner button.
29
29
  */
30
30
  export declare class HelixHeadlessIconButton extends HelixHeadlessButton {
31
31
  }
@@ -27,15 +27,20 @@ import { type PropertyValues, type TemplateResult } from 'lit';
27
27
  * @csspart fallback - The fallback, shown when the image fails to load.
28
28
  * @csspart image - The image itself.
29
29
  * @csspart placeholder - The placeholder, shown until the image loads.
30
+ *
31
+ * @cssstate error - The image failed to load, and the fallback shows.
32
+ * @cssstate loaded - The image loaded.
30
33
  */
31
34
  export declare class HelixHeadlessImage extends HelixElement {
32
35
  /**
33
36
  * A text description of the image, read by screen readers.
34
37
  *
35
38
  * Empty is a real answer and means decoration. Omitting the attribute is not
36
- * the same thing: a reader with nothing to read announces the file name.
39
+ * the same thing: the inner image is then written with no `alt` either, as a
40
+ * native one would be, so a screen reader announces the file name and an
41
+ * accessibility checker reports the missing description.
37
42
  */
38
- alt: string;
43
+ alt?: string;
39
44
  /**
40
45
  * How the image is fetched across origins. It decides whether a canvas can
41
46
  * read the image.
@@ -69,6 +74,14 @@ export declare class HelixHeadlessImage extends HelixElement {
69
74
  * that is not is the exception worth writing down.
70
75
  */
71
76
  loading?: 'eager' | 'lazy';
77
+ /**
78
+ * How long, in milliseconds, the placeholder waits before it shows.
79
+ *
80
+ * Absent or `0` shows it at once. A picture that arrives inside
81
+ * the wait never shows a placeholder at all, so a cached or fast image does
82
+ * not flash one. Radix's `delayMs` on its avatar fallback is the same idea.
83
+ */
84
+ placeholderDelay: number;
72
85
  /**
73
86
  * How much of the referring URL to send with the request.
74
87
  */
@@ -110,6 +123,8 @@ export declare class HelixHeadlessImage extends HelixElement {
110
123
  * Which `src` the current status belongs to, so a new one starts over.
111
124
  */
112
125
  private answered;
126
+ /** The placeholder's wait for this `src`, and whether it is over. */
127
+ private readonly wait;
113
128
  /**
114
129
  * Whether this picture's answer has been given, or is on its way.
115
130
  *
@@ -117,6 +132,11 @@ export declare class HelixHeadlessImage extends HelixElement {
117
132
  * for the event it reports, and `settle` runs twice in the first update.
118
133
  */
119
134
  private reported;
135
+ /**
136
+ * The event `settle` sent for a picture that finished before anything
137
+ * listened, so the platform's own, still on its way, is not sent again.
138
+ */
139
+ private synthesized;
120
140
  /**
121
141
  * Says so under the platform's own name, because the platform's cannot escape.
122
142
  *
@@ -170,6 +190,7 @@ export declare class HelixHeadlessImage extends HelixElement {
170
190
  private settle;
171
191
  protected willUpdate(changed: PropertyValues): void;
172
192
  protected updated(changed: PropertyValues): void;
193
+ private startWait;
173
194
  protected firstUpdated(changed: PropertyValues): void;
174
195
  /**
175
196
  * The picture's own state, under the platform's own names.
@@ -4,23 +4,25 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement } from '@fusion.dev/helix-core';
7
+ import { customElement, DelayController, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
- this.alt = '';
14
13
  this.crossOrigin = null;
15
14
  this.decoding = 'async';
16
15
  this.fetchPriority = 'auto';
16
+ this.placeholderDelay = 0;
17
17
  this.referrerPolicy = '';
18
18
  this.sizes = '';
19
19
  this.src = '';
20
20
  this.srcset = '';
21
21
  this.status = 'loading';
22
22
  this.answered = '';
23
+ this.wait = new DelayController(this);
23
24
  this.reported = false;
25
+ this.synthesized = undefined;
24
26
  this.handleLoad = (event) => {
25
27
  this.announce('loaded', event);
26
28
  };
@@ -32,10 +34,15 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
32
34
  this.reported = true;
33
35
  const name = status === 'loaded' ? 'load' : 'error';
34
36
  if (event) {
37
+ if (this.synthesized === name) {
38
+ this.synthesized = undefined;
39
+ return;
40
+ }
35
41
  this.status = status;
36
42
  this.relayNativeEvent(event);
37
43
  return;
38
44
  }
45
+ this.synthesized = name;
39
46
  const send = () => {
40
47
  this.status = status;
41
48
  this.dispatchEvent(new Event(name, { bubbles: false, cancelable: false, composed: false }));
@@ -64,6 +71,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
64
71
  if (changed.has('src') && this.answered !== this.src) {
65
72
  this.answered = this.src;
66
73
  this.reported = false;
74
+ this.synthesized = undefined;
67
75
  this.status = 'loading';
68
76
  }
69
77
  }
@@ -72,6 +80,9 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
72
80
  if (changed.has('src')) {
73
81
  this.settle();
74
82
  }
83
+ if (changed.has('src') || changed.has('placeholderDelay')) {
84
+ this.startWait();
85
+ }
75
86
  if (changed.has('status')) {
76
87
  if (this.status === 'loading') {
77
88
  this.removeAttribute('data-status');
@@ -79,8 +90,13 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
79
90
  else {
80
91
  this.setAttribute('data-status', this.status);
81
92
  }
93
+ this.toggleState('loaded', this.status === 'loaded');
94
+ this.toggleState('error', this.status === 'error');
82
95
  }
83
96
  }
97
+ startWait() {
98
+ this.wait.start(this.placeholderDelay > 0 ? this.placeholderDelay : undefined);
99
+ }
84
100
  firstUpdated(changed) {
85
101
  super.firstUpdated?.(changed);
86
102
  this.settle();
@@ -103,7 +119,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
103
119
  render() {
104
120
  return html `<img
105
121
  part="image"
106
- alt=${this.alt}
122
+ alt=${this.alt ?? nothing}
107
123
  loading=${this.loading ?? 'lazy'}
108
124
  decoding=${this.decoding}
109
125
  crossorigin=${this.crossOrigin ?? nothing}
@@ -118,7 +134,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
118
134
  <span
119
135
  part="placeholder"
120
136
  aria-hidden="true"
121
- ?hidden=${this.status !== 'loading'}
137
+ ?hidden=${this.status !== 'loading' || (this.placeholderDelay > 0 && !this.wait.elapsed)}
122
138
  ><slot name="placeholder"></slot
123
139
  ></span>
124
140
  <span
@@ -144,6 +160,9 @@ __decorate([
144
160
  __decorate([
145
161
  property({ reflect: true })
146
162
  ], HelixHeadlessImage.prototype, "loading", void 0);
163
+ __decorate([
164
+ property({ attribute: 'placeholder-delay', type: Number })
165
+ ], HelixHeadlessImage.prototype, "placeholderDelay", void 0);
147
166
  __decorate([
148
167
  property({ attribute: 'referrerpolicy' })
149
168
  ], HelixHeadlessImage.prototype, "referrerPolicy", void 0);
@@ -29,10 +29,14 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
29
29
  * @documentation https://fusion.dev/helix/components/input
30
30
  *
31
31
  * @slot end - After the text, for an icon or a unit.
32
+ * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
33
+ * @slot hint - Help under the control, for content richer than the `hint` text.
34
+ * @slot label - The label, for content richer than the `label` text.
32
35
  * @slot start - Before the text, for an icon or a prefix.
33
36
  *
34
37
  * @event {Event} change - Sent when the user finishes changing the value. Relayed from the native input.
35
38
  * @event {HelixBeforeChangeEvent} helix-before-change - The text is about to change. Cancelable: cancel it to keep the current text.
39
+ * @event {Event} helix-clear - Fired after the clear button has emptied the field, after `input` and `change`.
36
40
  * @event {Event} input - Fired as the value changes.
37
41
  *
38
42
  * @csspart clear - The button that empties the field.
@@ -50,6 +54,11 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
50
54
  protected readonly aria: AriaForwardController;
51
55
  /** Typed or dragged, so every edit is announced. See `announcesInput`. */
52
56
  protected readonly announcesInput = true;
57
+ /**
58
+ * Whether a phone capitalizes as the reader types: `off`, `sentences`,
59
+ * `words` or `characters`, as the platform's `autocapitalize`.
60
+ */
61
+ autocapitalize: string;
53
62
  /**
54
63
  * What the browser may autofill in the field, as an HTML `autocomplete`
55
64
  * token.
@@ -71,10 +80,30 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
71
80
  * The accessible name of the clear button, which shows only an icon.
72
81
  */
73
82
  clearLabel: string;
83
+ /**
84
+ * The key the on-screen keyboard shows for Enter, as the platform's
85
+ * `enterkeyhint`: `search`, `send`, `go`, `next`, `previous`, `done` or
86
+ * `enter`.
87
+ */
88
+ enterKeyHint: string;
89
+ /**
90
+ * The keyboard a phone offers, as the platform's `inputmode`, such as
91
+ * `numeric` for a code typed as text.
92
+ */
93
+ inputMode: string;
94
+ /**
95
+ * The greatest value, for `type="number"`. Number Input adds steppers and
96
+ * keys to the same bounds.
97
+ */
98
+ max: string;
74
99
  /**
75
100
  * Most characters the value may have.
76
101
  */
77
102
  maxLength?: number;
103
+ /**
104
+ * The least value, for `type="number"`.
105
+ */
106
+ min: string;
78
107
  /**
79
108
  * Fewest characters the value may have.
80
109
  */
@@ -106,6 +135,15 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
106
135
  * form, `readOnly` came back `false`.
107
136
  */
108
137
  readOnly: boolean;
138
+ /**
139
+ * Whether a password field offers a toggle that shows what was typed.
140
+ *
141
+ * Ignored on every other type. A reveal on an email field would be a button
142
+ * that does nothing visible, and guarding it here rather than asking the
143
+ * consumer not to means the property can be set once on a component that
144
+ * changes type.
145
+ */
146
+ reveal: boolean;
109
147
  /**
110
148
  * Whether the password is currently showing.
111
149
  *
@@ -181,6 +219,15 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
181
219
  * where it was.
182
220
  */
183
221
  private readonly handleClear;
222
+ /**
223
+ * Enter submits the form, as it does in a native text field.
224
+ *
225
+ * On `keypress`, where the platform runs its own implicit submission, so a
226
+ * consumer who prevents the `keydown` for Enter stops this too.
227
+ */
228
+ private readonly handleKeypress;
229
+ /** @internal A single line of text counts against implicit submission. */
230
+ protected get blocksImplicitSubmission(): boolean;
184
231
  /** Relayed, because `change` does not cross a shadow boundary on its own. */
185
232
  private readonly handleChange;
186
233
  /** Reports the value and the validity the host stands behind. */
@@ -189,6 +236,16 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
189
236
  focus(options?: FocusOptions): void;
190
237
  /** Selects everything in the field. */
191
238
  select(): void;
239
+ /**
240
+ * Moves a number, a date or a time up by `step`, `count` times, as the native
241
+ * method does. It sends no event, as the native method sends none, and it
242
+ * throws `InvalidStateError` on a type with no step, such as `text`.
243
+ */
244
+ stepUp(count?: number): void;
245
+ /** Moves a number, a date or a time down by `step`, `count` times. See `stepUp`. */
246
+ stepDown(count?: number): void;
247
+ /** Takes the native control's answer, which knows `min`, `max` and `step`. */
248
+ private takeStep;
192
249
  /**
193
250
  * The caret, held across a value the consumer wrote rather than the reader.
194
251
  *
@@ -198,21 +255,17 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
198
255
  private releaseCaret;
199
256
  protected willUpdate(changed: PropertyValues): void;
200
257
  protected updated(changed: PropertyValues): void;
201
- /**
202
- * Whether a password field offers a toggle that shows what was typed.
203
- *
204
- * Ignored on every other type. A reveal on an email field would be a button
205
- * that does nothing visible, and guarding it here rather than asking the
206
- * consumer not to means the property can be set once on a component that
207
- * changes type.
208
- */
209
- reveal: boolean;
210
258
  /**
211
259
  * The accessible name of the reveal toggle.
212
260
  *
213
261
  * The state is `aria-pressed`, not this.
214
262
  */
215
263
  revealLabel: string;
264
+ /**
265
+ * The step a valid value is a multiple of, counted from `min`, for
266
+ * `type="number"`.
267
+ */
268
+ step: string;
216
269
  /**
217
270
  * The kind of text the field accepts. It sets the on-screen keyboard and the
218
271
  * validation.