Spaces:
Build error
Build error
'use client'; | |
import { cva, VariantProps } from 'class-variance-authority'; | |
import * as React from 'react'; | |
import { AppLayoutAnatomy } from '.'; | |
import { cn, ComponentAnatomy, defineStyleAnatomy } from '../core/styling'; | |
import { Drawer, DrawerProps } from '../drawer'; | |
/* ------------------------------------------------------------------------------------------------- | |
* Context | |
* -----------------------------------------------------------------------------------------------*/ | |
export const __AppSidebarContext = React.createContext<{ | |
open: boolean; | |
setOpen: (open: boolean) => void; | |
size: VariantProps<typeof AppLayoutAnatomy.root>['sidebarSize']; | |
setSize: ( | |
size: VariantProps<typeof AppLayoutAnatomy.root>['sidebarSize'] | |
) => void; | |
isBelowBreakpoint: boolean; | |
}>({ | |
open: false, | |
setOpen: () => {}, | |
setSize: () => {}, | |
size: 'md', | |
isBelowBreakpoint: false, | |
}); | |
export function useAppSidebarContext() { | |
const ctx = React.useContext(__AppSidebarContext); | |
if (!ctx) | |
throw new Error( | |
'useAppSidebarContext must be used within a AppSidebarProvider' | |
); | |
return ctx; | |
} | |
/* ------------------------------------------------------------------------------------------------- | |
* Anatomy | |
* -----------------------------------------------------------------------------------------------*/ | |
export const AppSidebarAnatomy = defineStyleAnatomy({ | |
sidebar: cva([ | |
'UI-AppSidebar__sidebar', | |
'flex flex-grow flex-col overflow-y-auto border-r border-transparent bg-[--background]', | |
]), | |
}); | |
export const AppSidebarTriggerAnatomy = defineStyleAnatomy({ | |
trigger: cva([ | |
'UI-AppSidebarTrigger__trigger', | |
'block lg:hidden', | |
'items-center justify-center rounded-[--radius] p-2 text-[--muted] hover:bg-[--subtle] hover:text-[--foreground] transition-colors', | |
'focus:outline-none focus:ring-2 focus:ring-inset focus:ring-[--ring]', | |
]), | |
}); | |
/* ------------------------------------------------------------------------------------------------- | |
* AppSidebar | |
* -----------------------------------------------------------------------------------------------*/ | |
export type AppSidebarProps = React.ComponentPropsWithoutRef<'div'> & | |
ComponentAnatomy<typeof AppSidebarAnatomy> & { | |
mobileDrawerProps?: Partial<DrawerProps>; | |
}; | |
export const AppSidebar = React.forwardRef<HTMLDivElement, AppSidebarProps>( | |
(props, ref) => { | |
const { children, className, ...rest } = props; | |
const ctx = React.useContext(__AppSidebarContext); | |
return ( | |
<> | |
<div | |
ref={ref} | |
className={cn( | |
AppSidebarAnatomy.sidebar(), | |
// process.env.NEXT_PUBLIC_PLATFORM === "desktop" && "pt-4", | |
className | |
)} | |
{...rest} | |
> | |
{children} | |
</div> | |
<Drawer | |
open={ctx.open} | |
onOpenChange={(v) => ctx.setOpen(v)} | |
side="left" | |
> | |
{children} | |
</Drawer> | |
</> | |
); | |
} | |
); | |
AppSidebar.displayName = 'AppSidebar'; | |
/* ------------------------------------------------------------------------------------------------- | |
* AppSidebarTrigger | |
* -----------------------------------------------------------------------------------------------*/ | |
export type AppSidebarTriggerProps = React.ComponentPropsWithoutRef<'button'> & | |
ComponentAnatomy<typeof AppSidebarTriggerAnatomy>; | |
export const AppSidebarTrigger = React.forwardRef< | |
HTMLButtonElement, | |
AppSidebarTriggerProps | |
>((props, ref) => { | |
const { children, className, ...rest } = props; | |
const ctx = React.useContext(__AppSidebarContext); | |
return ( | |
<button | |
ref={ref} | |
className={cn(AppSidebarTriggerAnatomy.trigger(), className)} | |
onClick={() => ctx.setOpen(!ctx.open)} | |
{...rest} | |
> | |
<span className="sr-only">Open main menu</span> | |
{ctx.open ? ( | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="24" | |
height="24" | |
viewBox="0 0 24 24" | |
fill="none" | |
stroke="currentColor" | |
strokeWidth="2" | |
strokeLinecap="round" | |
strokeLinejoin="round" | |
className="block h-6 w-6" | |
> | |
<line x1="18" x2="6" y1="6" y2="18"></line> | |
<line x1="6" x2="18" y1="6" y2="18"></line> | |
</svg> | |
) : ( | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="24" | |
height="24" | |
viewBox="0 0 24 24" | |
fill="none" | |
stroke="currentColor" | |
strokeWidth="2" | |
strokeLinecap="round" | |
strokeLinejoin="round" | |
className="block h-6 w-6" | |
> | |
<line x1="4" x2="20" y1="12" y2="12"></line> | |
<line x1="4" x2="20" y1="6" y2="6"></line> | |
<line x1="4" x2="20" y1="18" y2="18"></line> | |
</svg> | |
)} | |
</button> | |
); | |
}); | |
AppSidebarTrigger.displayName = 'AppSidebarTrigger'; | |
/* ------------------------------------------------------------------------------------------------- | |
* AppSidebarProvider | |
* -----------------------------------------------------------------------------------------------*/ | |
export type AppSidebarProviderProps = { | |
children?: React.ReactNode; | |
open?: boolean; | |
onOpenChange?: (open: boolean) => void; | |
onSizeChange?: ( | |
size: VariantProps<typeof AppLayoutAnatomy.root>['sidebarSize'] | |
) => void; | |
}; | |
export const AppSidebarProvider: React.FC<AppSidebarProviderProps> = ({ | |
children, | |
onOpenChange, | |
onSizeChange, | |
}) => { | |
const [open, setOpen] = React.useState(false); | |
const [size, setSize] = | |
React.useState<VariantProps<typeof AppLayoutAnatomy.root>['sidebarSize']>( | |
undefined | |
); | |
const [isBelowBreakpoint, setIsBelowBreakpoint] = | |
React.useState<boolean>(false); | |
React.useEffect(() => { | |
const handleResize = () => setIsBelowBreakpoint(window.innerWidth < 1024); // lg breakpoint | |
handleResize(); | |
window.addEventListener('resize', handleResize); | |
return () => window.removeEventListener('resize', handleResize); | |
}, [isBelowBreakpoint]); | |
return ( | |
<__AppSidebarContext.Provider | |
value={{ | |
open, | |
setOpen: (open: boolean) => { | |
onOpenChange?.(open); | |
setOpen(open); | |
}, | |
setSize: ( | |
size: VariantProps<typeof AppLayoutAnatomy.root>['sidebarSize'] | |
) => { | |
onSizeChange?.(size); | |
setSize(size); | |
}, | |
size: size, | |
isBelowBreakpoint, | |
}} | |
> | |
{children} | |
</__AppSidebarContext.Provider> | |
); | |
}; | |
AppSidebarProvider.displayName = 'AppSidebarProvider'; | |