actual-css 0.3.1 → 0.4.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 +67 -3
- package/README.md +35 -30
- package/dist/actual.css +73 -4946
- package/dist/actual.full.css +7090 -0
- package/dist/actual.full.js +1 -0
- package/dist/actual.full.min.css +1 -0
- package/dist/actual.js +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/cascade-layer.md +34 -13
- package/docs/design-notes/column-layout.md +677 -0
- package/docs/design-notes/forced-colors.md +3 -0
- package/docs/design-notes/grid.md +612 -0
- package/docs/design-notes/naming.md +15 -0
- package/docs/design-notes/widget-primitives.md +1 -0
- package/docs/navigation.json +5 -1
- package/docs/pages/components/alert.md +16 -14
- package/docs/pages/components/aura.md +1 -1
- package/docs/pages/components/avatar.md +6 -6
- package/docs/pages/components/badge.md +7 -7
- package/docs/pages/components/button.md +16 -16
- package/docs/pages/components/card.md +13 -9
- package/docs/pages/components/chat.md +8 -8
- package/docs/pages/components/dialog.md +7 -7
- package/docs/pages/components/drawer.md +3 -3
- package/docs/pages/components/fab.md +7 -7
- package/docs/pages/components/navbar.md +9 -8
- package/docs/pages/components/pagination.md +4 -3
- package/docs/pages/components/skeleton.md +4 -4
- package/docs/pages/components/spinner.md +5 -5
- package/docs/pages/components/table.md +30 -5
- package/docs/pages/enhancements/flyout.md +13 -13
- package/docs/pages/enhancements/overview.md +1 -1
- package/docs/pages/enhancements/scrollspy.md +6 -6
- package/docs/pages/enhancements/status-bar.md +5 -1
- package/docs/pages/enhancements/tabs.md +6 -6
- package/docs/pages/enhancements/tooltip.md +1 -1
- package/docs/pages/examples/overview.md +39 -22
- package/docs/pages/forms/choice-cards.md +11 -6
- package/docs/pages/forms/controls.md +1 -1
- package/docs/pages/forms/detached-actions.md +1 -1
- package/docs/pages/forms/floating-field.md +10 -5
- package/docs/pages/forms/form-actions.md +1 -1
- package/docs/pages/forms/input-policy.md +1 -1
- package/docs/pages/forms/joined-controls.md +4 -4
- package/docs/pages/forms/labels.md +6 -6
- package/docs/pages/forms/otp.md +1 -1
- package/docs/pages/forms/overview.md +19 -19
- package/docs/pages/forms/password.md +1 -1
- package/docs/pages/forms/range.md +1 -1
- package/docs/pages/forms/states-and-sizes.md +41 -45
- package/docs/pages/forms/sticky-actions.md +3 -3
- package/docs/pages/forms/switch.md +110 -2
- package/docs/pages/forms/validation.md +9 -9
- package/docs/pages/foundations/philosophy.md +1 -1
- package/docs/pages/foundations/theming.md +17 -2
- package/docs/pages/foundations/tokens.md +22 -10
- package/docs/pages/foundations/typography.md +50 -20
- package/docs/pages/guides/bootstrap.md +11 -11
- package/docs/pages/guides/integrating-actual-css.md +186 -0
- package/docs/pages/guides/introduction.md +23 -26
- package/docs/pages/guides/modular-import.md +173 -0
- package/docs/pages/guides/progressive-enhancement.md +81 -78
- package/docs/pages/guides/tailwind.md +6 -8
- package/docs/pages/layout/app-shell.md +1 -1
- package/docs/pages/layout/center.md +1 -1
- package/docs/pages/layout/choosing.md +39 -0
- package/docs/pages/layout/column-layout.md +206 -0
- package/docs/pages/layout/frame.md +6 -1
- package/docs/pages/layout/grid.md +100 -102
- package/docs/pages/layout/list.md +1 -1
- package/docs/pages/layout/media.md +1 -1
- package/docs/pages/layout/overview.md +15 -2
- package/docs/pages/layout/scroll-snap.md +2 -2
- package/docs/pages/layout/scroll-target.md +45 -0
- package/docs/pages/layout/sidebar-layout.md +20 -19
- package/docs/pages/layout/stack.md +53 -1
- package/docs/pages/layout/switcher.md +10 -26
- package/docs/pages/layout/topbar.md +2 -2
- package/docs/pages/patterns/actions.md +1 -1
- package/docs/pages/patterns/code-block.md +1 -1
- package/docs/pages/patterns/exclusive-accordion.md +1 -1
- package/docs/pages/patterns/hierarchical-nav.md +1 -1
- package/docs/pages/patterns/icon-input.md +1 -1
- package/docs/pages/patterns/intent-nesting.md +1 -1
- package/docs/pages/patterns/navigation-list.md +1 -1
- package/docs/pages/patterns/overview.md +1 -1
- package/docs/pages/patterns/structured-lists.md +1 -1
- package/docs/pages/utilities/accessibility.md +3 -3
- package/docs/pages/utilities/flex.md +15 -15
- package/docs/pages/utilities/links.md +4 -4
- package/docs/pages/utilities/list.md +8 -8
- package/docs/pages/utilities/overflow.md +8 -8
- package/docs/pages/utilities/overview.md +1 -1
- package/docs/pages/utilities/shape.md +3 -3
- package/docs/pages/utilities/sizing-wrapping.md +23 -16
- package/docs/pages/utilities/spacing.md +20 -20
- package/docs/pages/utilities/text.md +10 -10
- package/llms.txt +46 -4
- package/package.json +42 -13
- package/scripts/reserved-classes.json +261 -0
- package/src/cli/actual-css.js +133 -0
- package/src/css/actual.css +1 -31
- package/src/css/actual.full.css +11 -2
- package/src/css/components/alert.css +17 -4
- package/src/css/components/badge.css +18 -6
- package/src/css/components/breadcrumb.css +1 -1
- package/src/css/components/button.css +19 -1
- package/src/css/components/card.css +27 -2
- package/src/css/components/drawer.css +27 -2
- package/src/css/components/flyout.css +5 -0
- package/src/css/components/index.css +32 -27
- package/src/css/components/join.css +8 -1
- package/src/css/components/key.css +2 -0
- package/src/css/components/menu.css +11 -1
- package/src/css/components/meter.css +4 -1
- package/src/css/components/modal.css +5 -0
- package/src/css/components/pagination.css +11 -0
- package/src/css/components/spinner.css +5 -0
- package/src/css/components/status-bar.css +5 -0
- package/src/css/components/surface.css +5 -0
- package/src/css/components/table.css +6 -0
- package/src/css/components/tooltip.css +5 -0
- package/src/css/core/index.css +9 -0
- package/src/css/core/print.css +18 -0
- package/src/css/{theme.css → core/theme.css} +20 -10
- package/src/css/{tokens.css → core/tokens.css} +15 -2
- package/src/css/{variants.css → core/variants.css} +3 -2
- package/src/css/effects/index.css +2 -0
- package/src/css/forms/base.css +8 -0
- package/src/css/forms/choice-card.css +5 -4
- package/src/css/forms/choice.css +49 -37
- package/src/css/forms/control.css +4 -1
- package/src/css/forms/custom-select.css +2 -0
- package/src/css/{optional → forms}/floating-field.css +25 -7
- package/src/css/forms/index.css +10 -13
- package/src/css/forms/native.css +15 -2
- package/src/css/{optional → forms}/otp.css +20 -16
- package/src/css/forms/switch.css +31 -29
- package/src/css/layout/app-shell.css +6 -0
- package/src/css/layout/center.css +13 -0
- package/src/css/layout/cluster.css +21 -0
- package/src/css/layout/column-layout.css +144 -0
- package/src/css/layout/container-query.css +13 -0
- package/src/css/layout/frame.css +19 -0
- package/src/css/layout/grid.css +141 -0
- package/src/css/layout/index.css +42 -0
- package/src/css/layout/measure.css +9 -0
- package/src/css/layout/media.css +10 -0
- package/src/css/layout/scroll-target.css +15 -0
- package/src/css/layout/scroller.css +41 -0
- package/src/css/layout/sidebar-layout.css +31 -0
- package/src/css/layout/stack.css +21 -0
- package/src/css/layout/switcher.css +23 -0
- package/src/css/{optional/layout-extra.css → layout/topbar.css} +0 -20
- package/src/css/typography/index.css +5 -0
- package/src/css/typography/lead.css +7 -0
- package/src/css/{components → typography}/overline.css +2 -2
- package/src/css/{prose.css → typography/prose.css} +53 -38
- package/src/css/{utilities.css → utilities/base.css} +2 -0
- package/src/css/utilities/index.css +3 -0
- package/src/js/escape.js +36 -0
- package/src/js/flyout.js +22 -12
- package/src/js/full.js +26 -0
- package/src/js/index.js +5 -21
- package/src/js/surface.js +1 -31
- package/src/js/tooltip.js +46 -18
- package/src/js/validation.js +1 -1
- package/src/tooling/css-bundle.js +308 -0
- package/dist/actual-themes.min.css +0 -1
- package/dist/optional.css +0 -1048
- package/dist/optional.min.css +0 -1
- package/docs/pages/guides/optional-components.md +0 -33
- package/src/css/grid.css +0 -109
- package/src/css/layout.css +0 -123
- package/src/css/optional/index.css +0 -10
- package/src/css/optional/scroller.css +0 -63
- package/src/css/print.css +0 -47
- package/src/css/themes/corporate.css +0 -60
- package/src/css/themes/cyberpunk.css +0 -60
- package/src/css/themes/dim.css +0 -33
- package/src/css/themes/edge.css +0 -117
- package/src/css/themes/forest.css +0 -65
- package/src/css/themes/gradient.css +0 -97
- package/src/css/themes/index.css +0 -47
- package/src/css/themes/indigo.css +0 -33
- package/src/css/themes/lavender.css +0 -66
- package/src/css/themes/mono.css +0 -60
- package/src/css/themes/neon.css +0 -66
- package/src/css/themes/ocean.css +0 -60
- package/src/css/themes/petrol.css +0 -64
- package/src/css/themes/spruce.css +0 -64
- package/src/css/themes/square.css +0 -65
- package/src/css/themes/sunset.css +0 -66
- /package/src/css/{optional → components}/chat.css +0 -0
- /package/src/css/{optional → components}/fab.css +0 -0
- /package/src/css/{base.css → core/base.css} +0 -0
- /package/src/css/{focus.css → core/focus.css} +0 -0
- /package/src/css/{intents.css → core/intents.css} +0 -0
- /package/src/css/{reset.css → core/reset.css} +0 -0
- /package/src/css/{optional → effects}/aura.css +0 -0
- /package/src/css/{optional → layout}/scroll-snap.css +0 -0
- /package/src/css/{optional/typography-fluid.css → typography/fluid.css} +0 -0
- /package/src/css/{optional/utilities-extra.css → utilities/extra.css} +0 -0
package/src/css/forms/choice.css
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* --choice-border
|
|
15
15
|
* --choice-bg
|
|
16
16
|
* --choice-mark
|
|
17
|
+
*
|
|
18
|
+
* --choice-control-size (tokens.css) is the shared typographic size for every
|
|
19
|
+
* inline choice; switch.css derives its track from it so a checkbox and a
|
|
20
|
+
* switch on the same line stay proportionate.
|
|
17
21
|
*/
|
|
18
22
|
/* Intent boundary — inherited intents do not tint this component.
|
|
19
23
|
Local intent classes still win because :where() has zero specificity. */
|
|
@@ -30,8 +34,6 @@
|
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
.choice {
|
|
33
|
-
--choice-control-offset: 0.25em;
|
|
34
|
-
|
|
35
37
|
display: inline-flex;
|
|
36
38
|
align-items: flex-start;
|
|
37
39
|
gap: var(--space-20);
|
|
@@ -40,17 +42,47 @@
|
|
|
40
42
|
cursor: pointer;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
/* Optical alignment: nudge the control down so
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
/* Optical alignment: nudge the control down so it sits visually centered with
|
|
46
|
+
the first line of label text, not flush with the top of the line-box. Every
|
|
47
|
+
inline choice runs the same formula — center the control's own block size on
|
|
48
|
+
the first line box, then drop it 0.0625em so it reads level with the
|
|
49
|
+
cap-height rather than the em-box. A checkbox and a switch therefore stay
|
|
50
|
+
level with each other under any line-height or --choice-control-size, which
|
|
51
|
+
a per-control constant cannot do (a taller switch and a shorter checkbox
|
|
52
|
+
need different offsets to land on the same optical line).
|
|
53
|
+
|
|
54
|
+
The constants are what the formula yields at the default 1.5 line-height:
|
|
55
|
+
0.25em (4px) for a checkbox, 0.1875em (3px) for the taller switch track.
|
|
56
|
+
They serve browsers without lh units. Multi-line labels still keep the
|
|
57
|
+
control at the top thanks to align-items: flex-start.
|
|
58
|
+
|
|
59
|
+
--choice-control-offset stays fallback-only rather than declared here, so an
|
|
60
|
+
override placed anywhere up the tree — :root included — reaches the control
|
|
61
|
+
instead of losing to a component-level declaration. */
|
|
51
62
|
.choice > :is(input[type="checkbox"]:not([role="switch"]), input[type="radio"]) {
|
|
52
63
|
flex: 0 0 auto;
|
|
53
|
-
margin-block-start: var(--choice-control-offset);
|
|
64
|
+
margin-block-start: var(--choice-control-offset, 0.25em);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.choice > .switch {
|
|
68
|
+
flex: 0 0 auto;
|
|
69
|
+
margin-block-start: var(--choice-control-offset, 0.1875em);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@supports (margin-block-start: 1lh) {
|
|
73
|
+
.choice > :is(input[type="checkbox"]:not([role="switch"]), input[type="radio"]) {
|
|
74
|
+
margin-block-start: var(
|
|
75
|
+
--choice-control-offset,
|
|
76
|
+
calc((1lh - var(--choice-control-size)) / 2 + 0.0625em)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.choice > .switch {
|
|
81
|
+
margin-block-start: var(
|
|
82
|
+
--choice-control-offset,
|
|
83
|
+
calc((1lh - var(--switch-block-size)) / 2 + 0.0625em)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
54
86
|
}
|
|
55
87
|
|
|
56
88
|
.choice > span > .field-help {
|
|
@@ -76,8 +108,8 @@
|
|
|
76
108
|
vertical-align: middle;
|
|
77
109
|
display: inline-grid;
|
|
78
110
|
place-content: center;
|
|
79
|
-
inline-size:
|
|
80
|
-
block-size:
|
|
111
|
+
inline-size: var(--choice-control-size);
|
|
112
|
+
block-size: var(--choice-control-size);
|
|
81
113
|
margin: 0;
|
|
82
114
|
border: var(--border-width) solid var(--form-invalid-border, var(--choice-border));
|
|
83
115
|
background: var(--choice-bg);
|
|
@@ -163,27 +195,7 @@
|
|
|
163
195
|
opacity: 1;
|
|
164
196
|
}
|
|
165
197
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
--choice-bg: Canvas;
|
|
171
|
-
--choice-mark: ButtonText;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.check:checked,
|
|
175
|
-
.radio:checked,
|
|
176
|
-
.check:indeterminate {
|
|
177
|
-
--choice-border: Highlight;
|
|
178
|
-
--choice-bg: Highlight;
|
|
179
|
-
--choice-mark: HighlightText;
|
|
180
|
-
forced-color-adjust: none;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.check:disabled,
|
|
184
|
-
.radio:disabled {
|
|
185
|
-
--choice-border: GrayText;
|
|
186
|
-
--choice-bg: Canvas;
|
|
187
|
-
--choice-mark: GrayText;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
198
|
+
/* Forced colors intentionally stay under UA control: the visible check/dot
|
|
199
|
+
carries state while native remapping preserves platform contrast and focus.
|
|
200
|
+
If real HCM testing ever loses a mark, opt out on that pseudo only—never on
|
|
201
|
+
the interactive input host. */
|
|
@@ -46,7 +46,10 @@
|
|
|
46
46
|
color: var(--control-fg);
|
|
47
47
|
font-size: var(--control-font-size);
|
|
48
48
|
cursor: var(--control-cursor);
|
|
49
|
-
outline: none
|
|
49
|
+
/* No outline: none here — the core :focus fallback must survive for browsers
|
|
50
|
+
without :focus-visible. Pointer focus is hidden by core's
|
|
51
|
+
:focus:not(:focus-visible); keyboard focus swaps in the transparent
|
|
52
|
+
outline + ring below. */
|
|
50
53
|
transition:
|
|
51
54
|
border-color var(--duration),
|
|
52
55
|
box-shadow var(--duration),
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* --control-border
|
|
13
13
|
* --control-bg
|
|
14
14
|
*/
|
|
15
|
+
/* This enhancement is excluded from forced-colors, where the native/shared
|
|
16
|
+
outline remains the focus fallback. */
|
|
15
17
|
@media (forced-colors: none) and (prefers-contrast: no-preference) and (hover: hover) and (
|
|
16
18
|
pointer: fine
|
|
17
19
|
) {
|
|
@@ -16,9 +16,13 @@
|
|
|
16
16
|
* and the reserved headroom with it, leaving typography untouched.
|
|
17
17
|
*
|
|
18
18
|
* Public hooks:
|
|
19
|
+
* --floating-label-top
|
|
20
|
+
* --floating-label-opacity
|
|
19
21
|
* --floating-pad-block-start
|
|
20
22
|
*/
|
|
21
23
|
.floating-field {
|
|
24
|
+
--floating-label-top: var(--space-10);
|
|
25
|
+
--floating-label-opacity: 0.8;
|
|
22
26
|
--floating-pad-block-start: calc(var(--control-size) / 2 + var(--space-20));
|
|
23
27
|
|
|
24
28
|
/* Grid blockifies the control, removing the inline descender gap a textarea
|
|
@@ -37,24 +41,30 @@
|
|
|
37
41
|
|
|
38
42
|
.floating-field > .field-label {
|
|
39
43
|
position: absolute;
|
|
40
|
-
inset-block-start: 50%;
|
|
41
44
|
inset-inline-start: calc(var(--space-30) + var(--border-width));
|
|
42
|
-
transform: translateY(-50%);
|
|
43
45
|
color: var(--text-muted);
|
|
44
46
|
font-size: var(--control-font-size);
|
|
45
47
|
font-weight: var(--font-weight);
|
|
48
|
+
opacity: var(--floating-label-opacity);
|
|
46
49
|
pointer-events: none;
|
|
47
50
|
transition:
|
|
48
51
|
inset-block-start var(--duration),
|
|
49
52
|
transform var(--duration),
|
|
50
53
|
font-size var(--duration),
|
|
54
|
+
opacity var(--duration),
|
|
51
55
|
color var(--duration);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
/*
|
|
55
|
-
|
|
58
|
+
/* Single-line controls rest in the middle until they receive a value. */
|
|
59
|
+
.floating-field > :is(.input, .select) + .field-label {
|
|
60
|
+
inset-block-start: 50%;
|
|
61
|
+
transform: translateY(-50%);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* An empty textarea label follows the control's normal first-line position;
|
|
65
|
+
the control itself keeps the extra headroom reserved for its floated state. */
|
|
56
66
|
.floating-field > .textarea + .field-label {
|
|
57
|
-
inset-block-start: var(--
|
|
67
|
+
inset-block-start: calc(1em + var(--border-width));
|
|
58
68
|
transform: none;
|
|
59
69
|
}
|
|
60
70
|
|
|
@@ -63,9 +73,10 @@
|
|
|
63
73
|
.floating-field
|
|
64
74
|
> :is(.input, .textarea):is(:focus, :autofill, :not(:placeholder-shown))
|
|
65
75
|
+ .field-label {
|
|
66
|
-
inset-block-start: var(--
|
|
76
|
+
inset-block-start: var(--floating-label-top);
|
|
67
77
|
transform: none;
|
|
68
78
|
font-size: var(--font-size-xs);
|
|
79
|
+
opacity: 1;
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
/* Controls without a dependable :placeholder-shown empty state stay floated:
|
|
@@ -81,7 +92,14 @@
|
|
|
81
92
|
.input[type="week"]
|
|
82
93
|
)
|
|
83
94
|
+ .field-label {
|
|
84
|
-
inset-block-start: var(--
|
|
95
|
+
inset-block-start: var(--floating-label-top);
|
|
85
96
|
transform: none;
|
|
86
97
|
font-size: var(--font-size-xs);
|
|
98
|
+
opacity: 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@media (forced-colors: active) {
|
|
102
|
+
.floating-field > .field-label {
|
|
103
|
+
opacity: 1;
|
|
104
|
+
}
|
|
87
105
|
}
|
package/src/css/forms/index.css
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
/* Forms —
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@import "./
|
|
1
|
+
/* Forms — the complete Forms family. base covers the ordinary native
|
|
2
|
+
controls; the leaves below add opt-in control skins. switch.css follows
|
|
3
|
+
choice.css (via base) so its rules land after the shared choice recipe.
|
|
4
|
+
validation.css stays part of base, but custom builds may omit it when
|
|
5
|
+
validation styling is app-owned. */
|
|
6
|
+
@import "./base.css";
|
|
7
7
|
@import "./input-icon.css";
|
|
8
|
-
@import "./
|
|
8
|
+
@import "./switch.css";
|
|
9
|
+
@import "./range.css";
|
|
9
10
|
@import "./choice-card.css";
|
|
10
|
-
@import "./select.css";
|
|
11
11
|
@import "./custom-select.css";
|
|
12
|
-
@import "./
|
|
13
|
-
@import "./
|
|
14
|
-
@import "./switch.css";
|
|
15
|
-
@import "./validation.css";
|
|
16
|
-
@import "./form-actions.css";
|
|
12
|
+
@import "./floating-field.css";
|
|
13
|
+
@import "./otp.css";
|
package/src/css/forms/native.css
CHANGED
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
box-shadow: var(--focus-ring-shadow);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/* Native color picker — keep the browser's dialog and selected-color UI.
|
|
44
|
+
/* Native color picker — keep the browser's dialog and selected-color UI. The
|
|
45
|
+
swatch fills almost the whole control so it reads as a color, not as a tiny
|
|
46
|
+
square inside a button; the 1px padding keeps a hair of --surface around it. */
|
|
45
47
|
.color {
|
|
46
48
|
inline-size: var(--control-size);
|
|
47
49
|
block-size: var(--control-size);
|
|
48
|
-
padding: var(--
|
|
50
|
+
padding: var(--border-width);
|
|
49
51
|
border: var(--border-width) solid var(--border);
|
|
50
52
|
border-radius: var(--radius);
|
|
51
53
|
background: var(--surface);
|
|
@@ -58,10 +60,12 @@
|
|
|
58
60
|
|
|
59
61
|
.color::-webkit-color-swatch {
|
|
60
62
|
border: 0;
|
|
63
|
+
border-radius: calc(var(--radius) - var(--border-width));
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
.color::-moz-color-swatch {
|
|
64
67
|
border: 0;
|
|
68
|
+
border-radius: calc(var(--radius) - var(--border-width));
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
.color:disabled {
|
|
@@ -78,6 +82,15 @@
|
|
|
78
82
|
.color {
|
|
79
83
|
border-color: ButtonText;
|
|
80
84
|
background: ButtonFace;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* The swatch color is content, so preserve it without disabling the host's
|
|
88
|
+
native forced-color focus treatment. Vendor pseudos cannot share a rule. */
|
|
89
|
+
.color::-webkit-color-swatch {
|
|
90
|
+
forced-color-adjust: none;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.color::-moz-color-swatch {
|
|
81
94
|
forced-color-adjust: none;
|
|
82
95
|
}
|
|
83
96
|
}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Internal:
|
|
13
13
|
* --otp-cell-border
|
|
14
|
+
* --otp-cell-border-width
|
|
14
15
|
* --otp-cell-bg
|
|
16
|
+
* --otp-caret-space
|
|
15
17
|
*/
|
|
16
18
|
.otp {
|
|
17
19
|
--otp-cell-size: var(--control-size);
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
--otp-font-size: 1.5rem;
|
|
20
22
|
--otp-cell-border: var(--border);
|
|
21
23
|
--otp-cell-bg: var(--surface);
|
|
24
|
+
--otp-caret-space: calc((var(--otp-cell-size) - 1ch) / 2 + var(--otp-gap) + 1px);
|
|
22
25
|
|
|
23
26
|
position: relative;
|
|
24
27
|
display: inline-grid;
|
|
@@ -28,31 +31,35 @@
|
|
|
28
31
|
max-inline-size: 100%;
|
|
29
32
|
gap: var(--otp-gap);
|
|
30
33
|
border-radius: var(--radius);
|
|
34
|
+
/* Unlike hidden, clip cannot become a scroll container when the caret moves
|
|
35
|
+
into the input extension. */
|
|
36
|
+
overflow: clip;
|
|
31
37
|
direction: ltr;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
.otp > span {
|
|
35
41
|
inline-size: var(--otp-cell-size);
|
|
36
42
|
block-size: var(--otp-cell-size);
|
|
37
|
-
border: var(--border-width) solid var(--otp-cell-border);
|
|
43
|
+
border: var(--otp-cell-border-width, var(--border-width)) solid var(--otp-cell-border);
|
|
38
44
|
border-radius: var(--radius);
|
|
39
45
|
background: var(--otp-cell-bg);
|
|
40
46
|
transition:
|
|
41
47
|
border-color var(--duration),
|
|
42
|
-
background-color var(--duration)
|
|
43
|
-
box-shadow var(--duration);
|
|
48
|
+
background-color var(--duration);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
/* The native input owns focus, selection, autofill, paste, and one-time-code
|
|
47
|
-
integration. Its
|
|
52
|
+
integration. Its clipped extension accommodates the trailing letter-space
|
|
53
|
+
and final caret so the browser never scrolls the glyphs out of alignment. */
|
|
48
54
|
.otp > input {
|
|
49
55
|
position: absolute;
|
|
50
56
|
z-index: 1;
|
|
51
57
|
inset: 0;
|
|
52
|
-
inline-size: 100
|
|
58
|
+
inline-size: calc(100% + var(--otp-caret-space));
|
|
53
59
|
block-size: 100%;
|
|
54
60
|
margin: 0;
|
|
55
|
-
padding: 0
|
|
61
|
+
padding-block: 0;
|
|
62
|
+
padding-inline: calc((var(--otp-cell-size) - 1ch) / 2) 0;
|
|
56
63
|
border: 0;
|
|
57
64
|
outline: 2px solid transparent;
|
|
58
65
|
box-shadow: none;
|
|
@@ -67,12 +74,15 @@
|
|
|
67
74
|
appearance: none;
|
|
68
75
|
}
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
/* Deliberately no group ring: a box around all the cells reads as a second
|
|
78
|
+
component. The caret already carries focus while the code is being typed,
|
|
79
|
+
but it sits in the clipped input extension once every cell is filled, so
|
|
80
|
+
the focused edge must be unambiguous on its own — hence the doubled width,
|
|
81
|
+
not only the color swap. Width is safe to change: box-sizing is border-box
|
|
82
|
+
and the cells have a fixed inline/block size, so nothing reflows. */
|
|
74
83
|
.otp > input:focus ~ span {
|
|
75
84
|
--otp-cell-border: var(--focus);
|
|
85
|
+
--otp-cell-border-width: calc(var(--border-width) * 2);
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
.otp > input[aria-invalid="true"] ~ span,
|
|
@@ -98,12 +108,6 @@
|
|
|
98
108
|
}
|
|
99
109
|
|
|
100
110
|
@media (forced-colors: active) {
|
|
101
|
-
.otp:focus-within {
|
|
102
|
-
outline: var(--focus-outline);
|
|
103
|
-
outline-offset: var(--focus-outline-offset);
|
|
104
|
-
box-shadow: none;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
111
|
.otp > input:focus ~ span {
|
|
108
112
|
--otp-cell-border: Highlight;
|
|
109
113
|
}
|
package/src/css/forms/switch.css
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* --switch-knob-margin
|
|
14
14
|
* --switch-knob-size
|
|
15
15
|
* --switch-travel
|
|
16
|
+
*
|
|
17
|
+
* The track is sized from --choice-control-size (tokens.css), not
|
|
18
|
+
* --control-size: a switch sits on a line of text next to a checkbox, so it
|
|
19
|
+
* follows the control typography rather than field density.
|
|
16
20
|
*/
|
|
17
21
|
/* Intent boundary — inherited intents do not tint this component.
|
|
18
22
|
Local intent classes still win because :where() has zero specificity. */
|
|
@@ -25,10 +29,22 @@
|
|
|
25
29
|
--switch-bg: var(--border);
|
|
26
30
|
--switch-border: var(--border);
|
|
27
31
|
--switch-knob: var(--surface-raised);
|
|
28
|
-
--switch-
|
|
29
|
-
--switch-
|
|
30
|
-
--switch-knob-margin: calc(var(--switch-block-size) * 0.
|
|
31
|
-
|
|
32
|
+
--switch-block-size: calc(var(--choice-control-size) + 0.125em);
|
|
33
|
+
--switch-width: calc(var(--switch-block-size) * 1.8);
|
|
34
|
+
--switch-knob-margin: calc(var(--switch-block-size) * 0.08);
|
|
35
|
+
|
|
36
|
+
/* The knob is concentric in the track: --switch-block-size is a border-box
|
|
37
|
+
height, so the borders have to come out before the inset is applied on
|
|
38
|
+
both axes. Deriving from the outer height instead leaves the knob
|
|
39
|
+
--border-width closer to the rails than to the ends — a 1px error on a
|
|
40
|
+
~1.6px inset, which reads as a knob squeezed against the track. */
|
|
41
|
+
--switch-knob-size: calc(
|
|
42
|
+
var(--switch-block-size) -
|
|
43
|
+
2 *
|
|
44
|
+
var(--border-width) -
|
|
45
|
+
2 *
|
|
46
|
+
var(--switch-knob-margin)
|
|
47
|
+
);
|
|
32
48
|
--switch-travel: calc(
|
|
33
49
|
var(--switch-width) -
|
|
34
50
|
var(--switch-knob-size) -
|
|
@@ -52,6 +68,11 @@
|
|
|
52
68
|
cursor: pointer;
|
|
53
69
|
}
|
|
54
70
|
|
|
71
|
+
/* No elevation on the knob: --shadow is a surface elevation (card, modal,
|
|
72
|
+
drawer, fab), and at this size its 12px blur reads as a smudge that spills
|
|
73
|
+
past the rail while carrying no state. The range thumb — the same kind of
|
|
74
|
+
small moving part — stays flat for the same reason. The concentric inset
|
|
75
|
+
against the track is what makes the knob legible. */
|
|
55
76
|
.switch::before {
|
|
56
77
|
content: "";
|
|
57
78
|
inline-size: var(--switch-knob-size);
|
|
@@ -59,11 +80,9 @@
|
|
|
59
80
|
margin-inline: var(--switch-knob-margin);
|
|
60
81
|
border-radius: var(--radius-full);
|
|
61
82
|
background: var(--switch-knob);
|
|
62
|
-
box-shadow: var(--shadow);
|
|
63
83
|
transition:
|
|
64
84
|
transform var(--duration),
|
|
65
|
-
background-color var(--duration)
|
|
66
|
-
box-shadow var(--duration);
|
|
85
|
+
background-color var(--duration);
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
.switch:hover:not(:disabled) {
|
|
@@ -101,28 +120,11 @@
|
|
|
101
120
|
}
|
|
102
121
|
|
|
103
122
|
@media (forced-colors: active) {
|
|
104
|
-
/*
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
--switch-knob: ButtonText;
|
|
109
|
-
}
|
|
110
|
-
|
|
123
|
+
/* The host intentionally stays under UA control for platform contrast and
|
|
124
|
+
focus. The custom knob has no native edge, so this system-color border
|
|
125
|
+
keeps it distinct from the remapped track. If real HCM testing ever needs
|
|
126
|
+
an opt-out, scope it to ::before—never to the interactive input host. */
|
|
111
127
|
.switch::before {
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.switch:checked {
|
|
116
|
-
--switch-bg: Highlight;
|
|
117
|
-
--switch-border: Highlight;
|
|
118
|
-
--switch-knob: HighlightText;
|
|
119
|
-
forced-color-adjust: none;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.switch:disabled {
|
|
123
|
-
--switch-bg: Canvas;
|
|
124
|
-
--switch-border: GrayText;
|
|
125
|
-
--switch-knob: GrayText;
|
|
126
|
-
forced-color-adjust: auto;
|
|
128
|
+
border: var(--border-width) solid ButtonText;
|
|
127
129
|
}
|
|
128
130
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Centered content column with a maximum measure.
|
|
3
|
+
*
|
|
4
|
+
* Public hooks:
|
|
5
|
+
* --center-size
|
|
6
|
+
* --center-pad
|
|
7
|
+
*/
|
|
8
|
+
.center {
|
|
9
|
+
box-sizing: content-box;
|
|
10
|
+
max-inline-size: var(--center-size, 72rem);
|
|
11
|
+
margin-inline: auto;
|
|
12
|
+
padding-inline: var(--center-pad, 1rem);
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Inline group that wraps when space runs out.
|
|
3
|
+
*
|
|
4
|
+
* Public hooks:
|
|
5
|
+
* --cluster-align
|
|
6
|
+
* --cluster-justify
|
|
7
|
+
* --cluster-wrap
|
|
8
|
+
*
|
|
9
|
+
* Child contract: direct-child margins are reset, spacing comes from --gap.
|
|
10
|
+
*/
|
|
11
|
+
.cluster {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-wrap: var(--cluster-wrap, wrap);
|
|
14
|
+
align-items: var(--cluster-align, center);
|
|
15
|
+
justify-content: var(--cluster-justify, flex-start);
|
|
16
|
+
gap: var(--gap);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.cluster > * {
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Explicit 12-column composition canvas.
|
|
3
|
+
*
|
|
4
|
+
* Neither space-driven like .grid nor count-driven like .grid-N: this is a
|
|
5
|
+
* coordinate system. The author places regions with .column-span-N /
|
|
6
|
+
* .column-start-N and owns narrow-container recomposition. There is
|
|
7
|
+
* deliberately no automatic collapse — no threshold, no hidden
|
|
8
|
+
* .container-query behavior, no breakpoint variants. A single framework
|
|
9
|
+
* threshold cannot be right for arbitrary per-region compositions, and a
|
|
10
|
+
* hidden default would have to be undone rather than extended.
|
|
11
|
+
*
|
|
12
|
+
* See docs/design-notes/column-layout.md.
|
|
13
|
+
*
|
|
14
|
+
* Selection — reach for this only when placement is part of the design:
|
|
15
|
+
* independent repeated items -> .grid
|
|
16
|
+
* a known peer density -> .grid-N
|
|
17
|
+
* peers switching together -> .switcher
|
|
18
|
+
* content + secondary region -> .sidebar-layout
|
|
19
|
+
* media + flexible content -> .media
|
|
20
|
+
* exact custom track templates -> --grid-columns on .grid
|
|
21
|
+
*
|
|
22
|
+
* Child contract: each direct child is placed on the canvas via its own
|
|
23
|
+
* .column-span-N / .column-start-N.
|
|
24
|
+
*
|
|
25
|
+
* Unlike .grid-N, the track template does not read --gap, so the gap
|
|
26
|
+
* utilities are exact here at every width.
|
|
27
|
+
*/
|
|
28
|
+
.column-layout {
|
|
29
|
+
display: grid;
|
|
30
|
+
gap: var(--gap);
|
|
31
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Three zero-specificity tiers, applied in this order and only ever separated
|
|
35
|
+
* by source order. ORDER IS LOAD-BEARING:
|
|
36
|
+
*
|
|
37
|
+
* 1. the child reset auto-placed, spanning the whole canvas
|
|
38
|
+
* 2. .column-start-* a definite start line, running to the canvas end
|
|
39
|
+
* 3. .column-span-* the end only, so it refines either of the above
|
|
40
|
+
*
|
|
41
|
+
* Moving tier 3 above tier 2 makes every start+span pair run to column 12;
|
|
42
|
+
* moving either above tier 1 makes every placement full-span. Both failures
|
|
43
|
+
* are silent. tests/css-audit.test.js locks the order and
|
|
44
|
+
* tests/browser/column-layout.test.js locks the resulting geometry.
|
|
45
|
+
*
|
|
46
|
+
* Zero specificity is the point: an application's own container-query rules
|
|
47
|
+
* override placement additively, with a single-class selector and without
|
|
48
|
+
* having to undo framework specificity first.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/* Tier 1. A child with no placement class stays a readable full-width region
|
|
52
|
+
* instead of collapsing to one twelfth. Expressed as a span, not as
|
|
53
|
+
* `1 / -1`: a definite start line would give every child a definite column
|
|
54
|
+
* position and disable auto-placement, so `.column-span-8` next to
|
|
55
|
+
* `.column-span-4` would stack instead of composing 8 + 4.
|
|
56
|
+
*
|
|
57
|
+
* min-inline-size: 0 keeps the item box inside its track so the canvas never
|
|
58
|
+
* grows past its container. It does not stop content from painting outside a
|
|
59
|
+
* narrow track — that distinction is the primitive's contract, not a bug. */
|
|
60
|
+
:where(.column-layout) > * {
|
|
61
|
+
grid-column-end: span 12;
|
|
62
|
+
min-inline-size: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Tier 2. A definite start line, running to the end of the canvas unless a
|
|
66
|
+
* .column-span-* refines the end. `column-start-9` alone is therefore the
|
|
67
|
+
* last four columns rather than an implicit 21-line overflow. */
|
|
68
|
+
:where(.column-start-1) {
|
|
69
|
+
grid-column: 1 / -1;
|
|
70
|
+
}
|
|
71
|
+
:where(.column-start-2) {
|
|
72
|
+
grid-column: 2 / -1;
|
|
73
|
+
}
|
|
74
|
+
:where(.column-start-3) {
|
|
75
|
+
grid-column: 3 / -1;
|
|
76
|
+
}
|
|
77
|
+
:where(.column-start-4) {
|
|
78
|
+
grid-column: 4 / -1;
|
|
79
|
+
}
|
|
80
|
+
:where(.column-start-5) {
|
|
81
|
+
grid-column: 5 / -1;
|
|
82
|
+
}
|
|
83
|
+
:where(.column-start-6) {
|
|
84
|
+
grid-column: 6 / -1;
|
|
85
|
+
}
|
|
86
|
+
:where(.column-start-7) {
|
|
87
|
+
grid-column: 7 / -1;
|
|
88
|
+
}
|
|
89
|
+
:where(.column-start-8) {
|
|
90
|
+
grid-column: 8 / -1;
|
|
91
|
+
}
|
|
92
|
+
:where(.column-start-9) {
|
|
93
|
+
grid-column: 9 / -1;
|
|
94
|
+
}
|
|
95
|
+
:where(.column-start-10) {
|
|
96
|
+
grid-column: 10 / -1;
|
|
97
|
+
}
|
|
98
|
+
:where(.column-start-11) {
|
|
99
|
+
grid-column: 11 / -1;
|
|
100
|
+
}
|
|
101
|
+
:where(.column-start-12) {
|
|
102
|
+
grid-column: 12 / -1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Tier 3. The end only. Combined with a start, keep the placement inside the
|
|
106
|
+
* canvas: S + N - 1 <= 12. Exceeding it adds an auto-sized implicit column,
|
|
107
|
+
* which reshapes every 1fr track — the whole canvas loses its alignment, not
|
|
108
|
+
* just the offending region. */
|
|
109
|
+
:where(.column-span-1) {
|
|
110
|
+
grid-column-end: span 1;
|
|
111
|
+
}
|
|
112
|
+
:where(.column-span-2) {
|
|
113
|
+
grid-column-end: span 2;
|
|
114
|
+
}
|
|
115
|
+
:where(.column-span-3) {
|
|
116
|
+
grid-column-end: span 3;
|
|
117
|
+
}
|
|
118
|
+
:where(.column-span-4) {
|
|
119
|
+
grid-column-end: span 4;
|
|
120
|
+
}
|
|
121
|
+
:where(.column-span-5) {
|
|
122
|
+
grid-column-end: span 5;
|
|
123
|
+
}
|
|
124
|
+
:where(.column-span-6) {
|
|
125
|
+
grid-column-end: span 6;
|
|
126
|
+
}
|
|
127
|
+
:where(.column-span-7) {
|
|
128
|
+
grid-column-end: span 7;
|
|
129
|
+
}
|
|
130
|
+
:where(.column-span-8) {
|
|
131
|
+
grid-column-end: span 8;
|
|
132
|
+
}
|
|
133
|
+
:where(.column-span-9) {
|
|
134
|
+
grid-column-end: span 9;
|
|
135
|
+
}
|
|
136
|
+
:where(.column-span-10) {
|
|
137
|
+
grid-column-end: span 10;
|
|
138
|
+
}
|
|
139
|
+
:where(.column-span-11) {
|
|
140
|
+
grid-column-end: span 11;
|
|
141
|
+
}
|
|
142
|
+
:where(.column-span-12) {
|
|
143
|
+
grid-column-end: span 12;
|
|
144
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* Local container-query opt-in: establishes an inline-size query context for
|
|
2
|
+
descendants. Use it for a component that changes representation according
|
|
3
|
+
to its allocated inline size, and to opt .grid-N into balanced subdivision
|
|
4
|
+
(see grid.css). Layout primitives are responsive without it — this adds
|
|
5
|
+
precision, it is never a prerequisite.
|
|
6
|
+
|
|
7
|
+
The element takes inline-size containment, so put it on a normal
|
|
8
|
+
block-level wrapper, never on a shrink-to-fit item (a .cluster child, a
|
|
9
|
+
float, an inline-block): its contents would stop contributing to its own
|
|
10
|
+
inline size and it would collapse. */
|
|
11
|
+
.container-query {
|
|
12
|
+
container-type: inline-size;
|
|
13
|
+
}
|