@howells/stacksheet 0.2.0 → 1.0.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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
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 Record<string, unknown>> =\n StacksheetSnapshot<TMap> & SheetActions<TMap>;\n\n/**\n * Create an isolated sheet stack instance with typed store, hooks, and provider.\n *\n * ```ts\n * const { StacksheetProvider, useSheet, useStacksheetState } = createStacksheet<{\n * \"bucket-create\": { onCreated?: (b: Bucket) => void };\n * \"bucket-edit\": { bucket: Bucket };\n * }>();\n * ```\n */\nexport function createStacksheet<TMap extends Record<string, unknown>>(\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 Record<string, unknown>> {\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 Record<string, unknown>>({\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 Record<string, unknown>> =\n StacksheetSnapshot<TMap> & SheetActions<TMap>;\n\n/** Return type of createSheetStore — store plus ad-hoc component maps */\nexport interface SheetStoreBundle<TMap extends Record<string, unknown>> {\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 Record<string, unknown>>(\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howells/stacksheet",
3
- "version": "0.2.0",
3
+ "version": "1.0.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",
@@ -14,7 +14,7 @@
14
14
  "bugs": {
15
15
  "url": "https://github.com/howells/stacksheet/issues"
16
16
  },
17
- "homepage": "https://github.com/howells/stacksheet#readme",
17
+ "homepage": "https://stacksheet.danielhowells.com",
18
18
  "files": [
19
19
  "dist"
20
20
  ],
@@ -41,21 +41,35 @@
41
41
  "animation"
42
42
  ],
43
43
  "dependencies": {
44
- "zustand": "^5.0.0",
45
- "motion": "^12.0.0"
44
+ "@radix-ui/react-portal": "^1.1.10",
45
+ "@radix-ui/react-scroll-area": "^1.2.10",
46
+ "@radix-ui/react-slot": "^1.2.4",
47
+ "focus-trap-react": "^12.0.0",
48
+ "motion": "^12.0.0",
49
+ "react-remove-scroll": "^2.7.2",
50
+ "zustand": "^5.0.0"
46
51
  },
47
52
  "peerDependencies": {
48
53
  "react": "^18.0.0 || ^19.0.0",
49
- "react-dom": "^18.0.0 || ^19.0.0"
54
+ "react-dom": "^18.0.0 || ^19.0.0",
55
+ "tailwindcss": ">=4.0.0"
50
56
  },
51
57
  "devDependencies": {
58
+ "@biomejs/biome": "^2.3.14",
52
59
  "@types/react": "^19.0.0",
53
60
  "@types/react-dom": "^19.0.0",
54
- "typescript": "^5.7.0"
61
+ "husky": "^9.1.7",
62
+ "tsup": "^8.5.1",
63
+ "typescript": "^5.7.0",
64
+ "ultracite": "^7.1.5"
55
65
  },
56
66
  "scripts": {
57
- "build": "tsc -p tsconfig.json",
58
- "dev": "tsc -p tsconfig.json -w",
59
- "typecheck": "tsc -p tsconfig.json --noEmit"
67
+ "build": "tsup",
68
+ "dev": "pnpm build && pnpm --filter stacksheet-docs dev",
69
+ "dev:lib": "tsup --watch",
70
+ "format": "ultracite fix --unsafe",
71
+ "lint": "biome check src --write --unsafe",
72
+ "docs": "tsx scripts/generate-docs.ts",
73
+ "typecheck": "tsc --noEmit"
60
74
  }
61
75
  }
package/dist/config.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { ResolvedConfig, SheetStackConfig } from "./types.js";
2
- export declare function resolveConfig(config?: SheetStackConfig): ResolvedConfig;
3
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAyBpB,wBAAgB,aAAa,CAAC,MAAM,GAAE,gBAAqB,GAAG,cAAc,CAmB3E"}
package/dist/config.js DELETED
@@ -1,37 +0,0 @@
1
- // ── Defaults ────────────────────────────────────
2
- const DEFAULT_STACKING = {
3
- scaleStep: 0.04,
4
- offsetStep: 24,
5
- opacityStep: 0.15,
6
- radius: 12,
7
- renderThreshold: 5,
8
- };
9
- const DEFAULT_SPRING = {
10
- damping: 30,
11
- stiffness: 170,
12
- mass: 0.8,
13
- };
14
- const DEFAULT_SIDE = {
15
- desktop: "right",
16
- mobile: "bottom",
17
- };
18
- // ── Resolver ────────────────────────────────────
19
- export function resolveConfig(config = {}) {
20
- const side = typeof config.side === "string"
21
- ? { desktop: config.side, mobile: config.side }
22
- : { ...DEFAULT_SIDE, ...config.side };
23
- return {
24
- maxDepth: config.maxDepth ?? Infinity,
25
- closeOnEscape: config.closeOnEscape ?? true,
26
- closeOnBackdrop: config.closeOnBackdrop ?? true,
27
- lockScroll: config.lockScroll ?? true,
28
- width: config.width ?? 420,
29
- maxWidth: config.maxWidth ?? "90vw",
30
- breakpoint: config.breakpoint ?? 768,
31
- side,
32
- stacking: { ...DEFAULT_STACKING, ...config.stacking },
33
- spring: { ...DEFAULT_SPRING, ...config.spring },
34
- zIndex: config.zIndex ?? 100,
35
- };
36
- }
37
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,mDAAmD;AAEnD,MAAM,gBAAgB,GAAmB;IACvC,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,IAAI;IACjB,MAAM,EAAE,EAAE;IACV,eAAe,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,cAAc,GAAiB;IACnC,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,GAAG;IACd,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,YAAY,GAAmB;IACnC,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,mDAAmD;AAEnD,MAAM,UAAU,aAAa,CAAC,SAA2B,EAAE;IACzD,MAAM,IAAI,GACR,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC7B,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;QAC/C,CAAC,CAAC,EAAE,GAAG,YAAY,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAE1C,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,QAAQ;QACrC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;QAC3C,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;QAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;QACrC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG;QAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,MAAM;QACnC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG;QACpC,IAAI;QACJ,QAAQ,EAAE,EAAE,GAAG,gBAAgB,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE;QACrD,MAAM,EAAE,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,GAAG;KAC7B,CAAC;AACJ,CAAC"}
package/dist/create.d.ts DELETED
@@ -1,13 +0,0 @@
1
- import type { SheetStackConfig, SheetStackInstance } from "./types.js";
2
- /**
3
- * Create an isolated sheet stack instance with typed store, hooks, and provider.
4
- *
5
- * ```ts
6
- * const { SheetProvider, useSheet, useSheetState } = createSheetStack<{
7
- * "bucket-create": { onCreated?: (b: Bucket) => void };
8
- * "bucket-edit": { bucket: Bucket };
9
- * }>();
10
- * ```
11
- */
12
- export declare function createSheetStack<TMap extends Record<string, unknown>>(config?: SheetStackConfig): SheetStackInstance<TMap>;
13
- //# sourceMappingURL=create.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAKV,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAKpB;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,MAAM,CAAC,EAAE,gBAAgB,GACxB,kBAAkB,CAAC,IAAI,CAAC,CAwE1B"}
package/dist/create.js DELETED
@@ -1,56 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createContext, useContext, useMemo } from "react";
3
- import { useStore } from "zustand";
4
- import { useShallow } from "zustand/react/shallow";
5
- import { resolveConfig } from "./config.js";
6
- import { SheetRenderer } from "./renderer.js";
7
- import { createSheetStore } from "./store.js";
8
- /**
9
- * Create an isolated sheet stack instance with typed store, hooks, and provider.
10
- *
11
- * ```ts
12
- * const { SheetProvider, useSheet, useSheetState } = createSheetStack<{
13
- * "bucket-create": { onCreated?: (b: Bucket) => void };
14
- * "bucket-edit": { bucket: Bucket };
15
- * }>();
16
- * ```
17
- */
18
- export function createSheetStack(config) {
19
- const resolved = resolveConfig(config);
20
- const store = createSheetStore(resolved);
21
- // Context for the store — allows multiple instances
22
- const StoreContext = createContext(null);
23
- function useStoreContext() {
24
- const ctx = useContext(StoreContext);
25
- if (!ctx) {
26
- throw new Error("useSheet/useSheetState must be used within <SheetProvider>");
27
- }
28
- return ctx;
29
- }
30
- // ── Provider ────────────────────────────────
31
- function SheetProvider({ content, children, classNames, renderHeader, }) {
32
- const value = useMemo(() => ({ store, config: resolved }), []);
33
- return (_jsxs(StoreContext.Provider, { value: value, children: [children, _jsx(SheetRenderer, { classNames: classNames, config: resolved, content: content, renderHeader: renderHeader, store: store })] }));
34
- }
35
- // ── Hooks ───────────────────────────────────
36
- function useSheet() {
37
- const { store: s } = useStoreContext();
38
- return useStore(s, useShallow((state) => ({
39
- open: state.open,
40
- push: state.push,
41
- replace: state.replace,
42
- navigate: state.navigate,
43
- pop: state.pop,
44
- close: state.close,
45
- })));
46
- }
47
- function useSheetState() {
48
- const { store: s } = useStoreContext();
49
- return useStore(s, useShallow((state) => ({
50
- stack: state.stack,
51
- isOpen: state.isOpen,
52
- })));
53
- }
54
- return { SheetProvider, useSheet, useSheetState, store };
55
- }
56
- //# sourceMappingURL=create.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAc9C;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAyB;IAEzB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,gBAAgB,CAAO,QAAQ,CAAC,CAAC;IAE/C,oDAAoD;IACpD,MAAM,YAAY,GAAG,aAAa,CAGxB,IAAI,CAAC,CAAC;IAEhB,SAAS,eAAe;QACtB,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,+CAA+C;IAE/C,SAAS,aAAa,CAAC,EACrB,OAAO,EACP,QAAQ,EACR,UAAU,EACV,YAAY,GACa;QACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/D,OAAO,CACL,MAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,aAChC,QAAQ,EACT,KAAC,aAAa,IACZ,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,KAAK,GACZ,IACoB,CACzB,CAAC;IACJ,CAAC;IAED,+CAA+C;IAE/C,SAAS,QAAQ;QACf,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,eAAe,EAAE,CAAC;QACvC,OAAO,QAAQ,CACb,CAAC,EACD,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,SAAS,aAAa;QACpB,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,eAAe,EAAE,CAAC;QACvC,OAAO,QAAQ,CACb,CAAC,EACD,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAC3D,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1D,YAAY,EAEV,SAAS,EACT,IAAI,EACJ,cAAc,EACd,UAAU,EAEV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EAEd,eAAe,EACf,iBAAiB,EAEjB,qBAAqB,EACrB,UAAU,EAEV,aAAa,EACb,YAAY,EAEZ,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
package/dist/media.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { ResolvedConfig, Side } from "./types.js";
2
- /**
3
- * Returns true when viewport width is at or below the breakpoint.
4
- * SSR-safe: defaults to false (desktop).
5
- */
6
- export declare function useIsMobile(breakpoint: number): boolean;
7
- /** Resolve the current side from config + viewport. */
8
- export declare function useResolvedSide(config: ResolvedConfig): Side;
9
- //# sourceMappingURL=media.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAavD;AAED,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAG5D"}
package/dist/media.js DELETED
@@ -1,22 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- /**
3
- * Returns true when viewport width is at or below the breakpoint.
4
- * SSR-safe: defaults to false (desktop).
5
- */
6
- export function useIsMobile(breakpoint) {
7
- const [isMobile, setIsMobile] = useState(false);
8
- useEffect(() => {
9
- const mql = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
10
- setIsMobile(mql.matches);
11
- const handler = (e) => setIsMobile(e.matches);
12
- mql.addEventListener("change", handler);
13
- return () => mql.removeEventListener("change", handler);
14
- }, [breakpoint]);
15
- return isMobile;
16
- }
17
- /** Resolve the current side from config + viewport. */
18
- export function useResolvedSide(config) {
19
- const isMobile = useIsMobile(config.breakpoint);
20
- return isMobile ? config.side.mobile : config.side.desktop;
21
- }
22
- //# sourceMappingURL=media.js.map
package/dist/media.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5C;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,eAAe,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC;QAClE,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEzB,MAAM,OAAO,GAAG,CAAC,CAAsB,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACnE,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,eAAe,CAAC,MAAsB;IACpD,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAChD,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AAC7D,CAAC"}
@@ -1,12 +0,0 @@
1
- import type { StoreApi } from "zustand";
2
- import type { ContentMap, HeaderRenderProps, ResolvedConfig, SheetActions, SheetClassNames, SheetSnapshot } from "./types.js";
3
- interface SheetRendererProps<TMap extends Record<string, unknown>> {
4
- store: StoreApi<SheetSnapshot<TMap> & SheetActions<TMap>>;
5
- config: ResolvedConfig;
6
- content: ContentMap<TMap>;
7
- classNames?: SheetClassNames;
8
- renderHeader?: (props: HeaderRenderProps) => React.ReactNode;
9
- }
10
- export declare function SheetRenderer<TMap extends Record<string, unknown>>({ store, config, content, classNames: classNamesProp, renderHeader, }: SheetRendererProps<TMap>): import("react/jsx-runtime").JSX.Element;
11
- export {};
12
- //# sourceMappingURL=renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AASxC,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,eAAe,EAEf,aAAa,EAEd,MAAM,YAAY,CAAC;AAkHpB,UAAU,kBAAkB,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,KAAK,CAAC,SAAS,CAAC;CAC9D;AAED,wBAAgB,aAAa,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClE,KAAK,EACL,MAAM,EACN,OAAO,EACP,UAAU,EAAE,cAAc,EAC1B,YAAY,GACb,EAAE,kBAAkB,CAAC,IAAI,CAAC,2CAyL1B"}