@rak200/ui 0.2.6 → 0.2.8

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 CHANGED
@@ -30,13 +30,20 @@ npm install @rak200/ui
30
30
 
31
31
  <ui-field>
32
32
  <label slot="label">Amount</label>
33
- <input type="number" />
33
+ <ui-input><input type="number" name="amount" /></ui-input>
34
34
  <span slot="help">In BRL, two decimals.</span>
35
35
  </ui-field>
36
36
 
37
37
  <ui-button>Save</ui-button>
38
38
  <ui-button variant="secondary">Cancel</ui-button>
39
39
  <ui-button disabled>Unavailable</ui-button>
40
+
41
+ <ui-dialog>
42
+ <h2 slot="title">Delete account</h2>
43
+ <p>This cannot be undone.</p>
44
+ <ui-button slot="actions" variant="secondary">Cancel</ui-button>
45
+ <ui-button slot="actions">Delete</ui-button>
46
+ </ui-dialog>
40
47
  ```
41
48
 
42
49
  Every visual decision is a CSS custom property, so a host restyles the kit without forking it:
@@ -64,8 +71,8 @@ components; `docs/` is what describes them.
64
71
 
65
72
  ## Status
66
73
 
67
- **v0.** Two components — `<ui-button>` and `<ui-field>` — and the token layer under them, built to
68
- the ecosystem's full quality bar rather than sketched: type-checked at the strictest available
74
+ **v0.** Five components — `<ui-button>`, `<ui-field>`, `<ui-dialog>`, `<ui-input>` and
75
+ `<ui-textarea>` — and the token layer under them, built to the ecosystem's full quality bar rather than sketched: type-checked at the strictest available
69
76
  setting, formatted, tested in a real browser and **asserted against axe** for WCAG A/AA, 100%
70
77
  coverage and **100% mutation score**, scanned, and every public symbol documented. The v0 surface in
71
78
  RFC 0016 grows from here — see [ROADMAP.md](ROADMAP.md).
@@ -0,0 +1,71 @@
1
+ import { LitElement, type TemplateResult } from 'lit';
2
+ /**
3
+ * A modal dialog.
4
+ *
5
+ * It delegates to a real `<dialog>` and opens it with `showModal()`, which is what makes
6
+ * the top layer, the inert background, the focus trap, <kbd>Esc</kbd> and — the half
7
+ * everyone forgets — **focus returning to whatever opened it** the platform's job rather
8
+ * than this file's. What is written here is the part the platform leaves out: the scroll
9
+ * lock, the accessible name across the shadow boundary, and an exit that can be seen.
10
+ *
11
+ * **This is where RFC 0016 expected Zag to arrive, and it does not.** Zag was adopted for
12
+ * dismissable layers and focus trapping, and its dialog machine implements both over a
13
+ * `<div>` — which means giving up the top layer and taking a JS focus trap in exchange for
14
+ * one the user agent enforces. *The platform owns what the platform is good at* is the
15
+ * older rule and the stronger one here. Zag arrives with the first component the platform
16
+ * gives nothing for; `ARCHITECTURE.md` carries that decision for a consumer, and
17
+ * `ROADMAP.md` names the component.
18
+ *
19
+ * @example
20
+ * ```html
21
+ * <ui-dialog>
22
+ * <h2 slot="title">Delete account</h2>
23
+ * <p>This cannot be undone.</p>
24
+ * <ui-button slot="actions" variant="secondary">Cancel</ui-button>
25
+ * <ui-button slot="actions">Delete</ui-button>
26
+ * </ui-dialog>
27
+ * ```
28
+ */
29
+ export declare class UiDialog extends LitElement {
30
+ #private;
31
+ static readonly styles: import("lit").CSSResult;
32
+ static readonly properties: {
33
+ open: {
34
+ type: BooleanConstructor;
35
+ reflect: boolean;
36
+ };
37
+ };
38
+ /**
39
+ * Whether the dialog is showing.
40
+ *
41
+ * **The single source of truth, and the only one.** {@link show} and {@link close} set
42
+ * it, <kbd>Esc</kbd> sets it, and the component reacts to it — so an attribute, a
43
+ * property and a method are three ways of saying one thing rather than three paths
44
+ * that can disagree. Reflected, so a host stylesheet can select on it.
45
+ *
46
+ * A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
47
+ * states beside its own.
48
+ */
49
+ open: boolean;
50
+ constructor();
51
+ connectedCallback(): void;
52
+ disconnectedCallback(): void;
53
+ firstUpdated(): void;
54
+ updated(): void;
55
+ render(): TemplateResult;
56
+ /**
57
+ * Opens the dialog.
58
+ *
59
+ * Sugar over `open = true` rather than a second way in — a method that opened by its
60
+ * own route would be a state the attribute does not describe.
61
+ */
62
+ show(): void;
63
+ /** Closes the dialog, running the exit. Sugar over `open = false`, for the same reason. */
64
+ close(): void;
65
+ }
66
+ declare global {
67
+ interface HTMLElementTagNameMap {
68
+ 'ui-dialog': UiDialog;
69
+ }
70
+ }
71
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../src/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAoGjE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,QAAS,SAAQ,UAAU;;IACpC,gBAAyB,MAAM,0BAwG7B;IAEF,gBAAyB,UAAU;;;;;MAEjC;IAEF;;;;;;;;;;OAUG;IACH,IAAI,UAAS;;IAyCJ,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;IAU5B,YAAY,IAAI,IAAI;IAIpB,OAAO,IAAI,IAAI;IAiBf,MAAM,IAAI,cAAc;IAIjC;;;;;OAKG;IACH,IAAI,IAAI,IAAI;IAIZ,2FAA2F;IAC3F,KAAK,IAAI,IAAI;CA0FhB;AAQD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,WAAW,EAAE,QAAQ,CAAC;KACzB;CACJ"}
package/dist/dialog.js ADDED
@@ -0,0 +1,406 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ import { reference } from './reference.js';
3
+ /** The class the exit is carried by, on the dialog for exactly as long as the exit runs. */
4
+ const closing = 'closing';
5
+ /** How many dialogs are holding the page still. */
6
+ let locks = 0;
7
+ /**
8
+ * The inline values the first hold displaced, given back by the last release.
9
+ *
10
+ * No initial value, deliberately: nothing reads it before {@link hold} writes it, and an
11
+ * initialiser here would be a value no test could ever observe.
12
+ */
13
+ let displaced;
14
+ /**
15
+ * Holds the page still behind a modal, and gives it back when the last one leaves.
16
+ *
17
+ * `<dialog>` gives a modal the top layer, an inert background, a focus trap and focus
18
+ * restoration. It does not stop the page behind it scrolling, and that is the one piece of
19
+ * modality left to write.
20
+ *
21
+ * **The gutter is reserved rather than the scrollbar measured**, which is the difference
22
+ * between a rule and an arithmetic nothing can check. `overflow: hidden` takes the
23
+ * scrollbar away and the page jumps left by its width; the usual answer adds that width
24
+ * back as padding — and the browser this suite runs in has overlay scrollbars, so the
25
+ * width is `0`, every sign error in that arithmetic passes, and the check is theatre.
26
+ * `scrollbar-gutter: stable` asks the browser to keep the space it was already using,
27
+ * with no number to get wrong.
28
+ *
29
+ * Counted rather than flagged, because a dialog opening a dialog is ordinary — a confirm
30
+ * over a form — and the second one closing must not give the page back while the first is
31
+ * still up.
32
+ */
33
+ function hold() {
34
+ locks += 1;
35
+ if (locks > 1) {
36
+ return;
37
+ }
38
+ const root = document.documentElement;
39
+ displaced = {
40
+ overflow: root.style.overflow,
41
+ gutter: root.style.getPropertyValue('scrollbar-gutter'),
42
+ };
43
+ // Only where there was a scrollbar to lose. `stable` on a page that never had one
44
+ // reserves space that was not there, which is the same layout shift in the other
45
+ // direction.
46
+ if (root.scrollHeight > root.clientHeight) {
47
+ root.style.setProperty('scrollbar-gutter', 'stable');
48
+ }
49
+ root.style.overflow = 'hidden';
50
+ }
51
+ /** Gives the page back, once the last dialog has closed. */
52
+ function release() {
53
+ locks -= 1;
54
+ if (locks > 0) {
55
+ return;
56
+ }
57
+ const root = document.documentElement;
58
+ // What the host had, not what this module would have chosen. A page that sets its own
59
+ // `overflow` or reserves its own gutter gets it back rather than being cleared.
60
+ root.style.overflow = displaced.overflow;
61
+ root.style.setProperty('scrollbar-gutter', displaced.gutter);
62
+ }
63
+ /** One of the dialog's slots — named, or the default one when the name is empty. */
64
+ function slot(name = '') {
65
+ return Object.assign(document.createElement('slot'), { name });
66
+ }
67
+ /**
68
+ * The shadow content, which is static all the way down: a `<dialog>` and three slots.
69
+ *
70
+ * Built here rather than queried out of the render root, and the reason is the floors
71
+ * this repository holds. `renderRoot.querySelector('dialog')` is typed `| null`, and that
72
+ * null is unreachable in a component that renders the element unconditionally — an
73
+ * unreachable branch is one no test can cover and no mutant can be killed on, against a
74
+ * coverage floor of 100 and a mutation floor of 100. The honest way to satisfy both is to
75
+ * not create the branch.
76
+ */
77
+ function build() {
78
+ const dialog = document.createElement('dialog');
79
+ dialog.setAttribute('part', 'dialog');
80
+ dialog.append(slot('title'), slot(), slot('actions'));
81
+ return dialog;
82
+ }
83
+ /**
84
+ * A modal dialog.
85
+ *
86
+ * It delegates to a real `<dialog>` and opens it with `showModal()`, which is what makes
87
+ * the top layer, the inert background, the focus trap, <kbd>Esc</kbd> and — the half
88
+ * everyone forgets — **focus returning to whatever opened it** the platform's job rather
89
+ * than this file's. What is written here is the part the platform leaves out: the scroll
90
+ * lock, the accessible name across the shadow boundary, and an exit that can be seen.
91
+ *
92
+ * **This is where RFC 0016 expected Zag to arrive, and it does not.** Zag was adopted for
93
+ * dismissable layers and focus trapping, and its dialog machine implements both over a
94
+ * `<div>` — which means giving up the top layer and taking a JS focus trap in exchange for
95
+ * one the user agent enforces. *The platform owns what the platform is good at* is the
96
+ * older rule and the stronger one here. Zag arrives with the first component the platform
97
+ * gives nothing for; `ARCHITECTURE.md` carries that decision for a consumer, and
98
+ * `ROADMAP.md` names the component.
99
+ *
100
+ * @example
101
+ * ```html
102
+ * <ui-dialog>
103
+ * <h2 slot="title">Delete account</h2>
104
+ * <p>This cannot be undone.</p>
105
+ * <ui-button slot="actions" variant="secondary">Cancel</ui-button>
106
+ * <ui-button slot="actions">Delete</ui-button>
107
+ * </ui-dialog>
108
+ * ```
109
+ */
110
+ export class UiDialog extends LitElement {
111
+ static { this.styles = css `
112
+ /* The dialog is promoted to the top layer, so the host must take no space of its
113
+ own: a <ui-dialog> laid out in the flow would leave a gap on every page where
114
+ the dialog is closed. */
115
+ :host {
116
+ display: contents;
117
+ }
118
+
119
+ /* display is named under [open] and nowhere else, and that is not a style
120
+ choice. The user agent closes a dialog with display: none; a rule here that
121
+ names display unconditionally outranks it, and the closed dialog simply stays
122
+ on the page. The attribute is still there through the exit below, which is what
123
+ lets the transition run at all. */
124
+ dialog[open] {
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: calc(${reference('--ui-space')} * 2);
128
+ }
129
+
130
+ dialog {
131
+ /* The user agent's own 2px border and white background are decisions this
132
+ component owns. Nothing is raised underneath: elevation arrives with the
133
+ component that needs to read as lifted, and a panel over a scrim is already
134
+ separated from the page by the scrim. */
135
+ border: none;
136
+ border-radius: ${reference('--ui-radius')};
137
+ padding: calc(${reference('--ui-space')} * 3);
138
+ background: ${reference('--ui-color-surface')};
139
+ color: ${reference('--ui-color-text')};
140
+ font-family: ${reference('--ui-font')};
141
+
142
+ /* A cap is a layout decision rather than a visual one, so it is not a token
143
+ and opens no category. A host that wants another size reaches
144
+ ::part(dialog), which is the surface for what the token set does not name.
145
+
146
+ border-box, and the mutation floor is what found this: a dialog is
147
+ content-box by default, so the cap applied to the content alone and the
148
+ padding was added on top of it — the panel then ran wider than the cap by
149
+ six spacing steps, and the clearance the calc promises was not the
150
+ clearance it left. */
151
+ box-sizing: border-box;
152
+ max-inline-size: min(32rem, calc(100% - ${reference('--ui-space')} * 8));
153
+
154
+ opacity: 1;
155
+ transition: opacity ${reference('--ui-duration-state')}
156
+ ${reference('--ui-easing-enter')};
157
+ }
158
+
159
+ /* Where the entrance comes *from*. Without it there is nothing to transition out
160
+ of: the dialog goes from display: none to laid out in a single frame, and a
161
+ transition needs a before-change style that an unrendered element does not
162
+ have. */
163
+ @starting-style {
164
+ dialog[open] {
165
+ opacity: 0;
166
+ }
167
+ }
168
+
169
+ dialog::backdrop {
170
+ background: ${reference('--ui-color-scrim')};
171
+ opacity: 1;
172
+ transition: opacity ${reference('--ui-duration-state')}
173
+ ${reference('--ui-easing-enter')};
174
+ }
175
+
176
+ @starting-style {
177
+ dialog[open]::backdrop {
178
+ opacity: 0;
179
+ }
180
+ }
181
+
182
+ /* The exit, driven from the class rather than from [open] going away: the
183
+ platform removes a closed dialog in the same frame it is closed, so an exit
184
+ waiting on the attribute would never be seen. Both halves are declared together
185
+ because moving together is what lets #exit await one of them. */
186
+ dialog.closing,
187
+ dialog.closing::backdrop {
188
+ opacity: 0;
189
+ transition-timing-function: ${reference('--ui-easing-exit')};
190
+ }
191
+
192
+ /* showModal() focuses the dialog itself when nothing inside it can take focus,
193
+ and a focused thing with no ring is the most common way a component stops being
194
+ usable by keyboard. */
195
+ dialog:focus-visible {
196
+ outline: 2px solid ${reference('--ui-color-focus')};
197
+ outline-offset: 2px;
198
+ }
199
+
200
+ /* A heading's own margin would add to the padding and to the gap above it. This
201
+ resets the user agent's default and yields to a decision: for slotted content
202
+ the outer tree wins, so a host's own rule for the element still beats this. */
203
+ slot[name='title']::slotted(*) {
204
+ margin: 0;
205
+ }
206
+
207
+ /* A slot is display: contents until something says otherwise, which is what
208
+ makes this the line that turns three buttons into a row. */
209
+ slot[name='actions'] {
210
+ display: flex;
211
+ flex-wrap: wrap;
212
+ justify-content: flex-end;
213
+ gap: ${reference('--ui-space')};
214
+ }
215
+ `; }
216
+ static { this.properties = {
217
+ open: { type: Boolean, reflect: true },
218
+ }; }
219
+ /** The real `<dialog>` this component is a shell around. */
220
+ #dialog;
221
+ /**
222
+ * Watches the light DOM for a title that changed without the element changing.
223
+ *
224
+ * Built here rather than on connection so it is never absent: a disconnect that has to
225
+ * ask whether the observer exists is a branch no test can reach.
226
+ */
227
+ #observer;
228
+ constructor() {
229
+ super();
230
+ /**
231
+ * Whether the dialog is showing.
232
+ *
233
+ * **The single source of truth, and the only one.** {@link show} and {@link close} set
234
+ * it, <kbd>Esc</kbd> sets it, and the component reacts to it — so an attribute, a
235
+ * property and a method are three ways of saying one thing rather than three paths
236
+ * that can disagree. Reflected, so a host stylesheet can select on it.
237
+ *
238
+ * A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
239
+ * states beside its own.
240
+ */
241
+ this.open = false;
242
+ /** The real `<dialog>` this component is a shell around. */
243
+ this.#dialog = build();
244
+ /**
245
+ * Watches the light DOM for a title that changed without the element changing.
246
+ *
247
+ * Built here rather than on connection so it is never absent: a disconnect that has to
248
+ * ask whether the observer exists is a branch no test can reach.
249
+ */
250
+ this.#observer = new MutationObserver(() => {
251
+ this.#label();
252
+ });
253
+ this.#dialog.addEventListener('cancel', (event) => {
254
+ // Esc reaches a modal as `cancel`, and letting it through closes in the same
255
+ // frame — the exit this component just gained would never be seen. Prevented
256
+ // and routed back through `open`, so however a close was asked for it leaves
257
+ // by the one door.
258
+ event.preventDefault();
259
+ this.open = false;
260
+ });
261
+ this.#dialog.addEventListener('close', () => {
262
+ // The announcement only. The platform fires `close` as a *queued task* rather
263
+ // than synchronously, so this runs a turn after the dialog actually closed —
264
+ // which is fine for telling a host, and was wrong for giving the page back:
265
+ // the lock outlived the dialog by a task, and a second dialog opening inside
266
+ // that window counted against a page nobody was holding any more. Measured on
267
+ // Node 22 in CI and not on Node 24, which is what a timing dependency looks
268
+ // like from the outside. {@link UiDialog.#shut} owns the release instead, at
269
+ // both of the synchronous points where this element closes the dialog.
270
+ this.open = false;
271
+ this.dispatchEvent(new Event('ui-close', { bubbles: true, composed: true }));
272
+ });
273
+ }
274
+ connectedCallback() {
275
+ super.connectedCallback();
276
+ // The title may be replaced, or its text rewritten in place without any element
277
+ // changing, which is what a host's re-render looks like from here — so
278
+ // characterData matters as much as childList, and both can happen below a wrapper.
279
+ this.#observer.observe(this, { childList: true, characterData: true, subtree: true });
280
+ }
281
+ disconnectedCallback() {
282
+ this.#observer.disconnect();
283
+ // Removing an open dialog takes it out of the top layer and announces nothing, so
284
+ // the page would stay held by a dialog that is no longer anywhere.
285
+ this.#shut();
286
+ super.disconnectedCallback();
287
+ }
288
+ firstUpdated() {
289
+ this.#label();
290
+ }
291
+ updated() {
292
+ // Compared against the platform's own state rather than against Lit's changed
293
+ // properties, and it has to be: on the first update Lit reports every initialised
294
+ // property as changed, so a dialog that has never been open would run the closing
295
+ // path and announce a close that never happened. It is also what makes a re-render
296
+ // for any other reason a no-op instead of a second `showModal()`, which throws.
297
+ if (this.open === this.#dialog.open) {
298
+ return;
299
+ }
300
+ if (this.open) {
301
+ this.#enter();
302
+ }
303
+ else {
304
+ void this.#exit();
305
+ }
306
+ }
307
+ render() {
308
+ return html `${this.#dialog}`;
309
+ }
310
+ /**
311
+ * Opens the dialog.
312
+ *
313
+ * Sugar over `open = true` rather than a second way in — a method that opened by its
314
+ * own route would be a state the attribute does not describe.
315
+ */
316
+ show() {
317
+ this.open = true;
318
+ }
319
+ /** Closes the dialog, running the exit. Sugar over `open = false`, for the same reason. */
320
+ close() {
321
+ this.open = false;
322
+ }
323
+ /**
324
+ * Puts the dialog in the top layer.
325
+ *
326
+ * `showModal()` rather than the `open` attribute, and the distance between the two is
327
+ * the whole component: the attribute opens a dialog *in the flow*, with no top layer,
328
+ * no inert background, no focus trap and no focus restoration. It is the one way to
329
+ * get something that looks modal and traps nobody — which is why this host's `open` is
330
+ * never bound onto the inner element's.
331
+ */
332
+ #enter() {
333
+ this.#dialog.showModal();
334
+ hold();
335
+ }
336
+ /** Runs the exit, and closes once it has finished. */
337
+ async #exit() {
338
+ const dialog = this.#dialog;
339
+ dialog.classList.add(closing);
340
+ // `finished` rejects when an animation is cancelled, which is exactly what
341
+ // reopening mid-exit does — so what this waits for is settlement rather than
342
+ // fulfilment. `getAnimations` flushes the pending style change before it answers,
343
+ // so the transition the line above started is already in the list.
344
+ //
345
+ // The backdrop is not in that list: a pseudo-element needs `subtree: true`,
346
+ // measured. It does not need to be — the panel and the scrim move the same
347
+ // property over the same duration token, so they start together and end together,
348
+ // and awaiting one is awaiting both. `tests/dialog.test.ts` asserts that shared
349
+ // duration rather than leaving it to this paragraph.
350
+ await Promise.allSettled(dialog.getAnimations().map((animation) => animation.finished));
351
+ dialog.classList.remove(closing);
352
+ // Reopened while the exit was running. The dialog never left the top layer, so
353
+ // there is nothing to close, and taking the class back off is the whole of the
354
+ // way back.
355
+ if (this.open) {
356
+ return;
357
+ }
358
+ this.#shut();
359
+ }
360
+ /**
361
+ * Closes the dialog and gives the page back, in that order and in one place.
362
+ *
363
+ * Both ways out run through here — the exit above and the disconnect below — so the
364
+ * release is paired with the close rather than with the event the close will later
365
+ * fire. The guard is the platform's own state rather than a flag this element keeps:
366
+ * a dialog that is not open is holding nothing, so calling this twice gives the page
367
+ * back once.
368
+ */
369
+ #shut() {
370
+ if (!this.#dialog.open) {
371
+ return;
372
+ }
373
+ this.#dialog.close();
374
+ release();
375
+ }
376
+ /**
377
+ * Names the dialog after its own title.
378
+ *
379
+ * **A copy of the text rather than a reference to the element, and that is forced.**
380
+ * APG names a modal with `aria-labelledby` pointing at its heading, and an IDREF does
381
+ * not cross a shadow boundary — so a `<dialog>` in this shadow root cannot point at a
382
+ * heading in the host's tree. `ui-field` answers the same constraint by leaving every
383
+ * associated element in the light DOM; a dialog cannot, because the element that has
384
+ * to reach the top layer is the one this component renders. What does cross is a
385
+ * string, so the name is copied and the observer above keeps the copy honest.
386
+ */
387
+ #label() {
388
+ const title = this.querySelector(':scope > [slot="title"]');
389
+ const label = title?.textContent.trim() ?? '';
390
+ // A dialog with no title has no accessible name, and a blank `aria-label` would be
391
+ // worse than none: a screen reader announces "dialog" either way, and an attribute
392
+ // that is present and empty is the shape that makes an audit read as handled.
393
+ if (label === '') {
394
+ this.#dialog.removeAttribute('aria-label');
395
+ }
396
+ else {
397
+ this.#dialog.setAttribute('aria-label', label);
398
+ }
399
+ }
400
+ }
401
+ // Stryker disable next-line StringLiteral: the registration runs once, at import, inside
402
+ // the warm process Stryker switches mutants in — so by the time a mutant on this line is
403
+ // active the element is already defined under the original name, and no test can observe
404
+ // the change. Outside the runner's reach, not an equivalent mutant.
405
+ customElements.define('ui-dialog', UiDialog);
406
+ //# sourceMappingURL=dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.js","sourceRoot":"","sources":["../src/dialog.ts"],"names":[],"mappings":"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"}
package/dist/field.d.ts CHANGED
@@ -13,6 +13,10 @@ import { LitElement, type TemplateResult } from 'lit';
13
13
  * where the association is the platform's job — and this element only generates the ids
