actual-css 0.4.2 → 0.6.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 +66 -3
- package/README.md +2 -2
- package/dist/actual.css +54 -14
- package/dist/actual.full.css +744 -185
- 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/browser-support.md +14 -14
- package/docs/design-notes/enhancement-contract.md +30 -13
- package/docs/design-notes/forced-colors.md +11 -7
- package/docs/design-notes/grid.md +4 -4
- package/docs/design-notes/naming.md +15 -9
- package/docs/design-notes/platform-alignment.md +9 -0
- package/docs/design-notes/references.md +4 -0
- package/docs/design-notes/spacing-units.md +286 -0
- package/docs/design-notes/steps.md +748 -0
- package/docs/design-notes/widget-primitives.md +32 -15
- package/docs/navigation.json +2 -0
- package/docs/pages/components/alert.md +14 -9
- package/docs/pages/components/app-navigation.md +2 -0
- package/docs/pages/components/aura.md +102 -6
- package/docs/pages/components/avatar.md +9 -6
- package/docs/pages/components/badge.md +27 -9
- package/docs/pages/components/button.md +25 -18
- package/docs/pages/components/card.md +27 -7
- package/docs/pages/components/chat.md +1 -1
- package/docs/pages/components/data-list.md +72 -0
- package/docs/pages/components/dialog.md +12 -7
- package/docs/pages/components/drawer.md +3 -1
- package/docs/pages/components/fab.md +14 -10
- package/docs/pages/components/indicator.md +6 -6
- package/docs/pages/components/list.md +11 -2
- package/docs/pages/components/meter.md +56 -1
- package/docs/pages/components/navbar.md +1 -1
- package/docs/pages/components/pagination.md +1 -1
- package/docs/pages/components/progress.md +10 -0
- package/docs/pages/components/rating.md +4 -4
- package/docs/pages/components/skeleton.md +3 -1
- package/docs/pages/components/spinner.md +1 -1
- package/docs/pages/components/steps.md +379 -47
- package/docs/pages/components/table.md +6 -5
- package/docs/pages/enhancements/flyout.md +14 -10
- package/docs/pages/enhancements/overview.md +2 -2
- package/docs/pages/enhancements/scrollspy.md +1 -1
- package/docs/pages/enhancements/status-bar.md +10 -1
- package/docs/pages/enhancements/tabs.md +1 -1
- package/docs/pages/examples/overview.md +4 -1
- package/docs/pages/forms/choice-cards.md +4 -4
- package/docs/pages/forms/combobox.md +87 -0
- package/docs/pages/forms/floating-field.md +5 -3
- package/docs/pages/forms/joined-controls.md +6 -4
- package/docs/pages/forms/labels.md +8 -5
- package/docs/pages/forms/overview.md +26 -19
- package/docs/pages/forms/password.md +3 -2
- package/docs/pages/forms/range.md +15 -2
- package/docs/pages/forms/states-and-sizes.md +7 -5
- package/docs/pages/forms/validation.md +15 -9
- package/docs/pages/foundations/philosophy.md +11 -1
- package/docs/pages/foundations/tokens.md +16 -9
- package/docs/pages/foundations/typography.md +11 -3
- package/docs/pages/guides/bootstrap.md +3 -3
- package/docs/pages/guides/introduction.md +2 -2
- package/docs/pages/guides/modular-import.md +21 -10
- package/docs/pages/guides/progressive-enhancement.md +75 -54
- package/docs/pages/guides/tailwind.md +2 -2
- package/docs/pages/layout/app-shell.md +4 -4
- package/docs/pages/layout/choosing.md +10 -6
- package/docs/pages/layout/grid.md +11 -10
- package/docs/pages/layout/scroll-snap.md +2 -0
- package/docs/pages/layout/sidebar-layout.md +2 -0
- package/docs/pages/layout/stack.md +10 -6
- package/docs/pages/layout/topbar.md +2 -0
- package/docs/pages/patterns/structured-lists.md +7 -7
- package/docs/pages/utilities/accessibility.md +19 -1
- package/docs/pages/utilities/flex.md +20 -13
- package/docs/pages/utilities/links.md +1 -1
- package/docs/pages/utilities/list.md +1 -1
- package/docs/pages/utilities/overflow.md +14 -7
- package/docs/pages/utilities/overview.md +22 -0
- package/docs/pages/utilities/shape.md +1 -1
- package/docs/pages/utilities/sizing-wrapping.md +10 -8
- package/docs/pages/utilities/spacing.md +26 -19
- package/docs/pages/utilities/text.md +1 -1
- package/llms.txt +27 -4
- package/package.json +3 -2
- package/scripts/reserved-classes.json +8 -1
- package/src/css/components/data-list.css +27 -0
- package/src/css/components/drawer.css +30 -11
- package/src/css/components/fab.css +44 -8
- package/src/css/components/flyout.css +17 -12
- package/src/css/components/index.css +1 -0
- package/src/css/components/list.css +3 -1
- package/src/css/components/meter.css +28 -1
- package/src/css/components/modal.css +28 -11
- package/src/css/components/progress.css +5 -0
- package/src/css/components/status-bar.css +31 -15
- package/src/css/components/steps.css +289 -55
- package/src/css/components/surface.css +5 -3
- 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 +24 -9
- package/src/css/core/variants.css +17 -4
- package/src/css/effects/aura.css +101 -11
- package/src/css/forms/custom-select.css +1 -1
- package/src/css/forms/floating-field.css +8 -6
- package/src/css/forms/form.css +4 -4
- package/src/css/layout/container-query.css +37 -13
- package/src/css/layout/grid.css +7 -7
- package/src/css/layout/index.css +1 -1
- package/src/css/typography/prose.css +2 -3
- package/src/css/utilities/base.css +16 -0
- package/src/js/password.js +1 -1
- 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
|
@@ -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 {
|
|
@@ -1,20 +1,54 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Steps — semantic ordered-list progression
|
|
3
|
-
* the row when they fit and hold a minimum width otherwise, so the sequence
|
|
4
|
-
* scrolls horizontally only when it genuinely cannot fit. No breakpoint decides
|
|
5
|
-
* this — the item minimum tracks the real content, not an arbitrary width.
|
|
2
|
+
* Steps — semantic ordered-list progression for a multi-step process.
|
|
6
3
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* One primitive, two explicit compositions. Both classes are required:
|
|
5
|
+
*
|
|
6
|
+
* <ol class="steps steps-horizontal"> horizontal, 2 to 5 stages
|
|
7
|
+
* <ol class="steps steps-vertical"> vertical, any number of stages
|
|
8
|
+
*
|
|
9
|
+
* `.steps` is what a step *is* — the counter, the marker, `.step-label`,
|
|
10
|
+
* `.step-complete`, `aria-current="step"`. It carries no orientation, so it is
|
|
11
|
+
* never written alone. `.steps-horizontal` and `.steps-vertical` are what a
|
|
12
|
+
* sequence *looks like*, and they are peers: neither is the default the other
|
|
13
|
+
* has to exclude, so no rule says `:not(...)` and no rule undoes another's
|
|
14
|
+
* layout.
|
|
15
|
+
*
|
|
16
|
+
* Orientation and labels are independent dimensions. `.step-label` is optional
|
|
17
|
+
* in either orientation; when a sequence carries names, every step carries
|
|
18
|
+
* one:
|
|
19
|
+
*
|
|
20
|
+
* empty steps .step-label on every step
|
|
21
|
+
* horizontal compact progression named sequence, stacked or inline
|
|
22
|
+
* vertical compact rail named sequence, labels beside markers
|
|
23
|
+
*
|
|
24
|
+
* An empty step is a marker and nothing else, so it is compact by structure —
|
|
25
|
+
* `> li:empty` in both orientations, no variant class, and nothing authored
|
|
26
|
+
* only to be hidden again. The page around it owns the step name.
|
|
27
|
+
*
|
|
28
|
+
* A label may be an `a[href]`, which is the whole interactive surface: the
|
|
29
|
+
* marker is never navigable, so navigating a flow means naming its
|
|
30
|
+
* destinations. Anything else focusable in a step is out of contract.
|
|
31
|
+
*
|
|
32
|
+
* The framework never hides an authored label to solve a layout problem. A
|
|
33
|
+
* labelled row that outgrows its space scrolls. An `actual-container` size
|
|
34
|
+
* context buys it one thing: the wide representation, marker beside label.
|
|
35
|
+
*
|
|
36
|
+
* See docs/design-notes/steps.md for the threshold, the selector shapes, the
|
|
37
|
+
* rejected alternatives, and why there is no forced-colors branch.
|
|
38
|
+
*
|
|
39
|
+
* Each public hook is followed by the class that owns it.
|
|
9
40
|
*
|
|
10
41
|
* Public hooks:
|
|
11
|
-
* --step-size
|
|
12
|
-
* --step-
|
|
13
|
-
* --step-
|
|
14
|
-
* --step-
|
|
15
|
-
* --step-
|
|
16
|
-
* --step-
|
|
17
|
-
* --step-
|
|
42
|
+
* --step-size .steps
|
|
43
|
+
* --step-inline-gap .steps
|
|
44
|
+
* --step-line-size .steps
|
|
45
|
+
* --step-marker-radius .steps
|
|
46
|
+
* --step-complete-mark .steps
|
|
47
|
+
* --step-min .steps-horizontal
|
|
48
|
+
* --step-gap .steps-horizontal
|
|
49
|
+
* --step-connector .steps-horizontal
|
|
50
|
+
* --step-inline-connector .steps-horizontal
|
|
51
|
+
* --step-vertical-gap .steps-vertical
|
|
18
52
|
*
|
|
19
53
|
* Internal:
|
|
20
54
|
* --step-marker-bg
|
|
@@ -22,10 +56,12 @@
|
|
|
22
56
|
* --step-marker-fg
|
|
23
57
|
* --step-line
|
|
24
58
|
*/
|
|
59
|
+
|
|
60
|
+
/* Step primitive --------------------------------------------------------- */
|
|
61
|
+
|
|
25
62
|
.steps {
|
|
26
63
|
--step-size: 1.75rem;
|
|
27
|
-
--step-
|
|
28
|
-
--step-gap: var(--space-20);
|
|
64
|
+
--step-inline-gap: var(--space-20);
|
|
29
65
|
--step-line-size: var(--border-width);
|
|
30
66
|
--step-marker-bg: var(--surface);
|
|
31
67
|
--step-marker-border: var(--border);
|
|
@@ -35,29 +71,14 @@
|
|
|
35
71
|
|
|
36
72
|
counter-reset: actual-step;
|
|
37
73
|
display: flex;
|
|
38
|
-
flex-direction: row;
|
|
39
|
-
inline-size: 100%;
|
|
40
74
|
margin: 0;
|
|
41
75
|
padding: 0;
|
|
42
76
|
list-style: none;
|
|
43
|
-
/* Fill when it fits, scroll when it cannot: items never shrink below
|
|
44
|
-
--step-min, so labels keep a readable width and the sequence scrolls
|
|
45
|
-
horizontally instead of squishing. overscroll-behavior keeps the scroll
|
|
46
|
-
from chaining to the page. */
|
|
47
|
-
overflow-x: auto;
|
|
48
|
-
overscroll-behavior-inline: contain;
|
|
49
77
|
}
|
|
50
78
|
|
|
51
79
|
.steps > li {
|
|
52
80
|
position: relative;
|
|
53
|
-
display: grid;
|
|
54
|
-
flex: 1 0 var(--step-min);
|
|
55
|
-
grid-template-rows: var(--step-size) auto;
|
|
56
|
-
gap: var(--step-gap);
|
|
57
|
-
justify-items: center;
|
|
58
|
-
min-inline-size: max(var(--step-size), var(--step-min));
|
|
59
81
|
color: var(--text-muted);
|
|
60
|
-
text-align: center;
|
|
61
82
|
counter-increment: actual-step;
|
|
62
83
|
}
|
|
63
84
|
|
|
@@ -78,46 +99,259 @@
|
|
|
78
99
|
line-height: 1;
|
|
79
100
|
}
|
|
80
101
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
/* The marker carries the state, so the label reads a notch below it — set on
|
|
103
|
+
the component, never per representation: a size that changed with the layout
|
|
104
|
+
would resize the text under a reader dragging a window. `color: inherit` is
|
|
105
|
+
here rather than in a rule of its own for `a.step-label`, because a span
|
|
106
|
+
inherits its ink anyway; only a link has anything to take back, and taking it
|
|
107
|
+
back for every label costs nothing and one rule less. A navigable label keeps
|
|
108
|
+
its underline, hover and focus ring — just not a link color, which would read
|
|
109
|
+
ahead of the marker states.
|
|
110
|
+
|
|
111
|
+
Scoped to `.steps`, unlike `.menu-item-text` and the framework's other
|
|
112
|
+
sub-part classes: a bare `.step-label` weighs (0,1,0), exactly tying
|
|
113
|
+
`.prose :where(a)`, so a stepper in prose would be decided by bundle order. */
|
|
114
|
+
.steps .step-label {
|
|
115
|
+
font-size: var(--font-size-sm);
|
|
116
|
+
line-height: var(--line-height-tight);
|
|
117
|
+
color: inherit;
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
|
|
97
|
-
|
|
120
|
+
/* Each composition gives the connector its own geometry and background, so the
|
|
121
|
+
only shared fact is which steps get one — every step but the last. Stated as
|
|
122
|
+
the condition rather than as a `content: none` rule undoing a `content: ""`
|
|
123
|
+
rule: a pseudo-element with no content generates no box, so a composition can
|
|
124
|
+
address `> li::after` freely and still not trail a line past the last step. */
|
|
125
|
+
.steps > li:not(:last-child)::after {
|
|
126
|
+
content: "";
|
|
98
127
|
}
|
|
99
128
|
|
|
100
|
-
|
|
129
|
+
/* Prefixed like `.step-label`, unlike the framework's bare `.primary` /
|
|
130
|
+
`.outline` modifiers: those qualify a component on its own element, this
|
|
131
|
+
marks one item inside one. A bare `.complete` would also claim a very
|
|
132
|
+
ordinary English word globally, for a single component's single state. */
|
|
133
|
+
.steps > .step-complete {
|
|
101
134
|
--step-marker-bg: var(--state-selected);
|
|
102
135
|
--step-marker-border: var(--state-selected);
|
|
103
136
|
--step-marker-fg: var(--state-selected-fg);
|
|
137
|
+
--step-line: var(--state-selected);
|
|
138
|
+
|
|
139
|
+
color: var(--text);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Complete owns the accented connector that reaches the current step, so the
|
|
143
|
+
connector leaving current goes back to neutral. Declared after
|
|
144
|
+
.step-complete at equal specificity: current wins on every channel. */
|
|
145
|
+
.steps > [aria-current="step"] {
|
|
146
|
+
--step-marker-bg: var(--surface);
|
|
147
|
+
--step-marker-border: var(--state-selected);
|
|
148
|
+
--step-marker-fg: var(--state-selected);
|
|
149
|
+
--step-line: var(--border);
|
|
104
150
|
|
|
105
151
|
color: var(--text);
|
|
106
152
|
}
|
|
107
153
|
|
|
108
|
-
|
|
109
|
-
never competes with the outline channel owned by focus. */
|
|
110
|
-
.steps > :is(.complete, [aria-current="step"])::before {
|
|
154
|
+
.steps > [aria-current="step"]::before {
|
|
111
155
|
border-width: calc(var(--border-width) * 2);
|
|
112
156
|
}
|
|
113
157
|
|
|
114
|
-
|
|
115
|
-
|
|
158
|
+
/* Weight marks "where I am now". Complete needs none: its filled disc already
|
|
159
|
+
reads as strongly. */
|
|
160
|
+
.steps > [aria-current="step"] .step-label {
|
|
161
|
+
font-weight: var(--font-weight-strong);
|
|
116
162
|
}
|
|
117
163
|
|
|
118
|
-
|
|
119
|
-
--step-complete-mark accepts any content value and falls back to the
|
|
120
|
-
counter, so existing numbered steppers are unchanged. */
|
|
121
|
-
.steps > .complete::before {
|
|
164
|
+
.steps > .step-complete:not([aria-current="step"])::before {
|
|
122
165
|
content: var(--step-complete-mark, counter(actual-step));
|
|
123
166
|
}
|
|
167
|
+
|
|
168
|
+
/* Horizontal ------------------------------------------------------------- */
|
|
169
|
+
|
|
170
|
+
.steps-horizontal {
|
|
171
|
+
--step-min: 7rem;
|
|
172
|
+
--step-gap: var(--space-20);
|
|
173
|
+
|
|
174
|
+
inline-size: 100%;
|
|
175
|
+
overflow-x: auto;
|
|
176
|
+
/* Stated, never left to `overflow-x` alone: one scrolling axis computes the
|
|
177
|
+
other to `auto`, and a row hugs fractional content closely enough that a
|
|
178
|
+
rounding difference then raises a phantom vertical scrollbar. */
|
|
179
|
+
overflow-y: hidden;
|
|
180
|
+
overscroll-behavior-inline: contain;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* A scroll container clips at the padding edge, so a navigable row reserves the
|
|
184
|
+
focus ring's own width and offset. Only this composition scrolls, and only a
|
|
185
|
+
link has a ring to protect. */
|
|
186
|
+
.steps-horizontal:has(a[href]) {
|
|
187
|
+
padding-block: calc(var(--focus-outline-offset) + var(--border-width) * 2);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* One explicit row, the marker's: a `.step-label` is auto-placed into an
|
|
191
|
+
implicit second row, and two tracks are also the only thing `gap` has to sit
|
|
192
|
+
between. So an empty step measures exactly `--step-size`, and the rule below
|
|
193
|
+
takes back nothing. `var(--step-size) auto` would build that second row
|
|
194
|
+
whether or not a label ever arrives, and the compact form would then have to
|
|
195
|
+
remove both the track and the gap. */
|
|
196
|
+
.steps-horizontal > li {
|
|
197
|
+
display: grid;
|
|
198
|
+
flex: 1 0 var(--step-min);
|
|
199
|
+
grid-template-rows: var(--step-size);
|
|
200
|
+
gap: var(--step-gap);
|
|
201
|
+
justify-items: center;
|
|
202
|
+
min-inline-size: max(var(--step-size), var(--step-min));
|
|
203
|
+
text-align: center;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* An empty step is a marker and nothing else, so it needs a marker's width
|
|
207
|
+
rather than a reading width. That is what lets five of them fit a phone with
|
|
208
|
+
no size context and no variant class.
|
|
209
|
+
|
|
210
|
+
`justify-items` is not an override of the row's centring: the marker is
|
|
211
|
+
centred because a label sits under it and the two share a centre, and with no
|
|
212
|
+
label there is nothing to centre against. The marker takes the start of its
|
|
213
|
+
own share instead, the connector below fills the rest of it, and the last
|
|
214
|
+
step has no share to fill — so the track runs edge to edge and lines up with
|
|
215
|
+
the text around it, the way the inline representation does.
|
|
216
|
+
|
|
217
|
+
`:empty` says exactly what the markup says, the way `.badge:empty` does, and
|
|
218
|
+
it reads the item's own content: bare text in an `<li>` keeps a reading width
|
|
219
|
+
like its wrapped peers, where `> li:has(.step-label)` would give it a marker
|
|
220
|
+
floor and skew the row. It also predates `:has()` by a decade, so the compact
|
|
221
|
+
form reaches the Degraded tier and only the inline bonus needs `:has()`. */
|
|
222
|
+
.steps-horizontal > li:empty {
|
|
223
|
+
flex: 1 1 0;
|
|
224
|
+
justify-items: start;
|
|
225
|
+
min-inline-size: var(--step-size);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.steps-horizontal > li:empty::after {
|
|
229
|
+
inset-inline-start: var(--step-size);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.steps-horizontal > li:empty:last-child {
|
|
233
|
+
flex: 0 0 auto;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* The pseudo-element is marker-height so --step-connector may be any complete
|
|
237
|
+
background value. */
|
|
238
|
+
.steps-horizontal > li::after {
|
|
239
|
+
position: absolute;
|
|
240
|
+
inset-block-start: 0;
|
|
241
|
+
inset-inline-start: calc(50% + var(--step-size) / 2);
|
|
242
|
+
inline-size: calc(100% - var(--step-size));
|
|
243
|
+
block-size: var(--step-size);
|
|
244
|
+
background: var(
|
|
245
|
+
--step-connector,
|
|
246
|
+
linear-gradient(var(--step-line), var(--step-line)) center /
|
|
247
|
+
100% var(--step-line-size) no-repeat
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
* The one horizontal container query. Past 60rem a labelled row has the room
|
|
253
|
+
* to put marker and label inline and still leave the connector a real region
|
|
254
|
+
* between groups, rather than a stub. Calibrated on five steps — the widest
|
|
255
|
+
* supported row, and therefore the binding case — and it counts nothing, so it
|
|
256
|
+
* serves every count. Below it, stacked; a marker row is already the shape
|
|
257
|
+
* this query produces and stays out of it.
|
|
258
|
+
*
|
|
259
|
+
* Horizontal is a 2-5 step component. Outside that domain the rule simply
|
|
260
|
+
* applies as written, because a row that is out of contract is not owed a
|
|
261
|
+
* curated fallback.
|
|
262
|
+
*/
|
|
263
|
+
@supports (container-type: inline-size) {
|
|
264
|
+
@container actual-container (inline-size >= 60rem) {
|
|
265
|
+
.steps-horizontal:has(.step-label) > li {
|
|
266
|
+
display: flex;
|
|
267
|
+
flex: 1 1 auto;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: var(--step-inline-gap);
|
|
270
|
+
min-inline-size: 0;
|
|
271
|
+
text-align: start;
|
|
272
|
+
white-space: nowrap;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.steps-horizontal:has(.step-label) > li::after {
|
|
276
|
+
position: static;
|
|
277
|
+
flex: 1 1 2rem;
|
|
278
|
+
inline-size: auto;
|
|
279
|
+
block-size: var(--step-size);
|
|
280
|
+
margin-inline-end: var(--step-inline-gap);
|
|
281
|
+
background: var(
|
|
282
|
+
--step-inline-connector,
|
|
283
|
+
var(
|
|
284
|
+
--step-connector,
|
|
285
|
+
linear-gradient(var(--step-line), var(--step-line)) center /
|
|
286
|
+
100% var(--step-line-size) no-repeat
|
|
287
|
+
)
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.steps-horizontal:has(.step-label) > li:last-child {
|
|
292
|
+
flex: 0 0 auto;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* Vertical --------------------------------------------------------------- */
|
|
298
|
+
|
|
299
|
+
.steps-vertical {
|
|
300
|
+
--step-vertical-gap: var(--space-40);
|
|
301
|
+
|
|
302
|
+
flex-direction: column;
|
|
303
|
+
gap: var(--step-vertical-gap);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* `justify-items` looks like a reset and is not one — nothing here resets
|
|
307
|
+
anything, since the horizontal rules never applied. Grid items blockify, so
|
|
308
|
+
without it a label stretches the whole 1fr track: 264px against 75px for an
|
|
309
|
+
`a.step-label`, a full-width focus ring the row does not give the same link. */
|
|
310
|
+
.steps-vertical > li {
|
|
311
|
+
display: grid;
|
|
312
|
+
grid-template-columns: var(--step-size) minmax(0, 1fr);
|
|
313
|
+
align-items: start;
|
|
314
|
+
justify-items: start;
|
|
315
|
+
gap: var(--step-inline-gap);
|
|
316
|
+
min-block-size: var(--step-size);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* An empty step is a marker rail. The column cannot use the row's implicit
|
|
320
|
+
second track, because `grid-auto-flow` is `row`: an auto-placed label would
|
|
321
|
+
land *under* its marker. Its second track is therefore explicit, and this
|
|
322
|
+
takes it back.
|
|
323
|
+
|
|
324
|
+
Silent in a stretched column, where the item fills its line whatever its
|
|
325
|
+
tracks say. It bites in a shrink-to-fit box — which is what a sticky
|
|
326
|
+
progress rail usually is — where the label track and the gap to it make the
|
|
327
|
+
rail `--step-inline-gap` wider than the markers it draws: measured 36px
|
|
328
|
+
against 28px. No `gap: 0` needed; one track has nothing to sit beside. */
|
|
329
|
+
.steps-vertical > li:empty {
|
|
330
|
+
grid-template-columns: var(--step-size);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* The row starts at the top so a wrapped label begins level with its marker.
|
|
334
|
+
align-self only bites on a single line, which would otherwise float above
|
|
335
|
+
the marker's centre.
|
|
336
|
+
|
|
337
|
+
The one `.step-label` rule that keeps a child combinator: `align-self` is a
|
|
338
|
+
grid-item property, so this declaration is meaningless on anything but a
|
|
339
|
+
direct child of the row. Elsewhere the label is addressed as a descendant —
|
|
340
|
+
the framework owns the structure, and repeating it buys nothing. */
|
|
341
|
+
.steps-vertical > li > .step-label {
|
|
342
|
+
align-self: center;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* The vertical track publishes no hook of its own: a horizontal connector value
|
|
346
|
+
cannot transpose onto this geometry, and this selector is already a reachable
|
|
347
|
+
override for the design that finally asks. */
|
|
348
|
+
.steps-vertical > li::after {
|
|
349
|
+
position: absolute;
|
|
350
|
+
inset-block-start: var(--step-size);
|
|
351
|
+
inset-inline-start: calc((var(--step-size) - var(--step-line-size)) / 2);
|
|
352
|
+
inline-size: var(--step-line-size);
|
|
353
|
+
block-size: calc(100% - var(--step-size) + var(--step-vertical-gap));
|
|
354
|
+
background:
|
|
355
|
+
linear-gradient(var(--step-line), var(--step-line)) center / var(--step-line-size) 100%
|
|
356
|
+
no-repeat;
|
|
357
|
+
}
|
|
@@ -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.
|
|
@@ -135,6 +149,7 @@
|
|
|
135
149
|
--icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238a8594' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
|
|
136
150
|
--icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
|
|
137
151
|
--icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3C/svg%3E");
|
|
152
|
+
--icon-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
|
|
138
153
|
|
|
139
154
|
/* Viewport size tokens — fallback vh/vw with dvh/vi enhancement.
|
|
140
155
|
Consumed by full-viewport components (app-shell, drawer, modal, flyout).
|