import { type ReactNode } from 'react'; import { type VariantProps } from 'class-variance-authority'; import type { AgentAdapter } from '../../agent/types'; /** How far past `minMainWidth` an overlaid panel needs before it docks. */ export declare const PANEL_OVERLAY_HYSTERESIS_PX = 24; /** Whether an open panel overlays: docking would leave `
` below * `minMainWidth`; it docks again past the hysteresis band. */ export declare function shouldOverlayPanel(dockedMainWidth: number | null, minMainWidth: number | undefined, wasOverlay: boolean): boolean; export interface ToolRailTool { /** Stable tool id — used in `data-active`, the imperative handle, and * to label the open panel region. */ id: string; /** Accessible name for the strip icon + tooltip, and the open panel's * region label. Never rendered as visible body text. */ label: string; /** lucide-react glyph (rendered `aria-hidden` inside the IconButton). */ icon: ReactNode; /** Panel body for this tool. Rendered inline-start of the strip when * `side='end'` (mirrored for `'start'`). The consumer composes it. */ panel: ReactNode; /** * Optional non-scrolling header for this tool's panel. Rendered pinned at * the top of the open panel — above the scroll region — so a tool's title / * filters stay visible as the body scrolls. This is the rail-level home for * a sticky tool header; every tool gets it for free. */ header?: ReactNode; /** * When true the panel body is NOT wrapped in the rail's `ScrollArea` — the * tool fills the (height-bounded) panel and owns its own scroll/layout. * Use for self-scrolling tools (e.g. `AppointmentTimeline`, whose infinite * scroll + today-anchoring + edge fades require it to be the scroll * container). Default `false` (the rail scrolls the body). */ fill?: boolean; /** Optional unseen / notification count shown on the strip icon. */ badgeCount?: number; /** When true the icon is non-interactive and skipped by roving focus. */ disabled?: boolean; /** * Scope tier (drives the two-group divider). The two scope values render in * array order with a divider at the boundary between them — order the array * so the groups stay contiguous. A divider only appears when BOTH groups are * present; omit `scope` on every tool for an ungrouped strip (legacy). The * rail attaches no meaning beyond grouping — the host decides which value * leads (e.g. the Control Room pins favourites first). */ scope?: 'global' | 'contextual'; /** * When true this icon joins the drag-and-drop / `Alt`+Arrow reorder run. * The host supplies `onReorder` and owns the resulting order. Moves are * confined to the contiguous run of `reorderable` tools — so if EVERY tool * is `reorderable` the run is the whole strip and a tool can be dragged * across the scope divider; the host's `onReorder` decides what crossing it * means (e.g. the Control Room reads it as pin / unpin). Reordering never * changes focus roving — focus follows the moved tool to its new slot. */ reorderable?: boolean; } /** * Curated imperative handle for ToolRail. Exposed as the forwardRef * target so a future agent / MCP UI bridge can drive the rail without * touching the DOM. See `tool-rail.agent.ts`. * * State surfaced here is strictly identifiers + counts — never any * tool's panel content (which may carry PHI). */ export interface ToolRailHandle { /** Currently-active tool id, or null when collapsed to strip-only. */ getActiveToolId: () => string | null; /** How an open panel shows: beside the content, over it, or full screen. */ getPanelMode: () => 'docked' | 'overlay' | 'full-screen'; /** Activate a tool by id (opens its panel), or null to collapse. */ setActiveTool: (id: string | null) => void; /** Activate a tool by id (opens its panel). */ open: (id: string) => void; /** Collapse to strip-only (no active tool). */ close: () => void; } declare const railVariants: (props?: ({ side?: "end" | "start" | null | undefined; } & import("class-variance-authority/types").ClassProp) | undefined) => string; export interface ToolRailProps extends VariantProps { /** Stable instance id, surfaced on the root as `data-component-id`. */ id?: string; /** The tools shown as icons on the strip. */ tools: ToolRailTool[]; /** Controlled active tool id (null = collapsed / strip-only). */ activeToolId?: string | null; /** Uncontrolled initial active tool id (default null). */ defaultActiveToolId?: string | null; /** Fires whenever the active tool changes (incl. → null on collapse). */ onActiveToolChange?: (id: string | null) => void; /** Which edge the rail docks to. Default `'end'` (inline-end). */ side?: 'start' | 'end'; /** Accessible label for the toolbar strip. */ railLabel?: string; /** * Opt-in resize affordance for the open tool panel. Renders a * `role="separator"` drag handle on the panel's inner edge (the edge * facing the main content). The committed width is written to * `--tool-rail-panel-inline-size` on the panel element (288–880px); * Enter / double-click resets to the token-driven default. Default `false`. */ resizablePanel?: boolean; /** * Controlled committed panel width, px; `null` for the token-driven * default. Only meaningful when `resizablePanel` is `true` — the width * has nothing to resize without the handle. Applied to * `--tool-rail-panel-inline-size` on mount and whenever it changes, * clamped to 288–880px. Omit for uncontrolled sizing (the rail owns the * committed width internally, the existing behaviour). */ panelWidth?: number | null; /** * Fires with the committed px width on every commit — pointer release, * a keyboard step, or `null` on reset (Enter / double-click). Fires * whether or not `panelWidth` is controlled, so an uncontrolled host can * still observe the width to persist it. */ onPanelWidthChange?: (px: number | null) => void; /** * Fires when the user reorders the `reorderable` run (drag-drop or * `Alt`+Arrow). `from` / `to` are indices into `tools`; the host applies the * move to the array it passes back. Reordering is enabled when this callback * is supplied AND at least one tool is `reorderable`. When the whole strip is * reorderable, `to` may land in the other scope group — the host interprets * the crossing (and may treat it as a no-op, e.g. reordering within a * host-ordered group). */ onReorder?: (from: number, to: number) => void; /** * Optional override for the polite live-region message announced after a * reorder. Lets the host phrase membership-aware moves (e.g. "Pinned X to * favourites") instead of the generic "moved to position N". Return an empty * string to stay silent (e.g. for a move the host treats as a no-op). When * omitted, the rail announces the generic run-relative position. */ formatReorderAnnouncement?: (args: { tool: ToolRailTool; from: number; to: number; }) => string; /** * Optional per-icon overlay control, rendered as a sibling of each strip * IconButton (the same positioned box the notification badge uses). Use for * a small affordance such as a pin toggle — the rail attaches no meaning to * what it renders. Receives the tool and its index / active state. */ renderToolAffordance?: (tool: ToolRailTool, context: { index: number; isActive: boolean; isRovingTarget: boolean; }) => ReactNode; /** * Optional non-scrolling header rendered at the top of the OPEN tool panel, * above its scroll region. Host-owned content (e.g. a pin / unpin control) — * the rail attaches no meaning. Receives the active tool. */ renderPanelHeader?: (tool: ToolRailTool, context: { isActive: boolean; }) => ReactNode; /** * Identity override for the root's `data-component` attribute. Defaults to * `'tool-rail'`. A product wrapper (e.g. ControlRoomRail) passes its own * kebab id so the DOM / cascade boundary — and an agent's `domHooks.root` — * can tell its surface apart from a bare ToolRail, without the engine ever * importing the wrapper. */ dataComponent?: string; /** * Agent adapter registered for this rail instance. Defaults to * `toolRailAgent`. A wrapper passes its own adapter (matching * `dataComponent`) so the rail registers under the wrapper's identity. The * instance id is sourced from the `id` prop (also stamped as * `data-component-id`). */ agentAdapter?: AgentAdapter; className?: string; } export declare const ToolRail: import("react").ForwardRefExoticComponent>; export {}; //# sourceMappingURL=tool-rail.d.ts.map