14
14
  * and points them at each other.
15
15
  *
16
+ * **The control may sit below a wrapper**, and the same constraint is why: `<ui-input>` is
17
+ * a box around a control that had to stay in the light DOM, so this element looks through
18
+ * it. See {@link UiField.#control}.
19
+ *
16
20
  * @example
17
21
  * ```html
18
22
  * <ui-field>
@@ -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;;;;;;;;;;;;;;;;;;;;;;;GAuBG;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;CAyFpC;AAQD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,UAAU,EAAE,OAAO,CAAC;KACvB;CACJ"}
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;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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;CA2GpC;AAQD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,UAAU,EAAE,OAAO,CAAC;KACvB;CACJ"}
package/dist/field.js CHANGED
@@ -16,6 +16,10 @@ let sequence = 0;
16
16
  * where the association is the platform's job — and this element only generates the ids
17
17
  * and points them at each other.
18
18
  *
19
+ * **The control may sit below a wrapper**, and the same constraint is why: `<ui-input>` is
20
+ * a box around a control that had to stay in the light DOM, so this element looks through
21
+ * it. See {@link UiField.#control}.
22
+ *
19
23
  * @example
20
24
  * ```html
21
25
  * <ui-field>
@@ -92,6 +96,22 @@ export class UiField extends LitElement {
92
96
  const found = this.querySelector(selector);
93
97
  return found instanceof HTMLElement ? found : undefined;
94
98
  }
99
+ /**
100
+ * The control this field is about, which a wrapper may stand in front of.
101
+ *
102
+ * `<ui-input>` is such a wrapper, and it is one because the control has to stay in the
103
+ * light DOM for the IDREFs below to resolve at all — so the box that styles it can
104
+ * only ever sit around it, never instead of it. The label points at the control and
105
+ * never at the box: `<label for>` aimed at a custom element labels nothing, which axe
106
+ * reports at critical impact.
107
+ *
108
+ * A control written as a direct child, which is every call site that predates the
109
+ * wrapper, matches nothing to descend into and is returned as it is.
110
+ */
111
+ #control() {
112
+ const slotted = this.#slotted(null);
113
+ return slotted?.querySelector('input, textarea, select') ?? slotted;
114
+ }
95
115
  /**
96
116
  * Points the label, the help and the error at the control.
97
117
  *
@@ -99,7 +119,7 @@ export class UiField extends LitElement {
99
119
  * this element cannot see.
100
120
  */
