@codenhub/styles 0.7.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.
Files changed (121) hide show
  1. package/README.es.md +8 -7
  2. package/README.md +7 -6
  3. package/README.pt-BR.md +8 -7
  4. package/dist/aesthetics/chunky-tile.css +1 -1
  5. package/dist/aesthetics/cyber.css +1 -1
  6. package/dist/aesthetics/glass.css +1 -1
  7. package/dist/aesthetics/index.css +2 -2
  8. package/dist/aesthetics/neobrutalism.css +1 -1
  9. package/dist/aesthetics/sketch.css +1 -1
  10. package/dist/cli.js +189 -0
  11. package/dist/components.css +2 -2
  12. package/dist/index.css +2 -2
  13. package/dist/index.d.ts +1 -0
  14. package/dist/native.css +2 -2
  15. package/dist/palette.css +1 -1
  16. package/dist/theme.css +2 -2
  17. package/docs/accessibility.md +46 -27
  18. package/docs/changelog/0.8.0.md +70 -0
  19. package/docs/changelog/index.md +1 -0
  20. package/docs/es/accessibility.md +47 -28
  21. package/docs/es/index.md +3 -2
  22. package/docs/es/integrating/index.md +38 -10
  23. package/docs/es/integrating/tailwind.md +78 -8
  24. package/docs/es/integrating/without-a-bundler.md +128 -5
  25. package/docs/es/setup.md +42 -34
  26. package/docs/es/usage/aesthetics.md +19 -13
  27. package/docs/es/usage/buttons.md +6 -2
  28. package/docs/es/usage/composing.md +6 -2
  29. package/docs/es/usage/content-and-layout.md +8 -4
  30. package/docs/es/usage/customizing.md +19 -13
  31. package/docs/es/usage/feedback.md +5 -1
  32. package/docs/es/usage/forms.md +29 -4
  33. package/docs/es/usage/index.md +6 -2
  34. package/docs/es/usage/presets.md +92 -0
  35. package/docs/es/usage/solo.md +4 -2
  36. package/docs/es/usage/theming.md +28 -15
  37. package/docs/index.md +2 -1
  38. package/docs/integrating/index.md +38 -10
  39. package/docs/integrating/tailwind.md +77 -7
  40. package/docs/integrating/without-a-bundler.md +127 -4
  41. package/docs/pt-BR/accessibility.md +47 -28
  42. package/docs/pt-BR/index.md +3 -2
  43. package/docs/pt-BR/integrating/index.md +38 -10
  44. package/docs/pt-BR/integrating/tailwind.md +78 -8
  45. package/docs/pt-BR/integrating/without-a-bundler.md +128 -5
  46. package/docs/pt-BR/setup.md +42 -34
  47. package/docs/pt-BR/usage/aesthetics.md +19 -13
  48. package/docs/pt-BR/usage/buttons.md +6 -2
  49. package/docs/pt-BR/usage/composing.md +6 -2
  50. package/docs/pt-BR/usage/content-and-layout.md +8 -4
  51. package/docs/pt-BR/usage/customizing.md +19 -13
  52. package/docs/pt-BR/usage/feedback.md +5 -1
  53. package/docs/pt-BR/usage/forms.md +29 -4
  54. package/docs/pt-BR/usage/index.md +6 -2
  55. package/docs/pt-BR/usage/presets.md +92 -0
  56. package/docs/pt-BR/usage/solo.md +4 -2
  57. package/docs/pt-BR/usage/theming.md +21 -8
  58. package/docs/setup.md +30 -22
  59. package/docs/usage/aesthetics.md +18 -12
  60. package/docs/usage/buttons.md +5 -1
  61. package/docs/usage/composing.md +5 -1
  62. package/docs/usage/content-and-layout.md +7 -3
  63. package/docs/usage/customizing.md +18 -12
  64. package/docs/usage/feedback.md +4 -0
  65. package/docs/usage/forms.md +28 -3
  66. package/docs/usage/index.md +5 -1
  67. package/docs/usage/presets.md +91 -0
  68. package/docs/usage/solo.md +3 -1
  69. package/docs/usage/theming.md +20 -7
  70. package/llms-full.txt +592 -115
  71. package/package.json +113 -63
  72. package/{dist/tw → tw}/aesthetics/chunky-tile.css +39 -19
  73. package/{dist/tw → tw}/aesthetics/cyber.css +15 -24
  74. package/{dist/tw → tw}/aesthetics/glass.css +105 -36
  75. package/{dist/tw → tw}/aesthetics/neobrutalism.css +37 -20
  76. package/{dist/tw → tw}/aesthetics/sketch.css +152 -133
  77. package/{dist/tw → tw}/box.css +89 -12
  78. package/tw/components/button.css +11 -0
  79. package/tw/components/button.rules.css +187 -0
  80. package/tw/components/feedback.css +11 -0
  81. package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +134 -30
  82. package/tw/components/form.css +11 -0
  83. package/{dist/tw/components/form.css → tw/components/form.rules.css} +524 -111
  84. package/tw/components/index.css +16 -0
  85. package/tw/components/rules.css +41 -0
  86. package/tw/components/surface.css +11 -0
  87. package/tw/components/surface.rules.css +222 -0
  88. package/tw/components/tooltip.css +11 -0
  89. package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +43 -27
  90. package/{dist/tw → tw}/corner.css +18 -12
  91. package/{dist/tw → tw}/elevation.css +23 -17
  92. package/{dist/tw → tw}/index.css +11 -9
  93. package/tw/index.d.ts +1 -0
  94. package/tw/intent.css +312 -0
  95. package/tw/modifiers.css +127 -0
  96. package/tw/native.css +320 -0
  97. package/tw/presentation.css +139 -0
  98. package/tw/reset.css +10 -0
  99. package/{dist/tw/reset.css → tw/reset.rules.css} +7 -8
  100. package/tw/size.css +34 -0
  101. package/tw/surface.css +9 -0
  102. package/tw/surface.rules.css +212 -0
  103. package/{dist/tw → tw}/theme.css +92 -28
  104. package/tw/typography.css +8 -0
  105. package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
  106. package/{dist/tw → tw}/utilities/content.css +183 -63
  107. package/tw/utilities/index.css +11 -0
  108. package/tw/utilities/layout.css +208 -0
  109. package/tw/utilities/rules.css +8 -0
  110. package/dist/tw/components/button.css +0 -139
  111. package/dist/tw/components/index.css +0 -35
  112. package/dist/tw/components/surface.css +0 -184
  113. package/dist/tw/intent.css +0 -229
  114. package/dist/tw/native.css +0 -203
  115. package/dist/tw/palette.css +0 -460
  116. package/dist/tw/presentation.css +0 -68
  117. package/dist/tw/surface.css +0 -61
  118. package/dist/tw/utilities/index.css +0 -6
  119. package/dist/tw/utilities/layout.css +0 -144
  120. /package/{dist/tw → tw}/aesthetics/index.css +0 -0
  121. /package/{dist/tw → tw}/aesthetics/pixel.css +0 -0
