@codenhub/styles 0.6.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 +21 -16
- 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 +81 -23
- package/dist/tw/aesthetics/cyber.css +86 -29
- package/dist/tw/aesthetics/glass.css +177 -50
- package/dist/tw/aesthetics/neobrutalism.css +98 -22
- package/dist/tw/aesthetics/pixel.css +93 -8
- package/dist/tw/aesthetics/sketch.css +87 -22
- package/dist/tw/box.css +21 -2
- package/dist/tw/components/feedback.css +2 -2
- package/dist/tw/components/form.css +58 -19
- package/dist/tw/components/index.css +3 -4
- package/dist/tw/components/surface.css +15 -6
- package/dist/tw/index.css +1 -1
- package/dist/tw/intent.css +6 -5
- package/dist/tw/native.css +8 -8
- package/dist/tw/palette.css +6 -6
- package/dist/tw/reset.css +15 -15
- package/dist/tw/theme.css +29 -17
- package/dist/tw/utilities/content.css +43 -1
- package/dist/tw/utilities/layout.css +26 -12
- package/docs/accessibility.md +89 -60
- 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 +2 -1
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/index.md +1 -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 +85 -26
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +18 -13
- package/docs/integrating/nextjs.md +3 -4
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +16 -3
- 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 +76 -66
- package/docs/usage/buttons.md +108 -40
- package/docs/usage/composing.md +105 -92
- package/docs/usage/content-and-layout.md +157 -126
- package/docs/usage/customizing.md +107 -37
- package/docs/usage/feedback.md +134 -71
- package/docs/usage/forms.md +176 -107
- package/docs/usage/index.md +18 -14
- package/docs/usage/solo.md +83 -0
- package/docs/usage/theming.md +260 -118
- package/docs/usage/tooltips.md +90 -49
- package/llms-full.txt +2358 -1313
- package/llms.txt +24 -22
- package/package.json +25 -32
- package/dist/tw/components/loader.css +0 -116
|
@@ -154,12 +154,20 @@
|
|
|
154
154
|
|
|
155
155
|
The corner knobs are glass's own, with larger defaults: a continuous corner
|
|
156
156
|
reads smaller than a round one of the same radius. Where `corner-shape` is
|
|
157
|
-
not drawn the corners stay round.
|
|
158
|
-
|
|
157
|
+
not drawn the corners stay round.
|
|
158
|
+
|
|
159
|
+
Not on a solo element: `.glass-solo.glass-liquid` paints its own corner
|
|
160
|
+
below, and a token declared on it would inherit into whatever it holds --
|
|
161
|
+
a `.btn` inside a solo toast took liquid's corners on a page with no glass
|
|
162
|
+
in scope. Every scope below skips a solo element for the same reason. */
|
|
163
|
+
.glass-liquid:not(.glass-solo) {
|
|
159
164
|
--ui-corner: var(--glass-radius, 1rem);
|
|
160
165
|
--ui-corner-surface: var(--glass-radius-surface, 1.5rem);
|
|
161
166
|
--ui-corner-shape: squircle;
|
|
167
|
+
}
|
|
162
168
|
|
|
169
|
+
/* The layers' values, on a solo element too: it draws the same two. */
|
|
170
|
+
.glass-liquid {
|
|
163
171
|
--_glass-liquid-blur: blur(2px) saturate(1.8);
|
|
164
172
|
|
|
165
173
|
/* The lens is its own layer rather than a second function in the blur's
|
|
@@ -177,6 +185,12 @@
|
|
|
177
185
|
property, so the band and the strength are fixed, not knobs. */
|
|
178
186
|
--_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
187
|
|
|
188
|
+
/* The same lens at a control's size. The pane's band is 8px of erosion
|
|
189
|
+
under a 10px blur, which is most of a 40px button's height: the two
|
|
190
|
+
sides' ramps meet in the middle and the label sits in a loop. A third of
|
|
191
|
+
each length keeps a clear centre for the label. */
|
|
192
|
+
--_glass-liquid-lens-control: 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='3'/><feGaussianBlur stdDeviation='3.5' result='ramp'/><feOffset in='ramp' dx='-1' result='l'/><feOffset in='ramp' dx='1' result='r'/><feComposite in='l' in2='r' operator='arithmetic' k2='2' k3='-2' k4='0.5' result='dx'/><feOffset in='ramp' dy='-1' result='u'/><feOffset in='ramp' dy='1' 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='40' xChannelSelector='R' yChannelSelector='G'/></filter></svg>#lens");
|
|
193
|
+
|
|
180
194
|
/* The rim: light caught on the top-left edge and, fainter, the bottom-right,
|
|
181
195
|
over a soft inner glow. Drawn on the lens layer, the topmost, because a
|
|
182
196
|
rim drawn on the surface itself would sit under the layers and blur. */
|
|
@@ -192,57 +206,77 @@
|
|
|
192
206
|
}
|
|
193
207
|
|
|
194
208
|
/* The glass material the modifier changes, where glass is in scope: on the
|
|
195
|
-
same element, or on a surface inside a glass region.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
209
|
+
same element, or on a surface inside a glass region.
|
|
210
|
+
|
|
211
|
+
The backdrop is liquid's lighter blur, for whatever frosts under glass and
|
|
212
|
+
takes no layers below: a bare `<table>` under `/native`, a consumer's own
|
|
213
|
+
`@apply surface`. The layers' selector list cannot name those, and with
|
|
214
|
+
the backdrop cleared here they kept the clearer ground with nothing
|
|
215
|
+
blurred behind it. A surface that does take the layers clears its own. */
|
|
216
|
+
.glass.glass-liquid:not(.glass-solo),
|
|
217
|
+
.glass .glass-liquid:not(.glass-solo) {
|
|
201
218
|
--ui-ink: light-dark(rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.16));
|
|
202
219
|
--ui-surface-ground: color-mix(in srgb, var(--color-background) 30%, transparent);
|
|
203
220
|
--ui-surface-image: initial;
|
|
204
|
-
--ui-backdrop:
|
|
221
|
+
--ui-backdrop: var(--_glass-liquid-blur);
|
|
205
222
|
}
|
|
206
223
|
|
|
207
224
|
@media (prefers-reduced-transparency: reduce) {
|
|
208
|
-
.glass.glass-liquid,
|
|
209
|
-
.glass .glass-liquid {
|
|
225
|
+
.glass.glass-liquid:not(.glass-solo),
|
|
226
|
+
.glass .glass-liquid:not(.glass-solo) {
|
|
210
227
|
--ui-surface-ground: var(--color-background);
|
|
211
228
|
}
|
|
212
229
|
|
|
213
230
|
.glass-liquid {
|
|
214
231
|
--_glass-liquid-blur: none;
|
|
215
232
|
--_glass-liquid-lens: none;
|
|
233
|
+
--_glass-liquid-lens-control: none;
|
|
216
234
|
}
|
|
217
235
|
}
|
|
218
236
|
|
|
219
237
|
/* The layers: a treatment no token reaches, so a selector list glass owns and
|
|
220
|
-
the registry records. Two pseudo-elements behind
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
238
|
+
the registry records. Two pseudo-elements behind the content, the blur
|
|
239
|
+
beneath and the lens with the rim and sheen above it. `isolation` keeps
|
|
240
|
+
them above the element's own plate, which they then blur with the page;
|
|
241
|
+
`position` anchors them, and a component that positions itself -- the
|
|
242
|
+
tooltip bubble -- keeps its own. A default or `.soft` table frosts under
|
|
243
|
+
glass, so it takes the layers too. Both slots are spent, so a host carries
|
|
244
|
+
no `::before` or `::after` of the consumer's; the fields cannot host one.
|
|
245
|
+
|
|
246
|
+
The blur is on the layer and not on the host: an element with a backdrop
|
|
247
|
+
filter of its own is a backdrop root, and a layer inside one sees only that
|
|
248
|
+
element, never the page behind it. So a host clears the region's backdrop.
|
|
249
|
+
|
|
250
|
+
Surfaces take the layers from a liquid scope. A region of another
|
|
251
|
+
aesthetic nested inside, or of plain glass, keeps its own material and
|
|
252
|
+
takes none; this list names the other aesthetics, and `registry.test.ts`
|
|
253
|
+
fails when one is missing.
|
|
254
|
+
|
|
255
|
+
A button takes them only when it carries `.glass-liquid` itself, in a
|
|
256
|
+
glass scope. Controls stay solid under a liquid region, for the reason
|
|
257
|
+
glass gives -- two composited layers and a filter under every control of a
|
|
258
|
+
dense cluster -- and a class on the one button that is meant to be a pane
|
|
259
|
+
is a request rather than a cascade, the idiom `text-control` uses for
|
|
260
|
+
`.edgeless`. Its fill is still presentation's: `.solid` stays an opaque
|
|
261
|
+
plate under the rim, and `.soft` and `.ghost` are the clear panes. A
|
|
262
|
+
disabled one is dimmed by `opacity`, which makes it a backdrop root, so it
|
|
263
|
+
keeps the ground and the rim and bends nothing. */
|
|
264
|
+
:is(.glass-liquid:not(.glass-solo), .glass-liquid:not(.glass-solo) *):is(.glass, .glass *):is(
|
|
265
|
+
.card,
|
|
266
|
+
.panel,
|
|
267
|
+
.alert,
|
|
268
|
+
.tooltip-bubble,
|
|
269
|
+
.surface,
|
|
270
|
+
.data-table:not(.solid, .ghost)
|
|
271
|
+
):not(
|
|
272
|
+
.glass-liquid :is(.neobrutalism, .pixel, .chunky-tile, .cyber, .sketch),
|
|
273
|
+
.glass-liquid :is(.neobrutalism, .pixel, .chunky-tile, .cyber, .sketch) *,
|
|
274
|
+
.glass-liquid .glass:not(.glass-liquid),
|
|
275
|
+
.glass-liquid .glass:not(.glass-liquid) *
|
|
276
|
+
),
|
|
277
|
+
.btn.glass-liquid:is(.glass, .glass *) {
|
|
278
|
+
--ui-backdrop: none;
|
|
279
|
+
|
|
246
280
|
position: relative;
|
|
247
281
|
isolation: isolate;
|
|
248
282
|
|
|
@@ -269,6 +303,28 @@
|
|
|
269
303
|
box-shadow: var(--_glass-liquid-rim);
|
|
270
304
|
}
|
|
271
305
|
}
|
|
306
|
+
|
|
307
|
+
/* A button's lens is the control one. Swapped as the value the layer reads
|
|
308
|
+
rather than on the layer: the list above outranks any selector that names
|
|
309
|
+
the button's `::after` alone. */
|
|
310
|
+
.btn.glass-liquid:is(.glass, .glass *) {
|
|
311
|
+
--_glass-liquid-lens: var(--_glass-liquid-lens-control);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* A liquid button rests on liquid's ground rather than on nothing, so a
|
|
316
|
+
`.ghost` or `.soft` one is a pane and not a hole in the page. It reads the
|
|
317
|
+
surface ground the modifier set on it, so reduced transparency and a
|
|
318
|
+
consumer's own `--ui-surface-ground` reach it as they reach a card.
|
|
319
|
+
|
|
320
|
+
In `utilities`, not with the layers: it has to beat `box`'s own
|
|
321
|
+
`--_d-ground: transparent`, which it does there on specificity, and it
|
|
322
|
+
writes only a private nothing a consumer sets. See
|
|
323
|
+
docs/internal/model.md#cascade-layers. */
|
|
324
|
+
@layer utilities {
|
|
325
|
+
.btn.glass-liquid:is(.glass, .glass *) {
|
|
326
|
+
--_d-ground: var(--ui-surface-ground, transparent);
|
|
327
|
+
}
|
|
272
328
|
}
|
|
273
329
|
|
|
274
330
|
/* Forced colours paint the plain surface: no layer blurs, bends, or lights it. */
|
|
@@ -276,6 +332,7 @@
|
|
|
276
332
|
.glass-liquid {
|
|
277
333
|
--_glass-liquid-blur: none;
|
|
278
334
|
--_glass-liquid-lens: none;
|
|
335
|
+
--_glass-liquid-lens-control: none;
|
|
279
336
|
--_glass-liquid-rim: none;
|
|
280
337
|
--_glass-liquid-sheen: none;
|
|
281
338
|
}
|
|
@@ -286,24 +343,63 @@
|
|
|
286
343
|
`<div>` on a page that never loaded the base stylesheet. See
|
|
287
344
|
docs/internal/model.md#solo-classes.
|
|
288
345
|
|
|
289
|
-
It
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
346
|
+
It composes with what the element is asked to be, the way a component does:
|
|
347
|
+
the fill and edge a presentation class asks for, on the element or cascaded
|
|
348
|
+
from a container; the intent class on the element; the element's own
|
|
349
|
+
elevation class. Each is read with the unclassed look as its fallback, so
|
|
350
|
+
with none of them, or with no theme loaded, it paints what it always did.
|
|
351
|
+
|
|
352
|
+
Material is the exception. It reads the aesthetic's own knobs and the
|
|
353
|
+
theme's foundation tokens, each with its shipped literal as the fallback,
|
|
354
|
+
and never a material `--ui-*` or `--elevation-color` token: those belong to
|
|
355
|
+
whichever aesthetic an ancestor carries, and a solo element has to be this
|
|
356
|
+
aesthetic inside any of them.
|
|
357
|
+
|
|
293
358
|
Unlayered and one class deep, so it beats a foreign component's
|
|
294
359
|
zero-specificity rules wherever they load. Not for this package's own
|
|
295
|
-
components, which take the aesthetic class instead.
|
|
360
|
+
components, which take the aesthetic class instead.
|
|
361
|
+
|
|
362
|
+
The other five paint the fill as an inset layer over whatever the element
|
|
363
|
+
already is, and write no background, so an unclassed solo element keeps its
|
|
364
|
+
own. Glass's translucent ground is its material, so it owns the background
|
|
365
|
+
and mixes the fill over that ground. */
|
|
296
366
|
.glass-solo {
|
|
297
|
-
|
|
367
|
+
/* The composition, the same in every solo class; `registry.test.ts` holds
|
|
368
|
+
the copies together. See the note on `.glass-solo`. */
|
|
369
|
+
--_solo-intent-color: initial;
|
|
370
|
+
--_solo-intent-contrast: initial;
|
|
371
|
+
--_solo-intent-strong: initial;
|
|
372
|
+
--_solo-intent-border: initial;
|
|
373
|
+
--_solo-intent-fill-max: initial;
|
|
374
|
+
--_solo-color: var(--_solo-intent-color, var(--color-text, light-dark(oklch(14.5% 0 0), oklch(98.5% 0 0))));
|
|
375
|
+
--_solo-contrast: var(
|
|
376
|
+
--_solo-intent-contrast,
|
|
377
|
+
var(--color-text-contrast, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)))
|
|
378
|
+
);
|
|
379
|
+
--_solo-strong: var(--_solo-intent-strong, var(--color-text-strong, light-dark(oklch(20.5% 0 0), oklch(97% 0 0))));
|
|
380
|
+
--_solo-capped: min(var(--ui-fill, 0%), var(--_solo-intent-fill-max, 20%));
|
|
381
|
+
--_solo-fill: color-mix(in oklab, var(--_solo-color) var(--_solo-capped), transparent);
|
|
382
|
+
--_solo-on-fill: min(var(--ui-fg-on-fill, 0%), max(0%, calc(var(--_solo-capped) * 2 - 100%)));
|
|
383
|
+
--_solo-fg: color-mix(in oklab, var(--_solo-contrast) var(--_solo-on-fill), var(--_solo-strong));
|
|
384
|
+
/* The line with no intent on the element: this aesthetic's own ink. */
|
|
385
|
+
--_solo-ink: var(--_solo-intent-border, light-dark(rgb(255 255 255 / 0.65), rgb(255 255 255 / 0.22)));
|
|
386
|
+
--_solo-ground: color-mix(
|
|
298
387
|
in srgb,
|
|
299
388
|
var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0))) 45%,
|
|
300
389
|
transparent
|
|
301
390
|
);
|
|
302
|
-
|
|
391
|
+
/* The plate runs under the border, so the line fades to nothing, as `box`'s
|
|
392
|
+
does, rather than to the fill. */
|
|
393
|
+
--_solo-edge: color-mix(in oklab, var(--_solo-ink) var(--ui-border, 100%), transparent);
|
|
394
|
+
|
|
395
|
+
background-color: color-mix(in oklab, var(--_solo-color) var(--_solo-capped), var(--_solo-ground));
|
|
396
|
+
border: 1px solid var(--_solo-edge);
|
|
303
397
|
/* The surface corner: the element this exists for is a pane. */
|
|
304
398
|
border-radius: var(--glass-radius-surface, 1rem);
|
|
305
399
|
/* The theme's depth colour as a literal, for the reason above: inside a
|
|
306
|
-
`.chunky-tile` region the token is black.
|
|
400
|
+
`.chunky-tile` region the token is black. A complete shadow, so the
|
|
401
|
+
elevation classes do not reach it, as they do not under the aesthetic
|
|
402
|
+
class. */
|
|
307
403
|
box-shadow:
|
|
308
404
|
0 1px 2px -1px light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55)),
|
|
309
405
|
0 18px 40px -16px light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
|
|
@@ -313,9 +409,39 @@
|
|
|
313
409
|
backdrop-filter: blur(14px) saturate(1.6);
|
|
314
410
|
}
|
|
315
411
|
|
|
412
|
+
/* An intent class on the element colours it, as on a component. Named rather
|
|
413
|
+
than read from `--intent-*` alone: those slots inherit, so a `.success`
|
|
414
|
+
container would colour a solo element where it leaves a component neutral. */
|
|
415
|
+
.glass-solo:is(.primary, .secondary, .success, .warning, .destructive, .info) {
|
|
416
|
+
--_solo-intent-color: var(--intent-color);
|
|
417
|
+
--_solo-intent-contrast: var(--intent-contrast);
|
|
418
|
+
--_solo-intent-strong: var(--intent-strong);
|
|
419
|
+
--_solo-intent-border: var(--intent-border);
|
|
420
|
+
--_solo-intent-fill-max: var(--intent-fill-max);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* The text colour is written only where a fill or an intent is asked for, on
|
|
424
|
+
the element or by a container's fill class. Anywhere else the element keeps
|
|
425
|
+
its own: a dark toast keeps its light text. */
|
|
426
|
+
.glass-solo:is(
|
|
427
|
+
.solid,
|
|
428
|
+
.soft,
|
|
429
|
+
.ghost,
|
|
430
|
+
.primary,
|
|
431
|
+
.secondary,
|
|
432
|
+
.success,
|
|
433
|
+
.warning,
|
|
434
|
+
.destructive,
|
|
435
|
+
.info,
|
|
436
|
+
:is(.solid, .soft, .ghost) *
|
|
437
|
+
) {
|
|
438
|
+
color: var(--_solo-fg);
|
|
439
|
+
}
|
|
440
|
+
|
|
316
441
|
@media (prefers-reduced-transparency: reduce) {
|
|
317
442
|
.glass-solo {
|
|
318
|
-
|
|
443
|
+
--_solo-ground: var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)));
|
|
444
|
+
|
|
319
445
|
-webkit-backdrop-filter: none;
|
|
320
446
|
backdrop-filter: none;
|
|
321
447
|
}
|
|
@@ -336,13 +462,14 @@
|
|
|
336
462
|
}
|
|
337
463
|
|
|
338
464
|
.glass-solo.glass-liquid {
|
|
339
|
-
|
|
340
|
-
background-color: color-mix(
|
|
465
|
+
--_solo-ground: color-mix(
|
|
341
466
|
in srgb,
|
|
342
467
|
var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0))) 30%,
|
|
343
468
|
transparent
|
|
344
469
|
);
|
|
345
|
-
|
|
470
|
+
--_solo-ink: var(--_solo-intent-border, light-dark(rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.16)));
|
|
471
|
+
|
|
472
|
+
isolation: isolate;
|
|
346
473
|
border-radius: var(--glass-radius-surface, 1.5rem);
|
|
347
474
|
corner-shape: squircle;
|
|
348
475
|
-webkit-backdrop-filter: none;
|
|
@@ -373,6 +500,6 @@
|
|
|
373
500
|
|
|
374
501
|
@media (prefers-reduced-transparency: reduce) {
|
|
375
502
|
.glass-solo.glass-liquid {
|
|
376
|
-
|
|
503
|
+
--_solo-ground: var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)));
|
|
377
504
|
}
|
|
378
505
|
}
|
|
@@ -120,48 +120,108 @@
|
|
|
120
120
|
|
|
121
121
|
In `utilities`, not with the token class: it has to beat `@utility alert`'s
|
|
122
122
|
own `--_d-elevation: 0`, which it does there at 0-2-0, and it writes only a
|
|
123
|
-
private nothing a consumer sets.
|
|
123
|
+
private nothing a consumer sets.
|
|
124
|
+
|
|
125
|
+
Bounded by the nearest aesthetic region: an alert inside another aesthetic
|
|
126
|
+
nested in a neobrutalist region rests as that aesthetic rests it, and one in
|
|
127
|
+
a neobrutalist region nested again inside that takes the slab back. A
|
|
128
|
+
`:not(.neobrutalism :is(...) *)` exclusion cannot tell those two apart, since
|
|
129
|
+
the re-entered alert also sits below the other aesthetic, so each region
|
|
130
|
+
writes a private flag instead and inheritance hands the alert the nearest
|
|
131
|
+
one's. The slab is the alert's own resting default when the flag is unset. */
|
|
124
132
|
@layer utilities {
|
|
133
|
+
.neobrutalism {
|
|
134
|
+
--_neo-alert-elevation: 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
:is(.glass, .pixel, .chunky-tile, .cyber, .sketch) {
|
|
138
|
+
--_neo-alert-elevation: initial;
|
|
139
|
+
}
|
|
140
|
+
|
|
125
141
|
.neobrutalism .alert {
|
|
126
|
-
--_d-elevation:
|
|
142
|
+
--_d-elevation: var(--_neo-alert-elevation, 0);
|
|
127
143
|
}
|
|
128
144
|
}
|
|
129
145
|
|
|
130
146
|
/* Solo: the same look painted onto the one element carrying the class, for an
|
|
131
147
|
element the package does not style. See docs/internal/model.md#solo-classes and
|
|
132
|
-
the note on `.glass-solo`:
|
|
133
|
-
|
|
134
|
-
|
|
148
|
+
the note on `.glass-solo`: it composes with the element's presentation,
|
|
149
|
+
intent, and elevation, and reads its material from its own knobs and
|
|
150
|
+
foundation tokens with literal fallbacks, never a shared material `--ui-*`
|
|
151
|
+
or `--elevation-color` token. Unlayered, and not for this package's own
|
|
152
|
+
components. */
|
|
135
153
|
.neobrutalism-solo {
|
|
136
154
|
--_neo-offset: var(--neo-offset, 4px);
|
|
137
|
-
|
|
155
|
+
/* The composition, the same in every solo class; `registry.test.ts` holds
|
|
156
|
+
the copies together. See the note on `.glass-solo`. */
|
|
157
|
+
--_solo-intent-color: initial;
|
|
158
|
+
--_solo-intent-contrast: initial;
|
|
159
|
+
--_solo-intent-strong: initial;
|
|
160
|
+
--_solo-intent-border: initial;
|
|
161
|
+
--_solo-intent-fill-max: initial;
|
|
162
|
+
--_solo-color: var(--_solo-intent-color, var(--color-text, light-dark(oklch(14.5% 0 0), oklch(98.5% 0 0))));
|
|
163
|
+
--_solo-contrast: var(
|
|
164
|
+
--_solo-intent-contrast,
|
|
165
|
+
var(--color-text-contrast, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)))
|
|
166
|
+
);
|
|
167
|
+
--_solo-strong: var(--_solo-intent-strong, var(--color-text-strong, light-dark(oklch(20.5% 0 0), oklch(97% 0 0))));
|
|
168
|
+
--_solo-capped: min(var(--ui-fill, 0%), var(--_solo-intent-fill-max, 20%));
|
|
169
|
+
--_solo-fill: color-mix(in oklab, var(--_solo-color) var(--_solo-capped), transparent);
|
|
170
|
+
--_solo-on-fill: min(var(--ui-fg-on-fill, 0%), max(0%, calc(var(--_solo-capped) * 2 - 100%)));
|
|
171
|
+
--_solo-fg: color-mix(in oklab, var(--_solo-contrast) var(--_solo-on-fill), var(--_solo-strong));
|
|
172
|
+
/* The line with no intent on the element: this aesthetic's own ink. */
|
|
173
|
+
--_solo-ink: var(
|
|
174
|
+
--_solo-intent-border,
|
|
175
|
+
light-dark(var(--color-neutral-950, oklch(14.5% 0 0)), var(--color-neutral-50, oklch(98.5% 0 0)))
|
|
176
|
+
);
|
|
177
|
+
--_solo-edge: color-mix(in oklab, var(--_solo-ink) var(--ui-border, 100%), var(--_solo-fill));
|
|
178
|
+
/* The slab, scaled by the element's own elevation class: `.flat` takes it off
|
|
179
|
+
and `.floating` doubles it, and the press travels the same distance. */
|
|
180
|
+
--_solo-depth: calc(var(--_neo-offset) * var(--ui-elevation, 1));
|
|
138
181
|
|
|
139
|
-
border: 2px solid var(--
|
|
182
|
+
border: 2px solid var(--_solo-edge);
|
|
140
183
|
border-radius: 0;
|
|
141
|
-
box-shadow:
|
|
184
|
+
box-shadow:
|
|
185
|
+
var(--_solo-depth) var(--_solo-depth) 0 0 var(--_solo-ink),
|
|
186
|
+
inset 0 0 0 100vmax var(--_solo-fill);
|
|
142
187
|
transition:
|
|
143
188
|
box-shadow var(--motion-duration-normal, 200ms) var(--motion-ease, cubic-bezier(0.2, 0, 0, 1)),
|
|
144
189
|
transform var(--motion-duration-normal, 200ms) var(--motion-ease, cubic-bezier(0.2, 0, 0, 1));
|
|
145
190
|
}
|
|
146
191
|
|
|
192
|
+
/* An intent class on the element colours it, as on a component. Named rather
|
|
193
|
+
than read from `--intent-*` alone: those slots inherit, so a `.success`
|
|
194
|
+
container would colour a solo element where it leaves a component neutral. */
|
|
195
|
+
.neobrutalism-solo:is(.primary, .secondary, .success, .warning, .destructive, .info) {
|
|
196
|
+
--_solo-intent-color: var(--intent-color);
|
|
197
|
+
--_solo-intent-contrast: var(--intent-contrast);
|
|
198
|
+
--_solo-intent-strong: var(--intent-strong);
|
|
199
|
+
--_solo-intent-border: var(--intent-border);
|
|
200
|
+
--_solo-intent-fill-max: var(--intent-fill-max);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* The text colour is written only where a fill or an intent is asked for, on
|
|
204
|
+
the element or by a container's fill class. Anywhere else the element keeps
|
|
205
|
+
its own: a dark toast keeps its light text. */
|
|
206
|
+
.neobrutalism-solo:is(
|
|
207
|
+
.solid,
|
|
208
|
+
.soft,
|
|
209
|
+
.ghost,
|
|
210
|
+
.primary,
|
|
211
|
+
.secondary,
|
|
212
|
+
.success,
|
|
213
|
+
.warning,
|
|
214
|
+
.destructive,
|
|
215
|
+
.info,
|
|
216
|
+
:is(.solid, .soft, .ghost) *
|
|
217
|
+
) {
|
|
218
|
+
color: var(--_solo-fg);
|
|
219
|
+
}
|
|
220
|
+
|
|
147
221
|
/* The press, only on something pressed: an action, not disabled. A solo
|
|
148
222
|
container -- a toast clicked to dismiss -- stays put, the way only `.btn` and
|
|
149
223
|
an opted-in card press under the aesthetic class. */
|
|
150
224
|
.neobrutalism-solo:is(
|
|
151
|
-
button,
|
|
152
|
-
a[href],
|
|
153
|
-
[role="button"],
|
|
154
|
-
summary,
|
|
155
|
-
input[type="button"],
|
|
156
|
-
input[type="submit"],
|
|
157
|
-
input[type="reset"]
|
|
158
|
-
):active:not(:disabled, [aria-disabled="true"]) {
|
|
159
|
-
box-shadow: 0 0 0 0 var(--_neo-ink);
|
|
160
|
-
transform: translate(var(--_neo-offset), var(--_neo-offset));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@media (prefers-reduced-motion: reduce) {
|
|
164
|
-
.neobrutalism-solo:is(
|
|
165
225
|
button,
|
|
166
226
|
a[href],
|
|
167
227
|
[role="button"],
|
|
@@ -170,6 +230,22 @@
|
|
|
170
230
|
input[type="submit"],
|
|
171
231
|
input[type="reset"]
|
|
172
232
|
):active:not(:disabled, [aria-disabled="true"]) {
|
|
233
|
+
box-shadow:
|
|
234
|
+
0 0 0 0 var(--_solo-ink),
|
|
235
|
+
inset 0 0 0 100vmax var(--_solo-fill);
|
|
236
|
+
transform: translate(var(--_solo-depth), var(--_solo-depth));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@media (prefers-reduced-motion: reduce) {
|
|
240
|
+
.neobrutalism-solo:is(
|
|
241
|
+
button,
|
|
242
|
+
a[href],
|
|
243
|
+
[role="button"],
|
|
244
|
+
summary,
|
|
245
|
+
input[type="button"],
|
|
246
|
+
input[type="submit"],
|
|
247
|
+
input[type="reset"]
|
|
248
|
+
):active:not(:disabled, [aria-disabled="true"]) {
|
|
173
249
|
transform: none;
|
|
174
250
|
}
|
|
175
251
|
}
|
|
@@ -147,18 +147,46 @@
|
|
|
147
147
|
|
|
148
148
|
/* Solo: the same look painted onto the one element carrying the class, for an
|
|
149
149
|
element the package does not style. See docs/internal/model.md#solo-classes and
|
|
150
|
-
the note on `.glass-solo`:
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
the note on `.glass-solo`: it composes with the element's presentation,
|
|
151
|
+
intent, and elevation, and reads its material from its own knobs and
|
|
152
|
+
foundation tokens with literal fallbacks, never a shared material `--ui-*`
|
|
153
|
+
or `--elevation-color` token. Unlayered, and not for this package's own
|
|
154
|
+
components. */
|
|
153
155
|
.pixel-solo {
|
|
154
156
|
--_pixel-unit: var(--pixel-unit, 4px);
|
|
155
|
-
|
|
157
|
+
/* The composition, the same in every solo class; `registry.test.ts` holds
|
|
158
|
+
the copies together. See the note on `.glass-solo`. */
|
|
159
|
+
--_solo-intent-color: initial;
|
|
160
|
+
--_solo-intent-contrast: initial;
|
|
161
|
+
--_solo-intent-strong: initial;
|
|
162
|
+
--_solo-intent-border: initial;
|
|
163
|
+
--_solo-intent-fill-max: initial;
|
|
164
|
+
--_solo-color: var(--_solo-intent-color, var(--color-text, light-dark(oklch(14.5% 0 0), oklch(98.5% 0 0))));
|
|
165
|
+
--_solo-contrast: var(
|
|
166
|
+
--_solo-intent-contrast,
|
|
167
|
+
var(--color-text-contrast, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)))
|
|
168
|
+
);
|
|
169
|
+
--_solo-strong: var(--_solo-intent-strong, var(--color-text-strong, light-dark(oklch(20.5% 0 0), oklch(97% 0 0))));
|
|
170
|
+
--_solo-capped: min(var(--ui-fill, 0%), var(--_solo-intent-fill-max, 20%));
|
|
171
|
+
--_solo-fill: color-mix(in oklab, var(--_solo-color) var(--_solo-capped), transparent);
|
|
172
|
+
--_solo-on-fill: min(var(--ui-fg-on-fill, 0%), max(0%, calc(var(--_solo-capped) * 2 - 100%)));
|
|
173
|
+
--_solo-fg: color-mix(in oklab, var(--_solo-contrast) var(--_solo-on-fill), var(--_solo-strong));
|
|
174
|
+
/* The line with no intent on the element: this aesthetic's own ink. */
|
|
175
|
+
--_solo-ink: var(
|
|
176
|
+
--_solo-intent-border,
|
|
177
|
+
light-dark(var(--color-neutral-950, oklch(14.5% 0 0)), var(--color-neutral-50, oklch(98.5% 0 0)))
|
|
178
|
+
);
|
|
179
|
+
/* The ring is the edge, and the fill is a layer under it rather than a plate
|
|
180
|
+
beneath a border, so the line fades to nothing instead of to the fill. */
|
|
181
|
+
--_solo-edge: color-mix(in oklab, var(--_solo-ink) var(--ui-border, 100%), transparent);
|
|
156
182
|
|
|
157
183
|
/* The clip removes a border at the straight sides, so the ring draws the
|
|
158
184
|
edge and the element's own border goes. */
|
|
159
185
|
border: 0;
|
|
160
186
|
border-radius: 0;
|
|
161
|
-
box-shadow:
|
|
187
|
+
box-shadow:
|
|
188
|
+
inset 0 0 0 var(--_pixel-unit) var(--_solo-edge),
|
|
189
|
+
inset 0 0 0 100vmax var(--_solo-fill);
|
|
162
190
|
clip-path: polygon(
|
|
163
191
|
0 var(--_pixel-unit),
|
|
164
192
|
var(--_pixel-unit) var(--_pixel-unit),
|
|
@@ -176,11 +204,68 @@
|
|
|
176
204
|
font-family: var(--font-pixel, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
|
177
205
|
}
|
|
178
206
|
|
|
207
|
+
/* An intent class on the element colours it, as on a component. Named rather
|
|
208
|
+
than read from `--intent-*` alone: those slots inherit, so a `.success`
|
|
209
|
+
container would colour a solo element where it leaves a component neutral. */
|
|
210
|
+
.pixel-solo:is(.primary, .secondary, .success, .warning, .destructive, .info) {
|
|
211
|
+
--_solo-intent-color: var(--intent-color);
|
|
212
|
+
--_solo-intent-contrast: var(--intent-contrast);
|
|
213
|
+
--_solo-intent-strong: var(--intent-strong);
|
|
214
|
+
--_solo-intent-border: var(--intent-border);
|
|
215
|
+
--_solo-intent-fill-max: var(--intent-fill-max);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* The text colour is written only where a fill or an intent is asked for, on
|
|
219
|
+
the element or by a container's fill class. Anywhere else the element keeps
|
|
220
|
+
its own: a dark toast keeps its light text. */
|
|
221
|
+
.pixel-solo:is(
|
|
222
|
+
.solid,
|
|
223
|
+
.soft,
|
|
224
|
+
.ghost,
|
|
225
|
+
.primary,
|
|
226
|
+
.secondary,
|
|
227
|
+
.success,
|
|
228
|
+
.warning,
|
|
229
|
+
.destructive,
|
|
230
|
+
.info,
|
|
231
|
+
:is(.solid, .soft, .ghost) *
|
|
232
|
+
) {
|
|
233
|
+
color: var(--_solo-fg);
|
|
234
|
+
}
|
|
235
|
+
|
|
179
236
|
/* The clip takes the focus outline too, so focus is a second inset layer under
|
|
180
|
-
the ring, wider than it so it shows -- shadows paint first-on-top.
|
|
237
|
+
the ring, wider than it so it shows -- shadows paint first-on-top. A line of
|
|
238
|
+
the page colour sits inside that one, as in `box`: the ring is the ink, and
|
|
239
|
+
on an element filled with the ink it would not show. */
|
|
181
240
|
.pixel-solo:focus-visible {
|
|
182
241
|
box-shadow:
|
|
183
|
-
inset 0 0 0 var(--_pixel-unit) var(--
|
|
242
|
+
inset 0 0 0 var(--_pixel-unit) var(--_solo-edge),
|
|
184
243
|
inset 0 0 0 calc(var(--_pixel-unit) + var(--focus-ring-width, 3px))
|
|
185
|
-
var(
|
|
244
|
+
var(
|
|
245
|
+
--focus-ring,
|
|
246
|
+
color-mix(
|
|
247
|
+
in srgb,
|
|
248
|
+
light-dark(var(--color-neutral-950, oklch(14.5% 0 0)), var(--color-neutral-50, oklch(98.5% 0 0))) 64%,
|
|
249
|
+
transparent
|
|
250
|
+
)
|
|
251
|
+
),
|
|
252
|
+
inset 0 0 0 calc(var(--_pixel-unit) + var(--focus-ring-width, 3px) + 2px)
|
|
253
|
+
var(--color-background, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0))),
|
|
254
|
+
inset 0 0 0 100vmax var(--_solo-fill);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Forced colours remove every box shadow, and the ring is one: the element
|
|
258
|
+
would have no edge at all. An outline stands in for it, drawn inward so
|
|
259
|
+
nothing moves, and the clip goes so the focus outline can show. This
|
|
260
|
+
entrypoint may be the only package stylesheet loaded, so it says so itself. */
|
|
261
|
+
@media (forced-colors: active) {
|
|
262
|
+
.pixel-solo {
|
|
263
|
+
outline: var(--_pixel-unit) solid CanvasText;
|
|
264
|
+
outline-offset: calc(-1 * var(--_pixel-unit));
|
|
265
|
+
clip-path: none;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.pixel-solo:focus-visible {
|
|
269
|
+
outline-color: Highlight;
|
|
270
|
+
}
|
|
186
271
|
}
|