@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
@@ -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
+ }
@@ -8,6 +8,17 @@
8
8
  */
9
9
  /** Which scrollbars are drawn, and when. Absent keeps the browser's own. */
10
10
  export type Scrollbars = 'always' | 'auto' | 'hover' | 'scroll';
11
+ /** The two axes a scrollbar runs along. */
12
+ export type Axis = 'horizontal' | 'vertical';
13
+ /** The box a scrollbar reads, as the numbers it reads off it. */
14
+ export interface Box {
15
+ clientHeight: number;
16
+ clientWidth: number;
17
+ scrollHeight: number;
18
+ scrollLeft: number;
19
+ scrollTop: number;
20
+ scrollWidth: number;
21
+ }
11
22
  /** One axis of the viewport, read off the box. */
12
23
  export interface Extent {
13
24
  /** How much of the content the viewport shows, `clientHeight` or `clientWidth`. */
@@ -63,3 +74,19 @@ export declare const showsScrollbar: (mode: Scrollbars, moment: {
63
74
  held: boolean;
64
75
  hovered: boolean;
65
76
  }) => boolean;
77
+ /**
78
+ * One axis of a box, counted from its start whichever way the line runs: a
79
+ * right-to-left box counts `scrollLeft` down from zero, so its offset is the
80
+ * distance from zero.
81
+ */
82
+ export declare const extentOf: (box: Box, axis: Axis) => Extent;
83
+ /**
84
+ * Where a pointer is along a track, counted from the track's start: its top,
85
+ * or its left edge, or its right edge on a right-to-left page.
86
+ */
87
+ export declare const alongTrack: (pointer: number, track: {
88
+ bottom: number;
89
+ left: number;
90
+ right: number;
91
+ top: number;
92
+ }, axis: Axis, rtl: boolean) => number;
@@ -22,3 +22,12 @@ export const showsScrollbar = (mode, moment) => {
22
22
  }
23
23
  return moment.active || moment.held || (mode === 'hover' && moment.hovered);
24
24
  };
25
+ export const extentOf = (box, axis) => axis === 'vertical'
26
+ ? { client: box.clientHeight, offset: box.scrollTop, scroll: box.scrollHeight }
27
+ : { client: box.clientWidth, offset: Math.abs(box.scrollLeft), scroll: box.scrollWidth };
28
+ export const alongTrack = (pointer, track, axis, rtl) => {
29
+ if (axis === 'vertical') {
30
+ return pointer - track.top;
31
+ }
32
+ return rtl ? track.right - pointer : pointer - track.left;
33
+ };
@@ -48,6 +48,7 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
48
48
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the list closes. Cancelable: canceling it keeps the list open and leaves the decision to you.
49
49
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before the list opens. Cancelable: canceling it keeps the list closed and leaves the decision to you.
50
50
  * @event {HelixFilterEvent} helix-filter - Fired as the user types in the filter field of a `filterable` select, with the text the list is filtered by. Cancelable: cancel it to leave the list unfiltered and filter the options yourself.
51
+ * @event {HelixLoadMoreEvent} helix-load-more - Fired once the list is scrolled within a screen of its end, once for each number of options, and not while `loading` is set. Add the next page and set `loading` while you fetch it.
51
52
  * @event {Event} input - Fired after the value changes.
52
53
  * @event {ToggleEvent} toggle - Fired after the list opens or closes, with `newState` and `oldState`.
53
54
  *
@@ -57,6 +58,7 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
57
58
  * @csspart label - The label above the trigger.
58
59
  * @csspart listbox - The list inside the panel.
59
60
  * @csspart listbox-empty - The text shown when the filter hides every option.
61
+ * @csspart listbox-error - The inner list's `error` part, shown while its `load-error` is set.
60
62
  * @csspart listbox-feedback - The inner list's message that says what is wrong with the value.
61
63
  * @csspart listbox-filter-icon - The icon beside the filter field.
62
64
  * @csspart listbox-filter-mark - The default icon beside the filter field, shown when none is slotted.
