# Build the "Progressive UI streaming" pattern: `StreamingLayout`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
Skeletons and partial components render as the agent's structured output arrives.

Use it when: Any generative UI slower than a few hundred milliseconds.

## What to build
Renders generative UI from a structured object while it streams, reserving space for every expected part up front and filling values in place in whatever order they arrive. People can read and click finished parts while the rest loads. It renders wherever generated panels, cards or reports appear.

### Props
- `shape`: Array<{ id: string; kind: "kpi" | "chart" | "table" | "text"; count?: number; minHeight: number }>, the expected layout taken from the output schema, not from content.
- `partial`: DeepPartial<T>, the object received so far; the parent parses the stream.
- `isComplete(slotId, value)`: (id: string, value: unknown) => boolean, whether a slot's value is valid enough to show.
- `renderSlot(slotId, value)`: (id: string, value: unknown) => ReactNode, draws a finished slot.
- `status`: "waiting" | "streaming" | "complete" | "stopped" | "error", controlled by the parent.
- `onStop()` and `onRetry(slotIds?: string[])`: callbacks.
- `metrics?`: { firstContentMs?: number; layoutShifts?: number; completeMs?: number }, shown quietly when present.

### States it must render
- Waiting: the full skeleton for every slot in `shape` at final size, with a Stop control.
- Streaming: finished slots show real content and are interactive; others keep their skeleton; nothing moves.
- Complete: skeletons gone, optional timing such as "first content 0.4 s, complete 3.1 s, 0 layout shifts".
- Stopped: finished slots stay; unfinished ones say "Not generated" with Retry for just those.
- Error: as stopped, plus a short message that the stream broke.

### Interactions
- A slot swaps from skeleton to content only when `isComplete` returns true, in place.
- Stop calls `onStop` and shows the stopped state at once.
- Retry calls `onRetry` with the unfinished slot ids; focus is never moved by arriving content.

### Edge cases
- Values arriving out of order (the last table row before the first KPI): each fills its own slot; order of arrival never changes position.
- Half-arrived values ("3." of "3.4%", a chart missing its data array) stay as skeletons until complete.
- More items than `count`: append below the reserved block; fewer: collapse only the trailing empty slots once complete.
- Very fast streams: batch updates per animation frame.

## Must avoid
Layout that jumps on every chunk, so the user cannot start reading or clicking.

## Engineering constraint
Stream partial objects against a schema and reserve space by expected shape, not measured content.

## Accessibility
- Set `aria-busy` on the container until complete; announce "Ready" once rather than each slot.
- Skeletons are hidden from screen readers; each finished slot gets its own label.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
