@codenhub/styles 0.5.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 -1
- 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 +39 -39
- package/dist/tw/aesthetics/cyber.css +16 -11
- package/dist/tw/aesthetics/glass.css +235 -10
- package/dist/tw/aesthetics/index.css +2 -1
- package/dist/tw/aesthetics/neobrutalism.css +23 -11
- package/dist/tw/aesthetics/pixel.css +18 -8
- package/dist/tw/aesthetics/sketch.css +14 -7
- package/dist/tw/box.css +49 -27
- package/dist/tw/components/button.css +35 -14
- package/dist/tw/components/feedback.css +59 -56
- package/dist/tw/components/form.css +200 -126
- package/dist/tw/components/index.css +3 -7
- package/dist/tw/components/loader.css +4 -5
- package/dist/tw/components/surface.css +71 -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 +31 -24
- package/dist/tw/native.css +15 -5
- package/dist/tw/palette.css +8 -5
- package/dist/tw/presentation.css +16 -30
- package/dist/tw/reset.css +21 -28
- package/dist/tw/surface.css +11 -12
- package/dist/tw/theme.css +58 -86
- package/dist/tw/utilities/content.css +268 -199
- package/dist/tw/utilities/layout.css +15 -25
- package/docs/accessibility.md +50 -33
- package/docs/changelog/0.6.0.md +52 -0
- package/docs/changelog/index.md +1 -0
- package/docs/concepts.md +6 -6
- package/docs/index.md +9 -0
- package/docs/integrating/nextjs.md +1 -1
- package/docs/integrating/tailwind.md +14 -6
- package/docs/setup.md +6 -6
- package/docs/usage/aesthetics.md +35 -8
- package/docs/usage/buttons.md +1 -1
- package/docs/usage/composing.md +1 -1
- package/docs/usage/content-and-layout.md +12 -11
- package/docs/usage/customizing.md +8 -9
- package/docs/usage/feedback.md +5 -3
- package/docs/usage/forms.md +51 -35
- package/docs/usage/theming.md +39 -40
- package/docs/usage/tooltips.md +37 -17
- package/llms-full.txt +331 -183
- package/llms.txt +6 -0
- package/package.json +5 -5
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/* Glass: translucent surfaces over a blurred backdrop with a hairline highlight
|
|
2
|
-
edge. It needs something behind it to blur -- on a flat page background it is
|
|
3
|
-
translucent panel and nothing more.
|
|
2
|
+
edge. It needs something behind it to blur -- on a flat page background it is
|
|
3
|
+
a translucent panel and nothing more.
|
|
4
4
|
|
|
5
|
-
Tier 1 only
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
as noise. */
|
|
5
|
+
Tier 1 only: the scope is a token. Only `surface` resolves `--ui-backdrop`,
|
|
6
|
+
so blur reaches cards, panels, alerts and tooltips while controls stay solid.
|
|
7
|
+
An active blur costs a compositing layer apiece, and one under every control
|
|
8
|
+
of a dense cluster reads as noise. */
|
|
10
9
|
|
|
11
10
|
/* The layer map, stated before anything uses a layer -- see `theme.css`. The
|
|
12
11
|
aesthetic's token class sits in `components`, below every utility, so a
|
|
@@ -40,8 +39,19 @@
|
|
|
40
39
|
on a field's 60% resting line, in light. See
|
|
41
40
|
docs/internal/model.md#presentation. */
|
|
42
41
|
--ui-control-ink: light-dark(rgb(0 0 0 / 0.55), rgb(255 255 255 / 0.55));
|
|
42
|
+
/* Nor is a line drawn on a plate: the hairline vanishes on a table's light
|
|
43
|
+
plate, and its default, `.ruled`, and `.ruleless` forms would render as
|
|
44
|
+
one. A table's frame and rules take the theme's ink at a fifth,
|
|
45
|
+
translucent for the same reason the control line is. */
|
|
46
|
+
--ui-rule-ink: light-dark(rgb(0 0 0 / 0.2), rgb(255 255 255 / 0.2));
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
/* The glass is the ground, not the fill. Thinning fills with
|
|
49
|
+
`--ui-bg-alpha` would make how much colour a presentation asked for
|
|
50
|
+
depend on the aesthetic, which is presentation's question (R1): a
|
|
51
|
+
`.solid` button, a checked toggle, and a `.solid` card stay opaque.
|
|
52
|
+
Translucency lives in `--ui-surface-ground` below, the plate a partial
|
|
53
|
+
fill is painted over. */
|
|
54
|
+
--ui-bg-alpha: 1;
|
|
45
55
|
--ui-backdrop: blur(14px) saturate(1.6);
|
|
46
56
|
--ui-surface-image: initial;
|
|
47
57
|
|
|
@@ -54,6 +64,15 @@
|
|
|
54
64
|
--ui-shadow-y: 0px;
|
|
55
65
|
--ui-shadow-blur: 0px;
|
|
56
66
|
--ui-shadow-spread: 0px;
|
|
67
|
+
--ui-shadow-inset: initial;
|
|
68
|
+
--ui-shadow-ink: initial;
|
|
69
|
+
--ui-active-shadow-x: initial;
|
|
70
|
+
--ui-active-shadow-y: initial;
|
|
71
|
+
/* The theme's depth colour, restated: the surface shadow below resolves it
|
|
72
|
+
here, on the region, so inside chunky tile it inherited opaque black and
|
|
73
|
+
cast a black slab under every card, and inside cyber it inherited
|
|
74
|
+
transparent and cast none. */
|
|
75
|
+
--elevation-color: light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
57
76
|
/* No halo, cleared so a region nested inside another
|
|
58
77
|
aesthetic does not inherit one. */
|
|
59
78
|
--ui-halo-blur: initial;
|
|
@@ -88,8 +107,14 @@
|
|
|
88
107
|
/* Nothing here draws its edge as a ring, and an aesthetic nested inside pixel
|
|
89
108
|
has to say so rather than inherit it. */
|
|
90
109
|
--ui-shadow-edge: initial;
|
|
110
|
+
/* Nothing clips, so the global focus outline shows; pixel's inset focus
|
|
111
|
+
layer is cleared rather than inherited. */
|
|
112
|
+
--ui-focus-inset: initial;
|
|
91
113
|
--ui-hover-transform: none;
|
|
92
|
-
|
|
114
|
+
/* The base press, stated because every token here is: the depth in this
|
|
115
|
+
aesthetic is the blur, so a control has no slab to press into, and a pane
|
|
116
|
+
that gives slightly under the pointer is the one answer a press gets. */
|
|
117
|
+
--ui-active-transform: scale(0.97);
|
|
93
118
|
--ui-active-translate-x: initial;
|
|
94
119
|
--ui-active-translate-y: initial;
|
|
95
120
|
|
|
@@ -105,11 +130,155 @@
|
|
|
105
130
|
surface rather than a softer blur. */
|
|
106
131
|
@media (prefers-reduced-transparency: reduce) {
|
|
107
132
|
.glass {
|
|
108
|
-
--ui-bg-alpha: 1;
|
|
109
133
|
--ui-backdrop: none;
|
|
110
134
|
--ui-surface-ground: var(--color-background);
|
|
111
135
|
}
|
|
112
136
|
}
|
|
137
|
+
|
|
138
|
+
@media (prefers-reduced-motion: reduce) {
|
|
139
|
+
.glass {
|
|
140
|
+
--ui-active-transform: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Liquid glass: a modifier of glass, the way `.sketch-rounded` is of sketch.
|
|
145
|
+
Continuous corners, a bright rim where light catches the pane, a lighter
|
|
146
|
+
blur, and -- in engines that render an SVG filter in `backdrop-filter`,
|
|
147
|
+
Chromium today -- a lens that bends the backdrop at the edges. On the region
|
|
148
|
+
beside `.glass`, or on one surface inside a glass region.
|
|
149
|
+
|
|
150
|
+
Only the corners apply on their own. The ink, ground, and blur are glass
|
|
151
|
+
material, so they are set below only where `.glass` is in scope: a lone
|
|
152
|
+
`.glass-liquid` would otherwise make every surface translucent with nothing
|
|
153
|
+
to blur and every field's line a near-invisible hairline.
|
|
154
|
+
|
|
155
|
+
The corner knobs are glass's own, with larger defaults: a continuous corner
|
|
156
|
+
reads smaller than a round one of the same radius. Where `corner-shape` is
|
|
157
|
+
not drawn the corners stay round. */
|
|
158
|
+
.glass-liquid {
|
|
159
|
+
--ui-corner: var(--glass-radius, 1rem);
|
|
160
|
+
--ui-corner-surface: var(--glass-radius-surface, 1.5rem);
|
|
161
|
+
--ui-corner-shape: squircle;
|
|
162
|
+
|
|
163
|
+
--_glass-liquid-blur: blur(2px) saturate(1.8);
|
|
164
|
+
|
|
165
|
+
/* The lens is its own layer rather than a second function in the blur's
|
|
166
|
+
list: Firefox and WebKit accept `url()` there and draw nothing for it, and
|
|
167
|
+
a filter list with an unusable reference is dropped whole -- the blur with
|
|
168
|
+
it. Kept apart, an engine that ignores the lens still blurs.
|
|
169
|
+
|
|
170
|
+
The displacement map is built inside the filter from the box itself:
|
|
171
|
+
erode a flood of the filter region by 8px, blur it into a ramp, and take
|
|
172
|
+
the ramp's slope across x and y as the two displacement channels. Every
|
|
173
|
+
length is absolute, so the band is the same width on a tooltip and on a
|
|
174
|
+
page-wide card; no length is a percentage of the box. The blur is wider
|
|
175
|
+
than the erosion so the ramp's corners round off -- otherwise the square
|
|
176
|
+
core shows through as loops at every corner. A filter cannot read a custom
|
|
177
|
+
property, so the band and the strength are fixed, not knobs. */
|
|
178
|
+
--_glass-liquid-lens: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='lens' x='0' y='0' width='100%' height='100%' color-interpolation-filters='sRGB'><feFlood flood-color='white'/><feMorphology operator='erode' radius='8'/><feGaussianBlur stdDeviation='10' result='ramp'/><feOffset in='ramp' dx='-3' result='l'/><feOffset in='ramp' dx='3' result='r'/><feComposite in='l' in2='r' operator='arithmetic' k2='2' k3='-2' k4='0.5' result='dx'/><feOffset in='ramp' dy='-3' result='u'/><feOffset in='ramp' dy='3' result='d'/><feComposite in='u' in2='d' operator='arithmetic' k2='2' k3='-2' k4='0.5' result='dy'/><feColorMatrix in='dx' values='0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1' result='x'/><feColorMatrix in='dy' values='0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1'/><feComposite in='x' operator='arithmetic' k2='1' k3='1'/><feDisplacementMap in='SourceGraphic' scale='110' xChannelSelector='R' yChannelSelector='G'/></filter></svg>#lens");
|
|
179
|
+
|
|
180
|
+
/* The rim: light caught on the top-left edge and, fainter, the bottom-right,
|
|
181
|
+
over a soft inner glow. Drawn on the lens layer, the topmost, because a
|
|
182
|
+
rim drawn on the surface itself would sit under the layers and blur. */
|
|
183
|
+
--_glass-liquid-rim:
|
|
184
|
+
inset 1px 1px 0 light-dark(rgb(255 255 255 / 0.75), rgb(255 255 255 / 0.35)),
|
|
185
|
+
inset -1px -1px 0 light-dark(rgb(255 255 255 / 0.35), rgb(255 255 255 / 0.12)),
|
|
186
|
+
inset 0 0 18px light-dark(rgb(255 255 255 / 0.22), rgb(255 255 255 / 0.05));
|
|
187
|
+
--_glass-liquid-sheen: linear-gradient(
|
|
188
|
+
160deg,
|
|
189
|
+
light-dark(rgb(255 255 255 / 0.22), rgb(255 255 255 / 0.06)),
|
|
190
|
+
transparent 45%
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* The glass material the modifier changes, where glass is in scope: on the
|
|
195
|
+
same element, or on a surface inside a glass region. The blur moves off the
|
|
196
|
+
surface onto a layer behind its content (below): a surface with a backdrop
|
|
197
|
+
filter of its own is a backdrop root, and a layer inside one sees only the
|
|
198
|
+
surface, never the page behind it. */
|
|
199
|
+
.glass.glass-liquid,
|
|
200
|
+
.glass .glass-liquid {
|
|
201
|
+
--ui-ink: light-dark(rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.16));
|
|
202
|
+
--ui-surface-ground: color-mix(in srgb, var(--color-background) 30%, transparent);
|
|
203
|
+
--ui-surface-image: initial;
|
|
204
|
+
--ui-backdrop: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
208
|
+
.glass.glass-liquid,
|
|
209
|
+
.glass .glass-liquid {
|
|
210
|
+
--ui-surface-ground: var(--color-background);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.glass-liquid {
|
|
214
|
+
--_glass-liquid-blur: none;
|
|
215
|
+
--_glass-liquid-lens: none;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* The layers: a treatment no token reaches, so a selector list glass owns and
|
|
220
|
+
the registry records. Two pseudo-elements behind a surface's content, the
|
|
221
|
+
blur beneath and the lens with the rim and sheen above it. `isolation`
|
|
222
|
+
keeps them above the surface's own plate, which they then blur with the
|
|
223
|
+
page; `position` anchors them, and a component that positions itself --
|
|
224
|
+
the tooltip bubble -- keeps its own. A default or `.soft` table frosts
|
|
225
|
+
under glass, so it takes the layers too. Both slots are spent, so a surface
|
|
226
|
+
inside a liquid region carries no `::before` or `::after` of the
|
|
227
|
+
consumer's; the fields cannot host one, and controls stay solid as they do
|
|
228
|
+
under glass.
|
|
229
|
+
|
|
230
|
+
A region of another aesthetic nested inside, or of plain glass, keeps its
|
|
231
|
+
own material and takes no layers. This list names the other aesthetics, and
|
|
232
|
+
`registry.test.ts` fails when one is missing. */
|
|
233
|
+
:is(.glass-liquid, .glass-liquid *):is(.glass, .glass *):is(
|
|
234
|
+
.card,
|
|
235
|
+
.panel,
|
|
236
|
+
.alert,
|
|
237
|
+
.tooltip-bubble,
|
|
238
|
+
.surface,
|
|
239
|
+
.data-table:not(.solid, .ghost)
|
|
240
|
+
):not(
|
|
241
|
+
.glass-liquid :is(.neobrutalism, .pixel, .chunky-tile, .cyber, .sketch),
|
|
242
|
+
.glass-liquid :is(.neobrutalism, .pixel, .chunky-tile, .cyber, .sketch) *,
|
|
243
|
+
.glass-liquid .glass:not(.glass-liquid),
|
|
244
|
+
.glass-liquid .glass:not(.glass-liquid) *
|
|
245
|
+
) {
|
|
246
|
+
position: relative;
|
|
247
|
+
isolation: isolate;
|
|
248
|
+
|
|
249
|
+
&::before,
|
|
250
|
+
&::after {
|
|
251
|
+
position: absolute;
|
|
252
|
+
inset: 0;
|
|
253
|
+
z-index: -1;
|
|
254
|
+
border-radius: inherit;
|
|
255
|
+
corner-shape: inherit;
|
|
256
|
+
content: "";
|
|
257
|
+
pointer-events: none;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* Prefixed first, for the reason `surface` gives. */
|
|
261
|
+
&::before {
|
|
262
|
+
-webkit-backdrop-filter: var(--_glass-liquid-blur);
|
|
263
|
+
backdrop-filter: var(--_glass-liquid-blur);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
&::after {
|
|
267
|
+
backdrop-filter: var(--_glass-liquid-lens);
|
|
268
|
+
background-image: var(--_glass-liquid-sheen);
|
|
269
|
+
box-shadow: var(--_glass-liquid-rim);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Forced colours paint the plain surface: no layer blurs, bends, or lights it. */
|
|
275
|
+
@media (forced-colors: active) {
|
|
276
|
+
.glass-liquid {
|
|
277
|
+
--_glass-liquid-blur: none;
|
|
278
|
+
--_glass-liquid-lens: none;
|
|
279
|
+
--_glass-liquid-rim: none;
|
|
280
|
+
--_glass-liquid-sheen: none;
|
|
281
|
+
}
|
|
113
282
|
}
|
|
114
283
|
|
|
115
284
|
/* Solo: the same look painted onto the one element carrying the class, for an
|
|
@@ -151,3 +320,59 @@
|
|
|
151
320
|
backdrop-filter: none;
|
|
152
321
|
}
|
|
153
322
|
}
|
|
323
|
+
|
|
324
|
+
/* With `.glass-liquid`, the liquid pane: its corner and ground, and the same two
|
|
325
|
+
layers behind the element's content. The element's own blur goes, for the
|
|
326
|
+
backdrop-root reason the modifier gives. Both pseudo-elements are spent, so a
|
|
327
|
+
foreign element that draws its own `::before` or `::after` loses them.
|
|
328
|
+
|
|
329
|
+
The layers need a positioned element to anchor to. That one declaration is
|
|
330
|
+
layered, where the element's own `fixed` or `absolute` beats it -- a toast
|
|
331
|
+
keeps its placement, and an unpositioned element is anchored. */
|
|
332
|
+
@layer components {
|
|
333
|
+
.glass-solo.glass-liquid {
|
|
334
|
+
position: relative;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.glass-solo.glass-liquid {
|
|
339
|
+
isolation: isolate;
|
|
340
|
+
background-color: color-mix(
|
|
341
|
+
in srgb,
|
|
342
|
+
var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0))) 30%,
|
|
343
|
+
transparent
|
|
344
|
+
);
|
|
345
|
+
border-color: light-dark(rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.16));
|
|
346
|
+
border-radius: var(--glass-radius-surface, 1.5rem);
|
|
347
|
+
corner-shape: squircle;
|
|
348
|
+
-webkit-backdrop-filter: none;
|
|
349
|
+
backdrop-filter: none;
|
|
350
|
+
|
|
351
|
+
&::before,
|
|
352
|
+
&::after {
|
|
353
|
+
position: absolute;
|
|
354
|
+
inset: 0;
|
|
355
|
+
z-index: -1;
|
|
356
|
+
border-radius: inherit;
|
|
357
|
+
corner-shape: inherit;
|
|
358
|
+
content: "";
|
|
359
|
+
pointer-events: none;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
&::before {
|
|
363
|
+
-webkit-backdrop-filter: var(--_glass-liquid-blur);
|
|
364
|
+
backdrop-filter: var(--_glass-liquid-blur);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
&::after {
|
|
368
|
+
backdrop-filter: var(--_glass-liquid-lens);
|
|
369
|
+
background-image: var(--_glass-liquid-sheen);
|
|
370
|
+
box-shadow: var(--_glass-liquid-rim);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
375
|
+
.glass-solo.glass-liquid {
|
|
376
|
+
background-color: var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
for only the one in use: a cascading class has no static call site, so nothing
|
|
3
3
|
here can be tree-shaken.
|
|
4
4
|
|
|
5
|
-
Import after the base stylesheet in either form
|
|
5
|
+
Import before or after the base stylesheet, in either form: every entrypoint
|
|
6
|
+
states the layer order first, so load order decides nothing. */
|
|
6
7
|
@import "./neobrutalism.css";
|
|
7
8
|
@import "./glass.css";
|
|
8
9
|
@import "./pixel.css";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* Neobrutalism: thick ink outline, a hard unblurred offset shadow, and a press
|
|
2
2
|
that moves the element into its own shadow. Material tokens only, no component
|
|
3
3
|
named -- the ink reaches everything through the intent reset, the shadow is
|
|
4
|
-
colourless geometry each component colours against its own intent.
|
|
5
|
-
the base stylesheet; source order decides against the zero-specificity reset. */
|
|
4
|
+
colourless geometry each component colours against its own intent. */
|
|
6
5
|
|
|
7
6
|
/* The layer map, stated before anything uses a layer -- see `theme.css`. The
|
|
8
7
|
aesthetic's token class sits in `components`, below every utility, so a
|
|
@@ -37,6 +36,10 @@
|
|
|
37
36
|
is the whole look, so this aesthetic asks for the intent instead of the
|
|
38
37
|
neutral depth colour every other shadow uses. */
|
|
39
38
|
--ui-shadow-ink: 100%;
|
|
39
|
+
/* The ink replaces the depth colour whole, so this one is inert here; it is
|
|
40
|
+
restated so a region nested inside chunky tile or cyber does not inherit
|
|
41
|
+
their black or transparent depth. */
|
|
42
|
+
--elevation-color: light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
40
43
|
--ui-shadow-x: var(--_neo-offset);
|
|
41
44
|
--ui-shadow-y: var(--_neo-offset);
|
|
42
45
|
--ui-shadow-blur: 0px;
|
|
@@ -47,19 +50,24 @@
|
|
|
47
50
|
--ui-halo-spread: initial;
|
|
48
51
|
--ui-halo-ink: initial;
|
|
49
52
|
|
|
50
|
-
/* The press: travel the offset, shrink the shadow to nothing, so the
|
|
51
|
-
lands flat where its slab was. A translation `box` scales with
|
|
52
|
-
the two stay the same length at every size and elevation.
|
|
53
|
-
`box-hover`'s derived fill
|
|
54
|
-
no `:hover` list, R3
|
|
53
|
+
/* The press: travel the offset, shrink the shadow to nothing, so the
|
|
54
|
+
element lands flat where its slab was. A translation `box` scales with
|
|
55
|
+
the slab, so the two stay the same length at every size and elevation.
|
|
56
|
+
Hover keeps the slab still under the pointer; `box-hover`'s derived fill
|
|
57
|
+
tint is the whole hover response. One token pair, no `:hover` list, R3
|
|
58
|
+
intact. */
|
|
55
59
|
--ui-active-shadow-x: 0px;
|
|
56
60
|
--ui-active-shadow-y: 0px;
|
|
57
61
|
--ui-active-transform: none;
|
|
58
62
|
--ui-active-translate-x: var(--_neo-offset);
|
|
59
63
|
--ui-active-translate-y: var(--_neo-offset);
|
|
64
|
+
--ui-hover-transform: none;
|
|
60
65
|
|
|
61
66
|
/* Nothing here clips or blurs, and an aesthetic nested inside another has to
|
|
62
|
-
say so rather than inherit it.
|
|
67
|
+
say so rather than inherit it. Nothing clips, so the global focus outline
|
|
68
|
+
shows and no inset focus layer is wanted: cleared so a region nested
|
|
69
|
+
inside pixel does not inherit pixel's. */
|
|
70
|
+
--ui-focus-inset: initial;
|
|
63
71
|
--ui-clip: none;
|
|
64
72
|
--ui-clip-tight: none;
|
|
65
73
|
/* Round corners, said explicitly, and the pill and chip corners cleared back
|
|
@@ -86,9 +94,13 @@
|
|
|
86
94
|
--ui-bg-alpha: 1;
|
|
87
95
|
--ui-surface-image: initial;
|
|
88
96
|
|
|
89
|
-
/*
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
/* A control's neutral line is the theme's control border, not this
|
|
98
|
+
aesthetic's ink: that ink is the primary colour in both themes, so every
|
|
99
|
+
unchecked toggle and resting field drew its boundary as loudly as a
|
|
100
|
+
primary one. Named rather than cleared, so a region nested inside glass
|
|
101
|
+
or chunky tile does not inherit theirs either. */
|
|
102
|
+
--ui-control-ink: var(--color-control-border);
|
|
103
|
+
--ui-rule-ink: initial;
|
|
92
104
|
|
|
93
105
|
/* Chunky tile's heavier label, cleared so a region nested inside it keeps
|
|
94
106
|
the button's and the badge's own label. */
|
|
@@ -64,11 +64,10 @@
|
|
|
64
64
|
has to be wider than the edge to show at all. */
|
|
65
65
|
--ui-focus-inset: calc(var(--_pixel-unit) + var(--focus-ring-width));
|
|
66
66
|
|
|
67
|
-
/* One square unit off each corner, and nothing else.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
shape the look is actually made of.
|
|
67
|
+
/* One square unit off each corner, and nothing else. A staircase
|
|
68
|
+
approximates a curve, which is the one thing a low-resolution grid cannot
|
|
69
|
+
do: it reads as a bevel that has not quite committed. A single cut of the
|
|
70
|
+
grid's own unit is the shape the look is made of.
|
|
72
71
|
|
|
73
72
|
The polygon resolves the unit here, on `.pixel`, and inherits down
|
|
74
73
|
already-resolved -- so a component cannot rescale the corner by setting
|
|
@@ -108,6 +107,13 @@
|
|
|
108
107
|
--ui-corner-br: initial;
|
|
109
108
|
--ui-corner-bl: initial;
|
|
110
109
|
|
|
110
|
+
/* The ring is the edge and nothing here is depth, so the shadow ink, the
|
|
111
|
+
press's shadow, and the depth colour are cleared or restated rather than
|
|
112
|
+
inherited from an aesthetic around this one. */
|
|
113
|
+
--ui-shadow-ink: initial;
|
|
114
|
+
--ui-active-shadow-x: initial;
|
|
115
|
+
--ui-active-shadow-y: initial;
|
|
116
|
+
--elevation-color: light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
111
117
|
--ui-hover-transform: none;
|
|
112
118
|
--ui-active-transform: none;
|
|
113
119
|
--ui-active-translate-x: initial;
|
|
@@ -122,9 +128,13 @@
|
|
|
122
128
|
font to fall back to but a monospace stack. */
|
|
123
129
|
font-family: var(--font-pixel, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
|
124
130
|
|
|
125
|
-
/*
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
/* A control's neutral line is the theme's control border, not this
|
|
132
|
+
aesthetic's ink: that ink is the primary colour in both themes, so every
|
|
133
|
+
unchecked toggle and resting field drew its boundary as loudly as a
|
|
134
|
+
primary one. Named rather than cleared, so a region nested inside glass
|
|
135
|
+
or chunky tile does not inherit theirs either. */
|
|
136
|
+
--ui-control-ink: var(--color-control-border);
|
|
137
|
+
--ui-rule-ink: initial;
|
|
128
138
|
|
|
129
139
|
/* Chunky tile's heavier label, cleared so a region nested inside it keeps
|
|
130
140
|
the button's and the badge's own label. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Sketch: uneven elliptical corners, a solid ink edge, and a small hard shadow.
|
|
2
2
|
The handwriting face is consumer-supplied, so this file has no font asset or
|
|
3
|
-
network side effect.
|
|
3
|
+
network side effect. */
|
|
4
4
|
|
|
5
5
|
/* The layer map, stated before anything uses a layer -- see `theme.css`. The
|
|
6
6
|
aesthetic's token class sits in `components`, below every utility, so a
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
--ui-corner-shape: round;
|
|
29
29
|
|
|
30
30
|
--ui-ink: light-dark(var(--color-neutral-950), var(--color-neutral-50));
|
|
31
|
-
|
|
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;
|
|
32
35
|
--ui-border-width: 1px;
|
|
33
36
|
--ui-border-max: 100px;
|
|
34
37
|
--ui-line-style: solid;
|
|
@@ -107,7 +110,7 @@
|
|
|
107
110
|
) {
|
|
108
111
|
/* The pointed outlines: controls, fields, surfaces, and chips. */
|
|
109
112
|
&:is(.sketch, .sketch *):not(.sketch-rounded, .sketch-rounded *) {
|
|
110
|
-
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble
|
|
113
|
+
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
|
|
111
114
|
&:nth-child(4n + 2) {
|
|
112
115
|
--ui-radius: var(--sketch-radius, 18px 240px 15px 255px / 240px 15px 255px 18px);
|
|
113
116
|
}
|
|
@@ -139,7 +142,7 @@
|
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
144
|
|
|
142
|
-
&:is(.card, .panel, .alert) {
|
|
145
|
+
&:is(.card, .panel, .alert, .data-table) {
|
|
143
146
|
&:nth-child(4n + 2) {
|
|
144
147
|
--ui-radius-surface: var(--sketch-radius-surface, 4px 75px 5px 80px / 75px 3px 80px 4px);
|
|
145
148
|
}
|
|
@@ -170,7 +173,7 @@
|
|
|
170
173
|
|
|
171
174
|
/* The rounded outlines, in the same four places. */
|
|
172
175
|
&:is(.sketch-rounded, .sketch-rounded *) {
|
|
173
|
-
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble
|
|
176
|
+
&:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
|
|
174
177
|
&:nth-child(4n + 2) {
|
|
175
178
|
--ui-radius: var(--sketch-radius-rounded, 11px 25px 12px 24px / 23px 11px 22px 12px);
|
|
176
179
|
}
|
|
@@ -202,7 +205,7 @@
|
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
|
|
205
|
-
&:is(.card, .panel, .alert) {
|
|
208
|
+
&:is(.card, .panel, .alert, .data-table) {
|
|
206
209
|
&:nth-child(4n + 2) {
|
|
207
210
|
--ui-radius-surface: var(--sketch-radius-surface-rounded, 17px 36px 18px 34px / 33px 16px 32px 17px);
|
|
208
211
|
}
|
|
@@ -283,7 +286,11 @@
|
|
|
283
286
|
/* The surface shape: the element this exists for is usually a pane. An action
|
|
284
287
|
takes the control shape below. */
|
|
285
288
|
border-radius: var(--sketch-radius-surface, 80px 4px 75px 5px / 3px 70px 4px 80px);
|
|
286
|
-
|
|
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));
|
|
287
294
|
font-family: var(--font-sketch, cursive);
|
|
288
295
|
}
|
|
289
296
|
|
package/dist/tw/box.css
CHANGED
|
@@ -35,6 +35,21 @@
|
|
|
35
35
|
own presentation instead of the container's reinterpretation of one. */
|
|
36
36
|
--_fill-cap: 100%;
|
|
37
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
|
+
);
|
|
38
53
|
--_fill: calc(var(--_capped) * var(--ui-bg-alpha, 1));
|
|
39
54
|
--_hover-fill: calc(min(100%, var(--_capped) + var(--hover-step)) * var(--ui-bg-alpha, 1));
|
|
40
55
|
/* How much of the foreground is the contrast ink: what the presentation asks
|
|
@@ -57,40 +72,41 @@
|
|
|
57
72
|
declaration beats the inherited one at any specificity; `surface`, `kbd`,
|
|
58
73
|
`code`, `pre` and the tooltip each restate theirs after `@apply box`. */
|
|
59
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));
|
|
60
79
|
|
|
61
|
-
--_bg: color-mix(in oklab, var(--intent-color) var(--_fill), var(--
|
|
80
|
+
--_bg: color-mix(in oklab, var(--intent-color) var(--_fill), var(--_ground));
|
|
62
81
|
/* The two ends answer different questions: `--intent-contrast` prints *on* the
|
|
63
82
|
fill, `--intent-strong` prints on the page (the slot for readable ink on a
|
|
64
83
|
subtle fill). Reading `--intent-color` at the page end instead makes every
|
|
65
84
|
colour do double duty and prints a soft amber component at 3.1:1.
|
|
66
85
|
`--intent-contrast` keeps its own meaning -- `--_on-fill` reconciles it with
|
|
67
86
|
a capped intent -- rather than being bent so neutral's contrast is the ink,
|
|
68
|
-
which
|
|
87
|
+
which renders a checked neutral checkbox black-on-black. */
|
|
69
88
|
--_fg: color-mix(in oklab, var(--intent-contrast) var(--_on-fill), var(--intent-strong));
|
|
70
89
|
/* P3: the line fades out as the fill fills in, so a filled box has a seamless
|
|
71
|
-
edge. It fades toward `transparent`, not toward the plate: the plate
|
|
72
|
-
runs under the border (nothing
|
|
73
|
-
box), so a line blended toward `--_bg`
|
|
74
|
-
itself
|
|
75
|
-
neutral fill
|
|
76
|
-
|
|
77
|
-
nothing, the border shows the one coat beneath it.
|
|
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.
|
|
78
96
|
|
|
79
|
-
Blend first, amount after (`--_edge-amount` below)
|
|
80
|
-
`.edgeless` on the fill colour, which the border box
|
|
81
|
-
coat
|
|
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
|
|
82
100
|
docs/internal/model.md#presentation. */
|
|
83
101
|
--_line: color-mix(in oklab, transparent var(--ui-fill, var(--_d-fill)), var(--intent-border));
|
|
84
102
|
/* How much line there is, as an input rather than a result. A component that
|
|
85
103
|
must keep its line whatever the edge class says raises `--_edge-floor`
|
|
86
104
|
instead of rewriting `--_edge`, and the composition above still runs.
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
leaves the axis live, so `.edged` and `.edgeless` still mean what they say
|
|
93
|
-
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. */
|
|
94
110
|
--_edge-amount: max(var(--ui-border, var(--_d-border)), var(--_edge-floor, 0%));
|
|
95
111
|
--_edge: color-mix(in oklab, var(--_line) var(--_edge-amount), transparent);
|
|
96
112
|
--_width: min(var(--ui-border-width, var(--border-width)), var(--ui-border-max, 100px));
|
|
@@ -171,14 +187,11 @@
|
|
|
171
187
|
--_focus-stack: var(--_shadow), inset 0 0 0 var(--ui-focus-inset) var(--focus-ring);
|
|
172
188
|
|
|
173
189
|
/* Every box sizes itself as `min-height`/`min-width: var(--control-height)`
|
|
174
|
-
plus its own padding and the border shorthand above, so its geometry is
|
|
175
|
-
right under `
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
inherited the `content-box` default and every sized control came out
|
|
180
|
-
inflated by its own padding and border. A component's own geometry is not an
|
|
181
|
-
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. */
|
|
182
195
|
box-sizing: border-box;
|
|
183
196
|
background-color: var(--_bg);
|
|
184
197
|
color: var(--_fg);
|
|
@@ -221,6 +234,15 @@
|
|
|
221
234
|
transform var(--motion-duration-normal) var(--motion-ease),
|
|
222
235
|
translate var(--motion-duration-normal) var(--motion-ease);
|
|
223
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
|
+
}
|
|
245
|
+
|
|
224
246
|
/* An aesthetic that clips cannot show the global focus outline, so it declares
|
|
225
247
|
`--ui-focus-inset` and gets an inset layer instead. With no such aesthetic
|
|
226
248
|
the token is undefined, which makes the whole stack invalid at computed-value
|
|
@@ -254,7 +276,7 @@
|
|
|
254
276
|
and wrong for something you type into, so a component opts in. */
|
|
255
277
|
@utility box-hover {
|
|
256
278
|
&:not(:disabled, .disabled, [aria-disabled="true"], [data-disabled]):hover {
|
|
257
|
-
--_bg: color-mix(in oklab, var(--intent-hover) var(--_hover-fill), var(--
|
|
279
|
+
--_bg: color-mix(in oklab, var(--intent-hover) var(--_hover-fill), var(--_ground));
|
|
258
280
|
/* P3 again, against the hover tone: the line still fades as the fill fills
|
|
259
281
|
in, but toward the hover ink. Without this the edge keeps the resting ink
|
|
260
282
|
-- a ring of the colour the box just left. */
|