@@ -276,6 +278,19 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
276
278
  * cannot change.
277
279
  */
278
280
  protected renderIndicator(): TemplateResult;
281
+ /**
282
+ * What names the list once it opens: the `label`, the host's `aria-label`,
283
+ * or the words of what names the host from outside, its `aria-labelledby`
284
+ * or a `<label>` for it.
285
+ *
286
+ * **Words rather than a reference**, because the list is inside another
287
+ * element's shadow root and neither an IDREF nor the host's labels reach it.
288
+ * Read as the list renders, which opening it makes happen, so a label
289
+ * changed while the list is closed is read when it next opens. Without the
290
+ * last two routes a Select named by a `<label for>` opened onto a listbox
291
+ * with no name, which the missing-name warning reported.
292
+ */
293
+ private get listName();
279
294
  /**
280
295
  * What names the trigger: the label, then the choice.
281
296
  *
@@ -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 { AriaForwardController, afterLinkFollowed, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, afterLinkFollowed, customElement, elementById, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
8
8
  import { caretDown } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -214,15 +214,15 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
214
214
  loading-text=${this.loadingText}
215
215
  ?loading=${this.loading}
216
216
  part="listbox"
217
- exportparts="empty: listbox-empty, feedback: listbox-feedback, filter-icon: listbox-filter-icon,
218
- filter-mark: listbox-filter-mark, hint: listbox-hint, items: listbox-items,
219
- label: listbox-label, live: listbox-live, loading: listbox-loading, search: listbox-search,
220
- search-field: listbox-search-field"
217
+ exportparts="empty: listbox-empty, error: listbox-error, feedback: listbox-feedback,
218
+ filter-icon: listbox-filter-icon, filter-mark: listbox-filter-mark, hint: listbox-hint,
219
+ items: listbox-items, label: listbox-label, live: listbox-live, loading: listbox-loading,
220
+ search: listbox-search, search-field: listbox-search-field"
221
221
  .value=${this.value}
222
222
  ?multiple=${this.multiple}
223
223
  ?filterable=${this.filterable}
224
224
  manual
225
- aria-label=${this.label || this.getAttribute('aria-label') || nothing}
225
+ aria-label=${this.listName || nothing}
226
226
  @keydown=${this.handleListKeydown}
227
227
  @helix-before-change=${this.handleChange}
228
228
  @change=${this.stopInner}
@@ -240,6 +240,18 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
240
240
  </svg>
241
241
  </slot>`;
242
242
  }
243
+ get listName() {
244
+ const own = this.label || this.getAttribute('aria-label');
245
+ if (own) {
246
+ return own;
247
+ }
248
+ const ids = (this.getAttribute('aria-labelledby') ?? '').split(/\s+/).filter(Boolean);
249
+ const named = ids.length > 0 ? ids.map((id) => elementById(this, id)) : [...(this.labels ?? [])];
250
+ return named
251
+ .map((one) => (one?.textContent ?? '').replace(/\s+/g, ' ').trim())
252
+ .filter(Boolean)
253
+ .join(' ');
254
+ }
243
255
  get triggerNames() {
244
256
  const outside = (this.internals.labels?.length ?? 0) > 0 && !this.labeled;
245
257
  if (this.hasAttribute('aria-labelledby') || outside) {
@@ -31,7 +31,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
31
31
  * @slot - The content the skeleton stands in for, which sizes it. Optional.
32
32
  *
33
33
  * @csspart content - The box around the content, inert while `loading`.
34
+ * @csspart sheen - The highlight inside the shape, which the styled tier sweeps across it. Empty, and drawn by no rule on this tier.
34
35
  * @csspart skeleton - The placeholder shape.
36
+ *
37
+ * @cssstate wrapping - The skeleton holds content, an element or words, and takes that content's size. Line breaks and spaces alone are not content.
35
38
  */
