@fusion.dev/helix-headless 0.145.0 → 0.146.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 (278) hide show
  1. package/custom-elements.json +7373 -3849
  2. package/dist/accordion/item/accordion-item.d.ts +14 -0
  3. package/dist/accordion/item/accordion-item.js +16 -6
  4. package/dist/accordion/root/accordion-root.d.ts +8 -5
  5. package/dist/announcement/root/announcement-root.d.ts +3 -2
  6. package/dist/announcement/root/announcement-root.js +3 -1
  7. package/dist/app-header/root/app-header-root.d.ts +7 -2
  8. package/dist/app-header/root/app-header-root.js +9 -1
  9. package/dist/app-header/sectioning.d.ts +3 -1
  10. package/dist/app-header/sectioning.js +3 -2
  11. package/dist/avatar/group/avatar-group.d.ts +20 -14
  12. package/dist/avatar/group/avatar-group.js +17 -19
  13. package/dist/badge/root/badge-root.d.ts +3 -1
  14. package/dist/badge/root/badge-root.js +2 -2
  15. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  16. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  17. package/dist/bar-chart/stack.d.ts +15 -0
  18. package/dist/bar-chart/stack.js +19 -0
  19. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.js +50 -3
  21. package/dist/button/root/button-root.d.ts +26 -0
  22. package/dist/button/root/button-root.js +38 -18
  23. package/dist/button-group/root/button-group-root.d.ts +2 -1
  24. package/dist/button-group/root/button-group-root.js +5 -1
  25. package/dist/canvas/node/canvas-node.d.ts +4 -3
  26. package/dist/canvas/node/canvas-node.js +3 -2
  27. package/dist/canvas/root/canvas-root.js +2 -2
  28. package/dist/card/root/card-root.d.ts +24 -3
  29. package/dist/card/root/card-root.js +20 -8
  30. package/dist/carousel/root/carousel-root.d.ts +43 -4
  31. package/dist/carousel/root/carousel-root.js +40 -12
  32. package/dist/carousel/stops.d.ts +20 -0
  33. package/dist/carousel/stops.js +30 -0
  34. package/dist/chat/message/chat-message.js +5 -4
  35. package/dist/chat/naming.d.ts +5 -1
  36. package/dist/chat/naming.js +4 -2
  37. package/dist/chat/root/chat-root.d.ts +25 -3
  38. package/dist/chat/root/chat-root.js +22 -5
  39. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  40. package/dist/checkbox/root/checkbox-root.js +14 -1
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  42. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  43. package/dist/checkbox-group/select-all.d.ts +27 -0
  44. package/dist/checkbox-group/select-all.js +12 -0
  45. package/dist/code-block/highlight.d.ts +15 -0
  46. package/dist/code-block/highlight.js +4 -0
  47. package/dist/code-block/root/code-block-root.d.ts +49 -1
  48. package/dist/code-block/root/code-block-root.js +58 -3
  49. package/dist/color-input/root/color-input-root.d.ts +3 -0
  50. package/dist/color-input/root/color-input-root.js +6 -3
  51. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  52. package/dist/color-picker/root/color-picker-root.js +80 -21
  53. package/dist/color-picker/swatches.d.ts +12 -0
  54. package/dist/color-picker/swatches.js +26 -0
  55. package/dist/combobox/root/combobox-root.d.ts +43 -0
  56. package/dist/combobox/root/combobox-root.js +79 -15
  57. package/dist/command/root/command-root.d.ts +16 -1
  58. package/dist/command/root/command-root.js +22 -4
  59. package/dist/copy-button/root/copy-button-root.d.ts +5 -0
  60. package/dist/copy-button/root/copy-button-root.js +10 -3
  61. package/dist/data-table/index.d.ts +1 -1
  62. package/dist/data-table/index.js +1 -1
  63. package/dist/data-table/keys.d.ts +24 -0
  64. package/dist/data-table/keys.js +24 -0
  65. package/dist/data-table/root/data-table-root.d.ts +27 -18
  66. package/dist/data-table/root/data-table-root.js +20 -52
  67. package/dist/data-table/tree.d.ts +16 -1
  68. package/dist/data-table/tree.js +2 -3
  69. package/dist/date-input/root/date-input-root.d.ts +3 -1
  70. package/dist/date-input/root/date-input-root.js +18 -7
  71. package/dist/date-picker/root/date-picker-root.js +12 -6
  72. package/dist/dialog/description.js +15 -1
  73. package/dist/dialog/root/dialog-root.d.ts +8 -2
  74. package/dist/dialog/root/dialog-root.js +16 -1
  75. package/dist/divider/root/divider-root.d.ts +3 -0
  76. package/dist/divider/root/divider-root.js +2 -1
  77. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  78. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  79. package/dist/drawer/reveal.d.ts +8 -0
  80. package/dist/drawer/reveal.js +1 -0
  81. package/dist/drawer/root/drawer-root.d.ts +59 -0
  82. package/dist/drawer/root/drawer-root.js +63 -4
  83. package/dist/drilldown/item/drilldown-item.js +1 -1
  84. package/dist/drilldown/root/drilldown-root.d.ts +21 -3
  85. package/dist/drilldown/root/drilldown-root.js +21 -3
  86. package/dist/element-events.generated.js +31 -5
  87. package/dist/empty/root/empty-root.d.ts +3 -1
  88. package/dist/empty/root/empty-root.js +3 -2
  89. package/dist/file-input/root/file-input-root.d.ts +69 -6
  90. package/dist/file-input/root/file-input-root.js +82 -19
  91. package/dist/file-input/screen.d.ts +2 -1
  92. package/dist/filter-input/menu/filter-menu.d.ts +2 -0
  93. package/dist/filter-input/menu/filter-menu.js +12 -4
  94. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  95. package/dist/filter-input/root/filter-input-root.js +1 -1
  96. package/dist/filter-input/suggest.d.ts +28 -3
  97. package/dist/filter-input/suggest.js +18 -8
  98. package/dist/format-date/root/format-date-root.d.ts +9 -16
  99. package/dist/format-date/root/format-date-root.js +10 -27
  100. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  101. package/dist/heatmap/root/heatmap-root.js +34 -12
  102. package/dist/icon/root/icon-root.d.ts +12 -1
  103. package/dist/icon/root/icon-root.js +21 -10
  104. package/dist/icon/settle.d.ts +7 -0
  105. package/dist/icon/settle.js +10 -0
  106. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  107. package/dist/image/root/image-root.d.ts +5 -1
  108. package/dist/image/root/image-root.js +1 -1
  109. package/dist/input/root/input-root.d.ts +12 -2
  110. package/dist/input/root/input-root.js +11 -2
  111. package/dist/kbd/root/kbd-root.d.ts +35 -1
  112. package/dist/kbd/root/kbd-root.js +23 -4
  113. package/dist/legend/root/legend-root.d.ts +55 -8
  114. package/dist/legend/root/legend-root.js +55 -13
  115. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  116. package/dist/lightbox/root/lightbox-root.js +86 -19
  117. package/dist/lightbox/zoom-controller.d.ts +59 -0
  118. package/dist/lightbox/zoom-controller.js +128 -0
  119. package/dist/lightbox/zoom.d.ts +22 -0
  120. package/dist/lightbox/zoom.js +16 -0
  121. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  122. package/dist/line-chart/root/line-chart-root.js +21 -1
  123. package/dist/list/item/list-item.d.ts +2 -0
  124. package/dist/list/item/list-item.js +11 -2
  125. package/dist/list/root/list-root.d.ts +62 -13
  126. package/dist/list/root/list-root.js +70 -13
  127. package/dist/list/selection.d.ts +37 -7
  128. package/dist/list/selection.js +16 -7
  129. package/dist/listbox/root/listbox-root.d.ts +37 -1
  130. package/dist/listbox/root/listbox-root.js +49 -3
  131. package/dist/loader/busy.d.ts +10 -0
  132. package/dist/loader/busy.js +11 -0
  133. package/dist/loader/root/loader-root.d.ts +9 -2
  134. package/dist/loader/root/loader-root.js +23 -3
  135. package/dist/megamenu/root/megamenu-root.d.ts +51 -10
  136. package/dist/megamenu/root/megamenu-root.js +76 -5
  137. package/dist/menu/item/menu-item.d.ts +51 -2
  138. package/dist/menu/item/menu-item.js +47 -23
  139. package/dist/menu/root/menu-root.d.ts +14 -0
  140. package/dist/menu/root/menu-root.js +2 -2
  141. package/dist/meter/root/meter-root.d.ts +20 -1
  142. package/dist/meter/root/meter-root.js +11 -15
  143. package/dist/navigation/root/navigation-root.d.ts +2 -1
  144. package/dist/navigation/root/navigation-root.js +2 -2
  145. package/dist/notifications/root/notifications-root.d.ts +10 -3
  146. package/dist/notifications/root/notifications-root.js +19 -7
  147. package/dist/number-input/root/number-input-root.d.ts +17 -8
  148. package/dist/number-input/root/number-input-root.js +2 -7
  149. package/dist/object-inspector/root/object-inspector-root.d.ts +75 -27
  150. package/dist/object-inspector/root/object-inspector-root.js +117 -76
  151. package/dist/object-inspector/rows.d.ts +18 -0
  152. package/dist/object-inspector/rows.js +33 -0
  153. package/dist/option/root/option-root.d.ts +5 -3
  154. package/dist/outline/root/outline-root.d.ts +18 -0
  155. package/dist/outline/root/outline-root.js +23 -5
  156. package/dist/pagination/size/pagination-size.d.ts +1 -0
  157. package/dist/pagination/size/pagination-size.js +1 -1
  158. package/dist/pin-input/code.d.ts +10 -0
  159. package/dist/pin-input/code.js +13 -0
  160. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  161. package/dist/pin-input/root/pin-input-root.js +10 -11
  162. package/dist/popover/hide-outside.d.ts +14 -0
  163. package/dist/popover/hide-outside.js +41 -0
  164. package/dist/popover/root/popover-root.d.ts +57 -7
  165. package/dist/popover/root/popover-root.js +58 -3
  166. package/dist/progress/root/progress-root.d.ts +20 -0
  167. package/dist/progress/root/progress-root.js +15 -15
  168. package/dist/qr-code/export.d.ts +26 -1
  169. package/dist/qr-code/export.js +14 -0
  170. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  171. package/dist/qr-code/root/qr-code-root.js +58 -9
  172. package/dist/quote/marks.d.ts +8 -0
  173. package/dist/quote/marks.js +5 -0
  174. package/dist/quote/root/quote-root.d.ts +14 -2
  175. package/dist/quote/root/quote-root.js +23 -1
  176. package/dist/radio/root/radio-root.d.ts +6 -2
  177. package/dist/radio/root/radio-root.js +6 -1
  178. package/dist/rating/root/rating-root.d.ts +9 -4
  179. package/dist/rating/root/rating-root.js +31 -7
  180. package/dist/rating/steps.d.ts +7 -0
  181. package/dist/rating/steps.js +9 -0
  182. package/dist/scatter-chart/fit.d.ts +15 -0
  183. package/dist/scatter-chart/fit.js +35 -0
  184. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  185. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  186. package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
  187. package/dist/scroll-area/root/scroll-area-root.js +57 -173
  188. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  189. package/dist/scroll-area/scrollbar-controller.js +172 -0
  190. package/dist/scroll-area/scrollbar.d.ts +27 -0
  191. package/dist/scroll-area/scrollbar.js +9 -0
  192. package/dist/select/root/select-root.d.ts +15 -0
  193. package/dist/select/root/select-root.js +18 -6
  194. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  195. package/dist/skeleton/root/skeleton-root.js +4 -2
  196. package/dist/skip-link/root/skip-link-root.js +2 -2
  197. package/dist/slider/root/slider-root.d.ts +41 -4
  198. package/dist/slider/root/slider-root.js +23 -3
  199. package/dist/sparkline/readings.d.ts +18 -0
  200. package/dist/sparkline/readings.js +19 -0
  201. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  202. package/dist/sparkline/root/sparkline-root.js +118 -23
  203. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  204. package/dist/splitter/root/splitter-root.d.ts +7 -12
  205. package/dist/splitter/root/splitter-root.js +209 -204
  206. package/dist/stat/root/stat-root.d.ts +14 -5
  207. package/dist/stat/root/stat-root.js +21 -5
  208. package/dist/steps/reach.d.ts +5 -0
  209. package/dist/steps/reach.js +3 -0
  210. package/dist/steps/root/steps-root.d.ts +49 -3
  211. package/dist/steps/root/steps-root.js +44 -5
  212. package/dist/steps/step/step.d.ts +7 -0
  213. package/dist/steps/step/step.js +7 -2
  214. package/dist/switch/root/switch-root.d.ts +10 -0
  215. package/dist/table/column/table-column.d.ts +0 -10
  216. package/dist/table/column/table-column.js +3 -19
  217. package/dist/table/root/table-root.d.ts +31 -10
  218. package/dist/table/root/table-root.js +2 -13
  219. package/dist/tabs/panel/tab-panel.d.ts +16 -3
  220. package/dist/tabs/panel/tab-panel.js +34 -5
  221. package/dist/tabs/root/tabs-root.d.ts +12 -0
  222. package/dist/tabs/root/tabs-root.js +1 -1
  223. package/dist/tabs/tab/tab.d.ts +5 -0
  224. package/dist/tabs/tab/tab.js +5 -2
  225. package/dist/tag/group/tag-group.d.ts +31 -4
  226. package/dist/tag/group/tag-group.js +46 -7
  227. package/dist/tag/root/tag-root.js +9 -2
  228. package/dist/textarea/root/textarea-root.d.ts +28 -1
  229. package/dist/textarea/root/textarea-root.js +40 -1
  230. package/dist/time-input/root/time-input-root.d.ts +5 -1
  231. package/dist/time-input/root/time-input-root.js +16 -8
  232. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  233. package/dist/time-picker/root/time-picker-root.js +7 -10
  234. package/dist/time-picker/wheel-name.d.ts +9 -0
  235. package/dist/time-picker/wheel-name.js +15 -0
  236. package/dist/timeline/group/timeline-group.js +2 -2
  237. package/dist/toast/item/toast-item.d.ts +14 -1
  238. package/dist/toast/item/toast-item.js +22 -5
  239. package/dist/toast/root/toast-root.d.ts +6 -0
  240. package/dist/toast/root/toast-root.js +16 -1
  241. package/dist/toggle/group/toggle-group.d.ts +24 -3
  242. package/dist/toggle/group/toggle-group.js +34 -5
  243. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  244. package/dist/tooltip/root/tooltip-root.js +9 -1
  245. package/dist/tour/back.d.ts +10 -0
  246. package/dist/tour/back.js +8 -0
  247. package/dist/tour/root/tour-root.d.ts +30 -2
  248. package/dist/tour/root/tour-root.js +34 -8
  249. package/dist/tree/item/tree-item.d.ts +7 -3
  250. package/dist/tree/item/tree-item.js +3 -0
  251. package/dist/tree/root/tree-root.d.ts +24 -3
  252. package/dist/tree/root/tree-root.js +32 -13
  253. package/dist/tree/selection.js +2 -15
  254. package/dist/trend/root/trend-root.d.ts +43 -18
  255. package/dist/trend/root/trend-root.js +31 -6
  256. package/dist/video/media-events.d.ts +13 -18
  257. package/dist/video/media-events.js +1 -5
  258. package/dist/video/root/video-root.d.ts +18 -5
  259. package/dist/video/root/video-root.js +19 -10
  260. package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
  261. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  262. package/dist/video-playlist/root/video-playlist-root.d.ts +7 -1
  263. package/dist/virtual-list/fill.d.ts +0 -8
  264. package/dist/virtual-list/fill.js +1 -17
  265. package/dist/virtual-list/plan.d.ts +49 -0
  266. package/dist/virtual-list/plan.js +16 -0
  267. package/dist/virtual-list/root/virtual-list-root.d.ts +114 -13
  268. package/dist/virtual-list/root/virtual-list-root.js +183 -40
  269. package/lint.json +1 -1
  270. package/package.json +8 -8
  271. package/types/jsx.d.ts +4577 -835
  272. package/types/vue.d.ts +926 -168
  273. package/dist/chat/relative-clock.d.ts +0 -39
  274. package/dist/chat/relative-clock.js +0 -31
  275. package/dist/data-table/root/order.d.ts +0 -141
  276. package/dist/data-table/root/order.js +0 -76
  277. package/dist/tag/selection.d.ts +0 -10
  278. package/dist/tag/selection.js +0 -12
