@fusion.dev/helix-headless 0.42.0 → 0.44.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 +61 -65
- package/dist/chat/composer/chat-composer.d.ts +1 -1
- package/dist/chat/message/chat-message.d.ts +1 -1
- package/dist/chat/message/chat-message.js +1 -1
- package/dist/chat/root/chat-root.d.ts +1 -1
- package/dist/color-picker/root/color-picker-root.js +1 -2
- package/dist/date-picker/root/date-picker-root.d.ts +1 -1
- package/dist/element-events.generated.js +0 -1
- package/dist/format-date/root/format-date-root.d.ts +1 -1
- package/dist/notifications/group/notification-group.d.ts +17 -3
- package/dist/notifications/group/notification-group.js +8 -11
- package/dist/notifications/notification/notification.d.ts +3 -1
- package/dist/notifications/notification/notification.js +1 -1
- package/dist/notifications/root/notifications-root.d.ts +8 -3
- package/dist/option/root/option-root.d.ts +21 -11
- package/dist/option/root/option-root.js +2 -3
- package/dist/radio/root/radio-root.d.ts +16 -5
- package/dist/radio/root/radio-root.js +2 -3
- package/dist/slider/root/slider-root.d.ts +10 -3
- package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
- package/dist/speed-dial/root/speed-dial-root.d.ts +1 -1
- package/dist/splitter/root/splitter-root.d.ts +26 -3
- package/dist/splitter/root/splitter-root.js +4 -3
- package/dist/toast/item/toast-item.d.ts +1 -1
- package/dist/toast/root/toast-root.d.ts +2 -2
- package/dist/toggle/group/toggle-group.d.ts +45 -1
- package/dist/toggle/group/toggle-group.js +11 -0
- package/dist/toggle/root/toggle-root.d.ts +17 -6
- package/dist/toggle/root/toggle-root.js +2 -3
- package/dist/tour/root/tour-root.d.ts +0 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +246 -80
- package/types/vue.d.ts +58 -22
|
@@ -101,20 +101,30 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
101
101
|
*
|
|
102
102
|
* `<option selected>` reflects to `defaultSelected` and `option.selected` is
|
|
103
103
|
* live state that does not reflect, and those are two different facts. This
|
|
104
|
-
* element has one `selected` doing both jobs, so
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
104
|
+
* element has one `selected` doing both jobs, so the declaration is the
|
|
105
|
+
* attribute and the state is the property.
|
|
106
|
+
*
|
|
107
|
+
* **The attribute, read when it is asked for, and never a snapshot taken in
|
|
108
|
+
* the constructor.** A field initializer runs there, and an element the HTML
|
|
109
|
+
* parser created has none of its attributes yet at that moment: measured on
|
|
110
|
+
* this element, on `Radio` and on `Toggle`, `<helix-option value="a"
|
|
111
|
+
* selected>` reported `defaultSelected` as `false` both from parsed markup
|
|
112
|
+
* and from `createElement` followed by `setAttribute`, which is every way a
|
|
113
|
+
* consumer writes one. The snapshot could only ever be true for an element
|
|
114
|
+
* already in the document when `customElements.define` ran.
|
|
115
|
+
*
|
|
116
|
+
* Nothing overwrites it either, which is what makes reading it late correct
|
|
117
|
+
* rather than merely later: `selected` does not reflect, for the reason
|
|
118
|
+
* `willUpdate` records, so the listbox's writes never reach the attribute and
|
|
119
|
+
* what it says is what the markup said.
|
|
120
|
+
*
|
|
121
|
+
* **The deeper half is not this.** State reflecting under the declaration's
|
|
122
|
+
* name is the fault `TreeItem` avoids by mirroring to `data-selected`.
|
|
123
|
+
* Splitting them means moving what every stylesheet selects on, which is a
|
|
124
|
+
* change of its own rather than a property being added.
|
|
113
125
|
*/
|
|
114
126
|
get defaultSelected(): boolean;
|
|
115
127
|
set defaultSelected(next: boolean);
|
|
116
|
-
/** What the markup said, read once at construction for the reason above. */
|
|
117
|
-
private seeded;
|
|
118
128
|
/**
|
|
119
129
|
* A second line under the words, for what the choice actually is.
|
|
120
130
|
*
|
|
@@ -17,17 +17,16 @@ let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
|
|
|
17
17
|
this.active = false;
|
|
18
18
|
this.alternate = '';
|
|
19
19
|
this.alternateLabel = '';
|
|
20
|
-
this.seeded = this.hasAttribute('selected');
|
|
21
20
|
this.disabled = false;
|
|
22
21
|
this.label = '';
|
|
23
22
|
this.selected = false;
|
|
24
23
|
this.value = '';
|
|
25
24
|
}
|
|
26
25
|
get defaultSelected() {
|
|
27
|
-
return this.
|
|
26
|
+
return this.hasAttribute('selected');
|
|
28
27
|
}
|
|
29
28
|
set defaultSelected(next) {
|
|
30
|
-
this.
|
|
29
|
+
this.toggleAttribute('selected', next);
|
|
31
30
|
}
|
|
32
31
|
get text() {
|
|
33
32
|
return [...this.childNodes]
|
|
@@ -51,9 +51,22 @@ export declare class HelixHeadlessRadio extends HelixElement {
|
|
|
51
51
|
*
|
|
52
52
|
* `<option selected>` reflects to `defaultSelected` and `option.selected` is
|
|
53
53
|
* live state that does not reflect, and those are two different facts. This
|
|
54
|
-
* element has one `selected` doing both jobs, so
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* element has one `selected` doing both jobs, so the declaration is the
|
|
55
|
+
* attribute and the state is the property.
|
|
56
|
+
*
|
|
57
|
+
* **The attribute, read when it is asked for, and never a snapshot taken in
|
|
58
|
+
* the constructor.** A field initializer runs there, and an element the HTML
|
|
59
|
+
* parser created has none of its attributes yet at that moment: measured on
|
|
60
|
+
* this element, on `Option` and on `Toggle`, `<helix-radio value="a"
|
|
61
|
+
* selected>` reported `defaultSelected` as `false` both from parsed markup
|
|
62
|
+
* and from `createElement` followed by `setAttribute`, which is every way a
|
|
63
|
+
* consumer writes one. The snapshot could only ever be true for an element
|
|
64
|
+
* already in the document when `customElements.define` ran.
|
|
65
|
+
*
|
|
66
|
+
* Nothing overwrites it either, which is what makes reading it late correct
|
|
67
|
+
* rather than merely later: `selected` does not reflect, for the reason
|
|
68
|
+
* `willUpdate` records, so the group's writes never reach the attribute and
|
|
69
|
+
* what it says is what the markup said.
|
|
57
70
|
*
|
|
58
71
|
* **The deeper half is not this.** State reflecting under the declaration's
|
|
59
72
|
* name is the fault `TreeItem` avoids by mirroring to `data-selected`.
|
|
@@ -62,8 +75,6 @@ export declare class HelixHeadlessRadio extends HelixElement {
|
|
|
62
75
|
*/
|
|
63
76
|
get defaultSelected(): boolean;
|
|
64
77
|
set defaultSelected(next: boolean);
|
|
65
|
-
/** What the markup said, read once at construction for the reason above. */
|
|
66
|
-
private seeded;
|
|
67
78
|
/**
|
|
68
79
|
* Whether this is the current choice.
|
|
69
80
|
*
|
|
@@ -11,15 +11,14 @@ let HelixHeadlessRadio = class HelixHeadlessRadio extends HelixElement {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.disabled = false;
|
|
14
|
-
this.seeded = this.hasAttribute('selected');
|
|
15
14
|
this.selected = false;
|
|
16
15
|
this.value = '';
|
|
17
16
|
}
|
|
18
17
|
get defaultSelected() {
|
|
19
|
-
return this.
|
|
18
|
+
return this.hasAttribute('selected');
|
|
20
19
|
}
|
|
21
20
|
set defaultSelected(next) {
|
|
22
|
-
this.
|
|
21
|
+
this.toggleAttribute('selected', next);
|
|
23
22
|
}
|
|
24
23
|
focusItem() {
|
|
25
24
|
this.partNamed('item')?.focus();
|
|
@@ -23,8 +23,15 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
|
|
|
23
23
|
* **A range is two of them.** There is no native two-thumb range, so two are
|
|
24
24
|
* stacked on one track and each thumb keeps its own.
|
|
25
25
|
*
|
|
26
|
+
* **`required` arrives with the field mixin and cannot fail here**, which is
|
|
27
|
+
* worth saying rather than leaving a reader to find. A range is never empty:
|
|
28
|
+
* the platform shows its own midpoint whatever is set, and `willUpdate` seeds
|
|
29
|
+
* that midpoint into `defaultValue` so the value agrees with the handle from the
|
|
30
|
+
* first render. HTML does not apply `required` to a range either, so it stays
|
|
31
|
+
* off the control and the marker beside the label is all it does.
|
|
32
|
+
*
|
|
26
33
|
* @since 0.1.0
|
|
27
|
-
* @status
|
|
34
|
+
* @status stable
|
|
28
35
|
* @category forms
|
|
29
36
|
* @aliases Range, Range input
|
|
30
37
|
* @documentation https://fusion.dev/helix/components/slider
|
|
@@ -44,9 +51,9 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
|
|
|
44
51
|
* @csspart output - The current value, shown beside it.
|
|
45
52
|
*
|
|
46
53
|
* @cssproperty --slider-fraction - The value as a fraction of the range, 0 to 1.
|
|
47
|
-
* @cssproperty --slider-from - Where
|
|
54
|
+
* @cssproperty --slider-from - Where a range's filled span starts, as a fraction of the track, 0 to 1.
|
|
48
55
|
* @cssproperty --slider-marker-at - Where one marker sits, as a percentage of the track.
|
|
49
|
-
* @cssproperty --slider-to - Where
|
|
56
|
+
* @cssproperty --slider-to - Where a range's filled span ends, as a fraction of the track, 0 to 1.
|
|
50
57
|
*
|
|
51
58
|
* @cssstate invalid - While there is feedback to show: the platform's verdict, or the consumer's `feedback`.
|
|
52
59
|
*/
|
|
@@ -16,7 +16,7 @@ import { type TemplateResult } from 'lit';
|
|
|
16
16
|
* being there, so it is read, searched and translated like anything else.
|
|
17
17
|
*
|
|
18
18
|
* @since 0.1.0
|
|
19
|
-
* @status
|
|
19
|
+
* @status stable
|
|
20
20
|
* @category actions
|
|
21
21
|
* @aliases Speed dial action, FAB action, Quick action
|
|
22
22
|
* @documentation https://fusion.dev/helix/components/speed-dial
|
|
@@ -28,7 +28,7 @@ declare const HelixHeadlessSpeedDial_base: (new (...args: any[]) => import("@fus
|
|
|
28
28
|
* with no reason to argue with it.
|
|
29
29
|
*
|
|
30
30
|
* @since 0.1.0
|
|
31
|
-
* @status
|
|
31
|
+
* @status stable
|
|
32
32
|
* @category actions
|
|
33
33
|
* @aliases FAB, Floating action button, Action button, Quick actions
|
|
34
34
|
* @documentation https://fusion.dev/helix/components/speed-dial
|
|
@@ -41,8 +41,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
41
41
|
* @slot end - The pane after it.
|
|
42
42
|
* @slot start - The pane before the divider.
|
|
43
43
|
*
|
|
44
|
-
* @event {HelixBeforeCollapseEvent} helix-before-collapse - Fired before a pane shuts or reopens, and
|
|
45
|
-
* @event {HelixBeforeResizeEvent} helix-before-resize - Fired before the divider settles, and
|
|
44
|
+
* @event {HelixBeforeCollapseEvent} helix-before-collapse - Fired before a pane shuts or reopens, and only where the position it is derived from stood. Cancelable: refusing it leaves the pane as it was and the divider where the gesture put it.
|
|
45
|
+
* @event {HelixBeforeResizeEvent} helix-before-resize - Fired before the divider settles. Cancelable: refusing it takes the whole of where the gesture ended, so no collapse follows from it either. A drag has already drawn itself by then and holds where it was dropped until the consumer assigns their own.
|
|
46
46
|
*
|
|
47
47
|
* @csspart corner - The handle where two dividers cross, added on the client.
|
|
48
48
|
* @csspart end - The box holding the second.
|
|
@@ -300,11 +300,18 @@ export declare class HelixHeadlessSplitter extends HelixElement {
|
|
|
300
300
|
*/
|
|
301
301
|
get vertical(): boolean;
|
|
302
302
|
/**
|
|
303
|
-
*
|
|
303
|
+
* Moves the divider under a gesture that is still happening.
|
|
304
304
|
*
|
|
305
305
|
* Not announced per step: `helix-before-resize` is the settling, below. A drag that
|
|
306
306
|
* announced every position would be asking a consumer to record a hundred
|
|
307
307
|
* decisions to keep one.
|
|
308
|
+
*
|
|
309
|
+
* **A drag only, which is the whole of why applying before announcing is
|
|
310
|
+
* right here.** The divider has to follow the hand, and the one number worth
|
|
311
|
+
* a decision is where the hand let go. Nothing discrete calls this: a key and
|
|
312
|
+
* a double click go straight to `settle`, so their announcement comes before
|
|
313
|
+
* their change and refusing one takes the decision, and the corner's arrows
|
|
314
|
+
* already did.
|
|
308
315
|
*/
|
|
309
316
|
private move;
|
|
310
317
|
/**
|
|
@@ -312,6 +319,22 @@ export declare class HelixHeadlessSplitter extends HelixElement {
|
|
|
312
319
|
*
|
|
313
320
|
* Through the audited path, so a consumer who owns `position` is told what was
|
|
314
321
|
* asked for and decides, and one who does not has already had it applied.
|
|
322
|
+
*
|
|
323
|
+
* **The second announcement is conditional on the first, because it is derived
|
|
324
|
+
* from it.** `shutAt` reads the position the gesture ended on, so a refused
|
|
325
|
+
* `helix-before-resize` leaves a collapse computed from a number that was
|
|
326
|
+
* refused. Announced anyway, the refusal produced the outcome it was refusing:
|
|
327
|
+
* measured on a divider at 40 with a listener calling `preventDefault`, Home
|
|
328
|
+
* left `position` reporting 0 and `collapsed` reporting `start`, because the
|
|
329
|
+
* collapse applied and `position` reads the sliver once a pane is shut. The
|
|
330
|
+
* return of the first request is what says so, and it was being dropped: a
|
|
331
|
+
* cancelable event dispatched as a bare statement with nothing reading the
|
|
332
|
+
* answer, which is the shape the navigation cohort named on `Outline` and left.
|
|
333
|
+
*
|
|
334
|
+
* Refusing the collapse alone still leaves the resize, which is the other way
|
|
335
|
+
* round and is coherent: the divider goes where the drag put it and the pane
|
|
336
|
+
* is not declared shut. What a consumer cannot have is a pane that collapses
|
|
337
|
+
* out from under a position they said no to.
|
|
315
338
|
*/
|
|
316
339
|
private settle;
|
|
317
340
|
private readonly handlePointerDown;
|
|
@@ -82,7 +82,6 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
82
82
|
else {
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
this.move(next);
|
|
86
85
|
this.settle(next);
|
|
87
86
|
event.preventDefault();
|
|
88
87
|
};
|
|
@@ -300,7 +299,7 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
300
299
|
settle(next) {
|
|
301
300
|
const wanted = this.clamp(next);
|
|
302
301
|
const shut = this.shutAt(wanted);
|
|
303
|
-
requestChange({
|
|
302
|
+
const moved = requestChange({
|
|
304
303
|
apply: (value) => {
|
|
305
304
|
const previous = this.position;
|
|
306
305
|
this.positionState = value;
|
|
@@ -310,6 +309,9 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
310
309
|
host: this,
|
|
311
310
|
next: wanted,
|
|
312
311
|
});
|
|
312
|
+
if (!moved) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
313
315
|
if (shut !== this.collapsed) {
|
|
314
316
|
requestChange({
|
|
315
317
|
apply: (value) => {
|
|
@@ -334,7 +336,6 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
334
336
|
}
|
|
335
337
|
reset() {
|
|
336
338
|
const home = this.clamp(this.defaultPosition);
|
|
337
|
-
this.move(home);
|
|
338
339
|
this.settle(home);
|
|
339
340
|
}
|
|
340
341
|
cross(by, at) {
|
|
@@ -29,9 +29,9 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
29
29
|
* test, or twice.
|
|
30
30
|
*
|
|
31
31
|
* @since 0.1.0
|
|
32
|
-
* @status
|
|
32
|
+
* @status stable
|
|
33
33
|
* @category overlays
|
|
34
|
-
* @aliases Toaster, Snackbar
|
|
34
|
+
* @aliases Toaster, Snackbar
|
|
35
35
|
* @documentation https://fusion.dev/helix/components/toast
|
|
36
36
|
*
|
|
37
37
|
* @slot - The messages, as `helix-toast-item` elements.
|
|
@@ -16,11 +16,13 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
|
|
|
16
16
|
* it has somewhere to be, which is the harmless direction.
|
|
17
17
|
*
|
|
18
18
|
* @since 0.1.0
|
|
19
|
-
* @status
|
|
19
|
+
* @status stable
|
|
20
20
|
* @aliases SegmentedControl, Segmented, Navigation, Switcher
|
|
21
21
|
* @documentation https://fusion.dev/helix/components/toggle
|
|
22
22
|
*
|
|
23
23
|
* @slot - The group's items.
|
|
24
|
+
* @slot end - Whatever sits after the track on its own line, such as a count or a reset.
|
|
25
|
+
* @slot start - Whatever sits before the track on its own line, such as an icon or a caption.
|
|
24
26
|
*
|
|
25
27
|
* @event {Event} change - Announced once the value has moved.
|
|
26
28
|
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the answer moves, and cancelable. The only way to refuse one.
|
|
@@ -38,6 +40,48 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
|
|
|
38
40
|
* @cssstate invalid - While there is feedback to show: the platform's verdict, or the consumer's `feedback`.
|
|
39
41
|
*/
|
|
40
42
|
export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_base {
|
|
43
|
+
/**
|
|
44
|
+
* Takes the markup's own answer where nothing has set a value.
|
|
45
|
+
*
|
|
46
|
+
* **The case a server renders**, and `Tabs` records the same fault from the
|
|
47
|
+
* other side. This element cannot choose on the server, having no children to
|
|
48
|
+
* count, so a consumer whose first paint is right wrote `selected` on the
|
|
49
|
+
* item: that serves `aria-checked="true"`, and `sync` then cleared it one
|
|
50
|
+
* frame later, because `value` is `''` and nothing matches it. The shipped
|
|
51
|
+
* `disabled` example is exactly that markup, and drew both of its groups with
|
|
52
|
+
* nothing chosen.
|
|
53
|
+
*
|
|
54
|
+
* **Onto `defaultValue`, never onto `value`**, which is the same call
|
|
55
|
+
* `Slider` makes about the midpoint it seeds: what the markup declared is a
|
|
56
|
+
* fact about the markup, so it is where a reset returns to rather than
|
|
57
|
+
* something the reader chose. It also makes the group report the answer it is
|
|
58
|
+
* showing, which marking the item alone would not: a `required` group would
|
|
59
|
+
* otherwise tell a reader a value is missing while they are looking at one.
|
|
60
|
+
*
|
|
61
|
+
* A written `value` still wins, a declared property being a seed and a
|
|
62
|
+
* correction, and a group with neither still marks nothing at all.
|
|
63
|
+
*
|
|
64
|
+
* **The property and never `defaultSelected`, which is the attribute.** React
|
|
65
|
+
* assigns a JSX prop as a property where the custom element has one, and
|
|
66
|
+
* writes no attribute at all, so keying on the attribute answers for markup
|
|
67
|
+
* and not for JSX. Measured by the parity check on the shipped `disabled`
|
|
68
|
+
* example, whose two syntaxes are the same tree: 192 pixels apart, the HTML
|
|
69
|
+
* marking `List` and the TSX marking nothing. The attribute seeds the
|
|
70
|
+
* property at upgrade, so reading the property covers both.
|
|
71
|
+
*
|
|
72
|
+
* Read before `sync` writes to it, which is the only moment it still holds
|
|
73
|
+
* what the consumer declared: after that it holds this group's answer, and
|
|
74
|
+
* `value` is no longer empty, so this returns above.
|
|
75
|
+
*
|
|
76
|
+
* **Called from `willUpdate` and from the slot, never from `sync`**, which
|
|
77
|
+
* runs in `updated`: a reactive property set there schedules a second update,
|
|
78
|
+
* and Lit's development build warns about exactly that once per group. From
|
|
79
|
+
* `willUpdate` the first render already carries the value, which is the pass
|
|
80
|
+
* that has to be right. `children` is undefined on the server, whose element
|
|
81
|
+
* shim carries attributes and no tree, and that is the same guard
|
|
82
|
+
* `MixinCollection` records for the same reason.
|
|
83
|
+
*/
|
|
84
|
+
private adopt;
|
|
41
85
|
/** Marks the chosen item, separately from placing the indicator. */
|
|
42
86
|
private sync;
|
|
43
87
|
private readonly indicator;
|
|
@@ -25,6 +25,15 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
25
25
|
this.requestValue(event.detail.value);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
adopt() {
|
|
29
|
+
if (this.value !== '' || this.children === undefined) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const declared = this.items.find((item) => item.selected);
|
|
33
|
+
if (declared) {
|
|
34
|
+
this.defaultValue = declared.value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
28
37
|
sync() {
|
|
29
38
|
const active = this.items.find((item) => item.value === this.value);
|
|
30
39
|
const entry = active ? undefined : this.items.find((item) => !item.disabled);
|
|
@@ -57,6 +66,7 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
57
66
|
}
|
|
58
67
|
willUpdate(changed) {
|
|
59
68
|
super.willUpdate(changed);
|
|
69
|
+
this.adopt();
|
|
60
70
|
hostAria(this.internals, { label: this.label, role: 'radiogroup' });
|
|
61
71
|
this.internals.setFormValue(this.value === '' ? null : this.value);
|
|
62
72
|
}
|
|
@@ -74,6 +84,7 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
74
84
|
<div part="indicator" aria-hidden="true"></div>
|
|
75
85
|
<slot
|
|
76
86
|
@slotchange=${() => {
|
|
87
|
+
this.adopt();
|
|
77
88
|
this.sync();
|
|
78
89
|
this.indicator.place();
|
|
79
90
|
}}
|
|
@@ -11,7 +11,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
11
11
|
* without radio semantics announcing destinations as choices.
|
|
12
12
|
*
|
|
13
13
|
* @since 0.1.0
|
|
14
|
-
* @status
|
|
14
|
+
* @status stable
|
|
15
15
|
* @category actions
|
|
16
16
|
* @aliases Segment, NavItem, Option
|
|
17
17
|
* @documentation https://fusion.dev/helix/components/toggle
|
|
@@ -34,9 +34,22 @@ export declare class HelixHeadlessToggle extends HelixElement {
|
|
|
34
34
|
*
|
|
35
35
|
* `<option selected>` reflects to `defaultSelected` and `option.selected` is
|
|
36
36
|
* live state that does not reflect, and those are two different facts. This
|
|
37
|
-
* element has one `selected` doing both jobs, so
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* element has one `selected` doing both jobs, so the declaration is the
|
|
38
|
+
* attribute and the state is the property.
|
|
39
|
+
*
|
|
40
|
+
* **The attribute, read when it is asked for, and never a snapshot taken in
|
|
41
|
+
* the constructor.** A field initializer runs there, and an element the HTML
|
|
42
|
+
* parser created has none of its attributes yet at that moment: measured on
|
|
43
|
+
* this element, on `Option` and on `Radio`, `<helix-toggle value="light"
|
|
44
|
+
* selected>` reported `defaultSelected` as `false` both from parsed markup
|
|
45
|
+
* and from `createElement` followed by `setAttribute`, which is every way a
|
|
46
|
+
* consumer writes one. The snapshot could only ever be true for an element
|
|
47
|
+
* already in the document when `customElements.define` ran.
|
|
48
|
+
*
|
|
49
|
+
* Nothing overwrites it either, which is what makes reading it late correct
|
|
50
|
+
* rather than merely later: `selected` does not reflect, for the reason
|
|
51
|
+
* `willUpdate` records, so the group's writes never reach the attribute and
|
|
52
|
+
* what it says is what the markup said.
|
|
40
53
|
*
|
|
41
54
|
* **The deeper half is not this.** State reflecting under the declaration's
|
|
42
55
|
* name is the fault `TreeItem` avoids by mirroring to `data-selected`.
|
|
@@ -45,8 +58,6 @@ export declare class HelixHeadlessToggle extends HelixElement {
|
|
|
45
58
|
*/
|
|
46
59
|
get defaultSelected(): boolean;
|
|
47
60
|
set defaultSelected(next: boolean);
|
|
48
|
-
/** What the markup said, read once at construction for the reason above. */
|
|
49
|
-
private seeded;
|
|
50
61
|
/**
|
|
51
62
|
* Whether this item holds the group's tab stop while nothing is chosen.
|
|
52
63
|
*
|
|
@@ -11,16 +11,15 @@ let HelixHeadlessToggle = class HelixHeadlessToggle extends HelixElement {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.disabled = false;
|
|
14
|
-
this.seeded = this.hasAttribute('selected');
|
|
15
14
|
this.focusable = false;
|
|
16
15
|
this.selected = false;
|
|
17
16
|
this.value = '';
|
|
18
17
|
}
|
|
19
18
|
get defaultSelected() {
|
|
20
|
-
return this.
|
|
19
|
+
return this.hasAttribute('selected');
|
|
21
20
|
}
|
|
22
21
|
set defaultSelected(next) {
|
|
23
|
-
this.
|
|
22
|
+
this.toggleAttribute('selected', next);
|
|
24
23
|
}
|
|
25
24
|
focusItem() {
|
|
26
25
|
this.partNamed('item')?.focus();
|
|
@@ -32,7 +32,6 @@ import type { HelixHeadlessTourStop } from '../stop/tour-stop.js';
|
|
|
32
32
|
* @event {HelixCompleteEvent} helix-complete - Fired when the last stop is
|
|
33
33
|
* finished.
|
|
34
34
|
* @event {HelixTourAskEvent} helix-tour-ask - A stop's own controls asking the tour to move, dispatched by the stop and heard here because the tour is what moves.
|
|
35
|
-
* @event {Event} toggle - Says the state moved, carrying `newState` and `oldState`.
|
|
36
35
|
*
|
|
37
36
|
* @csspart spotlight - The box over the current target, which paints the scrim.
|
|
38
37
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-headless",
|
|
3
3
|
"description": "Headless component tier. Structure, accessibility, state, and form participation. No styling.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.44.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
},
|
|
47
47
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@fusion.dev/helix-core": "0.
|
|
50
|
-
"@fusion.dev/helix-icons": "0.
|
|
49
|
+
"@fusion.dev/helix-core": "0.44.0",
|
|
50
|
+
"@fusion.dev/helix-icons": "0.44.0",
|
|
51
51
|
"uqr": "^0.1.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@custom-elements-manifest/analyzer": "^0.11.0",
|
|
55
|
-
"@fusion.dev/helix-cem": "0.
|
|
56
|
-
"@fusion.dev/helix-testing": "0.
|
|
55
|
+
"@fusion.dev/helix-cem": "0.44.0",
|
|
56
|
+
"@fusion.dev/helix-testing": "0.44.0",
|
|
57
57
|
"@fusion.dev/scripts": "0.0.0-dev",
|
|
58
58
|
"@happy-dom/global-registrator": "^20.0.0",
|
|
59
59
|
"@lit-labs/ssr": "^4.1.0",
|