You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/process/RESEARCH-blocks-references.md

426 lines
59 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# RESEARCH — Estudio de referencia del tier blocks (paridad y superación)
> Proceso, no doctrina. Alimenta las fases 0 de `PLAN-blocks.md`: cada fiche
> de F1/F2/F3/F4 verifica contra este dossier en vez de investigar de cero.
> Encargo del usuario (2026-07-21): _"estar al menos a la par y cuanto menos
> superarlo"_. Método: 6 pistas de investigación web en paralelo sobre
> fuentes oficiales vivas, cada una contrastando el plan contra el panorama
> real y devolviendo brechas + ángulos de superación.
**Estado**: ✅ COMPLETA 2026-07-21 — 6/6 pistas recibidas y sintetizadas.
Enmiendas E-1…E-5 presentadas al usuario (ver §Síntesis; firmas se registran
en `PLAN-blocks.md` §Registro).
## Rúbrica
- **Suelo de paridad**: lo que ≥2 referencias convergen en ofrecer para un
ítem (features, props, variantes, comportamientos). Un ítem nuestro no está
"hecho" por debajo de su suelo salvo decisión explícita registrada.
- **Diferenciadores**: features únicos de una referencia que valga la pena
adoptar (con juicio, no por completismo).
- **Superación**: lo que nuestra arquitectura permite y ninguna referencia
tiene (contrato morfo introspectable, sema/percepción, tokens + density +
RTL + dark de serie, composición real vs copy-paste).
## Pistas
| # | Pista | Cubre | Estado |
| --- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| P1 | Catálogos de blocks de marketing | shadcn blocks · Tailwind Plus · Flowbite · PrimeBlocks · Relume · Untitled UI · daisyUI → F2 | lanzada |
| P2 | Blocks de aplicación + app-shell | Tailwind Plus App UI · shadcn dashboard/sidebar/login · Mantine AppShell · Tremor · AntD ProComponents · Refine · auth UIs → F3 | lanzada |
| P3 | Refs F1 (5 ligeros) | affix/anchor/empty/result/callout en AntD · Mantine · Radix Themes · Chakra · Polaris · GitHub/Docusaurus admonitions → F1.1–F1.4, F1.6 | lanzada |
| P4 | Refs F1 (2 pesados) | prose (@tailwindcss/typography · Mantine · Primer) · sidebar (shadcn EXHAUSTIVO · AntD Sider · Mantine) → F1.5, F1.7 | lanzada |
| P5 | Docs shells + docs blocks | Starlight · Fumadocs · Docusaurus · VitePress · Nextra · Mintlify · showcase/props-tables → F4 | lanzada |
| P6 | Ecosistema Svelte competidor | shadcn-svelte · Bits · Melt · Skeleton · Flowbite-Svelte · svelte-ux · nuevos Svelte-5 → el listón "mejor de Svelte" | lanzada |
## Hallazgos
### P1 — Catálogos de marketing — ✅ RECIBIDA 2026-07-21 (conteos y nombres de variante en vivo)
#### Panorama
- **shadcn/ui blocks: CERO marketing** (solo sidebar/login/signup/dashboard) — el marketing vive en registries de terceros. Su aporte es el modelo de distribución (registry + CLI + "Open in v0").
- **Tailwind Plus**: ~133 ejemplos de marketing en 16 categorías (Heroes 12 · Features 15 · Pricing 12 · CTA 11 · Stats 8 · Testimonials 8 · FAQs 7 · Footers 7 · Newsletter 6 · Team 9 · Blog 7 · Contact 7 · Content 7 · Logo Clouds 6 · Bento 3 · Headers 8) + elements (Navbars 11 · Flyout 7 · **Banners 13**) — dump estático HTML/React/Vue; **dark = segundo artefacto a la venta**.
- **Flowbite**: ~170 marketing en 28 categorías (Hero 18 con nombres capturados: carousel, phone-mockup+app-store, search-bar+datepicker, video, sign-up-in-hero…; auth y 404/500/maintenance clasificados como marketing).
- **PrimeBlocks** (relanzado, Vue-first, $599/dev): ~168 marketing (Feature 27 · Testimonial 20 · Team 12 · Navbar 12 · CTA 12 · Logo Cloud 10…).
- **Relume** (AI builder, 1.000+/plataforma): la taxonomía más ancha (31 categorías: gallery, events, careers, comparison, timeline, multi-step forms, cookie consent, link pages…); semántica débil ("Layout 249").
- **Untitled UI React**: el **casi-par más cercano** — componentes React reales con props (no dumps), la mayor profundidad por categoría (Hero 44 · Features 42 · Footers 40 · Testimonials 26 · Pricing 22 · FAQ 16 · Metrics 16) + 105 page examples; pero React-only, PRO-gated, sin tokens/RTL/density.
- **daisyUI**: sin blocks (solo templates de pago de página completa) — confirma que ninguna librería class-based shippea secciones componibles.
#### Suelo por bloque F2 (brechas concretas de nuestro v1)
| Block | Suelo/recurrencias que nos faltan |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hero | El esqueleto center\|split es correcto; la brecha es **tratamiento de media**, no conteo de layouts: presets de media (screenshot enmarcado / phone mockup / background-image cover), slot **form-in-hero** (email sign-up), **logo-strip** bajo las acciones, video embed. |
| feature-grid | **LA brecha #1 de F2**: el **split/alternante texto-vs-screenshot con lista de features** lo shippean las 5 refs y es la sección nº1 tras el hero; nuestro v1 solo tiene el grid de iconos. |
| testimonials | Falta la **cita única en spotlight** (logo + quote + avatar + autor) — la variante modal en TODAS las refs; el grid es minoría (2 de 8 en TW). |
| faq | Falta la **lista estática 2/3-columnas** (mayoría del formato: 6 de 7 en TW no son acordeón) + la cola "Still have questions?" (CTA a soporte). |
| pricing | Recurren y no tenemos: **tabla de comparación de features** y variante **single-price**. Toggle + featured = paridad OK. |
| site-header | Sin **flyout/dropdown de navegación** no hay paridad (todas lo traen; nuestro NavigationMenu ya lo da — es cuestión de scope del block); y falta el hermano **announcement banner** (13 TW · 16 Untitled — nuestro componente Banner existe: candidato a block `banner` o slot del header). |
| stats-band | Paridad OK; variantes recurrentes adoptables: split-with-image, timeline/stepped. **Ninguna ref puede shippear count-up** (markup estático) — nuestra superación literal. |
| cta | Paridad con centered; añadir arreglo **justified** (texto izq., botones dcha.) y variante split-with-media. |
| newsletter | Añadir slot de **nota de privacidad** bajo el field (convergente). |
| site-footer | Añadir slots: **newsletter-form en footer** (3 de 7 TW) y **language selector** (encaja con nuestro langs). |
| (ecosistema) | Todas las refs shippean **páginas compuestas** como artefacto de prueba (TW 10 · Untitled 105) — nuestra página de integración F2 cumple ese rol; considerar promocionarla a demo pública. |
#### Categorías de la unión que NO planeamos (decisión explícita pendiente)
≥2 refs shippean: **banners** · logo-cloud (diferido ya) · **team** · blog · **contact** · content/prose-section · bento grid · flyout/mega-menu (elemento) · careers · gallery/portfolio · events · comparison section · timeline section · multi-step forms · cookie consent · popups/promos. Candidatas obvias F2.5+: banner (componente ya existe), team, contact, content-section (composición de `prose`+Section), bento (AutoGrid?).
#### Superación ratificable
Variantes como **props tipadas** vs N dumps duplicados; dark/brand automático por tokens vs segundo artefacto; **gestión de landmarks + política de heading-level** (categoría que la industria NI VENDE — los dumps hardcodean h-levels y rompen jerarquías al componer); comportamiento del canon (Accordion/Drawer/ToggleGroup) vs "Requires Flowbite JS"; count-up con reduced-motion; RTL + density + cero strings horneados (i18n by construction).
### P2 — Aplicación — ✅ RECIBIDA 2026-07-21 (conteos de catálogos vivos + APIs de repo)
#### Panorama (los dos polos y el hueco del medio)
- **Copy-paste sin API** (Tailwind Plus App UI ~40 categorías con conteos —
Tables 19, Input Groups 21, Stacked Lists 15, Command Palettes 8, Empty
States 6…; Flowbite ~155 blocks de app con taxonomía **CRUD-céntrica**
(create/read/update/delete × form/modal/drawer/section — tratan "la
pantalla CRUD" como unidad); Tremor Blocks 303 — señal de GRANULARIDAD:
Filterbar/Table Actions/KPI Cards/Chart Tooltips como categorías de primer
nivel; Mantine UI 123). Cero modelo de composición: 19 tablas = 19
snapshots divergentes sin lifecycle.
- **Config-driven** (AntD ProComponents, Refine): todo props +
escape-hatches `xxxRender` (~10 en ProLayout) → acantilado de
personalización; ProTable = monolito search+table+toolbar infactorizable.
- **shadcn blocks** = scaffold eject-and-own: `dashboard-01` copia 19 deps
de registry + **6 paquetes npm a TU árbol** (tanstack-table, dnd-kit,
recharts, zod…). 16 sidebars porque las variantes no pueden ser props.
- **El hueco**: libertad de markup de Tailwind CON el comportamiento de
ProTable = exactamente la API compuesta de partes con children. Nadie lo
ocupa.
#### Suelos de paridad por bloque F3 (brechas concretas de nuestro v1)
| Block | Suelo que nos falta en v1 (decidir: subir alcance o registrar excepción) |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| app-shell | **Colapso desktop a icon-rail** (además de móvil→drawer; lo dan shadcn/Mantine/AntD); variante **stacked/topbar-only** (el primer fork en TODAS las refs); tamaños de slot responsive (`{base,sm,lg}` Mantine); scroll-hide del header; geometría de chrome como CSS vars (`--app-shell-*-offset` Mantine) para que el contenido se posicione contra ella. ~~Skip-link: NINGUNA ref lo trae — superación nuestra.~~ **[3 correcciones — fase 0 de F3.1, 2026-08-18, leídas las fuentes]** (1) **El skip-link SÍ lo traen dos referencias**: Polaris `Frame` tiene `skipToContentTarget` con enlace propio, y Atlassian genera un **menú entero** de skip-links a partir de los slots montados (`id` + `skipLinkTitle`/`skipLinkLabel`, `skipLinksLabel` = «Skip to:», Escape cierra y mueve el foco). La superación nuestra no es tenerlos: es **generarlos del mismo contrato que estampa el landmark**, sin que el consumidor escriba un `id`. (2) **El icon-rail no es de Mantine** — su `collapsed: {mobile, desktop}` es booleano, esconder o mostrar; los que sí lo tienen son shadcn (`collapsible='icon'`, 3rem), AntD (`collapsedWidth: 80`), Toolpad (mini variant) y Atlassian (colapsado + flyout al pasar el ratón). (3) Esta pista **nunca miró el `navigation-system` actual de Atlassian**, y `page-layout` —el que sí miró— está DEPRECADO. Lo nuevo añade suelo real: atajo `Ctrl+[` opt-in que se ignora bajo un modal, redimensionado con ratón **y teclado**, flyout que se queda abierto mientras haya capas abiertas dentro, y `useExpandSideNav` (la costura exacta que pide el `tour` de F5). |
| auth | Slot de **social providers**; slot de **error/mensaje** top-of-card (ProComponents `message`); prefill; estado de **carga/mounting** (Clerk `fallback`); la unión de vistas de Supabase es 6, no 4: falta **magic-link** y **update-password** (su `ViewType` = sign_in·sign_up·magic_link·forgotten_password·update_password·verify_otp — la enumeración más limpia del dominio). Nuestro OTP card SUPERA el suelo copy-paste (nadie lo shippea como block). |
| data-table | El cuarteto estándar de toolbar ProTable = reload + **density** + column-setting + **fullscreen** (density/fullscreen a decidir explícito — density además es concern de framework en nuestro caso); **persistencia de layout de columnas** (`columnsState.persistenceKey`); **clear-selection** en la barra bulk (el triple `{selectedRowKeys, selectedRows, onCleanSelected}`); historia móvil de filtros (**faceted-search en drawer**, Flowbite). |
| dashboard | Stat cards con **delta de tendencia** (up/down + tono) y **spark-chart embebido** (`chartPlacement` left/right/bottom); **selector de periodo** en panels de chart; arreglo fijo v1 OK (todas las refs lo fijan). Curiosidad adoptable: `StatisticCard.Group` con `Operation` ("=" "+" entre KPIs para expresar fórmulas). |
| settings | Completo salvo: descripción por fila como slot formal; **feedback de éxito tras guardar** (Flowbite "Success Message" es categoría propia de 5). |
| user-menu | Completo (tema/idioma SUPERA las refs — son auth-céntricas); falta `showName` (variante avatar+nombre) y la historia de **colocación en rail colapsado** (patrón nav-user de shadcn: flip a dropdown-up en pie de sidebar). |
| notifications | ¡Ya estamos SOBRE el suelo — ninguna ref shippea el inbox completo como block nombrado! Añadir explícito: timestamps + distinción visual unread. |
| wizard | Gate por paso **async** (promesa que resuelve false bloquea avance — StepsForm); `current` controlado para saltos del app; **stepper compacto móvil**; semántica de merge de valores entre pasos definida. |
| error-page | Añadir variante **maintenance** (Flowbite la trata como página de primera); 403 nuestro SUPERA el suelo (casi ausente en refs). |
| kanban | Slots de metadata en card (avatar/badge/due-date) + **add-card por columna**; toolbar de group-by/filtros = standout no-suelo (diferir dejando slot). Empty-state por columna: ninguna ref lo tiene — superación. shadcn NO tiene kanban block. |
#### Superación (ratificable) + debilidades ajenas a evitar
Lifecycle real (un fix de Table propaga a data-table/dashboard/kanban vs 19
snapshots); comportamiento heredado con CERO deps nuevas (vs 6 npm de
dashboard-01); el punto medio composición-con-comportamiento; a11y a nivel
block (skip-links, foco toolbar↔tabla↔paginación, live-regions "N
seleccionados"/"todas leídas"/cambio de paso, roving en columnas kanban —
NINGUNA ref lo shippea); theming/density/RTL/i18n del sustrato (todas
hardcodean `dark:` e inglés); coherencia cross-block vía runtime compartido
(sema en danger-zone/card-drop = canal que no existe fuera). **Evitar**:
fork-and-drift (16 sidebars), monolito ProTable, Inferencer desechable, y la
lección Supabase Auth UI: murió por appearance-API cerrada — nuestro auth
como composición sobre handlers del app es la forma durable.
### P3 — F1 ligeros — ✅ RECIBIDA 2026-07-21 (APIs a nivel de prop; AntD 6.5 · Mantine 9.4 · Bootstrap 5.3 · Chakra v3 · Polaris · Atlaskit · Base UI 1.6)
**Hueco headless verificado**: Base UI, Ark, React Aria y Radix Primitives
shippean CERO de los cinco — seríamos los primeros headless+contrato en
sticky y anchor-nav; los únicos comparables son kits estilizados (AntD) o
generadores de sitios.
#### sticky (F1.1)
- **La plataforma ya fijó el vocabulario**: CSS `@container scroll-state(stuck: top|bottom)` (Chrome/Edge 133+; Firefox/Safari NO ≤2026). **Espejar exactamente** en `data-stuck` + `data-edge="top|bottom"` → los selectores eidos traducen mecánicamente al CSS nativo cuando aterrice; seríamos el único contrato stuck CSS-direccionable cross-browser (motor = doble centinela IO bendecido por Chrome, que además cumple nuestra doctrina anti-reflow).
- **Brechas del boceto**: (1) **sin props de offset** — la geometría del centinela está acoplada matemáticamente al inset del sticky (el `-24px` del artículo de Chrome espeja el `top` del header): `offset` no es opcional; (2) **sin scroll-host** (AntD `target`, MDN: sticky se pega al ancestro con overflow más cercano AUNQUE no scrollee — el `root` del IO debe ser ese ancestro o la detección rompe en silencio); (3) "sin eventos v1" queda BAJO suelo (AntD `onChange(affixed)`) — recorte declarable, pero reservar el nombre del evento en el contrato ya; (4) borde bottom = centinela DISTINTO (`threshold:[1]`, por ratio) — es un centinela por borde con configs diferentes.
- **Pitfalls**: `overflow:hidden` en cualquier ancestro mata el sticky en silencio (detector dev-mode con warning); IO recorta por CADA ancestro con overflow; `rootMargin` solo px/% (no em); frontera exacta no dispara (centinelas con altura real, no 1px); `data-stuck` llega un frame tarde (async — solo styling, nunca matemática de layout); Mantine Affix NO es comparable (es un slot fixed en Portal).
#### anchor-nav (F1.6)
- **Suelo convergente**: compensación de offset del heading (`targetOffset` ≠ offset del affix — AntD los separa; SIN él, el click-scroll entierra headings bajo nuestro propio sticky; par CSS: `scroll-margin-top` en targets); anidación con indent (CSS var de profundidad — Mantine `--depth-offset`, nosotros tokenizada); callback de cambio; **mecanismo de re-scan** (Bootstrap `refresh()`, Mantine `reinitializeRef` — nuestro ciclo de registro de partes lo cubre tipado, decirlo); **regla de zona muerta al fondo** (Docusaurus: sin anchor bajo el umbral → el ÚLTIMO activo; su regla de lectura: si el siguiente anchor está bajo la mitad superior → el ANTERIOR es el activo — modela "qué se está leyendo").
- **Política de hash a decidir** (silencio en el boceto): AntD migró a history API (`replace` opt-in existe porque el push del spy contamina el historial); spy → replace o nada, click → puede push; deep-link `#id` al cargar fija el activo inicial.
- **aria-current: liderazgo barato** — solo 1 de 5 refs lo pone (Starlight `"true"`; Docusaurus/Bootstrap/Mantine/AntD = clase o data-attr). Valor spec-preciso: `"location"`; precedente shipped: `"true"`; **NUNCA `"page"`** (es para páginas de un set, no secciones).
- Scroll programático barre el spy por secciones intermedias (flicker) → suprimir spy hasta asentar o closest-wins; targets ocultos (tabs/colapsados) se saltan y re-observan al mostrar.
- Detección: **IO de banda** (Starlight: rootMargin calculado del chrome, recomputado en resize) — Mantine y Docusaurus usan scroll listeners crudos (la clase de bug que nuestra doctrina mata).
#### empty-state (F1.2) y result (F1.3) — un esqueleto, dos componentes
- Anatomía nuestra ≈ paridad exacta con shadcn `Empty`/Chakra v3. **Adoptar lo que nadie combina**: Atlaskit `headingLevel` (1–6, default 4) + `headingSize` DESACOPLADO (la única ref que hace bien la semántica de heading); `buttonGroupLabel` (nombre accesible del grupo de acciones); Polaris: UNA sola acción primaria (verbo+sustantivo), variantes secondary/tertiary; Chakra `size` sm/md/lg — **el tamaño compacto es lo que Table/Select/Command consumirán** (AntD SIMPLE preset + `ConfigProvider.renderEmpty` = inyección global en colecciones; los headless lo tratan como render-slot de colecciones: RAC `renderEmptyState` estampa `[data-empty]`); shadcn `EmptyMedia variant="icon"` → nuestro `data-media-kind`; clamp de ilustración (Atlaskit 160×160).
- **result = solo de AntD** (nadie más lo tiene; Tailwind lo vende como páginas 404). Nuestro enum semántico > su `'404'` stringly-typed, PERO: (1) **falta `warning`** (7º valor de AntD; mapea natural a nuestro intent `risk`) — decidir explícito; (2) default `status` (AntD: `info`) — sin default es contract smell; (3) **AntD NO pinta 403/404/500 de rojo** (son situaciones, no fallos — ilustración neutra reemplaza al icono; nuestro media debe aceptar reemplazo total); (4) foco/anuncio tras navegación SPA (mover foco al título o live region polite — ninguna ref lo hace).
#### callout (F1.4)
- **Nuestros 4 intents NO cubren el vocabulario de facto (5)**: GitHub NOTE/TIP/IMPORTANT/WARNING/CAUTION (y Docusaurus separa note-gris de info-azul). Mapeo: neutral→NOTE · affirm→TIP · risk→WARNING · threat→CAUTION; **IMPORTANT (énfasis, púrpura) no tiene hueco**. Opciones: documentar la pérdida / `color` override sobre intent (modelo Radix: intent=semántica, color=pintura) / 5º variante. No fingir que 4 cubre 5.
- **`role="alert"` estático = bug de shadcn, NO copiar** (MDN: alert solo anuncia en UPDATE — en carga no hace nada — y es assertive). Lo correcto: `role="note"` + `aria-labelledby`→title, con **escalación opt-in** (prop `live`/`role`) para callouts insertados dinámicamente (ahí sema puede sonar — cosa que ninguna ref puede expresar).
- **El title NO es heading en ninguna ref** (GitHub: párrafo estilizado) — y un heading contaminaría el outline que ESCANEA nuestro propio anchor-nav (interacción real intra-suite). **El intent no viaja solo en color/icono**: GitHub lleva LABEL de texto visible — título default por intent = patrón robusto (color-blind + SR).
- Radix como modelo de ejes: `variant soft|surface|outline` × color × size × highContrast, ortogonales. Nesting (Docusaurus): CSS tolerante a callout-en-callout.
### P4 — prose + sidebar — ✅ RECIBIDA 2026-07-21 (verificación a nivel de código fuente)
**Método**: el agente leyó el `sidebar.tsx` real del registry de shadcn
(new-york-v4) y el `styles.js`/`index.js` de @tailwindcss/typography en crudo
— los datos de abajo son de código, no de prosa de docs.
#### prose — suelo de paridad
- **Lista de elementos de paridad** (unión tailwind+GitHub+Mantine):
**h1–h6** (¡tailwind NO cubre h5/h6; GitHub y Mantine sí — cubrirlos!),
`p`, `a` (+ `a code`, `a strong`), `strong/em` (con contextos: dentro de
blockquote/th/h1–h4), `blockquote` (+ comillas de apertura/cierre en
`p:first/last-of-type::before/::after`), `ul/ol/li` + `::marker`
(counters/bullets tokenizados), correcciones de margen de listas anidadas
y `p`-en-`li`, `dl/dt/dd`, `table` completa (thead/tbody/**tfoot**/th/td,
trim de padding en primera/última celda), `code/pre` (+ reset `pre code`,
backticks vía `code::before/::after`), `kbd` (doble box-shadow), `img` /
`picture` (+ reset `picture > img`) / `video` / `figure` / `figcaption`,
`hr`, `lead` (clase, no `:first-of-type`), y **recorte de bordes**
`> :first-child { margin-top:0 }` / `> :last-child { margin-bottom:0 }`
(composición limpia dentro de cards). **Tier GFM a decidir explícito**:
task lists, footnotes, alerts, `details/summary`, `mark`, `sub/sup`.
- **Medida**: 65ch embebido por tamaño + escape (`max-w-none` equivalente).
**Tamaños**: tailwind re-deriva la escala COMPLETA 5 veces (sm 14 → 2xl 24) — nuestra fiche debe declarar qué eje (size/density) mapea esto.
- **Overflow de tablas**: la respuesta sin wrapper es la de GitHub —
`table { display:block; width:max-content; max-width:100%; overflow:auto }`
(tailwind no tiene ninguna: las tablas desbordan la columna).
- **El mecanismo `not-prose` (crítico)**: tailwind emite CADA selector como
`:where(.prose el):not(:where([class~="not-prose"], [class~="not-prose"] *))`
— especificidad CERO (cualquier clase gana) + exclusión "donut" del nodo y
descendientes. Limitación admitida: no se puede re-anidar prose dentro del
donut. Alternativa moderna: `@scope ([data-prose]) to ([data-prose-ignore])`
(Baseline _newly available_ desde finales de 2025 — evaluar contra nuestro
suelo de soporte).
- **Territorio sin reclamar** (superación): comillas de blockquote
hardcodeadas en inglés en TODAS las refs (`\201C…`) → CSS `quotes`
locale-aware vía langs; **exclusión automática de componentes embebidos**
(todo lo que cuelgue de una raíz `data-{component}` se auto-excluye — las
refs no pueden porque no poseen el markup de sus consumidores); dark
gratis vía roles (NO copiar el patrón `-invert`: es un parche por colores
horneados); code-in-heading (`h2 code` con corrección de tamaño — tailwind
lo trae, Fumadocs lo presume).
- **Avisos**: selectores de elemento = categoría "estructural bajo una
parte" del eidos-lint — sancionarlo deliberadamente o el recipe lintará
invalid; propiedades lógicas (`border-inline-start`) desde el día uno;
anchors de heading son capa docs-shell (patrón a11y correcto: link DESPUÉS
del heading, à la Starlight), no capa prose.
#### sidebar — suelo de paridad
- **shadcn = 23 partes + hook** (`Provider · Sidebar · Trigger · Rail ·
Inset · Input · Header · Footer · Separator · Content · Group ·
GroupLabel · GroupAction · GroupContent · Menu(ul) · MenuItem(li) ·
MenuButton · MenuAction · MenuBadge · MenuSkeleton · MenuSub(ul) ·
MenuSubItem · MenuSubButton(a) · useSidebar`). **Nuestro boceto tiene 8 —
demasiado grueso**: `item` funde MenuItem (li posicionador) + MenuButton
(interactivo, data-active, host del tooltip), y sin ese split no hay dónde
colgar action/badge/skeleton/sub-nivel. shadcn-svelte lo porta 1:1 con
dot-notation y Svelte 5 (`bind:open`, snippets para asChild) — el mapeo a
nuestro idioma está probado.
- **Dos ejes, no uno**: estado `data-state="expanded|collapsed"` + modo
`collapsible="offcanvas|icon|none"` (shadcn estampa `data-collapsible`
SOLO estando colapsado — ojo si espejamos nombres). Nuestro `data-rail`
fusionaba ambos ejes → separar. `Rail` además es una PARTE física (franja
de 16px toggle en el borde, tabIndex -1, cursores direccionales), no un
estado.
- **Props/constantes de referencia**: `side` left|right (table stakes),
`variant` sidebar|floating|inset (diferible declarándolo), widths 16rem /
18rem móvil / 3rem icon como TOKENS (no consts TS), cookie
`sidebar_state` 7d con lectura SSR → `defaultOpen` (evita flash de
hidratación), atajo global Cmd/Ctrl+B con `preventDefault` (¡secuestra
la negrita de cualquier editor embebido — el nuestro se scope-a fuera de
contextos editables!), tooltips en modo icon montados SIEMPRE y
suprimidos con `hidden` (no mount/unmount), móvil = Sheet <768px (nuestro
Drawer con props label/description, no hacks sr-only).
- **Exclusiones v1 legales SOLO con costuras**: `open`/`onOpenChange`
controlado + `defaultOpen` + `toggle()` expuesto en el provider — la
persistencia y el atajo viven en app-land únicamente si esas costuras
existen desde v1; si no, es rediseño posterior.
- **A11y — todas las refs suspenden**: shadcn NO tiene landmark `<nav>`, NI
`aria-current` (solo data-active), atajo sin `aria-keyshortcuts`, rail
inalcanzable por teclado. El patrón correcto es APG Disclosure Navigation:
nav landmark + botones `aria-expanded/aria-controls` + links con
`aria-current="page"` + Esc devuelve el foco al trigger. Superación
directa: emitir `aria-current` del MISMO prop que estampa `data-active`.
- **Nadie headless lo tiene** (Radix/Base/Ark/React-Aria confirmado): el
sidebar canónico es invención del tier estilizado — espacio abierto con
shadcn como estándar de facto.
- **Pitfalls**: animar `width` = layout por frame (aceptado por la
industria; nosotros: offcanvas por transform y width-anim solo en icon,
lecturas vía `dom.measure`); submenús en modo icon shadcn los OCULTA
(nuestro DropdownMenu/Popover flotante en rail = superación, es el mejor
comportamiento de AntD Menu); `overscroll-behavior: contain` en Content;
RTL lógico desde el día uno (shadcn necesitó un changelog entero de
retrofit); jitter de `will-change` en raíles finos a DPR≠1 (memoria).
### P5 — Docs — ✅ RECIBIDA 2026-07-21 (Starlight 0.41 · Fumadocs 16.11 · Docusaurus 3.10 · VitePress 1.6/2α · Nextra 4.6 · Mintlify)
#### Suelo del docs-shell (convergencia de los 6)
3 regiones con raíles sticky de scroll independiente + header sticky; sidebar
con ≥3 niveles, grupos colapsables, profundidad default-open, **active trail
auto-expandido**, badges, drawer móvil; TOC h2–h3 configurable con scrollspy,
**móvil = popover/dropdown**, back-to-top; búsqueda = **command palette ⌘K**
con índice estático (Pagefind/MiniSearch/Orama); breadcrumb del árbol (solo
anidado); prev/next del orden del árbol; fila meta (edit-on-GitHub +
last-updated); dark light/dark/system sin flash; slots reservados: banner de
anuncio, sidebar top/bottom, page-actions, versión/idioma. **Fumadocs es el
benchmark y el ÚNICO que shippea el shell como componentes reutilizables**
(DocsLayout/DocsPage con sistema de slots + fumadocs-core headless; anchos
TOKENIZADOS `--fd-sidebar-col`/`--fd-toc-width` — validación de nuestro
enfoque). Diferenciadores adoptables: tabs de sección en sidebar (Fumadocs),
TOC estilo "clerk" (raíl de pulgar), auto-colapso de hermanos (Docusaurus),
**acciones AI** (copy-page-as-Markdown, open-in-Claude/ChatGPT, `llms.txt`,
negociación de contenido `.md` — table stakes 2026 y casi gratis: nuestro
corpus YA es Markdown).
#### Suelo del code-showcase
Preview + código + copy SIEMPRE; barra de **filename con icono**; números de
línea; **marcas de línea/palabra**; **diff** (`++`/`--`); código largo
**colapsable** (shadcn: 3 líneas + gradiente + expandir); **tabs de package
manager** (npm/pnpm/yarn/bun de un solo bloque); **grupos multi-archivo**
con `syncKey` site-wide (Starlight); controles de preview: alineación +
**toggle RTL** (el de shadcn lleva disclaimer "AI-translated" — el nuestro
iría con langs real). ⚠️ La mayoría pertenece al canon `code-block`:
**verificar qué soporta nuestro recipe ANTES de F4.2; cada carencia = gap de
canon flaggeado** (regla de admisión).
#### Props-table: generación y suelo de presentación
- **Suelo de presentación = Ark UI**: secciones POR PARTE (props +
data-attributes + ARIA + keyboard por parte) + tabla de contexto/API.
Nuestro `<PropsTable>` plano queda por debajo — el morfo ya trae el
seccionado; renderizarlo.
- **Generación en refs**: manual (Radix — puro riesgo de drift) ·
build-time docgen → JSON (Mantine, Ark `generate-type-docs.ts`) ·
TS-Compiler-API en build (Fumadocs AutoTypeTable, solo server).
- **Vía Svelte para props TS** (la cuestión abierta de F4.3): **sveld
DESCALIFICADO** (sin resolución semántica — `ResponsiveProp<T>` quedaría
texto opaco); svelte-docgen pre-v1; **la ruta = svelte2tsx + TS Compiler
API en build-time → JSON por componente** (Storybook migró a ella
precisamente por runes; PRs #29423/#28492).
#### Brechas señaladas en NUESTRAS fiches F4/F1 (leyó el plan — 10 puntos)
1. **F4.1 slots insuficientes**: faltan topbar, banner, sidebar top/bottom, page-actions, opciones de breadcrumb, fila meta, slots versión/idioma. D-BLK.6 manda el wiring al app — pero el shell debe RESERVAR los puntos de montaje.
2. **⚠️ COLISIÓN F1.7 vs docs-tree (firmar ANTES de construir F1.7)**: el sidebar de app v1 (grupos+rail) no cubre árbol profundo, active-trail auto-expand, auto-colapso, default-open depth, scroll-active-into-view; y un árbol de 100 páginas como children choca con B-5 → o el componente canónico sidebar/tree es data-driven (precedente: Menubar ya lo es), o hay pieza canónica nueva (`nav-tree`). Decisión de usuario.
3. **⌘K sin decidir**: Command existe; el registro global de atajo está en F5. Todas las refs lo dan día uno. Decidir: listener app-land documentado o adelantar el art `shortcuts`.
4. **TOC móvil sin mecanismo** en F1.6/F4.1 (refs: popover o dropdown) + anchor-nav sin config min/max de nivel.
5. **prose sin heading-anchors**: Starlight 0.34 los hizo core con el patrón a11y correcto (link DESPUÉS del heading + label generada); sin ellos mueren los deep-links del TOC. + iconos de external-link (VitePress).
6. **F4.2 bajo suelo** (lista de arriba) y **los chips de tema/density/dir diferidos son EL FOSO, no un nice-to-have** — ver superación.
7. **F4.3 por-parte** (suelo Ark) + tabla de eventos familia·verbo·intent.
8. **Dirección TS-props**: fijar ya la ruta svelte2tsx build-time.
9. **Cero acciones AI** en los sketches (llms.txt, copy-as-md — casi gratis).
10. **Falta last-updated/edit-link** y la decisión del skip-link (diferida en F2.1) debe aterrizar antes de F4.1.
#### Superación (la más fuerte de las 6 pistas)
**Props tables que no pueden mentir**: `compileMorfo` da partes/attrs/ARIA/
keyboard/eventos EN RUNTIME del mismo objeto que ejecuta el componente —
cero drift por construcción, CI puede exigir tabla completa por componente
PASS; la tabla de keyboard de nadie más ES el plan de teclado real. **Tabla
de eventos semántica** (familia·verbo·intent·canales) que ninguna ref tiene.
**Ejes de tema por demo** (theme/density/contrast/RTL/motion vivos con
tokens reales — imposible para SSG estáticos). **Búsqueda contract-aware**
(Command indexando morfos: "¿quién maneja Escape?", "¿quién estampa
data-stuck?" — Pagefind indexa texto, no contratos). Scrollspy con
disciplina de reflow demostrable por `uix.perf`; sema demoable por evento;
dogfooding = el shell ES el test de aceptación de F4.
### P6 — Svelte — ✅ RECIBIDA 2026-07-21 (inventarios por llms.txt + npm; versiones al día)
#### El paisaje de blocks en Svelte (los 3 actores reales)
| Oferta | Qué shippea | Modelo |
| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **shadcn-svelte** (CLI 1.4.2, 82k dl/wk; sobre Bits UI 2 = 821k dl/wk) | **58 blocks first-party, SOLO app**: 16 sidebars · 15 auth (login/signup/OTP) · 26 calendar · 1 dashboard · 7 familias de charts (sobre LayerChart, 180k dl/wk). **CERO marketing sections** (igual que upstream) | copy-paste vía registry CLI (`registry.json`), `llms.txt`, visual builder `/create` |
| **Flowbite Svelte Blocks** v2.1.0 (MIT, Sv5+TW4) | El único con **marketing (~29 tipos: hero, pricing, CTA, FAQ, testimonials, newsletter, footer, 404/500/maintenance, cookie, onboarding…) + application (~20: CRUD en modals/drawers, advanced tables, faceted search, sidenav)** | paquete npm; estética datada; theming superficial |
| **sv-blocks** (port Tailark) | **150+ marketing blocks** para shadcn-svelte + 60 "Veil Kit" | jsrepo CLI + **MCP server** (instalables desde Cursor/Windsurf) |
Resto: Skeleton v5 (2026-07-17; theming profundo, CERO blocks), Melt original congelada (~16 meses), melt next 0.44 pre-1.0, **Ark UI Svelte 5.22** (45+ headless, org Chakra, cadencia semanal — vigilar), HeroUI sigue React-only ("Svelte planeado sin fecha"), plantillas admin = repos, no blocks componibles. Todo el paisaje asume **Tailwind v4 + copy-paste**.
#### Huecos objetivos del ecosistema (nadie los tiene)
docs-shell · settings/preferences · billing/checkout · empty/error states como SISTEMA · data-table CRUD componible (Flowbite = snippets sueltos) · blocks con i18n/RTL · a11y auditada a nivel sección · blocks sobre tokens no-Tailwind · capa perceptiva. **Nadie combina componentes + theming profundo + blocks**: shadcn tiene blocks sin theming profundo; Skeleton theming sin blocks; Flowbite blocks con theming superficial. Esa es la ventana.
#### Listón de paridad Svelte (para reclamar "la oferta más completa")
1. App-shell: cubrir la matriz de los 16 sidebars de shadcn con **1 block parametrizado + presets, documentando la equivalencia variante-a-variante** (no competir en cardinalidad copy-paste).
2. Auth: login/signup/OTP/forgot (15+ layouts entre shadcn y Flowbite).
3. Dashboard completo + stat/chart cards sueltos; **galería de charts con variantes día uno** (lección LayerChart: shadcn no escribió motor, montó galería).
4. CRUD: tabla avanzada + create/update en modal Y drawer + delete-confirm (el set Flowbite que shadcn no tiene).
5. Marketing: la unión Flowbite+sv-blocks ≈ 20 tipos — nuestra F2 (10) debe contrastarse contra esa unión (banners/cookie/team/blog/contact/onboarding no están en F2 → decisión explícita).
6. Calendar: shadcn 26 blocks; con nuestra riqueza de componentes bastan menos, cubriendo range/presets/time/booked.
#### Amenazas / lecciones arquitectónicas (para decidir, no resolver en silencio)
- **La cultura copy-paste GANÓ la distribución.** Un tier empaquetado necesita historia de **personalización estructural** (partes/snippets por zona — nuestra API composicional ya lo es) y quizá un camino de "eject" block→código propio.
- **Registry + llms.txt + MCP = table stakes 2026**: los blocks deberían ser enumerables/instalables por agentes (encaja con la vía agentiva del proyecto). Candidato a F5/decisión.
- **Zag/Ark = la vara de a11y** cross-framework: conviene poder DEMOSTRAR la nuestra (matriz teclado/ARIA por block, generada del morfo — inédito).
- **Tailwind v4 es el sustrato universal**: zero-dep es diferenciador (sin lock-in) y fricción a la vez — tensión estratégica del usuario.
- Los upgrades propagan en nuestro modelo (composición) vs congelación copy-paste — EL argumento; requiere la historia de personalización de arriba para sostenerse.
## Síntesis (6/6 pistas — 2026-07-21)
Los suelos de paridad por ítem viven en cada sección de pista (arriba); las
fases 0 del plan contrastan contra ellos. Lo transversal:
### Cinco conclusiones
1. **La ventana estratégica es real y está abierta**: nadie — en ningún
ecosistema — combina componentes + theming profundo + blocks con
comportamiento. En Svelte el espacio "sistema integrado" está vacío
(shadcn-svelte: blocks sin theming profundo; Skeleton: theming sin
blocks; Flowbite: blocks con theming superficial). El casi-par global es
Untitled UI React (componentes con props de verdad) — React-only,
PRO-gated, sin tokens/RTL/density. En los 7 componentes F1, los headless
(Radix/Base/Ark/React-Aria) shippean CERO.
2. **El patrón de brechas de nuestro v1 es consistente**: los esqueletos son
correctos; lo que falta es (a) la SEGUNDA variante convergente del
mercado (feature-split, testimonial-spotlight, faq-lista, hero-media,
cta-justified), (b) las costuras de estado (open/onOpenChange/toggle en
sidebar; error/loading slots en auth), y (c) los ejes que el mercado
resuelve con N copias y nosotros con props.
3. **La distribución copy-paste ganó**: registry + llms.txt + MCP son table
stakes 2026. Nuestro contraataque es estructural (upgrades que propagan,
variantes tipadas) pero necesita la historia de personalización
(composición por partes = ya la tenemos) y la enumerabilidad por agentes
(candidata a iniciativa propia).
4. **El liderazgo a11y es barato y sistémico**: las referencias suspenden en
TODO el tablero (sin landmarks ni gestión de heading-level en secciones,
sin `aria-current` en 4 de 5 scrollspies, `role="alert"` estático como
bug shipped, atajos globales sin scope). Nuestra doctrina ya obliga a lo
correcto; solo hay que no copiarles.
5. **Alinearse con la plataforma donde ya estandarizó**: `data-stuck`/
`data-edge` espejando `scroll-state(stuck:)`; `@scope` con donut como
mecanismo moderno de prose (con fallback `:where()`+donut); heading
anchors con el patrón Starlight; `aria-current="location|true"`.
### Enmiendas al plan
**Aplicadas (no cambian alcance)**: regla de trabajo nueva en el plan §4 —
toda fase 0 contrasta contra este dossier ANTES de diseñar; puntero de
colisión en la fiche F1.7 (sidebar-app vs árbol-docs / B-5).
**A decisión del usuario (cambian alcance — presentadas 2026-07-21)**:
| # | Decisión | Recomendación |
| --- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| E-1 | Colisión F1.7: el árbol de navegación docs (anidación profunda, active-trail, data-driven) no cabe en el sidebar-app v1 y choca con B-5 | Componente canónico NUEVO `nav-tree` data-driven (precedente: Menubar ya es data-driven); sidebar queda app-céntrico; F4.1 compone nav-tree |
| E-2 | Filosofía de alcance v1: ¿subir los v1 al suelo de paridad investigado, o construir fino y pasar una ola v1.1 de paridad? | Suelo de paridad = v1 (el encargo fue "a la par y cuanto menos superarlo"); las fases 0 dimensionan cada subida con el dossier |
| E-3 | Categorías de la unión no planeadas: banner · team · contact · content-section (· bento · gallery · cookie-consent…) | Añadir a F2 las 4 baratas (banner compone el componente existente; content-section = prose+Section); resto a F5 con disparador |
| E-4 | Distribución registry/llms.txt/MCP de blocks | Registrar como iniciativa PROPIA en next-features (no engorda este plan); llms.txt del corpus docs = barato y encaja con F4 |
| E-5 | ⌘K global (F4/command): ¿adelantar el art `shortcuts` o listener app-land? | Listener app-land documentado en el README del block; el art `shortcuts` mantiene su disparador F5 (≥2 consumidores) |
### Ángulos de superación ratificables (consolidado)
1. Variantes como props tipadas + upgrades que propagan (vs N dumps).
2. Landmarks + política de heading-level como API del block (la industria NI LO VENDE).
3. A11y por encima de toda referencia: `aria-current` del mismo prop que `data-active`, `role=note`+labelledby, APG focus-return, atajos scoped, live-regions en bulk/steps/inbox.
4. Tokens: dark/brand/density/RTL gratis por sustrato (vs dark como segundo artefacto a la venta).
5. i18n by construction (cero strings horneados; comillas de blockquote locale-aware — territorio sin reclamar).
6. `data-stuck` = polyfill del contrato CSS futuro; prose con auto-exclusión de componentes embebidos (nadie puede: no poseen el markup de sus consumidores).
7. Props tables runtime desde `compileMorfo` que no pueden mentir + tabla de eventos semántica + búsqueda contract-aware ("¿quién maneja Escape?").
8. Ejes de tema por demo (theme/density/contrast/RTL/motion vivos) = el foso del showcase; sema demoable por evento.
9. Count-up con reduced-motion, submenús flotantes en rail, kanban con roving focus y empty por columna — cada uno literalmente imposible o ausente en las refs.
10. Rendimiento demostrable: scrollspy/sticky por IO vía adom con `uix.perf` probando cero forced-reflow (ninguna ref puede afirmarlo).

Powered by TurnKey Linux.