@codenhub/styles 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +18 -16
- package/README.es.md +61 -0
- package/README.md +27 -22
- package/README.pt-BR.md +61 -0
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +2 -2
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/dist/tw/aesthetics/chunky-tile.css +120 -62
- package/dist/tw/aesthetics/cyber.css +102 -40
- package/dist/tw/aesthetics/glass.css +371 -19
- package/dist/tw/aesthetics/index.css +2 -1
- package/dist/tw/aesthetics/neobrutalism.css +121 -33
- package/dist/tw/aesthetics/pixel.css +111 -16
- package/dist/tw/aesthetics/sketch.css +100 -28
- package/dist/tw/box.css +69 -28
- package/dist/tw/components/button.css +35 -14
- package/dist/tw/components/feedback.css +61 -58
- package/dist/tw/components/form.css +255 -142
- package/dist/tw/components/index.css +4 -9
- package/dist/tw/components/surface.css +80 -68
- package/dist/tw/components/tooltip.css +75 -41
- package/dist/tw/elevation.css +14 -22
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +35 -27
- package/dist/tw/native.css +22 -12
- package/dist/tw/palette.css +14 -11
- package/dist/tw/presentation.css +16 -30
- package/dist/tw/reset.css +36 -43
- package/dist/tw/surface.css +11 -12
- package/dist/tw/theme.css +87 -103
- package/dist/tw/utilities/content.css +311 -200
- package/dist/tw/utilities/layout.css +41 -37
- package/docs/accessibility.md +104 -58
- package/docs/changelog/0.1.1.md +1 -0
- package/docs/changelog/0.2.0.md +1 -0
- package/docs/changelog/0.3.0.md +1 -0
- package/docs/changelog/0.4.0.md +1 -0
- package/docs/changelog/0.5.0.md +8 -3
- package/docs/changelog/0.6.0.md +53 -0
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +150 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +104 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +47 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +78 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +115 -0
- package/docs/es/setup.md +180 -0
- package/docs/es/usage/aesthetics.md +276 -0
- package/docs/es/usage/buttons.md +131 -0
- package/docs/es/usage/composing.md +164 -0
- package/docs/es/usage/content-and-layout.md +215 -0
- package/docs/es/usage/customizing.md +298 -0
- package/docs/es/usage/feedback.md +153 -0
- package/docs/es/usage/forms.md +231 -0
- package/docs/es/usage/index.md +29 -0
- package/docs/es/usage/solo.md +84 -0
- package/docs/es/usage/theming.md +296 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +89 -21
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +18 -13
- package/docs/integrating/nextjs.md +4 -5
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +29 -8
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +114 -0
- package/docs/pt-BR/accessibility.md +150 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +104 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +47 -0
- package/docs/pt-BR/integrating/nextjs.md +67 -0
- package/docs/pt-BR/integrating/svelte.md +45 -0
- package/docs/pt-BR/integrating/tailwind.md +78 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +115 -0
- package/docs/pt-BR/setup.md +180 -0
- package/docs/pt-BR/usage/aesthetics.md +276 -0
- package/docs/pt-BR/usage/buttons.md +131 -0
- package/docs/pt-BR/usage/composing.md +164 -0
- package/docs/pt-BR/usage/content-and-layout.md +215 -0
- package/docs/pt-BR/usage/customizing.md +298 -0
- package/docs/pt-BR/usage/feedback.md +153 -0
- package/docs/pt-BR/usage/forms.md +231 -0
- package/docs/pt-BR/usage/index.md +29 -0
- package/docs/pt-BR/usage/solo.md +84 -0
- package/docs/pt-BR/usage/theming.md +296 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +134 -91
- package/docs/usage/aesthetics.md +102 -65
- package/docs/usage/buttons.md +108 -40
- package/docs/usage/composing.md +105 -92
- package/docs/usage/content-and-layout.md +159 -127
- package/docs/usage/customizing.md +112 -43
- package/docs/usage/feedback.md +135 -70
- package/docs/usage/forms.md +184 -99
- package/docs/usage/index.md +18 -14
- package/docs/usage/solo.md +83 -0
- package/docs/usage/theming.md +260 -119
- package/docs/usage/tooltips.md +103 -42
- package/llms-full.txt +2465 -1272
- package/llms.txt +25 -17
- package/package.json +28 -35
- package/dist/tw/components/loader.css +0 -117
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Temas
|
|
3
|
+
description: Modo claro y oscuro, reemplazar la paleta con los colores de marca, definir una intención propia, y cada token de color, intención, base y fuente con su valor por defecto.
|
|
4
|
+
order: 5
|
|
5
|
+
source: ef2e6095c03e7765cb650f720aca10403a70930c
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Temas
|
|
9
|
+
|
|
10
|
+
La pantalla de ajustes funciona y tiene el aspecto por defecto del paquete: acciones casi negras sobre una página casi blanca. Esta página la hace tuya. Cubre el modo claro y oscuro, después reemplaza el color principal por un color de marca en los dos modos, y después define una intención que el paquete no incluye. La segunda mitad es la referencia de consulta: cada token de color, intención, base y fuente, con su valor por defecto.
|
|
11
|
+
|
|
12
|
+
## Claro y oscuro
|
|
13
|
+
|
|
14
|
+
De entrada, la página sigue al sistema operativo: clara cuando el sistema del usuario es claro, oscura cuando es oscuro. No tienes que hacer nada para eso.
|
|
15
|
+
|
|
16
|
+
Para que el usuario elija, pon un selector de tema en el elemento raíz:
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<html data-theme="dark">
|
|
20
|
+
…
|
|
21
|
+
</html>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Tema | Selectores equivalentes |
|
|
25
|
+
| ------ | ------------------------------------------------ |
|
|
26
|
+
| Claro | `.light`, `.theme-light`, `[data-theme="light"]` |
|
|
27
|
+
| Oscuro | `.dark`, `.theme-dark`, `[data-theme="dark"]` |
|
|
28
|
+
|
|
29
|
+
Una pantalla de ajustes con la opción "Sistema / Claro / Oscuro" quita el atributo para Sistema y lo pone para las otras dos.
|
|
30
|
+
|
|
31
|
+
Cómo se resuelve:
|
|
32
|
+
|
|
33
|
+
- Un selector de tema define la propiedad CSS `color-scheme` y nada más. Cada token de color contiene a la vez su valor claro y su valor oscuro, mediante `light-dark()`, y el `color-scheme` del elemento elige uno.
|
|
34
|
+
- `color-scheme` se hereda, así que un selector aplica el tema a todo lo que contiene. Un selector en cualquier elemento aplica el tema a esa parte de la página: una barra lateral oscura en una página clara es `<aside class="dark">`.
|
|
35
|
+
- Gana el selector más cercano, a cualquier profundidad. Una tarjeta `.light` dentro de una página `.dark` es clara.
|
|
36
|
+
- Sin selector, la raíz tiene `color-scheme: light dark`, que sigue al sistema.
|
|
37
|
+
- Pon un solo tema en cada elemento. Si un elemento lleva a la vez un selector claro y uno oscuro, gana el oscuro, pero no confíes en ello.
|
|
38
|
+
- Definir tú mismo `color-scheme` en un elemento funciona igual, porque es lo único que lee la paleta. También aplica el tema a partes nativas como las barras de desplazamiento y el interior de los controles de formulario.
|
|
39
|
+
|
|
40
|
+
Cada color de componente viene de un token o de `currentColor`, así que los componentes siguen el tema sin reglas propias de modo oscuro. Las marcas que dibuja el paquete, como el tick del checkbox y la flecha del select, también usan `currentColor`. Los iconos y las imágenes que añadas son tuyos para adaptarlos al tema.
|
|
41
|
+
|
|
42
|
+
`light-dark()` funciona desde Chrome 123, Safari 17.5 y Firefox 120. El paquete en su conjunto necesita Firefox 128; consulta [Configuración inicial → Requisitos](../setup.md#requisitos).
|
|
43
|
+
|
|
44
|
+
### La variante `dark:`
|
|
45
|
+
|
|
46
|
+
Con los puntos de entrada de código fuente de Tailwind (`/tw`), el paquete reemplaza la variante `dark:` de Tailwind para que tus propias utilidades sigan el mismo tema que los tokens. Una utilidad `dark:` se aplica bajo un selector oscuro explícito en el elemento o en un ancestro, o bajo una preferencia oscura del sistema cuando ningún ancestro define un tema:
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<html>
|
|
50
|
+
<body>
|
|
51
|
+
<p class="dark:text-white">Follows the system preference</p>
|
|
52
|
+
<div class="light">
|
|
53
|
+
<p class="dark:text-white">Stays light: this part of the page chose a theme</p>
|
|
54
|
+
</div>
|
|
55
|
+
</body>
|
|
56
|
+
</html>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Se diferencia de los tokens en un caso: un tema explícito anidado dentro del opuesto. Un elemento `.light` dentro de uno `.dark` tiene tokens claros, porque gana el `color-scheme` más cercano. Pero `dark:` coincide por selector, y `.dark *` coincide con cada elemento dentro de `.dark`, así que una utilidad `dark:` dentro de ese elemento `.light` se sigue aplicando. Si una página usa a la vez tokens y utilidades `dark:`, no anides temas opuestos.
|
|
60
|
+
|
|
61
|
+
Los puntos de entrada compilados no definen una variante `dark:`; no tienen un build de Tailwind en el que definirla.
|
|
62
|
+
|
|
63
|
+
## Cambiar el color de marca
|
|
64
|
+
|
|
65
|
+
El color principal es casi negro en una página clara y casi blanco en una oscura. Para convertirlo en un color de marca, reemplaza la familia principal completa: el color base y sus cuatro acompañantes. Cada uno contiene un valor claro y uno oscuro:
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
:root {
|
|
69
|
+
--color-primary: light-dark(#0f766e, #2dd4bf);
|
|
70
|
+
--color-primary-contrast: light-dark(#ffffff, #042f2e);
|
|
71
|
+
--color-primary-hover: light-dark(#115e59, #5eead4);
|
|
72
|
+
--color-primary-subtle: light-dark(#ccfbf1, #134e4a);
|
|
73
|
+
--color-primary-strong: light-dark(#115e59, #5eead4);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Para qué sirve cada uno:
|
|
78
|
+
|
|
79
|
+
| Token | Rol | Comprobación |
|
|
80
|
+
| -------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
81
|
+
| `--color-primary` | El relleno de un botón primario sólido, de un toggle marcado, del relleno de un progreso. | El texto en `-contrast` sobre él llega a 4.5:1. |
|
|
82
|
+
| `--color-primary-contrast` | Texto e iconos sobre un relleno primario completo. | Ver arriba. |
|
|
83
|
+
| `--color-primary-hover` | El relleno bajo el puntero. | El texto en `-contrast` sobre él sigue llegando a 4.5:1. |
|
|
84
|
+
| `--color-primary-subtle` | El tinte claro detrás de los componentes soft. | El texto en `-strong` sobre él llega a 4.5:1. |
|
|
85
|
+
| `--color-primary-strong` | Texto, iconos y bordes donde el relleno no es completo: soft y ghost. | Llega a 4.5:1 sobre la página y sobre `-subtle`. |
|
|
86
|
+
|
|
87
|
+
Los valores turquesa de arriba miden, en modo claro y oscuro: 5.47:1 y 7.77:1 para el relleno y su texto, 7.27:1 y 13.38:1 para el tono strong sobre la página, y 6.73:1 y 6.41:1 para el tono strong sobre el tinte subtle.
|
|
88
|
+
|
|
89
|
+
Reemplaza la familia completa. Cambiar solo `--color-primary` deja a sus acompañantes en el antiguo casi negro, así que un badge primario soft mantiene un texto gris y un botón con hover parpadea en negro. El anillo de foco se dibuja a partir de `--color-primary` con un 64% de opacidad, así que sigue al color de marca sin necesidad de cambiarlo.
|
|
90
|
+
|
|
91
|
+
El mismo patrón funciona con cada familia de [Tokens de color](#tokens-de-color): `--color-accent` es lo que lee `.secondary`, y las cuatro familias de estado son `success`, `warning`, `destructive` e `info`. Defínelas en `:root` para toda la página, o en cualquier elemento para cambiar el tema solo de lo que contiene.
|
|
92
|
+
|
|
93
|
+
Los valores tienen que ser colores completos: hex, `rgb()`, `oklch()` o una variable que hayas declarado tú. Las variables de la paleta de Tailwind, como `--color-teal-700`, existen en un build `/tw`, a partir de tu tema de Tailwind, pero el CSS compilado solo declara los colores de la paleta que usa el propio paquete. Con CSS compilado, una referencia a cualquier otra variable de la paleta está vacía, y el color que alimenta se pierde.
|
|
94
|
+
|
|
95
|
+
## Tu propia intención
|
|
96
|
+
|
|
97
|
+
El paquete incluye seis intenciones: `.primary`, `.secondary`, `.success`, `.warning`, `.destructive` e `.info`, y la de por defecto, `.neutral`. Para añadir una, como un color "Beta" para funciones en vista previa, escribe una clase que defina los siete huecos de intención. Usa colores completos, con `light-dark()` para todo lo que cambia entre temas:
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
.beta {
|
|
101
|
+
--intent-color: #7c3aed;
|
|
102
|
+
--intent-contrast: #ffffff;
|
|
103
|
+
--intent-hover: #6d28d9;
|
|
104
|
+
--intent-strong: light-dark(#5b21b6, #c4b5fd);
|
|
105
|
+
--intent-subtle: light-dark(#ede9fe, #4c1d95);
|
|
106
|
+
--intent-border: light-dark(#7c3aed, #a78bfa);
|
|
107
|
+
--intent-fill-max: 100%;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<span class="badge beta">Beta</span> <button class="btn beta" type="button">Try the new editor</button>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Estos valores miden 5.7:1 para el blanco sobre el relleno, 7.1:1 para el blanco sobre el color de hover, 8.61:1 (claro) y 10.72:1 (oscuro) para el tono strong sobre la página, y 7.57:1 y 5.93:1 para el tono strong sobre el tinte subtle.
|
|
116
|
+
|
|
117
|
+
**Define todos los huecos**, incluido `--intent-fill-max`. Cada componente restablece los siete huecos a los valores neutros en su propia raíz, así que un hueco que omitas conserva el valor neutro, y sin `--intent-fill-max: 100%` tu intención solo se rellena hasta el 20%, como la neutra. Lo que hace cada hueco está en [Tokens de intención](#tokens-de-intención).
|
|
118
|
+
|
|
119
|
+
La clase funciona en todo lo que acepta una intención: botones, badges, campos y toggles, tarjetas sólidas y ghost, barras de progreso, skeletons, burbujas de tooltip y el resto. Algunos comportamientos están escritos para los seis nombres incorporados, y una intención personalizada no los obtiene:
|
|
120
|
+
|
|
121
|
+
- **Un reposo discreto, sin tinte.** Una `.card.soft`, un `.panel` y una `.alert` neutros reposan sobre el tono de fondo discreto, y solo reconocen una intención por las seis clases incorporadas. `.card.soft.beta`, `.panel.beta` y `.alert.beta` se dibujan como el neutro: el tono de fondo discreto en lugar de un tinte violeta. Tu intención sigue coloreando su texto y su borde.
|
|
122
|
+
- **El tinte de los chips.** Una tecla o un bloque de código `.beta` muestra tu tinte `--intent-subtle`, pero no el 12% adicional de `--intent-color` que una intención incorporada añade encima.
|
|
123
|
+
- **Clases solo.** Una [clase solo](./solo.md) como `.neobrutalism-solo` solo toma una intención de las seis clases incorporadas, así que `.neobrutalism-solo.beta` se dibuja neutro.
|
|
124
|
+
|
|
125
|
+
Si los necesitas, hay dos caminos:
|
|
126
|
+
|
|
127
|
+
- **Cambia en su lugar el tema de una intención incorporada.** Define la familia `--color-info` (u otra) con tus colores, como en [Cambiar el color de marca](#cambiar-el-color-de-marca), y escribe `.info`. Todo, incluidos los casos anteriores, funciona entonces. El coste es que el cambio llega a cada `.info` dentro del elemento en el que lo defines, así que defínelo en el elemento más reducido que funcione, y no lo hagas con una intención que la página ya usa con su propio significado.
|
|
128
|
+
- **Píntalo tú.** Escribe tu propio CSS para ese componente concreto, como un `background-color` en `.panel.beta`.
|
|
129
|
+
|
|
130
|
+
> **La intención no se hereda.** Cada componente restablece los huecos de intención en su propia raíz, así que un contenedor `.success` no cambia el color de un botón destructivo que contenga. Pon la clase de intención en el elemento que muestra el color.
|
|
131
|
+
|
|
132
|
+
## Tokens de color
|
|
133
|
+
|
|
134
|
+
Cada token de color contiene un valor claro y uno oscuro mediante `light-dark()`; un solo valor significa que los dos temas lo usan. Los nombres de paleta como `neutral-950` son la paleta por defecto de Tailwind, que el CSS compilado del paquete declara para los colores que usa.
|
|
135
|
+
|
|
136
|
+
Cada fila es un punto de sobrescritura: defínelo en `:root` para cambiar el tema de la página, o en cualquier elemento para cambiar el de lo que contiene. Las filas `-hover`, `-subtle`, `-strong` y `-contrast` son acompañantes del color base de su familia y no lo siguen, así que cambia la familia completa. La familia `text` no tiene fila `-subtle`: la intención neutra toma su tono subtle de `--color-surface`.
|
|
137
|
+
|
|
138
|
+
| Token | Claro, oscuro | Propósito |
|
|
139
|
+
| ------------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| `--color-primary` | `neutral-950`, `neutral-50` | Relleno de `.primary`. |
|
|
141
|
+
| `--color-primary-contrast` | `neutral-50`, `neutral-950` | Texto e iconos sobre un relleno primario completo. |
|
|
142
|
+
| `--color-primary-hover` | `neutral-700`, `neutral-200` | Relleno primario bajo el puntero. |
|
|
143
|
+
| `--color-primary-subtle` | `neutral-200`, `neutral-900` | Tinte primario detrás de los componentes soft. |
|
|
144
|
+
| `--color-primary-strong` | `neutral-900`, `neutral-100` | Texto, iconos y bordes primarios donde el relleno no es completo. |
|
|
145
|
+
| `--color-accent` | `neutral-600`, `neutral-400` | Relleno de `.secondary`. |
|
|
146
|
+
| `--color-accent-contrast` | `neutral-50`, `neutral-950` | Texto e iconos sobre un relleno secundario completo. |
|
|
147
|
+
| `--color-accent-hover` | `neutral-700`, `neutral-300` | Relleno secundario bajo el puntero. |
|
|
148
|
+
| `--color-accent-subtle` | `neutral-100`, `neutral-800` | Tinte secundario detrás de los componentes soft. |
|
|
149
|
+
| `--color-accent-strong` | `neutral-800`, `neutral-200` | Texto, iconos y bordes secundarios donde el relleno no es completo. |
|
|
150
|
+
| `--color-border` | `neutral-400`, `neutral-700` | Borde de las superficies neutras, tablas, divisores y teclas. |
|
|
151
|
+
| `--color-border-hover` | `neutral-600`, `neutral-500` | Borde bajo el puntero. |
|
|
152
|
+
| `--color-control-border` | `neutral-500` | Borde en reposo de los controles de texto y toggles neutros, dibujado a una fracción en los controles de texto. |
|
|
153
|
+
| `--color-background` | `neutral-50`, `neutral-950` | La página. |
|
|
154
|
+
| `--color-foreground` | `neutral-100`, `neutral-900` | El tono de fondo discreto un paso por encima de la página: tarjetas soft, paneles y alertas neutros. |
|
|
155
|
+
| `--color-surface` | `neutral-200`, `neutral-800` | Un paso más: superficies anidadas y atenuadas, y el tinte de la intención neutra. |
|
|
156
|
+
| `--color-text` | `neutral-950`, `neutral-50` | Texto del cuerpo, y el color de la intención neutra. |
|
|
157
|
+
| `--color-text-secondary` | `neutral-700`, `neutral-400` | Texto secundario, como `.hint`. |
|
|
158
|
+
| `--color-text-contrast` | `neutral-50`, `neutral-950` | Texto sobre un relleno completo de `--color-text`, como la marca de un toggle neutro marcado. |
|
|
159
|
+
| `--color-text-hover` | `neutral-700`, `neutral-200` | Color neutro bajo el puntero. |
|
|
160
|
+
| `--color-text-strong` | `neutral-900`, `neutral-100` | Texto, iconos y bordes neutros donde el relleno no es completo. |
|
|
161
|
+
| `--color-tooltip` | `white`, `neutral-700` | Fondo de una burbuja de tooltip sin intención. Elegido para cada tema de modo que se perciba elevado en los dos. |
|
|
162
|
+
| `--color-tooltip-contrast` | `neutral-900`, `neutral-100` | Texto sobre `--color-tooltip`. |
|
|
163
|
+
| `--color-success` | `emerald-700` | Relleno de `.success`. |
|
|
164
|
+
| `--color-success-contrast` | `neutral-50` | Texto sobre un relleno success completo: 5.14:1. |
|
|
165
|
+
| `--color-success-hover` | `#007552`, `#008e66` | Relleno success bajo el puntero. |
|
|
166
|
+
| `--color-success-subtle` | `emerald-100`, `emerald-900` | Tinte success detrás de los componentes soft. |
|
|
167
|
+
| `--color-success-strong` | `emerald-800`, `emerald-300` | Texto, iconos y bordes success donde el relleno no es completo. |
|
|
168
|
+
| `--color-warning` | `amber-600` | Relleno de `.warning`. |
|
|
169
|
+
| `--color-warning-contrast` | `neutral-950` | Texto sobre un relleno warning completo: casi negro, no el color de la página. 6.19:1. |
|
|
170
|
+
| `--color-warning-hover` | `#d46700`, `#e78300` | Relleno warning bajo el puntero. |
|
|
171
|
+
| `--color-warning-subtle` | `amber-100`, `amber-900` | Tinte warning detrás de los componentes soft. |
|
|
172
|
+
| `--color-warning-strong` | `amber-800`, `amber-300` | Texto, iconos y bordes warning donde el relleno no es completo. |
|
|
173
|
+
| `--color-destructive` | `rose-700` | Relleno de `.destructive`. |
|
|
174
|
+
| `--color-destructive-contrast` | `neutral-50` | Texto sobre un relleno destructive completo: 5.78:1. |
|
|
175
|
+
| `--color-destructive-hover` | `#c00036`, `#d1054b` | Relleno destructive bajo el puntero. |
|
|
176
|
+
| `--color-destructive-subtle` | `rose-100`, `rose-900` | Tinte destructive detrás de los componentes soft. |
|
|
177
|
+
| `--color-destructive-strong` | `rose-800`, `rose-300` | Texto, iconos y bordes destructive donde el relleno no es completo. |
|
|
178
|
+
| `--color-info` | `indigo-600` | Relleno de `.info`. |
|
|
179
|
+
| `--color-info-contrast` | `neutral-50` | Texto sobre un relleno info completo: 6.19:1. |
|
|
180
|
+
| `--color-info-hover` | `#4b36e9`, `#5e4ff9` | Relleno info bajo el puntero. |
|
|
181
|
+
| `--color-info-subtle` | `indigo-100`, `indigo-900` | Tinte info detrás de los componentes soft. |
|
|
182
|
+
| `--color-info-strong` | `indigo-800`, `indigo-300` | Texto, iconos y bordes info donde el relleno no es completo. |
|
|
183
|
+
|
|
184
|
+
Los cambios de tema van en estos valores, no en reglas de componente que comprueban el tema.
|
|
185
|
+
|
|
186
|
+
## Tokens de intención
|
|
187
|
+
|
|
188
|
+
Una clase de intención define estos siete huecos, y los componentes los leen. Como todos los componentes leen los mismos siete nombres, una clase que define los siete funciona como intención, como muestra [Tu propia intención](#tu-propia-intención).
|
|
189
|
+
|
|
190
|
+
| Token | Propósito |
|
|
191
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
192
|
+
| `--intent-color` | El color base de la intención, del que está hecho un relleno. |
|
|
193
|
+
| `--intent-contrast` | Texto sobre un relleno completo de `--intent-color`. |
|
|
194
|
+
| `--intent-hover` | El color base bajo el puntero. |
|
|
195
|
+
| `--intent-strong` | La intención como texto, icono o borde dondequiera que el relleno no sea completo. |
|
|
196
|
+
| `--intent-subtle` | El tinte claro detrás de los componentes soft y de los carriles de progreso. La neutra usa `--color-surface`. |
|
|
197
|
+
| `--intent-border` | Color de línea. Sin intención es el `--ui-ink` de la estética y, si no, `--color-border`; los controles de texto y los toggles leen `--ui-control-ink`, después `--ui-ink` y después `--color-control-border`, y las tablas leen primero `--ui-rule-ink`. |
|
|
198
|
+
| `--intent-fill-max` | Hasta dónde puede llegar un relleno de esta intención. `100%` para todas las intenciones excepto la neutra. |
|
|
199
|
+
|
|
200
|
+
`--intent-color` e `--intent-strong` no son intercambiables. El color base se elige para rellenar con él; el tono strong se elige para leerse sobre la página. Un componente soft o ghost imprime el tono strong, y por eso un warning soft se lee en amber-800 mientras que uno sólido se rellena con amber-600.
|
|
201
|
+
|
|
202
|
+
El tono strong también tiene que seguir siendo reconociblemente de su propio matiz. En una página oscura, el tono `-100` de cada familia es un tinte pálido casi sin color en tamaños pequeños: un badge success soft y uno destructive soft se leerían los dos como blancos. Por eso los tonos strong oscuros son `-300`, y los tintes bajo ellos son `-900`, que mide 5.0:1 o más dondequiera que un relleno parcial contenga texto, y más de 9:1 sobre la página.
|
|
203
|
+
|
|
204
|
+
`--intent-border` existe para que un borde neutro siga siendo el gris discreto de los bordes y no el color del texto. Todo lo que dibuja una línea lo lee: bordes de los controles, líneas divisorias de las tablas, divisores, teclas y barras de las citas.
|
|
205
|
+
|
|
206
|
+
`--intent-fill-max` existe para la intención neutra, cuyo color es el propio color de texto de la página. Todas las demás intenciones son un matiz, legible como tinte pálido al 12% y saturado al 100%; un gris rellenado al 100% es un bloque negro o blanco, lo más llamativo de la página para la intención que no significa nada en particular. La neutra se queda en `20%`, así que `.solid` le da un gris discreto que sigue estando un paso más allá de `.soft`. El hover suma su paso por encima del tope, así que un relleno limitado sigue intensificándose bajo el puntero.
|
|
207
|
+
|
|
208
|
+
El color del texto sigue al relleno. `--intent-contrast` es el color de texto para un relleno completo; impreso sobre una quinta parte de uno, sería blanco sobre gris claro. Así que el texto de contraste solo aparece cuando el relleno pasa de la mitad, y llega a toda su intensidad con un relleno completo; por debajo, un componente imprime `--intent-strong`. Por tanto, un neutro limitado imprime el tono strong. Un estado que levanta el tope a propósito, como un checkbox marcado, llega a un relleno completo e imprime el color de contraste.
|
|
209
|
+
|
|
210
|
+
## Tokens base
|
|
211
|
+
|
|
212
|
+
Los tokens base definen el layout, la forma, el movimiento, el foco, la profundidad y el apilamiento. Sobrescríbelos en `:root`, o en un elemento para lo que contiene.
|
|
213
|
+
|
|
214
|
+
Las cuatro sombras `--elevation-*` son para elementos a los que das estilo tú. Son independientes de las clases `.flat`, `.raised` y `.floating`, que escalan la sombra propia de un componente y no dibujan nada hasta que una estética o una de esas clases pide profundidad; consulta [Composición → Elevación](./composing.md#elevación). Las dos usan los pesos ninguno, pequeño, mediano y grande, pero una es un valor fijo y la otra escala partes de la sombra, así que no siempre se ven igual.
|
|
215
|
+
|
|
216
|
+
| Token | Valor por defecto | Propósito |
|
|
217
|
+
| -------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
218
|
+
| `--font-default` | `"Segoe UI", system-ui, sans-serif` | Fuente de la página. Consulta [Fuentes](#fuentes). |
|
|
219
|
+
| `--container-narrow` | `48rem` | Ancho de `.section-content.narrow`. |
|
|
220
|
+
| `--container-max` | `80rem` | Ancho de `.section-content`. |
|
|
221
|
+
| `--container-wide` | `90rem` | Ancho de `.section-content.wide`. |
|
|
222
|
+
| `--layout-gutter` | `clamp(1rem, 4vw, 2rem)` | Relleno lateral de `.section`, que crece con la ventana. |
|
|
223
|
+
| `--layout-section-block` | `clamp(4rem, 9vw, 7rem)` | Relleno superior e inferior de `.section`, que crece con la ventana. |
|
|
224
|
+
| `--layout-gap` | `1rem` | Separación de `.view`, `.stack`, `.cluster` y `.auto-grid`. |
|
|
225
|
+
| `--layout-grid-min` | `16rem` | Columna más estrecha de `.auto-grid`. |
|
|
226
|
+
| `--radius-small` | `0.25rem` | Esquina de los chips pequeños: `.kbd` y `.code`. |
|
|
227
|
+
| `--radius-control` | `0.5rem` | Esquina de botones, campos y burbujas de tooltip. |
|
|
228
|
+
| `--radius-surface` | `0.875rem` | Esquina de tarjetas, paneles y alertas. |
|
|
229
|
+
| `--control-height` | `2.5rem` | Altura mínima de un botón por defecto y de un control de texto. |
|
|
230
|
+
| `--border-width` | `1px` | Grosor del borde. |
|
|
231
|
+
| `--elevation-color` | `rgb(15 23 42 / 0.08)` en claro, `rgb(0 0 0 / 0.55)` en oscuro | El color de sombra que usan las cuatro elevaciones. Más intenso en una página oscura, donde una sombra ligera no se vería. |
|
|
232
|
+
| `--elevation-none` | `none` | Sin sombra. |
|
|
233
|
+
| `--elevation-sm` | `0 1px 2px`, `0 1px 3px` | Una sombra ligera para tus propias superficies, como una tarjeta. |
|
|
234
|
+
| `--elevation-md` | `0 4px 6px -1px`, `0 2px 4px -2px` | Una sombra para tus propios elementos elevados, como un menú desplegable. |
|
|
235
|
+
| `--elevation-lg` | `0 20px 25px -5px`, `0 8px 10px -6px` | Una sombra para tus propias capas superpuestas, como un diálogo modal. |
|
|
236
|
+
| `--focus-ring` | `--color-primary` con un 64% de opacidad | Color del anillo de foco del teclado. |
|
|
237
|
+
| `--focus-ring-offset` | Sin definir | Distancia del anillo al elemento. Sin definir, el anillo queda sobre el borde del elemento con cualquier estética. |
|
|
238
|
+
| `--focus-ring-width` | `3px` | Grosor del anillo de foco del teclado. |
|
|
239
|
+
| `--motion-duration-fast` | `120ms` | El hover de una fila de tabla. |
|
|
240
|
+
| `--motion-duration-normal` | `200ms` | Transiciones de color, borde, sombra y pulsación, marcas de los toggles y la burbuja del tooltip. |
|
|
241
|
+
| `--motion-duration-slow` | `400ms` | Cambios de valor del progreso, y la base del ciclo de brillo del skeleton y del progreso. |
|
|
242
|
+
| `--motion-ease` | `cubic-bezier(0.2, 0, 0, 1)` | Curva de aceleración de todas las transiciones. |
|
|
243
|
+
| `--z-popover` | `40` | Orden de apilamiento de las burbujas de tooltip. Úsalo para tus propios popovers, para que se apilen igual. |
|
|
244
|
+
| `--breakpoint-xs` | `30rem` | El breakpoint adaptable `xs:`. Solo en un build `/tw`; los puntos de entrada compilados no lo declaran. |
|
|
245
|
+
|
|
246
|
+
Cada sombra `--elevation-*` está formada por las partes indicadas, cada una en `--elevation-color`. El paso de hover que intensifica un relleno bajo el puntero es un token de presentación, `--hover-step`; consulta [Personalización](./customizing.md#tokens-de-presentación).
|
|
247
|
+
|
|
248
|
+
## Fuentes
|
|
249
|
+
|
|
250
|
+
El paquete no incluye archivos de fuente ni hace peticiones de red. Cada token de fuente nombra fuentes ya instaladas en el dispositivo del lector hasta que aportes las tuyas.
|
|
251
|
+
|
|
252
|
+
| Token | Lo lee | Sin tu valor |
|
|
253
|
+
| ---------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
254
|
+
| `--font-default` | El reset, en `html` y `body`. Los botones y los controles de formulario lo heredan. | `"Segoe UI", system-ui, sans-serif` |
|
|
255
|
+
| `--font-mono` | Los helpers de contenido `kbd`, `code` y `pre`, y `<kbd>`, `<code>` y `<pre>` con `/native` | `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`. Con `/tw`, el valor de tu tema de Tailwind. |
|
|
256
|
+
| `--font-pixel` | [`.pixel`](./aesthetics.md#pixel) y `.pixel-solo` | No declarado. Recurre a una pila monoespaciada. |
|
|
257
|
+
| `--font-rounded` | [`.chunky-tile`](./aesthetics.md#chunky-tile) y `.chunky-tile-solo` | No declarado. Recurre a `--font-default` y después a una pila sans-serif. |
|
|
258
|
+
| `--font-cyber` | [`.cyber`](./aesthetics.md#cyber) y `.cyber-solo` | No declarado. Recurre a una pila monoespaciada. |
|
|
259
|
+
| `--font-sketch` | [`.sketch`](./aesthetics.md#sketch) y `.sketch-solo` | No declarado. Recurre a la familia `cursive` de la plataforma. |
|
|
260
|
+
|
|
261
|
+
`--font-default` solo llega a la página a través del reset, que incluyen `@codenhub/styles`, `/native`, `/tw`, `/tw/native` y `/tw/reset`. Con `/theme` o `/components` solos, define tú mismo `font-family` en `body`. Los tokens de las estéticas los lee la propia clase de la estética, así que funcionan con cualquier punto de entrada.
|
|
262
|
+
|
|
263
|
+
Para usar una fuente web, cárgala como cargas cualquier fuente y después nómbrala en el token. Define el token en `:root` para toda la página, o en cualquier elemento para esa parte:
|
|
264
|
+
|
|
265
|
+
```html
|
|
266
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
267
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
268
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&display=swap" />
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
```css
|
|
272
|
+
:root {
|
|
273
|
+
--font-default: "Inter", system-ui, sans-serif;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Una fuente alojada por ti se declara con `@font-face` y se nombra de la misma forma:
|
|
278
|
+
|
|
279
|
+
```css
|
|
280
|
+
@font-face {
|
|
281
|
+
font-family: "Pixelify Sans";
|
|
282
|
+
src: url("/fonts/pixelify-sans.woff2") format("woff2");
|
|
283
|
+
font-weight: 400 700;
|
|
284
|
+
font-display: swap;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
:root {
|
|
288
|
+
--font-pixel: "Pixelify Sans", monospace;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Carga los pesos de 400 a 700, y 800 para `--font-rounded`: los componentes definen `font-weight` de 400 a 700, y `.chunky-tile` pone sus etiquetas en 800. Un navegador al que le falta un peso lo simula engrosando el regular, lo que emborrona una fuente pixelada o manuscrita. Termina siempre la pila con una familia genérica, como `sans-serif` o `monospace`, para que el texto se siga renderizando mientras carga la fuente o si falla.
|
|
293
|
+
|
|
294
|
+
## Siguiente paso
|
|
295
|
+
|
|
296
|
+
La pantalla tiene tus colores en los dos temas. [Estéticas](./aesthetics.md) cambia de qué está hecha: contornos negros gruesos, vidrio esmerilado, píxeles y más.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tooltips
|
|
3
|
+
description: Ayuda de campo que se abre con hover y con foco, cómo conectarla para los lectores de pantalla y la tecla Escape, y dónde queda recortado un tooltip.
|
|
4
|
+
order: 4
|
|
5
|
+
source: ea0dd81935063e3e02f0b4d84e51fafab0511cc3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Tooltips
|
|
9
|
+
|
|
10
|
+
El switch "Perfil público" de la pantalla de ajustes merece una breve explicación: qué se vuelve visible cuando está activado. Esta página añade junto a él un botón de ayuda que muestra un tooltip con hover y con el foco del teclado. El CSS muestra, oculta y dibuja el mensaje; tú lo conectas con su disparador para los lectores de pantalla, añades la tecla Escape y compruebas que nada a su alrededor lo recorte.
|
|
11
|
+
|
|
12
|
+
## Un tooltip de ayuda
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<div class="cluster tight">
|
|
16
|
+
<label class="cluster tight">
|
|
17
|
+
<input class="switch primary" type="checkbox" role="switch" name="public-profile" />
|
|
18
|
+
Public profile
|
|
19
|
+
</label>
|
|
20
|
+
<span class="tooltip">
|
|
21
|
+
<button class="tooltip-icon" type="button" aria-label="About public profiles" aria-describedby="public-profile-help">?</button>
|
|
22
|
+
<span class="tooltip-bubble" role="tooltip" id="public-profile-help">Anyone with the link can see your name, photo, and public projects.</span>
|
|
23
|
+
</span>
|
|
24
|
+
</div>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Las tres partes:
|
|
28
|
+
|
|
29
|
+
- `.tooltip` envuelve el disparador y el mensaje. Posiciona el mensaje y no pinta nada por sí mismo.
|
|
30
|
+
- `.tooltip-bubble` es el mensaje. Es un elemento real, así que puede tener un `id` al que apunte el disparador.
|
|
31
|
+
- `.tooltip-icon` es un pequeño disparador redondo, para un mensaje que no tiene otra cosa a la que asociarse. Cualquier elemento que pueda recibir el foco puede ser el disparador: envuelve un `.btn` existente en `.tooltip` y conserva su propio aspecto.
|
|
32
|
+
|
|
33
|
+
Conéctalos tú: un `id` en la burbuja, `aria-describedby` en el disparador apuntando a ese `id` y `role="tooltip"` en la burbuja. Así un lector de pantalla lee el mensaje como la descripción del disparador. El CSS no puede crear esta conexión, y sin ella el mensaje es solo visual.
|
|
34
|
+
|
|
35
|
+
El disparador tiene que poder recibir el foco, como un `<button>`, para que quienes usan el teclado lleguen al mensaje. La burbuja se abre cuando cualquier elemento dentro de `.tooltip` tiene el foco, así que también se abre después de un clic con el ratón en el disparador.
|
|
36
|
+
|
|
37
|
+
## Posición
|
|
38
|
+
|
|
39
|
+
La burbuja se abre encima de su disparador, centrada en horizontal, con una separación de 0.5rem. Pon `data-tooltip-position` en `.tooltip` para elegir otro lado:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<span class="tooltip" data-tooltip-position="bottom">
|
|
43
|
+
<button class="btn ghost sm" type="button" aria-describedby="renewal-help">Renews 12 March 2027</button>
|
|
44
|
+
<span class="tooltip-bubble" role="tooltip" id="renewal-help">Your card is charged on this date.</span>
|
|
45
|
+
</span>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| `data-tooltip-position` | Burbuja |
|
|
49
|
+
| ----------------------- | ---------------------------------------------------- |
|
|
50
|
+
| _ninguno_ o `"top"` | Encima del disparador, centrada. |
|
|
51
|
+
| `"bottom"` | Debajo del disparador, centrada. |
|
|
52
|
+
| `"left"` | A la izquierda del disparador, centrada en vertical. |
|
|
53
|
+
| `"right"` | A la derecha del disparador, centrada en vertical. |
|
|
54
|
+
|
|
55
|
+
Una burbuja es tan ancha como su texto, hasta 18rem, y a partir de ahí el texto salta de línea.
|
|
56
|
+
|
|
57
|
+
### Dónde queda recortado un tooltip
|
|
58
|
+
|
|
59
|
+
La burbuja se posiciona solo con CSS, en el lado que elegiste. Nada mide la página: no se desplaza para quedarse dentro de la ventana, no cambia al otro lado cuando no hay espacio y no pasa a la capa superior de la página. Eso tiene tres consecuencias:
|
|
60
|
+
|
|
61
|
+
- **Un contenedor con scroll o con recorte la corta.** Un ancestro con `overflow: hidden`, `auto` o `scroll` recorta la burbuja en su borde. La tabla de claves de API de la pantalla de ajustes está dentro de un `.table-wrap`, que tiene scroll, así que un tooltip superior en la primera fila queda recortado en la parte de arriba del contenedor. Subir el `z-index` no ayuda: cambia sobre qué se pinta la burbuja, no si el contenedor la recorta.
|
|
62
|
+
- **El borde de la ventana la corta.** Un tooltip superior en la primera línea de una página, o uno a la derecha cerca del borde derecho, se sale de la pantalla.
|
|
63
|
+
- **Izquierda y derecha son lados físicos.** En una página de derecha a izquierda, `"left"` sigue significando el lado izquierdo de la pantalla.
|
|
64
|
+
|
|
65
|
+
Qué hacer:
|
|
66
|
+
|
|
67
|
+
- Elige un lado con espacio: en la primera fila de una tabla, usa `data-tooltip-position="bottom"`.
|
|
68
|
+
- Saca el disparador del tooltip del contenedor que recorta, o quita el `overflow` de un contenedor que no lo necesita.
|
|
69
|
+
- Si la posición del disparador no se puede saber de antemano, como en una lista con scroll o en un panel redimensionable, usa una librería de posicionamiento o el componente de popover de tu framework, que pueden medir y cambiar de lado. Puedes seguir dando a su elemento de mensaje las clases `.tooltip-bubble` para el aspecto, pero entonces mostrar, ocultar y posicionar, como se describe en esta página, lo hace esa librería, no `.tooltip`.
|
|
70
|
+
|
|
71
|
+
## Hover, permanencia y Escape
|
|
72
|
+
|
|
73
|
+
WCAG 1.4.13 pide tres cosas al contenido que aparece con hover o con foco. El paquete resuelve dos:
|
|
74
|
+
|
|
75
|
+
- **Se puede pasar el puntero por encima.** Cuando el puntero sale del disparador, la burbuja se queda durante `--tooltip-linger` (300ms) y después se desvanece, para que el puntero pueda cruzar la separación hasta ella. Sigue abierta mientras el puntero está encima. Una burbuja cerrada tiene `visibility: hidden`, así que nunca captura el puntero.
|
|
76
|
+
- **Persistente.** Sigue abierta hasta que el puntero y el foco se van.
|
|
77
|
+
- **Descartable.** El usuario tiene que poder cerrarla sin mover el puntero ni el foco, normalmente con Escape. El CSS no puede escuchar una tecla, así que esta parte es tuya.
|
|
78
|
+
|
|
79
|
+
Para cambiar el tiempo de permanencia, define `--tooltip-linger` en el elemento `.tooltip`, por ejemplo `style="--tooltip-linger: 500ms"`. El contenedor declara su propio valor por defecto, así que un valor definido en un padre de `.tooltip` no tiene efecto. Mantenlo lo bastante largo para que el puntero llegue a la burbuja. Es una de las seis [variables públicas de componente](./customizing.md#variables-de-componente).
|
|
80
|
+
|
|
81
|
+
Para Escape, escribe `data-state="closed"` en `.tooltip`: oculta la burbuja aunque tenga hover o foco. Quita el atributo solo cuando tanto el puntero como el foco hayan salido del tooltip, para que el siguiente hover o foco lo vuelva a abrir. Si lo quitas antes, mientras el disparador todavía tiene el foco, el mensaje vuelve a aparecer sin que el usuario haga nada.
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
for (const tooltip of document.querySelectorAll(".tooltip")) {
|
|
85
|
+
let pointerInside = tooltip.matches(":hover");
|
|
86
|
+
|
|
87
|
+
tooltip.addEventListener("pointerenter", () => {
|
|
88
|
+
pointerInside = true;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
tooltip.addEventListener("pointerleave", () => {
|
|
92
|
+
pointerInside = false;
|
|
93
|
+
if (!tooltip.contains(document.activeElement)) tooltip.removeAttribute("data-state");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
tooltip.addEventListener("focusout", (event) => {
|
|
97
|
+
const focusStaysInside = tooltip.contains(event.relatedTarget);
|
|
98
|
+
if (!focusStaysInside && !pointerInside) tooltip.removeAttribute("data-state");
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
document.addEventListener("keydown", (event) => {
|
|
103
|
+
if (event.key !== "Escape") return;
|
|
104
|
+
for (const tooltip of document.querySelectorAll(".tooltip:hover, .tooltip:focus-within")) {
|
|
105
|
+
tooltip.dataset.state = "closed";
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`data-state="open"` hace lo contrario: muestra la burbuja sin hover ni foco, para un mensaje que debe quedarse visible, o para una prueba o una captura de pantalla.
|
|
111
|
+
|
|
112
|
+
## Cómo se ve la burbuja
|
|
113
|
+
|
|
114
|
+
Sin clase de intención, la burbuja usa `--color-tooltip`, un fondo elegido para cada tema: casi blanco en una página clara y gris medio en una oscura, con `--color-tooltip-contrast` como color de texto. El casi blanco mide solo 1.04:1 frente a una página clara, así que la burbuja también dibuja un borde fino, y el `.edgeless` de un contenedor no puede quitarlo. Un `.edgeless` en la propia burbuja sí puede. El fondo sigue siendo opaco con cualquier presentación, así que la burbuja sigue siendo legible sobre lo que tape.
|
|
115
|
+
|
|
116
|
+
Una clase de intención rellena la burbuja con el color de esa intención y cambia el texto al color de contraste correspondiente:
|
|
117
|
+
|
|
118
|
+
- `.tooltip-bubble.primary` tiene un fondo casi negro con texto casi blanco en una página clara, y un fondo casi blanco con texto casi negro en una oscura.
|
|
119
|
+
- `.tooltip-bubble.destructive` tiene un fondo rojo con texto claro en ambos temas.
|
|
120
|
+
|
|
121
|
+
Pon las clases de intención, presentación, estética y elevación en `.tooltip-bubble`, el elemento que se pinta, no en `.tooltip`. La burbuja es plana por defecto, incluso bajo una estética que dibuja profundidad; añade `.raised` o `.floating` a la burbuja para elevarla. Una estética en el ámbito da forma a la burbuja como a cualquier otro componente; bajo `.glass` es esmerilada como una tarjeta. `.tooltip-icon` toma la esquina de la estética: cuadrada bajo `.neobrutalism` y `.pixel`, un rombo bajo `.cyber`.
|
|
122
|
+
|
|
123
|
+
La burbuja aparece sin el efecto de escala cuando el usuario pide movimiento reducido.
|
|
124
|
+
|
|
125
|
+
## Siguiente paso
|
|
126
|
+
|
|
127
|
+
La pantalla de ajustes está completa con su aspecto por defecto. [Temas](./theming.md) le da un modo oscuro y los colores de tu marca.
|
package/docs/index.md
CHANGED
|
@@ -1,35 +1,103 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Introduction
|
|
3
|
-
description: What @codenhub/styles is, what it
|
|
3
|
+
description: What @codenhub/styles is for, what it costs, and the order to read these docs in.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# @codenhub/styles
|
|
7
7
|
|
|
8
|
-
`@codenhub/styles`
|
|
8
|
+
`@codenhub/styles` lets you build a consistent, themeable interface by writing class names on plain HTML. You import one stylesheet and get tokens, a reset, layout and type helpers, and classes for buttons, form fields, alerts, cards, tables, and tooltips. There is no JavaScript to load and no component library to wrap: a `<button class="btn primary">` is the whole integration.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
These docs build one small screen from start to finish, an account settings page with a profile form, a plan summary, and a danger zone. Each page adds something to it, so by the end you have seen every part of the package working together instead of in isolation.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
```html
|
|
13
|
+
<main class="section">
|
|
14
|
+
<div class="section-content narrow stack">
|
|
15
|
+
<h1 class="text-title">Account settings</h1>
|
|
16
|
+
<form class="card stack">
|
|
17
|
+
<h2 class="text-title-sm">Profile</h2>
|
|
18
|
+
<div class="field">
|
|
19
|
+
<label class="label" for="display-name">Display name</label>
|
|
20
|
+
<input class="ipt" id="display-name" name="display-name" value="Ada Lovelace" />
|
|
21
|
+
</div>
|
|
22
|
+
<div class="cluster">
|
|
23
|
+
<button class="btn primary" type="submit">Save changes</button>
|
|
24
|
+
<button class="btn ghost" type="reset">Cancel</button>
|
|
25
|
+
</div>
|
|
26
|
+
</form>
|
|
27
|
+
</div>
|
|
28
|
+
</main>
|
|
29
|
+
```
|
|
13
30
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
31
|
+
## Three choices per component
|
|
32
|
+
|
|
33
|
+
Every component answers three independent questions with classes, so a new look never needs a new component variant:
|
|
34
|
+
|
|
35
|
+
- **Intent: which color?** `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, or `.info`. Leave it off for neutral.
|
|
36
|
+
- **Presentation: how much of that color?** `.solid`, `.soft`, or `.ghost` sets the fill; `.edged` or `.edgeless` sets the border.
|
|
37
|
+
- **Aesthetic: what is it made of?** An optional class such as `.neobrutalism` or `.glass` changes corners, border width, shadows, and type for everything inside it.
|
|
38
|
+
|
|
39
|
+
`<button class="btn destructive ghost edged">Delete account</button>` is a red outlined button, and wrapping the page in `.pixel` turns it into a pixel-art one without touching the button. [Building a screen](./concepts.md) introduces each axis as the settings page needs it.
|
|
40
|
+
|
|
41
|
+
## Compiled CSS or Tailwind source
|
|
42
|
+
|
|
43
|
+
The package ships the same classes two ways:
|
|
44
|
+
|
|
45
|
+
- **Compiled CSS**, ready to use. Import it from any bundler, or link the file from a CDN. You do not need Tailwind.
|
|
46
|
+
- **Tailwind CSS v4 source**, under `@codenhub/styles/tw`. Use it when your project already runs Tailwind v4, so your build compiles the package with your own utilities and theme.
|
|
47
|
+
|
|
48
|
+
[Setup](./setup.md) helps you choose.
|
|
20
49
|
|
|
21
50
|
## What it does not do
|
|
22
51
|
|
|
23
|
-
- No JavaScript
|
|
24
|
-
- No
|
|
25
|
-
- No theme
|
|
26
|
-
- No
|
|
27
|
-
- No compatibility
|
|
52
|
+
- **No JavaScript.** There is no runtime, no framework bindings, and no generated code. Anything that needs a script, such as opening a dialog, toggling a theme, or dismissing a tooltip, is your code.
|
|
53
|
+
- **No semantics or behavior.** The classes paint elements; they do not add HTML semantics, ARIA, keyboard handling, focus management, validation, or announcements. [Accessibility](./accessibility.md) draws the exact line.
|
|
54
|
+
- **No theme switching.** Choosing light or dark is a class or attribute you set. The separate `@codenhub/theme` package can remember and apply the choice for you.
|
|
55
|
+
- **No fonts or icons.** No font file is downloaded. Aesthetics that want a special font fall back to a system font until you supply one. Icons, including loading spinners, come from your own icon set, such as `@codenhub/icons`.
|
|
56
|
+
- **No compatibility aliases.** A removed class or token is listed in the changelog, not kept under its old name.
|
|
57
|
+
|
|
58
|
+
## Trade-offs
|
|
59
|
+
|
|
60
|
+
Know these costs before you adopt it:
|
|
61
|
+
|
|
62
|
+
- **Class names are short and unprefixed.** `.primary`, `.success`, `.dark`, `.label`, `.field`, `.section`, `.stack`, `.flat`, and `.ghost` are global names. Another stylesheet on the same page that uses them collides with this one. The package sits in [cascade layers](./setup.md#cascade-layers), so your own unlayered CSS wins a collision, but a third-party library's rules for the same name still apply alongside the package's.
|
|
63
|
+
- **The complete stylesheets are large before compression.** At the time of writing, minified, the complete stylesheet is about 410 KB, `/native` about 575 KB, and `/components` about 320 KB. Served with gzip they are about 19 KB, 25 KB, and 15 KB. Focused files are much smaller: `/theme` is about 10 KB (2 KB with gzip) and one aesthetic is 4 to 21 KB (1 to 2 KB with gzip). Most of the size is composition that every component repeats, which is why compression removes so much of it. Import the narrowest entrypoint that covers a page; see [Setup → All entrypoints](./setup.md#all-entrypoints).
|
|
64
|
+
- **`--color-foreground` is a background, not a text color.** It is the tone one step off the page that a quiet card or panel sits on. The text color is `--color-text`.
|
|
65
|
+
- **Four hover colors are fixed values.** `--color-success-hover`, `--color-warning-hover`, `--color-destructive-hover`, and `--color-info-hover` are precomputed, because mixing them live crashed WebKit. If you override `--color-success` alone, its hover keeps the old hue, so replace the whole family; see [Theming → Color tokens](./usage/theming.md#color-tokens).
|
|
66
|
+
- **Modern browsers only.** Chrome 123, Safari 17.5, or Firefox 128 and newer. There is no fallback layer for older browsers.
|
|
67
|
+
|
|
68
|
+
## What counts as supported
|
|
69
|
+
|
|
70
|
+
A combination of classes is supported when these docs describe it and the public demo at [demo.codenhub.dev/styles](https://demo.codenhub.dev/styles/) shows it. The demo renders the package's test fixtures, including the full intent, presentation, and aesthetic matrices, against the built CSS. A combination that is neither documented nor shown may still produce CSS, but it is not maintained and can change in any release.
|
|
71
|
+
|
|
72
|
+
The demo is rebuilt from the main branch, not from each release. It can show work that has not been released yet, so when the demo and these docs disagree about a released version, the docs and the [changelog](./changelog/index.md) for that version win.
|
|
73
|
+
|
|
74
|
+
## Versioning
|
|
75
|
+
|
|
76
|
+
The package is below 1.0 and follows the [semantic versioning rule for 0.x releases](https://semver.org/#spec-item-4): the public surface can still change between minor versions.
|
|
77
|
+
|
|
78
|
+
- A minor release, such as 0.7.0 to 0.8.0, may break. It can rename or remove a class or token, or change a default. Every break is listed under **Changed** or **Removed** on that version's [changelog](./changelog/index.md) page, with what to use instead.
|
|
79
|
+
- A patch release, such as 0.7.0 to 0.7.1, never breaks.
|
|
80
|
+
|
|
81
|
+
npm's default range for a new dependency, `^0.7.0`, already accepts patches only, because below 1.0 a caret range does not cross into the next minor version. Read the changelog before raising it. When you link a file from a CDN, put the exact version in the URL; see [Without a bundler](./integrating/without-a-bundler.md).
|
|
82
|
+
|
|
83
|
+
Breaks are not softened with aliases because the model is still settling, and keeping each old name beside its replacement would grow the surface every release. A rename or removal usually costs one find-and-replace when you upgrade; a changed default may need your own CSS retuned.
|
|
84
|
+
|
|
85
|
+
## Reading path
|
|
86
|
+
|
|
87
|
+
Read these in order the first time. Each page adds to the settings screen and ends by pointing to the next one.
|
|
28
88
|
|
|
29
|
-
|
|
89
|
+
1. [Setup](./setup.md): install the package, choose compiled CSS or Tailwind source, and render the empty page shell.
|
|
90
|
+
2. [Integrating](./integrating/index.md): only if you use Next.js, Vue, Svelte, Astro, Tailwind v4, or no bundler at all. Each guide returns you to the main path.
|
|
91
|
+
3. [Building a screen](./concepts.md): lay out the page, set its type, and add a card and a Save button, learning intent, fill, and edge on the way.
|
|
92
|
+
4. [Usage](./usage/index.md): the rest of the screen, in order:
|
|
93
|
+
- [Buttons](./usage/buttons.md): secondary and destructive actions, sizes, icon buttons, and disabled states.
|
|
94
|
+
- [Forms](./usage/forms.md): labeled fields, hints, errors, icons, selects, checkboxes, radios, and switches.
|
|
95
|
+
- [Feedback](./usage/feedback.md): a saving state, a success alert, a plan badge, a loading placeholder, and a usage bar.
|
|
96
|
+
- [Tooltips](./usage/tooltips.md): field help that works with a mouse, a keyboard, and a screen reader.
|
|
97
|
+
- [Theming](./usage/theming.md): light and dark mode, brand colors, and your own intents.
|
|
98
|
+
- [Aesthetics](./usage/aesthetics.md): restyle the whole screen with one class.
|
|
99
|
+
- [Solo classes](./usage/solo.md): paint an aesthetic onto a component this package does not style.
|
|
100
|
+
- [Composing](./usage/composing.md), [Customizing](./usage/customizing.md), and [Content and layout](./usage/content-and-layout.md): lookup pages with every axis rule, token, default, and helper class.
|
|
101
|
+
5. [Accessibility](./accessibility.md): what the CSS handles for you and what your application must still do.
|
|
30
102
|
|
|
31
|
-
|
|
32
|
-
- [Concepts](./concepts.md): The three-axis model, the token system, and how theme selection works — read this before the usage guides.
|
|
33
|
-
- [Usage](./usage/index.md): Guides for composing axes, theming, customizing, aesthetics, and each component family.
|
|
34
|
-
- [Integrating](./integrating/index.md): Wiring the stylesheet into Next.js, Vue, Svelte, Astro, or a Tailwind CSS v4 build.
|
|
35
|
-
- [Accessibility](./accessibility.md): CSS accessibility hooks and what remains an application responsibility.
|
|
103
|
+
The [changelog](./changelog/index.md) lists every release and what changed in it.
|
|
@@ -27,9 +27,8 @@ Every page that uses this layout loads the stylesheet once. Running Tailwind CSS
|
|
|
27
27
|
|
|
28
28
|
## Force a theme
|
|
29
29
|
|
|
30
|
-
Apply `.dark` or `.light` on `<html>` to force a theme instead of following the system preference; see [
|
|
30
|
+
Apply `.dark` or `.light` on `<html>` to force a theme instead of following the system preference; see [Theming → Light and dark](../usage/theming.md#light-and-dark).
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Next
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
- [Usage](../usage/index.md): component classes to compose once the stylesheet is loaded.
|
|
34
|
+
Return to the main path: [Building a screen](../concepts.md) adds the first card and form to the settings page. [Setup → All entrypoints](../setup.md#all-entrypoints) lists every other stylesheet you can import.
|