@@ -2,7 +2,7 @@
2
2
  title: Formularios
3
3
  description: Campos con etiqueta, pistas y errores, iconos y prefijos fijos, selects y toggles de checkbox, radio y switch.
4
4
  order: 2
5
- source: 58972b8573a07a3336b5765a725eb99abb2f907a
5
+ source: 00e6a57cfd62f524fde5a550af721786edd7a5dd
6
6
  ---
7
7
 
8
8
  # Formularios
@@ -28,6 +28,25 @@ Un campo es una etiqueta, un control y una pista opcional, apilados:
28
28
 
29
29
  Un control de texto mide al menos 2.5rem de alto (`--control-height`), la misma altura que un botón por defecto, así que un campo y un botón quedan alineados en una fila. Su aspecto por defecto es sin relleno y con borde. Un `.textarea` mide al menos 7rem de alto y se puede redimensionar en vertical.
30
30
 
31
+ ### Tamaños
32
+
33
+ `.ipt`, `.select`, `.textarea` e `.input-group` aceptan las clases de tamaño del botón, así que un campo pequeño y un botón pequeño quedan alineados en una fila:
34
+
35
+ | Clase | Altura | Relleno lateral | Texto |
36
+ | ----------- | ------ | --------------- | --------- |
37
+ | `.sm` | 2rem | 0.625rem | 0.875rem |
38
+ | por defecto | 2.5rem | 0.75rem | heredado |
39
+ | `.lg` | 3rem | 1rem | 1.0625rem |
40
+
41
+ Las esquinas escalan con el tamaño, como las de un botón. Un `.textarea` conserva su altura mínima de 7rem en todos los tamaños; la clase cambia su texto, su relleno y sus esquinas. Define el tamaño de un `.input-group` en el grupo, no en el control de dentro: el control y sus adornos toman el tamaño de texto del grupo.
42
+
43
+ ```html
44
+ <div class="cluster tight">
45
+ <input class="ipt sm" aria-label="Coupon code" />
46
+ <button class="btn sm" type="button">Apply</button>
47
+ </div>
48
+ ```
49
+
31
50
  ## Mostrar un error de validación
32
51
 
33
52
  Marca el control como inválido con `aria-invalid="true"` y dale al mensaje de error `.hint.destructive`:
@@ -40,7 +59,13 @@ Marca el control como inválido con `aria-invalid="true"` y dale al mensaje de e
40
59
  </div>
