@fusion.dev/helix-headless 0.23.0 → 0.24.1

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 (124) hide show
  1. package/custom-elements.json +50579 -26954
  2. package/dist/announcement/root/announcement-root.d.ts +19 -5
  3. package/dist/area-chart/index.d.ts +1 -0
  4. package/dist/area-chart/index.js +1 -0
  5. package/dist/area-chart/root/area-chart-root.d.ts +182 -0
  6. package/dist/area-chart/root/area-chart-root.js +205 -0
  7. package/dist/avatar/group/avatar-group.d.ts +1 -0
  8. package/dist/avatar/group/avatar-group.js +5 -1
  9. package/dist/avatar/root/avatar-root.d.ts +1 -0
  10. package/dist/avatar/root/avatar-root.js +11 -0
  11. package/dist/carousel/root/carousel-root.d.ts +3 -0
  12. package/dist/carousel/root/carousel-root.js +23 -4
  13. package/dist/chat/index.d.ts +1 -1
  14. package/dist/chat/message/chat-message.d.ts +7 -0
  15. package/dist/chat/message/chat-message.js +2 -1
  16. package/dist/chat/root/chat-root.d.ts +195 -4
  17. package/dist/chat/root/chat-root.js +316 -23
  18. package/dist/checkbox-group/root/checkbox-group-root.d.ts +2 -0
  19. package/dist/checkbox-group/root/checkbox-group-root.js +12 -2
  20. package/dist/code-block/index.d.ts +1 -0
  21. package/dist/code-block/index.js +1 -0
  22. package/dist/code-block/patch.d.ts +62 -0
  23. package/dist/code-block/patch.js +93 -0
  24. package/dist/code-block/root/code-block-root.d.ts +82 -17
  25. package/dist/code-block/root/code-block-root.js +83 -6
  26. package/dist/color-picker/root/color-picker-root.d.ts +4 -3
  27. package/dist/color-picker/root/color-picker-root.js +4 -1
  28. package/dist/combobox/root/combobox-root.d.ts +1 -0
  29. package/dist/combobox/root/combobox-root.js +6 -1
  30. package/dist/command/root/command-root.d.ts +7 -0
  31. package/dist/command/root/command-root.js +10 -0
  32. package/dist/data-table/root/data-table-root.d.ts +195 -23
  33. package/dist/data-table/root/data-table-root.js +308 -27
  34. package/dist/description-list/index.d.ts +2 -0
  35. package/dist/description-list/index.js +2 -0
  36. package/dist/description-list/item/description-list-item.d.ts +39 -0
  37. package/dist/description-list/item/description-list-item.js +26 -0
  38. package/dist/description-list/root/description-list-root.d.ts +56 -0
  39. package/dist/description-list/root/description-list-root.js +21 -0
  40. package/dist/element-events.generated.js +27 -6
  41. package/dist/filter-input/chip/filter-chip.d.ts +114 -0
  42. package/dist/filter-input/chip/filter-chip.js +61 -0
  43. package/dist/filter-input/field/filter-field.d.ts +128 -0
  44. package/dist/filter-input/field/filter-field.js +70 -0
  45. package/dist/filter-input/grammar.d.ts +96 -0
  46. package/dist/filter-input/grammar.js +133 -0
  47. package/dist/filter-input/index.d.ts +5 -0
  48. package/dist/filter-input/index.js +5 -0
  49. package/dist/filter-input/menu/filter-menu.d.ts +153 -0
  50. package/dist/filter-input/menu/filter-menu.js +164 -0
  51. package/dist/filter-input/operator/filter-operator.d.ts +105 -0
  52. package/dist/filter-input/operator/filter-operator.js +39 -0
  53. package/dist/filter-input/root/filter-input-root.d.ts +118 -9
  54. package/dist/filter-input/root/filter-input-root.js +96 -2
  55. package/dist/format-date/root/format-date-root.js +5 -2
  56. package/dist/image/root/image-root.d.ts +9 -0
  57. package/dist/image/root/image-root.js +16 -3
  58. package/dist/index.d.ts +5 -0
  59. package/dist/index.js +5 -0
  60. package/dist/kbd/root/kbd-root.d.ts +9 -2
  61. package/dist/kbd/root/kbd-root.js +7 -2
  62. package/dist/line-chart/root/line-chart-root.d.ts +9 -2
  63. package/dist/listbox/root/listbox-root.d.ts +8 -7
  64. package/dist/listbox/root/listbox-root.js +7 -2
  65. package/dist/menu/item/menu-item.d.ts +31 -6
  66. package/dist/menu/item/menu-item.js +18 -5
  67. package/dist/menu/root/menu-root.js +7 -2
  68. package/dist/notifications/group/notification-group.d.ts +129 -0
  69. package/dist/notifications/group/notification-group.js +106 -0
  70. package/dist/notifications/index.d.ts +1 -0
  71. package/dist/notifications/index.js +1 -0
  72. package/dist/notifications/notification/notification.d.ts +39 -13
  73. package/dist/notifications/notification/notification.js +11 -8
  74. package/dist/notifications/root/notifications-root.d.ts +57 -1
  75. package/dist/notifications/root/notifications-root.js +35 -4
  76. package/dist/number-input/root/number-input-root.d.ts +21 -1
  77. package/dist/number-input/root/number-input-root.js +18 -5
  78. package/dist/object-inspector/index.d.ts +1 -0
  79. package/dist/object-inspector/index.js +1 -0
  80. package/dist/object-inspector/root/object-inspector-root.d.ts +183 -0
  81. package/dist/object-inspector/root/object-inspector-root.js +348 -0
  82. package/dist/option/root/option-root.d.ts +17 -0
  83. package/dist/option/root/option-root.js +4 -0
  84. package/dist/outline/root/outline-root.d.ts +16 -1
  85. package/dist/outline/root/outline-root.js +27 -9
  86. package/dist/qr-code/root/qr-code-root.d.ts +3 -1
  87. package/dist/qr-code/root/qr-code-root.js +11 -1
  88. package/dist/radio/group/radio-group.d.ts +1 -0
  89. package/dist/rating/root/rating-root.d.ts +3 -0
  90. package/dist/rating/root/rating-root.js +9 -0
  91. package/dist/scatter-chart/index.d.ts +1 -0
  92. package/dist/scatter-chart/index.js +1 -0
  93. package/dist/scatter-chart/root/scatter-chart-root.d.ts +144 -0
  94. package/dist/scatter-chart/root/scatter-chart-root.js +205 -0
  95. package/dist/select/root/select-root.d.ts +8 -0
  96. package/dist/select/root/select-root.js +8 -6
  97. package/dist/skip-link/index.d.ts +1 -0
  98. package/dist/skip-link/index.js +1 -0
  99. package/dist/skip-link/root/skip-link-root.d.ts +81 -0
  100. package/dist/skip-link/root/skip-link-root.js +58 -0
  101. package/dist/speed-dial/root/speed-dial-root.d.ts +1 -0
  102. package/dist/speed-dial/root/speed-dial-root.js +6 -2
  103. package/dist/steps/root/steps-root.d.ts +1 -0
  104. package/dist/steps/root/steps-root.js +5 -2
  105. package/dist/table/column/table-column.d.ts +79 -0
  106. package/dist/table/column/table-column.js +125 -5
  107. package/dist/table/root/table-root.d.ts +2 -0
  108. package/dist/table/root/table-root.js +12 -3
  109. package/dist/time-picker/root/time-picker-root.d.ts +9 -0
  110. package/dist/time-picker/root/time-picker-root.js +5 -0
  111. package/dist/toast/root/toast-root.d.ts +2 -0
  112. package/dist/tooltip/root/tooltip-root.js +1 -1
  113. package/dist/tour/root/tour-root.d.ts +14 -0
  114. package/dist/tour/root/tour-root.js +43 -18
  115. package/dist/tree/item/tree-item.d.ts +7 -4
  116. package/dist/tree/item/tree-item.js +4 -1
  117. package/dist/video/root/video-root.d.ts +23 -1
  118. package/dist/video/root/video-root.js +46 -23
  119. package/dist/virtual-list/root/virtual-list-root.d.ts +10 -6
  120. package/dist/virtual-list/root/virtual-list-root.js +10 -4
  121. package/package.json +5 -5
  122. package/types/jsx.d.ts +4536 -346
  123. package/types/svelte.d.ts +11 -0
  124. package/types/vue.d.ts +738 -39
