@fusion.dev/helix-headless 0.147.0 → 0.149.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 (296) hide show
  1. package/custom-elements.json +11222 -2332
  2. package/dist/accordion/item/accordion-item.d.ts +5 -2
  3. package/dist/accordion/item/accordion-item.js +11 -7
  4. package/dist/accordion/root/accordion-root.js +4 -6
  5. package/dist/announcement/root/announcement-root.d.ts +61 -5
  6. package/dist/announcement/root/announcement-root.js +126 -20
  7. package/dist/area-chart/root/area-chart-root.d.ts +11 -0
  8. package/dist/area-chart/root/area-chart-root.js +21 -9
  9. package/dist/avatar/group/avatar-group.d.ts +10 -2
  10. package/dist/avatar/group/avatar-group.js +10 -5
  11. package/dist/badge/count.d.ts +19 -0
  12. package/dist/badge/count.js +20 -0
  13. package/dist/badge/root/badge-root.d.ts +6 -2
  14. package/dist/badge/root/badge-root.js +8 -22
  15. package/dist/bar-chart/root/bar-chart-root.d.ts +13 -1
  16. package/dist/bar-chart/root/bar-chart-root.js +17 -4
  17. package/dist/blockquote/root/blockquote-root.d.ts +66 -8
  18. package/dist/blockquote/root/blockquote-root.js +85 -8
  19. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +2 -2
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +8 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +5 -2
  22. package/dist/button/root/button-root.d.ts +10 -1
  23. package/dist/button/root/button-root.js +3 -2
  24. package/dist/button-group/arrows.d.ts +14 -0
  25. package/dist/button-group/arrows.js +10 -0
  26. package/dist/button-group/root/button-group-root.d.ts +144 -3
  27. package/dist/button-group/root/button-group-root.js +142 -2
  28. package/dist/callout/root/callout-root.d.ts +16 -2
  29. package/dist/callout/root/callout-root.js +16 -4
  30. package/dist/canvas/describe.d.ts +10 -0
  31. package/dist/canvas/describe.js +9 -0
  32. package/dist/canvas/edge-pan.d.ts +61 -0
  33. package/dist/canvas/edge-pan.js +63 -0
  34. package/dist/canvas/neighbor.d.ts +17 -0
  35. package/dist/canvas/neighbor.js +1 -0
  36. package/dist/canvas/node/canvas-node.d.ts +12 -2
  37. package/dist/canvas/node/canvas-node.js +8 -3
  38. package/dist/canvas/root/canvas-document.d.ts +10 -0
  39. package/dist/canvas/root/canvas-document.js +1 -0
  40. package/dist/canvas/root/canvas-root.d.ts +168 -9
  41. package/dist/canvas/root/canvas-root.js +239 -69
  42. package/dist/canvas/snap.d.ts +42 -0
  43. package/dist/canvas/snap.js +32 -0
  44. package/dist/carousel/root/carousel-root.d.ts +9 -3
  45. package/dist/carousel/root/carousel-root.js +17 -10
  46. package/dist/chat/composer/chat-composer.d.ts +5 -0
  47. package/dist/chat/composer/chat-composer.js +4 -1
  48. package/dist/chat/message/chat-message.d.ts +9 -5
  49. package/dist/chat/message/chat-message.js +8 -4
  50. package/dist/chat/naming.js +2 -2
  51. package/dist/chat/root/chat-root.d.ts +40 -4
  52. package/dist/chat/root/chat-root.js +38 -14
  53. package/dist/checkbox/root/checkbox-root.d.ts +11 -0
  54. package/dist/checkbox/root/checkbox-root.js +8 -2
  55. package/dist/checkbox-group/root/checkbox-group-root.d.ts +24 -0
  56. package/dist/checkbox-group/root/checkbox-group-root.js +28 -12
  57. package/dist/checkbox-group/select-all.d.ts +11 -0
  58. package/dist/checkbox-group/select-all.js +5 -0
  59. package/dist/code-block/root/code-block-root.d.ts +20 -8
  60. package/dist/code-block/root/code-block-root.js +16 -5
  61. package/dist/color-input/root/color-input-root.d.ts +13 -0
  62. package/dist/color-input/root/color-input-root.js +18 -5
  63. package/dist/color-picker/root/color-picker-root.d.ts +19 -3
  64. package/dist/color-picker/root/color-picker-root.js +52 -24
  65. package/dist/color-picker/wheel.d.ts +11 -0
  66. package/dist/color-picker/wheel.js +9 -0
  67. package/dist/combobox/root/combobox-root.d.ts +106 -18
  68. package/dist/combobox/root/combobox-root.js +101 -26
  69. package/dist/command/root/command-root.d.ts +19 -9
  70. package/dist/command/root/command-root.js +9 -4
  71. package/dist/copy-button/root/copy-button-root.d.ts +5 -0
  72. package/dist/copy-button/root/copy-button-root.js +7 -2
  73. package/dist/data-table/root/data-table-root.d.ts +171 -29
  74. package/dist/data-table/root/data-table-root.js +284 -161
  75. package/dist/date-input/root/date-input-root.d.ts +32 -9
  76. package/dist/date-input/root/date-input-root.js +66 -44
  77. package/dist/date-picker/root/date-picker-root.d.ts +38 -15
  78. package/dist/date-picker/root/date-picker-root.js +52 -33
  79. package/dist/description-list/item/description-list-item.d.ts +4 -0
  80. package/dist/description-list/item/description-list-item.js +7 -1
  81. package/dist/dialog/root/dialog-root.d.ts +12 -1
  82. package/dist/dialog/root/dialog-root.js +11 -4
  83. package/dist/divider/root/divider-root.d.ts +45 -16
  84. package/dist/divider/root/divider-root.js +28 -4
  85. package/dist/donut-chart/root/donut-chart-root.d.ts +5 -0
  86. package/dist/donut-chart/root/donut-chart-root.js +8 -5
  87. package/dist/drawer/root/drawer-root.d.ts +12 -1
  88. package/dist/drawer/root/drawer-root.js +9 -2
  89. package/dist/drilldown/item/drilldown-item.js +3 -4
  90. package/dist/drilldown/root/drilldown-root.d.ts +5 -0
  91. package/dist/drilldown/root/drilldown-root.js +4 -1
  92. package/dist/element-events.generated.js +26 -3
  93. package/dist/empty/root/empty-root.d.ts +17 -3
  94. package/dist/empty/root/empty-root.js +29 -5
  95. package/dist/file-input/root/file-input-root.d.ts +18 -3
  96. package/dist/file-input/root/file-input-root.js +34 -18
  97. package/dist/file-input/status.js +2 -1
  98. package/dist/filter-input/chip/filter-chip.d.ts +13 -0
  99. package/dist/filter-input/chip/filter-chip.js +7 -3
  100. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  101. package/dist/filter-input/menu/filter-menu.js +3 -1
  102. package/dist/filter-input/root/filter-input-root.d.ts +20 -3
  103. package/dist/filter-input/root/filter-input-root.js +8 -4
  104. package/dist/format-date/fields.d.ts +20 -0
  105. package/dist/format-date/fields.js +14 -0
  106. package/dist/format-date/options.d.ts +2 -1
  107. package/dist/format-date/options.js +9 -38
  108. package/dist/format-date/root/format-date-root.d.ts +55 -5
  109. package/dist/format-date/root/format-date-root.js +29 -34
  110. package/dist/graph/root/graph-model.d.ts +11 -0
  111. package/dist/graph/root/graph-model.js +4 -0
  112. package/dist/graph/root/graph-root.d.ts +101 -14
  113. package/dist/graph/root/graph-root.js +140 -46
  114. package/dist/heatmap/root/heatmap-root.d.ts +37 -4
  115. package/dist/heatmap/root/heatmap-root.js +51 -16
  116. package/dist/icon-button/root/icon-button-root.d.ts +5 -0
  117. package/dist/icon-button/root/icon-button-root.js +1 -0
  118. package/dist/image/root/image-root.d.ts +11 -0
  119. package/dist/input/root/input-root.d.ts +5 -0
  120. package/dist/input/root/input-root.js +4 -1
  121. package/dist/kbd/root/kbd-root.js +1 -2
  122. package/dist/legend/root/legend-root.js +4 -17
  123. package/dist/lightbox/root/lightbox-root.d.ts +14 -4
  124. package/dist/lightbox/root/lightbox-root.js +25 -7
  125. package/dist/line-chart/root/line-chart-root.d.ts +5 -0
  126. package/dist/line-chart/root/line-chart-root.js +4 -2
  127. package/dist/list/item/list-item.d.ts +32 -0
  128. package/dist/list/item/list-item.js +34 -7
  129. package/dist/list/root/list-root.d.ts +87 -0
  130. package/dist/list/root/list-root.js +119 -23
  131. package/dist/listbox/reorder/index.d.ts +1 -0
  132. package/dist/listbox/reorder/index.js +4 -0
  133. package/dist/listbox/reorder/listbox-reorder.d.ts +83 -0
  134. package/dist/listbox/reorder/listbox-reorder.js +151 -0
  135. package/dist/listbox/root/listbox-root.d.ts +185 -33
  136. package/dist/listbox/root/listbox-root.js +166 -136
  137. package/dist/loader/root/loader-root.d.ts +5 -0
  138. package/dist/loader/root/loader-root.js +3 -1
  139. package/dist/map/area/map-area.d.ts +5 -0
  140. package/dist/map/area/map-area.js +3 -1
  141. package/dist/map/buildings/map-buildings.d.ts +5 -0
  142. package/dist/map/buildings/map-buildings.js +3 -1
  143. package/dist/map/contours/map-contours.d.ts +5 -0
  144. package/dist/map/contours/map-contours.js +3 -1
  145. package/dist/map/landcover/map-landcover.d.ts +5 -0
  146. package/dist/map/landcover/map-landcover.js +3 -1
  147. package/dist/map/marker/map-marker.d.ts +18 -2
  148. package/dist/map/marker/map-marker.js +13 -5
  149. package/dist/map/points/map-points.d.ts +5 -0
  150. package/dist/map/points/map-points.js +6 -4
  151. package/dist/map/position/map-position.d.ts +5 -0
  152. package/dist/map/position/map-position.js +3 -1
  153. package/dist/map/raster/map-raster.d.ts +5 -0
  154. package/dist/map/raster/map-raster.js +3 -1
  155. package/dist/map/root/map-root.d.ts +73 -16
  156. package/dist/map/root/map-root.js +122 -44
  157. package/dist/map/route/map-route.d.ts +5 -0
  158. package/dist/map/route/map-route.js +3 -1
  159. package/dist/map/terrain/map-terrain.d.ts +5 -0
  160. package/dist/map/terrain/map-terrain.js +3 -1
  161. package/dist/megamenu/root/megamenu-root.js +4 -11
  162. package/dist/menu/root/menu-root.d.ts +7 -2
  163. package/dist/menu/root/menu-root.js +3 -1
  164. package/dist/meter/root/meter-root.d.ts +16 -3
  165. package/dist/meter/root/meter-root.js +12 -5
  166. package/dist/navigation/root/navigation-root.d.ts +5 -0
  167. package/dist/navigation/root/navigation-root.js +7 -8
  168. package/dist/notifications/group/notification-group.d.ts +8 -1
  169. package/dist/notifications/group/notification-group.js +12 -6
  170. package/dist/notifications/notification/notification.d.ts +17 -1
  171. package/dist/notifications/notification/notification.js +6 -2
  172. package/dist/notifications/root/notifications-root.d.ts +49 -5
  173. package/dist/notifications/root/notifications-root.js +36 -8
  174. package/dist/number-input/root/number-input-root.d.ts +21 -8
  175. package/dist/number-input/root/number-input-root.js +26 -11
  176. package/dist/object-inspector/root/object-inspector-root.d.ts +56 -13
  177. package/dist/object-inspector/root/object-inspector-root.js +41 -30
  178. package/dist/outline/root/outline-root.d.ts +5 -0
  179. package/dist/outline/root/outline-root.js +3 -1
  180. package/dist/pagination/root/pagination-root.d.ts +7 -1
  181. package/dist/pagination/root/pagination-root.js +16 -7
  182. package/dist/pagination/size/pagination-size.d.ts +8 -3
  183. package/dist/pagination/size/pagination-size.js +5 -3
  184. package/dist/pagination/summary/pagination-summary.d.ts +8 -6
  185. package/dist/pagination/summary/pagination-summary.js +4 -9
  186. package/dist/pin-input/code.d.ts +23 -0
  187. package/dist/pin-input/code.js +21 -0
  188. package/dist/pin-input/root/pin-input-root.d.ts +9 -3
  189. package/dist/pin-input/root/pin-input-root.js +13 -23
  190. package/dist/popover/root/popover-root.d.ts +12 -2
  191. package/dist/popover/root/popover-root.js +10 -4
  192. package/dist/progress/root/progress-root.d.ts +7 -2
  193. package/dist/progress/root/progress-root.js +5 -2
  194. package/dist/qr-code/name.d.ts +3 -2
  195. package/dist/qr-code/name.js +2 -2
  196. package/dist/qr-code/root/qr-code-root.d.ts +26 -5
  197. package/dist/qr-code/root/qr-code-root.js +27 -6
  198. package/dist/radio/group/radio-group.d.ts +11 -0
  199. package/dist/radio/group/radio-group.js +8 -2
  200. package/dist/rating/root/rating-root.d.ts +12 -1
  201. package/dist/rating/root/rating-root.js +10 -3
  202. package/dist/scatter-chart/measures.d.ts +22 -0
  203. package/dist/scatter-chart/measures.js +11 -0
  204. package/dist/scatter-chart/root/scatter-chart-root.d.ts +22 -8
  205. package/dist/scatter-chart/root/scatter-chart-root.js +25 -23
  206. package/dist/select/root/select-root.d.ts +67 -8
  207. package/dist/select/root/select-root.js +45 -11
  208. package/dist/skip-link/root/skip-link-root.d.ts +5 -0
  209. package/dist/skip-link/root/skip-link-root.js +3 -1
  210. package/dist/slider/root/slider-root.d.ts +7 -2
  211. package/dist/slider/root/slider-root.js +11 -5
  212. package/dist/sparkline/readings.d.ts +15 -5
  213. package/dist/sparkline/readings.js +3 -3
  214. package/dist/sparkline/root/sparkline-root.d.ts +9 -4
  215. package/dist/sparkline/root/sparkline-root.js +9 -3
  216. package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
  217. package/dist/speed-dial/group/speed-dial-group.js +43 -0
  218. package/dist/speed-dial/index.d.ts +1 -0
  219. package/dist/speed-dial/index.js +1 -0
  220. package/dist/speed-dial/item/speed-dial-item.d.ts +26 -1
  221. package/dist/speed-dial/item/speed-dial-item.js +41 -3
  222. package/dist/speed-dial/long-press.d.ts +50 -0
  223. package/dist/speed-dial/long-press.js +48 -0
  224. package/dist/speed-dial/root/speed-dial-root.d.ts +85 -1
  225. package/dist/speed-dial/root/speed-dial-root.js +117 -5
  226. package/dist/splitter/root/splitter-root.d.ts +12 -3
  227. package/dist/splitter/root/splitter-root.js +22 -4
  228. package/dist/steps/root/steps-root.d.ts +9 -2
  229. package/dist/steps/root/steps-root.js +6 -3
  230. package/dist/steps/step/step.d.ts +12 -0
  231. package/dist/steps/step/step.js +11 -2
  232. package/dist/switch/root/switch-root.d.ts +11 -0
  233. package/dist/switch/root/switch-root.js +8 -2
  234. package/dist/table/cell/table-cell.d.ts +8 -1
  235. package/dist/table/cell/table-cell.js +6 -2
  236. package/dist/table/column/table-column.d.ts +11 -4
  237. package/dist/table/column/table-column.js +15 -10
  238. package/dist/table/grid-controller.d.ts +122 -0
  239. package/dist/table/grid-controller.js +299 -0
  240. package/dist/table/root/table-root.d.ts +154 -8
  241. package/dist/table/root/table-root.js +197 -38
  242. package/dist/table/row/table-row.d.ts +55 -1
  243. package/dist/table/row/table-row.js +60 -7
  244. package/dist/tabs/root/tabs-root.d.ts +5 -0
  245. package/dist/tabs/root/tabs-root.js +3 -1
  246. package/dist/tag/group/tag-group.d.ts +5 -0
  247. package/dist/tag/group/tag-group.js +8 -15
  248. package/dist/tag/root/tag-root.d.ts +14 -1
  249. package/dist/tag/root/tag-root.js +11 -8
  250. package/dist/textarea/root/textarea-root.d.ts +5 -0
  251. package/dist/textarea/root/textarea-root.js +3 -1
  252. package/dist/time-input/root/time-input-root.d.ts +14 -7
  253. package/dist/time-input/root/time-input-root.js +43 -32
  254. package/dist/time-picker/root/time-picker-root.d.ts +16 -7
  255. package/dist/time-picker/root/time-picker-root.js +28 -12
  256. package/dist/toast/item/toast-item.d.ts +13 -3
  257. package/dist/toast/item/toast-item.js +2 -0
  258. package/dist/toast/root/toast-root.d.ts +22 -2
  259. package/dist/toast/root/toast-root.js +24 -17
  260. package/dist/toggle/group/toggle-group.js +3 -5
  261. package/dist/toolbar/root/toolbar-root.d.ts +36 -0
  262. package/dist/toolbar/root/toolbar-root.js +43 -9
  263. package/dist/tooltip/root/tooltip-root.d.ts +27 -17
  264. package/dist/tooltip/root/tooltip-root.js +1 -2
  265. package/dist/tour/root/tour-root.d.ts +8 -2
  266. package/dist/tour/root/tour-root.js +4 -2
  267. package/dist/tour/stop/tour-stop.d.ts +5 -0
  268. package/dist/tour/stop/tour-stop.js +6 -1
  269. package/dist/tree/grip.d.ts +5 -0
  270. package/dist/tree/grip.js +1 -0
  271. package/dist/tree/item/tree-item.d.ts +24 -0
  272. package/dist/tree/item/tree-item.js +27 -5
  273. package/dist/tree/root/tree-root.d.ts +66 -1
  274. package/dist/tree/root/tree-root.js +77 -5
  275. package/dist/trend/root/trend-root.d.ts +20 -4
  276. package/dist/trend/root/trend-root.js +20 -5
  277. package/dist/video/root/video-root.d.ts +23 -3
  278. package/dist/video/root/video-root.js +56 -15
  279. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  280. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  281. package/dist/video-playlist/root/video-playlist-root.d.ts +5 -0
  282. package/dist/video-playlist/root/video-playlist-root.js +3 -1
  283. package/dist/virtual-list/root/virtual-list-root.d.ts +19 -3
  284. package/dist/virtual-list/root/virtual-list-root.js +10 -19
  285. package/lint.json +1 -1
  286. package/package.json +7 -6
  287. package/types/jsx.d.ts +6005 -2114
  288. package/types/svelte.d.ts +1 -0
  289. package/types/vue.d.ts +1594 -676
  290. package/types/words.d.ts +3280 -0
  291. package/dist/kbd/keys.d.ts +0 -29
  292. package/dist/kbd/keys.js +0 -52
  293. package/dist/toast/hotkey.d.ts +0 -22
  294. package/dist/toast/hotkey.js +0 -23
  295. package/dist/tooltip/focus-target.d.ts +0 -6
  296. package/dist/tooltip/focus-target.js +0 -9
