"use client"; import { Accordion, AccordionItem, type ListboxProps, type ListboxSectionProps, type Selection, } from "@nextui-org/react"; import React from "react"; import { Listbox, Tooltip, ListboxItem, ListboxSection, } from "@nextui-org/react"; import { Icon } from "@iconify/react"; import { cn } from "@/lib/utils"; export enum SidebarItemType { Nest = "nest", } export type SidebarItem = { key: string; title: string; icon?: string; href?: string; onPress?: () => void; type?: SidebarItemType.Nest; startContent?: React.ReactNode; endContent?: React.ReactNode; items?: SidebarItem[]; className?: string; }; export type SidebarProps = Omit, "children"> & { items: SidebarItem[]; isCompact?: boolean; hideEndContent?: boolean; iconClassName?: string; sectionClasses?: ListboxSectionProps["classNames"]; classNames?: ListboxProps["classNames"]; defaultSelectedKey: string; onSelect?: (key: string) => void; }; const Sidebar = React.forwardRef( ( { items, isCompact, defaultSelectedKey, onSelect, hideEndContent, sectionClasses: sectionClassesProp = {}, itemClasses: itemClassesProp = {}, iconClassName, classNames, className, ...props }, ref, ) => { const [selected, setSelected] = React.useState(defaultSelectedKey); const sectionClasses = { ...sectionClassesProp, base: cn(sectionClassesProp?.base, "w-full", { "p-0 max-w-[44px]": isCompact, }), group: cn(sectionClassesProp?.group, { "flex flex-col gap-1": isCompact, }), heading: cn(sectionClassesProp?.heading, { hidden: isCompact, }), }; const itemClasses = { ...itemClassesProp, base: cn(itemClassesProp?.base, { "w-11 h-11 gap-0 p-0": isCompact, }), }; const renderNestItem = React.useCallback( (item: SidebarItem) => { const isNestType = item.items && item.items?.length > 0 && item?.type === SidebarItemType.Nest; if (isNestType) { // Is a nest type item , so we need to remove the href delete item.href; } return ( ) : ( item.startContent ?? null ) } title={isCompact || isNestType ? null : item.title} > {isCompact ? (
{item.icon ? ( ) : ( item.startContent ?? null )}
) : null} {!isCompact && isNestType ? ( {item.title} ) : ( item.startContent ?? null ) } > {item.items && item.items?.length > 0 ? ( {item.items.map(renderItem)} ) : ( renderItem(item) )} ) : null}
); }, [isCompact, hideEndContent, iconClassName, items], ); const renderItem = React.useCallback( (item: SidebarItem) => { const isNestType = item.items && item.items?.length > 0 && item?.type === SidebarItemType.Nest; if (isNestType) { return renderNestItem(item); } return ( ) : ( item.startContent ?? null ) } textValue={item.title} title={isCompact ? null : item.title} > {isCompact ? (
{item.icon ? ( ) : ( item.startContent ?? null )}
) : null}
); }, [isCompact, hideEndContent, iconClassName, itemClasses?.base], ); return ( { const key = Array.from(keys)[0]; setSelected(key as React.Key); onSelect?.(key as string); }} {...props} > {(item) => { return item.items && item.items?.length > 0 && item?.type === SidebarItemType.Nest ? ( renderNestItem(item) ) : item.items && item.items?.length > 0 ? ( {item.items.map(renderItem)} ) : ( renderItem(item) ); }} ); }, ); Sidebar.displayName = "Sidebar"; export default Sidebar;