"use client" import * as React from "react" import { usePersistedState } from "../lib/persisted-state" export const SIDEBAR_DRILL_IN_WIDTH_KEY = "shell:sidebar-drill-in-width" export const SIDEBAR_DRILL_IN_WIDTH_DEFAULT = 280 export const SIDEBAR_DRILL_IN_WIDTH_MIN = 216 export const SIDEBAR_DRILL_IN_WIDTH_MAX = 400 export const SIDEBAR_PRIMARY_WIDTH_KEY = "shell:primary-sidebar-width" /** Matches `SidebarShell` / `SidebarProvider` default rail width (`16rem`). */ export const SIDEBAR_PRIMARY_WIDTH_DEFAULT = 256 export const SIDEBAR_PRIMARY_WIDTH_MIN = 200 export const SIDEBAR_PRIMARY_WIDTH_MAX = 360 /** @deprecated Use {@link SIDEBAR_PRIMARY_WIDTH_DEFAULT} as px or `"16rem"`. */ export const SIDEBAR_WIDTH_DEFAULT = "16rem" function clampSidebarDrillInWidth(width: number) { return Math.min(SIDEBAR_DRILL_IN_WIDTH_MAX, Math.max(SIDEBAR_DRILL_IN_WIDTH_MIN, width)) } function clampSidebarPrimaryWidth(width: number) { return Math.min( SIDEBAR_PRIMARY_WIDTH_MAX, Math.max(SIDEBAR_PRIMARY_WIDTH_MIN, width), ) } function setWrapperSidebarWidth(px: number) { const wrapper = document.querySelector('[data-slot="sidebar-wrapper"]') if (!wrapper) return null wrapper.style.setProperty("--sidebar-width", `${px}px`) return wrapper } /** Widen `--sidebar-width` while a SidebarDrillIn section is open (design system, tokens, …). */ export function useSidebarDrillInWidth(enabled: boolean) { const [width, setWidth] = usePersistedState( SIDEBAR_DRILL_IN_WIDTH_KEY, SIDEBAR_DRILL_IN_WIDTH_DEFAULT, ) const [primaryWidth] = usePersistedState( SIDEBAR_PRIMARY_WIDTH_KEY, SIDEBAR_PRIMARY_WIDTH_DEFAULT, ) const widthRef = React.useRef(width) React.useEffect(() => { widthRef.current = width }) React.useEffect(() => { const wrapper = document.querySelector('[data-slot="sidebar-wrapper"]') if (!wrapper) return if (!enabled) { // Restore persisted primary width — never strip the var (gap collapses). wrapper.style.setProperty( "--sidebar-width", `${clampSidebarPrimaryWidth(primaryWidth)}px`, ) wrapper.removeAttribute("data-drill-in-open") return } wrapper.setAttribute("data-drill-in-open", "true") wrapper.style.setProperty( "--sidebar-width", `${clampSidebarDrillInWidth(width)}px`, ) return () => { wrapper.style.setProperty( "--sidebar-width", `${clampSidebarPrimaryWidth(primaryWidth)}px`, ) wrapper.removeAttribute("data-drill-in-open") } }, [enabled, width, primaryWidth]) const setClampedWidth = React.useCallback( (next: number) => { setWidth(clampSidebarDrillInWidth(next)) }, [setWidth], ) const resizeByDelta = React.useCallback( (deltaPx: number) => { setClampedWidth(widthRef.current + deltaPx) }, [setClampedWidth], ) return { width: clampSidebarDrillInWidth(width), setWidth: setClampedWidth, resizeByDelta, } } /** Persist and apply expanded primary rail width when not in drill-in. */ export function useSidebarPrimaryWidth(enabled: boolean) { const [width, setWidth] = usePersistedState( SIDEBAR_PRIMARY_WIDTH_KEY, SIDEBAR_PRIMARY_WIDTH_DEFAULT, ) const widthRef = React.useRef(width) React.useEffect(() => { widthRef.current = width }) React.useEffect(() => { if (!enabled) return const wrapper = setWrapperSidebarWidth(clampSidebarPrimaryWidth(width)) if (!wrapper) return wrapper.removeAttribute("data-drill-in-open") }, [enabled, width]) const setClampedWidth = React.useCallback( (next: number) => { setWidth(clampSidebarPrimaryWidth(next)) }, [setWidth], ) return { width: clampSidebarPrimaryWidth(width), setWidth: setClampedWidth, } }