feat(layout): plug Batch 1 gaps — Flex.alignContent + Grid.columns/rows/inline/alignContent

Addresses the "should" features documented as gaps in the layout
READMEs from `fdb0e680`. Audit script still reports 77 / 77 PASS,
svelte-check 0 errors.

**Flex**

- `alignContent` prop (multi-line cross-axis alignment). Maps to
  `--flex-align-content`; defaults to `normal` in the recipe so it
  has no effect when wrap is off. Closes the Radix / Chakra parity
  gap.

**Grid**

- `inline` boolean — renders as `display: inline-grid` (paridad con
  Flex.inline).
- `columns` / `rows` numeric shorthands — Radix Themes pattern.
  Internally resolved to `repeat(N, minmax(0, 1fr))`. `templateColumns`
  / `templateRows` string still wins if both are passed.
- `alignContent` prop — same shape as Flex.

**Shared**

- New `LayoutAlignContent` type added to `_layout/shared.ts`
  (covers start, end, center, stretch, space-between, space-around,
  space-evenly, flex-start, flex-end, normal, baseline).

**Group**

- Verified `grow` boolean already implemented in `0ec2a57a` /
  `591b0885` — no change needed; the README now correctly reflects it.

**Docs**

- Flex + Grid READMEs updated: comparison tables mark previously
  missing features as Sí; Gaps section marks them ✅ implementado.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
dev 5 months ago
parent ec66999b6c
commit 265a3946b5

@ -43,6 +43,18 @@ export type LayoutAlignSelf =
export type LayoutJustifySelf = 'auto' | 'start' | 'end' | 'center' | 'stretch';
export type LayoutFlexDirection = 'row' | 'row-reverse' | 'column' | 'column-reverse';
export type LayoutFlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';
export type LayoutAlignContent =
| 'start'
| 'end'
| 'center'
| 'stretch'
| 'space-between'
| 'space-around'
| 'space-evenly'
| 'flex-start'
| 'flex-end'
| 'normal'
| 'baseline';
export type LayoutAlignItems =
| 'stretch'
| 'start'

@ -39,7 +39,7 @@ intactos al Box raíz.
| `wrap` → flex-wrap | Sí | Sí | Sí (`flexWrap`) | Sí |
| `gap` + `rowGap` / `columnGap` | Sí | Sí (`gap`, `gapX`, `gapY`) | Sí | Sí |
| `inline` boolean (inline-flex) | Sí | Vía `display="inline-flex"` | Sí | Sí (`inline`) |
| `alignContent` (multi-line cross) | **No** — gap conocido | Sí | Sí | Sí |
| `alignContent` (multi-line cross) | Sí | Sí | Sí | Sí |
| Item props heredados de Box | Sí (composición) | Sí | Sí (style-props todo en Box) | — split |
| Responsive | Sí | Sí | Sí | Sí |
@ -64,7 +64,7 @@ intactos al Box raíz.
| Gap | Disposición | Detalle |
| --- | --- | --- |
| `alignContent` (multi-line cross-axis) | **implementar** | Radix + Chakra lo tienen. Útil cuando `wrap` está activo. Backlog Layout fixes. |
| `alignContent` (multi-line cross-axis) | ✅ implementado en `ec66999b` siguiente commit | Cubierto. |
| Helpers `HStack` / `VStack` (alias direction-fijo) | **diferir** | Ergonomía Chakra. UIX usa `<Stack direction="…">`. Reconsiderar si la fricción es real. |
| `inline-flex` shorthand alternativo (e.g. `<InlineFlex>`) | **descartar** | `inline` boolean cubre el caso. |
| Slot `divider` entre hijos (separator automático) | **diferir** | Patrón Chakra Stack. Más natural en Stack que en Flex. |

@ -9,6 +9,7 @@
align-items: var(--flex-align, stretch);
justify-content: var(--flex-justify, flex-start);
flex-wrap: var(--flex-wrap, nowrap);
align-content: var(--flex-align-content, normal);
row-gap: var(--flex-row-gap, var(--box-gap, revert-layer));
column-gap: var(--flex-column-gap, var(--box-gap, revert-layer));
}

@ -19,6 +19,7 @@
align,
justify,
wrap = 'nowrap',
alignContent,
rowGap,
columnGap,
style,
@ -35,6 +36,7 @@
pushStyleVar(decls, '--flex-align', eidos.resolve(align));
pushStyleVar(decls, '--flex-justify', eidos.resolve(justify));
pushStyleVar(decls, '--flex-wrap', eidos.resolve(wrap));
pushStyleVar(decls, '--flex-align-content', eidos.resolve(alignContent));
pushStyleVar(decls, '--flex-row-gap', formatLayoutSpace(eidos.resolve(rowGap)));
pushStyleVar(decls, '--flex-column-gap', formatLayoutSpace(eidos.resolve(columnGap)));
return composeStyle(decls, style);

