@fusion.dev/helix-core 0.2.0 → 0.4.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 +4 -4
- package/dist/controllers/aria-forward-controller/aria-forward-controller.js +0 -105
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +0 -71
- package/dist/controllers/command-controller/command-controller.js +0 -62
- package/dist/controllers/copy-controller/copy-controller.js +0 -63
- package/dist/controllers/disabled-cascade-controller/disabled-cascade-controller.js +0 -40
- package/dist/controllers/dismiss-controller/dismiss-controller.js +0 -124
- package/dist/controllers/drilldown-controller/drilldown-controller.js +0 -87
- package/dist/controllers/floating-controller/floating-controller.js +0 -152
- package/dist/controllers/focus-trap-controller/focus-trap-controller.js +0 -35
- package/dist/controllers/indicator-controller/indicator-controller.js +0 -82
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +0 -46
- package/dist/controllers/popover-controller/popover-controller.js +0 -72
- package/dist/controllers/source-controller/source-controller.js +0 -38
- package/dist/controllers/token-color-controller/token-color-controller.js +0 -51
- package/dist/controllers/virtualize-controller/virtualize-controller.js +0 -128
- package/dist/events/element-events.js +0 -22
- package/dist/events/events.js +0 -386
- package/dist/helix-element/helix-element.d.ts +10 -17
- package/dist/helix-element/helix-element.js +0 -505
- package/dist/helix-form-element/helix-form-element.js +0 -140
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +0 -77
- package/dist/mixins/mixin-collection/mixin-collection.js +0 -83
- package/dist/mixins/mixin-controller-active/mixin-controller-active.js +0 -82
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.js +0 -78
- package/dist/mixins/mixin-controller-open/mixin-controller-open.js +0 -93
- package/dist/mixins/mixin-controller-value/mixin-controller-value.js +0 -87
- package/dist/mixins/mixin-dismissible/mixin-dismissible.js +0 -38
- package/dist/mixins/mixin-field/mixin-field.js +0 -277
- package/dist/utils/anchor-element/anchor-element.js +0 -23
- package/dist/utils/capture-pointer/capture-pointer.js +0 -18
- package/dist/utils/closest-instance/closest-instance.js +0 -20
- package/dist/utils/create-sheet/create-sheet.js +0 -14
- package/dist/utils/custom-element/custom-element.js +0 -83
- package/dist/utils/draw-icon/draw-icon.js +0 -28
- package/dist/utils/draw-tooltip/draw-tooltip.js +1 -50
- package/dist/utils/elapsed-time/elapsed-time.js +0 -51
- package/dist/utils/focusable-elements/focusable-elements.js +1 -59
- package/dist/utils/format-numbers/format-numbers.js +0 -16
- package/dist/utils/host-aria/host-aria.js +0 -26
- package/dist/utils/inherit-disabled/inherit-disabled.js +0 -36
- package/dist/utils/line-path/line-path.js +0 -36
- package/dist/utils/on-unless-false/on-unless-false.js +0 -23
- package/dist/utils/read-series/read-series.js +0 -71
- package/dist/utils/relative-time/relative-time.js +0 -43
- package/dist/utils/resolve-active-item/resolve-active-item.js +0 -20
- package/dist/utils/restore-value/restore-value.js +0 -54
- package/dist/utils/scale/scale.js +0 -19
- package/dist/utils/scale/ticks.js +0 -36
- package/dist/utils/scroll-item-into-view/scroll-item-into-view.js +0 -53
- package/dist/utils/slot-filled/slot-filled.js +0 -23
- package/dist/utils/tell-disclosure/tell-disclosure.js +0 -53
- package/dist/utils/ticker/ticker.js +0 -22
- package/dist/utils/tone-marks/tone-marks.js +0 -24
- package/dist/utils/value-as/value-as.js +0 -56
- package/package.json +5 -5
|
@@ -7,63 +7,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { property } from 'lit/decorators.js';
|
|
8
8
|
import { HelixBeforeCloseEvent, HelixBeforeOpenEvent } from '../../events/events.js';
|
|
9
9
|
import { requestChange } from '../../utils/request-change/request-change.js';
|
|
10
|
-
/**
|
|
11
|
-
* Grafts open state onto a base class, and says so twice.
|
|
12
|
-
*
|
|
13
|
-
* `helix-before-open` and `helix-before-close` announce the change while it is
|
|
14
|
-
* still a request, so `preventDefault()` refuses it and nothing moves. Native
|
|
15
|
-
* `toggle` announces it afterwards, once the state has actually gone, carrying
|
|
16
|
-
* `newState` and `oldState` the way the platform does on `<details>` and on a
|
|
17
|
-
* popover. The first is how a consumer takes the decision; the second is what
|
|
18
|
-
* they bind when they only want to know.
|
|
19
|
-
*
|
|
20
|
-
* `open` is a seed and a correction rather than a claim: the element applies
|
|
21
|
-
* its own changes from wherever markup started it, and `defaultOpen` is what a
|
|
22
|
-
* reset returns to.
|
|
23
|
-
*
|
|
24
|
-
* Records `:state(open)` whenever the element is open. Styled tiers select on
|
|
25
|
-
* that rather than on `[open]`, which is absent until somebody writes it.
|
|
26
|
-
*/
|
|
27
10
|
export const MixinControllerOpen = (Base) => {
|
|
28
|
-
// JSDoc is duplicated from MixinControllerOpenInterface deliberately. The interface is
|
|
29
|
-
// what TypeScript consumers see; this class is what the manifest analyzer
|
|
30
|
-
// reads when resolving inherited members into dependent packages.
|
|
31
11
|
class OpenElement extends Base {
|
|
32
12
|
constructor() {
|
|
33
13
|
super(...arguments);
|
|
34
|
-
/**
|
|
35
|
-
* Initial open state for uncontrolled use, where nothing declared one.
|
|
36
|
-
*/
|
|
37
14
|
this.defaultOpen = false;
|
|
38
|
-
/**
|
|
39
|
-
* The state, whoever set it, and `undefined` until somebody has.
|
|
40
|
-
*
|
|
41
|
-
* Prefixed, and it has to be. These mixins compose onto one prototype
|
|
42
|
-
* chain, `Select` takes this one and `MixinControllerValue` together, and
|
|
43
|
-
* TypeScript's `private` is a compile-time fiction: two mixins with a field
|
|
44
|
-
* called `state` share one property on the instance, and the second one
|
|
45
|
-
* silently overwrites the first. Measured, as a select whose `value` came
|
|
46
|
-
* back holding its `open` boolean.
|
|
47
|
-
*
|
|
48
|
-
* One field and not two. Writing always applies, the way a native control
|
|
49
|
-
* does when a script assigns to it.
|
|
50
|
-
*/
|
|
51
15
|
this.openState = undefined;
|
|
52
16
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Whether the element is open.
|
|
55
|
-
*
|
|
56
|
-
* One property, not two, so `dialog.open` answers the question anyone
|
|
57
|
-
* asking it meant. Writing always applies; `<helix-dialog open>` is the
|
|
58
|
-
* same statement in markup.
|
|
59
|
-
*
|
|
60
|
-
* **Not reflected, and that is required rather than tidy.** Reflection
|
|
61
|
-
* writes the resolved state back as an attribute, so an element that opened
|
|
62
|
-
* itself would put `open` on its own host: cloned, serialized for
|
|
63
|
-
* hydration, or diffed by a framework, it comes back holding whatever the
|
|
64
|
-
* last reader did rather than what the author wrote. `:state(open)` carries
|
|
65
|
-
* the resolved state for stylesheets, which is what the mirror is for.
|
|
66
|
-
*/
|
|
67
17
|
get open() {
|
|
68
18
|
return this.openState ?? this.defaultOpen;
|
|
69
19
|
}
|
|
@@ -72,31 +22,10 @@ export const MixinControllerOpen = (Base) => {
|
|
|
72
22
|
this.openState = next;
|
|
73
23
|
this.requestUpdate('open', previous);
|
|
74
24
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Records the resolved state as the custom state `open`.
|
|
77
|
-
*
|
|
78
|
-
* **A custom state and never `data-open`.** An attribute mirror is in the
|
|
79
|
-
* DOM, so an `<helix-accordion-item default-open>` served without it gains
|
|
80
|
-
* it on upgrade, which is a hydration mismatch a React consumer reports.
|
|
81
|
-
* See `HelixElement.toggleState`, and see `Toast.Item` for the other answer
|
|
82
|
-
* to the same fault: inverting the hook so the write falls on the side that
|
|
83
|
-
* only happens after somebody acts. Inversion works where the resting state
|
|
84
|
-
* is the loud one and cannot help here, `checked` and `open` being true
|
|
85
|
-
* only because a consumer asked for them.
|
|
86
|
-
*/
|
|
87
25
|
willUpdate(changed) {
|
|
88
26
|
super.willUpdate(changed);
|
|
89
27
|
this.toggleState('open', this.open);
|
|
90
28
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Requests an open-state change, and reports whether it was applied.
|
|
93
|
-
*
|
|
94
|
-
* Announces before it acts, so `preventDefault()` on the `helix-before-open` or
|
|
95
|
-
* `helix-before-close` is a refusal and nothing moves. Nobody refusing means the
|
|
96
|
-
* element opens or closes itself, whether or not a consumer declared
|
|
97
|
-
* `open`: a declared property is a seed and a correction, and a consumer
|
|
98
|
-
* who wants the decision for themselves refuses it and assigns their own.
|
|
99
|
-
*/
|
|
100
29
|
requestOpen(next) {
|
|
101
30
|
if (this.open === next) {
|
|
102
31
|
return true;
|
|
@@ -116,27 +45,6 @@ export const MixinControllerOpen = (Base) => {
|
|
|
116
45
|
}
|
|
117
46
|
return applied;
|
|
118
47
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Says the state moved, under the platform's own name and in its shape.
|
|
121
|
-
*
|
|
122
|
-
* **A native `toggle` from inside a shadow root reaches nobody**, because
|
|
123
|
-
* it neither bubbles nor composes, so the ten families showing a
|
|
124
|
-
* `popover="manual"` panel and the two rendering a real `<dialog>` announce
|
|
125
|
-
* nothing to a consumer. The disclosures have no native element to fire
|
|
126
|
-
* anything at all: `AccordionItem` and `TreeItem` are `aria-expanded` and
|
|
127
|
-
* `hidden` written by hand, which is `<details>`'s job done manually.
|
|
128
|
-
*
|
|
129
|
-
* **From here rather than from `PopoverController`.** The controller covers
|
|
130
|
-
* eleven families and the mixin covers sixteen, so announcing from both
|
|
131
|
-
* would announce twice on the ten they share. What `toggle` reports is the
|
|
132
|
-
* *state*, and the state is this mixin's; the controller is a way of
|
|
133
|
-
* putting a panel on the screen.
|
|
134
|
-
*
|
|
135
|
-
* **`newState` and `oldState`, because that is the platform's shape**, so a
|
|
136
|
-
* consumer arriving from `<details>` reads the same two words. Not
|
|
137
|
-
* cancelable: the before events are the request, and a second cancelable
|
|
138
|
-
* event for one transition is two answers to one question.
|
|
139
|
-
*/
|
|
140
48
|
announceToggle(open) {
|
|
141
49
|
const event = new Event('toggle', { bubbles: false, cancelable: false, composed: false });
|
|
142
50
|
Object.assign(event, {
|
|
@@ -145,7 +53,6 @@ export const MixinControllerOpen = (Base) => {
|
|
|
145
53
|
});
|
|
146
54
|
this.dispatchEvent(event);
|
|
147
55
|
}
|
|
148
|
-
/** Requests the opposite of the current state. */
|
|
149
56
|
toggleOpen() {
|
|
150
57
|
return this.requestOpen(!this.open);
|
|
151
58
|
}
|
|
@@ -7,64 +7,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { property } from 'lit/decorators.js';
|
|
8
8
|
import { HelixBeforeChangeEvent } from '../../events/events.js';
|
|
9
9
|
import { requestChange } from '../../utils/request-change/request-change.js';
|
|
10
|
-
/**
|
|
11
|
-
* Grafts `value`, `defaultValue`, and the two callbacks that answer a form.
|
|
12
|
-
*
|
|
13
|
-
* **Derived on read, never seeded in a lifecycle hook.** `value` falls back to
|
|
14
|
-
* `defaultValue`, so the server and the client agree without either running a
|
|
15
|
-
* hook. Seeding in `connectedCallback` is the trap: SSR never calls it, so a
|
|
16
|
-
* control with a `default-value` would serve empty and fill itself at
|
|
17
|
-
* hydration, a flash for a reader and a mismatch for React.
|
|
18
|
-
*
|
|
19
|
-
* **What it does not own is reporting.** `setFormValue` stays with the
|
|
20
|
-
* component, because what an empty value means is the component's business: a
|
|
21
|
-
* text field submits its emptiness, since `""` is an answer and the field was
|
|
22
|
-
* on the form, while a group with nothing chosen submits nothing at all.
|
|
23
|
-
*
|
|
24
|
-
* `Checkbox` deliberately does not take this. Its `value` is what it submits
|
|
25
|
-
* *when it is on* rather than what it holds, so it is configuration rather than
|
|
26
|
-
* state, and the state it does have is `checked`, which is
|
|
27
|
-
* `MixinControllerChecked`'s.
|
|
28
|
-
*/
|
|
29
10
|
export const MixinControllerValue = (Base) => {
|
|
30
|
-
// JSDoc is duplicated from the interface deliberately. The interface is what
|
|
31
|
-
// TypeScript consumers see; this class is what the manifest analyzer reads
|
|
32
|
-
// when resolving inherited members into dependent packages.
|
|
33
11
|
class ValueElement extends Base {
|
|
34
12
|
constructor() {
|
|
35
13
|
super(...arguments);
|
|
36
|
-
/**
|
|
37
|
-
* The value the markup declared, which is where a reset returns to.
|
|
38
|
-
*/
|
|
39
14
|
this.defaultValue = '';
|
|
40
|
-
/**
|
|
41
|
-
* The state, whoever set it, and `undefined` until somebody has.
|
|
42
|
-
*
|
|
43
|
-
* One field and not two. Writing always applies, the way a native control
|
|
44
|
-
* does when a script assigns to it.
|
|
45
|
-
*/
|
|
46
15
|
this.valueState = undefined;
|
|
47
|
-
/**
|
|
48
|
-
* Whether a reader edits this continuously, which decides the native name.
|
|
49
|
-
*
|
|
50
|
-
* The request event is `helix-before-change` whatever the answer; this
|
|
51
|
-
* decides which native event announces the result, `input` while a reader
|
|
52
|
-
* is editing against `change` when they are done, which is the distinction
|
|
53
|
-
* the platform already draws.
|
|
54
|
-
*
|
|
55
|
-
* Discrete by default: only a control the reader edits continuously says
|
|
56
|
-
* otherwise.
|
|
57
|
-
*/
|
|
58
16
|
this.announcesInput = false;
|
|
59
17
|
}
|
|
60
|
-
/**
|
|
61
|
-
* What the control holds now, and what its form submits.
|
|
62
|
-
*
|
|
63
|
-
* One property, not two, so `input.value` answers the question anyone
|
|
64
|
-
* asking it meant. Writing always applies; `<helix-input value="x">` is the
|
|
65
|
-
* same statement in markup, and `default-value` is how markup seeds a value
|
|
66
|
-
* a reset should return to.
|
|
67
|
-
*/
|
|
68
18
|
get value() {
|
|
69
19
|
return this.valueState ?? this.defaultValue;
|
|
70
20
|
}
|
|
@@ -73,35 +23,12 @@ export const MixinControllerValue = (Base) => {
|
|
|
73
23
|
this.valueState = next;
|
|
74
24
|
this.requestUpdate('value', previous);
|
|
75
25
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Announces the applied value under the platform's own name.
|
|
78
|
-
*
|
|
79
|
-
* **After `apply`, never before**, which is the whole reason this is
|
|
80
|
-
* separate from the request event: a native handler reads
|
|
81
|
-
* `event.target.value`, and it has to be the value that was just applied.
|
|
82
|
-
*
|
|
83
|
-
* **Both, for a discrete control, because that is what the platform does.**
|
|
84
|
-
* A native `<select>` sends `input` and then `change` from one choice: the
|
|
85
|
-
* value moved, and the reader is also done. A continuous control announces
|
|
86
|
-
* `input` here and relays `change` from its inner control when the reader
|
|
87
|
-
* is done, so the pair keeps the platform's timings rather than reporting a
|
|
88
|
-
* commit on every keystroke.
|
|
89
|
-
*/
|
|
90
26
|
announceNatively() {
|
|
91
27
|
this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
92
28
|
if (!this.announcesInput) {
|
|
93
29
|
this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
|
|
94
30
|
}
|
|
95
31
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Requests a new value, and reports whether the request stood.
|
|
98
|
-
*
|
|
99
|
-
* Announces before it acts, so `preventDefault()` on the `helix-before-change` is
|
|
100
|
-
* a refusal and nothing moves. Nobody refusing means the control updates
|
|
101
|
-
* itself, whether or not a consumer declared `value`: a declared property
|
|
102
|
-
* is a seed and a correction, the way `<input value>` is, and a consumer
|
|
103
|
-
* who wants the change for themselves refuses it and assigns their own.
|
|
104
|
-
*/
|
|
105
32
|
requestValue(next) {
|
|
106
33
|
if (this.value === next) {
|
|
107
34
|
return true;
|
|
@@ -121,25 +48,11 @@ export const MixinControllerValue = (Base) => {
|
|
|
121
48
|
}
|
|
122
49
|
return applied;
|
|
123
50
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Returns the control to the value its markup declared.
|
|
126
|
-
*
|
|
127
|
-
* Both halves are dropped, the consumer's and the control's, because a
|
|
128
|
-
* reset means the form is as it was served. Clearing only the internal one
|
|
129
|
-
* would leave a control that had been written to stuck at that value.
|
|
130
|
-
*/
|
|
131
51
|
formResetCallback() {
|
|
132
52
|
const previous = this.value;
|
|
133
53
|
this.valueState = undefined;
|
|
134
54
|
this.requestUpdate('value', previous);
|
|
135
55
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Restores the value when the browser brings a form back.
|
|
138
|
-
*
|
|
139
|
-
* Falling back to `defaultValue` rather than to empty, because a restore
|
|
140
|
-
* with no state is a form the browser has nothing recorded for, which is
|
|
141
|
-
* the same situation as a fresh one.
|
|
142
|
-
*/
|
|
143
56
|
formStateRestoreCallback(state) {
|
|
144
57
|
const previous = this.value;
|
|
145
58
|
this.valueState = state ?? undefined;
|
|
@@ -6,58 +6,20 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { property } from 'lit/decorators.js';
|
|
8
8
|
import { HelixDismissEvent } from '../../events/events.js';
|
|
9
|
-
/**
|
|
10
|
-
* Grafts `dismissible`, its label, and the event that says so.
|
|
11
|
-
*
|
|
12
|
-
* **The label reads the default slot, never `this.textContent`**, which is
|
|
13
|
-
* every light-DOM descendant including the ones assigned elsewhere. On
|
|
14
|
-
* `Announcement` and `Tag` the two are the same thing, because they have one
|
|
15
|
-
* slot. On `Toast.Item` the second sweeps in the actions: a message reading
|
|
16
|
-
* "Could not reach the server" with a `Retry` button announces itself as "Could
|
|
17
|
-
* not reach the server Retry", and the consumer removing it from their list
|
|
18
|
-
* gets that string to match on.
|
|
19
|
-
*
|
|
20
|
-
* **`dismissEvent()` is separate from `dismiss()` for the one that needs it.**
|
|
21
|
-
* `Announcement` and `Tag` dispatch and are done: they own no state, so a
|
|
22
|
-
* refusal is the whole of the consumer's answer. `Toast.Item` holds an `open`
|
|
23
|
-
* and applies the change itself, so its event goes through `requestChange` with
|
|
24
|
-
* an `apply` beside it. Giving it the event rather than the method lets it keep
|
|
25
|
-
* the contract and skip the default.
|
|
26
|
-
*/
|
|
27
9
|
export const MixinDismissible = (Base) => {
|
|
28
10
|
class Dismissible extends Base {
|
|
29
11
|
constructor() {
|
|
30
12
|
super(...arguments);
|
|
31
|
-
/**
|
|
32
|
-
* Whether it offers a control to take it away.
|
|
33
|
-
*/
|
|
34
13
|
this.dismissible = false;
|
|
35
|
-
/**
|
|
36
|
-
* Accessible name for that control.
|
|
37
|
-
*
|
|
38
|
-
* `attribute` is spelled out because Lit lowercases a property name to
|
|
39
|
-
* derive one rather than dash-casing it, so this would otherwise be
|
|
40
|
-
* reachable only as `dismisslabel`, which nobody would guess and no linter
|
|
41
|
-
* would catch.
|
|
42
|
-
*/
|
|
43
14
|
this.dismissLabel = 'Dismiss';
|
|
44
15
|
}
|
|
45
|
-
/**
|
|
46
|
-
* The event, built and not dispatched.
|
|
47
|
-
*
|
|
48
|
-
* Reading text is safe here: nothing calls this on a server, because the
|
|
49
|
-
* only things that do are a press and a timer.
|
|
50
|
-
*/
|
|
51
16
|
dismissEvent() {
|
|
52
|
-
/* Default slot only. A node assigned to a named slot belongs to another
|
|
53
|
-
region and is not what this surface is called. */
|
|
54
17
|
const own = [...this.childNodes]
|
|
55
18
|
.filter((node) => !(node instanceof Element) || !node.slot)
|
|
56
19
|
.map((node) => node.textContent ?? '')
|
|
57
20
|
.join('');
|
|
58
21
|
return new HelixDismissEvent({ label: own.trim() });
|
|
59
22
|
}
|
|
60
|
-
/** Announces that it should go, and reports whether the request stood. */
|
|
61
23
|
dismiss() {
|
|
62
24
|
const event = this.dismissEvent();
|
|
63
25
|
this.dispatchEvent(event);
|