@rak200/ui 0.2.19 → 0.3.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/README.md +1 -4
- package/dist/checkbox.d.ts +250 -25
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +368 -77
- package/dist/checkbox.js.map +1 -1
- package/dist/field.d.ts +6 -2
- package/dist/field.d.ts.map +1 -1
- package/dist/field.js +6 -2
- package/dist/field.js.map +1 -1
- package/dist/radio.d.ts +2 -2
- package/dist/radio.js +2 -2
- package/dist/tooltip.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,10 +45,7 @@ npm install @rak200/ui
|
|
|
45
45
|
</ui-select>
|
|
46
46
|
</ui-field>
|
|
47
47
|
|
|
48
|
-
<ui-
|
|
49
|
-
<label slot="label">Email notifications</label>
|
|
50
|
-
<ui-switch><input type="checkbox" name="notify" checked /></ui-switch>
|
|
51
|
-
</ui-field>
|
|
48
|
+
<ui-switch label="Email notifications" name="notify" checked></ui-switch>
|
|
52
49
|
|
|
53
50
|
<ui-button><ui-icon name="check"></ui-icon> Save</ui-button>
|
|
54
51
|
<ui-button variant="secondary">Cancel</ui-button>
|
package/dist/checkbox.d.ts
CHANGED
|
@@ -2,20 +2,202 @@ import { LitElement, type CSSResult, type TemplateResult } from 'lit';
|
|
|
2
2
|
/**
|
|
3
3
|
* A boolean control, drawn from the token layer rather than replaced.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* {@link UiCheckbox} and {@link UiSwitch} differ in what they draw and in what they
|
|
6
|
+
* announce, never in what they are made of. Both render a native `<input type="checkbox">`
|
|
7
|
+
* inside a `<label>` in this element's shadow root, so every behaviour a boolean control
|
|
8
|
+
* has stays the platform's — see the docblock on the shared styles above.
|
|
9
|
+
*
|
|
10
|
+
* **The element is the form control**, through `ElementInternals`. An `<input>` inside a
|
|
11
|
+
* shadow root has no form owner, so the value reaches a submit because this element passes
|
|
12
|
+
* it on and never because the input did.
|
|
13
|
+
*
|
|
14
|
+
* That is the entire price, and it is worth listing because it is smaller than it looks:
|
|
15
|
+
* `setFormValue`, `setValidity`, the three form lifecycle callbacks a form can no longer
|
|
16
|
+
* perform directly, and a re-dispatch of `change`, which is non-composed. **None of it is
|
|
17
|
+
* accessibility** — the role, the checked state, the tab stop and what `disabled` does to
|
|
18
|
+
* it are all still the platform's, because the control really is one.
|
|
19
|
+
*
|
|
20
|
+
* The same object pays the other half, which is a cost of the control being *in here*
|
|
21
|
+
* rather than of the form: two states a host stylesheet could no longer see. See
|
|
22
|
+
* {@link UiToggle.expose}.
|
|
8
23
|
*/
|
|
9
24
|
declare class UiToggle extends LitElement {
|
|
25
|
+
#private;
|
|
26
|
+
static readonly formAssociated = true;
|
|
27
|
+
/**
|
|
28
|
+
* Focus is delegated, so `focus()` and `reportValidity()` reach the control.
|
|
29
|
+
*
|
|
30
|
+
* Neither is optional: the host is not a focusable element, so without this a call to
|
|
31
|
+
* either lands on something that cannot take focus and does nothing — and the second
|
|
32
|
+
* one is what the browser does on its own when a form with an invalid control is
|
|
33
|
+
* submitted.
|
|
34
|
+
*/
|
|
35
|
+
static readonly shadowRootOptions: {
|
|
36
|
+
delegatesFocus: boolean;
|
|
37
|
+
clonable?: boolean;
|
|
38
|
+
customElementRegistry?: CustomElementRegistry | null;
|
|
39
|
+
mode: ShadowRootMode;
|
|
40
|
+
serializable?: boolean;
|
|
41
|
+
slotAssignment?: SlotAssignmentMode;
|
|
42
|
+
};
|
|
43
|
+
static readonly properties: {
|
|
44
|
+
label: {
|
|
45
|
+
type: StringConstructor;
|
|
46
|
+
reflect: boolean;
|
|
47
|
+
};
|
|
48
|
+
name: {
|
|
49
|
+
type: StringConstructor;
|
|
50
|
+
reflect: boolean;
|
|
51
|
+
};
|
|
52
|
+
value: {
|
|
53
|
+
type: StringConstructor;
|
|
54
|
+
reflect: boolean;
|
|
55
|
+
};
|
|
56
|
+
checked: {
|
|
57
|
+
type: BooleanConstructor;
|
|
58
|
+
};
|
|
59
|
+
disabled: {
|
|
60
|
+
type: BooleanConstructor;
|
|
61
|
+
reflect: boolean;
|
|
62
|
+
};
|
|
63
|
+
required: {
|
|
64
|
+
type: BooleanConstructor;
|
|
65
|
+
reflect: boolean;
|
|
66
|
+
};
|
|
67
|
+
error: {
|
|
68
|
+
type: StringConstructor;
|
|
69
|
+
reflect: boolean;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The short road to a label. `slot="label"` overrides it where markup is needed.
|
|
74
|
+
*
|
|
75
|
+
* A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
|
|
76
|
+
* gives beside its own — and so for every property below.
|
|
77
|
+
*/
|
|
78
|
+
label: string;
|
|
79
|
+
/**
|
|
80
|
+
* The name the value is submitted under.
|
|
81
|
+
*
|
|
82
|
+
* **Reflected, and that is a requirement rather than a convenience.** A form reads a
|
|
83
|
+
* form-associated custom element's name from the content attribute, so a host who sets
|
|
84
|
+
* only the property would submit nothing at all — silently, with a value published and
|
|
85
|
+
* no entry to carry it.
|
|
86
|
+
*/
|
|
87
|
+
name: string;
|
|
88
|
+
/** What a checked control submits, which the platform spells `on` by default. */
|
|
89
|
+
value: string;
|
|
90
|
+
/**
|
|
91
|
+
* Whether the control is on.
|
|
92
|
+
*
|
|
93
|
+
* **Not reflected, which is the platform's own answer rather than an omission.** A
|
|
94
|
+
* native checkbox's `checked` IDL attribute does not reflect either: the content
|
|
95
|
+
* attribute is the *default*, which is what a form reset returns to, and an attribute
|
|
96
|
+
* that followed every click would make the default whatever the user last did.
|
|
97
|
+
*
|
|
98
|
+
* A host stylesheet reaches the live state through `:state(checked)` — see
|
|
99
|
+
* {@link UiToggle.expose}, and the measurement there for why it is not `::part()`.
|
|
100
|
+
*/
|
|
101
|
+
checked: boolean;
|
|
102
|
+
/** Whether the control rejects interaction. Reflected, the way the platform's is. */
|
|
103
|
+
disabled: boolean;
|
|
104
|
+
/** Whether a form is invalid while this control is off. Reflected, likewise. */
|
|
105
|
+
required: boolean;
|
|
106
|
+
/** The error message, which paints the boundary and is announced with the control. */
|
|
107
|
+
error: string;
|
|
108
|
+
/**
|
|
109
|
+
* Published after every render, and after the first one too — Lit calls this on the
|
|
110
|
+
* initial update as well, which is why there is no `firstUpdated` beside it. A second
|
|
111
|
+
* call from there would be a statement no test could distinguish from its own absence.
|
|
112
|
+
*/
|
|
113
|
+
updated(): void;
|
|
114
|
+
/**
|
|
115
|
+
* Puts one internal state where a host stylesheet can select on it.
|
|
116
|
+
*
|
|
117
|
+
* **This is what replaces the attribute `checked` deliberately does not reflect**, and
|
|
118
|
+
* the alternative was measured rather than assumed: `::part(box):checked` does not
|
|
119
|
+
* match. A `::part()` may be followed by user-action pseudo-classes and not by state
|
|
120
|
+
* ones, so a host had no way at all to reach a state this element keeps in its shadow
|
|
121
|
+
* root — which would have made *not reflecting* a decision that costs the host
|
|
122
|
+
* something, rather than one that costs nothing.
|
|
123
|
+
*
|
|
124
|
+
* Only the two states with no other route are exposed. `:valid`, `:invalid` and
|
|
125
|
+
* `:disabled` already match on this element, measured, because a form-associated
|
|
126
|
+
* custom element takes part in them; `required` reflects, so `[required]` reaches it.
|
|
127
|
+
*
|
|
128
|
+
* @param state - The name, as `:state(name)` spells it.
|
|
129
|
+
*/
|
|
130
|
+
protected expose(state: string, on: boolean): void;
|
|
131
|
+
/**
|
|
132
|
+
* What the inner control announces itself as, where the platform needs telling.
|
|
133
|
+
*
|
|
134
|
+
* Empty here, and the attribute is then omitted rather than written blank: an
|
|
135
|
+
* `<input type="checkbox">` already announces `checkbox`, and restating it would be
|
|
136
|
+
* this component overriding the platform with the platform. {@link UiSwitch} is the
|
|
137
|
+
* one that has something to add.
|
|
138
|
+
*/
|
|
139
|
+
protected readonly controlRole: string;
|
|
140
|
+
/**
|
|
141
|
+
* The listener, as a field rather than a method, which is this repository's shape for
|
|
142
|
+
* one — `src/toast.ts` carries the same. What it delegates to is a method, so a
|
|
143
|
+
* subclass can extend the mirroring without restating the binding.
|
|
144
|
+
*
|
|
145
|
+
* **The `change` is re-dispatched rather than left to bubble**, because it does not:
|
|
146
|
+
* `change` is one of the events the platform marks non-composed, so the one the inner
|
|
147
|
+
* control fires stops at the shadow boundary and a host listening on the tag would
|
|
148
|
+
* hear nothing. `input` needs no such help — it is composed, and arrives retargeted to
|
|
149
|
+
* this element on its own.
|
|
150
|
+
*/
|
|
151
|
+
protected readonly changed: (event: Event) => void;
|
|
152
|
+
/**
|
|
153
|
+
* Mirrors the platform's own state back into the properties it came from.
|
|
154
|
+
*
|
|
155
|
+
* Read off the control rather than inverted from what was there: the platform is what
|
|
156
|
+
* just changed it, and asking is the only way to stay right about a state this element
|
|
157
|
+
* did not decide.
|
|
158
|
+
*/
|
|
159
|
+
protected sync(control: HTMLInputElement): void;
|
|
160
|
+
/**
|
|
161
|
+
* A form reset, which the platform calls and this element cannot see any other way.
|
|
162
|
+
*
|
|
163
|
+
* The content attribute is what it returns to, which is exactly `defaultChecked` on a
|
|
164
|
+
* native control — and it stays a usable default only because `checked` is not
|
|
165
|
+
* reflected onto it.
|
|
166
|
+
*/
|
|
167
|
+
formResetCallback(): void;
|
|
168
|
+
/** A `<fieldset disabled>` above this element, which reaches it and nothing below. */
|
|
169
|
+
formDisabledCallback(disabled: boolean): void;
|
|
170
|
+
/** Restoring after a back-navigation, where the browser hands the value back. */
|
|
171
|
+
formStateRestoreCallback(state: string | null): void;
|
|
172
|
+
/** The form this element participates in, for a host that needs it. */
|
|
173
|
+
get form(): HTMLFormElement | null;
|
|
174
|
+
/** Whether the control currently satisfies its constraints. */
|
|
175
|
+
get validity(): ValidityState;
|
|
176
|
+
/** The message a form would report for it, empty while the control is valid. */
|
|
177
|
+
get validationMessage(): string;
|
|
10
178
|
render(): TemplateResult;
|
|
179
|
+
/**
|
|
180
|
+
* The whole drawing, with the one thing the two elements disagree on passed in.
|
|
181
|
+
*
|
|
182
|
+
* **A parameter rather than an overridable hook**, and the difference is one the
|
|
183
|
+
* mutation floor found: a hook returning `false` is indistinguishable from a hook
|
|
184
|
+
* returning nothing, because `input.indeterminate` coerces `undefined` to `false` — so
|
|
185
|
+
* no test could tell the base implementation from its own absence. Passed at the call
|
|
186
|
+
* site it is a value, and `<ui-switch>` reading back an unmixed control is what checks
|
|
187
|
+
* it.
|
|
188
|
+
*
|
|
189
|
+
* The mixed state is bound rather than written onto the control after render, which is
|
|
190
|
+
* what keeps this element free of a query whose null branch nothing could reach.
|
|
191
|
+
*/
|
|
192
|
+
protected template(mixed: boolean): TemplateResult;
|
|
11
193
|
}
|
|
12
194
|
/**
|
|
13
195
|
* A checkbox, styled by the token layer rather than replaced.
|
|
14
196
|
*
|
|
15
|
-
* **The
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
197
|
+
* **The control is this element's**, which RFC 0005 decided and reversed an earlier rule to
|
|
198
|
+
* do: the `<input>` and its `<label>` are rendered together in one shadow root, so `name`,
|
|
199
|
+
* `checked`, `required` and `disabled` are properties here rather than attributes a host
|
|
200
|
+
* writes on a control it supplies.
|
|
19
201
|
*
|
|
20
202
|
* **The indeterminate state is drawn, and that is not a feature being added.**
|
|
21
203
|
* `appearance: none` takes the platform's dash away with the rest of the drawing, so a
|
|
@@ -23,19 +205,68 @@ declare class UiToggle extends LitElement {
|
|
|
23
205
|
* rather than a missing one. The dash below is what stops that, and nothing here invites
|
|
24
206
|
* a tri-state that APG says is rare.
|
|
25
207
|
*
|
|
26
|
-
* Composes with {@link UiField}, which finds the control through this wrapper and wires
|
|
27
|
-
* the label, the help, the error and `aria-invalid` to it.
|
|
28
|
-
*
|
|
29
208
|
* @example
|
|
30
209
|
* ```html
|
|
31
|
-
* <ui-
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
210
|
+
* <ui-checkbox label="Send a receipt" name="receipt"></ui-checkbox>
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @example A label an attribute cannot hold.
|
|
214
|
+
* ```html
|
|
215
|
+
* <ui-checkbox name="terms">
|
|
216
|
+
* <span slot="label">I accept the <a href="/terms">terms</a></span>
|
|
217
|
+
* </ui-checkbox>
|
|
35
218
|
* ```
|
|
36
219
|
*/
|
|
37
220
|
export declare class UiCheckbox extends UiToggle {
|
|
221
|
+
static readonly properties: {
|
|
222
|
+
indeterminate: {
|
|
223
|
+
type: BooleanConstructor;
|
|
224
|
+
};
|
|
225
|
+
label: {
|
|
226
|
+
type: StringConstructor;
|
|
227
|
+
reflect: boolean;
|
|
228
|
+
};
|
|
229
|
+
name: {
|
|
230
|
+
type: StringConstructor;
|
|
231
|
+
reflect: boolean;
|
|
232
|
+
};
|
|
233
|
+
value: {
|
|
234
|
+
type: StringConstructor;
|
|
235
|
+
reflect: boolean;
|
|
236
|
+
};
|
|
237
|
+
checked: {
|
|
238
|
+
type: BooleanConstructor;
|
|
239
|
+
};
|
|
240
|
+
disabled: {
|
|
241
|
+
type: BooleanConstructor;
|
|
242
|
+
reflect: boolean;
|
|
243
|
+
};
|
|
244
|
+
required: {
|
|
245
|
+
type: BooleanConstructor;
|
|
246
|
+
reflect: boolean;
|
|
247
|
+
};
|
|
248
|
+
error: {
|
|
249
|
+
type: StringConstructor;
|
|
250
|
+
reflect: boolean;
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* The mixed state, which the platform stopped drawing once `appearance` was removed.
|
|
255
|
+
*
|
|
256
|
+
* It takes an attribute where the platform offers none, which is this element having
|
|
257
|
+
* become the control rather than a box around one — and it is not reflected, for the
|
|
258
|
+
* reason `checked` is not.
|
|
259
|
+
*/
|
|
260
|
+
indeterminate: boolean;
|
|
38
261
|
static readonly styles: CSSResult[];
|
|
262
|
+
render(): TemplateResult;
|
|
263
|
+
updated(): void;
|
|
264
|
+
/**
|
|
265
|
+
* A toggle answers the question the mixed state was asking, and the platform has
|
|
266
|
+
* already cleared it on the control — so this reads it back rather than assuming.
|
|
267
|
+
* Without it the next render would put the mixed state straight back.
|
|
268
|
+
*/
|
|
269
|
+
protected sync(control: HTMLInputElement): void;
|
|
39
270
|
}
|
|
40
271
|
/**
|
|
41
272
|
* A switch, which is a checkbox that says *on* and *off* rather than *checked*.
|
|
@@ -43,28 +274,22 @@ export declare class UiCheckbox extends UiToggle {
|
|
|
43
274
|
* **The difference is semantic and the drawing follows it**, which is the order that
|
|
44
275
|
* matters: a switch takes effect immediately and a checkbox is a value you submit, so the
|
|
45
276
|
* two are not one component with two skins. `role="switch"` is what carries that to a
|
|
46
|
-
* screen reader, and this element
|
|
47
|
-
*
|
|
48
|
-
* announces as a checkbox, with nothing anywhere to read. A role the host wrote is never
|
|
49
|
-
* overwritten, the same way {@link UiField} never overwrites an `id` it did not generate.
|
|
277
|
+
* screen reader, and this element writes it on the control it renders — so a host has
|
|
278
|
+
* nothing to remember and nothing to forget.
|
|
50
279
|
*
|
|
51
280
|
* There is no native switch to delegate to: `<input type="checkbox" switch>` is
|
|
52
281
|
* unsupported in the engine this suite measures, so the element is a checkbox with a role
|
|
53
282
|
* and a drawing. A host who wants the mixed state wants {@link UiCheckbox} — `switch` has
|
|
54
|
-
* no third value, so this element does not draw one.
|
|
283
|
+
* no third value, so this element does not draw one and offers no property for one.
|
|
55
284
|
*
|
|
56
285
|
* @example
|
|
57
286
|
* ```html
|
|
58
|
-
* <ui-
|
|
59
|
-
* <label slot="label">Email notifications</label>
|
|
60
|
-
* <ui-switch><input type="checkbox" name="notify" checked /></ui-switch>
|
|
61
|
-
* </ui-field>
|
|
287
|
+
* <ui-switch label="Email notifications" name="notify" checked></ui-switch>
|
|
62
288
|
* ```
|
|
63
289
|
*/
|
|
64
290
|
export declare class UiSwitch extends UiToggle {
|
|
65
|
-
#private;
|
|
66
291
|
static readonly styles: CSSResult[];
|
|
67
|
-
|
|
292
|
+
protected readonly controlRole: string;
|
|
68
293
|
}
|
|
69
294
|
declare global {
|
|
70
295
|
interface HTMLElementTagNameMap {
|
package/dist/checkbox.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["../src/checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["../src/checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAqL1F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,cAAM,QAAS,SAAQ,UAAU;;IAC7B,MAAM,CAAC,QAAQ,CAAC,cAAc,QAAQ;IAEtC;;;;;;;OAOG;IACH,gBAAyB,iBAAiB;;;;;;;MAGxC;IAEF,gBAAyB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAQjC;IAEF;;;;;OAKG;IACH,KAAK,SAAM;IAEX;;;;;;;OAOG;IACH,IAAI,SAAM;IAEV,iFAAiF;IACjF,KAAK,SAAQ;IAEb;;;;;;;;;;OAUG;IACH,OAAO,UAAS;IAEhB,qFAAqF;IACrF,QAAQ,UAAS;IAEjB,gFAAgF;IAChF,QAAQ,UAAS;IAEjB,sFAAsF;IACtF,KAAK,SAAM;IAoBX;;;;OAIG;IACM,OAAO,IAAI,IAAI;IAKxB;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI;IAQlD;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAM;IAE5C;;;;;;;;;;OAUG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,GAAI,OAAO,KAAK,KAAG,IAAI,CAG/C;IAEF;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI/C;;;;;;OAMG;IACH,iBAAiB,IAAI,IAAI;IAIzB,sFAAsF;IACtF,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI7C,iFAAiF;IACjF,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIpD,uEAAuE;IACvE,IAAI,IAAI,IAAI,eAAe,GAAG,IAAI,CAEjC;IAED,+DAA+D;IAC/D,IAAI,QAAQ,IAAI,aAAa,CAE5B;IAED,gFAAgF;IAChF,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAEQ,MAAM,IAAI,cAAc;IAIjC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc;CAwBrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,UAAW,SAAQ,QAAQ;IACpC,gBAAyB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAGjC;IAEF;;;;;;OAMG;IACH,aAAa,UAAS;IAEtB,gBAAyB,MAAM,EAAE,SAAS,EAAE,CA6C1C;IAEO,MAAM,IAAI,cAAc;IAIxB,OAAO,IAAI,IAAI;IAKxB;;;;OAIG;cACgB,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;CAI3D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,QAAS,SAAQ,QAAQ;IAClC,gBAAyB,MAAM,EAAE,SAAS,EAAE,CAuC1C;IAEF,mBAA4B,WAAW,EAAE,MAAM,CAAY;CAC9D;AAWD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,aAAa,EAAE,UAAU,CAAC;QAC1B,WAAW,EAAE,QAAQ,CAAC;KACzB;CACJ"}
|
package/dist/checkbox.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
2
|
import { reference } from './reference.js';
|
|
3
3
|
/**
|
|
4
4
|
* The size both controls are drawn at, and a floor rather than a preference.
|
|
@@ -19,12 +19,6 @@ const size = css `max(24px, calc(${reference('--ui-space')} * 3))`;
|
|
|
19
19
|
* decision. **A mask has no colour**: only its alpha is read, so the black below is a
|
|
20
20
|
* shape and never a value. What the tick shows is the surface behind the control, punched
|
|
21
21
|
* out of the accent fill by `mask-composite: exclude`.
|
|
22
|
-
*
|
|
23
|
-
* The alternative was a mark rendered into the shadow root, and it is not available:
|
|
24
|
-
* `:host(:has(input:checked))` is invalid in this engine — `CSS.supports` says so, so it
|
|
25
|
-
* is a selector that does not exist rather than one that fails to update — and shadow CSS
|
|
26
|
-
* has no other way to read a slotted control's state. Only `::slotted(input:checked)`
|
|
27
|
-
* does, which means the control has to paint its own mark.
|
|
28
22
|
*/
|
|
29
23
|
const tick = css `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E")`;
|
|
30
24
|
/** A mask layer covering the whole control, which the mark is then subtracted from. */
|
|
@@ -32,10 +26,20 @@ const whole = css `linear-gradient(#000, #000)`;
|
|
|
32
26
|
/**
|
|
33
27
|
* What a drawn boolean control looks like, which both elements share.
|
|
34
28
|
*
|
|
35
|
-
* The control
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
29
|
+
* **The control and its label are rendered together, in this element's shadow root.** RFC
|
|
30
|
+
* 0005 settled that and measured why: an ARIA relationship needs every end of it inside one
|
|
31
|
+
* tree scope, and the arrangement that strands a control is the one that puts the control on
|
|
32
|
+
* one side of a shadow boundary and its label on the other — not the fact that the control
|
|
33
|
+
* is rendered. With the `<label>` and the `<input>` in the same root the association is the
|
|
34
|
+
* platform's, and so is everything that follows from it: the toggle, the <kbd>Space</kbd>
|
|
35
|
+
* key, the click target over the label text, and the rule that a link inside a label
|
|
36
|
+
* follows the link rather than toggling. None of that is written in this file, which is the
|
|
37
|
+
* point of the shape.
|
|
38
|
+
*
|
|
39
|
+
* The state is this element's own, so these rules read `input:checked` directly. The
|
|
40
|
+
* `::slotted(input:checked)` this file used to be built on was forced by
|
|
41
|
+
* `:host(:has(input:checked))` being invalid in this engine, and that constraint went with
|
|
42
|
+
* the slotted control.
|
|
39
43
|
*
|
|
40
44
|
* **`appearance: none` is the whole cost of this component**, and it is taken knowingly.
|
|
41
45
|
* It buys one drawing for the pair — the same border, radius, focus ring and accent the
|
|
@@ -48,21 +52,43 @@ const whole = css `linear-gradient(#000, #000)`;
|
|
|
48
52
|
* target-size floor at {@link size}, and the forced-colors block at the end.
|
|
49
53
|
*/
|
|
50
54
|
const toggle = css `
|
|
55
|
+
/* A column, because the error sits under the control rather than beside it — and
|
|
56
|
+
flex-start rather than the default stretch, so a message wider than the label does
|
|
57
|
+
not widen the label, which is the click target. */
|
|
51
58
|
:host {
|
|
52
59
|
display: inline-flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
align-items: flex-start;
|
|
62
|
+
gap: calc(${reference('--ui-space')} / 2);
|
|
63
|
+
font-family: ${reference('--ui-font')};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* The label is the whole pair's worth of click target, which a host used to have to
|
|
67
|
+
build by wrapping the component in a <label> of their own.
|
|
68
|
+
|
|
69
|
+
flex rather than inline-flex, and the difference is one the platform erases: a flex
|
|
70
|
+
item's display is blockified, so inline-flex here would compute to flex anyway — a
|
|
71
|
+
declaration no rendering could tell from this one. */
|
|
72
|
+
label {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: ${reference('--ui-space')};
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
color: ${reference('--ui-color-text')};
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
|
|
80
|
+
input {
|
|
56
81
|
appearance: none;
|
|
57
82
|
box-sizing: border-box;
|
|
58
83
|
/* The user agent puts 3px around a checkbox. Left in, it would sit inside the
|
|
59
84
|
host box and put the control off centre in any layout that aligns to it. */
|
|
60
85
|
margin: 0;
|
|
86
|
+
flex: none;
|
|
61
87
|
block-size: ${size};
|
|
62
88
|
background-color: ${reference('--ui-color-surface')};
|
|
63
89
|
background-repeat: no-repeat;
|
|
64
90
|
border: 1px solid ${reference('--ui-color-border')};
|
|
65
|
-
cursor:
|
|
91
|
+
cursor: inherit;
|
|
66
92
|
/* The focus ring is deliberately not in this list, for the reason src/button.ts
|
|
67
93
|
gives beside its own: delaying the affordance that says *this is where you are*
|
|
68
94
|
is the opposite of what it exists to do. */
|
|
@@ -71,7 +97,7 @@ const toggle = css `
|
|
|
71
97
|
border-color ${reference('--ui-duration-state')} ${reference('--ui-easing-state')};
|
|
72
98
|
}
|
|
73
99
|
|
|
74
|
-
|
|
100
|
+
input:checked {
|
|
75
101
|
background-color: ${reference('--ui-color-accent')};
|
|
76
102
|
border-color: ${reference('--ui-color-accent')};
|
|
77
103
|
}
|
|
@@ -82,35 +108,50 @@ const toggle = css `
|
|
|
82
108
|
|
|
83
109
|
The disabled guard is measured rather than assumed: a disabled control still
|
|
84
110
|
matches :hover. */
|
|
85
|
-
|
|
111
|
+
input:hover:not(:disabled) {
|
|
86
112
|
border-color: ${reference('--ui-color-text')};
|
|
87
113
|
}
|
|
88
114
|
|
|
89
|
-
|
|
115
|
+
input:checked:hover:not(:disabled) {
|
|
90
116
|
background-color: ${reference('--ui-color-accent-hover')};
|
|
91
117
|
border-color: ${reference('--ui-color-accent-hover')};
|
|
92
118
|
}
|
|
93
119
|
|
|
94
120
|
/* A visible focus ring is not decoration: removing it is the single most common way a
|
|
95
121
|
component stops being usable by keyboard. */
|
|
96
|
-
|
|
122
|
+
input:focus-visible {
|
|
97
123
|
outline: 2px solid ${reference('--ui-color-focus')};
|
|
98
124
|
outline-offset: 2px;
|
|
99
125
|
}
|
|
100
126
|
|
|
101
|
-
|
|
102
|
-
cursor: not-allowed;
|
|
127
|
+
input:disabled {
|
|
103
128
|
opacity: 0.5;
|
|
104
129
|
}
|
|
105
130
|
|
|
106
|
-
/*
|
|
107
|
-
the
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
/* Read off the host rather than through :has(), because the property is reflected and
|
|
132
|
+
the host attribute is therefore the same fact one selector earlier. */
|
|
133
|
+
:host([disabled]) label {
|
|
134
|
+
cursor: not-allowed;
|
|
135
|
+
color: ${reference('--ui-color-text-muted')};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Read off the control's own aria-invalid rather than off a host attribute, which is
|
|
139
|
+
the same source a screen reader uses and the same rule this file carried when
|
|
140
|
+
ui-field was the one writing it. One property now feeds all three — the boundary,
|
|
141
|
+
the message and setValidity — so they cannot disagree. Only the boundary moves; a
|
|
142
|
+
red fill on a switch would read as *on*.
|
|
143
|
+
|
|
144
|
+
Not :host([error]): a reflected string property whose default is empty puts an
|
|
145
|
+
empty attribute on the host, and an attribute-presence selector matches it. */
|
|
146
|
+
input[aria-invalid='true'] {
|
|
111
147
|
border-color: ${reference('--ui-color-danger')};
|
|
112
148
|
}
|
|
113
149
|
|
|
150
|
+
.error {
|
|
151
|
+
color: ${reference('--ui-color-danger')};
|
|
152
|
+
font-size: ${reference('--ui-text-supporting')};
|
|
153
|
+
}
|
|
154
|
+
|
|
114
155
|
/* Forced colors replaces every author colour with one from the user's palette, so
|
|
115
156
|
the accent that says *checked* becomes the same Canvas as the surface that says
|
|
116
157
|
*not* — the state disappears, silently, for the people who turned the mode on to
|
|
@@ -122,13 +163,12 @@ const toggle = css `
|
|
|
122
163
|
half-transparent against a palette chosen for contrast. GrayText is what that mode
|
|
123
164
|
has for *unavailable*, and it is a colour rather than a veil. */
|
|
124
165
|
@media (forced-colors: active) {
|
|
125
|
-
|
|
126
|
-
::slotted(input:indeterminate) {
|
|
166
|
+
input:checked {
|
|
127
167
|
background-color: Highlight;
|
|
128
168
|
border-color: Highlight;
|
|
129
169
|
}
|
|
130
170
|
|
|
131
|
-
|
|
171
|
+
input:disabled {
|
|
132
172
|
border-color: GrayText;
|
|
133
173
|
opacity: 1;
|
|
134
174
|
}
|
|
@@ -137,22 +177,245 @@ const toggle = css `
|
|
|
137
177
|
/**
|
|
138
178
|
* A boolean control, drawn from the token layer rather than replaced.
|
|
139
179
|
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
180
|
+
* {@link UiCheckbox} and {@link UiSwitch} differ in what they draw and in what they
|
|
181
|
+
* announce, never in what they are made of. Both render a native `<input type="checkbox">`
|
|
182
|
+
* inside a `<label>` in this element's shadow root, so every behaviour a boolean control
|
|
183
|
+
* has stays the platform's — see the docblock on the shared styles above.
|
|
184
|
+
*
|
|
185
|
+
* **The element is the form control**, through `ElementInternals`. An `<input>` inside a
|
|
186
|
+
* shadow root has no form owner, so the value reaches a submit because this element passes
|
|
187
|
+
* it on and never because the input did.
|
|
188
|
+
*
|
|
189
|
+
* That is the entire price, and it is worth listing because it is smaller than it looks:
|
|
190
|
+
* `setFormValue`, `setValidity`, the three form lifecycle callbacks a form can no longer
|
|
191
|
+
* perform directly, and a re-dispatch of `change`, which is non-composed. **None of it is
|
|
192
|
+
* accessibility** — the role, the checked state, the tab stop and what `disabled` does to
|
|
193
|
+
* it are all still the platform's, because the control really is one.
|
|
194
|
+
*
|
|
195
|
+
* The same object pays the other half, which is a cost of the control being *in here*
|
|
196
|
+
* rather than of the form: two states a host stylesheet could no longer see. See
|
|
197
|
+
* {@link UiToggle.expose}.
|
|
143
198
|
*/
|
|
144
199
|
class UiToggle extends LitElement {
|
|
200
|
+
constructor() {
|
|
201
|
+
super(...arguments);
|
|
202
|
+
/**
|
|
203
|
+
* The short road to a label. `slot="label"` overrides it where markup is needed.
|
|
204
|
+
*
|
|
205
|
+
* A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
|
|
206
|
+
* gives beside its own — and so for every property below.
|
|
207
|
+
*/
|
|
208
|
+
this.label = '';
|
|
209
|
+
/**
|
|
210
|
+
* The name the value is submitted under.
|
|
211
|
+
*
|
|
212
|
+
* **Reflected, and that is a requirement rather than a convenience.** A form reads a
|
|
213
|
+
* form-associated custom element's name from the content attribute, so a host who sets
|
|
214
|
+
* only the property would submit nothing at all — silently, with a value published and
|
|
215
|
+
* no entry to carry it.
|
|
216
|
+
*/
|
|
217
|
+
this.name = '';
|
|
218
|
+
/** What a checked control submits, which the platform spells `on` by default. */
|
|
219
|
+
this.value = 'on';
|
|
220
|
+
/**
|
|
221
|
+
* Whether the control is on.
|
|
222
|
+
*
|
|
223
|
+
* **Not reflected, which is the platform's own answer rather than an omission.** A
|
|
224
|
+
* native checkbox's `checked` IDL attribute does not reflect either: the content
|
|
225
|
+
* attribute is the *default*, which is what a form reset returns to, and an attribute
|
|
226
|
+
* that followed every click would make the default whatever the user last did.
|
|
227
|
+
*
|
|
228
|
+
* A host stylesheet reaches the live state through `:state(checked)` — see
|
|
229
|
+
* {@link UiToggle.expose}, and the measurement there for why it is not `::part()`.
|
|
230
|
+
*/
|
|
231
|
+
this.checked = false;
|
|
232
|
+
/** Whether the control rejects interaction. Reflected, the way the platform's is. */
|
|
233
|
+
this.disabled = false;
|
|
234
|
+
/** Whether a form is invalid while this control is off. Reflected, likewise. */
|
|
235
|
+
this.required = false;
|
|
236
|
+
/** The error message, which paints the boundary and is announced with the control. */
|
|
237
|
+
this.error = '';
|
|
238
|
+
this.#internals = this.attachInternals();
|
|
239
|
+
/**
|
|
240
|
+
* What the inner control announces itself as, where the platform needs telling.
|
|
241
|
+
*
|
|
242
|
+
* Empty here, and the attribute is then omitted rather than written blank: an
|
|
243
|
+
* `<input type="checkbox">` already announces `checkbox`, and restating it would be
|
|
244
|
+
* this component overriding the platform with the platform. {@link UiSwitch} is the
|
|
245
|
+
* one that has something to add.
|
|
246
|
+
*/
|
|
247
|
+
this.controlRole = '';
|
|
248
|
+
/**
|
|
249
|
+
* The listener, as a field rather than a method, which is this repository's shape for
|
|
250
|
+
* one — `src/toast.ts` carries the same. What it delegates to is a method, so a
|
|
251
|
+
* subclass can extend the mirroring without restating the binding.
|
|
252
|
+
*
|
|
253
|
+
* **The `change` is re-dispatched rather than left to bubble**, because it does not:
|
|
254
|
+
* `change` is one of the events the platform marks non-composed, so the one the inner
|
|
255
|
+
* control fires stops at the shadow boundary and a host listening on the tag would
|
|
256
|
+
* hear nothing. `input` needs no such help — it is composed, and arrives retargeted to
|
|
257
|
+
* this element on its own.
|
|
258
|
+
*/
|
|
259
|
+
this.changed = (event) => {
|
|
260
|
+
this.sync(event.target);
|
|
261
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
static { this.formAssociated = true; }
|
|
265
|
+
/**
|
|
266
|
+
* Focus is delegated, so `focus()` and `reportValidity()` reach the control.
|
|
267
|
+
*
|
|
268
|
+
* Neither is optional: the host is not a focusable element, so without this a call to
|
|
269
|
+
* either lands on something that cannot take focus and does nothing — and the second
|
|
270
|
+
* one is what the browser does on its own when a form with an invalid control is
|
|
271
|
+
* submitted.
|
|
272
|
+
*/
|
|
273
|
+
static { this.shadowRootOptions = {
|
|
274
|
+
...LitElement.shadowRootOptions,
|
|
275
|
+
delegatesFocus: true,
|
|
276
|
+
}; }
|
|
277
|
+
static { this.properties = {
|
|
278
|
+
label: { type: String, reflect: true },
|
|
279
|
+
name: { type: String, reflect: true },
|
|
280
|
+
value: { type: String, reflect: true },
|
|
281
|
+
checked: { type: Boolean },
|
|
282
|
+
disabled: { type: Boolean, reflect: true },
|
|
283
|
+
required: { type: Boolean, reflect: true },
|
|
284
|
+
error: { type: String, reflect: true },
|
|
285
|
+
}; }
|
|
286
|
+
#internals;
|
|
287
|
+
/** The form value and the validity, which move together here or disagree anywhere. */
|
|
288
|
+
#publish() {
|
|
289
|
+
this.#internals.setFormValue(this.checked ? this.value : null);
|
|
290
|
+
if (this.error !== '') {
|
|
291
|
+
this.#internals.setValidity({ customError: true }, this.error);
|
|
292
|
+
}
|
|
293
|
+
else if (this.required && !this.checked) {
|
|
294
|
+
this.#internals.setValidity({ valueMissing: true }, 'Please tick this box if you want to proceed.');
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
this.#internals.setValidity({});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Published after every render, and after the first one too — Lit calls this on the
|
|
302
|
+
* initial update as well, which is why there is no `firstUpdated` beside it. A second
|
|
303
|
+
* call from there would be a statement no test could distinguish from its own absence.
|
|
304
|
+
*/
|
|
305
|
+
updated() {
|
|
306
|
+
this.#publish();
|
|
307
|
+
this.expose('checked', this.checked);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Puts one internal state where a host stylesheet can select on it.
|
|
311
|
+
*
|
|
312
|
+
* **This is what replaces the attribute `checked` deliberately does not reflect**, and
|
|
313
|
+
* the alternative was measured rather than assumed: `::part(box):checked` does not
|
|
314
|
+
* match. A `::part()` may be followed by user-action pseudo-classes and not by state
|
|
315
|
+
* ones, so a host had no way at all to reach a state this element keeps in its shadow
|
|
316
|
+
* root — which would have made *not reflecting* a decision that costs the host
|
|
317
|
+
* something, rather than one that costs nothing.
|
|
318
|
+
*
|
|
319
|
+
* Only the two states with no other route are exposed. `:valid`, `:invalid` and
|
|
320
|
+
* `:disabled` already match on this element, measured, because a form-associated
|
|
321
|
+
* custom element takes part in them; `required` reflects, so `[required]` reaches it.
|
|
322
|
+
*
|
|
323
|
+
* @param state - The name, as `:state(name)` spells it.
|
|
324
|
+
*/
|
|
325
|
+
expose(state, on) {
|
|
326
|
+
if (on) {
|
|
327
|
+
this.#internals.states.add(state);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
this.#internals.states.delete(state);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Mirrors the platform's own state back into the properties it came from.
|
|
335
|
+
*
|
|
336
|
+
* Read off the control rather than inverted from what was there: the platform is what
|
|
337
|
+
* just changed it, and asking is the only way to stay right about a state this element
|
|
338
|
+
* did not decide.
|
|
339
|
+
*/
|
|
340
|
+
sync(control) {
|
|
341
|
+
this.checked = control.checked;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* A form reset, which the platform calls and this element cannot see any other way.
|
|
345
|
+
*
|
|
346
|
+
* The content attribute is what it returns to, which is exactly `defaultChecked` on a
|
|
347
|
+
* native control — and it stays a usable default only because `checked` is not
|
|
348
|
+
* reflected onto it.
|
|
349
|
+
*/
|
|
350
|
+
formResetCallback() {
|
|
351
|
+
this.checked = this.hasAttribute('checked');
|
|
352
|
+
}
|
|
353
|
+
/** A `<fieldset disabled>` above this element, which reaches it and nothing below. */
|
|
354
|
+
formDisabledCallback(disabled) {
|
|
355
|
+
this.disabled = disabled;
|
|
356
|
+
}
|
|
357
|
+
/** Restoring after a back-navigation, where the browser hands the value back. */
|
|
358
|
+
formStateRestoreCallback(state) {
|
|
359
|
+
this.checked = state !== null;
|
|
360
|
+
}
|
|
361
|
+
/** The form this element participates in, for a host that needs it. */
|
|
362
|
+
get form() {
|
|
363
|
+
return this.#internals.form;
|
|
364
|
+
}
|
|
365
|
+
/** Whether the control currently satisfies its constraints. */
|
|
366
|
+
get validity() {
|
|
367
|
+
return this.#internals.validity;
|
|
368
|
+
}
|
|
369
|
+
/** The message a form would report for it, empty while the control is valid. */
|
|
370
|
+
get validationMessage() {
|
|
371
|
+
return this.#internals.validationMessage;
|
|
372
|
+
}
|
|
145
373
|
render() {
|
|
146
|
-
return
|
|
374
|
+
return this.template(false);
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* The whole drawing, with the one thing the two elements disagree on passed in.
|
|
378
|
+
*
|
|
379
|
+
* **A parameter rather than an overridable hook**, and the difference is one the
|
|
380
|
+
* mutation floor found: a hook returning `false` is indistinguishable from a hook
|
|
381
|
+
* returning nothing, because `input.indeterminate` coerces `undefined` to `false` — so
|
|
382
|
+
* no test could tell the base implementation from its own absence. Passed at the call
|
|
383
|
+
* site it is a value, and `<ui-switch>` reading back an unmixed control is what checks
|
|
384
|
+
* it.
|
|
385
|
+
*
|
|
386
|
+
* The mixed state is bound rather than written onto the control after render, which is
|
|
387
|
+
* what keeps this element free of a query whose null branch nothing could reach.
|
|
388
|
+
*/
|
|
389
|
+
template(mixed) {
|
|
390
|
+
return html `
|
|
391
|
+
<label part="label">
|
|
392
|
+
<input
|
|
393
|
+
type="checkbox"
|
|
394
|
+
part="box"
|
|
395
|
+
role=${this.controlRole === '' ? nothing : this.controlRole}
|
|
396
|
+
.checked=${this.checked}
|
|
397
|
+
.indeterminate=${mixed}
|
|
398
|
+
?disabled=${this.disabled}
|
|
399
|
+
?required=${this.required}
|
|
400
|
+
aria-invalid=${this.error === '' ? nothing : 'true'}
|
|
401
|
+
aria-describedby=${this.error === '' ? nothing : 'error'}
|
|
402
|
+
@change=${this.changed}
|
|
403
|
+
/>
|
|
404
|
+
<span part="text"><slot name="label">${this.label}</slot></span>
|
|
405
|
+
</label>
|
|
406
|
+
${this.error === ''
|
|
407
|
+
? nothing
|
|
408
|
+
: html `<span class="error" id="error" part="error">${this.error}</span>`}
|
|
409
|
+
`;
|
|
147
410
|
}
|
|
148
411
|
}
|
|
149
412
|
/**
|
|
150
413
|
* A checkbox, styled by the token layer rather than replaced.
|
|
151
414
|
*
|
|
152
|
-
* **The
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
415
|
+
* **The control is this element's**, which RFC 0005 decided and reversed an earlier rule to
|
|
416
|
+
* do: the `<input>` and its `<label>` are rendered together in one shadow root, so `name`,
|
|
417
|
+
* `checked`, `required` and `disabled` are properties here rather than attributes a host
|
|
418
|
+
* writes on a control it supplies.
|
|
156
419
|
*
|
|
157
420
|
* **The indeterminate state is drawn, and that is not a feature being added.**
|
|
158
421
|
* `appearance: none` takes the platform's dash away with the rest of the drawing, so a
|
|
@@ -160,22 +423,38 @@ class UiToggle extends LitElement {
|
|
|
160
423
|
* rather than a missing one. The dash below is what stops that, and nothing here invites
|
|
161
424
|
* a tri-state that APG says is rare.
|
|
162
425
|
*
|
|
163
|
-
* Composes with {@link UiField}, which finds the control through this wrapper and wires
|
|
164
|
-
* the label, the help, the error and `aria-invalid` to it.
|
|
165
|
-
*
|
|
166
426
|
* @example
|
|
167
427
|
* ```html
|
|
168
|
-
* <ui-
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
428
|
+
* <ui-checkbox label="Send a receipt" name="receipt"></ui-checkbox>
|
|
429
|
+
* ```
|
|
430
|
+
*
|
|
431
|
+
* @example A label an attribute cannot hold.
|
|
432
|
+
* ```html
|
|
433
|
+
* <ui-checkbox name="terms">
|
|
434
|
+
* <span slot="label">I accept the <a href="/terms">terms</a></span>
|
|
435
|
+
* </ui-checkbox>
|
|
172
436
|
* ```
|
|
173
437
|
*/
|
|
174
438
|
export class UiCheckbox extends UiToggle {
|
|
439
|
+
constructor() {
|
|
440
|
+
super(...arguments);
|
|
441
|
+
/**
|
|
442
|
+
* The mixed state, which the platform stopped drawing once `appearance` was removed.
|
|
443
|
+
*
|
|
444
|
+
* It takes an attribute where the platform offers none, which is this element having
|
|
445
|
+
* become the control rather than a box around one — and it is not reflected, for the
|
|
446
|
+
* reason `checked` is not.
|
|
447
|
+
*/
|
|
448
|
+
this.indeterminate = false;
|
|
449
|
+
}
|
|
450
|
+
static { this.properties = {
|
|
451
|
+
...UiToggle.properties,
|
|
452
|
+
indeterminate: { type: Boolean },
|
|
453
|
+
}; }
|
|
175
454
|
static { this.styles = [
|
|
176
455
|
toggle,
|
|
177
456
|
css `
|
|
178
|
-
|
|
457
|
+
input {
|
|
179
458
|
inline-size: ${size};
|
|
180
459
|
border-radius: ${reference('--ui-radius')};
|
|
181
460
|
}
|
|
@@ -183,7 +462,7 @@ export class UiCheckbox extends UiToggle {
|
|
|
183
462
|
/* The mark is a hole: the whole control, minus the shape, so what shows
|
|
184
463
|
through is whatever the control sits on. The docblock on the mask constant
|
|
185
464
|
above says why a hole rather than a colour. */
|
|
186
|
-
|
|
465
|
+
input:checked {
|
|
187
466
|
mask-image: ${whole}, ${tick};
|
|
188
467
|
mask-composite: exclude;
|
|
189
468
|
mask-size: 100% 100%;
|
|
@@ -191,7 +470,7 @@ export class UiCheckbox extends UiToggle {
|
|
|
191
470
|
}
|
|
192
471
|
|
|
193
472
|
/* A dash needs no drawing: a rectangle is a gradient with a size. */
|
|
194
|
-
|
|
473
|
+
input:indeterminate {
|
|
195
474
|
background-color: ${reference('--ui-color-accent')};
|
|
196
475
|
border-color: ${reference('--ui-color-accent')};
|
|
197
476
|
mask-image: ${whole}, ${whole};
|
|
@@ -202,8 +481,38 @@ export class UiCheckbox extends UiToggle {
|
|
|
202
481
|
mask-position: center;
|
|
203
482
|
mask-repeat: no-repeat;
|
|
204
483
|
}
|
|
484
|
+
|
|
485
|
+
/* The mixed state's forced-colors override lives here rather than beside the
|
|
486
|
+
checked one in the shared sheet, and the cascade is why: the rule above is
|
|
487
|
+
in a later sheet at equal specificity, so a Highlight declared back there
|
|
488
|
+
loses to the accent declared here — and the accent is exactly what forced
|
|
489
|
+
colors replaces with the surface, taking the state away for the reader who
|
|
490
|
+
turned the mode on to see it. Measured, as a test the shared block passed
|
|
491
|
+
for :checked and could not pass for this one. */
|
|
492
|
+
@media (forced-colors: active) {
|
|
493
|
+
input:indeterminate {
|
|
494
|
+
background-color: Highlight;
|
|
495
|
+
border-color: Highlight;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
205
498
|
`,
|
|
206
499
|
]; }
|
|
500
|
+
render() {
|
|
501
|
+
return this.template(this.indeterminate);
|
|
502
|
+
}
|
|
503
|
+
updated() {
|
|
504
|
+
super.updated();
|
|
505
|
+
this.expose('indeterminate', this.indeterminate);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* A toggle answers the question the mixed state was asking, and the platform has
|
|
509
|
+
* already cleared it on the control — so this reads it back rather than assuming.
|
|
510
|
+
* Without it the next render would put the mixed state straight back.
|
|
511
|
+
*/
|
|
512
|
+
sync(control) {
|
|
513
|
+
super.sync(control);
|
|
514
|
+
this.indeterminate = control.indeterminate;
|
|
515
|
+
}
|
|
207
516
|
}
|
|
208
517
|
/**
|
|
209
518
|
* A switch, which is a checkbox that says *on* and *off* rather than *checked*.
|
|
@@ -211,29 +520,28 @@ export class UiCheckbox extends UiToggle {
|
|
|
211
520
|
* **The difference is semantic and the drawing follows it**, which is the order that
|
|
212
521
|
* matters: a switch takes effect immediately and a checkbox is a value you submit, so the
|
|
213
522
|
* two are not one component with two skins. `role="switch"` is what carries that to a
|
|
214
|
-
* screen reader, and this element
|
|
215
|
-
*
|
|
216
|
-
* announces as a checkbox, with nothing anywhere to read. A role the host wrote is never
|
|
217
|
-
* overwritten, the same way {@link UiField} never overwrites an `id` it did not generate.
|
|
523
|
+
* screen reader, and this element writes it on the control it renders — so a host has
|
|
524
|
+
* nothing to remember and nothing to forget.
|
|
218
525
|
*
|
|
219
526
|
* There is no native switch to delegate to: `<input type="checkbox" switch>` is
|
|
220
527
|
* unsupported in the engine this suite measures, so the element is a checkbox with a role
|
|
221
528
|
* and a drawing. A host who wants the mixed state wants {@link UiCheckbox} — `switch` has
|
|
222
|
-
* no third value, so this element does not draw one.
|
|
529
|
+
* no third value, so this element does not draw one and offers no property for one.
|
|
223
530
|
*
|
|
224
531
|
* @example
|
|
225
532
|
* ```html
|
|
226
|
-
* <ui-
|
|
227
|
-
* <label slot="label">Email notifications</label>
|
|
228
|
-
* <ui-switch><input type="checkbox" name="notify" checked /></ui-switch>
|
|
229
|
-
* </ui-field>
|
|
533
|
+
* <ui-switch label="Email notifications" name="notify" checked></ui-switch>
|
|
230
534
|
* ```
|
|
231
535
|
*/
|
|
232
536
|
export class UiSwitch extends UiToggle {
|
|
537
|
+
constructor() {
|
|
538
|
+
super(...arguments);
|
|
539
|
+
this.controlRole = 'switch';
|
|
540
|
+
}
|
|
233
541
|
static { this.styles = [
|
|
234
542
|
toggle,
|
|
235
543
|
css `
|
|
236
|
-
|
|
544
|
+
input {
|
|
237
545
|
inline-size: calc(${size} * 5 / 3);
|
|
238
546
|
/* Any radius at or above half the block size rounds the ends fully, so
|
|
239
547
|
the whole size is a pill at every size this control can take. */
|
|
@@ -245,10 +553,10 @@ export class UiSwitch extends UiToggle {
|
|
|
245
553
|
colour — restating it here changed no pixel, which is how it was
|
|
246
554
|
found: as a mutant no test could possibly kill. */
|
|
247
555
|
background-color: ${reference('--ui-color-border')};
|
|
248
|
-
/* The thumb is a background layer rather than an element, because
|
|
249
|
-
|
|
250
|
-
the control is on. A closest-side radius comes from the
|
|
251
|
-
own size
|
|
556
|
+
/* The thumb is a background layer rather than an element, because the
|
|
557
|
+
layer moves with one number where an element would need a second rule
|
|
558
|
+
to be told the control is on. A closest-side radius comes from the
|
|
559
|
+
layer's own size. */
|
|
252
560
|
background-image: radial-gradient(
|
|
253
561
|
circle closest-side,
|
|
254
562
|
${reference('--ui-color-surface')} 100%,
|
|
@@ -265,28 +573,11 @@ export class UiSwitch extends UiToggle {
|
|
|
265
573
|
${reference('--ui-easing-state')};
|
|
266
574
|
}
|
|
267
575
|
|
|
268
|
-
|
|
576
|
+
input:checked {
|
|
269
577
|
background-position: calc(100% - ${size} / 6) center;
|
|
270
578
|
}
|
|
271
579
|
`,
|
|
272
580
|
]; }
|
|
273
|
-
render() {
|
|
274
|
-
return html `<slot @slotchange=${this.#announce}></slot>`;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Marks the slotted control a switch for anything reading the accessibility tree.
|
|
278
|
-
*
|
|
279
|
-
* On `slotchange` rather than once, because the host may replace the control — a
|
|
280
|
-
* framework re-render is indistinguishable from that here, and a switch that
|
|
281
|
-
* announces itself correctly only until the first re-render is worse than one that
|
|
282
|
-
* never did.
|
|
283
|
-
*/
|
|
284
|
-
#announce() {
|
|
285
|
-
const control = this.querySelector('input');
|
|
286
|
-
if (control !== null && !control.hasAttribute('role')) {
|
|
287
|
-
control.setAttribute('role', 'switch');
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
581
|
}
|
|
291
582
|
// Stryker disable next-line StringLiteral: the registration runs once, at import, inside
|
|
292
583
|
// the warm process Stryker switches mutants in — so by the time a mutant on this line is
|
package/dist/checkbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../src/checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../src/checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAuC,MAAM,KAAK,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,IAAI,GAAG,GAAG,CAAA,kBAAkB,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAG,GAAG,CAAA,sOAAsO,CAAC;AAEvP,uFAAuF;AACvF,MAAM,KAAK,GAAG,GAAG,CAAA,6BAA6B,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;oBAQE,SAAS,CAAC,YAAY,CAAC;uBACpB,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;;eAY9B,SAAS,CAAC,YAAY,CAAC;;iBAErB,SAAS,CAAC,iBAAiB,CAAC;;;;;;;;;;sBAUvB,IAAI;4BACE,SAAS,CAAC,oBAAoB,CAAC;;4BAE/B,SAAS,CAAC,mBAAmB,CAAC;;;;;;+BAM3B,SAAS,CAAC,qBAAqB,CAAC,IAAI,SAAS,CAAC,mBAAmB,CAAC;2BACtE,SAAS,CAAC,qBAAqB,CAAC,IAAI,SAAS,CAAC,mBAAmB,CAAC;;;;4BAIjE,SAAS,CAAC,mBAAmB,CAAC;wBAClC,SAAS,CAAC,mBAAmB,CAAC;;;;;;;;;;wBAU9B,SAAS,CAAC,iBAAiB,CAAC;;;;4BAIxB,SAAS,CAAC,yBAAyB,CAAC;wBACxC,SAAS,CAAC,yBAAyB,CAAC;;;;;;6BAM/B,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;;;;iBAYzC,SAAS,CAAC,uBAAuB,CAAC;;;;;;;;;;;;wBAY3B,SAAS,CAAC,mBAAmB,CAAC;;;;iBAIrC,SAAS,CAAC,mBAAmB,CAAC;qBAC1B,SAAS,CAAC,sBAAsB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwBrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,QAAS,SAAQ,UAAU;IAAjC;;QA0BI;;;;;WAKG;QACH,UAAK,GAAG,EAAE,CAAC;QAEX;;;;;;;WAOG;QACH,SAAI,GAAG,EAAE,CAAC;QAEV,iFAAiF;QACjF,UAAK,GAAG,IAAI,CAAC;QAEb;;;;;;;;;;WAUG;QACH,YAAO,GAAG,KAAK,CAAC;QAEhB,qFAAqF;QACrF,aAAQ,GAAG,KAAK,CAAC;QAEjB,gFAAgF;QAChF,aAAQ,GAAG,KAAK,CAAC;QAEjB,sFAAsF;QACtF,UAAK,GAAG,EAAE,CAAC;QAEF,eAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAoD7C;;;;;;;WAOG;QACgB,gBAAW,GAAW,EAAE,CAAC;QAE5C;;;;;;;;;;WAUG;QACgB,YAAO,GAAG,CAAC,KAAY,EAAQ,EAAE;YAChD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAA0B,CAAC,CAAC;YAC5C,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC;IA0FN,CAAC;aA1OmB,mBAAc,GAAG,IAAI,AAAP,CAAQ;IAEtC;;;;;;;OAOG;aACsB,sBAAiB,GAAG;QACzC,GAAG,UAAU,CAAC,iBAAiB;QAC/B,cAAc,EAAE,IAAI;KACvB,AAHyC,CAGxC;aAEuB,eAAU,GAAG;QAClC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACrC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAC1B,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;KACzC,AARkC,CAQjC;IA6CO,UAAU,CAA0B;IAE7C,sFAAsF;IACtF,QAAQ;QACJ,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAE/D,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACnE,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,CAAC,UAAU,CAAC,WAAW,CACvB,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,8CAA8C,CACjD,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACM,OAAO;QACZ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACO,MAAM,CAAC,KAAa,EAAE,EAAW;QACvC,IAAI,EAAE,EAAE,CAAC;YACL,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACL,CAAC;IA4BD;;;;;;OAMG;IACO,IAAI,CAAC,OAAyB;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACnC,CAAC;IAED;;;;;;OAMG;IACH,iBAAiB;QACb,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,sFAAsF;IACtF,oBAAoB,CAAC,QAAiB;QAClC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,iFAAiF;IACjF,wBAAwB,CAAC,KAAoB;QACzC,IAAI,CAAC,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC;IAClC,CAAC;IAED,uEAAuE;IACvE,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;IAChC,CAAC;IAED,+DAA+D;IAC/D,IAAI,QAAQ;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,gFAAgF;IAChF,IAAI,iBAAiB;QACjB,OAAO,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC;IAC7C,CAAC;IAEQ,MAAM;QACX,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;;;;OAYG;IACO,QAAQ,CAAC,KAAc;QAC7B,OAAO,IAAI,CAAA;;;;;2BAKQ,IAAI,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW;+BAChD,IAAI,CAAC,OAAO;qCACN,KAAK;gCACV,IAAI,CAAC,QAAQ;gCACb,IAAI,CAAC,QAAQ;mCACV,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;uCAChC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;8BAC9C,IAAI,CAAC,OAAO;;uDAEa,IAAI,CAAC,KAAK;;cAGjD,IAAI,CAAC,KAAK,KAAK,EAAE;YACb,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,IAAI,CAAA,+CAA+C,IAAI,CAAC,KAAK,SACvE;SACH,CAAC;IACN,CAAC;;AAGL;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAO,UAAW,SAAQ,QAAQ;IAAxC;;QAMI;;;;;;WAMG;QACH,kBAAa,GAAG,KAAK,CAAC;IAmE1B,CAAC;aA/E4B,eAAU,GAAG;QAClC,GAAG,QAAQ,CAAC,UAAU;QACtB,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KACnC,AAHkC,CAGjC;aAWuB,WAAM,GAAgB;QAC3C,MAAM;QACN,GAAG,CAAA;;+BAEoB,IAAI;iCACF,SAAS,CAAC,aAAa,CAAC;;;;;;;8BAO3B,KAAK,KAAK,IAAI;;;;;;;;oCAQR,SAAS,CAAC,mBAAmB,CAAC;gCAClC,SAAS,CAAC,mBAAmB,CAAC;8BAChC,KAAK,KAAK,KAAK;;;;2BAIlB,IAAI,cAAc,IAAI;;;;;;;;;;;;;;;;;;SAkBxC;KACJ,AA7C8B,CA6C7B;IAEO,MAAM;QACX,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC;IAEQ,OAAO;QACZ,KAAK,CAAC,OAAO,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACrD,CAAC;IAED;;;;OAIG;IACgB,IAAI,CAAC,OAAyB;QAC7C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC/C,CAAC;;AAGL;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,QAAS,SAAQ,QAAQ;IAAtC;;QA0CgC,gBAAW,GAAW,QAAQ,CAAC;IAC/D,CAAC;aA1C4B,WAAM,GAAgB;QAC3C,MAAM;QACN,GAAG,CAAA;;oCAEyB,IAAI;;;iCAGP,IAAI;;;;;;;oCAOD,SAAS,CAAC,mBAAmB,CAAC;;;;;;;sBAO5C,SAAS,CAAC,oBAAoB,CAAC;;;wCAGb,IAAI;4CACA,IAAI;;uCAET,SAAS,CAAC,qBAAqB,CAAC;0BAC7C,SAAS,CAAC,mBAAmB,CAAC;mCACrB,SAAS,CAAC,qBAAqB,CAAC;0BACzC,SAAS,CAAC,mBAAmB,CAAC;0CACd,SAAS,CAAC,qBAAqB,CAAC;0BAChD,SAAS,CAAC,mBAAmB,CAAC;;;;mDAIL,IAAI;;SAE9C;KACJ,AAvC8B,CAuC7B;;AAKN,yFAAyF;AACzF,yFAAyF;AACzF,yFAAyF;AACzF,oEAAoE;AACpE,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;AAEjD,0EAA0E;AAC1E,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC"}
|
package/dist/field.d.ts
CHANGED
|
@@ -3,8 +3,12 @@ import { LitElement, type TemplateResult } from 'lit';
|
|
|
3
3
|
* Form plumbing: a label bound to a control, help and error text bound through
|
|
4
4
|
* `aria-describedby`, and `aria-invalid` while the field is in error.
|
|
5
5
|
*
|
|
6
|
-
* Written once here rather than per control
|
|
7
|
-
*
|
|
6
|
+
* Written once here rather than per control that needs it, because copies of one wiring are
|
|
7
|
+
* copies of one chance to get it subtly wrong.
|
|
8
|
+
*
|
|
9
|
+
* **`<ui-checkbox>` and `<ui-switch>` are not among them any more.** They render their label,
|
|
10
|
+
* their message and their `aria-invalid` beside the control, in one tree scope, so there is
|
|
11
|
+
* nothing scattered here to point at anything — see `docs/checkbox.md`.
|
|
8
12
|
*
|
|
9
13
|
* **Everything is slotted, and that is forced rather than chosen.** An ARIA relationship
|
|
10
14
|
* by IDREF does not cross a shadow boundary: a `<label for>` rendered in this element's
|
package/dist/field.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAMjE
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAMjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,OAAQ,SAAQ,UAAU;;IACnC,gBAAyB,MAAM,0BAuB7B;IAeO,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;IAK5B,YAAY,IAAI,IAAI;IAIpB,MAAM,IAAI,cAAc;CAmLpC;AAQD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,UAAU,EAAE,OAAO,CAAC;KACvB;CACJ"}
|
package/dist/field.js
CHANGED
|
@@ -6,8 +6,12 @@ let sequence = 0;
|
|
|
6
6
|
* Form plumbing: a label bound to a control, help and error text bound through
|
|
7
7
|
* `aria-describedby`, and `aria-invalid` while the field is in error.
|
|
8
8
|
*
|
|
9
|
-
* Written once here rather than per control
|
|
10
|
-
*
|
|
9
|
+
* Written once here rather than per control that needs it, because copies of one wiring are
|
|
10
|
+
* copies of one chance to get it subtly wrong.
|
|
11
|
+
*
|
|
12
|
+
* **`<ui-checkbox>` and `<ui-switch>` are not among them any more.** They render their label,
|
|
13
|
+
* their message and their `aria-invalid` beside the control, in one tree scope, so there is
|
|
14
|
+
* nothing scattered here to point at anything — see `docs/checkbox.md`.
|
|
11
15
|
*
|
|
12
16
|
* **Everything is slotted, and that is forced rather than chosen.** An ARIA relationship
|
|
13
17
|
* by IDREF does not cross a shadow boundary: a `<label for>` rendered in this element's
|
package/dist/field.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.js","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,8DAA8D;AAC9D,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB
|
|
1
|
+
{"version":3,"file":"field.js","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"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"}
|
package/dist/radio.d.ts
CHANGED
|
@@ -84,8 +84,8 @@ export declare class UiRadioGroup extends LitElement {
|
|
|
84
84
|
* which lands before this element's. Set a microtask later, the role would arrive
|
|
85
85
|
* after the only reader that needs it.
|
|
86
86
|
*
|
|
87
|
-
* A `role` the host wrote is never overwritten, the same
|
|
88
|
-
*
|
|
87
|
+
* A `role` the host wrote is never overwritten, the same courtesy {@link UiField}
|
|
88
|
+
* extends to an `id` it finds already there.
|
|
89
89
|
*/
|
|
90
90
|
connectedCallback(): void;
|
|
91
91
|
/**
|
package/dist/radio.js
CHANGED
|
@@ -258,8 +258,8 @@ export class UiRadioGroup extends LitElement {
|
|
|
258
258
|
* which lands before this element's. Set a microtask later, the role would arrive
|
|
259
259
|
* after the only reader that needs it.
|
|
260
260
|
*
|
|
261
|
-
* A `role` the host wrote is never overwritten, the same
|
|
262
|
-
*
|
|
261
|
+
* A `role` the host wrote is never overwritten, the same courtesy {@link UiField}
|
|
262
|
+
* extends to an `id` it finds already there.
|
|
263
263
|
*/
|
|
264
264
|
connectedCallback() {
|
|
265
265
|
super.connectedCallback();
|
package/dist/tooltip.js
CHANGED
|
@@ -207,7 +207,7 @@ export class UiTooltip extends LitElement {
|
|
|
207
207
|
* one that stops being announced at a moment nothing reports.
|
|
208
208
|
*
|
|
209
209
|
* A `role` or an `id` the host wrote is never overwritten, the same courtesy
|
|
210
|
-
* `<ui-field>` and `<ui-
|
|
210
|
+
* `<ui-field>` and `<ui-radio-group>` extend. `aria-describedby` is **added to** rather than
|
|
211
211
|
* replaced: the trigger may already be described by a field's help text, and a
|
|
212
212
|
* description that silently replaced another is the failure nobody sees.
|
|
213
213
|
*/
|