@@ -30,10 +30,20 @@ declare const EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inli
30
30
  * and draws the thumb from the two custom properties written on each
31
31
  * scrollbar. An axis whose `overflow` is `hidden` gets no scrollbar.
32
32
  *
33
+ * **`orientation` keeps the content to one axis.** `vertical` scrolls up and
34
+ * down only, and `horizontal` sideways only, so the other axis has no
35
+ * scrollbar, the browser's or the component's, and clips what is past it.
36
+ * Leave it unset to scroll both ways.
37
+ *
33
38
  * The viewport's `scroll` and `scrollend` are sent again from the host, which
34
- * is the element you hold. In React, bind them with `onScroll` and
39
+ * is the element you hold. A thumb dragged across the content sends one
40
+ * `scrollend`, once it is let go. In React, bind them with `onScroll` and
35
41
  * `onScrollEnd`.
36
42
  *
43
+ * **Keyboard.** The viewport is the tab stop while the content overflows, and
44
+ * the browser's scrolling keys move it: the arrow keys, Page Up and Page Down,
45
+ * Home and End, and Space. The scrollbars take no focus.
46
+ *
37
47
  * @since 0.1.0
38
48
  * @status stable
39
49
  * @category layout
@@ -43,7 +53,7 @@ declare const EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inli
43
53
  * @slot - The content that scrolls.