41
60
  ```
42
61
 
43
- Un control inválido dibuja su borde, su anillo de foco y el texto escrito en el color destructivo, tenga la clase de intención que tenga. El texto usa el tono legible de ese color, `--intent-strong`, para que siga siendo legible sobre la página. El paquete solo pinta el estado: decidir que el valor es inválido, poner y quitar `aria-invalid` y escribir el mensaje es cosa de tu código. Quita `aria-invalid` en cuanto el valor vuelva a ser válido; si lo dejas puesto, el campo sigue en rojo.
62
+ Un control inválido dibuja su borde, su anillo de foco y el texto escrito en el color destructivo, tenga la clase de intención que tenga. El texto usa el tono legible de ese color, `--intent-strong`, para que siga siendo legible sobre la página. El paquete solo pinta el estado: decidir que el valor es inválido, poner y quitar `aria-invalid` y escribir el mensaje es cosa de tu código. Quita `aria-invalid` en cuanto el valor vuelva a ser válido; si lo dejas puesto, el campo sigue en rojo. En un checkbox, un radio o un switch, `aria-invalid="true"` dibuja el toggle exactamente igual que `.destructive`, marca de activado incluida.
63
+
64
+ Un `.hint` acepta cualquiera de las seis intenciones incorporadas, no solo `.destructive`: `.hint.success` confirma que se aceptó un valor, y `.hint.warning` señala uno que está permitido pero es inusual. Cada uno se muestra en el tono legible de su intención, `--intent-strong`, que mantiene 4.5:1 frente a la página en los dos temas. Un `.hint` sin intención, con `.neutral` o con una [intención que definiste tú](./theming.md#tu-propia-intención), se queda en el color secundario. Solo lo colorea una clase en el propio `.hint`; una intención en el campo o en un contenedor que lo rodee no lo hace.
65
+
66
+ ```html
67
+ <input class="ipt success" id="username" value="ada" aria-describedby="username-hint" /> <span class="hint success" id="username-hint">That username is available.</span>
68
+ ```
44
69
 
45
70
  ## Montar el formulario de perfil
46
71
 
@@ -84,7 +109,7 @@ Un `.select` dibuja su propia flecha. Con `multiple` o con un `size` mayor que 1
84
109
 
85
110
  ## Añadir un icono o un prefijo fijo
86
111
 
87
- `.input-group` pone un icono o un fragmento de texto dentro del borde de un campo. El grupo dibuja el borde, el fondo, el anillo de foco y los estados inválido y deshabilitado; el control de dentro renuncia a los suyos, así que el borde se dibuja una sola vez. Coloca el adorno antes del control para ponerlo al principio, o después para ponerlo al final.
112
+ `.input-group` pone un icono o un fragmento de texto dentro del borde de un campo. El grupo dibuja el borde, el fondo, el anillo de foco y los estados inválido y deshabilitado; el control de dentro renuncia a los suyos, así que el borde se dibuja una sola vez. Coloca el adorno antes del control para ponerlo al principio, o después para ponerlo al final. Un grupo mide lo mismo que un campo solo, así que queda alineado con los campos y los botones que tiene al lado.
88
113
 
89
114
  La dirección del perfil siempre empieza con el mismo host, así que es un prefijo fijo:
90
115
 
@@ -116,7 +141,7 @@ Un `.select` también funciona en un grupo. El grupo quita el relleno lateral de
116
141
 
117
142
  Cualquier elemento sirve como adorno: una clase de icono, un `<svg>` en línea, un `<img>` o texto. El paquete no incluye iconos para los campos, porque una imagen incorporada no podría seguir tu color de texto, tu tema ni tu estética.
118
143
 
119
- El grupo lee la intención y la presentación igual que un `.ipt` solo: `.input-group.primary` colorea el borde, y `.input-group.soft.edgeless` es un campo hundido en la página. `aria-invalid="true"` o `disabled` en el control de dentro se aplica a todo el grupo, y lo mismo si cualquiera de los dos está en el propio grupo. El anillo de foco aparece cuando cualquier elemento dentro del grupo tiene el foco, así que, a diferencia de un campo solo, también se muestra después de un clic con el ratón.
144
+ El grupo lee la intención y la presentación igual que un `.ipt` solo: `.input-group.primary` colorea el borde y el texto escrito, y `.input-group.soft.edgeless` es un campo hundido en la página. Pon la intención en el grupo, no en el control de dentro: el grupo dibuja el campo, así que el texto del control toma la intención del grupo y una clase de intención en el control no tiene efecto. `aria-invalid="true"` o `disabled` en el control de dentro se aplica a todo el grupo, y lo mismo si cualquiera de los dos está en el propio grupo. El anillo de foco del grupo aparece cuando su campo tiene el foco, así que, a diferencia de un campo solo, también se muestra después de un clic con el ratón. Un botón dentro del grupo, como un botón para borrar, dibuja su propio anillo cuando tiene el foco, y el grupo no dibuja ninguno: un solo anillo marca siempre el único control que tiene el foco.
120
145
 
121
146
  ## Decoraciones del navegador
122
147
 
@@ -3,12 +3,12 @@ title: Visión general
3
3
  description: Las guías que terminan la pantalla de ajustes y, después, las páginas de consulta con cada clase, token y valor por defecto.
4
4
  group: Uso
5
5
  order: 4
6
- source: cd4fa5f3fc9bc6e1ca74206616c5f58edfa6abf7
6
+ source: ccdf1949cd4f7688574d6f4fae9ad2cf34465fb3
7
7
  ---
8
8
 
9
9
  # Uso
10
10
 
11
- Estas guías terminan la pantalla de ajustes que empezó en [Construir una pantalla](../concepts.md). Lee las siete primeras en orden: cada una añade una parte de la pantalla y da por hechas las anteriores. Las tres últimas son páginas de consulta; las guías te enviarán a ellas cuando necesiten la tabla completa, y puedes volver siempre que necesites un valor por defecto o una regla.
11
+ Estas guías terminan la pantalla de ajustes que empezó en [Construir una pantalla](../concepts.md). Lee las siete primeras en orden: cada una añade una parte de la pantalla y da por hechas las anteriores. Las tres siguientes son páginas de consulta; las guías te enviarán a ellas cuando necesiten la tabla completa, y puedes volver siempre que necesites un valor por defecto o una regla. La última, Preajustes, es para cuando la pantalla ya funciona y te has cansado de escribir las mismas clases.
12
12
 
13
13
  Guías, en orden:
14
14
 
@@ -26,4 +26,8 @@ Páginas de consulta:
26
26
  - [Personalización](./customizing.md): tokens de presentación y de material, controles de las estéticas, las seis variables públicas de componente, la paleta generada y los helpers de composición para construir tus propios componentes.
27
27
  - [Contenido y layout](./content-and-layout.md): todos los helpers de layout, la escala tipográfica, tarjetas y paneles, tablas, citas, código y teclas.
28
28
 
29
+ Cuando la pantalla funcione:
30
+
31
+ - [Preajustes](./presets.md): define un aspecto una sola vez, con clases de eje en un contenedor, tokens de tema y de material, o tus propias clases de componente hechas con `@apply`.
32
+
29
33
  Cuando termines, [Accesibilidad](../accessibility.md) reúne lo que el CSS hace por ti y lo que tu aplicación todavía les debe a sus usuarios.
@@ -0,0 +1,92 @@
1
+ ---
2
+ title: Preajustes
3
+ description: Tres formas de definir un aspecto una sola vez en lugar de en cada elemento, y cuándo recurrir a cada una.
4
+ order: 11
5
+ source: 308b21076223635a3323bcfecb70abe3a9e6d1c7
6
+ ---
7
+
8
+ # Preajustes
9
+
10
+ A estas alturas, la pantalla de ajustes dice `btn primary soft sm` en una docena de sitios, y cambiar de opinión significa cambiar una docena de sitios. Esta página cubre las tres formas de definir un aspecto una sola vez: clases de eje en un contenedor, tokens de tema y de material, y tus propias clases de componente hechas con `@apply`. Cada una encaja con un tipo distinto de "una sola vez".
11
+
12
+ ## Cuál usar
13
+
14
+ | Quieres | Recurre a |
15
+ | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
16
+ | Que todos los componentes de una región compartan un relleno, un borde o un material | [Clases de eje en un contenedor](#clases-de-eje-en-un-contenedor) |
17
+ | Otros colores, esquinas, bordes o profundidad para una página o una región | [Tokens de tema y de material](#tokens-de-tema-y-de-material) |
18
+ | Un nombre para una receta que repites, como "el botón de guardar" | [Tus propias clases de componente](#tus-propias-clases-de-componente) |
19
+
20
+ Se combinan. Una región puede definir un token de material, estar bajo una estética y contener tu propia clase de botón, y cada elemento puede seguir sobrescribiendo lo que hereda.
21
+
22
+ ## Clases de eje en un contenedor
23
+
24
+ Algunas clases funcionan en un contenedor además de en un componente, y todo lo que hay dentro las toma:
25
+
26
+ - Las clases de presentación: `.solid`, `.soft`, `.ghost`, `.edged` y `.edgeless`.
27
+ - Los patrones de esquina: `.cut-diagonal` y `.cut-diagonal-reverse`.
28
+ - Las [estéticas](./aesthetics.md), como `.glass` o `.pixel`.
29
+
30
+ ```html
31
+ <div class="cluster soft edged">
32
+ <button class="btn primary" type="button">Negrita</button>
33
+ <button class="btn" type="button">Cursiva</button>
34
+ <button class="btn destructive solid" type="button">Quitar formato</button>
35
+ </div>
36
+ ```
37
+
38
+ Los botones de la barra son soft y con borde, y el último pide su propio relleno. Una clase en el elemento siempre gana a la de un contenedor.
39
+
40
+ Los demás ejes no se heredan. La intención, la elevación (`.flat`, `.raised`, `.floating`) y el tamaño (`.sm`, `.lg`) cambian solo el elemento en el que están, así que una barra `.sm` no encoge sus botones; [Composición → Combinar clases](./composing.md#combinar-clases) explica por qué. Una clase de estética también define su propio patrón de esquina en su región, así que un `.cut-diagonal` por encima de una región `.pixel` no llega a su interior.
41
+
42
+ Usa una clase de contenedor cuando el aspecto pertenece a la región, como una barra lateral discreta, y no a los componentes que contiene.
43
+
44
+ ## Tokens de tema y de material
45
+
46
+ Los tokens son propiedades personalizadas de CSS. Defínelo en `:root` y toda la página lo sigue; defínelo en un elemento y solo lo sigue lo que hay dentro. Llegan más lejos que las clases, porque los componentes los leen al dibujarse:
47
+
48
+ ```css
49
+ .admin {
50
+ --radius-control: 0.25rem;
51
+ --radius-surface: 0.5rem;
52
+ --border-width: 2px;
53
+ }
54
+ ```
55
+
56
+ Cada botón, campo, burbuja de tooltip y superficie dentro de `.admin` toma las esquinas más cerradas y el borde más grueso, sin una clase en ninguno de ellos. Las casillas de verificación, `.kbd` y `.code` mantienen su propia esquina más pequeña, `--radius-small`.
57
+
58
+ Las tablas están donde se explican los tokens, así que esta página no las repite:
59
+
60
+ - [Temas → Tokens de color](./theming.md#tokens-de-color): colores de marca y de estado, en los dos temas.
61
+ - [Temas → Tokens base](./theming.md#tokens-base): esquinas, grosor del borde, altura de los controles, anillo de foco, profundidad y movimiento.
62
+ - [Personalización → Tokens de presentación](./customizing.md#tokens-de-presentación): cuánto aportan un relleno, un borde o un hover.
63
+ - [Personalización → Tokens de material](./customizing.md#tokens-de-material): lo que define una estética, y que puedes definir tú, como `--ui-radius`.
64
+ - [Personalización → Tokens de estética](./customizing.md#tokens-de-estética): los controles de cada estética, como `--neo-offset`.
65
+
66
+ Usa tokens cuando el cambio es un valor, como un color o una esquina, y no una elección entre clases.
67
+
68
+ ## Tus propias clases de componente
69
+
70
+ Con los puntos de entrada de código fuente de Tailwind, cada componente, helper y clase de eje es una utilidad de Tailwind, así que una clase tuya puede llevar la receta completa:
71
+
72
+ ```css
73
+ @import "@codenhub/styles/tw";
74
+
75
+ @utility btn-save {
76
+ @apply btn primary soft sm;
77
+ }
78
+ ```
79
+
80
+ ```html
81
+ <button class="btn-save" type="submit">Guardar cambios</button>
82
+ ```
83
+
84
+ `btn-save` se comporta como `btn primary soft sm` escrito completo, con estéticas y hover incluidos, y cambiar la receta cambia todos los botones de guardar. Los modificadores que pertenecen a un componente, como `.tight` en `.stack` o `.icon` en `.btn`, también son utilidades, así que `@apply btn icon` te da un botón de icono propio. [Tailwind CSS v4 → Construir tus propios componentes con `@apply`](../integrating/tailwind.md#construir-tus-propios-componentes-con-apply) tiene las reglas, incluido por qué `@utility` es mejor que una regla simple.
85
+
86
+ Con el CSS compilado no hay `@apply`. Guarda la receta en un solo lugar del otro lado: un parcial de plantilla, un componente de tu framework o una constante como `const saveButton = "btn primary soft sm"`.
87
+
88
+ Usa tu propia clase cuando la misma combinación nombra una sola cosa de tu diseño, como el botón de guardar o la tarjeta de plan.
89
+
90
+ ## Siguiente paso
91
+
92
+ [Accesibilidad](../accessibility.md) enumera lo que el CSS hace por tus usuarios y lo que tu aplicación todavía les debe.
@@ -2,7 +2,7 @@
2
2
  title: Clases solo
3
3
  description: Cómo pintar una estética sobre un elemento de otra librería, como un toast o un diálogo, y qué lee e ignora una clase solo.
4
4
  order: 7
5
- source: 245473b119daf480163d69d38527a11b536fb5a0
5
+ source: c44308a8768737292529d4f93b703b3fa200255a
6
6
  ---
7
7
 
8
8
  # Clases solo
@@ -77,7 +77,9 @@ Sin ninguna de esas clases, una clase solo pinta solo el material (borde, esquin
77
77
  ## Cómo gana y cuándo se mueve
78
78
 
79
79
  - **Gana a los estilos de la otra librería.** Las reglas no tienen capa y tienen un solo nivel de clase, así que ganan a las reglas con capa de un componente, y a las de especificidad cero, se carguen donde se carguen. Una regla ajena sin capa que sea más específica, o igual de específica y posterior en la página, sigue ganando. La otra cara es que una utilidad de Tailwind en el mismo elemento, como `rounded-none`, pierde frente a la clase solo: ajústalo mediante sus controles.
80
- - **Solo pulsa una acción.** Neobrutalism, chunky tile y cyber pulsan un `button`, un `a[href]`, un `[role="button"]`, un `summary` o un `input` de tipo botón que no esté deshabilitado. Todo lo demás se queda quieto, así que un toast no se hunde al hacer clic. El movimiento reducido quita el desplazamiento. La etiqueta más gruesa de chunky tile sigue la misma regla.
80
+ - **Solo pulsa una acción.** Neobrutalism, chunky tile y cyber pulsan un `button`, un `a[href]`, un `[role="button"]`, un `summary` o un `input` de tipo botón que no esté deshabilitado. Todo lo demás se queda quieto, así que un toast no se hunde al hacer clic. La etiqueta más gruesa de chunky tile sigue la misma regla.
81
+ - **No toca el movimiento de un contenedor.** Solo una acción toma la `transition` de la pulsación, y la pulsación mueve el elemento mediante las propiedades `translate` y `scale`, no `transform`. Un toast conserva sus propias transiciones y su propio `transform`. En una acción, la `transition` de la pulsación reemplaza la que tuviera el elemento.
82
+ - **El movimiento reducido conserva la pulsación y quita su movimiento.** Con `prefers-reduced-motion: reduce`, neobrutalism, chunky tile y cyber siguen pulsando, pero al instante: el elemento cae en su sombra o su barra, o se encoge, sin recorrer la distancia.
81
83
 
82
84
  ## Siguiente paso
83
85
 
@@ -2,7 +2,7 @@
2
2
  title: Temas
3
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
4
  order: 5
5
- source: ef2e6095c03e7765cb650f720aca10403a70930c
5
+ source: faefe01e9a435bd2630c846cc365f3c8783107df
6
6
  ---
7
7
 
8
8
  # Temas
@@ -30,17 +30,26 @@ Una pantalla de ajustes con la opción "Sistema / Claro / Oscuro" quita el atrib
30
30
 
31
31
  Cómo se resuelve:
32
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">`.
33
+ - Un selector de tema define la propiedad CSS `color-scheme`, y el color del texto del elemento en `--color-text`. 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">`, y el texto que contiene toma el color de texto del tema oscuro.
35
+ - Un selector no define ningún fondo. Dale tú el fondo a la zona, por ejemplo con `background: var(--color-background)`. Cualquier utilidad o clase de componente en el mismo elemento sobrescribe el color de texto del selector.
35
36
  - Gana el selector más cercano, a cualquier profundidad. Una tarjeta `.light` dentro de una página `.dark` es clara.
