@fusion.dev/helix-headless 0.144.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 (319) hide show
  1. package/custom-elements.json +15195 -4240
  2. package/dist/accordion/item/accordion-item.d.ts +62 -12
  3. package/dist/accordion/item/accordion-item.js +41 -10
  4. package/dist/accordion/root/accordion-root.d.ts +14 -5
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +24 -3
  7. package/dist/announcement/root/announcement-root.js +39 -2
  8. package/dist/app-header/root/app-header-root.d.ts +12 -0
  9. package/dist/app-header/root/app-header-root.js +13 -1
  10. package/dist/app-header/sectioning.d.ts +9 -0
  11. package/dist/app-header/sectioning.js +27 -0
  12. package/dist/avatar/group/avatar-group.d.ts +20 -14
  13. package/dist/avatar/group/avatar-group.js +17 -19
  14. package/dist/badge/root/badge-root.d.ts +3 -1
  15. package/dist/badge/root/badge-root.js +2 -2
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  17. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  18. package/dist/bar-chart/stack.d.ts +15 -0
  19. package/dist/bar-chart/stack.js +19 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
  22. package/dist/button/root/button-root.d.ts +26 -0
  23. package/dist/button/root/button-root.js +38 -18
  24. package/dist/button-group/root/button-group-root.d.ts +2 -1
  25. package/dist/button-group/root/button-group-root.js +5 -1
  26. package/dist/canvas/node/canvas-node.d.ts +4 -3
  27. package/dist/canvas/node/canvas-node.js +3 -2
  28. package/dist/canvas/root/canvas-root.d.ts +38 -3
  29. package/dist/canvas/root/canvas-root.js +123 -42
  30. package/dist/card/root/card-root.d.ts +24 -3
  31. package/dist/card/root/card-root.js +20 -8
  32. package/dist/carousel/root/carousel-root.d.ts +133 -4
  33. package/dist/carousel/root/carousel-root.js +174 -24
  34. package/dist/carousel/stops.d.ts +20 -0
  35. package/dist/carousel/stops.js +30 -0
  36. package/dist/chat/composer/chat-composer.d.ts +38 -6
  37. package/dist/chat/composer/chat-composer.js +42 -9
  38. package/dist/chat/message/chat-message.d.ts +32 -1
  39. package/dist/chat/message/chat-message.js +27 -10
  40. package/dist/chat/naming.d.ts +26 -0
  41. package/dist/chat/naming.js +14 -0
  42. package/dist/chat/root/chat-root.d.ts +58 -0
  43. package/dist/chat/root/chat-root.js +43 -3
  44. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  45. package/dist/checkbox/root/checkbox-root.js +14 -1
  46. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  47. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  48. package/dist/checkbox-group/select-all.d.ts +27 -0
  49. package/dist/checkbox-group/select-all.js +12 -0
  50. package/dist/code-block/highlight.d.ts +15 -0
  51. package/dist/code-block/highlight.js +4 -0
  52. package/dist/code-block/root/code-block-root.d.ts +57 -2
  53. package/dist/code-block/root/code-block-root.js +63 -8
  54. package/dist/color-input/root/color-input-root.d.ts +3 -0
  55. package/dist/color-input/root/color-input-root.js +6 -3
  56. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  57. package/dist/color-picker/root/color-picker-root.js +80 -21
  58. package/dist/color-picker/swatches.d.ts +12 -0
  59. package/dist/color-picker/swatches.js +26 -0
  60. package/dist/combobox/root/combobox-root.d.ts +43 -0
  61. package/dist/combobox/root/combobox-root.js +79 -15
  62. package/dist/command/root/command-root.d.ts +16 -1
  63. package/dist/command/root/command-root.js +22 -4
  64. package/dist/copy-button/root/copy-button-root.d.ts +26 -1
  65. package/dist/copy-button/root/copy-button-root.js +12 -5
  66. package/dist/data-table/index.d.ts +1 -1
  67. package/dist/data-table/index.js +1 -1
  68. package/dist/data-table/keys.d.ts +24 -0
  69. package/dist/data-table/keys.js +24 -0
  70. package/dist/data-table/root/data-table-root.d.ts +170 -13
  71. package/dist/data-table/root/data-table-root.js +294 -52
  72. package/dist/data-table/tree.d.ts +55 -0
  73. package/dist/data-table/tree.js +54 -0
  74. package/dist/date-input/root/date-input-root.d.ts +3 -1
  75. package/dist/date-input/root/date-input-root.js +18 -7
  76. package/dist/date-picker/root/date-picker-root.js +12 -6
  77. package/dist/description-list/item/description-list-item.d.ts +17 -2
  78. package/dist/description-list/item/description-list-item.js +15 -2
  79. package/dist/description-list/root/description-list-root.d.ts +27 -1
  80. package/dist/description-list/root/description-list-root.js +26 -1
  81. package/dist/dialog/description.js +15 -1
  82. package/dist/dialog/root/dialog-root.d.ts +8 -2
  83. package/dist/dialog/root/dialog-root.js +16 -1
  84. package/dist/divider/root/divider-root.d.ts +3 -0
  85. package/dist/divider/root/divider-root.js +2 -1
  86. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  87. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  88. package/dist/drawer/reveal.d.ts +8 -0
  89. package/dist/drawer/reveal.js +1 -0
  90. package/dist/drawer/root/drawer-root.d.ts +59 -0
  91. package/dist/drawer/root/drawer-root.js +63 -4
  92. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  93. package/dist/drilldown/item/drilldown-item.js +8 -5
  94. package/dist/drilldown/root/drilldown-root.d.ts +29 -0
  95. package/dist/drilldown/root/drilldown-root.js +28 -5
  96. package/dist/element-events.generated.js +83 -12
  97. package/dist/empty/root/empty-root.d.ts +3 -1
  98. package/dist/empty/root/empty-root.js +3 -2
  99. package/dist/file-input/root/file-input-root.d.ts +69 -6
  100. package/dist/file-input/root/file-input-root.js +82 -19
  101. package/dist/file-input/screen.d.ts +2 -1
  102. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  103. package/dist/filter-input/menu/filter-menu.js +16 -4
  104. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  105. package/dist/filter-input/root/filter-input-root.js +1 -1
  106. package/dist/filter-input/suggest.d.ts +28 -3
  107. package/dist/filter-input/suggest.js +18 -8
  108. package/dist/format-date/root/format-date-root.d.ts +9 -16
  109. package/dist/format-date/root/format-date-root.js +10 -27
  110. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  111. package/dist/heatmap/root/heatmap-root.js +34 -12
  112. package/dist/icon/root/icon-root.d.ts +12 -1
  113. package/dist/icon/root/icon-root.js +21 -10
  114. package/dist/icon/settle.d.ts +7 -0
  115. package/dist/icon/settle.js +10 -0
  116. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  117. package/dist/image/root/image-root.d.ts +5 -1
  118. package/dist/image/root/image-root.js +10 -2
  119. package/dist/input/root/input-root.d.ts +13 -3
  120. package/dist/input/root/input-root.js +12 -3
  121. package/dist/kbd/root/kbd-root.d.ts +35 -1
  122. package/dist/kbd/root/kbd-root.js +23 -4
  123. package/dist/legend/root/legend-root.d.ts +55 -8
  124. package/dist/legend/root/legend-root.js +55 -13
  125. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  126. package/dist/lightbox/root/lightbox-root.js +86 -19
  127. package/dist/lightbox/zoom-controller.d.ts +59 -0
  128. package/dist/lightbox/zoom-controller.js +128 -0
  129. package/dist/lightbox/zoom.d.ts +22 -0
  130. package/dist/lightbox/zoom.js +16 -0
  131. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  132. package/dist/line-chart/root/line-chart-root.js +21 -1
  133. package/dist/list/item/list-item.d.ts +70 -1
  134. package/dist/list/item/list-item.js +77 -6
  135. package/dist/list/numbering.d.ts +14 -0
  136. package/dist/list/numbering.js +8 -0
  137. package/dist/list/root/list-root.d.ts +155 -9
  138. package/dist/list/root/list-root.js +246 -4
  139. package/dist/list/selection.d.ts +49 -0
  140. package/dist/list/selection.js +30 -0
  141. package/dist/listbox/root/listbox-root.d.ts +37 -1
  142. package/dist/listbox/root/listbox-root.js +49 -4
  143. package/dist/loader/busy.d.ts +10 -0
  144. package/dist/loader/busy.js +11 -0
  145. package/dist/loader/root/loader-root.d.ts +9 -2
  146. package/dist/loader/root/loader-root.js +23 -3
  147. package/dist/map/root/map-root.d.ts +6 -2
  148. package/dist/map/root/map-root.js +5 -2
  149. package/dist/megamenu/root/megamenu-root.d.ts +62 -0
  150. package/dist/megamenu/root/megamenu-root.js +90 -5
  151. package/dist/menu/index.d.ts +1 -0
  152. package/dist/menu/index.js +1 -0
  153. package/dist/menu/item/menu-item.d.ts +87 -11
  154. package/dist/menu/item/menu-item.js +78 -22
  155. package/dist/menu/root/menu-root.d.ts +39 -1
  156. package/dist/menu/root/menu-root.js +65 -8
  157. package/dist/menu/section/menu-section.d.ts +55 -0
  158. package/dist/menu/section/menu-section.js +60 -0
  159. package/dist/meter/root/meter-root.d.ts +20 -1
  160. package/dist/meter/root/meter-root.js +11 -15
  161. package/dist/navigation/root/navigation-root.d.ts +18 -2
  162. package/dist/navigation/root/navigation-root.js +29 -3
  163. package/dist/notifications/root/notifications-root.d.ts +25 -0
  164. package/dist/notifications/root/notifications-root.js +33 -5
  165. package/dist/number-input/root/number-input-root.d.ts +17 -8
  166. package/dist/number-input/root/number-input-root.js +2 -7
  167. package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
  168. package/dist/object-inspector/root/object-inspector-root.js +264 -123
  169. package/dist/object-inspector/rows.d.ts +75 -0
  170. package/dist/object-inspector/rows.js +119 -0
  171. package/dist/option/root/option-root.d.ts +5 -3
  172. package/dist/outline/levels.d.ts +31 -0
  173. package/dist/outline/levels.js +23 -0
  174. package/dist/outline/root/outline-root.d.ts +86 -3
  175. package/dist/outline/root/outline-root.js +95 -12
  176. package/dist/pagination/size/pagination-size.d.ts +12 -2
  177. package/dist/pagination/size/pagination-size.js +20 -5
  178. package/dist/pin-input/code.d.ts +10 -0
  179. package/dist/pin-input/code.js +13 -0
  180. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  181. package/dist/pin-input/root/pin-input-root.js +10 -11
  182. package/dist/popover/hide-outside.d.ts +14 -0
  183. package/dist/popover/hide-outside.js +41 -0
  184. package/dist/popover/root/popover-root.d.ts +57 -7
  185. package/dist/popover/root/popover-root.js +58 -3
  186. package/dist/progress/root/progress-root.d.ts +20 -0
  187. package/dist/progress/root/progress-root.js +15 -15
  188. package/dist/qr-code/export.d.ts +26 -1
  189. package/dist/qr-code/export.js +14 -0
  190. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  191. package/dist/qr-code/root/qr-code-root.js +58 -9
  192. package/dist/quote/marks.d.ts +8 -0
  193. package/dist/quote/marks.js +5 -0
  194. package/dist/quote/root/quote-root.d.ts +14 -2
  195. package/dist/quote/root/quote-root.js +23 -1
  196. package/dist/radio/group/radio-group.d.ts +4 -10
  197. package/dist/radio/group/radio-group.js +5 -10
  198. package/dist/radio/root/radio-root.d.ts +6 -2
  199. package/dist/radio/root/radio-root.js +6 -1
  200. package/dist/rating/root/rating-root.d.ts +10 -5
  201. package/dist/rating/root/rating-root.js +32 -8
  202. package/dist/rating/steps.d.ts +7 -0
  203. package/dist/rating/steps.js +9 -0
  204. package/dist/scatter-chart/fit.d.ts +15 -0
  205. package/dist/scatter-chart/fit.js +35 -0
  206. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  207. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  208. package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
  209. package/dist/scroll-area/root/scroll-area-root.js +106 -7
  210. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  211. package/dist/scroll-area/scrollbar-controller.js +172 -0
  212. package/dist/scroll-area/scrollbar.d.ts +92 -0
  213. package/dist/scroll-area/scrollbar.js +33 -0
  214. package/dist/select/root/select-root.d.ts +15 -0
  215. package/dist/select/root/select-root.js +18 -6
  216. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  217. package/dist/skeleton/root/skeleton-root.js +4 -2
  218. package/dist/skip-link/root/skip-link-root.js +2 -2
  219. package/dist/slider/root/slider-root.d.ts +41 -4
  220. package/dist/slider/root/slider-root.js +23 -3
  221. package/dist/sparkline/readings.d.ts +18 -0
  222. package/dist/sparkline/readings.js +19 -0
  223. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  224. package/dist/sparkline/root/sparkline-root.js +118 -23
  225. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  226. package/dist/splitter/root/splitter-root.d.ts +20 -12
  227. package/dist/splitter/root/splitter-root.js +226 -203
  228. package/dist/splitter/snap.d.ts +9 -0
  229. package/dist/splitter/snap.js +12 -0
  230. package/dist/stat/root/stat-root.d.ts +14 -5
  231. package/dist/stat/root/stat-root.js +21 -5
  232. package/dist/steps/reach.d.ts +20 -0
  233. package/dist/steps/reach.js +15 -0
  234. package/dist/steps/root/steps-root.d.ts +76 -0
  235. package/dist/steps/root/steps-root.js +93 -1
  236. package/dist/steps/step/step.d.ts +45 -2
  237. package/dist/steps/step/step.js +33 -6
  238. package/dist/switch/root/switch-root.d.ts +10 -0
  239. package/dist/table/column/table-column.d.ts +11 -10
  240. package/dist/table/column/table-column.js +8 -19
  241. package/dist/table/root/table-root.d.ts +126 -4
  242. package/dist/table/root/table-root.js +156 -6
  243. package/dist/table/row/table-row.d.ts +47 -1
  244. package/dist/table/row/table-row.js +39 -2
  245. package/dist/tabs/panel/tab-panel.d.ts +22 -5
  246. package/dist/tabs/panel/tab-panel.js +34 -6
  247. package/dist/tabs/root/tabs-root.d.ts +37 -1
  248. package/dist/tabs/root/tabs-root.js +22 -4
  249. package/dist/tabs/tab/tab.d.ts +41 -4
  250. package/dist/tabs/tab/tab.js +49 -3
  251. package/dist/tag/group/tag-group.d.ts +31 -4
  252. package/dist/tag/group/tag-group.js +46 -7
  253. package/dist/tag/root/tag-root.js +9 -2
  254. package/dist/textarea/root/textarea-root.d.ts +28 -1
  255. package/dist/textarea/root/textarea-root.js +40 -1
  256. package/dist/time-input/root/time-input-root.d.ts +5 -1
  257. package/dist/time-input/root/time-input-root.js +16 -8
  258. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  259. package/dist/time-picker/root/time-picker-root.js +7 -10
  260. package/dist/time-picker/wheel-name.d.ts +9 -0
  261. package/dist/time-picker/wheel-name.js +15 -0
  262. package/dist/timeline/group/timeline-group.d.ts +46 -0
  263. package/dist/timeline/group/timeline-group.js +37 -0
  264. package/dist/timeline/index.d.ts +1 -0
  265. package/dist/timeline/index.js +1 -0
  266. package/dist/timeline/root/timeline-root.d.ts +10 -3
  267. package/dist/toast/item/toast-item.d.ts +24 -18
  268. package/dist/toast/item/toast-item.js +36 -40
  269. package/dist/toast/root/toast-root.d.ts +6 -0
  270. package/dist/toast/root/toast-root.js +16 -1
  271. package/dist/toggle/group/toggle-group.d.ts +24 -3
  272. package/dist/toggle/group/toggle-group.js +34 -5
  273. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  274. package/dist/toolbar/root/toolbar-root.js +15 -5
  275. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  276. package/dist/tooltip/root/tooltip-root.js +9 -1
  277. package/dist/tour/back.d.ts +10 -0
  278. package/dist/tour/back.js +8 -0
  279. package/dist/tour/root/tour-root.d.ts +30 -2
  280. package/dist/tour/root/tour-root.js +34 -8
  281. package/dist/tree/item/tree-item.d.ts +61 -4
  282. package/dist/tree/item/tree-item.js +92 -20
  283. package/dist/tree/root/tree-root.d.ts +58 -0
  284. package/dist/tree/root/tree-root.js +80 -16
  285. package/dist/tree/selection.d.ts +24 -0
  286. package/dist/tree/selection.js +13 -0
  287. package/dist/trend/root/trend-root.d.ts +43 -18
  288. package/dist/trend/root/trend-root.js +31 -6
  289. package/dist/video/media-events.d.ts +44 -0
  290. package/dist/video/media-events.js +35 -0
  291. package/dist/video/root/video-root.d.ts +117 -18
  292. package/dist/video/root/video-root.js +93 -47
  293. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  294. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  295. package/dist/video-playlist/order.d.ts +41 -0
  296. package/dist/video-playlist/order.js +34 -0
  297. package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
  298. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  299. package/dist/virtual-list/controls.d.ts +4 -0
  300. package/dist/virtual-list/controls.js +30 -0
  301. package/dist/virtual-list/fill.d.ts +22 -0
  302. package/dist/virtual-list/fill.js +23 -0
  303. package/dist/virtual-list/keys.d.ts +15 -0
  304. package/dist/virtual-list/keys.js +24 -0
  305. package/dist/virtual-list/plan.d.ts +49 -0
  306. package/dist/virtual-list/plan.js +16 -0
  307. package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
  308. package/dist/virtual-list/root/virtual-list-root.js +333 -49
  309. package/lint.json +1 -1
  310. package/package.json +8 -8
  311. package/types/jsx.d.ts +8113 -1394
  312. package/types/svelte.d.ts +2 -0
  313. package/types/vue.d.ts +1678 -353
  314. package/dist/data-table/root/order.d.ts +0 -141
  315. package/dist/data-table/root/order.js +0 -76
  316. package/dist/listbox/range.d.ts +0 -17
  317. package/dist/listbox/range.js +0 -5
  318. package/dist/tag/selection.d.ts +0 -10
  319. package/dist/tag/selection.js +0 -12