44
54
  *
45
55
  * @event {Event} scroll - The content scrolled. Sent from the host, because the viewport's own does not leave the shadow root. Does not bubble.
46
- * @event {Event} scrollend - The content stopped scrolling. Sent from the host, as `scroll` is. Does not bubble.
56
+ * @event {Event} scrollend - The content stopped scrolling. Sent from the host, as `scroll` is, and once for a thumb dragged across the content. Does not bubble.
47
57
  *
48
58
  * @csspart corner - The square where the two scrollbars meet, under `scrollbars`. Hidden unless both are drawn.
49
59
  * @csspart edges - The layer that draws the cues on the inline start and end edges.
@@ -80,6 +90,11 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
80
90
  * Without one there is no region: see the note on the class.
81
91
  */
82
92
  label: string;
93
+ /**
94
+ * The one axis the content scrolls along: `vertical` or `horizontal`. The
95
+ * other axis clips what is past it and has no scrollbar. Unset scrolls both.
96
+ */
97
+ orientation?: 'horizontal' | 'vertical';
83
98
  /**
84
99
  * Draws scrollbars of the component's own in place of the browser's, and
85
100
  * says when they show.
@@ -93,18 +108,8 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
93
108
  * Absent keeps the browser's scrollbars.
94
109
  */
95
110
  scrollbars?: 'always' | 'auto' | 'hover' | 'scroll';
