@codenhub/styles 0.6.0 → 0.8.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 +62 -0
- package/README.md +28 -22
- package/README.pt-BR.md +62 -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/cli.js +189 -0
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/docs/accessibility.md +108 -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/0.8.0.md +70 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +169 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +105 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +75 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +148 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +238 -0
- package/docs/es/setup.md +188 -0
- package/docs/es/usage/aesthetics.md +282 -0
- package/docs/es/usage/buttons.md +135 -0
- package/docs/es/usage/composing.md +168 -0
- package/docs/es/usage/content-and-layout.md +219 -0
- package/docs/es/usage/customizing.md +304 -0
- package/docs/es/usage/feedback.md +157 -0
- package/docs/es/usage/forms.md +256 -0
- package/docs/es/usage/index.md +33 -0
- package/docs/es/usage/presets.md +92 -0
- package/docs/es/usage/solo.md +86 -0
- package/docs/es/usage/theming.md +309 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +86 -26
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +46 -13
- package/docs/integrating/nextjs.md +3 -4
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +89 -6
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +237 -0
- package/docs/pt-BR/accessibility.md +169 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +105 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +75 -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 +148 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +238 -0
- package/docs/pt-BR/setup.md +188 -0
- package/docs/pt-BR/usage/aesthetics.md +282 -0
- package/docs/pt-BR/usage/buttons.md +135 -0
- package/docs/pt-BR/usage/composing.md +168 -0
- package/docs/pt-BR/usage/content-and-layout.md +219 -0
- package/docs/pt-BR/usage/customizing.md +304 -0
- package/docs/pt-BR/usage/feedback.md +157 -0
- package/docs/pt-BR/usage/forms.md +256 -0
- package/docs/pt-BR/usage/index.md +33 -0
- package/docs/pt-BR/usage/presets.md +92 -0
- package/docs/pt-BR/usage/solo.md +86 -0
- package/docs/pt-BR/usage/theming.md +309 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +142 -91
- package/docs/usage/aesthetics.md +89 -73
- package/docs/usage/buttons.md +112 -40
- package/docs/usage/composing.md +109 -92
- package/docs/usage/content-and-layout.md +160 -125
- package/docs/usage/customizing.md +117 -41
- package/docs/usage/feedback.md +138 -71
- package/docs/usage/forms.md +201 -107
- package/docs/usage/index.md +22 -14
- package/docs/usage/presets.md +91 -0
- package/docs/usage/solo.md +85 -0
- package/docs/usage/theming.md +273 -118
- package/docs/usage/tooltips.md +90 -49
- package/llms-full.txt +2820 -1298
- package/llms.txt +24 -22
- package/package.json +134 -91
- package/{dist/tw → tw}/aesthetics/chunky-tile.css +107 -29
- package/{dist/tw → tw}/aesthetics/cyber.css +88 -40
- package/{dist/tw → tw}/aesthetics/glass.css +257 -61
- package/{dist/tw → tw}/aesthetics/neobrutalism.css +113 -20
- package/{dist/tw → tw}/aesthetics/pixel.css +93 -8
- package/tw/aesthetics/sketch.css +417 -0
- package/{dist/tw → tw}/box.css +105 -9
- package/tw/components/button.css +11 -0
- package/tw/components/button.rules.css +187 -0
- package/tw/components/feedback.css +11 -0
- package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +136 -32
- package/tw/components/form.css +11 -0
- package/{dist/tw/components/form.css → tw/components/form.rules.css} +577 -125
- package/tw/components/index.css +16 -0
- package/tw/components/rules.css +41 -0
- package/tw/components/surface.css +11 -0
- package/tw/components/surface.rules.css +222 -0
- package/tw/components/tooltip.css +11 -0
- package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +43 -27
- package/{dist/tw → tw}/corner.css +18 -12
- package/{dist/tw → tw}/elevation.css +23 -17
- package/{dist/tw → tw}/index.css +12 -10
- package/tw/index.d.ts +1 -0
- package/tw/intent.css +312 -0
- package/tw/modifiers.css +127 -0
- package/tw/native.css +320 -0
- package/tw/presentation.css +139 -0
- package/tw/reset.css +10 -0
- package/{dist/tw/reset.css → tw/reset.rules.css} +21 -22
- package/tw/size.css +34 -0
- package/tw/surface.css +9 -0
- package/tw/surface.rules.css +212 -0
- package/{dist/tw → tw}/theme.css +121 -45
- package/tw/typography.css +8 -0
- package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
- package/{dist/tw → tw}/utilities/content.css +212 -50
- package/tw/utilities/index.css +11 -0
- package/tw/utilities/layout.css +208 -0
- package/tw/utilities/rules.css +8 -0
- package/dist/tw/aesthetics/sketch.css +0 -333
- package/dist/tw/components/button.css +0 -139
- package/dist/tw/components/index.css +0 -36
- package/dist/tw/components/loader.css +0 -116
- package/dist/tw/components/surface.css +0 -175
- package/dist/tw/intent.css +0 -228
- package/dist/tw/native.css +0 -203
- package/dist/tw/palette.css +0 -460
- package/dist/tw/presentation.css +0 -68
- package/dist/tw/surface.css +0 -61
- package/dist/tw/utilities/index.css +0 -6
- package/dist/tw/utilities/layout.css +0 -130
- /package/{dist/tw → tw}/aesthetics/index.css +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Personalización
|
|
3
|
+
description: Consulta de los tokens de presentación y de material, los controles de las estéticas, las seis variables públicas de componente, la paleta generada y los helpers para construir tus propios componentes.
|
|
4
|
+
order: 9
|
|
5
|
+
source: 790dec3b1fcf41af4b38aca7c5b8a93135827c1e
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Personalización
|
|
9
|
+
|
|
10
|
+
Esta es una página de consulta para cambiar el paquete más allá de sus clases. [Temas](./theming.md) cubre los colores y los tokens base; esta página cubre el resto:
|
|
11
|
+
|
|
12
|
+
- [Tokens de presentación](#tokens-de-presentación): cuánto de una intención muestra un componente.
|
|
13
|
+
- [Tokens de material](#tokens-de-material): de qué está hecho un componente.
|
|
14
|
+
- [Tokens de estética](#tokens-de-estética): los controles que expone cada estética.
|
|
15
|
+
- [Variables de componente](#variables-de-componente): las seis variables que lee un único componente.
|
|
16
|
+
- [Paleta generada](#paleta-generada): valores de color fijos para el código que no puede cargar el paquete.
|
|
17
|
+
- [Helpers de composición](#helpers-de-composición): las clases con las que construir un componente propio.
|
|
18
|
+
|
|
19
|
+
## Tokens de presentación
|
|
20
|
+
|
|
21
|
+
Los tokens de presentación describen _cuánto_ de una intención muestra un componente, nunca _qué_ intención muestra. Son números y porcentajes sin unidad, así que no llevan color y se heredan sin riesgo: un contenedor los define una vez y cada componente de debajo los resuelve con su propia intención.
|
|
22
|
+
|
|
23
|
+
| Token | Propósito | Valor por defecto |
|
|
24
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
25
|
+
| `--ui-fill` | Porcentaje del color de la intención mezclado en el fondo. | El valor por defecto del componente; consulta más abajo. |
|
|
26
|
+
| `--ui-fg-on-fill` | Porcentaje de mezcla desde el tono strong de la intención hacia su color de contraste. | El valor por defecto del componente. |
|
|
27
|
+
| `--ui-border` | Porcentaje del color de borde de la intención en el borde. | El valor por defecto del componente. |
|
|
28
|
+
| `--hover-step` | Se suma al relleno en reposo bajo el puntero, en `--intent-hover`. Defínelo en `:root` o en cualquier elemento. | `14%` |
|
|
29
|
+
|
|
30
|
+
Sin definir, cada componente usa su propio valor por defecto, que aparece en [Composición → Valores por defecto de los componentes](./composing.md#valores-por-defecto-de-los-componentes). Las clases de presentación definen los tres primeros con los valores de [Composición → Presentación](./composing.md#presentación). No hay tokens de hover por presentación: el hover es siempre el relleno en reposo más `--hover-step`, hasta el 100%.
|
|
31
|
+
|
|
32
|
+
Ninguna clase de relleno escribe `--ui-border` y ninguna clase de borde escribe `--ui-fill`. Una caja rellena sin línea es `.solid.edgeless`, y `.solid.edged` renderiza la misma caja: la línea se desvanece a medida que el relleno se completa, así que incluso un relleno neutro, limitado y translúcido, se ve a través de su propio borde como una sola capa.
|
|
33
|
+
|
|
34
|
+
```css
|
|
35
|
+
background: color-mix(in oklab, var(--color-primary) var(--ui-fill, 100%), transparent);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Ahí hay dos decisiones deliberadas. Mezclar hacia `transparent` en lugar de hacia un token de fondo permite que una superficie teñida se adapte a lo que tenga debajo. Mezclar en `oklab` conserva intacta la paleta de tokens de gama amplia y mezcla de forma perceptual, mientras que `srgb` la recortaría.
|
|
39
|
+
|
|
40
|
+
Por eso un color calculado llega a la página como un resultado de `color-mix` resuelto y no con la sintaxis `oklch` del propio token. Es el mismo color; el código que compara cadenas de colores calculados debería comparar colores.
|
|
41
|
+
|
|
42
|
+
> **Contrato de los tokens de presentación**: solo las clases de presentación y las sobrescrituras del consumidor definen estos tokens; los componentes solo los leen. Definir un valor que ninguna clase de presentación produce está soportado, pero no validado. Consulta [Composición](./composing.md) para ver las clases que incluyen estos valores.
|
|
43
|
+
|
|
44
|
+
## Tokens de material
|
|
45
|
+
|
|
46
|
+
Los tokens de material describen de qué está _hecho_ un componente, no qué intención muestra ni con cuánta intensidad. Controlan la forma, los bordes, las sombras, la translucidez, los filtros y las transformaciones.
|
|
47
|
+
|
|
48
|
+
Los componentes leen cada uno con un valor de respaldo, así que dejarlos sin definir da el aspecto por defecto. Definidos en un contenedor, cambian el estilo de todo lo que contiene. La única excepción es `--ui-elevation`, que no se hereda, así que solo llega al elemento en el que se define; consulta [Composición → Elevación](./composing.md#elevación).
|
|
49
|
+
|
|
50
|
+
La geometría de la sombra se divide en partes sin color, así que se heredan sin riesgo. Los tokens que reciben un color, como `--ui-ink` y `--ui-surface-shadow`, pueden incluir el suyo.
|
|
51
|
+
|
|
52
|
+
| Token | Propósito | Respaldo |
|
|
53
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
54
|
+
| `--ui-corner` | Esquina de control en el tamaño por defecto; se escala con el escalón de tamaño. | `--radius-control` |
|
|
55
|
+
| `--ui-corner-surface` | Esquina de superficie con el relleno interior por defecto; se escala con el escalón de tamaño. | `--radius-surface` |
|
|
56
|
+
| `--ui-corner-tl` | `0` o `1`: si la esquina superior izquierda toma la esquina. `-tr`, `-br` y `-bl` para las demás. | `1` |
|
|
57
|
+
| `--ui-radius` | Un radio de control completo, usado tal cual: sobrescribe la esquina, el escalón y el patrón. | Calculado a partir de la esquina |
|
|
58
|
+
| `--ui-radius-surface` | Un radio de superficie completo, usado tal cual. | Calculado a partir de la esquina |
|
|
59
|
+
| `--ui-scale` | Sobrescribe el escalón de tamaño que definen las clases de tamaño y de relleno interior. | El escalón |
|
|
60
|
+
| `--ui-corner-shape` | Lo que dibuja cada esquina: `round`, `bevel` para un corte recto o `squircle` para una curva continua. Hoy solo en Chromium. | `round` |
|
|
61
|
+
| `--ui-radius-pill` | Esquina de lo que es completamente redondo por defecto: badges, switches, progreso, el icono del tooltip; `.btn.pill` y `.radio` lo leen sin otro respaldo que el redondo completo. | `--ui-radius`, `--ui-corner` y después redondo completo |
|
|
62
|
+
| `--ui-radius-tight` | Radio completo para los chips, como un checkbox, `.kbd` o `.code`, cuando está definido. Sin definir, un pequeño valor por defecto calculado. | `min(--ui-radius o --ui-corner, pequeño)` |
|
|
63
|
+
| `--ui-line-style` | Estilo de cada línea que dibuja un componente: `solid`, `dashed`, `dotted` o `double` (de 3px de ancho o más). | `solid` |
|
|
64
|
+
| `--ui-border-width` | Grosor del borde. | `--border-width` |
|
|
65
|
+
| `--ui-border-max` | Tope del grosor de borde calculado. | `100px` |
|
|
66
|
+
| `--ui-ink` | Color de línea neutro cuando no hay intención. | `--color-border` |
|
|
67
|
+
| `--ui-control-ink` | Color de línea neutro de campos, selects, checkboxes, radios y switches cuando no hay intención. | `--ui-ink` y después `--color-control-border` |
|
|
68
|
+
| `--ui-rule-ink` | Color de línea neutro del marco y las líneas divisorias de una tabla cuando no hay intención. | `--ui-ink` y después `--color-border` |
|
|
69
|
+
| `--ui-rule` | Líneas dentro de una tabla. Sin definir dibuja solo los límites del encabezado y del pie; `0%` no dibuja ninguna; `100%` separa cada fila. | sin definir |
|
|
70
|
+
| `--ui-shadow-x` | Desplazamiento horizontal de la sombra. | `0px` |
|
|
71
|
+
| `--ui-shadow-y` | Desplazamiento vertical de la sombra. | `0px` |
|
|
72
|
+
| `--ui-shadow-blur` | Radio de desenfoque de la sombra. | `0px` |
|
|
73
|
+
| `--ui-shadow-spread` | Radio de extensión de la sombra. | `0px` |
|
|
74
|
+
| `--ui-shadow-inset` | La palabra clave `inset` para un anillo interior. | Vacío |
|
|
75
|
+
| `--ui-hover-shadow-x` | Desplazamiento horizontal de la sombra con hover. | `--ui-shadow-x` |
|
|
76
|
+
| `--ui-hover-shadow-y` | Desplazamiento vertical de la sombra con hover. | `--ui-shadow-y` |
|
|
77
|
+
| `--ui-active-shadow-x` | Desplazamiento horizontal de la sombra al pulsar. | `--ui-shadow-x` |
|
|
78
|
+
| `--ui-active-shadow-y` | Desplazamiento vertical de la sombra al pulsar. | `--ui-shadow-y` |
|
|
79
|
+
| `--ui-active-transform` | Transformación al pulsar. Se conserva con `prefers-reduced-motion`, que solo quita su transición. | `scale(0.97)` |
|
|
80
|
+
| `--ui-active-translate-x` | Distancia que recorre una pulsación hacia la profundidad del elemento; `-y` a su lado. Se escala como la sombra. | `0px` |
|
|
81
|
+
| `--ui-shadow-ink` | Porcentaje del color de la sombra tomado de la tinta de la intención. | `0%` |
|
|
82
|
+
| `--ui-halo-blur` | Desenfoque de un halo alrededor del elemento; `--ui-halo-spread` a su lado. La elevación no lo escala. | `0px` |
|
|
83
|
+
| `--ui-halo-ink` | La proporción del color de la intención en el halo, sobre nada. Sin definir, no hay halo. | Sin definir |
|
|
84
|
+
| `--ui-shadow-edge` | Se declara, aunque esté vacío, cuando la sombra es el borde del elemento y no su profundidad. Se lee por su presencia. | Sin definir |
|
|
85
|
+
| `--ui-elevation` | Multiplicador sin unidad sobre la geometría de la sombra. No se hereda. | `1` |
|
|
86
|
+
| `--ui-surface-shadow` | Sombra completa de varias capas, aceptada solo por las superficies. | Sin definir |
|
|
87
|
+
| `--ui-surface-ground` | Fondo sobre el que se apoya una superficie, o una tabla por defecto o `.soft`. | `--color-background` |
|
|
88
|
+
| `--ui-bg-alpha` | Multiplicador sobre cada relleno, incluido `.solid`. Ninguna estética incluida lo define. | `1` |
|
|
89
|
+
| `--ui-backdrop` | Filtro de fondo aceptado solo por las superficies y por una tabla por defecto o `.soft`. | `none` |
|
|
90
|
+
| `--ui-surface-image` | Una capa pintada sobre la placa de una superficie: cualquier valor de `background-image`. Solo superficies. | `none` |
|
|
91
|
+
| `--ui-hover-transform` | Transformación mientras un elemento interactivo tiene hover. | `none` |
|
|
92
|
+
| `--ui-clip` | Silueta estructural del componente. | `none` |
|
|
93
|
+
| `--ui-clip-tight` | Silueta compacta del componente. | `--ui-clip` |
|
|
94
|
+
| `--ui-focus-inset` | Grosor de la capa de foco interior. | Sin definir |
|
|
95
|
+
| `--ui-label-weight` | Grosor de la etiqueta de `.btn` (y, con `/native`, de un `<button>` sin clase) y de `.badge`. | Semibold en un botón, bold en un badge |
|
|
96
|
+
| `--ui-label-tracking` | Espaciado entre letras de la etiqueta. Sin definir, es `normal`, así que ni el espaciado de la página ni el de un contenedor llega a la etiqueta. | `normal` |
|
|
97
|
+
| `--ui-label-case` | `text-transform` de la etiqueta. | `none` en un botón; heredado en un badge |
|
|
98
|
+
| `--ui-label-shadow` | `text-shadow` de la etiqueta, escrito sin color para que tome el de la propia etiqueta. | `none` en un botón; heredado en un badge |
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<section style="--ui-corner: 0; --ui-border-width: 3px">
|
|
102
|
+
<button class="btn primary">Square and heavy</button>
|
|
103
|
+
<input class="ipt" placeholder="Matches" />
|
|
104
|
+
</section>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> **Contrato de los tokens de material**: los componentes los leen; las clases de estética y las sobrescrituras del consumidor los definen.
|
|
108
|
+
|
|
109
|
+
### Tamaño y patrón de las esquinas
|
|
110
|
+
|
|
111
|
+
La esquina escala con el elemento. `.p-xs` define un escalón de tamaño de `0.5`, `.sm` y `.p-sm` de `0.75`, y `.lg` y `.p-lg` de `1.25`. Cuando una clase de tamaño y una de relleno interior están en un mismo elemento, gana el escalón menor, así que `.lg.p-xs` es pequeño. `box` multiplica `--ui-corner` por el escalón, así que un botón pequeño toma una esquina pequeña y un bisel sigue siendo de 45 grados exactos. La profundidad sigue al escalón hacia abajo pero no hacia arriba: un botón `.p-xs` se apoya sobre la mitad de la sombra de su estética, y uno `.lg` sobre la sombra entera. Una pulsación que se mete en esa profundidad, indicada con `--ui-active-translate-x` y `-y`, recorre la misma distancia escalada, así que siempre termina a ras.
|
|
112
|
+
|
|
113
|
+
Qué esquinas toman la esquina es una elección aparte. `.cut-diagonal` conserva la superior izquierda y la inferior derecha y deja rectas las otras dos; `.cut-diagonal-reverse` conserva el otro par. Las dos definen `--ui-corner-tl`, `-tr`, `-br` y `-bl`, que también puedes definir tú: una hoja de dos esquinas con el aspecto por defecto, dos cortes en un control bajo `.cyber`. Una superficie bajo `.cyber` conserva la forma de superficie propia de la estética, a la que el patrón no llega, y un `--ui-radius` o `--ui-radius-surface` explícito ignora el escalón y el patrón.
|
|
114
|
+
|
|
115
|
+
### Líneas, capas y etiquetas
|
|
116
|
+
|
|
117
|
+
`--ui-line-style` llega a cada línea que dibuja un componente: el borde de la caja, el carril de progreso y los divisores y las líneas divisorias de las tablas. `--ui-rule-style` sobrescribe opcionalmente solo los divisores y las líneas divisorias de las tablas, sin cambiar el borde de la caja; sketch lo usa para sus detalles discontinuos. Una línea discontinua o punteada conserva su color, así que conserva su contraste. Una línea `double` necesita un grosor de 3px o más para dibujar dos líneas.
|
|
118
|
+
|
|
119
|
+
`--ui-halo-*` es luz y no profundidad: un resplandor en el propio color de intención del elemento. La elevación no lo escala, y `.flat` no lo quita. Solo aparece cuando su tinta está definida.
|
|
120
|
+
|
|
121
|
+
`--ui-surface-image` pone cualquier `background-image` sobre la placa de una superficie: tarjetas, paneles, alertas y tooltips, no controles. Quien lo define es responsable del contraste del texto que queda encima, y tu propio `background-image` en una superficie sigue ganando.
|
|
122
|
+
|
|
123
|
+
`--ui-label-*` trata la etiqueta de un botón o de un badge: grosor, espaciado entre letras, mayúsculas y una sombra de texto. Escribe la sombra sin color, como `0 0 6px`, para que tome el color de la propia etiqueta y no pueda reducir su contraste. Tus propias utilidades `font-*`, `tracking-*` y de mayúsculas siguen ganando. Una etiqueta no hereda el espaciado entre letras, así que una utilidad `tracking-*` en un contenedor deja sus botones y badges en `normal`; para espaciar todas las etiquetas de una región, define `--ui-label-tracking` en ella, que la heredan.
|
|
124
|
+
|
|
125
|
+
Con colores forzados, cada uno de estos dibuja su versión simple: una línea continua, sin halo, sin capa pintada y sin sombra de etiqueta. La silueta y el anillo de abajo también desaparecen. Los colores forzados eliminan todas las sombras de caja, así que `--ui-clip`, `--ui-clip-tight`, `--ui-border-max` y `--ui-shadow-edge` se anulan y un componente dibuja su borde real con `--ui-border-width`.
|
|
126
|
+
|
|
127
|
+
### Composición de forma y anillo
|
|
128
|
+
|
|
129
|
+
El recorte elimina los bordes, los outlines y las sombras exteriores. Una estética que usa un recorte puede reemplazar el borde con una sombra interior definiendo `--ui-shadow-inset` y las cuatro partes de la geometría de la sombra. Define `--ui-border-max: 0px` cuando ese anillo reemplaza el borde del componente. Los componentes que pueden recibir el foco recuperan el outline de foco recortado mediante `--ui-focus-inset`: una capa interior de ese grosor en `--focus-ring`, con una línea de 2px de `--color-background` dentro, para que el foco se siga viendo en un componente relleno con el propio color del anillo.
|
|
130
|
+
|
|
131
|
+
Un recorte no es la única forma de cortar una esquina. `--ui-corner-shape: bevel` dibuja la esquina que define el radio como un corte recto en lugar de un arco, y el borde, la sombra exterior, el outline de foco y el fondo desenfocado la siguen. Por eso un elemento biselado conserva su resplandor y su línea, mientras que uno recortado pierde los dos. `.cyber` lo usa. Los motores sin `corner-shape` lo ignoran y dibujan el radio redondo, así que una estética que bisela debería dejar recto su radio bajo `@supports not (corner-shape: bevel)`. Un bisel sobre un radio completo corta en puntas: un radio, un `.btn.pill` y todo lo que lea `--ui-radius-pill` se convierten en rombos o hexágonos con puntas.
|
|
132
|
+
|
|
133
|
+
`--ui-radius` acepta cualquier valor de `border-radius` y se usa tal cual, así que puede colocar la esquina por lado: `10px 0` corta solo la superior izquierda y la inferior derecha. Las esquinas pill y de chip son tokens aparte. Una esquina de chip sin definir calcula un pequeño valor por defecto a partir de `--ui-radius`, y después de `--ui-corner`, con `--radius-small` como tope; un `--ui-radius-tight` explícito se usa tal cual, incluso para un valor por esquina o elíptico. Por eso las sobrescrituras de las estéticas y del consumidor pueden dar a un chip una forma mayor o más irregular. `.btn.pill` toma `--ui-radius-pill` antes que los demás radios; bajo sketch toma un contorno de píldora irregular dibujado a mano cuyos extremos mantienen el mismo tamaño. Un `--ui-radius-pill` explícito en ese botón sigue ganando.
|
|
134
|
+
|
|
135
|
+
Declara `--ui-shadow-edge` cuando ese anillo _es_ el borde. Entonces el anillo toma el color del borde del elemento, que lleva el eje de borde como su alfa, así que `.edged` lo dibuja y `.edgeless` no: la misma respuesta que da un borde real. Sin él, el anillo se pinta en cada componente al que llega la estética y las clases de borde no tienen efecto. Usa en su lugar `--ui-shadow-ink` cuando la sombra es profundidad proyectada en la propia tinta de la intención, como una losa dura desplazada, que un elemento `.edgeless` sigue recibiendo.
|
|
136
|
+
|
|
137
|
+
El token se lee por su presencia, no por su valor: decláralo vacío para activar el anillo, e `initial` para volver a desactivarlo en una estética anidada dentro de otra que lo declara.
|
|
138
|
+
|
|
139
|
+
```css
|
|
140
|
+
.stepped {
|
|
141
|
+
--ui-clip: polygon(/* silueta estructural */);
|
|
142
|
+
--ui-clip-tight: none;
|
|
143
|
+
--ui-border-max: 0px;
|
|
144
|
+
--ui-shadow-inset: inset;
|
|
145
|
+
--ui-shadow-edge: ;
|
|
146
|
+
--ui-shadow-x: 0px;
|
|
147
|
+
--ui-shadow-y: 0px;
|
|
148
|
+
--ui-shadow-blur: 0px;
|
|
149
|
+
--ui-shadow-spread: 4px;
|
|
150
|
+
--ui-focus-inset: var(--focus-ring-width);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Las variables con el prefijo `--_` son salidas internas de la composición: `--_bg`, `--_fg`, `--_edge`, `--_fill`, `--_shadow` y los huecos de reposo `--_d-*` que un componente declara para que los lea `box`. No las definas ni las leas; solo las entradas `--ui-*` de arriba son públicas.
|
|
155
|
+
|
|
156
|
+
## Tokens de estética
|
|
157
|
+
|
|
158
|
+
Las [clases de estética](./aesthetics.md) incluidas definen los tokens de material por ti. Solo las estéticas con un token en la lista de abajo exponen un token propio. Ajusta el resto del comportamiento mediante los tokens de material compartidos de arriba. Los tokens de la lista solo están disponibles donde se importa la hoja de estilos de esa estética.
|
|
159
|
+
|
|
160
|
+
| Token | Estética | Propósito | Valor por defecto |
|
|
161
|
+
| --------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
162
|
+
| `--neo-offset` | `.neobrutalism` | Desplazamiento de la sombra dura y distancia que recorre la pulsación. | `4px` |
|
|
163
|
+
| `--glass-radius` | `.glass`, `.glass-liquid` | Radio de la esquina de control. `1rem` con `.glass-liquid`. | `0.75rem` |
|
|
164
|
+
| `--glass-radius-surface` | `.glass`, `.glass-liquid` | Radio de la esquina de superficie. `1.5rem` con `.glass-liquid`. | `1rem` |
|
|
165
|
+
| `--pixel-unit` | `.pixel` | Un píxel de la cuadrícula. El corte de la esquina y el anillo miden uno. | `4px` |
|
|
166
|
+
| `--font-pixel` | `.pixel` | Pila de fuentes pixeladas que aporta el consumidor. | Recurre a la pila monoespaciada |
|
|
167
|
+
| `--tile-radius` | `.chunky-tile` | Radio de la esquina, igual en controles y superficies. | `0.75rem` |
|
|
168
|
+
| `--tile-lift` | `.chunky-tile` | Profundidad de la barra de apoyo y distancia que recorre una pulsación. | `4px` |
|
|
169
|
+
| `--font-rounded` | `.chunky-tile` | Pila de fuentes redondeadas que aporta el consumidor. | Recurre a la pila de la página |
|
|
170
|
+
| `--cyber-cut` | `.cyber` | El corte en el tamaño por defecto, igual en controles y superficies; los controles lo escalan con el escalón. | `0.625rem` |
|
|
171
|
+
| `--cyber-shape` | `.cyber` | Dónde toman el corte los controles: cualquier valor de `border-radius`. | `<cut> 0` (superior izquierda, inferior derecha) |
|
|
172
|
+
| `--cyber-shape-surface` | `.cyber` | Dónde toman el corte las superficies: cualquier valor de `border-radius`. | `0 <cut>` (superior derecha, inferior izquierda) |
|
|
173
|
+
| `--cyber-glow` | `.cyber` | Desenfoque del resplandor. | `8px` |
|
|
174
|
+
| `--cyber-ink` | `.cyber` | Color neutro de la línea y del resplandor, donde ninguna intención define uno. | Tinta del tema (casi negro, casi blanco) |
|
|
175
|
+
| `--font-cyber` | `.cyber` | Pila de fuentes técnicas que aporta el consumidor. | Recurre a la pila monoespaciada |
|
|
176
|
+
| `--sketch-radius` | `.sketch` | Radio del contorno de los controles: cualquier valor de `border-radius`. | Contorno de caja irregular con variación entre hermanos |
|
|
177
|
+
| `--sketch-radius-surface` | `.sketch` | Radio del contorno de los contenedores de superficie: cualquier valor de `border-radius`. | Contorno cuadrado, irregular y marcado, con variación entre hermanos |
|
|
178
|
+
| `--sketch-radius-rounded` | `.sketch`, `.sketch-rounded` | Radio del contorno redondeado de los controles: un contorno elíptico expresivo con variación entre hermanos. | `26px 10px 24px 11px / 12px 23px 11px 20px` con variación entre hermanos |
|
|
179
|
+
| `--sketch-radius-surface-rounded` | `.sketch`, `.sketch-rounded` | Radio del contorno redondeado de los contenedores de superficie: un contorno elíptico expresivo con variación entre hermanos. | `38px 16px 36px 17px / 16px 34px 17px 32px` con variación entre hermanos |
|
|
180
|
+
| `--sketch-radius-pill` | `.sketch` | Radio del contorno de un botón pill: una píldora irregular dibujada a mano cuyos extremos mantienen el mismo tamaño. | `24px 16px 23px 17px / 17px 21px 16px 20px` con variación entre hermanos |
|
|
181
|
+
| `--font-sketch` | `.sketch` | Pila de fuentes manuscritas que aporta el consumidor. | Recurre a `cursive` |
|
|
182
|
+
|
|
183
|
+
Los controles de todas las estéticas llegan de la misma forma: cada control se _lee_ con su valor por defecto como respaldo de `var()` en lugar de declararse, así que se resuelve una sola vez en una variable privada en la propia clase de la estética (`--_pixel-unit`, `--_neo-offset`, `--_tile-radius`, `--_tile-lift`, etc.). Define un control en el elemento que lleva la clase de estética, o en cualquier ancestro, incluido `:root`:
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<section class="pixel" style="--pixel-unit: 6px">
|
|
187
|
+
<button class="btn primary">Chunkier</button>
|
|
188
|
+
</section>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```html
|
|
192
|
+
<html class="pixel" style="--pixel-unit: 6px">
|
|
193
|
+
<body>
|
|
194
|
+
<button class="btn primary">Also chunkier, set from the root</button>
|
|
195
|
+
</body>
|
|
196
|
+
</html>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Los controles y los tokens de material llegan en direcciones opuestas. Un control se lee una vez, en el elemento con la clase de estética, y el resultado se hereda. Así que define un control en ese elemento o en uno por encima; definido en un elemento dentro de la estética, no cambia nada, porque el valor ya se ha leído.
|
|
200
|
+
|
|
201
|
+
Cada componente lee `--ui-radius`, `--ui-radius-surface` y los demás tokens de material al dibujarse. Funcionan en el elemento en el que se definen y en todo lo que contiene, que es como redondeas una tarjeta de forma distinta a sus vecinas sin tocar el control. Fíjate en cuál lee cada componente: una superficie (`.card`, `.panel`, `.alert`) toma `--ui-radius-surface`, y un control como `.btn` o `.ipt` toma `--ui-radius`. `style="--ui-radius-surface: 0"` deja cuadrada una tarjeta; `--ui-radius` en esa tarjeta deja cuadrados los botones que contiene y la tarjeta sigue redondeada.
|
|
202
|
+
|
|
203
|
+
Las estéticas incluidas definen los tokens de material compartidos de arriba. Todas las estéticas incluidas definen `--ui-ink` para su línea neutra. Todas definen también `--ui-control-ink`: `.glass` y `.chunky-tile` con una línea propia, más intensa que la de sus superficies, y las demás con `--color-control-border`, ya que su tinta es casi negra o casi blanca y un checkbox en reposo con ese contorno parecería marcado. `.glass` define además `--ui-rule-ink`, para que las líneas de una tabla se lean sobre su placa; las demás lo anulan. Las clases de intención siguen sobrescribiendo los huecos de intención de cada componente.
|
|
204
|
+
|
|
205
|
+
Los mismos controles ajustan la [clase solo](./solo.md) de cada estética, que los lee en su propio elemento.
|
|
206
|
+
|
|
207
|
+
## Paleta generada
|
|
208
|
+
|
|
209
|
+
`@codenhub/styles/palette` es una hoja de estilos generada de colores fijos: para cada intención y presentación, el color de fondo, de texto y de borde que dibujaría un componente, como custom properties `--palette-*` planas. Es para el código que no puede cargar la hoja de estilos de este paquete pero quiere coincidir con ella, como una librería que tiene `@codenhub/styles` como peer opcional. Donde puedas cargar la hoja de estilos, usa los componentes.
|
|
210
|
+
|
|
211
|
+
**Los valores son una instantánea de los colores incluidos.** Se calcularon a partir del tema por defecto del paquete al hacer el build, y no cambian cuando sobrescribes un token. Si defines `--color-primary` con el color de tu marca, `--palette-primary-solid-bg` sigue siendo el casi negro incluido. El código que deba seguir a tu tema tiene que leer los tokens `--color-*`, lo que implica cargar `@codenhub/styles/theme`.
|
|
212
|
+
|
|
213
|
+
```css
|
|
214
|
+
@import "@codenhub/styles/palette";
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```css
|
|
218
|
+
.my-badge {
|
|
219
|
+
background: var(--palette-success-soft-bg);
|
|
220
|
+
color: var(--palette-success-soft-fg);
|
|
221
|
+
border-color: var(--palette-success-soft-edge);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Cada valor es un color final, nunca una referencia a otra variable, así que el archivo no necesita que se cargue nada más.
|
|
226
|
+
|
|
227
|
+
Nombres: `--palette-<intent>-<presentation>-<slot>`, donde `<intent>` es una de las siete intenciones publicadas (`neutral`, `primary`, `secondary`, `success`, `warning`, `destructive`, `info`) y `<presentation>` es `solid`, `soft` o `ghost`. `<slot>` es `bg`, `fg` o `edge`. Dos calificadores se añaden solo donde aplican:
|
|
228
|
+
|
|
229
|
+
- Un calificador de fondo, `page` o `subtle`, antes del hueco. Solo aparece en el `bg` y el `edge` de `.soft` y `.ghost`, porque un relleno `.solid` cubre su fondo y el color del texto nunca depende de él.
|
|
230
|
+
- Sin calificador es lo que dibujan `.badge` y `.btn`, sobre un fondo transparente: `--palette-success-soft-bg`.
|
|
231
|
+
- `page` es lo que dibuja `.alert`, sobre la página: `--palette-success-soft-page-bg`.
|
|
232
|
+
- `subtle` es lo que dibujan `.kbd`, `.code` y `.pre`, sobre el propio tono sutil de la intención: `--palette-success-soft-subtle-bg`.
|
|
233
|
+
|
|
234
|
+
Cada valor se lee del propio componente, así que incluye lo que el componente hace por su cuenta. Un `.alert`, `.kbd`, `.code` o `.pre` neutral conserva un relleno más discreto que un `.badge` neutral, y sus valores `neutral-soft-page` y `neutral-soft-subtle` lo reflejan. `.tooltip-bubble` no coincide con ninguno de los tres: sin intención se rellena con su propio tono de tooltip, y su borde es sólido en vez de atenuado.
|
|
235
|
+
|
|
236
|
+
- Un sufijo `-hover`, solo en `bg` y `edge`, porque el color del texto no cambia con hover: `--palette-success-soft-page-bg-hover`. `.alert`, `.kbd`, `.code` y `.pre` no tienen hover propio, así que sus valores de hover son lo que dibuja el componente cuando le añades `box-hover`.
|
|
237
|
+
|
|
238
|
+
Los valores claros se definen en `:root`. Los oscuros se aplican bajo `.dark`, `.theme-dark` o `[data-theme="dark"]` en el elemento o en uno por encima, los mismos selectores que usa el tema del paquete. Los valores claros también se aplican bajo `.light`, `.theme-light` y `[data-theme="light"]`, así que gana el tema explícito más cercano: una zona clara dentro de una oscura lee los valores claros.
|
|
239
|
+
|
|
240
|
+
El archivo no sigue `prefers-color-scheme`. El código que usa la paleta por sí sola ya cambia de tema por su cuenta, así que define una de esas clases o atributos.
|
|
241
|
+
|
|
242
|
+
Otros tres tokens no tienen intención, presentación, fondo ni hover: `--palette-border`, `--palette-surface` y `--palette-text`, valores fijos de `--color-border`, `--color-surface` y `--color-text`. Son para lo que no tiene color de intención, como el borde de un contenedor, el fondo de un diálogo y su texto.
|
|
243
|
+
|
|
244
|
+
## Variables de componente
|
|
245
|
+
|
|
246
|
+
Seis variables las lee un único componente y son entradas soportadas. Cualquier otra variable que declare un componente, como `--surface-padding`, `--field-gap`, `--switch-*`, `--table-*` o `--quote-*`, es interna y puede cambiar en cualquier versión.
|
|
247
|
+
|
|
248
|
+
| Variable | Elemento | Valor | Valor por defecto | Efecto | Dónde definirla |
|
|
249
|
+
| -------------------- | -------------- | ------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
250
|
+
| `--progress-value` | `.progress` | Un porcentaje, de `0%` a `100%` | `0%` | Ancho de la parte rellena. No se limita; un valor sin `%` no es válido y se muestra vacío. | En la barra o en cualquier elemento que la rodee. |
|
|
251
|
+
| `--progress-color` | `.progress` | Un color | El color de la intención | Color de la parte rellena y del brillo de `.active`. | En la barra o en cualquier elemento que la rodee. |
|
|
252
|
+
| `--progress-surface` | `.progress` | Un color | El color de la intención con el relleno de la presentación: 12% por defecto | Color del carril. | En la barra o en cualquier elemento que la rodee. |
|
|
253
|
+
| `--progress-edge` | `.progress` | Un color | El color de borde de la intención con el borde de la presentación: ninguno por defecto | Color del borde del carril. Solo se ve donde el carril tiene grosor de borde, como con `.edged`. | En la barra o en cualquier elemento que la rodee. |
|
|
254
|
+
| `--input-group-gap` | `.input-group` | Una longitud | `0.5rem` | Espacio entre el control y su icono o texto. | En el propio `.input-group`. El grupo declara el valor por defecto, así que un valor en un padre se ignora. |
|
|
255
|
+
| `--tooltip-linger` | `.tooltip` | Un tiempo | `300ms` | Cuánto tiempo se queda la burbuja después de que el puntero sale del disparador. | En el propio `.tooltip`. El contenedor declara el valor por defecto, así que un valor en un padre se ignora. |
|
|
256
|
+
|
|
257
|
+
```html
|
|
258
|
+
<div class="progress" role="meter" aria-label="Storage used" aria-valuemin="0" aria-valuemax="100" aria-valuenow="92" style="--progress-value: 92%; --progress-color: var(--color-warning)"></div>
|
|
259
|
+
|
|
260
|
+
<div class="input-group" style="--input-group-gap: 0">
|
|
261
|
+
<span>app.example.com/u/</span>
|
|
262
|
+
<input class="ipt" id="profile-url" aria-label="Profile address" />
|
|
263
|
+
</div>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Los ejemplos en contexto están en [Feedback → Mostrar el progreso](./feedback.md#mostrar-el-progreso), [Formularios → Añadir un icono o un prefijo fijo](./forms.md#añadir-un-icono-o-un-prefijo-fijo) y [Tooltips → Hover, permanencia y Escape](./tooltips.md#hover-permanencia-y-escape).
|
|
267
|
+
|
|
268
|
+
## Helpers de composición
|
|
269
|
+
|
|
270
|
+
Para construir un componente que el paquete no incluye, como un control segmentado o un chip de filtro, compónlo con las mismas clases con las que están construidos los componentes del paquete. Con CSS compilado, escríbelas como clases; con el código fuente de Tailwind, también puedes usarlas con `@apply`, junto con las clases de intención, presentación, elevación y esquina, que en `/tw` también son utilidades: `@apply box box-hover neutral soft edgeless`. Para darle en cambio una receta fija a un componente del paquete, como un botón primario pequeño y suave, consulta [Tailwind CSS v4 → Construir tus propios componentes con `@apply`](../integrating/tailwind.md#construir-tus-propios-componentes-con-apply).
|
|
271
|
+
|
|
272
|
+
| Clase | Lo que le da a un elemento |
|
|
273
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
274
|
+
| `box` | La caja pintada: fondo, color de texto, borde, esquina, sombra, el material de la estética, el anillo de foco y el aspecto deshabilitado. Lee la intención, la presentación, la estética y la elevación. |
|
|
275
|
+
| `box-hover` | El color de hover, para algo que se pulsa y no algo en lo que se escribe. Añádelo con `box`. |
|
|
276
|
+
| `box-active` | La pulsación: una ligera reducción, o la pulsación propia de la estética. Añádelo con `box`. |
|
|
277
|
+
| `surface` | `box` con los valores por defecto de una superficie: sin relleno y con borde, la esquina de superficie y el fondo, el desenfoque y la sombra de superficie de la estética, como en una tarjeta. |
|
|
278
|
+
| `text-control` | `box` con los valores por defecto de un campo de texto: sin relleno y con borde, las reglas de relleno limitado y de borde, el color del placeholder, un borde que cambia con hover y con foco, y el estado no válido. |
|
|
279
|
+
|
|
280
|
+
Chips de filtro para la lista de miembros, uno pulsado y otro no:
|
|
281
|
+
|
|
282
|
+
```html
|
|
283
|
+
<button class="box box-hover box-active neutral soft edgeless" type="button" aria-pressed="true" style="padding: 0.25rem 0.75rem; border-radius: 999px">Admins</button>
|
|
284
|
+
|
|
285
|
+
<button class="box box-hover box-active neutral ghost edgeless" type="button" aria-pressed="false" style="padding: 0.25rem 0.75rem; border-radius: 999px">Owners</button>
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`box` no lee `aria-pressed`, así que el chip pulsado parece pulsado solo porque tiene `.soft`. Cuando tu código cambie `aria-pressed`, cambia con él la clase de presentación: `.soft` cuando está pulsado, `.ghost` cuando no.
|
|
289
|
+
|
|
290
|
+
Qué darle a cada uno:
|
|
291
|
+
|
|
292
|
+
- **`box` necesita una clase de relleno y una de borde.** No tiene valores por defecto propios, así que sin `.solid`, `.soft` o `.ghost` y sin `.edged` o `.edgeless`, en el elemento o en un contenedor, no dibuja nada. `surface` y `text-control` tienen valores por defecto y funcionan solos.
|
|
293
|
+
- **Nombra la intención en `box`.** Un elemento `box` toma la intención del elemento más cercano a su alrededor que tenga una, a diferencia de los componentes del paquete. Ponle `.neutral` o una clase de intención. `surface` y `text-control` son neutrales salvo que el elemento tenga una clase de intención, como los componentes.
|
|
294
|
+
- **`@apply` lleva el helper completo.** `@utility my-field { @apply text-control; }` obtiene lo mismo que `class="text-control"`: la intención neutral y el borde del campo, `.soft`, `.solid` y `.edgeless` en el elemento, y el aspecto inválido con `aria-invalid="true"`. `@apply surface` es neutral de la misma forma. Una clase de intención que definas tú debe ser CSS plano o una utilidad para colorear un elemento así, no una regla en `@layer components`.
|
|
295
|
+
- **Escribe como utilidad la clase que aplica un helper.** Lo que copia `@apply` cae en la [capa de cascada](../setup.md#capas-de-cascada) de la regla en la que está escrito. Los helpers son utilidades, y `@utility my-field` mantiene tu clase en `utilities` junto a ellos, así que tus otras utilidades siguen alcanzándola. Escrita como CSS plano, `.my-field { @apply text-control; }` queda sin capa, y todo lo que declara el helper gana sobre cualquier utilidad en el elemento: una clase de intención que escribiste como utilidad deja el campo neutral, y `mt-8` no mueve un diálogo. Tu propio CSS sin capa sigue compitiendo con él, por especificidad y después por orden en el código, como dos reglas sin capa cualesquiera.
|
|
296
|
+
- **Un diálogo funciona con `@apply surface`.** Un `<dialog>` cerrado con tu propia clase que hace `@apply surface` permanece oculto, y uno abierto se centra, como con `.card`. Ocultar uno cerrado gana sobre una utilidad de display como `flex`; un margen que pongas sigue colocando uno abierto, y una utilidad de margen también lo hace cuando tu clase es una utilidad.
|
|
297
|
+
- **El tamaño y el espaciado son cosa tuya.** Ninguno de los helpers define el relleno interior, el ancho ni el alto; `text-control` no define la altura de 2.5rem que añade `.ipt`.
|
|
298
|
+
- **También el comportamiento y la semántica.** Usa un `<button>`, un `<input>` o un `<a href>` reales, o añade tú el rol y el manejo del teclado, y define estados como `aria-pressed` o `aria-invalid`. `box` dibuja el aspecto deshabilitado para `disabled`, `.disabled`, `aria-disabled="true"` y `data-disabled`, pero solo el atributo `disabled` impide la interacción.
|
|
299
|
+
|
|
300
|
+
No definas ni leas las variables con el prefijo `--_` que estos helpers usan internamente; cambian entre versiones.
|
|
301
|
+
|
|
302
|
+
## Siguiente paso
|
|
303
|
+
|
|
304
|
+
[Contenido y layout](./content-and-layout.md) enumera los helpers de layout, la escala tipográfica, las superficies, las tablas y los chips de contenido.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Feedback
|
|
3
|
+
description: Un botón que indica que está guardando, alertas, badges, placeholders de carga y barras de progreso, y lo que tu código debe mantener sincronizado con ellos.
|
|
4
|
+
order: 3
|
|
5
|
+
source: ce1defb7385bc009988d903fd895bcb7edb5ab3b
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Feedback
|
|
9
|
+
|
|
10
|
+
El formulario de perfil se puede enviar, pero nada le dice al usuario qué ha pasado. Esta página añade el feedback de la pantalla: un botón Guardar que muestra que está trabajando, una alerta cuando el guardado sale bien, un badge en la tarjeta del plan, un placeholder mientras carga el perfil y barras para el uso de almacenamiento y para una exportación de datos. El paquete dibuja cada uno de ellos; tu código decide cuándo aparecen, actualiza sus valores y se asegura de que los lectores de pantalla se enteren.
|
|
11
|
+
|
|
12
|
+
## Mostrar que el formulario se está guardando
|
|
13
|
+
|
|
14
|
+
No hay una clase de carga. Un botón que está guardando es un botón deshabilitado con un icono que gira:
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<button class="btn primary" type="submit" disabled>
|
|
18
|
+
<i class="ic-lucide-loader-circle ic-anim-spin" aria-hidden="true"></i>
|
|
19
|
+
Saving…
|
|
20
|
+
</button>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
El spinner viene de `@codenhub/icons`, que este paquete no carga. Cárgalo una vez, como muestra [Botones → Cargar los iconos](./buttons.md#cargar-los-iconos); con CSS compilado es así:
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
@import "@codenhub/icons";
|
|
27
|
+
@import "@codenhub/icons/lucide";
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`ic-anim-spin` hace girar el icono y se detiene cuando el usuario pide al sistema movimiento reducido. La familia animada `svg-spinners` de `@codenhub/icons` es distinta: su dibujo sigue moviéndose con esa preferencia. Cualquiera de los dos iconos toma el color de texto del botón.
|
|
31
|
+
|
|
32
|
+
Deshabilitar el botón evita que un segundo clic envíe el formulario dos veces. Mantener o reemplazar el texto depende de ti; el paquete no tiene forma de ocultarlo. Un cambio en el texto de un botón no se anuncia de forma fiable, así que comunica el resultado a quienes usan lector de pantalla con un mensaje de estado, como hace la siguiente sección.
|
|
33
|
+
|
|
34
|
+
## Confirmar el resultado con una alerta
|
|
35
|
+
|
|
36
|
+
Cuando el guardado sale bien, muestra una alerta encima del formulario:
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<div class="alert success" role="status">Profile saved.</div>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`role="status"` hace que los lectores de pantalla anuncien el texto de forma educada, después de lo que estén leyendo. Para un error sobre el que el usuario debe actuar, usa `role="alert"`, que interrumpe:
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div class="alert destructive" role="alert">Your changes were not saved. Check your connection and try again.</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Los lectores de pantalla anuncian una región live cuando cambia su contenido, así que renderiza la región vacía al cargar la página y pon el mensaje dentro, en lugar de insertar un nuevo elemento de alerta que ya contenga el texto. El paquete no añade rol, temporización ni botón de cierre; eso es cosa tuya.
|
|
49
|
+
|
|
50
|
+
Una alerta es una fila con una separación de 0.75rem, así que un icono colocado antes del mensaje queda espaciado automáticamente. `.alert-icon` da a un icono un tamaño de 1.25rem y lo alinea con la primera línea de texto:
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<div class="alert warning" role="status">
|
|
54
|
+
<i class="alert-icon ic-lucide-triangle-alert" aria-hidden="true"></i>
|
|
55
|
+
Your card expires next month. Update it to keep your plan.
|
|
56
|
+
</div>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Funciona cualquier elemento de icono: una clase de un conjunto de iconos, un `<svg>` en línea o un `<img>`. `@codenhub/icons` define el tamaño de sus glifos en una regla que ninguna clase puede superar, así que `.alert-icon` también define el `--ic-size` de ese conjunto. Para cambiar el tamaño del icono de una alerta, escribe tu propia regla que defina `width`, `height` y, para `@codenhub/icons`, `--ic-size`.
|
|
60
|
+
|
|
61
|
+
### Cómo se ven las alertas
|
|
62
|
+
|
|
63
|
+
Sin clase de presentación, una alerta es soft y con borde: un tinte claro de su intención, texto del color de la intención y un borde. Las clases de presentación lo cambian como en cualquier componente, por ejemplo `.alert.primary.solid` para un banner relleno.
|
|
64
|
+
|
|
65
|
+
Una alerta sin intención es una excepción. No tiene tinte en reposo; usa `--color-foreground`, el tono de fondo discreto un paso por encima de la página, igual que una `.card.soft` o un `.panel` neutros. Una alerta con `.primary`, `.secondary`, `.success`, `.warning`, `.destructive` o `.info` conserva su tinte. Aquí solo cuentan esas seis clases: una alerta con una clase de intención que hayas definido tú se trata como si no tuviera intención; consulta [Temas → Tu propia intención](./theming.md#tu-propia-intención).
|
|
66
|
+
|
|
67
|
+
## Etiquetar el plan con un badge
|
|
68
|
+
|
|
69
|
+
Un badge es una pequeña píldora para un estado o un recuento:
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<section class="card soft primary stack tight" aria-labelledby="plan-title">
|
|
73
|
+
<div class="cluster between">
|
|
74
|
+
<h2 class="text-label" id="plan-title">Current plan</h2>
|
|
75
|
+
<span class="badge success">Active</span>
|
|
76
|
+
</div>
|
|
77
|
+
<p class="text-title-sm">Team, billed yearly</p>
|
|
78
|
+
</section>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Un badge es soft y sin borde por defecto, y acepta las mismas clases de intención y presentación que un botón: `.badge.warning` para "Pago pendiente", `.badge.info.solid` para un "Nuevo" relleno. A diferencia de una alerta, un badge sin intención conserva su tinte claro, porque no tiene borde, y sin el tinte se perdería en el texto que lo rodea.
|
|
82
|
+
|
|
83
|
+
Un badge neutro que no es `.solid`, como un contador dentro de un `.btn.primary`, imprime en el color de texto del componente con relleno en el que está, así que sigue siendo legible sobre ese relleno. Un badge con intención conserva su propio color.
|
|
84
|
+
|
|
85
|
+
## Mostrar un placeholder mientras carga
|
|
86
|
+
|
|
87
|
+
Mientras la tarjeta de perfil espera los datos, muestra bloques grises donde irá el texto:
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<section class="card stack" aria-busy="true" aria-labelledby="profile-title">
|
|
91
|
+
<h2 class="text-title-sm" id="profile-title">Profile</h2>
|
|
92
|
+
<p class="visually-hidden">Loading your profile…</p>
|
|
93
|
+
<div class="stack tight" aria-hidden="true">
|
|
94
|
+
<div class="skeleton" style="height: 2.5rem"></div>
|
|
95
|
+
<div class="skeleton" style="width: 60%"></div>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Un `.skeleton` ocupa el ancho de su contenedor y mide al menos 1rem de alto. No tiene tamaño ni forma propios: usa un elemento de bloque como un `<div>`, y ajusta su ancho y su alto al contenido al que sustituye. Un elemento en línea vacío como `<span class="skeleton">` no tiene tamaño y no aparece.
|
|
101
|
+
|
|
102
|
+
Un skeleton acepta una intención pero ignora la presentación. Sin intención, es un gris claro teñido por el color del texto que lo rodea. Muestra un brillo en movimiento que se detiene cuando el usuario pide movimiento reducido.
|
|
103
|
+
|
|
104
|
+
Marca los bloques con `aria-hidden="true"`, porque no significan nada para un lector de pantalla. Indica en su lugar con texto que el contenido está cargando, como hace el párrafo visualmente oculto, y quita `aria-busy` cuando el contenido esté en su sitio.
|
|
105
|
+
|
|
106
|
+
## Mostrar el progreso
|
|
107
|
+
|
|
108
|
+
La tarjeta de almacenamiento muestra cuánto espacio se usa, y el botón "Exportar datos antes" de la zona de peligro inicia una exportación que tarda un rato. Las dos son barras `.progress`:
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<div class="progress" role="meter" aria-label="Storage used" aria-valuemin="0" aria-valuemax="100" aria-valuenow="48" aria-valuetext="48 GB of 100 GB" style="--progress-value: 48%"></div>
|
|
112
|
+
|
|
113
|
+
<div class="progress primary" role="progressbar" aria-label="Export progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="20" style="--progress-value: 20%"></div>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`--progress-value` es el ancho de la parte rellena, como porcentaje del carril. Vale 0% si no se define.
|
|
117
|
+
|
|
118
|
+
- **Escríbelo con `%`.** `--progress-value: 48` sin unidad no es un ancho válido, y la barra se muestra vacía.
|
|
119
|
+
- **No se limita ni se comprueba nada.** Por encima del 100%, el relleno se corta al final del carril y parece lleno; un valor negativo tampoco es un ancho válido. Mantén el valor entre 0% y 100% en tu código.
|
|
120
|
+
- **El valor visual y el valor anunciado son independientes.** El ancho de la barra viene de `--progress-value`; lo que anuncia un lector de pantalla viene de `aria-valuenow`. El paquete no los conecta, así que actualiza los dos a la vez.
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
function setExportProgress(bar, percent) {
|
|
124
|
+
const value = Math.min(100, Math.max(0, Math.round(percent)));
|
|
125
|
+
bar.classList.remove("indeterminate");
|
|
126
|
+
bar.style.setProperty("--progress-value", `${value}%`);
|
|
127
|
+
bar.setAttribute("aria-valuenow", String(value));
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Cuando no sabes cuánto ha avanzado el trabajo, como mientras se prepara la exportación, usa `.indeterminate`. Una barra de aproximadamente un tercio del ancho del carril lo recorre de principio a fin una y otra vez, y `--progress-value` se ignora. Quita `aria-valuenow`, porque no hay un valor conocido que anunciar:
|
|
132
|
+
|
|
133
|
+
```html
|
|
134
|
+
<div class="progress primary indeterminate" role="progressbar" aria-label="Preparing export"></div>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`.active` añade un brillo sobre el carril de una barra determinada, para mostrar que el trabajo sigue en marcha entre actualizaciones. Las dos animaciones se detienen cuando el usuario pide movimiento reducido; una barra indeterminada queda entonces en reposo con su relleno al principio.
|
|
138
|
+
|
|
139
|
+
Con la [hoja de estilos sin clases](../setup.md#html-sin-clases), un elemento `<progress>` simple se dibuja como `.progress`: lleno hasta su `value`, o con el barrido indeterminado cuando no tiene `value`. Anuncia su valor por sí mismo, así que no necesita `aria-valuenow`.
|
|
140
|
+
|
|
141
|
+
### Cómo se ven las barras de progreso
|
|
142
|
+
|
|
143
|
+
El relleno es el color de la intención con toda su intensidad, o `currentColor` sin intención. El carril es soft y sin borde por defecto: un tinte claro sin borde.
|
|
144
|
+
|
|
145
|
+
El carril por defecto es tenue. Frente a la página mide aproximadamente de 1.1:1 a 1.3:1, por debajo del 3:1 que WCAG 1.4.11 pide a las partes de un gráfico necesarias para entenderlo. Cuando importa la extensión del carril, usa `.ghost.edged` con una clase de intención, que dibuja un contorno alrededor en el color de la intención. Sin intención, el contorno es un gris claro que mide menos de 3:1; [Accesibilidad → Contornos de progreso](../accessibility.md#contornos-de-progreso) tiene las mediciones y lo que puedes hacer con una barra neutra. `.solid` no está soportado en el carril, porque el relleno y el carril serían del mismo color. `.ghost.edgeless` se renderiza, pero deja el carril sin un marco visible.
|
|
146
|
+
|
|
147
|
+
Para cambiar los colores del relleno, del carril o de su borde sin cambiar la intención, define `--progress-color`, `--progress-surface` o `--progress-edge` en la barra o en cualquier elemento que la rodee. Estas variables y `--progress-value` aparecen en [Personalización → Variables de componente](./customizing.md#variables-de-componente).
|
|
148
|
+
|
|
149
|
+
## Animación que no se detiene
|
|
150
|
+
|
|
151
|
+
Los skeletons, los brillos de `.active`, las barras indeterminadas y los spinners se animan mientras estén en la página. El paquete detiene sus propias animaciones cuando el usuario pide al sistema movimiento reducido, pero ese no es el único requisito. WCAG 2.2.2 pide que el movimiento que empieza automáticamente, dura más de cinco segundos y se muestra junto a otro contenido pueda ser pausado, detenido u ocultado por el usuario, salvo que el movimiento sea esencial.
|
|
152
|
+
|
|
153
|
+
Un indicador de carga que se muestra mientras el usuario no puede hacer otra cosa, y cuya ausencia lo confundiría, cuenta como esencial. Un brillo o un spinner que sigue moviéndose junto al contenido con el que el usuario está trabajando, como un brillo decorativo de "en vivo" en una tarjeta, no. Quítalos en cuanto terminen su trabajo, o dale al usuario un control que los detenga.
|
|
154
|
+
|
|
155
|
+
## Siguiente paso
|
|
156
|
+
|
|
157
|
+
La pantalla ya informa de lo que está haciendo. [Tooltips](./tooltips.md) añade un breve texto de ayuda junto a un campo de formulario.
|