{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "sidebar", "title": "Sidebar", "description": "Polaris-styled Sidebar component.", "dependencies": [ "lucide-react" ], "devDependencies": [ "@shopify/polaris-types" ], "registryDependencies": [ "@polaris-shadcn/theme", "@polaris-shadcn/utils" ], "files": [ { "path": "registry/templates/components/ui/sidebar.tsx", "content": "import * as React from \"react\";\nimport { PanelLeft } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\nexport interface SidebarContextValue {\n open: boolean;\n setOpen: (value: React.SetStateAction) => void;\n}\n\nconst SidebarContext = React.createContext(null);\n\nconst defaultSidebarVars = {\n \"--sidebar-width\": \"18rem\",\n \"--sidebar-width-icon\": \"3rem\",\n} as React.CSSProperties;\n\nexport function useSidebar(): SidebarContextValue {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error(\n \"useSidebar must be used within a SidebarProvider or Sidebar\",\n );\n }\n return context;\n}\n\nexport interface SidebarProviderProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nconst SidebarProvider = React.forwardRef(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange,\n className,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const [openState, setOpenState] = React.useState(defaultOpen);\n const open = openProp ?? openState;\n\n const setOpen = React.useCallback(\n (value: React.SetStateAction) => {\n const next = typeof value === \"function\" ? value(open) : value;\n if (openProp === undefined) {\n setOpenState(next);\n }\n onOpenChange?.(next);\n },\n [open, openProp, onOpenChange],\n );\n\n const value = React.useMemo(() => ({ open, setOpen }), [open, setOpen]);\n const mergedStyle = { ...defaultSidebarVars, ...style };\n\n return (\n \n \n {children}\n \n \n );\n },\n);\nSidebarProvider.displayName = \"SidebarProvider\";\n\nexport type SidebarCollapsible = \"icon\" | \"offcanvas\" | \"none\";\n\nexport interface SidebarProps extends React.ComponentPropsWithoutRef<\"div\"> {\n collapsible?: SidebarCollapsible;\n}\n\nconst Sidebar = React.forwardRef(\n ({ className, collapsible = \"icon\", style, ...props }, ref) => {\n const context = React.useContext(SidebarContext);\n\n if (!context) {\n return (\n \n );\n }\n\n const state = context.open ? \"expanded\" : \"collapsed\";\n\n return (\n \n );\n },\n);\nSidebar.displayName = \"Sidebar\";\n\nexport type SidebarInsetProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarInset = React.forwardRef(\n ({ className, ...props }, ref) => (\n \n ),\n);\nSidebarInset.displayName = \"SidebarInset\";\n\nexport type SidebarHeaderProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarHeader = React.forwardRef(\n ({ className, ...props }, ref) => (\n \n ),\n);\nSidebarHeader.displayName = \"SidebarHeader\";\n\nexport type SidebarFooterProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarFooter = React.forwardRef(\n ({ className, ...props }, ref) => (\n
\n ),\n);\nSidebarFooter.displayName = \"SidebarFooter\";\n\nexport type SidebarContentProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarContent = React.forwardRef(\n ({ className, ...props }, ref) => (\n \n ),\n);\nSidebarContent.displayName = \"SidebarContent\";\n\nexport type SidebarGroupProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarGroup = React.forwardRef(\n ({ className, ...props }, ref) => (\n
\n ),\n);\nSidebarGroup.displayName = \"SidebarGroup\";\n\nexport type SidebarGroupContentProps = React.ComponentPropsWithoutRef<\"div\">;\n\nconst SidebarGroupContent = React.forwardRef<\n HTMLDivElement,\n SidebarGroupContentProps\n>(({ className, ...props }, ref) => (\n
\n));\nSidebarGroupContent.displayName = \"SidebarGroupContent\";\n\nexport type SidebarMenuProps = React.ComponentPropsWithoutRef<\"ul\">;\n\nconst SidebarMenu = React.forwardRef(\n ({ className, ...props }, ref) => (\n
    \n ),\n);\nSidebarMenu.displayName = \"SidebarMenu\";\n\nexport type SidebarMenuItemProps = React.ComponentPropsWithoutRef<\"li\">;\n\nconst SidebarMenuItem = React.forwardRef(\n ({ className, ...props }, ref) => (\n
  • \n ),\n);\nSidebarMenuItem.displayName = \"SidebarMenuItem\";\n\nfunction composeEventHandlers(\n userHandler: ((event: E) => void) | undefined,\n theirHandler: ((event: E) => void) | undefined,\n) {\n return (event: E) => {\n userHandler?.(event);\n if (!event.defaultPrevented) {\n theirHandler?.(event);\n }\n };\n}\n\ninterface SlotChildProps {\n className?: string;\n onClick?: React.MouseEventHandler;\n ref?: React.Ref;\n}\n\ntype SlotProps = React.ButtonHTMLAttributes;\n\nconst Slot = React.forwardRef(\n ({ children, className, onClick, ...props }, ref) => {\n if (!React.isValidElement(children)) {\n return null;\n }\n\n const childProps = children.props;\n return React.cloneElement(children, {\n ...props,\n ...childProps,\n className: cn(className, childProps.className),\n onClick: composeEventHandlers(onClick, childProps.onClick),\n ref,\n });\n },\n);\nSlot.displayName = \"Slot\";\n\nexport type SidebarMenuButtonSize = \"default\" | \"lg\";\n\nconst menuButtonSizes: Record = {\n default: \"h-9 px-2.5 text-sm\",\n lg: \"h-10 px-3 text-sm\",\n};\n\nexport interface SidebarMenuButtonTooltip {\n children?: string;\n hidden?: boolean;\n}\n\nexport interface SidebarMenuButtonProps\n extends React.ComponentPropsWithoutRef<\"button\"> {\n size?: SidebarMenuButtonSize;\n isActive?: boolean;\n tooltip?: SidebarMenuButtonTooltip;\n asChild?: boolean;\n}\n\nconst SidebarMenuButton = React.forwardRef<\n HTMLButtonElement,\n SidebarMenuButtonProps\n>(\n (\n {\n className,\n size = \"default\",\n isActive = false,\n tooltip,\n asChild = false,\n type,\n ...props\n },\n ref,\n ) => {\n const tooltipText = tooltip?.children;\n const showTooltip = tooltipText && tooltip?.hidden !== true;\n const Comp = asChild ? Slot : \"button\";\n\n return (\n svg]:text-sidebar-foreground\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarMenuButton.displayName = \"SidebarMenuButton\";\n\nexport type SidebarInputProps = React.ComponentPropsWithoutRef<\"input\">;\n\nconst SidebarInput = React.forwardRef(\n ({ className, ...props }, ref) => (\n \n ),\n);\nSidebarInput.displayName = \"SidebarInput\";\n\nexport type SidebarTriggerProps = React.ComponentPropsWithoutRef<\"button\">;\n\nconst SidebarTrigger = React.forwardRef<\n HTMLButtonElement,\n SidebarTriggerProps\n>(({ className, onClick, style, ...props }, ref) => {\n const { open, setOpen } = useSidebar();\n const mergedStyle = { width: \"28px\", height: \"28px\", ...style };\n\n return (\n {\n onClick?.(event);\n if (!event.defaultPrevented) {\n setOpen((prev) => !prev);\n }\n }}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded-[8px] bg-transparent p-0\",\n \"text-foreground transition hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n className,\n )}\n style={mergedStyle}\n {...props}\n >\n \n \n );\n});\nSidebarTrigger.displayName = \"SidebarTrigger\";\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n SidebarTrigger,\n};\n", "type": "registry:ui" } ], "type": "registry:ui" }