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/src/uix/eidos/components/box/README.md

14 KiB

Eidos Box

Universal box-model utility. Eidos-native: cada prop mapea a una custom property --box-* emitida inline en un único <div data-box>, y la receta cae con revert-layer a la cascada normal cuando no se fija. Box es la primitiva sobre la que se componen Flex, Grid, Stack, Group, Wrap, Container y Section.

Superficie

<Box padding={4} gap={3} display="flex" maxWidth={600}>…</Box>

<!-- Como item de un Grid/Flex padre: -->
<Box gridColumn="1 / 3" placeSelf="center">…</Box>

Baseline

Origen: air/components/layout/box (rama morfo-runtime). Adaptaciones para eidos: drop del prefijo air-, selectores [data-box] directos, vars renombradas a --box-*, sustitución de var(--air-space-N) por var(--space-N) y resolución reactiva de props responsive vía ActiveEidos.require().resolve().

Decisión clave introducida en 66c6897c: los props de grid item placement (gridColumn, gridRow, gridArea, placeSelf) viven en Box, no en Grid. Son props del HIJO que declara su slot, no del container. Air los puso en Grid — corregido durante el port.

Comparativa

Capacidad UIX (eidos) Radix Themes Chakra UI Mantine
Display Sí Sí Sí Sí
Width / height + min/max Sí Sí Sí Sí
Padding / margin (+ shorthands X/Y/per-side) Sí (paddingX, paddingY, paddingTop…) Sí (p, px, pt…) Sí Sí
Position + insets Sí Sí Sí Sí
Overflow + axis variants Sí Sí Sí Sí
Flex item (flex, grow, shrink, basis, order) Sí Sí Sí — (en Flex)
Grid item (gridColumn, gridRow, gridArea, placeSelf) Sí (movido desde Grid 2026-05-22) Sí Sí —
align-self / justify-self Sí Sí Sí —
Background / color / shadow No — UIX separa layout de visual treatment Sí (bg, style) Sí (bg, color) Sí (bg)
as prop para semantic tag No — root fijo <div> (batch 1) Sí Sí (vía polymorphic ref) Sí (component)
Responsive prop syntax Sí (ResponsiveProp via Eidos) Sí ({ initial: …, sm: … }) Sí Sí
Visibilidad por breakpoint Sí — DESMONTA (visibleFrom/hiddenFrom) Sí, por CSS (hideFrom/hideBelow) Sí, por CSS Sí, por CSS (hiddenFrom/visibleFrom)
Container-side flex/grid (alignItems, justifyContent, templateColumns…) No — viven en Flex/Grid (split Radix) Split Radix Mezclado en Box Split Radix

