import type { ComponentType, ReactNode } from "react"; import type { SpringPreset } from "./springs"; import type { StoreApi } from "zustand"; /** Why the sheet stack was closed or popped */ export type CloseReason = "escape" | "backdrop" | "swipe" | "programmatic"; /** * A snap point for bottom sheets. * - `number` 0-1: fraction of viewport height (e.g. 0.5 = 50vh) * - `number` > 1: pixel value (e.g. 300 = 300px) * - `string`: CSS length (e.g. "148px", "30rem") */ export type SnapPoint = number | string; export interface StacksheetClassNames { /** Applied to backdrop overlay */ backdrop?: string; /** * @deprecated The header bar was removed — classic mode now renders * floating corner controls instead, so this class is never applied. * Style headers you build yourself in composable mode directly. */ header?: string; /** Applied to each panel container */ panel?: string; } export interface HeaderRenderProps { /** `true` when the stack has more than one sheet */ isNested: boolean; /** Pop the top sheet (go back one level) */ onBack: () => void; /** Close the entire sheet stack */ onClose: () => void; /** Current resolved side (left/right/bottom) */ side: Side; } export interface SheetPresentationOptions { /** Override the dialog aria-label for this specific sheet instance. */ ariaLabel?: string; } export interface SheetItem { /** Optional per-sheet presentation metadata */ ariaLabel?: string; /** Data payload passed when opening the sheet */ data: Record; /** Unique identifier for this sheet instance */ id: string; /** Sheet type key from the TMap */ type: TType; } export type Side = "left" | "right" | "bottom"; export type StacksheetLayout = "classic" | "composable"; /** * Placement of the auto drag handle on a bottom sheet. * - `inside` — pill inside the top edge (default) * - `outside` — pill floated above the sheet, on the backdrop * * Side sheets are unaffected: their handle always sits on the interior-facing * edge regardless of this setting. */ export type HandlePosition = "inside" | "outside"; export interface ResponsiveSide { desktop: Side; mobile: Side; } export type SideConfig = Side | Partial; export interface StackingConfig { /** Pixel offset per depth level — shifts panels away from the stack edge (default: 16) */ offsetStep: number; /** Opacity reduction per depth level (default: 0) */ opacityStep: number; /** Border radius applied to stacked panels in px (default: 12) */ radius: number; /** Max depth before content stops rendering (default: 3) */ renderThreshold: number; /** Scale reduction per depth level (default: 0.04) */ scaleStep: number; } export interface SpringConfig { /** Damping — higher = less oscillation (default: 30) */ damping: number; /** Mass — higher = more momentum (default: 0.8) */ mass: number; /** Stiffness — higher = snappier (default: 170) */ stiffness: number; } export interface StacksheetConfig { /** Default aria-label for dialog panels. Default: "Sheet dialog" */ ariaLabel?: string; /** Mobile breakpoint in px. Default: 768 */ breakpoint?: number; /** Close on backdrop click. Default: true */ closeOnBackdrop?: boolean; /** Close on ESC key. Default: true */ closeOnEscape?: boolean; /** Fraction of panel dimension to trigger close (0-1). Default: 0.25 */ closeThreshold?: number; /** Allow any form of dismissal (drag, backdrop, escape). Default: true */ dismissible?: boolean; /** Enable drag-driven dismissal. Default: true */ drag?: boolean; /** * Placement of the bottom sheet's auto drag handle. Default: "inside". * Side sheets always place their handle on the interior-facing edge. */ handle?: HandlePosition; /** Lock body scroll when open. Default: true */ lockScroll?: boolean; /** Maximum stack depth. Default: Infinity (unlimited) */ maxDepth?: number; /** Maximum panel width as CSS value. Default: "90vw" */ maxWidth?: string; /** Modal mode — overlay + scroll lock + focus trap. Default: true */ modal?: boolean; /** * Lift mobile bottom sheets above the on-screen keyboard when a field inside * them is focused, instead of relying on the browser's native * scroll-into-view. Mobile bottom sheets only. Default: true * * Note: this repositions the whole sheet; it does not scroll a focused field * that sits deep inside an internally-scrolling sheet body into view. */ repositionInputs?: boolean; /** Called when the last panel's exit animation completes (stack fully closed) */ onCloseComplete?: (reason: CloseReason) => void; /** Called when the top panel's entrance animation completes */ onOpenComplete?: () => void; /** Called when the active snap point changes. */ onSnapPointChange?: (index: number) => void; /** Scale factor applied to background (0-1). Default: 0.97 */ scaleBackgroundAmount?: number; /** Scale down [data-stacksheet-wrapper] when sheets open. Default: false */ shouldScaleBackground?: boolean; /** Show backdrop overlay when open. Default: true */ showOverlay?: boolean; /** Sheet slide-from side. Default: { desktop: "right", mobile: "bottom" } */ side?: SideConfig; /** * Initial snap point index. Resolved once at `createStacksheet()` and * cannot be changed after creation — when set, it pins the active snap * point. Use `onSnapPointChange` to observe user-driven snap changes. */ snapPointIndex?: number; /** Snap positions for bottom sheets. Numbers 0-1 = viewport fraction, >1 = px, strings = CSS lengths. */ snapPoints?: SnapPoint[]; /** When true, velocity can't skip intermediate snap points. Default: false */ snapToSequentialPoints?: boolean; /** Spring animation parameters — preset name or custom config */ spring?: SpringPreset | Partial; /** Stacking visual parameters */ stacking?: Partial; /** Velocity threshold (px/ms) to trigger close. Default: 0.5 */ velocityThreshold?: number; /** Panel width in px. Default: 420 */ width?: number; /** Base z-index. Default: 100 */ zIndex?: number; } /** Fully resolved config — all fields required */ export interface ResolvedConfig { ariaLabel: string; breakpoint: number; closeOnBackdrop: boolean; closeOnEscape: boolean; closeThreshold: number; dismissible: boolean; drag: boolean; handle: HandlePosition; lockScroll: boolean; maxDepth: number; maxWidth: string; modal: boolean; repositionInputs: boolean; onCloseComplete?: (reason: CloseReason) => void; onOpenComplete?: () => void; onSnapPointChange?: (index: number) => void; scaleBackgroundAmount: number; shouldScaleBackground: boolean; showOverlay: boolean; side: ResponsiveSide; snapPointIndex?: number; snapPoints: SnapPoint[]; snapToSequentialPoints: boolean; spring: SpringConfig; stacking: StackingConfig; velocityThreshold: number; width: number; zIndex: number; } /** Component rendered inside a sheet panel — receives data as spread props */ export type SheetContentComponent = ComponentType ? TData : Record>; /** Map of sheet type → content component */ export type ContentMap = { [K in keyof TMap]: SheetContentComponent; }; export interface StacksheetSnapshot<_TMap extends object> { /** Whether any sheets are currently visible */ isOpen: boolean; /** Current sheet stack, ordered bottom to top */ stack: SheetItem[]; } interface SheetStackCommand { >(type: K, id: string, data: TMap[K], options?: SheetPresentationOptions): void; >(component: ComponentType, data: TData, options?: SheetPresentationOptions): void; >(component: ComponentType, id: string, data: TData, options?: SheetPresentationOptions): void; } interface SheetSetDataCommand { >(type: K, id: string, data: TMap[K]): void; >(component: ComponentType, id: string, data: TData): void; } interface SheetSwapCommand { >(type: K, data: TMap[K], options?: SheetPresentationOptions): void; >(component: ComponentType, data: TData, options?: SheetPresentationOptions): void; } export interface SheetActions { /** Clear entire stack */ close: () => void; /** Smart: empty→open, same type on top→replace, different→push */ navigate: SheetStackCommand; /** Replace stack with a single item */ open: SheetStackCommand; /** Pop top item; close if last */ pop: () => void; /** Push onto stack (replaces top at maxDepth) */ push: SheetStackCommand; /** Remove a specific sheet by id; close if last */ remove: (id: string) => void; /** Swap the top item */ replace: SheetStackCommand; /** Update data on a sheet by id (no animation) */ setData: SheetSetDataCommand; /** Swap the top item's content in place (no animation) */ swap: SheetSwapCommand; } export interface StacksheetProviderProps { /** Your application content */ children: ReactNode; /** CSS class overrides for backdrop, panel, and header */ classNames?: StacksheetClassNames; /** Panel layout mode. `composable` disables the auto header and scroll wrapper. */ layout?: StacksheetLayout; /** * Controls the classic-mode header rendering. * - `undefined` — renders the default close/back header (classic mode) * - `function` — custom header renderer (classic mode with custom header) * - `false` — legacy alias for composable mode. Prefer `layout="composable"`. */ renderHeader?: false | ((props: HeaderRenderProps) => ReactNode); /** Map of sheet type keys to content components (optional — only needed for type registry pattern) */ sheets?: ContentMap; } export interface StacksheetInstance { /** Provider component — wrap your app, pass sheets map */ StacksheetProvider: ComponentType>; /** Raw Zustand store for advanced use */ store: StoreApi & SheetActions>; /** Hook returning sheet actions */ useSheet: () => SheetActions; /** Hook returning sheet state (stack, isOpen) */ useStacksheetState: () => StacksheetSnapshot; } export {}; //# sourceMappingURL=types.d.ts.map