fix(eidos): el eje size de form LLEGA a sus acciones - contexto A-112

<Form size="xs"> renderizaba acciones md: la talla moria en el provider
(form-submit/reset con default 'md', nada la propagaba) y del eje entero solo
sobrevivia el row-gap. Contexto de eidos calcado 1:1 de toolbar/context.ts
(el precedente A-112): form provee su size resuelto; Submit/Reset lo
consumen como default (su prop explicita gana; md standalone).

El eje va VERBATIM, no tapado en md - la bifurcacion de doctrina queda
RESUELTA Y ESCRITA (next-features 13 "Anchura vs densidad"):
reference.md:590 (tapar en md, precedente Dialog.Close) gobierna ejes de
ANCHURA; el de form es DENSIDAD declarada cuya receta ya escribio los cinco
peldanos.

- 5 ficheros de codigo, solo eidos (context.ts NUEVO); los dos costes
  avisados NO se tocan, verificado con linea: la excepcion A11 de
  form-auto-fields y el duck type CompatibleFormProvider quedan intactos
  (el puente es setContext/getContext con Simbolo propio, disjunto).
- Medido: 84 diffs y NI UNO fuera - submit 40, reset 40, form 4 (su panel);
  CERO en array/widget/error-summary; CERO en md. Alto -10/-6/0/+8/+16 px;
  la letra lg/xl difiere de la prediccion (+4/+12 vs +2/+8) por causa MEDIDA:
  --font-size-lg/xl son clamp() fluidos que saturan desde ~1200px - ningun
  valor fuera de la escalera. Capturas xs/md/xl revisadas por el supervisor.
- Los botones del array siguen POR HERENCIA CSS, intactos (0 diffs) -
  respuesta para E1: E2 ahorra el contexto, no la lectura (E1 debera pasar
  size al Button que inyecte o sigue siendo la regresion medida).
- Dos mentiras NUEVAS del instrumento, registradas: la sonda estandar fuerza
  data-size sobre el nodo compuesto y SE PISA (su 0 es por construccion) -
  y los clamp() fluidos no son comparables sin declarar viewport.
- Registro: 13 cierra E2 (diagnostico original conservado tachado - era
  exacto) y abre alert-dialog (mismo agujero; a el le toca la norma TAPADA
  por ser eje de anchura), error-summary con data-size que nadie lee, la
  escalera de fuente 3-sobre-5 que viola el 1:1 (E1, su carril), y la cita
  colgada de dialog/context.ts:9. Pendiente dicho: el parrafo de doctrina
  querria vivir tambien en reference.md (fuera del alcance liberado).
- Gates: eidos 443+1 ajeno - check 0 atribuibles - docs-check 0/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alpha-0.1-background
dev 2 months ago
parent 3bf7930baa
commit 318aac207d

