@howells/stacksheet 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +37 -17
- package/dist/index.js +534 -251
- package/dist/index.js.map +1 -1
- package/package.json +16 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/springs.ts","../src/config.ts","../src/create.tsx","../src/renderer.tsx","../src/icons.tsx","../src/media.ts","../src/panel-context.tsx","../src/stacking.ts","../src/use-drag.ts","../src/store.ts","../src/parts.tsx"],"sourcesContent":["import type { SpringConfig } from \"./types\";\n\n/**\n * Spring presets inspired by iOS animation feel.\n *\n * - `soft` — Very gentle, slow settle. Loaders, radial pickers.\n * - `subtle` — Barely noticeable bounce, professional.\n * - `natural` — Balanced, general-purpose default.\n * - `snappy` — Quick, responsive for interactions.\n * - `stiff` — Very quick, controlled. Panels, drawers. **(default)**\n */\nexport const springs = {\n soft: { stiffness: 120, damping: 18, mass: 1 },\n subtle: { stiffness: 300, damping: 30, mass: 1 },\n natural: { stiffness: 200, damping: 20, mass: 1 },\n snappy: { stiffness: 400, damping: 28, mass: 0.8 },\n stiff: { stiffness: 400, damping: 40, mass: 1 },\n} as const satisfies Record<string, SpringConfig>;\n\nexport type SpringPreset = keyof typeof springs;\n","import { springs } from \"./springs\";\nimport type {\n ResolvedConfig,\n ResponsiveSide,\n StackingConfig,\n StacksheetConfig,\n} from \"./types\";\n\n// ── Defaults ────────────────────────────────────\n\nconst DEFAULT_STACKING: StackingConfig = {\n scaleStep: 0.04,\n offsetStep: 36,\n opacityStep: 0,\n radius: 12,\n renderThreshold: 3,\n};\n\nconst DEFAULT_SIDE: ResponsiveSide = {\n desktop: \"right\",\n mobile: \"bottom\",\n};\n\n// ── Resolver ────────────────────────────────────\n\nexport function resolveConfig(config: StacksheetConfig = {}): ResolvedConfig {\n const side: ResponsiveSide =\n typeof config.side === \"string\"\n ? { desktop: config.side, mobile: config.side }\n : { ...DEFAULT_SIDE, ...config.side };\n\n const spring =\n typeof config.spring === \"string\"\n ? springs[config.spring]\n : { ...springs.stiff, ...config.spring };\n\n return {\n maxDepth: config.maxDepth ?? Number.POSITIVE_INFINITY,\n closeOnEscape: config.closeOnEscape ?? true,\n closeOnBackdrop: config.closeOnBackdrop ?? true,\n showOverlay: config.showOverlay ?? true,\n lockScroll: config.lockScroll ?? true,\n width: config.width ?? 420,\n maxWidth: config.maxWidth ?? \"90vw\",\n breakpoint: config.breakpoint ?? 768,\n side,\n stacking: { ...DEFAULT_STACKING, ...config.stacking },\n spring,\n zIndex: config.zIndex ?? 100,\n ariaLabel: config.ariaLabel ?? \"Sheet dialog\",\n onOpenComplete: config.onOpenComplete,\n onCloseComplete: config.onCloseComplete,\n drag: config.drag ?? true,\n closeThreshold: config.closeThreshold ?? 0.25,\n velocityThreshold: config.velocityThreshold ?? 0.5,\n dismissible: config.dismissible ?? true,\n modal: config.modal ?? true,\n shouldScaleBackground: config.shouldScaleBackground ?? false,\n scaleBackgroundAmount: config.scaleBackgroundAmount ?? 0.97,\n };\n}\n","import { Portal } from \"@radix-ui/react-portal\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { useStore } from \"zustand\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport { resolveConfig } from \"./config\";\nimport { SheetRenderer } from \"./renderer\";\nimport { createSheetStore } from \"./store\";\nimport type {\n ContentMap,\n ResolvedConfig,\n SheetActions,\n StacksheetConfig,\n StacksheetInstance,\n StacksheetProviderProps,\n StacksheetSnapshot,\n} from \"./types\";\n\ntype StoreState<TMap extends object> = StacksheetSnapshot<TMap> &\n SheetActions<TMap>;\n\n/**\n * Create an isolated sheet stack instance with typed store, hooks, and provider.\n *\n * Works with both `interface` and `type` definitions:\n *\n * ```ts\n * // Using an interface\n * interface SheetDataMap {\n * \"bucket-create\": { onCreated?: (b: Bucket) => void };\n * \"bucket-edit\": { bucket: Bucket };\n * }\n *\n * // Using a type alias\n * type SheetDataMap = {\n * \"bucket-create\": { onCreated?: (b: Bucket) => void };\n * \"bucket-edit\": { bucket: Bucket };\n * };\n *\n * const { StacksheetProvider, useSheet, useStacksheetState } =\n * createStacksheet<SheetDataMap>();\n * ```\n *\n * Sheet content components receive their data as **spread props**:\n * ```ts\n * // Data map defines: \"bucket-edit\": { bucket: Bucket }\n * // Component receives: ({ bucket }: { bucket: Bucket }) => JSX.Element\n * ```\n *\n * Use `useSheetPanel()` inside content components to access `close()` and `back()`.\n */\nexport function createStacksheet<TMap extends object>(\n config?: StacksheetConfig\n): StacksheetInstance<TMap> {\n const resolved = resolveConfig(config);\n const { store, componentMap } = createSheetStore<TMap>(resolved);\n\n // Context for the store — allows multiple instances\n const StoreContext = createContext<{\n store: StoreApi<StoreState<TMap>>;\n config: ResolvedConfig;\n } | null>(null);\n\n function useStoreContext() {\n const ctx = useContext(StoreContext);\n if (!ctx) {\n throw new Error(\n \"useSheet/useStacksheetState must be used within <StacksheetProvider>\"\n );\n }\n return ctx;\n }\n\n // ── Provider ────────────────────────────────\n\n const EMPTY_SHEETS = {} as ContentMap<TMap>;\n\n function StacksheetProvider({\n sheets = EMPTY_SHEETS,\n children,\n classNames,\n renderHeader,\n }: StacksheetProviderProps<TMap>) {\n const value = useMemo(() => ({ store, config: resolved }), []);\n return (\n <StoreContext.Provider value={value}>\n {children}\n <Portal asChild={false}>\n <SheetRenderer<TMap>\n classNames={classNames}\n componentMap={componentMap}\n config={resolved}\n renderHeader={renderHeader}\n sheets={sheets}\n store={store}\n />\n </Portal>\n </StoreContext.Provider>\n );\n }\n\n // ── Hooks ───────────────────────────────────\n\n function useSheet(): SheetActions<TMap> {\n const { store: s } = useStoreContext();\n // Actions are stable refs in Zustand v5 — read once, no subscription needed\n return useMemo(() => {\n const state = s.getState();\n return {\n open: state.open,\n push: state.push,\n replace: state.replace,\n swap: state.swap,\n navigate: state.navigate,\n setData: state.setData,\n remove: state.remove,\n pop: state.pop,\n close: state.close,\n };\n }, [s]);\n }\n\n function useStacksheetState(): StacksheetSnapshot<TMap> {\n const { store: s } = useStoreContext();\n return useStore(\n s,\n useShallow((state) => ({\n stack: state.stack,\n isOpen: state.isOpen,\n }))\n );\n }\n\n return { StacksheetProvider, useSheet, useStacksheetState, store };\n}\n","import FocusTrap from \"focus-trap-react\";\nimport { AnimatePresence, motion as m } from \"motion/react\";\nimport {\n type ComponentType,\n type CSSProperties,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport type { StoreApi } from \"zustand\";\nimport { useStore } from \"zustand\";\nimport { ArrowLeftIcon, XIcon } from \"./icons\";\nimport { useResolvedSide } from \"./media\";\nimport { SheetPanelContext } from \"./panel-context\";\nimport {\n getAnimatedBorderRadius,\n getPanelStyles,\n getSlideFrom,\n getSlideTarget,\n getStackTransform,\n type SlideValues,\n} from \"./stacking\";\nimport type {\n ContentMap,\n HeaderRenderProps,\n ResolvedConfig,\n SheetActions,\n SheetItem,\n Side,\n StacksheetClassNames,\n StacksheetSnapshot,\n} from \"./types\";\nimport { type DragState, useDrag } from \"./use-drag\";\n\n// ── Default header ──────────────────────────────\n\nconst BUTTON_STYLE: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 32,\n height: 32,\n borderRadius: \"50%\",\n border: \"none\",\n background: \"transparent\",\n cursor: \"pointer\",\n color: \"inherit\",\n opacity: 0.5,\n transition: \"opacity 150ms\",\n padding: 0,\n};\n\nconst HANDLE_BAR_STYLE: CSSProperties = {\n width: 36,\n height: 4,\n borderRadius: 2,\n background: \"var(--muted-foreground, rgba(0, 0, 0, 0.25))\",\n};\n\nfunction DefaultHeader({ isNested, onBack, onClose, side }: HeaderRenderProps) {\n return (\n <>\n {side === \"bottom\" && (\n <div\n data-stacksheet-handle=\"\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"12px 0 4px\",\n flexShrink: 0,\n cursor: \"grab\",\n touchAction: \"none\",\n }}\n >\n <div style={HANDLE_BAR_STYLE} />\n </div>\n )}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n height: 48,\n flexShrink: 0,\n padding: \"0 12px\",\n borderBottom: \"1px solid var(--border, transparent)\",\n }}\n >\n {isNested && (\n <button\n aria-label=\"Back\"\n onClick={onBack}\n style={BUTTON_STYLE}\n type=\"button\"\n >\n <ArrowLeftIcon />\n </button>\n )}\n <div style={{ flex: 1 }} />\n <button\n aria-label=\"Close\"\n onClick={onClose}\n style={BUTTON_STYLE}\n type=\"button\"\n >\n <XIcon />\n </button>\n </div>\n </>\n );\n}\n\n// ── Resolved classNames ─────────────────────────\n\ntype ResolvedClassNames = Required<StacksheetClassNames>;\n\nconst EMPTY_CLASSNAMES: ResolvedClassNames = {\n backdrop: \"\",\n panel: \"\",\n header: \"\",\n};\n\nfunction resolveClassNames(cn?: StacksheetClassNames): ResolvedClassNames {\n if (!cn) {\n return EMPTY_CLASSNAMES;\n }\n return {\n backdrop: cn.backdrop ?? \"\",\n panel: cn.panel ?? \"\",\n header: cn.header ?? \"\",\n };\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction selectSpring(\n isTop: boolean,\n spring: Record<string, unknown>,\n stackSpring: Record<string, unknown>\n): Record<string, unknown> {\n return isTop ? spring : stackSpring;\n}\n\nfunction buildAriaProps(\n isTop: boolean,\n isModal: boolean,\n isComposable: boolean,\n ariaLabel: string,\n panelId: string\n): Record<string, string | undefined> {\n if (!isTop) {\n return {};\n }\n const props: Record<string, string | undefined> = { role: \"dialog\" };\n if (isModal) {\n props[\"aria-modal\"] = \"true\";\n }\n if (isComposable) {\n props[\"aria-labelledby\"] = `${panelId}-title`;\n props[\"aria-describedby\"] = `${panelId}-desc`;\n } else {\n props[\"aria-label\"] = ariaLabel;\n }\n return props;\n}\n\n// ── Drag offset to CSS transform ────────────────\n\nfunction getDragTransform(\n side: Side,\n offset: number\n): { x?: number; y?: number } {\n if (offset === 0) {\n return {};\n }\n switch (side) {\n case \"right\":\n return { x: offset };\n case \"left\":\n return { x: -offset };\n case \"bottom\":\n return { y: offset };\n default:\n return {};\n }\n}\n\n// ── SheetPanel ──────────────────────────────────\n\ninterface SheetPanelProps {\n item: SheetItem;\n index: number;\n depth: number;\n isTop: boolean;\n isNested: boolean;\n side: Side;\n config: ResolvedConfig;\n classNames: ResolvedClassNames;\n // biome-ignore lint/suspicious/noExplicitAny: heterogeneous content component\n Content: ComponentType<any> | undefined;\n shouldRender: boolean;\n pop: () => void;\n close: () => void;\n renderHeader?: false | ((props: HeaderRenderProps) => React.ReactNode);\n slideFrom: SlideValues;\n slideTarget: SlideValues;\n spring: Record<string, unknown>;\n stackSpring: Record<string, unknown>;\n exitSpring: Record<string, unknown>;\n}\n\nfunction SheetPanel({\n item,\n index,\n depth,\n isTop,\n isNested,\n side,\n config,\n classNames,\n Content,\n shouldRender,\n pop,\n close,\n renderHeader,\n slideFrom,\n slideTarget,\n spring,\n stackSpring,\n exitSpring,\n}: SheetPanelProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const hasEnteredRef = useRef(false);\n const [dragState, setDragState] = useState<DragState>({\n offset: 0,\n isDragging: false,\n });\n\n const transform = getStackTransform(depth, config.stacking);\n const panelStyles = getPanelStyles(side, config, depth, index);\n const stackOffset = getStackingOffset(side, transform.offset);\n\n // Reset entrance flag when panel moves away from top\n useEffect(() => {\n if (!isTop) {\n hasEnteredRef.current = false;\n }\n }, [isTop]);\n\n const handleAnimationComplete = useCallback(() => {\n if (isTop && !hasEnteredRef.current) {\n hasEnteredRef.current = true;\n config.onOpenComplete?.();\n }\n }, [isTop, config]);\n\n // Drag-to-dismiss (only on top panel)\n useDrag(\n panelRef,\n {\n enabled: isTop && config.drag && config.dismissible,\n closeThreshold: config.closeThreshold,\n velocityThreshold: config.velocityThreshold,\n side,\n onClose: close,\n onPop: pop,\n isNested,\n },\n setDragState\n );\n\n // Per-sheet aria-label: check data.__ariaLabel, fall back to config\n const ariaLabel =\n (typeof item.data?.__ariaLabel === \"string\"\n ? item.data.__ariaLabel\n : undefined) ?? config.ariaLabel;\n\n // Panel context for composable parts (Sheet.Close, Sheet.Title, etc.)\n const panelId = `stacksheet-${item.id}`;\n const panelContext = useMemo(\n () => ({ close, back: pop, isNested, isTop, panelId, side }),\n [close, pop, isNested, isTop, panelId, side]\n );\n\n // Composable mode: renderHeader === false → no auto header, no scroll wrapper\n const isComposable = renderHeader === false;\n\n // Panel: use className if provided, strip inline background\n const hasPanelClass = classNames.panel !== \"\";\n const dragOffset = getDragTransform(side, dragState.offset);\n const panelStyle: CSSProperties = {\n ...panelStyles,\n boxShadow: isTop ? getShadow(side, false) : getShadow(side, true),\n pointerEvents: isTop ? \"auto\" : \"none\",\n // During drag, disable spring transition for immediate feedback\n ...(dragState.isDragging ? { transition: \"none\" } : {}),\n ...(hasPanelClass\n ? {}\n : {\n background: \"var(--background, #fff)\",\n borderColor: \"var(--border, transparent)\",\n }),\n };\n\n const headerProps: HeaderRenderProps = {\n isNested,\n onBack: pop,\n onClose: close,\n side,\n };\n\n const isModal = config.modal;\n const ariaProps = buildAriaProps(\n isTop,\n isModal,\n isComposable,\n ariaLabel,\n panelId\n );\n\n // Pick transition: immediate during drag, spring otherwise\n const transition = dragState.isDragging\n ? { type: \"tween\" as const, duration: 0 }\n : selectSpring(isTop, spring, stackSpring);\n\n // Border radius must be in the animate target (not static CSS) for\n // Motion to apply scale correction. See: motion.dev/docs/react-layout-animations#scale-correction\n const animatedRadius = getAnimatedBorderRadius(side, depth, config.stacking);\n\n // Merge drag offset into the animate target\n const animateTarget = {\n ...slideTarget,\n ...stackOffset,\n ...dragOffset,\n scale: transform.scale,\n opacity: transform.opacity,\n ...animatedRadius,\n transition,\n };\n\n const panelContent = (\n <m.div\n animate={animateTarget}\n className={classNames.panel || undefined}\n exit={{\n ...slideFrom,\n opacity: 0.6,\n transition: exitSpring,\n }}\n initial={{\n ...slideFrom,\n opacity: 0.8,\n }}\n key={item.id}\n onAnimationComplete={handleAnimationComplete}\n ref={panelRef}\n style={panelStyle}\n tabIndex={isTop ? -1 : undefined}\n transition={spring}\n {...ariaProps}\n >\n {isComposable ? (\n /* Composable mode: content fills panel directly, uses Sheet.* parts */\n shouldRender &&\n Content && <Content {...(item.data as Record<string, unknown>)} />\n ) : (\n <>\n {/* Classic mode: auto header + scroll wrapper */}\n {renderHeader ? (\n renderHeader(headerProps)\n ) : (\n <DefaultHeader {...headerProps} />\n )}\n {shouldRender && Content && (\n <div\n data-stacksheet-no-drag=\"\"\n style={{\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n overscrollBehavior: \"contain\",\n }}\n >\n <Content {...(item.data as Record<string, unknown>)} />\n </div>\n )}\n </>\n )}\n </m.div>\n );\n\n // Non-modal: skip focus trap\n if (!isModal) {\n return (\n <SheetPanelContext.Provider value={panelContext}>\n {panelContent}\n </SheetPanelContext.Provider>\n );\n }\n\n return (\n <SheetPanelContext.Provider value={panelContext}>\n <FocusTrap\n active={isTop}\n focusTrapOptions={{\n initialFocus: false,\n returnFocusOnDeactivate: true,\n escapeDeactivates: false,\n allowOutsideClick: true,\n checkCanFocusTrap: () =>\n new Promise<void>((resolve) =>\n requestAnimationFrame(() => resolve())\n ),\n fallbackFocus: () => {\n if (panelRef.current) {\n return panelRef.current;\n }\n return document.body;\n },\n }}\n >\n {panelContent}\n </FocusTrap>\n </SheetPanelContext.Provider>\n );\n}\n\n// ── Body scale effect ───────────────────────────\n\nfunction useBodyScale(config: ResolvedConfig, isOpen: boolean) {\n useEffect(() => {\n if (!config.shouldScaleBackground) {\n return;\n }\n\n const wrapper = document.querySelector(\"[data-stacksheet-wrapper]\");\n if (!(wrapper && wrapper instanceof HTMLElement)) {\n return;\n }\n\n if (isOpen) {\n const scale = config.scaleBackgroundAmount;\n wrapper.style.transition =\n \"transform 500ms cubic-bezier(0.32, 0.72, 0, 1), border-radius 500ms cubic-bezier(0.32, 0.72, 0, 1)\";\n wrapper.style.transform = `scale(${scale})`;\n wrapper.style.borderRadius = \"8px\";\n wrapper.style.overflow = \"hidden\";\n wrapper.style.transformOrigin = \"center top\";\n return;\n }\n\n wrapper.style.transform = \"\";\n wrapper.style.borderRadius = \"\";\n // Clean up after transition completes\n const handleEnd = () => {\n wrapper.style.transition = \"\";\n wrapper.style.overflow = \"\";\n wrapper.style.transformOrigin = \"\";\n };\n wrapper.addEventListener(\"transitionend\", handleEnd, { once: true });\n return () => wrapper.removeEventListener(\"transitionend\", handleEnd);\n }, [isOpen, config.shouldScaleBackground, config.scaleBackgroundAmount]);\n}\n\n// ── Renderer ────────────────────────────────────\n\ninterface SheetRendererProps<TMap extends object> {\n store: StoreApi<StacksheetSnapshot<TMap> & SheetActions<TMap>>;\n config: ResolvedConfig;\n sheets: ContentMap<TMap>;\n /** Ad-hoc component map (type key → component) */\n // biome-ignore lint/suspicious/noExplicitAny: heterogeneous component storage\n componentMap: Map<string, ComponentType<any>>;\n classNames?: StacksheetClassNames;\n renderHeader?: false | ((props: HeaderRenderProps) => React.ReactNode);\n}\n\nexport function SheetRenderer<TMap extends object>({\n store,\n config,\n sheets,\n componentMap,\n classNames: classNamesProp,\n renderHeader,\n}: SheetRendererProps<TMap>) {\n const isOpen = useStore(store, (s) => s.isOpen);\n const stack = useStore(store, (s) => s.stack);\n const close = useStore(store, (s) => s.close);\n const pop = useStore(store, (s) => s.pop);\n\n const side = useResolvedSide(config);\n const classNames = resolveClassNames(classNamesProp);\n\n // Body scale effect\n useBodyScale(config, isOpen);\n\n // Focus restoration: capture the element that was focused when the stack opens.\n // When the stack fully closes, return focus to that element.\n const triggerRef = useRef<Element | null>(null);\n const wasOpenRef = useRef(false);\n\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) {\n triggerRef.current = document.activeElement;\n } else if (!isOpen && wasOpenRef.current) {\n const el = triggerRef.current;\n if (el && el instanceof HTMLElement) {\n el.focus();\n }\n triggerRef.current = null;\n }\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n // Escape key\n useEffect(() => {\n if (!(isOpen && config.closeOnEscape && config.dismissible)) {\n return;\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n if (stack.length > 1) {\n pop();\n } else {\n close();\n }\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n isOpen,\n config.closeOnEscape,\n config.dismissible,\n stack.length,\n pop,\n close,\n ]);\n\n const slideFrom = getSlideFrom(side);\n const slideTarget = getSlideTarget();\n\n // Primary spring — drives the top sheet's entrance slide\n const spring = {\n type: \"spring\" as const,\n damping: config.spring.damping,\n stiffness: config.spring.stiffness,\n mass: config.spring.mass,\n };\n\n // Same spring for stacking transforms (scale, offset, opacity)\n const stackSpring = spring;\n\n // Same spring for exit (pop)\n const exitSpring = spring;\n\n // Non-modal: skip overlay, skip scroll lock\n const isModal = config.modal;\n const showOverlay = isModal && config.showOverlay;\n\n // Backdrop: use className if provided, otherwise inline fallback\n const hasBackdropClass = classNames.backdrop !== \"\";\n const backdropStyle: CSSProperties = {\n position: \"fixed\",\n inset: 0,\n zIndex: config.zIndex,\n cursor:\n config.closeOnBackdrop && config.dismissible ? \"pointer\" : undefined,\n ...(hasBackdropClass\n ? {}\n : { background: \"var(--overlay, rgba(0, 0, 0, 0.2))\" }),\n };\n\n // Handle exit complete — fire onCloseComplete when stack is fully empty\n const handleExitComplete = useCallback(() => {\n if (stack.length === 0) {\n config.onCloseComplete?.();\n }\n }, [stack.length, config]);\n\n // Non-modal: don't lock scroll\n const shouldLockScroll = isOpen && isModal && config.lockScroll;\n\n return (\n <>\n {/* Backdrop — independent AnimatePresence so it fades on its own */}\n {showOverlay && (\n <AnimatePresence>\n {isOpen && (\n <m.div\n animate={{ opacity: 1 }}\n className={classNames.backdrop || undefined}\n exit={{ opacity: 0 }}\n initial={{ opacity: 0 }}\n key=\"stacksheet-backdrop\"\n onClick={\n config.closeOnBackdrop && config.dismissible ? close : undefined\n }\n style={backdropStyle}\n transition={spring}\n />\n )}\n </AnimatePresence>\n )}\n\n {/* Panel clip container — always rendered, invisible when empty */}\n <RemoveScroll enabled={shouldLockScroll} forwardProps>\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: config.zIndex + 1,\n overflow: \"hidden\",\n pointerEvents: \"none\",\n }}\n >\n <AnimatePresence onExitComplete={handleExitComplete}>\n {stack.map((item, index) => {\n const depth = stack.length - 1 - index;\n const isTop = depth === 0;\n const isNested = stack.length > 1;\n const shouldRender = depth < config.stacking.renderThreshold;\n\n // Ad-hoc components take priority, then fall back to sheets map\n const Content = (componentMap.get(item.type) ??\n sheets[item.type as keyof TMap]) as\n | ComponentType<Record<string, unknown>>\n | undefined;\n\n return (\n <SheetPanel\n Content={Content}\n classNames={classNames}\n close={close}\n config={config}\n depth={depth}\n exitSpring={exitSpring}\n index={index}\n isNested={isNested}\n isTop={isTop}\n item={item}\n key={item.id}\n pop={pop}\n renderHeader={renderHeader}\n shouldRender={shouldRender}\n side={side}\n slideFrom={slideFrom}\n slideTarget={slideTarget}\n spring={spring}\n stackSpring={stackSpring}\n />\n );\n })}\n </AnimatePresence>\n </div>\n </RemoveScroll>\n </>\n );\n}\n\n// ── Helpers ─────────────────────────────────────\n\nfunction getStackingOffset(side: Side, offset: number): Record<string, number> {\n if (offset === 0) {\n return {};\n }\n switch (side) {\n case \"right\":\n return { x: -offset };\n case \"left\":\n return { x: offset };\n case \"bottom\":\n return { y: -offset };\n default:\n return {};\n }\n}\n\nfunction getShadow(side: Side, isNested: boolean): string {\n if (side === \"bottom\") {\n return isNested\n ? \"0 -2px 16px rgba(0,0,0,0.06)\"\n : \"0 -8px 32px rgba(0,0,0,0.15)\";\n }\n // Left/right\n const dir = side === \"right\" ? -1 : 1;\n return isNested\n ? `${dir * 2}px 0 16px rgba(0,0,0,0.06)`\n : `${dir * 8}px 0 32px rgba(0,0,0,0.15)`;\n}\n","/** Inline SVG icons — no external dependency */\n\nexport function ArrowLeftIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={16}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n viewBox=\"0 0 24 24\"\n width={16}\n >\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n );\n}\n\nexport function XIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={16}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n viewBox=\"0 0 24 24\"\n width={16}\n >\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport type { ResolvedConfig, Side } from \"./types\";\n\n/**\n * Returns true when viewport width is at or below the breakpoint.\n * SSR-safe: defaults to false (desktop).\n */\nexport function useIsMobile(breakpoint: number): boolean {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);\n setIsMobile(mql.matches);\n\n const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches);\n mql.addEventListener(\"change\", handler);\n return () => mql.removeEventListener(\"change\", handler);\n }, [breakpoint]);\n\n return isMobile;\n}\n\n/** Resolve the current side from config + viewport. */\nexport function useResolvedSide(config: ResolvedConfig): Side {\n const isMobile = useIsMobile(config.breakpoint);\n return isMobile ? config.side.mobile : config.side.desktop;\n}\n","import { createContext, useContext } from \"react\";\nimport type { Side } from \"./types\";\n\nexport interface SheetPanelContextValue {\n /** Close the entire sheet stack */\n close: () => void;\n /** Pop the top sheet (go back one level) */\n back: () => void;\n /** Whether the stack has more than one sheet */\n isNested: boolean;\n /** Whether this is the top (active) sheet */\n isTop: boolean;\n /** Unique ID prefix for this panel (for aria-labelledby linking) */\n panelId: string;\n /** Current resolved side (left/right/bottom) */\n side: Side;\n}\n\nexport const SheetPanelContext = createContext<SheetPanelContextValue | null>(\n null\n);\n\n/**\n * Access the current sheet panel's context.\n * Must be called inside a component rendered by the sheet stack.\n */\nexport function useSheetPanel(): SheetPanelContextValue {\n const ctx = useContext(SheetPanelContext);\n if (!ctx) {\n throw new Error(\n \"Sheet.* components must be used inside a sheet panel. \" +\n \"They should be rendered by a component opened via actions.open(), push(), etc.\"\n );\n }\n return ctx;\n}\n","import type { CSSProperties } from \"react\";\nimport type { ResolvedConfig, Side, StackingConfig } from \"./types\";\n\n// ── Depth transforms ────────────────────────────\n\nexport interface StackTransform {\n scale: number;\n offset: number;\n opacity: number;\n borderRadius: number;\n}\n\n/**\n * Compute visual transforms for a panel at a given depth.\n * depth=0 is the top (foreground) panel.\n * Panels beyond renderThreshold are clamped to the edge position and faded out.\n */\nexport function getStackTransform(\n depth: number,\n stacking: StackingConfig\n): StackTransform {\n if (depth <= 0) {\n return { scale: 1, offset: 0, opacity: 1, borderRadius: 0 };\n }\n\n const beyondThreshold = depth >= stacking.renderThreshold;\n // Clamp visual depth so panels beyond threshold stay at the edge position\n const visualDepth = beyondThreshold ? stacking.renderThreshold - 1 : depth;\n\n return {\n scale: Math.max(0.5, 1 - visualDepth * stacking.scaleStep),\n offset: visualDepth * stacking.offsetStep,\n opacity: beyondThreshold\n ? 0\n : Math.max(0, 1 - visualDepth * stacking.opacityStep),\n borderRadius: stacking.radius,\n };\n}\n\n/**\n * Border radius values for the animate target.\n * Must be animated (not static CSS) so Motion applies scale correction\n * when panels are scaled. See: https://motion.dev/docs/react-layout-animations#scale-correction\n */\nexport function getAnimatedBorderRadius(\n side: Side,\n depth: number,\n stacking: StackingConfig\n): Record<string, number> {\n if (side === \"bottom\") {\n const radius = depth > 0 ? stacking.radius : 16;\n return {\n borderTopLeftRadius: radius,\n borderTopRightRadius: radius,\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n };\n }\n\n // Left/right panels: stacked panels get uniform radius, top panel gets none\n if (depth > 0) {\n return { borderRadius: stacking.radius };\n }\n return { borderRadius: 0 };\n}\n\n// ── Slide directions ────────────────────────────\n\nexport interface SlideValues {\n x?: string | number;\n y?: string | number;\n}\n\n/** Motion initial/exit values for sliding from the given side. */\nexport function getSlideFrom(side: Side): SlideValues {\n switch (side) {\n case \"right\":\n return { x: \"100%\" };\n case \"left\":\n return { x: \"-100%\" };\n case \"bottom\":\n return { y: \"100%\" };\n default:\n return { x: \"100%\" };\n }\n}\n\n/** Motion animate target — the resting position. */\nexport function getSlideTarget(): SlideValues {\n return { x: 0, y: 0 };\n}\n\n// ── Panel positioning ───────────────────────────\n\n/**\n * Fixed-position styles for a panel, accounting for side, width, and depth.\n */\nexport function getPanelStyles(\n side: Side,\n config: ResolvedConfig,\n _depth: number,\n index: number\n): CSSProperties {\n const { width, maxWidth, zIndex } = config;\n const base: CSSProperties = {\n position: \"fixed\",\n zIndex: zIndex + 10 + index,\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n willChange: \"transform\",\n transformOrigin: side === \"bottom\" ? \"center bottom\" : `${side} center`,\n };\n\n if (side === \"bottom\") {\n return {\n ...base,\n left: 0,\n right: 0,\n bottom: 0,\n maxHeight: \"85vh\",\n // borderRadius is animated via Motion's animate prop for scale correction\n };\n }\n\n // Left or right side panel\n const sideStyles: CSSProperties =\n side === \"right\"\n ? { top: 0, right: 0, bottom: 0 }\n : { top: 0, left: 0, bottom: 0 };\n\n return {\n ...base,\n ...sideStyles,\n width,\n maxWidth,\n };\n}\n","import { type RefObject, useCallback, useEffect, useRef } from \"react\";\nimport type { Side } from \"./types\";\n\nexport interface DragConfig {\n /** Enable drag-to-dismiss. Default: true */\n enabled: boolean;\n /** Fraction of panel dimension to trigger close (0-1). Default: 0.25 */\n closeThreshold: number;\n /** Velocity threshold (px/ms) to trigger close. Default: 0.5 */\n velocityThreshold: number;\n /** Side the panel is on — determines drag direction */\n side: Side;\n /** Callback when drag ends and close should fire */\n onClose: () => void;\n /** Callback when drag ends and pop should fire */\n onPop: () => void;\n /** Whether the stack has >1 sheet (swipe pops instead of closing) */\n isNested: boolean;\n}\n\nexport interface DragState {\n /** Current drag offset in the dismiss direction (px) */\n offset: number;\n /** Whether a drag is currently active */\n isDragging: boolean;\n}\n\n/** Elements that should never initiate a drag */\nconst INTERACTIVE_TAGS = new Set([\n \"INPUT\",\n \"TEXTAREA\",\n \"SELECT\",\n \"BUTTON\",\n \"A\",\n]);\n\nfunction isInteractiveElement(el: Element): boolean {\n if (INTERACTIVE_TAGS.has(el.tagName)) {\n return true;\n }\n if ((el as HTMLElement).isContentEditable) {\n return true;\n }\n // Children of interactive elements (e.g. SVG inside button, span inside link)\n if (el.closest(\"button, a, input, textarea, select, [contenteditable]\")) {\n return true;\n }\n if (el.closest(\"[data-stacksheet-no-drag]\")) {\n return true;\n }\n return false;\n}\n\n/**\n * Get the dismiss direction axis and sign for a given side.\n * - right panel → dismiss by dragging right (+x)\n * - left panel → dismiss by dragging left (-x)\n * - bottom panel → dismiss by dragging down (+y)\n */\nfunction getDismissAxis(side: Side): {\n axis: \"x\" | \"y\";\n sign: 1 | -1;\n} {\n switch (side) {\n case \"right\":\n return { axis: \"x\", sign: 1 };\n case \"left\":\n return { axis: \"x\", sign: -1 };\n case \"bottom\":\n return { axis: \"y\", sign: 1 };\n default:\n return { axis: \"x\", sign: 1 };\n }\n}\n\n/** Dead zone in px before committing to drag vs text selection */\nconst DEAD_ZONE = 10;\n\n/** Max angle (degrees) from dismiss axis to qualify as drag intent */\nconst MAX_ANGLE_DEG = 35;\n\n/**\n * Decide whether a gesture past the dead zone qualifies as a dismiss drag.\n * Returns \"drag\" if it's a valid dismiss gesture, \"none\" if it's off-axis\n * or moving in the wrong direction.\n */\nfunction classifyGesture(\n dx: number,\n dy: number,\n axis: \"x\" | \"y\",\n sign: 1 | -1\n): \"drag\" | \"none\" {\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n\n // Compute angle between movement vector and dismiss axis\n let angleDeg: number;\n if (axis === \"y\") {\n angleDeg = absDy === 0 ? 90 : (Math.atan(absDx / absDy) * 180) / Math.PI;\n } else {\n angleDeg = absDx === 0 ? 90 : (Math.atan(absDy / absDx) * 180) / Math.PI;\n }\n\n if (angleDeg > MAX_ANGLE_DEG) {\n return \"none\";\n }\n\n // Must be moving in the dismiss direction\n const moveInAxis = axis === \"x\" ? dx : dy;\n if (moveInAxis * sign < 0) {\n return \"none\";\n }\n\n return \"drag\";\n}\n\nfunction getPanelDimension(\n panel: HTMLDivElement | null,\n axis: \"x\" | \"y\"\n): number {\n if (!panel) {\n return 300;\n }\n return axis === \"x\" ? panel.offsetWidth : panel.offsetHeight;\n}\n\n/**\n * Hook that manages drag-to-dismiss for a sheet panel.\n *\n * Returns a ref callback for the drag offset, which the caller\n * uses to apply inline transforms during drag. The hook handles\n * pointer events, gesture discrimination, and velocity-based close.\n */\nexport function useDrag(\n panelRef: RefObject<HTMLDivElement | null>,\n config: DragConfig,\n onDragUpdate: (state: DragState) => void\n) {\n const startRef = useRef<{ x: number; y: number; time: number } | null>(null);\n const committedRef = useRef<\"drag\" | \"none\" | null>(null);\n const offsetRef = useRef(0);\n\n const { axis, sign } = getDismissAxis(config.side);\n\n const handlePointerDown = useCallback(\n (e: PointerEvent) => {\n if (!config.enabled) {\n return;\n }\n // Only primary button\n if (e.button !== 0) {\n return;\n }\n // Check target element\n const target = e.target as Element;\n if (!target) {\n return;\n }\n\n // Allow drag from handle elements always\n const isHandle = !!target.closest(\"[data-stacksheet-handle]\");\n\n // For non-handle areas, check if the target is interactive\n if (!isHandle && isInteractiveElement(target)) {\n return;\n }\n\n // For non-handle areas, check if the content is scrolled\n // (don't start drag if user might be scrolling)\n if (!isHandle) {\n const scrollable = target.closest(\"[data-radix-scroll-area-viewport]\");\n if (scrollable && scrollable.scrollTop > 0 && axis === \"y\") {\n return;\n }\n }\n\n startRef.current = { x: e.clientX, y: e.clientY, time: Date.now() };\n committedRef.current = null;\n offsetRef.current = 0;\n\n // Capture pointer for reliable move/up outside the element\n (e.currentTarget as HTMLElement)?.setPointerCapture?.(e.pointerId);\n },\n [config.enabled, axis]\n );\n\n const handlePointerMove = useCallback(\n (e: PointerEvent) => {\n if (!startRef.current) {\n return;\n }\n\n const dx = e.clientX - startRef.current.x;\n const dy = e.clientY - startRef.current.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n // Still in dead zone — don't commit yet\n if (committedRef.current === null && dist < DEAD_ZONE) {\n return;\n }\n\n // Commit decision: check if movement direction matches dismiss axis\n if (committedRef.current === null) {\n committedRef.current = classifyGesture(dx, dy, axis, sign);\n if (committedRef.current === \"none\") {\n startRef.current = null;\n return;\n }\n }\n\n if (committedRef.current !== \"drag\") {\n return;\n }\n\n // Calculate offset in dismiss direction\n const rawOffset = axis === \"x\" ? dx : dy;\n // Only allow positive offset in dismiss direction (can't drag past resting position)\n const clampedOffset = Math.max(0, rawOffset * sign);\n\n offsetRef.current = clampedOffset;\n onDragUpdate({ offset: clampedOffset, isDragging: true });\n\n // Prevent text selection during active drag\n e.preventDefault();\n },\n [axis, sign, onDragUpdate]\n );\n\n const handlePointerUp = useCallback(\n (_e: PointerEvent) => {\n if (!startRef.current || committedRef.current !== \"drag\") {\n startRef.current = null;\n committedRef.current = null;\n return;\n }\n\n const offset = offsetRef.current;\n const elapsed = Date.now() - startRef.current.time;\n const velocity = elapsed > 0 ? offset / elapsed : 0;\n\n startRef.current = null;\n committedRef.current = null;\n offsetRef.current = 0;\n\n // Determine panel dimension for threshold calculation\n const panelSize = getPanelDimension(panelRef.current, axis);\n\n const pastThreshold = offset / panelSize > config.closeThreshold;\n const fastEnough = velocity > config.velocityThreshold;\n\n if (pastThreshold || fastEnough) {\n // Dismiss\n if (config.isNested) {\n config.onPop();\n } else {\n config.onClose();\n }\n // Reset drag state after dismiss\n onDragUpdate({ offset: 0, isDragging: false });\n } else {\n // Snap back\n onDragUpdate({ offset: 0, isDragging: false });\n }\n },\n [\n panelRef,\n axis,\n config.closeThreshold,\n config.velocityThreshold,\n config.isNested,\n config.onClose,\n config.onPop,\n onDragUpdate,\n config,\n ]\n );\n\n const handlePointerCancel = useCallback(() => {\n startRef.current = null;\n committedRef.current = null;\n offsetRef.current = 0;\n onDragUpdate({ offset: 0, isDragging: false });\n }, [onDragUpdate]);\n\n // Attach pointer events to the panel element\n useEffect(() => {\n const el = panelRef.current;\n if (!(el && config.enabled)) {\n return;\n }\n\n el.addEventListener(\"pointerdown\", handlePointerDown);\n el.addEventListener(\"pointermove\", handlePointerMove);\n el.addEventListener(\"pointerup\", handlePointerUp);\n el.addEventListener(\"pointercancel\", handlePointerCancel);\n\n return () => {\n el.removeEventListener(\"pointerdown\", handlePointerDown);\n el.removeEventListener(\"pointermove\", handlePointerMove);\n el.removeEventListener(\"pointerup\", handlePointerUp);\n el.removeEventListener(\"pointercancel\", handlePointerCancel);\n };\n }, [\n panelRef,\n config.enabled,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n ]);\n}\n","declare const process: undefined | { env?: { NODE_ENV?: string } };\n\nimport type { ComponentType } from \"react\";\nimport { createStore, type StoreApi } from \"zustand\";\nimport type {\n ResolvedConfig,\n SheetActions,\n SheetItem,\n StacksheetSnapshot,\n} from \"./types\";\n\n// biome-ignore lint/suspicious/noExplicitAny: maps store heterogeneous components — type safety is at the call site\ntype AnyComponent = ComponentType<any>;\n\ntype StoreState<TMap extends object> = StacksheetSnapshot<TMap> &\n SheetActions<TMap>;\n\n/** Return type of createSheetStore — store plus ad-hoc component maps */\nexport interface SheetStoreBundle<TMap extends object> {\n store: StoreApi<StoreState<TMap>>;\n /** Component → generated type key (dedup) */\n componentRegistry: Map<AnyComponent, string>;\n /** Generated type key → Component (for renderer lookup) */\n componentMap: Map<string, AnyComponent>;\n}\n\n// ── Ad-hoc helpers ──────────────────────────────\n\n/**\n * Dev-mode warning: detect likely inline arrow functions passed as ad-hoc components.\n * When a new component reference has the same displayName/name as an existing one,\n * it's almost always an inline arrow being re-created every render.\n */\nfunction warnInlineComponent(\n component: AnyComponent,\n componentRegistry: Map<AnyComponent, string>,\n warnedNames: Set<string>\n): void {\n if (\n typeof process === \"undefined\" ||\n process?.env?.NODE_ENV === \"production\"\n ) {\n return;\n }\n\n const name = component.displayName || component.name;\n if (!name) {\n return;\n }\n if (warnedNames.has(name)) {\n return;\n }\n\n for (const [existing, key] of componentRegistry) {\n const existingName = existing.displayName || existing.name;\n if (existingName === name) {\n warnedNames.add(name);\n console.warn(\n `[stacksheet] A new component reference with name \"${name}\" was registered ` +\n `(key: ${key}), but a different reference with the same name already exists. ` +\n `This usually means you're passing an inline arrow function (e.g. ` +\n \"open(() => <MySheet />)). Define the component outside of render to avoid \" +\n \"memory leaks and broken navigate() same-type detection.\"\n );\n return;\n }\n }\n}\n\n/**\n * If `first` is a function (component), register it and return { type, id, data }.\n * Otherwise, pass through the string-based (type, id, data) args unchanged.\n */\nfunction resolveArgs(\n componentRegistry: Map<AnyComponent, string>,\n componentMap: Map<string, AnyComponent>,\n getNextKey: () => string,\n warnedNames: Set<string>,\n first: unknown,\n second: unknown,\n third: unknown\n): { type: string; id: string; data: Record<string, unknown> } {\n if (typeof first === \"function\") {\n const component = first as AnyComponent;\n\n let typeKey = componentRegistry.get(component);\n if (!typeKey) {\n warnInlineComponent(component, componentRegistry, warnedNames);\n typeKey = getNextKey();\n componentRegistry.set(component, typeKey);\n componentMap.set(typeKey, component);\n }\n\n if (typeof second === \"string\") {\n return {\n type: typeKey,\n id: second,\n data: (third ?? {}) as Record<string, unknown>,\n };\n }\n return {\n type: typeKey,\n id: crypto.randomUUID(),\n data: (second ?? {}) as Record<string, unknown>,\n };\n }\n\n return {\n type: first as string,\n id: second as string,\n data: (third ?? {}) as Record<string, unknown>,\n };\n}\n\n/** Pre-resolved args — skips resolveArgs entirely */\ninterface ResolvedItem {\n type: string;\n id: string;\n data: Record<string, unknown>;\n}\n\n/**\n * Create an isolated Zustand store for a sheet stack instance.\n */\nexport function createSheetStore<TMap extends object>(\n config: ResolvedConfig\n): SheetStoreBundle<TMap> {\n type Item = SheetItem<Extract<keyof TMap, string>>;\n\n const componentRegistry = new Map<AnyComponent, string>();\n const componentMap = new Map<string, AnyComponent>();\n\n // Per-instance counter (not module-level) — prevents identity leaks across instances/tests\n let adhocCounter = 0;\n function getNextKey() {\n return `__adhoc_${adhocCounter++}`;\n }\n\n // Set of component names already warned about (avoid log spam)\n const warnedNames = new Set<string>();\n\n function resolve(first: unknown, second: unknown, third: unknown) {\n return resolveArgs(\n componentRegistry,\n componentMap,\n getNextKey,\n warnedNames,\n first,\n second,\n third\n );\n }\n\n const store = createStore<StoreState<TMap>>()((set, get) => {\n // ── Internal resolved methods (no double-resolution) ──\n\n function _openResolved({ type, id, data }: ResolvedItem) {\n set({\n stack: [{ id, type, data } as Item],\n isOpen: true,\n });\n }\n\n function _pushResolved({ type, id, data }: ResolvedItem) {\n set((state) => {\n const item = { id, type, data } as Item;\n if (\n Number.isFinite(config.maxDepth) &&\n state.stack.length >= config.maxDepth\n ) {\n return {\n stack: [...state.stack.slice(0, -1), item],\n isOpen: true,\n };\n }\n return {\n stack: [...state.stack, item],\n isOpen: true,\n };\n });\n }\n\n function _replaceResolved({ type, id, data }: ResolvedItem) {\n set((state) => {\n const item = { id, type, data } as Item;\n if (state.stack.length === 0) {\n return { stack: [item], isOpen: true };\n }\n return {\n stack: [...state.stack.slice(0, -1), item],\n isOpen: true,\n };\n });\n }\n\n return {\n stack: [],\n isOpen: false,\n\n open(first: unknown, second?: unknown, third?: unknown) {\n _openResolved(resolve(first, second, third));\n },\n\n push(first: unknown, second?: unknown, third?: unknown) {\n _pushResolved(resolve(first, second, third));\n },\n\n replace(first: unknown, second?: unknown, third?: unknown) {\n _replaceResolved(resolve(first, second, third));\n },\n\n swap(first: unknown, second?: unknown) {\n let type: string;\n let data: Record<string, unknown>;\n\n if (typeof first === \"function\") {\n const component = first as AnyComponent;\n let typeKey = componentRegistry.get(component);\n if (!typeKey) {\n warnInlineComponent(component, componentRegistry, warnedNames);\n typeKey = getNextKey();\n componentRegistry.set(component, typeKey);\n componentMap.set(typeKey, component);\n }\n type = typeKey;\n data = (second ?? {}) as Record<string, unknown>;\n } else {\n type = first as string;\n data = (second ?? {}) as Record<string, unknown>;\n }\n\n set((state) => {\n const top = state.stack.at(-1);\n if (!top) {\n return state;\n }\n const newStack = [...state.stack];\n newStack[newStack.length - 1] = { id: top.id, type, data } as Item;\n return { stack: newStack };\n });\n },\n\n navigate(first: unknown, second?: unknown, third?: unknown) {\n const resolved = resolve(first, second, third);\n const { stack } = get();\n const top = stack.at(-1);\n\n if (stack.length === 0) {\n _openResolved(resolved);\n return;\n }\n\n // For ad-hoc components, check if the top item's type maps to the same\n // component in the registry. For string types, compare directly.\n let isSameType = top?.type === resolved.type;\n if (!isSameType && typeof first === \"function\") {\n const topComponent = componentMap.get(top?.type ?? \"\");\n isSameType = topComponent === first;\n }\n\n if (isSameType) {\n _replaceResolved(resolved);\n return;\n }\n\n _pushResolved(resolved);\n },\n\n setData(first: unknown, second?: unknown, third?: unknown) {\n // setData always has an id: (type, id, data) or (Component, id, data)\n const { id, data } = resolve(first, second, third);\n set((state) => {\n const idx = state.stack.findIndex((item) => item.id === id);\n if (idx === -1) {\n return state;\n }\n const updated = [...state.stack];\n updated[idx] = { ...updated[idx], data } as Item;\n return { stack: updated };\n });\n },\n\n remove(id) {\n set((state) => {\n const next = state.stack.filter((item) => item.id !== id);\n if (next.length === state.stack.length) {\n return state;\n }\n if (next.length === 0) {\n return { stack: [], isOpen: false };\n }\n return { stack: next };\n });\n },\n\n pop() {\n set((state) => {\n if (state.stack.length <= 1) {\n return { stack: [], isOpen: false };\n }\n return { stack: state.stack.slice(0, -1), isOpen: true };\n });\n },\n\n close() {\n set({ stack: [], isOpen: false });\n },\n };\n });\n\n return { store, componentRegistry, componentMap };\n}\n","import {\n Root as ScrollAreaRoot,\n Scrollbar as ScrollAreaScrollbar,\n Thumb as ScrollAreaThumb,\n Viewport as ScrollAreaViewport,\n} from \"@radix-ui/react-scroll-area\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { ArrowLeftIcon, XIcon } from \"./icons\";\nimport { useSheetPanel } from \"./panel-context\";\n\n// ── Sheet.Handle ────────────────────────────────\n\nexport interface SheetHandleProps {\n /** Render as child element, merging props */\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom handle content. Defaults to a centered grab bar. */\n children?: ReactNode;\n}\n\nconst HANDLE_STYLE: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"12px 0 4px\",\n flexShrink: 0,\n cursor: \"grab\",\n touchAction: \"none\",\n};\n\nconst HANDLE_BAR_STYLE: CSSProperties = {\n width: 36,\n height: 4,\n borderRadius: 2,\n background: \"var(--muted-foreground, rgba(0, 0, 0, 0.25))\",\n};\n\nfunction SheetHandle({\n asChild,\n className,\n style,\n children,\n}: SheetHandleProps) {\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n className={className}\n data-stacksheet-handle=\"\"\n style={{ ...HANDLE_STYLE, ...style }}\n >\n {children ?? <div style={HANDLE_BAR_STYLE} />}\n </Comp>\n );\n}\n\n// ── Sheet.Header ────────────────────────────────\n\nexport interface SheetHeaderProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nconst HEADER_STYLE: CSSProperties = {\n flexShrink: 0,\n};\n\nfunction SheetHeader({\n asChild,\n className,\n style,\n children,\n}: SheetHeaderProps) {\n const Comp = asChild ? Slot : \"header\";\n return (\n <Comp className={className} style={{ ...HEADER_STYLE, ...style }}>\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Title ─────────────────────────────────\n\nexport interface SheetTitleProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetTitle({ asChild, className, style, children }: SheetTitleProps) {\n const { panelId } = useSheetPanel();\n const Comp = asChild ? Slot : \"h2\";\n return (\n <Comp className={className} id={`${panelId}-title`} style={style}>\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Description ───────────────────────────\n\nexport interface SheetDescriptionProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetDescription({\n asChild,\n className,\n style,\n children,\n}: SheetDescriptionProps) {\n const { panelId } = useSheetPanel();\n const Comp = asChild ? Slot : \"p\";\n return (\n <Comp className={className} id={`${panelId}-desc`} style={style}>\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Body ──────────────────────────────────\n\nexport interface SheetBodyProps {\n /** When true, renders child element directly instead of ScrollArea */\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nconst BODY_STYLE: CSSProperties = {\n flex: 1,\n minHeight: 0,\n position: \"relative\",\n};\n\nconst SCROLLBAR_STYLE: CSSProperties = {\n display: \"flex\",\n userSelect: \"none\",\n touchAction: \"none\",\n padding: 2,\n width: 8,\n};\n\nconst THUMB_STYLE: CSSProperties = {\n flex: 1,\n borderRadius: 4,\n background: \"var(--border, rgba(0, 0, 0, 0.15))\",\n position: \"relative\",\n};\n\nfunction SheetBody({ asChild, className, style, children }: SheetBodyProps) {\n if (asChild) {\n return (\n <Slot\n className={className}\n data-stacksheet-no-drag=\"\"\n style={{ ...BODY_STYLE, ...style }}\n >\n {children}\n </Slot>\n );\n }\n\n return (\n <ScrollAreaRoot\n className={className}\n data-stacksheet-no-drag=\"\"\n style={{ ...BODY_STYLE, overflow: \"hidden\", ...style }}\n >\n <ScrollAreaViewport\n style={{ height: \"100%\", width: \"100%\", overscrollBehavior: \"contain\" }}\n >\n {children}\n </ScrollAreaViewport>\n <ScrollAreaScrollbar orientation=\"vertical\" style={SCROLLBAR_STYLE}>\n <ScrollAreaThumb style={THUMB_STYLE} />\n </ScrollAreaScrollbar>\n </ScrollAreaRoot>\n );\n}\n\n// ── Sheet.Footer ────────────────────────────────\n\nexport interface SheetFooterProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nconst FOOTER_STYLE: CSSProperties = {\n flexShrink: 0,\n};\n\nfunction SheetFooter({\n asChild,\n className,\n style,\n children,\n}: SheetFooterProps) {\n const Comp = asChild ? Slot : \"footer\";\n return (\n <Comp className={className} style={{ ...FOOTER_STYLE, ...style }}>\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Close ─────────────────────────────────\n\nexport interface SheetCloseProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom content. Defaults to an X icon. */\n children?: ReactNode;\n}\n\nfunction SheetClose({ asChild, className, style, children }: SheetCloseProps) {\n const { close } = useSheetPanel();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n aria-label={children ? undefined : \"Close\"}\n className={className}\n onClick={close}\n style={style}\n type={asChild ? undefined : \"button\"}\n >\n {children ?? <XIcon />}\n </Comp>\n );\n}\n\n// ── Sheet.Back ──────────────────────────────────\n\nexport interface SheetBackProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom content. Defaults to an arrow-left icon. */\n children?: ReactNode;\n}\n\nfunction SheetBack({ asChild, className, style, children }: SheetBackProps) {\n const { back, isNested } = useSheetPanel();\n\n if (!isNested) {\n return null;\n }\n\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n aria-label={children ? undefined : \"Back\"}\n className={className}\n onClick={back}\n style={style}\n type={asChild ? undefined : \"button\"}\n >\n {children ?? <ArrowLeftIcon />}\n </Comp>\n );\n}\n\n// ── Sheet namespace ─────────────────────────────\n\nexport const Sheet = {\n Handle: SheetHandle,\n Header: SheetHeader,\n Title: SheetTitle,\n Description: SheetDescription,\n Body: SheetBody,\n Footer: SheetFooter,\n Close: SheetClose,\n Back: SheetBack,\n} as const;\n"],"mappings":"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","names":["createContext","useContext","useMemo","useStore","useCallback","useEffect","useRef","useState","useEffect","jsx","useRef","useState","useEffect","useCallback","jsx","jsxs","createContext","useContext","useMemo","useStore","jsx","jsxs","HANDLE_BAR_STYLE"]}
|
|
1
|
+
{"version":3,"sources":["../src/springs.ts","../src/config.ts","../src/create.tsx","../src/renderer.tsx","../src/icons.tsx","../src/media.ts","../src/panel-context.tsx","../src/snap-points.ts","../src/stacking.ts","../src/use-drag.ts","../src/store.ts","../src/parts.tsx"],"sourcesContent":["import type { SpringConfig } from \"./types\";\n\n/**\n * Spring presets inspired by iOS animation feel.\n *\n * - `subtle` — Barely noticeable bounce, professional.\n * - `snappy` — Quick, responsive for interactions.\n * - `stiff` — Very quick, controlled. Panels, drawers. **(default)**\n */\nexport const springs = {\n subtle: { stiffness: 300, damping: 30, mass: 1 },\n snappy: { stiffness: 400, damping: 28, mass: 0.8 },\n stiff: { stiffness: 400, damping: 40, mass: 1 },\n} as const satisfies Record<string, SpringConfig>;\n\nexport type SpringPreset = keyof typeof springs;\n","import type { SpringPreset } from \"./springs\";\nimport { springs } from \"./springs\";\nimport type {\n ResolvedConfig,\n ResponsiveSide,\n SideConfig,\n SpringConfig,\n StackingConfig,\n StacksheetConfig,\n} from \"./types\";\n\n// ── Defaults ────────────────────────────────────\n\nconst DEFAULT_STACKING: StackingConfig = {\n scaleStep: 0.04,\n offsetStep: 16,\n opacityStep: 0,\n radius: 12,\n renderThreshold: 3,\n};\n\nconst DEFAULT_SIDE: ResponsiveSide = {\n desktop: \"right\",\n mobile: \"bottom\",\n};\n\n// ── Helpers ─────────────────────────────────────\n\n/** Normalize a string side to a responsive object, merging with defaults. */\nfunction resolveSide(side: SideConfig | undefined): ResponsiveSide {\n if (typeof side === \"string\") {\n return { desktop: side, mobile: side };\n }\n return { ...DEFAULT_SIDE, ...side };\n}\n\n/** Resolve a preset name to a SpringConfig, or merge partial config with defaults. */\nfunction resolveSpring(\n spring: SpringPreset | Partial<SpringConfig> | undefined\n): SpringConfig {\n if (typeof spring === \"string\") {\n return springs[spring];\n }\n return { ...springs.stiff, ...spring };\n}\n\n// ── Resolver ────────────────────────────────────\n\n/** Merge user-provided config with defaults. Resolves union types (side, spring) to concrete values. */\nexport function resolveConfig(config: StacksheetConfig = {}): ResolvedConfig {\n return {\n maxDepth: config.maxDepth ?? Number.POSITIVE_INFINITY,\n closeOnEscape: config.closeOnEscape ?? true,\n closeOnBackdrop: config.closeOnBackdrop ?? true,\n showOverlay: config.showOverlay ?? true,\n lockScroll: config.lockScroll ?? true,\n width: config.width ?? 420,\n maxWidth: config.maxWidth ?? \"90vw\",\n breakpoint: config.breakpoint ?? 768,\n side: resolveSide(config.side),\n stacking: { ...DEFAULT_STACKING, ...config.stacking },\n spring: resolveSpring(config.spring),\n zIndex: config.zIndex ?? 100,\n ariaLabel: config.ariaLabel ?? \"Sheet dialog\",\n onOpenComplete: config.onOpenComplete,\n onCloseComplete: config.onCloseComplete,\n snapPoints: config.snapPoints ?? [],\n snapPointIndex: config.snapPointIndex,\n onSnapPointChange: config.onSnapPointChange,\n snapToSequentialPoints: config.snapToSequentialPoints ?? false,\n drag: config.drag ?? true,\n closeThreshold: config.closeThreshold ?? 0.25,\n velocityThreshold: config.velocityThreshold ?? 0.5,\n dismissible: config.dismissible ?? true,\n modal: config.modal ?? true,\n shouldScaleBackground: config.shouldScaleBackground ?? false,\n scaleBackgroundAmount: config.scaleBackgroundAmount ?? 0.97,\n };\n}\n","import { Portal } from \"@radix-ui/react-portal\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { useStore } from \"zustand\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport { resolveConfig } from \"./config\";\nimport { SheetRenderer } from \"./renderer\";\nimport { createSheetStore } from \"./store\";\nimport type {\n ContentMap,\n ResolvedConfig,\n SheetActions,\n StacksheetConfig,\n StacksheetInstance,\n StacksheetProviderProps,\n StacksheetSnapshot,\n} from \"./types\";\n\ntype StoreState<TMap extends object> = StacksheetSnapshot<TMap> &\n SheetActions<TMap>;\n\n/**\n * Create an isolated sheet stack instance with typed store, hooks, and provider.\n *\n * Works with both `interface` and `type` definitions:\n *\n * ```ts\n * // Using an interface\n * interface SheetDataMap {\n * \"bucket-create\": { onCreated?: (b: Bucket) => void };\n * \"bucket-edit\": { bucket: Bucket };\n * }\n *\n * // Using a type alias\n * type SheetDataMap = {\n * \"bucket-create\": { onCreated?: (b: Bucket) => void };\n * \"bucket-edit\": { bucket: Bucket };\n * };\n *\n * const { StacksheetProvider, useSheet, useStacksheetState } =\n * createStacksheet<SheetDataMap>();\n * ```\n *\n * Sheet content components receive their data as **spread props**:\n * ```ts\n * // Data map defines: \"bucket-edit\": { bucket: Bucket }\n * // Component receives: ({ bucket }: { bucket: Bucket }) => JSX.Element\n * ```\n *\n * Use `useSheetPanel()` inside content components to access `close()` and `back()`.\n */\nexport function createStacksheet<TMap extends object>(\n config?: StacksheetConfig\n): StacksheetInstance<TMap> {\n const resolved = resolveConfig(config);\n const { store, componentMap } = createSheetStore<TMap>(resolved);\n\n // Context for the store — allows multiple instances\n const StoreContext = createContext<{\n store: StoreApi<StoreState<TMap>>;\n config: ResolvedConfig;\n } | null>(null);\n\n function useStoreContext() {\n const ctx = useContext(StoreContext);\n if (!ctx) {\n throw new Error(\n \"useSheet/useStacksheetState must be used within <StacksheetProvider>\"\n );\n }\n return ctx;\n }\n\n // ── Provider ────────────────────────────────\n\n const EMPTY_SHEETS = {} as ContentMap<TMap>;\n\n function StacksheetProvider({\n sheets = EMPTY_SHEETS,\n children,\n classNames,\n renderHeader,\n }: StacksheetProviderProps<TMap>) {\n const value = useMemo(() => ({ store, config: resolved }), []);\n return (\n <StoreContext.Provider value={value}>\n {children}\n <Portal asChild={false}>\n <SheetRenderer<TMap>\n classNames={classNames}\n componentMap={componentMap}\n config={resolved}\n renderHeader={renderHeader}\n sheets={sheets}\n store={store}\n />\n </Portal>\n </StoreContext.Provider>\n );\n }\n\n // ── Hooks ───────────────────────────────────\n\n function useSheet(): SheetActions<TMap> {\n const { store: s } = useStoreContext();\n // Actions are stable refs in Zustand v5 — read once, no subscription needed\n return useMemo(() => {\n const state = s.getState();\n return {\n open: state.open,\n push: state.push,\n replace: state.replace,\n swap: state.swap,\n navigate: state.navigate,\n setData: state.setData,\n remove: state.remove,\n pop: state.pop,\n close: state.close,\n };\n }, [s]);\n }\n\n function useStacksheetState(): StacksheetSnapshot<TMap> {\n const { store: s } = useStoreContext();\n return useStore(\n s,\n useShallow((state) => ({\n stack: state.stack,\n isOpen: state.isOpen,\n }))\n );\n }\n\n return { StacksheetProvider, useSheet, useStacksheetState, store };\n}\n","// CloseWatcher — ambient type for browsers that support it (Chromium 120+)\ndeclare global {\n var CloseWatcher:\n | (new () => { onclose: (() => void) | null; destroy: () => void })\n | undefined;\n}\n\nimport FocusTrap from \"focus-trap-react\";\nimport { AnimatePresence, motion as m } from \"motion/react\";\nimport {\n type ComponentType,\n type CSSProperties,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport type { StoreApi } from \"zustand\";\nimport { useStore } from \"zustand\";\nimport { ArrowLeftIcon, XIcon } from \"./icons\";\nimport { useResolvedSide } from \"./media\";\nimport { SheetPanelContext } from \"./panel-context\";\nimport { getSnapOffset, resolveSnapPoints } from \"./snap-points\";\nimport {\n getAnimatedBorderRadius,\n getPanelStyles,\n getSlideFrom,\n getSlideTarget,\n getStackOffset,\n getStackTransform,\n type SlideValues,\n} from \"./stacking\";\nimport type {\n CloseReason,\n ContentMap,\n HeaderRenderProps,\n ResolvedConfig,\n SheetActions,\n SheetItem,\n Side,\n StacksheetClassNames,\n StacksheetSnapshot,\n} from \"./types\";\nimport { type DragState, useDrag } from \"./use-drag\";\n\n// ── Default header ──────────────────────────────\n\nfunction DefaultHeader({\n isNested,\n onBack,\n onClose,\n className,\n}: HeaderRenderProps & { className?: string }) {\n return (\n <div\n className={`flex h-14 shrink-0 items-center justify-between border-b px-6 ${className ?? \"\"}`}\n >\n <div className=\"flex items-center gap-2\">\n {isNested && (\n <button\n aria-label=\"Back\"\n className=\"flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent p-0 text-inherit opacity-60 transition-opacity duration-150 hover:opacity-100\"\n onClick={onBack}\n type=\"button\"\n >\n <ArrowLeftIcon />\n </button>\n )}\n </div>\n <button\n aria-label=\"Close\"\n className=\"flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent p-0 text-inherit opacity-60 transition-opacity duration-150 hover:opacity-100\"\n onClick={onClose}\n type=\"button\"\n >\n <XIcon />\n </button>\n </div>\n );\n}\n\n// ── Resolved classNames ─────────────────────────\n\ntype ResolvedClassNames = Required<StacksheetClassNames>;\n\nconst EMPTY_CLASSNAMES: ResolvedClassNames = {\n backdrop: \"\",\n panel: \"\",\n header: \"\",\n};\n\nfunction resolveClassNames(cn?: StacksheetClassNames): ResolvedClassNames {\n if (!cn) {\n return EMPTY_CLASSNAMES;\n }\n return {\n backdrop: cn.backdrop ?? \"\",\n panel: cn.panel ?? \"\",\n header: cn.header ?? \"\",\n };\n}\n\n// ── Helpers ──────────────────────────────────────\n\nfunction selectSpring(\n isTop: boolean,\n spring: Record<string, unknown>,\n stackSpring: Record<string, unknown>\n): Record<string, unknown> {\n return isTop ? spring : stackSpring;\n}\n\nfunction buildAriaProps(\n isTop: boolean,\n isModal: boolean,\n isComposable: boolean,\n ariaLabel: string,\n panelId: string\n): Record<string, string | undefined> {\n if (!isTop) {\n return {};\n }\n const props: Record<string, string | undefined> = { role: \"dialog\" };\n if (isModal) {\n props[\"aria-modal\"] = \"true\";\n }\n if (isComposable) {\n props[\"aria-labelledby\"] = `${panelId}-title`;\n props[\"aria-describedby\"] = `${panelId}-desc`;\n } else {\n props[\"aria-label\"] = ariaLabel;\n }\n return props;\n}\n\n// ── Drag offset to CSS transform ────────────────\n\nfunction getDragTransform(\n side: Side,\n offset: number\n): { x?: number; y?: number } {\n if (offset === 0) {\n return {};\n }\n switch (side) {\n case \"right\":\n return { x: offset };\n case \"left\":\n return { x: -offset };\n case \"bottom\":\n return { y: offset };\n default:\n return {};\n }\n}\n\n// ── Panel helpers (extracted to reduce SheetPanel complexity) ──\n\n/** Measure panel height via ResizeObserver for snap point calculations */\nfunction usePanelHeight(\n panelRef: React.RefObject<HTMLDivElement | null>,\n hasSnapPoints: boolean\n): number {\n const [height, setHeight] = useState(0);\n\n useEffect(() => {\n const el = panelRef.current;\n if (!(el && hasSnapPoints)) {\n return;\n }\n setHeight(el.offsetHeight);\n const observer = new ResizeObserver(([entry]) => {\n if (entry) {\n setHeight(entry.contentRect.height);\n }\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, [panelRef, hasSnapPoints]);\n\n return height;\n}\n\n/** Build the panel's inline style object */\nfunction buildPanelStyle(\n panelStyles: CSSProperties,\n isTop: boolean,\n hasPanelClass: boolean,\n isDragging: boolean\n): CSSProperties {\n return {\n ...panelStyles,\n pointerEvents: isTop ? \"auto\" : \"none\",\n ...(isTop ? {} : { contain: \"layout style paint\" }),\n ...(isDragging ? { transition: \"none\" } : {}),\n ...(hasPanelClass\n ? {}\n : {\n background: \"var(--background, #fff)\",\n borderColor: \"var(--border, transparent)\",\n }),\n };\n}\n\n/** Build per-property transition config */\nfunction buildPanelTransition(\n isDragging: boolean,\n isTop: boolean,\n spring: Record<string, unknown>,\n stackSpring: Record<string, unknown>\n) {\n const visualTween = {\n type: \"tween\" as const,\n duration: 0.25,\n ease: \"easeOut\" as const,\n };\n\n if (isDragging) {\n return { type: \"tween\" as const, duration: 0 };\n }\n\n const base = selectSpring(isTop, spring, stackSpring);\n return { ...base, borderRadius: visualTween, boxShadow: visualTween };\n}\n\n/** Compute the Y offset for the current snap point */\nfunction computeSnapYOffset(\n side: Side,\n snapHeights: number[],\n activeSnapIndex: number,\n measuredHeight: number\n): number {\n if (side !== \"bottom\" || snapHeights.length === 0 || measuredHeight <= 0) {\n return 0;\n }\n return getSnapOffset(activeSnapIndex, snapHeights, measuredHeight);\n}\n\n// ── SheetPanel ──────────────────────────────────\n\ninterface SheetPanelProps {\n item: SheetItem;\n index: number;\n depth: number;\n isTop: boolean;\n isNested: boolean;\n side: Side;\n config: ResolvedConfig;\n classNames: ResolvedClassNames;\n // biome-ignore lint/suspicious/noExplicitAny: heterogeneous content component\n Content: ComponentType<any> | undefined;\n shouldRender: boolean;\n pop: () => void;\n close: () => void;\n /** Swipe-specific close — sets reason to \"swipe\" */\n swipeClose: () => void;\n /** Swipe-specific pop — sets reason to \"swipe\" */\n swipePop: () => void;\n /** Resolved snap point heights in px (ascending). Empty = no snaps. */\n snapHeights: number[];\n /** Currently active snap index */\n activeSnapIndex: number;\n /** Called when drag release targets a snap point */\n onSnap: (index: number) => void;\n renderHeader?: false | ((props: HeaderRenderProps) => React.ReactNode);\n slideFrom: SlideValues;\n slideTarget: SlideValues;\n spring: Record<string, unknown>;\n stackSpring: Record<string, unknown>;\n exitSpring: Record<string, unknown>;\n}\n\n/** Renders panel inner content — composable mode vs classic (header + scroll) */\nfunction PanelInnerContent({\n isComposable,\n shouldRender,\n Content,\n data,\n renderHeader,\n headerProps,\n headerClassName,\n}: {\n isComposable: boolean;\n shouldRender: boolean;\n // biome-ignore lint/suspicious/noExplicitAny: heterogeneous content component\n Content: ComponentType<any> | undefined;\n data: Record<string, unknown>;\n renderHeader?: false | ((props: HeaderRenderProps) => React.ReactNode);\n headerProps: HeaderRenderProps;\n headerClassName: string | undefined;\n}) {\n if (isComposable) {\n return shouldRender && Content ? <Content {...data} /> : null;\n }\n\n return (\n <>\n {renderHeader ? (\n renderHeader(headerProps)\n ) : (\n <DefaultHeader {...headerProps} className={headerClassName} />\n )}\n {shouldRender && Content && (\n <div\n className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain\"\n data-stacksheet-no-drag=\"\"\n >\n <Content {...data} />\n </div>\n )}\n </>\n );\n}\n\n/** Built-in drag handle for bottom panels — always visible on the top sheet */\nfunction BottomHandle() {\n return (\n <div\n className=\"flex shrink-0 cursor-grab touch-none items-center justify-center pt-4 pb-1\"\n data-stacksheet-handle=\"\"\n >\n <div className=\"h-1 w-9 rounded-sm bg-current/25\" />\n </div>\n );\n}\n\n/** Floating drag handle for left/right side panels */\nfunction SideHandle({ side, isHovered }: { side: Side; isHovered: boolean }) {\n const position: CSSProperties =\n side === \"right\" ? { right: \"100%\" } : { left: \"100%\" };\n\n return (\n <m.div\n animate={{ opacity: isHovered ? 1 : 0 }}\n className=\"absolute top-0 bottom-0 flex w-6 cursor-grab touch-none items-center justify-center\"\n data-stacksheet-handle=\"\"\n style={position}\n transition={{ duration: isHovered ? 0.15 : 0.4, ease: \"easeOut\" }}\n >\n <div className=\"h-10 w-[5px] rounded-sm bg-current/35 shadow-sm\" />\n </m.div>\n );\n}\n\nfunction SheetPanel({\n item,\n index,\n depth,\n isTop,\n isNested,\n side,\n config,\n classNames,\n Content,\n shouldRender,\n pop,\n close,\n swipeClose,\n swipePop,\n snapHeights,\n activeSnapIndex,\n onSnap,\n renderHeader,\n slideFrom,\n slideTarget,\n spring,\n stackSpring,\n exitSpring,\n}: SheetPanelProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const hasEnteredRef = useRef(false);\n const [dragState, setDragState] = useState<DragState>({\n offset: 0,\n isDragging: false,\n });\n const [isHovered, setIsHovered] = useState(false);\n\n const measuredHeight = usePanelHeight(panelRef, snapHeights.length > 0);\n\n const transform = getStackTransform(depth, config.stacking);\n const panelStyles = getPanelStyles(side, config, depth, index);\n\n // Reset entrance flag when panel moves away from top\n useEffect(() => {\n if (!isTop) {\n hasEnteredRef.current = false;\n }\n }, [isTop]);\n\n const handleAnimationComplete = useCallback(() => {\n if (isTop && !hasEnteredRef.current) {\n hasEnteredRef.current = true;\n config.onOpenComplete?.();\n }\n }, [isTop, config]);\n\n // Drag-to-dismiss (only on top panel)\n useDrag(\n panelRef,\n {\n enabled: isTop && config.drag && config.dismissible,\n closeThreshold: config.closeThreshold,\n velocityThreshold: config.velocityThreshold,\n side,\n onClose: swipeClose,\n onPop: swipePop,\n isNested,\n snapHeights,\n activeSnapIndex,\n onSnap,\n sequential: config.snapToSequentialPoints,\n },\n setDragState\n );\n\n // Per-sheet aria-label: check data.__ariaLabel, fall back to config\n const ariaLabel =\n (typeof item.data?.__ariaLabel === \"string\"\n ? item.data.__ariaLabel\n : undefined) ?? config.ariaLabel;\n\n // Panel context for composable parts (Sheet.Close, Sheet.Title, etc.)\n const panelId = `stacksheet-${item.id}`;\n const panelContext = useMemo(\n () => ({ close, back: pop, isNested, isTop, panelId, side }),\n [close, pop, isNested, isTop, panelId, side]\n );\n\n const isComposable = renderHeader === false;\n const hasPanelClass = classNames.panel !== \"\";\n const dragOffset = getDragTransform(side, dragState.offset);\n const panelStyle = buildPanelStyle(\n panelStyles,\n isTop,\n hasPanelClass,\n dragState.isDragging\n );\n\n const headerProps: HeaderRenderProps = {\n isNested,\n onBack: pop,\n onClose: close,\n side,\n };\n\n const ariaProps = buildAriaProps(\n isTop,\n config.modal,\n isComposable,\n ariaLabel,\n panelId\n );\n\n const transition = buildPanelTransition(\n dragState.isDragging,\n isTop,\n spring,\n stackSpring\n );\n\n const animatedRadius = getAnimatedBorderRadius(side, depth, config.stacking);\n const snapYOffset = computeSnapYOffset(\n side,\n snapHeights,\n activeSnapIndex,\n measuredHeight\n );\n\n // Merge stack offset + drag offset + snap offset into the animate target\n const stackOffset = getStackOffset(side, transform.offset);\n const animateTarget = {\n ...slideTarget,\n ...stackOffset,\n ...dragOffset,\n scale: transform.scale,\n opacity: transform.opacity,\n ...animatedRadius,\n boxShadow: getShadow(side, !isTop),\n transition,\n ...(snapYOffset > 0 ? { y: (dragOffset.y ?? 0) + snapYOffset } : {}),\n };\n\n const initialRadius = getInitialRadius(side);\n const showSideHandle = isTop && side !== \"bottom\";\n const showBottomHandle = isTop && side === \"bottom\";\n\n const exitTween = {\n type: \"tween\" as const,\n duration: 0.25,\n ease: \"easeOut\" as const,\n };\n\n const panelContent = (\n <m.div\n animate={animateTarget}\n className={classNames.panel || undefined}\n exit={{\n ...slideFrom,\n opacity: 0.6,\n boxShadow: getShadow(side, false),\n transition: { ...exitSpring, boxShadow: exitTween },\n }}\n initial={{\n ...slideFrom,\n opacity: 0.8,\n ...initialRadius,\n boxShadow: getShadow(side, false),\n }}\n key={item.id}\n onAnimationComplete={handleAnimationComplete}\n onMouseEnter={showSideHandle ? () => setIsHovered(true) : undefined}\n onMouseLeave={showSideHandle ? () => setIsHovered(false) : undefined}\n ref={panelRef}\n style={panelStyle}\n tabIndex={isTop ? -1 : undefined}\n {...ariaProps}\n >\n {showSideHandle && <SideHandle isHovered={isHovered} side={side} />}\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden rounded-[inherit]\">\n {showBottomHandle && <BottomHandle />}\n <PanelInnerContent\n Content={Content}\n data={item.data as Record<string, unknown>}\n headerClassName={classNames.header || undefined}\n headerProps={headerProps}\n isComposable={isComposable}\n renderHeader={renderHeader}\n shouldRender={shouldRender}\n />\n </div>\n </m.div>\n );\n\n // Non-modal: skip focus trap\n if (!config.modal) {\n return (\n <SheetPanelContext.Provider value={panelContext}>\n {panelContent}\n </SheetPanelContext.Provider>\n );\n }\n\n return (\n <SheetPanelContext.Provider value={panelContext}>\n <FocusTrap\n active={isTop}\n focusTrapOptions={{\n initialFocus: false,\n returnFocusOnDeactivate: true,\n escapeDeactivates: false,\n allowOutsideClick: true,\n checkCanFocusTrap: () =>\n new Promise<void>((resolve) =>\n requestAnimationFrame(() => resolve())\n ),\n fallbackFocus: () => {\n if (panelRef.current) {\n return panelRef.current;\n }\n return document.body;\n },\n }}\n >\n {panelContent}\n </FocusTrap>\n </SheetPanelContext.Provider>\n );\n}\n\n// ── Body scale effect ───────────────────────────\n\nfunction useBodyScale(config: ResolvedConfig, isOpen: boolean) {\n useEffect(() => {\n if (!config.shouldScaleBackground) {\n return;\n }\n\n const wrapper = document.querySelector(\"[data-stacksheet-wrapper]\");\n if (!(wrapper && wrapper instanceof HTMLElement)) {\n return;\n }\n\n if (isOpen) {\n const scale = config.scaleBackgroundAmount;\n wrapper.style.transition =\n \"transform 500ms cubic-bezier(0.32, 0.72, 0, 1), border-radius 500ms cubic-bezier(0.32, 0.72, 0, 1)\";\n wrapper.style.transform = `scale(${scale})`;\n wrapper.style.borderRadius = \"8px\";\n wrapper.style.overflow = \"hidden\";\n wrapper.style.transformOrigin = \"center top\";\n return;\n }\n\n wrapper.style.transform = \"\";\n wrapper.style.borderRadius = \"\";\n // Clean up after transition completes\n const handleEnd = () => {\n wrapper.style.transition = \"\";\n wrapper.style.overflow = \"\";\n wrapper.style.transformOrigin = \"\";\n };\n wrapper.addEventListener(\"transitionend\", handleEnd, { once: true });\n return () => wrapper.removeEventListener(\"transitionend\", handleEnd);\n }, [isOpen, config.shouldScaleBackground, config.scaleBackgroundAmount]);\n}\n\n// ── Renderer ────────────────────────────────────\n\ninterface SheetRendererProps<TMap extends object> {\n store: StoreApi<StacksheetSnapshot<TMap> & SheetActions<TMap>>;\n config: ResolvedConfig;\n sheets: ContentMap<TMap>;\n /** Ad-hoc component map (type key → component) */\n // biome-ignore lint/suspicious/noExplicitAny: heterogeneous component storage\n componentMap: Map<string, ComponentType<any>>;\n classNames?: StacksheetClassNames;\n renderHeader?: false | ((props: HeaderRenderProps) => React.ReactNode);\n}\n\n/**\n * Root renderer component — manages the backdrop, scroll lock, snap points,\n * close reasons, focus restoration, keyboard/CloseWatcher dismissal, and\n * delegates per-panel rendering to `SheetPanel`.\n *\n * Mounted inside a Portal by `StacksheetProvider`.\n */\nexport function SheetRenderer<TMap extends object>({\n store,\n config,\n sheets,\n componentMap,\n classNames: classNamesProp,\n renderHeader,\n}: SheetRendererProps<TMap>) {\n const isOpen = useStore(store, (s) => s.isOpen);\n const stack = useStore(store, (s) => s.stack);\n const rawClose = useStore(store, (s) => s.close);\n const rawPop = useStore(store, (s) => s.pop);\n\n const side = useResolvedSide(config);\n const classNames = resolveClassNames(classNamesProp);\n\n // ── Snap points ──────────────────────────────\n const snapHeights = useMemo(\n () =>\n side === \"bottom\" && config.snapPoints.length > 0\n ? resolveSnapPoints(\n config.snapPoints,\n typeof window !== \"undefined\" ? window.innerHeight : 0\n )\n : [],\n [side, config.snapPoints]\n );\n\n // Default to the last snap point (fully open) when snap points are defined\n const [internalSnapIndex, setInternalSnapIndex] = useState(\n snapHeights.length > 0 ? snapHeights.length - 1 : 0\n );\n\n // Controlled vs uncontrolled snap index\n const activeSnapIndex = config.snapPointIndex ?? internalSnapIndex;\n\n const handleSnap = useCallback(\n (index: number) => {\n setInternalSnapIndex(index);\n config.onSnapPointChange?.(index);\n },\n [config.onSnapPointChange, config]\n );\n\n // Reset snap index when stack opens (start at initial snap point or fully open)\n useEffect(() => {\n if (isOpen && snapHeights.length > 0) {\n const initial = config.snapPointIndex ?? snapHeights.length - 1;\n setInternalSnapIndex(initial);\n }\n }, [isOpen, snapHeights.length, config.snapPointIndex]);\n\n // Track why the sheet was closed — ref survives until exit animation completes\n const closeReasonRef = useRef<CloseReason>(\"programmatic\");\n\n const closeWith = useCallback(\n (reason: CloseReason) => {\n closeReasonRef.current = reason;\n rawClose();\n },\n [rawClose]\n );\n\n const popWith = useCallback(\n (reason: CloseReason) => {\n closeReasonRef.current = reason;\n rawPop();\n },\n [rawPop]\n );\n\n // Default close/pop (programmatic) for child components\n const close = useCallback(() => closeWith(\"programmatic\"), [closeWith]);\n const pop = useCallback(() => popWith(\"programmatic\"), [popWith]);\n\n // Body scale effect\n useBodyScale(config, isOpen);\n\n // Focus restoration: capture the element that was focused when the stack opens.\n // When the stack fully closes, return focus to that element.\n const triggerRef = useRef<Element | null>(null);\n const wasOpenRef = useRef(false);\n\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) {\n triggerRef.current = document.activeElement;\n } else if (!isOpen && wasOpenRef.current) {\n const el = triggerRef.current;\n if (el && el instanceof HTMLElement) {\n el.focus();\n }\n triggerRef.current = null;\n }\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n // Escape key\n useEffect(() => {\n if (!(isOpen && config.closeOnEscape && config.dismissible)) {\n return;\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n if (stack.length > 1) {\n popWith(\"escape\");\n } else {\n closeWith(\"escape\");\n }\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n isOpen,\n config.closeOnEscape,\n config.dismissible,\n stack.length,\n popWith,\n closeWith,\n ]);\n\n // CloseWatcher — handles Android back gesture (progressive enhancement).\n // On browsers without support (Safari, Firefox), this is a no-op.\n useEffect(() => {\n if (\n !(isOpen && config.dismissible) ||\n typeof globalThis.CloseWatcher === \"undefined\"\n ) {\n return;\n }\n\n const watcher = new globalThis.CloseWatcher();\n watcher.onclose = () => {\n if (stack.length > 1) {\n popWith(\"escape\");\n } else {\n closeWith(\"escape\");\n }\n };\n\n return () => watcher.destroy();\n }, [isOpen, config.dismissible, stack.length, popWith, closeWith]);\n\n const slideFrom = getSlideFrom(side);\n const slideTarget = getSlideTarget();\n\n // Primary spring — drives the top sheet's entrance slide\n const spring = {\n type: \"spring\" as const,\n damping: config.spring.damping,\n stiffness: config.spring.stiffness,\n mass: config.spring.mass,\n };\n\n // Same spring for stacking transforms (scale, offset, opacity)\n const stackSpring = spring;\n\n // Same spring for exit (pop)\n const exitSpring = spring;\n\n // Non-modal: skip overlay, skip scroll lock\n const isModal = config.modal;\n const showOverlay = isModal && config.showOverlay;\n\n // Backdrop: use className if provided, otherwise inline fallback\n const hasBackdropClass = classNames.backdrop !== \"\";\n const backdropStyle: CSSProperties = {\n zIndex: config.zIndex,\n cursor:\n config.closeOnBackdrop && config.dismissible ? \"pointer\" : undefined,\n ...(hasBackdropClass\n ? {}\n : { background: \"var(--overlay, rgba(0, 0, 0, 0.2))\" }),\n };\n\n // Handle exit complete — fire onCloseComplete when stack is fully empty\n const handleExitComplete = useCallback(() => {\n if (stack.length === 0) {\n config.onCloseComplete?.(closeReasonRef.current);\n }\n }, [stack.length, config]);\n\n // Swipe-specific dismiss callbacks\n const swipeClose = useCallback(() => closeWith(\"swipe\"), [closeWith]);\n const swipePop = useCallback(() => popWith(\"swipe\"), [popWith]);\n\n // Non-modal: don't lock scroll\n const shouldLockScroll = isOpen && isModal && config.lockScroll;\n\n return (\n <>\n {/* Backdrop — independent AnimatePresence so it fades on its own */}\n {showOverlay && (\n <AnimatePresence>\n {isOpen && (\n <m.div\n animate={{ opacity: 1 }}\n className={`fixed inset-0 ${classNames.backdrop || \"\"}`}\n exit={{ opacity: 0 }}\n initial={{ opacity: 0 }}\n key=\"stacksheet-backdrop\"\n onClick={\n config.closeOnBackdrop && config.dismissible\n ? () => closeWith(\"backdrop\")\n : undefined\n }\n style={backdropStyle}\n transition={spring}\n />\n )}\n </AnimatePresence>\n )}\n\n {/* Panel clip container — always rendered, invisible when empty */}\n <RemoveScroll enabled={shouldLockScroll} forwardProps>\n <div\n className=\"pointer-events-none fixed inset-0 overflow-hidden\"\n style={{ zIndex: config.zIndex + 1 }}\n >\n <AnimatePresence onExitComplete={handleExitComplete}>\n {stack.map((item, index) => {\n const depth = stack.length - 1 - index;\n const isTop = depth === 0;\n const isNested = index > 0;\n // Keep one extra hidden panel mounted as a warm buffer.\n // Without this, popping from deep stacks can mount content on the\n // same frame it becomes visible, which can cause a reverse jank.\n const shouldRender = depth <= config.stacking.renderThreshold;\n\n // Ad-hoc components take priority, then fall back to sheets map\n const Content = (componentMap.get(item.type) ??\n sheets[item.type as keyof TMap]) as\n | ComponentType<Record<string, unknown>>\n | undefined;\n\n return (\n <SheetPanel\n activeSnapIndex={activeSnapIndex}\n Content={Content}\n classNames={classNames}\n close={close}\n config={config}\n depth={depth}\n exitSpring={exitSpring}\n index={index}\n isNested={isNested}\n isTop={isTop}\n item={item}\n key={item.id}\n onSnap={handleSnap}\n pop={pop}\n renderHeader={renderHeader}\n shouldRender={shouldRender}\n side={side}\n slideFrom={slideFrom}\n slideTarget={slideTarget}\n snapHeights={snapHeights}\n spring={spring}\n stackSpring={stackSpring}\n swipeClose={swipeClose}\n swipePop={swipePop}\n />\n );\n })}\n </AnimatePresence>\n </div>\n </RemoveScroll>\n </>\n );\n}\n\n// ── Helpers ─────────────────────────────────────\n\nfunction getInitialRadius(side: Side): Record<string, number> {\n if (side === \"bottom\") {\n return {\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n };\n }\n return { borderRadius: 0 };\n}\n\n// Collins-style layered shadows — soft, diffused, multi-stop.\nconst SHADOW_SM =\n \"0px 2px 5px 0px rgba(0,0,0,0.11), 0px 9px 9px 0px rgba(0,0,0,0.1), 0px 21px 13px 0px rgba(0,0,0,0.06)\";\nconst SHADOW_LG =\n \"0px 23px 52px 0px rgba(0,0,0,0.08), 0px 94px 94px 0px rgba(0,0,0,0.07), 0px 211px 127px 0px rgba(0,0,0,0.04)\";\n\nfunction getShadow(_side: Side, isNested: boolean): string {\n return isNested ? SHADOW_SM : SHADOW_LG;\n}\n","/** Inline SVG icons — no external dependency */\n\nexport function ArrowLeftIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={16}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n viewBox=\"0 0 24 24\"\n width={16}\n >\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n );\n}\n\nexport function XIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={16}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n viewBox=\"0 0 24 24\"\n width={16}\n >\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport type { ResolvedConfig, Side } from \"./types\";\n\n/**\n * Returns true when viewport width is at or below the breakpoint.\n * SSR-safe: defaults to false (desktop).\n */\nexport function useIsMobile(breakpoint: number): boolean {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);\n setIsMobile(mql.matches);\n\n const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches);\n mql.addEventListener(\"change\", handler);\n return () => mql.removeEventListener(\"change\", handler);\n }, [breakpoint]);\n\n return isMobile;\n}\n\n/** Resolve the current side from config + viewport. */\nexport function useResolvedSide(config: ResolvedConfig): Side {\n const isMobile = useIsMobile(config.breakpoint);\n return isMobile ? config.side.mobile : config.side.desktop;\n}\n","import { createContext, useContext } from \"react\";\nimport type { Side } from \"./types\";\n\nexport interface SheetPanelContextValue {\n /** Close the entire sheet stack */\n close: () => void;\n /** Pop the top sheet (go back one level) */\n back: () => void;\n /** Whether the stack has more than one sheet */\n isNested: boolean;\n /** Whether this is the top (active) sheet */\n isTop: boolean;\n /** Unique ID prefix for this panel (for aria-labelledby linking) */\n panelId: string;\n /** Current resolved side (left/right/bottom) */\n side: Side;\n}\n\nexport const SheetPanelContext = createContext<SheetPanelContextValue | null>(\n null\n);\n\n/**\n * Access the current sheet panel's context.\n * Must be called inside a component rendered by the sheet stack.\n */\nexport function useSheetPanel(): SheetPanelContextValue {\n const ctx = useContext(SheetPanelContext);\n if (!ctx) {\n throw new Error(\n \"Sheet.* components must be used inside a sheet panel. \" +\n \"They should be rendered by a component opened via actions.open(), push(), etc.\"\n );\n }\n return ctx;\n}\n","import type { SnapPoint } from \"./types\";\n\nconst SNAP_POINT_RE = /^(\\d+(?:\\.\\d+)?)(px|rem|em|vh|%)$/;\n\n/**\n * Resolve a snap point value to pixels given the viewport height.\n * - number 0-1: fraction of viewport (0.5 → 50% of vh)\n * - number > 1: pixel value (300 → 300px)\n * - string: parsed via regex for CSS unit support\n */\nfunction resolveSnapPointPx(point: SnapPoint, viewportHeight: number): number {\n if (typeof point === \"number\") {\n return point <= 1 ? point * viewportHeight : point;\n }\n\n if (typeof point === \"string\") {\n const match = point.match(SNAP_POINT_RE);\n if (!match?.[1]) {\n return 0;\n }\n const value = Number.parseFloat(match[1]);\n const unit = match[2];\n switch (unit) {\n case \"px\":\n return value;\n case \"rem\":\n case \"em\":\n return (\n value *\n Number.parseFloat(getComputedStyle(document.documentElement).fontSize)\n );\n case \"vh\":\n case \"%\":\n return (value / 100) * viewportHeight;\n default:\n return 0;\n }\n }\n\n return 0;\n}\n\n/**\n * Resolve all snap points to sorted pixel heights (ascending).\n * Returns an array of heights in px that the drawer should snap to.\n */\nexport function resolveSnapPoints(\n points: SnapPoint[],\n viewportHeight: number\n): number[] {\n if (points.length === 0) {\n return [];\n }\n\n const resolved = points\n .map((p) => resolveSnapPointPx(p, viewportHeight))\n .filter((px) => px > 0);\n\n // Sort ascending (smallest snap point first)\n resolved.sort((a, b) => a - b);\n\n // Deduplicate (1px tolerance)\n const deduped: number[] = [];\n for (const px of resolved) {\n const last = deduped.at(-1);\n if (last === undefined || Math.abs(px - last) > 1) {\n deduped.push(px);\n }\n }\n\n return deduped;\n}\n\n/** Velocity threshold (px/ms) for skipping intermediate snap points */\nconst SNAP_VELOCITY_THRESHOLD = 0.4;\n\n/** Max velocity to consider for snap offset calculation */\nconst MAX_SNAP_VELOCITY = 2;\n\n/** Multiplier to convert velocity to pixel offset for snap target */\nconst SNAP_VELOCITY_MULTIPLIER = 150;\n\n/**\n * Given the current drag offset (from fully open), resolved snap heights,\n * the panel height, and release velocity, find the best snap point index.\n *\n * `dragOffset` is positive in the dismiss direction (downward for bottom sheets).\n * Snap heights are \"how tall the drawer should be\" (ascending order).\n *\n * Returns -1 if the gesture indicates full dismissal.\n */\nexport function findSnapTarget(\n dragOffset: number,\n panelHeight: number,\n snapHeights: number[],\n velocity: number,\n currentIndex: number,\n sequential: boolean\n): number {\n if (snapHeights.length === 0) {\n return -1;\n }\n\n // Convert snap heights to offsets from fully open (panelHeight = 0 offset)\n // A smaller snap height = larger offset from top = more closed\n const snapOffsets = snapHeights.map((h) => panelHeight - h);\n\n // Current position = dragOffset from fully open\n const currentPos = dragOffset;\n\n if (sequential) {\n // Sequential mode: only snap to adjacent points\n const direction = velocity > 0 ? 1 : -1; // positive = dismissing\n const nextIndex = currentIndex - direction; // snap heights are ascending, so -1 = more closed\n if (nextIndex < 0) {\n return -1; // dismiss\n }\n if (nextIndex >= snapHeights.length) {\n return snapHeights.length - 1; // fully open\n }\n return nextIndex;\n }\n\n // Velocity-based: project position forward based on velocity\n const velocityOffset =\n Math.abs(velocity) >= SNAP_VELOCITY_THRESHOLD\n ? Math.min(Math.max(velocity, -MAX_SNAP_VELOCITY), MAX_SNAP_VELOCITY) *\n SNAP_VELOCITY_MULTIPLIER\n : 0;\n\n const projectedPos = currentPos + velocityOffset;\n\n // Find nearest snap offset to projected position\n const first = snapOffsets[0] ?? 0;\n let bestIndex = 0;\n let bestDist = Math.abs(projectedPos - first);\n\n for (let i = 1; i < snapOffsets.length; i++) {\n const offset = snapOffsets[i] ?? 0;\n const dist = Math.abs(projectedPos - offset);\n if (dist < bestDist) {\n bestDist = dist;\n bestIndex = i;\n }\n }\n\n // Check if dismissal is closer than (or equal to) any snap point.\n // Ties favor dismiss — the user dragged past the last snap point.\n const dismissDist = Math.abs(projectedPos - panelHeight);\n if (dismissDist <= bestDist) {\n return -1;\n }\n\n return bestIndex;\n}\n\n/**\n * Get the Y offset for a snap point relative to fully open (0 offset).\n * Returns the number of pixels the drawer should be translated down from fully open.\n */\nexport function getSnapOffset(\n snapIndex: number,\n snapHeights: number[],\n panelHeight: number\n): number {\n if (snapIndex < 0 || snapIndex >= snapHeights.length) {\n return 0;\n }\n const targetHeight = snapHeights[snapIndex] ?? 0;\n return panelHeight - targetHeight;\n}\n","import type { CSSProperties } from \"react\";\nimport type { ResolvedConfig, Side, StackingConfig } from \"./types\";\n\n// ── Depth transforms ────────────────────────────\n\nexport interface StackTransform {\n scale: number;\n offset: number;\n opacity: number;\n borderRadius: number;\n}\n\n/**\n * Compute visual transforms for a panel at a given depth.\n * depth=0 is the top (foreground) panel.\n * Panels beyond renderThreshold are clamped to the edge position and faded out.\n */\nexport function getStackTransform(\n depth: number,\n stacking: StackingConfig\n): StackTransform {\n if (depth <= 0) {\n return { scale: 1, offset: 0, opacity: 1, borderRadius: 0 };\n }\n\n const beyondThreshold = depth >= stacking.renderThreshold;\n // Clamp visual depth so panels beyond threshold stay at the edge position\n const visualDepth = beyondThreshold ? stacking.renderThreshold - 1 : depth;\n\n return {\n scale: Math.max(0.5, 1 - visualDepth * stacking.scaleStep),\n offset: visualDepth * stacking.offsetStep,\n opacity: beyondThreshold\n ? 0\n : Math.max(0, 1 - visualDepth * stacking.opacityStep),\n borderRadius: stacking.radius,\n };\n}\n\n/**\n * Border radius values for the animate target.\n * Must be animated (not static CSS) so Motion applies scale correction\n * when panels are scaled. See: https://motion.dev/docs/react-layout-animations#scale-correction\n */\nexport function getAnimatedBorderRadius(\n side: Side,\n depth: number,\n stacking: StackingConfig\n): Record<string, number> {\n if (side === \"bottom\") {\n const radius = depth > 0 ? stacking.radius : 16;\n return {\n borderTopLeftRadius: radius,\n borderTopRightRadius: radius,\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n };\n }\n\n // Left/right panels: stacked panels get uniform radius, top panel gets none\n if (depth > 0) {\n return { borderRadius: stacking.radius };\n }\n return { borderRadius: 0 };\n}\n\n// ── Slide directions ────────────────────────────\n\nexport interface SlideValues {\n x?: string | number;\n y?: string | number;\n}\n\n/** Motion initial/exit values for sliding from the given side. */\nexport function getSlideFrom(side: Side): SlideValues {\n switch (side) {\n case \"right\":\n return { x: \"100%\" };\n case \"left\":\n return { x: \"-100%\" };\n case \"bottom\":\n return { y: \"100%\" };\n default:\n return { x: \"100%\" };\n }\n}\n\n/** Motion animate target — the resting position. */\nexport function getSlideTarget(): SlideValues {\n return { x: 0, y: 0 };\n}\n\n/** Translate offset that pushes stacked panels away from the stack edge. */\nexport function getStackOffset(\n side: Side,\n offset: number\n): { x?: number; y?: number } {\n if (offset === 0) {\n return {};\n }\n switch (side) {\n case \"right\":\n return { x: -offset };\n case \"left\":\n return { x: offset };\n case \"bottom\":\n return { y: -offset };\n default:\n return {};\n }\n}\n\n// ── Transform origin ────────────────────────────\n\n/** Opposite-side origin so stacked panels recede away from the stack edge. */\nfunction getTransformOrigin(side: Side): string {\n if (side === \"right\") {\n return \"left center\";\n }\n if (side === \"left\") {\n return \"right center\";\n }\n return \"center top\";\n}\n\n// ── Panel positioning ───────────────────────────\n\n/**\n * Fixed-position styles for a panel, accounting for side, width, and depth.\n */\nexport function getPanelStyles(\n side: Side,\n config: ResolvedConfig,\n _depth: number,\n index: number\n): CSSProperties {\n const { width, maxWidth, zIndex } = config;\n const base: CSSProperties = {\n position: \"fixed\",\n zIndex: zIndex + 10 + index,\n display: \"flex\",\n flexDirection: \"column\",\n willChange: \"transform\",\n transformOrigin: getTransformOrigin(side),\n };\n\n if (side === \"bottom\") {\n return {\n ...base,\n left: 0,\n right: 0,\n bottom: 0,\n maxHeight: \"85vh\",\n // borderRadius is animated via Motion's animate prop for scale correction\n };\n }\n\n // Left or right side panel\n const sideStyles: CSSProperties =\n side === \"right\"\n ? { top: 0, right: 0, bottom: 0 }\n : { top: 0, left: 0, bottom: 0 };\n\n return {\n ...base,\n ...sideStyles,\n width,\n maxWidth,\n };\n}\n","import { type RefObject, useCallback, useEffect, useRef } from \"react\";\nimport { findSnapTarget } from \"./snap-points\";\nimport type { Side } from \"./types\";\n\nexport interface DragConfig {\n /** Enable drag-to-dismiss. Default: true */\n enabled: boolean;\n /** Fraction of panel dimension to trigger close (0-1). Default: 0.25 */\n closeThreshold: number;\n /** Velocity threshold (px/ms) to trigger close. Default: 0.5 */\n velocityThreshold: number;\n /** Side the panel is on — determines drag direction */\n side: Side;\n /** Callback when drag ends and close should fire */\n onClose: () => void;\n /** Callback when drag ends and pop should fire */\n onPop: () => void;\n /** Whether the stack has >1 sheet (swipe pops instead of closing) */\n isNested: boolean;\n /** Resolved snap point heights in px (sorted ascending). Empty = no snap points. */\n snapHeights: number[];\n /** Current active snap point index */\n activeSnapIndex: number;\n /** Called when snap target changes on release */\n onSnap: (index: number) => void;\n /** When true, can't skip intermediate snap points */\n sequential: boolean;\n}\n\nexport interface DragState {\n /** Current drag offset in the dismiss direction (px) */\n offset: number;\n /** Whether a drag is currently active */\n isDragging: boolean;\n}\n\n/** Elements that should never initiate a drag */\nconst INTERACTIVE_TAGS = new Set([\n \"INPUT\",\n \"TEXTAREA\",\n \"SELECT\",\n \"BUTTON\",\n \"A\",\n]);\n\nfunction isInteractiveElement(el: Element): boolean {\n if (INTERACTIVE_TAGS.has(el.tagName)) {\n return true;\n }\n if ((el as HTMLElement).isContentEditable) {\n return true;\n }\n // Children of interactive elements (e.g. SVG inside button, span inside link)\n if (el.closest(\"button, a, input, textarea, select, [contenteditable]\")) {\n return true;\n }\n if (el.closest(\"[data-stacksheet-no-drag]\")) {\n return true;\n }\n return false;\n}\n\n/**\n * Walk up from `el` to find the nearest scrollable ancestor.\n * Returns null if nothing is scrollable in the dismiss axis.\n */\nfunction findScrollableAncestor(el: Element, axis: \"x\" | \"y\"): Element | null {\n let current: Element | null = el;\n while (current) {\n if (current instanceof HTMLElement) {\n const style = getComputedStyle(current);\n const overflow = axis === \"y\" ? style.overflowY : style.overflowX;\n if (overflow === \"auto\" || overflow === \"scroll\") {\n const scrollable =\n axis === \"y\"\n ? current.scrollHeight > current.clientHeight\n : current.scrollWidth > current.clientWidth;\n if (scrollable) {\n return current;\n }\n }\n }\n current = current.parentElement;\n }\n return null;\n}\n\n/**\n * Check if a scrollable element is at its edge in the dismiss direction.\n * For bottom sheets (sign=1, axis=y), \"at edge\" means scrolled to top.\n * For left panels (sign=-1, axis=x), \"at edge\" means scrolled to right end.\n */\nfunction isAtScrollEdge(el: Element, axis: \"x\" | \"y\", sign: 1 | -1): boolean {\n if (axis === \"y\") {\n // Dismiss down (sign=1): at edge when scrollTop ≈ 0\n // Dismiss up (sign=-1): at edge when scrolled to bottom\n return sign === 1\n ? el.scrollTop <= 0\n : el.scrollTop + el.clientHeight >= el.scrollHeight - 1;\n }\n return sign === 1\n ? el.scrollLeft <= 0\n : el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;\n}\n\n/**\n * Get the dismiss direction axis and sign for a given side.\n * - right panel → dismiss by dragging right (+x)\n * - left panel → dismiss by dragging left (-x)\n * - bottom panel → dismiss by dragging down (+y)\n */\nfunction getDismissAxis(side: Side): {\n axis: \"x\" | \"y\";\n sign: 1 | -1;\n} {\n switch (side) {\n case \"right\":\n return { axis: \"x\", sign: 1 };\n case \"left\":\n return { axis: \"x\", sign: -1 };\n case \"bottom\":\n return { axis: \"y\", sign: 1 };\n default:\n return { axis: \"x\", sign: 1 };\n }\n}\n\n/** Dead zone in px before committing to drag vs text selection */\nconst DEAD_ZONE = 10;\n\n/** Max angle (degrees) from dismiss axis to qualify as drag intent */\nconst MAX_ANGLE_DEG = 35;\n\n/** Rubber-band resistance factor for dragging past resting position */\nconst RUBBER_BAND_FACTOR = 0.6;\n\n/**\n * Decide whether a gesture past the dead zone qualifies as a dismiss drag.\n * Returns \"drag\" if it's a valid dismiss gesture, \"none\" if it's off-axis\n * or moving in the wrong direction.\n */\nfunction classifyGesture(\n dx: number,\n dy: number,\n axis: \"x\" | \"y\",\n sign: 1 | -1\n): \"drag\" | \"none\" {\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n\n // Compute angle between movement vector and dismiss axis\n let angleDeg: number;\n if (axis === \"y\") {\n angleDeg = absDy === 0 ? 90 : (Math.atan(absDx / absDy) * 180) / Math.PI;\n } else {\n angleDeg = absDx === 0 ? 90 : (Math.atan(absDy / absDx) * 180) / Math.PI;\n }\n\n if (angleDeg > MAX_ANGLE_DEG) {\n return \"none\";\n }\n\n // Must be moving in the dismiss direction\n const moveInAxis = axis === \"x\" ? dx : dy;\n if (moveInAxis * sign < 0) {\n return \"none\";\n }\n\n return \"drag\";\n}\n\nfunction getPanelDimension(\n panel: HTMLDivElement | null,\n axis: \"x\" | \"y\"\n): number {\n if (!panel) {\n return 300;\n }\n return axis === \"x\" ? panel.offsetWidth : panel.offsetHeight;\n}\n\n/**\n * Hook that manages drag-to-dismiss for a sheet panel.\n *\n * Gesture pipeline:\n * 1. Dead zone (10px) — ignores micro-movements\n * 2. Angle check (35°) — must be roughly aligned with dismiss axis\n * 3. Scroll conflict — yields to scrollable containers not at edge\n * 4. Commit — drag is active, applies offset via `onDragUpdate`\n * 5. Release — velocity + threshold determine close/snap/bounce-back\n *\n * Opposite-direction drag uses √(offset) damping for elastic\n * rubber-band resistance (same physics as iOS over-scroll).\n *\n * When `snapHeights` is provided, release targeting uses\n * `findSnapTarget()` instead of the simple threshold check.\n */\nexport function useDrag(\n panelRef: RefObject<HTMLDivElement | null>,\n config: DragConfig,\n onDragUpdate: (state: DragState) => void\n) {\n const startRef = useRef<{ x: number; y: number; time: number } | null>(null);\n const committedRef = useRef<\"drag\" | \"none\" | null>(null);\n const offsetRef = useRef(0);\n const scrollTargetRef = useRef<Element | null>(null);\n\n const { axis, sign } = getDismissAxis(config.side);\n\n const handlePointerDown = useCallback(\n (e: PointerEvent) => {\n if (!config.enabled) {\n return;\n }\n // Only primary button\n if (e.button !== 0) {\n return;\n }\n // Check target element\n const target = e.target as Element;\n if (!target) {\n return;\n }\n\n // Allow drag from handle elements always\n const isHandle = !!target.closest(\"[data-stacksheet-handle]\");\n\n // For non-handle areas, check if the target is interactive\n if (!isHandle && isInteractiveElement(target)) {\n return;\n }\n\n // Track nearest scrollable ancestor — checked at commit time\n scrollTargetRef.current = isHandle\n ? null\n : findScrollableAncestor(target, axis);\n\n startRef.current = { x: e.clientX, y: e.clientY, time: Date.now() };\n committedRef.current = null;\n offsetRef.current = 0;\n\n // Capture pointer for reliable move/up outside the element\n (e.currentTarget as HTMLElement)?.setPointerCapture?.(e.pointerId);\n },\n [config.enabled, axis]\n );\n\n const handlePointerMove = useCallback(\n (e: PointerEvent) => {\n if (!startRef.current) {\n return;\n }\n\n const dx = e.clientX - startRef.current.x;\n const dy = e.clientY - startRef.current.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n // Still in dead zone — don't commit yet\n if (committedRef.current === null && dist < DEAD_ZONE) {\n return;\n }\n\n // Commit decision: check direction + scroll state\n if (committedRef.current === null) {\n const gesture = classifyGesture(dx, dy, axis, sign);\n if (gesture === \"none\") {\n committedRef.current = \"none\";\n startRef.current = null;\n return;\n }\n // If inside a scrollable container that isn't at its edge\n // in the dismiss direction, let the browser scroll instead.\n const scrollEl = scrollTargetRef.current;\n if (scrollEl && !isAtScrollEdge(scrollEl, axis, sign)) {\n committedRef.current = \"none\";\n startRef.current = null;\n return;\n }\n committedRef.current = \"drag\";\n }\n\n if (committedRef.current !== \"drag\") {\n return;\n }\n\n // Calculate offset in dismiss direction\n const rawOffset = axis === \"x\" ? dx : dy;\n const directional = rawOffset * sign;\n\n // Dismiss direction: linear movement. Opposite direction: √ damping\n // for elastic rubber-band resistance (same math as iOS over-scroll).\n const clampedOffset =\n directional >= 0\n ? directional\n : -Math.sqrt(Math.abs(directional)) * RUBBER_BAND_FACTOR;\n\n offsetRef.current = clampedOffset;\n onDragUpdate({ offset: clampedOffset, isDragging: true });\n\n // Prevent text selection during active drag\n e.preventDefault();\n },\n [axis, sign, onDragUpdate]\n );\n\n const dismiss = useCallback(() => {\n if (config.isNested) {\n config.onPop();\n } else {\n config.onClose();\n }\n onDragUpdate({ offset: 0, isDragging: false });\n }, [config, onDragUpdate]);\n\n const handlePointerUp = useCallback(\n (_e: PointerEvent) => {\n if (!startRef.current || committedRef.current !== \"drag\") {\n startRef.current = null;\n committedRef.current = null;\n scrollTargetRef.current = null;\n return;\n }\n\n const offset = Math.max(0, offsetRef.current);\n const elapsed = Date.now() - startRef.current.time;\n const velocity = elapsed > 0 ? offset / elapsed : 0;\n\n startRef.current = null;\n committedRef.current = null;\n offsetRef.current = 0;\n scrollTargetRef.current = null;\n\n const panelSize = getPanelDimension(panelRef.current, axis);\n\n // Snap points mode\n if (config.snapHeights.length > 0) {\n const targetIndex = findSnapTarget(\n offset,\n panelSize,\n config.snapHeights,\n velocity,\n config.activeSnapIndex,\n config.sequential\n );\n if (targetIndex === -1) {\n dismiss();\n } else {\n config.onSnap(targetIndex);\n onDragUpdate({ offset: 0, isDragging: false });\n }\n return;\n }\n\n // Standard mode: threshold-based close\n const pastThreshold = offset / panelSize > config.closeThreshold;\n const fastEnough = velocity > config.velocityThreshold;\n if (pastThreshold || fastEnough) {\n dismiss();\n } else {\n onDragUpdate({ offset: 0, isDragging: false });\n }\n },\n [panelRef, axis, config, onDragUpdate, dismiss]\n );\n\n const handlePointerCancel = useCallback(() => {\n startRef.current = null;\n committedRef.current = null;\n offsetRef.current = 0;\n scrollTargetRef.current = null;\n onDragUpdate({ offset: 0, isDragging: false });\n }, [onDragUpdate]);\n\n // Attach pointer events to the panel element\n useEffect(() => {\n const el = panelRef.current;\n if (!(el && config.enabled)) {\n return;\n }\n\n el.addEventListener(\"pointerdown\", handlePointerDown);\n el.addEventListener(\"pointermove\", handlePointerMove);\n el.addEventListener(\"pointerup\", handlePointerUp);\n el.addEventListener(\"pointercancel\", handlePointerCancel);\n\n return () => {\n el.removeEventListener(\"pointerdown\", handlePointerDown);\n el.removeEventListener(\"pointermove\", handlePointerMove);\n el.removeEventListener(\"pointerup\", handlePointerUp);\n el.removeEventListener(\"pointercancel\", handlePointerCancel);\n };\n }, [\n panelRef,\n config.enabled,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n ]);\n}\n","declare const process: undefined | { env?: { NODE_ENV?: string } };\n\nimport type { ComponentType } from \"react\";\nimport { createStore, type StoreApi } from \"zustand\";\nimport type {\n ResolvedConfig,\n SheetActions,\n SheetItem,\n StacksheetSnapshot,\n} from \"./types\";\n\n// biome-ignore lint/suspicious/noExplicitAny: maps store heterogeneous components — type safety is at the call site\ntype AnyComponent = ComponentType<any>;\n\ntype StoreState<TMap extends object> = StacksheetSnapshot<TMap> &\n SheetActions<TMap>;\n\n/** Return type of createSheetStore — store plus ad-hoc component maps */\nexport interface SheetStoreBundle<TMap extends object> {\n store: StoreApi<StoreState<TMap>>;\n /** Component → generated type key (dedup) */\n componentRegistry: Map<AnyComponent, string>;\n /** Generated type key → Component (for renderer lookup) */\n componentMap: Map<string, AnyComponent>;\n}\n\n// ── Ad-hoc helpers ──────────────────────────────\n\n/**\n * Dev-mode warning: detect likely inline arrow functions passed as ad-hoc components.\n * When a new component reference has the same displayName/name as an existing one,\n * it's almost always an inline arrow being re-created every render.\n */\nfunction warnInlineComponent(\n component: AnyComponent,\n componentRegistry: Map<AnyComponent, string>,\n warnedNames: Set<string>\n): void {\n if (\n typeof process === \"undefined\" ||\n process?.env?.NODE_ENV === \"production\"\n ) {\n return;\n }\n\n const name = component.displayName || component.name;\n if (!name) {\n return;\n }\n if (warnedNames.has(name)) {\n return;\n }\n\n for (const [existing, key] of componentRegistry) {\n const existingName = existing.displayName || existing.name;\n if (existingName === name) {\n warnedNames.add(name);\n console.warn(\n `[stacksheet] A new component reference with name \"${name}\" was registered ` +\n `(key: ${key}), but a different reference with the same name already exists. ` +\n `This usually means you're passing an inline arrow function (e.g. ` +\n \"open(() => <MySheet />)). Define the component outside of render to avoid \" +\n \"memory leaks and broken navigate() same-type detection.\"\n );\n return;\n }\n }\n}\n\n/**\n * If `first` is a function (component), register it and return { type, id, data }.\n * Otherwise, pass through the string-based (type, id, data) args unchanged.\n */\nfunction resolveArgs(\n componentRegistry: Map<AnyComponent, string>,\n componentMap: Map<string, AnyComponent>,\n getNextKey: () => string,\n warnedNames: Set<string>,\n first: unknown,\n second: unknown,\n third: unknown\n): { type: string; id: string; data: Record<string, unknown> } {\n if (typeof first === \"function\") {\n const component = first as AnyComponent;\n\n let typeKey = componentRegistry.get(component);\n if (!typeKey) {\n warnInlineComponent(component, componentRegistry, warnedNames);\n typeKey = getNextKey();\n componentRegistry.set(component, typeKey);\n componentMap.set(typeKey, component);\n }\n\n if (typeof second === \"string\") {\n return {\n type: typeKey,\n id: second,\n data: (third ?? {}) as Record<string, unknown>,\n };\n }\n return {\n type: typeKey,\n id: crypto.randomUUID(),\n data: (second ?? {}) as Record<string, unknown>,\n };\n }\n\n return {\n type: first as string,\n id: second as string,\n data: (third ?? {}) as Record<string, unknown>,\n };\n}\n\n/** Pre-resolved args — skips resolveArgs entirely */\ninterface ResolvedItem {\n type: string;\n id: string;\n data: Record<string, unknown>;\n}\n\n/**\n * Create an isolated Zustand store for a sheet stack instance.\n *\n * Returns a store bundle containing the Zustand store plus two maps\n * that track ad-hoc (component-direct) registrations:\n * - `componentRegistry` — maps `ComponentType` → generated type key (dedup)\n * - `componentMap` — maps generated type key → `ComponentType` (renderer lookup)\n *\n * The ad-hoc counter is scoped per instance to prevent identity leaks across\n * multiple `createStacksheet()` calls or test runs.\n */\nexport function createSheetStore<TMap extends object>(\n config: ResolvedConfig\n): SheetStoreBundle<TMap> {\n type Item = SheetItem<Extract<keyof TMap, string>>;\n\n const componentRegistry = new Map<AnyComponent, string>();\n const componentMap = new Map<string, AnyComponent>();\n\n // Per-instance counter (not module-level) — prevents identity leaks across instances/tests\n let adhocCounter = 0;\n function getNextKey() {\n return `__adhoc_${adhocCounter++}`;\n }\n\n // Set of component names already warned about (avoid log spam)\n const warnedNames = new Set<string>();\n\n function resolve(first: unknown, second: unknown, third: unknown) {\n return resolveArgs(\n componentRegistry,\n componentMap,\n getNextKey,\n warnedNames,\n first,\n second,\n third\n );\n }\n\n const store = createStore<StoreState<TMap>>()((set, get) => {\n // ── Internal resolved methods (no double-resolution) ──\n\n function _openResolved({ type, id, data }: ResolvedItem) {\n set({\n stack: [{ id, type, data } as Item],\n isOpen: true,\n });\n }\n\n function _pushResolved({ type, id, data }: ResolvedItem) {\n set((state) => {\n const item = { id, type, data } as Item;\n if (\n Number.isFinite(config.maxDepth) &&\n state.stack.length >= config.maxDepth\n ) {\n return {\n stack: [...state.stack.slice(0, -1), item],\n isOpen: true,\n };\n }\n return {\n stack: [...state.stack, item],\n isOpen: true,\n };\n });\n }\n\n function _replaceResolved({ type, id, data }: ResolvedItem) {\n set((state) => {\n const item = { id, type, data } as Item;\n if (state.stack.length === 0) {\n return { stack: [item], isOpen: true };\n }\n return {\n stack: [...state.stack.slice(0, -1), item],\n isOpen: true,\n };\n });\n }\n\n return {\n stack: [],\n isOpen: false,\n\n open(first: unknown, second?: unknown, third?: unknown) {\n _openResolved(resolve(first, second, third));\n },\n\n push(first: unknown, second?: unknown, third?: unknown) {\n _pushResolved(resolve(first, second, third));\n },\n\n replace(first: unknown, second?: unknown, third?: unknown) {\n _replaceResolved(resolve(first, second, third));\n },\n\n swap(first: unknown, second?: unknown) {\n let type: string;\n let data: Record<string, unknown>;\n\n if (typeof first === \"function\") {\n const component = first as AnyComponent;\n let typeKey = componentRegistry.get(component);\n if (!typeKey) {\n warnInlineComponent(component, componentRegistry, warnedNames);\n typeKey = getNextKey();\n componentRegistry.set(component, typeKey);\n componentMap.set(typeKey, component);\n }\n type = typeKey;\n data = (second ?? {}) as Record<string, unknown>;\n } else {\n type = first as string;\n data = (second ?? {}) as Record<string, unknown>;\n }\n\n set((state) => {\n const top = state.stack.at(-1);\n if (!top) {\n return state;\n }\n const newStack = [...state.stack];\n newStack[newStack.length - 1] = { id: top.id, type, data } as Item;\n return { stack: newStack };\n });\n },\n\n navigate(first: unknown, second?: unknown, third?: unknown) {\n const resolved = resolve(first, second, third);\n const { stack } = get();\n const top = stack.at(-1);\n\n if (stack.length === 0) {\n _openResolved(resolved);\n return;\n }\n\n // For ad-hoc components, check if the top item's type maps to the same\n // component in the registry. For string types, compare directly.\n let isSameType = top?.type === resolved.type;\n if (!isSameType && typeof first === \"function\") {\n const topComponent = componentMap.get(top?.type ?? \"\");\n isSameType = topComponent === first;\n }\n\n if (isSameType) {\n _replaceResolved(resolved);\n return;\n }\n\n _pushResolved(resolved);\n },\n\n setData(first: unknown, second?: unknown, third?: unknown) {\n // setData always has an id: (type, id, data) or (Component, id, data)\n const { id, data } = resolve(first, second, third);\n set((state) => {\n const idx = state.stack.findIndex((item) => item.id === id);\n if (idx === -1) {\n return state;\n }\n const updated = [...state.stack];\n updated[idx] = { ...updated[idx], data } as Item;\n return { stack: updated };\n });\n },\n\n remove(id) {\n set((state) => {\n const next = state.stack.filter((item) => item.id !== id);\n if (next.length === state.stack.length) {\n return state;\n }\n if (next.length === 0) {\n return { stack: [], isOpen: false };\n }\n return { stack: next };\n });\n },\n\n pop() {\n set((state) => {\n if (state.stack.length <= 1) {\n return { stack: [], isOpen: false };\n }\n return { stack: state.stack.slice(0, -1), isOpen: true };\n });\n },\n\n close() {\n set({ stack: [], isOpen: false });\n },\n };\n });\n\n return { store, componentRegistry, componentMap };\n}\n","import {\n Root as ScrollAreaRoot,\n Scrollbar as ScrollAreaScrollbar,\n Thumb as ScrollAreaThumb,\n Viewport as ScrollAreaViewport,\n} from \"@radix-ui/react-scroll-area\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { ArrowLeftIcon, XIcon } from \"./icons\";\nimport { useSheetPanel } from \"./panel-context\";\n\n// ── Sheet.Handle ────────────────────────────────\n\nexport interface SheetHandleProps {\n /** Render as child element, merging props */\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom handle content. Defaults to a centered grab bar. */\n children?: ReactNode;\n}\n\nfunction SheetHandle({\n asChild,\n className,\n style,\n children,\n}: SheetHandleProps) {\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n className={`flex shrink-0 cursor-grab touch-none items-center justify-center pt-4 pb-1 ${className ?? \"\"}`}\n data-stacksheet-handle=\"\"\n style={style}\n >\n {children ?? <div className=\"h-1 w-9 rounded-sm bg-current/25\" />}\n </Comp>\n );\n}\n\n// ── Sheet.Header ────────────────────────────────\n\nexport interface SheetHeaderProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetHeader({\n asChild,\n className,\n style,\n children,\n}: SheetHeaderProps) {\n const Comp = asChild ? Slot : \"header\";\n return (\n <Comp\n className={`flex h-14 shrink-0 items-center justify-between border-b px-6 ${className ?? \"\"}`}\n style={style}\n >\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Title ─────────────────────────────────\n\nexport interface SheetTitleProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetTitle({ asChild, className, style, children }: SheetTitleProps) {\n const { panelId } = useSheetPanel();\n const Comp = asChild ? Slot : \"h2\";\n return (\n <Comp\n className={`font-semibold text-sm ${className ?? \"\"}`}\n id={`${panelId}-title`}\n style={style}\n >\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Description ───────────────────────────\n\nexport interface SheetDescriptionProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetDescription({\n asChild,\n className,\n style,\n children,\n}: SheetDescriptionProps) {\n const { panelId } = useSheetPanel();\n const Comp = asChild ? Slot : \"p\";\n return (\n <Comp className={className} id={`${panelId}-desc`} style={style}>\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Body ──────────────────────────────────\n\nexport interface SheetBodyProps {\n /** When true, renders child element directly instead of ScrollArea */\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetBody({ asChild, className, style, children }: SheetBodyProps) {\n if (asChild) {\n return (\n <Slot\n className={`relative min-h-0 flex-1 ${className ?? \"\"}`}\n data-stacksheet-no-drag=\"\"\n style={style}\n >\n {children}\n </Slot>\n );\n }\n\n return (\n <ScrollAreaRoot\n className={`relative min-h-0 flex-1 overflow-hidden ${className ?? \"\"}`}\n data-stacksheet-no-drag=\"\"\n style={style}\n >\n <ScrollAreaViewport className=\"h-full w-full overscroll-contain\">\n {children}\n </ScrollAreaViewport>\n <ScrollAreaScrollbar\n className=\"flex w-2 touch-none select-none p-0.5\"\n orientation=\"vertical\"\n >\n <ScrollAreaThumb className=\"relative flex-1 rounded bg-current/15\" />\n </ScrollAreaScrollbar>\n </ScrollAreaRoot>\n );\n}\n\n// ── Sheet.Footer ────────────────────────────────\n\nexport interface SheetFooterProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n}\n\nfunction SheetFooter({\n asChild,\n className,\n style,\n children,\n}: SheetFooterProps) {\n const Comp = asChild ? Slot : \"footer\";\n return (\n <Comp\n className={`flex shrink-0 items-center gap-2 border-t px-6 py-3 ${className ?? \"\"}`}\n style={style}\n >\n {children}\n </Comp>\n );\n}\n\n// ── Sheet.Close ─────────────────────────────────\n\nexport interface SheetCloseProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom content. Defaults to an X icon. */\n children?: ReactNode;\n}\n\nfunction SheetClose({ asChild, className, style, children }: SheetCloseProps) {\n const { close } = useSheetPanel();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n aria-label={children ? undefined : \"Close\"}\n className={`flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent p-0 text-inherit opacity-60 transition-opacity duration-150 hover:opacity-100 ${className ?? \"\"}`}\n onClick={close}\n style={style}\n type={asChild ? undefined : \"button\"}\n >\n {children ?? <XIcon />}\n </Comp>\n );\n}\n\n// ── Sheet.Back ──────────────────────────────────\n\nexport interface SheetBackProps {\n asChild?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Custom content. Defaults to an arrow-left icon. */\n children?: ReactNode;\n}\n\nfunction SheetBack({ asChild, className, style, children }: SheetBackProps) {\n const { back, isNested } = useSheetPanel();\n\n if (!isNested) {\n return null;\n }\n\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n aria-label={children ? undefined : \"Back\"}\n className={`flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border-none bg-transparent p-0 text-inherit opacity-60 transition-opacity duration-150 hover:opacity-100 ${className ?? \"\"}`}\n onClick={back}\n style={style}\n type={asChild ? undefined : \"button\"}\n >\n {children ?? <ArrowLeftIcon />}\n </Comp>\n );\n}\n\n// ── Sheet namespace ─────────────────────────────\n\n/**\n * Composable sheet parts for building custom panel layouts.\n *\n * Use with `renderHeader={false}` on the provider to opt into\n * composable mode — no auto header or scroll wrapper, full control\n * over the panel's structure.\n *\n * `Sheet.Title` and `Sheet.Description` are linked to the panel's\n * `aria-labelledby` and `aria-describedby` via matching IDs.\n */\nexport const Sheet = {\n Handle: SheetHandle,\n Header: SheetHeader,\n Title: SheetTitle,\n Description: SheetDescription,\n Body: SheetBody,\n Footer: SheetFooter,\n Close: SheetClose,\n Back: SheetBack,\n} as const;\n"],"mappings":"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","names":["createContext","useContext","useMemo","useStore","useCallback","useEffect","useRef","useState","useEffect","useEffect","jsx","useState","useEffect","useRef","useCallback","jsx","jsxs","createContext","useContext","useMemo","useStore","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@howells/stacksheet",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Typed, animated sheet stack system. Zustand store + Motion animations with Apple-style depth stacking.",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./dist/index.d.ts",
|
|
24
24
|
"default": "./dist/index.js"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
26
27
|
},
|
|
27
28
|
"publishConfig": {
|
|
28
29
|
"access": "public"
|
|
@@ -38,8 +39,11 @@
|
|
|
38
39
|
"lint": "biome check src --write --unsafe",
|
|
39
40
|
"prepack": "pnpm build",
|
|
40
41
|
"docs": "tsx scripts/generate-docs.ts",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
41
44
|
"typecheck": "tsc --noEmit",
|
|
42
|
-
"prepare": "husky"
|
|
45
|
+
"prepare": "husky",
|
|
46
|
+
"knip": "knip"
|
|
43
47
|
},
|
|
44
48
|
"keywords": [
|
|
45
49
|
"sheet",
|
|
@@ -70,9 +74,16 @@
|
|
|
70
74
|
"@types/react": "^19.0.0",
|
|
71
75
|
"@types/react-dom": "^19.0.0",
|
|
72
76
|
"husky": "^9.1.7",
|
|
77
|
+
"knip": "^5.83.1",
|
|
78
|
+
"lint-staged": "^16.2.7",
|
|
79
|
+
"next": "^16.1.6",
|
|
73
80
|
"tsup": "^8.5.1",
|
|
74
81
|
"typescript": "^5.7.0",
|
|
75
|
-
"ultracite": "^7.1.5"
|
|
82
|
+
"ultracite": "^7.1.5",
|
|
83
|
+
"vitest": "^4.0.18"
|
|
76
84
|
},
|
|
77
|
-
"packageManager": "pnpm@10.12.4"
|
|
85
|
+
"packageManager": "pnpm@10.12.4",
|
|
86
|
+
"lint-staged": {
|
|
87
|
+
"*.{js,ts,jsx,tsx,json,jsonc,css}": "biome format --write --no-errors-on-unmatched"
|
|
88
|
+
}
|
|
78
89
|
}
|