@codenhub/styles 0.5.0 → 0.7.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/NOTICE +18 -16
- package/README.es.md +61 -0
- package/README.md +27 -22
- package/README.pt-BR.md +61 -0
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +2 -2
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/dist/tw/aesthetics/chunky-tile.css +120 -62
- package/dist/tw/aesthetics/cyber.css +102 -40
- package/dist/tw/aesthetics/glass.css +371 -19
- package/dist/tw/aesthetics/index.css +2 -1
- package/dist/tw/aesthetics/neobrutalism.css +121 -33
- package/dist/tw/aesthetics/pixel.css +111 -16
- package/dist/tw/aesthetics/sketch.css +100 -28
- package/dist/tw/box.css +69 -28
- package/dist/tw/components/button.css +35 -14
- package/dist/tw/components/feedback.css +61 -58
- package/dist/tw/components/form.css +255 -142
- package/dist/tw/components/index.css +4 -9
- package/dist/tw/components/surface.css +80 -68
- package/dist/tw/components/tooltip.css +75 -41
- package/dist/tw/elevation.css +14 -22
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +35 -27
- package/dist/tw/native.css +22 -12
- package/dist/tw/palette.css +14 -11
- package/dist/tw/presentation.css +16 -30
- package/dist/tw/reset.css +36 -43
- package/dist/tw/surface.css +11 -12
- package/dist/tw/theme.css +87 -103
- package/dist/tw/utilities/content.css +311 -200
- package/dist/tw/utilities/layout.css +41 -37
- package/docs/accessibility.md +104 -58
- package/docs/changelog/0.1.1.md +1 -0
- package/docs/changelog/0.2.0.md +1 -0
- package/docs/changelog/0.3.0.md +1 -0
- package/docs/changelog/0.4.0.md +1 -0
- package/docs/changelog/0.5.0.md +8 -3
- package/docs/changelog/0.6.0.md +53 -0
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +150 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +104 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +47 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +78 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +115 -0
- package/docs/es/setup.md +180 -0
- package/docs/es/usage/aesthetics.md +276 -0
- package/docs/es/usage/buttons.md +131 -0
- package/docs/es/usage/composing.md +164 -0
- package/docs/es/usage/content-and-layout.md +215 -0
- package/docs/es/usage/customizing.md +298 -0
- package/docs/es/usage/feedback.md +153 -0
- package/docs/es/usage/forms.md +231 -0
- package/docs/es/usage/index.md +29 -0
- package/docs/es/usage/solo.md +84 -0
- package/docs/es/usage/theming.md +296 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +89 -21
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +18 -13
- package/docs/integrating/nextjs.md +4 -5
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +29 -8
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +114 -0
- package/docs/pt-BR/accessibility.md +150 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +104 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +47 -0
- package/docs/pt-BR/integrating/nextjs.md +67 -0
- package/docs/pt-BR/integrating/svelte.md +45 -0
- package/docs/pt-BR/integrating/tailwind.md +78 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +115 -0
- package/docs/pt-BR/setup.md +180 -0
- package/docs/pt-BR/usage/aesthetics.md +276 -0
- package/docs/pt-BR/usage/buttons.md +131 -0
- package/docs/pt-BR/usage/composing.md +164 -0
- package/docs/pt-BR/usage/content-and-layout.md +215 -0
- package/docs/pt-BR/usage/customizing.md +298 -0
- package/docs/pt-BR/usage/feedback.md +153 -0
- package/docs/pt-BR/usage/forms.md +231 -0
- package/docs/pt-BR/usage/index.md +29 -0
- package/docs/pt-BR/usage/solo.md +84 -0
- package/docs/pt-BR/usage/theming.md +296 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +134 -91
- package/docs/usage/aesthetics.md +102 -65
- package/docs/usage/buttons.md +108 -40
- package/docs/usage/composing.md +105 -92
- package/docs/usage/content-and-layout.md +159 -127
- package/docs/usage/customizing.md +112 -43
- package/docs/usage/feedback.md +135 -70
- package/docs/usage/forms.md +184 -99
- package/docs/usage/index.md +18 -14
- package/docs/usage/solo.md +83 -0
- package/docs/usage/theming.md +260 -119
- package/docs/usage/tooltips.md +103 -42
- package/llms-full.txt +2465 -1272
- package/llms.txt +25 -17
- package/package.json +28 -35
- package/dist/tw/components/loader.css +0 -117
|
@@ -24,18 +24,16 @@
|
|
|
24
24
|
--_d-fg-on-fill: 0%;
|
|
25
25
|
--_d-border: 100%;
|
|
26
26
|
|
|
27
|
-
/*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
`.soft`
|
|
31
|
-
|
|
32
|
-
classed.
|
|
27
|
+
/* 6% is a quiet wash, and it is the cap rather than a presentation: `.soft`
|
|
28
|
+
names the tint it wants and takes it whole below, so what this governs is
|
|
29
|
+
`.solid` and the container that cascades one onto a field nobody classed. A
|
|
30
|
+
cap equal to `.soft`'s 12% would hand `.solid` and `.soft` the same tint
|
|
31
|
+
through `min()`.
|
|
33
32
|
|
|
34
33
|
Named rather than written into the `min()`, because the soft hover below is
|
|
35
34
|
derived from it and the two must not drift apart. Typed text is
|
|
36
|
-
`--intent-
|
|
37
|
-
|
|
38
|
-
written for.
|
|
35
|
+
`--intent-strong` over a wash of its own tone, which holds 4.5:1 for every
|
|
36
|
+
intent in both themes up to `.solid`'s 20% below.
|
|
39
37
|
|
|
40
38
|
The fill and the ink are `box`'s own, unrestated: its `--_capped` reads
|
|
41
39
|
this cap, so the plate and the ink ramp stay in step at every bound,
|
|
@@ -54,17 +52,16 @@
|
|
|
54
52
|
back to 100% -- its line is a silhouette rather than a field's edge, and
|
|
55
53
|
there is nothing else marking an unchecked box. */
|
|
56
54
|
--_line-rest: 60%;
|
|
57
|
-
/* Two seams rather than one composed result. `--_line-tone` is what colour
|
|
58
|
-
line is, and the states below move it; `--_line` folds in the fill,
|
|
59
|
-
the line toward the intent colour by the fill amount, so a state
|
|
60
|
-
to restate that blend to keep it. It is a field's own form of P3
|
|
61
|
-
`box`'s: a field keeps its line whatever it is filled with, so
|
|
62
|
-
toward the fill's colour instead of fading out into it.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
below, one property over. */
|
|
55
|
+
/* Two seams rather than one composed result. `--_line-tone` is what colour
|
|
56
|
+
the line is, and the states below move it; `--_line` folds in the fill,
|
|
57
|
+
walking the line toward the intent colour by the fill amount, so a state
|
|
58
|
+
never has to restate that blend to keep it. It is a field's own form of P3
|
|
59
|
+
rather than `box`'s: a field keeps its line whatever it is filled with, so
|
|
60
|
+
the line walks toward the fill's colour instead of fading out into it.
|
|
61
|
+
|
|
62
|
+
A single `--_line` that states overwrote would lose the blend along with
|
|
63
|
+
the tone, because replacing a composed result drops every term it was
|
|
64
|
+
composed from -- the same failure as the edge below. */
|
|
68
65
|
--_line-tone: color-mix(in oklab, var(--intent-border) var(--_line-rest), transparent);
|
|
69
66
|
--_line: color-mix(in oklab, var(--intent-color) var(--_fill), var(--_line-tone));
|
|
70
67
|
/* The edge floor, as an input to `box` rather than a rewrite of its result.
|
|
@@ -76,22 +73,34 @@
|
|
|
76
73
|
An element's own `.edgeless` lowers the floor -- see the rule below the
|
|
77
74
|
utility -- which is a consumer naming what they want rather than a cascade
|
|
78
75
|
reaching something nobody classed. `.checkbox` and `.radio` are left off
|
|
79
|
-
that rule and keep the floor absolute: they have nothing outside their
|
|
80
|
-
so removing it removes the control.
|
|
81
|
-
|
|
82
|
-
This used to be `--_edge: color-mix(...)` written after `@apply box`, which
|
|
83
|
-
dropped `--ui-border` out of the composition entirely. `.edged` and
|
|
84
|
-
`.edgeless` were both inert on all six text controls, and `--_d-border` was
|
|
85
|
-
declared and never read on each of them. */
|
|
76
|
+
that rule and keep the floor absolute: they have nothing outside their
|
|
77
|
+
line, so removing it removes the control. */
|
|
86
78
|
--_edge-floor: 100%;
|
|
87
79
|
|
|
88
80
|
@apply w-full appearance-none;
|
|
89
81
|
|
|
82
|
+
/* The surrounding font rather than the user agent's smaller field one, on
|
|
83
|
+
every entry: `/components` carries no reset to say so. */
|
|
84
|
+
font-family: inherit;
|
|
85
|
+
font-size: inherit;
|
|
86
|
+
line-height: inherit;
|
|
87
|
+
|
|
90
88
|
&::placeholder {
|
|
91
89
|
color: var(--color-text-secondary);
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
/* The last exclusion is `.input-group`'s: a group whose control is disabled
|
|
93
|
+
dims as a disabled field does (see `input-group`), so it does not answer
|
|
94
|
+
the pointer either. The list is the group's own, so a `<select>` with a
|
|
95
|
+
disabled `<option>` is not caught by it. */
|
|
96
|
+
&:hover:not(
|
|
97
|
+
:disabled,
|
|
98
|
+
.disabled,
|
|
99
|
+
[aria-disabled="true"],
|
|
100
|
+
[data-disabled],
|
|
101
|
+
:focus-visible,
|
|
102
|
+
:has(> :is(.ipt, .textarea, .select, .text-control, input, textarea, select):disabled)
|
|
103
|
+
) {
|
|
95
104
|
--_line-tone: var(--intent-hover);
|
|
96
105
|
}
|
|
97
106
|
|
|
@@ -103,60 +112,69 @@
|
|
|
103
112
|
--_line-tone: var(--intent-color);
|
|
104
113
|
}
|
|
105
114
|
|
|
106
|
-
/*
|
|
107
|
-
|
|
108
|
-
them, and `box` composes the rest. It does not write a result
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
The fill
|
|
118
|
-
|
|
119
|
-
plate
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
something. Lives here, not on the toggles, because a text input is never
|
|
129
|
-
`:checked`.
|
|
130
|
-
|
|
131
|
-
The ink is declared alongside the fill: the other half of what a fill
|
|
132
|
-
class asks for is how much contrast ink it wants (`--ui-fg-on-fill: 0%` is
|
|
133
|
-
`.ghost`/`.soft` declaring "none, my plate stays quiet"), and setting the
|
|
134
|
-
fill without this left a checked `.ghost`/`.soft` toggle with an opaque
|
|
135
|
-
plate and a mark that still read as though the plate were quiet -- both
|
|
136
|
-
derived from the same intent tone, close enough to disappear into each
|
|
137
|
-
other. `box` ramps the ink against the bounded fill before `--ui-bg-alpha`
|
|
138
|
-
thins it, so a checked toggle under `.glass` keeps full contrast ink on
|
|
139
|
-
its translucent plate. */
|
|
115
|
+
/* S1, P6: `:checked` is a state, so it re-declares the presentation inputs --
|
|
116
|
+
a full fill and full contrast ink -- and lifts the cap that would bound
|
|
117
|
+
them, and `box` composes the rest. It does not write a result: pinning
|
|
118
|
+
`--_fill` and `--_fg` directly would make a checked toggle ignore its own
|
|
119
|
+
aesthetic and elevation along with presentation. It sits in `utilities` at
|
|
120
|
+
0-2-0, above the fill classes in `components`, so a checked toggle renders
|
|
121
|
+
one plate whatever presentation it or a container asks for, and a
|
|
122
|
+
consumer's utility loses to it because state wins over every choice
|
|
123
|
+
(model.md#precedence). A toggle is a void `<input>`, so the inputs it
|
|
124
|
+
writes reach nothing but its own mark.
|
|
125
|
+
|
|
126
|
+
The checked fill is 100% whatever the presentation, so a checkbox, a radio,
|
|
127
|
+
and a switch each have one "on" identity; presentation separates the
|
|
128
|
+
*unchecked* plate instead (see `checkbox`/`radio`/`switch` below). It lives
|
|
129
|
+
here, not on the toggles, because a text input is never `:checked`.
|
|
130
|
+
|
|
131
|
+
The ink is declared alongside the fill: `--ui-fg-on-fill: 0%` is
|
|
132
|
+
`.ghost`/`.soft` declaring "my plate stays quiet", and a checked toggle
|
|
133
|
+
with an opaque plate and an ink that still expects a quiet one loses its
|
|
134
|
+
mark into the plate. `box` ramps the ink against the bounded fill before
|
|
135
|
+
`--ui-bg-alpha` thins it, so a checked toggle under `.glass` keeps full
|
|
136
|
+
contrast ink on its translucent plate. */
|
|
140
137
|
&:checked {
|
|
141
138
|
--ui-fill: 100%;
|
|
142
139
|
--ui-fg-on-fill: 100%;
|
|
143
140
|
--_fill-cap: 100%;
|
|
144
141
|
}
|
|
142
|
+
}
|
|
145
143
|
|
|
146
|
-
|
|
144
|
+
/* The browser's own field decorations -- the date picker button, a number's
|
|
145
|
+
spin buttons, a search field's clear and magnifier -- stay by default,
|
|
146
|
+
because each one is also behaviour: hiding the picker button hides the only
|
|
147
|
+
pointer route to the picker. `.unadorned` removes them for a consumer who
|
|
148
|
+
draws their own adornments in an `.input-group` and wires the behaviour back
|
|
149
|
+
(`showPicker()`, `stepUp()`/`stepDown()`, clearing the value). On the
|
|
150
|
+
control, or on the group to reach the control inside.
|
|
151
|
+
|
|
152
|
+
Firefox exposes no pseudo-element for its date picker button, so that one
|
|
153
|
+
stays there; its number spinners go with `appearance: textfield`. */
|
|
154
|
+
@utility unadorned {
|
|
147
155
|
&::-webkit-search-decoration,
|
|
148
156
|
&::-webkit-search-cancel-button,
|
|
149
157
|
&::-webkit-search-results-button,
|
|
150
158
|
&::-webkit-search-results-decoration,
|
|
151
159
|
&::-webkit-calendar-picker-indicator,
|
|
152
160
|
&::-webkit-inner-spin-button,
|
|
153
|
-
&::-webkit-
|
|
161
|
+
&::-webkit-outer-spin-button,
|
|
162
|
+
&::-webkit-clear-button,
|
|
163
|
+
& > input::-webkit-search-decoration,
|
|
164
|
+
& > input::-webkit-search-cancel-button,
|
|
165
|
+
& > input::-webkit-search-results-button,
|
|
166
|
+
& > input::-webkit-search-results-decoration,
|
|
167
|
+
& > input::-webkit-calendar-picker-indicator,
|
|
168
|
+
& > input::-webkit-inner-spin-button,
|
|
169
|
+
& > input::-webkit-outer-spin-button,
|
|
170
|
+
& > input::-webkit-clear-button {
|
|
154
171
|
-webkit-appearance: none;
|
|
155
|
-
display: none
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
display: none;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
&[type="number"],
|
|
176
|
+
& > input[type="number"] {
|
|
177
|
+
appearance: textfield;
|
|
160
178
|
}
|
|
161
179
|
}
|
|
162
180
|
|
|
@@ -164,19 +182,19 @@
|
|
|
164
182
|
`@utility`, placed in `utilities` and winning there on specificity, each at
|
|
165
183
|
least 0-2-0 against the component's 0-1-0. They write only package privates
|
|
166
184
|
(`--_fill-cap`, `--_edge-floor`) or a state's intent slots, so nothing a
|
|
167
|
-
consumer writes competes with them.
|
|
168
|
-
|
|
169
|
-
too. See docs/internal/model.md#cascade-layers. */
|
|
185
|
+
consumer writes competes with them. See
|
|
186
|
+
docs/internal/model.md#cascade-layers. */
|
|
170
187
|
@layer utilities {
|
|
171
188
|
/* A fill class on the element names its own cap; the 6% cascade cap in the
|
|
172
189
|
utility is for a container reaching a field nobody classed. Both raise
|
|
173
190
|
`--_fill-cap` rather than writing `--_fill` (P6), which is also what keeps
|
|
174
|
-
`.soft` < `.solid
|
|
175
|
-
quieter box
|
|
176
|
-
|
|
191
|
+
`.soft` < `.solid`: written as a rewrite, the louder name renders the
|
|
192
|
+
quieter box. 20% clears `.soft`'s 12% and matches the plate a `.solid`
|
|
193
|
+
badge draws.
|
|
177
194
|
|
|
178
195
|
`.switch` is deliberately absent: its track caps at 40% in its own utility,
|
|
179
|
-
and a 0-2-0 rule here would overrule that. See
|
|
196
|
+
and a 0-2-0 rule here would overrule that. See
|
|
197
|
+
model.md#the-bounds-that-survive-and-the-test-for-keeping-one. */
|
|
180
198
|
:is(.text-control, .ipt, .textarea, .select, .input-group).soft {
|
|
181
199
|
--_fill-cap: 12%;
|
|
182
200
|
}
|
|
@@ -211,24 +229,22 @@
|
|
|
211
229
|
/* The element's own `.edgeless` lowers the floor `text-control` raises -- a
|
|
212
230
|
class on the element is a consumer's request, a class on a container is a
|
|
213
231
|
cascade. `.checkbox` and `.radio` are absent: an unchecked one is a
|
|
214
|
-
transparent square/circle with nothing but its line, so the floor is
|
|
215
|
-
and `.edgeless` on them is published unsupported. `.input-group`
|
|
216
|
-
because the group is the field boundary
|
|
232
|
+
transparent square/circle with nothing but its line, so the floor is
|
|
233
|
+
absolute and `.edgeless` on them is published unsupported. `.input-group`
|
|
234
|
+
is on it because the group is the field boundary. */
|
|
217
235
|
:is(.text-control, .ipt, .textarea, .select, .switch, .input-group).edgeless {
|
|
218
236
|
--_edge-floor: 0%;
|
|
219
237
|
}
|
|
220
238
|
|
|
221
239
|
/* `.switch`'s one exception to the opt-out above: `.ghost` already asks for
|
|
222
|
-
zero fill, so a `.switch.ghost.edgeless` track
|
|
223
|
-
plate and
|
|
224
|
-
knob. Every other fill on this component
|
|
225
|
-
(`.soft`/`.solid`/default all rest above 0%), so only this
|
|
226
|
-
|
|
227
|
-
`.switch.ghost.edged
|
|
228
|
-
the
|
|
229
|
-
|
|
230
|
-
specificity than the rule above (three classes, not an `:is()` of one)
|
|
231
|
-
wins regardless of source order. */
|
|
240
|
+
zero fill, so a `.switch.ghost.edgeless` track would have neither a line
|
|
241
|
+
nor a plate and disappear -- nothing would mark its bounds but the floating
|
|
242
|
+
knob. Every other fill on this component has something to paint
|
|
243
|
+
(`.soft`/`.solid`/default all rest above 0%), so only this pairing needs
|
|
244
|
+
the floor held up. `.switch.ghost.edgeless` therefore renders identically
|
|
245
|
+
to `.switch.ghost.edged`, and is published unsupported as a distinct look.
|
|
246
|
+
Higher specificity than the rule above (three classes, not an `:is()` of
|
|
247
|
+
one) wins regardless of source order. */
|
|
232
248
|
.switch.ghost.edgeless {
|
|
233
249
|
--_edge-floor: 100%;
|
|
234
250
|
}
|
|
@@ -236,10 +252,12 @@
|
|
|
236
252
|
/* An invalid control is destructive whatever else it was asked to be. It sits
|
|
237
253
|
in `utilities`, above every intent class and both intent resets in
|
|
238
254
|
`components`, and `:is()` gives it 0-2-0 so it also outranks the control's
|
|
239
|
-
own utility; a consumer's utility setting an intent slot on an invalid
|
|
240
|
-
loses to it too, because state wins over every choice
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
own utility; a consumer's utility setting an intent slot on an invalid
|
|
256
|
+
field loses to it too, because state wins over every choice
|
|
257
|
+
(model.md#precedence). `--intent-hover` is redirected with the others so
|
|
258
|
+
the line does not go grey under the pointer, and `--intent-strong` so typed
|
|
259
|
+
text is destructive too. The `:has()` arm bridges an
|
|
260
|
+
inner control's state to an `.input-group`. */
|
|
243
261
|
:is(
|
|
244
262
|
.text-control,
|
|
245
263
|
.ipt,
|
|
@@ -257,6 +275,7 @@
|
|
|
257
275
|
--intent-color: var(--color-destructive);
|
|
258
276
|
--intent-hover: var(--color-destructive-hover);
|
|
259
277
|
--intent-border: var(--color-destructive);
|
|
278
|
+
--intent-strong: var(--color-destructive-strong);
|
|
260
279
|
}
|
|
261
280
|
}
|
|
262
281
|
|
|
@@ -272,10 +291,12 @@
|
|
|
272
291
|
--_d-border: 100%;
|
|
273
292
|
--_d-elevation: 0;
|
|
274
293
|
|
|
275
|
-
/* Typed text is the intent
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
294
|
+
/* Typed text is the intent printed on a page, `--intent-strong`: a field's
|
|
295
|
+
plate is at most a wash, and `--intent-color`, a fill colour, reads below
|
|
296
|
+
4.5:1 there for several intents. On the three text inputs, not
|
|
297
|
+
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
298
|
+
instead. See docs/internal/model.md#intent. */
|
|
299
|
+
--_fg: var(--intent-strong);
|
|
279
300
|
|
|
280
301
|
min-height: var(--control-height);
|
|
281
302
|
}
|
|
@@ -292,12 +313,14 @@
|
|
|
292
313
|
letter-spacing: 0.025em;
|
|
293
314
|
}
|
|
294
315
|
|
|
316
|
+
/* A hint wraps, so it takes `text-sm`'s leading like the package's other 14px
|
|
317
|
+
text rather than a line height equal to its size, where wrapped lines touch. */
|
|
295
318
|
@utility hint {
|
|
319
|
+
@apply text-sm;
|
|
320
|
+
|
|
296
321
|
color: var(--color-text-secondary);
|
|
297
|
-
font-size: 0.875rem;
|
|
298
322
|
font-weight: 400;
|
|
299
323
|
letter-spacing: 0.05em;
|
|
300
|
-
line-height: 100%;
|
|
301
324
|
|
|
302
325
|
&.destructive {
|
|
303
326
|
color: var(--intent-color);
|
|
@@ -313,10 +336,12 @@
|
|
|
313
336
|
--_d-border: 100%;
|
|
314
337
|
--_d-elevation: 0;
|
|
315
338
|
|
|
316
|
-
/* Typed text is the intent
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
339
|
+
/* Typed text is the intent printed on a page, `--intent-strong`: a field's
|
|
340
|
+
plate is at most a wash, and `--intent-color`, a fill colour, reads below
|
|
341
|
+
4.5:1 there for several intents. On the three text inputs, not
|
|
342
|
+
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
343
|
+
instead. See docs/internal/model.md#intent. */
|
|
344
|
+
--_fg: var(--intent-strong);
|
|
320
345
|
|
|
321
346
|
@apply min-h-28 resize-y;
|
|
322
347
|
}
|
|
@@ -325,17 +350,19 @@
|
|
|
325
350
|
gradients rather than masked, because `appearance: none` removes the platform
|
|
326
351
|
arrow and a background image is the only thing a replaced element can paint. */
|
|
327
352
|
@utility select {
|
|
328
|
-
@apply text-control h-(--control-height,2.5rem) py-2
|
|
353
|
+
@apply text-control h-(--control-height,2.5rem) py-2 ps-3 pe-10;
|
|
329
354
|
|
|
330
355
|
--_d-fill: 0%;
|
|
331
356
|
--_d-fg-on-fill: 0%;
|
|
332
357
|
--_d-border: 100%;
|
|
333
358
|
--_d-elevation: 0;
|
|
334
359
|
|
|
335
|
-
/* Typed text is the intent
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
360
|
+
/* Typed text is the intent printed on a page, `--intent-strong`: a field's
|
|
361
|
+
plate is at most a wash, and `--intent-color`, a fill colour, reads below
|
|
362
|
+
4.5:1 there for several intents. On the three text inputs, not
|
|
363
|
+
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
364
|
+
instead. See docs/internal/model.md#intent. */
|
|
365
|
+
--_fg: var(--intent-strong);
|
|
339
366
|
|
|
340
367
|
min-height: var(--control-height);
|
|
341
368
|
background-image:
|
|
@@ -347,6 +374,15 @@
|
|
|
347
374
|
background-repeat: no-repeat;
|
|
348
375
|
background-size: 0.3125rem 0.3125rem;
|
|
349
376
|
|
|
377
|
+
/* The chevron sits at the inline end, like the padding kept for it, so a
|
|
378
|
+
right-to-left select draws it at the left. `background-position` has no
|
|
379
|
+
logical form, so the mirror is named here. */
|
|
380
|
+
&:dir(rtl) {
|
|
381
|
+
background-position:
|
|
382
|
+
0.6875rem center,
|
|
383
|
+
1rem center;
|
|
384
|
+
}
|
|
385
|
+
|
|
350
386
|
/* The open list is painted by the browser, over the select's own background
|
|
351
387
|
when it has one. A ghost select has none, so Chromium falls back to its
|
|
352
388
|
default popup -- white on Windows -- while the options inherit the select's
|
|
@@ -357,6 +393,15 @@
|
|
|
357
393
|
background-color: var(--color-background);
|
|
358
394
|
color: var(--color-text);
|
|
359
395
|
}
|
|
396
|
+
|
|
397
|
+
/* Several rows showing is a list box, not a drop-down: no chevron, the height
|
|
398
|
+
of its rows, and the chevron's room given back. `--control-height` stays
|
|
399
|
+
the floor. */
|
|
400
|
+
&:is([multiple], [size]:not([size="1"])) {
|
|
401
|
+
height: auto;
|
|
402
|
+
padding-inline: 0.75rem;
|
|
403
|
+
background-image: none;
|
|
404
|
+
}
|
|
360
405
|
}
|
|
361
406
|
|
|
362
407
|
/* A wrapper that owns the field box so a control can carry adornments beside it
|
|
@@ -410,7 +455,7 @@
|
|
|
410
455
|
--_line-tone: var(--intent-color);
|
|
411
456
|
|
|
412
457
|
outline: var(--focus-ring-width) solid var(--focus-ring);
|
|
413
|
-
outline-offset: var(--focus-ring-offset);
|
|
458
|
+
outline-offset: var(--focus-ring-offset, calc(-1 * var(--ui-border-width, var(--border-width))));
|
|
414
459
|
box-shadow: var(--_focus-stack, var(--_shadow));
|
|
415
460
|
}
|
|
416
461
|
|
|
@@ -444,6 +489,14 @@
|
|
|
444
489
|
}
|
|
445
490
|
}
|
|
446
491
|
|
|
492
|
+
/* Except a drop-down's end: its chevron is the select's own background,
|
|
493
|
+
drawn inside its box 0.6875-1.3125rem from the inline end, so a long label
|
|
494
|
+
with no padding there ran under it. A list box draws none and keeps the
|
|
495
|
+
padding its own rule gives it. */
|
|
496
|
+
& > :is(.select, select):not([multiple], [size]:not([size="1"])) {
|
|
497
|
+
padding-inline-end: 1.75rem;
|
|
498
|
+
}
|
|
499
|
+
|
|
447
500
|
/* Anything else in the group -- an icon, affix text -- does not stretch and
|
|
448
501
|
reads as secondary. A nested `<button>` keeps its own styling. */
|
|
449
502
|
& > :not(.ipt, .textarea, .select, .text-control, input, textarea, select, button) {
|
|
@@ -456,19 +509,14 @@
|
|
|
456
509
|
/* The three toggles compose `text-control` for its bounds, not its chrome: the
|
|
457
510
|
edge floor keeps a container's `.edgeless` from erasing the closed silhouette
|
|
458
511
|
(WCAG 1.4.11), and the checked state that pins the fill (see `text-control`'s
|
|
459
|
-
`:checked` above) lives there. They raise the fill cap to 40
|
|
512
|
+
`:checked` above) lives there. They raise the fill cap to 40%: the 6% cap
|
|
460
513
|
keeps typed text legible and a toggle has none, and 40% is where a resting
|
|
461
514
|
`.ghost` (0%), `.soft`/default (12%), and `.solid` (the cap itself) read as
|
|
462
|
-
three distinct plates rather than three shades of
|
|
463
|
-
|
|
464
|
-
`.soft`
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
asks for -- a consumer still reaches that plate by writing `.solid` itself.
|
|
468
|
-
`.ghost` used to be unsupported here -- a checked one used to be a mark on
|
|
469
|
-
nothing -- and is not any more, now that checked reads the same plate
|
|
470
|
-
whatever the presentation.
|
|
471
|
-
See model.md#the-bounds-that-survive-and-the-test-for-keeping-one. */
|
|
515
|
+
three distinct plates rather than three shades of one wash. Unclassed rests
|
|
516
|
+
at `.soft` rather than at the cap: `--_d-fill`/`--_d-fg-on-fill` below name
|
|
517
|
+
the same pair `.soft` does, so a bare `<input class="checkbox">` reads as the
|
|
518
|
+
quiet tint, and a consumer reaches the louder plate by writing `.solid`. See
|
|
519
|
+
model.md#the-bounds-that-survive-and-the-test-for-keeping-one. */
|
|
472
520
|
@utility checkbox {
|
|
473
521
|
@apply text-control inline-grid size-4 cursor-pointer place-content-center;
|
|
474
522
|
|
|
@@ -520,6 +568,31 @@
|
|
|
520
568
|
&:checked::after {
|
|
521
569
|
@apply opacity-100;
|
|
522
570
|
}
|
|
571
|
+
|
|
572
|
+
/* Mixed -- part of a group checked -- takes the checked plate, the same
|
|
573
|
+
inputs `text-control`'s `:checked` writes, and a dash for its mark. After
|
|
574
|
+
the checked mark, so a box that is both draws the dash, as the browser's
|
|
575
|
+
own checkbox does. */
|
|
576
|
+
&:indeterminate {
|
|
577
|
+
--ui-fill: 100%;
|
|
578
|
+
--ui-fg-on-fill: 100%;
|
|
579
|
+
--_fill-cap: 100%;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
&:indeterminate::after {
|
|
583
|
+
@apply opacity-100;
|
|
584
|
+
|
|
585
|
+
mask-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round'><line x1='5' y1='12' x2='19' y2='12'/></svg>");
|
|
586
|
+
-webkit-mask-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round'><line x1='5' y1='12' x2='19' y2='12'/></svg>");
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* The mark appears without moving under reduced motion, for the entries
|
|
590
|
+
without the reset; see `box.css`. */
|
|
591
|
+
@media (prefers-reduced-motion: reduce) {
|
|
592
|
+
&::after {
|
|
593
|
+
transition-duration: 0.01ms;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
523
596
|
}
|
|
524
597
|
|
|
525
598
|
/* The same control with a round silhouette and a dot for its mark, and the
|
|
@@ -561,13 +634,12 @@
|
|
|
561
634
|
}
|
|
562
635
|
|
|
563
636
|
/* A checked radio thickens its ring and takes the intent whole on the line.
|
|
564
|
-
The fill is pinned by `text-control`'s `:checked
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
floor still draws the ring under a container's `.edgeless`. */
|
|
637
|
+
The fill is pinned by `text-control`'s `:checked`, so every checked radio
|
|
638
|
+
is a filled circle whatever fill class it carries. The dot takes `box`'s
|
|
639
|
+
composed foreground, which walks to the contrast tone as the (always full)
|
|
640
|
+
plate fills, so it stays readable. `--_line-tone` rather than `--_edge`, so
|
|
641
|
+
`text-control`'s edge floor still draws the ring under a container's
|
|
642
|
+
`.edgeless`. */
|
|
571
643
|
&:checked {
|
|
572
644
|
--_line-tone: var(--intent-color);
|
|
573
645
|
|
|
@@ -580,6 +652,14 @@
|
|
|
580
652
|
&:checked::after {
|
|
581
653
|
@apply scale-100 opacity-100;
|
|
582
654
|
}
|
|
655
|
+
|
|
656
|
+
/* The mark appears without moving under reduced motion, for the entries
|
|
657
|
+
without the reset; see `box.css`. */
|
|
658
|
+
@media (prefers-reduced-motion: reduce) {
|
|
659
|
+
&::after {
|
|
660
|
+
transition-duration: 0.01ms;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
583
663
|
}
|
|
584
664
|
|
|
585
665
|
/* A2: every dimension derives from the border width `box` resolved, so the knob
|
|
@@ -593,24 +673,30 @@
|
|
|
593
673
|
--_d-border: 100%;
|
|
594
674
|
--_d-elevation: 0;
|
|
595
675
|
|
|
596
|
-
/* 40%, measured: at `text-control`'s 6% the three resting fills
|
|
597
|
-
two looks
|
|
598
|
-
the one place a fill class
|
|
676
|
+
/* 40%, measured: at `text-control`'s 6% the three resting fills collapse to
|
|
677
|
+
two looks, so the switch would have to vary its *line* per fill class --
|
|
678
|
+
the one place a fill class would decide an edge. 40% separates all three
|
|
599
679
|
(29/67/144 sRGB steps on the light page, against ~20 for a visible one)
|
|
600
680
|
without reaching a checked track's pinned 100%, so the knob's position
|
|
601
|
-
still says which
|
|
602
|
-
raise their own cap to the same value for the same reason
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
not the 20% ceiling a badge or a card stays under. */
|
|
681
|
+
still says which; `axes.spec.ts` asserts all three. `checkbox`/`radio`
|
|
682
|
+
raise their own cap to the same value for the same reason. A cap rather
|
|
683
|
+
than a resting value, because it answers the cascade case;
|
|
684
|
+
`--intent-fill-max` (declared where the intents are, above) lifts to 100%
|
|
685
|
+
for all three toggles so a neutral one reads this cap, not the 20% ceiling
|
|
686
|
+
a badge or a card stays under. */
|
|
608
687
|
--_fill-cap: 40%;
|
|
609
688
|
|
|
610
689
|
--switch-height: 1.25rem;
|
|
611
690
|
--switch-width: 2.5rem;
|
|
612
691
|
--switch-gap: 1px;
|
|
613
|
-
|
|
692
|
+
/* The edge an aesthetic draws as an inset ring rather than as a border
|
|
693
|
+
(`.pixel`), present only while `--ui-shadow-edge` is declared -- the idiom
|
|
694
|
+
`box` uses. That ring paints under the knob, so a knob sized from the
|
|
695
|
+
border alone covered it: under pixel the border is zero, the knob met the
|
|
696
|
+
edge, and an unchecked and a checked switch both read as two halves. */
|
|
697
|
+
--_switch-ring: var(--ui-shadow-edge) var(--_ss);
|
|
698
|
+
--_switch-offset: calc(var(--_switch-ring, 0px) + var(--switch-gap));
|
|
699
|
+
--switch-inset: calc(var(--_width) + var(--_switch-offset));
|
|
614
700
|
--switch-knob: calc(var(--switch-height) - var(--switch-inset) * 2);
|
|
615
701
|
--switch-travel: calc(var(--switch-width) - var(--switch-inset) * 2 - var(--switch-knob));
|
|
616
702
|
|
|
@@ -647,8 +733,8 @@
|
|
|
647
733
|
content: "";
|
|
648
734
|
height: var(--switch-knob);
|
|
649
735
|
width: var(--switch-knob);
|
|
650
|
-
top: var(--
|
|
651
|
-
inset-inline-start: var(--
|
|
736
|
+
top: var(--_switch-offset);
|
|
737
|
+
inset-inline-start: var(--_switch-offset);
|
|
652
738
|
}
|
|
653
739
|
|
|
654
740
|
&:checked::after {
|
|
@@ -657,9 +743,20 @@
|
|
|
657
743
|
physical x offset and mirrored under :dir(rtl) to travel toward the
|
|
658
744
|
opposite edge, matching the inset-inline-start resting position. */
|
|
659
745
|
translate: var(--switch-travel);
|
|
746
|
+
}
|
|
660
747
|
|
|
661
|
-
|
|
662
|
-
|
|
748
|
+
/* Direction sits on the control, ahead of the pseudo-element: nested as
|
|
749
|
+
`:dir(rtl) &` inside `&:checked::after`, `&` carries `::after`, which
|
|
750
|
+
cannot appear inside `:is()`, and the emitted rule matched nothing. */
|
|
751
|
+
&:checked:dir(rtl)::after {
|
|
752
|
+
translate: calc(-1 * var(--switch-travel));
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/* The mark appears without moving under reduced motion, for the entries
|
|
756
|
+
without the reset; see `box.css`. */
|
|
757
|
+
@media (prefers-reduced-motion: reduce) {
|
|
758
|
+
&::after {
|
|
759
|
+
transition-duration: 0.01ms;
|
|
663
760
|
}
|
|
664
761
|
}
|
|
665
762
|
}
|
|
@@ -675,7 +772,23 @@
|
|
|
675
772
|
transition: none;
|
|
676
773
|
}
|
|
677
774
|
|
|
775
|
+
/* The switch knob is the one mark visible while unchecked, and with forced
|
|
776
|
+
colours off it would keep the package grey on a system Canvas. */
|
|
777
|
+
.switch::after {
|
|
778
|
+
background-color: CanvasText;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/* The chevron is two gradients, and forced colours drop every gradient, so a
|
|
782
|
+
drop-down with `appearance: none` showed no arrow at all and read as a text
|
|
783
|
+
field. The platform's own arrow comes back instead: it is drawn in system
|
|
784
|
+
colours, and the author border, padding and focus outline still apply. A
|
|
785
|
+
list box has no arrow to restore. */
|
|
786
|
+
.select:not([multiple], [size]:not([size="1"])) {
|
|
787
|
+
appearance: auto;
|
|
788
|
+
}
|
|
789
|
+
|
|
678
790
|
.checkbox:checked,
|
|
791
|
+
.checkbox:indeterminate,
|
|
679
792
|
.radio:checked,
|
|
680
793
|
.switch:checked {
|
|
681
794
|
background-color: Highlight;
|
|
@@ -20,21 +20,16 @@
|
|
|
20
20
|
@import "./button.css";
|
|
21
21
|
@import "./feedback.css";
|
|
22
22
|
@import "./form.css";
|
|
23
|
-
@import "./loader.css";
|
|
24
23
|
@import "./surface.css";
|
|
25
24
|
@import "./tooltip.css";
|
|
26
25
|
|
|
27
|
-
/* The composition utilities -- `box`, `box-hover`, `box-active`,
|
|
26
|
+
/* The composition utilities -- `box`, `box-hover`, `box-active`,
|
|
28
27
|
`text-control`, `surface`, `input-group` -- are `@utility` rules whose bodies
|
|
29
28
|
the content scan will not emit on its own. `box` and friends appear only as
|
|
30
29
|
`@utility` blocks and `@apply` targets; `text-control`, `surface` and
|
|
31
30
|
`input-group` appear only inside `:is()`/`:where()` argument lists in
|
|
32
|
-
`intent.css` and `form.css`, never as a selector of their own.
|
|
33
|
-
|
|
34
|
-
`docs/` from the scan removed that -- `.input-group` (and, with it, its focus
|
|
35
|
-
ring, its flush inner control, and `:has()`-propagated invalid state) went
|
|
36
|
-
silently dark, caught only by the browser suite. Safelisting all seven here
|
|
37
|
-
makes the emission deliberate; the composition-body check in
|
|
31
|
+
`intent.css` and `form.css`, never as a selector of their own. Safelisting
|
|
32
|
+
all six makes the emission deliberate; the composition-body check in
|
|
38
33
|
`exports.test.ts` fails the build if one is dropped. `text-control` and
|
|
39
34
|
`surface` are also documented as consumer-usable on their own. */
|
|
40
|
-
@source inline("box box-hover box-active
|
|
35
|
+
@source inline("box box-hover box-active text-control surface input-group unadorned text-display text-title-lg text-title text-title-sm text-label-lg text-label text-body btn field label hint ipt icon textarea select checkbox radio switch alert alert-icon badge skeleton progress tooltip tooltip-bubble tooltip-icon card panel interactive flush neutral solid soft ghost edged edgeless flat raised floating");
|