101
121
  #associate() {
102
- const control = this.#slotted(null);
122
+ const control = this.#control();
103
123
  if (control === undefined) {
104
124
  return;
105
125
  }
package/dist/field.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"field.js","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { UiButton, type ButtonVariant } from './button.js';
2
+ export { UiDialog } from './dialog.js';
2
3
  export { UiField } from './field.js';
4
+ export { UiInput, UiTextarea } from './input.js';
3
5
  export { tokens, derivedTokens, defaults, formulas, darkScheme, tokenStyleSheet, type Token, type DerivedToken, } from './tokens.js';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EACH,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,KAAK,KAAK,EACV,KAAK,YAAY,GACpB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACH,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,KAAK,KAAK,EACV,KAAK,YAAY,GACpB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export { UiButton } from './button.js';
2
+ export { UiDialog } from './dialog.js';
2
3
  export { UiField } from './field.js';
4
+ export { UiInput, UiTextarea } from './input.js';
3
5
  export { tokens, derivedTokens, defaults, formulas, darkScheme, tokenStyleSheet, } from './tokens.js';
4
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EACH,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,GAGlB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACH,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,GAGlB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { LitElement, type CSSResult, type TemplateResult } from 'lit';
2
+ /**
3
+ * A styled native form control.
4
+ *
5
+ * The control is the host's own, slotted in rather than rendered here, and that is the
6
+ * single decision this component is made of. {@link UiInput} and {@link UiTextarea} carry
7
+ * the appearance; the element inside carries everything else.
8
+ */
9
+ declare class UiControl extends LitElement {
10
+ render(): TemplateResult;
11
+ }
12
+ /**
13
+ * A text input, styled by the token layer rather than replaced.
14
+ *
15
+ * **The `<input>` is yours.** You write it, you set its attributes, and it stays in the
16
+ * light DOM — so `type`, `required`, `readonly`, `name` and `value` are the platform's
17
+ * business and there is no pass-through layer to fall out of step with them. It reaches a
18
+ * form submit for the same reason: a native control inside a `<form>` participates
19
+ * because it is a native control inside a `<form>`, with no `ElementInternals` and no
20
+ * value mirroring. That was the open question on the issue, and the answer is that the
21
+ * shape the accessibility rule forced happens to be the shape that answers it.
22
+ *
23
+ * Composes with {@link UiField}, which finds the control through this wrapper and wires
24
+ * the label, the help, the error and `aria-invalid` to it.
25
+ *
26
+ * @example
27
+ * ```html
28
+ * <ui-field>
29
+ * <label slot="label">Amount</label>
30
+ * <ui-input><input type="number" name="amount" /></ui-input>
31
+ * <span slot="help">In BRL, two decimals.</span>
32
+ * </ui-field>
33
+ * ```
34
+ */
35
+ export declare class UiInput extends UiControl {
36
+ static readonly styles: CSSResult;
37
+ }
38
+ /**
39
+ * A multi-line text control, styled by the token layer rather than replaced.
40
+ *
41
+ * Everything {@link UiInput} says applies. What differs is two rules: a height to start
42
+ * at, and resizing left on the vertical axis — a control that cannot grow is one people
43
+ * fight, and one that grows sideways breaks the layout around it.
44
+ *
45
+ * @example
46
+ * ```html
47
+ * <ui-field>
48
+ * <label slot="label">Notes</label>
49
+ * <ui-textarea><textarea name="notes" rows="4"></textarea></ui-textarea>
50
+ * </ui-field>
51
+ * ```
52
+ */
53
+ export declare class UiTextarea extends UiControl {
54
+ static readonly styles: CSSResult[];
55
+ }
56
+ declare global {
57
+ interface HTMLElementTagNameMap {
58
+ 'ui-input': UiInput;
59
+ 'ui-textarea': UiTextarea;
60
+ }
61
+ }
62
+ export {};
63
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAyFjF;;;;;;GAMG;AACH,cAAM,SAAU,SAAQ,UAAU;IACrB,MAAM,IAAI,cAAc;CAGpC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,OAAQ,SAAQ,SAAS;IAClC,gBAAyB,MAAM,EAAE,SAAS,CAAW;CACxD;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACrC,gBAAyB,MAAM,EAAE,SAAS,EAAE,CAQ1C;CACL;AAWD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,UAAU,EAAE,OAAO,CAAC;QACpB,aAAa,EAAE,UAAU,CAAC;KAC7B;CACJ"}
package/dist/input.js ADDED
@@ -0,0 +1,159 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ import { reference } from './reference.js';
3
+ /**
4
+ * What a styled native control looks like, which both elements share.
5
+ *
6
+ * One stylesheet naming both `input` and `textarea` rather than one per element: the two
7
+ * differ in what they accept and in one rule about resizing, and duplicating the whole
8
+ * box to express that would be two copies of a contract with nothing comparing them.
9
+ */
10
+ const control = css `
11
+ :host {
12
+ display: block;
13
+ }
14
+
15
+ /* Everything below reaches a control the *host* wrote, through ::slotted. That is the
16
+ whole shape of this component and it is forced rather than preferred — the control
17
+ has to stay in the light DOM, where the label and the description ui-field writes
18
+ can resolve against it. Measured, in this suite's own instrument: the same control
19
+ rendered into a shadow root is an axe label violation at critical impact, and the
20
+ aria-describedby pointing at it dangles.
21
+
22
+ ::slotted reaches a pseudo-element of a slotted node too, which is what makes the
23
+ placeholder rule below possible — measured, because the selector looks like it
24
+ should not work. */
25
+ ::slotted(input),
26
+ ::slotted(textarea) {
27
+ box-sizing: border-box;
28
+ inline-size: 100%;
29
+ font: inherit;
30
+ font-family: ${reference('--ui-font')};
31
+ color: ${reference('--ui-color-text')};
32
+ background: ${reference('--ui-color-surface')};
33
+ border: 1px solid ${reference('--ui-color-border')};
34
+ border-radius: ${reference('--ui-radius')};
35
+ padding: ${reference('--ui-space')};
36
+ /* Only the boundary moves. The focus ring is deliberately not in this list, for
37
+ the reason src/button.ts gives beside its own: delaying the affordance that
38
+ says *this is where you are* is the opposite of what it exists to do. */
39
+ transition: border-color ${reference('--ui-duration-state')}
40
+ ${reference('--ui-easing-state')};
41
+ }
42
+
43
+ ::slotted(input)::placeholder,
44
+ ::slotted(textarea)::placeholder {
45
+ color: ${reference('--ui-color-text-muted')};
46
+ /* Firefox lowers a placeholder's opacity by default, which would take the colour
47
+ below the 4.5:1 it was chosen to clear — a contrast floor undone by a rule
48
+ nobody wrote. */
49
+ opacity: 1;
50
+ }
51
+
52
+ /* The boundary completes the mix it already started: the resting border is the
53
+ surface half way to the text, and hovering finishes the trip. A hover colour of its
54
+ own would be a fourth name for a point on a line the token layer already draws.
55
+
56
+ The guards are measured rather than assumed, the same way ui-button's are: a
57
+ disabled control still matches :hover, and a readonly one accepts a pointer it will
58
+ do nothing with. */
59
+ ::slotted(input:hover:not(:disabled):not([readonly])),
60
+ ::slotted(textarea:hover:not(:disabled):not([readonly])) {
61
+ border-color: ${reference('--ui-color-text')};
62
+ }
63
+
64
+ /* A visible focus ring is not decoration: removing it is the single most common way a
65
+ component stops being usable by keyboard. */
66
+ ::slotted(input:focus-visible),
67
+ ::slotted(textarea:focus-visible) {
68
+ outline: 2px solid ${reference('--ui-color-focus')};
69
+ outline-offset: 2px;
70
+ }
71
+
72
+ ::slotted(input:disabled),
73
+ ::slotted(textarea:disabled) {
74
+ cursor: not-allowed;
75
+ opacity: 0.5;
76
+ }
77
+
78
+ /* The error state is not this component's to decide, and it does not decide it:
79
+ ui-field sets aria-invalid on the control as part of the wiring it already
80
+ owns, and this rule reads it. So the message under the field and the box around it
81
+ cannot disagree about whether there is an error — there is one source and it is the
82
+ one a screen reader is already using. */
83
+ ::slotted(input[aria-invalid='true']),
84
+ ::slotted(textarea[aria-invalid='true']) {
85
+ border-color: ${reference('--ui-color-danger')};
86
+ }
87
+ `;
88
+ /**
89
+ * A styled native form control.
90
+ *
91
+ * The control is the host's own, slotted in rather than rendered here, and that is the
92
+ * single decision this component is made of. {@link UiInput} and {@link UiTextarea} carry
93
+ * the appearance; the element inside carries everything else.
94
+ */
95
+ class UiControl extends LitElement {
96
+ render() {
97
+ return html `<slot></slot>`;
98
+ }
99
+ }
100
+ /**
101
+ * A text input, styled by the token layer rather than replaced.
102
+ *
103
+ * **The `<input>` is yours.** You write it, you set its attributes, and it stays in the
104
+ * light DOM — so `type`, `required`, `readonly`, `name` and `value` are the platform's
105
+ * business and there is no pass-through layer to fall out of step with them. It reaches a
106
+ * form submit for the same reason: a native control inside a `<form>` participates
107
+ * because it is a native control inside a `<form>`, with no `ElementInternals` and no
108
+ * value mirroring. That was the open question on the issue, and the answer is that the
109
+ * shape the accessibility rule forced happens to be the shape that answers it.
110
+ *
111
+ * Composes with {@link UiField}, which finds the control through this wrapper and wires
112
+ * the label, the help, the error and `aria-invalid` to it.
113
+ *
114
+ * @example
115
+ * ```html
116
+ * <ui-field>
117
+ * <label slot="label">Amount</label>
118
+ * <ui-input><input type="number" name="amount" /></ui-input>
119
+ * <span slot="help">In BRL, two decimals.</span>
120
+ * </ui-field>
121
+ * ```
122
+ */
123
+ export class UiInput extends UiControl {
124
+ static { this.styles = control; }
125
+ }
126
+ /**
127
+ * A multi-line text control, styled by the token layer rather than replaced.
128
+ *
129
+ * Everything {@link UiInput} says applies. What differs is two rules: a height to start
130
+ * at, and resizing left on the vertical axis — a control that cannot grow is one people
131
+ * fight, and one that grows sideways breaks the layout around it.
132
+ *
133
+ * @example
134
+ * ```html
135
+ * <ui-field>
136
+ * <label slot="label">Notes</label>
137
+ * <ui-textarea><textarea name="notes" rows="4"></textarea></ui-textarea>
138
+ * </ui-field>
139
+ * ```
140
+ */
141
+ export class UiTextarea extends UiControl {
142
+ static { this.styles = [
143
+ control,
144
+ css `
145
+ ::slotted(textarea) {
146
+ min-block-size: calc(${reference('--ui-space')} * 10);
147
+ resize: vertical;
148
+ }
149
+ `,
150
+ ]; }
151
+ }
152
+ // Stryker disable next-line StringLiteral: the registration runs once, at import, inside
153
+ // the warm process Stryker switches mutants in — so by the time a mutant on this line is
154
+ // active the element is already defined under the original name, and no test can observe
155
+ // the change. Outside the runner's reach, not an equivalent mutant.
156
+ customElements.define('ui-input', UiInput);
157
+ // Stryker disable next-line StringLiteral: the same, for the same reason.
158
+ customElements.define('ui-textarea', UiTextarea);
159
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuC,MAAM,KAAK,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,OAAO,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;uBAoBI,SAAS,CAAC,WAAW,CAAC;iBAC5B,SAAS,CAAC,iBAAiB,CAAC;sBACvB,SAAS,CAAC,oBAAoB,CAAC;4BACzB,SAAS,CAAC,mBAAmB,CAAC;yBACjC,SAAS,CAAC,aAAa,CAAC;mBAC9B,SAAS,CAAC,YAAY,CAAC;;;;mCAIP,SAAS,CAAC,qBAAqB,CAAC;cACrD,SAAS,CAAC,mBAAmB,CAAC;;;;;iBAK3B,SAAS,CAAC,uBAAuB,CAAC;;;;;;;;;;;;;;;;wBAgB3B,SAAS,CAAC,iBAAiB,CAAC;;;;;;;6BAOvB,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;;;;;;;;;wBAiBlC,SAAS,CAAC,mBAAmB,CAAC;;CAErD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,SAAU,SAAQ,UAAU;IACrB,MAAM;QACX,OAAO,IAAI,CAAA,eAAe,CAAC;IAC/B,CAAC;CACJ;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,OAAQ,SAAQ,SAAS;aACT,WAAM,GAAc,OAAO,CAAC;;AAGzD;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,UAAW,SAAQ,SAAS;aACZ,WAAM,GAAgB;QAC3C,OAAO;QACP,GAAG,CAAA;;uCAE4B,SAAS,CAAC,YAAY,CAAC;;;SAGrD;KACJ,CAAC;;AAGN,yFAAyF;AACzF,yFAAyF;AACzF,yFAAyF;AACzF,oEAAoE;AACpE,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAE3C,0EAA0E;AAC1E,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC"}
package/dist/tokens.d.ts CHANGED
@@ -31,7 +31,7 @@
31
31
  * it does break is code that **enumerates** the set, an exhaustive `Record<Token, string>`