@ -162,6 +162,31 @@ arquitectónica escrita una vez) y anotadas para firma.
> abierto en `next-features` §13 que esos dos botones compongan también el
> `Button` canónico (toca soma y morfo, clase A-112).
> **Nota 2026-08-25 — el eje `size` ya LLEGA a las acciones (expediente E2).**
> Ceder el cromo dejó a la vista el reverso: `Form.Submit` y `Form.Reset`
> traían su propio `size = 'md'` y nada lo puenteaba, así que un
> `<Form size="xs">` los renderizaba con `data-size="md"` en las CINCO tallas
> (36 px de alto, 16 px de letra) y del eje sólo sobrevivía el `row-gap`.
> Firmado el puente de densidad de `toolbar/context.ts`, calcado 1:1: nuevo
> `components/form/context.ts` (`Symbol('form-eidos-ctx')` + getter de
> propiedad), `form.svelte` publica el `resolvedSize` que ya calculaba, y las
> dos acciones pierden su default y leen `size={size ?? form?.size}` — la prop
> explícita siempre gana, y sin `<Form>` ancestro cae en el `md` del propio
> `Button`. **VERBATIM, sin tapar en `md`**: la tapa de `reference.md`
> §«Container→part derivation» gobierna contenedores cuyo eje es ANCHURA (su
> primer consumidor es `Dialog.Close`, y un diálogo `full` no debe engordar sus
> controles); el de `form` es DENSIDAD declarada — `types.ts` lo escribe
> («Visual density for form spacing and action controls») y `form.css:25-51` ya
> tenía los cinco peldaños distintos de su acción. Medido: alto
> **−10 / −6 / 0 / +8 / +16** px y letra **−4 / −2 / 0 / +4 / +12** px
> (los dos últimos son el `clamp()` fluido de `--font-size-lg` / `-xl`
> saturado a 1280 px de ancho; a 900 px dan +3,05 / +10,1). `md` no se mueve un
> solo valor. Sólo eidos: cinco ficheros, cero morfo, cero soma, cero sema —
> el contrato de 64 claves y el ledger quedan intactos.
> Sigue abierto: `form-error-summary.svelte` estampa un `data-size` que
> **ninguna regla lee** (tercer defecto de talla del componente, el único
> totalmente inerte), y el hermano `alert-dialog` tiene el mismo agujero.
**Las adjudicaciones restantes son ramas que la demo no monta**: el layout
`grid` (forzado alcanza — y ojo, su `grid-template-columns` sólo CAMBIA si el
valor altera el número de columnas: con 90px pasa de una columna de 502px a

@ -2046,18 +2046,71 @@ Lo que `chart` destapó (2026-08-22):
cerrarlo, las 23 claves se retiran: el censo de `form` bajaría 64 → 41. Ceder
sin componer no es opción — medido, caen al `<button>` del UA (89,52×36 →
68,61×21 px, borde `outset`, Arial 13,33 px, eje de talla colapsado a 21 px).
- **El eje `size` de `form` NO LLEGA a sus acciones** (medido 2026-08-24 con el
control `size` REAL de la demo, sin tocar atributos): un `<Form size="xs">`
renderiza `Form.Submit` con `data-size="md"` — 36 px de alto y 16 px de letra
**en las cinco tallas**. La causa está en el código, no en la cascada:
`eidos/components/form/form-submit.svelte:20` y `form-reset.svelte:15`
declaran `size = 'md'` por defecto y **nada les pasa la talla del
formulario**; `form.svelte:16-19`
estampa `data-size` en el provider y no hay contexto que lo propague — el
reverso exacto de `toolbar/context.ts`, que es lo que A-112 introdujo con el
precedente `ButtonGroup`. Del eje `size` de `form` sólo sobrevive hoy el hueco
entre filas (`row-gap` 12/16/20/24/28 px). **Mueve píxel en xs/sm/lg/xl** ⇒
firma. Es independiente de la cascada: existía ganase quien ganase.
- ~~**El eje `size` de `form` NO LLEGA a sus acciones**~~ — **EJECUTADO
2026-08-25.** El diagnóstico era exacto: un `<Form size="xs">` renderizaba
`Form.Submit` con `data-size="md"` —36 px de alto y 16 px de letra **en las
cinco tallas**— porque `form-submit.svelte:20` y `form-reset.svelte:15`
declaraban `size = 'md'` y **nada les pasaba la talla del formulario**;
`form.svelte:16-19` estampaba `data-size` en el provider y no había contexto.
Del eje sólo sobrevivía el `row-gap` (12/16/20/24/28 px). ⚠ Quitar el default
no arreglaba nada: el `Button` tiene el suyo — hacía falta el puente.
Firmado el puente de densidad calcado **1:1 de `toolbar/context.ts`**: nuevo
`eidos/components/form/context.ts` (`Symbol('form-eidos-ctx')` + **getter de
propiedad** para la reactividad), `form.svelte` publica el `resolvedSize` que
ya calculaba, y las dos acciones pierden su default y leen
`size={size ?? form?.size}` — la prop explícita siempre gana, y sin `<Form>`
ancestro se cae en el `md` del propio `Button`, sin re-declararlo.
**Sólo eidos**: cinco ficheros, cero morfo / soma / sema; el contrato de 64
claves y el ledger, intactos. Medido con el chip `size` REAL de la demo:
alto **−10 / −6 / 0 / +8 / +16** px y letra **−4 / −2 / 0 / +4 / +12** px
(los dos últimos son el `clamp()` fluido de `--font-size-lg` / `-xl` saturado
a 1280 px de ancho; a 900 px dan +3,05 / +10,1), `md` sin mover un valor, y
la sonda estándar **0 diffs sobre 832 valores en 7 estados**.
**Doctrina adjudicada: VERBATIM, no la norma tapada en `md`** — ver
§«Anchura vs densidad» al final de esta sección.
- **`alert-dialog` tiene el MISMO agujero, un peldaño** (registrado por el
barrido de la clase, **no medido**). `alert-dialog-action.svelte:25` y
`alert-dialog-cancel.svelte:24` llevan `size = 'md'` sobre un `<Button>`;
`alert-dialog-content.svelte:19` / `:34` / `:78` resuelve y estampa la talla y
**no publica contexto** (no hay `context.ts` en el directorio). Un
`<AlertDialog size="sm">` deja sus botones en `md` — justo lo que
`Dialog.Close` sí resuelve. ⚠ Su `size` es `DialogContentProps['size']`
(`types.ts:112` reexporta el del diálogo) ⇒ eje de **ANCHURA**, así que le
toca la norma **TAPADA**, NO el verbatim de `form`. Verificado además que
`alert-dialog-content.svelte:75` envuelve la **SOMA** `AlertDialog.Content`,
no la eidos `Dialog.Content`: tampoco hereda el puente del diálogo por la
puerta de atrás.
- **`Form.ErrorSummary` estampa un `data-size` que NADIE lee** — tercer defecto
de talla del mismo componente, y el único totalmente inerte.
`form-error-summary.svelte:7` declara `size = 'md'`, `:14` lo resuelve y
`:18` / `:24` lo estampan. Verificado por grep: **las ÚNICAS cuatro reglas con
`data-size` de todo `form.css` son `[data-form][data-size='xs'|'sm'|'lg'|'xl']`**
(`:25`, `:32`, `:39`, `:46`; `md` es la base), y el bloque del resumen
(`:154-178`) no tiene variante de talla. El instrumento lo corrobora —el nodo
no mueve un valor en las cinco— con el matiz de que en modo `auto` el resumen
está `data-hidden`, así que el peso de la prueba lo lleva el grep. Decidirlo
es elegir entre **darle escalera o retirar el prop**: decisión de producto.
Quedó FUERA de la firma del 2026-08-25 a propósito.
- **La escalera de fuente de la acción de `form` viola el 1:1 universal.**
`lib/recipes/base.ts:1405-1409` mapea `action-font-size-{xs,sm}` →
`--size-xs-font-size`, `{md,lg}` → `--size-sm-font-size` y `xl` →
`--size-md-font-size`: **cada peldaño una coordenada por debajo de su propio
nombre**, y sólo tres valores distintos estirados sobre cinco. Medido:
**12·12·14·14·16**, ni el 1:1 de `reference.md` §«The size→font mapping»
(12·14·16·18→20·24→28) ni la escalera de etiqueta — una TERCERA. `form` no
está en las excepciones legítimas. Hoy ese bloque sólo pinta los dos
`<button>` pelados del array, así que **la corrige E1 de paso** al componer el
`Button` — por eso el +2 px de fuente que E1 mide no es regresión, es el
peldaño que manda el canon.
- **`dialog/context.ts:9` cita una sección que NO EXISTE.** Remite a
`THEMING.md §5 "Subset por componente"`; `src/uix/eidos/THEMING.md` es hoy un
stub de redirección y su §5 se llama «The size canon». La sección que la norma
necesita vive en `docs/theming/reference.md` §«Per-component subset» +
§«Container→part derivation». El único fichero del repo con el literal
`Subset por componente` es `docs/decisions/guia-semantica-historica.md:206`,
marcado como NO autoritativo. Una línea.
⚠ Por esto el `context.ts` de `form` cita **por título de sección, nunca por
número de línea**.
Lo que dejó ABIERTO la firma `aria-selected` de `tags-input` (2026-08-25) —
**CERRADO el 2026-08-25** por la firma «el árbol ARIA de `tags-input` habla UN
@ -2153,5 +2206,39 @@ Lo que ABRE la firma «el árbol ARIA de `tags-input` habla UN patrón» (2026-0
congelación); mientras tanto, `avatar.badge-fg-custom-contrast` va adjudicada
en el ledger con la razón medida.
### Anchura vs densidad — cuándo la parte TAPA en `md` y cuándo hereda VERBATIM
Adjudicado el 2026-08-25 al firmar el puente de talla de `form`, porque la
doctrina bifurca y una firma tiene que elegir bando.
El parque tiene DOS mecanismos para que una parte reciba la talla de su
contenedor, y no son alternativas de gusto:
- **TAPADO en `md`** — `docs/theming/reference.md` §«Container→part derivation»
(norma 2026-06-19). Primer consumidor: `Dialog.Close`. Se aplica cuando el eje
`size` del contenedor es **ANCHURA**: un diálogo `lg` / `xl` / `full` es más
ANCHO, no más denso, y engordar sus controles sería leer mal el eje.
- **VERBATIM** — `toolbar/context.ts`, y los puentes de `button-group`,
`card-group`, `split-button` y `toggle-group`. Se aplica cuando el eje es
**DENSIDAD**: el contenedor declara la escala del control y la parte la hereda
entera.
**La prueba no es la opinión: es la propia receta.** Si la receta del contenedor
YA escribió peldaños DISTINTOS para su control en las cinco tallas, el eje es
densidad y la derivación va verbatim. `form` es el caso canónico — `types.ts`
documenta su `size` como *«Visual density for form spacing and action
controls»* y `form.css:25-51` declara los cinco valores distintos de
`--_form-action-height` / `-padding-inline` / `-font-size`. Una receta que ya
escaló su acción en cinco peldaños no está tapando en `md`.
Corolario para el hermano: `alert-dialog` hereda su `size` del diálogo
(`DialogContentProps['size']`) ⇒ eje de anchura ⇒ le toca la norma TAPADA,
aunque hoy no aplique ninguna de las dos.
⚠ La razón MECÁNICA de que haga falta un contexto (y no baste un selector
descendente) es la misma en los dos bandos, y la escribe `toolbar/context.ts`:
la receta del `Button` lee `data-size` **SOBRE el elemento**, así que el hijo
tiene que llevar el atributo — el contexto sólo le deja heredar el valor.
**Deps**: ninguna. Son mejoras del instrumental del eje, ejecutables cuando
estorben.

@ -51,6 +51,44 @@ y los tres comentarios de código que seguían afirmando **(0,2,0)** del sobre
sigue viva— y `lib/recipes/base.ts`). Se ANOTAN, no se reescriben: cada medida
fue correcta con la cascada de su día.
### FIRMA EJECUTADA (2026-08-25) — el eje `size` de `form` LLEGA a sus acciones
**Qué se firmó**: ceder el cromo de `submit`/`reset` al `Button` compuesto
(firma del 2026-08-24) destapó el reverso. `form-submit.svelte:20` y
`form-reset.svelte:15` traían su propio `size = 'md'` y **nada les pasaba la
talla del formulario**, así que un `<Form size="xs">` los renderizaba con
`data-size="md"` —36 px de alto y 16 px de letra— **en las cinco tallas**; del
eje sólo sobrevivía el `row-gap`. Quitar el default no arreglaba nada (el
`Button` tiene el suyo): hacía falta el puente, y el precedente es literal.
Nuevo `eidos/components/form/context.ts` calcado **1:1 de `toolbar/context.ts`**
(`Symbol('form-eidos-ctx')` + getter de propiedad), `form.svelte` publica el
`resolvedSize` que ya calculaba, y las dos acciones leen
`size={size ?? form?.size}` — la prop explícita gana, y standalone cae en el
`md` del propio `Button` sin re-declararlo. **Sólo eidos: cinco ficheros, cero
morfo / soma / sema; el contrato de 64 claves y el ledger, intactos.**
**Los números**: alto **−10 / −6 / 0 / +8 / +16** px y letra
**−4 / −2 / 0 / +4 / +12** px, sobre `submit` y `reset` por igual; **`md` no
mueve un solo valor**; 84 diffs en total y **cero** en los cuatro nodos del
array, el widget y el resumen de errores. Sonda estándar antes/después **0 sobre
832 valores en 7 estados**; instrumento propio reproducible (dos pasadas sobre
código idéntico ⇒ 0 diffs). `vitest src/uix/eidos` 443/444 (el rojo es el ajeno
conocido `skin-media-player`), `check` 0 errores atribuidos a los cinco
ficheros, `docs:check` 0/0.
**La doctrina que hubo que adjudicar**: **VERBATIM, no la norma tapada en `md`**.
La tapa de `reference.md` §«Container→part derivation» gobierna contenedores
cuyo eje es ANCHURA (su primer consumidor es `Dialog.Close`); el de `form` es
DENSIDAD declarada, y su propia receta ya había escrito los cinco peldaños
distintos de la acción. Escrita en `next-features.md` §13 §«Anchura vs
densidad», con el corolario de que a `alert-dialog` —mismo agujero, eje de
anchura— le toca la TAPADA.
**Lo que quedó fuera, con su entrada en §13**: `alert-dialog` (no medido),
`Form.ErrorSummary` con un `data-size` que ninguna regla lee, la escalera de
fuente `12·12·14·14·16` de la acción de `form` (que corrige E1 en su carril) y
la cita colgada de `dialog/context.ts:9`.
### FIRMA B′ EJECUTADA (2026-08-24) — la cascada de paleta es una ESCALERA
**Qué se firmó**: los tres escritores de `--{c}-palette-*` pasan a tres peldaños
@ -1862,6 +1900,22 @@ solo uso (verificaciones dirigidas de ayer); no se commitean.
acto** (2026-08-23): la lectura devuelve el valor viejo y parece un token
imposible de mover. Pasó con el fondo del cuentagotas: tres diagnósticos
falsos hasta congelar.
- **La sonda es CIEGA a un puente de talla por contexto** (2026-08-25, `form`):
fuerza la talla **ESCRIBIENDO `data-size` sobre cada nodo casado que ya lo
lleva** (`__theming-probe.ts:279-281`) — y una parte que COMPONE el `Button`
lleva `data-{c}-…` **y** `data-size`. Se lo pisa DESPUÉS del render, así que
mide el mismo atributo forzado antes y después: **el diff sale 0 por
construcción**, no por ausencia de efecto. Medido: 0 diffs sobre 832 valores
mientras el botón pasaba de 36 px fijos a 26/30/36/44/52. Para esta clase de
firma el instrumento tiene que mover el **chip REAL de la demo** (el prop),
nunca el atributo. La sonda estándar sigue valiendo como gate de «no se movió
nada COLATERAL» — que no es poco, pero no es la prueba.
- **`--font-size-lg` / `-xl` son `clamp()` FLUIDOS** (18→20 y 24→28): una medida
de letra en esas dos tallas **no es comparable entre informes si el viewport
no viaja con ella**. Medido: a 900 px dan 19,05 / 26,10 y desde ~1200 px
saturan en 20 / 28. Costó una desviación aparente de +2 px contra la cifra de
un expediente que no declaraba su ancho. **Declara el viewport en toda medida
de fuente `lg` / `xl`.**
## Trampas que costaron un commit cada una (no repetirlas)

