({
defaultOpen = true,
open: openProp,
onOpenChange: setOpenProp,
className,
style,
children,
...props
}: React.ComponentProps<"div"> & {
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
})
| 41 | } |
| 42 | |
| 43 | function SidebarProvider({ |
| 44 | defaultOpen = true, |
| 45 | open: openProp, |
| 46 | onOpenChange: setOpenProp, |
| 47 | className, |
| 48 | style, |
| 49 | children, |
| 50 | ...props |
| 51 | }: React.ComponentProps<"div"> & { |
| 52 | defaultOpen?: boolean; |
| 53 | open?: boolean; |
| 54 | onOpenChange?: (open: boolean) => void; |
| 55 | }) { |
| 56 | const isMobile = useIsMobile(); |
| 57 | const [openMobile, setOpenMobile] = React.useState(false); |
| 58 | |
| 59 | // This is the internal state of the sidebar. |
| 60 | // We use openProp and setOpenProp for control from outside the component. |
| 61 | const [_open, _setOpen] = React.useState(defaultOpen); |
| 62 | const open = openProp ?? _open; |
| 63 | const setOpen = React.useCallback( |
| 64 | (value: boolean | ((value: boolean) => boolean)) => { |
| 65 | const openState = typeof value === "function" ? value(open) : value; |
| 66 | if (setOpenProp) { |
| 67 | setOpenProp(openState); |
| 68 | } else { |
| 69 | _setOpen(openState); |
| 70 | } |
| 71 | |
| 72 | // This sets the cookie to keep the sidebar state. |
| 73 | document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; |
| 74 | }, |
| 75 | [setOpenProp, open], |
| 76 | ); |
| 77 | |
| 78 | // Helper to toggle the sidebar. |
| 79 | const toggleSidebar = React.useCallback(() => { |
| 80 | return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); |
| 81 | }, [isMobile, setOpen, setOpenMobile]); |
| 82 | |
| 83 | // Adds a keyboard shortcut to toggle the sidebar. |
| 84 | React.useEffect(() => { |
| 85 | const handleKeyDown = (event: KeyboardEvent) => { |
| 86 | if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) { |
| 87 | event.preventDefault(); |
| 88 | toggleSidebar(); |
| 89 | } |
| 90 | }; |
| 91 | |
| 92 | window.addEventListener("keydown", handleKeyDown); |
| 93 | return () => window.removeEventListener("keydown", handleKeyDown); |
| 94 | }, [toggleSidebar]); |
| 95 | |
| 96 | // We add a state so that we can do data-state="expanded" or "collapsed". |
| 97 | // This makes it easier to style the sidebar with Tailwind classes. |
| 98 | const state = open ? "expanded" : "collapsed"; |
| 99 | |
| 100 | const contextValue = React.useMemo<SidebarContextProps>( |
nothing calls this directly
no test coverage detected