actual-css 0.8.0 → 0.9.1
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 +76 -0
- package/components.json +2 -0
- package/dist/actual.css +10 -3
- package/dist/actual.full.css +360 -109
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/pages/components/alert.md +6 -1
- package/docs/pages/components/dialog.md +5 -0
- package/docs/pages/components/drawer.md +13 -0
- package/docs/pages/components/skeleton.md +3 -1
- package/docs/pages/enhancements/flyout.md +16 -2
- package/docs/pages/forms/choice-cards.md +5 -4
- package/docs/pages/foundations/tokens.md +1 -1
- package/docs/pages/guides/progressive-enhancement.md +12 -8
- package/package.json +3 -2
- package/src/css/components/accordion.css +2 -0
- package/src/css/components/actions.css +2 -0
- package/src/css/components/alert.css +2 -0
- package/src/css/components/app-nav.css +2 -0
- package/src/css/components/avatar.css +2 -0
- package/src/css/components/badge.css +2 -0
- package/src/css/components/breadcrumb.css +2 -0
- package/src/css/components/busy.css +2 -0
- package/src/css/components/button.css +2 -0
- package/src/css/components/card.css +2 -0
- package/src/css/components/chat.css +2 -0
- package/src/css/components/data-list.css +2 -0
- package/src/css/components/drawer.css +55 -27
- package/src/css/components/fab.css +2 -0
- package/src/css/components/flyout.css +2 -0
- package/src/css/components/indicator.css +2 -0
- package/src/css/components/join.css +2 -0
- package/src/css/components/key.css +2 -0
- package/src/css/components/list.css +2 -0
- package/src/css/components/meter.css +2 -0
- package/src/css/components/modal.css +47 -40
- package/src/css/components/navbar.css +2 -0
- package/src/css/components/pagination.css +2 -0
- package/src/css/components/progress.css +2 -0
- package/src/css/components/rating.css +2 -0
- package/src/css/components/scrollspy.css +2 -0
- package/src/css/components/skeleton.css +17 -4
- package/src/css/components/spinner.css +2 -0
- package/src/css/components/status-bar.css +2 -0
- package/src/css/components/steps.css +2 -0
- package/src/css/components/tab.css +2 -0
- package/src/css/components/table.css +10 -0
- package/src/css/components/tooltip.css +2 -0
- package/src/css/core/print.css +3 -0
- package/src/css/core/variants.css +7 -3
- package/src/css/effects/aura.css +2 -0
- package/src/css/forms/choice-card.css +4 -0
- package/src/css/forms/choice.css +70 -26
- package/src/css/forms/control.css +2 -0
- package/src/css/forms/floating-field.css +5 -1
- package/src/css/forms/form-actions.css +2 -0
- package/src/css/forms/form.css +2 -0
- package/src/css/forms/input-icon.css +2 -0
- package/src/css/forms/native.css +2 -0
- package/src/css/forms/otp.css +10 -0
- package/src/css/forms/range.css +2 -0
- package/src/css/forms/select.css +2 -0
- package/src/css/forms/switch.css +11 -3
- package/src/css/forms/validation.css +2 -0
- package/src/css/layout/app-layout.css +2 -0
- package/src/css/layout/app-shell.css +5 -1
- package/src/css/layout/center.css +2 -0
- package/src/css/layout/cluster.css +2 -0
- package/src/css/layout/column-layout.css +2 -0
- package/src/css/layout/frame.css +2 -0
- package/src/css/layout/grid.css +2 -0
- package/src/css/layout/media.css +2 -1
- package/src/css/layout/scroll-snap.css +2 -0
- package/src/css/layout/scroll-target.css +2 -0
- package/src/css/layout/sidebar-layout.css +2 -0
- package/src/css/layout/stack.css +2 -1
- package/src/css/layout/switcher.css +2 -0
- package/src/css/layout/topbar.css +2 -0
- package/src/css/typography/fluid.css +2 -0
- package/src/css/typography/lead.css +2 -1
- package/src/css/typography/overline.css +2 -0
- package/src/css/typography/prose.css +2 -0
- package/src/css/utilities/base.css +6 -1
- package/src/js/context-menu.js +56 -15
- package/src/js/enhancement-loader.js +5 -1
- package/src/js/escape.js +11 -1
- package/src/js/flyout.js +6 -1
- package/src/js/focus.js +8 -3
- package/src/js/surface.js +28 -0
- package/src/js/tooltip.js +10 -4
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Modal shell styling for native dialog elements.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/dialog.md
|
|
5
|
+
*
|
|
4
6
|
* Spacing, radius, transitions, and focus treatment come from shared tokens.
|
|
5
7
|
* Opening behavior and intent-specific decisions stay outside this component.
|
|
6
8
|
*
|
|
@@ -12,16 +14,15 @@
|
|
|
12
14
|
*
|
|
13
15
|
* Internal:
|
|
14
16
|
* --dialog-close-icon-size
|
|
17
|
+
* --dialog-focus-bleed
|
|
15
18
|
* --dialog-viewport-block
|
|
16
19
|
* --dialog-viewport-gap-default
|
|
17
20
|
* --dialog-viewport-gap-2x
|
|
18
21
|
*/
|
|
19
|
-
dialog.modal {
|
|
20
|
-
/* --dialog-viewport-gap stays fallback-only
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
responsive default lives in an internal token instead, so a media query
|
|
24
|
-
can still move it without closing the hook.
|
|
22
|
+
:where(dialog).modal {
|
|
23
|
+
/* --dialog-viewport-gap stays fallback-only so the responsive default can
|
|
24
|
+
live in an internal token: a media query moves it without closing the
|
|
25
|
+
public hook.
|
|
25
26
|
|
|
26
27
|
calc() multiplication is not in the supported browser range, so the
|
|
27
28
|
doubled gap is spelled out with an additive calc. */
|
|
@@ -35,10 +36,8 @@ dialog.modal {
|
|
|
35
36
|
provides the containing block for the absolutely positioned close button. */
|
|
36
37
|
position: fixed;
|
|
37
38
|
|
|
38
|
-
/*
|
|
39
|
-
|
|
40
|
-
public hook would silently keep this default. Same reason choice.css never
|
|
41
|
-
declares --choice-control-offset. */
|
|
39
|
+
/* The root is :where(dialog).modal (0-1-0), so a single author class can
|
|
40
|
+
outrank these defaults — no fallback-only indirection needed here. */
|
|
42
41
|
max-inline-size: min(calc(100% - var(--dialog-viewport-gap-2x)), var(--modal-size, 32rem));
|
|
43
42
|
|
|
44
43
|
/* Stable viewport cap for the panel: dvh tracks the dynamic browser toolbar
|
|
@@ -68,8 +67,8 @@ dialog.modal {
|
|
|
68
67
|
transform var(--duration) var(--ease-exit);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
dialog.modal > form,
|
|
72
|
-
dialog.modal > .stack {
|
|
70
|
+
:where(dialog).modal > form,
|
|
71
|
+
:where(dialog).modal > .stack {
|
|
73
72
|
display: grid;
|
|
74
73
|
gap: var(--space-40);
|
|
75
74
|
max-block-size: calc(var(--dialog-viewport-block) - var(--dialog-viewport-gap-2x));
|
|
@@ -79,7 +78,7 @@ dialog.modal > .stack {
|
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
@supports (block-size: 100svh) {
|
|
82
|
-
dialog.modal {
|
|
81
|
+
:where(dialog).modal {
|
|
83
82
|
--dialog-viewport-block: 100svh;
|
|
84
83
|
}
|
|
85
84
|
}
|
|
@@ -87,42 +86,50 @@ dialog.modal > .stack {
|
|
|
87
86
|
/* Keep the dialog off the viewport edges on small screens. Moves the internal
|
|
88
87
|
default, not the public hook, so an author override still wins here too. */
|
|
89
88
|
@media (max-width: 30rem) {
|
|
90
|
-
dialog.modal {
|
|
89
|
+
:where(dialog).modal {
|
|
91
90
|
--dialog-viewport-gap-default: var(--space-30);
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
dialog.modal.scrollable > form,
|
|
96
|
-
dialog.modal.scrollable > .stack {
|
|
94
|
+
:where(dialog).modal.scrollable > form,
|
|
95
|
+
:where(dialog).modal.scrollable > .stack {
|
|
97
96
|
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
98
97
|
overflow: hidden;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
|
-
dialog.modal.scrollable > form > :not(:is(header, footer)),
|
|
102
|
-
dialog.modal.scrollable > .stack > :not(:is(header, footer)) {
|
|
100
|
+
:where(dialog).modal.scrollable > form > :not(:is(header, footer)),
|
|
101
|
+
:where(dialog).modal.scrollable > .stack > :not(:is(header, footer)) {
|
|
102
|
+
--dialog-focus-bleed: calc(var(--focus-outline-offset) + var(--border-width) * 2);
|
|
103
|
+
|
|
103
104
|
min-block-size: 0;
|
|
105
|
+
/* Keep focus paint inside the clip without moving the body off the fixed
|
|
106
|
+
header and footer edges. */
|
|
107
|
+
margin-inline: calc(var(--dialog-focus-bleed) * -1);
|
|
108
|
+
padding-inline: var(--dialog-focus-bleed);
|
|
104
109
|
overflow: auto;
|
|
105
110
|
overscroll-behavior: contain;
|
|
106
111
|
}
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
/* Anatomy is bounded to the structural slots (direct children of the
|
|
114
|
+
form/.stack body): a header or footer deeper in the content keeps its own
|
|
115
|
+
rhythm and is not restyled as the modal's chrome. */
|
|
116
|
+
:where(dialog).modal > :where(form, .stack) > :is(header, footer) > :first-child {
|
|
110
117
|
margin-block-start: 0;
|
|
111
118
|
}
|
|
112
119
|
|
|
113
|
-
dialog.modal header > :last-child
|
|
114
|
-
dialog.modal footer > :last-child {
|
|
120
|
+
:where(dialog).modal > :where(form, .stack) > :is(header, footer) > :last-child {
|
|
115
121
|
margin-block-end: 0;
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
/* The close button is anchored to the dialog at top inline-end, out of the
|
|
119
|
-
content flow; headers reserve inline room so titles never run under it.
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
content flow; headers reserve inline room so titles never run under it.
|
|
126
|
+
The form/.stack anatomy is structural, so it stays in :where() and never
|
|
127
|
+
lends .stack's specificity to a bare <form>. */
|
|
128
|
+
:where(dialog).modal > :where(form, .stack) > header {
|
|
122
129
|
padding-inline-end: calc(var(--control-size) + var(--space-30));
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
dialog.modal footer {
|
|
132
|
+
:where(dialog).modal > :where(form, .stack) > footer {
|
|
126
133
|
display: flex;
|
|
127
134
|
flex-wrap: wrap;
|
|
128
135
|
justify-content: flex-end;
|
|
@@ -132,17 +139,17 @@ dialog.modal footer {
|
|
|
132
139
|
/* Confirmation layout — a focused message followed by a visually distinct
|
|
133
140
|
action band. The media primitive owns icon/content alignment; this variant
|
|
134
141
|
only removes the standard form inset so both regions can own their padding. */
|
|
135
|
-
dialog.modal.dialog-confirmation > form {
|
|
142
|
+
:where(dialog).modal.dialog-confirmation > form {
|
|
136
143
|
gap: 0;
|
|
137
144
|
padding: 0;
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
dialog.modal.dialog-confirmation > form > .media {
|
|
147
|
+
:where(dialog).modal.dialog-confirmation > form > .media {
|
|
141
148
|
gap: var(--space-40);
|
|
142
149
|
padding: var(--space-50);
|
|
143
150
|
}
|
|
144
151
|
|
|
145
|
-
dialog.modal.dialog-confirmation > form > footer {
|
|
152
|
+
:where(dialog).modal.dialog-confirmation > form > footer {
|
|
146
153
|
padding: var(--space-40) var(--space-50);
|
|
147
154
|
border-end-start-radius: calc(var(--radius-lg) - var(--border-width));
|
|
148
155
|
border-end-end-radius: calc(var(--radius-lg) - var(--border-width));
|
|
@@ -183,13 +190,13 @@ dialog.modal.dialog-confirmation > form > footer {
|
|
|
183
190
|
}
|
|
184
191
|
|
|
185
192
|
@media (max-width: 30rem) {
|
|
186
|
-
dialog.modal.dialog-confirmation > form > .media,
|
|
187
|
-
dialog.modal.dialog-confirmation > form > footer {
|
|
193
|
+
:where(dialog).modal.dialog-confirmation > form > .media,
|
|
194
|
+
:where(dialog).modal.dialog-confirmation > form > footer {
|
|
188
195
|
padding: var(--space-40);
|
|
189
196
|
}
|
|
190
197
|
}
|
|
191
198
|
|
|
192
|
-
dialog.modal[open] {
|
|
199
|
+
:where(dialog).modal[open] {
|
|
193
200
|
opacity: 1;
|
|
194
201
|
transform: none;
|
|
195
202
|
transition:
|
|
@@ -198,13 +205,13 @@ dialog.modal[open] {
|
|
|
198
205
|
}
|
|
199
206
|
|
|
200
207
|
@starting-style {
|
|
201
|
-
dialog.modal[open] {
|
|
208
|
+
:where(dialog).modal[open] {
|
|
202
209
|
opacity: 0;
|
|
203
210
|
transform: translateY(0.35rem);
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
|
|
207
|
-
dialog.modal::backdrop {
|
|
214
|
+
:where(dialog).modal::backdrop {
|
|
208
215
|
background: var(--backdrop-fill);
|
|
209
216
|
opacity: 0;
|
|
210
217
|
/* Scrim curve stays neutral `ease`; only the panel carries the character
|
|
@@ -213,7 +220,7 @@ dialog.modal::backdrop {
|
|
|
213
220
|
}
|
|
214
221
|
|
|
215
222
|
@supports (transition-behavior: allow-discrete) {
|
|
216
|
-
dialog.modal {
|
|
223
|
+
:where(dialog).modal {
|
|
217
224
|
transition:
|
|
218
225
|
opacity var(--duration) var(--ease-exit),
|
|
219
226
|
transform var(--duration) var(--ease-exit),
|
|
@@ -221,7 +228,7 @@ dialog.modal::backdrop {
|
|
|
221
228
|
display var(--duration) allow-discrete;
|
|
222
229
|
}
|
|
223
230
|
|
|
224
|
-
dialog.modal[open] {
|
|
231
|
+
:where(dialog).modal[open] {
|
|
225
232
|
transition:
|
|
226
233
|
opacity var(--duration) var(--ease-enter),
|
|
227
234
|
transform var(--duration) var(--ease-enter),
|
|
@@ -229,7 +236,7 @@ dialog.modal::backdrop {
|
|
|
229
236
|
display var(--duration) allow-discrete;
|
|
230
237
|
}
|
|
231
238
|
|
|
232
|
-
dialog.modal::backdrop {
|
|
239
|
+
:where(dialog).modal::backdrop {
|
|
233
240
|
transition:
|
|
234
241
|
opacity var(--duration) ease,
|
|
235
242
|
overlay var(--duration) allow-discrete,
|
|
@@ -237,7 +244,7 @@ dialog.modal::backdrop {
|
|
|
237
244
|
}
|
|
238
245
|
}
|
|
239
246
|
|
|
240
|
-
dialog.modal[open]::backdrop {
|
|
247
|
+
:where(dialog).modal[open]::backdrop {
|
|
241
248
|
opacity: 1;
|
|
242
249
|
}
|
|
243
250
|
|
|
@@ -250,7 +257,7 @@ html.has-modal-open.had-scrollbar {
|
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
@starting-style {
|
|
253
|
-
dialog.modal[open]::backdrop {
|
|
260
|
+
:where(dialog).modal[open]::backdrop {
|
|
254
261
|
opacity: 0;
|
|
255
262
|
}
|
|
256
263
|
}
|
|
@@ -258,7 +265,7 @@ html.has-modal-open.had-scrollbar {
|
|
|
258
265
|
@media (prefers-reduced-motion: no-preference) {
|
|
259
266
|
/* Wrong-close feedback and view-transition transport are motion quirks, not
|
|
260
267
|
presence enter/exit, so they stay on the plain CSS default easing. */
|
|
261
|
-
dialog.modal.is-static {
|
|
268
|
+
:where(dialog).modal.is-static {
|
|
262
269
|
animation: actual-dialog-static var(--duration-slow) ease;
|
|
263
270
|
}
|
|
264
271
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Navbar — top-level navigation bar.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/navbar.md
|
|
5
|
+
*
|
|
4
6
|
* .navbar is a horizontal bar; .navbar-brand is the brand link; .navbar-nav is
|
|
5
7
|
* the inline link list using .nav-link items. .nav-list is the vertical nav
|
|
6
8
|
* list shared with .drawer, fed by the shared --gap token.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Progress — native progress bar with theme-aware track and value.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/progress.md
|
|
5
|
+
*
|
|
4
6
|
* Consumes the shared --intent/--primary for the value bar and --bar-height
|
|
5
7
|
* for thickness. Indeterminate state animates a shimmer using --duration-shimmer.
|
|
6
8
|
*
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Rating — integer star rating drawn on native radio inputs.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/rating.md
|
|
5
|
+
*
|
|
4
6
|
* The checked radio remains the functional baseline. :has() progressively
|
|
5
7
|
* fills preceding stars without reversing DOM or keyboard order. Forced
|
|
6
8
|
* colors restores the platform radio presentation.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Scrollspy — behavior hook for navigation that marks the active section
|
|
3
3
|
* while the page scrolls.
|
|
4
4
|
*
|
|
5
|
+
* Docs: docs/pages/enhancements/scrollspy.md
|
|
6
|
+
*
|
|
5
7
|
* Does not add visual styles by itself. scrollspy.js watches
|
|
6
8
|
* <nav class="scrollspy">
|
|
7
9
|
* containing <a href="#section"> links and toggles aria-current="location" on
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Skeleton placeholders for loading states.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/skeleton.md
|
|
5
|
+
*
|
|
4
6
|
* Shows approximate loading structure without implying real content hierarchy.
|
|
5
7
|
* Geometry, animation, and color stay theme-aware.
|
|
6
8
|
*
|
|
@@ -11,16 +13,24 @@
|
|
|
11
13
|
* --skeleton-track
|
|
12
14
|
* --skeleton-highlight
|
|
13
15
|
*/
|
|
16
|
+
/* A placeholder fills its container up to --skeleton-width; the preset widths
|
|
17
|
+
are a cap, never an intrinsic size. Stated the other way round — a rem
|
|
18
|
+
`inline-size` capped by a percentage `max-inline-size` — the cap is ignored
|
|
19
|
+
during intrinsic sizing, so every shrink-to-fit ancestor inherits the
|
|
20
|
+
preset as a min-content floor: a card holding a title placeholder could not
|
|
21
|
+
go below 18rem and pushed a phone's layout sideways. A percentage
|
|
22
|
+
`inline-size` contributes nothing intrinsically and a rem cap only lowers
|
|
23
|
+
the contribution, so the same geometry costs no floor. */
|
|
14
24
|
.skeleton {
|
|
15
25
|
--skeleton-size: 1rem;
|
|
16
|
-
--skeleton-width:
|
|
26
|
+
--skeleton-width: none;
|
|
17
27
|
--skeleton-radius: var(--radius);
|
|
18
28
|
--skeleton-track: var(--surface-subtle);
|
|
19
29
|
--skeleton-highlight: var(--surface-raised);
|
|
20
30
|
|
|
21
31
|
display: block;
|
|
22
|
-
inline-size:
|
|
23
|
-
max-inline-size:
|
|
32
|
+
inline-size: 100%;
|
|
33
|
+
max-inline-size: var(--skeleton-width);
|
|
24
34
|
block-size: var(--skeleton-size);
|
|
25
35
|
border-radius: var(--skeleton-radius);
|
|
26
36
|
background:
|
|
@@ -44,11 +54,14 @@
|
|
|
44
54
|
--skeleton-width: 18rem;
|
|
45
55
|
}
|
|
46
56
|
|
|
57
|
+
/* The one preset with a real intrinsic width: a disc is square, so it sizes
|
|
58
|
+
rather than caps. The floor it does carry is the avatar size, which is small
|
|
59
|
+
enough never to widen a layout. */
|
|
47
60
|
.skeleton[data-shape="avatar"] {
|
|
48
61
|
--skeleton-size: var(--avatar-size, 2.25rem);
|
|
49
|
-
--skeleton-width: var(--skeleton-size);
|
|
50
62
|
--skeleton-radius: var(--radius-full);
|
|
51
63
|
|
|
64
|
+
inline-size: var(--skeleton-size);
|
|
52
65
|
flex: 0 0 auto;
|
|
53
66
|
}
|
|
54
67
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Status bar — singleton floating status area.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/enhancements/status-bar.md
|
|
5
|
+
*
|
|
4
6
|
* One element in the HTML, empty by default. .is-open is the visual state, set
|
|
5
7
|
* by status.js like any other surface: it lands after the message is written
|
|
6
8
|
* and lifts before the bar is cleared, so the bar leaves in the exact state it
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Steps — semantic ordered-list progression for a multi-step process.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/steps.md
|
|
5
|
+
*
|
|
4
6
|
* One primitive, two explicit compositions. Both classes are required:
|
|
5
7
|
*
|
|
6
8
|
* <ol class="steps steps-horizontal"> horizontal, 2 to 5 stages
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Tabs — in-place panel switcher with real tab semantics.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/enhancements/tabs.md
|
|
5
|
+
*
|
|
4
6
|
* JavaScript owns roving tabindex, aria-selected, panel visibility,
|
|
5
7
|
* and arrow-key navigation. CSS owns the tab strip appearance and
|
|
6
8
|
* active indicator.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Table — structured tabular data.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/table.md
|
|
5
|
+
*
|
|
4
6
|
* .table-wrap provides the scroll container and outer chrome; .table owns row
|
|
5
7
|
* and cell rules. Tokens are sourced from the shared scale.
|
|
6
8
|
*
|
|
@@ -9,6 +11,14 @@
|
|
|
9
11
|
* --table-cell-pad
|
|
10
12
|
*/
|
|
11
13
|
.table-wrap {
|
|
14
|
+
/* Containing block for anything absolutely positioned inside the table —
|
|
15
|
+
`.sr-only` on a column header above all. Without it that box resolves
|
|
16
|
+
against the initial containing block, so it keeps the static position of a
|
|
17
|
+
cell that may be a thousand pixels along the scrolled row, escapes this
|
|
18
|
+
scroller, and extends the *document's* scrollable width. The page then
|
|
19
|
+
scrolls sideways on a phone with nothing painted out there. */
|
|
20
|
+
position: relative;
|
|
21
|
+
|
|
12
22
|
inline-size: 100%;
|
|
13
23
|
max-inline-size: 100%;
|
|
14
24
|
min-inline-size: 0;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Tooltip — supplemental label overlaid near a trigger.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/enhancements/tooltip.md
|
|
5
|
+
*
|
|
4
6
|
* Position, placement, and arrow position are managed by JavaScript via left,
|
|
5
7
|
* top, data-placement, and --arrow-x. The runtime also owns `position`: it
|
|
6
8
|
* writes `absolute` for a tip whose trigger scrolls with the page, so the
|
package/src/css/core/print.css
CHANGED
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/* Shared control scale. Wrappers are listed when their descendants form one
|
|
95
|
-
component (field, input-icon, join, pagination,
|
|
96
|
-
declaration beats inherited density because it
|
|
97
|
-
component itself. */
|
|
95
|
+
component (field, choice-card, floating-field, input-icon, join, pagination,
|
|
96
|
+
tabs, flyout). A local size declaration beats inherited density because it
|
|
97
|
+
is declared on the sized component itself. */
|
|
98
98
|
:where(
|
|
99
99
|
.btn,
|
|
100
100
|
.input,
|
|
@@ -104,7 +104,9 @@
|
|
|
104
104
|
.file,
|
|
105
105
|
.field,
|
|
106
106
|
.choice,
|
|
107
|
+
.choice-card,
|
|
107
108
|
.input-icon,
|
|
109
|
+
.floating-field,
|
|
108
110
|
.otp,
|
|
109
111
|
.join,
|
|
110
112
|
.pagination,
|
|
@@ -126,7 +128,9 @@
|
|
|
126
128
|
.file,
|
|
127
129
|
.field,
|
|
128
130
|
.choice,
|
|
131
|
+
.choice-card,
|
|
129
132
|
.input-icon,
|
|
133
|
+
.floating-field,
|
|
130
134
|
.otp,
|
|
131
135
|
.join,
|
|
132
136
|
.pagination,
|
package/src/css/effects/aura.css
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Decorative intent-colored frame for one direct child.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/components/aura.md
|
|
5
|
+
*
|
|
4
6
|
* The effect is built from three layers with distinct roles: a frame carrying
|
|
5
7
|
* a short accent of light, a small halo that belongs to the frame and keeps
|
|
6
8
|
* that light attached to the edge, and a wide static halo that belongs to the
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Choice cards — card-style radio and checkbox labels.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/forms/choice-cards.md
|
|
5
|
+
*
|
|
4
6
|
* Each .choice-card is a <label> wrapping a native radio or checkbox. When
|
|
5
7
|
* :has() is supported the input is visually hidden and the card mirrors its
|
|
6
8
|
* state: checked border and tint, checkmark badge (round for radio, rounded
|
|
@@ -37,6 +39,8 @@
|
|
|
37
39
|
border-radius: var(--choice-card-radius);
|
|
38
40
|
background: var(--choice-card-bg);
|
|
39
41
|
color: var(--text);
|
|
42
|
+
/* Consumed so .sm/.lg reach the card; the badge's em sizing follows. */
|
|
43
|
+
font-size: var(--control-font-size);
|
|
40
44
|
cursor: pointer;
|
|
41
45
|
transition:
|
|
42
46
|
border-color var(--duration),
|
package/src/css/forms/choice.css
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* geometry and states. switch.css is imported after this file.
|
|
11
11
|
*
|
|
12
12
|
* Public hooks:
|
|
13
|
-
* --choice-control-
|
|
13
|
+
* --choice-control-nudge
|
|
14
14
|
* --choice-border
|
|
15
15
|
* --choice-bg
|
|
16
16
|
* --choice-mark
|
|
@@ -42,45 +42,89 @@
|
|
|
42
42
|
cursor: pointer;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/* Optical alignment:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
/* Optical alignment: the control reads level with the first line's cap height,
|
|
46
|
+
not with the top of its line box. Every inline choice runs the same formula
|
|
47
|
+
over its own block size, so a checkbox and a taller switch stay level with
|
|
48
|
+
each other under any line-height or --choice-control-size — something a
|
|
49
|
+
per-control constant cannot do.
|
|
50
|
+
|
|
51
|
+
Three tiers, each the best the engine can express:
|
|
52
|
+
|
|
53
|
+
- `cap` unit: exact, and the only font-independent answer. Where the cap
|
|
54
|
+
center sits inside a line box depends on the font's ascent/descent/cap
|
|
55
|
+
ratios, so no constant can serve both Segoe UI and Roboto — the same rule
|
|
56
|
+
was a pixel high on Windows and two pixels low on Android. Baseline
|
|
57
|
+
alignment puts the control's border-box bottom on the text baseline, and
|
|
58
|
+
one inset drops it by half the difference between its own height and the
|
|
59
|
+
cap height. Both classed controls synthesize that baseline from their
|
|
60
|
+
border box because their mark and knob are out of flow.
|
|
61
|
+
- `lh` only: center the control on the line box, which is within a pixel of
|
|
62
|
+
the cap center for the usual UI faces.
|
|
63
|
+
- neither: the constants that formula yields at the default 1.5
|
|
64
|
+
line-height, 0.1875em for a checkbox and 0.125em for the switch track.
|
|
65
|
+
|
|
66
|
+
--choice-control-nudge adds to whichever tier applies, rather than replacing
|
|
67
|
+
it: the derived value is exact now, so a design has a correction to make,
|
|
68
|
+
not a formula to restate — and one number cannot stand in for three
|
|
69
|
+
different references anyway. It stays fallback-only rather than declared
|
|
70
|
+
here, so an override placed anywhere up the tree — :root included — reaches
|
|
71
|
+
the control instead of losing to a component-level declaration. */
|
|
62
72
|
.choice > :is(input[type="checkbox"]:not([role="switch"]), input[type="radio"]) {
|
|
63
73
|
flex: 0 0 auto;
|
|
64
|
-
margin-block-start: var(--choice-control-
|
|
74
|
+
margin-block-start: calc(0.1875em + var(--choice-control-nudge, 0px));
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
.choice > .switch {
|
|
68
78
|
flex: 0 0 auto;
|
|
69
|
-
margin-block-start: var(--choice-control-
|
|
79
|
+
margin-block-start: calc(0.125em + var(--choice-control-nudge, 0px));
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
@supports (margin-block-start: 1lh) {
|
|
73
83
|
.choice > :is(input[type="checkbox"]:not([role="switch"]), input[type="radio"]) {
|
|
74
|
-
margin-block-start:
|
|
75
|
-
--choice-control-
|
|
76
|
-
|
|
84
|
+
margin-block-start: calc(
|
|
85
|
+
(1lh - var(--choice-control-size)) /
|
|
86
|
+
2 +
|
|
87
|
+
var(--choice-control-nudge, 0px)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.choice > .switch {
|
|
92
|
+
margin-block-start: calc(
|
|
93
|
+
(1lh - var(--switch-block-size)) /
|
|
94
|
+
2 +
|
|
95
|
+
var(--choice-control-nudge, 0px)
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@supports (margin-block-start: 1cap) {
|
|
101
|
+
.choice {
|
|
102
|
+
align-items: baseline;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Baseline alignment owns the block position now; the tier above would only
|
|
106
|
+
grow the row. An unclassed native input keeps the UA's own baseline, which
|
|
107
|
+
is already tuned for text — the formula below describes the framework's
|
|
108
|
+
geometry and would not fit it. */
|
|
109
|
+
.choice > :is(input[type="checkbox"], input[type="radio"]) {
|
|
110
|
+
margin-block-start: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* inset-block-start rides the `position: relative` these controls already
|
|
114
|
+
carry for their mark and knob. */
|
|
115
|
+
.choice > :is(.check, .radio) {
|
|
116
|
+
inset-block-start: calc(
|
|
117
|
+
(var(--choice-control-size) - 1cap) /
|
|
118
|
+
2 +
|
|
119
|
+
var(--choice-control-nudge, 0px)
|
|
77
120
|
);
|
|
78
121
|
}
|
|
79
122
|
|
|
80
123
|
.choice > .switch {
|
|
81
|
-
|
|
82
|
-
--
|
|
83
|
-
|
|
124
|
+
inset-block-start: calc(
|
|
125
|
+
(var(--switch-block-size) - 1cap) /
|
|
126
|
+
2 +
|
|
127
|
+
var(--choice-control-nudge, 0px)
|
|
84
128
|
);
|
|
85
129
|
}
|
|
86
130
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Text controls — input, textarea, select.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/forms/overview.md
|
|
5
|
+
*
|
|
4
6
|
* Neutral geometry and interaction states shared across all text-like
|
|
5
7
|
* controls. select shares this base recipe; its chevron/appearance layer
|
|
6
8
|
* lives in select.css. checkbox, radio, range, switch, and file have their
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Floating labels — optional composition over the text controls
|
|
3
3
|
* (.input, .textarea, .select) and .field-label.
|
|
4
4
|
*
|
|
5
|
+
* Docs: docs/pages/forms/floating-field.md
|
|
6
|
+
*
|
|
5
7
|
* The cell owns a control plus its label; the label overlays the control and
|
|
6
8
|
* floats to the top when the control is focused or non-empty. Help and error
|
|
7
9
|
* messages stay in the surrounding .field, not inside the cell, so the
|
|
@@ -43,7 +45,9 @@
|
|
|
43
45
|
|
|
44
46
|
.floating-field > .field-label {
|
|
45
47
|
position: absolute;
|
|
46
|
-
|
|
48
|
+
/* Same start edge as the control's text: --control-pad-x owns that shared
|
|
49
|
+
geometry, so .sm/.lg keep label and value aligned. */
|
|
50
|
+
inset-inline-start: calc(var(--control-pad-x) + var(--border-width));
|
|
47
51
|
color: var(--text-muted);
|
|
48
52
|
font-size: var(--control-font-size);
|
|
49
53
|
font-weight: var(--font-weight-normal);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Form actions — bottom form bar with sticky variant.
|
|
3
3
|
*
|
|
4
|
+
* Docs: docs/pages/forms/form-actions.md
|
|
5
|
+
*
|
|
4
6
|
* A flex cluster of buttons/actions that closes a form. The sticky variant
|
|
5
7
|
* docks to the viewport bottom with a translucent blur where supported; at
|
|
6
8
|
* rest it stays visually neutral so it does not double as a separator.
|