

<Preview name="StageDefault" />

## Overview [#overview]

`Stage` coordinates nested resizable panel groups from a typed preset record.
Each configured group is its own preset machine, so regions such as a main
chat/canvas split and a bottom terminal can change independently.

Stage does not own app surfaces. Add backgrounds, borders, and layout chrome
with `className` on `Stage` or `Stage.Panel`; Stage owns preset orchestration,
transitioning, mounted state, and resize handles.

## Usage [#usage]

```tsx
import {
  Stage,
  defineStageConfig,
  useStageSnapshot,
} from "@tilt-legal/cubitt-components/stage";
```

```tsx
const mainConfig = defineStageConfig({
  chat: {
    thread: "fill",
    canvas: 0,
  },
  canvas: {
    thread: { size: 33.333, minSize: "260px" },
    canvas: {
      size: "fill",
      minSize: "240px",
      collapseToPreset: "chat",
    },
  },
});

const shellConfig = defineStageConfig({
  closed: {
    content: "fill",
    terminal: 0,
  },
  open: {
    content: "fill",
    terminal: { size: "280px", minSize: "180px", collapseToPreset: "closed" },
  },
});

const configs = {
  shell: shellConfig,
  main: mainConfig,
};

export function Component() {
  return (
    <Stage
      className="h-96 overflow-hidden rounded-lg border border-border-1 bg-surface-1"
      configs={configs}
      defaultPreset={{ shell: "closed", main: "chat" }}
    >
      <Stage.Group id="shell" orientation="vertical">
        <Stage.Panel id="content">
          <Stage.Group id="main" orientation="horizontal">
            <Stage.Panel className="bg-surface-3" id="thread">
              Thread
            </Stage.Panel>
            <Stage.Panel className="bg-surface-1" id="canvas" keepMounted>
              Canvas
            </Stage.Panel>
          </Stage.Group>
        </Stage.Panel>
        <Stage.Panel className="bg-surface-3" id="terminal" keepMounted>
          Terminal
        </Stage.Panel>
      </Stage.Group>
    </Stage>
  );
}
```

## Examples [#examples]

### Controlled Presets [#controlled-presets]

<Preview name="StageControlled" />

### Responsive Group Size Presets [#responsive-group-size-presets]

<Preview name="StageResponsivePresets" />

`groupSizePresets` requests presets when a group enters a measured size band
along its orientation axis. Rules are ordered from the smallest `below`
threshold to the largest. Omit `below` on the final rule to request a preset
when no threshold matches.

```tsx
<Stage.Group
  groupSizePresets={[
    { below: "520px", preset: "collapsed" },
    { below: "760px", preset: "compact" },
    { preset: "expanded" },
  ]}
  id="summary"
  orientation="horizontal"
>
  <Stage.Panel id="transcript">Transcript</Stage.Panel>
  <Stage.Panel id="comments">Comments</Stage.Panel>
  <Stage.Panel id="outline">Outline</Stage.Panel>
</Stage.Group>
```

The rule fires when the group enters a different matching size band. It is not a
hard constraint, so custom controls can still call `setPreset` while the group
remains in the same band. If no rule matches and no final catch-all rule exists,
Stage does not request a preset.

### Stage Snapshot [#stage-snapshot]

Use `useStageSnapshot` when controls or integrations need the layout state Stage
is already observing internally.

```tsx
function SummaryInspector() {
  const snapshot = useStageSnapshot<typeof configs>();
  const summary = snapshot.groups.summary;

  return (
    <output>
      {summary?.activePreset} - {summary?.groupSizePx}px -{" "}
      {summary?.panels.comments?.sizePx}px
    </output>
  );
}
```

The snapshot includes registered groups, configured presets, group size rules,
the current active preset record, observed group sizes, and observed panel
sizes. Panel sizes are live measurements from the resizable panel, not preset
targets.

### Terminal Toggle [#terminal-toggle]

<Preview name="StageTerminal" />

## API Reference [#api-reference]

### Stage [#stage]

Root provider and preset orchestrator.

| Prop              | Type                          | Default | Description                                                             |
| ----------------- | ----------------------------- | ------- | ----------------------------------------------------------------------- |
| `configs`         | `StageConfigs`                | -       | Preset machine configs keyed by matching group id.                      |
| `preset`          | `StagePresetRecord<TConfigs>` | -       | Controlled active preset record.                                        |
| `defaultPreset`   | `StagePresetRecord<TConfigs>` | -       | Uncontrolled initial preset record.                                     |
| `onPresetChange`  | `(next, event) => void`       | -       | Fires when `setPreset` or `collapseToPreset` requests a machine preset. |
| `onPresetSettled` | `(event) => void`             | -       | Fires once a changed machine preset transition has visually settled.    |
| `className`       | `string`                      | -       | Additional classes for the stage root.                                  |

### Stage.Group [#stagegroup]

Axis wrapper for sibling panels.

| Prop               | Type                                                           | Default | Description                                                                                                                                                                        |
| ------------------ | -------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`                                                       | -       | Group key that must match one key in `configs`.                                                                                                                                    |
| `orientation`      | `"horizontal" \| "vertical"`                                   | -       | Panel layout axis.                                                                                                                                                                 |
| `groupSizePresets` | `({ below: "520px"; preset: string } \| { preset: string })[]` | -       | Ordered pixel breakpoints that request a preset when the measured group size enters a matching band. Omit `below` on the final rule to request a preset when no threshold matches. |
| `children`         | `Stage.Panel[]`                                                | -       | Direct panel children only.                                                                                                                                                        |

### Stage.Panel [#stagepanel]

Addressable content region within the nearest group.

| Prop          | Type      | Default | Description                                                                                    |
| ------------- | --------- | ------- | ---------------------------------------------------------------------------------------------- |
| `id`          | `string`  | -       | Panel key scoped to the nearest group.                                                         |
| `keepMounted` | `boolean` | `false` | Preserve closed panel content state while hiding it from interaction and assistive technology. |
| `className`   | `string`  | -       | Additional classes for the mounted panel content wrapper.                                      |

### useStage [#usestage]

Use the hook for custom controls inside the provider.

```tsx
const useAppStage = () =>
  useStage<typeof configs>();
```

### useStageSnapshot [#usestagesnapshot]

Use the hook for controls or integrations that react to live Stage layout state.

```tsx
const snapshot = useStageSnapshot<typeof configs>();
```
