periplo-ui 4.9.0 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Starting in **v4.0.0**, periplo-ui declares heavy libraries as **peer dependencies** so consumers control the versions and avoid duplicates. See [MIGRATION.md](./MIGRATION.md) for upgrade steps. Install only what your app uses:
|
|
17
|
-
|
|
18
17
|
- Always required: `react`, `react-dom`
|
|
19
18
|
- When using `<Form>` and form-bound inputs (`MultiSelect`, `RadioGroup`, `InlineMultiSelect`, `DatePicker`): `react-hook-form`, `@hookform/resolvers`, `zod`
|
|
20
19
|
- Per-component peers (install only if you import the component):
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.js","sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { X } from '@phosphor-icons/react/dist/ssr/X'\nimport { useEffect, useRef } from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Command, CommandInput } from '../Command'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport { ComboboxTrigger } from './ComboboxTrigger'\nimport { StaticComboboxList } from './StaticComboboxList'\nimport { useCombobox } from './useCombobox'\nimport { VirtualizedComboboxList } from './VirtualizedComboboxList'\n\ntype ComboboxBaseProps<T> = {\n /** Unique identifier for the combobox */\n id?: string\n /** Array of options to display in the combobox (static mode). */\n options?: Array<T>\n /** Function to get the unique identifier from an option. */\n getOptionValue: (option: T) => string\n /** Function to get the display text from an option. */\n getOptionLabel: (option: T) => string\n /** Custom render function for options. If not provided, defaults to showing a checkmark and label */\n renderOption?: (option: T, isSelected: boolean) => React.ReactNode\n /** Placeholder text shown when no option is selected */\n placeholder?: string\n /** Placeholder text for the search input field */\n searchPlaceholder?: string\n /** Message shown when no options match the search query */\n emptyMessage?: string\n /** Additional CSS classes to apply to the combobox trigger */\n className?: string\n /** Additional CSS classes to apply to the popover content */\n contentClassName?: string\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Maximum height of the options list. Can be any valid CSS height value */\n maxHeight?: string | number\n /** Whether to close the dropdown when an option is selected. Defaults to `true` for single select and `false` for multi-select. */\n closeOnSelect?: boolean\n /** Whether the combobox is in a loading state */\n loading?: boolean\n /** Message to show when in loading state */\n loadingPlaceholder?: string\n /** Whether the combobox has an error */\n error?: boolean | string\n /** Custom function to filter options based on search term (static mode only) */\n filterOptions?: (options: Array<T>, searchTerm: string) => Array<T>\n /** Callback function executed when the clear button is clicked. When provided, an X button will appear on hover to clear the selection. */\n onClear?: boolean | (() => void)\n /** Whether the selection can be cleared */\n clearable?: boolean\n /** Whether the combobox is inside a modal */\n modal?: boolean\n /** Placeholder text for the selected multiple options */\n selectedMultiplePlaceholder?: string\n /** Placeholder text for the multiple options */\n multipleOptionsPlaceholder?: string\n /** Special options that appear at the top with their own title. When selected, the combobox switches to single-select mode. */\n specialOptions?: Array<T>\n /** Title for the special options group */\n specialOptionsTitle?: string\n /** Container element to position the combobox relative to. */\n container?: HTMLElement\n /** Alignment of the dropdown relative to the trigger. Defaults to 'center'. */\n align?: 'start' | 'center' | 'end'\n /** Auto-focus the search input when the dropdown opens. */\n onOpenAutoFocus?: boolean\n}\n\nexport type ComboboxSingleProps<T> = ComboboxBaseProps<T> & {\n virtualized?: false\n multiple?: false\n value?: string\n onChange: (value: string) => void\n /** Custom render function for the selected value display. */\n renderLabel?: (selectedOption: T) => React.ReactNode\n}\n\nexport type ComboboxMultipleProps<T> = ComboboxBaseProps<T> & {\n virtualized?: false\n multiple: true\n value?: Array<string>\n onChange: (value: Array<string>) => void\n /** Custom render function for the selected value(s) display. */\n renderLabel?: (selectedOptions: Array<T>, onRemove: (value: string) => void) => React.ReactNode\n}\n\nexport type ComboboxVirtualizedProps<T> = ComboboxBaseProps<T> & {\n virtualized: true\n multiple?: false\n value?: string\n onChange: (value: string) => void\n /** Custom render function for the selected value display. */\n renderLabel?: (selectedOption: T) => React.ReactNode\n /** The accumulated, flattened list of loaded items. */\n items: Array<T>\n /** The resolved selected item, fetched independently of the list. Used for the trigger label. */\n selectedItem?: T\n /** Whether more pages can be loaded. */\n hasNextPage: boolean\n /** Whether the next page is currently being fetched. */\n isFetchingNextPage: boolean\n /** Request the next page (triggered near the end of the list). */\n onLoadMore: () => void\n /** Emitted (debounced) when the search term changes. The consumer refetches. */\n onSearchChange: (search: string) => void\n}\n\nexport type ComboboxProps<T> = ComboboxSingleProps<T> | ComboboxMultipleProps<T> | ComboboxVirtualizedProps<T>\n\n/**\n * A searchable combobox component with support for custom rendering, keyboard navigation, and search filtering.\n *\n * @example Basic usage\n * ```tsx\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * />\n * ```\n */\nexport const Combobox = <T extends object>(props: ComboboxProps<T>) => {\n const {\n id,\n options = [],\n getOptionValue,\n getOptionLabel,\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found.',\n className = 'w-60',\n contentClassName,\n disabled = false,\n maxHeight = '300px',\n renderOption,\n loading = false,\n loadingPlaceholder = 'Cargando...',\n error = false,\n multiple,\n onClear,\n modal = false,\n selectedMultiplePlaceholder = 'Selected',\n multipleOptionsPlaceholder = 'Options',\n specialOptions,\n specialOptionsTitle,\n container,\n align,\n onOpenAutoFocus = false,\n } = props\n\n const searchInputRef = useRef<HTMLInputElement>(null)\n const normalizedMaxHeight = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight\n const boundedListMaxHeight = `min(${normalizedMaxHeight}, max(120px, calc(var(--radix-popover-content-available-height, 100dvh) - 68px)))`\n\n const {\n open,\n setOpen,\n searchTerm,\n setSearchTerm,\n setIsHovered,\n hasNextPage,\n loadingMore,\n isVirtualized,\n filteredOptions,\n displayValue,\n hasValue,\n showClearButton,\n handleSelect,\n handleClear,\n loadNextPage,\n } = useCombobox(props)\n\n useEffect(() => {\n if (!open || !onOpenAutoFocus) return\n const timeoutId = globalThis.setTimeout(() => searchInputRef.current?.focus(), 0)\n return () => globalThis.clearTimeout(timeoutId)\n }, [open, onOpenAutoFocus])\n\n const hasMultipleRenderLabel = !!(multiple && 'renderLabel' in props && props.renderLabel)\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <PopoverRoot open={open} onOpenChange={setOpen} modal={modal}>\n <div\n className={cn('relative', className)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <PopoverTrigger\n asChild\n onPointerDown={(event) => {\n event.stopPropagation()\n if (open) {\n setOpen(false)\n event.preventDefault()\n } else {\n setOpen(true)\n }\n }}\n onClick={(event) => {\n event.preventDefault()\n event.stopPropagation()\n }}\n >\n <ComboboxTrigger\n id={id}\n disabled={disabled}\n open={open}\n error={error}\n hasValue={hasValue}\n showClearButton={showClearButton}\n isMultilineLabel={hasMultipleRenderLabel}\n displayValue={displayValue}\n className=\"w-full\"\n />\n </PopoverTrigger>\n {!!onClear && hasValue && (\n <X\n data-testid=\"clear-button\"\n className={cn(\n 'absolute top-1/2 right-4 z-10 h-4 w-4 -translate-y-1/2 cursor-pointer transition-opacity duration-150',\n showClearButton ? 'opacity-100 hover:opacity-70' : 'opacity-0',\n )}\n onPointerDown={(event) => event.stopPropagation()}\n onClick={handleClear}\n />\n )}\n </div>\n <PopoverContent\n className={cn('overflow-hidden p-0', contentClassName)}\n container={container}\n side=\"bottom\"\n align={align}\n onOpenAutoFocus={onOpenAutoFocus ? (event) => event.preventDefault() : undefined}\n >\n <Command shouldFilter={false}>\n <CommandInput\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={searchTerm}\n onValueChange={setSearchTerm}\n />\n {isVirtualized ? (\n <VirtualizedComboboxList\n localOptions={filteredOptions}\n loading={loading}\n loadingPlaceholder={loadingPlaceholder}\n emptyMessage={emptyMessage}\n value={props.value as string}\n getOptionValue={getOptionValue}\n getOptionLabel={getOptionLabel}\n handleSelect={handleSelect}\n renderOption={renderOption}\n maxHeight={boundedListMaxHeight}\n hasNextPage={hasNextPage}\n loadingMore={loadingMore}\n onLoadMore={loadNextPage}\n />\n ) : (\n <StaticComboboxList\n filteredOptions={filteredOptions}\n loading={loading}\n loadingPlaceholder={loadingPlaceholder}\n emptyMessage={emptyMessage}\n multiple={!!multiple}\n value={props.value}\n getOptionValue={getOptionValue}\n getOptionLabel={getOptionLabel}\n handleSelect={handleSelect}\n renderOption={renderOption}\n maxHeight={boundedListMaxHeight}\n selectedMultiplePlaceholder={selectedMultiplePlaceholder}\n multipleOptionsPlaceholder={multipleOptionsPlaceholder}\n options={options}\n specialOptions={specialOptions}\n specialOptionsTitle={specialOptionsTitle}\n />\n )}\n </Command>\n </PopoverContent>\n </PopoverRoot>\n {typeof error === 'string' && <span className=\"text-error-500 text-sm\">{error}</span>}\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Combobox.js","sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { X } from '@phosphor-icons/react/dist/ssr/X'\nimport { useEffect, useRef } from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Command, CommandInput } from '../Command'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport { ComboboxTrigger } from './ComboboxTrigger'\nimport { StaticComboboxList } from './StaticComboboxList'\nimport { useCombobox } from './useCombobox'\nimport { VirtualizedComboboxList } from './VirtualizedComboboxList'\n\ntype ComboboxBaseProps<T> = {\n /** Unique identifier for the combobox */\n id?: string\n /** Array of options to display in the combobox (static mode). */\n options?: Array<T>\n /** Function to get the unique identifier from an option. */\n getOptionValue: (option: T) => string\n /** Function to get the display text from an option. */\n getOptionLabel: (option: T) => string\n /** Custom render function for options. If not provided, defaults to showing a checkmark and label */\n renderOption?: (option: T, isSelected: boolean) => React.ReactNode\n /** Placeholder text shown when no option is selected */\n placeholder?: string\n /** Placeholder text for the search input field */\n searchPlaceholder?: string\n /** Message shown when no options match the search query */\n emptyMessage?: string\n /** Additional CSS classes to apply to the combobox trigger */\n className?: string\n /** Additional CSS classes to apply to the popover content */\n contentClassName?: string\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Maximum height of the options list. Can be any valid CSS height value */\n maxHeight?: string | number\n /** Whether to close the dropdown when an option is selected. Defaults to `true` for single select and `false` for multi-select. */\n closeOnSelect?: boolean\n /** Whether the combobox is in a loading state */\n loading?: boolean\n /** Message to show when in loading state */\n loadingPlaceholder?: string\n /** Whether the combobox has an error */\n error?: boolean | string\n /** Custom function to filter options based on search term (static mode only) */\n filterOptions?: (options: Array<T>, searchTerm: string) => Array<T>\n /** Callback function executed when the clear button is clicked. When provided, an X button will appear on hover to clear the selection. */\n onClear?: boolean | (() => void)\n /** Whether the selection can be cleared */\n clearable?: boolean\n /** Whether the combobox is inside a modal */\n modal?: boolean\n /** Placeholder text for the selected multiple options */\n selectedMultiplePlaceholder?: string\n /** Placeholder text for the multiple options */\n multipleOptionsPlaceholder?: string\n /** Special options that appear at the top with their own title. When selected, the combobox switches to single-select mode. */\n specialOptions?: Array<T>\n /** Title for the special options group */\n specialOptionsTitle?: string\n /** Container element to position the combobox relative to. */\n container?: HTMLElement\n /** Alignment of the dropdown relative to the trigger. Defaults to 'center'. */\n align?: 'start' | 'center' | 'end'\n /** Auto-focus the search input when the dropdown opens. */\n onOpenAutoFocus?: boolean\n}\n\nexport type ComboboxSingleProps<T> = ComboboxBaseProps<T> & {\n virtualized?: false\n multiple?: false\n value?: string\n onChange: (value: string) => void\n /** Custom render function for the selected value display. */\n renderLabel?: (selectedOption: T) => React.ReactNode\n}\n\nexport type ComboboxMultipleProps<T> = ComboboxBaseProps<T> & {\n virtualized?: false\n multiple: true\n value?: Array<string>\n onChange: (value: Array<string>) => void\n /** Custom render function for the selected value(s) display. */\n renderLabel?: (selectedOptions: Array<T>, onRemove: (value: string) => void) => React.ReactNode\n}\n\nexport type ComboboxVirtualizedProps<T> = ComboboxBaseProps<T> & {\n virtualized: true\n multiple?: false\n value?: string\n onChange: (value: string) => void\n /** Custom render function for the selected value display. */\n renderLabel?: (selectedOption: T) => React.ReactNode\n /** The accumulated, flattened list of loaded items. */\n items: Array<T>\n /** The resolved selected item, fetched independently of the list. Used for the trigger label. */\n selectedItem?: T\n /** Whether more pages can be loaded. */\n hasNextPage: boolean\n /** Whether the next page is currently being fetched. */\n isFetchingNextPage: boolean\n /** Request the next page (triggered near the end of the list). */\n onLoadMore: () => void\n /** Emitted (debounced) when the search term changes. The consumer refetches. */\n onSearchChange: (search: string) => void\n}\n\nexport type ComboboxProps<T> = ComboboxSingleProps<T> | ComboboxMultipleProps<T> | ComboboxVirtualizedProps<T>\n\n/**\n * A searchable combobox component with support for custom rendering, keyboard navigation, and search filtering.\n *\n * @example Basic usage\n * ```tsx\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * />\n * ```\n */\nexport const Combobox = <T extends object>(props: ComboboxProps<T>) => {\n const {\n id,\n options = [],\n getOptionValue,\n getOptionLabel,\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found.',\n className = 'w-60',\n contentClassName,\n disabled = false,\n maxHeight = '300px',\n renderOption,\n loading = false,\n loadingPlaceholder = 'Cargando...',\n error = false,\n multiple,\n onClear,\n modal = false,\n selectedMultiplePlaceholder = 'Selected',\n multipleOptionsPlaceholder = 'Options',\n specialOptions,\n specialOptionsTitle,\n container,\n align,\n onOpenAutoFocus = false,\n } = props\n\n const searchInputRef = useRef<HTMLInputElement>(null)\n const normalizedMaxHeight = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight\n const boundedListMaxHeight = `min(${normalizedMaxHeight}, max(120px, calc(var(--radix-popover-content-available-height, 100dvh) - 68px)))`\n\n const {\n open,\n setOpen,\n searchTerm,\n setSearchTerm,\n setIsHovered,\n hasNextPage,\n loadingMore,\n isVirtualized,\n filteredOptions,\n displayValue,\n hasValue,\n showClearButton,\n handleSelect,\n handleClear,\n loadNextPage,\n } = useCombobox(props)\n\n useEffect(() => {\n if (!open || !onOpenAutoFocus) return\n const timeoutId = globalThis.setTimeout(() => searchInputRef.current?.focus(), 0)\n return () => globalThis.clearTimeout(timeoutId)\n }, [open, onOpenAutoFocus])\n\n const hasMultipleRenderLabel = !!(multiple && 'renderLabel' in props && props.renderLabel)\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <PopoverRoot open={open} onOpenChange={setOpen} modal={modal}>\n <div\n className={cn('relative', className)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <PopoverTrigger\n asChild\n onPointerDown={(event) => {\n event.stopPropagation()\n if (open) {\n setOpen(false)\n event.preventDefault()\n } else {\n setOpen(true)\n }\n }}\n onClick={(event) => {\n event.preventDefault()\n event.stopPropagation()\n }}\n >\n <ComboboxTrigger\n id={id}\n disabled={disabled}\n open={open}\n error={error}\n hasValue={hasValue}\n showClearButton={showClearButton}\n isMultilineLabel={hasMultipleRenderLabel}\n displayValue={displayValue}\n className={cn('w-full', className)}\n />\n </PopoverTrigger>\n {!!onClear && hasValue && (\n <X\n data-testid=\"clear-button\"\n className={cn(\n 'absolute top-1/2 right-4 z-10 h-4 w-4 -translate-y-1/2 cursor-pointer transition-opacity duration-150',\n showClearButton ? 'opacity-100 hover:opacity-70' : 'opacity-0',\n )}\n onPointerDown={(event) => event.stopPropagation()}\n onClick={handleClear}\n />\n )}\n </div>\n <PopoverContent\n className={cn('overflow-hidden p-0', contentClassName)}\n container={container}\n side=\"bottom\"\n align={align}\n onOpenAutoFocus={onOpenAutoFocus ? (event) => event.preventDefault() : undefined}\n >\n <Command shouldFilter={false}>\n <CommandInput\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={searchTerm}\n onValueChange={setSearchTerm}\n />\n {isVirtualized ? (\n <VirtualizedComboboxList\n localOptions={filteredOptions}\n loading={loading}\n loadingPlaceholder={loadingPlaceholder}\n emptyMessage={emptyMessage}\n value={props.value as string}\n getOptionValue={getOptionValue}\n getOptionLabel={getOptionLabel}\n handleSelect={handleSelect}\n renderOption={renderOption}\n maxHeight={boundedListMaxHeight}\n hasNextPage={hasNextPage}\n loadingMore={loadingMore}\n onLoadMore={loadNextPage}\n />\n ) : (\n <StaticComboboxList\n filteredOptions={filteredOptions}\n loading={loading}\n loadingPlaceholder={loadingPlaceholder}\n emptyMessage={emptyMessage}\n multiple={!!multiple}\n value={props.value}\n getOptionValue={getOptionValue}\n getOptionLabel={getOptionLabel}\n handleSelect={handleSelect}\n renderOption={renderOption}\n maxHeight={boundedListMaxHeight}\n selectedMultiplePlaceholder={selectedMultiplePlaceholder}\n multipleOptionsPlaceholder={multipleOptionsPlaceholder}\n options={options}\n specialOptions={specialOptions}\n specialOptionsTitle={specialOptionsTitle}\n />\n )}\n </Command>\n </PopoverContent>\n </PopoverRoot>\n {typeof error === 'string' && <span className=\"text-error-500 text-sm\">{error}</span>}\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.js","sources":["../../../src/components/Sidebar/Sidebar.tsx"],"sourcesContent":["'use client'\n\nimport { List } from '@phosphor-icons/react/dist/ssr/List'\nimport { SidebarSimple } from '@phosphor-icons/react/dist/ssr/SidebarSimple'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../../lib/useMobile'\nimport { Button } from '../Button'\nimport { Input } from '../Input'\nimport { Separator } from '../Separator'\nimport { SheetContent, SheetDescription, SheetHeader, SheetRoot, SheetTitle } from '../Sheet'\nimport { Skeleton } from '../Skeleton'\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '../Tooltip'\nimport { Typography } from '../Typography'\n\nimport { cn } from '@/lib/utils'\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar_state'\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = '16rem'\nconst SIDEBAR_WIDTH_MOBILE = '18rem'\nconst SIDEBAR_KEYBOARD_SHORTCUT = 'b'\n\nexport type SidebarSize = 'small' | 'medium' | 'big'\n\nconst SIDEBAR_WIDTH_ICON: Record<SidebarSize, string> = {\n small: '3rem',\n medium: '3.5rem',\n big: '4rem',\n}\n\ntype SidebarContext = {\n state: 'expanded' | 'collapsed'\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n size: SidebarSize\n}\n\nconst SidebarContext = React.createContext<SidebarContext | null>(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error('useSidebar must be used within a SidebarProvider.')\n }\n\n return context\n}\n\nconst SidebarProvider = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n size?: SidebarSize\n }\n>(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n size = 'small',\n className,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === 'function' ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open],\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [toggleSidebar])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? 'expanded' : 'collapsed'\n\n const contextValue = React.useMemo<SidebarContext>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n size,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, size],\n )\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delayDuration={0}>\n <div\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON[size],\n ...style,\n } as React.CSSProperties\n }\n className={cn('group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', className)}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n )\n },\n)\nSidebarProvider.displayName = 'SidebarProvider'\n\nconst SidebarRoot = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n side?: 'left' | 'right'\n variant?: 'default' | 'hidden'\n }\n>(({ side = 'left', variant = 'default', className, children, ...props }, ref) => {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n\n if (isMobile) {\n return (\n <SheetRoot open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n className=\"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </SheetRoot>\n )\n }\n\n return (\n <div\n ref={ref}\n className=\"group peer text-sidebar-foreground hidden shadow-md md:block\"\n data-state={state}\n data-side={side}\n data-variant={variant}\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n className={cn(\n 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:w-0',\n 'group-data-[side=right]:rotate-180',\n )}\n />\n <div\n className={cn(\n 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',\n side === 'left'\n ? [\n 'left-0',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:-left-(--sidebar-width)',\n ]\n : [\n 'right-0',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:-right-(--sidebar-width)',\n ],\n 'group-data-[side=left]:border-r group-data-[side=right]:border-l',\n className,\n )}\n {...props}\n >\n <div data-sidebar=\"sidebar\" className=\"bg-sidebar flex h-full w-full flex-col\">\n {children}\n </div>\n </div>\n </div>\n )\n})\nSidebarRoot.displayName = 'SidebarRoot'\n\nconst SidebarTrigger = React.forwardRef<React.ComponentRef<typeof Button>, React.ComponentProps<typeof Button>>(\n ({ className, onClick, ...props }, ref) => {\n const { isMobile, toggleSidebar } = useSidebar()\n\n return (\n <Button\n ref={ref}\n data-sidebar=\"trigger\"\n variant=\"text\"\n className={cn('text-primary-foreground h-8 w-8 p-1', className)}\n onClick={(event) => {\n onClick?.(event)\n toggleSidebar()\n }}\n {...props}\n StartIcon={isMobile ? List : SidebarSimple}\n >\n <span className=\"sr-only\">Toggle Sidebar</span>\n </Button>\n )\n },\n)\nSidebarTrigger.displayName = 'SidebarTrigger'\n\nconst SidebarRail = React.forwardRef<HTMLButtonElement, React.ComponentProps<'button'>>(\n ({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar()\n\n return (\n <button\n ref={ref}\n data-sidebar=\"rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n 'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 sm:flex',\n 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',\n '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',\n 'group-data-[variant=offcanvas]:hover:bg-sidebar group-data-[variant=offcanvas]:translate-x-0 group-data-[variant=offcanvas]:after:left-full',\n '[[data-side=left][data-variant=offcanvas]_&]:-right-2',\n '[[data-side=right][data-variant=offcanvas]_&]:-left-2',\n className,\n )}\n {...props}\n />\n )\n },\n)\nSidebarRail.displayName = 'SidebarRail'\n\nconst SidebarInset = React.forwardRef<HTMLDivElement, React.ComponentProps<'main'>>(({ className, ...props }, ref) => {\n return (\n <main\n ref={ref}\n className={cn(\n 'bg-background relative flex w-full flex-1 flex-col',\n 'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2',\n className,\n )}\n {...props}\n />\n )\n})\nSidebarInset.displayName = 'SidebarInset'\n\nconst SIDEBAR_INPUT_HEIGHT: Record<SidebarSize, string> = {\n small: 'h-8',\n medium: 'h-10',\n big: 'h-12',\n}\n\nconst SidebarInput = React.forwardRef<\n React.ComponentRef<typeof Input>,\n React.ComponentProps<typeof Input> & { size?: SidebarSize }\n>(({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Input\n ref={ref}\n data-sidebar=\"input\"\n className={cn(\n 'bg-background focus-visible:ring-sidebar-ring w-full shadow-none focus-visible:ring-2',\n SIDEBAR_INPUT_HEIGHT[resolvedSize],\n className,\n )}\n {...props}\n />\n )\n})\nSidebarInput.displayName = 'SidebarInput'\n\nconst SidebarHeader = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return <div ref={ref} data-sidebar=\"header\" className={cn('flex flex-col gap-2 p-2', className)} {...props} />\n})\nSidebarHeader.displayName = 'SidebarHeader'\n\nconst SidebarFooter = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return <div ref={ref} data-sidebar=\"footer\" className={cn('flex flex-col gap-2 p-2', className)} {...props} />\n})\nSidebarFooter.displayName = 'SidebarFooter'\n\nconst SidebarSeparator = React.forwardRef<React.ComponentRef<typeof Separator>, React.ComponentProps<typeof Separator>>(\n ({ className, ...props }, ref) => {\n return (\n <Separator\n ref={ref}\n data-sidebar=\"separator\"\n className={cn('bg-sidebar-border mx-2 w-auto', className)}\n {...props}\n />\n )\n },\n)\nSidebarSeparator.displayName = 'SidebarSeparator'\n\nconst SidebarContent = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"content\"\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-2 overflow-auto',\n 'group-data-[variant=default]:group-data-[state=collapsed]:overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n})\nSidebarContent.displayName = 'SidebarContent'\n\nconst SidebarGroup = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"group\"\n className={cn('relative flex w-full min-w-0 flex-col p-2', className)}\n {...props}\n />\n )\n})\nSidebarGroup.displayName = 'SidebarGroup'\n\nconst sidebarGroupLabelVariants = cva(\n 'text-sidebar-foreground/70 ring-sidebar-ring flex shrink-0 items-center rounded-md transition-[margin,opacity] duration-200 ease-linear outline-none focus-visible:ring-2 [&>svg]:shrink-0 group-data-[state=collapsed]:group-data-[variant=hidden]:hidden',\n {\n variants: {\n size: {\n small:\n 'h-8 px-2 [&>svg]:size-4 group-data-[state=collapsed]:group-data-[variant=default]:-mt-8 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n medium:\n 'h-9 px-2.5 [&>svg]:size-4 group-data-[state=collapsed]:group-data-[variant=default]:-mt-9 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n big: 'h-10 px-3 [&>svg]:size-5 group-data-[state=collapsed]:group-data-[variant=default]:-mt-10 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SIDEBAR_GROUP_LABEL_TEXT_VARIANT: Record<SidebarSize, 'label-md' | 'label-lg'> = {\n small: 'label-md',\n medium: 'label-md',\n big: 'label-lg',\n}\n\nconst SidebarGroupLabel = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & { asChild?: boolean; size?: SidebarSize }\n>(({ className, asChild = false, size, children, ...props }, ref) => {\n const Comp = asChild ? Slot : 'div'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-label\"\n className={cn(sidebarGroupLabelVariants({ size: resolvedSize }), className)}\n {...props}\n >\n {typeof children === 'string' ? (\n <Typography variant={SIDEBAR_GROUP_LABEL_TEXT_VARIANT[resolvedSize]} color=\"secondary\">\n {children}\n </Typography>\n ) : (\n children\n )}\n </Comp>\n )\n})\nSidebarGroupLabel.displayName = 'SidebarGroupLabel'\n\nconst sidebarGroupActionVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute flex aspect-square items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 after:absolute after:-inset-2 after:md:hidden group-data-[state=collapsed]:hidden [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'top-3.5 right-3 w-5 [&>svg]:size-4',\n medium: 'top-4 right-3 w-5 [&>svg]:size-4',\n big: 'top-4 right-3 w-6 [&>svg]:size-5',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarGroupAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & { asChild?: boolean; size?: SidebarSize }\n>(({ className, asChild = false, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-action\"\n className={cn(sidebarGroupActionVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n})\nSidebarGroupAction.displayName = 'SidebarGroupAction'\n\nconst SidebarGroupContent = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} data-sidebar=\"group-content\" className={cn('w-full text-sm', className)} {...props} />\n ),\n)\nSidebarGroupContent.displayName = 'SidebarGroupContent'\n\nconst SidebarMenu = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(({ className, ...props }, ref) => (\n <ul ref={ref} data-sidebar=\"menu\" className={cn('flex w-full min-w-0 flex-col gap-1', className)} {...props} />\n))\nSidebarMenu.displayName = 'SidebarMenu'\n\nconst SidebarMenuItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(({ className, ...props }, ref) => (\n <li ref={ref} data-sidebar=\"menu-item\" className={cn('group/menu-item relative', className)} {...props} />\n))\nSidebarMenuItem.displayName = 'SidebarMenuItem'\n\nconst sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full text-sm hover:bg-sidebar-accent hover:text-sidebar-accent-foreground items-center overflow-hidden rounded-md text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=expanded]:hover:bg-sidebar-accent data-[state=expanded]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n 'navigation-item': '',\n element: 'group-data-[state=collapsed]:!p-0',\n },\n size: {\n small: 'h-8 gap-2 p-2 [&>svg]:size-4',\n medium: 'h-10 gap-3 p-2.5 [&>svg]:size-5',\n big: 'h-12 gap-4 p-3 [&>svg]:size-6',\n },\n },\n defaultVariants: {\n variant: 'navigation-item',\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & {\n asChild?: boolean\n isActive?: boolean\n tooltip?: string | React.ComponentProps<typeof TooltipContent>\n variant?: 'navigation-item' | 'element'\n size?: SidebarSize\n }\n>(\n (\n { asChild = false, isActive = false, tooltip, className, children, variant = 'navigation-item', size, ...props },\n ref,\n ) => {\n const Comp = asChild ? Slot : 'button'\n const { isMobile, state, size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n const button = (\n <Comp\n ref={ref}\n data-sidebar=\"menu-button\"\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size: resolvedSize }), className)}\n {...props}\n >\n {children}\n </Comp>\n )\n\n if (!tooltip) {\n return button\n }\n\n if (typeof tooltip === 'string') {\n tooltip = {\n children: tooltip,\n }\n }\n\n return (\n <TooltipRoot>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent side=\"right\" align=\"center\" hidden={state !== 'collapsed' || isMobile} {...tooltip} />\n </TooltipRoot>\n )\n },\n)\nSidebarMenuButton.displayName = 'SidebarMenuButton'\n\nconst sidebarMenuActionVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute flex aspect-square items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 after:absolute after:-inset-2 after:md:hidden group-data-[state=collapsed]:hidden [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'top-1.5 right-1 w-5 [&>svg]:size-4',\n medium: 'top-2.5 right-1 w-5 [&>svg]:size-4',\n big: 'top-3 right-1.5 w-6 [&>svg]:size-5',\n },\n showOnHover: {\n true: 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=expanded]:opacity-100 md:opacity-0',\n false: '',\n },\n },\n defaultVariants: {\n size: 'small',\n showOnHover: false,\n },\n },\n)\n\nconst SidebarMenuAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & {\n asChild?: boolean\n showOnHover?: boolean\n size?: SidebarSize\n }\n>(({ className, asChild = false, showOnHover = false, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-action\"\n className={cn(sidebarMenuActionVariants({ size: resolvedSize, showOnHover }), className)}\n {...props}\n />\n )\n})\nSidebarMenuAction.displayName = 'SidebarMenuAction'\n\nconst sidebarMenuBadgeVariants = cva(\n 'text-sidebar-foreground pointer-events-none absolute flex items-center justify-center rounded-md font-medium tabular-nums select-none peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-data-[state=collapsed]:group-data-[variant=hidden]:hidden group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n {\n variants: {\n size: {\n small: 'top-1.5 right-1 h-5 min-w-5 px-1 text-xs',\n medium: 'top-2.5 right-1 h-5 min-w-5 px-1 text-xs',\n big: 'top-3 right-1.5 h-6 min-w-6 px-1.5 text-sm',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuBadge = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'> & { size?: SidebarSize }>(\n ({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-badge\"\n className={cn(sidebarMenuBadgeVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n },\n)\nSidebarMenuBadge.displayName = 'SidebarMenuBadge'\n\nconst SIDEBAR_MENU_SKELETON: Record<SidebarSize, { row: string; icon: string; text: string }> = {\n small: { row: 'h-8 gap-2 px-2', icon: 'size-4', text: 'h-4' },\n medium: { row: 'h-10 gap-3 px-2.5', icon: 'size-5', text: 'h-4' },\n big: { row: 'h-12 gap-4 px-3', icon: 'size-6', text: 'h-5' },\n}\n\nconst SidebarMenuSkeleton = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n showIcon?: boolean\n size?: SidebarSize\n }\n>(({ className, showIcon = false, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n const dims = SIDEBAR_MENU_SKELETON[resolvedSize]\n\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor((window.crypto.getRandomValues(new Uint32Array(1))[0] % 40) + 50)}%`\n }, [])\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-skeleton\"\n className={cn('flex items-center rounded-md', dims.row, className)}\n {...props}\n >\n {showIcon && <Skeleton className={cn('rounded-md', dims.icon)} data-sidebar=\"menu-skeleton-icon\" />}\n <Skeleton\n className={cn('max-w-(--skeleton-width) flex-1', dims.text)}\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n '--skeleton-width': width,\n } as React.CSSProperties\n }\n />\n </div>\n )\n})\nSidebarMenuSkeleton.displayName = 'SidebarMenuSkeleton'\n\nconst sidebarMenuSubVariants = cva(\n 'border-sidebar-border flex min-w-0 flex-col gap-1 border-l py-0.5 group-data-[state=collapsed]:hidden',\n {\n variants: {\n size: {\n small: 'ml-[15px] pl-2.5',\n medium: 'ml-[19px] pl-2.5',\n big: 'ml-[23px] pl-3',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuSub = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'> & { size?: SidebarSize }>(\n ({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <ul\n ref={ref}\n data-sidebar=\"menu-sub\"\n className={cn(sidebarMenuSubVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n },\n)\nSidebarMenuSub.displayName = 'SidebarMenuSub'\n\nconst SidebarMenuSubItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(({ ...props }, ref) => (\n <li ref={ref} {...props} />\n))\nSidebarMenuSubItem.displayName = 'SidebarMenuSubItem'\n\nconst sidebarMenuSubButtonVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex w-full min-w-0 items-center gap-2 overflow-hidden rounded-md outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground group-data-[state=collapsed]:hidden [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'h-8 px-2',\n medium: 'h-10 px-2.5',\n big: 'h-12 px-3',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuSubButton = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<'a'> & {\n asChild?: boolean\n isActive?: boolean\n size?: SidebarSize\n }\n>(({ asChild = false, isActive, className, children, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'a'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-sub-button\"\n data-active={isActive}\n className={cn(sidebarMenuSubButtonVariants({ size: resolvedSize }), className)}\n {...props}\n >\n {typeof children === 'string' ? <Typography variant=\"body-md\">{children}</Typography> : children}\n </Comp>\n )\n})\nSidebarMenuSubButton.displayName = 'SidebarMenuSubButton'\n\nexport {\n SidebarRoot,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n sidebarGroupActionVariants,\n sidebarGroupLabelVariants,\n sidebarMenuActionVariants,\n sidebarMenuBadgeVariants,\n sidebarMenuButtonVariants,\n sidebarMenuSubButtonVariants,\n sidebarMenuSubVariants,\n useSidebar,\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAmBA;AACA;AACA;AACA;AACA;AAIA;AAAwD;AAC/C;AACC;AAEV;AAaA;AAEA;AACE;AACA;AACE;AAAmE;AAGrE;AACF;AAEA;AAA8B;AAU1B;AACgB;AACR;AACQ;AACP;AACP;AACA;AACA;AACG;AAIL;AACA;AAIA;AACA;AACA;AAAsB;AAElB;AACA;AACE;AAAqB;AAErB;AAAkB;AAIpB;AAAgG;AAClG;AACkB;AAIpB;AACE;AAAmE;AAIrE;AACE;AACE;AACE;AACA;AAAc;AAChB;AAGF;AACA;AAAgE;AAKlE;AAEA;AAA2B;AAClB;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAC+E;AAGjF;AAGM;AAAC;AAAA;AAEG;AACqB;AAC4B;AAC5C;AACL;AAEwG;AAC1G;AACI;AAEH;AAAA;AAGP;AAGN;AACA;AAEA;AAOE;AAEA;AACE;AAEI;AAAC;AAAA;AACc;AACD;AACF;AAER;AACqB;AACrB;AAEF;AAEA;AACE;AAAmB;AAC2B;AAChD;AACuD;AAAA;AAAA;AAE3D;AAIJ;AACE;AAAC;AAAA;AACC;AACU;AACE;AACD;AACG;AAGd;AAAA;AAAC;AAAA;AACY;AACT;AACyB;AACD;AACxB;AACF;AAAA;AACF;AACA;AAAC;AAAA;AACY;AACT;AAEI;AACE;AACyB;AACD;AAE1B;AACE;AACyB;AACD;AAC1B;AACJ;AACA;AACF;AACI;AAIJ;AAAA;AACF;AAAA;AAAA;AAGN;AACA;AAEA;AAA6B;AAEzB;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACL;AACsD;AAE5D;AACA;AAAc;AAChB;AACI;AACyB;AAEW;AAAA;AAC1C;AAGN;AACA;AAEA;AAA0B;AAEtB;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACF;AACD;AACD;AACH;AACK;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AACI;AAAA;AACN;AAGN;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACW;AACT;AACA;AACA;AACF;AACI;AAAA;AAGV;AACA;AAEA;AAA0D;AACjD;AACC;AAEV;AAEA;AAIE;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACF;AACT;AACiC;AACjC;AACF;AACI;AAAA;AAGV;AACA;AAEA;AACE;AACF;AACA;AAEA;AACE;AACF;AACA;AAEA;AAA+B;AAE3B;AACE;AAAC;AAAA;AACC;AACa;AAC2C;AACpD;AAAA;AACN;AAGN;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACa;AACF;AACT;AACA;AACA;AACF;AACI;AAAA;AAGV;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACa;AACuD;AAChE;AAAA;AAGV;AACA;AAEA;AAAkC;AAChC;AACA;AACY;AACF;AAEF;AAEA;AACG;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAAuF;AAC9E;AACC;AAEV;AAEA;AAIE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC6D;AACtE;AAOF;AAAA;AAIR;AACA;AAEA;AAAmC;AACjC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAIE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC8D;AACvE;AAAA;AAGV;AACA;AAEA;AAAkC;AAIlC;AACA;AAEA;AAGA;AAEA;AAGA;AAEA;AAAkC;AAChC;AACA;AACY;AACC;AACY;AACV;AACX;AACM;AACG;AACC;AACH;AACP;AACF;AACiB;AACN;AACH;AACR;AAEJ;AAEA;AAAgC;AAc5B;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACA;AACsE;AAC/E;AAEH;AAAA;AAIL;AACE;AAAO;AAGT;AACE;AAAU;AACE;AACZ;AAGF;AAEI;AAAgC;AACoE;AACtG;AAGN;AACA;AAEA;AAAkC;AAChC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACa;AACL;AACC;AACT;AACF;AACiB;AACT;AACO;AACf;AAEJ;AAEA;AAQE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC0E;AACnF;AAAA;AAGV;AACA;AAEA;AAAiC;AAC/B;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAA+B;AAE3B;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC4D;AACrE;AAAA;AACN;AAGN;AACA;AAEA;AAAgG;AAClC;AACI;AAElE;AAEA;AAOE;AACA;AACA;AAGA;AACE;AAAsF;AAGxF;AACE;AAAC;AAAA;AACC;AACa;AACoD;AAC7D;AAEH;AAAgG;AACjG;AAAC;AAAA;AAC2D;AAC7C;AAEX;AACsB;AACtB;AAAA;AAEJ;AAAA;AAAA;AAGN;AACA;AAEA;AAA+B;AAC7B;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAA6B;AAEzB;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC0D;AACnE;AAAA;AACN;AAGN;AACA;AAEA;AAGA;AAEA;AAAqC;AACnC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAQE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACA;AACgE;AACzE;AAEoF;AAAA;AAG9F;AACA;;"}
|
|
1
|
+
{"version":3,"file":"Sidebar.js","sources":["../../../src/components/Sidebar/Sidebar.tsx"],"sourcesContent":["'use client'\n\nimport { List } from '@phosphor-icons/react/dist/ssr/List'\nimport { SidebarSimple } from '@phosphor-icons/react/dist/ssr/SidebarSimple'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../../lib/useMobile'\nimport { Button } from '../Button'\nimport { Input } from '../Input'\nimport { Separator } from '../Separator'\nimport { SheetContent, SheetDescription, SheetHeader, SheetRoot, SheetTitle } from '../Sheet'\nimport { Skeleton } from '../Skeleton'\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '../Tooltip'\nimport { Typography } from '../Typography'\n\nimport { cn } from '@/lib/utils'\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar_state'\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = '16rem'\nconst SIDEBAR_WIDTH_MOBILE = '18rem'\nconst SIDEBAR_KEYBOARD_SHORTCUT = 'b'\n\nexport type SidebarSize = 'small' | 'medium' | 'big'\n\nconst SIDEBAR_WIDTH_ICON: Record<SidebarSize, string> = {\n small: '3rem',\n medium: '3.5rem',\n big: '4rem',\n}\n\ntype SidebarContext = {\n state: 'expanded' | 'collapsed'\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n size: SidebarSize\n}\n\nconst SidebarContext = React.createContext<SidebarContext | null>(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error('useSidebar must be used within a SidebarProvider.')\n }\n\n return context\n}\n\nconst SidebarProvider = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n size?: SidebarSize\n }\n>(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n size = 'small',\n className,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === 'function' ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open],\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [toggleSidebar])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? 'expanded' : 'collapsed'\n\n const contextValue = React.useMemo<SidebarContext>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n size,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, size],\n )\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delayDuration={0}>\n <div\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON[size],\n ...style,\n } as React.CSSProperties\n }\n className={cn('group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', className)}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n )\n },\n)\nSidebarProvider.displayName = 'SidebarProvider'\n\nconst SidebarRoot = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n side?: 'left' | 'right'\n variant?: 'default' | 'hidden'\n }\n>(({ side = 'left', variant = 'default', className, children, ...props }, ref) => {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n\n if (isMobile) {\n return (\n <SheetRoot open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n className=\"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </SheetRoot>\n )\n }\n\n return (\n <div\n ref={ref}\n className=\"group peer text-sidebar-foreground hidden shadow-md md:block\"\n data-state={state}\n data-side={side}\n data-variant={variant}\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n className={cn(\n 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:w-0',\n 'group-data-[side=right]:rotate-180',\n )}\n />\n <div\n className={cn(\n 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',\n side === 'left'\n ? [\n 'left-0',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:-left-(--sidebar-width)',\n ]\n : [\n 'right-0',\n variant === 'default' && 'group-data-[state=collapsed]:w-(--sidebar-width-icon)',\n variant === 'hidden' && 'group-data-[state=collapsed]:-right-(--sidebar-width)',\n ],\n 'group-data-[side=left]:border-r group-data-[side=right]:border-l',\n className,\n )}\n {...props}\n >\n <div data-sidebar=\"sidebar\" className=\"bg-sidebar flex h-full w-full flex-col\">\n {children}\n </div>\n </div>\n </div>\n )\n})\nSidebarRoot.displayName = 'SidebarRoot'\n\nconst SidebarTrigger = React.forwardRef<React.ComponentRef<typeof Button>, React.ComponentProps<typeof Button>>(\n ({ className, onClick, ...props }, ref) => {\n const { isMobile, toggleSidebar } = useSidebar()\n\n return (\n <Button\n ref={ref}\n data-sidebar=\"trigger\"\n variant=\"text\"\n className={cn('text-primary-foreground h-8 w-8 p-1', className)}\n onClick={(event) => {\n onClick?.(event)\n toggleSidebar()\n }}\n {...props}\n StartIcon={isMobile ? List : SidebarSimple}\n >\n <span className=\"sr-only\">Toggle Sidebar</span>\n </Button>\n )\n },\n)\nSidebarTrigger.displayName = 'SidebarTrigger'\n\nconst SidebarRail = React.forwardRef<HTMLButtonElement, React.ComponentProps<'button'>>(\n ({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar()\n\n return (\n <button\n ref={ref}\n data-sidebar=\"rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n 'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 sm:flex',\n 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',\n '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',\n 'group-data-[variant=offcanvas]:hover:bg-sidebar group-data-[variant=offcanvas]:translate-x-0 group-data-[variant=offcanvas]:after:left-full',\n '[[data-side=left][data-variant=offcanvas]_&]:-right-2',\n '[[data-side=right][data-variant=offcanvas]_&]:-left-2',\n className,\n )}\n {...props}\n />\n )\n },\n)\nSidebarRail.displayName = 'SidebarRail'\n\nconst SidebarInset = React.forwardRef<HTMLDivElement, React.ComponentProps<'main'>>(({ className, ...props }, ref) => {\n return (\n <main\n ref={ref}\n className={cn(\n 'bg-background relative flex w-full flex-1 flex-col',\n 'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2',\n className,\n )}\n {...props}\n />\n )\n})\nSidebarInset.displayName = 'SidebarInset'\n\nconst SIDEBAR_INPUT_HEIGHT: Record<SidebarSize, string> = {\n small: 'h-8',\n medium: 'h-10',\n big: 'h-12',\n}\n\nconst SidebarInput = React.forwardRef<\n React.ComponentRef<typeof Input>,\n React.ComponentProps<typeof Input> & { size?: SidebarSize }\n>(({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Input\n ref={ref}\n data-sidebar=\"input\"\n className={cn(\n 'bg-background focus-visible:ring-sidebar-ring w-full shadow-none focus-visible:ring-2',\n SIDEBAR_INPUT_HEIGHT[resolvedSize],\n className,\n )}\n {...props}\n />\n )\n})\nSidebarInput.displayName = 'SidebarInput'\n\nconst SidebarHeader = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return <div ref={ref} data-sidebar=\"header\" className={cn('flex flex-col gap-2 p-2', className)} {...props} />\n})\nSidebarHeader.displayName = 'SidebarHeader'\n\nconst SidebarFooter = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return <div ref={ref} data-sidebar=\"footer\" className={cn('flex flex-col gap-2 p-2', className)} {...props} />\n})\nSidebarFooter.displayName = 'SidebarFooter'\n\nconst SidebarSeparator = React.forwardRef<React.ComponentRef<typeof Separator>, React.ComponentProps<typeof Separator>>(\n ({ className, ...props }, ref) => {\n return (\n <Separator\n ref={ref}\n data-sidebar=\"separator\"\n className={cn('bg-sidebar-border mx-2 w-auto', className)}\n {...props}\n />\n )\n },\n)\nSidebarSeparator.displayName = 'SidebarSeparator'\n\nconst SidebarContent = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"content\"\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-2 overflow-auto',\n 'group-data-[variant=default]:group-data-[state=collapsed]:overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n})\nSidebarContent.displayName = 'SidebarContent'\n\nconst SidebarGroup = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"group\"\n className={cn('relative flex w-full min-w-0 flex-col p-2', className)}\n {...props}\n />\n )\n})\nSidebarGroup.displayName = 'SidebarGroup'\n\nconst sidebarGroupLabelVariants = cva(\n 'text-sidebar-foreground/70 ring-sidebar-ring flex shrink-0 items-center rounded-md transition-[margin,opacity] duration-200 ease-linear outline-none focus-visible:ring-2 [&>svg]:shrink-0 group-data-[state=collapsed]:group-data-[variant=hidden]:hidden',\n {\n variants: {\n size: {\n small:\n 'h-8 px-2 [&>svg]:size-4 group-data-[state=collapsed]:group-data-[variant=default]:-mt-8 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n medium:\n 'h-9 px-2.5 [&>svg]:size-4 group-data-[state=collapsed]:group-data-[variant=default]:-mt-9 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n big: 'h-10 px-3 [&>svg]:size-5 group-data-[state=collapsed]:group-data-[variant=default]:-mt-10 group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SIDEBAR_GROUP_LABEL_TEXT_VARIANT: Record<SidebarSize, 'label-md' | 'label-lg'> = {\n small: 'label-md',\n medium: 'label-md',\n big: 'label-lg',\n}\n\nconst SidebarGroupLabel = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & { asChild?: boolean; size?: SidebarSize }\n>(({ className, asChild = false, size, children, ...props }, ref) => {\n const Comp = asChild ? Slot : 'div'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-label\"\n className={cn(sidebarGroupLabelVariants({ size: resolvedSize }), className)}\n {...props}\n >\n {typeof children === 'string' ? (\n <Typography variant={SIDEBAR_GROUP_LABEL_TEXT_VARIANT[resolvedSize]} color=\"secondary\">\n {children}\n </Typography>\n ) : (\n children\n )}\n </Comp>\n )\n})\nSidebarGroupLabel.displayName = 'SidebarGroupLabel'\n\nconst sidebarGroupActionVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute flex aspect-square items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 after:absolute after:-inset-2 after:md:hidden group-data-[state=collapsed]:hidden [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'top-3.5 right-3 w-5 [&>svg]:size-4',\n medium: 'top-4 right-3 w-5 [&>svg]:size-4',\n big: 'top-4 right-3 w-6 [&>svg]:size-5',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarGroupAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & { asChild?: boolean; size?: SidebarSize }\n>(({ className, asChild = false, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-action\"\n className={cn(sidebarGroupActionVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n})\nSidebarGroupAction.displayName = 'SidebarGroupAction'\n\nconst SidebarGroupContent = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} data-sidebar=\"group-content\" className={cn('w-full text-sm', className)} {...props} />\n ),\n)\nSidebarGroupContent.displayName = 'SidebarGroupContent'\n\nconst SidebarMenu = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(({ className, ...props }, ref) => (\n <ul ref={ref} data-sidebar=\"menu\" className={cn('flex w-full min-w-0 flex-col gap-1', className)} {...props} />\n))\nSidebarMenu.displayName = 'SidebarMenu'\n\nconst SidebarMenuItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(({ className, ...props }, ref) => (\n <li ref={ref} data-sidebar=\"menu-item\" className={cn('group/menu-item relative', className)} {...props} />\n))\nSidebarMenuItem.displayName = 'SidebarMenuItem'\n\nconst sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full text-sm hover:bg-sidebar-accent hover:text-sidebar-accent-foreground items-center overflow-hidden rounded-md text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=expanded]:hover:bg-sidebar-accent data-[state=expanded]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n 'navigation-item': '',\n element: 'group-data-[state=collapsed]:!p-0',\n },\n size: {\n small: 'h-8 gap-2 p-2 [&>svg]:size-4',\n medium: 'h-10 gap-3 p-2.5 [&>svg]:size-5',\n big: 'h-12 gap-4 p-3 [&>svg]:size-6',\n },\n },\n defaultVariants: {\n variant: 'navigation-item',\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & {\n asChild?: boolean\n isActive?: boolean\n tooltip?: string | React.ComponentProps<typeof TooltipContent>\n variant?: 'navigation-item' | 'element'\n size?: SidebarSize\n }\n>(\n (\n { asChild = false, isActive = false, tooltip, className, children, variant = 'navigation-item', size, ...props },\n ref,\n ) => {\n const Comp = asChild ? Slot : 'button'\n const { isMobile, state, size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n const button = (\n <Comp\n ref={ref}\n data-sidebar=\"menu-button\"\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size: resolvedSize }), className)}\n {...props}\n >\n {children}\n </Comp>\n )\n\n if (!tooltip) {\n return button\n }\n\n if (typeof tooltip === 'string') {\n tooltip = {\n children: tooltip,\n }\n }\n\n return (\n <TooltipRoot>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent side=\"right\" align=\"center\" hidden={state !== 'collapsed' || isMobile} {...tooltip} />\n </TooltipRoot>\n )\n },\n)\nSidebarMenuButton.displayName = 'SidebarMenuButton'\n\nconst sidebarMenuActionVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute flex aspect-square items-center justify-center rounded-md p-0 transition-transform outline-none focus-visible:ring-2 after:absolute after:-inset-2 after:md:hidden group-data-[state=collapsed]:hidden [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'top-1.5 right-1 w-5 [&>svg]:size-4',\n medium: 'top-2.5 right-1 w-5 [&>svg]:size-4',\n big: 'top-3 right-1.5 w-6 [&>svg]:size-5',\n },\n showOnHover: {\n true: 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=expanded]:opacity-100 md:opacity-0',\n false: '',\n },\n },\n defaultVariants: {\n size: 'small',\n showOnHover: false,\n },\n },\n)\n\nconst SidebarMenuAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'> & {\n asChild?: boolean\n showOnHover?: boolean\n size?: SidebarSize\n }\n>(({ className, asChild = false, showOnHover = false, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-action\"\n className={cn(sidebarMenuActionVariants({ size: resolvedSize, showOnHover }), className)}\n {...props}\n />\n )\n})\nSidebarMenuAction.displayName = 'SidebarMenuAction'\n\nconst sidebarMenuBadgeVariants = cva(\n 'text-sidebar-foreground pointer-events-none absolute flex items-center justify-center rounded-md font-medium tabular-nums select-none peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-data-[state=collapsed]:group-data-[variant=hidden]:hidden group-data-[state=collapsed]:group-data-[variant=default]:opacity-0',\n {\n variants: {\n size: {\n small: 'top-1.5 right-1 h-5 min-w-5 px-1 text-xs',\n medium: 'top-2.5 right-1 h-5 min-w-5 px-1 text-xs',\n big: 'top-3 right-1.5 h-6 min-w-6 px-1.5 text-sm',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuBadge = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'> & { size?: SidebarSize }>(\n ({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-badge\"\n className={cn(sidebarMenuBadgeVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n },\n)\nSidebarMenuBadge.displayName = 'SidebarMenuBadge'\n\nconst SIDEBAR_MENU_SKELETON: Record<SidebarSize, { row: string; icon: string; text: string }> = {\n small: { row: 'h-8 gap-2 px-2', icon: 'size-4', text: 'h-4' },\n medium: { row: 'h-10 gap-3 px-2.5', icon: 'size-5', text: 'h-4' },\n big: { row: 'h-12 gap-4 px-3', icon: 'size-6', text: 'h-5' },\n}\n\nconst SidebarMenuSkeleton = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n showIcon?: boolean\n size?: SidebarSize\n }\n>(({ className, showIcon = false, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n const dims = SIDEBAR_MENU_SKELETON[resolvedSize]\n\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor((window.crypto.getRandomValues(new Uint32Array(1))[0] % 40) + 50)}%`\n }, [])\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-skeleton\"\n className={cn('flex items-center rounded-md', dims.row, className)}\n {...props}\n >\n {showIcon && <Skeleton className={cn('rounded-md', dims.icon)} data-sidebar=\"menu-skeleton-icon\" />}\n <Skeleton\n className={cn('max-w-(--skeleton-width) flex-1', dims.text)}\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n '--skeleton-width': width,\n } as React.CSSProperties\n }\n />\n </div>\n )\n})\nSidebarMenuSkeleton.displayName = 'SidebarMenuSkeleton'\n\nconst sidebarMenuSubVariants = cva(\n 'border-sidebar-border flex min-w-0 flex-col gap-1 border-l py-0.5 group-data-[state=collapsed]:hidden',\n {\n variants: {\n size: {\n small: 'ml-[15px] pl-2.5',\n medium: 'ml-[19px] pl-2.5',\n big: 'ml-[23px] pl-3',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuSub = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'> & { size?: SidebarSize }>(\n ({ className, size, ...props }, ref) => {\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <ul\n ref={ref}\n data-sidebar=\"menu-sub\"\n className={cn(sidebarMenuSubVariants({ size: resolvedSize }), className)}\n {...props}\n />\n )\n },\n)\nSidebarMenuSub.displayName = 'SidebarMenuSub'\n\nconst SidebarMenuSubItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(({ ...props }, ref) => (\n <li ref={ref} {...props} />\n))\nSidebarMenuSubItem.displayName = 'SidebarMenuSubItem'\n\nconst sidebarMenuSubButtonVariants = cva(\n 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex w-full min-w-0 items-center gap-2 overflow-hidden rounded-md outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground group-data-[state=collapsed]:hidden [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n size: {\n small: 'h-8 px-2',\n medium: 'h-9 px-2.5',\n big: 'h-10 px-3',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n },\n)\n\nconst SidebarMenuSubButton = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<'a'> & {\n asChild?: boolean\n isActive?: boolean\n size?: SidebarSize\n }\n>(({ asChild = false, isActive, className, children, size, ...props }, ref) => {\n const Comp = asChild ? Slot : 'a'\n const { size: contextSize } = useSidebar()\n const resolvedSize = size ?? contextSize\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-sub-button\"\n data-active={isActive}\n className={cn(sidebarMenuSubButtonVariants({ size: resolvedSize }), className)}\n {...props}\n >\n {typeof children === 'string' ? <Typography variant=\"body-md\">{children}</Typography> : children}\n </Comp>\n )\n})\nSidebarMenuSubButton.displayName = 'SidebarMenuSubButton'\n\nexport {\n SidebarRoot,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n sidebarGroupActionVariants,\n sidebarGroupLabelVariants,\n sidebarMenuActionVariants,\n sidebarMenuBadgeVariants,\n sidebarMenuButtonVariants,\n sidebarMenuSubButtonVariants,\n sidebarMenuSubVariants,\n useSidebar,\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAmBA;AACA;AACA;AACA;AACA;AAIA;AAAwD;AAC/C;AACC;AAEV;AAaA;AAEA;AACE;AACA;AACE;AAAmE;AAGrE;AACF;AAEA;AAA8B;AAU1B;AACgB;AACR;AACQ;AACP;AACP;AACA;AACA;AACG;AAIL;AACA;AAIA;AACA;AACA;AAAsB;AAElB;AACA;AACE;AAAqB;AAErB;AAAkB;AAIpB;AAAgG;AAClG;AACkB;AAIpB;AACE;AAAmE;AAIrE;AACE;AACE;AACE;AACA;AAAc;AAChB;AAGF;AACA;AAAgE;AAKlE;AAEA;AAA2B;AAClB;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAC+E;AAGjF;AAGM;AAAC;AAAA;AAEG;AACqB;AAC4B;AAC5C;AACL;AAEwG;AAC1G;AACI;AAEH;AAAA;AAGP;AAGN;AACA;AAEA;AAOE;AAEA;AACE;AAEI;AAAC;AAAA;AACc;AACD;AACF;AAER;AACqB;AACrB;AAEF;AAEA;AACE;AAAmB;AAC2B;AAChD;AACuD;AAAA;AAAA;AAE3D;AAIJ;AACE;AAAC;AAAA;AACC;AACU;AACE;AACD;AACG;AAGd;AAAA;AAAC;AAAA;AACY;AACT;AACyB;AACD;AACxB;AACF;AAAA;AACF;AACA;AAAC;AAAA;AACY;AACT;AAEI;AACE;AACyB;AACD;AAE1B;AACE;AACyB;AACD;AAC1B;AACJ;AACA;AACF;AACI;AAIJ;AAAA;AACF;AAAA;AAAA;AAGN;AACA;AAEA;AAA6B;AAEzB;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACL;AACsD;AAE5D;AACA;AAAc;AAChB;AACI;AACyB;AAEW;AAAA;AAC1C;AAGN;AACA;AAEA;AAA0B;AAEtB;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACF;AACD;AACD;AACH;AACK;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AACI;AAAA;AACN;AAGN;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACW;AACT;AACA;AACA;AACF;AACI;AAAA;AAGV;AACA;AAEA;AAA0D;AACjD;AACC;AAEV;AAEA;AAIE;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACF;AACT;AACiC;AACjC;AACF;AACI;AAAA;AAGV;AACA;AAEA;AACE;AACF;AACA;AAEA;AACE;AACF;AACA;AAEA;AAA+B;AAE3B;AACE;AAAC;AAAA;AACC;AACa;AAC2C;AACpD;AAAA;AACN;AAGN;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACa;AACF;AACT;AACA;AACA;AACF;AACI;AAAA;AAGV;AACA;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACa;AACuD;AAChE;AAAA;AAGV;AACA;AAEA;AAAkC;AAChC;AACA;AACY;AACF;AAEF;AAEA;AACG;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAAuF;AAC9E;AACC;AAEV;AAEA;AAIE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC6D;AACtE;AAOF;AAAA;AAIR;AACA;AAEA;AAAmC;AACjC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAIE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC8D;AACvE;AAAA;AAGV;AACA;AAEA;AAAkC;AAIlC;AACA;AAEA;AAGA;AAEA;AAGA;AAEA;AAAkC;AAChC;AACA;AACY;AACC;AACY;AACV;AACX;AACM;AACG;AACC;AACH;AACP;AACF;AACiB;AACN;AACH;AACR;AAEJ;AAEA;AAAgC;AAc5B;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACA;AACsE;AAC/E;AAEH;AAAA;AAIL;AACE;AAAO;AAGT;AACE;AAAU;AACE;AACZ;AAGF;AAEI;AAAgC;AACoE;AACtG;AAGN;AACA;AAEA;AAAkC;AAChC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACa;AACL;AACC;AACT;AACF;AACiB;AACT;AACO;AACf;AAEJ;AAEA;AAQE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC0E;AACnF;AAAA;AAGV;AACA;AAEA;AAAiC;AAC/B;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAA+B;AAE3B;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC4D;AACrE;AAAA;AACN;AAGN;AACA;AAEA;AAAgG;AAClC;AACI;AAElE;AAEA;AAOE;AACA;AACA;AAGA;AACE;AAAsF;AAGxF;AACE;AAAC;AAAA;AACC;AACa;AACoD;AAC7D;AAEH;AAAgG;AACjG;AAAC;AAAA;AAC2D;AAC7C;AAEX;AACsB;AACtB;AAAA;AAEJ;AAAA;AAAA;AAGN;AACA;AAEA;AAA+B;AAC7B;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAA6B;AAEzB;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AAC0D;AACnE;AAAA;AACN;AAGN;AACA;AAEA;AAGA;AAEA;AAAqC;AACnC;AACA;AACY;AACF;AACG;AACC;AACH;AACP;AACF;AACiB;AACT;AACR;AAEJ;AAEA;AAQE;AACA;AACA;AAEA;AACE;AAAC;AAAA;AACC;AACa;AACA;AACgE;AACzE;AAEoF;AAAA;AAG9F;AACA;;"}
|