reactigoded 1.0.0-beta.26

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 (177) hide show
  1. package/CHANGELOG.md +3001 -0
  2. package/LICENSE +21 -0
  3. package/README.md +556 -0
  4. package/dist/Toast-FZUdYH1L.js +594 -0
  5. package/dist/cn.js +7 -0
  6. package/dist/components/Accordion/Accordion.d.ts +49 -0
  7. package/dist/components/Accordion/AccordionContent.d.ts +15 -0
  8. package/dist/components/Accordion/AccordionContext.d.ts +59 -0
  9. package/dist/components/Accordion/AccordionHeader.d.ts +22 -0
  10. package/dist/components/Accordion/AccordionItem.d.ts +11 -0
  11. package/dist/components/Accordion/index.d.ts +8 -0
  12. package/dist/components/Alert/Alert.d.ts +39 -0
  13. package/dist/components/Alert/index.d.ts +2 -0
  14. package/dist/components/AlertDialog/AlertDialogClose.d.ts +64 -0
  15. package/dist/components/AlertDialog/AlertDialogContent.d.ts +58 -0
  16. package/dist/components/AlertDialog/index.d.ts +14 -0
  17. package/dist/components/Avatar/Avatar.d.ts +62 -0
  18. package/dist/components/Avatar/AvatarGroup.d.ts +13 -0
  19. package/dist/components/Avatar/index.d.ts +4 -0
  20. package/dist/components/Badge/Badge.d.ts +33 -0
  21. package/dist/components/Badge/index.d.ts +2 -0
  22. package/dist/components/Breadcrumb/Breadcrumb.d.ts +14 -0
  23. package/dist/components/Breadcrumb/BreadcrumbItem.d.ts +21 -0
  24. package/dist/components/Breadcrumb/index.d.ts +4 -0
  25. package/dist/components/Button/Button.d.ts +61 -0
  26. package/dist/components/Button/IconButton.d.ts +48 -0
  27. package/dist/components/Button/index.d.ts +4 -0
  28. package/dist/components/Card/Card.d.ts +79 -0
  29. package/dist/components/Card/CardBody.d.ts +8 -0
  30. package/dist/components/Card/CardDivider.d.ts +8 -0
  31. package/dist/components/Card/CardFooter.d.ts +8 -0
  32. package/dist/components/Card/CardHeader.d.ts +8 -0
  33. package/dist/components/Card/CardImage.d.ts +15 -0
  34. package/dist/components/Card/index.d.ts +12 -0
  35. package/dist/components/Checkbox/Checkbox.d.ts +47 -0
  36. package/dist/components/Checkbox/index.d.ts +2 -0
  37. package/dist/components/Chip/Chip.d.ts +38 -0
  38. package/dist/components/Chip/index.d.ts +2 -0
  39. package/dist/components/Dialog/Dialog.d.ts +80 -0
  40. package/dist/components/Dialog/DialogBody.d.ts +8 -0
  41. package/dist/components/Dialog/DialogClose.d.ts +61 -0
  42. package/dist/components/Dialog/DialogContent.d.ts +36 -0
  43. package/dist/components/Dialog/DialogContext.d.ts +1 -0
  44. package/dist/components/Dialog/DialogFooter.d.ts +8 -0
  45. package/dist/components/Dialog/DialogHeader.d.ts +13 -0
  46. package/dist/components/Dialog/DialogTrigger.d.ts +44 -0
  47. package/dist/components/Dialog/index.d.ts +16 -0
  48. package/dist/components/Divider/Divider.d.ts +34 -0
  49. package/dist/components/Divider/index.d.ts +2 -0
  50. package/dist/components/Input/ErrorText.d.ts +13 -0
  51. package/dist/components/Input/Helper.d.ts +11 -0
  52. package/dist/components/Input/Input.d.ts +35 -0
  53. package/dist/components/Input/InputAddon.d.ts +8 -0
  54. package/dist/components/Input/InputGroup.d.ts +17 -0
  55. package/dist/components/Input/Label.d.ts +12 -0
  56. package/dist/components/Input/index.d.ts +12 -0
  57. package/dist/components/NativeSelect/NativeSelect.d.ts +41 -0
  58. package/dist/components/NativeSelect/index.d.ts +2 -0
  59. package/dist/components/Navbar/Navbar.d.ts +46 -0
  60. package/dist/components/Navbar/NavbarActions.d.ts +10 -0
  61. package/dist/components/Navbar/NavbarLink.d.ts +13 -0
  62. package/dist/components/Navbar/NavbarLogo.d.ts +22 -0
  63. package/dist/components/Navbar/NavbarMenuButton.d.ts +15 -0
  64. package/dist/components/Navbar/NavbarNav.d.ts +14 -0
  65. package/dist/components/Navbar/index.d.ts +12 -0
  66. package/dist/components/Pagination/Pagination.d.ts +77 -0
  67. package/dist/components/Pagination/index.d.ts +2 -0
  68. package/dist/components/Progress/Progress.d.ts +63 -0
  69. package/dist/components/Progress/index.d.ts +2 -0
  70. package/dist/components/Radio/Radio.d.ts +28 -0
  71. package/dist/components/Radio/index.d.ts +2 -0
  72. package/dist/components/Rating/Rating.d.ts +85 -0
  73. package/dist/components/Rating/index.d.ts +2 -0
  74. package/dist/components/Sidebar/Sidebar.d.ts +28 -0
  75. package/dist/components/Sidebar/SidebarContext.d.ts +32 -0
  76. package/dist/components/Sidebar/SidebarDivider.d.ts +8 -0
  77. package/dist/components/Sidebar/SidebarFooter.d.ts +8 -0
  78. package/dist/components/Sidebar/SidebarHeader.d.ts +13 -0
  79. package/dist/components/Sidebar/SidebarItem.d.ts +42 -0
  80. package/dist/components/Sidebar/SidebarNav.d.ts +13 -0
  81. package/dist/components/Sidebar/SidebarSection.d.ts +11 -0
  82. package/dist/components/Sidebar/SidebarToggle.d.ts +17 -0
  83. package/dist/components/Sidebar/index.d.ts +16 -0
  84. package/dist/components/Skeleton/Skeleton.d.ts +60 -0
  85. package/dist/components/Skeleton/index.d.ts +2 -0
  86. package/dist/components/Slider/Slider.d.ts +44 -0
  87. package/dist/components/Slider/index.d.ts +2 -0
  88. package/dist/components/Slot/Slot.d.ts +1 -0
  89. package/dist/components/Slot/composeEventHandlers.d.ts +1 -0
  90. package/dist/components/Slot/composeRefs.d.ts +1 -0
  91. package/dist/components/Slot/index.d.ts +3 -0
  92. package/dist/components/Spinner/Spinner.d.ts +31 -0
  93. package/dist/components/Spinner/index.d.ts +2 -0
  94. package/dist/components/Stepper/Step.d.ts +17 -0
  95. package/dist/components/Stepper/Stepper.d.ts +97 -0
  96. package/dist/components/Stepper/index.d.ts +4 -0
  97. package/dist/components/Switch/Switch.d.ts +53 -0
  98. package/dist/components/Switch/index.d.ts +2 -0
  99. package/dist/components/Table/Table.d.ts +74 -0
  100. package/dist/components/Table/index.d.ts +2 -0
  101. package/dist/components/Tabs/Tabs.d.ts +41 -0
  102. package/dist/components/Tabs/TabsContent.d.ts +15 -0
  103. package/dist/components/Tabs/TabsContext.d.ts +61 -0
  104. package/dist/components/Tabs/TabsList.d.ts +10 -0
  105. package/dist/components/Tabs/TabsTrigger.d.ts +15 -0
  106. package/dist/components/Tabs/index.d.ts +8 -0
  107. package/dist/components/Textarea/Textarea.d.ts +51 -0
  108. package/dist/components/Textarea/index.d.ts +2 -0
  109. package/dist/components/ThemeToggle/ThemeToggle.d.ts +43 -0
  110. package/dist/components/ThemeToggle/index.d.ts +2 -0
  111. package/dist/components/Timeline/Timeline.d.ts +20 -0
  112. package/dist/components/Timeline/TimelineItem.d.ts +32 -0
  113. package/dist/components/Timeline/index.d.ts +4 -0
  114. package/dist/components/Toast/Toast.d.ts +47 -0
  115. package/dist/components/Toast/ToastContext.d.ts +93 -0
  116. package/dist/components/Toast/ToastProvider.d.ts +116 -0
  117. package/dist/components/Toast/index.d.ts +6 -0
  118. package/dist/components/floating/Menu/Menu.d.ts +67 -0
  119. package/dist/components/floating/Menu/MenuContent.d.ts +60 -0
  120. package/dist/components/floating/Menu/MenuContext.d.ts +78 -0
  121. package/dist/components/floating/Menu/MenuItem.d.ts +47 -0
  122. package/dist/components/floating/Menu/MenuLabel.d.ts +6 -0
  123. package/dist/components/floating/Menu/MenuSeparator.d.ts +6 -0
  124. package/dist/components/floating/Menu/MenuTrigger.d.ts +53 -0
  125. package/dist/components/floating/Menu/index.d.ts +12 -0
  126. package/dist/components/floating/Menu/menuSelectors.d.ts +15 -0
  127. package/dist/components/floating/Tooltip/Tooltip.d.ts +194 -0
  128. package/dist/components/floating/Tooltip/index.d.ts +2 -0
  129. package/dist/components/floating/index.d.ts +3 -0
  130. package/dist/components/floating/primitives/FloatingTreeRoot.d.ts +55 -0
  131. package/dist/components/floating/primitives/index.d.ts +2 -0
  132. package/dist/components/floating/primitives/useFloatingNode.d.ts +1 -0
  133. package/dist/components/index.d.ts +38 -0
  134. package/dist/hooks/useControllableState.d.ts +152 -0
  135. package/dist/hooks/useTheme.d.ts +44 -0
  136. package/dist/index.d.ts +36 -0
  137. package/dist/index.js +1843 -0
  138. package/dist/server-safe.d.ts +69 -0
  139. package/dist/server-safe.js +47 -0
  140. package/dist/styles/igoded-base.css +1 -0
  141. package/dist/styles/igoded-components.css +1 -0
  142. package/dist/styles/igoded-design.css +1 -0
  143. package/dist/styles/igoded-fonts.css +1 -0
  144. package/dist/styles/igoded-reset.css +1 -0
  145. package/dist/styles/igoded-state-css.css +1 -0
  146. package/dist/styles/igoded-tokens.css +1 -0
  147. package/dist/styles/index.css +3 -0
  148. package/dist/styles/state/active.css +1 -0
  149. package/dist/styles/state/checked.css +1 -0
  150. package/dist/styles/state/default.css +1 -0
  151. package/dist/styles/state/disabled.css +1 -0
  152. package/dist/styles/state/empty.css +1 -0
  153. package/dist/styles/state/first-child.css +1 -0
  154. package/dist/styles/state/first-of-type.css +1 -0
  155. package/dist/styles/state/focus-visible.css +1 -0
  156. package/dist/styles/state/focus-within.css +1 -0
  157. package/dist/styles/state/focus.css +1 -0
  158. package/dist/styles/state/group-hover.css +1 -0
  159. package/dist/styles/state/hover.css +1 -0
  160. package/dist/styles/state/in-range.css +1 -0
  161. package/dist/styles/state/indeterminate.css +1 -0
  162. package/dist/styles/state/invalid.css +1 -0
  163. package/dist/styles/state/last-child.css +1 -0
  164. package/dist/styles/state/last-of-type.css +1 -0
  165. package/dist/styles/state/nth-child.css +1 -0
  166. package/dist/styles/state/only-child.css +1 -0
  167. package/dist/styles/state/optional.css +1 -0
  168. package/dist/styles/state/other.css +1 -0
  169. package/dist/styles/state/out-of-range.css +1 -0
  170. package/dist/styles/state/placeholder-shown.css +1 -0
  171. package/dist/styles/state/read-only.css +1 -0
  172. package/dist/styles/state/read-write.css +1 -0
  173. package/dist/styles/state/required.css +1 -0
  174. package/dist/styles/state/target.css +1 -0
  175. package/dist/styles/state/valid.css +1 -0
  176. package/dist/utils/cn.d.ts +11 -0
  177. package/package.json +282 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Iván Goded
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,556 @@
1
+ # reactigoded
2
+
3
+ Design system de **igoded** — 32 componentes React 19 + TypeScript estricto
4
+ sobre un CSS modular utility-first state-driven (`tokens` / `base` /
5
+ `components` + `reset` opt-in + `state` opt-in).
6
+
7
+ > **Estado**: `1.0.0-beta.25`.
8
+ > Paleta cardinal estable: 7 cardinales con geometría OKLCH dual
9
+ > (L_lux≈0.32 / L_nox≈0.84 / ΔH≤10°), todos AAA contra los 5 fondos
10
+ > del tema en ambos modos. El cardinal `info` se llama internamente
11
+ > `kobalium` (azul cobalto, H≈260°); la API semántica pública —
12
+ > `info` / `--ig-info` / `.ig-*-info` — no cambia. `vitreus` (brand)
13
+ > está reposicionado en H=207.50° (centro perceptual verde↔azul en
14
+ > OKLCH), hex `#053a40` lux / `#3ae2f7` nox. CI local en verde:
15
+ > `lint + typecheck + test:unit + test:contrast (WCAG ≥ 4.5 ambos
16
+ > temas + geometría OKLCH + ΔE OKLab) + build + storybook+axe +
17
+ > verify:size`.
18
+
19
+ ## Instalación
20
+
21
+ > **Nota**: el paquete aún no está publicado a npm. La instalación
22
+ > se hace vía clone + `npm link` mientras tanto. La publicación al
23
+ > registro está prevista pero sin fecha confirmada.
24
+
25
+ ```bash
26
+ git clone https://github.com/ivangc1/reactigoded.git
27
+ cd reactigoded
28
+ npm ci
29
+ npm run build
30
+ npm link
31
+
32
+ # en tu app:
33
+ cd /tu/app
34
+ npm link reactigoded
35
+ ```
36
+
37
+ `react` y `react-dom` >= 19 son `peerDependencies`.
38
+
39
+ **`@floating-ui/react` (^0.27) es peer-dep requerido** — lo usa
40
+ internamente `Tooltip` (y futuros `Popover`, `HoverCard`, etc.).
41
+ Instálalo **siempre** junto a la librería:
42
+
43
+ ```bash
44
+ npm install reactigoded react react-dom @floating-ui/react clsx
45
+ ```
46
+
47
+ **`clsx` (^2.1) también es peer-dep requerido** — lo usa el helper `cn`
48
+ (y el export `reactigoded/cn`). Sin él, `reactigoded/cn` revienta con
49
+ `ERR_MODULE_NOT_FOUND`. Se externaliza como peer (D1-P2, beta.24) para
50
+ no duplicar `clsx` en consumers que ya lo traen vía Tailwind/shadcn.
51
+
52
+ Aunque el tree-shaking elimina `Tooltip` + `@floating-ui/react`
53
+ del bundle final si no los importas, el peer-dep no satisfecho
54
+ rompe la resolución de módulos del bundler **antes** de que el
55
+ tree-shake ocurra. No es opcional para el install, solo para el
56
+ bundle.
57
+
58
+ Razón: `@floating-ui/react` ocupa ~17 KB gz; bundlearla duplicaba
59
+ la dep si el consumer ya la tenía vía Radix/Headless UI/otra DS.
60
+ Externalizarla mantiene el bundle ESM de reactigoded en ~16 KB gz
61
+ (budget 20 KB con headroom para crecimiento, D9 beta.24).
62
+
63
+ ### ⚠ Riesgo pre-1.0 — qué pasa cuando FUI publique 0.28
64
+
65
+ `@floating-ui/react` está actualmente en `0.27.x` (pre-1.0). En semver
66
+ pre-1.0 el caret `^0.27.0` se comporta distinto que en versiones
67
+ mayores estables:
68
+
69
+ ```
70
+ ^0.27.0 → matchea 0.27.x SOLAMENTE (NO matchea 0.28.0)
71
+ ^1.27.0 → matchea 1.x.x (sí matchearía 1.28.0)
72
+ ```
73
+
74
+ Es decir: una vez FUI publique `0.28.0`, los consumers haciendo
75
+ `npm install reactigoded` con la rango `^0.27.0` de nuestro
76
+ peerDependencies verán warning de peer-dep no satisfecho si tienen
77
+ `@floating-ui/react@0.28.x` ya instalado por otra dep. Eso es
78
+ intencional — un minor bump en `0.x` puede traer breaking changes
79
+ (la convención semver de pre-1.0).
80
+
81
+ **Política del DS** (decision doc `D10-fui-peer-dep-verify.md`):
82
+
83
+ 1. Mantenemos `^0.27.0` cerrado hasta verificar compatibilidad
84
+ con la nueva minor.
85
+ 2. Cuando FUI publique `0.28.0`, hacemos cross-check de los 20
86
+ símbolos que usamos (`autoUpdate`, `useFloating`, `flip`, etc.).
87
+ 3. Si la nueva minor no rompe nuestros uses, ampliamos el rango a
88
+ `^0.27.0 || ^0.28.0` en un patch release del DS.
89
+ 4. Si rompe, evaluamos: pinar `0.27.x` permanente, o adoptar `0.28`
90
+ con un minor bump del DS (breaking si el cambio toca API expuesta).
91
+
92
+ **Si tu app YA usa `@floating-ui/react` directamente**: pinea
93
+ explícitamente `0.27.x` en tu `package.json` para evitar que un `npm
94
+ install` de tu app traiga `0.28.0` automático y rompa la resolución
95
+ del peer-dep antes de que actualicemos el rango.
96
+
97
+ ```jsonc
98
+ // tu package.json
99
+ "dependencies": {
100
+ "@floating-ui/react": "~0.27.0", // tilde — solo patches dentro de 0.27
101
+ "reactigoded": "^1.0.0"
102
+ }
103
+ ```
104
+
105
+ Una vez FUI llegue a `1.0.0`, este riesgo desaparece (`^1.0.0`
106
+ permite minor bumps con backwards compat semver-standard).
107
+
108
+ ## CSS imports
109
+
110
+ 8 entradas. Lo habitual: importa solo `design.css` (+ opcionalmente `fonts.css` si quieres las tipografías Google del DS).
111
+
112
+ ```ts
113
+ // 100% variables --ig-* + keyframes. Cero selectores globales, cero
114
+ // requests remotos. Útil si construyes tus propios componentes sobre los
115
+ // tokens del DS sin cargar nada más.
116
+ import "reactigoded/styles/tokens.css"; // ~98 KB
117
+
118
+ // Globales mínimos: box-sizing + html scroll + scrollbars + ::selection +
119
+ // prefers-reduced-motion / contrast / forced-colors. Garantías a11y +
120
+ // scrollbar tematizada. Requiere tokens.css.
121
+ import "reactigoded/styles/base.css"; // ~4 KB
122
+
123
+ // Solo clases .ig-* (utilities + componentes). Cero globales. Requiere
124
+ // tokens.css + base.css.
125
+ import "reactigoded/styles/components.css"; // ~363 KB
126
+
127
+ // Atajo: tokens + base + components vía @import. Lo habitual.
128
+ import "reactigoded/styles/design.css"; // ~370 KB total
129
+
130
+ // Estilos por defecto para HTML nativo (h1-h6, p, a, button, input, table,
131
+ // code, blockquote…). NO lo importes si ya usas Tailwind preflight,
132
+ // Bootstrap reboot u otro reset.
133
+ import "reactigoded/styles/reset.css"; // ~5.5 KB
134
+
135
+ // Tipografías Google Fonts oficiales del DS (Electrolize / Saira / JetBrains
136
+ // Mono). Opt-in desde 1.0.0-beta.3: el paquete ya NO impone request remoto
137
+ // al consumer. Si no lo importas, los componentes caen al fallback
138
+ // system-ui declarado en tokens.css. Recomendado: self-host con next/font
139
+ // o @fontsource/* para mejor LCP, privacidad y CSP.
140
+ import "reactigoded/styles/fonts.css"; // ~2 KB (solo @import a Google Fonts)
141
+
142
+ // Utilities pseudo-class (hover:ig-bg-brand, focus:..., etc.) — solo si
143
+ // usas las utilities directamente en HTML.
144
+ import "reactigoded/styles/state.css"; // ~6.5 MB sin gzip / ~700 KB gzipped
145
+
146
+ // Atajo final: design + reset + state vía @import (sin duplicar bytes).
147
+ import "reactigoded/styles/all.css";
148
+ ```
149
+
150
+ ### Escenarios típicos
151
+
152
+ | Caso de uso | Imports |
153
+ |---------------------------------------------------|--------------------------------------------|
154
+ | Uso normal del DS | `design.css` |
155
+ | DS + tipografías oficiales Google Fonts | `design.css` + `fonts.css` |
156
+ | DS + estilos para HTML nativo | `design.css` + `reset.css` |
157
+ | DS completo con HTML nativo y utilities pseudo | `all.css` (+ `fonts.css` aparte si quieres)|
158
+ | Solo tokens, construyo encima | `tokens.css` |
159
+ | Tokens + a11y baseline, mis componentes | `tokens.css` + `base.css` |
160
+ | Tema custom, mismas clases del DS | `design.css` + override `:root` |
161
+
162
+ > El `<dialog>` de `<Dialog>` / `<AlertDialog>` y los componentes con flex/transition usan
163
+ > `var(--ig-*)` definidos en `design.css`. **Si solo importas `state.css` o
164
+ > `reset.css`, los componentes no tendrán estilo.**
165
+
166
+ > El `reset.css` se separó del `design.css` en `1.0.0-beta.1` (antes estaba
167
+ > activo dentro de `design.css`). Si actualizas desde una beta anterior y
168
+ > notas que tu HTML nativo perdió estilos, importa `reset.css`.
169
+
170
+ > ⚠️ **Breaking visual desde `1.0.0-beta.5`**: el `reset.css` ya no estiliza
171
+ > `<button>` con la marca. Antes daba a todo `<button>` `background: vitreus`
172
+ > + `color: text-on-vitreus`; ahora salen `background: transparent`,
173
+ > `color: inherit`, `border: 0`, `padding: 0`, `cursor: pointer`. Si tu app
174
+ > dependía de que cualquier `<button>` nativo apareciera con look brand
175
+ > "gratis", ahora los verás transparentes. **Migración**: añade la clase
176
+ > base `.ig-btn` + la variante (`.ig-btn-brand`, `.ig-btn-secondary`,
177
+ > `.ig-btn-success`, `.ig-btn-warning`, `.ig-btn-danger`, `.ig-btn-info`,
178
+ > `.ig-btn-outline-*`, `.ig-btn-ghost-*`, `.ig-btn-link`) a esos
179
+ > elementos — usa preferentemente el componente `<Button variant="…">`
180
+ > de la librería, esas clases son la API CSS pública subyacente.
181
+ > **Razón**: combinaciones bg/color heredadas rompían contraste cuando
182
+ > un wrapper aplicaba sus propios colores.
183
+
184
+ ### Globales aplicados por `base.css` (incluido en `design.css`)
185
+
186
+ `design.css` **no estiliza** elementos HTML nativos como `h1`, `p`, `a`,
187
+ `button`, `input` o `table` — eso vive en `reset.css` (opt-in).
188
+
189
+ Sí aplica un baseline global mínimo (`base.css`), pensado como
190
+ infraestructura del sistema (no como opinión visual sobre tu HTML):
191
+
192
+ | Selector / @-rule | Qué hace |
193
+ |---|---|
194
+ | `*, *::before, *::after { box-sizing: border-box }` | Necesario para que padding+border de los componentes calcule el tamaño correcto. |
195
+ | `html { scroll-behavior, scrollbar-gutter, accent-color, caret-color }` | Suaviza scroll, reserva gutter de scrollbar, fija color de focus en checkboxes/radios nativos y caret de inputs. |
196
+ | `::-webkit-scrollbar*` | Scrollbar tematizada (solo Chrome/Edge/Safari). |
197
+ | `::selection`, `::-moz-selection` | Color de selección de texto coherente con la marca. |
198
+ | `@media (prefers-reduced-motion: reduce)` | Reduce animation/transition a `0.01ms` para usuarios con sensibilidad al movimiento. **Garantía a11y, no opcional.** |
199
+ | `@media (prefers-contrast: more)` | Refuerza bordes en `.ig-btn`, `.ig-input`, `.ig-card`. |
200
+ | `@media (forced-colors: active)` | Compatibilidad con Windows High Contrast Mode. |
201
+
202
+ **Si quieres cero globales** en una sub-zona aislada, importa solo
203
+ `tokens.css` + `components.css` (sin `base.css`). Pierdes el baseline a11y
204
+ del sistema; asegúrate de que ya lo tienes en tu propia capa.
205
+
206
+ ## Uso
207
+
208
+ ```tsx
209
+ import {
210
+ Button,
211
+ Dialog,
212
+ DialogTrigger,
213
+ DialogContent,
214
+ DialogHeader,
215
+ DialogBody,
216
+ DialogClose,
217
+ Toast,
218
+ ToastProvider,
219
+ useToast,
220
+ } from "reactigoded";
221
+ import "reactigoded/styles/design.css";
222
+
223
+ function App() {
224
+ return (
225
+ <ToastProvider position="top-right">
226
+ <Page />
227
+ </ToastProvider>
228
+ );
229
+ }
230
+
231
+ function Page() {
232
+ const { toast } = useToast();
233
+ return (
234
+ <Button onClick={() => toast({ variant: "success", title: "Guardado" })}>
235
+ Guardar
236
+ </Button>
237
+ );
238
+ }
239
+ ```
240
+
241
+ ## Componentes (32)
242
+
243
+ | Categoría | Componentes |
244
+ |---|---|
245
+ | **Acciones** | `Button`, `IconButton`, `Chip`, `Pagination` |
246
+ | **Display** | `Avatar`, `AvatarGroup`, `Badge`, `Card` (+`CardHeader`/`Body`/`Footer`/`Image`/`Divider`), `Divider`, `Skeleton`, `Spinner`, `Timeline`+`TimelineItem` |
247
+ | **Feedback** | `Alert`, `AlertDialog`+`AlertDialogTrigger`+`AlertDialogContent`+`AlertDialogHeader`+`AlertDialogBody`+`AlertDialogFooter`+`AlertDialogClose`, `Dialog`+`DialogTrigger`+`DialogContent`+`DialogHeader`+`DialogBody`+`DialogFooter`+`DialogClose`, `Progress`, `Toast`+`ToastProvider`+`useToast`, `Tooltip`, `FloatingTreeRoot` |
248
+ | **Formularios** | `Checkbox`, `Input` (+`Label`/`Helper`/`ErrorText`/`InputGroup`/`InputAddon`), `Radio`, `Rating`, `NativeSelect`, `Slider`, `Switch`, `Textarea`, `ThemeToggle` |
249
+ | **Navegación** | `Accordion`+`AccordionItem`+`AccordionHeader`+`AccordionContent`, `Breadcrumb`+`BreadcrumbItem`, `Menu`+`MenuTrigger`+`MenuContent`+`MenuItem`+`MenuSeparator`+`MenuLabel`, `Navbar`+`NavbarLogo`+`NavbarNav`+`NavbarLink`+`NavbarActions`+`NavbarMenuButton`, `Sidebar`+`SidebarHeader`+`SidebarNav`+`SidebarItem`+`SidebarFooter`+`SidebarToggle`+`SidebarDivider`+`SidebarSection`, `Stepper`+`Step`, `Table` (+`TableHead`/`Body`/`Foot`/`Row`/`HeaderCell`/`Cell`/`Caption`), `Tabs`+`TabsList`+`TabsTrigger`+`TabsContent` |
250
+
251
+ Hooks públicos: `useTheme`, `useToast`, `useControllableState` + el componente helper `FloatingTreeRoot` (anidación de floats). Detalle completo en la sección [Hooks públicos del DS](#hooks-públicos-del-ds) (D11 beta.24).
252
+
253
+ > **D11 / B-04 (RC1+beta.24)**: los context hooks internos (`useAccordion`,
254
+ > `useTabs`, etc.) quedan retirados del API público. Su shape está
255
+ > acoplada a internals del compound; exponerlos firmaría una API que
256
+ > bloquearía refactor a Floating UI. JSDoc marca explícitamente
257
+ > `@public` / `@internal` (D11). Detalle en
258
+ > `docs/decisions/D11-hooks-disposition.md`.
259
+
260
+ ## API CSS pública
261
+
262
+ Las clases `.ig-*` **documentadas en esta sección** (las tablas por componente) son **API pública del paquete**
263
+ y se pueden aplicar directamente sobre HTML estático sin montar React (útil
264
+ para emails, PDFs, demos rápidas, fragmentos server-rendered). El convenio
265
+ es uniforme: **clase base + modifiers de variant / size / shape / state**,
266
+ todos kebab-case y todos compuestos por concatenación con guion.
267
+
268
+ Tabla mínima (clase base por componente). Los modifiers siguen el patrón
269
+ estándar `{base}-{variant}` / `{base}-{size}` y se documentan exhaustivamente
270
+ en Storybook → *Fundamentos / CSS API pública* — [referencia con
271
+ tablas detalladas y ejemplos HTML por los 32 componentes](https://igoded.es/?path=/docs/fundamentos-css-api-publica--docs).
272
+
273
+ | Componente | Clase base | Modifiers principales |
274
+ |-------------------------|---------------------------|----------------------------------------------------------------------------------------|
275
+ | `Accordion` | `.ig-accordion` | `-item`, `-item-open`, `-header`, `-content`, `-icon` |
276
+ | `Alert` | `.ig-alert` | variants `-brand`/`-secondary`/`-success`/`-warning`/`-danger`/`-info`/`-neutral`, `-title`, `-description`, `-icon`, `-close` |
277
+ | `Avatar` / `AvatarGroup`| `.ig-avatar` | sizes `-xs`…`-xl`, `-square`, `-group`, `-status-online`/`-busy`/`-away`/`-offline` |
278
+ | `Badge` | `.ig-badge` | variants color, sizes, `-pill`, `-dot` |
279
+ | `Breadcrumb` | `.ig-breadcrumb` | `-item`, `-current`, `-separator` |
280
+ | `Button` | `.ig-btn` | variants `-brand`/`-secondary`/`-success`/`-warning`/`-danger`/`-info`, `-outline-*`, `-ghost-*`, `-link`, sizes `-xs`…`-xl`, `-block`, `-icon`, `-loading` |
281
+ | `Card` | `.ig-card` | `-header`, `-body`, `-footer`, `-image`, `-divider`, `-bordered` |
282
+ | `Checkbox` | `.ig-checkbox` | variants color, sizes |
283
+ | `Chip` | `.ig-chip` | variants color, `-close` |
284
+ | `Divider` | `.ig-divider` | variants color, `-vertical`, `-dashed`, `-with-text` |
285
+ | `Menu` | `.ig-menu` | `-trigger`, `-content`, `-item`, `-separator`, `-label` *(portal real via Floating UI, D2/D7 beta.24)* |
286
+ | `Input` / `Textarea` / `NativeSelect` | `.ig-input` · `.ig-textarea` · `.ig-native-select` | `-invalid`, `-valid`, `-addon`, `-group`, `-textarea-auto`, `-select-auto` |
287
+ | `Dialog` / `AlertDialog` | `.ig-dialog` *(<dialog> nativo)* | `-header`, `-body`, `-footer`, `-close`, sizes `-sm`…`-xl`/`-full`, `-backdrop-blur`/`-dark`/`-light`/`-no-backdrop`, `-loading`. `AlertDialog` aplica `role="alertdialog"` + `closeOnBackdrop=false` default (D8 beta.24) |
288
+ | `Navbar` | `.ig-navbar` | `-logo`, `-nav`, `-actions`, `-link`, `-menu-button`, `-sticky`/`-fixed` |
289
+ | `Pagination` | `.ig-pagination` | variants color, `-active` |
290
+ | `Progress` | `.ig-progress` | `-bar`, variants color, sizes |
291
+ | `Radio` | `.ig-radio` | variants color, sizes |
292
+ | `Rating` | `.ig-rating` | sizes `-sm`/`-md`/`-lg`, `-readonly` |
293
+ | `Sidebar` | `.ig-sidebar` | `-header`, `-nav`, `-item`, `-section`, `-footer`, `-toggle`, `-divider`, `-collapsed` |
294
+ | `Skeleton` | `.ig-skeleton` | `-avatar`, `-avatar-lg`, `-text`, `-rect`, `-circle` |
295
+ | `Slider` | `.ig-slider` | `-group`, `-value` |
296
+ | `Spinner` | `.ig-spinner` | variants color, sizes |
297
+ | `Stepper` | `.ig-stepper` | `-labeled` |
298
+ | `Switch` / `ThemeToggle`| `.ig-switch` | variants color, sizes |
299
+ | `Table` | `.ig-table` | `-bordered`, `-auto`, `-row`, `-header-cell`, `-cell`, `-caption` |
300
+ | `Tabs` | `.ig-tabs` | variants color, `-content`, `-list`, `-tab`, `-panel` |
301
+ | `Timeline` | `.ig-timeline` | `-item`, `-content`, `-date` |
302
+ | `Toast` | `.ig-toast` | placement `-top-left`/`-top-right`/`-bottom-left`/`-bottom-right`/`-bottom-center` … |
303
+ | `Tooltip` | `.ig-tooltip` | placement `-place-top`/`-place-bottom`/`-place-left`/`-place-right`, variants `-brand`/`-secondary`/… |
304
+
305
+ > Los modifiers son aditivos: una variante completa de Button es, p.ej.,
306
+ > `<button class="ig-btn ig-btn-brand ig-btn-lg ig-btn-block">…</button>`.
307
+ > La librería React monta exactamente estas mismas clases — los componentes
308
+ > son wrappers delgados sobre la capa CSS.
309
+
310
+ ## Patrones recurrentes
311
+
312
+ ### Controlled vs. uncontrolled
313
+
314
+ Componentes con estado (`Accordion`, `Dialog`, `AlertDialog`, `Menu`,
315
+ `Pagination`, `Rating`, `Sidebar`, `Slider`, `Stepper`, `Switch`, `Tabs`,
316
+ `ThemeToggle`) soportan ambos modos. Convención DS-wide cerrada en
317
+ beta.24 (D3/D4/D5/D6): `{prop}?` + `default{Prop}?` + `on{Prop}Change`.
318
+
319
+ ```tsx
320
+ // Uncontrolled — el componente gestiona su estado.
321
+ <Tabs defaultValue="perfil">…</Tabs>
322
+
323
+ // Controlled — la app gestiona el estado.
324
+ const [tab, setTab] = useState("perfil");
325
+ <Tabs value={tab} onValueChange={setTab}>…</Tabs>
326
+ ```
327
+
328
+ Convención completa por componente:
329
+
330
+ | Componente | Controlled | Uncontrolled | Callback |
331
+ |---|---|---|---|
332
+ | Accordion | `value` | `defaultValue` | `onValueChange` |
333
+ | Dialog / AlertDialog | `open` | `defaultOpen` | `onOpenChange` |
334
+ | Pagination | `page` | `defaultPage` | `onPageChange` |
335
+ | Rating | `value` | `defaultValue` | `onValueChange` |
336
+ | Sidebar | `collapsed` | `defaultCollapsed` | `onCollapsedChange` |
337
+ | Slider | `value` | `defaultValue` | `onValueChange` |
338
+ | Stepper | `active` | `defaultActive` | `onActiveChange` |
339
+ | Switch | `checked` | `defaultChecked` | `onCheckedChange` |
340
+ | Tabs | `value` | `defaultValue` | `onValueChange` |
341
+ | ThemeToggle | `theme` | `defaultTheme` | `onThemeChange` |
342
+
343
+ `Dialog` y `AlertDialog` (D6/D8 beta.24) además aceptan
344
+ `<DialogTrigger>` / `<AlertDialogTrigger>` para abrir sin necesidad de
345
+ gestionar `open` externamente:
346
+
347
+ ```tsx
348
+ <Dialog defaultOpen={false}>
349
+ <DialogTrigger className="ig-btn ig-btn-brand">Abrir</DialogTrigger>
350
+ <DialogContent>
351
+ <DialogHeader>Título <DialogClose /></DialogHeader>
352
+ <DialogBody>Contenido</DialogBody>
353
+ </DialogContent>
354
+ </Dialog>
355
+ ```
356
+
357
+ ### Tema light/dark
358
+
359
+ Tres opciones según necesidad:
360
+
361
+ 1. **Toggle UI listo**: `<ThemeToggle />` (persiste en `localStorage`,
362
+ aplica `data-theme` a `<html>`, SSR-safe).
363
+ 2. **Hook programático**: `const { theme, toggleTheme, setTheme } = useTheme()`
364
+ para integrarlo en menús de ajustes.
365
+ 3. **Manual**: `document.documentElement.dataset.theme = "dark"` en cualquier
366
+ momento.
367
+
368
+ Para evitar el flash de tema incorrecto en SSR (Next.js, Remix), inyecta un
369
+ script blocking en `<head>` que aplique `data-theme` antes del paint:
370
+
371
+ ```html
372
+ <script>
373
+ (function () {
374
+ // Orden de prioridad: storage > preferencia del sistema > dark (default
375
+ // del DS desde 1.0.0-beta.3 — branding dark-first). Sin esto, hay un
376
+ // flash de tema incorrecto entre el primer paint server y el primer
377
+ // paint cliente cuando el usuario tiene tema persistido distinto.
378
+ try {
379
+ var stored = localStorage.getItem("theme");
380
+ var systemDark =
381
+ typeof window.matchMedia === "function" &&
382
+ window.matchMedia("(prefers-color-scheme: dark)").matches;
383
+ var t = stored || (systemDark ? "dark" : "light") || "dark";
384
+ document.documentElement.dataset.theme = t;
385
+ } catch (e) {
386
+ document.documentElement.dataset.theme = "dark";
387
+ }
388
+ })();
389
+ </script>
390
+ ```
391
+
392
+ ### Hooks públicos del DS
393
+
394
+ El DS expone cuatro símbolos como API pública estable (`@public` en su
395
+ JSDoc). Importables directamente desde `"reactigoded"`:
396
+
397
+ | Símbolo | Para qué sirve | Return type |
398
+ |---|---|---|
399
+ | `useTheme()` | Lee/escribe el tema activo (`data-theme` en `<html>`). Observer con `useSyncExternalStore`, SSR-safe. | `UseThemeReturn` |
400
+ | `useControllableState()` | Pattern controlled/uncontrolled estándar para componentes con estado. Soporta modo `derive()` para fuentes externas (storage, MediaQuery). | `UseControllableStateReturn<T>` |
401
+ | `useToast()` | Dispara toasts desde cualquier hijo de `<ToastProvider>`. Devuelve `{ toast, dismiss, dismissAll }`. | `UseToastReturn` |
402
+ | `FloatingTreeRoot` | Componente. Envuelve la app si anidas Tooltips/Popovers/Menus del DS y quieres cascade dismiss. Opt-in: sin el wrapper, cada float opera independiente. | — |
403
+
404
+ ```tsx
405
+ import {
406
+ useTheme,
407
+ useControllableState,
408
+ useToast,
409
+ FloatingTreeRoot,
410
+ type UseToastReturn,
411
+ } from "reactigoded";
412
+ ```
413
+
414
+ Hooks `useDropdown` / `useTabs` / `useFloatingNode` / `useSidebar` / etc. NO son
415
+ públicos — son detalle de implementación de cada componente. Detalle completo
416
+ en [`docs/decisions/D11-hooks-disposition.md`](docs/decisions/D11-hooks-disposition.md).
417
+
418
+ ### Accesibilidad
419
+
420
+ - Todos los componentes interactivos siguen el patrón [WAI-ARIA APG](https://www.w3.org/WAI/ARIA/apg/) más cercano: `role`, `aria-*`, keyboard nav, focus management.
421
+ - Los textos por defecto (`aria-label`, `closeLabel`, `prevLabel`, etc.) están
422
+ **en español**. Para otros idiomas, pasa la prop con tu traducción:
423
+
424
+ ```tsx
425
+ <Pagination
426
+ prevLabel="Previous"
427
+ nextLabel="Next"
428
+ aria-label="Pagination"
429
+
430
+ />
431
+ ```
432
+
433
+ - `Dialog` / `AlertDialog` usan `<dialog>` HTML nativo (focus trap,
434
+ ESC, top-layer y `aria-modal` automáticos). `AlertDialog` aplica
435
+ `role="alertdialog"` + `closeOnBackdrop=false` por defecto (D8).
436
+ - `Tooltip` inyecta `aria-describedby` en el child y un `<span role="tooltip">`
437
+ sr-only para lectores de pantalla.
438
+
439
+ ### SSR / hydration
440
+
441
+ - Todos los componentes son SSR-safe: `renderToString` no lanza con
442
+ ningún componente público (verificado en `src/__ssr__.test.tsx`,
443
+ 37 casos sobre los 32 componentes raíz).
444
+ - Componentes que necesitan estado del cliente (ej. `ThemeToggle`,
445
+ para sincronizarse con un script anti-flash que ya escribió
446
+ `data-theme` en `<html>` antes de la hidratación) leen el DOM
447
+ detrás de guards `typeof document !== "undefined"`. En server caen
448
+ a defaults sensatos sin crashear; en cliente recuperan el estado
449
+ real evitando hydration mismatches.
450
+ - `<Dialog>` / `<AlertDialog>` no llaman `showModal()` en server (el
451
+ `<dialog>` queda con `display:none` hasta que el efecto cliente lo
452
+ abre — sin flash).
453
+ - `<Toast>` se renderiza inline en SSR (no portal) hasta que
454
+ `document.body` está disponible.
455
+ - Los effects (`useEffect`, `useLayoutEffect`) corren solo en
456
+ cliente — comportamiento React estándar.
457
+
458
+ ## Browserslist
459
+
460
+ Targets oficiales (últimas 2 versiones de Chrome, Firefox, Safari, Edge):
461
+
462
+ - `<dialog>.showModal()`: 98% global ✓
463
+ - `color-mix()`: 95% ✓
464
+ - `backdrop-filter`: 97% ✓
465
+ - `field-sizing` (`Textarea auto`): Chrome 123+, Safari 17.4+; **Firefox aún
466
+ no** — el `Textarea auto` en Firefox cae al comportamiento `rows` por
467
+ defecto.
468
+
469
+ ## Scripts (dev)
470
+
471
+ ```bash
472
+ npm run dev # playground (http://localhost:5173)
473
+ npm run storybook # docs/demos (http://localhost:6006)
474
+ npm run build # dist/ con index.js + index.cjs + .d.ts + styles/
475
+ npm run test:unit # vitest happy-dom (suite completa)
476
+ npm run test:unit:ci # como test:unit, con isolate=true + pool=forks (CI estricto)
477
+ npm run test:contrast # CSS estático: pares bg/color + geometría OKLCH
478
+ npm run test:storybook # vitest browser Chromium + axe-a11y (DOM real)
479
+ npm run verify # lint + typecheck + test:unit + test:contrast + build + test:storybook + verify:size
480
+ ```
481
+
482
+ **`test:contrast` vs `test:storybook`** — son guardrails complementarios,
483
+ no redundantes. `test:contrast` parsea `igoded-components.css` con postcss
484
+ y valida cada regla que declara `color` + `background[-color]` en el mismo
485
+ bloque, contra los 14 hex de los pares cardinales en ambos temas. Es rápido
486
+ y atrapa la mayoría de regresiones, pero **no cubre**: alphas/tinted con
487
+ `color-mix(... transparent)` o `rgba(... .5)` (no compone contra el padre),
488
+ combinators padre-hijo en reglas separadas (solo ve pares dentro del mismo
489
+ bloque), gradients ni `currentColor`. Para esos casos depende
490
+ `test:storybook`, que ejecuta cada story en chromium headless con axe-core
491
+ sobre el DOM final ya pintado.
492
+
493
+ ## Estructura
494
+
495
+ ```
496
+ src/
497
+ ├── components/ # 32 carpetas (1 por componente raíz)
498
+ ├── hooks/ # useTheme
499
+ ├── utils/ # cn (wrapper de clsx)
500
+ ├── styles/ # igoded-{tokens,base,components,design,reset,state-css}.css
501
+ └── index.ts # entry del paquete
502
+ scripts/
503
+ └── strip-orphan-css.mjs # limpia utilities de state-css apuntando a tokens eliminados
504
+ ```
505
+
506
+ ## Decisiones técnicas
507
+
508
+ - **`ref` como prop** (React 19) — sin `forwardRef`, mejor inferencia.
509
+ - **Sin `PropTypes`** — TypeScript estricto.
510
+ - **`exactOptionalPropertyTypes: true`** — `prop={undefined}` no equivale a
511
+ no pasar la prop.
512
+ - **CSS-first** — la lógica visual vive en `.css`; los componentes React
513
+ son wrappers delgados que aplican clases condicionalmente.
514
+ - **Sin transpilación CSS** — el CSS publicado usa `color-mix()`,
515
+ `backdrop-filter`, `@container`, `field-sizing`. Targets modernos
516
+ (browserslist arriba).
517
+ - **Sourcemaps desactivados en publish** — ni sourcemaps de JS ni
518
+ `.d.ts.map` se publican. El go-to-definition del consumer cae en los
519
+ `.d.ts` (tipos); el source `.ts` no se shippea (`files`), así que un
520
+ `.d.ts.map` colgaría apuntando a `src` ausente (#23).
521
+ - **`sideEffects: ["**/*.css"]`** — bundlers tree-shake JS pero conservan
522
+ CSS imports.
523
+ - **`console.error` legítimos de `tabbable`** — `tabbable` es dep
524
+ transitiva de `@floating-ui/react` (vía `Tooltip` y futuros
525
+ `Popover`/`HoverCard`). Para focus management sobre nodos sin
526
+ tabIndex válido, emite `console.error` del propio upstream. **No
527
+ es bug del DS** — viene del ecosistema Floating UI. El gate de CI
528
+ `bundle-no-dev-warns` filtra solo el prefijo `[reactigoded]` para
529
+ no confundir esos errors legítimos con regresiones nuestras.
530
+
531
+ ## Desarrollo
532
+
533
+ Para trabajar sobre el repo (no como consumidor del paquete):
534
+
535
+ ```bash
536
+ git clone https://github.com/ivangc1/reactigoded.git
537
+ cd reactigoded
538
+ npm ci
539
+ ```
540
+
541
+ `npm ci` plano resuelve limpio: el ERESOLVE de devDeps (eslint 10 vs
542
+ `eslint-plugin-jest-dom`/`jsx-a11y` con peer `^9`) se cierra con
543
+ `overrides` en package.json (#138), y el bump de toolchain
544
+ (storybook 10.5 / vitest 4) alineó el peer de `@vitest/browser`. Ya no
545
+ hace falta `--legacy-peer-deps` (verificado: `npm ci` plano instala 532
546
+ paquetes sin ERESOLVE).
547
+
548
+ **No afecta a los consumidores del paquete**: cuando alguien instala
549
+ `reactigoded` como dep, solo se resuelven `peerDependencies` (`react`,
550
+ `react-dom`, `@floating-ui/react`). Las devDependencies del repo no
551
+ viajan al consumer.
552
+
553
+ ## Licencia
554
+
555
+ MIT — ver [LICENSE](./LICENSE).
556
+