Decisiones

  • Item-side props en Box, container-side en Flex/Grid — split estilo Radix Themes / Mantine. Chakra y MUI mezclan todo en Box, pero el split deja un API más predecible.

  • No bg/color/shadow — UIX separa estructura de tratamiento visual. Esos props viven en componentes con variant/color (avatar, dialog, button…). Box es sólo layout.

  • Root <div> fijo — sin as prop en batch 1 → as desde 2026-08-19 (F21). Los «≥2 casos reales» que la decisión pedía llegaron: una columna de enlaces de pie que debía ser ul/li, y dieciséis blocks del tier envolviendo Section en un <section> escrito a mano sólo para poder nombrarlo. La lista de elementos es cerrada (BoxElement: contenedores, nunca void) — es una escotilla SEMÁNTICA, no un prop de tag libre. Default div, así que ningún consumidor anterior cambia; el modelo de caja, las vars y la receta son idénticos rinda lo que rinda.

  • Inline styles, no classnames generados — el style attr lista cada --box-* declarada; debugger en DevTools muestra exactamente qué propiedades activas tiene cada Box.

  • revert-layer como fallback — props sin setear no fuerzan initial, dejan que la cascada normal aplique. Permite mezclar Box con cualquier otro CSS sin "ganar" sobre estilos no relacionados.

  • visibleFrom / hiddenFrom NO renderizan, no ocultan (2026-08-18) — la diferencia entera con display={{ base: 'none' }}. Un {#if} alrededor de la raíz: el box no está en el DOM, sus efectos no corren y el media de dentro no se pide. Por herencia lo ganan los once contenedores que componen Box (Section, Container, Flex, Grid, Stack, Group, Wrap, AutoGrid, Surface, AspectRatio, Float), sin tocar sus ficheros — doce con Box.

    Ninguna referencia hace esto: Mantine (hiddenFrom/visibleFrom), Chakra y Panda (hideFrom/hideBelow), Framer y Webflow ocultan todos con CSS y dejan el DOM montado — Webflow lo documenta («hidden elements still load initially, consuming bandwidth») y Framer llega a duplicar secciones enteras por breakpoint. Eligieron CSS porque con SSR una puerta JS pinta la variante equivocada en el HTML (MUI: «returns a default matches during the first mount»; Vuetify #17252: «major layout shifts during hydration»), y el precio de evitarlo es adivinar el ancho por User-Agent o Client Hints.

    Aquí ese precio no existe: el proyecto se despliega como SPA (adapter-static + fallback, y ninguna ruta declara prerender = true), así que el primer render ocurre en el navegador con el innerWidth real. La contrapartida que SÍ se paga está escrita en el tipo: cruzar un breakpoint destruye el subárbol y su estado. Cuando el estado deba sobrevivir, display.

    Sólo en DESARROLLO verás otra cosa, y conviene saberlo antes de abrir un issue: el dev server de SvelteKit sí renderiza en servidor, donde el ancho es 0, así que el HTML inicial trae la variante base y el navegador empieza a descargar su media antes de que la hidratación la pode. Medido: con visibleFrom="md" el HTML del dev no contiene la sección, con hiddenFrom sí, y el video.mp4 de dentro se pide una vez. En producción no ocurre: el build es un 200.html de ~1,8 KB, shell puro, sin una sola sección.

    Verificado en Chrome real (2026-08-18): a 2133px conviven correctamente visibleFrom="md" presente, hiddenFrom="md" ausente y un rango sm–lg ausente; al cerrar la puerta en vivo desaparecen del DOM la sección, su <video> y el <input>; al reabrirla el input vuelve vacío — la renuncia, medida, no supuesta.

  • El shorthand flex se EXPANDE en el wrapper, no en el recipe (2026-08-17) — box.css declara flex-grow/flex-shrink/flex-basis desde sus vars; un flex: shorthand al lado lo borraba aquel de los tres cuya var estuviera sin poner, porque revert-layer (eidos no envía @layer) devuelve la propiedad a su valor inicial. Medido: <Box flex={2}> computaba 0 1 auto y se quedaba en el ancho de su contenido dentro de una fila flex; inyectando --box-grow: 2 en el mismo nodo pasaba a 2 1 auto. El prop sigue igual y ahora funciona: expandFlexShorthand (lib/layout-helpers.ts, con la gramática de CSS pinneada en test) escribe las tres vars, y un grow/shrink/basis explícito sigue ganando. El token público --box-flex desaparece con el shorthand: era un nombre que ya no lee nadie. La misma trampa que affix/types.ts documenta para position.

Eventos Sema

Box declara 0 eventos. Es una primitiva pasiva: no commit, no emerge, no reacciona a nada — sólo estiliza hijos vía cascade. Componentes que animan/cambian estado al aparecer componen Box con una primitiva interactiva (popover, drawer, collapsible) que sí posee los verbos sema relevantes.

Gaps

Gap Disposición Detalle
as prop para semantic tag (section, article, main, aside…) diferir Esperamos ≥2 casos reales antes de añadir polimorfismo. Hoy se envuelve Box en el tag semántico.
bg / color shorthand sobre tokens UIX descartar Box es layout puro. Los componentes con variant/color son los que llevan tratamiento visual.
borderRadius / boxShadow props descartar Idem — escapar vía style= cuando se necesite un one-off.
visibleFrom/hiddenFrom en Card, Banner, ScrollArea y Sticky diferir Rinden su propia raíz (svelte:element, <header>, un Provider), así que no heredan la puerta. La regla es la del as: se añaden a mano cuando aparezcan ≥2 casos reales; hasta entonces, envolver en <Box visibleFrom>.
Puente de SSR para visibleFrom/hiddenFrom diferir, con disparador Si algún día una ruta activa prerender/ssr, el HTML llevará la variante base. El paso es: estampar data-visible-from/data-hidden-from, emitir dos reglas @media por breakpoint en render-css.ts (junto a las de tipografía) y pasar la puerta a hidratado ? resuelto : true. Hoy sería un atributo que nadie lee.
flexBasis (alias de basis) diferir Posible alias por familiaridad con devs Chakra. Bajo prioridad.
Documentación per-prop con ejemplos visuales individuales implementar En la pasada de docs final. Hoy el demo cubre los casos comunes.

Referencias

Passive justification

Visual-only primitive (scope: ['eidos'] en el morfo). Una sola part Provider que emite el marker [data-box], sin estados, sin data-attrs específicos, sin ARIA, sin keyboard. El recipe consume las CSS variables que el componente escribe inline. No hay nada que animar, ningún ciclo de vida que enviar a sema.

Powered by TurnKey Linux.