36
37
  - Sin selector, la raíz tiene `color-scheme: light dark`, que sigue al sistema.
37
38
  - 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
+ - Definir tú mismo `color-scheme` en un elemento aplica el tema a los tokens de la misma forma, 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. El texto simple de dentro conserva el color que heredó hasta que también defines `color: var(--color-text)`.
39
40
 
40
41
  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
 
42
43
  `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
 
45
+ ### Impresión
46
+
47
+ Una página se imprime con el tema claro, sea cual sea el tema que muestra en pantalla. Dentro de `@media print`, la raíz y cada selector oscuro definen `color-scheme: light`, así que cada token se resuelve a su valor claro, también el de una barra lateral forzada a oscuro. El papel es claro, y un texto oscuro sobre él gasta menos tinta que una página oscura impresa.
48
+
49
+ Los componentes con relleno imprimen su fondo. Por defecto, un navegador quita los fondos de una página impresa, lo que deja el texto de contraste de un botón sólido sobre nada, así que cada componente define `print-color-adjust: exact`. La propiedad se hereda, de modo que el contenido de un componente también conserva sus colores.
50
+
51
+ Un límite: una utilidad `dark:` se sigue aplicando al imprimir. Se compara por selector, no por `color-scheme`, así que con `<html class="dark">` y `dark:bg-black` en un elemento, ese fondo se imprime negro. Escribe una utilidad `print:` a su lado si la página impresa importa.
52
+
44
53
  ### La variante `dark:`
45
54
 
46
55
  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:
@@ -92,6 +101,8 @@ El mismo patrón funciona con cada familia de [Tokens de color](#tokens-de-color
92
101
 
93
102
  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
103
 
104
+ Con `/tw` puedes prescindir de los tonos de Tailwind que tu diseño no usa, para que `bg-red-500` y sus hermanas dejen de ser clases. Conserva los que lee el tema, `neutral`, `emerald`, `amber`, `rose`, `indigo` y `white`: si los borras, los colores que se construyen con ellos se pierden sin ningún error. [Tailwind CSS v4 → Prescindir de la paleta de Tailwind](../integrating/tailwind.md#prescindir-de-la-paleta-de-tailwind) tiene el bloque para copiar.
105
+
95
106
  ## Tu propia intención
96
107
 
97
108
  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:
@@ -121,6 +132,8 @@ La clase funciona en todo lo que acepta una intención: botones, badges, campos
121
132
  - **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
133
  - **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
134
  - **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.
135
+ - **El texto del hint.** Un [`.hint`](./forms.md#mostrar-un-error-de-validación) solo se muestra en el tono legible de una intención con las seis clases incorporadas, así que `.hint.beta` se queda en el color secundario.
136
+ - **Filas de tabla.** Una fila del cuerpo cambia el color de su texto, su línea y su hover solo con las clases de intención incorporadas. `<tr class="beta">` se ve como el resto de su tabla.
124
137
 
125
138
  Si los necesitas, hay dos caminos:
126
139
 
@@ -233,7 +246,7 @@ Las cuatro sombras `--elevation-*` son para elementos a los que das estilo tú.
233
246
  | `--elevation-sm` | `0 1px 2px`, `0 1px 3px` | Una sombra ligera para tus propias superficies, como una tarjeta. |
234
247
  | `--elevation-md` | `0 4px 6px -1px`, `0 2px 4px -2px` | Una sombra para tus propios elementos elevados, como un menú desplegable. |
235
248
  | `--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. |