@ -115,6 +115,38 @@ claves públicas se quedan, adjudicadas ahora como **rama que la demo no monta**
que sus once vecinas de AutoFields. Que esos dos botones compongan también el
`Button` canónico queda abierto en `next-features` §13 — toca soma y morfo.
**Firmado el 2026-08-25 — el eje `size` LLEGA a las acciones.** Ceder el cromo
destapó el reverso: `Form.Submit` y `Form.Reset` traían su propio `size = 'md'`
y nada lo puenteaba, así que un `<Form size="xs">` los renderizaba con
`data-size="md"` en las CINCO tallas —36 px de alto y 16 px de letra— y del eje
sólo sobrevivía el `row-gap` (12/16/20/24/28). Quitar el default no arreglaba
nada: el `Button` tiene el suyo. Hacía falta el puente, y el precedente es
literal: `components/form/context.ts` calca `toolbar/context.ts`
(`Symbol('form-eidos-ctx')` + **getter de propiedad** para la reactividad),
`form.svelte` publica el `resolvedSize` que ya calculaba, y las dos acciones
leen `size={size ?? form?.size}`. La **prop explícita siempre gana**; sin
`<Form>` ancestro se cae en el `md` del propio `Button`, sin re-declararlo.
La razón mecánica es la misma que escribe toolbar: la receta del `Button` lee
`data-size` **SOBRE el elemento**, así que un selector descendente desde el
formulario no lo alcanza — el hijo tiene que llevar el atributo, y el contexto
es lo que le deja heredar el valor del contenedor.
⚠ **VERBATIM, no tapado en `md`.** La norma «Container→part derivation» de
`docs/theming/reference.md` tapa en `md` a la parte que deriva del contenedor,
y su primer consumidor es `Dialog.Close`: el eje de un diálogo es ANCHURA, y uno
`full` no debe engordar sus controles.
El de `form` es **DENSIDAD declarada** — `types.ts` lo dice por
escrito («Visual density for form spacing and action controls») y `form.css`
ya había escrito los cinco peldaños DISTINTOS de `--_form-action-height` /
`-padding-inline` / `-font-size`. Una receta que escaló su acción en cinco
peldaños no está tapando en `md`.
Coste medido (viewport 1280): alto **26 / 30 / 36 / 44 / 52** y letra
**12 / 14 / 16 / 20 / 28** — el 1:1 tipográfico universal. `md` no mueve un solo
valor. Queda abierto: `Form.ErrorSummary` estampa un `data-size` que **ninguna
regla lee**.
**Lo que queda fuera por doctrina**: los tres privados del panel
(`--_form-padding` / `-bg` / `-shadow`) son un CONMUTADOR (dos fuentes: la
variante `plain` y la `panel`), y los `--_form-action-*` son el eje de talla

