@rak200/ui 0.2.4 → 0.2.6
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 +5 -5
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +50 -8
- package/dist/button.js.map +1 -1
- package/dist/field.d.ts.map +1 -1
- package/dist/field.js +5 -4
- 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/reference.d.ts +41 -0
- package/dist/reference.d.ts.map +1 -0
- package/dist/reference.js +47 -0
- package/dist/reference.js.map +1 -0
- package/dist/tokens.d.ts +77 -5
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +148 -5
- package/dist/tokens.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,8 +64,8 @@ components; `docs/` is what describes them.
|
|
|
64
64
|
|
|
65
65
|
## Status
|
|
66
66
|
|
|
67
|
-
**v0.**
|
|
68
|
-
sketched: type-checked at the strictest available
|
|
69
|
-
and **asserted against axe** for WCAG A/AA, 100%
|
|
70
|
-
every public symbol documented. The v0
|
|
71
|
-
|
|
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
|
|
69
|
+
setting, formatted, tested in a real browser and **asserted against axe** for WCAG A/AA, 100%
|
|
70
|
+
coverage and **100% mutation score**, scanned, and every public symbol documented. The v0 surface in
|
|
71
|
+
RFC 0016 grows from here — see [ROADMAP.md](ROADMAP.md).
|
package/dist/button.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../src/button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../src/button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAGjE,+CAA+C;AAC/C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,qBAAa,QAAS,SAAQ,UAAU;IACpC,gBAAyB,MAAM,0BA6E7B;IAEF,gBAAyB,UAAU;;;;;;;;;MAGjC;IAEF;;;;;;;;OAQG;IACH,OAAO,EAAE,aAAa,CAAa;IAEnC,kFAAkF;IAClF,QAAQ,UAAS;IAER,MAAM,IAAI,cAAc;CAOpC;AAQD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,WAAW,EAAE,QAAQ,CAAC;KACzB;CACJ"}
|
package/dist/button.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement, css, html } from 'lit';
|
|
2
|
+
import { reference } from './reference.js';
|
|
2
3
|
/**
|
|
3
4
|
* A button.
|
|
4
5
|
*
|
|
@@ -36,11 +37,25 @@ export class UiButton extends LitElement {
|
|
|
36
37
|
|
|
37
38
|
button {
|
|
38
39
|
font: inherit;
|
|
39
|
-
font-family:
|
|
40
|
+
font-family: ${reference('--ui-font')};
|
|
40
41
|
border: 1px solid transparent;
|
|
41
|
-
border-radius:
|
|
42
|
-
padding:
|
|
42
|
+
border-radius: ${reference('--ui-radius')};
|
|
43
|
+
padding: ${reference('--ui-space')} calc(${reference('--ui-space')} * 2);
|
|
43
44
|
cursor: pointer;
|
|
45
|
+
/* Measured in WebKit and in Chromium under a phone viewport: the platform
|
|
46
|
+
paints its own wash on tap — 40% black in WebKit, the Android blue in
|
|
47
|
+
Chromium — over whatever the component decided, so the pressed colour below
|
|
48
|
+
arrives underneath it and is not what a finger sees.
|
|
49
|
+
|
|
50
|
+
Removing it is only correct because the pressed state exists. Until it did,
|
|
51
|
+
this wash was the ONLY response a touch got, and turning it off would have
|
|
52
|
+
left a button that answers a finger with nothing. */
|
|
53
|
+
-webkit-tap-highlight-color: transparent;
|
|
54
|
+
/* Only the colour moves. The focus ring is deliberately not in this list:
|
|
55
|
+
delaying the affordance that says *this is where you are* is the opposite of
|
|
56
|
+
what it exists to do. */
|
|
57
|
+
transition: background-color ${reference('--ui-duration-state')}
|
|
58
|
+
${reference('--ui-easing-state')};
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
button:disabled {
|
|
@@ -51,20 +66,47 @@ export class UiButton extends LitElement {
|
|
|
51
66
|
/* A visible focus ring is not decoration: removing it is the single most common
|
|
52
67
|
way a component stops being usable by keyboard. */
|
|
53
68
|
button:focus-visible {
|
|
54
|
-
outline: 2px solid
|
|
69
|
+
outline: 2px solid ${reference('--ui-color-focus')};
|
|
55
70
|
outline-offset: 2px;
|
|
56
71
|
}
|
|
57
72
|
|
|
58
73
|
button.primary {
|
|
59
|
-
background:
|
|
60
|
-
color:
|
|
74
|
+
background: ${reference('--ui-color-accent')};
|
|
75
|
+
color: ${reference('--ui-color-accent-contrast')};
|
|
61
76
|
}
|
|
62
77
|
|
|
63
78
|
button.secondary {
|
|
64
|
-
background:
|
|
65
|
-
color:
|
|
79
|
+
background: ${reference('--ui-color-surface')};
|
|
80
|
+
color: ${reference('--ui-color-text')};
|
|
66
81
|
border-color: currentcolor;
|
|
67
82
|
}
|
|
83
|
+
|
|
84
|
+
/* The :not(:disabled) guard is measured rather than assumed: a disabled button
|
|
85
|
+
still matches :hover and :active, so without it the button would light up under a
|
|
86
|
+
pointer that cannot activate it. Ordering does not substitute for the guard — both
|
|
87
|
+
rules below outrank the resting one on specificity whatever their position. */
|
|
88
|
+
button.primary:not(:disabled):hover {
|
|
89
|
+
background: ${reference('--ui-color-accent-hover')};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
button.secondary:not(:disabled):hover {
|
|
93
|
+
background: ${reference('--ui-color-hover')};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* A press is over in about 100ms, so an entering transition of 150ms would land
|
|
97
|
+
after the finger has left and the pressed colour would never be seen. Zero here
|
|
98
|
+
rather than a second token: it is a fact about how long a click lasts, not a
|
|
99
|
+
decision a host would want to retune. And the pressed state is never the only
|
|
100
|
+
feedback a component gives — activating by Enter produces no :active at all. */
|
|
101
|
+
button.primary:not(:disabled):active {
|
|
102
|
+
background: ${reference('--ui-color-accent-pressed')};
|
|
103
|
+
transition-duration: 0s;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
button.secondary:not(:disabled):active {
|
|
107
|
+
background: ${reference('--ui-color-pressed')};
|
|
108
|
+
transition-duration: 0s;
|
|
109
|
+
}
|
|
68
110
|
`; }
|
|
69
111
|
static { this.properties = {
|
|
70
112
|
variant: { type: String, reflect: true },
|
package/dist/button.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sourceRoot":"","sources":["../src/button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../src/button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAK3C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,QAAS,SAAQ,UAAU;IAAxC;;QAqFI;;;;;;;;WAQG;QACH,YAAO,GAAkB,SAAS,CAAC;QAEnC,kFAAkF;QAClF,aAAQ,GAAG,KAAK,CAAC;IASrB,CAAC;aAzG4B,WAAM,GAAG,GAAG,CAAA;;;;;;;2BAOd,SAAS,CAAC,WAAW,CAAC;;6BAEpB,SAAS,CAAC,aAAa,CAAC;uBAC9B,SAAS,CAAC,YAAY,CAAC,SAAS,SAAS,CAAC,YAAY,CAAC;;;;;;;;;;;;;;2CAcnC,SAAS,CAAC,qBAAqB,CAAC;kBACzD,SAAS,CAAC,mBAAmB,CAAC;;;;;;;;;;;iCAWf,SAAS,CAAC,kBAAkB,CAAC;;;;;0BAKpC,SAAS,CAAC,mBAAmB,CAAC;qBACnC,SAAS,CAAC,4BAA4B,CAAC;;;;0BAIlC,SAAS,CAAC,oBAAoB,CAAC;qBACpC,SAAS,CAAC,iBAAiB,CAAC;;;;;;;;;0BASvB,SAAS,CAAC,yBAAyB,CAAC;;;;0BAIpC,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;0BAS7B,SAAS,CAAC,2BAA2B,CAAC;;;;;0BAKtC,SAAS,CAAC,oBAAoB,CAAC;;;KAGpD,AA7E8B,CA6E7B;aAEuB,eAAU,GAAG;QAClC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACxC,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;KAC7C,AAHkC,CAGjC;IAgBO,MAAM;QACX,OAAO,IAAI,CAAA;4BACS,IAAI,CAAC,OAAO,cAAc,IAAI,CAAC,QAAQ;;;SAG1D,CAAC;IACN,CAAC;;AAGL,kFAAkF;AAClF,wFAAwF;AACxF,yFAAyF;AACzF,4EAA4E;AAC5E,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC"}
|
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;
|
|
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"}
|
package/dist/field.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement, css, html } from 'lit';
|
|
2
|
+
import { reference } from './reference.js';
|
|
2
3
|
/** Distinguishes one field's generated ids from another's. */
|
|
3
4
|
let sequence = 0;
|
|
4
5
|
/**
|
|
@@ -29,24 +30,24 @@ export class UiField extends LitElement {
|
|
|
29
30
|
static { this.styles = css `
|
|
30
31
|
:host {
|
|
31
32
|
display: block;
|
|
32
|
-
font-family:
|
|
33
|
+
font-family: ${reference('--ui-font')};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
.stack {
|
|
36
37
|
display: flex;
|
|
37
38
|
flex-direction: column;
|
|
38
|
-
gap: calc(
|
|
39
|
+
gap: calc(${reference('--ui-space')} / 2);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
slot[name='help']::slotted(*) {
|
|
42
|
-
color:
|
|
43
|
+
color: ${reference('--ui-color-text')};
|
|
43
44
|
font-size: 0.875em;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/* Colour is not the only cue — the error text says what is wrong, and
|
|
47
48
|
aria-invalid marks the control regardless of styling. */
|
|
48
49
|
slot[name='error']::slotted(*) {
|
|
49
|
-
color:
|
|
50
|
+
color: ${reference('--ui-color-danger')};
|
|
50
51
|
font-size: 0.875em;
|
|
51
52
|
}
|
|
52
53
|
`; }
|
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;
|
|
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,4 @@
|
|
|
1
1
|
export { UiButton, type ButtonVariant } from './button.js';
|
|
2
2
|
export { UiField } from './field.js';
|
|
3
|
-
export { tokens, defaults, darkScheme, tokenStyleSheet, type Token } from './tokens.js';
|
|
3
|
+
export { tokens, derivedTokens, defaults, formulas, darkScheme, tokenStyleSheet, type Token, type DerivedToken, } from './tokens.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { UiButton } from './button.js';
|
|
2
2
|
export { UiField } from './field.js';
|
|
3
|
-
export { tokens, defaults, darkScheme, tokenStyleSheet } from './tokens.js';
|
|
3
|
+
export { tokens, derivedTokens, defaults, formulas, darkScheme, tokenStyleSheet, } from './tokens.js';
|
|
4
4
|
//# 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,
|
|
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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a component writes a token, and the only way one should.
|
|
3
|
+
*
|
|
4
|
+
* Every `var(--ui-*, fallback)` used to carry a hand-copied literal — thirteen of them
|
|
5
|
+
* across two components, all agreeing, none compared to anything. A fallback only shows
|
|
6
|
+
* when the `:root` block is absent, so the first copy to disagree would have done it
|
|
7
|
+
* invisibly. Generated from `defaults` and `formulas`, a fallback stops being a value that
|
|
8
|
+
* *can* drift and becomes one that cannot.
|
|
9
|
+
*
|
|
10
|
+
* **For a derived name the fallback is the formula, and that placement is the whole of
|
|
11
|
+
* RFC 0002's item 1.** A derivation resolves where it is *used*, against the grounds in
|
|
12
|
+
* force at that element — so a component in a dark subtree, or under a second theme, mixes
|
|
13
|
+
* against that subtree's grounds without either being restated. Declared beside the
|
|
14
|
+
* grounds instead, it would resolve once at `:root` and freeze; `src/tokens.ts` carries
|
|
15
|
+
* that measurement beside {@link formulas}.
|
|
16
|
+
*
|
|
17
|
+
* **This module exists because `src/tokens.ts` imports no Lit, and must not start.** That
|
|
18
|
+
* module is what a native shell reads, and a target that is not the web cannot take a
|
|
19
|
+
* dependency on a web renderer to find out what a colour is. `unsafeCSS` is what forces
|
|
20
|
+
* the split, and it is safe here in the only sense that matters: every argument it ever
|
|
21
|
+
* receives is this package's own literal, from a record the compiler keeps exhaustive.
|
|
22
|
+
*
|
|
23
|
+
* Internal — it is not re-exported from `src/index.ts`, because what a consumer overrides
|
|
24
|
+
* is the token, never the reference to it.
|
|
25
|
+
*/
|
|
26
|
+
import { type CSSResult } from 'lit';
|
|
27
|
+
import { type DerivedToken, type Token } from './tokens.js';
|
|
28
|
+
/**
|
|
29
|
+
* A token as a component reads it: the custom property, with the package's own value
|
|
30
|
+
* behind it.
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* css`button { border-radius: ${reference('--ui-radius')}; }`;
|
|
34
|
+
* // → button { border-radius: var(--ui-radius, 0.375rem); }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @param name - A ground or derived token. The fallback is that token's default where it
|
|
38
|
+
* has one and its formula where it does not.
|
|
39
|
+
*/
|
|
40
|
+
export declare function reference(name: Token | DerivedToken): CSSResult;
|
|
41
|
+
//# sourceMappingURL=reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAqC,KAAK,YAAY,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAO/F;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,KAAK,GAAG,YAAY,GAAG,SAAS,CAE/D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a component writes a token, and the only way one should.
|
|
3
|
+
*
|
|
4
|
+
* Every `var(--ui-*, fallback)` used to carry a hand-copied literal — thirteen of them
|
|
5
|
+
* across two components, all agreeing, none compared to anything. A fallback only shows
|
|
6
|
+
* when the `:root` block is absent, so the first copy to disagree would have done it
|
|
7
|
+
* invisibly. Generated from `defaults` and `formulas`, a fallback stops being a value that
|
|
8
|
+
* *can* drift and becomes one that cannot.
|
|
9
|
+
*
|
|
10
|
+
* **For a derived name the fallback is the formula, and that placement is the whole of
|
|
11
|
+
* RFC 0002's item 1.** A derivation resolves where it is *used*, against the grounds in
|
|
12
|
+
* force at that element — so a component in a dark subtree, or under a second theme, mixes
|
|
13
|
+
* against that subtree's grounds without either being restated. Declared beside the
|
|
14
|
+
* grounds instead, it would resolve once at `:root` and freeze; `src/tokens.ts` carries
|
|
15
|
+
* that measurement beside {@link formulas}.
|
|
16
|
+
*
|
|
17
|
+
* **This module exists because `src/tokens.ts` imports no Lit, and must not start.** That
|
|
18
|
+
* module is what a native shell reads, and a target that is not the web cannot take a
|
|
19
|
+
* dependency on a web renderer to find out what a colour is. `unsafeCSS` is what forces
|
|
20
|
+
* the split, and it is safe here in the only sense that matters: every argument it ever
|
|
21
|
+
* receives is this package's own literal, from a record the compiler keeps exhaustive.
|
|
22
|
+
*
|
|
23
|
+
* Internal — it is not re-exported from `src/index.ts`, because what a consumer overrides
|
|
24
|
+
* is the token, never the reference to it.
|
|
25
|
+
*/
|
|
26
|
+
import { unsafeCSS } from 'lit';
|
|
27
|
+
import { defaults, derivedTokens, formulas } from './tokens.js';
|
|
28
|
+
/** Whether a name is computed rather than declared, which decides where its fallback comes from. */
|
|
29
|
+
function isDerived(name) {
|
|
30
|
+
return derivedTokens.includes(name);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A token as a component reads it: the custom property, with the package's own value
|
|
34
|
+
* behind it.
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* css`button { border-radius: ${reference('--ui-radius')}; }`;
|
|
38
|
+
* // → button { border-radius: var(--ui-radius, 0.375rem); }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @param name - A ground or derived token. The fallback is that token's default where it
|
|
42
|
+
* has one and its formula where it does not.
|
|
43
|
+
*/
|
|
44
|
+
export function reference(name) {
|
|
45
|
+
return unsafeCSS(`var(${name}, ${isDerived(name) ? formulas[name] : defaults[name]})`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,SAAS,EAAkB,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAiC,MAAM,aAAa,CAAC;AAE/F,oGAAoG;AACpG,SAAS,SAAS,CAAC,IAA0B;IACzC,OAAQ,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,IAA0B;IAChD,OAAO,SAAS,CAAC,OAAO,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3F,CAAC"}
|
package/dist/tokens.d.ts
CHANGED
|
@@ -8,18 +8,79 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Every token is a CSS custom property under `--ui-`, so a host overrides one by
|
|
10
10
|
* setting it anywhere above the component — no build step, no theme object, no fork.
|
|
11
|
+
*
|
|
12
|
+
* **The exported set splits in two, and the split is the shape of RFC 0002.** {@link tokens}
|
|
13
|
+
* are *ground*: they carry a literal default and are emitted at `:root`.
|
|
14
|
+
* {@link derivedTokens} are computed from the grounds by a {@link formulas | formula} and
|
|
15
|
+
* are **never** emitted there — a derivation declared beside its grounds resolves once and
|
|
16
|
+
* freezes, which is measured rather than feared.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The token names this package defines, as they appear in CSS — the *ground* half: the
|
|
20
|
+
* names that have a default and are emitted at `:root`.
|
|
21
|
+
*
|
|
22
|
+
* It is not called `groundTokens`, and that is a cost rather than an oversight: renaming
|
|
23
|
+
* an exported name is breaking, and Layer 1 would spend a major on it. So the pair reads
|
|
24
|
+
* asymmetrically and this one carries the documented meaning *the names that have a
|
|
25
|
+
* default*.
|
|
26
|
+
*
|
|
27
|
+
* **The set is open, and that is a promise rather than an accident.** It grows as
|
|
28
|
+
* components arrive — a category enters with the pull request of the component that
|
|
29
|
+
* consumes it — so asserting completeness over it asserts something this package does not
|
|
30
|
+
* offer. Adding a name is a `feat`, never a break, and it costs nothing at runtime; what
|
|
31
|
+
* it does break is code that **enumerates** the set, an exhaustive `Record<Token, string>`
|
|
32
|
+
* above all. The supported shape is the partial map, which is what a theme is anyway.
|
|
11
33
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/** A CSS custom property this package defines. */
|
|
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"];
|
|
35
|
+
/** A CSS custom property this package defines and gives a default. */
|
|
15
36
|
export type Token = (typeof tokens)[number];
|
|
16
37
|
/**
|
|
17
|
-
* The
|
|
38
|
+
* The roles computed from the grounds rather than declared beside them.
|
|
39
|
+
*
|
|
40
|
+
* **These are write-only.** A host may override one, and every component picks the
|
|
41
|
+
* override up; nothing can read one back, because a derived name has no declared value —
|
|
42
|
+
* only a {@link formulas | formula} that lives in the `var()` fallback at the point of
|
|
43
|
+
* use. That is the one cost of the derivation that a consumer can be surprised by, and
|
|
44
|
+
* what it buys is an override surface a host can hold in their head: change the accent and
|
|
45
|
+
* the hover and pressed colours follow, rather than being one more name each.
|
|
46
|
+
*/
|
|
47
|
+
export declare const derivedTokens: readonly ["--ui-duration-state", "--ui-color-hover", "--ui-color-pressed", "--ui-color-accent-hover", "--ui-color-accent-pressed"];
|
|
48
|
+
/** A CSS custom property this package computes rather than declares. */
|
|
49
|
+
export type DerivedToken = (typeof derivedTokens)[number];
|
|
50
|
+
/**
|
|
51
|
+
* The default value of every ground token, applied at `:root` by {@link tokenStyleSheet}.
|
|
18
52
|
*
|
|
19
53
|
* These are deliberately plain and low-contrast-safe rather than branded: a design
|
|
20
54
|
* system's defaults are what a host sees before it has decided anything.
|
|
21
55
|
*/
|
|
22
56
|
export declare const defaults: Readonly<Record<Token, string>>;
|
|
57
|
+
/**
|
|
58
|
+
* How each derived role computes when the host has not set it.
|
|
59
|
+
*
|
|
60
|
+
* **Never emitted at `:root`, and this is the one measured failure of the whole design
|
|
61
|
+
* rather than a caution:**
|
|
62
|
+
*
|
|
63
|
+
* ```css
|
|
64
|
+
* :root {
|
|
65
|
+
* --ui-color-hover: color-mix(in oklab, var(--ui-color-text) 8%, var(--ui-color-surface));
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* That resolves *once*, against the grounds in force at `:root`, and freezes. A dark
|
|
70
|
+
* subtree then inherits the light mix — a near-white hover on charcoal — with nothing to
|
|
71
|
+
* read anywhere. The formula belongs in the `var()` fallback at the point of use, where it
|
|
72
|
+
* resolves against the grounds in force *there*, which is what makes a derived role follow
|
|
73
|
+
* a theme and a scheme without being restated in either. `src/reference.ts` is what writes
|
|
74
|
+
* it, and `tests/tokens.test.ts` gates the rule rather than trusting this comment.
|
|
75
|
+
*
|
|
76
|
+
* Composed rather than written out, because a formula is data about *which* grounds a role
|
|
77
|
+
* mixes and in what proportion — and a hand-written string can name a token that does not
|
|
78
|
+
* exist, or forget the default above, and CSS reports either by rendering nothing.
|
|
79
|
+
*
|
|
80
|
+
* Exported because a target that is not CSS cannot evaluate `color-mix()` and has to
|
|
81
|
+
* resolve these itself, frozen per theme, from the same source the components read.
|
|
82
|
+
*/
|
|
83
|
+
export declare const formulas: Readonly<Record<DerivedToken, string>>;
|
|
23
84
|
/**
|
|
24
85
|
* The grounds whose value differs when the page is rendered dark.
|
|
25
86
|
*
|
|
@@ -42,7 +103,8 @@ export declare const defaults: Readonly<Record<Token, string>>;
|
|
|
42
103
|
export declare const darkScheme: Readonly<Partial<Record<Token, string>>>;
|
|
43
104
|
/**
|
|
44
105
|
* The token defaults as a CSS rule, for a host that wants them without importing a
|
|
45
|
-
* component. Returns the text of a `:root` block
|
|
106
|
+
* component. Returns the text of a `:root` block and the reduced-motion rule beside it; a
|
|
107
|
+
* host inserts them however it prefers.
|
|
46
108
|
*
|
|
47
109
|
* **It declares `color-scheme` as well as the tokens, and that is deliberate.**
|
|
48
110
|
* `color-scheme` is a real property rather than a custom one, so it can never be a token —
|
|
@@ -50,6 +112,16 @@ export declare const darkScheme: Readonly<Partial<Record<Token, string>>>;
|
|
|
50
112
|
* host would have to remember, and forgetting means dark mode simply never happens, with
|
|
51
113
|
* no error anywhere to read. A host who wants something else — `only light`, say — governs
|
|
52
114
|
* the order this sheet is inserted in, which is a knob they already hold.
|
|
115
|
+
*
|
|
116
|
+
* **Reduced motion is honoured here, once, rather than in each component.** A component
|
|
117
|
+
* reads `--ui-duration-state` and never learns why it changed, which is the argument for
|
|
118
|
+
* motion being tokens rather than literals: a hardcoded `150ms` is not merely
|
|
119
|
+
* un-overridable, it is an accessibility defect every component would have to fix on its
|
|
120
|
+
* own. The block declares the *derived* duration names as well as the ground ones — the
|
|
121
|
+
* only place either may appear at `:root`, and legal there precisely because what it
|
|
122
|
+
* declares is a literal rather than a formula. Without it, a host who tuned
|
|
123
|
+
* `--ui-duration-state` would keep their motion through the collapse, and the setting
|
|
124
|
+
* would be honoured for everyone except the people who had touched it.
|
|
53
125
|
*/
|
|
54
126
|
export declare function tokenStyleSheet(): string;
|
|
55
127
|
//# sourceMappingURL=tokens.d.ts.map
|
package/dist/tokens.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
package/dist/tokens.js
CHANGED
|
@@ -8,8 +8,29 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Every token is a CSS custom property under `--ui-`, so a host overrides one by
|
|
10
10
|
* setting it anywhere above the component — no build step, no theme object, no fork.
|
|
11
|
+
*
|
|
12
|
+
* **The exported set splits in two, and the split is the shape of RFC 0002.** {@link tokens}
|
|
13
|
+
* are *ground*: they carry a literal default and are emitted at `:root`.
|
|
14
|
+
* {@link derivedTokens} are computed from the grounds by a {@link formulas | formula} and
|
|
15
|
+
* are **never** emitted there — a derivation declared beside its grounds resolves once and
|
|
16
|
+
* freezes, which is measured rather than feared.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The token names this package defines, as they appear in CSS — the *ground* half: the
|
|
20
|
+
* names that have a default and are emitted at `:root`.
|
|
21
|
+
*
|
|
22
|
+
* It is not called `groundTokens`, and that is a cost rather than an oversight: renaming
|
|
23
|
+
* an exported name is breaking, and Layer 1 would spend a major on it. So the pair reads
|
|
24
|
+
* asymmetrically and this one carries the documented meaning *the names that have a
|
|
25
|
+
* default*.
|
|
26
|
+
*
|
|
27
|
+
* **The set is open, and that is a promise rather than an accident.** It grows as
|
|
28
|
+
* components arrive — a category enters with the pull request of the component that
|
|
29
|
+
* consumes it — so asserting completeness over it asserts something this package does not
|
|
30
|
+
* offer. Adding a name is a `feat`, never a break, and it costs nothing at runtime; what
|
|
31
|
+
* it does break is code that **enumerates** the set, an exhaustive `Record<Token, string>`
|
|
32
|
+
* above all. The supported shape is the partial map, which is what a theme is anyway.
|
|
11
33
|
*/
|
|
12
|
-
/** The token names this package defines, as they appear in CSS. */
|
|
13
34
|
export const tokens = [
|
|
14
35
|
'--ui-color-accent',
|
|
15
36
|
'--ui-color-accent-contrast',
|
|
@@ -20,9 +41,40 @@ export const tokens = [
|
|
|
20
41
|
'--ui-radius',
|
|
21
42
|
'--ui-space',
|
|
22
43
|
'--ui-font',
|
|
44
|
+
// Motion, and it arrives with the component that consumes it rather than with the
|
|
45
|
+
// twelve that might: `ui-button` accepts interaction and until now showed no feedback
|
|
46
|
+
// for it, which is a defect rather than a gap.
|
|
47
|
+
//
|
|
48
|
+
// The duration is a *step* in a scale, named by an ordinal with gaps so that inserting
|
|
49
|
+
// `--ui-duration-150` later is additive rather than a rename. No component reads it —
|
|
50
|
+
// they read `--ui-duration-state`, which points in here. Easing has no scale under it,
|
|
51
|
+
// because a curve is qualitative rather than relative, so its purpose name *is* the
|
|
52
|
+
// ground and a component reads it directly.
|
|
53
|
+
'--ui-duration-100',
|
|
54
|
+
'--ui-easing-state',
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* The roles computed from the grounds rather than declared beside them.
|
|
58
|
+
*
|
|
59
|
+
* **These are write-only.** A host may override one, and every component picks the
|
|
60
|
+
* override up; nothing can read one back, because a derived name has no declared value —
|
|
61
|
+
* only a {@link formulas | formula} that lives in the `var()` fallback at the point of
|
|
62
|
+
* use. That is the one cost of the derivation that a consumer can be surprised by, and
|
|
63
|
+
* what it buys is an override surface a host can hold in their head: change the accent and
|
|
64
|
+
* the hover and pressed colours follow, rather than being one more name each.
|
|
65
|
+
*/
|
|
66
|
+
export const derivedTokens = [
|
|
67
|
+
'--ui-duration-state',
|
|
68
|
+
// `hover` matches the pseudo-class it answers to; `pressed` deliberately does not —
|
|
69
|
+
// `--ui-color-active` would read as *the active item* as readily as *the pressed
|
|
70
|
+
// control*, and the role this implements was named `accent hover / pressed`.
|
|
71
|
+
'--ui-color-hover',
|
|
72
|
+
'--ui-color-pressed',
|
|
73
|
+
'--ui-color-accent-hover',
|
|
74
|
+
'--ui-color-accent-pressed',
|
|
23
75
|
];
|
|
24
76
|
/**
|
|
25
|
-
* The default value of every token, applied at `:root` by {@link tokenStyleSheet}.
|
|
77
|
+
* The default value of every ground token, applied at `:root` by {@link tokenStyleSheet}.
|
|
26
78
|
*
|
|
27
79
|
* These are deliberately plain and low-contrast-safe rather than branded: a design
|
|
28
80
|
* system's defaults are what a host sees before it has decided anything.
|
|
@@ -45,6 +97,73 @@ export const defaults = {
|
|
|
45
97
|
'--ui-radius': '0.375rem',
|
|
46
98
|
'--ui-space': '0.5rem',
|
|
47
99
|
'--ui-font': 'system-ui, sans-serif',
|
|
100
|
+
// The ordinal is a position, not a millisecond count, and the value is chosen so that
|
|
101
|
+
// the two cannot be confused: `--ui-duration-100: 100ms` would teach a reader an
|
|
102
|
+
// arithmetic that breaks the moment a second step is anything but 200ms.
|
|
103
|
+
'--ui-duration-100': '150ms',
|
|
104
|
+
// Symmetric, because a state transition reverses mid-flight: the pointer leaves a
|
|
105
|
+
// button while the hover is still arriving, and an asymmetric curve makes the return
|
|
106
|
+
// trip visibly different from the outbound one. The keyword rather than the
|
|
107
|
+
// `cubic-bezier` it stands for — nothing here needs a curve the platform has no name
|
|
108
|
+
// for. `enter` will want an ease-out and `exit` an ease-in, and they arrive with the
|
|
109
|
+
// overlays that have an enter and an exit to name.
|
|
110
|
+
'--ui-easing-state': 'ease-in-out',
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* A ground as it is written inside a formula: the name, with its own default behind it.
|
|
114
|
+
*
|
|
115
|
+
* **The default is not decoration.** A formula only ever runs as the fallback of a name
|
|
116
|
+
* nobody declared, which is precisely the page that inserted no `:root` block — and a bare
|
|
117
|
+
* `var(--ui-color-text)` there is invalid at computed-value time, which takes the whole
|
|
118
|
+
* `color-mix()` down with it and leaves the declaration unset. Measured, as a transparent
|
|
119
|
+
* hover on a page that had declared nothing. So a derivation carries its grounds' defaults
|
|
120
|
+
* exactly the way a component carries them.
|
|
121
|
+
*/
|
|
122
|
+
function ground(name) {
|
|
123
|
+
return `var(${name}, ${defaults[name]})`;
|
|
124
|
+
}
|
|
125
|
+
/** `amount`% of `foreground` mixed into `background`, in a perceptual space. */
|
|
126
|
+
function mix(foreground, amount, background) {
|
|
127
|
+
return `color-mix(in oklab, ${ground(foreground)} ${String(amount)}%, ${ground(background)})`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* How each derived role computes when the host has not set it.
|
|
131
|
+
*
|
|
132
|
+
* **Never emitted at `:root`, and this is the one measured failure of the whole design
|
|
133
|
+
* rather than a caution:**
|
|
134
|
+
*
|
|
135
|
+
* ```css
|
|
136
|
+
* :root {
|
|
137
|
+
* --ui-color-hover: color-mix(in oklab, var(--ui-color-text) 8%, var(--ui-color-surface));
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* That resolves *once*, against the grounds in force at `:root`, and freezes. A dark
|
|
142
|
+
* subtree then inherits the light mix — a near-white hover on charcoal — with nothing to
|
|
143
|
+
* read anywhere. The formula belongs in the `var()` fallback at the point of use, where it
|
|
144
|
+
* resolves against the grounds in force *there*, which is what makes a derived role follow
|
|
145
|
+
* a theme and a scheme without being restated in either. `src/reference.ts` is what writes
|
|
146
|
+
* it, and `tests/tokens.test.ts` gates the rule rather than trusting this comment.
|
|
147
|
+
*
|
|
148
|
+
* Composed rather than written out, because a formula is data about *which* grounds a role
|
|
149
|
+
* mixes and in what proportion — and a hand-written string can name a token that does not
|
|
150
|
+
* exist, or forget the default above, and CSS reports either by rendering nothing.
|
|
151
|
+
*
|
|
152
|
+
* Exported because a target that is not CSS cannot evaluate `color-mix()` and has to
|
|
153
|
+
* resolve these itself, frozen per theme, from the same source the components read.
|
|
154
|
+
*/
|
|
155
|
+
export const formulas = {
|
|
156
|
+
// A formula may be a plain reference. A purpose points into the scale; the scale is
|
|
157
|
+
// where the number lives, and a host who wants slower state changes moves the step.
|
|
158
|
+
'--ui-duration-state': ground('--ui-duration-100'),
|
|
159
|
+
// Mixing toward the text rather than toward black or white is what makes one formula
|
|
160
|
+
// right in both schemes: text is always the far pole from surface, so the mix darkens
|
|
161
|
+
// on a light page and lightens on a dark one, without either being named. The contrast
|
|
162
|
+
// against whatever sits on top rises either way rather than falling.
|
|
163
|
+
'--ui-color-hover': mix('--ui-color-text', 8, '--ui-color-surface'),
|
|
164
|
+
'--ui-color-pressed': mix('--ui-color-text', 14, '--ui-color-surface'),
|
|
165
|
+
'--ui-color-accent-hover': mix('--ui-color-text', 12, '--ui-color-accent'),
|
|
166
|
+
'--ui-color-accent-pressed': mix('--ui-color-text', 22, '--ui-color-accent'),
|
|
48
167
|
};
|
|
49
168
|
/**
|
|
50
169
|
* The grounds whose value differs when the page is rendered dark.
|
|
@@ -77,9 +196,12 @@ export const darkScheme = {
|
|
|
77
196
|
// text is the one thing in this set that must never be hard to read. Red-400 is 6.41.
|
|
78
197
|
'--ui-color-danger': '#f87171',
|
|
79
198
|
};
|
|
199
|
+
/** The category every duration name shares, which is what reduced motion collapses. */
|
|
200
|
+
const duration = '--ui-duration-';
|
|
80
201
|
/**
|
|
81
202
|
* The token defaults as a CSS rule, for a host that wants them without importing a
|
|
82
|
-
* component. Returns the text of a `:root` block
|
|
203
|
+
* component. Returns the text of a `:root` block and the reduced-motion rule beside it; a
|
|
204
|
+
* host inserts them however it prefers.
|
|
83
205
|
*
|
|
84
206
|
* **It declares `color-scheme` as well as the tokens, and that is deliberate.**
|
|
85
207
|
* `color-scheme` is a real property rather than a custom one, so it can never be a token —
|
|
@@ -87,14 +209,35 @@ export const darkScheme = {
|
|
|
87
209
|
* host would have to remember, and forgetting means dark mode simply never happens, with
|
|
88
210
|
* no error anywhere to read. A host who wants something else — `only light`, say — governs
|
|
89
211
|
* the order this sheet is inserted in, which is a knob they already hold.
|
|
212
|
+
*
|
|
213
|
+
* **Reduced motion is honoured here, once, rather than in each component.** A component
|
|
214
|
+
* reads `--ui-duration-state` and never learns why it changed, which is the argument for
|
|
215
|
+
* motion being tokens rather than literals: a hardcoded `150ms` is not merely
|
|
216
|
+
* un-overridable, it is an accessibility defect every component would have to fix on its
|
|
217
|
+
* own. The block declares the *derived* duration names as well as the ground ones — the
|
|
218
|
+
* only place either may appear at `:root`, and legal there precisely because what it
|
|
219
|
+
* declares is a literal rather than a formula. Without it, a host who tuned
|
|
220
|
+
* `--ui-duration-state` would keep their motion through the collapse, and the setting
|
|
221
|
+
* would be honoured for everyone except the people who had touched it.
|
|
90
222
|
*/
|
|
91
223
|
export function tokenStyleSheet() {
|
|
92
|
-
const
|
|
224
|
+
const grounds = tokens
|
|
93
225
|
.map((token) => {
|
|
94
226
|
const dark = darkScheme[token];
|
|
95
227
|
return ` ${token}: ${dark === undefined ? defaults[token] : `light-dark(${defaults[token]}, ${dark})`};`;
|
|
96
228
|
})
|
|
97
229
|
.join('\n');
|
|
98
|
-
|
|
230
|
+
// Not zero, and the difference is not cosmetic: a zero-length transition fires no
|
|
231
|
+
// `transitionstart` and no `transitionend`, measured, so a component that awaits the
|
|
232
|
+
// end of one before removing itself waits forever — and only for the people who asked
|
|
233
|
+
// for less motion. At `0.01ms` the lifecycle still runs; the time is what goes.
|
|
234
|
+
const collapsed = [...tokens, ...derivedTokens]
|
|
235
|
+
.filter((token) => token.startsWith(duration))
|
|
236
|
+
.map((token) => ` ${token}: 0.01ms;`)
|
|
237
|
+
.join('\n');
|
|
238
|
+
return [
|
|
239
|
+
`:root {\n color-scheme: light dark;\n${grounds}\n}`,
|
|
240
|
+
`@media (prefers-reduced-motion: reduce) {\n :root {\n${collapsed}\n }\n}`,
|
|
241
|
+
].join('\n\n');
|
|
99
242
|
}
|
|
100
243
|
//# sourceMappingURL=tokens.js.map
|
package/dist/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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"}
|