249
+ | `--focus-ring` | Sin definir | Color del anillo de foco del teclado. Sin definir, `--color-primary` con un 64% de opacidad, en el elemento con foco. |
237
250
  | `--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
251
  | `--focus-ring-width` | `3px` | Grosor del anillo de foco del teclado. |
239
252
  | `--motion-duration-fast` | `120ms` | El hover de una fila de tabla. |
@@ -243,22 +256,22 @@ Las cuatro sombras `--elevation-*` son para elementos a los que das estilo tú.
243
256
  | `--z-popover` | `40` | Orden de apilamiento de las burbujas de tooltip. Úsalo para tus propios popovers, para que se apilen igual. |
244
257
  | `--breakpoint-xs` | `30rem` | El breakpoint adaptable `xs:`. Solo en un build `/tw`; los puntos de entrada compilados no lo declaran. |
245
258
 
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).
259
+ Cada sombra `--elevation-*` está formada por las partes indicadas, cada una en `--elevation-color`. Las cuatro sombras se componen una sola vez, en la raíz, así que un `--elevation-color` que definas en un contenedor no les llega: defínelo en `:root`, o define el propio token `--elevation-*` en el contenedor. Las clases de elevación, como `.card.raised`, leen `--elevation-color` en el elemento y siguen el valor de un contenedor, con una excepción: cada clase de estética define su propio `--elevation-color` en su región. Un valor definido por encima de una región `.glass` o `.pixel` no llega a su interior. Defínelo en el propio elemento de la estética, donde tu utilidad o tu CSS sin capa supera a la clase, o en un elemento dentro de la región. Con glass, la sombra de una superficie se construye en el elemento `.glass`, así que solo la cambia un valor definido ahí. Con `.neobrutalism` la sombra se dibuja en la intención o en la tinta, y `.cyber` no dibuja profundidad, así que ninguna de las dos lee el token. 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
260
 
248
261
  ## Fuentes
249
262
 
250
263
  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
264
 
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. |
265
+ | Token | Lo lee | Sin tu valor |
266
+ | ---------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
267
+ | `--font-default` | El reset, en `html` y `body`, y las regiones `.glass` y `.neobrutalism`. Los controles lo heredan. | `"Segoe UI", system-ui, sans-serif` |
268
+ | `--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. |
269
+ | `--font-pixel` | [`.pixel`](./aesthetics.md#pixel) y `.pixel-solo` | No declarado. Recurre a una pila monoespaciada. |
270
+ | `--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. |
271
+ | `--font-cyber` | [`.cyber`](./aesthetics.md#cyber) y `.cyber-solo` | No declarado. Recurre a una pila monoespaciada. |
272
+ | `--font-sketch` | [`.sketch`](./aesthetics.md#sketch) y `.sketch-solo` | No declarado. Recurre a la familia `cursive` de la plataforma. |
260
273
 
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.
274
+ `--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` y define `--font-default` con la misma fuente: las regiones `.glass` y `.neobrutalism` definen su propio `font-family` a partir del token, así que una fuente definida solo en `body` no llega dentro de ellas. O define solo el token y escribe `font-family: var(--font-default)` 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
275
 
263
276
  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
277
 
package/docs/index.md CHANGED
@@ -60,7 +60,7 @@ The package ships the same classes two ways:
60
60
  Know these costs before you adopt it:
61
61
 
62
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).
63
+ - **The complete stylesheets are large before compression.** At the time of writing, minified, the complete stylesheet is about 198 KB, `/native` about 295 KB, and `/components` about 159 KB. Served with gzip they are about 17 KB, 22 KB, and 13 KB. Focused files are much smaller: `/theme` is about 12 KB (3 KB with gzip) and one aesthetic is 4 to 14 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. A compiled file ships every class, whether a page uses it or not. To ship only the classes your pages use, compile the package in your own build: through [Tailwind CSS v4](./integrating/tailwind.md) when the project runs it, or with the package's [`build` command](./integrating/without-a-bundler.md#build-only-the-classes-you-use) in any other project. A page with one button gets 26 to 28 KB minified that way, and about 6 KB with gzip. Otherwise import the narrowest entrypoint that covers a page; see [Setup → All entrypoints](./setup.md#all-entrypoints).
64
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
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
66
  - **Modern browsers only.** Chrome 123, Safari 17.5, or Firefox 128 and newer. There is no fallback layer for older browsers.
@@ -98,6 +98,7 @@ Read these in order the first time. Each page adds to the settings screen and en
98
98
  - [Aesthetics](./usage/aesthetics.md): restyle the whole screen with one class.
99
99
  - [Solo classes](./usage/solo.md): paint an aesthetic onto a component this package does not style.
100
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
+ - [Presets](./usage/presets.md): set a look once, for a region, a theme, or your own component class, instead of repeating it on every element.
101
102
  5. [Accessibility](./accessibility.md): what the CSS handles for you and what your application must still do.
102
103
 
103
104
  The [changelog](./changelog/index.md) lists every release and what changed in it.
@@ -20,16 +20,44 @@ Importing from one place matters for two reasons. Some frameworks only _allow_ g
20
20
 
21
21
  ## Which guide to follow
22
22
 
23
- | Stack | Guide |
24
- | ------------------------------------------------------------ | ------------------------------------------- |
25
- | A Tailwind CSS v4 project on any bundler | [Tailwind CSS v4](./tailwind.md) |
26
- | Next.js / React | [Next.js](./nextjs.md) |
27
- | Vue | [Vue](./vue.md) |
28
- | Svelte / SvelteKit | [Svelte](./svelte.md) |
29
- | Astro | [Astro](./astro.md) |
30
- | Plain HTML, Rails, Django, or any app with no CSS build step | [Without a bundler](./without-a-bundler.md) |
31
-
32
- A project with no framework — a plain Vite, webpack, or Parcel build — needs nothing beyond [Setup → Import the stylesheet](../setup.md#import-the-stylesheet): import the compiled stylesheet from the project's existing global CSS entry.
23
+ | Stack | Guide |
24
+ | ----------------------------------------------------------------------------- | ------------------------------------------- |
25
+ | A Tailwind CSS v4 project on any bundler | [Tailwind CSS v4](./tailwind.md) |
26
+ | Next.js / React | [Next.js](./nextjs.md) |
27
+ | Vue | [Vue](./vue.md) |
28
+ | Svelte / SvelteKit | [Svelte](./svelte.md) |
29
+ | Astro | [Astro](./astro.md) |
30
+ | Plain HTML, Rails, Laravel, Django, or any app with no Node.js CSS build step | [Without a bundler](./without-a-bundler.md) |
31
+
32
+ A project with no framework — a plain Vite, webpack, or Parcel build — imports the compiled stylesheet from the project's existing global CSS entry, as [Setup → Import the stylesheet](../setup.md#import-the-stylesheet) shows. Vite and webpack resolve the package name as it is; Parcel and PostCSS with `postcss-import` need the change below. The compiled stylesheet holds every class; to ship only the ones your pages use without adopting Tailwind, write a trimmed stylesheet with the package's [`build` command](./without-a-bundler.md#build-only-the-classes-you-use) and import that instead.
33
+
34
+ ### Bundlers that need a nudge
35
+
36
+ Both tools find the stylesheet once they are told how; neither needs a different entrypoint.
37
+
38
+ **Parcel.** Turn on its support for a package's `exports` map in your `package.json`:
39
+
40
+ ```json
41
+ {
42
+ "@parcel/resolver-default": {
43
+ "packageExports": true
44
+ }
45
+ }
46
+ ```
47
+
48
+ Then import the package with Parcel's `npm:` prefix, which tells it the name is a package and not a file next to the stylesheet:
49
+
50
+ ```css
51
+ @import "npm:@codenhub/styles";
52
+ ```
53
+
54
+ **PostCSS with `postcss-import`.** The plugin does not read a package's `exports` map, so the package name alone does not resolve. Import the compiled file by its path on disk instead, relative to your own stylesheet, the same file a `<link>` would name:
55
+
56
+ ```css
57
+ @import "../node_modules/@codenhub/styles/dist/index.css";
58
+ ```
59
+
60
+ The other compiled entrypoints work the same way, such as `@codenhub/styles/dist/aesthetics/neobrutalism.css`.
33
61
 
34
62
  ## Verifying it worked
35
63
 
@@ -6,11 +6,11 @@ order: 1
6
6
 
7
7
  # Tailwind CSS v4
8
8
 
9
- A project that already runs Tailwind CSS v4 can compile this package's source instead of loading its compiled output. Your app's utilities and the package's classes then come out of one build, share one theme, and use one `dark:` variant. This page covers the import, aesthetics, the focused entrypoints, and the build problems you are likely to meet.
9
+ A project that already runs Tailwind CSS v4 can compile this package's source instead of loading its compiled output. Your app's utilities and the package's classes then come out of one build, share one theme, and use one `dark:` variant. This page covers the import, aesthetics, the focused entrypoints, building your own components with `@apply`, dropping Tailwind's palette, and the build problems you are likely to meet.
10
10
 
11
11
  ## Why source instead of compiled
12
12
 
13
- `/tw` entrypoints publish copied, uncompiled source from `dist/tw`; your own Tailwind build compiles it alongside your app, so its `@theme`, `@utility`, and `@apply` directives resolve together with yours. The compiled entrypoints (`@codenhub/styles`) still work in a Tailwind project, but then two separate CSS pipelines run side by side instead of one — use `/tw` unless a specific reason rules it out.
13
+ `/tw` entrypoints publish copied, uncompiled source from the package's `tw/` folder; your own Tailwind build compiles it alongside your app, so its `@theme`, `@utility`, and `@apply` directives resolve together with yours. The compiled entrypoints (`@codenhub/styles`) still work in a Tailwind project, but then two separate CSS pipelines run side by side instead of one — use `/tw` unless a specific reason rules it out.
14
14
 
15
15
  ## Import the source entrypoint
16
16
 
@@ -22,7 +22,7 @@ A project that already runs Tailwind CSS v4 can compile this package's source in
22
22
 
23
23
  `/tw` imports Tailwind itself, so it replaces your own `@import "tailwindcss"` rather than joining it: with both, Tailwind's Preflight is emitted twice. Every other `/tw/*` entrypoint expects your import to come first; see [Using a focused entrypoint](#using-a-focused-entrypoint).
24
24
 
25
- Tailwind CSS v4 scans your project automatically — most projects need nothing beyond the import above. `@source` paths resolve relative to the CSS file that declares them, not your project root, so `./src` here means "the `src/` next to this stylesheet"; adjust it to match where your own global stylesheet actually lives. Add `@source` only for markup Tailwind's automatic scan won't reach on its own: a path excluded by default (`.gitignore`d, or inside `node_modules` — an external component library, for instance) or, in a monorepo, one outside this file's own directory tree. Point it at your app's markup, not at this package — `/tw` already ships every class definition it publishes, so scanning it too only slows the build without adding classes.
25
+ Tailwind CSS v4 scans your project automatically — most projects need nothing beyond the import above. `@source` paths resolve relative to the CSS file that declares them, not your project root, so `./src` here means "the `src/` next to this stylesheet"; adjust it to match where your own global stylesheet actually lives. Add `@source` only for markup Tailwind's automatic scan won't reach on its own: a path excluded by default (`.gitignore`d, or inside `node_modules` — an external component library, for instance) or, in a monorepo, one outside this file's own directory tree. Point it at your app's markup, not at this package: the package's source names every class it defines, so scanning it emits all of them whether your pages use them or not.
26
26
 
27
27
  ## Add aesthetics
28
28
 
@@ -46,6 +46,70 @@ Unlike `/tw`, the focused entrypoints and `/tw/native` do not import Tailwind, s
46
46
  @import "@codenhub/styles/tw/button";
47
47
  ```
48
48
 
49
+ ## Build your own components with `@apply`
50
+
51
+ On `/tw`, every component, helper, and axis class is a Tailwind utility. That includes the intents (`neutral`, `primary`, `secondary`, `success`, `warning`, `destructive`, `info`), the presentation (`solid`, `soft`, `ghost`, `edged`, `edgeless`), the elevation (`flat`, `raised`, `floating`), the corner patterns (`cut-diagonal`, `cut-diagonal-reverse`), and the sizes (`sm`, `lg`). So one class of yours can carry a whole recipe:
52
+
53
+ ```css
54
+ @import "@codenhub/styles/tw";
55
+
56
+ @utility btn-save {
57
+ @apply btn primary soft sm;
58
+ }
59
+
60
+ @utility btn-danger {
61
+ @apply btn destructive md:lg dark:solid;
62
+ }
63
+ ```
64
+
65
+ ```html
66
+ <button class="btn-save" type="submit">Save</button>
67
+ ```
68
+
69
+ - **An applied component behaves like the class.** `btn-save` hovers, presses, takes focus, and follows an aesthetic the way `class="btn primary soft sm"` does.
70
+ - **Variants work.** `hover:primary`, `md:lg`, and `dark:solid` apply an axis class under that condition, in your markup or inside `@apply`.
71
+ - **Write your class as `@utility`.** It then stays in the `utilities` layer, so your other utilities on the same element still beat it. A plain `.btn-save { @apply … }` rule works too, but it is unlayered, so what it applies beats every utility on the element; [Customizing → Composition helpers](../usage/customizing.md#composition-helpers) has the details.
72
+ - **Modifiers apply too.** A component's modifiers, such as `.tight` on `.stack`, `.icon` on `.btn`, or `.interactive` on `.card`, are utilities as well, so `@apply stack tight`, `@apply btn icon pill`, and `md:tight` work. The disabled state is the exception: it stays an attribute or the `.disabled` class in markup.
73
+ - **Your utility beats a component's inner defaults.** `p-0 text-center` on a `.data-table` cell, `text-sm` on a `.label`, and `px-8` on a `.btn.sm` all apply.
74
+
75
+ [Presets](../usage/presets.md) compares this with the other ways to set a look once.
76
+
77
+ ## Drop Tailwind's palette
78
+
79
+ `/tw` builds on Tailwind's default theme, so Tailwind's palette utilities, such as `bg-red-500`, stay available. If your design uses only the package's tokens, clear the hues you do not use:
80
+
81
+ ```css
82
+ @import "@codenhub/styles/tw";
83
+
84
+ @theme {
85
+ --color-red-*: initial;
86
+ --color-orange-*: initial;
87
+ --color-yellow-*: initial;
88
+ --color-lime-*: initial;
89
+ --color-green-*: initial;
90
+ --color-teal-*: initial;
91
+ --color-cyan-*: initial;
92
+ --color-sky-*: initial;
93
+ --color-blue-*: initial;
94
+ --color-violet-*: initial;
95
+ --color-purple-*: initial;
96
+ --color-fuchsia-*: initial;
97
+ --color-pink-*: initial;
98
+ --color-slate-*: initial;
99
+ --color-gray-*: initial;
100
+ --color-zinc-*: initial;
101
+ --color-stone-*: initial;
102
+ --color-black: initial;
103
+ }
104
+ ```
105
+
106
+ The package's own colors do not change, and you can still add colors of your own in the same block.
107
+
108
+ The block leaves out `neutral`, `emerald`, `amber`, `rose`, `indigo`, and `white` on purpose: the theme builds its colors from them.
109
+
110
+ - **Do not clear the whole namespace.** `--color-*: initial` also removes the package's semantic colors, and the build stops with an error such as `Cannot apply unknown utility class`.
111
+ - **Do not clear a ramp the theme reads.** Clearing `--color-emerald-*` builds without an error, but the success colors made from it are lost.
112
+
49
113
  ## Troubleshooting
50
114
 
51
115
  **Classes resolve to no styling**
@@ -62,11 +126,17 @@ Unlike `/tw`, the focused entrypoints and `/tw/native` do not import Tailwind, s
62
126
 
63
127
  **A class built at runtime has no styling**
64
128
 
65
- - **What happened:** `<button class="btn primary">` is styled, but a button whose intent comes from a variable, such as `` `btn ${tone}` ``, is not.
66
- - **Why:** Tailwind generates a class only when it finds the complete name in your source files. The package's own component and axis classes are always generated, but your own utilities are not, and a name assembled from strings is invisible to the scan.
67
- - **Fix:** write complete class names in your source, for example in a lookup object (`{ save: "btn primary", remove: "btn destructive" }`), or list the names your code can produce with `@source inline("...")` in your stylesheet.
129
+ - **What happened:** `<button class="btn primary">` is styled, but a button whose class comes from a variable, such as `"btn " + variant`, or from CMS content, is not.
130
+ - **Why:** Tailwind emits only the classes it finds written out in the files it scans. That holds for the package's component classes too: a `/tw` build emits `.alert` only if `alert` appears somewhere it scans, which keeps the stylesheet to what your pages use. The intent, presentation, elevation, corner, and size classes, such as `.primary`, `.soft`, and `.sm`, are utilities too, so the same holds for them. The aesthetic classes, such as `.glass`, are plain CSS and always emitted. A name assembled at runtime never appears whole in a file, so the scan misses it.
131
+ - **Fix:** write each complete class name somewhere Tailwind scans, for example in a lookup object (`{ save: "btn primary", remove: "btn destructive" }`), or list the names your code or content can produce in your stylesheet:
132
+
133
+ ```css
134
+ @import "@codenhub/styles/tw";
135
+
136
+ @source inline("btn alert badge primary destructive soft");
137
+ ```
68
138
 
69
- Every `/tw` entrypoint requires Tailwind CSS 4.3.2 or newer, below 5: the source uses `@source not` and `@source inline()`, which arrived in 4.1, and it is tested against 4.3.2.
139
+ Every `/tw` entrypoint requires Tailwind CSS 4.3.2 or newer, below 5 (`>=4.3.2 <5`).
70
140
 
71
141
  ## The `dark:` variant
72
142