@rak200/ui 0.3.0 → 0.5.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 +10 -18
- package/dist/button.d.ts +1 -2
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +1 -2
- package/dist/button.js.map +1 -1
- package/dist/dialog.d.ts +3 -7
- package/dist/dialog.d.ts.map +1 -1
- package/dist/dialog.js +3 -7
- package/dist/dialog.js.map +1 -1
- package/dist/field.d.ts +5 -3
- package/dist/field.d.ts.map +1 -1
- package/dist/field.js +5 -3
- package/dist/field.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +330 -33
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +355 -64
- package/dist/input.js.map +1 -1
- package/dist/menu.d.ts +3 -14
- package/dist/menu.d.ts.map +1 -1
- package/dist/menu.js +3 -14
- package/dist/menu.js.map +1 -1
- package/dist/radio.d.ts +142 -59
- package/dist/radio.d.ts.map +1 -1
- package/dist/radio.js +378 -147
- package/dist/radio.js.map +1 -1
- package/dist/select.d.ts +220 -14
- package/dist/select.d.ts.map +1 -1
- package/dist/select.js +381 -26
- package/dist/select.js.map +1 -1
- package/dist/tokens.js +1 -1
- package/dist/tokens.js.map +1 -1
- package/package.json +1 -1
package/dist/radio.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
2
|
import { reference } from './reference.js';
|
|
3
|
+
// Stryker disable next-line StringLiteral: both ends of this event read the constant — the
|
|
4
|
+
// declaration dispatches it and the group listens for it — so a different name, the empty
|
|
5
|
+
// string included, still meets itself. Nothing outside this module names it, which is what
|
|
6
|
+
// makes the mutant provably equivalent rather than merely uncaught.
|
|
7
|
+
const announcement = 'ui-radio-changed';
|
|
8
|
+
/**
|
|
9
|
+
* The name the rendered controls share, which is what makes them one group.
|
|
10
|
+
*
|
|
11
|
+
* It never leaves this shadow root and never reaches a form: a radio group with no form
|
|
12
|
+
* owner is scoped by its **tree**, so one literal is safe in every instance on a page —
|
|
13
|
+
* two groups carrying it are two groups, measured. What a form submits is the host's own
|
|
14
|
+
* `name`, through `ElementInternals`.
|
|
15
|
+
*/
|
|
16
|
+
const grouping = 'option';
|
|
3
17
|
/**
|
|
4
18
|
* The size the control is drawn at, and a floor rather than a preference.
|
|
5
19
|
*
|
|
@@ -31,60 +45,206 @@ const whole = css `linear-gradient(#000, #000)`;
|
|
|
31
45
|
*/
|
|
32
46
|
const mark = css `radial-gradient(circle closest-side, #000 100%, transparent 100%)`;
|
|
33
47
|
/**
|
|
34
|
-
* One
|
|
48
|
+
* One choice in a {@link UiRadioGroup}: a value, and the text beside it.
|
|
35
49
|
*
|
|
36
|
-
* **The `<input type="radio">`
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `<
|
|
41
|
-
*
|
|
42
|
-
* **This element carries no state and no name.** It is a drawing, and everything that
|
|
43
|
-
* makes a set of radios *a group* — one tab stop, arrow keys that move and select, one
|
|
44
|
-
* value out of the set — is the platform's, because they are native radios sharing a
|
|
45
|
-
* `name`. Wrapping each one changes none of that: measured in this suite, a group whose
|
|
46
|
-
* radios sit inside custom elements is still one group.
|
|
50
|
+
* **It draws nothing.** The group renders the real `<input type="radio">` and the
|
|
51
|
+
* `<label>` around it, because a `role="radiogroup"`, the name pointing at it and the
|
|
52
|
+
* controls it contains have to share one tree scope — `ARCHITECTURE.md`, *A relationship
|
|
53
|
+
* needs one tree scope*. So this element exists to be read rather than to be seen, the way
|
|
54
|
+
* `<ui-option>` does for `<ui-select>`.
|
|
47
55
|
*
|
|
48
56
|
* @example
|
|
49
57
|
* ```html
|
|
50
|
-
* <
|
|
51
|
-
* <ui-radio><input type="radio" name="plan" value="free" /></ui-radio>
|
|
52
|
-
* Free
|
|
53
|
-
* </label>
|
|
58
|
+
* <ui-radio value="free">Free</ui-radio>
|
|
54
59
|
* ```
|
|
55
60
|
*/
|
|
56
61
|
export class UiRadio extends LitElement {
|
|
62
|
+
constructor() {
|
|
63
|
+
super(...arguments);
|
|
64
|
+
/** What the group submits while this choice is the one in force. */
|
|
65
|
+
this.value = '';
|
|
66
|
+
/** Whether this is the choice a group with no `value` starts on, and resets to. */
|
|
67
|
+
this.checked = false;
|
|
68
|
+
/** Whether this one choice refuses interaction, the rest of the set staying live. */
|
|
69
|
+
this.disabled = false;
|
|
70
|
+
this.#announce = () => {
|
|
71
|
+
this.dispatchEvent(new Event(announcement, { bubbles: true }));
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
static { this.styles = css `
|
|
75
|
+
:host {
|
|
76
|
+
display: none;
|
|
77
|
+
}
|
|
78
|
+
`; }
|
|
79
|
+
static { this.properties = {
|
|
80
|
+
value: { type: String, reflect: true },
|
|
81
|
+
checked: { type: Boolean, reflect: true },
|
|
82
|
+
disabled: { type: Boolean, reflect: true },
|
|
83
|
+
}; }
|
|
84
|
+
/**
|
|
85
|
+
* Tells the group something changed, on every update and on every slot change.
|
|
86
|
+
*
|
|
87
|
+
* A property write is not something a `MutationObserver` reports, which is what makes a
|
|
88
|
+
* declaration this package owns different from an element a host wrote: the property is
|
|
89
|
+
* reactive here. It bubbles because the choices are the group's own light-DOM children,
|
|
90
|
+
* and it is dispatched from `updated()` rather than from `disconnectedCallback`, which
|
|
91
|
+
* has no path left to bubble along.
|
|
92
|
+
*/
|
|
93
|
+
updated() {
|
|
94
|
+
this.#announce();
|
|
95
|
+
}
|
|
96
|
+
#announce;
|
|
97
|
+
render() {
|
|
98
|
+
return html `<slot @slotchange=${this.#announce}></slot>`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A set of choices, laid out and named as one thing.
|
|
103
|
+
*
|
|
104
|
+
* **It hand-rolls no roving tabindex and it brings no state machine.** Native radios
|
|
105
|
+
* sharing a `name` **are** the APG **Radio Group** pattern — one tab stop, arrow keys that
|
|
106
|
+
* move *and* select, wrapping at the ends, and left/right swapped under `dir="rtl"` — and
|
|
107
|
+
* that holds inside a shadow root, where the group is scoped by its tree because the
|
|
108
|
+
* controls have no form owner. `tests/radio.test.ts` measures it rather than trusting it.
|
|
109
|
+
* `ARCHITECTURE.md`, *Behaviour is delegated*, carries why no machine arrived.
|
|
110
|
+
*
|
|
111
|
+
* **What it owns is what the platform leaves out**: the drawing, the layout, the group's
|
|
112
|
+
* own name, help and message, and form participation through `ElementInternals` — a
|
|
113
|
+
* control in a shadow root has no form owner, so the element answers for the value, the
|
|
114
|
+
* validity and the three form lifecycle callbacks.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```html
|
|
118
|
+
* <ui-radio-group label="Plan" name="plan" help="Change it any time.">
|
|
119
|
+
* <ui-radio value="free">Free</ui-radio>
|
|
120
|
+
* <ui-radio value="pro" checked>Pro</ui-radio>
|
|
121
|
+
* </ui-radio-group>
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export class UiRadioGroup extends LitElement {
|
|
125
|
+
constructor() {
|
|
126
|
+
super(...arguments);
|
|
127
|
+
/**
|
|
128
|
+
* The accessible name, and the text above the set.
|
|
129
|
+
*
|
|
130
|
+
* A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
|
|
131
|
+
* gives beside its own — and so for every property below.
|
|
132
|
+
*/
|
|
133
|
+
this.label = '';
|
|
134
|
+
/** Supporting text under the set, which survives an error rather than yielding. */
|
|
135
|
+
this.help = '';
|
|
136
|
+
/** The message, which paints the boundaries and is announced with the group. */
|
|
137
|
+
this.error = '';
|
|
138
|
+
/**
|
|
139
|
+
* The name the value is submitted under.
|
|
140
|
+
*
|
|
141
|
+
* **Reflected, and that is a requirement rather than a convenience.** A form names a
|
|
142
|
+
* form-associated custom element's entry from the content attribute, so a host who set
|
|
143
|
+
* only the property would submit nothing at all — silently.
|
|
144
|
+
*/
|
|
145
|
+
this.name = '';
|
|
146
|
+
/**
|
|
147
|
+
* The choice currently made.
|
|
148
|
+
*
|
|
149
|
+
* **Empty means _the declared default_ rather than _nothing_**, which is what lets a
|
|
150
|
+
* `<ui-radio checked>` mean what `<input checked>` means and a reset return to it.
|
|
151
|
+
* Not reflected, the way a native control's `checked` IDL attribute is not.
|
|
152
|
+
*/
|
|
153
|
+
this.value = '';
|
|
154
|
+
/** Which way the options are laid out, and what the group announces it did. */
|
|
155
|
+
this.orientation = 'vertical';
|
|
156
|
+
/** Whether a form is invalid while no choice is made. */
|
|
157
|
+
this.required = false;
|
|
158
|
+
/** Whether the whole set refuses interaction, and submits nothing. */
|
|
159
|
+
this.disabled = false;
|
|
160
|
+
this.#internals = this.attachInternals();
|
|
161
|
+
this.#redraw = () => {
|
|
162
|
+
this.requestUpdate();
|
|
163
|
+
};
|
|
164
|
+
/** A choice made by hand, mirrored back and re-dispatched. */
|
|
165
|
+
this.#changed = (event) => {
|
|
166
|
+
this.value = event.target.value;
|
|
167
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
168
|
+
};
|
|
169
|
+
}
|
|
57
170
|
static { this.styles = css `
|
|
58
171
|
:host {
|
|
59
|
-
display:
|
|
172
|
+
display: block;
|
|
173
|
+
font-family: ${reference('--ui-font')};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* The rhythm ui-field used to own, now owned by the control it was wrapping. */
|
|
177
|
+
.stack {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: calc(${reference('--ui-space')} / 2);
|
|
60
181
|
}
|
|
61
182
|
|
|
62
|
-
|
|
63
|
-
|
|
183
|
+
.label {
|
|
184
|
+
color: ${reference('--ui-color-text')};
|
|
185
|
+
}
|
|
64
186
|
|
|
65
|
-
|
|
187
|
+
:host([disabled]) .label {
|
|
188
|
+
color: ${reference('--ui-color-text-muted')};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.options {
|
|
192
|
+
display: flex;
|
|
193
|
+
flex-direction: column;
|
|
194
|
+
gap: calc(${reference('--ui-space')} / 2);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Laid out by the attribute rather than by the host's own CSS, so the drawing and
|
|
198
|
+
the announcement cannot disagree: orientation sets both this rule and
|
|
199
|
+
aria-orientation, and a host who reached for flex-direction instead would change
|
|
200
|
+
one of the two. */
|
|
201
|
+
:host([orientation='horizontal']) .options {
|
|
202
|
+
flex-direction: row;
|
|
203
|
+
flex-wrap: wrap;
|
|
204
|
+
column-gap: calc(${reference('--ui-space')} * 2);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* The label CONTAINS its control, so there is no IDREF to resolve and no id to
|
|
208
|
+
generate — the same shape src/checkbox.ts takes, and the reason the click target
|
|
209
|
+
covers the text for free. align-items rather than center: an option whose text
|
|
210
|
+
wraps to two lines should keep its control on the first. */
|
|
211
|
+
.option {
|
|
212
|
+
display: flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
gap: calc(${reference('--ui-space')} / 2);
|
|
215
|
+
color: ${reference('--ui-color-text')};
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.option:has(input:disabled) {
|
|
220
|
+
color: ${reference('--ui-color-text-muted')};
|
|
221
|
+
cursor: not-allowed;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* appearance: none is this component's whole cost, and it is taken for the reason
|
|
66
225
|
ARCHITECTURE.md states as a debt rather than a free hand: it removes the
|
|
67
226
|
platform's dot, its target size and its behaviour under forced colors in one
|
|
68
227
|
declaration, and each of those is answered below. What it buys is a radio that
|
|
69
228
|
belongs beside the checkbox this kit already draws — a native 13px radio next to
|
|
70
229
|
a drawn 24px checkbox would argue cosmetically for a difference that is
|
|
71
230
|
semantic. */
|
|
72
|
-
|
|
231
|
+
input {
|
|
73
232
|
appearance: none;
|
|
74
233
|
box-sizing: border-box;
|
|
75
|
-
|
|
76
|
-
|
|
234
|
+
flex: none;
|
|
235
|
+
/* The user agent puts 3px around a radio. Left in, it would put the control
|
|
236
|
+
off centre against the text beside it. */
|
|
77
237
|
margin: 0;
|
|
78
238
|
inline-size: ${size};
|
|
79
239
|
block-size: ${size};
|
|
80
|
-
/* A circle, and the one measurement here that is not a token: the shape is
|
|
81
|
-
|
|
82
|
-
|
|
240
|
+
/* A circle, and the one measurement here that is not a token: the shape is what
|
|
241
|
+
tells a radio from a checkbox before either is read, so it cannot follow
|
|
242
|
+
--ui-radius without a square radio becoming possible. */
|
|
83
243
|
border-radius: 50%;
|
|
84
244
|
background-color: ${reference('--ui-color-surface')};
|
|
85
245
|
background-repeat: no-repeat;
|
|
86
246
|
border: 1px solid ${reference('--ui-color-border')};
|
|
87
|
-
cursor:
|
|
247
|
+
cursor: inherit;
|
|
88
248
|
/* The focus ring is deliberately not in this list, for the reason
|
|
89
249
|
src/button.ts gives beside its own: delaying the affordance that says *this
|
|
90
250
|
is where you are* is the opposite of what it exists to do. */
|
|
@@ -94,10 +254,10 @@ export class UiRadio extends LitElement {
|
|
|
94
254
|
border-color ${reference('--ui-duration-state')} ${reference('--ui-easing-state')};
|
|
95
255
|
}
|
|
96
256
|
|
|
97
|
-
/* The mark is a hole: the whole control, minus the circle, so what shows through
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
257
|
+
/* The mark is a hole: the whole control, minus the circle, so what shows through is
|
|
258
|
+
whatever the control sits on. The docblock on the mask constant says why a hole
|
|
259
|
+
rather than a colour. */
|
|
260
|
+
input:checked {
|
|
101
261
|
background-color: ${reference('--ui-color-accent')};
|
|
102
262
|
border-color: ${reference('--ui-color-accent')};
|
|
103
263
|
mask-image: ${whole}, ${mark};
|
|
@@ -116,32 +276,52 @@ export class UiRadio extends LitElement {
|
|
|
116
276
|
|
|
117
277
|
The disabled guard is measured rather than assumed: a disabled control still
|
|
118
278
|
matches :hover. */
|
|
119
|
-
|
|
279
|
+
input:hover:not(:disabled) {
|
|
120
280
|
border-color: ${reference('--ui-color-text')};
|
|
121
281
|
}
|
|
122
282
|
|
|
123
|
-
|
|
283
|
+
input:checked:hover:not(:disabled) {
|
|
124
284
|
background-color: ${reference('--ui-color-accent-hover')};
|
|
125
285
|
border-color: ${reference('--ui-color-accent-hover')};
|
|
126
286
|
}
|
|
127
287
|
|
|
128
|
-
/* A visible focus ring is not decoration: removing it is the single most common
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
288
|
+
/* A visible focus ring is not decoration: removing it is the single most common way
|
|
289
|
+
a component stops being usable by keyboard — and on a radio group it is the only
|
|
290
|
+
thing that says which option an arrow key just moved to. */
|
|
291
|
+
input:focus-visible {
|
|
132
292
|
outline: 2px solid ${reference('--ui-color-focus')};
|
|
133
293
|
outline-offset: 2px;
|
|
134
294
|
}
|
|
135
295
|
|
|
136
|
-
|
|
296
|
+
input:disabled {
|
|
137
297
|
cursor: not-allowed;
|
|
138
298
|
opacity: 0.5;
|
|
139
299
|
}
|
|
140
300
|
|
|
141
|
-
/*
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
301
|
+
/* The error is the SET's, not one option's: what a radio group gets wrong is the
|
|
302
|
+
choice. Read off the rendered aria-invalid rather than a reflected attribute on
|
|
303
|
+
the host, which is the trap ui-checkbox measured — Lit reflects an empty string
|
|
304
|
+
default as an empty attribute, and an attribute-presence selector matches every
|
|
305
|
+
element.
|
|
306
|
+
|
|
307
|
+
This used to retarget --ui-color-border over the whole subtree, because no
|
|
308
|
+
selector in this sheet could reach a control two elements down in the host's
|
|
309
|
+
tree. The controls are in here now, so the rule names them. */
|
|
310
|
+
.options[aria-invalid='true'] input {
|
|
311
|
+
border-color: ${reference('--ui-color-danger')};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.help {
|
|
315
|
+
color: ${reference('--ui-color-text')};
|
|
316
|
+
font-size: ${reference('--ui-text-supporting')};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Colour is not the only cue — the message says what is wrong, and aria-invalid
|
|
320
|
+
marks the group whatever the styling does. */
|
|
321
|
+
.error {
|
|
322
|
+
color: ${reference('--ui-color-danger')};
|
|
323
|
+
font-size: ${reference('--ui-text-supporting')};
|
|
324
|
+
}
|
|
145
325
|
|
|
146
326
|
/* Forced colors replaces every author colour with one from the user's palette, so
|
|
147
327
|
the accent that says *selected* becomes the same Canvas as the surface that says
|
|
@@ -150,135 +330,186 @@ export class UiRadio extends LitElement {
|
|
|
150
330
|
selected state names Highlight and the difference survives; the mark keeps
|
|
151
331
|
working untouched, because a mask has no colour to force.
|
|
152
332
|
|
|
153
|
-
Opacity is not a colour and is not forced, so the disabled control would still
|
|
154
|
-
|
|
333
|
+
Opacity is not a colour and is not forced, so the disabled control would still be
|
|
334
|
+
half-transparent against a palette chosen for contrast. GrayText is what that
|
|
155
335
|
mode has for *unavailable*, and it is a colour rather than a veil. */
|
|
156
336
|
@media (forced-colors: active) {
|
|
157
|
-
|
|
337
|
+
input:checked {
|
|
158
338
|
background-color: Highlight;
|
|
159
339
|
border-color: Highlight;
|
|
160
340
|
}
|
|
161
341
|
|
|
162
|
-
|
|
342
|
+
input:disabled {
|
|
163
343
|
border-color: GrayText;
|
|
164
344
|
opacity: 1;
|
|
165
345
|
}
|
|
166
346
|
}
|
|
167
347
|
`; }
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
* justified Zag. Neither was needed: native radios sharing a `name` **are** that pattern,
|
|
180
|
-
* and this suite measures it here rather than trusting it, wrappers and all.
|
|
181
|
-
*
|
|
182
|
-
* That is the test `ROADMAP.md` states, applied: Zag arrives where the platform has **no
|
|
183
|
-
* element** for the pattern, not merely where the pattern has state. `ui-menu` is where
|
|
184
|
-
* that question is open; a radio group is not.
|
|
185
|
-
*
|
|
186
|
-
* **What is left for this element is what the platform leaves out**: the layout, the
|
|
187
|
-
* `role` that makes a set of radios a group to a screen reader, and the group-level name,
|
|
188
|
-
* description and error state — which {@link UiField} wires onto *this* element rather
|
|
189
|
-
* than onto an option, because a `<label for>` naming one radio names one option and
|
|
190
|
-
* leaves the group anonymous.
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* ```html
|
|
194
|
-
* <ui-field>
|
|
195
|
-
* <label slot="label">Plan</label>
|
|
196
|
-
* <ui-radio-group>
|
|
197
|
-
* <label><ui-radio><input type="radio" name="plan" value="free" /></ui-radio> Free</label>
|
|
198
|
-
* <label><ui-radio><input type="radio" name="plan" value="pro" /></ui-radio> Pro</label>
|
|
199
|
-
* </ui-radio-group>
|
|
200
|
-
* </ui-field>
|
|
201
|
-
* ```
|
|
202
|
-
*/
|
|
203
|
-
export class UiRadioGroup extends LitElement {
|
|
204
|
-
constructor() {
|
|
205
|
-
super(...arguments);
|
|
206
|
-
/**
|
|
207
|
-
* Which way the options are laid out.
|
|
208
|
-
*
|
|
209
|
-
* A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
|
|
210
|
-
* gives beside its own: the browser this suite runs in does not implement
|
|
211
|
-
* auto-accessors, and the module would fail to parse.
|
|
212
|
-
*/
|
|
213
|
-
this.orientation = 'vertical';
|
|
214
|
-
}
|
|
215
|
-
static { this.styles = css `
|
|
216
|
-
:host {
|
|
217
|
-
display: flex;
|
|
218
|
-
flex-direction: column;
|
|
219
|
-
gap: calc(${reference('--ui-space')} / 2);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/* Laid out by the attribute rather than by the host's own CSS, so the drawing and
|
|
223
|
-
the announcement cannot disagree: orientation sets both this rule and
|
|
224
|
-
aria-orientation, and a host who reached for flex-direction instead would
|
|
225
|
-
change one of the two. */
|
|
226
|
-
:host([orientation='horizontal']) {
|
|
227
|
-
flex-direction: row;
|
|
228
|
-
flex-wrap: wrap;
|
|
229
|
-
column-gap: calc(${reference('--ui-space')} * 2);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/* The error, painted for the whole set by retargeting the boundary token over this
|
|
233
|
-
subtree — which is the override surface the token layer already publishes,
|
|
234
|
-
pointed at the group's own descendants instead of at a page.
|
|
235
|
-
|
|
236
|
-
A custom property inherits through a shadow boundary and a selector does not, so
|
|
237
|
-
this is what reaches a control two elements down that this sheet cannot name:
|
|
238
|
-
::slotted() stops at the group's own children, :host-context() is not
|
|
239
|
-
cross-engine, and :host(:has(...)) is invalid in this engine. The value still
|
|
240
|
-
arrives as a token reference, so a host who retunes danger retunes this too.
|
|
241
|
-
|
|
242
|
-
aria-invalid is not written here: ui-field sets it as part of the wiring it
|
|
243
|
-
already owns, so the message under the group and the boundary around its options
|
|
244
|
-
cannot disagree about whether there is an error. */
|
|
245
|
-
:host([aria-invalid='true']) {
|
|
246
|
-
--ui-color-border: ${reference('--ui-color-danger')};
|
|
247
|
-
}
|
|
248
|
-
`; }
|
|
348
|
+
static { this.formAssociated = true; }
|
|
349
|
+
/**
|
|
350
|
+
* Focus is delegated, so `focus()` and `reportValidity()` reach a control — the host is
|
|
351
|
+
* not a focusable element. Measured with the group: the delegation lands on the first
|
|
352
|
+
* option rather than making all of them tab stops, because the roving one is still the
|
|
353
|
+
* platform's.
|
|
354
|
+
*/
|
|
355
|
+
static { this.shadowRootOptions = {
|
|
356
|
+
...LitElement.shadowRootOptions,
|
|
357
|
+
delegatesFocus: true,
|
|
358
|
+
}; }
|
|
249
359
|
static { this.properties = {
|
|
360
|
+
label: { type: String, reflect: true },
|
|
361
|
+
help: { type: String, reflect: true },
|
|
362
|
+
error: { type: String, reflect: true },
|
|
363
|
+
name: { type: String, reflect: true },
|
|
364
|
+
// Stryker disable next-line ObjectLiteral: `{}` is what Lit's default converter
|
|
365
|
+
// already does for a string — `type` only switches the converter for Boolean,
|
|
366
|
+
// Number, Object and Array — and `reflect` defaults to false either way. The
|
|
367
|
+
// declaration is written out to say which of the two `value` is, not to change it.
|
|
368
|
+
value: { type: String },
|
|
250
369
|
orientation: { type: String, reflect: true },
|
|
370
|
+
required: { type: Boolean, reflect: true },
|
|
371
|
+
disabled: { type: Boolean, reflect: true },
|
|
251
372
|
}; }
|
|
373
|
+
#internals;
|
|
374
|
+
#redraw;
|
|
375
|
+
connectedCallback() {
|
|
376
|
+
super.connectedCallback();
|
|
377
|
+
// The half a slot cannot report: a property write on a choice. It reaches here by
|
|
378
|
+
// bubbling, because the choices are this element's own light-DOM children.
|
|
379
|
+
//
|
|
380
|
+
// There is deliberately no removal in `disconnectedCallback`. A listener an element
|
|
381
|
+
// holds on *itself* cannot outlive it, and `#redraw` is one stable reference, so
|
|
382
|
+
// re-adding it on a reconnect is discarded rather than doubled.
|
|
383
|
+
this.addEventListener(announcement, this.#redraw);
|
|
384
|
+
}
|
|
385
|
+
/** Every choice a host declared, in the order they were written. */
|
|
386
|
+
#choices() {
|
|
387
|
+
return [...this.querySelectorAll('ui-radio')];
|
|
388
|
+
}
|
|
252
389
|
/**
|
|
253
|
-
*
|
|
390
|
+
* The choice in force: the host's `value` where it names one, the declared default
|
|
391
|
+
* otherwise.
|
|
254
392
|
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
* radio
|
|
258
|
-
*
|
|
259
|
-
|
|
393
|
+
* The fallback is the platform's own rule read off the declarations — the first choice
|
|
394
|
+
* marked `checked`, and failing that nothing at all, which is what a native set with no
|
|
395
|
+
* checked radio in it does. A radio group differs from a `<select>` exactly here: it
|
|
396
|
+
* has an empty state and a drop-down does not.
|
|
397
|
+
*/
|
|
398
|
+
#chosen() {
|
|
399
|
+
const choices = this.#choices();
|
|
400
|
+
if (choices.some((choice) => choice.value === this.value)) {
|
|
401
|
+
return this.value;
|
|
402
|
+
}
|
|
403
|
+
return choices.find((choice) => choice.checked)?.value ?? '';
|
|
404
|
+
}
|
|
405
|
+
/** The validity, taken from a control that computed it. */
|
|
406
|
+
#publish(control) {
|
|
407
|
+
if (this.error !== '') {
|
|
408
|
+
this.#internals.setValidity({ customError: true }, this.error, control);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
this.#internals.setValidity(control.validity, control.validationMessage, control);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* The value and the validity, which move together here or disagree anywhere.
|
|
260
415
|
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
416
|
+
* The first control is the one asked, and it is the one the browser would focus when a
|
|
417
|
+
* form reports an invalid group. Iterated rather than asserted, for the reason
|
|
418
|
+
* `src/input.ts` gives beside the same shape: a null branch here is unreachable, which
|
|
419
|
+
* is a coverage hole and an immortal mutant at once.
|
|
263
420
|
*/
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this
|
|
421
|
+
updated() {
|
|
422
|
+
this.#internals.setFormValue(this.#chosen());
|
|
423
|
+
for (const control of this.renderRoot.querySelectorAll('input')) {
|
|
424
|
+
this.#publish(control);
|
|
425
|
+
return;
|
|
268
426
|
}
|
|
427
|
+
// A group with no choices declared has nothing to validate against and nothing to
|
|
428
|
+
// submit, which is a state a host can reach by writing an empty element.
|
|
429
|
+
this.#internals.setValidity({});
|
|
430
|
+
}
|
|
431
|
+
/** A choice made by hand, mirrored back and re-dispatched. */
|
|
432
|
+
#changed;
|
|
433
|
+
/** A form reset, which returns to the choice the declarations name. */
|
|
434
|
+
formResetCallback() {
|
|
435
|
+
this.value = '';
|
|
436
|
+
}
|
|
437
|
+
/** A `<fieldset disabled>` above this element, which reaches it and nothing below. */
|
|
438
|
+
formDisabledCallback(disabled) {
|
|
439
|
+
this.disabled = disabled;
|
|
440
|
+
}
|
|
441
|
+
/** Restoring after a back-navigation, where the browser hands the value back. */
|
|
442
|
+
formStateRestoreCallback(state) {
|
|
443
|
+
this.value = state ?? '';
|
|
444
|
+
}
|
|
445
|
+
/** The form this element participates in, for a host that needs it. */
|
|
446
|
+
get form() {
|
|
447
|
+
return this.#internals.form;
|
|
448
|
+
}
|
|
449
|
+
/** Whether the group currently satisfies its constraints. */
|
|
450
|
+
get validity() {
|
|
451
|
+
return this.#internals.validity;
|
|
452
|
+
}
|
|
453
|
+
/** The message a form would report for it, empty while the group is valid. */
|
|
454
|
+
get validationMessage() {
|
|
455
|
+
return this.#internals.validationMessage;
|
|
456
|
+
}
|
|
457
|
+
/** The ids describing the group, in the order a reader needs them. */
|
|
458
|
+
#described() {
|
|
459
|
+
const ids = [this.error === '' ? '' : 'error', this.help === '' ? '' : 'help'].filter((id) => id !== '');
|
|
460
|
+
return ids.length === 0 ? nothing : ids.join(' ');
|
|
269
461
|
}
|
|
270
462
|
/**
|
|
271
|
-
*
|
|
463
|
+
* One declaration, as the label and control the platform needs.
|
|
272
464
|
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
465
|
+
* **`.checked` is a property binding and `?checked` would be wrong**, which is not a
|
|
466
|
+
* style choice: on a radio the content attribute is `defaultChecked`, so once the
|
|
467
|
+
* control has been interacted with — or once anything has set the property — the
|
|
468
|
+
* attribute stops driving the live state. Measured, as a reset that redrew the
|
|
469
|
+
* declared default and left the control on the choice the reader had made.
|
|
276
470
|
*/
|
|
277
|
-
|
|
278
|
-
|
|
471
|
+
#draw(choice, chosen) {
|
|
472
|
+
return html `<label class="option" part="option">
|
|
473
|
+
<input
|
|
474
|
+
type="radio"
|
|
475
|
+
part="control"
|
|
476
|
+
name=${grouping}
|
|
477
|
+
value=${choice.value}
|
|
478
|
+
.checked=${choice.value === chosen}
|
|
479
|
+
?disabled=${this.disabled || choice.disabled}
|
|
480
|
+
?required=${this.required}
|
|
481
|
+
@change=${this.#changed}
|
|
482
|
+
/>
|
|
483
|
+
<span part="option-label">${choice.textContent}</span>
|
|
484
|
+
</label>`;
|
|
279
485
|
}
|
|
280
486
|
render() {
|
|
281
|
-
|
|
487
|
+
const chosen = this.#chosen();
|
|
488
|
+
return html `
|
|
489
|
+
<div class="stack" part="stack">
|
|
490
|
+
<span class="label" id="label" part="label">${this.label}</span>
|
|
491
|
+
<div
|
|
492
|
+
class="options"
|
|
493
|
+
part="options"
|
|
494
|
+
role="radiogroup"
|
|
495
|
+
aria-labelledby="label"
|
|
496
|
+
aria-orientation=${this.orientation}
|
|
497
|
+
aria-invalid=${this.error === '' ? nothing : 'true'}
|
|
498
|
+
aria-describedby=${this.#described()}
|
|
499
|
+
>
|
|
500
|
+
${this.#choices().map((choice) => this.#draw(choice, chosen))}
|
|
501
|
+
</div>
|
|
502
|
+
${this.help === ''
|
|
503
|
+
? nothing
|
|
504
|
+
: html `<span class="help" id="help" part="help">${this.help}</span>`}
|
|
505
|
+
${this.error === ''
|
|
506
|
+
? nothing
|
|
507
|
+
: html `<span class="error" id="error" part="error">${this.error}</span>`}
|
|
508
|
+
<!-- The structural half, which slotchange reports and no observer has to.
|
|
509
|
+
What it holds draws nothing: a declaration is display: none. -->
|
|
510
|
+
<slot @slotchange=${this.#redraw}></slot>
|
|
511
|
+
</div>
|
|
512
|
+
`;
|
|
282
513
|
}
|
|
283
514
|
}
|
|
284
515
|
// Stryker disable next-line StringLiteral: the registration runs once, at import, inside
|
package/dist/radio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio.js","sourceRoot":"","sources":["../src/radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"radio.js","sourceRoot":"","sources":["../src/radio.ts"],"names":[],"mappings":"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"}
|