@fusion.dev/helix-headless 0.144.0 → 0.145.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.
- package/custom-elements.json +8312 -881
- package/dist/accordion/item/accordion-item.d.ts +48 -12
- package/dist/accordion/item/accordion-item.js +26 -5
- package/dist/accordion/root/accordion-root.d.ts +6 -0
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +21 -1
- package/dist/announcement/root/announcement-root.js +36 -1
- package/dist/app-header/root/app-header-root.d.ts +7 -0
- package/dist/app-header/root/app-header-root.js +5 -1
- package/dist/app-header/sectioning.d.ts +7 -0
- package/dist/app-header/sectioning.js +26 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +121 -40
- package/dist/carousel/root/carousel-root.d.ts +90 -0
- package/dist/carousel/root/carousel-root.js +134 -12
- package/dist/chat/composer/chat-composer.d.ts +38 -6
- package/dist/chat/composer/chat-composer.js +42 -9
- package/dist/chat/message/chat-message.d.ts +32 -1
- package/dist/chat/message/chat-message.js +25 -9
- package/dist/chat/naming.d.ts +22 -0
- package/dist/chat/naming.js +12 -0
- package/dist/chat/relative-clock.d.ts +39 -0
- package/dist/chat/relative-clock.js +31 -0
- package/dist/chat/root/chat-root.d.ts +36 -0
- package/dist/chat/root/chat-root.js +24 -1
- package/dist/code-block/root/code-block-root.d.ts +8 -1
- package/dist/code-block/root/code-block-root.js +5 -5
- package/dist/copy-button/root/copy-button-root.d.ts +21 -1
- package/dist/copy-button/root/copy-button-root.js +2 -2
- package/dist/data-table/root/data-table-root.d.ts +150 -2
- package/dist/data-table/root/data-table-root.js +303 -29
- package/dist/data-table/tree.d.ts +40 -0
- package/dist/data-table/tree.js +55 -0
- package/dist/description-list/item/description-list-item.d.ts +17 -2
- package/dist/description-list/item/description-list-item.js +15 -2
- package/dist/description-list/root/description-list-root.d.ts +27 -1
- package/dist/description-list/root/description-list-root.js +26 -1
- package/dist/drilldown/item/drilldown-item.d.ts +11 -6
- package/dist/drilldown/item/drilldown-item.js +8 -5
- package/dist/drilldown/root/drilldown-root.d.ts +11 -0
- package/dist/drilldown/root/drilldown-root.js +8 -3
- package/dist/element-events.generated.js +53 -8
- package/dist/filter-input/menu/filter-menu.d.ts +3 -0
- package/dist/filter-input/menu/filter-menu.js +8 -4
- package/dist/image/root/image-root.js +9 -1
- package/dist/input/root/input-root.d.ts +1 -1
- package/dist/input/root/input-root.js +2 -2
- package/dist/list/item/list-item.d.ts +68 -1
- package/dist/list/item/list-item.js +66 -4
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +106 -9
- package/dist/list/root/list-root.js +189 -4
- package/dist/list/selection.d.ts +19 -0
- package/dist/list/selection.js +21 -0
- package/dist/listbox/root/listbox-root.js +1 -2
- package/dist/map/root/map-root.d.ts +6 -2
- package/dist/map/root/map-root.js +5 -2
- package/dist/megamenu/root/megamenu-root.d.ts +21 -0
- package/dist/megamenu/root/megamenu-root.js +16 -2
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +38 -11
- package/dist/menu/item/menu-item.js +33 -1
- package/dist/menu/root/menu-root.d.ts +25 -1
- package/dist/menu/root/menu-root.js +63 -6
- package/dist/menu/section/menu-section.d.ts +55 -0
- package/dist/menu/section/menu-section.js +60 -0
- package/dist/navigation/root/navigation-root.d.ts +16 -1
- package/dist/navigation/root/navigation-root.js +27 -1
- package/dist/notifications/root/notifications-root.d.ts +18 -0
- package/dist/notifications/root/notifications-root.js +17 -1
- package/dist/object-inspector/root/object-inspector-root.d.ts +97 -16
- package/dist/object-inspector/root/object-inspector-root.js +179 -79
- package/dist/object-inspector/rows.d.ts +57 -0
- package/dist/object-inspector/rows.js +86 -0
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +68 -3
- package/dist/outline/root/outline-root.js +73 -8
- package/dist/pagination/size/pagination-size.d.ts +11 -2
- package/dist/pagination/size/pagination-size.js +19 -4
- package/dist/radio/group/radio-group.d.ts +4 -10
- package/dist/radio/group/radio-group.js +5 -10
- package/dist/rating/root/rating-root.d.ts +1 -1
- package/dist/rating/root/rating-root.js +2 -2
- package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
- package/dist/scroll-area/root/scroll-area-root.js +218 -3
- package/dist/scroll-area/scrollbar.d.ts +65 -0
- package/dist/scroll-area/scrollbar.js +24 -0
- package/dist/select/root/select-root.js +1 -1
- package/dist/splitter/root/splitter-root.d.ts +13 -0
- package/dist/splitter/root/splitter-root.js +20 -2
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/steps/reach.d.ts +15 -0
- package/dist/steps/reach.js +12 -0
- package/dist/steps/root/steps-root.d.ts +30 -0
- package/dist/steps/root/steps-root.js +53 -0
- package/dist/steps/step/step.d.ts +38 -2
- package/dist/steps/step/step.js +28 -6
- package/dist/table/column/table-column.d.ts +11 -0
- package/dist/table/column/table-column.js +6 -1
- package/dist/table/root/table-root.d.ts +101 -0
- package/dist/table/root/table-root.js +166 -5
- package/dist/table/row/table-row.d.ts +47 -1
- package/dist/table/row/table-row.js +39 -2
- package/dist/tabs/panel/tab-panel.d.ts +9 -5
- package/dist/tabs/panel/tab-panel.js +3 -4
- package/dist/tabs/root/tabs-root.d.ts +25 -1
- package/dist/tabs/root/tabs-root.js +21 -3
- package/dist/tabs/tab/tab.d.ts +36 -4
- package/dist/tabs/tab/tab.js +46 -3
- package/dist/timeline/group/timeline-group.d.ts +46 -0
- package/dist/timeline/group/timeline-group.js +37 -0
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/index.js +1 -0
- package/dist/timeline/root/timeline-root.d.ts +10 -3
- package/dist/toast/item/toast-item.d.ts +10 -17
- package/dist/toast/item/toast-item.js +15 -36
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- package/dist/tree/item/tree-item.d.ts +54 -1
- package/dist/tree/item/tree-item.js +89 -20
- package/dist/tree/root/tree-root.d.ts +37 -0
- package/dist/tree/root/tree-root.js +51 -6
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +26 -0
- package/dist/video/media-events.d.ts +49 -0
- package/dist/video/media-events.js +39 -0
- package/dist/video/root/video-root.d.ts +99 -13
- package/dist/video/root/video-root.js +84 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
- package/dist/video-playlist/order.d.ts +41 -0
- package/dist/video-playlist/order.js +34 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +70 -2
- package/dist/video-playlist/root/video-playlist-root.js +60 -16
- package/dist/virtual-list/controls.d.ts +4 -0
- package/dist/virtual-list/controls.js +30 -0
- package/dist/virtual-list/fill.d.ts +30 -0
- package/dist/virtual-list/fill.js +39 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
- package/dist/virtual-list/root/virtual-list-root.js +175 -34
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +3778 -801
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +782 -215
- package/dist/listbox/range.d.ts +0 -17
- package/dist/listbox/range.js +0 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { type Branch } from '../levels.js';
|
|
3
4
|
/**
|
|
4
5
|
* @summary Links to the headings on the page, with the section in view marked.
|
|
5
6
|
*
|
|
@@ -12,8 +13,12 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
12
13
|
* the same page.
|
|
13
14
|
*
|
|
14
15
|
* Write the anchors flat, with `data-level` for their depth, or nested in
|
|
15
|
-
* lists, `<ul><li><a>`. A screen reader hears
|
|
16
|
-
*
|
|
16
|
+
* lists, `<ul><li><a>`. A screen reader hears the levels either way: the
|
|
17
|
+
* outline puts a flat run into lists inside list items of its own, nested by
|
|
18
|
+
* `data-level`, and leaves the links where they are. A link without
|
|
19
|
+
* `data-level` is at the top level.
|
|
20
|
+
*
|
|
21
|
+
* A heading slotted into `heading` names the navigation, in place of `label`.
|
|
17
22
|
*
|
|
18
23
|
* The current section is decided by the headings' positions. An
|
|
19
24
|
* `IntersectionObserver` with a band near the top fails both ways: when
|
|
@@ -27,13 +32,24 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
27
32
|
* @documentation https://fusion.dev/helix/components/outline
|
|
28
33
|
*
|
|
29
34
|
* @slot - The links, as anchors with fragment hrefs, or lists holding them.
|
|
35
|
+
* @slot heading - A heading above the links, such as "On this page". It names the navigation.
|
|
30
36
|
*
|
|
31
37
|
* @event {HelixActivateEvent} helix-activate - Fired when the section in view changes, with its id as the value. It reports the scroll position and cannot be prevented.
|
|
32
38
|
*
|
|
39
|
+
* @csspart heading - The box holding the `heading` slot, above the navigation.
|
|
33
40
|
* @csspart indicator - The mark that moves to the section in view.
|
|
34
41
|
* @csspart nav - The navigation landmark.
|
|
35
42
|
*/
|
|
36
43
|
export declare class HelixHeadlessOutline extends HelixElement {
|
|
44
|
+
/**
|
|
45
|
+
* Manual, so each link in a flat run can be put in a list item of its own.
|
|
46
|
+
*
|
|
47
|
+
* The list items are slots, which lay out as nothing at all, so each link is
|
|
48
|
+
* still laid out as a child of the navigation exactly where it was, and the
|
|
49
|
+
* consumer's markup is not touched. A run holding anything but links, a
|
|
50
|
+
* `<ul>` among them, goes to one plain slot as before.
|
|
51
|
+
*/
|
|
52
|
+
static shadowRootOptions: ShadowRootInit;
|
|
37
53
|
private readonly indicator;
|
|
38
54
|
/**
|
|
39
55
|
* How the page scrolls to a section when its link is clicked.
|
|
@@ -58,7 +74,8 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
58
74
|
*/
|
|
59
75
|
behavior: ScrollBehavior;
|
|
60
76
|
/**
|
|
61
|
-
* The navigation's name, read by screen readers.
|
|
77
|
+
* The navigation's name, read by screen readers. A heading in the `heading`
|
|
78
|
+
* slot names it in place of this.
|
|
62
79
|
*/
|
|
63
80
|
label: string;
|
|
64
81
|
/**
|
|
@@ -92,6 +109,11 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
92
109
|
*/
|
|
93
110
|
private reading;
|
|
94
111
|
private observer;
|
|
112
|
+
/**
|
|
113
|
+
* Watches the children, which a manual root is not told about: a link
|
|
114
|
+
* arriving, leaving or changing its level changes the lists drawn for them.
|
|
115
|
+
*/
|
|
116
|
+
private childWatch;
|
|
95
117
|
/**
|
|
96
118
|
* The links, in document order. Empty on the server, which has no tree.
|
|
97
119
|
*
|
|
@@ -101,6 +123,18 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
101
123
|
* nothing was announced, and nothing said why.
|
|
102
124
|
*/
|
|
103
125
|
private get links();
|
|
126
|
+
/** The children that are the content, which is all of them but the heading. */
|
|
127
|
+
private get content();
|
|
128
|
+
/**
|
|
129
|
+
* The links of a flat run, which the render puts into lists, or `undefined`
|
|
130
|
+
* where the content is anything else.
|
|
131
|
+
*
|
|
132
|
+
* Anything else is a list a consumer wrote, which already has its levels, a
|
|
133
|
+
* slot forwarded from a component around this one, or a server's render and
|
|
134
|
+
* the hydration of one, which cannot know the children. A root a server sent
|
|
135
|
+
* routes by name, so it keeps the plain slot after hydration too.
|
|
136
|
+
*/
|
|
137
|
+
private get run();
|
|
104
138
|
/**
|
|
105
139
|
* What each link points at, paired with the link, skipping anything missing.
|
|
106
140
|
*
|
|
@@ -250,8 +284,39 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
250
284
|
private unland;
|
|
251
285
|
connectedCallback(): void;
|
|
252
286
|
protected firstUpdated(changed: PropertyValues): void;
|
|
287
|
+
/**
|
|
288
|
+
* Puts each child in its slot, on a root this element made.
|
|
289
|
+
*
|
|
290
|
+
* A link of a flat run goes to the slot inside its list item, and anything
|
|
291
|
+
* else, with the text between, to the plain slot. A root a server sent
|
|
292
|
+
* routes by name and needs none of it.
|
|
293
|
+
*/
|
|
294
|
+
private assign;
|
|
295
|
+
/** Whether the heading is what names the navigation. */
|
|
296
|
+
private namedByHeading;
|
|
297
|
+
/**
|
|
298
|
+
* Names the navigation by what is in the `heading` slot, in place of `label`.
|
|
299
|
+
*
|
|
300
|
+
* An element reference, because the heading is in the light DOM and the
|
|
301
|
+
* `<nav>` in this shadow root, which an IDREF cannot cross. A browser without
|
|
302
|
+
* element reflection keeps `label`.
|
|
303
|
+
*/
|
|
304
|
+
private readonly nameByHeading;
|
|
253
305
|
protected updated(changed: PropertyValues): void;
|
|
254
306
|
protected render(): TemplateResult;
|
|
307
|
+
/**
|
|
308
|
+
* A list for a run of links, with a list item for each, nested by level.
|
|
309
|
+
*
|
|
310
|
+
* **Slots, because a slot lays out as nothing.** A list and its items drawn
|
|
311
|
+
* as boxes would put each link inside an item, out of the navigation's own
|
|
312
|
+
* flex column, and every outline styled against that column would move. A
|
|
313
|
+
* slot is `display: contents`, keeps a role it is given, and shows its
|
|
314
|
+
* children while nothing is assigned to it, so the items nest in the
|
|
315
|
+
* accessibility tree and nowhere else. Measured in Chromium: every link at the
|
|
316
|
+
* same box with and without the lists, and each item at the level its
|
|
317
|
+
* nesting gives it.
|
|
318
|
+
*/
|
|
319
|
+
protected renderList(branches: Branch[]): TemplateResult;
|
|
255
320
|
}
|
|
256
321
|
declare global {
|
|
257
322
|
interface HTMLElementTagNameMap {
|
|
@@ -4,9 +4,11 @@ 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, HelixActivateEvent, HelixElement, IndicatorController, } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
7
|
+
import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, reflectElements, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { levelOf, nest } from '../levels.js';
|
|
11
|
+
const isFragment = (element) => element instanceof HTMLAnchorElement && element.getAttribute('href')?.startsWith('#') === true;
|
|
10
12
|
let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
11
13
|
constructor() {
|
|
12
14
|
super(...arguments);
|
|
@@ -72,16 +74,38 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
72
74
|
this.watch();
|
|
73
75
|
this.indicator.place();
|
|
74
76
|
};
|
|
77
|
+
this.namedByHeading = false;
|
|
78
|
+
this.nameByHeading = () => {
|
|
79
|
+
const slot = this.renderRoot?.querySelector?.('slot[name="heading"]');
|
|
80
|
+
this.namedByHeading = reflectElements(this.partNamed('nav'), 'ariaLabelledByElements', slot?.assignedElements({ flatten: true }) ?? [], this.namedByHeading);
|
|
81
|
+
};
|
|
75
82
|
}
|
|
83
|
+
static { this.shadowRootOptions = {
|
|
84
|
+
...HelixElement.shadowRootOptions,
|
|
85
|
+
slotAssignment: 'manual',
|
|
86
|
+
}; }
|
|
76
87
|
get current() {
|
|
77
88
|
return this.reading;
|
|
78
89
|
}
|
|
79
90
|
get links() {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
const slots = [
|
|
92
|
+
...(this.renderRoot?.querySelectorAll?.('slot[data-link], nav > slot:not([role])') ?? []),
|
|
93
|
+
];
|
|
94
|
+
return slots
|
|
95
|
+
.flatMap((slot) => slot.assignedElements({ flatten: true }))
|
|
96
|
+
.flatMap((element) => isFragment(element)
|
|
83
97
|
? [element]
|
|
84
|
-
: [...element.querySelectorAll('a[href^="#"]')].filter(
|
|
98
|
+
: [...element.querySelectorAll('a[href^="#"]')].filter(isFragment));
|
|
99
|
+
}
|
|
100
|
+
get content() {
|
|
101
|
+
return this.knownChildren.filter((child) => child.slot !== 'heading');
|
|
102
|
+
}
|
|
103
|
+
get run() {
|
|
104
|
+
const content = this.content;
|
|
105
|
+
if (this.assignsByName || content.length === 0 || !content.every(isFragment)) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
return content;
|
|
85
109
|
}
|
|
86
110
|
get sections() {
|
|
87
111
|
return this.links.flatMap((link) => {
|
|
@@ -163,6 +187,8 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
163
187
|
}
|
|
164
188
|
disconnectedCallback() {
|
|
165
189
|
super.disconnectedCallback();
|
|
190
|
+
this.childWatch?.disconnect();
|
|
191
|
+
this.childWatch = undefined;
|
|
166
192
|
this.removeEventListener('click', this.handleClick);
|
|
167
193
|
document.removeEventListener('scroll', this.handleScroll, true);
|
|
168
194
|
if (this.frame !== 0) {
|
|
@@ -183,6 +209,12 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
183
209
|
}
|
|
184
210
|
connectedCallback() {
|
|
185
211
|
super.connectedCallback();
|
|
212
|
+
this.childWatch = new MutationObserver(() => this.requestUpdate());
|
|
213
|
+
this.childWatch.observe(this, {
|
|
214
|
+
attributeFilter: ['data-level', 'href', 'slot'],
|
|
215
|
+
childList: true,
|
|
216
|
+
subtree: true,
|
|
217
|
+
});
|
|
186
218
|
this.addEventListener('click', this.handleClick);
|
|
187
219
|
document.addEventListener('scroll', this.handleScroll, {
|
|
188
220
|
capture: true,
|
|
@@ -195,9 +227,32 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
195
227
|
firstUpdated(changed) {
|
|
196
228
|
super.firstUpdated(changed);
|
|
197
229
|
this.watch();
|
|
230
|
+
this.finishHydration();
|
|
231
|
+
}
|
|
232
|
+
assign() {
|
|
233
|
+
if (this.assignsByName) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const root = this.renderRoot;
|
|
237
|
+
const heading = root?.querySelector?.('slot[name="heading"]');
|
|
238
|
+
heading?.assign?.(...this.knownChildren.filter((child) => child.slot === 'heading'));
|
|
239
|
+
const run = this.run;
|
|
240
|
+
if (run) {
|
|
241
|
+
for (const slot of root?.querySelectorAll?.('slot[data-link]') ?? []) {
|
|
242
|
+
const link = run[Number(slot.dataset.link)];
|
|
243
|
+
if (link) {
|
|
244
|
+
slot.assign(link);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const plain = root?.querySelector?.('nav > slot:not([role])');
|
|
250
|
+
plain?.assign?.(...[...this.childNodes].filter((node) => node instanceof Element ? node.slot !== 'heading' : node instanceof Text));
|
|
198
251
|
}
|
|
199
252
|
updated(changed) {
|
|
200
253
|
super.updated(changed);
|
|
254
|
+
this.assign();
|
|
255
|
+
this.nameByHeading();
|
|
201
256
|
if (changed.has('offset')) {
|
|
202
257
|
this.reach();
|
|
203
258
|
this.mark();
|
|
@@ -208,11 +263,21 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
208
263
|
this.indicator.place();
|
|
209
264
|
}
|
|
210
265
|
render() {
|
|
211
|
-
|
|
212
|
-
|
|
266
|
+
const run = this.run;
|
|
267
|
+
return html `<div part="heading"><slot name="heading" @slotchange=${this.nameByHeading}></slot></div>
|
|
268
|
+
<nav part="nav" aria-label=${this.label} @slotchange=${this.handleSlotChange}>
|
|
269
|
+
${run ? this.renderList(nest(run.map((link) => levelOf(link.getAttribute('data-level'))))) : html `<slot></slot>`}
|
|
213
270
|
<span part="indicator" aria-hidden="true"></span>
|
|
214
271
|
</nav>`;
|
|
215
272
|
}
|
|
273
|
+
renderList(branches) {
|
|
274
|
+
return html `<slot role="list"
|
|
275
|
+
>${branches.map((branch) => html `<slot role="listitem"
|
|
276
|
+
><slot data-link=${branch.index}></slot
|
|
277
|
+
>${branch.children.length > 0 ? this.renderList(branch.children) : nothing}</slot
|
|
278
|
+
>`)}</slot
|
|
279
|
+
>`;
|
|
280
|
+
}
|
|
216
281
|
};
|
|
217
282
|
__decorate([
|
|
218
283
|
property()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../option/index.js';
|
|
4
4
|
import '../../select/index.js';
|
|
@@ -28,6 +28,11 @@ import '../../select/index.js';
|
|
|
28
28
|
* Re-querying and returning to page one is up to you, because only you know
|
|
29
29
|
* whether the current position should be kept.
|
|
30
30
|
*
|
|
31
|
+
* It takes part in a form. Give it a `name` and the size in force is submitted
|
|
32
|
+
* under that name, so a `GET` form carries it in the address beside the page.
|
|
33
|
+
* A form reset returns it to `default-value`, and `disabled`, or a disabled
|
|
34
|
+
* `<fieldset>` around it, turns the select off.
|
|
35
|
+
*
|
|
31
36
|
* @since 0.1.0
|
|
32
37
|
* @status stable
|
|
33
38
|
* @aliases Page size, Rows per page
|
|
@@ -67,7 +72,7 @@ import '../../select/index.js';
|
|
|
67
72
|
*
|
|
68
73
|
* @cssstate empty - While there are no sizes to offer.
|
|
69
74
|
*/
|
|
70
|
-
export declare class HelixHeadlessPaginationSize extends
|
|
75
|
+
export declare class HelixHeadlessPaginationSize extends HelixFormElement {
|
|
71
76
|
/**
|
|
72
77
|
* The size to start on when `value` is not set.
|
|
73
78
|
*/
|
|
@@ -115,6 +120,10 @@ export declare class HelixHeadlessPaginationSize extends HelixElement {
|
|
|
115
120
|
* after it, and a refused size still sent it.
|
|
116
121
|
*/
|
|
117
122
|
private readonly stopNative;
|
|
123
|
+
/** Returns to the size the markup declared, as a native `<select>` does on a reset. */
|
|
124
|
+
formResetCallback(): void;
|
|
125
|
+
/** Takes back the size a browser restores with the form, or the declared one. */
|
|
126
|
+
formStateRestoreCallback(state: string | File | FormData | null): void;
|
|
118
127
|
protected willUpdate(changed: PropertyValues): void;
|
|
119
128
|
/**
|
|
120
129
|
* The control itself, which is the whole of this part, behind a seam the styled tier can move.
|
|
@@ -4,13 +4,13 @@ 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, formatNumbers, HelixBeforeChangeEvent,
|
|
7
|
+
import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, requestChange, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
11
11
|
import '../../option/index.js';
|
|
12
12
|
import '../../select/index.js';
|
|
13
|
-
let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends
|
|
13
|
+
let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends HelixFormElement {
|
|
14
14
|
constructor() {
|
|
15
15
|
super(...arguments);
|
|
16
16
|
this.defaultValue = 0;
|
|
@@ -29,8 +29,8 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
29
29
|
const previous = this.value;
|
|
30
30
|
this.valueState = size;
|
|
31
31
|
this.requestUpdate('value', previous);
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
32
|
+
this.announceInput();
|
|
33
|
+
this.announceChange();
|
|
34
34
|
},
|
|
35
35
|
event: (size) => new HelixBeforeChangeEvent({ value: String(size) }),
|
|
36
36
|
host: this,
|
|
@@ -68,9 +68,23 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
68
68
|
const options = this.options;
|
|
69
69
|
return options.includes(this.value) ? this.value : (options[0] ?? 0);
|
|
70
70
|
}
|
|
71
|
+
formResetCallback() {
|
|
72
|
+
super.formResetCallback();
|
|
73
|
+
const previous = this.value;
|
|
74
|
+
this.valueState = undefined;
|
|
75
|
+
this.requestUpdate('value', previous);
|
|
76
|
+
}
|
|
77
|
+
formStateRestoreCallback(state) {
|
|
78
|
+
const size = typeof state === 'string' ? Number.parseInt(state, 10) : Number.NaN;
|
|
79
|
+
const previous = this.value;
|
|
80
|
+
this.valueState = Number.isFinite(size) && size > 0 ? size : undefined;
|
|
81
|
+
this.requestUpdate('value', previous);
|
|
82
|
+
}
|
|
71
83
|
willUpdate(changed) {
|
|
72
84
|
super.willUpdate(changed);
|
|
73
85
|
this.toggleState('empty', this.options.length === 0);
|
|
86
|
+
const current = this.current;
|
|
87
|
+
this.internals.setFormValue(current > 0 ? String(current) : null);
|
|
74
88
|
}
|
|
75
89
|
renderSelect() {
|
|
76
90
|
const select = this.tag('select');
|
|
@@ -86,6 +100,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
86
100
|
listbox-search-field: control-listbox-search-field, surface: control-surface,
|
|
87
101
|
trigger: control-trigger, value: control-value"
|
|
88
102
|
label=${this.label}
|
|
103
|
+
?disabled=${this.isDisabled}
|
|
89
104
|
.value=${String(this.current)}
|
|
90
105
|
@helix-before-change=${this.handleChange}
|
|
91
106
|
@input=${this.stopNative}
|
|
@@ -80,18 +80,12 @@ export declare class HelixHeadlessRadioGroup extends HelixHeadlessRadioGroup_bas
|
|
|
80
80
|
* Whether a reader can see and focus the answer and cannot change it. A
|
|
81
81
|
* read-only group still submits its value.
|
|
82
82
|
*
|
|
83
|
-
* React Aria's `isReadOnly`. A press on a radio is refused
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* A script can still set `value`.
|
|
83
|
+
* React Aria's `isReadOnly`. A press on a radio is refused. The arrow keys,
|
|
84
|
+
* Home and End move focus between the radios and choose nothing, so a reader
|
|
85
|
+
* can hear every choice, and Tab still reaches the answer. The group says
|
|
86
|
+
* `aria-readonly`. A script can still set `value`.
|
|
87
87
|
*/
|
|
88
88
|
readOnly: boolean;
|
|
89
|
-
/**
|
|
90
|
-
* Keeps the keys that would move the answer from the keyboard controller
|
|
91
|
-
* while the group is read-only. A capture listener on the host runs ahead of
|
|
92
|
-
* the controller's own on the same target.
|
|
93
|
-
*/
|
|
94
|
-
private readonly holdKeys;
|
|
95
89
|
protected readonly keys: KeyboardNavigationController;
|
|
96
90
|
protected readonly cascade: DisabledCascadeController;
|
|
97
91
|
/** The radios, in light-DOM order. Client only: the server has no tree. */
|
|
@@ -8,19 +8,16 @@ import { customElement, DisabledCascadeController, HelixFormElement, hostAria, K
|
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessRadio } from '../root/radio-root.js';
|
|
11
|
-
const MOVING_KEYS = new Set(['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home']);
|
|
12
11
|
let HelixHeadlessRadioGroup = class HelixHeadlessRadioGroup extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
13
12
|
constructor() {
|
|
14
13
|
super(...arguments);
|
|
15
14
|
this.focusable = true;
|
|
16
15
|
this.readOnly = false;
|
|
17
|
-
this.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
this.keys = new KeyboardNavigationController(this, { items: () => this.items });
|
|
16
|
+
this.keys = new KeyboardNavigationController(this, {
|
|
17
|
+
items: () => this.items,
|
|
18
|
+
origin: () => (this.readOnly ? 'focus' : 'selection'),
|
|
19
|
+
selects: () => !this.readOnly,
|
|
20
|
+
});
|
|
24
21
|
this.cascade = new DisabledCascadeController(this, {
|
|
25
22
|
items: () => this.items,
|
|
26
23
|
});
|
|
@@ -92,12 +89,10 @@ let HelixHeadlessRadioGroup = class HelixHeadlessRadioGroup extends MixinControl
|
|
|
92
89
|
connectedCallback() {
|
|
93
90
|
super.connectedCallback();
|
|
94
91
|
this.addEventListener('helix-select', this.handleSelection);
|
|
95
|
-
this.addEventListener('keydown', this.holdKeys, { capture: true });
|
|
96
92
|
}
|
|
97
93
|
disconnectedCallback() {
|
|
98
94
|
super.disconnectedCallback();
|
|
99
95
|
this.removeEventListener('helix-select', this.handleSelection);
|
|
100
|
-
this.removeEventListener('keydown', this.holdKeys, { capture: true });
|
|
101
96
|
}
|
|
102
97
|
willUpdate(changed) {
|
|
103
98
|
super.willUpdate(changed);
|
|
@@ -31,7 +31,7 @@ declare const HelixHeadlessRating_base: (new (...args: any[]) => import("@fusion
|
|
|
31
31
|
*
|
|
32
32
|
* @event {Event} change - The score was chosen. Sent together with `input`, because each choice commits the score.
|
|
33
33
|
* @event {HelixBeforeChangeEvent} helix-before-change - The score is about to change. Cancelable: cancel it to keep the current score.
|
|
34
|
-
* @event {
|
|
34
|
+
* @event {HelixClearEvent} helix-clear - The rating went back to unrated, under `clearable`. Sent after `input` and `change`.
|
|
35
35
|
* @event {Event} input - The score changed.
|
|
36
36
|
*
|
|
37
37
|
* @csspart feedback - The message that says what is wrong.
|
|
@@ -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, valueAsNumber as asNumber, customElement, fillTemplate, numberAsValue as fromNumber, HelixFormElement, KeyboardNavigationController, MixinControllerValue, MixinField, reportRuntime, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, valueAsNumber as asNumber, customElement, fillTemplate, numberAsValue as fromNumber, HelixClearEvent, HelixFormElement, KeyboardNavigationController, MixinControllerValue, MixinField, reportRuntime, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
@@ -195,7 +195,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
195
195
|
}
|
|
196
196
|
clear() {
|
|
197
197
|
if (this.value !== '' && !this.readOnly && !this.isDisabled && this.requestValue('')) {
|
|
198
|
-
this.dispatchEvent(new
|
|
198
|
+
this.dispatchEvent(new HelixClearEvent());
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
connectedCallback() {
|
|
@@ -20,6 +20,20 @@ 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
|
+
* The viewport's `scroll` and `scrollend` are sent again from the host, which
|
|
34
|
+
* is the element you hold. In React, bind them with `onScroll` and
|
|
35
|
+
* `onScrollEnd`.
|
|
36
|
+
*
|
|
23
37
|
* @since 0.1.0
|
|
24
38
|
* @status stable
|
|
25
39
|
* @category layout
|
|
@@ -28,22 +42,69 @@ declare const EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inli
|
|
|
28
42
|
*
|
|
29
43
|
* @slot - The content that scrolls.
|
|
30
44
|
*
|
|
45
|
+
* @event {Event} scroll - The content scrolled. Sent from the host, because the viewport's own does not leave the shadow root. Does not bubble.
|
|
46
|
+
* @event {Event} scrollend - The content stopped scrolling. Sent from the host, as `scroll` is. Does not bubble.
|
|
47
|
+
*
|
|
48
|
+
* @csspart corner - The square where the two scrollbars meet, under `scrollbars`. Hidden unless both are drawn.
|
|
31
49
|
* @csspart edges - The layer that draws the cues on the inline start and end edges.
|
|
50
|
+
* @csspart scrollbar - Each scrollbar, under `scrollbars`. Hidden on an axis that has none.
|
|
51
|
+
* @csspart scrollbar-horizontal - The scrollbar along the inline axis, alongside `scrollbar`.
|
|
52
|
+
* @csspart scrollbar-vertical - The scrollbar along the block axis, alongside `scrollbar`.
|
|
53
|
+
* @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`.
|
|
54
|
+
* @csspart thumb - The thumb inside each scrollbar, which drags.
|
|
55
|
+
* @csspart thumb-horizontal - The thumb of the horizontal scrollbar, alongside `thumb`.
|
|
56
|
+
* @csspart thumb-vertical - The thumb of the vertical scrollbar, alongside `thumb`.
|
|
32
57
|
* @csspart viewport - The scrolling box.
|
|
33
58
|
*
|
|
59
|
+
* @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.
|
|
60
|
+
* @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.
|
|
61
|
+
*
|
|
34
62
|
* @cssstate more-block-end - While there is more to scroll to past the block end.
|
|
35
63
|
* @cssstate more-block-start - While there is more to scroll back to before the block start.
|
|
36
64
|
* @cssstate more-inline-end - While there is more to scroll to past the inline end.
|
|
37
65
|
* @cssstate more-inline-start - While there is more to scroll back to before the inline start.
|
|
66
|
+
* @cssstate scrollbar-horizontal - While the horizontal scrollbar is drawn, under `scrollbars`.
|
|
67
|
+
* @cssstate scrollbar-vertical - While the vertical scrollbar is drawn, under `scrollbars`.
|
|
38
68
|
* @cssstate scrolls - While the content is larger than the viewport, on either axis.
|
|
39
69
|
*/
|
|
40
70
|
export declare class HelixHeadlessScrollArea extends HelixElement {
|
|
71
|
+
/**
|
|
72
|
+
* How long the scrollbars stay after the content stops moving, or the pointer
|
|
73
|
+
* leaves, in milliseconds. Read under `scrollbars="scroll"` and
|
|
74
|
+
* `scrollbars="hover"`.
|
|
75
|
+
*/
|
|
76
|
+
hideDelay: number;
|
|
41
77
|
/**
|
|
42
78
|
* The region's name, read by screen readers.
|
|
43
79
|
*
|
|
44
80
|
* Without one there is no region: see the note on the class.
|
|
45
81
|
*/
|
|
46
82
|
label: string;
|
|
83
|
+
/**
|
|
84
|
+
* Draws scrollbars of the component's own in place of the browser's, and
|
|
85
|
+
* says when they show.
|
|
86
|
+
*
|
|
87
|
+
* - `auto`: on each axis that has content past it.
|
|
88
|
+
* - `always`: on each axis that can scroll, whether or not it has anything to
|
|
89
|
+
* scroll, so the scrollbar is there before the content grows.
|
|
90
|
+
* - `scroll`: while the content is moving, and for `hide-delay` after.
|
|
91
|
+
* - `hover`: as `scroll`, and while the pointer is over the scroll area.
|
|
92
|
+
*
|
|
93
|
+
* Absent keeps the browser's scrollbars.
|
|
94
|
+
*/
|
|
95
|
+
scrollbars?: 'always' | 'auto' | 'hover' | 'scroll';
|
|
96
|
+
/** What each scrollbar shows, measured, and `undefined` until it has been. */
|
|
97
|
+
private bars;
|
|
98
|
+
/** Whether the content moved, or the pointer left, within the hide delay. */
|
|
99
|
+
private active;
|
|
100
|
+
/** Whether the pointer is over the scroll area. */
|
|
101
|
+
private hovered;
|
|
102
|
+
/** Whether the pointer is over a scrollbar. */
|
|
103
|
+
private over;
|
|
104
|
+
/** The thumb being dragged, if one is. */
|
|
105
|
+
private drag;
|
|
106
|
+
/** Puts the scrollbars away once nothing has moved for the hide delay. */
|
|
107
|
+
private readonly hide;
|
|
47
108
|
/**
|
|
48
109
|
* Which edges have content past them, measured rather than guessed.
|
|
49
110
|
*/
|
|
@@ -76,6 +137,46 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
|
|
|
76
137
|
* costs.
|
|
77
138
|
*/
|
|
78
139
|
private measure;
|
|
140
|
+
/** One axis of the box, counted from its start whichever way the line runs. */
|
|
141
|
+
private extent;
|
|
142
|
+
/**
|
|
143
|
+
* Reads what each scrollbar shows off the box.
|
|
144
|
+
*
|
|
145
|
+
* An axis scrolls unless its `overflow` says it cannot. An empty reading is a
|
|
146
|
+
* harness with no layout, where the mark `core` puts on the viewport is
|
|
147
|
+
* `overflow: auto` on both axes, so it counts as one that scrolls.
|
|
148
|
+
*
|
|
149
|
+
* Written only on a change, so a scroll that moves no thumb renders nothing.
|
|
150
|
+
*/
|
|
151
|
+
private readBars;
|
|
152
|
+
/**
|
|
153
|
+
* Shows the scrollbars and starts the wait that puts them away again, under
|
|
154
|
+
* `scroll` and `hover`.
|
|
155
|
+
*/
|
|
156
|
+
private wake;
|
|
157
|
+
/** Sends the content to `offset` along an axis, counted from its start. */
|
|
158
|
+
private scrollAlong;
|
|
159
|
+
/**
|
|
160
|
+
* Takes hold of a thumb, or presses the track.
|
|
161
|
+
*
|
|
162
|
+
* A press on the track sends the thumb's middle to the press first, and the
|
|
163
|
+
* drag carries on from there, so a press and a drag are one gesture as they
|
|
164
|
+
* are on the browser's own scrollbar. `preventDefault` keeps the press from
|
|
165
|
+
* starting a text selection, and from moving focus off the viewport.
|
|
166
|
+
*/
|
|
167
|
+
private grab;
|
|
168
|
+
private readonly handleVerticalDown;
|
|
169
|
+
private readonly handleHorizontalDown;
|
|
170
|
+
/** Moves the content with a dragged thumb. Nothing while no thumb is held. */
|
|
171
|
+
private readonly handleDragMove;
|
|
172
|
+
private readonly handleDragEnd;
|
|
173
|
+
private readonly handleBarEnter;
|
|
174
|
+
private readonly handleBarLeave;
|
|
175
|
+
private readonly handleEnter;
|
|
176
|
+
private readonly handleLeave;
|
|
177
|
+
/** Measures, shows the scrollbars, and sends the event on from the host. */
|
|
178
|
+
private readonly handleScroll;
|
|
179
|
+
private readonly handleScrollEnd;
|
|
79
180
|
connectedCallback(): void;
|
|
80
181
|
disconnectedCallback(): void;
|
|
81
182
|
protected firstUpdated(changed: PropertyValues): void;
|
|
@@ -84,6 +185,18 @@ export declare class HelixHeadlessScrollArea extends HelixElement {
|
|
|
84
185
|
protected updated(changed: PropertyValues): void;
|
|
85
186
|
private readonly handleSlotChange;
|
|
86
187
|
protected render(): TemplateResult;
|
|
188
|
+
/**
|
|
189
|
+
* The scrollbars, the thumbs in them and the corner.
|
|
190
|
+
*
|
|
191
|
+
* **For the pointer, and hidden from everything else.** The viewport is
|
|
192
|
+
* already the tab stop and the region, and the keys scroll it, so a second
|
|
193
|
+
* way in would be one more stop that does the same thing. The scrollbars
|
|
194
|
+
* carry `aria-hidden` and take no focus, as Radix's do.
|
|
195
|
+
*
|
|
196
|
+
* Hidden on the server, which cannot measure whether there is anything to
|
|
197
|
+
* scroll, and until the first measurement.
|
|
198
|
+
*/
|
|
199
|
+
private renderScrollbars;
|
|
87
200
|
}
|
|
88
201
|
declare global {
|
|
89
202
|
interface HTMLElementTagNameMap {
|