@@ -4,15 +4,21 @@ 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, deepActiveElement, HelixElement, HelixSelectEvent, } from '@fusion.dev/helix-core';
7
+ import { ariaChord, chordParts, customElement, deepActiveElement, HelixElement, HelixSelectEvent, keyNames, onApple, reportRuntime, slotFilled, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
- import { property } from 'lit/decorators.js';
9
+ import { property, state } from 'lit/decorators.js';
10
+ let toldSelected = false;
10
11
  let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixElement {
11
12
  constructor() {
12
13
  super(...arguments);
13
14
  this.disabled = false;
15
+ this.shortcut = '';
14
16
  this.value = '';
15
17
  this.isSpeedDialItem = true;
18
+ this.hasShortcut = false;
19
+ this.readShortcut = () => {
20
+ this.hasShortcut = slotFilled(this.renderRoot.querySelector('slot[name="shortcut"]'));
21
+ };
16
22
  this.handleClick = () => {
17
23
  this.choose();
18
24
  };
@@ -31,6 +37,14 @@ let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixE
31
37
  return active !== null && active.getRootNode() === this.renderRoot;
32
38
  }
33
39
  get selected() {
40
+ if (!toldSelected) {
41
+ toldSelected = true;
42
+ reportRuntime({
43
+ kind: 'deprecated',
44
+ message: `<${this.localName}>.selected is deprecated: read \`active\`, which says the same.`,
45
+ tag: this.localName,
46
+ });
47
+ }
34
48
  return this.active;
35
49
  }
36
50
  choose() {
@@ -40,26 +54,50 @@ let HelixHeadlessSpeedDialItem = class HelixHeadlessSpeedDialItem extends HelixE
40
54
  this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
41
55
  }
42
56
  render() {
57
+ const keys = this.shortcut === '' ? nothing : ariaChord(this.shortcut, !this.hydrating && onApple());
43
58
  return html `<button
44
59
  part="item"
45
60
  role="menuitem"
46
61
  type="button"
47
62
  aria-disabled=${this.disabled ? 'true' : nothing}
63
+ aria-keyshortcuts=${keys}
48
64
  ?disabled=${this.disabled}
49
65
  tabindex="-1"
50
66
  @click=${this.handleClick}
51
67
  >
52
68
  <span part="icon"><slot name="icon"></slot></span>
53
- <span part="label"><slot></slot></span>
69
+ <span part="label"><slot></slot><span
70
+ part="shortcut"
71
+ aria-hidden="true"
72
+ ?hidden=${!this.hasShortcut && this.shortcut === ''}
73
+ >${this.renderShortcut()}</span
74
+ ></span>
54
75
  </button>`;
55
76
  }
77
+ renderShortcut() {
78
+ const drawn = keyNames(chordParts(this.shortcut), !this.hydrating && onApple());
79
+ return html `<slot name="shortcut" @slotchange=${this.readShortcut}>${drawn.keys.join(drawn.separator)}</slot>`;
80
+ }
81
+ firstUpdated(changed) {
82
+ super.firstUpdated(changed);
83
+ this.readShortcut();
84
+ if (this.shortcut !== '') {
85
+ this.finishHydration();
86
+ }
87
+ }
56
88
  };
57
89
  __decorate([
58
90
  property({ reflect: true, type: Boolean })
59
91
  ], HelixHeadlessSpeedDialItem.prototype, "disabled", void 0);
92
+ __decorate([
93
+ property()
94
+ ], HelixHeadlessSpeedDialItem.prototype, "shortcut", void 0);
60
95
  __decorate([
61
96
  property()
62
97
  ], HelixHeadlessSpeedDialItem.prototype, "value", void 0);
98
+ __decorate([
99
+ state()
100
+ ], HelixHeadlessSpeedDialItem.prototype, "hasShortcut", void 0);
63
101
  HelixHeadlessSpeedDialItem = __decorate([
64
102
  customElement('helix-headless-speed-dial-item')
65
103
  ], HelixHeadlessSpeedDialItem);
@@ -0,0 +1,50 @@
1
+ import type { ReactiveControllerHost } from 'lit';
2
+ /** How long a press is held before it counts, in milliseconds, as React Aria waits. */
3
+ export declare const LONG_PRESS_DELAY = 500;
4
+ /**
5
+ * How far a held pointer may drift and still be the same press, in pixels. A
6
+ * finger is never still, and one that moves further is scrolling or dragging.
7
+ */
8
+ export declare const LONG_PRESS_SLOP = 10;
9
+ /** What a long press reads and calls. */
10
+ export interface LongPressOptions {
11
+ /** Called once a press has been held for the delay without drifting. */
12
+ onLongPress: () => void;
13
+ }
14
+ /**
15
+ * Watches one control's presses for a held one.
16
+ *
17
+ * The control's own handlers call `down`, `move` and `up`, so a press counts
18
+ * only where it started on the control, and `cancel` drops it. The click a
19
+ * held press ends in is the long press's, and `takeClick` says so once, so the
20
+ * control's own action does not run as well.
21
+ */
22
+ export declare class LongPress {
23
+ private readonly options;
24
+ private readonly wait;
25
+ /** Where the press began, while one is held and still counts. */
26
+ private from;
27
+ /** Whether the press that just ended was a long one, until its click is taken. */
28
+ private held;
29
+ constructor(host: ReactiveControllerHost, options: LongPressOptions);
30
+ /** Starts the wait for a press of the primary button. */
31
+ down(event: PointerEvent): void;
32
+ /** Drops the press once the pointer drifts past the slop. */
33
+ move(event: PointerEvent): void;
34
+ /**
35
+ * Ends the press. A press released before the delay is an ordinary one.
36
+ *
37
+ * A held one keeps its claim on a click only until the task ends: the click
38
+ * a release makes comes in the same task, and a release that makes none, off
39
+ * the control or after a touch's own menu, must not leave the next Enter on
40
+ * the control swallowed.
41
+ */
42
+ up(): void;
43
+ /** Drops the press, which then neither opens anything nor swallows a click. */
44
+ cancel(): void;
45
+ /**
46
+ * Whether a click belongs to the long press that just ended, and so is not
47
+ * the control's. True once.
48
+ */
49
+ takeClick(): boolean;
50
+ }
@@ -0,0 +1,48 @@
1
+ import { DelayController } from '@fusion.dev/helix-core';
2
+ export const LONG_PRESS_DELAY = 500;
3
+ export const LONG_PRESS_SLOP = 10;
4
+ export class LongPress {
5
+ constructor(host, options) {
6
+ this.options = options;
7
+ this.from = undefined;
8
+ this.held = false;
9
+ this.wait = new DelayController(host);
10
+ }
11
+ down(event) {
12
+ this.held = false;
13
+ if (event.button !== 0) {
14
+ return;
15
+ }
16
+ this.from = { x: event.clientX, y: event.clientY };
17
+ this.wait.start(LONG_PRESS_DELAY, () => {
18
+ this.from = undefined;
19
+ this.held = true;
20
+ this.options.onLongPress();
21
+ });
22
+ }
23
+ move(event) {
24
+ const from = this.from;
25
+ if (from && Math.hypot(event.clientX - from.x, event.clientY - from.y) > LONG_PRESS_SLOP) {
26
+ this.cancel();
27
+ }
28
+ }
29
+ up() {
30
+ this.from = undefined;
31
+ this.wait.cancel();
32
+ if (this.held) {
33
+ setTimeout(() => {
34
+ this.held = false;
35
+ });
36
+ }
37
+ }
38
+ cancel() {
39
+ this.from = undefined;
40
+ this.held = false;
41
+ this.wait.cancel();
42
+ }
43
+ takeClick() {
44
+ const held = this.held;
45
+ this.held = false;
46
+ return held;
47
+ }
48
+ }
@@ -25,6 +25,31 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
25
25
  * action whose name starts with it. The actions are one tab stop, and Tab
26
26
  * closes the dial and moves on.
27
27
  *
28
+ * **Keyboard.** On the trigger, Enter, Space or a press opens the dial on its
29
+ * first action. With the dial open:
30
+ *
31
+ * | Key | What it does |
32
+ * |---|---|
33
+ * | Down, Right | Moves to the next action, from the last back to the first. |
34
+ * | Up, Left | Moves to the action before, from the first round to the last. |
35
+ * | Home, End | Moves to the first or the last action. |
36
+ * | A letter | Moves to the next action whose name starts with it. |
37
+ * | Enter, Space | Chooses the action, and the dial closes. |
38
+ * | Escape | Closes the dial and puts focus back on the trigger. |
39
+ * | Tab | Closes the dial and moves on. |
40
+ *
41
+ * **Groups.** Put actions in `Speed Dial.Group`, named by its `label`, to set
42
+ * them apart as Menu's sections do: each is a `group` of the menu, and the
43
+ * arrow keys walk through every group's actions in order.
44
+ *
45
+ * **A trigger with its own action.** With `open-on="long-press"`, a press on
46
+ * the trigger is the trigger's own, such as composing a message, and holding it
47
+ * for half a second opens the dial, as React Aria's menu trigger does with
48
+ * `trigger="longPress"`. Alt+Down or Alt+Up opens it from the keyboard, and
49
+ * the trigger says so in its description, `long-press-label`, the drawn one
50
+ * and a slotted one alike. A press that has opened the dial does not also do
51
+ * the trigger's action.
52
+ *
28
53
  * @since 0.1.0
29
54
  * @status stable
30
55
  * @category actions
@@ -45,14 +70,35 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
45
70
  * @cssstate open - While the actions are out.
46
71
  */
47
72
  export declare class HelixHeadlessSpeedDial extends HelixHeadlessSpeedDial_base {
73
+ /**
74
+ * The key this family's words are registered under, its styled tag:
75
+ * `registerWords('de', { 'helix-speed-dial': { label: 'Aktionen' } })`.
76
+ */
77
+ static words: string;
48
78
  /**
49
79
  * Accessible name for the trigger and the set of actions it opens.
50
80
  */
51
81
  label: string;
82
+ /**
83
+ * The description the trigger gives under `open-on="long-press"`, saying how
84
+ * its actions are reached.
85
+ *
86
+ * A slotted trigger is described by the dial, which carries the words as
87
+ * its own label for that: a Helix button's inner control at once, and a
88
+ * plain element of yours once a reader reaches it, after hydration, unless
89
+ * you described or labeled it yourself.
90
+ */
91
+ longPressLabel: string;
52
92
  /**
53
93
  * Space between the trigger and the actions, in pixels.
54
94
  */
55
95
  offset: number;
96
+ /**
97
+ * What opens the dial. `click` opens it on a press of the trigger. Under
98
+ * `long-press`, a press is the trigger's own action, and the dial opens on a
99
+ * press held for half a second, or on Alt+Down or Alt+Up.
100
+ */
101
+ openOn: 'click' | 'long-press';
56
102
  /**
57
103
  * The direction the actions open in. They move to another side if that side
58
104
  * does not fit.
@@ -74,8 +120,14 @@ export declare class HelixHeadlessSpeedDial extends HelixHeadlessSpeedDial_base
74
120
  protected readonly panel: PopoverController;
75
121
  /** Whatever the consumer slotted, or the button rendered in its place. */
76
122
  private get trigger();
77
- /** The actions, which are this element's own rows and nothing else slotted. */
123
+ /**
124
+ * The actions, in order: this element's own rows, and the rows of each group
125
+ * slotted beside them, and nothing else slotted.
126
+ */
78
127
  private get items();
128
+ /** Watches the trigger for a held press, under `open-on="long-press"`. */
129
+ private readonly longPress;
130
+ private get pressHeld();
79
131
  /**
80
132
  * Puts focus on the trigger, the slotted one or the button drawn in its
81
133
  * place, as a `focus()` on a native control would. The host itself takes no
@@ -85,6 +137,17 @@ export declare class HelixHeadlessSpeedDial extends HelixHeadlessSpeedDial_base
85
137
  /** Shuts it and puts the reader back on the trigger. */
86
138
  private close;
87
139
  private readonly handleTriggerClick;
140
+ /**
141
+ * Takes the click a held press ends in, ahead of the trigger's own
142
+ * listeners, so a press that opened the dial does not also do the trigger's
143
+ * action. In capture, on the host, which is above a slotted trigger.
144
+ */
145
+ private readonly handleHeldClick;
146
+ private readonly handleTriggerPointerDown;
147
+ private readonly handleTriggerPointerMove;
148
+ private readonly handleTriggerPointerUp;
149
+ private readonly handleTriggerPointerCancel;
150
+ private readonly handleTriggerContextMenu;
88
151
  private readonly handleSelect;
89
152
  private readonly handleKeydown;
90
153
  connectedCallback(): void;
@@ -113,6 +176,27 @@ export declare class HelixHeadlessSpeedDial extends HelixHeadlessSpeedDial_base
113
176
  * is expanded is already saying it has something to expand.
114
177
  */
115
178
  private announce;
179
+ /** The control the dial has described, so the description can be taken back. */
180
+ private described;
181
+ /**
182
+ * Describes a slotted trigger by `long-press-label` under
183
+ * `open-on="long-press"`, as the drawn one is, or takes it back.
184
+ *
185
+ * **By the host, which carries the words as its label.** The drawn
186
+ * trigger's description is in this shadow root, and a reference from the
187
+ * consumer's trigger, or from the button inside a Helix one, cannot point
188
+ * in; it can point out, to the host. Core's `linkDescription` says where
189
+ * that is safe: inside a component's shadow root always, and on the
190
+ * consumer's own element only once `light` says a reader has acted, which
191
+ * is after hydration. React Aria's long press describes whatever trigger it
192
+ * is given.
193
+ *
194
+ * @param light A reader has just reached the trigger.
195
+ */
196
+ private describeTrigger;
197
+ /** A reader reaching a slotted trigger, which is late enough to describe a plain one. */
198
+ private readonly handleTriggerFocusIn;
199
+ protected firstUpdated(changed: PropertyValues): void;
116
200
  protected updated(changed: PropertyValues): void;
117
201
  /**
118
202
  * The control that opens it, behind a seam the styled tier can move.
@@ -4,20 +4,31 @@ 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, drawIcon, HelixElement, KeyboardNavigationController, MixinControllerOpen, PopoverController, slottedWords, tellDisclosure, typeaheadBy, } from '@fusion.dev/helix-core';
7
+ import { anchorElement, customElement, drawIcon, focusTarget, HelixElement, KeyboardNavigationController, linkDescription, MixinControllerOpen, PopoverController, slottedWords, tellDisclosure, typeaheadByWords, unlinkDescription, words, } from '@fusion.dev/helix-core';
8
8
  import { plus } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
11
+ import { LongPress } from '../long-press.js';
12
+ const navigable = (item) => ({
13
+ contains: (node) => item.contains(node),
14
+ disabled: item.disabled,
15
+ focusItem: () => item.focusItem(),
16
+ select: () => item.select(),
17
+ selected: item.active,
18
+ words: slottedWords(item, ['']),
19
+ });
11
20
  let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControllerOpen(HelixElement) {
12
21
  constructor() {
13
22
  super(...arguments);
14
23
  this.label = 'Actions';
24
+ this.longPressLabel = 'Long press or press Alt+Down to show the actions';
15
25
  this.offset = 12;
26
+ this.openOn = 'click';
16
27
  this.placement = 'top-end';
17
28
  this.keys = new KeyboardNavigationController(this, {
18
- items: () => (this.open ? this.items : []),
29
+ items: () => (this.open ? this.items.map(navigable) : []),
19
30
  selects: () => false,
20
- typeahead: typeaheadBy((item) => slottedWords(item, [''])),
31
+ typeahead: typeaheadByWords(),
21
32
  });
22
33
  this.focusOnOpen = false;
23
34
  this.panel = new PopoverController(this, {
@@ -29,13 +40,48 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
29
40
  placement: () => this.placement,
30
41
  surface: () => this.partNamed('actions'),
31
42
  });
43
+ this.longPress = new LongPress(this, {
44
+ onLongPress: () => {
45
+ if (!this.open) {
46
+ this.focusOnOpen = this.requestOpen(true);
47
+ }
48
+ },
49
+ });
32
50
  this.handleTriggerClick = () => {
33
51
  if (this.open) {
34
52
  this.requestOpen(false);
35
53
  return;
36
54
  }
55
+ if (this.pressHeld) {
56
+ return;
57
+ }
37
58
  this.focusOnOpen = this.requestOpen(true);
38
59
  };
60
+ this.handleHeldClick = (event) => {
61
+ if (this.pressHeld && this.longPress.takeClick()) {
62
+ event.stopImmediatePropagation();
63
+ event.preventDefault();
64
+ }
65
+ };
66
+ this.handleTriggerPointerDown = (event) => {
67
+ if (this.pressHeld && !this.open) {
68
+ this.longPress.down(event);
69
+ }
70
+ };
71
+ this.handleTriggerPointerMove = (event) => {
72
+ this.longPress.move(event);
73
+ };
74
+ this.handleTriggerPointerUp = () => {
75
+ this.longPress.up();
76
+ };
77
+ this.handleTriggerPointerCancel = () => {
78
+ this.longPress.cancel();
79
+ };
80
+ this.handleTriggerContextMenu = (event) => {
81
+ if (this.pressHeld) {
82
+ event.preventDefault();
83
+ }
84
+ };
39
85
  this.handleSelect = (event) => {
40
86
  queueMicrotask(() => {
41
87
  if (!event.defaultPrevented) {
@@ -45,6 +91,12 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
45
91
  };
46
92
  this.handleKeydown = (event) => {
47
93
  if (!this.open) {
94
+ if (this.pressHeld &&
95
+ event.altKey &&
96
+ (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
97
+ event.preventDefault();
98
+ this.focusOnOpen = this.requestOpen(true);
99
+ }
48
100
  return;
49
101
  }
50
102
  if (event.key === 'Tab') {
@@ -58,13 +110,27 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
58
110
  this.close();
59
111
  event.preventDefault();
60
112
  };
113
+ this.handleTriggerFocusIn = () => {
114
+ if (this.pressHeld) {
115
+ this.describeTrigger(true);
116
+ }
117
+ };
61
118
  }
119
+ static { this.words = 'helix-speed-dial'; }
62
120
  get trigger() {
63
121
  return anchorElement(this.renderRoot?.querySelector('slot[name="trigger"]'), this.partNamed('trigger') ?? this);
64
122
  }
65
123
  get items() {
66
124
  const slot = this.renderRoot?.querySelector('slot:not([name])');
67
- return (slot?.assignedElements?.() ?? []).filter((one) => one.isSpeedDialItem === true);
125
+ const isItem = (one) => one.isSpeedDialItem === true;
126
+ return (slot?.assignedElements?.() ?? []).flatMap((one) => isItem(one)
127
+ ? [one]
128
+ : one.isSpeedDialGroup === true
129
+ ? [...one.children].filter(isItem)
130
+ : []);
131
+ }
132
+ get pressHeld() {
133
+ return this.openOn === 'long-press';
68
134
  }
69
135
  focus(options) {
70
136
  const trigger = this.trigger;
@@ -84,11 +150,18 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
84
150
  super.connectedCallback();
85
151
  this.addEventListener('helix-select', this.handleSelect);
86
152
  this.addEventListener('keydown', this.handleKeydown);
153
+ this.addEventListener('click', this.handleHeldClick, true);
87
154
  }
88
155
  disconnectedCallback() {
89
156
  super.disconnectedCallback();
157
+ if (this.described) {
158
+ unlinkDescription(this.described, this);
159
+ this.described = undefined;
160
+ this.internals.ariaLabel = null;
161
+ }
90
162
  this.removeEventListener('helix-select', this.handleSelect);
91
163
  this.removeEventListener('keydown', this.handleKeydown);
164
+ this.removeEventListener('click', this.handleHeldClick, true);
92
165
  }
93
166
  announce() {
94
167
  const trigger = this.trigger;
@@ -97,9 +170,27 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
97
170
  }
98
171
  tellDisclosure(trigger, this.open, 'menu');
99
172
  }
173
+ describeTrigger(light = false) {
174
+ const trigger = this.trigger;
175
+ const slotted = this.pressHeld && trigger !== this && trigger !== this.partNamed('trigger');
176
+ const control = slotted ? focusTarget(trigger) : undefined;
177
+ if (this.described && this.described !== control) {
178
+ unlinkDescription(this.described, this);
179
+ this.described = undefined;
180
+ }
181
+ if (control && control !== this.described && linkDescription(control, this, light)) {
182
+ this.described = control;
183
+ }
184
+ this.internals.ariaLabel = this.described ? this.longPressLabel : null;
185
+ }
186
+ firstUpdated(changed) {
187
+ super.firstUpdated(changed);
188
+ requestAnimationFrame(() => this.describeTrigger());
189
+ }
100
190
  updated(changed) {
101
191
  super.updated?.(changed);
102
192
  this.announce();
193
+ this.describeTrigger();
103
194
  if (this.open && this.focusOnOpen) {
104
195
  this.focusOnOpen = false;
105
196
  this.updateComplete.then(() => {
@@ -110,10 +201,22 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
110
201
  }
111
202
  }
112
203
  renderTrigger() {
113
- return html `<slot name="trigger" @click=${this.handleTriggerClick}>
204
+ const held = this.pressHeld;
205
+ return html `<slot
206
+ name="trigger"
207
+ @click=${this.handleTriggerClick}
208
+ @contextmenu=${this.handleTriggerContextMenu}
209
+ @focusin=${this.handleTriggerFocusIn}
210
+ @pointercancel=${this.handleTriggerPointerCancel}
211
+ @pointerdown=${this.handleTriggerPointerDown}
212
+ @pointermove=${this.handleTriggerPointerMove}
213
+ @pointerup=${this.handleTriggerPointerUp}
214
+ @slotchange=${() => this.describeTrigger()}
215
+ >
114
216
  <button
115
217
  part="trigger"
116
218
  type="button"
219
+ aria-describedby=${held ? 'long-press' : nothing}
117
220
  aria-expanded=${this.open ? 'true' : 'false'}
118
221
  aria-haspopup="menu"
119
222
  aria-label=${this.label}
@@ -121,6 +224,7 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
121
224
  ${''}
122
225
  ${drawIcon(plus)}
123
226
  </button>
227
+ ${held ? html `<span id="long-press" hidden>${this.longPressLabel}</span>` : nothing}
124
228
  </slot>`;
125
229
  }
126
230
  render() {
@@ -137,11 +241,19 @@ let HelixHeadlessSpeedDial = class HelixHeadlessSpeedDial extends MixinControlle
137
241
  }
138
242
  };
139
243
  __decorate([
244
+ words,
140
245
  property()
141
246
  ], HelixHeadlessSpeedDial.prototype, "label", void 0);
247
+ __decorate([
248
+ words,
249
+ property({ attribute: 'long-press-label' })
250
+ ], HelixHeadlessSpeedDial.prototype, "longPressLabel", void 0);
142
251
  __decorate([
143
252
  property({ type: Number })
144
253
  ], HelixHeadlessSpeedDial.prototype, "offset", void 0);
254
+ __decorate([
255
+ property({ attribute: 'open-on' })
256
+ ], HelixHeadlessSpeedDial.prototype, "openOn", void 0);
145
257
  __decorate([
146
258
  property()
147
259
  ], HelixHeadlessSpeedDial.prototype, "placement", void 0);
@@ -13,8 +13,9 @@ import { type PropertyValues, type TemplateResult } from 'lit';
13
13
  * added at `firstUpdated` and is not in the server markup. Before it appears,
14
14
  * both dividers work on their own.
15
15
  *
16
- * The divider has `role="separator"` and `aria-valuenow`, and `aria-controls`
17
- * names the start pane. Drag it with a pointer or move it with the arrow keys,
16
+ * The divider has `role="separator"` and `aria-valuenow`, with
17
+ * `aria-valuetext` saying the start pane's share as a percentage in the
18
+ * nearest `lang`, or in the reader's locale where no `lang` is set, and `aria-controls` names the start pane. Drag it with a pointer or move it with the arrow keys,
18
19
  * press `Home` or `End` to move it to its bounds, and press `Enter` to collapse
19
20
  * the start pane and open it again. A drag in progress is tracked as a state, so both dividers a
20
21
  * corner moves stay lit for as long as they move.
@@ -36,13 +37,14 @@ import { type PropertyValues, type TemplateResult } from 'lit';
36
37
  * @documentation https://fusion.dev/helix/components/splitter
37
38
  *
38
39
  * @slot end - The pane after the divider.
40
+ * @slot handle - A mark drawn at the middle of the divider, such as a grip icon. It takes no focus and no pointer of its own: a press on it is a press on the divider.
39
41
  * @slot start - The pane before the divider.
40
42
  *
41
43
  * @event {HelixBeforeCollapseEvent} helix-before-collapse - Fired before a pane shuts or reopens, whether or not the resize that caused it was allowed. It carries its own position, because a shut pane sits at `collapsed-size`. Cancelable: canceling it leaves the pane as it was and the divider where the gesture put it.
42
44
  * @event {HelixBeforeResizeEvent} helix-before-resize - Fired before the divider settles, and only when the gesture moved it. A press that moved nothing, a drag that came back, an arrow key with no room left, and a corner that moved only the other divider do not fire it. Cancelable: canceling it leaves the position to you and keeps the rest of the gesture, so a collapse the gesture reached still fires `helix-before-collapse`, which you can also cancel. A dragged divider stays where it was dropped until you set your own `position`.
43
45
  * @event {HelixCollapseEvent} helix-collapse - Fired after a pane shuts or reopens, with the side that is shut, or empty where both are open.
44
46
  * @event {HelixResizedEvent} helix-resized - Fired after the divider settles somewhere new, with the new position.
45
- * @event {Event} input - Fired each time a drag moves the divider, before it settles, as a range input does while it is dragged. Read `position` for where it is now.
47
+ * @event {Event} input - Fired each time the divider moves, as a range input does: on each step of a drag, and before `helix-resized` for a key, a double click or a corner. Read `position` for where it is now.
46
48
  *
47
49
  * @csspart corner - The handle where two dividers cross, added on the client.
48
50
  * @csspart end - The box that holds the second pane.
@@ -52,9 +54,16 @@ import { type PropertyValues, type TemplateResult } from 'lit';
52
54
  * @cssproperty --splitter-corner-at - Where a nested splitter crosses this one, as a percentage.
53
55
  * @cssproperty --splitter-position - Where the divider sits, as a percentage of the box.
54
56
  *
57
+ * @cssstate collapsed - While a pane is shut. `data-collapsed` on the host says which.
55
58
  * @cssstate dragging - While the pointer or a corner holds the divider.
59
+ * @cssstate vertical - While the panes are one above the other, whether `orientation` says so or `auto` turned them.
56
60
  */
57
61
  export declare class HelixHeadlessSplitter extends HelixElement {
62
+ /**
63
+ * The key this family's words are registered under, its styled tag:
64
+ * `registerWords('de', { 'helix-splitter': { label: 'Bereiche anpassen' } })`.
65
+ */
66
+ static words: string;
58
67
  /**
59
68
  * Which pane is shut, if either.
60
69
  *