96
- /** What each scrollbar shows, measured, and `undefined` until it has been. */
97
- private bars;
98
- /** Whether the content moved, or the pointer left, within the hide delay. */
99
- private active;
100
- /** Whether the pointer is over the scroll area. */
101
- private hovered;
102
- /** Whether the pointer is over a scrollbar. */
103
- private over;
104
- /** The thumb being dragged, if one is. */
105
- private drag;
106
- /** Puts the scrollbars away once nothing has moved for the hide delay. */
107
- private readonly hide;
111
+ /** The scrollbars drawn under `scrollbars`: what they show, when, and the drag. */
112
+ private readonly bars;
108
113
  /**
109
114
  * Which edges have content past them, measured rather than guessed.
110
115
  */
@@ -137,45 +142,9 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
137
142
  * costs.
138
143
  */
139
144
  private measure;
140
- /** One axis of the box, counted from its start whichever way the line runs. */
141
- private extent;
142
- /**
143
- * Reads what each scrollbar shows off the box.
144
- *
145
- * An axis scrolls unless its `overflow` says it cannot. An empty reading is a
146
- * harness with no layout, where the mark `core` puts on the viewport is
147
- * `overflow: auto` on both axes, so it counts as one that scrolls.
148
- *
149
- * Written only on a change, so a scroll that moves no thumb renders nothing.
150
- */
151
- private readBars;
152
- /**
153
- * Shows the scrollbars and starts the wait that puts them away again, under
154
- * `scroll` and `hover`.
155
- */
156
- private wake;
157
- /** Sends the content to `offset` along an axis, counted from its start. */
158
- private scrollAlong;
159
- /**
160
- * Takes hold of a thumb, or presses the track.
161
- *
162
- * A press on the track sends the thumb's middle to the press first, and the
163
- * drag carries on from there, so a press and a drag are one gesture as they
164
- * are on the browser's own scrollbar. `preventDefault` keeps the press from
165
- * starting a text selection, and from moving focus off the viewport.
166
- */
167
- private grab;
168
- private readonly handleVerticalDown;
169
- private readonly handleHorizontalDown;
170
- /** Moves the content with a dragged thumb. Nothing while no thumb is held. */
171
- private readonly handleDragMove;
172
- private readonly handleDragEnd;
173
- private readonly handleBarEnter;
174
- private readonly handleBarLeave;
175
- private readonly handleEnter;
176
- private readonly handleLeave;
177
145
  /** Measures, shows the scrollbars, and sends the event on from the host. */