@@ -8,6 +8,7 @@ import { CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, HelixEle
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import '../../tooltip/index.js';
11
+ import { correlation, leastSquares } from '../fit.js';
11
12
  const REACH = 24;
12
13
  const COEFFICIENTS = new Map();
13
14
  const coefficientIn = (locale) => {
@@ -31,28 +32,12 @@ const nice = ([low, high]) => {
31
32
  const round = (value) => Number(value.toPrecision(12));
32
33
  return [round(Math.floor(low / step) * step), round(Math.ceil(high / step) * step)];
33
34
  };
34
- const correlation = (pairs) => {
35
- if (pairs.length < 3) {
36
- return undefined;
37
- }
38
- const mean = (values) => values.reduce((sum, one) => sum + one, 0) / values.length;
39
- const across = mean(pairs.map(([x]) => x));
40
- const up = mean(pairs.map(([, y]) => y));
41
- let both = 0;
42
- let xs = 0;
43
- let ys = 0;
44
- for (const [x, y] of pairs) {
45
- both += (x - across) * (y - up);
46
- xs += (x - across) ** 2;
47
- ys += (y - up) ** 2;
48
- }
49
- return xs === 0 || ys === 0 ? undefined : both / Math.sqrt(xs * ys);
50
- };
51
35
  let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinChartSource(HelixElement) {
52
36
  constructor() {
53
37
  super(...arguments);
54
38
  this.correlationLabel = 'correlation';
55
39
  this.pointsLabel = 'points';
40
+ this.trend = false;
56
41
  this.drawn = [];
57
42
  this.nearest = undefined;
58
43
  this.handleMove = (event) => {
@@ -180,6 +165,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
180
165
  ${this.rulesY
181
166
  ? ticks(field.y).map((level) => svg `<line part="gridline" x1="0" x2=${PLOT_WIDTH} y1=${up(level)} y2=${up(level)} />`)
182
167
  : nothing}
168
+ ${this.renderTrends(field, along, up)}
183
169
  </svg>
184
170
  ${field.points.map((point) => {
185
171
  const index = seriesIndex(point.depth);
@@ -194,6 +180,30 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
194
180
  ${this.renderTooltip()}
195
181
  </div>`;
196
182
  }
183
+ renderTrends(field, along, up) {
184
+ if (!this.trend) {
185
+ return nothing;
186
+ }
187
+ const [start, end] = field.x;
188
+ return field.yNames.flatMap((name, depth) => {
189
+ const fit = this.showsSeries(name) ? leastSquares(field.pairs[depth] ?? []) : undefined;
190
+ if (fit === undefined) {
191
+ return [];
192
+ }
193
+ const index = seriesIndex(depth);
194
+ return [
195
+ svg `<line
196
+ data-series=${index}
197
+ part="trend"
198
+ style="--chart-series: var(--chart-series-${index})"
199
+ x1=${along(start)}
200
+ x2=${along(end)}
201
+ y1=${up(fit.intercept + fit.slope * start)}
202
+ y2=${up(fit.intercept + fit.slope * end)}
203
+ />`,
204
+ ];
205
+ });
206
+ }
197
207
  renderSummary(field) {
198
208
  const clauses = field.yNames.map((name, depth) => {
199
209
  const pairs = field.pairs[depth] ?? [];
@@ -233,6 +243,9 @@ __decorate([
233
243
  __decorate([
234
244
  property({ attribute: 'points-label' })
235
245
  ], HelixHeadlessScatterChart.prototype, "pointsLabel", void 0);
246
+ __decorate([
247
+ property({ reflect: true, type: Boolean })
248
+ ], HelixHeadlessScatterChart.prototype, "trend", void 0);
236
249
  HelixHeadlessScatterChart = __decorate([
237
250
  customElement('helix-headless-scatter-chart')
238
251
  ], HelixHeadlessScatterChart);
@@ -20,6 +20,30 @@ declare const EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inli
20
20
  * It has `role="region"` only when you set a `label`, because a screen reader
21
21
  * announces an unnamed region as only "region".
22
22
  *
23
+ * **`scrollbars` draws scrollbars of its own** in place of the browser's: a
24
+ * `scrollbar` part for each axis that scrolls, a `thumb` in each, and a
25
+ * `corner` where the two meet. They are for the pointer. The thumb drags, and
26
+ * a press on the track moves the thumb to the press. The viewport stays the
27
+ * tab stop and the region a screen reader reads, and the scrollbars are hidden
28
+ * from screen readers. On the headless tier your stylesheet sizes and places
29
+ * them, hides the browser's own with `scrollbar-width: none` on the viewport,
30
+ * and draws the thumb from the two custom properties written on each
31
+ * scrollbar. An axis whose `overflow` is `hidden` gets no scrollbar.
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
+ *
38
+ * The viewport's `scroll` and `scrollend` are sent again from the host, which
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
41
+ * `onScrollEnd`.
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
+ *
23
47
  * @since 0.1.0
24
48
  * @status stable
25
49
  * @category layout
@@ -28,22 +52,64 @@ declare const EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inli
28
52
  *
29
53
  * @slot - The content that scrolls.
30
54
  *
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.
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.
57
+ *
58
+ * @csspart corner - The square where the two scrollbars meet, under `scrollbars`. Hidden unless both are drawn.
31
59
  * @csspart edges - The layer that draws the cues on the inline start and end edges.
60
+ * @csspart scrollbar - Each scrollbar, under `scrollbars`. Hidden on an axis that has none.
61
+ * @csspart scrollbar-horizontal - The scrollbar along the inline axis, alongside `scrollbar`.
62
+ * @csspart scrollbar-vertical - The scrollbar along the block axis, alongside `scrollbar`.
63
+ * @csspart scrollbar-visible - A scrollbar while it is showing, alongside `scrollbar`. Always under `auto` and `always`, and while scrolling, held, or hovered under `scroll` and `hover`.
64
+ * @csspart thumb - The thumb inside each scrollbar, which drags.
65
+ * @csspart thumb-horizontal - The thumb of the horizontal scrollbar, alongside `thumb`.
66
+ * @csspart thumb-vertical - The thumb of the vertical scrollbar, alongside `thumb`.
32
67
  * @csspart viewport - The scrolling box.
33
68
  *
69
+ * @cssproperty --scroll-area-scroll-fraction - How far along its axis the content is scrolled, from 0 at the start to 1 at the end. Written on each `scrollbar` part, so its thumb inherits it. Counted from the right on a right-to-left page.
70
+ * @cssproperty --scroll-area-thumb-fraction - The share of the track the thumb covers, from 0 to 1, which is how much of the content is in view. Written on each `scrollbar` part.
71
+ *
34
72
  * @cssstate more-block-end - While there is more to scroll to past the block end.
35
73
  * @cssstate more-block-start - While there is more to scroll back to before the block start.
36
74
  * @cssstate more-inline-end - While there is more to scroll to past the inline end.
37
75
  * @cssstate more-inline-start - While there is more to scroll back to before the inline start.
76
+ * @cssstate scrollbar-horizontal - While the horizontal scrollbar is drawn, under `scrollbars`.
77
+ * @cssstate scrollbar-vertical - While the vertical scrollbar is drawn, under `scrollbars`.
38
78
  * @cssstate scrolls - While the content is larger than the viewport, on either axis.
39
79
  */
40
80
  export declare class HelixHeadlessScrollArea extends HelixElement {
81
+ /**
82
+ * How long the scrollbars stay after the content stops moving, or the pointer
83
+ * leaves, in milliseconds. Read under `scrollbars="scroll"` and
84
+ * `scrollbars="hover"`.
85
+ */
86
+ hideDelay: number;
41
87
  /**
42
88
  * The region's name, read by screen readers.
43
89
  *
44
90
  * Without one there is no region: see the note on the class.
45
91
  */
46
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';
98
+ /**
99
+ * Draws scrollbars of the component's own in place of the browser's, and
100
+ * says when they show.
101
+ *
102
+ * - `auto`: on each axis that has content past it.
103
+ * - `always`: on each axis that can scroll, whether or not it has anything to
104
+ * scroll, so the scrollbar is there before the content grows.
105
+ * - `scroll`: while the content is moving, and for `hide-delay` after.
106
+ * - `hover`: as `scroll`, and while the pointer is over the scroll area.
107
+ *
108
+ * Absent keeps the browser's scrollbars.
109
+ */
110
+ scrollbars?: 'always' | 'auto' | 'hover' | 'scroll';
111
+ /** The scrollbars drawn under `scrollbars`: what they show, when, and the drag. */
112
+ private readonly bars;
47
113
  /**
48
114
  * Which edges have content past them, measured rather than guessed.
49
115
  */
@@ -76,6 +142,10 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
76
142
  * costs.
77
143
  */
78
144
  private measure;
145
+ /** Measures, shows the scrollbars, and sends the event on from the host. */
146
+ private readonly handleScroll;
147
+ /** Sends the event on from the host, except the ones a thumb drag holds back. */
148
+ private readonly handleScrollEnd;
79
149
  connectedCallback(): void;
80
150
  disconnectedCallback(): void;
81
151
  protected firstUpdated(changed: PropertyValues): void;
@@ -83,7 +153,21 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
83
153
  private watchContent;
84
154
  protected updated(changed: PropertyValues): void;
85
155
  private readonly handleSlotChange;
156
+ /** The axis `orientation` takes away, clipped where the content would overflow it. */
157
+ private get clipped();
86
158
  protected render(): TemplateResult;
159
+ /**
160
+ * The scrollbars, the thumbs in them and the corner.
161
+ *
162
+ * **For the pointer, and hidden from everything else.** The viewport is
163
+ * already the tab stop and the region, and the keys scroll it, so a second
164
+ * way in would be one more stop that does the same thing. The scrollbars
165
+ * carry `aria-hidden` and take no focus, as Radix's do.
166
+ *
167
+ * Hidden on the server, which cannot measure whether there is anything to
168
+ * scroll, and until the first measurement.
169
+ */
170
+ private renderScrollbars;
87
171
  }
88
172
  declare global {
89
173
  interface HTMLElementTagNameMap {
@@ -7,11 +7,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
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 { ScrollbarController } from '../scrollbar-controller.js';
10
11
  const EDGES = ['block-start', 'block-end', 'inline-start', 'inline-end'];
11
12
  let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement {
12
13
  constructor() {
13
14
  super(...arguments);
15
+ this.hideDelay = 600;
14
16
  this.label = '';
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
+ });
15
23
  this.more = [];
16
24
  this.scrolls = false;
17
25
  this.measure = () => {
@@ -20,22 +28,39 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
20
28
  return;
21
29
  }
22
30
  const slack = 1;
31
+ const block = this.orientation !== 'horizontal';
32
+ const inline = this.orientation !== 'vertical';
23
33
  const found = [];
24
- if (box.scrollTop > slack) {
34
+ if (block && box.scrollTop > slack) {
25
35
  found.push('block-start');
26
36
  }
27
- if (box.scrollTop + box.clientHeight < box.scrollHeight - slack) {
37
+ if (block && box.scrollTop + box.clientHeight < box.scrollHeight - slack) {
28
38
  found.push('block-end');
29
39
  }
30
40
  const along = Math.abs(box.scrollLeft);
31
- if (along > slack) {
41
+ if (inline && along > slack) {
32
42
  found.push('inline-start');
33
43
  }
34
- if (along + box.clientWidth < box.scrollWidth - slack) {
44
+ if (inline && along + box.clientWidth < box.scrollWidth - slack) {
35
45
  found.push('inline-end');
36
46
  }
37
47
  this.more = found;
38
- 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);
51
+ if (this.scrollbars) {
52
+ this.bars.read(box);
53
+ }
54
+ };
55
+ this.handleScroll = (event) => {
56
+ this.measure();
57
+ this.bars.wake();
58
+ this.relayNativeEvent(event);
59
+ };
60
+ this.handleScrollEnd = (event) => {
61
+ if (!this.bars.holdsScrollEnd()) {
62
+ this.relayNativeEvent(event);
63
+ }
39
64
  };
40
65
  this.handleSlotChange = (event) => {
41
66
  const slot = event.target;
@@ -79,20 +104,40 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
79
104
  }
80
105
  updated(changed) {
81
106
  super.updated?.(changed);
107
+ if (changed.has('orientation') && this.hasUpdated) {
108
+ this.measure();
109
+ }
110
+ else if (changed.has('scrollbars') && this.scrollbars) {
111
+ const box = this.scroller;
112
+ if (box) {
113
+ this.bars.read(box);
114
+ }
115
+ }
82
116
  this.toggleState('scrolls', this.scrolls);
83
117
  this.toggleState('more-block-start', this.more.includes('block-start'));
84
118
  this.toggleState('more-block-end', this.more.includes('block-end'));
85
119
  this.toggleState('more-inline-start', this.more.includes('inline-start'));
86
120
  this.toggleState('more-inline-end', this.more.includes('inline-end'));
121
+ const drawn = this.scrollbars ? this.bars.bars : undefined;
122
+ this.toggleState('scrollbar-horizontal', drawn?.horizontal.drawn === true);
123
+ this.toggleState('scrollbar-vertical', drawn?.vertical.drawn === true);
124
+ }
125
+ get clipped() {
126
+ if (this.orientation === 'vertical') {
127
+ return 'overflow-x: hidden';
128
+ }
129
+ return this.orientation === 'horizontal' ? 'overflow-y: hidden' : nothing;
87
130
  }
88
131
  render() {
89
132
  return html `<div
90
133
  data-scroller
91
134
  part="viewport"
135
+ style=${this.clipped}
92
136
  role=${this.label ? 'region' : nothing}
93
137
  aria-label=${this.label || nothing}
94
138
  tabindex=${this.scrolls ? '0' : nothing}
95
- @scroll=${this.measure}
139
+ @scroll=${this.handleScroll}
140
+ @scrollend=${this.handleScrollEnd}
96
141
  >
97
142
  <slot @slotchange=${this.handleSlotChange}></slot>
98
143
  </div>
@@ -104,12 +149,66 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
104
149
  <div
105
150
  part="edges"
106
151
  aria-hidden="true"
107
- ></div>`;
152
+ ></div>${this.scrollbars ? this.renderScrollbars() : nothing}`;
153
+ }
154
+ renderScrollbars() {
155
+ const controller = this.bars;
156
+ const bars = controller.bars;
157
+ const shown = controller.shown;
158
+ const facts = (bar) => bar
159
+ ? `--scroll-area-thumb-fraction: ${bar.thumb}; --scroll-area-scroll-fraction: ${bar.along}`
160
+ : nothing;
161
+ const vertical = bars?.vertical.drawn === true;
162
+ const horizontal = bars?.horizontal.drawn === true;
163
+ return html `<div
164
+ part="scrollbar scrollbar-vertical${vertical && shown ? ' scrollbar-visible' : ''}"
165
+ aria-hidden="true"
166
+ ?hidden=${!vertical}
167
+ style=${facts(bars?.vertical)}
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}
175
+ >
176
+ <div part="thumb thumb-vertical"></div>
177
+ </div>
178
+ <div
179
+ part="scrollbar scrollbar-horizontal${horizontal && shown ? ' scrollbar-visible' : ''}"
180
+ aria-hidden="true"
181
+ ?hidden=${!horizontal}
182
+ style=${facts(bars?.horizontal)}
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}
190
+ >
191
+ <div part="thumb thumb-horizontal"></div>
192
+ </div>
193
+ <div
194
+ part="corner"
195
+ aria-hidden="true"
196
+ ?hidden=${!(vertical && horizontal)}
197
+ ></div>`;
108
198
  }
109
199
  };
200
+ __decorate([
201
+ property({ attribute: 'hide-delay', type: Number })
202
+ ], HelixHeadlessScrollArea.prototype, "hideDelay", void 0);
110
203
  __decorate([
111
204
  property()
112
205
  ], HelixHeadlessScrollArea.prototype, "label", void 0);
206
+ __decorate([
207
+ property()
208
+ ], HelixHeadlessScrollArea.prototype, "orientation", void 0);
209
+ __decorate([
210
+ property({ reflect: true })
211
+ ], HelixHeadlessScrollArea.prototype, "scrollbars", void 0);
113
212
  __decorate([
114
213
  state()
115
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
+ }
@@ -0,0 +1,172 @@
1
+ import { capturePointer, DelayController, isRtl } from '@fusion.dev/helix-core';
2
+ import { alongTrack, extentOf, hasScrollbar, offsetAt, scrollFraction, scrollPerPixel, showsScrollbar, thumbFraction, } from './scrollbar.js';
3
+ const SETTLE = 100;
4
+ export class ScrollbarController {
5
+ constructor(host, options) {
6
+ this.active = false;
7
+ this.hovered = false;
8
+ this.over = false;
9
+ this.heldEnd = false;
10
+ this.handleVerticalDown = (event) => {
11
+ this.grab(event, 'vertical');
12
+ };
13
+ this.handleHorizontalDown = (event) => {
14
+ this.grab(event, 'horizontal');
15
+ };
16
+ this.handleDragMove = (event) => {
17
+ const drag = this.drag;
18
+ const box = this.options.box();
19
+ if (!drag || !box) {
20
+ return;
21
+ }
22
+ const pointer = drag.axis === 'vertical' ? event.clientY : event.clientX;
23
+ this.scrollAlong(box, drag.axis, drag.from + (pointer - drag.pointer) * drag.sign * drag.perPixel);
24
+ };
25
+ this.handleDragEnd = () => {
26
+ if (!this.drag) {
27
+ return;
28
+ }
29
+ this.drag = undefined;
30
+ if (this.heldEnd) {
31
+ this.settle.start(SETTLE, () => {
32
+ if (this.heldEnd) {
33
+ this.heldEnd = false;
34
+ this.options.scrollEnd();
35
+ }
36
+ });
37
+ }
38
+ this.wake();
39
+ this.host.requestUpdate();
40
+ };
41
+ this.handleBarEnter = () => {
42
+ this.set('over', true);
43
+ };
44
+ this.handleBarLeave = () => {
45
+ this.set('over', false);
46
+ this.wake();
47
+ };
48
+ this.handleEnter = () => {
49
+ this.set('hovered', true);
50
+ };
51
+ this.handleLeave = () => {
52
+ this.set('hovered', false);
53
+ if (this.options.mode() === 'hover') {
54
+ this.wake();
55
+ }
56
+ };
57
+ this.host = host;
58
+ this.options = options;
59
+ this.hide = new DelayController(host, { renders: false });
60
+ this.settle = new DelayController(host, { renders: false });
61
+ host.addController(this);
62
+ }
63
+ hostConnected() {
64
+ this.host.addEventListener('pointerenter', this.handleEnter);
65
+ this.host.addEventListener('pointerleave', this.handleLeave);
66
+ }
67
+ hostDisconnected() {
68
+ this.host.removeEventListener('pointerenter', this.handleEnter);
69
+ this.host.removeEventListener('pointerleave', this.handleLeave);
70
+ this.drag = undefined;
71
+ this.heldEnd = false;
72
+ this.active = false;
73
+ this.hovered = false;
74
+ this.over = false;
75
+ }
76
+ get dragging() {
77
+ return this.drag !== undefined;
78
+ }
79
+ get shown() {
80
+ const mode = this.options.mode();
81
+ return mode
82
+ ? showsScrollbar(mode, {
83
+ active: this.active,
84
+ held: this.over || this.drag !== undefined,
85
+ hovered: this.hovered,
86
+ })
87
+ : false;
88
+ }
89
+ read(box) {
90
+ const mode = this.options.mode() ?? 'auto';
91
+ const style = getComputedStyle(box);
92
+ const bar = (axis, overflow) => {
93
+ const extent = extentOf(box, axis);
94
+ return {
95
+ along: scrollFraction(extent),
96
+ drawn: hasScrollbar(mode, !['clip', 'hidden', 'visible'].includes(overflow), extent.offset > 1 || extent.client < extent.scroll - 1),
97
+ thumb: thumbFraction(extent),
98
+ };
99
+ };
100
+ const next = {
101
+ horizontal: bar('horizontal', style.overflowX),
102
+ vertical: bar('vertical', style.overflowY),
103
+ };
104
+ if (JSON.stringify(next) !== JSON.stringify(this.bars)) {
105
+ this.bars = next;
106
+ this.host.requestUpdate();
107
+ }
108
+ }
109
+ wake() {
110
+ const mode = this.options.mode();
111
+ if (mode !== 'scroll' && mode !== 'hover') {
112
+ return;
113
+ }
114
+ this.set('active', true);
115
+ this.hide.start(this.options.hideDelay(), () => {
116
+ this.set('active', false);
117
+ });
118
+ }
119
+ holdsScrollEnd() {
120
+ if (this.drag) {
121
+ this.heldEnd = true;
122
+ return true;
123
+ }
124
+ if (this.heldEnd) {
125
+ this.heldEnd = false;
126
+ this.settle.cancel();
127
+ }
128
+ return false;
129
+ }
130
+ set(key, value) {
131
+ if (this[key] !== value) {
132
+ this[key] = value;
133
+ this.host.requestUpdate();
134
+ }
135
+ }
136
+ scrollAlong(box, axis, offset) {
137
+ box.scrollTo(axis === 'vertical'
138
+ ? { behavior: 'instant', top: offset }
139
+ : { behavior: 'instant', left: isRtl(box) ? -offset : offset });
140
+ }
141
+ grab(event, axis) {
142
+ const box = this.options.box();
143
+ const bar = event.currentTarget;
144
+ const thumb = bar.querySelector('[part~="thumb"]');
145
+ if (event.button !== 0 || !box || !thumb) {
146
+ return;
147
+ }
148
+ event.preventDefault();
149
+ const vertical = axis === 'vertical';
150
+ const rtl = !vertical && isRtl(box);
151
+ const track = bar.getBoundingClientRect();
152
+ const held = thumb.getBoundingClientRect();
153
+ const length = vertical ? track.height : track.width;
154
+ const size = vertical ? held.height : held.width;
155
+ const extent = extentOf(box, axis);
156
+ const pointer = vertical ? event.clientY : event.clientX;
157
+ let from = extent.offset;
158
+ if (!thumb.contains(event.target)) {
159
+ from = offsetAt(extent, alongTrack(pointer, track, axis, rtl), length, size);
160
+ this.scrollAlong(box, axis, from);
161
+ }
162
+ this.drag = {
163
+ axis,
164
+ from,
165
+ perPixel: scrollPerPixel(extent, length, size),
166
+ pointer,
167
+ sign: rtl ? -1 : 1,
168
+ };
169
+ capturePointer(bar, event.pointerId);
170
+ this.host.requestUpdate();
171
+ }
172
+ }