32
32
  * above all. The supported shape is the partial map, which is what a theme is anyway.
33
33
  */
34
- export declare const tokens: readonly ["--ui-color-accent", "--ui-color-accent-contrast", "--ui-color-surface", "--ui-color-text", "--ui-color-focus", "--ui-color-danger", "--ui-radius", "--ui-space", "--ui-font", "--ui-duration-100", "--ui-easing-state"];
34
+ export declare const tokens: readonly ["--ui-color-accent", "--ui-color-accent-contrast", "--ui-color-surface", "--ui-color-text", "--ui-color-focus", "--ui-color-danger", "--ui-color-scrim", "--ui-radius", "--ui-space", "--ui-font", "--ui-duration-100", "--ui-easing-state", "--ui-easing-enter", "--ui-easing-exit"];
35
35
  /** A CSS custom property this package defines and gives a default. */
36
36
  export type Token = (typeof tokens)[number];
37
37
  /**
@@ -44,7 +44,7 @@ export type Token = (typeof tokens)[number];
44
44
  * what it buys is an override surface a host can hold in their head: change the accent and
45
45
  * the hover and pressed colours follow, rather than being one more name each.
46
46
  */
47
- export declare const derivedTokens: readonly ["--ui-duration-state", "--ui-color-hover", "--ui-color-pressed", "--ui-color-accent-hover", "--ui-color-accent-pressed"];
47
+ export declare const derivedTokens: readonly ["--ui-duration-state", "--ui-color-border", "--ui-color-text-muted", "--ui-color-hover", "--ui-color-pressed", "--ui-color-accent-hover", "--ui-color-accent-pressed"];
48
48
  /** A CSS custom property this package computes rather than declares. */
