@humain/ui 2.2.3 → 2.2.5

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.
Files changed (116) hide show
  1. package/dist/components/templates/AppShell/AppShell.d.ts +1 -1
  2. package/dist/components/templates/AppSidebar/AppSidebar.constants.d.ts +1 -1
  3. package/dist/index11.js +4 -4
  4. package/dist/index11.js.map +1 -1
  5. package/dist/index110.js +4 -4
  6. package/dist/index110.js.map +1 -1
  7. package/dist/index134.js +4 -4
  8. package/dist/index134.js.map +1 -1
  9. package/dist/index135.js +2 -2
  10. package/dist/index135.js.map +1 -1
  11. package/dist/index151.js +3 -3
  12. package/dist/index151.js.map +1 -1
  13. package/dist/index152.js +2 -2
  14. package/dist/index152.js.map +1 -1
  15. package/dist/index155.js +1 -1
  16. package/dist/index155.js.map +1 -1
  17. package/dist/index173.js +1 -1
  18. package/dist/index173.js.map +1 -1
  19. package/dist/index184.js +1 -1
  20. package/dist/index184.js.map +1 -1
  21. package/dist/index188.js +4 -4
  22. package/dist/index188.js.map +1 -1
  23. package/dist/index201.js +1 -1
  24. package/dist/index201.js.map +1 -1
  25. package/dist/index217.js +1 -1
  26. package/dist/index217.js.map +1 -1
  27. package/dist/index223.js.map +1 -1
  28. package/dist/index225.js +3 -3
  29. package/dist/index225.js.map +1 -1
  30. package/dist/index228.js +1 -1
  31. package/dist/index228.js.map +1 -1
  32. package/dist/index24.js +1 -1
  33. package/dist/index24.js.map +1 -1
  34. package/dist/index25.js +4 -4
  35. package/dist/index25.js.map +1 -1
  36. package/dist/index39.js +2 -2
  37. package/dist/index39.js.map +1 -1
  38. package/dist/index5.js +8 -8
  39. package/dist/index5.js.map +1 -1
  40. package/dist/styles.css +1 -1
  41. package/dist/wc/AIScrollButton.js +8 -8
  42. package/dist/wc/AIScrollButton.js.map +1 -1
  43. package/dist/wc/AISource.js +46 -46
  44. package/dist/wc/AISource.js.map +1 -1
  45. package/dist/wc/AIToolCall.js +9 -9
  46. package/dist/wc/AIToolCall.js.map +1 -1
  47. package/dist/wc/AppSidebar.constants.js +1 -1
  48. package/dist/wc/AppSidebar.constants.js.map +1 -1
  49. package/dist/wc/Badge.js +9 -9
  50. package/dist/wc/Badge.js.map +1 -1
  51. package/dist/wc/Checkbox.js +22 -22
  52. package/dist/wc/Checkbox.js.map +1 -1
  53. package/dist/wc/Pagination.js +4 -4
  54. package/dist/wc/Pagination.js.map +1 -1
  55. package/dist/wc/Switch.js +23 -23
  56. package/dist/wc/Switch.js.map +1 -1
  57. package/dist/wc/Tabs.js +110 -110
  58. package/dist/wc/Tabs.js.map +1 -1
  59. package/dist/wc/Tooltip.js +28 -28
  60. package/dist/wc/Tooltip.js.map +1 -1
  61. package/dist/wc/button.js +33 -33
  62. package/dist/wc/button.js.map +1 -1
  63. package/dist/wc/hf-alert.js +10 -10
  64. package/dist/wc/hf-alert.js.map +1 -1
  65. package/dist/wc/hf-app-shell.js.map +1 -1
  66. package/dist/wc/hf-app-sidebar.js +3 -3
  67. package/dist/wc/hf-app-sidebar.js.map +1 -1
  68. package/dist/wc/hf-nav-account-menu.js +8 -8
  69. package/dist/wc/hf-nav-account-menu.js.map +1 -1
  70. package/dist/wc/hf-steps.js +8 -8
  71. package/dist/wc/hf-steps.js.map +1 -1
  72. package/dist/wc/markdown-renderer.js +5 -5
  73. package/dist/wc/markdown-renderer.js.map +1 -1
  74. package/dist/wc/selection-group.js +6 -6
  75. package/dist/wc/selection-group.js.map +1 -1
  76. package/dist/wc-react/AIScrollButton.js +18 -18
  77. package/dist/wc-react/AIScrollButton.js.map +1 -1
  78. package/dist/wc-react/AISource.js +8 -8
  79. package/dist/wc-react/AISource.js.map +1 -1
  80. package/dist/wc-react/AIToolCall.js +42 -42
  81. package/dist/wc-react/AIToolCall.js.map +1 -1
  82. package/dist/wc-react/AppSidebar.constants.js +1 -1
  83. package/dist/wc-react/AppSidebar.constants.js.map +1 -1
  84. package/dist/wc-react/Badge.js +16 -16
  85. package/dist/wc-react/Badge.js.map +1 -1
  86. package/dist/wc-react/Checkbox.js +14 -14
  87. package/dist/wc-react/Checkbox.js.map +1 -1
  88. package/dist/wc-react/Pagination.js +130 -130
  89. package/dist/wc-react/Pagination.js.map +1 -1
  90. package/dist/wc-react/Switch.js +2 -2
  91. package/dist/wc-react/Switch.js.map +1 -1
  92. package/dist/wc-react/Tabs.js +38 -38
  93. package/dist/wc-react/Tabs.js.map +1 -1
  94. package/dist/wc-react/Tooltip.js +22 -22
  95. package/dist/wc-react/Tooltip.js.map +1 -1
  96. package/dist/wc-react/button.js +8 -8
  97. package/dist/wc-react/button.js.map +1 -1
  98. package/dist/wc-react/hf-alert.js +28 -28
  99. package/dist/wc-react/hf-alert.js.map +1 -1
  100. package/dist/wc-react/hf-app-shell.js.map +1 -1
  101. package/dist/wc-react/hf-app-sidebar.js +3 -3
  102. package/dist/wc-react/hf-app-sidebar.js.map +1 -1
  103. package/dist/wc-react/hf-nav-account-menu.js +7 -7
  104. package/dist/wc-react/hf-nav-account-menu.js.map +1 -1
  105. package/dist/wc-react/hf-steps.js +16 -16
  106. package/dist/wc-react/hf-steps.js.map +1 -1
  107. package/dist/wc-react/markdown-renderer.js +5 -5
  108. package/dist/wc-react/markdown-renderer.js.map +1 -1
  109. package/dist/wc-react/selection-group.js +1 -1
  110. package/dist/wc-react/selection-group.js.map +1 -1
  111. package/package.json +1 -1
  112. package/skills/humain-ui/SKILL.md +1 -1
  113. package/skills/humain-ui-wc/SKILL.md +1 -1
  114. package/skills/humain-ui-wc.skill +0 -0
  115. package/skills/humain-ui.skill +0 -0
  116. package/src/tokens.css +10 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index225.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/noNoninteractiveTabindex: ChatList uses tabIndex on scrollable div for keyboard scrolling */\n/** biome-ignore-all lint/a11y/useSemanticElements: NavSection uses role=\"separator\" on inner <div>; ChatList uses role=\"list\" on scrollable div */\n/** biome-ignore-all lint/a11y/useFocusableInteractive: Non-focusable separator per WAI-ARIA spec for decorative separators */\n/** biome-ignore-all lint/a11y/useAriaPropsForRole: Non-focusable separators don't require aria-valuenow per WAI-ARIA spec */\n/** biome-ignore-all lint/a11y/noNoninteractiveElementToInteractiveRole: role=\"separator\" on <div> inside list items for semantic section boundaries */\n\n'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n ChevronRight,\n MessageCircle,\n PanelLeftClose,\n PanelLeftOpen,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Badge } from '@/components/atoms/display/Badge';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { BrandIcon } from '@/components/molecules/data/BrandIcon';\nimport {\n PopoverPopup,\n PopoverRoot,\n PopoverTrigger,\n} from '@/components/organisms/overlays/Popover';\nimport {\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n} from '@/components/ui/sidebar';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\n\nfunction formatAccessibleLabel(\n label: string,\n badge?: string | number | null,\n): string {\n if (badge == null) return label;\n return `${label}, ${typeof badge === 'number' ? `${badge} ${badge === 1 ? 'item' : 'items'}` : badge}`;\n}\n\nfunction getSidebarBgClass(\n isCollapsed: boolean,\n sidebarBgColor?: string,\n): string {\n return isCollapsed\n ? 'bg-transparent'\n : (sidebarBgColor ?? 'bg-[var(--sidebar)]');\n}\n\nfunction getSidebarSurfaceClass({\n isCollapsed,\n side,\n rounded,\n backgroundClass,\n}: {\n isCollapsed: boolean;\n side: AppSidebarSide;\n rounded: boolean;\n backgroundClass: string;\n}): string {\n return cn(\n 'flex h-full min-h-0 flex-col items-center pb-4 pt-6',\n isCollapsed\n ? 'w-full px-6'\n : [\n 'w-[calc(100%-0.75rem)] px-3',\n side === 'left' ? 'mr-3 self-start' : 'ml-3 self-end',\n ],\n backgroundClass,\n rounded && (side === 'left' ? 'rounded-r-lg' : 'rounded-l-lg'),\n );\n}\n\nfunction getSkeletonCount(count: number | undefined, fallback: number): number {\n return typeof count === 'number' && Number.isFinite(count) && count >= 0\n ? Math.floor(count)\n : fallback;\n}\n\n// ============================================\n// Slot Distribution Hook\n// ============================================\n\nconst APP_SIDEBAR_IMPLICIT_SLOT = Symbol('AppSidebarImplicitSlot');\n\ntype AppSidebarImplicitSlot = 'header' | 'content' | 'footer';\n\ninterface AppSidebarImplicitSlotComponent {\n [APP_SIDEBAR_IMPLICIT_SLOT]: AppSidebarImplicitSlot;\n}\n\ninterface AppSidebarWrappedComponent {\n type?: unknown;\n render?: unknown;\n}\n\nfunction markAppSidebarImplicitSlot<Component extends object>(\n component: Component,\n slot: AppSidebarImplicitSlot,\n): Component & AppSidebarImplicitSlotComponent {\n const slottedComponent = component as Component &\n AppSidebarImplicitSlotComponent;\n slottedComponent[APP_SIDEBAR_IMPLICIT_SLOT] = slot;\n return slottedComponent;\n}\n\nfunction isAppSidebarImplicitSlotComponent(\n value: unknown,\n): value is AppSidebarImplicitSlotComponent {\n return (\n (typeof value === 'function' ||\n (typeof value === 'object' && value !== null)) &&\n APP_SIDEBAR_IMPLICIT_SLOT in value\n );\n}\n\nfunction getAppSidebarImplicitSlot(\n childType: unknown,\n): AppSidebarImplicitSlot | undefined {\n if (isAppSidebarImplicitSlotComponent(childType)) {\n return childType[APP_SIDEBAR_IMPLICIT_SLOT];\n }\n\n if (typeof childType === 'object' && childType !== null) {\n const wrappedComponent = childType as AppSidebarWrappedComponent;\n return (\n getAppSidebarImplicitSlot(wrappedComponent.type) ??\n getAppSidebarImplicitSlot(wrappedComponent.render)\n );\n }\n\n return undefined;\n}\n\ntype SlotResult = {\n header: React.ReactNode[];\n content: React.ReactNode[];\n footer: React.ReactNode[];\n explicitHeader: React.ReactElement | null;\n explicitContent: React.ReactElement | null;\n explicitFooter: React.ReactElement | null;\n};\n\nfunction useSlotChildren(children: React.ReactNode): SlotResult {\n return React.useMemo(() => {\n const result: SlotResult = {\n header: [],\n content: [],\n footer: [],\n explicitHeader: null,\n explicitContent: null,\n explicitFooter: null,\n };\n\n React.Children.forEach(children, (child) => {\n if (!React.isValidElement(child)) return;\n\n const childType = child.type;\n\n // Check for explicit slot components\n if (childType === AppSidebarHeader) {\n result.explicitHeader = child;\n return;\n }\n if (childType === AppSidebarContent) {\n result.explicitContent = child;\n return;\n }\n if (childType === AppSidebarFooter) {\n result.explicitFooter = child;\n return;\n }\n\n // Distribute to slots based on explicit component-owned slot markers.\n const implicitSlot = getAppSidebarImplicitSlot(childType);\n if (implicitSlot === 'header') {\n result.header.push(child);\n } else if (implicitSlot === 'content') {\n result.content.push(child);\n } else if (implicitSlot === 'footer') {\n result.footer.push(child);\n } else {\n // Unknown children go to content by default\n result.content.push(child);\n }\n });\n\n return result;\n }, [children]);\n}\n\ntype AppSidebarSide = 'left' | 'right';\ntype AppSidebarDirection = 'ltr' | 'rtl';\n\nconst AppSidebarLayoutContext = React.createContext<{ side: AppSidebarSide }>({\n side: 'left',\n});\n\nfunction useAppSidebarLayout() {\n return React.useContext(AppSidebarLayoutContext);\n}\n\nfunction getAppSidebarDirection(\n element: HTMLElement | null,\n): AppSidebarDirection {\n const win = element?.ownerDocument.defaultView;\n if (!element || !win) return 'ltr';\n return win.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\nfunction normalizeAppSidebarDirection(\n dir: string | undefined,\n): AppSidebarDirection | undefined {\n return dir === 'rtl' || dir === 'ltr' ? dir : undefined;\n}\n\nfunction getAppSidebarSideFromDirection(\n direction: AppSidebarDirection,\n): AppSidebarSide {\n return direction === 'rtl' ? 'right' : 'left';\n}\n\nfunction getAppSidebarDirectionTargets(element: HTMLElement): Element[] {\n const targets = new Set<Element>();\n let current: Element | null = element;\n\n while (current) {\n targets.add(current);\n if (current === element.ownerDocument.documentElement) break;\n current = current.parentElement;\n }\n\n targets.add(element.ownerDocument.documentElement);\n if (element.ownerDocument.body) targets.add(element.ownerDocument.body);\n\n return Array.from(targets);\n}\n\nfunction useResolvedAppSidebarSide({\n containerRef,\n explicitDir,\n explicitSide,\n}: {\n containerRef: React.RefObject<HTMLDivElement | null>;\n explicitDir?: string;\n explicitSide?: AppSidebarSide;\n}): AppSidebarSide {\n const [detectedDirection, setDetectedDirection] =\n React.useState<AppSidebarDirection>(\n () => normalizeAppSidebarDirection(explicitDir) ?? 'ltr',\n );\n\n React.useEffect(() => {\n if (explicitSide) return;\n\n const normalizedExplicitDir = normalizeAppSidebarDirection(explicitDir);\n if (normalizedExplicitDir) {\n setDetectedDirection((current) =>\n current === normalizedExplicitDir ? current : normalizedExplicitDir,\n );\n return;\n }\n\n const container = containerRef.current;\n const win = container?.ownerDocument.defaultView;\n if (!container || !win) return;\n\n const detectDirection = () => {\n const nextDirection = getAppSidebarDirection(container);\n setDetectedDirection((current) =>\n current === nextDirection ? current : nextDirection,\n );\n };\n\n detectDirection();\n\n const Observer = win.MutationObserver;\n if (!Observer) return;\n\n const observer = new Observer(detectDirection);\n for (const target of getAppSidebarDirectionTargets(container)) {\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['dir', 'class', 'style'],\n });\n }\n\n return () => observer.disconnect();\n }, [containerRef, explicitDir, explicitSide]);\n\n return explicitSide ?? getAppSidebarSideFromDirection(detectedDirection);\n}\n\n// ============================================\n// Sidebar Logo\n// ============================================\n\nexport interface AppSidebarLogoProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo image or element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n subtext?: string;\n}\n\nconst DEFAULT_COMPACTED_LOGO = (\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n <BrandIcon icon=\"mark\" size=\"sm\" />\n </span>\n);\n\nfunction AppSidebarLogo({\n logo,\n compactedLogo,\n subtext,\n className,\n ...props\n}: AppSidebarLogoProps) {\n const { state, toggleSidebar } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const effectiveCompactedLogo = compactedLogo ?? DEFAULT_COMPACTED_LOGO;\n\n if (isCollapsed) {\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn('flex items-center justify-center', className)}\n {...props}\n dir=\"ltr\"\n >\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"group/logo relative flex size-[52px] items-center justify-center rounded-md p-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Expand sidebar\"\n >\n <span className=\"transition-opacity duration-200 ease-smooth group-hover/logo:opacity-0 motion-reduce:transition-none\">\n {effectiveCompactedLogo}\n </span>\n <PanelLeftOpen className=\"absolute size-5 opacity-0 transition-opacity duration-200 ease-smooth group-hover/logo:opacity-100 motion-reduce:transition-none\" />\n </button>\n </div>\n );\n }\n\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn(\n 'flex h-[52px] items-center justify-between gap-2 rounded-md p-2',\n className,\n )}\n {...props}\n dir=\"ltr\"\n >\n <div className=\"flex min-w-0 flex-col gap-0\">\n <div className=\"flex items-center gap-2\">\n {logo || (\n <>\n {DEFAULT_COMPACTED_LOGO}\n <span className=\"text-lg font-semibold tracking-tight text-foreground\">\n HUMAIN\n </span>\n </>\n )}\n </div>\n {subtext && (\n <p className=\"ps-11 text-sm text-sidebar-foreground\">\n <span data-slot=\"app-sidebar-logo-subtext\">{subtext}</span>\n </p>\n )}\n </div>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"relative flex size-9 items-center justify-center rounded-lg text-sidebar-foreground transition-colors duration-200 ease-smooth hover:bg-sidebar-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none after:absolute after:-inset-1\"\n aria-label=\"Collapse sidebar\"\n >\n <PanelLeftClose aria-hidden=\"true\" className=\"size-5\" />\n </button>\n </div>\n );\n}\n\nAppSidebarLogo.displayName = 'AppSidebar.Logo';\n\n// ============================================\n// Slot Components (Header, Content, Footer)\n// ============================================\n\nexport interface AppSidebarSlotProps {\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarHeader({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-header\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarHeader.displayName = 'AppSidebar.Header';\n\nfunction AppSidebarContent({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-content\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarContent.displayName = 'AppSidebar.Content';\n\nfunction AppSidebarFooter({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-footer\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarFooter.displayName = 'AppSidebar.Footer';\n\n// ============================================\n// Nav Component\n// ============================================\n\nexport interface AppSidebarNavProps {\n children?: React.ReactNode;\n /** Accessible label for the nav landmark (useful when multiple Nav instances exist) */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction AppSidebarNav({\n children,\n 'aria-label': ariaLabel = 'Sidebar navigation',\n className,\n}: AppSidebarNavProps) {\n const menuContent = (\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-1\">\n {React.Children.map(children, (child) => (\n <SidebarMenuItem>{child}</SidebarMenuItem>\n ))}\n </SidebarMenu>\n );\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-nav\"\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <nav aria-label={ariaLabel}>{menuContent}</nav>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNav.displayName = 'AppSidebar.Nav';\nmarkAppSidebarImplicitSlot(AppSidebarNav, 'content');\n\n// ============================================\n// Nav Section (Group Label / Divider)\n// ============================================\n\nexport interface AppSidebarNavSectionProps {\n /** Section label shown when sidebar is expanded */\n label: string;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarNavSection({ label, className }: AppSidebarNavSectionProps) {\n return (\n <div\n data-slot=\"app-sidebar-nav-section\"\n role=\"separator\"\n aria-label={label}\n className={cn('py-2 group-data-[collapsible=icon]:w-[52px]', className)}\n >\n <div className=\"flex h-8 items-center px-2 group-data-[collapsible=icon]:hidden\">\n <span className=\"text-xs font-medium text-sidebar-foreground/80\">\n {label}\n </span>\n </div>\n <div className=\"hidden py-2 group-data-[collapsible=icon]:block\">\n <span className=\"sr-only\">{label}</span>\n <Separator className=\"mx-auto w-full\" />\n </div>\n </div>\n );\n}\n\nAppSidebarNavSection.displayName = 'AppSidebar.NavSection';\n\n// ============================================\n// Nav Item Component\n// ============================================\n\nconst navItemVariants = cva(\n 'relative flex w-full items-center gap-1.5 rounded-lg px-2 py-2 text-sm font-normal transition-[color,background-color] duration-200 ease-smooth motion-reduce:transition-none',\n {\n variants: {\n state: {\n default: 'text-sidebar-foreground hover:bg-sidebar-accent',\n active: 'bg-primary/10 text-sidebar-foreground',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarNavItemProps {\n icon: React.ReactNode;\n label: string;\n isActive?: boolean;\n badge?: string | number;\n onClick?: () => void;\n href?: string;\n className?: string;\n /** Sub-navigation children (AppSidebar.NavSub items). When present, renders as collapsible parent. */\n children?: React.ReactNode;\n}\n\nfunction AppSidebarNavItem({\n icon,\n label,\n isActive = false,\n badge,\n onClick,\n href,\n className,\n children,\n}: AppSidebarNavItemProps) {\n const { state, containerRef } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const hasChildren = React.Children.count(children) > 0;\n const hasActiveChild = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement<{ isActive?: boolean }>(child) &&\n child.props.isActive === true,\n );\n const isHighlighted = isActive || hasActiveChild;\n const [isOpen, setIsOpen] = React.useState(isHighlighted && hasChildren);\n const subNavId = React.useId();\n const floatingSide = sidebarSide === 'right' ? 'left' : 'right';\n const flyoutPanelBackground =\n 'linear-gradient(108deg, var(--opacity-white-87) 0.5219%, var(--opacity-white-75) 98.419%)';\n const flyoutFrameEdgeClassName =\n sidebarSide === 'right'\n ? 'justify-end rounded-l-xl rounded-r-none'\n : 'justify-start rounded-r-xl rounded-l-none';\n const flyoutPanelEdgeClassName =\n sidebarSide === 'right' ? 'rounded-l-xl' : 'rounded-r-xl';\n const flyoutAnchor = React.useMemo(\n () => ({\n getBoundingClientRect: () => {\n const container = containerRef.current;\n const rect = container?.getBoundingClientRect();\n const win = container?.ownerDocument.defaultView;\n const viewportHeight = win?.innerHeight ?? rect?.height ?? 0;\n const x = rect ? (sidebarSide === 'right' ? rect.left : rect.right) : 0;\n\n return {\n x,\n y: 0,\n top: 0,\n right: x,\n bottom: viewportHeight,\n left: x,\n width: 0,\n height: viewportHeight,\n };\n },\n }),\n [containerRef, sidebarSide],\n );\n\n React.useEffect(() => {\n if (isHighlighted && hasChildren) setIsOpen(true);\n }, [isHighlighted, hasChildren]);\n\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const iconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const labelElement = (\n <span className=\"flex-1 text-start group-data-[collapsible=icon]:hidden\">\n {label}\n </span>\n );\n\n const badgeElement = badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5 group-data-[collapsible=icon]:hidden\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n );\n\n const chevronElement = hasChildren && (\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth group-data-[collapsible=icon]:hidden motion-reduce:transition-none',\n isOpen ? 'rotate-90' : 'rtl:rotate-180',\n isHighlighted && isOpen && 'text-primary',\n )}\n />\n );\n\n const itemClassName = cn(\n navItemVariants({ state: isHighlighted ? 'active' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'min-h-11 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:py-2 group-data-[collapsible=icon]:w-11 group-data-[collapsible=icon]:h-11',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n // --- Collapsed: icon-only with tooltip, flyout popover for children ---\n if (isCollapsed) {\n const collapsedIconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center justify-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const triggerElement = href ? (\n <a\n href={href}\n className={cn(itemClassName)}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={hasChildren ? () => setIsOpen(!isOpen) : onClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </button>\n );\n\n if (!hasChildren) {\n if (!label) return triggerElement;\n return (\n <Tooltip>\n <TooltipTrigger render={triggerElement} />\n <TooltipPopup side={floatingSide} sideOffset={8}>\n {label}\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <PopoverRoot>\n <PopoverTrigger\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </PopoverTrigger>\n <PopoverPopup\n side={floatingSide}\n align=\"start\"\n sideOffset={0}\n alignOffset={0}\n anchor={flyoutAnchor}\n collisionAvoidance={{\n side: 'none',\n align: 'none',\n fallbackAxisSide: 'none',\n }}\n positionMethod=\"fixed\"\n aria-label={`${label} sub-navigation`}\n style={\n {\n '--app-sidebar-flyout-panel-bg': flyoutPanelBackground,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-[var(--anchor-height)] w-[276px] border-0 bg-transparent p-0 ring-0 shadow-none',\n 'overflow-clip',\n flyoutFrameEdgeClassName,\n )}\n >\n <div\n className={cn(\n 'flex h-full w-64 flex-col gap-0.5 overflow-y-auto p-3 shadow-[var(--shadow-hover-card)]',\n 'supports-backdrop-filter:backdrop-blur-[60px] [background-image:var(--app-sidebar-flyout-panel-bg)] delight-tooltip-stagger',\n flyoutPanelEdgeClassName,\n )}\n data-slot=\"app-sidebar-nav-flyout-panel\"\n role=\"group\"\n aria-label={label}\n >\n <p\n className=\"px-2 pb-2 pt-1 text-xs font-semibold text-primary opacity-70\"\n aria-hidden=\"true\"\n >\n {label}\n </p>\n {children}\n </div>\n </PopoverPopup>\n </PopoverRoot>\n );\n }\n\n // --- Expanded: full item with optional inline sub-nav ---\n const handleClick = () => {\n if (hasChildren) {\n setIsOpen(!isOpen);\n }\n onClick?.();\n };\n\n const mainElement =\n href && !hasChildren ? (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n aria-expanded={hasChildren ? isOpen : undefined}\n aria-controls={hasChildren ? subNavId : undefined}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </button>\n );\n\n if (!hasChildren) return mainElement;\n\n return (\n <>\n {mainElement}\n {isOpen && (\n <ul\n id={subNavId}\n role=\"group\"\n aria-label={`${label} sub-navigation`}\n className=\"ms-4 flex flex-col items-start border-s border-sidebar-border py-1 ps-2\"\n >\n {children}\n </ul>\n )}\n </>\n );\n}\n\nAppSidebarNavItem.displayName = 'AppSidebar.NavItem';\n\n// ============================================\n// Nav Sub Component\n// ============================================\n\nexport interface AppSidebarNavSubProps {\n label: string;\n badge?: string | number;\n isActive?: boolean;\n href?: string;\n onClick?: () => void;\n className?: string;\n}\n\nfunction AppSidebarNavSub({\n label,\n badge,\n isActive = false,\n href,\n onClick,\n className,\n}: AppSidebarNavSubProps) {\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const itemClassName = cn(\n navItemVariants({ state: isActive ? 'active' : 'default' }),\n 'min-h-11 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'transition-[color,background-color,transform] ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n const content = (\n <>\n <span className=\"flex-1 text-start\">{label}</span>\n {badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n )}\n </>\n );\n\n if (href) {\n return (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </a>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(itemClassName, 'cursor-pointer delight-selection-press')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </button>\n );\n}\nAppSidebarNavSub.displayName = 'AppSidebar.NavSub';\n\n// ============================================\n// Nav Skeleton\n// ============================================\n\nexport interface AppSidebarNavSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n className?: string;\n}\n\nfunction AppSidebarNavSkeleton({\n count = 3,\n className,\n}: AppSidebarNavSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 3);\n\n return (\n <SidebarGroup\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-2\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuItem key={`nav-skeleton-${i}`}>\n <SidebarNavSkeleton />\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNavSkeleton.displayName = 'AppSidebar.NavSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarNavSkeleton, 'content');\n\n// ============================================\n// Chat List Component\n// ============================================\n\nexport interface AppSidebarChatListProps {\n /** Section label */\n label?: string;\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarChatList({\n label = 'Recent Chats',\n children,\n className,\n}: AppSidebarChatListProps) {\n const { state } = useSidebar();\n const isCollapsed = state === 'collapsed';\n\n // Collapsed state doesn't show chat list\n if (isCollapsed) {\n return null;\n }\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-chat-list\"\n className={cn('mt-4 flex min-h-0 flex-1 flex-col p-0', className)}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div\n className=\"flex h-full flex-col overflow-y-auto pb-5 rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n tabIndex={0}\n role=\"list\"\n aria-label={label}\n >\n {children}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatList.displayName = 'AppSidebar.ChatList';\nmarkAppSidebarImplicitSlot(AppSidebarChatList, 'content');\n\n// ============================================\n// Chat Item Component\n// ============================================\n\nconst chatItemVariants = cva(\n 'flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 min-h-11 transition-[color,background-color,transform] duration-200 ease-smooth cursor-pointer motion-reduce:transition-none ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n {\n variants: {\n state: {\n default: 'hover:bg-muted',\n hover: 'bg-muted',\n selected: 'bg-primary/10',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarChatItemProps\n extends VariantProps<typeof chatItemVariants> {\n /** Chat title */\n title: string;\n /** Time indicator (e.g., \"12h ago\") */\n time?: string;\n /** Icon for collapsed view (defaults to chat bubble) */\n icon?: React.ReactNode;\n /** Whether this chat is selected */\n isSelected?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Context menu handler (right-click) */\n onContextMenu?: (event: React.MouseEvent) => void;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarChatItem({\n title,\n time,\n icon,\n isSelected = false,\n onClick,\n onContextMenu,\n className,\n}: AppSidebarChatItemProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const collapsedButton = (\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title || undefined}\n className={cn(\n 'flex size-11 items-center justify-center rounded-md transition-colors duration-200 ease-smooth motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n isSelected ? 'bg-primary/10' : 'hover:bg-muted',\n className,\n )}\n >\n {icon || <MessageCircle className=\"size-5 text-secondary-foreground\" />}\n </button>\n );\n\n if (!title && !time) {\n return collapsedButton;\n }\n\n return (\n <Tooltip>\n <TooltipTrigger render={collapsedButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{title}</span>\n {time && (\n <span className=\"text-xs text-muted-foreground\">{time}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <div role=\"listitem\">\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title}\n className={cn(\n chatItemVariants({ state: isSelected ? 'selected' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <span className=\"text-base font-semibold text-secondary-foreground truncate\">\n {title}\n </span>\n {time && (\n <span className=\"text-xs font-normal text-muted-foreground shrink-0\">\n {time}\n </span>\n )}\n </button>\n </div>\n );\n}\n\nAppSidebarChatItem.displayName = 'AppSidebar.ChatItem';\n\n// ============================================\n// Chat List Skeleton\n// ============================================\n\nexport interface AppSidebarChatListSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n /** Section label */\n label?: string;\n className?: string;\n}\n\nfunction AppSidebarChatListSkeleton({\n count = 5,\n label = 'Recent Chats',\n className,\n}: AppSidebarChatListSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 5);\n\n return (\n <SidebarGroup\n className={cn(\n 'mt-4 flex min-h-0 flex-1 flex-col p-0 group-data-[collapsible=icon]:hidden',\n className,\n )}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div className=\"flex h-full flex-col overflow-y-auto pb-5\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuSkeleton key={`chat-skeleton-${i}`} />\n ))}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatListSkeleton.displayName = 'AppSidebar.ChatListSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarChatListSkeleton, 'content');\n\n// ============================================\n// Account Component\n// ============================================\n\nexport interface AppSidebarAccountProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** User's name */\n name: string;\n /** Subtitle text (e.g., email, role) */\n subtitle?: string;\n /** User's avatar URL */\n avatarSrc?: string;\n /** Whether user is online */\n isOnline?: boolean;\n /** Click handler for the expand button */\n onExpand?: () => void;\n}\n\nfunction AppSidebarAccount({\n name,\n subtitle,\n avatarSrc,\n isOnline = false,\n onExpand,\n className,\n}: AppSidebarAccountProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const avatarButton = (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex min-h-11 min-w-11 items-center justify-center rounded-lg transition-opacity duration-200 ease-smooth hover:opacity-80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n </button>\n );\n\n if (!name && !subtitle) return avatarButton;\n\n return (\n <Tooltip>\n <TooltipTrigger render={avatarButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n {name && <span className=\"font-medium\">{name}</span>}\n {subtitle && (\n <span className=\"text-xs text-muted-foreground\">{subtitle}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex w-full items-center gap-1.5 rounded-lg px-1 py-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n <div className=\"flex flex-1 flex-col items-start overflow-hidden\">\n <span className=\"w-full truncate text-start text-sm font-medium text-sidebar-foreground\">\n {name}\n </span>\n {subtitle && (\n <span className=\"w-full truncate text-start text-xs font-light text-sidebar-foreground\">\n {subtitle}\n </span>\n )}\n </div>\n </button>\n );\n}\n\nAppSidebarAccount.displayName = 'AppSidebar.Account';\nmarkAppSidebarImplicitSlot(AppSidebarAccount, 'footer');\n\n// ============================================\n// Account Skeleton\n// ============================================\n\nfunction AppSidebarAccountSkeleton({ className }: { className?: string }) {\n return <SidebarAccountSkeleton className={className} />;\n}\n\nAppSidebarAccountSkeleton.displayName = 'AppSidebar.AccountSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarAccountSkeleton, 'footer');\n\n// ============================================\n// Full Sidebar Skeleton\n// ============================================\n\nexport interface AppSidebarSkeletonProps {\n /** Number of nav skeleton items */\n navCount?: number;\n /** Number of chat skeleton items */\n chatCount?: number;\n /** Logo element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Collapsible mode */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card') */\n sidebarBgColor?: string;\n className?: string;\n}\n\nfunction AppSidebarSkeleton({\n navCount = 4,\n chatCount = 5,\n logo,\n compactedLogo,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n}: AppSidebarSkeletonProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n return (\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n className={cn('bg-transparent', className)}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2\">\n <AppSidebarLogo logo={logo} compactedLogo={compactedLogo} />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n <AppSidebarNavSkeleton count={navCount} />\n <AppSidebarChatListSkeleton count={chatCount} />\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n <AppSidebarAccountSkeleton />\n </SidebarFooter>\n </div>\n </Sidebar>\n );\n}\n\nAppSidebarSkeleton.displayName = 'AppSidebar.Skeleton';\n\n// ============================================\n// Main App Sidebar\n// ============================================\n\nexport interface AppSidebarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo element or configuration */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n logoSubtext?: string;\n /** Collapsible mode - 'icon' shows only icons when collapsed, 'none' disables collapsing */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen. When omitted, resolves from the nearest DOM direction. */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card'). Defaults to the sidebar token when expanded, bg-transparent when collapsed. */\n sidebarBgColor?: string;\n /** Children (compound components) */\n children?: React.ReactNode;\n}\n\n/**\n * AppSidebar is a full-featured application sidebar with navigation, chat list, and account sections.\n * Supports collapsible modes with a unified logo toggle and loading skeletons.\n *\n * @llms Full-featured app sidebar with nav, chat list, account, collapsible modes\n * @example\n * ```tsx\n * <AppSidebar logo={<Logo />} collapsible=\"icon\">\n * <AppSidebar.Nav>\n * <AppSidebar.NavItem icon={<Home />} label=\"Home\" isActive />\n * </AppSidebar.Nav>\n * <AppSidebar.ChatList>\n * <AppSidebar.ChatItem title=\"Chat 1\" />\n * </AppSidebar.ChatList>\n * <AppSidebar.Account name=\"User\" subtitle=\"user@example.com\" />\n * </AppSidebar>\n * ```\n */\nfunction AppSidebarRoot({\n logo,\n compactedLogo,\n logoSubtext,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n children,\n dir,\n ...props\n}: AppSidebarProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitDir: dir,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n const slots = useSlotChildren(children);\n\n return (\n <AppSidebarLayoutContext.Provider value={{ side: resolvedSide }}>\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n dir={dir}\n className={cn('bg-transparent', className)}\n {...props}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2\">\n <AppSidebarLogo\n logo={logo}\n compactedLogo={compactedLogo}\n subtext={logoSubtext}\n />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n {slots.explicitContent\n ? (slots.explicitContent.props as AppSidebarSlotProps).children\n : slots.content}\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n {slots.explicitFooter\n ? (slots.explicitFooter.props as AppSidebarSlotProps).children\n : slots.footer}\n </SidebarFooter>\n </div>\n </Sidebar>\n </AppSidebarLayoutContext.Provider>\n );\n}\n\nAppSidebarRoot.displayName = 'AppSidebar';\n\n// ============================================\n// Compound Component Export\n// ============================================\n\nexport const AppSidebar = Object.assign(AppSidebarRoot, {\n Header: AppSidebarHeader,\n Content: AppSidebarContent,\n Footer: AppSidebarFooter,\n Nav: AppSidebarNav,\n NavSection: AppSidebarNavSection,\n NavItem: AppSidebarNavItem,\n NavSub: AppSidebarNavSub,\n NavSkeleton: AppSidebarNavSkeleton,\n ChatList: AppSidebarChatList,\n ChatItem: AppSidebarChatItem,\n ChatListSkeleton: AppSidebarChatListSkeleton,\n Account: AppSidebarAccount,\n AccountSkeleton: AppSidebarAccountSkeleton,\n Skeleton: AppSidebarSkeleton,\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\n// Re-export mobile detection utilities for client use\nexport { MOBILE_BREAKPOINT, useIsMobile } from '@/hooks/use-mobile';\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\nexport type {\n AppSidebarAccountProps as AccountProps,\n AppSidebarChatItemProps as ChatItemProps,\n AppSidebarChatListProps as ChatListProps,\n AppSidebarChatListSkeletonProps as ChatListSkeletonProps,\n AppSidebarNavItemProps as NavItemProps,\n AppSidebarNavProps as NavProps,\n AppSidebarNavSectionProps as NavSectionProps,\n AppSidebarNavSkeletonProps as NavSkeletonProps,\n AppSidebarNavSubProps as NavSubProps,\n AppSidebarSkeletonProps as SkeletonProps,\n AppSidebarSlotProps as SlotProps,\n};\n// Re-export sidebar primitives for custom compositions\nexport {\n chatItemVariants,\n navItemVariants,\n // Re-export base components for advanced usage\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index225.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/noNoninteractiveTabindex: ChatList uses tabIndex on scrollable div for keyboard scrolling */\n/** biome-ignore-all lint/a11y/useSemanticElements: NavSection uses role=\"separator\" on inner <div>; ChatList uses role=\"list\" on scrollable div */\n/** biome-ignore-all lint/a11y/useFocusableInteractive: Non-focusable separator per WAI-ARIA spec for decorative separators */\n/** biome-ignore-all lint/a11y/useAriaPropsForRole: Non-focusable separators don't require aria-valuenow per WAI-ARIA spec */\n/** biome-ignore-all lint/a11y/noNoninteractiveElementToInteractiveRole: role=\"separator\" on <div> inside list items for semantic section boundaries */\n\n'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n ChevronRight,\n MessageCircle,\n PanelLeftClose,\n PanelLeftOpen,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Badge } from '@/components/atoms/display/Badge';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { BrandIcon } from '@/components/molecules/data/BrandIcon';\nimport {\n PopoverPopup,\n PopoverRoot,\n PopoverTrigger,\n} from '@/components/organisms/overlays/Popover';\nimport {\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n} from '@/components/ui/sidebar';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\n\nfunction formatAccessibleLabel(\n label: string,\n badge?: string | number | null,\n): string {\n if (badge == null) return label;\n return `${label}, ${typeof badge === 'number' ? `${badge} ${badge === 1 ? 'item' : 'items'}` : badge}`;\n}\n\nfunction getSidebarBgClass(\n isCollapsed: boolean,\n sidebarBgColor?: string,\n): string {\n return isCollapsed\n ? 'bg-transparent'\n : (sidebarBgColor ?? 'bg-[var(--sidebar)]');\n}\n\nfunction getSidebarSurfaceClass({\n isCollapsed,\n side,\n rounded,\n backgroundClass,\n}: {\n isCollapsed: boolean;\n side: AppSidebarSide;\n rounded: boolean;\n backgroundClass: string;\n}): string {\n return cn(\n 'flex h-full min-h-0 flex-col items-center pb-4 pt-6',\n isCollapsed\n ? 'w-full px-2'\n : [\n 'w-[calc(100%-0.75rem)] px-3',\n side === 'left' ? 'mr-3 self-start' : 'ml-3 self-end',\n ],\n backgroundClass,\n rounded && (side === 'left' ? 'rounded-r-lg' : 'rounded-l-lg'),\n );\n}\n\nfunction getSkeletonCount(count: number | undefined, fallback: number): number {\n return typeof count === 'number' && Number.isFinite(count) && count >= 0\n ? Math.floor(count)\n : fallback;\n}\n\n// ============================================\n// Slot Distribution Hook\n// ============================================\n\nconst APP_SIDEBAR_IMPLICIT_SLOT = Symbol('AppSidebarImplicitSlot');\n\ntype AppSidebarImplicitSlot = 'header' | 'content' | 'footer';\n\ninterface AppSidebarImplicitSlotComponent {\n [APP_SIDEBAR_IMPLICIT_SLOT]: AppSidebarImplicitSlot;\n}\n\ninterface AppSidebarWrappedComponent {\n type?: unknown;\n render?: unknown;\n}\n\nfunction markAppSidebarImplicitSlot<Component extends object>(\n component: Component,\n slot: AppSidebarImplicitSlot,\n): Component & AppSidebarImplicitSlotComponent {\n const slottedComponent = component as Component &\n AppSidebarImplicitSlotComponent;\n slottedComponent[APP_SIDEBAR_IMPLICIT_SLOT] = slot;\n return slottedComponent;\n}\n\nfunction isAppSidebarImplicitSlotComponent(\n value: unknown,\n): value is AppSidebarImplicitSlotComponent {\n return (\n (typeof value === 'function' ||\n (typeof value === 'object' && value !== null)) &&\n APP_SIDEBAR_IMPLICIT_SLOT in value\n );\n}\n\nfunction getAppSidebarImplicitSlot(\n childType: unknown,\n): AppSidebarImplicitSlot | undefined {\n if (isAppSidebarImplicitSlotComponent(childType)) {\n return childType[APP_SIDEBAR_IMPLICIT_SLOT];\n }\n\n if (typeof childType === 'object' && childType !== null) {\n const wrappedComponent = childType as AppSidebarWrappedComponent;\n return (\n getAppSidebarImplicitSlot(wrappedComponent.type) ??\n getAppSidebarImplicitSlot(wrappedComponent.render)\n );\n }\n\n return undefined;\n}\n\ntype SlotResult = {\n header: React.ReactNode[];\n content: React.ReactNode[];\n footer: React.ReactNode[];\n explicitHeader: React.ReactElement | null;\n explicitContent: React.ReactElement | null;\n explicitFooter: React.ReactElement | null;\n};\n\nfunction useSlotChildren(children: React.ReactNode): SlotResult {\n return React.useMemo(() => {\n const result: SlotResult = {\n header: [],\n content: [],\n footer: [],\n explicitHeader: null,\n explicitContent: null,\n explicitFooter: null,\n };\n\n React.Children.forEach(children, (child) => {\n if (!React.isValidElement(child)) return;\n\n const childType = child.type;\n\n // Check for explicit slot components\n if (childType === AppSidebarHeader) {\n result.explicitHeader = child;\n return;\n }\n if (childType === AppSidebarContent) {\n result.explicitContent = child;\n return;\n }\n if (childType === AppSidebarFooter) {\n result.explicitFooter = child;\n return;\n }\n\n // Distribute to slots based on explicit component-owned slot markers.\n const implicitSlot = getAppSidebarImplicitSlot(childType);\n if (implicitSlot === 'header') {\n result.header.push(child);\n } else if (implicitSlot === 'content') {\n result.content.push(child);\n } else if (implicitSlot === 'footer') {\n result.footer.push(child);\n } else {\n // Unknown children go to content by default\n result.content.push(child);\n }\n });\n\n return result;\n }, [children]);\n}\n\ntype AppSidebarSide = 'left' | 'right';\ntype AppSidebarDirection = 'ltr' | 'rtl';\n\nconst AppSidebarLayoutContext = React.createContext<{ side: AppSidebarSide }>({\n side: 'left',\n});\n\nfunction useAppSidebarLayout() {\n return React.useContext(AppSidebarLayoutContext);\n}\n\nfunction getAppSidebarDirection(\n element: HTMLElement | null,\n): AppSidebarDirection {\n const win = element?.ownerDocument.defaultView;\n if (!element || !win) return 'ltr';\n return win.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\nfunction normalizeAppSidebarDirection(\n dir: string | undefined,\n): AppSidebarDirection | undefined {\n return dir === 'rtl' || dir === 'ltr' ? dir : undefined;\n}\n\nfunction getAppSidebarSideFromDirection(\n direction: AppSidebarDirection,\n): AppSidebarSide {\n return direction === 'rtl' ? 'right' : 'left';\n}\n\nfunction getAppSidebarDirectionTargets(element: HTMLElement): Element[] {\n const targets = new Set<Element>();\n let current: Element | null = element;\n\n while (current) {\n targets.add(current);\n if (current === element.ownerDocument.documentElement) break;\n current = current.parentElement;\n }\n\n targets.add(element.ownerDocument.documentElement);\n if (element.ownerDocument.body) targets.add(element.ownerDocument.body);\n\n return Array.from(targets);\n}\n\nfunction useResolvedAppSidebarSide({\n containerRef,\n explicitDir,\n explicitSide,\n}: {\n containerRef: React.RefObject<HTMLDivElement | null>;\n explicitDir?: string;\n explicitSide?: AppSidebarSide;\n}): AppSidebarSide {\n const [detectedDirection, setDetectedDirection] =\n React.useState<AppSidebarDirection>(\n () => normalizeAppSidebarDirection(explicitDir) ?? 'ltr',\n );\n\n React.useEffect(() => {\n if (explicitSide) return;\n\n const normalizedExplicitDir = normalizeAppSidebarDirection(explicitDir);\n if (normalizedExplicitDir) {\n setDetectedDirection((current) =>\n current === normalizedExplicitDir ? current : normalizedExplicitDir,\n );\n return;\n }\n\n const container = containerRef.current;\n const win = container?.ownerDocument.defaultView;\n if (!container || !win) return;\n\n const detectDirection = () => {\n const nextDirection = getAppSidebarDirection(container);\n setDetectedDirection((current) =>\n current === nextDirection ? current : nextDirection,\n );\n };\n\n detectDirection();\n\n const Observer = win.MutationObserver;\n if (!Observer) return;\n\n const observer = new Observer(detectDirection);\n for (const target of getAppSidebarDirectionTargets(container)) {\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['dir', 'class', 'style'],\n });\n }\n\n return () => observer.disconnect();\n }, [containerRef, explicitDir, explicitSide]);\n\n return explicitSide ?? getAppSidebarSideFromDirection(detectedDirection);\n}\n\n// ============================================\n// Sidebar Logo\n// ============================================\n\nexport interface AppSidebarLogoProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo image or element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n subtext?: string;\n}\n\nconst DEFAULT_COMPACTED_LOGO = (\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n <BrandIcon icon=\"mark\" size=\"sm\" />\n </span>\n);\n\nfunction AppSidebarLogo({\n logo,\n compactedLogo,\n subtext,\n className,\n ...props\n}: AppSidebarLogoProps) {\n const { state, toggleSidebar } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const effectiveCompactedLogo = compactedLogo ?? DEFAULT_COMPACTED_LOGO;\n\n if (isCollapsed) {\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn('flex items-center justify-center', className)}\n {...props}\n dir=\"ltr\"\n >\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"group/logo relative flex size-[52px] items-center justify-center rounded-md p-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Expand sidebar\"\n >\n <span className=\"transition-opacity duration-200 ease-smooth group-hover/logo:opacity-0 motion-reduce:transition-none\">\n {effectiveCompactedLogo}\n </span>\n <PanelLeftOpen className=\"absolute size-5 opacity-0 transition-opacity duration-200 ease-smooth group-hover/logo:opacity-100 motion-reduce:transition-none\" />\n </button>\n </div>\n );\n }\n\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn(\n 'flex h-[52px] items-center justify-between gap-2 rounded-md p-2',\n className,\n )}\n {...props}\n dir=\"ltr\"\n >\n <div className=\"flex min-w-0 flex-col gap-0\">\n <div className=\"flex items-center gap-2\">\n {logo || (\n <>\n {DEFAULT_COMPACTED_LOGO}\n <span className=\"text-lg font-semibold tracking-tight text-foreground\">\n HUMAIN\n </span>\n </>\n )}\n </div>\n {subtext && (\n <p className=\"ps-11 text-sm text-sidebar-foreground\">\n <span data-slot=\"app-sidebar-logo-subtext\">{subtext}</span>\n </p>\n )}\n </div>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"relative flex size-9 items-center justify-center rounded-lg text-sidebar-foreground transition-colors duration-200 ease-smooth hover:bg-sidebar-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none after:absolute after:-inset-1\"\n aria-label=\"Collapse sidebar\"\n >\n <PanelLeftClose aria-hidden=\"true\" className=\"size-5\" />\n </button>\n </div>\n );\n}\n\nAppSidebarLogo.displayName = 'AppSidebar.Logo';\n\n// ============================================\n// Slot Components (Header, Content, Footer)\n// ============================================\n\nexport interface AppSidebarSlotProps {\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarHeader({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-header\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarHeader.displayName = 'AppSidebar.Header';\n\nfunction AppSidebarContent({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-content\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarContent.displayName = 'AppSidebar.Content';\n\nfunction AppSidebarFooter({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-footer\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarFooter.displayName = 'AppSidebar.Footer';\n\n// ============================================\n// Nav Component\n// ============================================\n\nexport interface AppSidebarNavProps {\n children?: React.ReactNode;\n /** Accessible label for the nav landmark (useful when multiple Nav instances exist) */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction AppSidebarNav({\n children,\n 'aria-label': ariaLabel = 'Sidebar navigation',\n className,\n}: AppSidebarNavProps) {\n const menuContent = (\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-1\">\n {React.Children.map(children, (child) => (\n <SidebarMenuItem>{child}</SidebarMenuItem>\n ))}\n </SidebarMenu>\n );\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-nav\"\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <nav aria-label={ariaLabel}>{menuContent}</nav>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNav.displayName = 'AppSidebar.Nav';\nmarkAppSidebarImplicitSlot(AppSidebarNav, 'content');\n\n// ============================================\n// Nav Section (Group Label / Divider)\n// ============================================\n\nexport interface AppSidebarNavSectionProps {\n /** Section label shown when sidebar is expanded */\n label: string;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarNavSection({ label, className }: AppSidebarNavSectionProps) {\n return (\n <div\n data-slot=\"app-sidebar-nav-section\"\n role=\"separator\"\n aria-label={label}\n className={cn('py-2 group-data-[collapsible=icon]:w-[52px]', className)}\n >\n <div className=\"flex h-8 items-center px-2 group-data-[collapsible=icon]:hidden\">\n <span className=\"text-xs font-medium text-sidebar-foreground/80\">\n {label}\n </span>\n </div>\n <div className=\"hidden py-2 group-data-[collapsible=icon]:block\">\n <span className=\"sr-only\">{label}</span>\n <Separator className=\"mx-auto w-full\" />\n </div>\n </div>\n );\n}\n\nAppSidebarNavSection.displayName = 'AppSidebar.NavSection';\n\n// ============================================\n// Nav Item Component\n// ============================================\n\nconst navItemVariants = cva(\n 'relative flex w-full items-center gap-1.5 rounded-lg px-2 py-2 text-sm font-normal transition-[color,background-color] duration-200 ease-smooth motion-reduce:transition-none',\n {\n variants: {\n state: {\n default: 'text-sidebar-foreground hover:bg-sidebar-accent',\n active: 'bg-primary/10 text-sidebar-foreground',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarNavItemProps {\n icon: React.ReactNode;\n label: string;\n isActive?: boolean;\n badge?: string | number;\n onClick?: () => void;\n href?: string;\n className?: string;\n /** Sub-navigation children (AppSidebar.NavSub items). When present, renders as collapsible parent. */\n children?: React.ReactNode;\n}\n\nfunction AppSidebarNavItem({\n icon,\n label,\n isActive = false,\n badge,\n onClick,\n href,\n className,\n children,\n}: AppSidebarNavItemProps) {\n const { state, containerRef } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const hasChildren = React.Children.count(children) > 0;\n const hasActiveChild = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement<{ isActive?: boolean }>(child) &&\n child.props.isActive === true,\n );\n const isHighlighted = isActive || hasActiveChild;\n const [isOpen, setIsOpen] = React.useState(isHighlighted && hasChildren);\n const subNavId = React.useId();\n const floatingSide = sidebarSide === 'right' ? 'left' : 'right';\n const flyoutPanelBackground =\n 'linear-gradient(108deg, var(--opacity-white-87) 0.5219%, var(--opacity-white-75) 98.419%)';\n const flyoutFrameEdgeClassName =\n sidebarSide === 'right'\n ? 'justify-end rounded-l-xl rounded-r-none'\n : 'justify-start rounded-r-xl rounded-l-none';\n const flyoutPanelEdgeClassName =\n sidebarSide === 'right' ? 'rounded-l-xl' : 'rounded-r-xl';\n const flyoutAnchor = React.useMemo(\n () => ({\n getBoundingClientRect: () => {\n const container = containerRef.current;\n const rect = container?.getBoundingClientRect();\n const win = container?.ownerDocument.defaultView;\n const viewportHeight = win?.innerHeight ?? rect?.height ?? 0;\n const x = rect ? (sidebarSide === 'right' ? rect.left : rect.right) : 0;\n\n return {\n x,\n y: 0,\n top: 0,\n right: x,\n bottom: viewportHeight,\n left: x,\n width: 0,\n height: viewportHeight,\n };\n },\n }),\n [containerRef, sidebarSide],\n );\n\n React.useEffect(() => {\n if (isHighlighted && hasChildren) setIsOpen(true);\n }, [isHighlighted, hasChildren]);\n\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const iconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const labelElement = (\n <span className=\"flex-1 text-start group-data-[collapsible=icon]:hidden\">\n {label}\n </span>\n );\n\n const badgeElement = badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5 group-data-[collapsible=icon]:hidden\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n );\n\n const chevronElement = hasChildren && (\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth group-data-[collapsible=icon]:hidden motion-reduce:transition-none',\n isOpen ? 'rotate-90' : 'rtl:rotate-180',\n isHighlighted && isOpen && 'text-primary',\n )}\n />\n );\n\n const itemClassName = cn(\n navItemVariants({ state: isHighlighted ? 'active' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'min-h-11 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:py-2 group-data-[collapsible=icon]:w-11 group-data-[collapsible=icon]:h-11',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n // --- Collapsed: icon-only with tooltip, flyout popover for children ---\n if (isCollapsed) {\n const collapsedIconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center justify-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const triggerElement = href ? (\n <a\n href={href}\n className={cn(itemClassName)}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={hasChildren ? () => setIsOpen(!isOpen) : onClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </button>\n );\n\n if (!hasChildren) {\n if (!label) return triggerElement;\n return (\n <Tooltip>\n <TooltipTrigger render={triggerElement} />\n <TooltipPopup side={floatingSide} sideOffset={8}>\n {label}\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <PopoverRoot>\n <PopoverTrigger\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </PopoverTrigger>\n <PopoverPopup\n side={floatingSide}\n align=\"start\"\n sideOffset={0}\n alignOffset={0}\n anchor={flyoutAnchor}\n collisionAvoidance={{\n side: 'none',\n align: 'none',\n fallbackAxisSide: 'none',\n }}\n positionMethod=\"fixed\"\n aria-label={`${label} sub-navigation`}\n style={\n {\n '--app-sidebar-flyout-panel-bg': flyoutPanelBackground,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-[var(--anchor-height)] w-[276px] border-0 bg-transparent p-0 ring-0 shadow-none',\n 'overflow-clip',\n flyoutFrameEdgeClassName,\n )}\n >\n <div\n className={cn(\n 'flex h-full w-64 flex-col gap-0.5 overflow-y-auto p-3 shadow-[var(--shadow-hover-card)]',\n 'supports-backdrop-filter:backdrop-blur-[60px] [background-image:var(--app-sidebar-flyout-panel-bg)] delight-tooltip-stagger',\n flyoutPanelEdgeClassName,\n )}\n data-slot=\"app-sidebar-nav-flyout-panel\"\n role=\"group\"\n aria-label={label}\n >\n <p\n className=\"px-2 pb-2 pt-1 text-xs font-semibold text-primary opacity-70\"\n aria-hidden=\"true\"\n >\n {label}\n </p>\n {children}\n </div>\n </PopoverPopup>\n </PopoverRoot>\n );\n }\n\n // --- Expanded: full item with optional inline sub-nav ---\n const handleClick = () => {\n if (hasChildren) {\n setIsOpen(!isOpen);\n }\n onClick?.();\n };\n\n const mainElement =\n href && !hasChildren ? (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n aria-expanded={hasChildren ? isOpen : undefined}\n aria-controls={hasChildren ? subNavId : undefined}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </button>\n );\n\n if (!hasChildren) return mainElement;\n\n return (\n <>\n {mainElement}\n {isOpen && (\n <ul\n id={subNavId}\n role=\"group\"\n aria-label={`${label} sub-navigation`}\n className=\"ms-4 flex flex-col items-start border-s border-sidebar-border py-1 ps-2\"\n >\n {children}\n </ul>\n )}\n </>\n );\n}\n\nAppSidebarNavItem.displayName = 'AppSidebar.NavItem';\n\n// ============================================\n// Nav Sub Component\n// ============================================\n\nexport interface AppSidebarNavSubProps {\n label: string;\n badge?: string | number;\n isActive?: boolean;\n href?: string;\n onClick?: () => void;\n className?: string;\n}\n\nfunction AppSidebarNavSub({\n label,\n badge,\n isActive = false,\n href,\n onClick,\n className,\n}: AppSidebarNavSubProps) {\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const itemClassName = cn(\n navItemVariants({ state: isActive ? 'active' : 'default' }),\n 'min-h-11 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'transition-[color,background-color,transform] ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n const content = (\n <>\n <span className=\"flex-1 text-start\">{label}</span>\n {badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n )}\n </>\n );\n\n if (href) {\n return (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </a>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(itemClassName, 'cursor-pointer delight-selection-press')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </button>\n );\n}\nAppSidebarNavSub.displayName = 'AppSidebar.NavSub';\n\n// ============================================\n// Nav Skeleton\n// ============================================\n\nexport interface AppSidebarNavSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n className?: string;\n}\n\nfunction AppSidebarNavSkeleton({\n count = 3,\n className,\n}: AppSidebarNavSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 3);\n\n return (\n <SidebarGroup\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-2\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuItem key={`nav-skeleton-${i}`}>\n <SidebarNavSkeleton />\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNavSkeleton.displayName = 'AppSidebar.NavSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarNavSkeleton, 'content');\n\n// ============================================\n// Chat List Component\n// ============================================\n\nexport interface AppSidebarChatListProps {\n /** Section label */\n label?: string;\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarChatList({\n label = 'Recent Chats',\n children,\n className,\n}: AppSidebarChatListProps) {\n const { state } = useSidebar();\n const isCollapsed = state === 'collapsed';\n\n // Collapsed state doesn't show chat list\n if (isCollapsed) {\n return null;\n }\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-chat-list\"\n className={cn('mt-4 flex min-h-0 flex-1 flex-col p-0', className)}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div\n className=\"flex h-full flex-col overflow-y-auto pb-5 rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n tabIndex={0}\n role=\"list\"\n aria-label={label}\n >\n {children}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatList.displayName = 'AppSidebar.ChatList';\nmarkAppSidebarImplicitSlot(AppSidebarChatList, 'content');\n\n// ============================================\n// Chat Item Component\n// ============================================\n\nconst chatItemVariants = cva(\n 'flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 min-h-11 transition-[color,background-color,transform] duration-200 ease-smooth cursor-pointer motion-reduce:transition-none ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n {\n variants: {\n state: {\n default: 'hover:bg-muted',\n hover: 'bg-muted',\n selected: 'bg-primary/10',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarChatItemProps\n extends VariantProps<typeof chatItemVariants> {\n /** Chat title */\n title: string;\n /** Time indicator (e.g., \"12h ago\") */\n time?: string;\n /** Icon for collapsed view (defaults to chat bubble) */\n icon?: React.ReactNode;\n /** Whether this chat is selected */\n isSelected?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Context menu handler (right-click) */\n onContextMenu?: (event: React.MouseEvent) => void;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarChatItem({\n title,\n time,\n icon,\n isSelected = false,\n onClick,\n onContextMenu,\n className,\n}: AppSidebarChatItemProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const collapsedButton = (\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title || undefined}\n className={cn(\n 'flex size-11 items-center justify-center rounded-md transition-colors duration-200 ease-smooth motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n isSelected ? 'bg-primary/10' : 'hover:bg-muted',\n className,\n )}\n >\n {icon || <MessageCircle className=\"size-5 text-secondary-foreground\" />}\n </button>\n );\n\n if (!title && !time) {\n return collapsedButton;\n }\n\n return (\n <Tooltip>\n <TooltipTrigger render={collapsedButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{title}</span>\n {time && (\n <span className=\"text-xs text-muted-foreground\">{time}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <div role=\"listitem\">\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title}\n className={cn(\n chatItemVariants({ state: isSelected ? 'selected' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <span className=\"text-base font-semibold text-secondary-foreground truncate\">\n {title}\n </span>\n {time && (\n <span className=\"text-xs font-normal text-muted-foreground shrink-0\">\n {time}\n </span>\n )}\n </button>\n </div>\n );\n}\n\nAppSidebarChatItem.displayName = 'AppSidebar.ChatItem';\n\n// ============================================\n// Chat List Skeleton\n// ============================================\n\nexport interface AppSidebarChatListSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n /** Section label */\n label?: string;\n className?: string;\n}\n\nfunction AppSidebarChatListSkeleton({\n count = 5,\n label = 'Recent Chats',\n className,\n}: AppSidebarChatListSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 5);\n\n return (\n <SidebarGroup\n className={cn(\n 'mt-4 flex min-h-0 flex-1 flex-col p-0 group-data-[collapsible=icon]:hidden',\n className,\n )}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div className=\"flex h-full flex-col overflow-y-auto pb-5\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuSkeleton key={`chat-skeleton-${i}`} />\n ))}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatListSkeleton.displayName = 'AppSidebar.ChatListSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarChatListSkeleton, 'content');\n\n// ============================================\n// Account Component\n// ============================================\n\nexport interface AppSidebarAccountProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** User's name */\n name: string;\n /** Subtitle text (e.g., email, role) */\n subtitle?: string;\n /** User's avatar URL */\n avatarSrc?: string;\n /** Whether user is online */\n isOnline?: boolean;\n /** Click handler for the expand button */\n onExpand?: () => void;\n}\n\nfunction AppSidebarAccount({\n name,\n subtitle,\n avatarSrc,\n isOnline = false,\n onExpand,\n className,\n}: AppSidebarAccountProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const avatarButton = (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex min-h-11 min-w-11 items-center justify-center rounded-lg transition-opacity duration-200 ease-smooth hover:opacity-80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n </button>\n );\n\n if (!name && !subtitle) return avatarButton;\n\n return (\n <Tooltip>\n <TooltipTrigger render={avatarButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n {name && <span className=\"font-medium\">{name}</span>}\n {subtitle && (\n <span className=\"text-xs text-muted-foreground\">{subtitle}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex w-full items-center gap-1.5 rounded-lg px-1 py-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n <div className=\"flex flex-1 flex-col items-start overflow-hidden\">\n <span className=\"w-full truncate text-start text-sm font-medium text-sidebar-foreground\">\n {name}\n </span>\n {subtitle && (\n <span className=\"w-full truncate text-start text-xs font-light text-sidebar-foreground\">\n {subtitle}\n </span>\n )}\n </div>\n </button>\n );\n}\n\nAppSidebarAccount.displayName = 'AppSidebar.Account';\nmarkAppSidebarImplicitSlot(AppSidebarAccount, 'footer');\n\n// ============================================\n// Account Skeleton\n// ============================================\n\nfunction AppSidebarAccountSkeleton({ className }: { className?: string }) {\n return <SidebarAccountSkeleton className={className} />;\n}\n\nAppSidebarAccountSkeleton.displayName = 'AppSidebar.AccountSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarAccountSkeleton, 'footer');\n\n// ============================================\n// Full Sidebar Skeleton\n// ============================================\n\nexport interface AppSidebarSkeletonProps {\n /** Number of nav skeleton items */\n navCount?: number;\n /** Number of chat skeleton items */\n chatCount?: number;\n /** Logo element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Collapsible mode */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card') */\n sidebarBgColor?: string;\n className?: string;\n}\n\nfunction AppSidebarSkeleton({\n navCount = 4,\n chatCount = 5,\n logo,\n compactedLogo,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n}: AppSidebarSkeletonProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n return (\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n className={cn('bg-transparent', className)}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo logo={logo} compactedLogo={compactedLogo} />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n <AppSidebarNavSkeleton count={navCount} />\n <AppSidebarChatListSkeleton count={chatCount} />\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n <AppSidebarAccountSkeleton />\n </SidebarFooter>\n </div>\n </Sidebar>\n );\n}\n\nAppSidebarSkeleton.displayName = 'AppSidebar.Skeleton';\n\n// ============================================\n// Main App Sidebar\n// ============================================\n\nexport interface AppSidebarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo element or configuration */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n logoSubtext?: string;\n /** Collapsible mode - 'icon' shows only icons when collapsed, 'none' disables collapsing */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen. When omitted, resolves from the nearest DOM direction. */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card'). Defaults to the sidebar token when expanded, bg-transparent when collapsed. */\n sidebarBgColor?: string;\n /** Children (compound components) */\n children?: React.ReactNode;\n}\n\n/**\n * AppSidebar is a full-featured application sidebar with navigation, chat list, and account sections.\n * Supports collapsible modes with a unified logo toggle and loading skeletons.\n *\n * @llms Full-featured app sidebar with nav, chat list, account, collapsible modes\n * @example\n * ```tsx\n * <AppSidebar logo={<Logo />} collapsible=\"icon\">\n * <AppSidebar.Nav>\n * <AppSidebar.NavItem icon={<Home />} label=\"Home\" isActive />\n * </AppSidebar.Nav>\n * <AppSidebar.ChatList>\n * <AppSidebar.ChatItem title=\"Chat 1\" />\n * </AppSidebar.ChatList>\n * <AppSidebar.Account name=\"User\" subtitle=\"user@example.com\" />\n * </AppSidebar>\n * ```\n */\nfunction AppSidebarRoot({\n logo,\n compactedLogo,\n logoSubtext,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n children,\n dir,\n ...props\n}: AppSidebarProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitDir: dir,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n const slots = useSlotChildren(children);\n\n return (\n <AppSidebarLayoutContext.Provider value={{ side: resolvedSide }}>\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n dir={dir}\n className={cn('bg-transparent', className)}\n {...props}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo\n logo={logo}\n compactedLogo={compactedLogo}\n subtext={logoSubtext}\n />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n {slots.explicitContent\n ? (slots.explicitContent.props as AppSidebarSlotProps).children\n : slots.content}\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n {slots.explicitFooter\n ? (slots.explicitFooter.props as AppSidebarSlotProps).children\n : slots.footer}\n </SidebarFooter>\n </div>\n </Sidebar>\n </AppSidebarLayoutContext.Provider>\n );\n}\n\nAppSidebarRoot.displayName = 'AppSidebar';\n\n// ============================================\n// Compound Component Export\n// ============================================\n\nexport const AppSidebar = Object.assign(AppSidebarRoot, {\n Header: AppSidebarHeader,\n Content: AppSidebarContent,\n Footer: AppSidebarFooter,\n Nav: AppSidebarNav,\n NavSection: AppSidebarNavSection,\n NavItem: AppSidebarNavItem,\n NavSub: AppSidebarNavSub,\n NavSkeleton: AppSidebarNavSkeleton,\n ChatList: AppSidebarChatList,\n ChatItem: AppSidebarChatItem,\n ChatListSkeleton: AppSidebarChatListSkeleton,\n Account: AppSidebarAccount,\n AccountSkeleton: AppSidebarAccountSkeleton,\n Skeleton: AppSidebarSkeleton,\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\n// Re-export mobile detection utilities for client use\nexport { MOBILE_BREAKPOINT, useIsMobile } from '@/hooks/use-mobile';\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\nexport type {\n AppSidebarAccountProps as AccountProps,\n AppSidebarChatItemProps as ChatItemProps,\n AppSidebarChatListProps as ChatListProps,\n AppSidebarChatListSkeletonProps as ChatListSkeletonProps,\n AppSidebarNavItemProps as NavItemProps,\n AppSidebarNavProps as NavProps,\n AppSidebarNavSectionProps as NavSectionProps,\n AppSidebarNavSkeletonProps as NavSkeletonProps,\n AppSidebarNavSubProps as NavSubProps,\n AppSidebarSkeletonProps as SkeletonProps,\n AppSidebarSlotProps as SlotProps,\n};\n// Re-export sidebar primitives for custom compositions\nexport {\n chatItemVariants,\n navItemVariants,\n // Re-export base components for advanced usage\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAmDA,SAAS,sBACP,OACA,OACQ;CACR,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO,GAAG,MAAM,IAAI,OAAO,UAAU,WAAW,GAAG,MAAM,GAAG,UAAU,IAAI,SAAS,YAAY;AACjG;AAEA,SAAS,kBACP,aACA,gBACQ;CACR,OAAO,cACH,mBACC,kBAAkB;AACzB;AAEA,SAAS,uBAAuB,EAC9B,aACA,MACA,SACA,mBAMS;CACT,OAAO,GACL,uDACA,cACI,gBACA,CACE,+BACA,SAAS,SAAS,oBAAoB,eACxC,GACJ,iBACA,YAAY,SAAS,SAAS,iBAAiB,eACjD;AACF;AAEA,SAAS,iBAAiB,OAA2B,UAA0B;CAC7E,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,IACnE,KAAK,MAAM,KAAK,IAChB;AACN;AAMA,IAAM,4BAA4B,OAAO,wBAAwB;AAajE,SAAS,2BACP,WACA,MAC6C;CAC7C,MAAM,mBAAmB;CAEzB,iBAAiB,6BAA6B;CAC9C,OAAO;AACT;AAEA,SAAS,kCACP,OAC0C;CAC1C,QACG,OAAO,UAAU,cACf,OAAO,UAAU,YAAY,UAAU,SAC1C,6BAA6B;AAEjC;AAEA,SAAS,0BACP,WACoC;CACpC,IAAI,kCAAkC,SAAS,GAC7C,OAAO,UAAU;CAGnB,IAAI,OAAO,cAAc,YAAY,cAAc,MAAM;EACvD,MAAM,mBAAmB;EACzB,OACE,0BAA0B,iBAAiB,IAAI,KAC/C,0BAA0B,iBAAiB,MAAM;CAErD;AAGF;AAWA,SAAS,gBAAgB,UAAuC;CAC9D,OAAO,QAAM,cAAc;EACzB,MAAM,SAAqB;GACzB,QAAQ,CAAC;GACT,SAAS,CAAC;GACV,QAAQ,CAAC;GACT,gBAAgB;GAChB,iBAAiB;GACjB,gBAAgB;EAClB;EAEA,QAAM,SAAS,QAAQ,WAAW,UAAU;GAC1C,IAAI,CAAC,QAAM,eAAe,KAAK,GAAG;GAElC,MAAM,YAAY,MAAM;GAGxB,IAAI,cAAc,kBAAkB;IAClC,OAAO,iBAAiB;IACxB;GACF;GACA,IAAI,cAAc,mBAAmB;IACnC,OAAO,kBAAkB;IACzB;GACF;GACA,IAAI,cAAc,kBAAkB;IAClC,OAAO,iBAAiB;IACxB;GACF;GAGA,MAAM,eAAe,0BAA0B,SAAS;GACxD,IAAI,iBAAiB,UACnB,OAAO,OAAO,KAAK,KAAK;QACnB,IAAI,iBAAiB,WAC1B,OAAO,QAAQ,KAAK,KAAK;QACpB,IAAI,iBAAiB,UAC1B,OAAO,OAAO,KAAK,KAAK;QAGxB,OAAO,QAAQ,KAAK,KAAK;EAE7B,CAAC;EAED,OAAO;CACT,GAAG,CAAC,QAAQ,CAAC;AACf;AAKA,IAAM,0BAA0B,QAAM,cAAwC,EAC5E,MAAM,OACR,CAAC;AAED,SAAS,sBAAsB;CAC7B,OAAO,QAAM,WAAW,uBAAuB;AACjD;AAEA,SAAS,uBACP,SACqB;CACrB,MAAM,MAAM,SAAS,cAAc;CACnC,IAAI,CAAC,WAAW,CAAC,KAAK,OAAO;CAC7B,OAAO,IAAI,iBAAiB,OAAO,CAAC,CAAC,cAAc,QAAQ,QAAQ;AACrE;AAEA,SAAS,6BACP,KACiC;CACjC,OAAO,QAAQ,SAAS,QAAQ,QAAQ,MAAM,KAAA;AAChD;AAEA,SAAS,+BACP,WACgB;CAChB,OAAO,cAAc,QAAQ,UAAU;AACzC;AAEA,SAAS,8BAA8B,SAAiC;CACtE,MAAM,0BAAU,IAAI,IAAa;CACjC,IAAI,UAA0B;CAE9B,OAAO,SAAS;EACd,QAAQ,IAAI,OAAO;EACnB,IAAI,YAAY,QAAQ,cAAc,iBAAiB;EACvD,UAAU,QAAQ;CACpB;CAEA,QAAQ,IAAI,QAAQ,cAAc,eAAe;CACjD,IAAI,QAAQ,cAAc,MAAM,QAAQ,IAAI,QAAQ,cAAc,IAAI;CAEtE,OAAO,MAAM,KAAK,OAAO;AAC3B;AAEA,SAAS,0BAA0B,EACjC,cACA,aACA,gBAKiB;CACjB,MAAM,CAAC,mBAAmB,wBACxB,QAAM,eACE,6BAA6B,WAAW,KAAK,KACrD;CAEF,QAAM,gBAAgB;EACpB,IAAI,cAAc;EAElB,MAAM,wBAAwB,6BAA6B,WAAW;EACtE,IAAI,uBAAuB;GACzB,sBAAsB,YACpB,YAAY,wBAAwB,UAAU,qBAChD;GACA;EACF;EAEA,MAAM,YAAY,aAAa;EAC/B,MAAM,MAAM,WAAW,cAAc;EACrC,IAAI,CAAC,aAAa,CAAC,KAAK;EAExB,MAAM,wBAAwB;GAC5B,MAAM,gBAAgB,uBAAuB,SAAS;GACtD,sBAAsB,YACpB,YAAY,gBAAgB,UAAU,aACxC;EACF;EAEA,gBAAgB;EAEhB,MAAM,WAAW,IAAI;EACrB,IAAI,CAAC,UAAU;EAEf,MAAM,WAAW,IAAI,SAAS,eAAe;EAC7C,KAAK,MAAM,UAAU,8BAA8B,SAAS,GAC1D,SAAS,QAAQ,QAAQ;GACvB,YAAY;GACZ,iBAAiB;IAAC;IAAO;IAAS;GAAO;EAC3C,CAAC;EAGH,aAAa,SAAS,WAAW;CACnC,GAAG;EAAC;EAAc;EAAa;CAAY,CAAC;CAE5C,OAAO,gBAAgB,+BAA+B,iBAAiB;AACzE;AAgBA,IAAM,yBACJ,oBAAC,QAAD;CAAM,WAAU;WACd,oBAAC,WAAD;EAAW,MAAK;EAAO,MAAK;CAAM,CAAA;AAC9B,CAAA;AAGR,SAAS,eAAe,EACtB,MACA,eACA,SACA,WACA,GAAG,SACmB;CACtB,MAAM,EAAE,OAAO,kBAAkB,WAAW;CAC5C,MAAM,cAAc,UAAU;CAC9B,MAAM,yBAAyB,iBAAiB;CAEhD,IAAI,aACF,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,oCAAoC,SAAS;EAC3D,GAAI;EACJ,KAAI;YAEJ,qBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAW;aAJb,CAME,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,GACN,oBAAC,eAAD,EAAe,WAAU,mIAAoI,CAAA,CACvJ;;CACL,CAAA;CAIT,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,mEACA,SACF;EACA,GAAI;EACJ,KAAI;YAPN,CASE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;cACZ,QACC,qBAAA,UAAA,EAAA,UAAA,CACG,wBACD,oBAAC,QAAD;KAAM,WAAU;eAAuD;IAEjE,CAAA,CACN,EAAA,CAAA;GAED,CAAA,GACJ,WACC,oBAAC,KAAD;IAAG,WAAU;cACX,oBAAC,QAAD;KAAM,aAAU;eAA4B;IAAc,CAAA;GACzD,CAAA,CAEF;MACL,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAW;aAEX,oBAAC,gBAAD;IAAgB,eAAY;IAAO,WAAU;GAAU,CAAA;EACjD,CAAA,CACL;;AAET;AAEA,eAAe,cAAc;AAW7B,SAAS,iBAAiB,EAAE,UAAU,aAAkC;CACtE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgC;EAC5C;CACE,CAAA;AAET;AACA,iBAAiB,cAAc;AAE/B,SAAS,kBAAkB,EAAE,UAAU,aAAkC;CACvE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAiC;EAC7C;CACE,CAAA;AAET;AACA,kBAAkB,cAAc;AAEhC,SAAS,iBAAiB,EAAE,UAAU,aAAkC;CACtE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgC;EAC5C;CACE,CAAA;AAET;AACA,iBAAiB,cAAc;AAa/B,SAAS,cAAc,EACrB,UACA,cAAc,YAAY,sBAC1B,aACqB;CACrB,MAAM,cACJ,oBAAC,aAAD;EAAa,WAAU;YACpB,QAAM,SAAS,IAAI,WAAW,UAC7B,oBAAC,iBAAD,EAAA,UAAkB,MAAuB,CAAA,CAC1C;CACU,CAAA;CAGf,OACE,oBAAC,cAAD;EACE,aAAU;EACV,WAAW,GACT,qDACA,SACF;YAEA,oBAAC,qBAAD,EAAA,UACE,oBAAC,OAAD;GAAK,cAAY;aAAY;EAAiB,CAAA,EAC3B,CAAA;CACT,CAAA;AAElB;AAEA,cAAc,cAAc;AAC5B,2BAA2B,eAAe,SAAS;AAanD,SAAS,qBAAqB,EAAE,OAAO,aAAwC;CAC7E,OACE,qBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,cAAY;EACZ,WAAW,GAAG,+CAA+C,SAAS;YAJxE,CAME,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA;EACH,CAAA,GACL,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cAAW;GAAY,CAAA,GACvC,oBAAC,WAAD,EAAW,WAAU,iBAAkB,CAAA,CACpC;IACF;;AAET;AAEA,qBAAqB,cAAc;AAMnC,IAAM,kBAAkB,IACtB,iLACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,QAAQ;CACV,EACF;CACA,iBAAiB,EACf,OAAO,UACT;AACF,CACF;AAcA,SAAS,kBAAkB,EACzB,MACA,OACA,WAAW,OACX,OACA,SACA,MACA,WACA,YACyB;CACzB,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,QAAM,SAAS,MAAM,QAAQ,IAAI;CACrD,MAAM,iBAAiB,QAAM,SAAS,QAAQ,QAAQ,CAAC,CAAC,MACrD,UACC,QAAM,eAAuC,KAAK,KAClD,MAAM,MAAM,aAAa,IAC7B;CACA,MAAM,gBAAgB,YAAY;CAClC,MAAM,CAAC,QAAQ,aAAa,QAAM,SAAS,iBAAiB,WAAW;CACvE,MAAM,WAAW,QAAM,MAAM;CAC7B,MAAM,eAAe,gBAAgB,UAAU,SAAS;CACxD,MAAM,wBACJ;CACF,MAAM,2BACJ,gBAAgB,UACZ,4CACA;CACN,MAAM,2BACJ,gBAAgB,UAAU,iBAAiB;CAC7C,MAAM,eAAe,QAAM,eAClB,EACL,6BAA6B;EAC3B,MAAM,YAAY,aAAa;EAC/B,MAAM,OAAO,WAAW,sBAAsB;EAE9C,MAAM,kBADM,WAAW,cAAc,YAAA,EACT,eAAe,MAAM,UAAU;EAC3D,MAAM,IAAI,OAAQ,gBAAgB,UAAU,KAAK,OAAO,KAAK,QAAS;EAEtE,OAAO;GACL;GACA,GAAG;GACH,KAAK;GACL,OAAO;GACP,QAAQ;GACR,MAAM;GACN,OAAO;GACP,QAAQ;EACV;CACF,EACF,IACA,CAAC,cAAc,WAAW,CAC5B;CAEA,QAAM,gBAAgB;EACpB,IAAI,iBAAiB,aAAa,UAAU,IAAI;CAClD,GAAG,CAAC,eAAe,WAAW,CAAC;CAE/B,MAAM,kBAAkB,sBAAsB,OAAO,KAAK;CAE1D,MAAM,cACJ,oBAAC,QAAD;EACE,aAAU;EACV,WAAU;YAET;CACG,CAAA;CAGR,MAAM,eACJ,oBAAC,QAAD;EAAM,WAAU;YACb;CACG,CAAA;CAGR,MAAM,eAAe,SAAS,QAC5B,oBAAC,OAAD;EACE,MAAK;EACL,SAAQ;EACR,OAAM;EACN,WAAU;EACV,eAAY;YAEX;CACI,CAAA;CAGT,MAAM,iBAAiB,eACrB,oBAAC,cAAD;EACE,eAAY;EACZ,WAAW,GACT,0JACA,SAAS,cAAc,kBACvB,iBAAiB,UAAU,cAC7B;CACD,CAAA;CAGH,MAAM,gBAAgB,GACpB,gBAAgB,EAAE,OAAO,gBAAgB,WAAW,UAAU,CAAC,GAC/D,qFACA,qMACA,SACF;CAEA,MAAM,YAAY,WAAW,EAAE,gBAAgB,OAAgB,IAAI,CAAC;CAGpE,IAAI,aAAa;EACf,MAAM,uBACJ,oBAAC,QAAD;GACE,aAAU;GACV,WAAU;aAET;EACG,CAAA;EAGR,MAAM,iBAAiB,OACrB,oBAAC,KAAD;GACQ;GACN,WAAW,GAAG,aAAa;GAC3B,cAAY;GACZ,GAAI;GACJ,aAAU;aAET;EACA,CAAA,IAEH,oBAAC,UAAD;GACE,MAAK;GACL,SAAS,oBAAoB,UAAU,CAAC,MAAM,IAAI;GAClD,WAAW,GAAG,eAAe,gBAAgB;GAC7C,cAAY;GACZ,GAAI;GACJ,aAAU;aAET;EACK,CAAA;EAGV,IAAI,CAAC,aAAa;GAChB,IAAI,CAAC,OAAO,OAAO;GACnB,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,eAAiB,CAAA,GACzC,oBAAC,cAAD;IAAc,MAAM;IAAc,YAAY;cAC3C;GACW,CAAA,CACP,EAAA,CAAA;EAEb;EAEA,OACE,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;GACE,WAAW,GAAG,eAAe,gBAAgB;GAC7C,cAAY;GACZ,aAAU;aAET;EACa,CAAA,GAChB,oBAAC,cAAD;GACE,MAAM;GACN,OAAM;GACN,YAAY;GACZ,aAAa;GACb,QAAQ;GACR,oBAAoB;IAClB,MAAM;IACN,OAAO;IACP,kBAAkB;GACpB;GACA,gBAAe;GACf,cAAY,GAAG,MAAM;GACrB,OACE,EACE,iCAAiC,sBACnC;GAEF,WAAW,GACT,0FACA,iBACA,wBACF;aAEA,qBAAC,OAAD;IACE,WAAW,GACT,2FACA,+HACA,wBACF;IACA,aAAU;IACV,MAAK;IACL,cAAY;cARd,CAUE,oBAAC,KAAD;KACE,WAAU;KACV,eAAY;eAEX;IACA,CAAA,GACF,QACE;;EACO,CAAA,CACH,EAAA,CAAA;CAEjB;CAGA,MAAM,oBAAoB;EACxB,IAAI,aACF,UAAU,CAAC,MAAM;EAEnB,UAAU;CACZ;CAEA,MAAM,cACJ,QAAQ,CAAC,cACP,qBAAC,KAAD;EACQ;EACN,WAAW;EACX,cAAY;EACZ,GAAI;EACJ,aAAU;YALZ;GAOG;GACA;GACA;GACA;EACA;MAEH,qBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,WAAW,GAAG,eAAe,gBAAgB;EAC7C,cAAY;EACZ,iBAAe,cAAc,SAAS,KAAA;EACtC,iBAAe,cAAc,WAAW,KAAA;EACxC,GAAI;EACJ,aAAU;YARZ;GAUG;GACA;GACA;GACA;EACK;;CAGZ,IAAI,CAAC,aAAa,OAAO;CAEzB,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,aACA,UACC,oBAAC,MAAD;EACE,IAAI;EACJ,MAAK;EACL,cAAY,GAAG,MAAM;EACrB,WAAU;EAET;CACC,CAAA,CAEN,EAAA,CAAA;AAEN;AAEA,kBAAkB,cAAc;AAehC,SAAS,iBAAiB,EACxB,OACA,OACA,WAAW,OACX,MACA,SACA,aACwB;CACxB,MAAM,kBAAkB,sBAAsB,OAAO,KAAK;CAE1D,MAAM,gBAAgB,GACpB,gBAAgB,EAAE,OAAO,WAAW,WAAW,UAAU,CAAC,GAC1D,8FACA,kLACA,SACF;CAEA,MAAM,YAAY,WAAW,EAAE,gBAAgB,OAAgB,IAAI,CAAC;CAEpE,MAAM,UACJ,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EAAM,WAAU;YAAqB;CAAY,CAAA,GAChD,SAAS,QACR,oBAAC,OAAD;EACE,MAAK;EACL,SAAQ;EACR,OAAM;EACN,WAAU;EACV,eAAY;YAEX;CACI,CAAA,CAET,EAAA,CAAA;CAGJ,IAAI,MACF,OACE,oBAAC,KAAD;EACQ;EACN,WAAW;EACX,cAAY;EACZ,GAAI;EACJ,aAAU;YAET;CACA,CAAA;CAIP,OACE,oBAAC,UAAD;EACE,MAAK;EACI;EACT,WAAW,GAAG,eAAe,wCAAwC;EACrE,cAAY;EACZ,GAAI;EACJ,aAAU;YAET;CACK,CAAA;AAEZ;AACA,iBAAiB,cAAc;AAY/B,SAAS,sBAAsB,EAC7B,QAAQ,GACR,aAC6B;CAC7B,MAAM,gBAAgB,iBAAiB,OAAO,CAAC;CAE/C,OACE,oBAAC,cAAD;EACE,WAAW,GACT,qDACA,SACF;YAEA,oBAAC,qBAAD,EAAA,UACE,oBAAC,aAAD;GAAa,WAAU;aACpB,MAAM,KAAK,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG,MAC7C,oBAAC,iBAAD,EAAA,UACE,oBAAC,oBAAD,CAAqB,CAAA,EACN,GAFK,gBAAgB,GAErB,CAClB;EACU,CAAA,EACM,CAAA;CACT,CAAA;AAElB;AAEA,sBAAsB,cAAc;AACpC,2BAA2B,uBAAuB,SAAS;AAa3D,SAAS,mBAAmB,EAC1B,QAAQ,gBACR,UACA,aAC0B;CAC1B,MAAM,EAAE,UAAU,WAAW;CAI7B,IAHoB,UAAU,aAI5B,OAAO;CAGT,OACE,qBAAC,cAAD;EACE,aAAU;EACV,WAAW,GAAG,yCAAyC,SAAS;YAFlE,CAIE,oBAAC,mBAAD;GAAmB,WAAU;aAC1B;EACgB,CAAA,GACnB,oBAAC,qBAAD;GAAqB,WAAU;aAC7B,oBAAC,OAAD;IACE,WAAU;IACV,UAAU;IACV,MAAK;IACL,cAAY;IAEX;GACE,CAAA;EACc,CAAA,CACT;;AAElB;AAEA,mBAAmB,cAAc;AACjC,2BAA2B,oBAAoB,SAAS;AAMxD,IAAM,mBAAmB,IACvB,qUACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,OAAO;EACP,UAAU;CACZ,EACF;CACA,iBAAiB,EACf,OAAO,UACT;AACF,CACF;AAoBA,SAAS,mBAAmB,EAC1B,OACA,MACA,MACA,aAAa,OACb,SACA,eACA,aAC0B;CAC1B,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,gBAAgB,UAAU,SAAS;CAEvD,IAAI,aAAa;EACf,MAAM,kBACJ,oBAAC,UAAD;GACE,MAAK;GACI;GACM;GACf,aAAU;GACV,cAAY,SAAS,KAAA;GACrB,WAAW,GACT,kNACA,aAAa,kBAAkB,kBAC/B,SACF;aAEC,QAAQ,oBAAC,eAAD,EAAe,WAAU,mCAAoC,CAAA;EAChE,CAAA;EAGV,IAAI,CAAC,SAAS,CAAC,MACb,OAAO;EAGT,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,gBAAkB,CAAA,GAC1C,oBAAC,cAAD;GAAc,MAAM;GAAa,YAAY;aAC3C,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KAAM,WAAU;eAAe;IAAY,CAAA,GAC1C,QACC,oBAAC,QAAD;KAAM,WAAU;eAAiC;IAAW,CAAA,CAE3D;;EACO,CAAA,CACP,EAAA,CAAA;CAEb;CAEA,OACE,oBAAC,OAAD;EAAK,MAAK;YACR,qBAAC,UAAD;GACE,MAAK;GACI;GACM;GACf,aAAU;GACV,cAAY;GACZ,WAAW,GACT,iBAAiB,EAAE,OAAO,aAAa,aAAa,UAAU,CAAC,GAC/D,qFACA,SACF;aAVF,CAYE,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,GACL,QACC,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,CAEF;;CACL,CAAA;AAET;AAEA,mBAAmB,cAAc;AAcjC,SAAS,2BAA2B,EAClC,QAAQ,GACR,QAAQ,gBACR,aACkC;CAClC,MAAM,gBAAgB,iBAAiB,OAAO,CAAC;CAE/C,OACE,qBAAC,cAAD;EACE,WAAW,GACT,8EACA,SACF;YAJF,CAME,oBAAC,mBAAD;GAAmB,WAAU;aAC1B;EACgB,CAAA,GACnB,oBAAC,qBAAD;GAAqB,WAAU;aAC7B,oBAAC,OAAD;IAAK,WAAU;cACZ,MAAM,KAAK,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG,MAC7C,oBAAC,qBAAD,CAAiD,GAAvB,iBAAiB,GAAM,CAClD;GACE,CAAA;EACc,CAAA,CACT;;AAElB;AAEA,2BAA2B,cAAc;AACzC,2BAA2B,4BAA4B,SAAS;AAoBhE,SAAS,kBAAkB,EACzB,MACA,UACA,WACA,WAAW,OACX,UACA,aACyB;CACzB,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,gBAAgB,UAAU,SAAS;CAEvD,IAAI,aAAa;EACf,MAAM,eACJ,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,aAAU;GACV,cAAY,OAAO,GAAG,KAAK,iBAAiB;GAC5C,iBAAc;GACd,WAAW,GACT,8OACA,SACF;aAEA,oBAAC,QAAD;IACE,KAAK;IACL,KAAK;IACL,UAAU;IACV,MAAK;IACL,WAAU;IACV,WAAW,WAAW,WAAW,KAAA;GAClC,CAAA;EACK,CAAA;EAGV,IAAI,CAAC,QAAQ,CAAC,UAAU,OAAO;EAE/B,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,aAAe,CAAA,GACvC,oBAAC,cAAD;GAAc,MAAM;GAAa,YAAY;aAC3C,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,QAAQ,oBAAC,QAAD;KAAM,WAAU;eAAe;IAAW,CAAA,GAClD,YACC,oBAAC,QAAD;KAAM,WAAU;eAAiC;IAAe,CAAA,CAE/D;;EACO,CAAA,CACP,EAAA,CAAA;CAEb;CAEA,OACE,qBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,aAAU;EACV,cAAY,OAAO,GAAG,KAAK,iBAAiB;EAC5C,iBAAc;EACd,WAAW,GACT,4OACA,SACF;YATF,CAWE,oBAAC,QAAD;GACE,KAAK;GACL,KAAK;GACL,UAAU;GACV,MAAK;GACL,WAAU;GACV,WAAW,WAAW,WAAW,KAAA;EAClC,CAAA,GACD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,GACL,YACC,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,CAEL;IACC;;AAEZ;AAEA,kBAAkB,cAAc;AAChC,2BAA2B,mBAAmB,QAAQ;AAMtD,SAAS,0BAA0B,EAAE,aAAqC;CACxE,OAAO,oBAAC,wBAAD,EAAmC,UAAY,CAAA;AACxD;AAEA,0BAA0B,cAAc;AACxC,2BAA2B,2BAA2B,QAAQ;AA0B9D,SAAS,mBAAmB,EAC1B,WAAW,GACX,YAAY,GACZ,MACA,eACA,cAAc,QACd,MACA,UAAU,OACV,gBACA,aAC0B;CAC1B,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,cAAc,UAAU;CAC9B,MAAM,eAAe,0BAA0B;EAC7C;EACA,cAAc;CAChB,CAAC;CAED,MAAM,UAAU,kBAAkB,aAAa,cAAc;CAE7D,OACE,oBAAC,iBAAD;EACe;EACb,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,WAAW,GAAG,kBAAkB,SAAS;YAEzC,qBAAC,OAAD;GACE,aAAU;GACV,WAAW,uBAAuB;IAChC;IACA,MAAM;IACN;IACA,iBAAiB;GACnB,CAAC;aAPH;IASE,oBAAC,eAAD;KAAe,WAAU;eACvB,oBAAC,gBAAD;MAAsB;MAAqB;KAAgB,CAAA;IAC9C,CAAA;IAEf,qBAAC,gBAAD;KAAgB,WAAU;eAA1B,CACE,oBAAC,uBAAD,EAAuB,OAAO,SAAW,CAAA,GACzC,oBAAC,4BAAD,EAA4B,OAAO,UAAY,CAAA,CACjC;;IAEhB,oBAAC,eAAD;KAAe,WAAU;eACvB,oBAAC,2BAAD,CAA4B,CAAA;IACf,CAAA;GACZ;;CACE,CAAA;AAEb;AAEA,mBAAmB,cAAc;;;;;;;;;;;;;;;;;;;AA2CjC,SAAS,eAAe,EACtB,MACA,eACA,aACA,cAAc,QACd,MACA,UAAU,OACV,gBACA,WACA,UACA,KACA,GAAG,SACe;CAClB,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,cAAc,UAAU;CAC9B,MAAM,eAAe,0BAA0B;EAC7C;EACA,aAAa;EACb,cAAc;CAChB,CAAC;CAED,MAAM,UAAU,kBAAkB,aAAa,cAAc;CAE7D,MAAM,QAAQ,gBAAgB,QAAQ;CAEtC,OACE,oBAAC,wBAAwB,UAAzB;EAAkC,OAAO,EAAE,MAAM,aAAa;YAC5D,oBAAC,iBAAD;GACe;GACb,MAAM;GACN,OAAO;GACP,gBAAgB;GACX;GACL,WAAW,GAAG,kBAAkB,SAAS;GACzC,GAAI;aAEJ,qBAAC,OAAD;IACE,aAAU;IACV,WAAW,uBAAuB;KAChC;KACA,MAAM;KACN;KACA,iBAAiB;IACnB,CAAC;cAPH;KASE,oBAAC,eAAD;MAAe,WAAU;gBACvB,oBAAC,gBAAD;OACQ;OACS;OACf,SAAS;MACV,CAAA;KACY,CAAA;KAEf,oBAAC,gBAAD;MAAgB,WAAU;gBACvB,MAAM,kBACF,MAAM,gBAAgB,MAA8B,WACrD,MAAM;KACI,CAAA;KAEhB,oBAAC,eAAD;MAAe,WAAU;gBACtB,MAAM,iBACF,MAAM,eAAe,MAA8B,WACpD,MAAM;KACG,CAAA;IACZ;;EACE,CAAA;CACuB,CAAA;AAEtC;AAEA,eAAe,cAAc;AAM7B,IAAa,aAAa,OAAO,OAAO,gBAAgB;CACtD,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,KAAK;CACL,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,UAAU;CACV,UAAU;CACV,kBAAkB;CAClB,SAAS;CACT,iBAAiB;CACjB,UAAU;AACZ,CAAC"}
package/dist/index228.js CHANGED
@@ -217,7 +217,7 @@ function NavAccountMenuAccount({ avatar, name, email, selected = false, onSelect
217
217
  /* @__PURE__ */ jsx("div", {
218
218
  "aria-hidden": "true",
219
219
  className: cn("size-4 rounded-full border-2 shrink-0 flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none", selected ? "bg-primary border-primary" : "border-border bg-transparent"),
220
- children: selected && /* @__PURE__ */ jsx("div", { className: "size-1.5 rounded-full bg-primary-foreground delight-check-bounce" })
220
+ children: selected && /* @__PURE__ */ jsx("div", { className: "size-1.5 rounded-full bg-background delight-check-bounce" })
221
221
  })
222
222
  ]
223
223
  })
@@ -1 +1 @@
1
- {"version":3,"file":"index228.js","names":[],"sources":["../src/components/templates/NavAccountMenu/NavAccountMenu.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight, LogOut } from 'lucide-react';\nimport * as React from 'react';\nimport { Switch } from '@/components/atoms/forms/Switch/Switch';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n PopoverRoot as PopoverBase,\n PopoverPopup as PopoverContentBase,\n PopoverTrigger as PopoverTriggerBase,\n} from '@/components/organisms/overlays/Popover';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Context for NavAccountMenu\n// ============================================\n\ninterface NavAccountMenuContextValue {\n type: 'card' | 'simple';\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst [NavAccountMenuContext, useNavAccountMenuContext] =\n createSafeContext<NavAccountMenuContextValue>('NavAccountMenu');\n\n// ============================================\n// NavAccountMenu (Root)\n// ============================================\n\nexport interface NavAccountMenuProps {\n /** Trigger variant style */\n type?: 'card' | 'simple';\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Initial open state for uncontrolled mode */\n defaultOpen?: boolean;\n /** Children (trigger + content) */\n children: React.ReactNode;\n}\n\nfunction NavAccountMenu({\n type = 'card',\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n}: NavAccountMenuProps) {\n const [open, handleOpenChange] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const contextValue = React.useMemo(\n () => ({\n type,\n open,\n onOpenChange: handleOpenChange,\n }),\n [type, open, handleOpenChange],\n );\n\n return (\n <NavAccountMenuContext.Provider value={contextValue}>\n <PopoverBase open={open} onOpenChange={handleOpenChange}>\n <div data-slot=\"nav-account-menu\">{children}</div>\n </PopoverBase>\n </NavAccountMenuContext.Provider>\n );\n}\n\n// ============================================\n// NavAccountMenuTrigger\n// ============================================\n\nconst triggerVariants = cva(\n 'flex items-center gap-4 w-full text-left cursor-pointer transition-colors duration-200 ease-smooth outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n {\n variants: {\n type: {\n card: 'bg-surface-1 border border-border rounded-xl shadow-xs p-3 hover:bg-surface-2',\n simple: 'border border-border px-2 py-3 hover:bg-surface-2 rounded-lg',\n },\n },\n defaultVariants: {\n type: 'card',\n },\n },\n);\n\nexport interface NavAccountMenuTriggerProps\n extends VariantProps<typeof triggerVariants> {\n /** Avatar element (use Avatar component) */\n avatar?: React.ReactNode;\n /** User display name */\n name: string;\n /** User email address */\n email?: string;\n /** Optional badge after name (e.g., \"External\" tag) */\n badge?: React.ReactNode;\n /** Show logout button instead of chevron (for 'simple' type) */\n showLogoutButton?: boolean;\n /** Logout callback for simple variant */\n onLogout?: () => void;\n /** Show only avatar without name/email - useful for collapsed sidebar */\n compact?: boolean;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuTrigger({\n avatar,\n name,\n email,\n badge,\n showLogoutButton,\n onLogout,\n compact = false,\n className,\n}: NavAccountMenuTriggerProps) {\n const { type, open } = useNavAccountMenuContext();\n\n const handleLogoutClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onLogout?.();\n };\n\n const avatarContent = avatar ? (\n <div className=\"shrink-0\">{avatar}</div>\n ) : null;\n const accountDetails = !compact ? (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {name}\n </span>\n {badge && <span className=\"shrink-0\">{badge}</span>}\n </div>\n {email && (\n <span className=\"truncate text-sm text-muted-foreground\">{email}</span>\n )}\n </div>\n ) : null;\n\n if (type === 'simple' && showLogoutButton && !compact) {\n return (\n <div\n data-slot=\"nav-account-menu-trigger\"\n className={cn(triggerVariants({ type }), 'group/trigger', className)}\n >\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n aria-haspopup=\"true\"\n className=\"flex min-w-0 flex-1 items-center gap-4 text-left outline-none\"\n />\n }\n >\n {avatarContent}\n {accountDetails}\n </PopoverTriggerBase>\n <button\n type=\"button\"\n onClick={handleLogoutClick}\n className=\"shrink-0 rounded-md p-1.5 text-text-quaternary transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Sign out\"\n >\n <LogOut className=\"size-5\" />\n </button>\n </div>\n );\n }\n\n return (\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n data-slot=\"nav-account-menu-trigger\"\n aria-haspopup=\"true\"\n aria-label={compact ? `${name} account menu` : undefined}\n className={cn(\n triggerVariants({ type }),\n 'group/trigger',\n compact ? 'w-auto justify-center' : 'max-w-[280px]',\n className,\n )}\n />\n }\n >\n {avatarContent}\n {!compact && (\n <>\n {accountDetails}\n <ChevronRight\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth motion-reduce:transition-none',\n open ? 'rotate-180' : 'rtl:rotate-180',\n )}\n />\n </>\n )}\n </PopoverTriggerBase>\n );\n}\n\n// ============================================\n// NavAccountMenuContent\n// ============================================\n\nexport interface NavAccountMenuContentProps {\n /** Popover side positioning */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Popover alignment */\n align?: 'start' | 'center' | 'end';\n /** Side offset */\n sideOffset?: number;\n /** Children */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuContent({\n side = 'right',\n align = 'end',\n sideOffset = 8,\n children,\n className,\n}: NavAccountMenuContentProps) {\n return (\n <PopoverContentBase\n side={side}\n align={align}\n sideOffset={sideOffset}\n aria-label=\"Account menu\"\n data-slot=\"nav-account-menu-content\"\n className={cn(\n 'w-[300px] max-w-[calc(100vw-2rem)] p-0 gap-0 bg-popover border border-border rounded-[14px] overflow-hidden',\n 'shadow-[0px_12px_16px_-4px_color-mix(in_srgb,var(--foreground)_8%,transparent),0px_4px_6px_-2px_color-mix(in_srgb,var(--foreground)_3%,transparent),0px_2px_2px_-1px_color-mix(in_srgb,var(--foreground)_4%,transparent)]',\n 'data-open:animate-in data-closed:animate-out',\n 'data-closed:fade-out-0 data-open:fade-in-0',\n 'data-closed:zoom-out-95 data-open:zoom-in-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'duration-200 motion-reduce:animate-none',\n className,\n )}\n >\n <div className=\"flex flex-col py-2\" role=\"menu\" aria-label=\"Account menu\">\n {children}\n </div>\n </PopoverContentBase>\n );\n}\n\n// ============================================\n// NavAccountMenuHeader\n// ============================================\n\nexport interface NavAccountMenuHeaderProps {\n /** Header title (e.g. \"Profile\") */\n title: string;\n /** Subtitle text or custom React node (e.g. \"Last login 22 May, 2026 11:30pm\") */\n subtitle?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuHeader({\n title,\n subtitle,\n className,\n}: NavAccountMenuHeaderProps) {\n return (\n <div\n data-slot=\"nav-account-menu-header\"\n className={cn('px-6 pb-3 delight-fade-in', className)}\n >\n <p className=\"text-base font-semibold text-foreground\">{title}</p>\n {subtitle &&\n (typeof subtitle === 'string' ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n ) : (\n <div className=\"mt-2\">{subtitle}</div>\n ))}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSection\n// ============================================\n\nexport interface NavAccountMenuSectionProps {\n /** Optional section header label */\n label?: string;\n /** Show top border separator between sections */\n bordered?: boolean;\n /** Section content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSection({\n label,\n bordered = false,\n children,\n className,\n}: NavAccountMenuSectionProps) {\n return (\n <section\n data-slot=\"nav-account-menu-section\"\n aria-label={label}\n className={cn(\n 'flex flex-col gap-1 py-1.5',\n bordered && 'border-t border-border',\n className,\n )}\n >\n {label && (\n <div className=\"px-3 pt-1.5 pb-1\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {label}\n </span>\n </div>\n )}\n {children}\n </section>\n );\n}\n\n// ============================================\n// NavAccountMenuItem\n// ============================================\n\n/**\n * Props passed to the render function for custom menu item rendering.\n */\nexport interface NavAccountMenuItemRenderProps {\n /** Combined className for styling */\n className: string;\n /** Click handler that closes menu and triggers onSelect */\n onClick: () => void;\n /** Menu item content (icon, label, shortcut) */\n children: React.ReactNode;\n}\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts a function that receives props and returns an element.\n */\ntype NavAccountMenuItemRenderFn = (\n props: NavAccountMenuItemRenderProps,\n) => React.ReactElement;\n\nexport interface NavAccountMenuItemProps {\n /** Left icon (20px) */\n icon?: React.ReactNode;\n /** Keyboard shortcut display */\n shortcut?: string;\n /** Destructive styling (red) */\n destructive?: boolean;\n /** Disabled state */\n disabled?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /**\n * Render prop for polymorphic rendering.\n * Use this to render the menu item as a different element (e.g., link).\n * @example\n * <NavAccountMenuItem\n * icon={<User01 />}\n * render={(props) => <a {...props} href=\"/profile\" />}\n * >\n * View profile\n * </NavAccountMenuItem>\n */\n render?: NavAccountMenuItemRenderFn;\n /** Label text */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuItem({\n icon,\n shortcut,\n destructive = false,\n disabled = false,\n onSelect,\n render,\n children,\n className,\n}: NavAccountMenuItemProps) {\n const { onOpenChange } = useNavAccountMenuContext();\n\n const handleClick = () => {\n if (disabled) return;\n onSelect?.();\n onOpenChange(false);\n };\n\n const content = (\n <div className=\"flex flex-1 gap-2 items-center overflow-hidden p-2 rounded-md transition-[background-color] duration-200 ease-smooth delight-selection-press motion-reduce:transition-none\">\n <div className=\"flex flex-1 gap-2 items-center min-w-0\">\n {icon && (\n <span\n className={cn(\n 'shrink-0 [&>svg]:size-4 transition-transform duration-200 ease-smooth group-hover/menuitem:translate-x-0.5 motion-reduce:transition-none',\n destructive ? 'text-destructive' : 'text-foreground',\n )}\n >\n {icon}\n </span>\n )}\n <span\n className={cn(\n 'flex-1 text-sm truncate',\n destructive ? 'text-destructive' : 'text-secondary-foreground',\n )}\n >\n {children}\n </span>\n </div>\n {shortcut && (\n <Kbd variant=\"outline\" size=\"xs\" className=\"shrink-0\">\n {shortcut}\n </Kbd>\n )}\n </div>\n );\n\n const baseClassName = cn(\n 'group/menuitem flex items-center px-1.5 py-0 w-full text-left cursor-pointer outline-none',\n 'hover:[&>div]:bg-muted focus-visible:[&>div]:bg-muted',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n disabled && 'pointer-events-none opacity-50',\n className,\n );\n\n if (render) {\n return render({\n className: baseClassName,\n onClick: handleClick,\n children: content,\n });\n }\n\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-slot=\"nav-account-menu-item\"\n className={baseClassName}\n onClick={handleClick}\n disabled={disabled}\n aria-disabled={disabled || undefined}\n >\n {content}\n </button>\n );\n}\n\n// ============================================\n// NavAccountMenuAccount\n// ============================================\n\nexport interface NavAccountMenuAccountProps {\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Account display name */\n name: string;\n /** Account email */\n email: string;\n /** Whether this account is currently selected */\n selected?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuAccount({\n avatar,\n name,\n email,\n selected = false,\n onSelect,\n className,\n}: NavAccountMenuAccountProps) {\n return (\n <div\n data-slot=\"nav-account-menu-account\"\n className={cn('flex items-center px-1.5 py-0 w-full', className)}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n aria-label={`Switch to ${name} (${email})`}\n className={cn(\n 'relative flex flex-1 gap-2 items-center overflow-hidden px-2 py-1.5 rounded-md cursor-pointer outline-none',\n 'hover:bg-muted focus-visible:bg-muted',\n 'transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n 'text-left',\n selected && 'bg-surface-2',\n )}\n onClick={onSelect}\n >\n {avatar && <div className=\"shrink-0\">{avatar}</div>}\n <div className=\"flex flex-col min-w-0 flex-1\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {name}\n </span>\n <span className=\"text-sm text-muted-foreground truncate\">\n {email}\n </span>\n </div>\n {/* Radio indicator */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'size-4 rounded-full border-2 shrink-0 flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n selected\n ? 'bg-primary border-primary'\n : 'border-border bg-transparent',\n )}\n >\n {selected && (\n <div className=\"size-1.5 rounded-full bg-primary-foreground delight-check-bounce\" />\n )}\n </div>\n </button>\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSeparator\n// ============================================\n\nexport interface NavAccountMenuSeparatorProps {\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSeparator({ className }: NavAccountMenuSeparatorProps) {\n return (\n <hr\n data-slot=\"nav-account-menu-separator\"\n className={cn('h-px border-0 bg-border mx-5', className)}\n />\n );\n}\n\n// ============================================\n// NavAccountMenuFooter\n// ============================================\n\nexport interface NavAccountMenuFooterProps {\n /** Footer content (typically buttons) */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuFooter({\n children,\n className,\n}: NavAccountMenuFooterProps) {\n return (\n <div\n data-slot=\"nav-account-menu-footer\"\n className={cn('flex items-center justify-center px-5 pt-4', className)}\n >\n {children}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuThemeSwitch (uses Switch theme variant)\n// ============================================\n\nexport interface NavAccountMenuThemeSwitchProps {\n /** Switch theme variant to render */\n variant?:\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n /** Switch size */\n size?: 'sm' | 'md' | 'lg';\n /** Controlled checked state (dark = checked) */\n checked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n /** Optional label displayed next to the switch (e.g. \"Light Mode\") */\n label?: string;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuThemeSwitch({\n variant = 'theme-gradient',\n size = 'sm',\n checked,\n onCheckedChange,\n label,\n className,\n}: NavAccountMenuThemeSwitchProps) {\n const switchId = React.useId();\n const labelId = label ? `${switchId}-label` : undefined;\n\n return (\n <div\n data-slot=\"nav-account-menu-theme-switch\"\n className={cn('flex items-center px-1.5 py-0', className)}\n >\n <div className=\"flex items-center gap-2.5 p-2\">\n <Switch\n id={switchId}\n variant={variant}\n size={size}\n checked={checked}\n onCheckedChange={onCheckedChange}\n aria-labelledby={labelId}\n aria-label={label ? undefined : 'Theme selector'}\n />\n {label && (\n <label\n htmlFor={switchId}\n id={labelId}\n className=\"cursor-pointer text-sm text-secondary-foreground\"\n >\n {label}\n </label>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================\n// Display Names\n// ============================================\n\nNavAccountMenu.displayName = 'NavAccountMenu';\nNavAccountMenuTrigger.displayName = 'NavAccountMenuTrigger';\nNavAccountMenuContent.displayName = 'NavAccountMenuContent';\nNavAccountMenuHeader.displayName = 'NavAccountMenuHeader';\nNavAccountMenuSection.displayName = 'NavAccountMenuSection';\nNavAccountMenuItem.displayName = 'NavAccountMenuItem';\nNavAccountMenuAccount.displayName = 'NavAccountMenuAccount';\nNavAccountMenuSeparator.displayName = 'NavAccountMenuSeparator';\nNavAccountMenuFooter.displayName = 'NavAccountMenuFooter';\nNavAccountMenuThemeSwitch.displayName = 'NavAccountMenuThemeSwitch';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n NavAccountMenu,\n NavAccountMenuAccount,\n NavAccountMenuContent,\n NavAccountMenuFooter,\n NavAccountMenuHeader,\n NavAccountMenuItem,\n NavAccountMenuSection,\n NavAccountMenuSeparator,\n NavAccountMenuThemeSwitch,\n NavAccountMenuTrigger,\n triggerVariants as navAccountMenuTriggerVariants,\n};\n"],"mappings":";;;;;;;;;;;;AA0BA,IAAM,CAAC,uBAAuB,4BAC5B,kBAA8C,gBAAgB;AAmBhE,SAAS,eAAe,EACtB,OAAO,QACP,MAAM,gBACN,cAAc,OACd,cACA,YACsB;CACtB,MAAM,CAAC,MAAM,oBAAoB,qBAAqB;EACpD,OAAO;EACP,cAAc;EACd,UAAU;CACZ,CAAC;CAED,MAAM,eAAe,QAAM,eAClB;EACL;EACA;EACA,cAAc;CAChB,IACA;EAAC;EAAM;EAAM;CAAgB,CAC/B;CAEA,OACE,oBAAC,sBAAsB,UAAvB;EAAgC,OAAO;YACrC,oBAAC,aAAD;GAAmB;GAAM,cAAc;aACrC,oBAAC,OAAD;IAAK,aAAU;IAAoB;GAAc,CAAA;EACtC,CAAA;CACiB,CAAA;AAEpC;AAMA,IAAM,kBAAkB,IACtB,mOACA;CACE,UAAU,EACR,MAAM;EACJ,MAAM;EACN,QAAQ;CACV,EACF;CACA,iBAAiB,EACf,MAAM,OACR;AACF,CACF;AAsBA,SAAS,sBAAsB,EAC7B,QACA,MACA,OACA,OACA,kBACA,UACA,UAAU,OACV,aAC6B;CAC7B,MAAM,EAAE,MAAM,SAAS,yBAAyB;CAEhD,MAAM,qBAAqB,MAAwB;EACjD,EAAE,gBAAgB;EAClB,WAAW;CACb;CAEA,MAAM,gBAAgB,SACpB,oBAAC,OAAD;EAAK,WAAU;YAAY;CAAY,CAAA,IACrC;CACJ,MAAM,iBAAiB,CAAC,UACtB,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,GACL,SAAS,oBAAC,QAAD;IAAM,WAAU;cAAY;GAAY,CAAA,CAC/C;MACJ,SACC,oBAAC,QAAD;GAAM,WAAU;aAA0C;EAAY,CAAA,CAErE;MACH;CAEJ,IAAI,SAAS,YAAY,oBAAoB,CAAC,SAC5C,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,gBAAgB,EAAE,KAAK,CAAC,GAAG,iBAAiB,SAAS;YAFrE,CAIE,qBAAC,gBAAD;GACE,QACE,oBAAC,UAAD;IACE,MAAK;IACL,iBAAc;IACd,WAAU;GACX,CAAA;aANL,CASG,eACA,cACiB;MACpB,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAW;aAEX,oBAAC,QAAD,EAAQ,WAAU,SAAU,CAAA;EACtB,CAAA,CACL;;CAIT,OACE,qBAAC,gBAAD;EACE,QACE,oBAAC,UAAD;GACE,MAAK;GACL,aAAU;GACV,iBAAc;GACd,cAAY,UAAU,GAAG,KAAK,iBAAiB,KAAA;GAC/C,WAAW,GACT,gBAAgB,EAAE,KAAK,CAAC,GACxB,iBACA,UAAU,0BAA0B,iBACpC,SACF;EACD,CAAA;YAbL,CAgBG,eACA,CAAC,WACA,qBAAA,UAAA,EAAA,UAAA,CACG,gBACD,oBAAC,cAAD,EACE,WAAW,GACT,qHACA,OAAO,eAAe,gBACxB,EACD,CAAA,CACD,EAAA,CAAA,CAEc;;AAExB;AAmBA,SAAS,sBAAsB,EAC7B,OAAO,SACP,QAAQ,OACR,aAAa,GACb,UACA,aAC6B;CAC7B,OACE,oBAAC,cAAD;EACQ;EACC;EACK;EACZ,cAAW;EACX,aAAU;EACV,WAAW,GACT,+GACA,6NACA,gDACA,8CACA,gDACA,0CACA,0CACA,0CACA,0CACA,2CACA,SACF;YAEA,oBAAC,OAAD;GAAK,WAAU;GAAqB,MAAK;GAAO,cAAW;GACxD;EACE,CAAA;CACa,CAAA;AAExB;AAeA,SAAS,qBAAqB,EAC5B,OACA,UACA,aAC4B;CAC5B,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,6BAA6B,SAAS;YAFtD,CAIE,oBAAC,KAAD;GAAG,WAAU;aAA2C;EAAS,CAAA,GAChE,aACE,OAAO,aAAa,WACnB,oBAAC,KAAD;GAAG,WAAU;aAAsC;EAAY,CAAA,IAE/D,oBAAC,OAAD;GAAK,WAAU;aAAQ;EAAc,CAAA,EAEtC;;AAET;AAiBA,SAAS,sBAAsB,EAC7B,OACA,WAAW,OACX,UACA,aAC6B;CAC7B,OACE,qBAAC,WAAD;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,8BACA,YAAY,0BACZ,SACF;YAPF,CASG,SACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA;EACH,CAAA,GAEN,QACM;;AAEb;AAuDA,SAAS,mBAAmB,EAC1B,MACA,UACA,cAAc,OACd,WAAW,OACX,UACA,QACA,UACA,aAC0B;CAC1B,MAAM,EAAE,iBAAiB,yBAAyB;CAElD,MAAM,oBAAoB;EACxB,IAAI,UAAU;EACd,WAAW;EACX,aAAa,KAAK;CACpB;CAEA,MAAM,UACJ,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,QACC,oBAAC,QAAD;IACE,WAAW,GACT,4IACA,cAAc,qBAAqB,iBACrC;cAEC;GACG,CAAA,GAER,oBAAC,QAAD;IACE,WAAW,GACT,2BACA,cAAc,qBAAqB,2BACrC;IAEC;GACG,CAAA,CACH;MACJ,YACC,oBAAC,KAAD;GAAK,SAAQ;GAAU,MAAK;GAAK,WAAU;aACxC;EACE,CAAA,CAEJ;;CAGP,MAAM,gBAAgB,GACpB,6FACA,yDACA,0FACA,YAAY,kCACZ,SACF;CAEA,IAAI,QACF,OAAO,OAAO;EACZ,WAAW;EACX,SAAS;EACT,UAAU;CACZ,CAAC;CAGH,OACE,oBAAC,UAAD;EACE,MAAK;EACL,MAAK;EACL,aAAU;EACV,WAAW;EACX,SAAS;EACC;EACV,iBAAe,YAAY,KAAA;YAE1B;CACK,CAAA;AAEZ;AAqBA,SAAS,sBAAsB,EAC7B,QACA,MACA,OACA,WAAW,OACX,UACA,aAC6B;CAC7B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,wCAAwC,SAAS;YAE/D,qBAAC,UAAD;GACE,MAAK;GACL,MAAK;GACL,gBAAc;GACd,cAAY,aAAa,KAAK,IAAI,MAAM;GACxC,WAAW,GACT,8GACA,yCACA,4EACA,0FACA,aACA,YAAY,cACd;GACA,SAAS;aAbX;IAeG,UAAU,oBAAC,OAAD;KAAK,WAAU;eAAY;IAAY,CAAA;IAClD,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,QAAD;MAAM,WAAU;gBACb;KACG,CAAA,GACN,oBAAC,QAAD;MAAM,WAAU;gBACb;KACG,CAAA,CACH;;IAEL,oBAAC,OAAD;KACE,eAAY;KACZ,WAAW,GACT,mJACA,WACI,8BACA,8BACN;eAEC,YACC,oBAAC,OAAD,EAAK,WAAU,mEAAoE,CAAA;IAElF,CAAA;GACC;;CACL,CAAA;AAET;AAWA,SAAS,wBAAwB,EAAE,aAA2C;CAC5E,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GAAG,gCAAgC,SAAS;CACxD,CAAA;AAEL;AAaA,SAAS,qBAAqB,EAC5B,UACA,aAC4B;CAC5B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,8CAA8C,SAAS;EAEpE;CACE,CAAA;AAET;AAyBA,SAAS,0BAA0B,EACjC,UAAU,kBACV,OAAO,MACP,SACA,iBACA,OACA,aACiC;CACjC,MAAM,WAAW,QAAM,MAAM;CAC7B,MAAM,UAAU,QAAQ,GAAG,SAAS,UAAU,KAAA;CAE9C,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,iCAAiC,SAAS;YAExD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IACE,IAAI;IACK;IACH;IACG;IACQ;IACjB,mBAAiB;IACjB,cAAY,QAAQ,KAAA,IAAY;GACjC,CAAA,GACA,SACC,oBAAC,SAAD;IACE,SAAS;IACT,IAAI;IACJ,WAAU;cAET;GACI,CAAA,CAEN;;CACF,CAAA;AAET;AAMA,eAAe,cAAc;AAC7B,sBAAsB,cAAc;AACpC,sBAAsB,cAAc;AACpC,qBAAqB,cAAc;AACnC,sBAAsB,cAAc;AACpC,mBAAmB,cAAc;AACjC,sBAAsB,cAAc;AACpC,wBAAwB,cAAc;AACtC,qBAAqB,cAAc;AACnC,0BAA0B,cAAc"}
1
+ {"version":3,"file":"index228.js","names":[],"sources":["../src/components/templates/NavAccountMenu/NavAccountMenu.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight, LogOut } from 'lucide-react';\nimport * as React from 'react';\nimport { Switch } from '@/components/atoms/forms/Switch/Switch';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n PopoverRoot as PopoverBase,\n PopoverPopup as PopoverContentBase,\n PopoverTrigger as PopoverTriggerBase,\n} from '@/components/organisms/overlays/Popover';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Context for NavAccountMenu\n// ============================================\n\ninterface NavAccountMenuContextValue {\n type: 'card' | 'simple';\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst [NavAccountMenuContext, useNavAccountMenuContext] =\n createSafeContext<NavAccountMenuContextValue>('NavAccountMenu');\n\n// ============================================\n// NavAccountMenu (Root)\n// ============================================\n\nexport interface NavAccountMenuProps {\n /** Trigger variant style */\n type?: 'card' | 'simple';\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Initial open state for uncontrolled mode */\n defaultOpen?: boolean;\n /** Children (trigger + content) */\n children: React.ReactNode;\n}\n\nfunction NavAccountMenu({\n type = 'card',\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n}: NavAccountMenuProps) {\n const [open, handleOpenChange] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const contextValue = React.useMemo(\n () => ({\n type,\n open,\n onOpenChange: handleOpenChange,\n }),\n [type, open, handleOpenChange],\n );\n\n return (\n <NavAccountMenuContext.Provider value={contextValue}>\n <PopoverBase open={open} onOpenChange={handleOpenChange}>\n <div data-slot=\"nav-account-menu\">{children}</div>\n </PopoverBase>\n </NavAccountMenuContext.Provider>\n );\n}\n\n// ============================================\n// NavAccountMenuTrigger\n// ============================================\n\nconst triggerVariants = cva(\n 'flex items-center gap-4 w-full text-left cursor-pointer transition-colors duration-200 ease-smooth outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n {\n variants: {\n type: {\n card: 'bg-surface-1 border border-border rounded-xl shadow-xs p-3 hover:bg-surface-2',\n simple: 'border border-border px-2 py-3 hover:bg-surface-2 rounded-lg',\n },\n },\n defaultVariants: {\n type: 'card',\n },\n },\n);\n\nexport interface NavAccountMenuTriggerProps\n extends VariantProps<typeof triggerVariants> {\n /** Avatar element (use Avatar component) */\n avatar?: React.ReactNode;\n /** User display name */\n name: string;\n /** User email address */\n email?: string;\n /** Optional badge after name (e.g., \"External\" tag) */\n badge?: React.ReactNode;\n /** Show logout button instead of chevron (for 'simple' type) */\n showLogoutButton?: boolean;\n /** Logout callback for simple variant */\n onLogout?: () => void;\n /** Show only avatar without name/email - useful for collapsed sidebar */\n compact?: boolean;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuTrigger({\n avatar,\n name,\n email,\n badge,\n showLogoutButton,\n onLogout,\n compact = false,\n className,\n}: NavAccountMenuTriggerProps) {\n const { type, open } = useNavAccountMenuContext();\n\n const handleLogoutClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onLogout?.();\n };\n\n const avatarContent = avatar ? (\n <div className=\"shrink-0\">{avatar}</div>\n ) : null;\n const accountDetails = !compact ? (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {name}\n </span>\n {badge && <span className=\"shrink-0\">{badge}</span>}\n </div>\n {email && (\n <span className=\"truncate text-sm text-muted-foreground\">{email}</span>\n )}\n </div>\n ) : null;\n\n if (type === 'simple' && showLogoutButton && !compact) {\n return (\n <div\n data-slot=\"nav-account-menu-trigger\"\n className={cn(triggerVariants({ type }), 'group/trigger', className)}\n >\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n aria-haspopup=\"true\"\n className=\"flex min-w-0 flex-1 items-center gap-4 text-left outline-none\"\n />\n }\n >\n {avatarContent}\n {accountDetails}\n </PopoverTriggerBase>\n <button\n type=\"button\"\n onClick={handleLogoutClick}\n className=\"shrink-0 rounded-md p-1.5 text-text-quaternary transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Sign out\"\n >\n <LogOut className=\"size-5\" />\n </button>\n </div>\n );\n }\n\n return (\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n data-slot=\"nav-account-menu-trigger\"\n aria-haspopup=\"true\"\n aria-label={compact ? `${name} account menu` : undefined}\n className={cn(\n triggerVariants({ type }),\n 'group/trigger',\n compact ? 'w-auto justify-center' : 'max-w-[280px]',\n className,\n )}\n />\n }\n >\n {avatarContent}\n {!compact && (\n <>\n {accountDetails}\n <ChevronRight\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth motion-reduce:transition-none',\n open ? 'rotate-180' : 'rtl:rotate-180',\n )}\n />\n </>\n )}\n </PopoverTriggerBase>\n );\n}\n\n// ============================================\n// NavAccountMenuContent\n// ============================================\n\nexport interface NavAccountMenuContentProps {\n /** Popover side positioning */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Popover alignment */\n align?: 'start' | 'center' | 'end';\n /** Side offset */\n sideOffset?: number;\n /** Children */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuContent({\n side = 'right',\n align = 'end',\n sideOffset = 8,\n children,\n className,\n}: NavAccountMenuContentProps) {\n return (\n <PopoverContentBase\n side={side}\n align={align}\n sideOffset={sideOffset}\n aria-label=\"Account menu\"\n data-slot=\"nav-account-menu-content\"\n className={cn(\n 'w-[300px] max-w-[calc(100vw-2rem)] p-0 gap-0 bg-popover border border-border rounded-[14px] overflow-hidden',\n 'shadow-[0px_12px_16px_-4px_color-mix(in_srgb,var(--foreground)_8%,transparent),0px_4px_6px_-2px_color-mix(in_srgb,var(--foreground)_3%,transparent),0px_2px_2px_-1px_color-mix(in_srgb,var(--foreground)_4%,transparent)]',\n 'data-open:animate-in data-closed:animate-out',\n 'data-closed:fade-out-0 data-open:fade-in-0',\n 'data-closed:zoom-out-95 data-open:zoom-in-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'duration-200 motion-reduce:animate-none',\n className,\n )}\n >\n <div className=\"flex flex-col py-2\" role=\"menu\" aria-label=\"Account menu\">\n {children}\n </div>\n </PopoverContentBase>\n );\n}\n\n// ============================================\n// NavAccountMenuHeader\n// ============================================\n\nexport interface NavAccountMenuHeaderProps {\n /** Header title (e.g. \"Profile\") */\n title: string;\n /** Subtitle text or custom React node (e.g. \"Last login 22 May, 2026 11:30pm\") */\n subtitle?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuHeader({\n title,\n subtitle,\n className,\n}: NavAccountMenuHeaderProps) {\n return (\n <div\n data-slot=\"nav-account-menu-header\"\n className={cn('px-6 pb-3 delight-fade-in', className)}\n >\n <p className=\"text-base font-semibold text-foreground\">{title}</p>\n {subtitle &&\n (typeof subtitle === 'string' ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n ) : (\n <div className=\"mt-2\">{subtitle}</div>\n ))}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSection\n// ============================================\n\nexport interface NavAccountMenuSectionProps {\n /** Optional section header label */\n label?: string;\n /** Show top border separator between sections */\n bordered?: boolean;\n /** Section content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSection({\n label,\n bordered = false,\n children,\n className,\n}: NavAccountMenuSectionProps) {\n return (\n <section\n data-slot=\"nav-account-menu-section\"\n aria-label={label}\n className={cn(\n 'flex flex-col gap-1 py-1.5',\n bordered && 'border-t border-border',\n className,\n )}\n >\n {label && (\n <div className=\"px-3 pt-1.5 pb-1\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {label}\n </span>\n </div>\n )}\n {children}\n </section>\n );\n}\n\n// ============================================\n// NavAccountMenuItem\n// ============================================\n\n/**\n * Props passed to the render function for custom menu item rendering.\n */\nexport interface NavAccountMenuItemRenderProps {\n /** Combined className for styling */\n className: string;\n /** Click handler that closes menu and triggers onSelect */\n onClick: () => void;\n /** Menu item content (icon, label, shortcut) */\n children: React.ReactNode;\n}\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts a function that receives props and returns an element.\n */\ntype NavAccountMenuItemRenderFn = (\n props: NavAccountMenuItemRenderProps,\n) => React.ReactElement;\n\nexport interface NavAccountMenuItemProps {\n /** Left icon (20px) */\n icon?: React.ReactNode;\n /** Keyboard shortcut display */\n shortcut?: string;\n /** Destructive styling (red) */\n destructive?: boolean;\n /** Disabled state */\n disabled?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /**\n * Render prop for polymorphic rendering.\n * Use this to render the menu item as a different element (e.g., link).\n * @example\n * <NavAccountMenuItem\n * icon={<User01 />}\n * render={(props) => <a {...props} href=\"/profile\" />}\n * >\n * View profile\n * </NavAccountMenuItem>\n */\n render?: NavAccountMenuItemRenderFn;\n /** Label text */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuItem({\n icon,\n shortcut,\n destructive = false,\n disabled = false,\n onSelect,\n render,\n children,\n className,\n}: NavAccountMenuItemProps) {\n const { onOpenChange } = useNavAccountMenuContext();\n\n const handleClick = () => {\n if (disabled) return;\n onSelect?.();\n onOpenChange(false);\n };\n\n const content = (\n <div className=\"flex flex-1 gap-2 items-center overflow-hidden p-2 rounded-md transition-[background-color] duration-200 ease-smooth delight-selection-press motion-reduce:transition-none\">\n <div className=\"flex flex-1 gap-2 items-center min-w-0\">\n {icon && (\n <span\n className={cn(\n 'shrink-0 [&>svg]:size-4 transition-transform duration-200 ease-smooth group-hover/menuitem:translate-x-0.5 motion-reduce:transition-none',\n destructive ? 'text-destructive' : 'text-foreground',\n )}\n >\n {icon}\n </span>\n )}\n <span\n className={cn(\n 'flex-1 text-sm truncate',\n destructive ? 'text-destructive' : 'text-secondary-foreground',\n )}\n >\n {children}\n </span>\n </div>\n {shortcut && (\n <Kbd variant=\"outline\" size=\"xs\" className=\"shrink-0\">\n {shortcut}\n </Kbd>\n )}\n </div>\n );\n\n const baseClassName = cn(\n 'group/menuitem flex items-center px-1.5 py-0 w-full text-left cursor-pointer outline-none',\n 'hover:[&>div]:bg-muted focus-visible:[&>div]:bg-muted',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n disabled && 'pointer-events-none opacity-50',\n className,\n );\n\n if (render) {\n return render({\n className: baseClassName,\n onClick: handleClick,\n children: content,\n });\n }\n\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-slot=\"nav-account-menu-item\"\n className={baseClassName}\n onClick={handleClick}\n disabled={disabled}\n aria-disabled={disabled || undefined}\n >\n {content}\n </button>\n );\n}\n\n// ============================================\n// NavAccountMenuAccount\n// ============================================\n\nexport interface NavAccountMenuAccountProps {\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Account display name */\n name: string;\n /** Account email */\n email: string;\n /** Whether this account is currently selected */\n selected?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuAccount({\n avatar,\n name,\n email,\n selected = false,\n onSelect,\n className,\n}: NavAccountMenuAccountProps) {\n return (\n <div\n data-slot=\"nav-account-menu-account\"\n className={cn('flex items-center px-1.5 py-0 w-full', className)}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n aria-label={`Switch to ${name} (${email})`}\n className={cn(\n 'relative flex flex-1 gap-2 items-center overflow-hidden px-2 py-1.5 rounded-md cursor-pointer outline-none',\n 'hover:bg-muted focus-visible:bg-muted',\n 'transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n 'text-left',\n selected && 'bg-surface-2',\n )}\n onClick={onSelect}\n >\n {avatar && <div className=\"shrink-0\">{avatar}</div>}\n <div className=\"flex flex-col min-w-0 flex-1\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {name}\n </span>\n <span className=\"text-sm text-muted-foreground truncate\">\n {email}\n </span>\n </div>\n {/* Radio indicator */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'size-4 rounded-full border-2 shrink-0 flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n selected\n ? 'bg-primary border-primary'\n : 'border-border bg-transparent',\n )}\n >\n {selected && (\n <div className=\"size-1.5 rounded-full bg-background delight-check-bounce\" />\n )}\n </div>\n </button>\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSeparator\n// ============================================\n\nexport interface NavAccountMenuSeparatorProps {\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSeparator({ className }: NavAccountMenuSeparatorProps) {\n return (\n <hr\n data-slot=\"nav-account-menu-separator\"\n className={cn('h-px border-0 bg-border mx-5', className)}\n />\n );\n}\n\n// ============================================\n// NavAccountMenuFooter\n// ============================================\n\nexport interface NavAccountMenuFooterProps {\n /** Footer content (typically buttons) */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuFooter({\n children,\n className,\n}: NavAccountMenuFooterProps) {\n return (\n <div\n data-slot=\"nav-account-menu-footer\"\n className={cn('flex items-center justify-center px-5 pt-4', className)}\n >\n {children}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuThemeSwitch (uses Switch theme variant)\n// ============================================\n\nexport interface NavAccountMenuThemeSwitchProps {\n /** Switch theme variant to render */\n variant?:\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n /** Switch size */\n size?: 'sm' | 'md' | 'lg';\n /** Controlled checked state (dark = checked) */\n checked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n /** Optional label displayed next to the switch (e.g. \"Light Mode\") */\n label?: string;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuThemeSwitch({\n variant = 'theme-gradient',\n size = 'sm',\n checked,\n onCheckedChange,\n label,\n className,\n}: NavAccountMenuThemeSwitchProps) {\n const switchId = React.useId();\n const labelId = label ? `${switchId}-label` : undefined;\n\n return (\n <div\n data-slot=\"nav-account-menu-theme-switch\"\n className={cn('flex items-center px-1.5 py-0', className)}\n >\n <div className=\"flex items-center gap-2.5 p-2\">\n <Switch\n id={switchId}\n variant={variant}\n size={size}\n checked={checked}\n onCheckedChange={onCheckedChange}\n aria-labelledby={labelId}\n aria-label={label ? undefined : 'Theme selector'}\n />\n {label && (\n <label\n htmlFor={switchId}\n id={labelId}\n className=\"cursor-pointer text-sm text-secondary-foreground\"\n >\n {label}\n </label>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================\n// Display Names\n// ============================================\n\nNavAccountMenu.displayName = 'NavAccountMenu';\nNavAccountMenuTrigger.displayName = 'NavAccountMenuTrigger';\nNavAccountMenuContent.displayName = 'NavAccountMenuContent';\nNavAccountMenuHeader.displayName = 'NavAccountMenuHeader';\nNavAccountMenuSection.displayName = 'NavAccountMenuSection';\nNavAccountMenuItem.displayName = 'NavAccountMenuItem';\nNavAccountMenuAccount.displayName = 'NavAccountMenuAccount';\nNavAccountMenuSeparator.displayName = 'NavAccountMenuSeparator';\nNavAccountMenuFooter.displayName = 'NavAccountMenuFooter';\nNavAccountMenuThemeSwitch.displayName = 'NavAccountMenuThemeSwitch';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n NavAccountMenu,\n NavAccountMenuAccount,\n NavAccountMenuContent,\n NavAccountMenuFooter,\n NavAccountMenuHeader,\n NavAccountMenuItem,\n NavAccountMenuSection,\n NavAccountMenuSeparator,\n NavAccountMenuThemeSwitch,\n NavAccountMenuTrigger,\n triggerVariants as navAccountMenuTriggerVariants,\n};\n"],"mappings":"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"}
package/dist/index24.js CHANGED
@@ -188,7 +188,7 @@ var SelectionIndicator = React$1.forwardRef(({ type, checked = false, disabled =
188
188
  "data-checked": checked,
189
189
  className: cn(selectionIndicatorVariants({ size }), "transition-[background-color,border-color] duration-150 motion-reduce:transition-none", checked ? cn(colors.indicatorChecked, "border-transparent") : "border-border bg-background", disabled && "opacity-50", className),
190
190
  "aria-hidden": "true",
191
- children: /* @__PURE__ */ jsx("span", { className: cn("bg-primary-foreground rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none", innerDotSizes[size], checked ? "scale-100" : "scale-0") })
191
+ children: /* @__PURE__ */ jsx("span", { className: cn("bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none", innerDotSizes[size], checked ? "scale-100" : "scale-0") })
192
192
  });
193
193
  });
194
194
  SelectionIndicator.displayName = "SelectionIndicator";
@@ -1 +1 @@
1
- {"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-primary-foreground rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:bg-foreground/60 dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground dark:text-text-quaternary',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:bg-foreground/60 dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground dark:text-text-quaternary',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}