Stage
Animated, preset-driven panel workspaces built on Cubitt resizable primitives.
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
import {
Stage,
defineStageConfig,
useStageSnapshot,
} from "@tilt-legal/cubitt-components/stage";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
Controlled Presets
Responsive Group Size Presets
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.
<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
Use useStageSnapshot when controls or integrations need the layout state Stage
is already observing internally.
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
API Reference
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
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
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
Use the hook for custom controls inside the provider.
const useAppStage = () =>
useStage<typeof configs>();useStageSnapshot
Use the hook for controls or integrations that react to live Stage layout state.
const snapshot = useStageSnapshot<typeof configs>();