actual-css 0.4.1 → 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/CHANGELOG.md +54 -0
- package/README.md +2 -2
- package/dist/actual.css +53 -14
- package/dist/actual.full.css +300 -91
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/spacing-units.md +286 -0
- package/docs/navigation.json +1 -0
- package/docs/pages/components/alert.md +1 -1
- package/docs/pages/components/app-navigation.md +2 -0
- package/docs/pages/components/badge.md +17 -3
- package/docs/pages/components/button.md +9 -2
- package/docs/pages/components/card.md +13 -0
- package/docs/pages/components/data-list.md +72 -0
- package/docs/pages/components/dialog.md +2 -0
- package/docs/pages/components/drawer.md +2 -0
- package/docs/pages/components/fab.md +2 -0
- package/docs/pages/components/meter.md +56 -1
- package/docs/pages/components/progress.md +10 -0
- package/docs/pages/components/skeleton.md +2 -0
- package/docs/pages/components/steps.md +10 -2
- package/docs/pages/components/table.md +1 -0
- package/docs/pages/enhancements/flyout.md +2 -0
- package/docs/pages/enhancements/status-bar.md +10 -1
- package/docs/pages/examples/overview.md +2 -1
- package/docs/pages/forms/joined-controls.md +2 -0
- package/docs/pages/forms/overview.md +1 -1
- package/docs/pages/forms/range.md +2 -0
- package/docs/pages/forms/states-and-sizes.md +1 -1
- package/docs/pages/forms/validation.md +2 -0
- package/docs/pages/foundations/philosophy.md +11 -1
- package/docs/pages/foundations/tokens.md +7 -3
- package/docs/pages/foundations/typography.md +10 -2
- package/docs/pages/guides/introduction.md +1 -1
- package/docs/pages/layout/scroll-snap.md +2 -0
- package/docs/pages/layout/sidebar-layout.md +2 -0
- package/docs/pages/layout/topbar.md +2 -0
- package/docs/pages/utilities/accessibility.md +18 -0
- package/package.json +1 -1
- package/scripts/reserved-classes.json +4 -0
- package/src/css/components/actions.css +1 -0
- package/src/css/components/breadcrumb.css +1 -0
- package/src/css/components/data-list.css +27 -0
- package/src/css/components/drawer.css +30 -11
- package/src/css/components/flyout.css +17 -12
- package/src/css/components/index.css +1 -0
- package/src/css/components/meter.css +28 -1
- package/src/css/components/modal.css +28 -11
- package/src/css/components/navbar.css +2 -0
- package/src/css/components/pagination.css +1 -0
- package/src/css/components/progress.css +5 -0
- package/src/css/components/status-bar.css +31 -15
- package/src/css/components/steps.css +36 -9
- package/src/css/components/surface.css +5 -3
- package/src/css/components/tab.css +1 -0
- package/src/css/components/tooltip.css +5 -8
- package/src/css/core/base.css +7 -1
- package/src/css/core/intents.css +6 -0
- package/src/css/core/tokens.css +23 -9
- package/src/css/core/variants.css +17 -4
- package/src/css/forms/form-actions.css +1 -0
- package/src/css/forms/form.css +4 -4
- package/src/css/layout/cluster.css +1 -0
- package/src/css/layout/scroll-snap.css +1 -0
- package/src/css/layout/sidebar-layout.css +1 -0
- package/src/css/layout/switcher.css +1 -0
- package/src/css/layout/topbar.css +1 -0
- package/src/css/typography/prose.css +2 -3
- package/src/css/utilities/base.css +16 -0
- package/src/js/selectors.js +1 -0
- package/src/js/status.js +88 -7
- package/src/js/surface.js +2 -11
- package/src/js/transition.js +20 -0
|
@@ -39,12 +39,14 @@ dialog.modal {
|
|
|
39
39
|
* Keep the open dialog root untransformed. Fixed overlays mounted inside a
|
|
40
40
|
* modal dialog use viewport coordinates; transform/translate/scale on this
|
|
41
41
|
* element would make them position against the dialog instead. The closed
|
|
42
|
-
* state can still carry a small transform for enter/exit motion.
|
|
42
|
+
* state can still carry a small transform for enter/exit motion. The lift
|
|
43
|
+
* is a pure vertical offset: scaling a wide panel around its center drags
|
|
44
|
+
* both edges, which reads as horizontal movement.
|
|
43
45
|
*/
|
|
44
|
-
transform: translateY(0.35rem)
|
|
46
|
+
transform: translateY(0.35rem);
|
|
45
47
|
transition:
|
|
46
|
-
opacity var(--duration),
|
|
47
|
-
transform var(--duration);
|
|
48
|
+
opacity var(--duration) var(--ease-exit),
|
|
49
|
+
transform var(--duration) var(--ease-exit);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
dialog.modal > form,
|
|
@@ -163,33 +165,46 @@ dialog.modal.dialog-confirmation > form > footer {
|
|
|
163
165
|
dialog.modal[open] {
|
|
164
166
|
opacity: 1;
|
|
165
167
|
transform: none;
|
|
168
|
+
transition:
|
|
169
|
+
opacity var(--duration) var(--ease-enter),
|
|
170
|
+
transform var(--duration) var(--ease-enter);
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
@starting-style {
|
|
169
174
|
dialog.modal[open] {
|
|
170
175
|
opacity: 0;
|
|
171
|
-
transform: translateY(0.35rem)
|
|
176
|
+
transform: translateY(0.35rem);
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
dialog.modal::backdrop {
|
|
176
181
|
background: var(--backdrop-fill);
|
|
177
182
|
opacity: 0;
|
|
178
|
-
|
|
183
|
+
/* Scrim curve stays neutral `ease`; only the panel carries the character
|
|
184
|
+
curves. */
|
|
185
|
+
transition: opacity var(--duration) ease;
|
|
179
186
|
}
|
|
180
187
|
|
|
181
188
|
@supports (transition-behavior: allow-discrete) {
|
|
182
189
|
dialog.modal {
|
|
183
190
|
transition:
|
|
184
|
-
opacity var(--duration),
|
|
185
|
-
transform var(--duration),
|
|
191
|
+
opacity var(--duration) var(--ease-exit),
|
|
192
|
+
transform var(--duration) var(--ease-exit),
|
|
193
|
+
overlay var(--duration) allow-discrete,
|
|
194
|
+
display var(--duration) allow-discrete;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
dialog.modal[open] {
|
|
198
|
+
transition:
|
|
199
|
+
opacity var(--duration) var(--ease-enter),
|
|
200
|
+
transform var(--duration) var(--ease-enter),
|
|
186
201
|
overlay var(--duration) allow-discrete,
|
|
187
202
|
display var(--duration) allow-discrete;
|
|
188
203
|
}
|
|
189
204
|
|
|
190
205
|
dialog.modal::backdrop {
|
|
191
206
|
transition:
|
|
192
|
-
opacity var(--duration),
|
|
207
|
+
opacity var(--duration) ease,
|
|
193
208
|
overlay var(--duration) allow-discrete,
|
|
194
209
|
display var(--duration) allow-discrete;
|
|
195
210
|
}
|
|
@@ -214,13 +229,15 @@ html.has-modal-open.had-scrollbar {
|
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
@media (prefers-reduced-motion: no-preference) {
|
|
232
|
+
/* Wrong-close feedback and view-transition transport are motion quirks, not
|
|
233
|
+
presence enter/exit, so they stay on the plain CSS default easing. */
|
|
217
234
|
dialog.modal.is-static {
|
|
218
|
-
animation: actual-dialog-static var(--duration-slow)
|
|
235
|
+
animation: actual-dialog-static var(--duration-slow) ease;
|
|
219
236
|
}
|
|
220
237
|
|
|
221
238
|
::view-transition-group(actual-dialog) {
|
|
222
239
|
animation-duration: var(--duration);
|
|
223
|
-
animation-timing-function:
|
|
240
|
+
animation-timing-function: ease;
|
|
224
241
|
}
|
|
225
242
|
}
|
|
226
243
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
.navbar {
|
|
20
20
|
display: flex;
|
|
21
|
+
flex-direction: row;
|
|
21
22
|
flex-wrap: wrap;
|
|
22
23
|
align-items: center;
|
|
23
24
|
justify-content: space-between;
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
|
|
46
47
|
.navbar-nav {
|
|
47
48
|
display: flex;
|
|
49
|
+
flex-direction: row;
|
|
48
50
|
flex-wrap: wrap;
|
|
49
51
|
align-items: center;
|
|
50
52
|
gap: var(--space-10);
|
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* Consumes the shared --intent/--primary for the value bar and --bar-height
|
|
5
5
|
* for thickness. Indeterminate state animates a shimmer using --duration-shimmer.
|
|
6
6
|
*
|
|
7
|
+
* Thickness is a dimension, not a density step: the bar always spans its
|
|
8
|
+
* container and only gets thinner or thicker, so --bar-height is the API and
|
|
9
|
+
* .sm/.lg are deliberately not supported.
|
|
10
|
+
*
|
|
7
11
|
* Public hooks:
|
|
8
12
|
* --progress-track
|
|
9
13
|
* --progress-value
|
|
14
|
+
* --bar-height
|
|
10
15
|
*/
|
|
11
16
|
/* Intent boundary — inherited intents do not tint this component.
|
|
12
17
|
Local intent classes still win because :where() has zero specificity. */
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Status bar — singleton floating status area.
|
|
3
3
|
*
|
|
4
|
-
* One element in the HTML, empty by default
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* One element in the HTML, empty by default. .is-open is the visual state, set
|
|
5
|
+
* by status.js like any other surface: it lands after the message is written
|
|
6
|
+
* and lifts before the bar is cleared, so the bar leaves in the exact state it
|
|
7
|
+
* was shown in — same text, same width, same intent color — instead of snapping
|
|
8
|
+
* to a neutral empty pill mid-exit. Emptying the text is the *end* of the exit,
|
|
9
|
+
* not its trigger.
|
|
7
10
|
*
|
|
8
11
|
* Consumes intent like badge or alert. No need for status-bar-specific modifier
|
|
9
12
|
* classes — .danger / .success / .warning / .neutral from intents.css drive
|
|
@@ -17,6 +20,7 @@
|
|
|
17
20
|
* Internal:
|
|
18
21
|
* --status-bg
|
|
19
22
|
* --status-fg
|
|
23
|
+
* --status-viewport-offset (written by status.js while the bar is open)
|
|
20
24
|
*/
|
|
21
25
|
|
|
22
26
|
/* Intent boundary — inherited intents do not tint this component.
|
|
@@ -31,7 +35,9 @@
|
|
|
31
35
|
--status-fg: var(--intent-fg, var(--surface));
|
|
32
36
|
|
|
33
37
|
position: fixed;
|
|
34
|
-
|
|
38
|
+
/* Fixed positioning tracks the layout viewport, which the mobile software
|
|
39
|
+
keyboard covers. status.js writes the occluded band into the offset. */
|
|
40
|
+
inset-block-end: calc(var(--space-40) + var(--status-viewport-offset, 0px));
|
|
35
41
|
inset-inline: var(--space-40);
|
|
36
42
|
z-index: var(--z-status);
|
|
37
43
|
|
|
@@ -53,22 +59,32 @@
|
|
|
53
59
|
color: var(--status-fg);
|
|
54
60
|
box-shadow: var(--shadow-popout);
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
/* Closed by default. Opacity, not visibility or display: the bar has to stay
|
|
63
|
+
in the accessibility tree to work as a live region. */
|
|
64
|
+
opacity: 0;
|
|
65
|
+
translate: 0 var(--space-30);
|
|
59
66
|
pointer-events: none;
|
|
60
67
|
|
|
68
|
+
/* Exit is shorter than entry so dismissed feedback gets out of the way.
|
|
69
|
+
background stays a shorthand so --status-bg still accepts gradients;
|
|
70
|
+
solid colors expose an interpolable computed background-color. The
|
|
71
|
+
intent color follows the state/interaction `ease`, not the presence
|
|
72
|
+
curves. */
|
|
61
73
|
transition:
|
|
62
|
-
opacity var(--duration-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
opacity var(--duration-fast) var(--ease-exit),
|
|
75
|
+
translate var(--duration) var(--ease-exit),
|
|
76
|
+
background-color var(--duration) ease;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
|
-
.status-bar
|
|
68
|
-
opacity:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
.status-bar.is-open {
|
|
80
|
+
opacity: 1;
|
|
81
|
+
translate: 0 0;
|
|
82
|
+
/* Entry takes a little longer and decelerates, making the message legible
|
|
83
|
+
before its motion settles. */
|
|
84
|
+
transition:
|
|
85
|
+
opacity var(--duration) var(--ease-enter),
|
|
86
|
+
translate var(--duration-slow) var(--ease-enter),
|
|
87
|
+
background-color var(--duration) ease;
|
|
72
88
|
}
|
|
73
89
|
@media print {
|
|
74
90
|
.status-bar {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
counter-reset: actual-step;
|
|
37
37
|
display: flex;
|
|
38
|
+
flex-direction: row;
|
|
38
39
|
inline-size: 100%;
|
|
39
40
|
margin: 0;
|
|
40
41
|
padding: 0;
|
|
@@ -96,27 +97,53 @@
|
|
|
96
97
|
content: none;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
/* Three states must be readable without a check glyph: future stays neutral,
|
|
101
|
+
complete is a filled marker, current is an outlined one. Filled reads as
|
|
102
|
+
"done", outlined as "you are here" — the distinction survives a numbered
|
|
103
|
+
stepper that never sets --step-complete-mark. */
|
|
104
|
+
.steps > .complete {
|
|
100
105
|
--step-marker-bg: var(--state-selected);
|
|
101
106
|
--step-marker-border: var(--state-selected);
|
|
102
107
|
--step-marker-fg: var(--state-selected-fg);
|
|
108
|
+
--step-line: var(--state-selected);
|
|
103
109
|
|
|
104
110
|
color: var(--text);
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
/*
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
/* Declared after .complete at equal specificity, and it wins on every channel
|
|
114
|
+
including the connector: the accented line means "already walked", so the
|
|
115
|
+
segment leaving the current step must stay neutral. The line reaching the
|
|
116
|
+
current step is owned by the previous step, which is complete. */
|
|
117
|
+
.steps > [aria-current="step"] {
|
|
118
|
+
--step-marker-bg: var(--surface);
|
|
119
|
+
--step-marker-border: var(--state-selected);
|
|
120
|
+
--step-marker-fg: var(--state-selected);
|
|
121
|
+
--step-line: var(--border);
|
|
122
|
+
|
|
123
|
+
color: var(--text);
|
|
111
124
|
}
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
/* Thicker border is the current affordance in every mode — structural, so it
|
|
127
|
+
survives forced colors, and it never competes with the outline channel owned
|
|
128
|
+
by focus. */
|
|
129
|
+
.steps > [aria-current="step"]::before {
|
|
130
|
+
border-width: calc(var(--border-width) * 2);
|
|
115
131
|
}
|
|
116
132
|
|
|
117
133
|
/* A finished step may replace its number with a mark (e.g. a check glyph):
|
|
118
134
|
--step-complete-mark accepts any content value and falls back to the
|
|
119
|
-
counter, so existing numbered steppers are unchanged.
|
|
120
|
-
|
|
135
|
+
counter, so existing numbered steppers are unchanged. Excluded on the
|
|
136
|
+
current step so "current wins" holds on the glyph too, not only on color. */
|
|
137
|
+
.steps > .complete:not([aria-current="step"])::before {
|
|
121
138
|
content: var(--step-complete-mark, counter(actual-step));
|
|
122
139
|
}
|
|
140
|
+
|
|
141
|
+
/* Forced colors drop the accent fill, which would leave complete and future
|
|
142
|
+
markers identical — current keeps its thicker ring, complete needs a system
|
|
143
|
+
color to stay filled. Same exclusion, for the same reason. */
|
|
144
|
+
@media (forced-colors: active) {
|
|
145
|
+
.steps > .complete:not([aria-current="step"])::before {
|
|
146
|
+
background: Highlight;
|
|
147
|
+
color: HighlightText;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
z-index: calc(var(--z-menu) - 1);
|
|
20
20
|
background: var(--backdrop-fill);
|
|
21
21
|
opacity: 1;
|
|
22
|
-
|
|
22
|
+
/* A scrim never travels; it fades on the neutral `ease`. Duration matches
|
|
23
|
+
the flyout sheet it accompanies so it never lags the panel. */
|
|
24
|
+
transition: opacity var(--duration-fast) ease;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
.surface-backdrop[hidden] {
|
|
@@ -36,8 +38,8 @@
|
|
|
36
38
|
@supports (transition-behavior: allow-discrete) {
|
|
37
39
|
.surface-backdrop {
|
|
38
40
|
transition:
|
|
39
|
-
opacity var(--duration)
|
|
40
|
-
display var(--duration) allow-discrete;
|
|
41
|
+
opacity var(--duration-fast) ease,
|
|
42
|
+
display var(--duration-fast) allow-discrete;
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
@media print {
|
|
@@ -32,31 +32,28 @@
|
|
|
32
32
|
overflow-wrap: anywhere;
|
|
33
33
|
pointer-events: auto;
|
|
34
34
|
user-select: none;
|
|
35
|
+
/* Tooltips fade only: the anchor edge, marked by the arrow, must stay put
|
|
36
|
+
during motion, and a 4% scale was perceptible on small text. Scaling moves
|
|
37
|
+
the arrow tip away from its trigger on every placement. */
|
|
35
38
|
opacity: 1;
|
|
36
|
-
|
|
37
|
-
transition:
|
|
38
|
-
opacity var(--duration-fast) var(--ease),
|
|
39
|
-
scale var(--duration-fast) var(--ease);
|
|
39
|
+
transition: opacity var(--duration-fast) ease;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
.tooltip[hidden] {
|
|
43
43
|
display: none;
|
|
44
44
|
opacity: 0;
|
|
45
|
-
scale: 0.96;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
@starting-style {
|
|
49
48
|
.tooltip:not([hidden]) {
|
|
50
49
|
opacity: 0;
|
|
51
|
-
scale: 0.96;
|
|
52
50
|
}
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
@supports (transition-behavior: allow-discrete) {
|
|
56
54
|
.tooltip {
|
|
57
55
|
transition:
|
|
58
|
-
opacity var(--duration-fast)
|
|
59
|
-
scale var(--duration-fast) var(--ease),
|
|
56
|
+
opacity var(--duration-fast) ease,
|
|
60
57
|
display var(--duration-fast) allow-discrete;
|
|
61
58
|
}
|
|
62
59
|
}
|
package/src/css/core/base.css
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sits between reset (browser defaults) and prose (rich content scope).
|
|
5
5
|
* These styles apply everywhere — cards, dialogs, heroes — not only in prose.
|
|
6
|
+
*
|
|
7
|
+
* Public hooks:
|
|
8
|
+
* --link
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
body {
|
|
@@ -12,8 +15,11 @@ body {
|
|
|
12
15
|
line-height: var(--line-height);
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
/* Bare links inherit their ink by default, so nothing changes unless a theme
|
|
19
|
+
opts in by setting --link. Because this is an element selector, any component
|
|
20
|
+
rule that colors its own anchors still wins. */
|
|
15
21
|
a {
|
|
16
|
-
color: inherit;
|
|
22
|
+
color: var(--link, inherit);
|
|
17
23
|
text-underline-offset: 0.18em;
|
|
18
24
|
}
|
|
19
25
|
|
package/src/css/core/intents.css
CHANGED
|
@@ -31,3 +31,9 @@
|
|
|
31
31
|
--intent: var(--neutral);
|
|
32
32
|
--intent-fg: var(--neutral-fg);
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
/* Paint an inherited or local intent on a simple foreground element without
|
|
36
|
+
turning the intent classes into general-purpose color utilities. */
|
|
37
|
+
.intent-color {
|
|
38
|
+
color: var(--intent);
|
|
39
|
+
}
|
package/src/css/core/tokens.css
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Derived: "Theme-derived aliases" and "State tokens" reference intent and
|
|
10
10
|
* surface tokens and follow the theme; do not hard-code values into them.
|
|
11
|
-
* Internal: indicator offsets, --
|
|
12
|
-
*
|
|
11
|
+
* Internal: indicator offsets, --disabled-opacity and the like are
|
|
12
|
+
* consumed by components, not authored.
|
|
13
13
|
*
|
|
14
14
|
* Component-local hooks and internal state relays live with their
|
|
15
15
|
* components. See docs/pages/foundations/tokens.md for the public/internal
|
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
--font-size-md: 1rem;
|
|
34
34
|
--font-size-lg: 1.125rem;
|
|
35
35
|
|
|
36
|
-
/* Spacing — official steps are named in tens so the scale stays open
|
|
37
|
-
|
|
38
|
-
--space-45…)
|
|
36
|
+
/* Spacing — official steps are named in tens so the scale stays open.
|
|
37
|
+
Actual CSS will never define a --space-* that is not a multiple of 10:
|
|
38
|
+
the intermediate names (--space-15, --space-45…) are reserved for
|
|
39
|
+
applications, and no future framework step can collide with them. */
|
|
39
40
|
--gap: 0.75rem;
|
|
40
41
|
--density-space: var(--space-40);
|
|
41
42
|
--density-compact-size: 1.5rem;
|
|
@@ -53,14 +54,25 @@
|
|
|
53
54
|
--shadow-popout: 0 0.25rem 0.75rem rgb(0 0 0 / 0.15);
|
|
54
55
|
|
|
55
56
|
/* Motion — see reset.css for the prefers-reduced-motion hard reset.
|
|
56
|
-
--duration
|
|
57
|
-
animation rates below tune one-shot open/close and decorative loops.
|
|
57
|
+
--duration scales component transitions (hover/focus); the dedicated
|
|
58
|
+
animation rates below tune one-shot open/close and decorative loops.
|
|
59
|
+
Generic state/interaction motion uses the CSS default `ease` directly
|
|
60
|
+
(registered nowhere). --ease-enter/--ease-exit express the character of
|
|
61
|
+
one-shot presence changes, owned by the open/closed state rules that
|
|
62
|
+
separate them (status-bar, drawer, modal). The pair follows the standard
|
|
63
|
+
M3 rhythm; the more aggressive emphasized-decelerate entrance is
|
|
64
|
+
deliberately not offered because it only pays off on 250–400ms motions,
|
|
65
|
+
beyond this vocabulary. Toggles that share one transition list at
|
|
66
|
+
--duration-fast (flyout, tooltip) and pure-opacity backdrops stay on
|
|
67
|
+
`ease`: at 100ms the curve has almost no resolving time, and a scrim is
|
|
68
|
+
not traveling anywhere. */
|
|
58
69
|
--duration: 150ms;
|
|
59
70
|
--duration-fast: 100ms;
|
|
60
71
|
--duration-slow: 200ms;
|
|
61
72
|
--duration-spin: 0.75s;
|
|
62
73
|
--duration-shimmer: 1.2s;
|
|
63
|
-
--ease:
|
|
74
|
+
--ease-enter: cubic-bezier(0.2, 0, 0, 1);
|
|
75
|
+
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
|
|
64
76
|
|
|
65
77
|
/* Focus ring — shared by every interactive component's :focus-visible */
|
|
66
78
|
--focus-outline-color: currentColor;
|
|
@@ -78,7 +90,9 @@
|
|
|
78
90
|
--backdrop-opacity: 0.45;
|
|
79
91
|
--backdrop-fill: rgb(0 0 0 / var(--backdrop-opacity));
|
|
80
92
|
|
|
81
|
-
/*
|
|
93
|
+
/* Bar thickness shared by .progress and .meter — two conceptual variants of
|
|
94
|
+
the same geometry. Public: set it on the element or on an application
|
|
95
|
+
class rather than reaching for a size variant. */
|
|
82
96
|
--bar-height: 0.65rem;
|
|
83
97
|
|
|
84
98
|
/* Controls — inputs and buttons share --control-size so heights always match.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Cross-cutting variant token mapping.
|
|
3
3
|
*
|
|
4
|
-
* Variant scope: .solid/.soft/.outline set --ui-* for components that
|
|
5
|
-
* shared variants. .inverted is a surface modifier, not a variant: it paints
|
|
4
|
+
* Variant scope: .solid/.soft/.outline/.surface set --ui-* for components that
|
|
5
|
+
* opt into shared variants. .inverted is a surface modifier, not a variant: it paints
|
|
6
6
|
* the element directly (background/color/border-color) so it works on any bare
|
|
7
7
|
* block, and remaps the shared --ui-* tokens so participating components
|
|
8
8
|
* (.card, .navbar, .alert, .badge) invert through their own rules. Loaded
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
* components may consume --density-* when the density context should affect
|
|
22
22
|
* their local rhythm. Compact components may consume --density-compact-size.
|
|
23
23
|
* Components with bespoke sizing (spinner, avatar) define local .sm/.lg;
|
|
24
|
-
* applying .sm/.lg to card, dialog, accordion, navbar, table
|
|
25
|
-
* a no-op.
|
|
24
|
+
* applying .sm/.lg to card, dialog, accordion, navbar, table, progress, meter
|
|
25
|
+
* is a no-op. Progress and meter are deliberate: a bar keeps its inline size
|
|
26
|
+
* and only changes thickness, which --bar-height expresses better than a
|
|
27
|
+
* three-step scale.
|
|
26
28
|
*
|
|
27
29
|
* Intent list source of truth: intents.css. Components consume --intent* tokens
|
|
28
30
|
* instead of re-listing intent classes.
|
|
@@ -45,6 +47,17 @@
|
|
|
45
47
|
--ui-border: var(--intent, currentColor);
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/* Neutral chrome, intent only in the ink: the page surface with the theme
|
|
51
|
+
border. .soft is the intent-tinted treatment (its baseline fallback uses
|
|
52
|
+
--surface-subtle) and .outline has no fill at all, so neither can express
|
|
53
|
+
it. Deliberately literal — no color-mix enhancement — so this stays the one
|
|
54
|
+
variant that reads exactly as the theme's own surface. */
|
|
55
|
+
.surface {
|
|
56
|
+
--ui-bg: var(--surface);
|
|
57
|
+
--ui-fg: var(--intent, var(--text));
|
|
58
|
+
--ui-border: var(--border);
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
/* Inverse surface treatment. Paints the element directly (so it works on any
|
|
49
62
|
bare block) and remaps the shared --ui-* tokens so opt-in components
|
|
50
63
|
(.card, .navbar) invert through their own rules. Because this loads before
|
package/src/css/forms/form.css
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* Individual controls keep their own files; .choice label layout lives in
|
|
5
5
|
* choice.css; .form-actions lives in form-actions.css.
|
|
6
6
|
*
|
|
7
|
+
* .field-group owns its own box only. Distance between sibling groups is a
|
|
8
|
+
* composition concern (.stack on the form), never a sibling margin here: the
|
|
9
|
+
* component cannot know whether its siblings are stacked or gridded.
|
|
10
|
+
*
|
|
7
11
|
* Public API: .field, .field-label, .field-help, .field-error, .field-group,
|
|
8
12
|
* .required-mark.
|
|
9
13
|
*
|
|
@@ -24,10 +28,6 @@
|
|
|
24
28
|
border-radius: var(--radius);
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
.field-group + .field-group {
|
|
28
|
-
margin-block-start: var(--space-40);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
31
|
.field-label,
|
|
32
32
|
.field-group > legend {
|
|
33
33
|
color: var(--text);
|
|
@@ -83,9 +83,8 @@
|
|
|
83
83
|
font-size: var(--prose-h4);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
/*
|
|
87
|
-
|
|
88
|
-
it without having to restate the rule. */
|
|
86
|
+
/* --link is a theme-level token (core/base.css also reads it for bare links);
|
|
87
|
+
prose falls back to --primary so a theme that never sets it is unaffected. */
|
|
89
88
|
.prose :where(a) {
|
|
90
89
|
color: var(--link, var(--primary));
|
|
91
90
|
text-decoration-line: underline;
|
|
@@ -18,6 +18,22 @@
|
|
|
18
18
|
border: 0;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/* Enlarge a small control's touch target on touch-primary devices without
|
|
22
|
+
growing the visual. Opt-in — apply to genuinely small targets only. The
|
|
23
|
+
::after exists only under (pointer: coarse), so on fine pointers the class
|
|
24
|
+
is fully neutral. */
|
|
25
|
+
@media (pointer: coarse) {
|
|
26
|
+
.touch-target {
|
|
27
|
+
position: relative;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.touch-target::after {
|
|
31
|
+
content: "";
|
|
32
|
+
position: absolute;
|
|
33
|
+
inset: calc(var(--space-20) * -1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
.overflow-auto {
|
|
22
38
|
overflow: auto;
|
|
23
39
|
}
|
package/src/js/selectors.js
CHANGED
|
@@ -25,6 +25,7 @@ export const CLASSES = {
|
|
|
25
25
|
// for aria-invalid/danger state. Optional — degrades to no-op.
|
|
26
26
|
field: "field",
|
|
27
27
|
// surface.js — state class on the open flyout/menu/dialog surface.
|
|
28
|
+
// status.js writes the same class on the status bar while a message shows.
|
|
28
29
|
open: "is-open",
|
|
29
30
|
// surface.js — state class while the surface renders as a mobile sheet.
|
|
30
31
|
sheet: "is-sheet",
|