@ -0,0 +1,39 @@
import { getContext, setContext } from 'svelte';
import type { FormSize } from './types';
/**
* Eidos context published by `<Form>` and read by `<Form.Submit>` / `<Form.Reset>`.
*
* It carries the form's resolved `size` so the composed canon `<Button>`
* defaults to the form's density instead of Button's own `md`. Same shape and
* rationale as Toolbar's context: Button's recipe reads `data-size` ON the
* button element, so a descendant selector on the form can't reach it — the
* child must carry the attr itself, and the context lets it inherit the form's
* value while an explicit prop on the action always wins.
*
* VERBATIM, not capped at `md`. The `md` cap of
* `docs/theming/reference.md` §"Container→part derivation" governs a container
* whose size axis is WIDTH (its first consumer is `Dialog.Close`: a wider — or
* `full` — dialog must not fatten its controls). A form's axis is declared
* DENSITY (`types.ts`: "Visual density for form spacing and action controls")
* and its own recipe already wrote the five distinct steps of
* `--_form-action-height` / `-padding-inline` / `-font-size`, xs..xl. A recipe
* that ladders its action across five steps is not capping at `md`.
*
* A property getter keeps the bridge reactive: when the form's `size` prop
* changes, every action re-reads on its next derivation.
*/
const KEY = Symbol('form-eidos-ctx');
export interface FormEidosCtx {
readonly size: FormSize;
}
export function setFormEidosCtx(ctx: FormEidosCtx): void {
setContext(KEY, ctx);
}
export function getFormEidosCtx(): FormEidosCtx | undefined {
return getContext<FormEidosCtx | undefined>(KEY);
}