@ -1,6 +1,7 @@
import type { ResponsiveProp } from '$uix/eidos/lib/types';
import type { BoxProps } from '../box/types';
import type {
LayoutAlignContent,
LayoutAlignItems,
LayoutFlexDirection,
LayoutFlexWrap,
@ -19,6 +20,11 @@ export type FlexProps = Omit<BoxProps, 'display'> & {
justify?: ResponsiveProp<LayoutJustifyContent>;
/** `flex-wrap`. @default 'nowrap' */
wrap?: ResponsiveProp<LayoutFlexWrap>;
/**
* `align-content` — multi-line cross-axis alignment. Only takes effect
* when `wrap !== 'nowrap'` and the lines actually wrap.
*/
alignContent?: ResponsiveProp<LayoutAlignContent>;
/** `row-gap`. Overrides `gap` for the row axis. */
rowGap?: ResponsiveProp<LayoutSpaceValue>;
/** `column-gap`. Overrides `gap` for the column axis. */

@ -27,14 +27,14 @@ selectores `[data-box][data-grid] { … }`.
| Capacidad | UIX | Radix Themes | Chakra UI | Mantine SimpleGrid |
| --- | --- | --- | --- | --- |
| `templateColumns` / `templateRows` | Sí (string libre) | Sí | Sí | — (sólo cols) |
| `columns` / `rows` shorthand (`columns={3}` → `repeat(3, 1fr)`) | **No** — gap conocido | Sí (`columns="3"`) | Sí (`columns={3}`) | Sí |
| `columns` / `rows` shorthand (`columns={3}` → `repeat(3, 1fr)`) | Sí | Sí (`columns="3"`) | Sí (`columns={3}`) | Sí |
| `autoColumns` / `autoRows` / `autoFlow` | Sí | Sí | Sí | — |
| `gap` + `rowGap` / `columnGap` | Sí | Sí | Sí | Sí |
| `align` → align-items | Sí | Sí | Sí | — |
| `justify` → justify-content | Sí | Sí | Sí | — |
| `placeItems` / `placeContent` | Sí | Sí | Sí | — |
| `alignContent` (multi-line) | **No** — gap conocido | Sí | Sí | — |
| `inline` boolean (inline-grid) | **No** — gap conocido | Vía `display="inline-grid"` | Sí | — |
| `alignContent` (multi-line) | Sí | Sí | Sí | — |
| `inline` boolean (inline-grid) | Sí | Vía `display="inline-grid"` | Sí | — |
| Item placement (`gridColumn`, `gridRow`, `gridArea`, `placeSelf`) | **En Box** (Radix) | En Box | En Box | — |
| Responsive `breakpoints` | Sí | Sí | Sí | Sí |
@ -57,9 +57,9 @@ selectores `[data-box][data-grid] { … }`.
| Gap | Disposición | Detalle |
| --- | --- | --- |
| `columns` / `rows` numeric shorthand | **implementar** | Patrón Radix Themes (`columns="3"` → `repeat(3, 1fr)`). Ergonomía Mantine SimpleGrid. Backlog Layout fixes. |
| `inline` boolean | **implementar** | Paridad con Flex.inline. Trivial — display: inline-grid. |
| `alignContent` (multi-line cross-axis align) | **implementar** | Útil con `autoRows` + scroll. Radix lo tiene. |
| `columns` / `rows` numeric shorthand | ✅ implementado | Pasa template `repeat(N, minmax(0, 1fr))`. `templateColumns` string sigue ganando si se pasan ambos. |
| `inline` boolean | ✅ implementado | display: inline-grid. |
| `alignContent` (multi-line cross-axis align) | ✅ implementado | Útil con `autoRows` + scroll. |
| Slot/Cell helpers (e.g. `<Grid.Cell column="2 / 4">`) | **diferir** | Box ya cumple. Reconsiderar si emerge un patrón estable. |
| `subgrid` support | **diferir** | Soporte navegador todavía parcheado; esperar penetración. |

@ -16,6 +16,7 @@
grid-auto-flow: var(--grid-auto-flow, row);
align-items: var(--grid-align, stretch);
justify-content: var(--grid-justify, start);
align-content: var(--grid-align-content, normal);
place-items: var(--grid-place-items, revert-layer);
place-content: var(--grid-place-content, revert-layer);
row-gap: var(--grid-row-gap, var(--grid-gap, revert-layer));

@ -14,6 +14,9 @@
import type { GridProps } from './types';
let {
inline = false,
columns,
rows,
templateColumns,
templateRows,
autoColumns,
@ -24,6 +27,7 @@
gap,
align,
justify,
alignContent,
placeItems,
placeContent,
style,
@ -34,15 +38,32 @@
const eidos = ActiveEidos.require();
// Numeric `columns` / `rows` shorthand maps to `repeat(N, 1fr)`.
// Full template string from `templateColumns` / `templateRows` wins
// if both are passed.
const resolvedTemplateColumns = $derived.by(() => {
const tpl = eidos.resolve(templateColumns);
if (tpl) return tpl;
const n = eidos.resolve(columns);
return typeof n === 'number' && n > 0 ? `repeat(${n}, minmax(0, 1fr))` : undefined;
});
const resolvedTemplateRows = $derived.by(() => {
const tpl = eidos.resolve(templateRows);
if (tpl) return tpl;
const n = eidos.resolve(rows);
return typeof n === 'number' && n > 0 ? `repeat(${n}, minmax(0, 1fr))` : undefined;
});
const resolvedStyle = $derived.by(() => {
const decls: string[] = [];
pushStyleVar(decls, '--grid-template-columns', eidos.resolve(templateColumns));
pushStyleVar(decls, '--grid-template-rows', eidos.resolve(templateRows));
pushStyleVar(decls, '--grid-template-columns', resolvedTemplateColumns);
pushStyleVar(decls, '--grid-template-rows', resolvedTemplateRows);
pushStyleVar(decls, '--grid-auto-columns', eidos.resolve(autoColumns));
pushStyleVar(decls, '--grid-auto-rows', eidos.resolve(autoRows));
pushStyleVar(decls, '--grid-auto-flow', eidos.resolve(autoFlow));
pushStyleVar(decls, '--grid-align', eidos.resolve(align));
pushStyleVar(decls, '--grid-justify', eidos.resolve(justify));
pushStyleVar(decls, '--grid-align-content', eidos.resolve(alignContent));
pushStyleVar(decls, '--grid-place-items', eidos.resolve(placeItems));
pushStyleVar(decls, '--grid-place-content', eidos.resolve(placeContent));
pushStyleVar(decls, '--grid-gap', formatLayoutSpace(eidos.resolve(gap)));
@ -52,6 +73,12 @@
});
</script>
<Box {...restProps} display="grid" class={className} style={resolvedStyle} data-grid="">
<Box
{...restProps}
display={inline ? 'inline-grid' : 'grid'}
class={className}
style={resolvedStyle}
data-grid=""
>
{@render children?.()}
</Box>

@ -1,6 +1,7 @@
import type { ResponsiveProp } from '$uix/eidos/lib/types';
import type { BoxProps } from '../box/types';
import type {
LayoutAlignContent,
LayoutAlignItems,
LayoutGridAutoFlow,
LayoutJustifyContent,
@ -8,9 +9,19 @@ import type {
} from '../_layout/shared';
export type GridProps = Omit<BoxProps, 'display'> & {
/** `grid-template-columns`. */
/** Use `inline-grid` instead of `grid`. @default false */
inline?: boolean;
/**
* Numeric shorthand for `grid-template-columns: repeat(N, 1fr)`. Radix
* Themes pattern. Use `templateColumns` when you need a custom track
* list (e.g. `'200px 1fr auto'`).
*/
columns?: ResponsiveProp<number>;
/** Numeric shorthand for `grid-template-rows: repeat(N, 1fr)`. */
rows?: ResponsiveProp<number>;
/** `grid-template-columns` — full track list. Takes precedence over `columns`. */
templateColumns?: ResponsiveProp<string>;
/** `grid-template-rows`. */
/** `grid-template-rows` — full track list. Takes precedence over `rows`. */
templateRows?: ResponsiveProp<string>;
/** `grid-auto-columns`. */
autoColumns?: ResponsiveProp<string>;
@ -28,6 +39,8 @@ export type GridProps = Omit<BoxProps, 'display'> & {
align?: ResponsiveProp<LayoutAlignItems>;
/** `justify-content`. */
justify?: ResponsiveProp<LayoutJustifyContent>;
/** `align-content` — multi-line cross-axis alignment. */
alignContent?: ResponsiveProp<LayoutAlignContent>;
/** `place-items` shorthand. */
placeItems?: ResponsiveProp<string>;
/** `place-content` shorthand. */

Loading…
Cancel
Save

Powered by TurnKey Linux.