178
146
  private readonly handleScroll;
147
+ /** Sends the event on from the host, except the ones a thumb drag holds back. */
179
148
  private readonly handleScrollEnd;
180
149
  connectedCallback(): void;
181
150
  disconnectedCallback(): void;
@@ -184,6 +153,8 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
184
153
  private watchContent;
185
154
  protected updated(changed: PropertyValues): void;
186
155
  private readonly handleSlotChange;
156
+ /** The axis `orientation` takes away, clipped where the content would overflow it. */
157
+ private get clipped();
187
158
  protected render(): TemplateResult;
188
159
  /**
189
160
  * The scrollbars, the thumbs in them and the corner.
@@ -4,20 +4,22 @@ 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 { capturePointer, customElement, DelayController, HelixElement, isRtl, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
- import { hasScrollbar, offsetAt, scrollFraction, scrollPerPixel, showsScrollbar, thumbFraction, } from '../scrollbar.js';
10
+ import { ScrollbarController } from '../scrollbar-controller.js';
11
11
  const EDGES = ['block-start', 'block-end', 'inline-start', 'inline-end'];
12
12
  let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.hideDelay = 600;
16
16
  this.label = '';
17
- this.active = false;
18
- this.hovered = false;
19
- this.over = false;
20
- this.hide = new DelayController(this, { renders: false });
17
+ this.bars = new ScrollbarController(this, {
18
+ box: () => this.scroller,
19
+ hideDelay: () => this.hideDelay,
20
+ mode: () => this.scrollbars,
21
+ scrollEnd: () => this.dispatchEvent(new Event('scrollend')),
22
+ });
21
23
  this.more = [];
22
24
  this.scrolls = false;
23
25
  this.measure = () => {
@@ -26,72 +28,39 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
26
28
  return;
27
29
  }
28
30
  const slack = 1;
31
+ const block = this.orientation !== 'horizontal';
32
+ const inline = this.orientation !== 'vertical';
29
33
  const found = [];
30
- if (box.scrollTop > slack) {
34
+ if (block && box.scrollTop > slack) {
31
35
  found.push('block-start');
32
36
  }
33
- if (box.scrollTop + box.clientHeight < box.scrollHeight - slack) {
37
+ if (block && box.scrollTop + box.clientHeight < box.scrollHeight - slack) {
34
38
  found.push('block-end');
35
39
  }
36
40
  const along = Math.abs(box.scrollLeft);
37
- if (along > slack) {
41
+ if (inline && along > slack) {
38
42
  found.push('inline-start');
39
43
  }
40
- if (along + box.clientWidth < box.scrollWidth - slack) {
44
+ if (inline && along + box.clientWidth < box.scrollWidth - slack) {
41
45
  found.push('inline-end');
42
46
  }
43
47
  this.more = found;
44
- this.scrolls = box.scrollHeight > box.clientHeight || box.scrollWidth > box.clientWidth;
48
+ this.scrolls =
49
+ (block && box.scrollHeight > box.clientHeight) ||
50
+ (inline && box.scrollWidth > box.clientWidth);
45
51
  if (this.scrollbars) {
46
- this.readBars(box);
47
- }
48
- };
49
- this.handleVerticalDown = (event) => {
50
- this.grab(event, 'vertical');
51
- };
52
- this.handleHorizontalDown = (event) => {
53
- this.grab(event, 'horizontal');
54
- };
55
- this.handleDragMove = (event) => {
56
- const drag = this.drag;
57
- const box = this.scroller;
58
- if (!drag || !box) {
59
- return;
60
- }
61
- const pointer = drag.axis === 'vertical' ? event.clientY : event.clientX;
62
- this.scrollAlong(box, drag.axis, drag.from + (pointer - drag.pointer) * drag.sign * drag.perPixel);
63
- };
64
- this.handleDragEnd = () => {
65
- if (!this.drag) {
66
- return;
67
- }
68
- this.drag = undefined;
69
- this.wake();
70
- this.requestUpdate();
71
- };
72
- this.handleBarEnter = () => {
73
- this.over = true;
74
- };
75
- this.handleBarLeave = () => {
76
- this.over = false;
77
- this.wake();
78
- };
79
- this.handleEnter = () => {
80
- this.hovered = true;
81
- };
82
- this.handleLeave = () => {
83
- this.hovered = false;
84
- if (this.scrollbars === 'hover') {
85
- this.wake();
52
+ this.bars.read(box);
86
53
  }
87
54
  };
88
55
  this.handleScroll = (event) => {
89
56
  this.measure();
90
- this.wake();
57
+ this.bars.wake();
91
58
  this.relayNativeEvent(event);
92
59
  };
93
60
  this.handleScrollEnd = (event) => {
94
- this.relayNativeEvent(event);
61
+ if (!this.bars.holdsScrollEnd()) {
62
+ this.relayNativeEvent(event);
63
+ }
95
64
  };
96
65
  this.handleSlotChange = (event) => {
97
66
  const slot = event.target;
@@ -104,84 +73,8 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
104
73
  get scroller() {
105
74
  return this.partNamed('viewport');
106
75
  }
107
- extent(box, axis) {
108
- return axis === 'vertical'
109
- ? { client: box.clientHeight, offset: box.scrollTop, scroll: box.scrollHeight }
110
- : { client: box.clientWidth, offset: Math.abs(box.scrollLeft), scroll: box.scrollWidth };
111
- }
112
- readBars(box) {
113
- const mode = this.scrollbars ?? 'auto';
114
- const style = getComputedStyle(box);
115
- const bar = (axis, overflow) => {
116
- const extent = this.extent(box, axis);
117
- return {
118
- along: scrollFraction(extent),
119
- drawn: hasScrollbar(mode, !['clip', 'hidden', 'visible'].includes(overflow), extent.offset > 1 || extent.client < extent.scroll - 1),
120
- thumb: thumbFraction(extent),
121
- };
122
- };
123
- const next = {
124
- horizontal: bar('horizontal', style.overflowX),
125
- vertical: bar('vertical', style.overflowY),
126
- };
127
- if (JSON.stringify(next) !== JSON.stringify(this.bars)) {
128
- this.bars = next;
129
- }
130
- }
131
- wake() {
132
- if (this.scrollbars !== 'scroll' && this.scrollbars !== 'hover') {
133
- return;
134
- }
135
- this.active = true;
136
- this.hide.start(this.hideDelay, () => {
137
- this.active = false;
138
- });
139
- }
140
- scrollAlong(box, axis, offset) {
141
- box.scrollTo(axis === 'vertical'
142
- ? { behavior: 'instant', top: offset }
143
- : { behavior: 'instant', left: isRtl(box) ? -offset : offset });
144
- }
145
- grab(event, axis) {
146
- const box = this.scroller;
147
- const bar = event.currentTarget;
148
- const thumb = bar.querySelector('[part~="thumb"]');
149
- if (event.button !== 0 || !box || !thumb) {
150
- return;
151
- }
152
- event.preventDefault();
153
- const vertical = axis === 'vertical';
154
- const rtl = !vertical && isRtl(box);
155
- const track = bar.getBoundingClientRect();
156
- const held = thumb.getBoundingClientRect();
157
- const length = vertical ? track.height : track.width;
158
- const size = vertical ? held.height : held.width;
159
- const extent = this.extent(box, axis);
160
- const pointer = vertical ? event.clientY : event.clientX;
161
- let from = extent.offset;
162
- if (!thumb.contains(event.target)) {
163
- const along = vertical
164
- ? pointer - track.top
165
- : rtl
166
- ? track.right - pointer
167
- : pointer - track.left;
168
- from = offsetAt(extent, along, length, size);
169
- this.scrollAlong(box, axis, from);
170
- }
171
- this.drag = {
172
- axis,
173
- from,
174
- perPixel: scrollPerPixel(extent, length, size),
175
- pointer,
176
- sign: rtl ? -1 : 1,
177
- };
178
- capturePointer(bar, event.pointerId);
179
- this.requestUpdate();
180
- }
181
76
  connectedCallback() {
182
77
  super.connectedCallback();
183
- this.addEventListener('pointerenter', this.handleEnter);
184
- this.addEventListener('pointerleave', this.handleLeave);
185
78
  this.watcher = new ResizeObserver(this.measure);
186
79
  if (this.hasUpdated) {
187
80
  this.watchContent();
@@ -189,14 +82,8 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
189
82
  }
190
83
  disconnectedCallback() {
191
84
  super.disconnectedCallback();
192
- this.removeEventListener('pointerenter', this.handleEnter);
193
- this.removeEventListener('pointerleave', this.handleLeave);
194
85
  this.watcher?.disconnect();
195
86
  this.watcher = undefined;
196
- this.drag = undefined;
197
- this.active = false;
198
- this.hovered = false;
199
- this.over = false;
200
87
  }
201
88
  firstUpdated(changed) {
202
89
  super.firstUpdated?.(changed);
@@ -217,10 +104,13 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
217
104
  }
218
105
  updated(changed) {
219
106
  super.updated?.(changed);
220
- if (changed.has('scrollbars') && this.hasUpdated && this.scrollbars) {
107
+ if (changed.has('orientation') && this.hasUpdated) {
108
+ this.measure();
109
+ }
110
+ else if (changed.has('scrollbars') && this.scrollbars) {
221
111
  const box = this.scroller;
222
112
  if (box) {
223
- this.readBars(box);
113
+ this.bars.read(box);
224
114
  }
225
115
  }
226
116
  this.toggleState('scrolls', this.scrolls);
@@ -228,14 +118,21 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
228
118
  this.toggleState('more-block-end', this.more.includes('block-end'));
229
119
  this.toggleState('more-inline-start', this.more.includes('inline-start'));
230
120
  this.toggleState('more-inline-end', this.more.includes('inline-end'));
231
- const drawn = this.scrollbars ? this.bars : undefined;
121
+ const drawn = this.scrollbars ? this.bars.bars : undefined;
232
122
  this.toggleState('scrollbar-horizontal', drawn?.horizontal.drawn === true);
233
123
  this.toggleState('scrollbar-vertical', drawn?.vertical.drawn === true);
234
124
  }
125
+ get clipped() {
126
+ if (this.orientation === 'vertical') {
127
+ return 'overflow-x: hidden';
128
+ }
129
+ return this.orientation === 'horizontal' ? 'overflow-y: hidden' : nothing;
130
+ }
235
131
  render() {
236
132
  return html `<div
237
133
  data-scroller
238
134
  part="viewport"
135
+ style=${this.clipped}
239
136
  role=${this.label ? 'region' : nothing}
240
137
  aria-label=${this.label || nothing}
241
138
  tabindex=${this.scrolls ? '0' : nothing}
@@ -252,16 +149,12 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
252
149
  <div
253
150
  part="edges"
254
151
  aria-hidden="true"
255
- ></div>${this.scrollbars ? this.renderScrollbars(this.scrollbars) : nothing}`;
152
+ ></div>${this.scrollbars ? this.renderScrollbars() : nothing}`;
256
153
  }
257
- renderScrollbars(mode) {
258
- const bars = this.bars;
259
- const moment = {
260
- active: this.active,
261
- held: this.over || this.drag !== undefined,
262
- hovered: this.hovered,
263
- };
264
- const shown = showsScrollbar(mode, moment);
154
+ renderScrollbars() {
155
+ const controller = this.bars;
156
+ const bars = controller.bars;
157
+ const shown = controller.shown;
265
158
  const facts = (bar) => bar
266
159
  ? `--scroll-area-thumb-fraction: ${bar.thumb}; --scroll-area-scroll-fraction: ${bar.along}`
267
160
  : nothing;
@@ -272,13 +165,13 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
272
165
  aria-hidden="true"
273
166
  ?hidden=${!vertical}
274
167
  style=${facts(bars?.vertical)}
275
- @pointerdown=${this.handleVerticalDown}
276
- @pointermove=${this.handleDragMove}
277
- @pointerup=${this.handleDragEnd}
278
- @pointercancel=${this.handleDragEnd}
279
- @lostpointercapture=${this.handleDragEnd}
280
- @pointerenter=${this.handleBarEnter}
281
- @pointerleave=${this.handleBarLeave}
168
+ @pointerdown=${controller.handleVerticalDown}
169
+ @pointermove=${controller.handleDragMove}
170
+ @pointerup=${controller.handleDragEnd}
171
+ @pointercancel=${controller.handleDragEnd}
172
+ @lostpointercapture=${controller.handleDragEnd}
173
+ @pointerenter=${controller.handleBarEnter}
174
+ @pointerleave=${controller.handleBarLeave}
282
175
  >
283
176
  <div part="thumb thumb-vertical"></div>
284
177
  </div>
@@ -287,13 +180,13 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
287
180
  aria-hidden="true"
288
181
  ?hidden=${!horizontal}
289
182
  style=${facts(bars?.horizontal)}
290
- @pointerdown=${this.handleHorizontalDown}
291
- @pointermove=${this.handleDragMove}
292
- @pointerup=${this.handleDragEnd}
293
- @pointercancel=${this.handleDragEnd}
294
- @lostpointercapture=${this.handleDragEnd}
295
- @pointerenter=${this.handleBarEnter}
296
- @pointerleave=${this.handleBarLeave}
183
+ @pointerdown=${controller.handleHorizontalDown}
184
+ @pointermove=${controller.handleDragMove}
185
+ @pointerup=${controller.handleDragEnd}
186
+ @pointercancel=${controller.handleDragEnd}
187
+ @lostpointercapture=${controller.handleDragEnd}
188
+ @pointerenter=${controller.handleBarEnter}
189
+ @pointerleave=${controller.handleBarLeave}
297
190
  >
298
191
  <div part="thumb thumb-horizontal"></div>
299
192
  </div>
@@ -310,21 +203,12 @@ __decorate([
310
203
  __decorate([
311
204
  property()
312
205
  ], HelixHeadlessScrollArea.prototype, "label", void 0);
206
+ __decorate([
207
+ property()
208
+ ], HelixHeadlessScrollArea.prototype, "orientation", void 0);
313
209
  __decorate([
314
210
  property({ reflect: true })
315
211
  ], HelixHeadlessScrollArea.prototype, "scrollbars", void 0);
316
- __decorate([
317
- state()
318
- ], HelixHeadlessScrollArea.prototype, "bars", void 0);
319
- __decorate([
320
- state()
321
- ], HelixHeadlessScrollArea.prototype, "active", void 0);
322
- __decorate([
323
- state()
324
- ], HelixHeadlessScrollArea.prototype, "hovered", void 0);
325
- __decorate([
326
- state()
327
- ], HelixHeadlessScrollArea.prototype, "over", void 0);
328
212
  __decorate([
329
213
  state()
330
214
  ], HelixHeadlessScrollArea.prototype, "more", void 0);
@@ -0,0 +1,111 @@
1
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import { type Axis, type Scrollbars } from './scrollbar.js';
3
+ /** What one drawn scrollbar shows: whether it is there, and its thumb's facts. */
4
+ export interface Bar {
5
+ /** Whether the axis has a scrollbar at all. See `hasScrollbar`. */
6
+ drawn: boolean;
7
+ /** How far along the axis is scrolled, from 0 to 1. */
8
+ along: number;
9
+ /** The share of the track the thumb covers, from 0 to 1. */
10
+ thumb: number;
11
+ }
12
+ /** What the controller needs of the scroll area it serves. */
13
+ export interface ScrollbarOptions {
14
+ /** The box that scrolls, or null before it renders. */
15
+ box: () => HTMLElement | null;
16
+ /** The host's `hide-delay`, in milliseconds. */
17
+ hideDelay: () => number;
18
+ /** The host's `scrollbars`, or undefined for the browser's own. */
19
+ mode: () => Scrollbars | undefined;
20
+ /** Sends a `scrollend` from the host, for the one a drag held back. */
21
+ scrollEnd: () => void;
22
+ }
23
+ /**
24
+ * The scrollbars a scroll area draws under `scrollbars`: what each shows, when
25
+ * they show, and the thumb a pointer drags.
26
+ *
27
+ * **A controller, so the element only draws.** It holds the drag, whether the
28
+ * pointer is over the area or a scrollbar, and the wait that puts the
29
+ * scrollbars away, and asks the host to render when any of them changes.
30
+ *
31
+ * **A drag sends one `scrollend`.** The thumb moves the content by
32
+ * `scrollTo`, and the browser ends each of those steps with a `scrollend` of
33
+ * its own, so a drag sent a burst of them. While a thumb is held they are held
34
+ * back, and once it is let go one is sent: the browser's own for the last
35
+ * step, or the held one where none comes.
36
+ */
37
+ export declare class ScrollbarController implements ReactiveController {
38
+ /** What each scrollbar shows, measured, and `undefined` until it has been. */
39
+ bars: Record<Axis, Bar> | undefined;
40
+ /** Whether the content moved, or the pointer left, within the hide delay. */
41
+ active: boolean;
42
+ /** Whether the pointer is over the scroll area. */
43
+ hovered: boolean;
44
+ /** Whether the pointer is over a scrollbar. */
45
+ over: boolean;
46
+ /** The thumb being dragged, if one is. */
47
+ private drag;
48
+ /** Whether a `scrollend` was held back by a drag and not sent yet. */
49
+ private heldEnd;
50
+ private readonly host;
51
+ private readonly options;
52
+ /** Puts the scrollbars away once nothing has moved for the hide delay. */
53
+ private readonly hide;
54
+ /** Waits after a drag for the browser's last `scrollend`. */
55
+ private readonly settle;
56
+ constructor(host: ReactiveControllerHost & HTMLElement, options: ScrollbarOptions);
57
+ hostConnected(): void;
58
+ hostDisconnected(): void;
59
+ /** Whether a thumb is held. */
60
+ get dragging(): boolean;
61
+ /** Whether the scrollbars that are drawn are showing at this moment. */
62
+ get shown(): boolean;
63
+ /**
64
+ * Reads what each scrollbar shows off the box.
65
+ *
66
+ * An axis scrolls unless its `overflow` says it cannot. An empty reading is a
67
+ * harness with no layout, where the mark `core` puts on the viewport is
68
+ * `overflow: auto` on both axes, so it counts as one that scrolls.
69
+ *
70
+ * Asks for a render only on a change, so a scroll that moves no thumb
71
+ * renders nothing.
72
+ */
73
+ read(box: HTMLElement): void;
74
+ /**
75
+ * Shows the scrollbars and starts the wait that puts them away again, under
76
+ * `scroll` and `hover`.
77
+ */
78
+ wake(): void;
79
+ /**
80
+ * Whether to hold back a `scrollend` the viewport sent: true while a thumb is
81
+ * held. One arriving after the drag ends is the browser's last, and stands
82
+ * for the one held back.
83
+ */
84
+ holdsScrollEnd(): boolean;
85
+ /** Writes one of the moment's facts, and renders where it changed. */
86
+ private set;
87
+ /** Sends the content to `offset` along an axis, counted from its start. */
88
+ private scrollAlong;
89
+ /**
90
+ * Takes hold of a thumb, or presses the track.
91
+ *
92
+ * A press on the track sends the thumb's middle to the press first, and the
93
+ * drag carries on from there, so a press and a drag are one gesture as they
94
+ * are on the browser's own scrollbar. `preventDefault` keeps the press from
95
+ * starting a text selection, and from moving focus off the viewport.
96
+ */
97
+ private grab;
98
+ readonly handleVerticalDown: (event: PointerEvent) => void;
99
+ readonly handleHorizontalDown: (event: PointerEvent) => void;
100
+ /** Moves the content with a dragged thumb. Nothing while no thumb is held. */
101
+ readonly handleDragMove: (event: PointerEvent) => void;
102
+ /**
103
+ * Lets go of the thumb. A `scrollend` the drag held back goes out once the
104
+ * browser's last one has had a frame or two to arrive and has not.
105
+ */
106
+ readonly handleDragEnd: () => void;
107
+ readonly handleBarEnter: () => void;
108
+ readonly handleBarLeave: () => void;
109
+ private readonly handleEnter;
110
+ private readonly handleLeave;
111
+ }