diff --git a/docs/architecture/blocks.md b/docs/architecture/blocks.md index 6ed96b096..c924ecc35 100644 --- a/docs/architecture/blocks.md +++ b/docs/architecture/blocks.md @@ -151,6 +151,17 @@ asserts its own detectors against inline fixtures on every run). announcer on the page. Anything beyond these two is the app's, or the admission rule firing. +- **Prop naming — `size` es del BLOCK, nunca de una pieza interna**: un block que + reenvía el eje de tamaño de algo que envuelve lo nombra **`{pieza}Size`** + (`containerSize` para la medida del `Container`, `sectionSize` para el aire del + `Section`), y deja `size` libre para significar siempre lo mismo: **el tamaño + del block**. Nació midiendo (2026-08-17): trece blocks exponían `size` con el + significado «padding de la sección» y `banner` con el de «altura de la tira» + — misma prop, dos cosas, y una con un valor menos en la escala. El precedente + ya estaba en el tier (`container` nombraba la pieza) y ahora es regla. Corolario: + un eje que el canon ya nombra se reenvía **con su nombre** — `minChildWidth`, + no un sinónimo local. + ## The promotion path (lived) The tier was bootstrapped the way the admission rule prescribes: the eight diff --git a/docs/process/AUDIT-blocks-ledger.md b/docs/process/AUDIT-blocks-ledger.md index 53d408c53..0835be7b6 100644 --- a/docs/process/AUDIT-blocks-ledger.md +++ b/docs/process/AUDIT-blocks-ledger.md @@ -68,7 +68,7 @@ Columna **or.** = de qué sección del documento viejo salió la fila (`C` confi | A-22 | `stats-band` | doctrina | BAJA | C | El README no documenta landmark ni jerarquía de encabezados (B-8); el dato solo vive en la pestaña A11y de la demo. | `src/uix/blocks/stats-band/README.md` | ARREGLADO | | A-23 | `pricing` | doctrina | BAJA | C | Pulsar el segmento de periodo YA ACTIVO devuelve la sección entera al periodo contrario: el block posee el estado y su propio control lo mueve a un… | `src/uix/blocks/pricing/pricing-switch.svelte` | ARREGLADO | | A-24 | `pricing` | percepcion | BAJA | C | Las tarjetas de plan NO son de igual alto y los CTA NO se alinean: `height="100%"` sobre `Card` es un atributo HTML inerte, no una prop. El README y… | `src/uix/blocks/pricing/pricing-plan.svelte` | ARREGLADO | -| A-25 | `pricing` | doctrina | BAJA | C | La demo documenta una elevación que el código se niega explícitamente a hacer y que el propio README lista como brecha abierta del canon. | `web/routes/blocks/pricing/+page.svelte` | CONFIRMADO | +| A-25 | `pricing` | doctrina | BAJA | C | La demo documenta una elevación que el código se niega explícitamente a hacer y que el propio README lista como brecha abierta del canon. | `web/routes/blocks/pricing/+page.svelte` | ARREGLADO | | A-26 | `pricing` | doctrina | BAJA | C | El block exige a la app tres cadenas obligatorias para nombrar el ÚNICO estado que coordina, y justifica esa exigencia citando una lectura de B-7 que… | `src/uix/blocks/pricing/pricing-switch.svelte` | REFUTADO | | A-27 | `testimonials` | doctrina | BAJA | C | El tipo público documenta un default de `variant` que el componente no usa. | `src/uix/blocks/testimonials/types.ts` | ARREGLADO | | A-28 | `testimonials` | doctrina | BAJA | C | `.Items` tipa toda la superficie de `AutoGrid` pero descarta en silencio parte de ella: el spread del consumidor va ANTES de props fijadas a mano. | `src/uix/blocks/testimonials/testimonials-items.svelte` | ARREGLADO | @@ -138,6 +138,11 @@ Columna **or.** = de qué sección del documento viejo salió la fila (`C` confi | A-92 | `pricing` | doctrina | BAJA | F7 | Una restricción estructural del modelo de cascada (sólo los presets CSS participan del stagger) vive en un comentario del block y falta en §D.13 de la doctrina… | `docs/theming/motion.md` | CONFIRMADO | | A-93 | `stats-band` | doctrina | MEDIA | F7 | `Motion` no expone su momento «visto» (privado + `data-animation-pending`), así que un block no puede sincronizarse con el revelado sin violar B-6… | `src/uix/eidos/components/motion/motion.svelte` | CONFIRMADO | | A-94 | `feature-grid · team · testimonials` | doctrina | MEDIA | F7 | Los tres declaran `= AutoGridProps` y ponen `{...rest}` antes de props fijadas: el consumidor tipa `align`/`width` y se descartan en silencio (A-28 ×3)… | `src/uix/blocks/testimonials/types.ts` | ARREGLADO | +| A-95 | `banner` | doctrina | MEDIA | F7 | Con `affix="top"` la tira fijada tapa la cabecera pegada y la navegación queda inalcanzable; la pieza que falta es la que posee las alturas de página (`app-shell`)… | `web/routes/blocks/banner/BannerSite.svelte` | CONFIRMADO | +| A-96 | `banner` | doctrina | BAJA | F7 | `affixOffset` es prop público sin control vivo en la demo, contra la regla «cada prop público, un control»… | `web/routes/blocks/banner/+page.svelte` | CONFIRMADO | +| A-97 | `feature-grid + 6 blocks` | percepcion | MEDIA | F7 | El texto `color="muted"` mide 3,70:1 en claro — bajo AA de cuerpo — en 8 sitios de 7 blocks; el hallazgo estaba enterrado en la ficha de A-70, que es REFUTADO… | `src/uix/blocks/feature-grid/feature-grid-item-text.svelte` | REFUTADO | +| A-98 | `hero` | percepcion | MEDIA | F7 | Las acciones no apilan en móvil: `Group` es row/nowrap y a 375px los dos botones ocupan 315 de 327px; `cta` ya lo resolvió con `Flex` responsive… | `src/uix/blocks/hero/hero.svelte` | CONFIRMADO | +| A-99 | `Group` (canon) | doctrina | MEDIA | F7 | `Group` no aplica el `wrap` que su README promete en tres sitios: no lo pasa a `Flex`, no lo declara el recipe, y `Omit` impide compensarlo… | `src/uix/eidos/components/group/group.svelte` | CONFIRMADO | ## Reparto @@ -352,6 +357,85 @@ Los trece restantes, por filas vivas primero: `pricing` · `faq` · `site-header +### A-95 — CONFIRMADO · `banner` · doctrina · MEDIA + +**Mecanismo** — Con `affix="top"` la tira fijada TAPA la cabecera pegada, y la navegación del sitio queda inalcanzable mientras el aviso siga visible. Medido en `/blocks/banner/preview?affix=top` a 1280×700 con la página desplazada 800px: la tira ocupa `0..54` y el `
` del `site-header` `0..31` —se solapan—, y `document.elementFromPoint` en el centro del header devuelve LA TIRA. El apilamiento en sí es correcto y está firmado: `Affix` monta en el peldaño `--viewport-placement-z` = 150, «encima de un sticky header, debajo de menús y diálogos», y el escenario lo dice («las dos compiten por el mismo borde — por eso el aviso va por encima del cromo»). El escenario ya compensa con `padding-block-start: 3.5rem` en la página, pero eso empuja el CONTENIDO: un sticky con `top: 0` se sigue anclando donde está la tira. + +**La solución NO está en el banner, y ahí estaba el error de análisis.** La primera propuesta fue pasar `offset` al `site-header` (que lo expone, en px), y se cayó con una pregunta del usuario: «¿y si tenemos banners a diferentes alturas?». Cualquier número acordado se rompe con `size="lg"`, con el mensaje envolviendo a dos líneas en móvil, o con dos avisos. + +**Cómo lo resuelve la referencia** (verificado en su documentación, 2026-08-15): Mantine NO usa `Affix` para esto —su `Affix` es «renders children inside portal at fixed position», para elementos flotantes puntuales tipo scroll-to-top—. Lo resuelve en **`AppShell`**: todas las secciones son `position: fixed`, las alturas se DECLARAN una vez en el shell (`header={{ height: 60 }}`, aceptando objeto con breakpoints) y `AppShell.Main` es «statically positioned and **offset by the other sections**». Su configuración lleva además `collapsed` —«the section is hidden from the viewport and **doesn't affect the Main offset**»— y `offset?: boolean`, así que un aviso descartado deja de contar para el desplazamiento sin que nadie recalcule nada. + +**Evidencia** — `web/routes/blocks/banner/BannerSite.svelte:39-49` (el padding compensatorio) · `src/uix/eidos/components/affix/types.ts` (el peldaño 150) · https://mantine.dev/core/affix/ y https://mantine.dev/core/app-shell/ (leídas). + +**Disposición** — **NO se arregla en `banner` ni en `site-header`**: la pieza que falta es la que POSEE las alturas de página y propaga los offsets, y en el plan del tier es el block `app-shell` (F3.1, sin construir). Hasta que exista, cualquier solución en el banner es un número acordado con otro nombre. Lo que sí procede ya, y es documental: que el README del block diga que `affix="top"` no está pensado para convivir con una cabecera pegada — para eso, hasta que haya shell, el app agrupa aviso y cabecera en un solo `Sticky` (⚠️ esa alternativa está RAZONADA, no medida). + + +### A-96 — CONFIRMADO · `banner` · doctrina · BAJA + +**Mecanismo** — `affixOffset` es prop público y no tiene control vivo en la demo; sólo lo tiene `affix`. La regla del tier es «cada prop público, un control vivo» (B-9 + la doctrina de demos del handoff). + +**Evidencia** — `web/routes/blocks/banner/+page.svelte` — controles: intent · variant · descartable · affix · dir. + +**Disposición** — Un control más, o declararlo en la ficha de la API como omitido a propósito (podría serlo: un selector de longitud CSS es ruido en una fila de chips). + + +### A-97 — REFUTADO · `feature-grid + 6 blocks` · percepcion · MEDIA + +**Mecanismo** — El texto que los blocks pintan con `color="muted"` mide **3,70:1** sobre el lienzo de página en claro, por debajo del suelo AA de cuerpo (4,5:1). Medido hoy en `/blocks/feature-grid/preview`: la descripción de cada celda (`feature-grid-item-text.svelte:12`, `Text color="muted"`, 16px) resuelve tinta `rgb(131,131,131)` sobre fondo `rgb(252,252,252)` = 3,70:1. Es EXACTAMENTE el mismo número que midió el verificador de la fase 2, y ahí está el problema de proceso: ese hallazgo vive enterrado dentro de la ficha de **A-70, que está marcada REFUTADO**. La reclamación de A-70 («feature-grid no tiene nada que auditar perceptivamente») se refutó correctamente, pero el verificador encontró de paso ESTO y nunca se le dio fila propia, así que el recuento del ledger lo daba por inexistente. + +**No es de un block: es del tier.** Censo de `color="muted"` en `src/uix/blocks/`: **8 sitios en 7 blocks** — `feature-grid-item-text` (16px, cuerpo) · `feature-split-text` (lg) · `content-section` lede (lg) y meta (sm) · `content-section-media` caption (sm) · `pricing-plan-description` (sm) · `pricing-plan-price` suffix · `testimonials-author-role` (sm). El ratio es idéntico en todos —mismo token, mismo lienzo—; lo que cambia es el umbral aplicable: a 16px y a `sm` es 4,5:1, así que fallan; sólo los `lg` podrían salvarse si superan los 18,66px que bajan el umbral a 3:1. + +**Evidencia** — Medición con composición hecha por el navegador (canvas) en `/blocks/feature-grid/preview`, 1280×900, tema claro. ⚠️ La medición en oscuro NO vale: dio el mismo valor, señal de que la preview no conmuta con `prefers-color-scheme`, así que sólo se declara el modo claro. + +**Disposición** — El valor sale del token del canon (`content-muted`), no del block, pero es cada block quien ELIGE el rol `muted` para su cuerpo. Dos salidas y no son excluyentes: (a) CANON — que `content-muted` alcance AA sobre el lienzo de página, que es donde se arregla para todos; (b) block-side — no usar `muted` para el CUERPO de un párrafo, reservándolo a metadato. Antes de tocar nada hay que medir los `lg` por separado, porque su umbral es otro. + + + +**REFUTADO el mismo día (2026-08-15) — la vara era ajena.** El proyecto NO mide el contraste con el 4,5:1 genérico de WCAG: su suelo es DOBLE y está escrito en `theming/reference.md:1719` — «floors APCA ≥ 60 ∧ WCAG ≥ 3» — con guard propio (`scripts/contrast-audit.ts`, «WCAG 2 gate + APCA Lc, over the 33 scales × 2 modes»). Y sobre esta tinta en concreto, `reference.md:1780-1781`: «`text·11` is the secondary / low-contrast ink (≈APCA 60) — **marginal sub-4.5:1** on the muddy light-mode scales… **by design**». + +Re-medido con las funciones del propio repo (`src/arts/color/apca.ts`, en el formato que declara — gamma sRGB **0..1**, no 0..255): **Lc APCA = 63,7** (suelo 60 ✅) y **WCAG = 3,70:1** (suelo ≥3 ✅). La tinta CUMPLE los dos suelos del sistema. + +⚠️ Dos lecciones, y la segunda es de instrumento: (1) **antes de medir contraste hay que usar la vara del proyecto**, que aquí es APCA + un WCAG rebajado para la tinta secundaria, no el 4,5 de manual; (2) el primer intento con `apcaLc` devolvió **102666.5** — Lc va de −108 a +106 — porque le pasé el color en 0..255. Un valor fuera de rango no es un hallazgo raro: es un formato mal pasado. + +Lo que SÍ sobrevive de esta ficha, como dato y no como defecto: el censo de dónde se pinta cuerpo con `muted` — 8 sitios en 7 blocks —, útil el día que se retoque ese rol. + +### A-99 — CONFIRMADO · `Group` (canon) · doctrina · MEDIA + +**Mecanismo** — `Group` **no envuelve, y nadie puede hacer que envuelva**, mientras su documentación promete lo contrario en tres sitios. La cadena, leída entera: + +``` +group.svelte → ← NUNCA pasa `wrap` +flex.svelte → wrap = 'nowrap' → pushStyleVar('--flex-wrap', …) +flex.css:51 → flex-wrap: var(--flex-wrap, nowrap) +types.ts:4 → GroupProps = Omit ← el consumidor tampoco puede +group.css → sólo `--group-attached-overlap`, `data-grow` y las reglas de `attached` +``` + +Lo que su README afirma: «`wrap="wrap"` + `align="center"` por defecto», «**Defaults pensados para action rows** — `align: center`, `wrap: wrap`», y en la comparativa «Row con wrap por defecto | UIX: **Sí** | Chakra HStack: No». Medido en la demo del propio componente (`/uix/components/group`): `flex-wrap: **nowrap**`, `flex-direction: row`, `align-items: center`. **El `align` SÍ se cumple**, lo que descarta que el recipe no cargue: falta específicamente el `wrap`. + +**Evidencia** — Lectura de los cuatro ficheros de la cadena + medición del componente aislado en su propia demo, no en un block. + +**Disposición** — CANON. O `group.svelte` pasa el `wrap` con su default documentado, o el recipe lo declara, o la documentación deja de prometerlo. Nota de tipo: `Omit` fue deliberado (el wrap era una decisión del componente, no del consumidor) — coherente con un default fijo, incoherente con que ese default no exista. + + +### A-98 — CONFIRMADO · `hero` · percepcion · MEDIA + +**Mecanismo** — El cluster de acciones del hero no apila en móvil: `hero.svelte:127` lo compone con ``, y `Group` es `flex-direction: row` / `flex-wrap: nowrap`. Medido a 375×800 en `/blocks/hero/preview`: el grupo mide 327px y sus dos hijos 191 + 124 = **315px sin contar el gap**, en una sola fila, con la etiqueta de la acción secundaria ya truncándose. El block hermano resolvió exactamente esto: `cta.svelte:98-99` usa ``, y sus dos acciones SÍ apilan a la misma anchura (medido: 279 y 191px, una debajo de otra). + +**Evidencia** — Playwright headless, 375×800, tras la puerta de hidratación. ⚠️ La primera medición de esta fila fue INVÁLIDA y se descarta: el selector cogió el primer contenedor con dos botones, que en `hero` es el `Stack` de la copia (anchos 100/327/327/327 = eyebrow · título · descripción · acciones), no el `Group`. El dato bueno viene de seleccionar `[data-group]` con ≥2 hijos interactivos. + +**Disposición** — Block-side y por composición pura, con el patrón que el tier ya usa: cambiar el `Group` por `Flex direction={{ base: 'column', sm: 'row' }}`, como `cta`. Estaba anotado en el handoff desde julio («`Group` no apila… `hero` todavía compone sus acciones con `Group`») sin medición; ahora la tiene. + +**REESCRITA (2026-08-17) — la causa está una capa más abajo: [A-99].** La disposición anterior («cambiar el `Group` por `Flex direction` responsive, como `cta`») da por hecho que el block eligió mal el componente, y es falso: `Group` ES el componente para una fila de acciones —su README lo llama «defaults pensados para action rows»— y además expone `direction` responsive, así que ni siquiera hacía falta `Flex`. Lo que falla es que `Group` no aplica el `wrap` que documenta (A-99), y por eso las acciones ni envuelven ni apilan. + +Alcance del síntoma, medido: `hero` (dos acciones, 315 de 327px a 375px, la segunda etiqueta truncándose — contenido REAL de la demo) y `feature-split` (`.Actions` también compone `Group`; su escenario pone una sola acción, así que el caso no se ejercita — al forzar una segunda, sigue en una línea. ⚠️ el «desborda el viewport» que se afirmó primero era artefacto: el ancho lo puso el texto inventado para el clon). + +`cta` se salva por accidente: usa `Flex` a mano, no porque `Group` fuera inadecuado. + +**Disposición corregida** — sin arreglo block-side. En cuanto `Group` envuelva, los dos blocks se curan solos. Si se quisiera además APILAR en móvil (que no es lo mismo que envolver), eso sí sería block-side y por props: `direction={{ base: 'column', sm: 'row' }}` sobre el propio `Group`. + + + ### A-91 — ARREGLADO · `banner` · doctrina · BAJA **Mecanismo** — El canon avisa EN SU PROPIO TIPO (`eidos/components/banner/types.ts`, typedoc de `BannerIntent`) de que su eje `intent` «conflates two axes the doctrine separates»: `intent` es el eje EVALUATIVO (los 6 intents) mientras `primary`/`secondary`/`tertiary` son roles de jerarquía que pertenecen a `color`; y de que Banner, al no tener prop `color`, «is the one painted component outside the open colour system — resolving this is a pending decision, not an oversight». El block re-expone ese eje entero vía `Omit` y su mapa de composición lo describe como «`intent` (the canonical color roles)», sin registrarlo. Su README registra CINCO huecos del canon (el `role="banner"` no anulable, la tinta de la ✕ con sus medidas, la persistencia del descarte, la animación diferida, el sticky) — la doctrina del tier es que «un hueco del canon se registra, no se falsea», y a éste le falta la fila. @@ -606,7 +690,7 @@ Preferible (a): la asimetría con `container='xl'` es fea y el hermano ya la res **Evidencia** — Ver A-13. -### A-25 — CONFIRMADO · `pricing` · doctrina · BAJA +### A-25 — ARREGLADO · `pricing` · doctrina · BAJA **Mecanismo** — La demo documenta una elevación que el código se niega explícitamente a hacer: «`featured` le da acento y elevación» frente al comentario de implementación «The featured tier is NOT elevated: `Card` exposes no elevation prop… Registered as a gap in the README instead of faked with an inline `box-shadow`». @@ -614,6 +698,9 @@ Preferible (a): la asimetría con `container='xl'` es fea y el hermano ya la res **Disposición** — Corregir la demo (acento cromático, sin elevación). Fase 3, trivial. +**Re-verificación (2026-08-17)** — ya no se reproduce: no queda ninguna mención de «elevación» ni en `web/routes/blocks/cta/+page.svelte` ni en el README del block. + + ### A-26 — REFUTADO · `pricing` · doctrina · BAJA @@ -934,6 +1021,15 @@ Parche local en el block NO recomendado: el contrato B de cta prohíbe `.css` pr Al cerrarlo, corregir también la redacción del hallazgo en el ledger: el indicador EXISTE y ambos elementos son alcanzables por teclado; el defecto es de contraste del anillo y sólo en esquema oscuro. Y anotar el hueco de percepción en `src/uix/blocks/cta/README.md`, junto a los que ya declara el docstring (cta.svelte:18-23). +**Re-medición y DISPOSICIÓN CORREGIDA (2026-08-17)** — sigue viva y con el mismo número: 1,43:1 compuesto, en los dos elementos del block. Pero la disposición anterior («que `Surface variant='solid'` re-ancle `--focus-ring-color` para su subárbol») es **la capa equivocada, y eso explica el revert de `e468e764b`**. + +La doctrina lo fija en `theming/reference.md:1797` (§«Borders — two tiers»): el anillo de foco es «the one always-sole indicator» y está en el tramo **load-bearing con objetivo 3:1** —no entre los decorativos exentos—, PERO su apariencia es «a config axis, parameterised, NOT hardcoded»: `primitives.focusRing` + `color.focus.{ring,ringError}`, emitidos UNA vez como `--focus-ring-*`. Y textualmente: «The shipped default (`primary·8 @ ~50%` translucent) **measures sub-3:1 as a raw ratio**; hardening it (opaque color, `innerWidth > 0`, offset) is a **default-VALUE decision via config, never a per-component CSS change**». + +Es decir: el proyecto YA SABE que su anillo por defecto queda sub-3:1, y tiene decidido dónde se arregla — subiendo el valor por defecto en la config del tema, no re-anclando el token desde un componente. El intento revertido hacía justo lo segundo. + +**Disposición** — decisión de VALOR sobre `color.focus.ring` / `primitives.focusRing`, fuera del tier `blocks` y fuera de `Surface`. El block `cta` no tiene nada que arreglar: sólo elige un lienzo sólido, que es donde el default se nota más. + + ### A-48 — CONFIRMADO · `banner` · percepcion · MEDIA diff --git a/src/uix/blocks/banner/banner.svelte b/src/uix/blocks/banner/banner.svelte index a91e8e4ff..921cc1a09 100644 --- a/src/uix/blocks/banner/banner.svelte +++ b/src/uix/blocks/banner/banner.svelte @@ -30,7 +30,7 @@ import type { SiteBannerProps } from './types'; let { - container = 'xl', + containerSize = 'xl', affix, affixOffset = '0px', onDismiss, @@ -61,7 +61,7 @@ content); `paddingX={0}` because the gutter is already the Banner's padding, and doubling it would push the message off its column on a phone. --> - + diff --git a/src/uix/blocks/banner/types.ts b/src/uix/blocks/banner/types.ts index 6d5bbbde5..1ac378627 100644 --- a/src/uix/blocks/banner/types.ts +++ b/src/uix/blocks/banner/types.ts @@ -45,7 +45,7 @@ export type SiteBannerProps = Omit & { * page's content column instead of running edge to edge on a wide screen. * Passed straight to `Container`. @default 'xl' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** * Wire the dismiss. When present the block renders `Banner.Close` (which * composes the canon `IconButton` and localises its own accessible name) and diff --git a/src/uix/blocks/contact/contact.svelte b/src/uix/blocks/contact/contact.svelte index 6ba203d4c..2d0298935 100644 --- a/src/uix/blocks/contact/contact.svelte +++ b/src/uix/blocks/contact/contact.svelte @@ -35,8 +35,8 @@ type SyncCheckable = { validateSync(values: unknown): { ok: boolean } }; let { - container = 'lg', - size = 'lg', + containerSize = 'lg', + sectionSize = 'lg', form: externalForm, schema: externalSchema, verification, @@ -116,8 +116,8 @@
-
- +
+ {@render children?.({ state, form: ownForm, schema })} diff --git a/src/uix/blocks/contact/types.ts b/src/uix/blocks/contact/types.ts index c4071b352..dcff7ea14 100644 --- a/src/uix/blocks/contact/types.ts +++ b/src/uix/blocks/contact/types.ts @@ -23,9 +23,9 @@ export type ContactSnippetProps = { // (which already refine `style`/`class`), never `HTMLAttributes`. export type ContactProps = Omit, 'children'> & { /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'lg' */ - size?: SectionSize; + sectionSize?: SectionSize; /** * A form handle from the app's `createForm`. OPTIONAL: without one the block * builds its own over the default schema (name · email · message) and calls diff --git a/src/uix/blocks/content-section/content-section.svelte b/src/uix/blocks/content-section/content-section.svelte index dbfe532d4..084ba7271 100644 --- a/src/uix/blocks/content-section/content-section.svelte +++ b/src/uix/blocks/content-section/content-section.svelte @@ -35,7 +35,7 @@ let { measure = 'normal', wide = 'lg', - size = 'lg', + sectionSize = 'lg', level = 2, eyebrow, title, @@ -67,7 +67,7 @@
-
+
- + diff --git a/src/uix/blocks/cta/types.ts b/src/uix/blocks/cta/types.ts index e06d0abc4..feae17ce8 100644 --- a/src/uix/blocks/cta/types.ts +++ b/src/uix/blocks/cta/types.ts @@ -44,9 +44,9 @@ export type CtaProps = Omit, 'children' | 'title'> & /** Semantic level of the title heading. @default 2 */ level?: HeadingLevel; /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding of the SECTION (around the panel). @default 'lg' */ - size?: SectionSize; + sectionSize?: SectionSize; /** A chip or label above the title. */ eyebrow?: Snippet; /** The title's words — the block wraps them in a `Heading` and owns the diff --git a/src/uix/blocks/faq/faq.svelte b/src/uix/blocks/faq/faq.svelte index d50835384..cf6f8d002 100644 --- a/src/uix/blocks/faq/faq.svelte +++ b/src/uix/blocks/faq/faq.svelte @@ -14,12 +14,12 @@ import { Stack } from '$uix/eidos/components/stack'; import type { FaqProps } from './types'; - let { container = 'md', size = 'lg', children, ...rest }: FaqProps = $props(); + let { containerSize = 'md', sectionSize = 'lg', children, ...rest }: FaqProps = $props();
-
- +
+ {@render children?.()} diff --git a/src/uix/blocks/faq/types.ts b/src/uix/blocks/faq/types.ts index 3404f1256..47efffd32 100644 --- a/src/uix/blocks/faq/types.ts +++ b/src/uix/blocks/faq/types.ts @@ -7,9 +7,9 @@ import type { AccordionProps } from '$uix/eidos/components/accordion'; export type FaqProps = Omit, 'children'> & { /** Content measure — narrow by default for a single readable column. @default 'md' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'lg' */ - size?: SectionSize; + sectionSize?: SectionSize; /** `Header` and `List` in composition order. */ children?: Snippet; }; diff --git a/src/uix/blocks/feature-grid/feature-grid.svelte b/src/uix/blocks/feature-grid/feature-grid.svelte index 1dc37e20b..7290605e6 100644 --- a/src/uix/blocks/feature-grid/feature-grid.svelte +++ b/src/uix/blocks/feature-grid/feature-grid.svelte @@ -15,8 +15,8 @@ import type { FeatureGridProps } from './types'; let { - container = 'lg', - size = 'lg', + containerSize = 'lg', + sectionSize = 'lg', align = 'center', children, ...rest @@ -33,8 +33,8 @@
-
- +
+ diff --git a/src/uix/blocks/feature-grid/types.ts b/src/uix/blocks/feature-grid/types.ts index 6e2ab4d44..a7e82cb10 100644 --- a/src/uix/blocks/feature-grid/types.ts +++ b/src/uix/blocks/feature-grid/types.ts @@ -15,9 +15,9 @@ import type { TextProps } from '$uix/eidos/components/text'; // the raw HTML attribute surface into a canon component clashes on `style`. export type FeatureGridProps = Omit, 'children'> & { /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'lg' */ - size?: SectionSize; + sectionSize?: SectionSize; /** * Cross-axis placement of the section — `center` sits the header in the middle * and centres each cell's content; `start` runs both flush with the item diff --git a/src/uix/blocks/feature-split/feature-split.svelte b/src/uix/blocks/feature-split/feature-split.svelte index 4563c8e87..72116a2b9 100644 --- a/src/uix/blocks/feature-split/feature-split.svelte +++ b/src/uix/blocks/feature-split/feature-split.svelte @@ -14,12 +14,18 @@ import { Stack } from '$uix/eidos/components/stack'; import type { FeatureSplitProps } from './types'; - let { container = 'lg', size = 'xl', gap = 12, children, ...rest }: FeatureSplitProps = $props(); + let { + containerSize = 'lg', + sectionSize = 'xl', + gap = 12, + children, + ...rest + }: FeatureSplitProps = $props();
-
- +
+ {@render children?.()} diff --git a/src/uix/blocks/feature-split/types.ts b/src/uix/blocks/feature-split/types.ts index f08c1a8db..585f9ea99 100644 --- a/src/uix/blocks/feature-split/types.ts +++ b/src/uix/blocks/feature-split/types.ts @@ -10,9 +10,9 @@ import type { ComponentColorProp } from '$uix/eidos/lib/types'; export type FeatureSplitProps = Omit, 'children'> & { /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'xl' */ - size?: SectionSize; + sectionSize?: SectionSize; /** Gap between the alternating rows (space scale). @default 12 */ gap?: number; /** The `Row`s. */ diff --git a/src/uix/blocks/hero/README.md b/src/uix/blocks/hero/README.md index ef68567ff..ffbae1ba7 100644 --- a/src/uix/blocks/hero/README.md +++ b/src/uix/blocks/hero/README.md @@ -13,8 +13,8 @@ renders) while the app owns every word. | Slot | Composes | Notes | | ------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | root | bare `
` | landmark; `id` names it from the title the block renders | -| padding | `Section` | `size` (block-axis padding, default `xl`) | -| measure | `Container` | `size` (`container` prop, default `lg`) | +| padding | `Section` | `sectionSize` (block-axis padding, default `xl`) | +| measure | `Container` | `containerSize` (default `lg`) | | decoration | `Backdrop` | `decor` prop — `glow` (default) · `mesh` · `grid` · `dots` · `none`; skipped under `background` | | layout | `Grid` (split) · `Stack` (center) · positioned `Box` layers (background) | `split` is two columns only when there is `media` | | entrance | `Motion` (`trigger="viewport"`) + `data-stagger` on the copy stack | the copy unfolds by structural index; media enters with `scale-fade` after it | diff --git a/src/uix/blocks/hero/hero.svelte b/src/uix/blocks/hero/hero.svelte index 6f7aaa6bd..8cd008e5c 100644 --- a/src/uix/blocks/hero/hero.svelte +++ b/src/uix/blocks/hero/hero.svelte @@ -25,8 +25,8 @@ let { layout = 'center', level = 1, - container = 'lg', - size = 'xl', + containerSize = 'lg', + sectionSize = 'xl', decor, eyebrow, title, @@ -152,8 +152,8 @@ style="background: var(--color-overlay); opacity: var(--opacity-scrim);" > -
- +
+ {@render copy()}
@@ -163,8 +163,8 @@ -
- +
+ {#if twoColumn} {@render copy()} diff --git a/src/uix/blocks/hero/types.ts b/src/uix/blocks/hero/types.ts index 7b8b27d4b..d5b7720d9 100644 --- a/src/uix/blocks/hero/types.ts +++ b/src/uix/blocks/hero/types.ts @@ -29,9 +29,9 @@ export type HeroProps = Omit, 'children' | 'title'> */ level?: HeadingLevel; /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'xl' */ - size?: SectionSize; + sectionSize?: SectionSize; /** * Decoration painted behind the section (a `Backdrop`): `glow` · `mesh` · * `grid` · `dots` · `none`. Defaults to `glow` — a hero is the page's loudest diff --git a/src/uix/blocks/newsletter/README.md b/src/uix/blocks/newsletter/README.md index fc0a9c394..d7d706d9d 100644 --- a/src/uix/blocks/newsletter/README.md +++ b/src/uix/blocks/newsletter/README.md @@ -15,7 +15,7 @@ and a handler here. | Slot | Composes | Notes | | ------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | root | bare `
` | landmark; `id` names it from the title the block renders | -| padding · measure | `Section` + `Container` | `size` / `container` | +| padding · measure | `Section` + `Container` | `sectionSize` / `containerSize` | | entrance | `Motion` (`trigger="viewport"`, `scale-fade`) | one entrance for the whole section — a sign-up is a single ask | | panel | `Surface` (always `solid` · `color` · `gradient` · `rounded`) | `panel={false}` drops it and the form returns to the page surface | | layout | `Stack` (center) · `Grid` 2-col (justified) | | diff --git a/src/uix/blocks/newsletter/newsletter.svelte b/src/uix/blocks/newsletter/newsletter.svelte index 45f37b1d7..fb584880d 100644 --- a/src/uix/blocks/newsletter/newsletter.svelte +++ b/src/uix/blocks/newsletter/newsletter.svelte @@ -40,8 +40,8 @@ color = 'primary', gradient = true, level = 2, - container = 'lg', - size = 'lg', + containerSize = 'lg', + sectionSize = 'lg', form, schema, sent = $bindable(false), @@ -196,8 +196,8 @@ {/snippet}
-
- +
+ {#if panel} diff --git a/src/uix/blocks/newsletter/types.ts b/src/uix/blocks/newsletter/types.ts index 64363819d..565cd25d9 100644 --- a/src/uix/blocks/newsletter/types.ts +++ b/src/uix/blocks/newsletter/types.ts @@ -49,9 +49,9 @@ export type NewsletterProps = Omit, 'children' | 'ti /** Semantic level of the title heading. @default 2 */ level?: HeadingLevel; /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding of the SECTION (around the panel). @default 'lg' */ - size?: SectionSize; + sectionSize?: SectionSize; /** * The form handle from `createForm` — REQUIRED. The app owns the schema, the * values, the defaults, the validation timing AND the submit handler, because diff --git a/src/uix/blocks/pricing/pricing-plan.svelte b/src/uix/blocks/pricing/pricing-plan.svelte index a860984aa..386288ac7 100644 --- a/src/uix/blocks/pricing/pricing-plan.svelte +++ b/src/uix/blocks/pricing/pricing-plan.svelte @@ -26,12 +26,7 @@ opposite of what this composition is for. --> - + diff --git a/src/uix/blocks/pricing/pricing.svelte b/src/uix/blocks/pricing/pricing.svelte index e210a7dd9..4c50925bb 100644 --- a/src/uix/blocks/pricing/pricing.svelte +++ b/src/uix/blocks/pricing/pricing.svelte @@ -17,8 +17,8 @@ let { period = $bindable('monthly'), - container = 'lg', - size = 'xl', + containerSize = 'lg', + sectionSize = 'xl', children, ...rest }: PricingProps = $props(); @@ -34,8 +34,8 @@
-
- +
+ {@render children?.()} diff --git a/src/uix/blocks/pricing/types.ts b/src/uix/blocks/pricing/types.ts index 240c7547f..5111f1efb 100644 --- a/src/uix/blocks/pricing/types.ts +++ b/src/uix/blocks/pricing/types.ts @@ -16,9 +16,9 @@ export type PricingProps = Omit, 'children'> & { /** Billing period, bindable. The `Switch` writes it, `PlanPrice` reads it. @default 'monthly' */ period?: BillingPeriod; /** Content measure. Passed straight to `Container`. @default 'lg' */ - container?: ContainerSize; + containerSize?: ContainerSize; /** Block-axis padding. Passed straight to `Section`. @default 'xl' */ - size?: SectionSize; + sectionSize?: SectionSize; /** `Header`, `Switch`, `Plans` in composition order. */ children?: Snippet; }; diff --git a/src/uix/blocks/site-footer/README.md b/src/uix/blocks/site-footer/README.md index c29b0f1ff..def046a6a 100644 --- a/src/uix/blocks/site-footer/README.md +++ b/src/uix/blocks/site-footer/README.md @@ -8,19 +8,19 @@ there (language / theme / region pickers). ## Composition map -| Slot | Composes | Notes | -| ---------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------- | -| root | bare `