reactigoded 1.0.0-beta.26 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +183 -6
- package/README.md +17 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,17 +7,194 @@ versionado [SemVer](https://semver.org/lang/es/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
_Sin cambios desde `1.0.0-rc.1`._
|
|
11
|
+
|
|
12
|
+
## [1.0.0-rc.1] — 2026-07-19 · **API pública congelada**
|
|
13
|
+
|
|
14
|
+
Primer release candidate. **La superficie pública de 1.0 queda congelada**: a partir de
|
|
15
|
+
aquí, cambiarla exige un bump MAJOR. Cierra el gate `claudegate6` (auditoría con cruce de
|
|
16
|
+
dos auditores independientes A+B sobre `beta.26`) — 2 BLOCKER, 3 HIGH, 6 MEDIUM y 4 LOW.
|
|
17
|
+
|
|
18
|
+
Este documento declara también **lo que NO se hizo y por qué**: en un release de freeze,
|
|
19
|
+
los residuales declarados valen más que una lista solo de logros.
|
|
20
|
+
|
|
10
21
|
### Cambiado — BREAKING (última ventana antes de 1.0)
|
|
11
22
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
Renombres de API pública para eliminar colisiones de nombre antes de congelar. Se hacen
|
|
24
|
+
ahora porque el paquete tenía **0 consumidores en npm**; después de 1.0 costarían un major.
|
|
25
|
+
|
|
26
|
+
- Clases `.ig-tooltip-color-*` → `.ig-tooltip-*` (el infijo `-color-` era dialecto local; la doc ya prometía la forma sin él).
|
|
27
|
+
- Clase `.ig-navbar-brand` → `.ig-navbar-logo` y componente `NavbarBrand` → **`NavbarLogo`** (`brand` colisionaba con el eje de rol de color; el slot es el logo).
|
|
28
|
+
- Clases `.ig-input-error`/`.ig-input-success` → `.ig-input-invalid`/`.ig-input-valid` y valores del prop `state` (`"invalid"`/`"valid"`), alineados con `aria-invalid`.
|
|
29
|
+
|
|
30
|
+
Además, 4 correcciones de documentación de clases que **se documentaban pero no shippean**:
|
|
31
|
+
`ig-btn-md`, `ig-timeline-dot-default`, `ig-step-interactive`, `ig-text-on-cinis`.
|
|
16
32
|
|
|
17
33
|
### Añadido
|
|
18
34
|
|
|
19
|
-
- **
|
|
20
|
-
|
|
35
|
+
- **Freeze de API pública (§5.13)**. La superficie estable de 1.0 se congela en
|
|
36
|
+
`src/_audit/public-api-names.json`: **332 clases** de componente, **2 classHooks**,
|
|
37
|
+
**6 data-attributes** de estado y **37 tokens Tier-2**. Protegido por el gate
|
|
38
|
+
`scripts/check-public-api-names.mjs` (verifica `JSON ⊆ dist`, encadenado en `verify:unit`
|
|
39
|
+
**post-build**). Editar el freeze exige **bump MAJOR** + entrada aquí.
|
|
40
|
+
**Alcance declarado del gate: solo integridad.** Caza el rename *accidental* que olvida
|
|
41
|
+
actualizar el contrato; **no** impide el rename deliberado — así es exactamente como se
|
|
42
|
+
renombra, a propósito y con major.
|
|
43
|
+
**Fuera del freeze por declaración explícita** (no por silencio): la **capa utility** de
|
|
44
|
+
`state.css` (`ig-bg-*`, `ig-text-*`, `ig-flex`, `ig-gap-*`…), por ser opt-in y
|
|
45
|
+
**experimental** — su vocabulario puede evolucionar sin major hasta que se declare estable
|
|
46
|
+
aquí; y los **tokens Tier-1 y Tier-3**, porque una escala conserva la libertad de perder un
|
|
47
|
+
escalón sin major. Documentado en `docs/CSSAPI.mdx` y `docs/DesignTokens.mdx`.
|
|
48
|
+
- **Publicación en npm.** El paquete existe en el registro (`reactigoded`). Ver
|
|
49
|
+
*Limitaciones conocidas* para el estado de los dist-tags.
|
|
50
|
+
- **Pipeline de release automatizado** vía **Trusted Publishing (OIDC)**: sin tokens
|
|
51
|
+
almacenados, sin 2FA/OTP, con **provenance firmada** automáticamente. Se dispara al
|
|
52
|
+
pushear un tag `v*` y publica tras el `verify` completo, registrando versión, dist-tag y
|
|
53
|
+
commit en la GitHub Release.
|
|
54
|
+
|
|
55
|
+
### Corregido
|
|
56
|
+
|
|
57
|
+
**BLOCKER**
|
|
58
|
+
|
|
59
|
+
- **Gate `@server-safe`: de denylist frágil a fail-closed.** `CLIENT_GLOBALS` era una
|
|
60
|
+
**denylist de ~46 nombres**, pero `lib.dom.d.ts` declara ~826 globals client-only que
|
|
61
|
+
lanzan `ReferenceError` en Node: **~780 pasaban en silencio** (`HTMLElement`, `self`,
|
|
62
|
+
`CSS`, `instanceof Element`…), incluso por ruta transitiva. Reemplazado por una
|
|
63
|
+
**whitelist fail-closed** (`SAFE_GLOBALS` = builtins ES ∪ globals de Node, menos
|
|
64
|
+
denegaciones intencionales y overclaims verificados), anclada al engine mínimo (Node
|
|
65
|
+
22.12) mediante la matriz CI. Ahora un global DOM nuevo **se caza solo**: un falso
|
|
66
|
+
positivo es ruido corregible, no un crash en producción SSR.
|
|
67
|
+
- **Marcador `@server-safe` anidado = fail-open silencioso.** La detección solo miraba los
|
|
68
|
+
statements top-level, así que un marcador en posición anidada no marcaba **y no avisaba**.
|
|
69
|
+
Ahora recorre el AST completo y **lanza** en posición no soportada (fail-loud).
|
|
70
|
+
|
|
71
|
+
**HIGH**
|
|
72
|
+
|
|
73
|
+
- **`Slot` descartaba children en silencio.** Con más de un hijo renderizaba solo el
|
|
74
|
+
primero, borrando CTAs y nodos accesibles sin aviso. Ahora devuelve `null`: fallo
|
|
75
|
+
observable en vez de pérdida silenciosa.
|
|
76
|
+
- **`composeRefs` descartaba los cleanups de refs de React 19.** Un callback ref que
|
|
77
|
+
devuelve función de limpieza nunca la ejecutaba al desmontar (y recibía un `ref(null)`
|
|
78
|
+
inesperado), **fugando observers**. Retorno ensanchado a `void | (() => void)` con
|
|
79
|
+
recolección y combinación de cleanups.
|
|
80
|
+
- **`ContrastPairs` con aserción unidireccional.** Solo comprobaba el límite inferior, así
|
|
81
|
+
que un drift **hacia arriba** (cardinales separándose) pasaba silencioso. Ahora es una
|
|
82
|
+
banda de dos lados, más un assert fail-loud de que todo cardinal del allowlist esté
|
|
83
|
+
mapeado a variante.
|
|
84
|
+
|
|
85
|
+
**MEDIUM**
|
|
86
|
+
|
|
87
|
+
- `clsx` faltaba en el **comando de install del README**: quien lo siguiera y lo omitiera se
|
|
88
|
+
encontraba `reactigoded/cn` reventando con `ERR_MODULE_NOT_FOUND`. *(El packaging no se
|
|
89
|
+
toca: `clsx` es peer externalizada por decisión cerrada de beta.24.)*
|
|
90
|
+
- **133 `.d.ts.map` colgantes**: apuntaban a `../src/*.ts`, que **no se publica** (`files` no
|
|
91
|
+
incluye `src`), rompiendo el go-to-definition del consumer y engordando el tarball.
|
|
92
|
+
`declarationMap: false` — **decisión final**.
|
|
93
|
+
- **`consumer-pack` validaba 2 de 36 exports** server-safe desde el tarball; el bug que
|
|
94
|
+
motivó el gate (259 errores TS2834 bajo NodeNext) seguía latente en los otros 34. Ahora
|
|
95
|
+
materializa los 36 en ambas resoluciones (Bundler y NodeNext).
|
|
96
|
+
- **Rutas UNC** (`//host/share`) colapsaban a `/` en el gate, rompiendo la ejecución en esos
|
|
97
|
+
paths. Fix simétrico al del drive-letter.
|
|
98
|
+
- **Crash de `attw` en ARM64** — resuelto upstream y verificado en vivo.
|
|
99
|
+
- **~106 líneas de warnings en stderr** durante los tests. Política nueva: solo se permiten
|
|
100
|
+
los dev-warnings propios del DS; cualquier otro `console` **falla el test**. stderr = 0.
|
|
101
|
+
|
|
102
|
+
**LOW**
|
|
103
|
+
|
|
104
|
+
- **ERESOLVE en `npm ci` plano** (eslint 10 vs plugins con peer `^9`): cerrado con
|
|
105
|
+
`overrides` quirúrgico. `--legacy-peer-deps` **eliminado de los 3 jobs de CI**.
|
|
106
|
+
- **`npm run verify` ≠ CI**: `test:no-dev-warns` corría en CI pero no en `verify`, así que
|
|
107
|
+
`prepublishOnly` podía saltárselo. Encadenado.
|
|
108
|
+
- **`build-storybook` pasaba con warnings**: glob `.mdx` vacío eliminado y umbral de chunk
|
|
109
|
+
ajustado. *(Ver Diferido para el tercer warning, que no se toca a propósito.)*
|
|
110
|
+
- **`npm publish --dry-run` inutilizable**: npm propaga `npm_config_dry_run` a los comandos
|
|
111
|
+
anidados, así que el `npm pack` del gate anunciaba el tarball **sin escribirlo** →
|
|
112
|
+
el ensayo previo a una operación irreversible fallaba siempre. Neutralizada la herencia.
|
|
113
|
+
|
|
114
|
+
### Garantía `@server-safe` validada contra Vercel Edge **real**
|
|
115
|
+
|
|
116
|
+
El catálogo de globals permitidos se derivaba de `@edge-runtime/vm`, un sandbox sobre Node
|
|
117
|
+
que **filtra globals Node-shared** (~95% fiel). Un probe desplegado a Vercel Edge de
|
|
118
|
+
producción cerró ese ~5%:
|
|
119
|
+
|
|
120
|
+
- **3 falsos negativos cazados** — `WeakRef`, `FinalizationRegistry` y `DOMException`
|
|
121
|
+
aparecían como presentes por la fuga de Node, pero **no existen en Vercel Edge**. Restados
|
|
122
|
+
de `SAFE_GLOBALS` (set nuevo `EDGE_MISSING_REAL`). Cierra un fallo latente que habría
|
|
123
|
+
dejado pasar un `new WeakRef(...)` que crashea en producción.
|
|
124
|
+
- **Premisas confirmadas** (`createObjectURL`/`revokeObjectURL` lanzan, `WebAssembly.compile`
|
|
125
|
+
lanza `CompileError`, `new Function` lanza `EvalError`, `performance.eventLoopUtilization`
|
|
126
|
+
ausente) y **0 fail-opens** en los 22 guards browser-only.
|
|
127
|
+
- **Validado cross-región**: `lhr1` vs `iad1`, **0 diferencias en 1489 puntos** medidos → lo
|
|
128
|
+
pineado es propiedad del *runtime*, no de una región.
|
|
129
|
+
|
|
130
|
+
Medición reproducible en `scripts/runtime-oracle/vercel/`.
|
|
131
|
+
|
|
132
|
+
### `exactOptionalPropertyTypes` — las 2 fronteras
|
|
133
|
+
|
|
134
|
+
307 props públicas se ensancharon a `?: T | undefined` para consumers con
|
|
135
|
+
`exactOptionalPropertyTypes: true`. **Dos clases quedan fuera a propósito**, porque
|
|
136
|
+
ensancharlas rompería su semántica:
|
|
137
|
+
|
|
138
|
+
1. **Discriminantes con literal `?: undefined`** (3): `NavbarLogo`, `SidebarItem` y
|
|
139
|
+
`MenuItem` — el `undefined` literal *es* lo que activa la rama `button`/`div` del
|
|
140
|
+
discriminated union.
|
|
141
|
+
2. **Exclusiones con `?: never`** (8): en `Accordion`, `Avatar` (×3), `BreadcrumbItem` y
|
|
142
|
+
`useControllableState` (×3) — `never` *es* el mecanismo de exclusión de variantes.
|
|
143
|
+
|
|
144
|
+
Inventario completo: `node scripts/eopt-classify.mjs`.
|
|
145
|
+
|
|
146
|
+
### Limitaciones conocidas
|
|
147
|
+
|
|
148
|
+
- **Paquete ESM-only.** Desde CJS hay que usar `import()` dinámico. El engine mínimo es Node
|
|
149
|
+
`>=22.12`.
|
|
150
|
+
- **`npm install reactigoded` devuelve `1.0.0-beta.26`, no el rc.1.** El dist-tag `latest`
|
|
151
|
+
quedó apuntando a la beta en la primera publicación y **npm no permite retirarlo**
|
|
152
|
+
(responde 400). `--tag rc` no lo mueve. Para el rc.1: `npm install reactigoded@rc`. Se
|
|
153
|
+
corrige solo al publicar `1.0.0` final.
|
|
154
|
+
- **Go-to-definition aterriza en los `.d.ts`**, no en el `.ts` original (consecuencia de
|
|
155
|
+
`declarationMap: false`). Shippear `src` + maps es aditivo y se evalúa post-1.0.
|
|
156
|
+
- **Falsos positivos conocidos del gate `@server-safe`** — todos *fail-closed*, ninguno
|
|
157
|
+
oculta código ejecutable: `process.env` con guard `typeof` se flagea (workaround:
|
|
158
|
+
`import.meta.env`); 10 globals de streams/eventos presentes en Edge real siguen flageados
|
|
159
|
+
por sobre-estrictez deliberada; `console.clear` se flagea aunque funciona.
|
|
160
|
+
- **El marcador `@server-safe` debe ir en su propia línea.** Prosa *antes* del marcador en la
|
|
161
|
+
misma línea no marca **y no avisa** (residual declarado abajo).
|
|
162
|
+
- **Contraste `axis` vs `kobalium` en tema oscuro**: ΔE `0.0522`, allowlisteado
|
|
163
|
+
conscientemente. Pueden confundirse si quedan adyacentes.
|
|
164
|
+
- **CSP estricta con el Storybook del DS**: el script propio está 100% externalizado, pero
|
|
165
|
+
Storybook inyecta upstream un `<script>` inline. Requiere `'unsafe-inline'` o un nonce.
|
|
166
|
+
|
|
167
|
+
### Diferido y residual — con su razón
|
|
168
|
+
|
|
169
|
+
**No hecho a propósito** (no es deuda olvidada):
|
|
170
|
+
|
|
171
|
+
- **Coverage de `perceptual-allowlist.json?import`** — *verificado no-issue*. Lo excluido es
|
|
172
|
+
un JSON de **datos, no código**; coverage **no es gate**; y en vitest 4
|
|
173
|
+
`coverageConfigDefaults.exclude` viene vacío, así que setearlo habría borrado los excludes
|
|
174
|
+
built-in y **deflactado** el número. Arreglarlo era un falso arreglo.
|
|
175
|
+
- **Tercer warning de `build-storybook`** (`Skipping docgen for preview.tsx`) — es Storybook
|
|
176
|
+
informando de que saltó **correctamente** un fichero de configuración. Silenciarlo exigiría
|
|
177
|
+
parchear un plugin minificado.
|
|
178
|
+
|
|
179
|
+
**Residual por diseño** (fronteras declaradas, no huecos):
|
|
180
|
+
|
|
181
|
+
- **Data-flow / provenance** — el gate no sigue valores a través de llamadas, parámetros,
|
|
182
|
+
fronteras cross-módulo ni round-trips de representación. Cazar solo el subconjunto
|
|
183
|
+
sintáctico obvio sería **falsa cobertura**.
|
|
184
|
+
- **Frontera del eval-sink** — se caza el *token presente en su sitio*; el **token
|
|
185
|
+
ensamblado** (`"a"+"b"`, `fromCharCode`, `join`) es residual: hay infinitas escrituras
|
|
186
|
+
equivalentes y cazar una sería teatro. Con cláusula de caducidad si `@server-safe` pasara a
|
|
187
|
+
ser frontera de confianza sobre código no auditado.
|
|
188
|
+
- **Prosa antes del marcador en la misma línea** — se tolera en silencio porque el
|
|
189
|
+
discriminador intención-vs-mención dentro de prosa es genuinamente ambiguo
|
|
190
|
+
(`/** not yet @server-safe */` es una mención legítima que no debe lanzar).
|
|
191
|
+
|
|
192
|
+
**Diferido a releases posteriores**: `process.env` con guard (rc.2); derivación sistemática
|
|
193
|
+
de globals Edge con las patas **workerd** y **Deno** (la de Vercel Edge ya está cerrada);
|
|
194
|
+
re-derivar `EDGE_MISSING_GLOBALS` desde Edge real para retirar la receta basada en
|
|
195
|
+
`@edge-runtime/vm`; `typescript@7` como autoritativo (bloqueado por `typescript-eslint` y
|
|
196
|
+
porque el port nativo no expone la Compiler API que usan los gates AST); `attw` como gate de
|
|
197
|
+
CI; go-to-definition al source.
|
|
21
198
|
|
|
22
199
|
## [1.0.0-beta.26] — 2026-05-29 (bloque claudegate5 / beta.27 cerrado)
|
|
23
200
|
|
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@ Design system de **igoded** — 32 componentes React 19 + TypeScript estricto
|
|
|
4
4
|
sobre un CSS modular utility-first state-driven (`tokens` / `base` /
|
|
5
5
|
`components` + `reset` opt-in + `state` opt-in).
|
|
6
6
|
|
|
7
|
-
> **Estado**:
|
|
7
|
+
> **Estado**: pre-1.0 — la versión publicada vive en
|
|
8
|
+
> [Instalación](#instalación), no aquí (duplicarla derivaba en cada bump:
|
|
9
|
+
> este banner decía `beta.25` con el paquete ya en `beta.26`).
|
|
8
10
|
> Paleta cardinal estable: 7 cardinales con geometría OKLCH dual
|
|
9
11
|
> (L_lux≈0.32 / L_nox≈0.84 / ΔH≤10°), todos AAA contra los 5 fondos
|
|
10
12
|
> del tema en ambos modos. El cardinal `info` se llama internamente
|
|
@@ -18,9 +20,19 @@ sobre un CSS modular utility-first state-driven (`tokens` / `base` /
|
|
|
18
20
|
|
|
19
21
|
## Instalación
|
|
20
22
|
|
|
21
|
-
> **
|
|
22
|
-
>
|
|
23
|
-
|
|
23
|
+
> **Release candidate `1.0.0-rc.1`** — la API pública está **congelada**
|
|
24
|
+
> (§5.13, protegida por gate): cambiarla exige un bump MAJOR.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install reactigoded@rc react react-dom @floating-ui/react clsx
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> ⚠️ **El `@rc` es necesario.** El dist-tag `latest` quedó apuntando a
|
|
31
|
+
> `1.0.0-beta.26` en la primera publicación y npm no permite retirarlo, así que
|
|
32
|
+
> `npm install reactigoded` **a secas devuelve la beta**. Se corrige solo al
|
|
33
|
+
> publicar `1.0.0` final. Ver CHANGELOG → *Limitaciones conocidas*.
|
|
34
|
+
|
|
35
|
+
Para trabajar **sobre** la librería (o probar cambios sin publicar):
|
|
24
36
|
|
|
25
37
|
```bash
|
|
26
38
|
git clone https://github.com/ivangc1/reactigoded.git
|
|
@@ -41,7 +53,7 @@ internamente `Tooltip` (y futuros `Popover`, `HoverCard`, etc.).
|
|
|
41
53
|
Instálalo **siempre** junto a la librería:
|
|
42
54
|
|
|
43
55
|
```bash
|
|
44
|
-
npm install reactigoded react react-dom @floating-ui/react clsx
|
|
56
|
+
npm install reactigoded@rc react react-dom @floating-ui/react clsx
|
|
45
57
|
```
|
|
46
58
|
|
|
47
59
|
**`clsx` (^2.1) también es peer-dep requerido** — lo usa el helper `cn`
|