49
49
  export type DerivedToken = (typeof derivedTokens)[number];
50
50
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,MAAM,oOAqBT,CAAC;AAEX,sEAAsE;AACtE,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,oIAShB,CAAC;AAEX,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CA6BpD,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAY3D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAW/D,CAAC;AAKF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAsBxC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,MAAM,iSA6CT,CAAC;AAEX,sEAAsE;AACtE,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,kLAmBhB,CAAC;AAEX,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAuCpD,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAoB3D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAW/D,CAAC;AAKF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAsBxC"}
package/dist/tokens.js CHANGED
@@ -38,6 +38,19 @@ export const tokens = [
38
38
  '--ui-color-text',
39
39
  '--ui-color-focus',
40
40
  '--ui-color-danger',
41
+ // The dim behind a modal, and a *ground* rather than a derivation even though every
42
+ // other neutral here is derived. A derived neutral mixes toward the text, which is
43
+ // what makes one formula right in both schemes — and it is exactly wrong for this
44
+ // one: on a dark page the text is the light pole, so the mix would *lighten* the
45
+ // page behind the dialog instead of dimming it. A scrim dims in both schemes, so it
46
+ // carries a literal and appears in neither `darkScheme` nor `formulas`.
47
+ //
48
+ // **This departs from RFC 0002**, whose survey of the queued components answered
49
+ // *text at an alpha* for this role. That table asks whether a role needs a new hue,
50
+ // and the answer to that question is still no — what it could not weigh, with no
51
+ // overlay yet written to judge against, is which pole the mix should run toward. The
52
+ // proposal says so in the same breath: read as a judgement, not a measurement.
53
+ '--ui-color-scrim',
41
54
  '--ui-radius',
42
55
  '--ui-space',
43
56
  '--ui-font',
@@ -52,6 +65,17 @@ export const tokens = [
52
65
  // ground and a component reads it directly.
53
66
  '--ui-duration-100',
54
67
  '--ui-easing-state',
68
+ // The pair `--ui-easing-state` promised, arriving with the overlay that has an enter
69
+ // and an exit to name — `ui-dialog`. A state change reverses mid-flight and wants a
70
+ // symmetric curve; an overlay does not reverse, it arrives and it leaves, and the two
71
+ // directions are asked to feel different on purpose.
72
+ //
73
+ // No duration steps come with them. The scale is ordinal with gaps precisely so a step
74
+ // can be inserted when something needs one, and the dialog needs no duration the state
75
+ // step does not already give it — inventing `--ui-duration-200` before a component
76
+ // judges it against something is the claim ROADMAP.md declines to make about Zag.
77
+ '--ui-easing-enter',
78
+ '--ui-easing-exit',
55
79
  ];
56
80
  /**
57
81
  * The roles computed from the grounds rather than declared beside them.
@@ -65,6 +89,16 @@ export const tokens = [
65
89
  */
66
90
  export const derivedTokens = [
67
91
  '--ui-duration-state',
92
+ // The boundary of a control, and the text inside one that is not a value yet. Both
93
+ // arrive with `ui-input`, and both are the same mix at different strengths — which is
94
+ // what makes them one category rather than two: a border and a placeholder are the
95
+ // surface travelling toward the text, stopped at the contrast each one owes.
96
+ //
97
+ // The percentages are read off a measurement rather than chosen. A control's boundary
98
+ // is what identifies the component, so WCAG 1.4.11 asks 3:1 against the surface, and
99
+ // a placeholder is text, so 1.4.3 asks 4.5:1. `tests/tokens.test.ts` holds both.
100
+ '--ui-color-border',
101
+ '--ui-color-text-muted',
68
102
  // `hover` matches the pseudo-class it answers to; `pressed` deliberately does not —
69
103
  // `--ui-color-active` would read as *the active item* as readily as *the pressed
70
104
  // control*, and the role this implements was named `accent hover / pressed`.
@@ -94,6 +128,11 @@ export const defaults = {
94
128
  // because no axe rule does.
95
129
  '--ui-color-focus': '#b45309',
96
130
  '--ui-color-danger': '#b91c1c',
131
+ // Half black. Enough to push the page behind a modal out of the reading order for the
132
+ // eye as well as for the accessibility tree, and not so much that the context a modal
133
+ // is *about* stops being visible. The alpha is the whole point, so this is the one
134
+ // default that is not an opaque hex.
135
+ '--ui-color-scrim': 'rgb(0 0 0 / 0.5)',
97
136
  '--ui-radius': '0.375rem',
98
137
  '--ui-space': '0.5rem',
99
138
  '--ui-font': 'system-ui, sans-serif',
@@ -108,6 +147,11 @@ export const defaults = {
108
147
  // for. `enter` will want an ease-out and `exit` an ease-in, and they arrive with the
109
148
  // overlays that have an enter and an exit to name.
110
149
  '--ui-easing-state': 'ease-in-out',
150
+ // Fast out of the gate and settling at the end, which is what makes an arriving
151
+ // overlay feel like it was already on its way. The exit is its mirror: slow to let go
152
+ // and quick to be gone, so a dismissal does not linger over a decision already made.
153
+ '--ui-easing-enter': 'ease-out',
154
+ '--ui-easing-exit': 'ease-in',
111
155
  };
112
156
  /**
113
157
  * A ground as it is written inside a formula: the name, with its own default behind it.
@@ -164,6 +208,14 @@ export const formulas = {
164
208
  '--ui-color-pressed': mix('--ui-color-text', 14, '--ui-color-surface'),
165
209
  '--ui-color-accent-hover': mix('--ui-color-text', 12, '--ui-color-accent'),
166
210
  '--ui-color-accent-pressed': mix('--ui-color-text', 22, '--ui-color-accent'),
211
+ // 3.39:1 on the light surface and 3.96:1 on the dark one, against a floor of 3. The
212
+ // step below clears neither — 45% is 2.94 in light, which is what a value chosen by
213
+ // eye would have shipped.
214
+ '--ui-color-border': mix('--ui-color-text', 50, '--ui-color-surface'),
215
+ // 5.24:1 and 6.07:1, against a floor of 4.5. Not the 60% that first cleared it: that
216
+ // is 4.52 in light, a rounding error from failing, and a default nobody could then
217
+ // retune without breaking a floor they were not thinking about.
218
+ '--ui-color-text-muted': mix('--ui-color-text', 65, '--ui-color-surface'),
167
219
  };
168
220
  /**
169
221
  * The grounds whose value differs when the page is rendered dark.
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rak200/ui",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Host-agnostic custom-element UI components for the rak200 ecosystem",
5
5
  "license": "MIT",
6
6
  "author": "rak200 <rak.ricardo@windowslive.com>",