@ -9,21 +9,27 @@
*/
import * as Form from '$soma/components/form';
import { Button } from '$uix/eidos/components/button';
import { getFormEidosCtx } from './context';
import type { FormResetProps } from './types';
let {
size = 'md',
size,
variant = 'ghost',
color = 'neutral',
style,
children: bodyContent,
...rest
}: FormResetProps = $props();
// Same density bridge as `form-submit`: the form's size reaches the action
// through the eidos context; an explicit prop wins; standalone falls
// through to the Button's own `md`.
const form = getFormEidosCtx();
</script>
<Form.Reset {...rest}>
{#snippet child({ props })}
<Button {...props} {size} {variant} {color} {style}>
<Button {...props} size={size ?? form?.size} {variant} {color} {style}>
{#if bodyContent}{@render bodyContent()}{/if}
</Button>
{/snippet}

@ -14,21 +14,27 @@
*/
import * as Form from '$soma/components/form';
import { Button } from '$uix/eidos/components/button';
import { getFormEidosCtx } from './context';
import type { FormSubmitProps } from './types';
let {
size = 'md',
size,
variant = 'surface',
color = 'primary',
style,
children: bodyContent,
...rest
}: FormSubmitProps = $props();
// No default of its own: the form's density reaches the action through the
// eidos context, and an explicit `size` prop always wins. Standalone (no
// form ancestor) falls through to the Button's own `md`.
const form = getFormEidosCtx();
</script>
<Form.Submit {...rest}>
{#snippet child({ props })}
<Button {...props} {size} {variant} {color} {style}>
<Button {...props} size={size ?? form?.size} {variant} {color} {style}>
{#if bodyContent}{@render bodyContent()}{/if}
</Button>
{/snippet}

@ -2,6 +2,7 @@
import './form.css';
import { ActiveEidos } from '$uix/eidos';
import * as Form from '$soma/components/form';
import { setFormEidosCtx } from './context';
import type { FormProps, FormProviderSnippetProps } from './types';
let {
@ -14,6 +15,15 @@
const eidos = ActiveEidos.require();
const resolvedSize = $derived(eidos.resolve(size, 'md'));
// Density bridge for `<Form.Submit>` / `<Form.Reset>`: the composed canon
// `<Button>` defaults its `size` to the form's, so an `xs` form gets `xs`
// actions without every call site repeating it. Getter keeps it reactive.
setFormEidosCtx({
get size() {
return resolvedSize;
}
});
</script>
<Form.Provider {...rest} data-size={resolvedSize} data-layout={layout} data-variant={variant}>

@ -26,12 +26,14 @@ export type FormProps = ProviderProps & {
};
export type FormSubmitProps = SubmitProps & {
/** Sizing scale of the composed Button. @default the form's `size` */
size?: ResponsiveProp<FormSize>;
variant?: FormActionVariant;
color?: FormActionColor;
};
export type FormResetProps = ResetProps & {
/** Sizing scale of the composed Button. @default the form's `size` */
size?: ResponsiveProp<FormSize>;
variant?: FormActionVariant;
color?: FormActionColor;

Loading…
Cancel
Save

Powered by TurnKey Linux.