@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
@@ -1,4 +1,4 @@
1
- import { CommandController, HelixElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, CommandController, HelixElement, OpenPhaseController, SwipeController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessDrawer_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
4
4
  /**
@@ -9,11 +9,26 @@ declare const HelixHeadlessDrawer_base: (new (...args: any[]) => import("@fusion
9
9
  * `helix-before-open` and `helix-before-close` events work the same way as on
10
10
  * an accordion item.
11
11
  *
12
- * The drawer is modal by default, which means three things:
12
+ * The drawer is modal by default, which means four things:
13
13
  *
14
14
  * - focus is trapped inside
15
15
  * - Escape and a press outside close it
16
16
  * - the page behind is covered
17
+ * - the page behind does not scroll
18
+ *
19
+ * A drawer with `modal="false"` leaves the page usable and still closes on
20
+ * Escape, in a browser without `closedby` as well.
21
+ *
22
+ * **A touch or a pen swipes it away**, toward the edge it came from, resolved
23
+ * against the writing direction. A swipe past halfway, or a quick one, closes
24
+ * it through the same request as every other way out. `snap-points` lists the
25
+ * fractions of the panel a reader can leave on screen, such as `0.5 1` for a
26
+ * sheet that rests half open: it opens at the smallest, and a swipe settles at
27
+ * the nearest. While a swipe moves the panel, the distance is written on it as
28
+ * `--drawer-swipe-x` and `--drawer-swipe-y`. `swipe="false"` turns swiping off.
29
+ *
30
+ * The panel's name is `label` when you set it. Otherwise it is the heading in
31
+ * the `header` slot, or the elements an `aria-labelledby` on the host names.
17
32
  *
18
33
  * Content stays mounted when the drawer is closed, so it is in the server
19
34
  * markup and can animate. A closed `<dialog>` is already out of the tab order
@@ -36,17 +51,24 @@ declare const HelixHeadlessDrawer_base: (new (...args: any[]) => import("@fusion
36
51
  * @documentation https://fusion.dev/helix/components/drawer
37
52
  *
38
53
  * @slot - The drawer's content.
54
+ * @slot footer - Content pinned below the scrolling area, such as the drawer's actions.
39
55
  * @slot header - Content pinned above the scrolling area.
40
56
  *
41
57
  * @event {Event} close - Sent from the host after the drawer closes, because the native `close` event does not leave the shadow root.
42
58
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the panel closes, and cancelable.
43
59
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before the panel opens, and cancelable. Canceling it keeps the panel closed.
44
- * @event {Event} toggle - Sent when the drawer opens or closes, with `newState` and `oldState`.
60
+ * @event {ToggleEvent} toggle - Sent when the drawer opens or closes, with `newState` and `oldState`.
45
61
  *
46
62
  * @csspart content - The scrolling content region.
63
+ * @csspart footer - The footer region.
47
64
  * @csspart header - The header region.
48
65
  * @csspart panel - The sliding panel.
49
66
  *
67
+ * @cssproperty --drawer-swipe-x - How far a swipe, or a snap point, has moved the panel across, in pixels, toward the right.
68
+ * @cssproperty --drawer-swipe-y - How far a swipe, or a snap point, has moved the panel down, in pixels.
69
+ *
70
+ * @cssstate entering - From the moment the drawer opens until its entrance has finished.
71
+ * @cssstate exiting - From the moment the drawer closes until its exit has finished.
50
72
  * @cssstate open - While the drawer is open.
51
73
  */
52
74
  export declare class HelixHeadlessDrawer extends HelixHeadlessDrawer_base {
@@ -65,9 +87,11 @@ export declare class HelixHeadlessDrawer extends HelixHeadlessDrawer_base {
65
87
  */
66
88
  closedBy?: 'any' | 'closerequest' | 'none';
67
89
  /**
68
- * Accessible name for the panel.
90
+ * Accessible name for the panel. When it is empty, the heading in the
91
+ * `header` slot names the panel.
69
92
  */
70
93
  label: string;
94
+ protected readonly aria: AriaForwardController;
71
95
  /**
72
96
  * Whether the drawer blocks the page behind it.
73
97
  *
@@ -91,6 +115,21 @@ export declare class HelixHeadlessDrawer extends HelixHeadlessDrawer_base {
91
115
  * guarantees is the absence, and a sheet selects on it.
92
116
  */
93
117
  placement?: 'start' | 'end' | 'top' | 'bottom';
118
+ /**
119
+ * The fractions of the panel a reader can leave on screen, as a list such as
120
+ * `0.5 1`. The drawer opens at the smallest, and a swipe comes to rest at the
121
+ * nearest, or closes the drawer below the smallest.
122
+ *
123
+ * Empty is `1`: the whole panel, and a swipe either closes it or puts it
124
+ * back.
125
+ */
126
+ snapPoints: string;
127
+ /**
128
+ * Whether a touch or a pen can swipe the drawer away. `swipe="false"` turns
129
+ * it off, for a panel whose content has its own use for the gesture, such as
130
+ * a map.
131
+ */
132
+ swipe: boolean;
94
133
  /**
95
134
  * What the dialog closed with, the way `<dialog>` reports it.
96
135
  *
@@ -111,6 +150,37 @@ export declare class HelixHeadlessDrawer extends HelixHeadlessDrawer_base {
111
150
  set returnValue(value: string);
112
151
  /** What a value set before the element existed is kept in. */
113
152
  private returned;
153
+ protected readonly phases: OpenPhaseController;
154
+ /** How far the panel rests toward its edge, in pixels, at the snap point it settled on. */
155
+ private rest;
156
+ /** The edge the panel leaves through, from its placement and the writing direction. */
157
+ private get edge();
158
+ /** The panel's size along the swipe, in pixels. */
159
+ private get extent();
160
+ protected readonly swipes: SwipeController;
161
+ /**
162
+ * Writes how far the panel sits toward its edge, as the two properties the
163
+ * styled tier translates it by. Nothing is written at rest.
164
+ */
165
+ private place;
166
+ /** Brings a released swipe to rest: at a snap point, or closed through the request. */
167
+ private settle;
168
+ /** Opens the drawer. */
169
+ show(): void;
170
+ /**
171
+ * Requests that the drawer close, and takes what it closed with, the way
172
+ * `Dialog.close(value)` does. A `helix-before-close` listener can refuse it,
173
+ * and then the value is not kept.
174
+ */
175
+ close(returnValue?: string): void;
176
+ /**
177
+ * Escape on a drawer that is not modal, in a browser without `closedby`.
178
+ *
179
+ * `show()` gives a `<dialog>` no close watcher, and `closedby="closerequest"`
180
+ * is what asks for one. Where the browser does not know the attribute, the
181
+ * key is read here, and comes through the same request.
182
+ */
183
+ private readonly handleKeydown;
114
184
  /** The panel, which is a real `<dialog>`. */
115
185
  private get panel();
116
186
  /**
@@ -126,11 +196,27 @@ export declare class HelixHeadlessDrawer extends HelixHeadlessDrawer_base {
126
196
  /**
127
197
  * A press on the backdrop, which lands on the dialog element itself.
128
198
  *
129
- * The panel fills only part of the dialog's box, so a press beside it hits
130
- * the dialog and not a child. A native `<dialog>` does not close on that, and
131
- * it is the gesture that most obviously means close.
199
+ * A native `<dialog>` does not close on that, and it is the gesture that most
200
+ * obviously means close.
201
+ *
202
+ * **The target alone is not enough.** The panel is the `<dialog>`, and a
203
+ * press in its own padding has the dialog as its target too, the same as a
204
+ * press on the backdrop. So the point is compared against the panel's box,
205
+ * as `Dialog` does.
132
206
  */
133
207
  private readonly handleBackdrop;
208
+ /** Whether the `header` slot's heading is what currently names the panel. */
209
+ private namedByHeader;
210
+ /**
211
+ * Names the panel by its heading, where nothing else names it.
212
+ *
213
+ * An element reference, because the heading is in the light DOM and the
214
+ * `<dialog>` is in this shadow root, which an IDREF cannot cross. `label` and
215
+ * an `aria-labelledby` on the host come first. A browser without element
216
+ * reflection keeps the fallback name.
217
+ */
218
+ private nameByHeader;
219
+ disconnectedCallback(): void;
134
220
  protected updated(changed: PropertyValues): void;
135
221
  protected render(): TemplateResult;
136
222
  }
@@ -4,9 +4,10 @@ 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 { CommandController, customElement, HelixElement, MixinControllerOpen, onUnlessFalse, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, CommandController, customElement, edgeOffset, HelixElement, headingsIn, isRtl, lockScroll, MixinControllerOpen, OpenPhaseController, onUnlessFalse, parseSnapPoints, reflectElements, SwipeController, settleSwipe, snapTravel, swipeAxis, swipeEdge, towardEdge, unlockScroll, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { startsSwipe } from '../swipe-start.js';
10
11
  let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(HelixElement) {
11
12
  constructor() {
12
13
  super(...arguments);
@@ -18,8 +19,38 @@ let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(
18
19
  },
19
20
  });
20
21
  this.label = '';
22
+ this.aria = new AriaForwardController(this, { target: () => this.panel });
21
23
  this.modal = true;
24
+ this.snapPoints = '';
25
+ this.swipe = true;
22
26
  this.returned = '';
27
+ this.phases = new OpenPhaseController(this, {
28
+ mark: {
29
+ entering: (on) => this.toggleState('entering', on),
30
+ exiting: (on) => this.toggleState('exiting', on),
31
+ },
32
+ open: () => this.open,
33
+ surface: () => this.panel,
34
+ });
35
+ this.rest = 0;
36
+ this.swipes = new SwipeController(this, {
37
+ axis: () => (this.open && this.swipe ? swipeAxis(this.edge) : undefined),
38
+ end: (dx, dy, vx, vy) => this.settle(dx, dy, vx, vy),
39
+ move: (dx, dy) => this.place(Math.max(0, this.rest + towardEdge(this.edge, dx, dy))),
40
+ start: (target, event) => startsSwipe(target, event.pointerType, swipeAxis(this.edge), this.partNamed('content')),
41
+ surface: () => this.panel,
42
+ });
43
+ this.handleKeydown = (event) => {
44
+ if (event.key !== 'Escape' ||
45
+ event.defaultPrevented ||
46
+ this.modal ||
47
+ !this.open ||
48
+ closedByKnown()) {
49
+ return;
50
+ }
51
+ event.preventDefault();
52
+ this.requestOpen(false);
53
+ };
23
54
  this.handleCancel = (event) => {
24
55
  event.preventDefault();
25
56
  this.requestOpen(false);
@@ -31,10 +62,20 @@ let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(
31
62
  this.relayNativeEvent(event);
32
63
  };
33
64
  this.handleBackdrop = (event) => {
34
- if (event.target === this.panel && this.modal) {
35
- this.requestOpen(false);
65
+ const panel = this.panel;
66
+ if (!panel || event.target !== panel || !this.modal) {
67
+ return;
68
+ }
69
+ const box = panel.getBoundingClientRect();
70
+ if (event.clientX >= box.left &&
71
+ event.clientX <= box.right &&
72
+ event.clientY >= box.top &&
73
+ event.clientY <= box.bottom) {
74
+ return;
36
75
  }
76
+ this.requestOpen(false);
37
77
  };
78
+ this.namedByHeader = false;
38
79
  }
39
80
  get returnValue() {
40
81
  return this.panel?.returnValue ?? this.returned;
@@ -46,11 +87,79 @@ let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(
46
87
  panel.returnValue = value;
47
88
  }
48
89
  }
90
+ get edge() {
91
+ return swipeEdge(this.placement ?? 'end', isRtl(this));
92
+ }
93
+ get extent() {
94
+ const box = this.panel?.getBoundingClientRect();
95
+ return (swipeAxis(this.edge) === 'x' ? box?.width : box?.height) ?? 0;
96
+ }
97
+ place(travel) {
98
+ const panel = this.panel;
99
+ if (!panel) {
100
+ return;
101
+ }
102
+ const { x, y } = edgeOffset(this.edge, travel);
103
+ const px = (value) => (value === 0 ? '' : `${Math.round(value)}px`);
104
+ panel.style.setProperty('--drawer-swipe-x', px(x));
105
+ panel.style.setProperty('--drawer-swipe-y', px(y));
106
+ }
107
+ settle(dx, dy, vx, vy) {
108
+ const edge = this.edge;
109
+ const size = this.extent;
110
+ const shown = settleSwipe({
111
+ points: parseSnapPoints(this.snapPoints),
112
+ size,
113
+ travel: Math.max(0, this.rest + towardEdge(edge, dx, dy)),
114
+ velocity: towardEdge(edge, vx, vy),
115
+ });
116
+ if (shown === 0 && this.requestOpen(false)) {
117
+ return;
118
+ }
119
+ if (shown !== 0) {
120
+ this.rest = snapTravel(size, shown);
121
+ }
122
+ this.place(this.rest);
123
+ }
124
+ show() {
125
+ this.requestOpen(true);
126
+ }
127
+ close(returnValue) {
128
+ const previous = this.returnValue;
129
+ if (returnValue !== undefined) {
130
+ this.returnValue = returnValue;
131
+ }
132
+ if (!this.requestOpen(false) && returnValue !== undefined) {
133
+ this.returnValue = previous;
134
+ }
135
+ }
49
136
  get panel() {
50
137
  return this.partNamed('panel');
51
138
  }
139
+ nameByHeader() {
140
+ const slot = this.renderRoot.querySelector('slot[name="header"]');
141
+ const heading = this.label || this.hasAttribute('aria-labelledby')
142
+ ? []
143
+ : headingsIn(slot?.assignedElements({ flatten: true }) ?? []);
144
+ this.namedByHeader = reflectElements(this.panel, 'ariaLabelledByElements', heading, this.namedByHeader);
145
+ }
146
+ disconnectedCallback() {
147
+ super.disconnectedCallback();
148
+ unlockScroll(this);
149
+ }
52
150
  updated(changed) {
53
151
  super.updated(changed);
152
+ this.nameByHeader();
153
+ if (changed.has('open') && !this.open) {
154
+ this.rest = 0;
155
+ this.place(0);
156
+ }
157
+ if (this.open && this.modal) {
158
+ lockScroll(this);
159
+ }
160
+ else {
161
+ unlockScroll(this);
162
+ }
54
163
  const panel = this.panel;
55
164
  if (!panel) {
56
165
  return;
@@ -62,22 +171,27 @@ let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(
62
171
  else {
63
172
  panel.show();
64
173
  }
174
+ this.rest = snapTravel(this.extent, parseSnapPoints(this.snapPoints)[0] ?? 1);
175
+ this.place(this.rest);
65
176
  }
66
177
  else if (!this.open && panel.open) {
67
178
  panel.close();
68
179
  }
69
180
  }
70
181
  render() {
182
+ const closedBy = this.closedBy ?? (this.modal ? undefined : 'closerequest');
71
183
  return html `<dialog
72
184
  part="panel"
73
- closedby=${this.closedBy ?? nothing}
185
+ closedby=${closedBy ?? nothing}
74
186
  aria-label=${this.label || 'Drawer'}
75
187
  @cancel=${this.handleCancel}
76
188
  @click=${this.handleBackdrop}
77
189
  @close=${this.handleClose}
190
+ @keydown=${this.handleKeydown}
78
191
  >
79
- <div part="header"><slot name="header"></slot></div>
192
+ <div part="header"><slot name="header" @slotchange=${this.nameByHeader}></slot></div>
80
193
  <div part="content"><slot></slot></div>
194
+ <div part="footer"><slot name="footer"></slot></div>
81
195
  </dialog>`;
82
196
  }
83
197
  };
@@ -93,7 +207,14 @@ __decorate([
93
207
  __decorate([
94
208
  property({ reflect: true })
95
209
  ], HelixHeadlessDrawer.prototype, "placement", void 0);
210
+ __decorate([
211
+ property({ attribute: 'snap-points' })
212
+ ], HelixHeadlessDrawer.prototype, "snapPoints", void 0);
213
+ __decorate([
214
+ property({ converter: onUnlessFalse })
215
+ ], HelixHeadlessDrawer.prototype, "swipe", void 0);
96
216
  HelixHeadlessDrawer = __decorate([
97
217
  customElement('helix-headless-drawer')
98
218
  ], HelixHeadlessDrawer);
99
219
  export { HelixHeadlessDrawer };
220
+ const closedByKnown = () => typeof HTMLDialogElement !== 'undefined' && 'closedBy' in HTMLDialogElement.prototype;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Whether a press may start swiping a drawer away.
3
+ *
4
+ * Not a mouse, which drags to select text. Not a press on a field or on
5
+ * editable text, which drags to move its caret. And not a press inside a
6
+ * scroller that can scroll along the swipe, which drags to scroll, so a bottom
7
+ * sheet holding a long list scrolls the list.
8
+ */
9
+ export declare const startsSwipe: (target: Element, pointerType: string, axis: 'x' | 'y', scroller: Element | null | undefined) => boolean;
@@ -0,0 +1,12 @@
1
+ const EDITABLE = 'input, select, textarea, [contenteditable]:not([contenteditable="false"])';
2
+ export const startsSwipe = (target, pointerType, axis, scroller) => {
3
+ if (pointerType === 'mouse' || target.closest(EDITABLE)) {
4
+ return false;
5
+ }
6
+ if (!scroller || !(scroller === target || scroller.contains(target))) {
7
+ return true;
8
+ }
9
+ return axis === 'x'
10
+ ? scroller.scrollWidth <= scroller.clientWidth
11
+ : scroller.scrollHeight <= scroller.clientHeight;
12
+ };
@@ -112,21 +112,24 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
112
112
  /** Moves focus onto the row itself. */
113
113
  focusItem(): void;
114
114
  /**
115
- * Whether this is the current row, which in a drill-down is the row with
116
- * focus.
115
+ * Whether the row has focus, which makes it the row the keyboard is on.
117
116
  *
118
- * A radio group's selection is an answer it holds; a page of rows has no
119
- * answer, only the row a reader has walked to, so focus is the whole of what
120
- * "the current one" can mean here. This is `Menu.Item`'s reading word for
121
- * word, and the two are one pattern: a menu that drills and a drill-down are
122
- * the same rows through the same controller.
117
+ * `Option` calls the same thing `active`. A page of rows holds no answer the
118
+ * way a radio group does, only the row a reader has walked to, so focus is
119
+ * the whole of what "the current one" can mean here. This is `Menu.Item`'s
120
+ * reading word for word, and the two are one pattern: a menu that drills and
121
+ * a drill-down are the same rows through the same controller.
123
122
  *
124
- * Asked of the document rather than of the shadow root. `focusItem` puts
125
- * focus on the control inside this row and the platform retargets it, so from
126
- * outside the shadow tree `activeElement` is this element already and nothing
127
- * has to walk a tree. `ShadowRoot.activeElement` is also the reading that does
128
- * not survive happy-dom, which climbs `getRootNode()` to the top and then
129
- * dereferences what it ran out of.
123
+ * The focused node is found through every shadow root and asked whether it
124
+ * is in this row's own, as `Menu.Item` does, so a drill-down inside another
125
+ * component's shadow root still knows its current row.
126
+ */
127
+ get active(): boolean;
128
+ /**
129
+ * Whether the row has focus, the same as `active`.
130
+ *
131
+ * @deprecated Read `active`. Everywhere else in the library `selected` means
132
+ * chosen out of a set, and a drill-down row is never chosen that way.
130
133
  */
131
134
  get selected(): boolean;
132
135
  /** Fires `helix-select` for this row. */
@@ -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, HelixElement, HelixSelectEvent, } from '@fusion.dev/helix-core';
8
8
  import { caretRight } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -37,8 +37,12 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
37
37
  focusItem() {
38
38
  this.partNamed('item')?.focus();
39
39
  }
40
+ get active() {
41
+ const active = deepActiveElement();
42
+ return active !== null && active.getRootNode() === this.renderRoot;
43
+ }
40
44
  get selected() {
41
- return this.ownerDocument.activeElement === this;
45
+ return this.active;
42
46
  }
43
47
  select() {
44
48
  if (this.disabled) {
@@ -1,4 +1,4 @@
1
- import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & typeof HelixElement;
4
4
  /**
@@ -20,6 +20,11 @@ declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fus
20
20
  * and reads the rest from the DOM. The behavior lives in `DrilldownController`,
21
21
  * which `Menu` shares.
22
22
  *
23
+ * The rows of the page showing are a `menu`, named by `label` on the top page
24
+ * and by the page's title below it. The back button and the title sit above
25
+ * the menu. Disabled rows stay reachable with the arrow keys, and typing a
26
+ * letter moves to the next row whose name starts with it.
27
+ *
23
28
  * @since 0.1.0
24
29
  * @status stable
25
30
  * @category navigation
@@ -36,14 +41,18 @@ declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fus
36
41
  * @csspart header - The bar above a page, which holds the back button and the page's name.
37
42
  * @csspart live - A copy of the empty and loading text, in a region that screen readers announce when it changes. Visually hidden in the styled tier.
38
43
  * @csspart loading - Shown while the entries load.
39
- * @csspart page - The region the rows are in.
44
+ * @csspart page - The menu the rows are in.
40
45
  * @csspart title - The name of the page showing.
41
46
  *
42
47
  * @cssstate drilled - A row's page is showing, so a frame around the drilldown can style itself for that depth.
43
48
  */
44
49
  export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base {
45
50
  /**
46
- * The region's name, read by screen readers.
51
+ * The name of the top page's menu, read by screen readers. A page below it is
52
+ * named by its title.
53
+ *
54
+ * An `aria-label` or `aria-labelledby` on the host names the top page too,
55
+ * and wins over this.
47
56
  */
48
57
  label: string;
49
58
  /**
@@ -66,8 +75,16 @@ export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base
66
75
  */
67
76
  private direction?;
68
77
  private readonly drilldown;
69
- /** The rows on the page showing, which is what the keys move over. */
78
+ /**
79
+ * The rows on the page showing, which is what the keys move over.
80
+ *
81
+ * Disabled rows included. A row renders `aria-disabled` and keeps its
82
+ * `tabindex` so a reader can reach it and hear why it cannot be chosen, and
83
+ * `select()` is what refuses it.
84
+ */
70
85
  private get items();
86
+ /** Carries a host `aria-label` and `aria-labelledby` to the menu. */
87
+ protected readonly aria: AriaForwardController;
71
88
  /**
72
89
  * Moving between rows, which is `Menu`'s arrangement and not a second one.
73
90
  *
@@ -115,7 +132,6 @@ export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base
115
132
  private readonly handleKeydown;
116
133
  connectedCallback(): void;
117
134
  disconnectedCallback(): void;
118
- protected willUpdate(changed: PropertyValues): void;
119
135
  protected updated(changed: PropertyValues): void;
120
136
  /** Walks the tree marking which rows are on the page showing. */
121
137
  private mark;
@@ -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, DrilldownController, HelixElement, hostAria, inlineStep, KeyboardNavigationController, keyClaimed, MixinCollection, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, DrilldownController, HelixElement, inlineStep, KeyboardNavigationController, keyClaimed, MixinCollection, slottedWords, } 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, state } from 'lit/decorators.js';
@@ -20,14 +20,28 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
20
20
  root: () => [...this.children],
21
21
  slot: 'page',
22
22
  });
23
+ this.aria = new AriaForwardController(this, {
24
+ label: true,
25
+ target: () => this.partNamed('page'),
26
+ });
23
27
  this.keys = new KeyboardNavigationController(this, {
24
- items: () => this.items,
28
+ items: () => this.items.map((item) => ({
29
+ contains: (node) => item.contains(node),
30
+ disabled: false,
31
+ focusItem: () => item.focusItem(),
32
+ select: () => item.select(),
33
+ get selected() {
34
+ return item.active;
35
+ },
36
+ words: slottedWords(item, ['']),
37
+ })),
25
38
  reserved: () => ['ArrowLeft', 'ArrowRight'],
26
39
  selects: () => false,
40
+ typeahead: (item) => item.words,
27
41
  });
28
42
  this.handleFocusIn = (event) => {
29
43
  const item = this.drilldown.rows.find((row) => row.contains(event.target));
30
- if (item && !item.disabled) {
44
+ if (item) {
31
45
  for (const row of this.drilldown.rows) {
32
46
  row.focusable = row === item;
33
47
  }
@@ -71,7 +85,7 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
71
85
  };
72
86
  }
73
87
  get items() {
74
- return this.drilldown.rows.filter((item) => !item.disabled);
88
+ return this.drilldown.rows;
75
89
  }
76
90
  placeTabStop() {
77
91
  const items = this.items;
@@ -109,10 +123,6 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
109
123
  this.removeEventListener('keydown', this.handleKeydown);
110
124
  this.removeEventListener('focusin', this.handleFocusIn);
111
125
  }
112
- willUpdate(changed) {
113
- super.willUpdate(changed);
114
- hostAria(this.internals, { label: this.label, role: 'menu' });
115
- }
116
126
  updated(changed) {
117
127
  super.updated(changed);
118
128
  const page = this.drilldown.page;
@@ -149,9 +159,15 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
149
159
  ${unsafeSVG(caretLeft.content)}
150
160
  </svg>
151
161
  </button>
152
- <span part="title">${this.drilldown.label}</span>
162
+ <span id="title" part="title">${this.drilldown.label}</span>
153
163
  </div>`}
154
- <div aria-busy=${this.loading ? 'true' : nothing} part="page">
164
+ <div
165
+ aria-busy=${this.loading ? 'true' : nothing}
166
+ aria-label=${this.drilldown.atRoot ? this.label || nothing : nothing}
167
+ aria-labelledby=${this.drilldown.atRoot ? nothing : 'title'}
168
+ part="page"
169
+ role="menu"
170
+ >
155
171
  <slot @slotchange=${(event) => this.countRows(event)}></slot>
156
172
  ${this.renderStatus(this.hasRows)}
157
173
  </div>${this.renderLive(this.hasRows)}`;