@@ -0,0 +1,348 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { CopyController, customElement, HelixElement, VirtualizeController, } from '@fusion.dev/helix-core';
8
+ import { caretDown, caretRight } from '@fusion.dev/helix-icons';
9
+ import { html, nothing } from 'lit';
10
+ import { property, state } from 'lit/decorators.js';
11
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
+ import { html as staticHtml } from 'lit/static-html.js';
13
+ import '../../copy-button/index.js';
14
+ const branchy = (value) => value !== null && typeof value === 'object';
15
+ const entries = (value) => Array.isArray(value) ? value.map((item, at) => [String(at), item]) : Object.entries(value);
16
+ const child = (path, key) => `${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`;
17
+ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends HelixElement {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.defaultDepth = 1;
21
+ this.for = '';
22
+ this.label = '';
23
+ this.noCopy = false;
24
+ this.value = undefined;
25
+ this.windowed = false;
26
+ this.read = undefined;
27
+ this.opened = new Set();
28
+ this.active = 0;
29
+ this.revealing = false;
30
+ this.virtualize = new VirtualizeController(this, {
31
+ container: () => this.windowed ? this.renderRoot?.querySelector('[part="tree"]') : null,
32
+ count: () => this.rows.length,
33
+ estimate: () => 24,
34
+ measured: () => this.windowed,
35
+ rows: () => [...(this.renderRoot?.querySelectorAll('[part="row"]') ?? [])].map((element) => ({ element, index: Number(element.dataset.index) })),
36
+ });
37
+ this.rows = [];
38
+ this.copier = new CopyController(this);
39
+ this.handleKeydown = (event) => {
40
+ const rows = this.rows;
41
+ const row = rows[this.active];
42
+ if (!row) {
43
+ return;
44
+ }
45
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'c') {
46
+ if (globalThis.getSelection?.()?.toString()) {
47
+ return;
48
+ }
49
+ void this.copier.copy(this.copyable(row));
50
+ event.preventDefault();
51
+ return;
52
+ }
53
+ switch (event.key) {
54
+ case 'ArrowDown':
55
+ this.move(this.active + 1);
56
+ break;
57
+ case 'ArrowUp':
58
+ this.move(this.active - 1);
59
+ break;
60
+ case 'Home':
61
+ this.move(0);
62
+ break;
63
+ case 'End':
64
+ this.move(rows.length - 1);
65
+ break;
66
+ case 'ArrowRight':
67
+ if (row.branch && !row.open) {
68
+ this.toggle(row, true);
69
+ }
70
+ else if (row.open) {
71
+ this.move(this.active + 1);
72
+ }
73
+ break;
74
+ case 'ArrowLeft':
75
+ if (row.open) {
76
+ this.toggle(row, false);
77
+ }
78
+ else {
79
+ const parent = rows.findLastIndex((candidate, at) => at < this.active && candidate.depth === row.depth - 1);
80
+ if (parent >= 0) {
81
+ this.move(parent);
82
+ }
83
+ }
84
+ break;
85
+ case 'Enter':
86
+ case ' ':
87
+ if (row.branch) {
88
+ this.toggle(row);
89
+ }
90
+ break;
91
+ default:
92
+ return;
93
+ }
94
+ event.preventDefault();
95
+ };
96
+ }
97
+ get root() {
98
+ return this.value === undefined ? this.read : this.value;
99
+ }
100
+ flatten() {
101
+ const rows = [];
102
+ if (this.root === undefined) {
103
+ return rows;
104
+ }
105
+ const visit = (value, path, depth, position, siblings, key) => {
106
+ const branch = branchy(value);
107
+ const open = branch && this.opened.has(path);
108
+ rows.push({
109
+ branch,
110
+ depth,
111
+ open,
112
+ path,
113
+ position,
114
+ siblings,
115
+ value,
116
+ ...(key === undefined ? {} : { key }),
117
+ });
118
+ if (open) {
119
+ const children = entries(value);
120
+ children.forEach(([name, item], at) => {
121
+ visit(item, child(path, name), depth + 1, at + 1, children.length, name);
122
+ });
123
+ }
124
+ };
125
+ visit(this.root, '', 0, 1, 1);
126
+ return rows;
127
+ }
128
+ seed() {
129
+ const opened = new Set();
130
+ const visit = (value, path, depth) => {
131
+ if (!branchy(value) || depth >= this.defaultDepth) {
132
+ return;
133
+ }
134
+ opened.add(path);
135
+ for (const [name, item] of entries(value)) {
136
+ visit(item, child(path, name), depth + 1);
137
+ }
138
+ };
139
+ visit(this.root, '', 0);
140
+ this.opened = opened;
141
+ this.active = 0;
142
+ }
143
+ willUpdate(changed) {
144
+ super.willUpdate(changed);
145
+ if (this.loadedFor !== this.for &&
146
+ typeof this.ownerDocument?.getElementById === 'function' &&
147
+ !this.hydrating) {
148
+ this.loadedFor = this.for;
149
+ this.load();
150
+ }
151
+ if (changed.has('value') || changed.has('read') || changed.has('defaultDepth')) {
152
+ this.seed();
153
+ }
154
+ if (changed.has('value') ||
155
+ changed.has('read') ||
156
+ changed.has('opened') ||
157
+ changed.has('defaultDepth')) {
158
+ this.rows = this.flatten();
159
+ this.active = Math.min(this.active, Math.max(0, this.rows.length - 1));
160
+ }
161
+ }
162
+ firstUpdated(changed) {
163
+ super.firstUpdated(changed);
164
+ this.finishHydration();
165
+ }
166
+ updated(changed) {
167
+ super.updated?.(changed);
168
+ if (this.windowed) {
169
+ this.virtualize.measure();
170
+ }
171
+ if (this.revealing) {
172
+ this.revealing = false;
173
+ this.reveal();
174
+ }
175
+ }
176
+ load() {
177
+ const text = this.for === '' ? '' : (this.ownerDocument.getElementById(this.for)?.textContent ?? '');
178
+ try {
179
+ this.read = text.trim() === '' ? undefined : JSON.parse(text);
180
+ }
181
+ catch {
182
+ this.read = undefined;
183
+ }
184
+ }
185
+ reveal(attempts = 8) {
186
+ const tree = this.renderRoot?.querySelector('[part="tree"]');
187
+ const row = tree?.querySelector(`[data-index="${this.active}"]`);
188
+ if (row) {
189
+ row.scrollIntoView({ block: 'nearest' });
190
+ return;
191
+ }
192
+ const drawn = [...(tree?.querySelectorAll('[part="row"]') ?? [])];
193
+ const first = drawn[0];
194
+ const last = drawn.at(-1);
195
+ if (!tree || !this.windowed || !first || !last || attempts === 0) {
196
+ return;
197
+ }
198
+ const height = first.offsetHeight || 24;
199
+ const from = Number(this.active > Number(last.dataset.index) ? last.dataset.index : first.dataset.index);
200
+ tree.scrollTop += (this.active - from) * height;
201
+ this.virtualize.measure();
202
+ void this.updateComplete.then(() => this.reveal(attempts - 1));
203
+ }
204
+ copyable(row) {
205
+ if (!row) {
206
+ return '';
207
+ }
208
+ if (typeof row.value === 'string') {
209
+ return row.value;
210
+ }
211
+ return JSON.stringify(row.value, null, 2) ?? String(row.value);
212
+ }
213
+ toggle(row, open = !row.open) {
214
+ const opened = new Set(this.opened);
215
+ if (open) {
216
+ opened.add(row.path);
217
+ }
218
+ else {
219
+ opened.delete(row.path);
220
+ }
221
+ this.opened = opened;
222
+ }
223
+ move(to) {
224
+ const last = this.rows.length - 1;
225
+ this.active = Math.max(0, Math.min(to, last));
226
+ this.revealing = true;
227
+ }
228
+ handleRowClick(index, row) {
229
+ this.active = index;
230
+ if (row.branch) {
231
+ this.toggle(row);
232
+ }
233
+ }
234
+ renderValue(row) {
235
+ const { value } = row;
236
+ if (row.branch) {
237
+ const count = entries(value).length;
238
+ const array = Array.isArray(value);
239
+ const noun = array ? (count === 1 ? 'item' : 'items') : count === 1 ? 'key' : 'keys';
240
+ return html `<span part="summary">${array ? '[…]' : '{…}'}</span>
241
+ <span part="count">${`${count} ${noun}`}</span>`;
242
+ }
243
+ if (typeof value === 'string') {
244
+ return html `<span part="string">${JSON.stringify(value)}</span>`;
245
+ }
246
+ if (typeof value === 'number') {
247
+ return html `<span part="number">${String(value)}</span>`;
248
+ }
249
+ if (typeof value === 'boolean') {
250
+ return html `<span part="boolean">${String(value)}</span>`;
251
+ }
252
+ if (value === null) {
253
+ return html `<span part="null">null</span>`;
254
+ }
255
+ return html `<span part="string">${String(value)}</span>`;
256
+ }
257
+ renderRow(row, index) {
258
+ return html `<div
259
+ part="row"
260
+ role="treeitem"
261
+ id=${`row-${index}`}
262
+ data-index=${index}
263
+ ?data-active=${index === this.active}
264
+ aria-level=${row.depth + 1}
265
+ aria-posinset=${row.position}
266
+ aria-setsize=${row.siblings}
267
+ aria-expanded=${row.branch ? String(row.open) : nothing}
268
+ style=${`--object-inspector-level: ${row.depth}`}
269
+ @click=${() => this.handleRowClick(index, row)}
270
+ >
271
+ ${row.branch
272
+ ? html `<svg
273
+ part="toggle"
274
+ fill="currentColor"
275
+ viewBox=${(row.open ? caretDown : caretRight).viewBox}
276
+ aria-hidden="true"
277
+ >
278
+ ${unsafeSVG((row.open ? caretDown : caretRight).content)}
279
+ </svg>`
280
+ : nothing}${row.key === undefined ? nothing : html `<span part="key">${row.key}</span>: `}${this.renderValue(row)}
281
+ </div>`;
282
+ }
283
+ renderCopyButton(row) {
284
+ return staticHtml `<${this.tag('copy-button')}
285
+ part="copy"
286
+ exportparts="button: copy-button, mark: copy-mark, tooltip: copy-tooltip,
287
+ tooltip-arrow: copy-tooltip-arrow"
288
+ label=${row?.key === undefined ? 'Copy value' : `Copy ${row.key}`}
289
+ .value=${this.copyable(row)}
290
+ ></${this.tag('copy-button')}>`;
291
+ }
292
+ render() {
293
+ const rows = this.rows;
294
+ const { after, before, first, last } = this.windowed
295
+ ? this.virtualize.window
296
+ : { after: 0, before: 0, first: 0, last: rows.length };
297
+ const shown = rows.slice(first, last);
298
+ return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}
299
+ <div part="frame">
300
+ <div
301
+ part="tree"
302
+ role="tree"
303
+ tabindex="0"
304
+ ?data-scroller=${this.windowed}
305
+ aria-label=${this.label || 'Value'}
306
+ aria-activedescendant=${rows.length > 0 ? `row-${this.active}` : nothing}
307
+ @keydown=${this.handleKeydown}
308
+ @scroll=${() => this.virtualize.measure()}
309
+ >
310
+ ${this.windowed ? html `<div part="before" role="presentation" style="block-size: ${before}px"></div>` : nothing}
311
+ ${shown.map((row, at) => this.renderRow(row, first + at))}
312
+ ${this.windowed ? html `<div part="after" role="presentation" style="block-size: ${after}px"></div>` : nothing}
313
+ </div>
314
+ ${this.noCopy ? nothing : this.renderCopyButton(rows[this.active])}
315
+ </div>`;
316
+ }
317
+ };
318
+ __decorate([
319
+ property({ attribute: 'default-depth', type: Number })
320
+ ], HelixHeadlessObjectInspector.prototype, "defaultDepth", void 0);
321
+ __decorate([
322
+ property()
323
+ ], HelixHeadlessObjectInspector.prototype, "for", void 0);
324
+ __decorate([
325
+ property()
326
+ ], HelixHeadlessObjectInspector.prototype, "label", void 0);
327
+ __decorate([
328
+ property({ attribute: 'no-copy', reflect: true, type: Boolean })
329
+ ], HelixHeadlessObjectInspector.prototype, "noCopy", void 0);
330
+ __decorate([
331
+ property({ attribute: false })
332
+ ], HelixHeadlessObjectInspector.prototype, "value", void 0);
333
+ __decorate([
334
+ property({ reflect: true, type: Boolean })
335
+ ], HelixHeadlessObjectInspector.prototype, "windowed", void 0);
336
+ __decorate([
337
+ state()
338
+ ], HelixHeadlessObjectInspector.prototype, "read", void 0);
339
+ __decorate([
340
+ state()
341
+ ], HelixHeadlessObjectInspector.prototype, "opened", void 0);
342
+ __decorate([
343
+ state()
344
+ ], HelixHeadlessObjectInspector.prototype, "active", void 0);
345
+ HelixHeadlessObjectInspector = __decorate([
346
+ customElement('helix-headless-object-inspector')
347
+ ], HelixHeadlessObjectInspector);
348
+ export { HelixHeadlessObjectInspector };
@@ -1,5 +1,22 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
+ /**
4
+ * The options among some elements, reaching one level into a group.
5
+ *
6
+ * What a control holding options reads its words from, off its own children
7
+ * rather than off the listbox they are slotted into: the slot exists only once a
8
+ * render has made it, so the listbox has none on a first render, and on a page a
9
+ * server rendered the `slotchange` that would correct it fires before anything
10
+ * listens.
11
+ *
12
+ * **An option by its shape, not by `instanceof`.** A tag is defined once, by
13
+ * whichever copy of this class registered it first, and a second copy in the
14
+ * same document tests against a class no element on the page has: every option
15
+ * failed it, and a select said "Choose" over its value. Two copies are a
16
+ * consumer with a duplicated dependency, or the browser specs, where each
17
+ * family's bundle carries its own and they share one page.
18
+ */
19
+ export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadlessOption[];
3
20
  /**
4
21
  * @summary One choice in a listbox.
5
22
  *
@@ -7,6 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, HelixElement, HelixSelectEvent } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ export const optionsAmong = (elements) => {
11
+ const isOption = (element) => 'text' in element && 'value' in element && 'selected' in element;
12
+ return elements.flatMap((element) => isOption(element) ? [element] : [...element.children].filter(isOption));
13
+ };
10
14
  let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
11
15
  constructor() {
12
16
  super(...arguments);
@@ -58,7 +58,8 @@ export declare class HelixHeadlessOutline extends HelixElement {
58
58
  */
59
59
  label: string;
60
60
  /**
61
- * How far below the top of the window a heading counts as reached, in pixels.
61
+ * How far below the top of what scrolls a heading counts as reached, in
62
+ * pixels: the window, or the panel the sections scroll in.
62
63
  *
63
64
  * The reading line. A page with a sticky masthead sets this to its height, or
64
65
  * a little more: without it the current section changes as a heading slides
@@ -119,6 +120,20 @@ export declare class HelixHeadlessOutline extends HelixElement {
119
120
  * measured against.
120
121
  */
121
122
  private get atEnd();
123
+ /** The element the page itself scrolls with, which `atEnd` explains. */
124
+ private get page();
125
+ /**
126
+ * What the sections scroll in: the nearest ancestor of the first one that
127
+ * scrolls, or the page when none does.
128
+ *
129
+ * **The window is not always what moves.** A contents rail beside a panel
130
+ * with its own scrollbar, which is a docs layout and every sandbox preview,
131
+ * measured the window. The window never scrolled, so it was always at its end
132
+ * and the last section was always current: the events example named `api`
133
+ * at rest with `install` on screen, a wheel over the panel changed nothing,
134
+ * and a press on `install` marked it for a moment and snapped back.
135
+ */
136
+ private get scroller();
122
137
  /** The frame a mark is already scheduled for, so a scroll asks for one. */
123
138
  private frame;
124
139
  /** Where a click said to go, while the page is still on its way there. */
@@ -47,10 +47,10 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
47
47
  const arrive = () => {
48
48
  clearTimeout(this.landed);
49
49
  this.landing = undefined;
50
- globalThis.removeEventListener?.('scrollend', arrive);
50
+ globalThis.document?.removeEventListener('scrollend', arrive, true);
51
51
  this.mark();
52
52
  };
53
- globalThis.addEventListener?.('scrollend', arrive, { once: true });
53
+ globalThis.document?.addEventListener('scrollend', arrive, { capture: true, once: true });
54
54
  this.landed = setTimeout(arrive, 1200);
55
55
  if (this.behavior === 'auto') {
56
56
  return;
@@ -97,7 +97,10 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
97
97
  if (sections.length === 0) {
98
98
  return;
99
99
  }
100
- const passed = sections.filter(({ target }) => target.getBoundingClientRect().top - this.offset <= 1);
100
+ const scroller = this.scroller;
101
+ const page = scroller === this.page;
102
+ const origin = page ? 0 : scroller.getBoundingClientRect().top;
103
+ const passed = sections.filter(({ target }) => target.getBoundingClientRect().top - origin - this.offset <= 1);
101
104
  const active = this.atEnd ? sections.at(-1) : (passed.at(-1) ?? sections[0]);
102
105
  this.markTo(active);
103
106
  }
@@ -117,12 +120,24 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
117
120
  }
118
121
  }
119
122
  get atEnd() {
120
- const doc = globalThis.document?.scrollingElement ?? globalThis.document?.documentElement;
121
- if (!doc) {
122
- return false;
123
- }
123
+ const doc = this.scroller;
124
124
  return Math.ceil(doc.scrollTop + doc.clientHeight) >= doc.scrollHeight - 1;
125
125
  }
126
+ get page() {
127
+ const doc = globalThis.document;
128
+ return (doc.scrollingElement ?? doc.documentElement);
129
+ }
130
+ get scroller() {
131
+ const doc = globalThis.document;
132
+ const first = this.sections[0]?.target;
133
+ for (let node = first?.parentElement; node && node !== doc.body && node !== doc.documentElement; node = node.parentElement) {
134
+ const { overflowY } = getComputedStyle(node);
135
+ if (/auto|scroll|overlay/.test(overflowY) && node.scrollHeight > node.clientHeight) {
136
+ return node;
137
+ }
138
+ }
139
+ return this.page;
140
+ }
126
141
  reach() {
127
142
  for (const { target } of this.sections) {
128
143
  const element = target;
@@ -147,7 +162,7 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
147
162
  disconnectedCallback() {
148
163
  super.disconnectedCallback();
149
164
  this.removeEventListener('click', this.handleClick);
150
- globalThis.removeEventListener?.('scroll', this.handleScroll);
165
+ globalThis.document?.removeEventListener('scroll', this.handleScroll, true);
151
166
  if (this.frame !== 0) {
152
167
  globalThis.cancelAnimationFrame(this.frame);
153
168
  this.frame = 0;
@@ -162,7 +177,10 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
162
177
  connectedCallback() {
163
178
  super.connectedCallback();
164
179
  this.addEventListener('click', this.handleClick);
165
- globalThis.addEventListener?.('scroll', this.handleScroll, { passive: true });
180
+ globalThis.document?.addEventListener('scroll', this.handleScroll, {
181
+ capture: true,
182
+ passive: true,
183
+ });
166
184
  if (this.hasUpdated) {
167
185
  this.watch();
168
186
  this.resize = new ResizeObserver(() => this.indicator.place());
@@ -1,5 +1,5 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type TemplateResult } from 'lit';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  /** How much of the code can be lost and still read. */
4
4
  export type QrCorrection = 'H' | 'L' | 'M' | 'Q';
5
5
  /** How the modules are drawn. */
@@ -81,6 +81,8 @@ export declare class HelixHeadlessQrCode extends HelixElement {
81
81
  value: string;
82
82
  /** Whether anything is slotted into the middle. */
83
83
  private logo;
84
+ protected willUpdate(changed: PropertyValues): void;
85
+ protected firstUpdated(changed: PropertyValues): void;
84
86
  /** The level actually used, which the slot can raise. */
85
87
  private get level();
86
88
  private renderCode;
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
- import { html, nothing, svg } from 'lit';
8
+ import { html, nothing, svg, } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { encode } from 'uqr';
11
11
  const isFinder = (x, y, size) => {
@@ -67,6 +67,16 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
67
67
  this.value = '';
68
68
  this.logo = false;
69
69
  }
70
+ willUpdate(changed) {
71
+ super.willUpdate(changed);
72
+ if (this.childrenKnown) {
73
+ this.logo = this.knownChildren.some((child) => child.slot === 'logo');
74
+ }
75
+ }
76
+ firstUpdated(changed) {
77
+ super.firstUpdated(changed);
78
+ this.finishHydration();
79
+ }
70
80
  get level() {
71
81
  return this.correction ?? (this.logo ? 'H' : 'M');
72
82
  }
@@ -36,6 +36,7 @@ declare const HelixHeadlessRadioGroup_base: (new (...args: any[]) => import("@fu
36
36
  *
37
37
  * @event {Event} change - Announced once the value has moved.
38
38
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired when the answer changes, and cancelable.
39
+ * @event {HelixSelectEvent} helix-select - Fired when an answer is chosen. Dispatched by the radio and listened for here, because the group is what a consumer holds. Cancelable: refusing it takes the decision and nothing moves.
39
40
  * @event {Event} input - Announced once the value has moved.
40
41
  *
41
42
  * @csspart feedback - What is wrong with it.
@@ -111,6 +111,8 @@ export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
111
111
  * ignored.
112
112
  */
113
113
  private markSource;
114
+ /** Whether `markSource` has had its first answer from the children. */
115
+ private markRead;
114
116
  /**
115
117
  * What the pointer is over, which is shown instead of the score while it is.
116
118
  */
@@ -194,6 +196,7 @@ export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
194
196
  connectedCallback(): void;
195
197
  disconnectedCallback(): void;
196
198
  protected updated(changed: PropertyValues): void;
199
+ protected willUpdate(changed: PropertyValues): void;
197
200
  protected firstUpdated(changed: PropertyValues): void;
198
201
  protected render(): TemplateResult;
199
202
  /**
@@ -18,6 +18,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
18
18
  this.step = 1;
19
19
  this.valueText = '';
20
20
  this.markSource = undefined;
21
+ this.markRead = false;
21
22
  this.previewing = undefined;
22
23
  this.keys = new KeyboardNavigationController(this, {
23
24
  items: () => this.options,
@@ -157,8 +158,16 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
157
158
  super.updated?.(changed);
158
159
  this.sync();
159
160
  }
161
+ willUpdate(changed) {
162
+ super.willUpdate(changed);
163
+ if (!this.markRead && this.childrenKnown) {
164
+ this.markRead = true;
165
+ this.markSource = this.knownChildren.find((child) => child.slot === 'mark');
166
+ }
167
+ }
160
168
  firstUpdated(changed) {
161
169
  super.firstUpdated?.(changed);
170
+ this.finishHydration();
162
171
  this.sync();
163
172
  }
164
173
  render() {
@@ -0,0 +1 @@
1
+ export * from './root/scatter-chart-root.js';
@@ -0,0 +1 @@
1
+ export * from './root/scatter-chart-root.js';