36
39
  export declare class HelixHeadlessSkeleton extends HelixElement {
37
40
  /**
@@ -19,6 +19,8 @@ let HelixHeadlessSkeleton = class HelixHeadlessSkeleton extends HelixElement {
19
19
  }
20
20
  willUpdate(changed) {
21
21
  super.willUpdate(changed);
22
+ const wraps = this.wraps;
23
+ this.toggleState('wrapping', wraps);
22
24
  this.internals.ariaBusy = this.loading ? 'true' : null;
23
25
  if (this.label) {
24
26
  hostAria(this.internals, { label: this.label, role: 'progressbar' });
@@ -26,7 +28,7 @@ let HelixHeadlessSkeleton = class HelixHeadlessSkeleton extends HelixElement {
26
28
  }
27
29
  else {
28
30
  hostAria(this.internals, { label: '', role: '' });
29
- this.internals.ariaHidden = this.wraps ? null : 'true';
31
+ this.internals.ariaHidden = wraps ? null : 'true';
30
32
  }
31
33
  }
32
34
  firstUpdated(changed) {
@@ -36,7 +38,7 @@ let HelixHeadlessSkeleton = class HelixHeadlessSkeleton extends HelixElement {
36
38
  render() {
37
39
  return html `<span part="content" ?inert=${this.loading}
38
40
  ><slot @slotchange=${() => this.requestUpdate()}></slot></span
39
- ><span part="skeleton"></span>`;
41
+ ><span part="skeleton"><span part="sheen"></span></span>`;
40
42
  }
41
43
  };
42
44
  __decorate([
@@ -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, elementById, HelixElement, reportRuntime } from '@fusion.dev/helix-core';
7
+ import { customElement, elementById, HelixElement, plainClick, reportRuntime, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessSkipLink = class HelixHeadlessSkipLink extends HelixElement {
@@ -13,7 +13,7 @@ let HelixHeadlessSkipLink = class HelixHeadlessSkipLink extends HelixElement {
13
13
  this.href = '#main';
14
14
  this.label = 'Skip to content';
15
15
  this.skip = (event) => {
16
- if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
16
+ if (!plainClick(event)) {
17
17
  return;
18
18
  }
19
19
  const target = this.target;
@@ -20,7 +20,13 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
20
20
  *
21
21
  * A range with two thumbs is two inputs stacked on one track, because there is
22
22
  * no native two-thumb range. Each thumb keeps its own value.
23
- * `min-steps-between-thumbs` keeps them that many steps apart.
23
+ * `min-steps-between-thumbs` keeps them that many steps apart, and the readout
24
+ * joins the two as `range-text` writes them.
25
+ *
26
+ * `origin` sets where a single thumb's fill starts: at `min`, at the middle of
27
+ * the track, or at `max`. A balance or an offset from zero fills from the
28
+ * middle, as Zag's slider `origin` does. The fill's ends are published as
29
+ * `--slider-from` and `--slider-to`.
24
30
  *
25
31
  * `format-options` writes the value with `Intl.NumberFormat` in `locale`, as a
26
32
  * currency, a percent or a unit, and `formatter` writes it with a function of
@@ -34,6 +40,20 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
34
40
  * the first render. HTML does not apply `required` to a range either, so it is
35
41
  * not set on the input. It only adds the marker beside the label.
36
42
  *
43
+ * **Keyboard.** Each thumb is one tab stop, and its keys are the native
44
+ * range's.
45
+ *
46
+ * | Key | What it does |
47
+ * |---|---|
48
+ * | Right, Up | Moves the thumb up by `step`. |
49
+ * | Left, Down | Moves the thumb down by `step`. |
50
+ * | Page Up, Page Down | Moves the thumb by a larger step. |
51
+ * | Home, End | Moves the thumb to its lowest or highest value. |
52
+ *
53
+ * Each thumb is an `<input type="range">` with `aria-valuetext` where the value
54
+ * is formatted or worded. A range's thumbs say they stop at each other with
55
+ * `aria-valuemin` and `aria-valuemax`.
56
+ *
37
57
  * @since 0.1.0
38
58
  * @status stable
39
59
  * @category forms
@@ -59,9 +79,9 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
59
79
  * @csspart output - The current value, shown beside the track.
60
80
  *
61
81
  * @cssproperty --slider-fraction - The value as a fraction of the range, 0 to 1.
62
- * @cssproperty --slider-from - Where a range's filled span starts, as a fraction of the track, 0 to 1.
82
+ * @cssproperty --slider-from - Where the filled span starts, as a fraction of the track, 0 to 1: a range's lower thumb, or a single thumb's `origin`.
63
83
  * @cssproperty --slider-marker-at - Where one marker sits, as a percentage of the track.
64
- * @cssproperty --slider-to - Where a range's filled span ends, as a fraction of the track, 0 to 1.
84
+ * @cssproperty --slider-to - Where the filled span ends, as a fraction of the track, 0 to 1: a range's upper thumb, or the farther of a single thumb and its `origin`.
65
85
  *
66
86
  * @cssstate invalid - The slider has an error to show, from the browser's validation or from your `feedback`.
67
87
  */
@@ -148,6 +168,12 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
148
168
  * rather than a thumb sitting on nothing.
149
169
  */
150
170
  orientation?: 'horizontal' | 'vertical';
171
+ /**
172
+ * Where a single thumb's fill starts: `start` at `min`, `center` at the
173
+ * middle of the track, or `end` at `max`. Absent is `start`. A range fills
174
+ * between its thumbs and ignores it.
175
+ */
176
+ origin?: 'center' | 'end' | 'start';
151
177
  /**
152
178
  * Adds a second thumb, so the value is a pair.
153
179
  *
@@ -156,6 +182,11 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
156
182
  * the two, since a range has no single number.
157
183
  */
158
184
  range: boolean;
185
+ /**
186
+ * How the readout joins a range's two values, with `{start}` and `{end}`
187
+ * filled in. Write it in the page's language, such as `{start} bis {end}`.
188
+ */
189
+ rangeText: string;
159
190
  /**
160
191
  * Shows the chosen value beside the track.
161
192
  */
@@ -174,7 +205,8 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
174
205
  *
175
206
  * Widest rather than current, so the box never changes size at all. Measured
176
207
  * off the bounds because that is what the readout can ever say: the longer of
177
- * the two ends, twice, plus the four of " to " when both are shown. Negative
208
+ * the two ends, twice, plus the words `range-text` puts between them when
209
+ * both are shown. Negative
178
210
  * bounds are covered by measuring the rendered string rather than the digits,
179
211
  * since the sign is a character like any other.
180
212
  *
@@ -238,6 +270,11 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
238
270
  * there is no order for this to be on the wrong side of.
239
271
  */
240
272
  private get fraction();
273
+ /**
274
+ * A single thumb's fill: `--slider-fraction`, and under `origin` the span
275
+ * from the origin to the thumb as `--slider-from` and `--slider-to`.
276
+ */
277
+ private get fillStyle();
241
278
  /**
242
279
  * A value snapped to the step, counted from `min` the way a range counts it.
243
280
  *
@@ -23,6 +23,7 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
23
23
  this.minimumLabel = 'minimum';
24
24
  this.minStepsBetweenThumbs = 0;
25
25
  this.range = false;
26
+ this.rangeText = '{start} to {end}';
26
27
  this.showValue = false;
27
28
  this.step = 1;
28
29
  this.handleInput = (event) => {
@@ -51,7 +52,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
51
52
  }
52
53
  get reserve() {
53
54
  const widest = Math.max(this.said(this.min).length, this.said(this.max).length);
54
- return this.range ? widest * 2 + ' to '.length : widest;
55
+ return this.range
56
+ ? widest * 2 + fillTemplate(this.rangeText, { end: '', start: '' }).length
57
+ : widest;
55
58
  }
56
59
  get precision() {
57
60
  return String(this.step).split('.')[1]?.length ?? 0;
@@ -104,6 +107,14 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
104
107
  }
105
108
  return this.along(this.snapped(this.valueAsNumber));
106
109
  }
110
+ get fillStyle() {
111
+ const fraction = this.fraction;
112
+ if (!this.origin) {
113
+ return `--slider-fraction: ${fraction}`;
114
+ }
115
+ const at = { center: 0.5, end: 1, start: 0 }[this.origin] ?? 0;
116
+ return `--slider-fraction: ${fraction}; --slider-from: ${Math.min(at, fraction)}; --slider-to: ${Math.max(at, fraction)}`;
117
+ }
107
118
  snapped(at) {
108
119
  if (!(this.step > 0)) {
109
120
  return at;
@@ -211,7 +222,8 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
211
222
  part="control"
212
223
  id=${this.controlId}
213
224
  type="range"
214
- style="--slider-fraction: ${this.fraction}"
225
+ style=${this.fillStyle}
226
+ data-origin=${this.origin ?? nothing}
215
227
  min=${this.min}
216
228
  max=${this.max}
217
229
  step=${this.step}
@@ -241,7 +253,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
241
253
  for=${this.range ? 'control control-end' : 'control'}
242
254
  aria-hidden="true"
243
255
  style=${`--_slider-output-reserve: ${this.reserve}ch`}
244
- >${this.range ? `${this.said(start)} to ${this.said(end)}` : this.said(this.value)}</output
256
+ >${this.range
257
+ ? fillTemplate(this.rangeText, { end: this.said(end), start: this.said(start) })
258
+ : this.said(this.value)}</output
245
259
  >`
246
260
  : nothing}
247
261
  </div>
@@ -281,9 +295,15 @@ __decorate([
281
295
  __decorate([
282
296
  property({ reflect: true })
283
297
  ], HelixHeadlessSlider.prototype, "orientation", void 0);
298
+ __decorate([
299
+ property({ reflect: true })
300
+ ], HelixHeadlessSlider.prototype, "origin", void 0);
284
301
  __decorate([
285
302
  property({ reflect: true, type: Boolean })
286
303
  ], HelixHeadlessSlider.prototype, "range", void 0);
304
+ __decorate([
305
+ property({ attribute: 'range-text' })
306
+ ], HelixHeadlessSlider.prototype, "rangeText", void 0);
287
307
  __decorate([
288
308
  property({ attribute: 'show-value', reflect: true, type: Boolean })
289
309
  ], HelixHeadlessSlider.prototype, "showValue", void 0);
@@ -0,0 +1,18 @@
1
+ /** Where the highest and the lowest readings are, by place, or none. */
2
+ export interface Extremes {
3
+ /** The place of the highest reading, the first where several tie. */
4
+ high?: number;
5
+ /** The place of the lowest reading, the first where several tie. */
6
+ low?: number;
7
+ }
8
+ /**
9
+ * Where the highest and the lowest readings stand. A blank slot is passed
10
+ * over, and a list with nothing in it has neither.
11
+ */
12
+ export declare const extremesOf: (slots: readonly (number | undefined)[]) => Extremes;
13
+ /**
14
+ * A reading in words, for the readout: the row's name where a table gave one,
15
+ * the reading as it is written, and where it stands in brackets, such as
16
+ * "Mon: 12 (3 of 7)". The same order every chart's readout uses.
17
+ */
18
+ export declare const readingWords: (label: string, text: string, position: string) => string;
@@ -0,0 +1,19 @@
1
+ export const extremesOf = (slots) => {
2
+ const found = {};
3
+ slots.forEach((value, at) => {
4
+ if (value === undefined) {
5
+ return;
6
+ }
7
+ if (found.high === undefined || value > slots[found.high]) {
8
+ found.high = at;
9
+ }
10
+ if (found.low === undefined || value < slots[found.low]) {
11
+ found.low = at;
12
+ }
13
+ });
14
+ return found;
15
+ };
16
+ export const readingWords = (label, text, position) => {
17
+ const named = label === '' ? text : text === '' ? label : `${label}: ${text}`;
18
+ return position === '' ? named : `${named} (${position})`;
19
+ };