@codenhub/styles 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- 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 +1 -1
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -0
- package/dist/components.css +1 -1
- package/dist/index.css +1 -1
- package/dist/native.css +1 -1
- package/dist/palette.css +1 -1
- package/dist/theme.css +1 -1
- package/dist/tw/aesthetics/chunky-tile.css +144 -128
- package/dist/tw/aesthetics/cyber.css +138 -96
- package/dist/tw/aesthetics/glass.css +332 -66
- package/dist/tw/aesthetics/index.css +3 -1
- package/dist/tw/aesthetics/neobrutalism.css +113 -54
- package/dist/tw/aesthetics/pixel.css +137 -87
- package/dist/tw/aesthetics/sketch.css +333 -0
- package/dist/tw/box.css +139 -52
- package/dist/tw/components/button.css +67 -28
- package/dist/tw/components/feedback.css +85 -67
- package/dist/tw/components/form.css +300 -230
- package/dist/tw/components/index.css +17 -9
- package/dist/tw/components/loader.css +38 -30
- package/dist/tw/components/surface.css +89 -129
- package/dist/tw/components/tooltip.css +91 -47
- package/dist/tw/corner.css +26 -0
- package/dist/tw/elevation.css +19 -28
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +47 -32
- package/dist/tw/native.css +58 -42
- package/dist/tw/palette.css +455 -446
- package/dist/tw/presentation.css +20 -29
- package/dist/tw/reset.css +21 -28
- package/dist/tw/surface.css +61 -0
- package/dist/tw/theme.css +156 -153
- package/dist/tw/utilities/content.css +283 -205
- package/dist/tw/utilities/layout.css +17 -27
- package/docs/accessibility.md +63 -46
- package/docs/changelog/0.5.0.md +38 -0
- package/docs/changelog/0.6.0.md +52 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +6 -6
- package/docs/index.md +12 -3
- package/docs/integrating/nextjs.md +1 -1
- package/docs/integrating/tailwind.md +14 -6
- package/docs/setup.md +28 -8
- package/docs/usage/aesthetics.md +88 -18
- package/docs/usage/buttons.md +14 -14
- package/docs/usage/composing.md +12 -12
- package/docs/usage/content-and-layout.md +25 -24
- package/docs/usage/customizing.md +92 -55
- package/docs/usage/feedback.md +5 -3
- package/docs/usage/forms.md +61 -45
- package/docs/usage/theming.md +41 -42
- package/docs/usage/tooltips.md +37 -17
- package/llms-full.txt +590 -304
- package/llms.txt +6 -0
- package/package.json +15 -5
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/* Sketch: uneven elliptical corners, a solid ink edge, and a small hard shadow.
|
|
2
|
+
The handwriting face is consumer-supplied, so this file has no font asset or
|
|
3
|
+
network side effect. */
|
|
4
|
+
|
|
5
|
+
/* The layer map, stated before anything uses a layer -- see `theme.css`. The
|
|
6
|
+
aesthetic's token class sits in `components`, below every utility, so a
|
|
7
|
+
consumer's own utility or unlayered CSS beats it; the solo class stays
|
|
8
|
+
unlayered, because it has to beat a foreign component's unlayered CSS. See
|
|
9
|
+
docs/internal/model.md#cascade-layers. */
|
|
10
|
+
@layer theme, base, components, utilities;
|
|
11
|
+
|
|
12
|
+
@layer components {
|
|
13
|
+
.sketch {
|
|
14
|
+
/* Complete radii are taken as written, without the size step or corner
|
|
15
|
+
pattern. Chips use a smaller version of the same irregular outline.
|
|
16
|
+
Surfaces use sharp, hand-drawn square contours tailored for container
|
|
17
|
+
dimensions to avoid interior padding encroachment. Knobs follow R8. */
|
|
18
|
+
--ui-corner: initial;
|
|
19
|
+
--ui-corner-surface: initial;
|
|
20
|
+
--ui-corner-tl: initial;
|
|
21
|
+
--ui-corner-tr: initial;
|
|
22
|
+
--ui-corner-br: initial;
|
|
23
|
+
--ui-corner-bl: initial;
|
|
24
|
+
--ui-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
|
|
25
|
+
--ui-radius-surface: var(--sketch-radius-surface, 80px 4px 75px 5px / 3px 70px 4px 80px);
|
|
26
|
+
--ui-radius-pill: var(--sketch-radius-pill, 20px 22px 21px 19px / 20px 22px 21px 19px);
|
|
27
|
+
--ui-radius-tight: 11px 1px 7px 2px / 2px 7px 1px 11px;
|
|
28
|
+
--ui-corner-shape: round;
|
|
29
|
+
|
|
30
|
+
--ui-ink: light-dark(var(--color-neutral-950), var(--color-neutral-50));
|
|
31
|
+
/* Controls take the theme's control border rather than the ink, which is the
|
|
32
|
+
primary colour in both themes; see `neobrutalism.css`. */
|
|
33
|
+
--ui-control-ink: var(--color-control-border);
|
|
34
|
+
--ui-rule-ink: initial;
|
|
35
|
+
--ui-border-width: 1px;
|
|
36
|
+
--ui-border-max: 100px;
|
|
37
|
+
--ui-line-style: solid;
|
|
38
|
+
--ui-rule-style: initial;
|
|
39
|
+
|
|
40
|
+
--ui-shadow-ink: 0%;
|
|
41
|
+
/* The foundation depth colour is restated so a sketch region nested inside
|
|
42
|
+
cyber does not inherit cyber's transparent depth. */
|
|
43
|
+
--elevation-color: light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
44
|
+
--ui-shadow-x: 2px;
|
|
45
|
+
--ui-shadow-y: 2px;
|
|
46
|
+
--ui-shadow-blur: 0px;
|
|
47
|
+
--ui-shadow-spread: 0px;
|
|
48
|
+
--ui-shadow-inset: ;
|
|
49
|
+
--ui-shadow-edge: initial;
|
|
50
|
+
--ui-halo-blur: initial;
|
|
51
|
+
--ui-halo-spread: initial;
|
|
52
|
+
--ui-halo-ink: initial;
|
|
53
|
+
--ui-focus-inset: initial;
|
|
54
|
+
|
|
55
|
+
--ui-active-shadow-x: initial;
|
|
56
|
+
--ui-active-shadow-y: initial;
|
|
57
|
+
--ui-active-transform: scale(0.97);
|
|
58
|
+
--ui-active-translate-x: initial;
|
|
59
|
+
--ui-active-translate-y: initial;
|
|
60
|
+
--ui-hover-transform: none;
|
|
61
|
+
--ui-clip: none;
|
|
62
|
+
--ui-clip-tight: none;
|
|
63
|
+
--ui-backdrop: none;
|
|
64
|
+
--ui-surface-image: initial;
|
|
65
|
+
--ui-surface-ground: initial;
|
|
66
|
+
--ui-surface-shadow: initial;
|
|
67
|
+
--ui-bg-alpha: 1;
|
|
68
|
+
--ui-label-weight: initial;
|
|
69
|
+
--ui-label-tracking: initial;
|
|
70
|
+
--ui-label-case: initial;
|
|
71
|
+
--ui-label-shadow: initial;
|
|
72
|
+
|
|
73
|
+
font-family: var(--font-sketch, cursive);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (prefers-reduced-motion: reduce) {
|
|
77
|
+
.sketch {
|
|
78
|
+
--ui-active-transform: none;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Rounded variant: bounded elliptical corners, so the top and bottom edges of
|
|
83
|
+
a wide element stay straight instead of bulging into an egg. On the region
|
|
84
|
+
with `.sketch`, or on one component inside it. Knobs follow R8. */
|
|
85
|
+
.sketch-rounded {
|
|
86
|
+
--ui-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
|
|
87
|
+
--ui-radius-surface: var(--sketch-radius-surface-rounded, 38px 16px 36px 17px / 16px 34px 17px 32px);
|
|
88
|
+
--ui-radius-pill: var(--sketch-radius-pill, 24px 16px 23px 17px / 17px 21px 16px 20px);
|
|
89
|
+
--ui-radius-tight: 9px 3px 8px 4px / 4px 8px 3px 7px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* One region token gives every element the same outline, so the rotation and
|
|
93
|
+
the dashed accents are written on components, which the registry records.
|
|
94
|
+
The root is a component carrying either class, or one inside either region
|
|
95
|
+
and not inside another aesthetic nested there, which keeps its own
|
|
96
|
+
material. The list below is the one place other aesthetics are named, and
|
|
97
|
+
`registry.test.ts` fails when one is missing from it.
|
|
98
|
+
|
|
99
|
+
Rotation is by sibling position, and a field's control takes its field's
|
|
100
|
+
position instead of its own, so stacked rows alternate. It is stable for a
|
|
101
|
+
given DOM order. A knob, when set, is one outline for every position. */
|
|
102
|
+
:is(
|
|
103
|
+
.sketch,
|
|
104
|
+
.sketch-rounded,
|
|
105
|
+
:is(.sketch, .sketch-rounded)
|
|
106
|
+
:not(
|
|
107
|
+
:is(.sketch, .sketch-rounded) :is(.neobrutalism, .glass, .pixel, .chunky-tile, .cyber),
|
|
108
|
+
:is(.sketch, .sketch-rounded) :is(.neobrutalism, .glass, .pixel, .chunky-tile, .cyber) *
|
|
109
|
+
)
|
|
110
|
+
) {
|
|
111
|
+
/* The pointed outlines: controls, fields, surfaces, and chips. */
|
|
112
|
+
&:is(.sketch, .sketch *):not(.sketch-rounded, .sketch-rounded *) {
|
|
113
|
+
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
|
|
114
|
+
&:nth-child(4n + 2) {
|
|
115
|
+
--ui-radius: var(--sketch-radius, 18px 240px 15px 255px / 240px 15px 255px 18px);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&:nth-child(4n + 3) {
|
|
119
|
+
--ui-radius: var(--sketch-radius, 245px 220px 15px 18px / 18px 15px 245px 235px);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&:nth-child(4n) {
|
|
123
|
+
--ui-radius: var(--sketch-radius, 18px 250px 225px 15px / 245px 15px 18px 235px);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&:is(.ipt, .textarea, .select, .input-group) {
|
|
128
|
+
.field:nth-child(4n + 1) & {
|
|
129
|
+
--ui-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.field:nth-child(4n + 2) & {
|
|
133
|
+
--ui-radius: var(--sketch-radius, 18px 240px 15px 255px / 240px 15px 255px 18px);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.field:nth-child(4n + 3) & {
|
|
137
|
+
--ui-radius: var(--sketch-radius, 245px 220px 15px 18px / 18px 15px 245px 235px);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.field:nth-child(4n) & {
|
|
141
|
+
--ui-radius: var(--sketch-radius, 18px 250px 225px 15px / 245px 15px 18px 235px);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
&:is(.card, .panel, .alert, .data-table) {
|
|
146
|
+
&:nth-child(4n + 2) {
|
|
147
|
+
--ui-radius-surface: var(--sketch-radius-surface, 4px 75px 5px 80px / 75px 3px 80px 4px);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&:nth-child(4n + 3) {
|
|
151
|
+
--ui-radius-surface: var(--sketch-radius-surface, 75px 70px 4px 5px / 4px 3px 75px 70px);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&:nth-child(4n) {
|
|
155
|
+
--ui-radius-surface: var(--sketch-radius-surface, 5px 80px 75px 4px / 75px 4px 5px 70px);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
&:is(.badge, .kbd, .code, .checkbox, .switch, .progress) {
|
|
160
|
+
&:nth-child(4n + 2) {
|
|
161
|
+
--ui-radius-tight: 2px 8px 1px 10px / 8px 2px 10px 1px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
&:nth-child(4n + 3) {
|
|
165
|
+
--ui-radius-tight: 8px 2px 10px 1px / 1px 9px 2px 8px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
&:nth-child(4n) {
|
|
169
|
+
--ui-radius-tight: 1px 10px 2px 7px / 9px 1px 8px 2px;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* The rounded outlines, in the same four places. */
|
|
175
|
+
&:is(.sketch-rounded, .sketch-rounded *) {
|
|
176
|
+
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
|
|
177
|
+
&:nth-child(4n + 2) {
|
|
178
|
+
--ui-radius: var(--sketch-radius-rounded, 11px 25px 12px 24px / 23px 11px 22px 12px);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
&:nth-child(4n + 3) {
|
|
182
|
+
--ui-radius: var(--sketch-radius-rounded, 24px 12px 26px 10px / 11px 23px 12px 22px);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&:nth-child(4n) {
|
|
186
|
+
--ui-radius: var(--sketch-radius-rounded, 12px 24px 10px 25px / 22px 12px 23px 11px);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&:is(.ipt, .textarea, .select, .input-group) {
|
|
191
|
+
.field:nth-child(4n + 1) & {
|
|
192
|
+
--ui-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.field:nth-child(4n + 2) & {
|
|
196
|
+
--ui-radius: var(--sketch-radius-rounded, 11px 25px 12px 24px / 23px 11px 22px 12px);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.field:nth-child(4n + 3) & {
|
|
200
|
+
--ui-radius: var(--sketch-radius-rounded, 24px 12px 26px 10px / 11px 23px 12px 22px);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.field:nth-child(4n) & {
|
|
204
|
+
--ui-radius: var(--sketch-radius-rounded, 12px 24px 10px 25px / 22px 12px 23px 11px);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
&:is(.card, .panel, .alert, .data-table) {
|
|
209
|
+
&:nth-child(4n + 2) {
|
|
210
|
+
--ui-radius-surface: var(--sketch-radius-surface-rounded, 17px 36px 18px 34px / 33px 16px 32px 17px);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
&:nth-child(4n + 3) {
|
|
214
|
+
--ui-radius-surface: var(--sketch-radius-surface-rounded, 35px 18px 38px 15px / 17px 32px 16px 34px);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&:nth-child(4n) {
|
|
218
|
+
--ui-radius-surface: var(--sketch-radius-surface-rounded, 18px 35px 16px 37px / 31px 17px 34px 16px);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
&:is(.badge, .kbd, .code, .checkbox, .switch, .progress) {
|
|
223
|
+
&:nth-child(4n + 2) {
|
|
224
|
+
--ui-radius-tight: 4px 8px 3px 9px / 8px 3px 8px 4px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
&:nth-child(4n + 3) {
|
|
228
|
+
--ui-radius-tight: 8px 4px 9px 3px / 3px 9px 4px 8px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&:nth-child(4n) {
|
|
232
|
+
--ui-radius-tight: 3px 9px 4px 8px / 9px 4px 8px 3px;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* A pill button keeps a rounded pill in either variant, bounded to the
|
|
238
|
+
button's half-height so a wide one keeps flat top and bottom edges. */
|
|
239
|
+
&.btn.pill {
|
|
240
|
+
--ui-radius-pill: var(--sketch-radius-pill, 24px 16px 23px 17px / 17px 21px 16px 20px);
|
|
241
|
+
|
|
242
|
+
&:nth-child(4n + 2) {
|
|
243
|
+
--ui-radius-pill: var(--sketch-radius-pill, 17px 23px 16px 24px / 21px 16px 20px 17px);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
&:nth-child(4n + 3) {
|
|
247
|
+
--ui-radius-pill: var(--sketch-radius-pill, 23px 17px 24px 16px / 16px 20px 17px 21px);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
&:nth-child(4n) {
|
|
251
|
+
--ui-radius-pill: var(--sketch-radius-pill, 16px 24px 17px 23px / 20px 17px 21px 16px);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* Badges, progress bars, and switches take their chip outline where they
|
|
256
|
+
would be fully round. */
|
|
257
|
+
&:is(.badge, .progress, .switch) {
|
|
258
|
+
--ui-radius-pill: var(--ui-radius-tight);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* Radios and the tooltip trigger stay circles, slightly uneven, so a radio
|
|
262
|
+
is never mistaken for a checkbox. */
|
|
263
|
+
&:is(.radio, .tooltip-icon) {
|
|
264
|
+
--ui-radius-pill: 48% 52% 46% 54% / 53% 46% 54% 47%;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* The dashed accents; every other line stays solid. */
|
|
268
|
+
&:is(.sketch, .sketch *) {
|
|
269
|
+
&.checkbox {
|
|
270
|
+
--ui-line-style: dashed;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
&:is(.divider, .data-table) {
|
|
274
|
+
--ui-rule-style: dashed;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Solo: the look on one unstyled element. It uses standalone fallbacks rather
|
|
281
|
+
than material tokens inherited from an aesthetic around it. */
|
|
282
|
+
.sketch-solo {
|
|
283
|
+
--_sketch-ink: light-dark(var(--color-neutral-950, oklch(14.5% 0 0)), var(--color-neutral-50, oklch(98.5% 0 0)));
|
|
284
|
+
|
|
285
|
+
border: 1px solid var(--_sketch-ink);
|
|
286
|
+
/* The surface shape: the element this exists for is usually a pane. An action
|
|
287
|
+
takes the control shape below. */
|
|
288
|
+
border-radius: var(--sketch-radius-surface, 80px 4px 75px 5px / 3px 70px 4px 80px);
|
|
289
|
+
/* The aesthetic's neutral depth cue, not the ink: the class casts its 2px
|
|
290
|
+
offset in the depth colour, and casting a solo pane in full ink would read
|
|
291
|
+
as a heavier, neobrutalist slab. The depth colour is a literal, for the reason
|
|
292
|
+
`.glass-solo` gives. */
|
|
293
|
+
box-shadow: 2px 2px 0 0 light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
294
|
+
font-family: var(--font-sketch, cursive);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* An action takes the expressive control shape. */
|
|
298
|
+
.sketch-solo:is(
|
|
299
|
+
button,
|
|
300
|
+
a[href],
|
|
301
|
+
[role="button"],
|
|
302
|
+
summary,
|
|
303
|
+
input[type="button"],
|
|
304
|
+
input[type="submit"],
|
|
305
|
+
input[type="reset"]
|
|
306
|
+
) {
|
|
307
|
+
border-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* With `.sketch-rounded`, the rounded outlines, through their own knobs. */
|
|
311
|
+
.sketch-solo.sketch-rounded {
|
|
312
|
+
border-radius: var(--sketch-radius-surface-rounded, 38px 16px 36px 17px / 16px 34px 17px 32px);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.sketch-solo.sketch-rounded:is(
|
|
316
|
+
button,
|
|
317
|
+
a[href],
|
|
318
|
+
[role="button"],
|
|
319
|
+
summary,
|
|
320
|
+
input[type="button"],
|
|
321
|
+
input[type="submit"],
|
|
322
|
+
input[type="reset"]
|
|
323
|
+
) {
|
|
324
|
+
border-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* This entrypoint may be the only package stylesheet loaded, so it cannot rely
|
|
328
|
+
on theme.css's forced-colors material reset. */
|
|
329
|
+
@media (forced-colors: active) {
|
|
330
|
+
.sketch-solo {
|
|
331
|
+
border-style: solid;
|
|
332
|
+
}
|
|
333
|
+
}
|
package/dist/tw/box.css
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
@reference "tailwindcss";
|
|
2
|
-
|
|
3
1
|
/* How a box is painted, in one place: intent supplies the colour, presentation
|
|
4
2
|
how much of it, the aesthetic the material, and this composes the three. It
|
|
5
3
|
composes here, not on a container, because a custom property resolves its
|
|
@@ -16,14 +14,15 @@
|
|
|
16
14
|
|
|
17
15
|
`--_fill-cap` is the matching slot for a component that reinterprets what a
|
|
18
16
|
presentation means for itself rather than merely bounding it -- `.card.soft`
|
|
19
|
-
uses it to rest at 0% regardless of what `.soft` asks for. It
|
|
20
|
-
separate term rather than a
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
a
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
uses it to rest at 0% regardless of what `.soft` asks for. It is a
|
|
18
|
+
separate term rather than a write of `--ui-fill`, for two reasons. A
|
|
19
|
+
component writing `--ui-fill` from `utilities` would beat a consumer's own
|
|
20
|
+
`[--ui-fill:...]` utility, which the layer map reserves for state
|
|
21
|
+
(docs/internal/model.md#cascade-layers); a private competes with nothing a
|
|
22
|
+
consumer writes. And `--ui-fill` cascades by design, so a neutral panel
|
|
23
|
+
writing `0%` would turn every badge and button inside it ghost, where a
|
|
24
|
+
cap bounds the component and stops there (below). A state that means the
|
|
25
|
+
fill it names -- `:checked` -- writes `--ui-fill` itself.
|
|
27
26
|
|
|
28
27
|
Restated here at `100%` -- a no-op -- for the same reason `--_d-ground`
|
|
29
28
|
is restated `transparent` below rather than left to its `var()` fallback:
|
|
@@ -36,6 +35,21 @@
|
|
|
36
35
|
own presentation instead of the container's reinterpretation of one. */
|
|
37
36
|
--_fill-cap: 100%;
|
|
38
37
|
--_capped: min(var(--ui-fill, var(--_d-fill)), var(--_fill-cap, 100%), var(--intent-fill-max, 100%));
|
|
38
|
+
/* Whether the intent's cap stopped the fill short, as 0% or 100%. A capped
|
|
39
|
+
fill is a plate the presentation asked to be full, so it rests on the page
|
|
40
|
+
background rather than on nothing: 20% of the page's ink over nothing
|
|
41
|
+
showed whatever sat behind a neutral `.solid` -- glass's backdrop, an
|
|
42
|
+
image, the colour of a filled card around it -- where on a plain page it
|
|
43
|
+
read as the light grey plate it is meant to be. The component's own cap
|
|
44
|
+
is measured out first, so a text control's 20% wash and a neutral
|
|
45
|
+
`.card.soft`'s 0% stay the tints they are, whatever the intent. Stepped
|
|
46
|
+
rather than scaled because the two percentages cannot be divided in every
|
|
47
|
+
engine yet. */
|
|
48
|
+
--_plate: clamp(
|
|
49
|
+
0%,
|
|
50
|
+
calc((min(var(--ui-fill, var(--_d-fill)), var(--_fill-cap, 100%)) - var(--_capped)) * 1000),
|
|
51
|
+
100%
|
|
52
|
+
);
|
|
39
53
|
--_fill: calc(var(--_capped) * var(--ui-bg-alpha, 1));
|
|
40
54
|
--_hover-fill: calc(min(100%, var(--_capped) + var(--hover-step)) * var(--ui-bg-alpha, 1));
|
|
41
55
|
/* How much of the foreground is the contrast ink: what the presentation asks
|
|
@@ -58,34 +72,41 @@
|
|
|
58
72
|
declaration beats the inherited one at any specificity; `surface`, `kbd`,
|
|
59
73
|
`code`, `pre` and the tooltip each restate theirs after `@apply box`. */
|
|
60
74
|
--_d-ground: transparent;
|
|
75
|
+
/* The ground, made the page background wherever `--_plate` says the cap
|
|
76
|
+
stopped the fill -- over a component's own ground too, so a capped
|
|
77
|
+
`.solid` surface under glass is opaque like every other `.solid`. */
|
|
78
|
+
--_ground: color-mix(in oklab, var(--color-background) var(--_plate), var(--_d-ground, transparent));
|
|
61
79
|
|
|
62
|
-
--_bg: color-mix(in oklab, var(--intent-color) var(--_fill), var(--
|
|
80
|
+
--_bg: color-mix(in oklab, var(--intent-color) var(--_fill), var(--_ground));
|
|
63
81
|
/* The two ends answer different questions: `--intent-contrast` prints *on* the
|
|
64
82
|
fill, `--intent-strong` prints on the page (the slot for readable ink on a
|
|
65
83
|
subtle fill). Reading `--intent-color` at the page end instead makes every
|
|
66
84
|
colour do double duty and prints a soft amber component at 3.1:1.
|
|
67
85
|
`--intent-contrast` keeps its own meaning -- `--_on-fill` reconciles it with
|
|
68
86
|
a capped intent -- rather than being bent so neutral's contrast is the ink,
|
|
69
|
-
which
|
|
87
|
+
which renders a checked neutral checkbox black-on-black. */
|
|
70
88
|
--_fg: color-mix(in oklab, var(--intent-contrast) var(--_on-fill), var(--intent-strong));
|
|
71
|
-
/* P3: the line
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
89
|
+
/* P3: the line fades out as the fill fills in, so a filled box has a seamless
|
|
90
|
+
edge. It fades toward `transparent`, not toward the plate: the plate
|
|
91
|
+
already runs under the border (nothing clips the background to the padding
|
|
92
|
+
box), so a line blended toward `--_bg` paints the plate a second time over
|
|
93
|
+
itself -- invisible on an opaque plate, a ring on a translucent one (a
|
|
94
|
+
neutral fill capped at 20%, or any fill `--ui-bg-alpha` thins). Faded
|
|
95
|
+
toward nothing, the border shows the one coat beneath it.
|
|
96
|
+
|
|
97
|
+
Blend first, amount after (`--_edge-amount` below): the other order lands
|
|
98
|
+
`.edgeless` on the fill colour, which the border box paints as a second
|
|
99
|
+
coat -- a ring around an element that asked for no edge. See
|
|
100
|
+
docs/internal/model.md#presentation. */
|
|
101
|
+
--_line: color-mix(in oklab, transparent var(--ui-fill, var(--_d-fill)), var(--intent-border));
|
|
79
102
|
/* How much line there is, as an input rather than a result. A component that
|
|
80
103
|
must keep its line whatever the edge class says raises `--_edge-floor`
|
|
81
104
|
instead of rewriting `--_edge`, and the composition above still runs.
|
|
82
105
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
leaves the axis live, so `.edged` and `.edgeless` still mean what they say
|
|
88
|
-
on a component that happens to floor itself. */
|
|
106
|
+
Rewriting the result drops every term it was composed from, silently and
|
|
107
|
+
with nothing to report. Bounding the input leaves the axis live, so
|
|
108
|
+
`.edged` and `.edgeless` still mean what they say on a component that
|
|
109
|
+
floors itself. */
|
|
89
110
|
--_edge-amount: max(var(--ui-border, var(--_d-border)), var(--_edge-floor, 0%));
|
|
90
111
|
--_edge: color-mix(in oklab, var(--_line) var(--_edge-amount), transparent);
|
|
91
112
|
--_width: min(var(--ui-border-width, var(--border-width)), var(--ui-border-max, 100px));
|
|
@@ -95,14 +116,30 @@
|
|
|
95
116
|
draws. Zero lengths are written `0px` because `calc(0 * 1)` yields a number
|
|
96
117
|
and a shadow position needs a length. */
|
|
97
118
|
--_elevation: var(--ui-elevation, var(--_d-elevation, 1));
|
|
98
|
-
|
|
119
|
+
|
|
120
|
+
/* The size step, a unitless multiplier the size and padding modifiers publish
|
|
121
|
+
as two privates -- `.sm`/`.p-sm` 0.75, `.p-xs` 0.5, `.lg`/`.p-lg` 1.25 --
|
|
122
|
+
so that when both sit on one element the tighter wins: `.lg.p-xs` is
|
|
123
|
+
small. An unset step takes the other's value, so a lone `.lg` still grows.
|
|
124
|
+
Restated `initial` here, before any modifier, because a custom property
|
|
125
|
+
inherits and a `.card.p-xs` would otherwise shrink every button inside it;
|
|
126
|
+
the modifier rules outrank this one on specificity. `--ui-scale` is the
|
|
127
|
+
public override, undeclared by the package. See docs/internal/model.md#material-tokens. */
|
|
128
|
+
--_scale-size: initial;
|
|
129
|
+
--_scale-pad: initial;
|
|
130
|
+
--_scale: var(--ui-scale, min(var(--_scale-size, var(--_scale-pad, 1)), var(--_scale-pad, var(--_scale-size, 1))));
|
|
131
|
+
/* Depth follows the step down and not up: a 4px slab under a 20px button
|
|
132
|
+
swallows it, while a press that travels the aesthetic's whole depth has to
|
|
133
|
+
land flat on a `.lg` button too. */
|
|
134
|
+
--_depth: calc(var(--_elevation) * min(1, var(--_scale)));
|
|
135
|
+
--_sx: calc(var(--ui-shadow-x, var(--_d-shadow-x, 0px)) * var(--_depth));
|
|
99
136
|
/* Three slots, most specific first: the aesthetic, then a component that draws
|
|
100
137
|
its own depth, then the plain step `.raised`/`.floating` supply on a page
|
|
101
138
|
with no aesthetic. The order lets a raised card under `.neobrutalism` keep
|
|
102
139
|
the slab. Nothing declares the last slot until something asks for depth, so
|
|
103
140
|
a plain unmodified page has no shadow anywhere. */
|
|
104
|
-
--_sy: calc(var(--ui-shadow-y, var(--_d-shadow-y, var(--elevation-y, 0px))) * var(--
|
|
105
|
-
--_sb: calc(var(--ui-shadow-blur, var(--_d-shadow-blur, var(--elevation-blur, 0px))) * var(--
|
|
141
|
+
--_sy: calc(var(--ui-shadow-y, var(--_d-shadow-y, var(--elevation-y, 0px))) * var(--_depth));
|
|
142
|
+
--_sb: calc(var(--ui-shadow-blur, var(--_d-shadow-blur, var(--elevation-blur, 0px))) * var(--_depth));
|
|
106
143
|
/* Spread is deliberately not scaled. An aesthetic that draws its edge as an
|
|
107
144
|
inset ring spends spread on it, and scaling that by elevation would erase
|
|
108
145
|
the edge of every component the registry rests at zero. Elevation is depth:
|
|
@@ -130,29 +167,50 @@
|
|
|
130
167
|
--_edge-shadow-color: var(--ui-shadow-edge) var(--_edge);
|
|
131
168
|
--_shadow-color: var(--_edge-shadow-color, var(--_depth-color));
|
|
132
169
|
--_shadow-parts: var(--ui-shadow-inset,) var(--_sx) var(--_sy) var(--_sb) var(--_ss) var(--_shadow-color);
|
|
170
|
+
/* A shadow that is not depth: light in the element's own intent colour, with
|
|
171
|
+
no offset. Outside the depth layer, and not scaled by elevation, so `.flat`
|
|
172
|
+
leaves it alone and a field resting at zero still takes it. Present only
|
|
173
|
+
when `--ui-halo-ink` is declared: undeclared, the whole layer, leading
|
|
174
|
+
comma included, is invalid at computed-value time and `var()` drops it, so
|
|
175
|
+
no empty layer sits in every box's shadow. */
|
|
176
|
+
--_halo-layer:
|
|
177
|
+
,
|
|
178
|
+
0 0 var(--ui-halo-blur, 0px) var(--ui-halo-spread, 0px)
|
|
179
|
+
color-mix(in oklab, var(--intent-border) var(--ui-halo-ink), transparent);
|
|
133
180
|
/* Indirection so a component can substitute a complete value of its own
|
|
134
181
|
without restating the parts -- `surface` does, for the multi-layer case.
|
|
135
182
|
There is deliberately no `--ui-shadow` wrapper: a complete value has nothing
|
|
136
183
|
for the elevation multiplier to reach, so `.flat` would silently stop working
|
|
137
184
|
on anything that set one. `--ui-surface-shadow` is that escape hatch narrowed
|
|
138
185
|
to the single case that needs it. */
|
|
139
|
-
--_shadow: var(--_shadow-parts);
|
|
186
|
+
--_shadow: var(--_shadow-parts) var(--_halo-layer,);
|
|
140
187
|
--_focus-stack: var(--_shadow), inset 0 0 0 var(--ui-focus-inset) var(--focus-ring);
|
|
141
188
|
|
|
142
189
|
/* Every box sizes itself as `min-height`/`min-width: var(--control-height)`
|
|
143
|
-
plus its own padding and the border shorthand above, so its geometry is
|
|
144
|
-
right under `
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
inherited the `content-box` default and every sized control came out
|
|
149
|
-
inflated by its own padding and border. A component's own geometry is not an
|
|
150
|
-
external reset's job; `box` owns it. */
|
|
190
|
+
plus its own padding and the border shorthand above, so its geometry is
|
|
191
|
+
only right under `border-box`. `reset.css` sets that on `*`, but only the
|
|
192
|
+
`.`, `/native` and `/tw/reset` entrypoints carry the reset; `/components`
|
|
193
|
+
and the granular `/tw/*` component entrypoints ship neither it nor
|
|
194
|
+
Preflight, so `box` owns it. */
|
|
151
195
|
box-sizing: border-box;
|
|
152
196
|
background-color: var(--_bg);
|
|
153
197
|
color: var(--_fg);
|
|
154
|
-
|
|
155
|
-
|
|
198
|
+
/* The line's style is material: `solid`, `dashed`, `dotted`, or `double`,
|
|
199
|
+
which needs a width of 3px or more to draw two lines. It keeps the line's
|
|
200
|
+
colour, so its contrast, whatever it draws. */
|
|
201
|
+
border: var(--_width) var(--ui-line-style, solid) var(--_edge);
|
|
202
|
+
/* The corner is the aesthetic's length at scale 1 times the size step, so a
|
|
203
|
+
small button takes a small corner and a cut stays a true 45 degrees. Each
|
|
204
|
+
corner then multiplies by its own `--ui-corner-tl`/`-tr`/`-br`/`-bl`, 0 or
|
|
205
|
+
1, which is how `.cut-diagonal` and a bevelling aesthetic's diagonal draw
|
|
206
|
+
two corners and leave two square. An explicit `--ui-radius` still wins,
|
|
207
|
+
taken as written. */
|
|
208
|
+
--_corner: calc(var(--ui-corner, var(--radius-control)) * var(--_scale));
|
|
209
|
+
border-radius: var(
|
|
210
|
+
--ui-radius,
|
|
211
|
+
calc(var(--_corner) * var(--ui-corner-tl, 1)) calc(var(--_corner) * var(--ui-corner-tr, 1))
|
|
212
|
+
calc(var(--_corner) * var(--ui-corner-br, 1)) calc(var(--_corner) * var(--ui-corner-bl, 1))
|
|
213
|
+
);
|
|
156
214
|
/* What the radius draws: a round arc by default, a straight cut under an
|
|
157
215
|
aesthetic that bevels (`.cyber`). `round` is the property's initial value,
|
|
158
216
|
so with no aesthetic in scope this is a no-op, and an engine without
|
|
@@ -162,13 +220,28 @@
|
|
|
162
220
|
corner-shape: var(--ui-corner-shape, round);
|
|
163
221
|
box-shadow: var(--_shadow);
|
|
164
222
|
clip-path: var(--ui-clip, none);
|
|
223
|
+
/* The press travel `box-active` writes; `none` at rest, because any other
|
|
224
|
+
`translate` makes the box a stacking context and a containing block.
|
|
225
|
+
Restated here so a pressed card does not carry the boxes inside it. */
|
|
226
|
+
--_press: none;
|
|
227
|
+
translate: var(--_press);
|
|
165
228
|
transition:
|
|
166
229
|
background-color var(--motion-duration-normal) var(--motion-ease),
|
|
167
230
|
border-color var(--motion-duration-normal) var(--motion-ease),
|
|
168
231
|
box-shadow var(--motion-duration-normal) var(--motion-ease),
|
|
169
232
|
color var(--motion-duration-normal) var(--motion-ease),
|
|
170
233
|
opacity var(--motion-duration-normal) var(--motion-ease),
|
|
171
|
-
transform var(--motion-duration-normal) var(--motion-ease)
|
|
234
|
+
transform var(--motion-duration-normal) var(--motion-ease),
|
|
235
|
+
translate var(--motion-duration-normal) var(--motion-ease);
|
|
236
|
+
|
|
237
|
+
/* Reduced motion stops here as well as in `reset.css`: `/components` and the
|
|
238
|
+
focused `/tw/*` entries carry no reset, so each component that moves says
|
|
239
|
+
so itself -- this for everything `box` paints, and the components with a
|
|
240
|
+
transition or animation of their own beside it. The same near-zero
|
|
241
|
+
duration the reset uses, so a `transitionend` still fires. */
|
|
242
|
+
@media (prefers-reduced-motion: reduce) {
|
|
243
|
+
transition-duration: 0.01ms;
|
|
244
|
+
}
|
|
172
245
|
|
|
173
246
|
/* An aesthetic that clips cannot show the global focus outline, so it declares
|
|
174
247
|
`--ui-focus-inset` and gets an inset layer instead. With no such aesthetic
|
|
@@ -203,15 +276,14 @@
|
|
|
203
276
|
and wrong for something you type into, so a component opts in. */
|
|
204
277
|
@utility box-hover {
|
|
205
278
|
&:not(:disabled, .disabled, [aria-disabled="true"], [data-disabled]):hover {
|
|
206
|
-
--_bg: color-mix(in oklab, var(--intent-hover) var(--_hover-fill), var(--
|
|
207
|
-
/* P3 again, against the hover tone
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
--
|
|
212
|
-
--_sx: calc(var(--ui-hover-shadow-x, var(--ui-shadow-x, var(--_d-shadow-x, 0px))) * var(--_elevation));
|
|
279
|
+
--_bg: color-mix(in oklab, var(--intent-hover) var(--_hover-fill), var(--_ground));
|
|
280
|
+
/* P3 again, against the hover tone: the line still fades as the fill fills
|
|
281
|
+
in, but toward the hover ink. Without this the edge keeps the resting ink
|
|
282
|
+
-- a ring of the colour the box just left. */
|
|
283
|
+
--_line: color-mix(in oklab, transparent var(--ui-fill, var(--_d-fill)), var(--intent-hover));
|
|
284
|
+
--_sx: calc(var(--ui-hover-shadow-x, var(--ui-shadow-x, var(--_d-shadow-x, 0px))) * var(--_depth));
|
|
213
285
|
--_sy: calc(
|
|
214
|
-
var(--ui-hover-shadow-y, var(--ui-shadow-y, var(--_d-shadow-y, var(--elevation-y, 0px)))) * var(--
|
|
286
|
+
var(--ui-hover-shadow-y, var(--ui-shadow-y, var(--_d-shadow-y, var(--elevation-y, 0px)))) * var(--_depth)
|
|
215
287
|
);
|
|
216
288
|
|
|
217
289
|
transform: var(--ui-hover-transform, none);
|
|
@@ -224,11 +296,26 @@
|
|
|
224
296
|
aesthetic's -- neobrutalism travels into its offset shadow, chunky-tile drops
|
|
225
297
|
onto its bar -- and with no aesthetic it is the base `scale(0.97)` from
|
|
226
298
|
`theme.css`, dropped under reduced motion. The `--ui-active-shadow-*` slots
|
|
227
|
-
stay no-ops until an aesthetic sets them.
|
|
299
|
+
stay no-ops until an aesthetic sets them.
|
|
300
|
+
|
|
301
|
+
A press that travels into the element's own depth is a translation, given as
|
|
302
|
+
`--ui-active-translate-x`/`-y` and scaled by `--_depth` like the shadow it
|
|
303
|
+
travels into, so a `.p-xs` button that sits on half the slab moves half as
|
|
304
|
+
far, a `.floating` one twice as far, and a `.flat` one, with no slab to land
|
|
305
|
+
on, not at all. It is the independent `translate` property, so it composes
|
|
306
|
+
with `--ui-active-transform` rather than replacing it.
|
|
307
|
+
|
|
308
|
+
The press writes only `--_press`, and `box` declares `translate` from it.
|
|
309
|
+
A `translate` declaration here sorts this rule ahead of `box-hover`'s -- the
|
|
310
|
+
property ranks before `transform` in Tailwind's order -- and the hovered
|
|
311
|
+
`transform: none` then beats every press. */
|
|
228
312
|
@utility box-active {
|
|
229
313
|
&:active:not(:disabled, .disabled, [aria-disabled="true"], [data-disabled]) {
|
|
230
|
-
--_sx: calc(var(--ui-active-shadow-x, var(--ui-shadow-x, var(--_d-shadow-x, 0px))) * var(--
|
|
231
|
-
--_sy: calc(var(--ui-active-shadow-y, var(--ui-shadow-y, var(--_d-shadow-y, 0px))) * var(--
|
|
314
|
+
--_sx: calc(var(--ui-active-shadow-x, var(--ui-shadow-x, var(--_d-shadow-x, 0px))) * var(--_depth));
|
|
315
|
+
--_sy: calc(var(--ui-active-shadow-y, var(--ui-shadow-y, var(--_d-shadow-y, 0px))) * var(--_depth));
|
|
316
|
+
|
|
317
|
+
--_press: calc(var(--ui-active-translate-x, 0px) * var(--_depth))
|
|
318
|
+
calc(var(--ui-active-translate-y, 0px) * var(--_depth));
|
|
232
319
|
|
|
233
320
|
transform: var(--ui-active-transform, none);
|
|
234
321
|
}
|