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/web/routes/blocks/_lib/reset.css

99 lines
4.2 KiB

feat(blocks): `newsletter` — el alta al boletín, y el reset que el framework daba por hecho F2.9. Slots de snippet (eyebrow · title · description · field · submit · note · children), `center` y `justified`, y `panel` como interruptor real: el panel de marca es la cara de las referencias, pero el control, la ayuda y el error están calibrados para la superficie de página, así que apagarlo es un estado de primera y no un fallback. La fila es `Grid templateColumns={{ base: '1fr', sm: '1fr auto' }}`: el campo se queda la pista libre y la acción abraza su contenido —eso es lo que hace que un alta se lea como UN gesto— y bajo `sm` pasa a una columna, porque un botón al lado de un campo de correo deja inservibles a los dos. El block NO valida y NO emite sema. `Form` posee el runtime, el esquema, dirty/ touched, la agregación de errores y el foco al primer error; `Field` posee el cableado ARIA; el morfo del `Form` ya declara `commit-submit` y `signal-invalid`. El app posee esquema, valores y handler. No hay ni un `if` sobre un correo aquí. ## Superación del dossier: la etiqueta El único hueco que el dossier nombraba era la nota de privacidad, y está. Pero la diferencia de verdad es la etiqueta: las referencias shipean la fila escondiéndola con `sr-only` o dejando solo un placeholder. El canon tiene `Field floatingLabel` —arranca dentro del control y sube al borde al enfocar o rellenar—, así que la fila queda alineada CON etiqueta real y asociada. Verificado con pulsaciones de teclado de verdad: 10px dentro en reposo → −11px sobre el borde al enfocar y al rellenar. ## Tres hallazgos de canon más, medidos - **La fundación de eidos no trae reset de modelo de caja y lo asume del app.** `[data-field-control]` declara `inline-size: 100%` + padding, así que bajo `content-box` el control mide 30px más que su contenedor: el campo se metía por debajo del botón de envío. Campo 480 / control 510 en la galería frente a 502 / 502 en los docs de componentes, que sí resetean (igual que `web/routes/active/styles.css`). Arreglado en app-land con `web/routes/blocks/_lib/reset.css`, con A/B sobre los 10 previews y 5 páginas de shell: cambia el newsletter y NADA más. Hay que importarlo dos veces porque la galería arranca UIX en línea en vez de pasar por `BootUix` — deuda del arnés, anotada en el handoff. - **`onValidSubmit` es un no-op silencioso** cuando se pasa un `form` ya construido: el componente solo lo reenvía al `createForm` que hace él mismo. El envío validaba, limpiaba el error y no anunciaba nada. Por eso el block no expone el prop: el handler va en el `createForm` del app. - **Los mensajes de SIUM son idlangref.** La vía correcta es `uix.langs.t(issue.message, issue.params)` —verificado, sale «Debe ser una dirección de correo válida»—, pero la demo de docs del propio `Form` parte la cadena a mano tras el `|`, así que el único ejemplo del repo enseña el patrón equivocado y siempre muestra inglés. Los tres quedan en los gaps del README y en `PLAN-blocks-quality.md` §6 (F18/F19/F20), sin tocar nada fuera del tier. Verificado en navegador el arco completo: correo inválido → error traducido con `role="alert"`, `aria-invalid`, `aria-describedby` y foco al primer error; correo válido → confirmación del app (`Callout` afirmativo con la dirección) y error limpio. Claro/oscuro/RTL, tres colores, `panel` sí/no, 420px. Cero errores de página. Gates: `blocks:check` verde (10 blocks) · `svelte-check` sin errores propios · prettier limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
/*
* The one reset the blocks section needs, for BOTH of its surfaces (the gallery
* shell and every block's standalone `preview` page) — which is why it is
* imported from `BootUix`, the bootstrap they share.
*
* WHY: the eidos foundation ships no box-model reset; recipes assume the APP
* provides one. Every other surface in this repo does — `web/routes/uix/uix.css`
* under `[data-uix-docs]`, `web/routes/active/styles.css` for the app — and the
* blocks gallery was the one harness built without it (F0).
*
* The cost of that omission is not cosmetic. A recipe like `[data-field-control]`
* declares `inline-size: 100%` + `padding-inline`, so under `content-box` the
* control renders 30px WIDER than its container: in the newsletter's
* `1fr auto` row the email control grew past its track and slid under the submit
* button. Measured, not guessed — field 480 / control 510 here versus 502 / 502
* on the component docs, which have the reset.
*
* The canon-side question (should the foundation own this rather than assume it?)
* is registered in `docs/process/PLAN-blocks-quality.md` §6.
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
blocks(app-shell): la pieza que posee las alturas de la página, y por eso el aviso deja de tapar la cabecera F3.1 del tier, con su fase 0 firmada delante. El block que faltaba: el que POSEE las regiones de una página de aplicación — sus landmarks, sus enlaces de salto y sus alturas. **A-95 se cierra por construcción, no compensando.** Bajo `scroll="main"` no hay nada fijo: el aviso es una fila, el cromo es una fila y la página es la fila que se desplaza. Medido con la tira puesta: aviso [0,54], cabecera [54,85], **solape 0**, y el hit-test en el centro de la cabecera cae en la cabecera (antes: 49px de solape y el clic en la tira). El eje `scroll` es el que Mantine expone como `mode` y Atlassian como `isFixed` por slot; `body` existe porque `docs-shell` lo necesitará para anclas y TOC. Compone `Sidebar` (sus tres colapsos, su drawer móvil, sus dos landmarks), `SkipLink`, `Sticky`, `Grid`/`Flex`/`Box`. Sin `.css`. Coordina tres booleanos (`navOpen · asideOpen · mobile`) por contexto, sin máquina y sin palabras: nada en un shell puede bloquearse, así que no hay frase que decir. Medido en navegador (Playwright; 1280 y 375, claro y oscuro, LTR y RTL): - landmarks por construcción — 1 banner · 1 main · 2 navigation NOMBRADOS · 2 complementary NOMBRADOS · 1 contentinfo; encabezados 1-2-2-2-2 sin saltos. - `scroll="main"`: documento 720 = viewport, el main scrollea dentro y la cabecera se queda en 0 tras desplazar 900px. `scroll="body"`: el documento scrollea y la cabecera SE PEGA (top 0 a 900px de scroll). - teclado: los tres enlaces de salto son las tres primeras paradas y Enter deja el foco en el `<main>`. - 375: el raíl es drawer, devuelve el foco al trigger con Escape, el aside se pliega y el documento no crece. RTL: sin desbordamiento horizontal, raíl a la derecha, aside a la izquierda. Cuatro averías que sólo aparecieron midiendo, y las cuatro son doctrina ahora: 1. `minHeight` es un SUELO, no un techo: con `100dvh` ahí el documento crecía con el contenido. Es `height`. 2. Un grid que sólo declara filas tiene UNA columna implícita `auto`, que se encoge a su contenido: la página salía en una tira de 32px al lado del raíl. 3. `Box` declara `flex-grow/shrink/basis`, así que pisa el `flex: 1 1 auto` de la receta del inset. Quien está más abajo en el árbol tiene que PEDIR crecer. 4. Un ancestro con `overflow` se lleva el `position: sticky` de dentro. El `overflow: auto` de `Sidebar.Inset` dejaba la barra sin pegar bajo `body` mientras `data-stuck` decía que sí — el atributo dando la razón a una página que no la tenía. Por eso el shell pone su propia caja: gap de canon anotado (el inset debería dejar elegir si es contenedor de scroll). **Y una avería del ARNÉS que este block destapó**: los 19 previews del tier llevaban los 8px de margen por defecto del navegador, así que ningún block se enseñaba a sangre — contra la regla dura del propio tier. Medido: `x: 8, y: 8, w: 1264` en 1280, la página compuesta incluida, cuyo README cita cifras a sangre. Invisible porque todos scrollean; deja de serlo con un shell que llena el viewport. Arreglado en el reset del arnés. De paso, en el canon `skip-link`: el enlace del panel complementario decía «Ir a la barra lateral», que es como todo el mundo llama al raíl de NAVEGACIÓN. En una página que tiene los dos, nombraba al que no era. Ahora «Ir al panel lateral». Guards: `blocks:check` verde con 19 blocks · `docs:check` 0/0 (638) · `svelte-check` 74, ninguno aquí. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
/*
* The browser's default `body { margin: 8px }`, removed — and it is not a
* cosmetic call either.
*
* The tier's hard rule is that a block is shown A SANGRE: nothing between it
* and the edge, because a frame changes what the block DOES (a header pinned at
* `offset: 0` measured 21px off inside a Card). That rule was being broken by
* the document itself: measured 2026-08-19, every preview rendered at
* `x: 8, y: 8, w: 1264` inside a 1280 viewport — the composed landing page
* included, whose README quotes full-bleed numbers.
*
* It stayed invisible because every other block's page scrolls anyway, so 16px
* of extra document height reads as nothing. `app-shell` is where it stops
* being invisible: a shell that fills the viewport (`100dvh`) plus 16px of
* margin is a page with a scrollbar and no content to scroll.
*/
body {
margin: 0;
}
blocks(app-shell): la demo no usaba los componentes que SIGNIFICAN lo que enseñaba Rehecha entera. Cada pieza es ahora el componente del canon que corresponde al acto, no una caja con el aspecto adecuado: - las tres cifras son `Metrics` (label · value · delta), con la dirección desacoplada de la valencia: en «sin asignar», BAJAR es bueno (`goodTrend`), que es justo lo que las referencias hacen mal; - la bandeja y la actividad son `Feed` — `role="feed"`, cada conversación un `role="article"` con `aria-posinset/setsize` y su título con `aria-level`, teclado de feed incluido. Medido: 2 feeds, 11 artículos, 11 encabezados; - la barra superior es `Toolbar` (`role="toolbar"`, roving tabindex: cinco controles cuestan UNA parada de tabulación) más `Breadcrumb` con `current`; - la tipografía sale de los estilos SEMÁNTICOS del tema — `Text style="label|caption|body"`, `Heading level` + `style` — en vez de tamaños elegidos a ojo, que es lo que había. **Y la avería que esto destapó, que era del arnés y afectaba a los 19 previews**: la foundation declara los `@font-face` y emite los estilos (`--style-body-*`…) pero no los aplica a ningún elemento — un `Text` ancla su familia en su recipe y todo lo demás HEREDA del documento. El arnés de blocks no anclaba nada, así que `html`, `body`, `[data-sidebar]` y cada fila del raíl computaban **Times New Roman** al lado de los `Text` en Instrument Sans. El shell de docs sí lo ancla (`uix.css`); éste no. Anclado en `_lib/reset.css` con los tokens del tema, no con una familia escrita. De paso, el sangrado de 40px que el navegador pone a `dd`. Tres huecos del canon que salieron al componer, registrados en los Gaps: 1. **`Sidebar.MenuButton` es mudo y `NavigationMenu.Link` no** — el mismo acto con dos respuestas. El README del `Sidebar` firma que «navegar una fila es nativo y no suena», pero entonces el `NavigationMenu` contradice la firma; y en un shell la fila casi nunca navega: SELECCIONA la sección. Es de sema, no del tier. 2. **`Toolbar.Button` no acepta `variant`/`color`** — tipa contra el `ButtonProps` de soma (`{id, disabled}`), así que un cluster no puede decir cuál es su acción principal. Aquí va al lado, como en las referencias. 3. **No existe `description-list`** y el panel de detalle es exactamente el «primer detail-view real» que su ficha F5 pone como disparador. Guards: `blocks:check` verde · `docs:check` 0/0 · `svelte-check` sin errores propios (dos props inexistentes corregidas de paso: `Icon.Filter` y el `variant` del `Toolbar.Button`). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
/*
* The document's typographic anchor — the theme's own `body` style, and the
* second thing the foundation leaves to the app (the box model was the first).
*
* The foundation declares the `@font-face`s and emits the semantic styles
* (`--style-body-*`, `--style-label-*`, `--style-h1-*` …) but applies none of
* them to any element: a `Text` or a `Heading` anchors its own family in its
* recipe, and everything else INHERITS from the document. So any text the canon
* renders as plain text — the label `<span>` inside a `Sidebar.MenuButton`, a
* `Sidebar.GroupLabel` — falls to the browser default when the document says
* nothing. Measured 2026-08-19 on the app-shell preview: `html`, `body`,
* `[data-sidebar]` and every rail item computed `"Times New Roman"`, next to
* `Text` nodes in Instrument Sans. The component docs shell anchors its root
* (`uix.css`, `[data-uix-docs]`); this harness did not, on any of its 19
* previews.
*
* The values are the theme's `body` style, by token — never a family or a
* size written here — so a theme that redefines its body redefines this too.
*/
body {
font-family: var(--style-body-font-family);
font-size: var(--style-body-font-size);
line-height: var(--style-body-line-height);
letter-spacing: var(--style-body-letter-spacing);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/*
* The description-list defaults, removed for the same reason as the body
* margin: the browser indents `dd` by 40px, which reads as an alignment choice
* nobody made. Measured on the app-shell preview's detail panel, where every
* value sat a step to the right of its term. Layout in the tier comes from the
* layout components' props, so a UA margin is noise, not a decision.
*/
dl,
dd {
margin: 0;
}
/*
* The description-list defaults, removed for the same reason as the body
* margin: the browser indents `dd` by 40px, which reads as an alignment choice
* nobody made. Measured on the app-shell preview's detail panel, where every
* value sat a step to the right of its term. Layout in the tier comes from the
* layout components' props, so a UA margin is noise, not a decision.
*/
dl,
dd {
margin: 0;
}

Powered by TurnKey Linux.