@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
@@ -4,10 +4,11 @@ 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, fillTemplate, formatNumbers, HelixActivateEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, } from '@fusion.dev/helix-core';
7
+ import { customElement, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeChangeEvent, HelixBeforeToggleEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { buildings, cloudRain, dotsNine, leaf, mountains, path, polygon, stack, target, } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
+ import { live } from 'lit/directives/live.js';
11
12
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
13
  const MAP_TYPES = ['standard', 'hybrid', 'satellite'];
13
14
  const iconOf = (layer) => {
@@ -205,10 +206,37 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
205
206
  : this.standardLabel;
206
207
  }
207
208
  showLayers(layers, shown) {
208
- for (const layer of layers) {
209
- layer.hidden = !shown;
209
+ const first = layers[0];
210
+ if (!first) {
211
+ return;
212
+ }
213
+ requestChange({
214
+ apply: () => {
215
+ for (const layer of layers) {
216
+ layer.hidden = !shown;
217
+ }
218
+ this.requestUpdate();
219
+ },
220
+ event: (checked) => new HelixBeforeToggleEvent({ checked }),
221
+ host: first,
222
+ next: shown,
223
+ });
224
+ }
225
+ chooseMapType(type) {
226
+ const applied = requestChange({
227
+ apply: (value) => {
228
+ this.mapType = value === 'standard' ? undefined : value;
229
+ },
230
+ event: (value) => new HelixBeforeChangeEvent({ value }),
231
+ host: this,
232
+ next: type,
233
+ });
234
+ if (applied) {
235
+ this.dispatchEvent(new Event('change', { bubbles: true }));
236
+ }
237
+ else {
238
+ this.requestUpdate();
210
239
  }
211
- this.requestUpdate();
212
240
  }
213
241
  get layerEntries() {
214
242
  const entries = [];
@@ -382,9 +410,10 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
382
410
  <input
383
411
  type="radio"
384
412
  name="map-type"
385
- .checked=${chosen === type}
386
- @change=${() => {
387
- this.mapType = type === 'standard' ? undefined : type;
413
+ .checked=${live(chosen === type)}
414
+ @change=${(event) => {
415
+ event.stopPropagation();
416
+ this.chooseMapType(type);
388
417
  }}
389
418
  />
390
419
  ${preview
@@ -31,7 +31,7 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
31
31
  *
32
32
  * @event {HelixBeforeCloseEvent} helix-before-close - The panel is about to close. Cancelable.
33
33
  * @event {HelixBeforeOpenEvent} helix-before-open - The panel is about to open. Cancelable.
34
- * @event {Event} toggle - The panel opened or closed. Carries `newState` and `oldState`.
34
+ * @event {ToggleEvent} toggle - The panel opened or closed. Carries `newState` and `oldState`.
35
35
  *
36
36
  * @csspart surface - The floating panel that opens.
37
37
  * @csspart trigger - The default trigger button, shown when the `trigger` slot is empty.
@@ -194,6 +194,15 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
194
194
  private readonly handlePointerDown;
195
195
  private readonly handlePointerEnter;
196
196
  private readonly handlePointerLeave;
197
+ /**
198
+ * Closes the panel when keyboard focus leaves it for the page.
199
+ *
200
+ * Only when focus went somewhere: a `relatedTarget` of null is focus leaving
201
+ * the document, such as a switch to another window, and a reader who comes
202
+ * back expects the panel as they left it. `requestOpen` rather than `close`,
203
+ * because focus has already gone where the reader sent it.
204
+ */
205
+ private readonly handleFocusOut;
197
206
  private readonly handleTriggerClick;
198
207
  /**
199
208
  * Shuts the panel when a reader takes one of the destinations in it.
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessMegamenu_1;
8
- import { anchorElement, customElement, HelixElement, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
8
+ import { anchorElement, customElement, deepContains, HelixElement, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  let showing;
@@ -57,6 +57,13 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
57
57
  this.requestOpen(false);
58
58
  });
59
59
  };
60
+ this.handleFocusOut = (event) => {
61
+ const next = event.relatedTarget;
62
+ if (!this.open || next === null || deepContains(this, next)) {
63
+ return;
64
+ }
65
+ this.requestOpen(false);
66
+ };
60
67
  this.handleTriggerClick = (event) => {
61
68
  this.stop();
62
69
  if (this.openOn !== 'hover') {
@@ -154,6 +161,7 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
154
161
  this.addEventListener('click', this.handleContentClick);
155
162
  this.addEventListener('pointerenter', this.handlePointerEnter);
156
163
  this.addEventListener('pointerleave', this.handlePointerLeave);
164
+ this.addEventListener('focusout', this.handleFocusOut);
157
165
  }
158
166
  disconnectedCallback() {
159
167
  super.disconnectedCallback();
@@ -164,6 +172,7 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
164
172
  this.removeEventListener('click', this.handleContentClick);
165
173
  this.removeEventListener('pointerenter', this.handlePointerEnter);
166
174
  this.removeEventListener('pointerleave', this.handlePointerLeave);
175
+ this.removeEventListener('focusout', this.handleFocusOut);
167
176
  this.stop();
168
177
  if (showing === this) {
169
178
  showing = undefined;
@@ -14,6 +14,11 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
14
14
  * only one can be on. A row that opens a page keeps `menuitem` and sets
15
15
  * `aria-haspopup`.
16
16
  *
17
+ * Choosing a choice row checks or unchecks it before `helix-select` is sent,
18
+ * so a listener reads the new `checked`. An `exclusive` row turns on and turns
19
+ * off the `exclusive` rows next to it. Cancel `helix-before-toggle` to keep a
20
+ * row as it is and set `checked` yourself.
21
+ *
17
22
  * The menu sets whether the row's page is showing as a property, never as an
18
23
  * attribute. An attribute written onto your element after it upgrades causes a
19
24
  * hydration mismatch.
@@ -27,12 +32,15 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
27
32
  * @slot start - Content before the label, such as an icon.
28
33
  * @slot submenu - The rows of a submenu that this row opens.
29
34
  *
35
+ * @event {HelixBeforeToggleEvent} helix-before-toggle - A choice row is about to be checked or unchecked, carrying the state asked for. Cancelable: cancel it to keep the row as it is.
30
36
  * @event {HelixSelectEvent} helix-select - The row was chosen. Cancelable: cancel it to keep the menu open.
31
37
  *
32
38
  * @csspart item - The row, which is an `<a>` where `href` is set.
33
39
  * @csspart mark - The trailing mark: a check mark when the row is checked, or a caret
34
40
  * when it opens a submenu. A row never shows both, so they share one column.
35
41
  * @csspart start - The leading column that holds the `start` slot. It is always rendered.
42
+ *
43
+ * @cssstate checked - The row is checked.
36
44
  */
37
45
  export declare class HelixHeadlessMenuItem extends HelixElement {
38
46
  /**
@@ -45,10 +53,16 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
45
53
  * thing they are not.
46
54
  *
47
55
  * `checked` implies it, so a row that is on never has to say both.
56
+ *
57
+ * Choosing the row checks or unchecks it, after a `helix-before-toggle` that
58
+ * you can cancel.
48
59
  */
49
60
  checkable: boolean;
50
61
  /**
51
62
  * Whether the row is checked.
63
+ *
64
+ * The row changes it when it is chosen. Not reflected: the attribute is the
65
+ * state you start the row in, and `:state(checked)` carries the current one.
52
66
  */
53
67
  checked: boolean;
54
68
  /**
@@ -66,11 +80,11 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
66
80
  /**
67
81
  * Whether only one row in its set can be checked at a time.
68
82
  *
69
- * Announcement and nothing else, the way `checkable` is: this element applies
70
- * no choice and polices no group, so what it does is tell a reader which kind
71
- * of set they are in. `menuitemcheckbox` says every row here is independent,
72
- * which for a run of comparisons, or the values of a filter that compares
73
- * against one, is the opposite of true.
83
+ * The set is the run of `exclusive` rows next to this one, up to the first
84
+ * element that is not one, such as a divider. Choosing a row in it checks
85
+ * that row and unchecks the others. Choosing the row that is checked leaves
86
+ * it checked. `menuitemradio` tells a reader which kind of set they are in,
87
+ * where `menuitemcheckbox` says every row is independent.
74
88
  *
75
89
  * Meaningless without `checkable`, since a row that cannot be ticked is not
76
90
  * one of a set of anything.
@@ -225,16 +239,31 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
225
239
  /** Chooses the row, the same as pressing it. */
226
240
  select(): void;
227
241
  /**
228
- * Whether the row has focus, which is what selected means in a menu.
242
+ * Whether the row has focus, which makes it the row the keyboard is on.
243
+ *
244
+ * `Option` calls the same thing `active`. A menu holds no answer the way a
245
+ * radio group does, only a row the reader has walked to, so focus is the
246
+ * whole of what "the current one" can mean here. Read from the shadow root
247
+ * rather than kept as state, because focus moves for reasons this element is
248
+ * not told about: a press, a Tab, the drilldown putting the reader on the
249
+ * first row of a page it has just opened.
250
+ */
251
+ get active(): boolean;
252
+ /**
253
+ * Whether the row has focus, the same as `active`.
229
254
  *
230
- * A radio group's selection is an answer it holds; a menu has no answer, only
231
- * a row the reader has walked to, so focus is the whole of what "the current
232
- * one" can mean here. Read from the shadow root rather than kept as state,
233
- * because focus moves for reasons this element is not told about: a press, a
234
- * Tab, the drilldown putting the reader on the first row of a page it has
235
- * just opened.
255
+ * @deprecated Read `active`. Everywhere else in the library `selected` means
256
+ * chosen out of a set, and a menu row is never chosen that way.
236
257
  */
237
258
  get selected(): boolean;
259
+ /**
260
+ * Checks or unchecks a choice row.
261
+ *
262
+ * An `exclusive` row only turns on, and turning on turns its set off.
263
+ */
264
+ private tick;
265
+ /** The other `exclusive` rows in this row's run of siblings. */
266
+ private exclusivePeers;
238
267
  private choose;
239
268
  private readonly handleClick;
240
269
  /**
@@ -4,7 +4,7 @@ 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, HelixSelectEvent } from '@fusion.dev/helix-core';
7
+ import { customElement, deepActiveElement, HelixBeforeToggleEvent, HelixElement, HelixSelectEvent, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { caretRight, check } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -58,6 +58,7 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
58
58
  }
59
59
  willUpdate(changed) {
60
60
  super.willUpdate(changed);
61
+ this.toggleState('checked', this.checked);
61
62
  if (!this.childrenKnown) {
62
63
  return;
63
64
  }
@@ -78,13 +79,55 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
78
79
  select() {
79
80
  this.choose();
80
81
  }
82
+ get active() {
83
+ const active = deepActiveElement();
84
+ return active !== null && active.getRootNode() === this.renderRoot;
85
+ }
81
86
  get selected() {
82
- return this.ownerDocument.activeElement === this;
87
+ return this.active;
88
+ }
89
+ tick() {
90
+ if (!(this.checkable || this.checked) || this.hasSubmenu) {
91
+ return;
92
+ }
93
+ const next = this.exclusive ? true : !this.checked;
94
+ if (next === this.checked) {
95
+ return;
96
+ }
97
+ const applied = requestChange({
98
+ apply: (checked) => {
99
+ this.checked = checked;
100
+ },
101
+ event: (checked) => new HelixBeforeToggleEvent({ checked }),
102
+ host: this,
103
+ next,
104
+ });
105
+ if (applied && this.exclusive) {
106
+ for (const peer of this.exclusivePeers()) {
107
+ peer.checked = false;
108
+ }
109
+ }
110
+ }
111
+ exclusivePeers() {
112
+ const peers = [];
113
+ const inSet = (node) => node !== null &&
114
+ node.isMenuItem === true &&
115
+ node.exclusive &&
116
+ node.slot === this.slot;
117
+ for (const step of ['previousElementSibling', 'nextElementSibling']) {
118
+ let node = this[step];
119
+ while (inSet(node)) {
120
+ peers.push(node);
121
+ node = node[step];
122
+ }
123
+ }
124
+ return peers;
83
125
  }
84
126
  choose() {
85
127
  if (this.disabled) {
86
128
  return;
87
129
  }
130
+ this.tick();
88
131
  this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
89
132
  }
90
133
  render() {
@@ -155,7 +198,7 @@ __decorate([
155
198
  property({ reflect: true, type: Boolean })
156
199
  ], HelixHeadlessMenuItem.prototype, "checkable", void 0);
157
200
  __decorate([
158
- property({ reflect: true, type: Boolean })
201
+ property({ type: Boolean })
159
202
  ], HelixHeadlessMenuItem.prototype, "checked", void 0);
160
203
  __decorate([
161
204
  property({ reflect: true, type: Boolean })
@@ -1,4 +1,4 @@
1
- import { HelixElement, KeyboardNavigationController, type Placement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement, KeyboardNavigationController, type Placement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
4
4
  /**
@@ -9,6 +9,12 @@ declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.d
9
9
  * menu renders its surface in the top layer with the popover API, so an
10
10
  * ancestor with `overflow: hidden` does not clip it and it needs no `z-index`.
11
11
  *
12
+ * Slot a `helix-button` or `helix-icon-button` as the trigger, and the menu
13
+ * tells it that it opens a menu and whether the menu is open. A plain
14
+ * `<button>` can only be told by writing attributes onto your markup, which
15
+ * the menu does not do, so give it `aria-haspopup="menu"` and set its
16
+ * `aria-expanded` from the `toggle` event.
17
+ *
12
18
  * Submenus drill down. A submenu replaces the panel's content, and a back row
13
19
  * returns to the previous page. One panel avoids the diagonal pointer path that
14
20
  * side-by-side panels need, stays inside a narrow window, and works on touch
@@ -30,7 +36,7 @@ declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.d
30
36
  * @event {HelixBeforeCloseEvent} helix-before-close - The menu is about to close. Cancelable: cancel it to keep it open.
31
37
  * @event {HelixBeforeOpenEvent} helix-before-open - The menu is about to open. Cancelable: cancel it to keep it closed.
32
38
  * @event {HelixSelectEvent} helix-select - An item was chosen. Cancelable: cancel it to keep the menu open.
33
- * @event {Event} toggle - The menu opened or closed. The event carries `newState` and `oldState`.
39
+ * @event {ToggleEvent} toggle - The menu opened or closed. The event carries `newState` and `oldState`.
34
40
  *
35
41
  * @csspart back - The control that returns from a submenu.
36
42
  * @csspart back-mark - The glyph on the back control of a submenu.
@@ -53,6 +59,10 @@ export declare class HelixHeadlessMenu extends HelixHeadlessMenu_base {
53
59
  backLabel: string;
54
60
  /**
55
61
  * Accessible name for the surface.
62
+ *
63
+ * Empty by default, which names the surface by its trigger, so a menu opened
64
+ * from "Actions" is announced as "Actions". An `aria-label` or
65
+ * `aria-labelledby` on the host names it too, and wins over both.
56
66
  */
57
67
  label: string;
58
68
  /**
@@ -92,6 +102,8 @@ export declare class HelixHeadlessMenu extends HelixHeadlessMenu_base {
92
102
  * menu that drills, so those keys are spoken for here rather than unhandled.
93
103
  */
94
104
  protected readonly keys: KeyboardNavigationController;
105
+ /** Carries a host `aria-label` and `aria-labelledby` to the surface. */
106
+ protected readonly aria: AriaForwardController;
95
107
  private readonly panel;
96
108
  /**
97
109
  * Tells a slotted trigger the disclosure state, by property.
@@ -108,6 +120,8 @@ export declare class HelixHeadlessMenu extends HelixHeadlessMenu_base {
108
120
  private get items();
109
121
  /** Opens the menu. */
110
122
  show(): void;
123
+ /** Opens the menu with focus on its first or its last row. */
124
+ private openAt;
111
125
  /** Closes the menu and returns it to its first page. */
112
126
  hide(): void;
113
127
  /** Shows an item's submenu in place of the current page. */
@@ -124,10 +138,26 @@ export declare class HelixHeadlessMenu extends HelixHeadlessMenu_base {
124
138
  */
125
139
  private readonly handleFocusIn;
126
140
  private readonly handleKeydown;
141
+ /**
142
+ * Down and Up on the trigger open the menu on its first and its last row.
143
+ *
144
+ * Everything else passes through. Escape in particular is not this element's
145
+ * while the menu is closed, so a dialog around the menu still closes on it.
146
+ */
147
+ private handleClosedKeydown;
127
148
  private readonly handleTriggerClick;
128
149
  connectedCallback(): void;
129
150
  disconnectedCallback(): void;
130
151
  protected updated(changed: PropertyValues): void;
152
+ /**
153
+ * Names the surface by its trigger, where nothing else names it.
154
+ *
155
+ * By element reference, which is the one direction that crosses: the surface
156
+ * is in this shadow root and the trigger is in the tree around it. A host
157
+ * `aria-labelledby` is carried down by `aria`, and a host `aria-label` or
158
+ * `label` is a name of its own, so each of them clears this reference.
159
+ */
160
+ private nameSurface;
131
161
  /**
132
162
  * Says whether the page showing reserves a column either side of its labels.
133
163
  *
@@ -4,7 +4,7 @@ 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 { anchorElement, customElement, DrilldownController, HelixElement, inlineStep, KeyboardNavigationController, MixinCollection, MixinControllerOpen, PopoverController, scrollItemIntoView, tellDisclosure, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, anchorElement, customElement, DrilldownController, deepActiveElement, deepContains, HelixElement, inlineStep, KeyboardNavigationController, MixinCollection, MixinControllerOpen, PopoverController, scrollItemIntoView, slottedWords, tellDisclosure, } from '@fusion.dev/helix-core';
8
8
  import { caretLeft } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -13,7 +13,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.backLabel = 'Back';
16
- this.label = 'Menu';
16
+ this.label = '';
17
17
  this.offset = 4;
18
18
  this.placement = 'bottom-start';
19
19
  this.drilldown = new DrilldownController(this, {
@@ -22,9 +22,14 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
22
22
  slot: 'submenu',
23
23
  });
24
24
  this.keys = new KeyboardNavigationController(this, {
25
- items: () => this.items,
25
+ items: () => (this.open ? this.items : []),
26
26
  reserved: () => ['ArrowLeft', 'ArrowRight'],
27
27
  selects: () => false,
28
+ typeahead: (item) => slottedWords(item, ['']),
29
+ });
30
+ this.aria = new AriaForwardController(this, {
31
+ label: true,
32
+ target: () => this.partNamed('surface'),
28
33
  });
29
34
  this.panel = new PopoverController(this, {
30
35
  anchor: () => this.trigger,
@@ -61,8 +66,12 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
61
66
  scrollItemIntoView(item, { padding: 4, ...(surface ? { scroller: surface } : {}) });
62
67
  };
63
68
  this.handleKeydown = (event) => {
69
+ if (!this.open) {
70
+ this.handleClosedKeydown(event);
71
+ return;
72
+ }
64
73
  const items = this.items;
65
- const at = items.indexOf(document.activeElement);
74
+ const at = items.findIndex((item) => item.active);
66
75
  const along = inlineStep(this, event.key);
67
76
  if (event.key === 'Escape') {
68
77
  event.stopPropagation();
@@ -94,7 +103,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
94
103
  }
95
104
  tellTrigger() {
96
105
  const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
97
- tellDisclosure(slot?.assignedElements({ flatten: false })[0], this.open, 'menu');
106
+ tellDisclosure(slot?.assignedElements({ flatten: true })[0], this.open, 'menu');
98
107
  }
99
108
  get trigger() {
100
109
  return anchorElement(this.renderRoot?.querySelector('slot[name="trigger"]'), this);
@@ -103,11 +112,15 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
103
112
  return this.drilldown.rows.filter((row) => !row.disabled);
104
113
  }
105
114
  show() {
115
+ this.openAt('first');
116
+ }
117
+ openAt(end) {
106
118
  if (this.open || !this.requestOpen(true)) {
107
119
  return;
108
120
  }
109
121
  this.updateComplete.then(() => {
110
- this.items[0]?.focus();
122
+ const items = this.items;
123
+ (end === 'first' ? items[0] : items[items.length - 1])?.focus();
111
124
  });
112
125
  }
113
126
  hide() {
@@ -116,7 +129,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
116
129
  }
117
130
  this.panel.hide();
118
131
  this.drilldown.reset();
119
- if (this.contains(document.activeElement)) {
132
+ if (deepContains(this, deepActiveElement())) {
120
133
  this.trigger.focus();
121
134
  }
122
135
  }
@@ -135,6 +148,18 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
135
148
  this.drilldown.back();
136
149
  this.updateComplete.then(() => leaving?.focus());
137
150
  }
151
+ handleClosedKeydown(event) {
152
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') {
153
+ return;
154
+ }
155
+ const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
156
+ const triggers = slot?.assignedElements({ flatten: true }) ?? [];
157
+ if (!event.composedPath().some((node) => triggers.includes(node))) {
158
+ return;
159
+ }
160
+ event.preventDefault();
161
+ this.openAt(event.key === 'ArrowDown' ? 'first' : 'last');
162
+ }
138
163
  connectedCallback() {
139
164
  super.connectedCallback();
140
165
  this.addEventListener('helix-select', this.handleSelect, true);
@@ -159,6 +184,21 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
159
184
  }
160
185
  this.toggleState('drilled', !this.drilldown.atRoot);
161
186
  this.markColumns();
187
+ this.nameSurface();
188
+ }
189
+ nameSurface() {
190
+ const surface = this.partNamed('surface');
191
+ if (!surface || !('ariaLabelledByElements' in surface)) {
192
+ return;
193
+ }
194
+ if (this.hasAttribute('aria-labelledby')) {
195
+ return;
196
+ }
197
+ const trigger = this.renderRoot
198
+ ?.querySelector('slot[name="trigger"]')
199
+ ?.assignedElements({ flatten: true })[0];
200
+ const named = this.label !== '' || this.hasAttribute('aria-label');
201
+ surface.ariaLabelledByElements = trigger && !named ? [trigger] : null;
162
202
  }
163
203
  markColumns() {
164
204
  const rows = this.drilldown.rows;
@@ -183,7 +223,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
183
223
  popover="manual"
184
224
  role="menu"
185
225
  aria-busy=${this.loading ? 'true' : nothing}
186
- aria-label=${this.label}
226
+ aria-label=${this.label || nothing}
187
227
  data-drilled=${this.drilldown.atRoot ? nothing : ''}
188
228
  ?hidden=${!this.open}
189
229
  >
@@ -22,6 +22,8 @@ export type MeterBand = 'fair' | 'good' | 'poor';
22
22
  * @aliases Gauge, Level, Capacity
23
23
  * @documentation https://fusion.dev/helix/components/meter
24
24
  *
25
+ * @slot label - A visible label. Its words name the meter in place of `label`.
26
+ *
25
27
  * @csspart groove - The unfilled circle, in `ring` and `arc`.
26
28
  * @csspart indicator - The part of the track the value fills.
27
29
  * @csspart indicator-fair - The fill while the reading is in a band next to the good band. Set alongside `indicator`.
@@ -77,8 +79,17 @@ export declare class HelixHeadlessMeter extends HelixElement {
77
79
  high?: number;
78
80
  /**
79
81
  * Accessible name for the reading.
82
+ *
83
+ * A visible label in the `label` slot names it instead, with the words it
84
+ * shows, so the name and the label cannot disagree.
80
85
  */
81
86
  label: string;
87
+ /**
88
+ * The locale the percentage is written in, such as `fr` for `72 %`.
89
+ *
90
+ * Absent uses the runtime's own.
91
+ */
92
+ locale: string;
82
93
  /**
83
94
  * Top of the low band.
84
95
  *
@@ -212,6 +223,8 @@ export declare class HelixHeadlessMeter extends HelixElement {
212
223
  * where the arc starts.
213
224
  */
214
225
  private renderRound;
226
+ /** A label's words changed, so the name is written again. */
227
+ private readonly renamed;
215
228
  protected render(): TemplateResult;
216
229
  }
217
230
  declare global {
@@ -4,18 +4,34 @@ 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, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, hostAria, slottedWords } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ const percents = new Map();
11
+ const percent = (share, locale) => {
12
+ let format = percents.get(locale);
13
+ if (!format) {
14
+ format = new Intl.NumberFormat(locale || undefined, {
15
+ maximumFractionDigits: 0,
16
+ style: 'percent',
17
+ });
18
+ percents.set(locale, format);
19
+ }
20
+ return format.format(share);
21
+ };
10
22
  let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
11
23
  constructor() {
12
24
  super(...arguments);
13
25
  this.label = 'Meter';
26
+ this.locale = '';
14
27
  this.max = 100;
15
28
  this.min = 0;
16
29
  this.showValue = false;
17
30
  this.value = 0;
18
31
  this.valueText = '';
32
+ this.renamed = () => {
33
+ this.requestUpdate();
34
+ };
19
35
  }
20
36
  get span() {
21
37
  const min = Number.isFinite(this.min) ? this.min : 0;
@@ -64,17 +80,17 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
64
80
  return distance === 0 ? 'good' : distance === 1 ? 'fair' : 'poor';
65
81
  }
66
82
  get text() {
67
- return this.valueText || `${Math.round(this.ratio * 100)}%`;
83
+ return this.valueText || percent(this.ratio, this.locale);
68
84
  }
69
85
  willUpdate(changed) {
70
86
  super.willUpdate(changed);
71
87
  const { max, min } = this.span;
72
- hostAria(this.internals, { label: this.label, role: 'meter' });
88
+ hostAria(this.internals, { label: slottedWords(this, ['label']) || this.label, role: 'meter' });
73
89
  this.internals.ariaValueMin = String(min);
74
90
  this.internals.ariaValueMax = String(max);
75
91
  this.internals.ariaValueNow = String(this.reading);
76
92
  this.internals.ariaValueText =
77
- this.valueText || (this.beyond ? `${Math.round(this.ratio * 100)}%` : null);
93
+ this.valueText || (this.beyond ? percent(this.ratio, this.locale) : null);
78
94
  }
79
95
  renderRound() {
80
96
  const bounds = this.thresholds;
@@ -108,7 +124,7 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
108
124
  const beyond = this.beyond;
109
125
  const { max, min } = this.span;
110
126
  const at = (value) => `${((value - min) / (max - min)) * 100}%`;
111
- return html `${this.shape
127
+ return html `<slot name="label" @slotchange=${this.renamed}></slot>${this.shape
112
128
  ? this.renderRound()
113
129
  : html `<div part="track">
114
130
  ${bounds
@@ -134,6 +150,9 @@ __decorate([
134
150
  __decorate([
135
151
  property()
136
152
  ], HelixHeadlessMeter.prototype, "label", void 0);
153
+ __decorate([
154
+ property()
155
+ ], HelixHeadlessMeter.prototype, "locale", void 0);
137
156
  __decorate([
138
157
  property({ type: Number })
139
158
  ], HelixHeadlessMeter.prototype, "low", void 0);