@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":"index188.js","names":[],"sources":["../src/components/organisms/overlays/Tooltip/Tooltip.tsx"],"sourcesContent":["'use client';\n\nimport { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip';\nimport { cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn, extractText } from '@/lib/utils';\n\nconst tooltipVariants = cva(\n 'data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 motion-reduce:animate-none z-50 w-fit max-w-xs origin-(--transform-origin) px-3 py-1.5 text-xs shadow-[var(--shadow-tooltip)]',\n {\n variants: {\n variant: {\n primary: 'bg-foreground text-background',\n secondary:\n 'bg-secondary text-secondary-foreground border border-border shadow-sm',\n info: 'bg-info text-primary-foreground',\n success: 'bg-success text-primary-foreground',\n warning: 'bg-warning text-primary-foreground',\n destructive: 'bg-destructive text-primary-foreground',\n },\n shape: {\n default: 'rounded-md',\n rounded: 'rounded-full',\n },\n },\n defaultVariants: {\n variant: 'primary',\n shape: 'default',\n },\n },\n);\n\nconst arrowVariants = cva(\n 'size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5',\n {\n variants: {\n variant: {\n primary: 'bg-foreground fill-foreground',\n secondary: 'bg-secondary fill-secondary',\n info: 'bg-info fill-info',\n success: 'bg-success fill-success',\n warning: 'bg-warning fill-warning',\n destructive: 'bg-destructive fill-destructive',\n },\n },\n defaultVariants: {\n variant: 'primary',\n },\n },\n);\n\ntype TooltipVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype TooltipShape = 'default' | 'rounded';\ntype TooltipPosition = 'top' | 'bottom' | 'left' | 'right' | 'none';\n\n// =============================================================================\n// Base Tooltip Sub-components\n// =============================================================================\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n );\n}\n\nfunction TooltipRoot(props: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n}\n\nconst TooltipTrigger = React.forwardRef<\n HTMLButtonElement,\n TooltipPrimitive.Trigger.Props\n>(function TooltipTrigger(props, ref) {\n return (\n <TooltipPrimitive.Trigger\n ref={ref}\n data-slot=\"tooltip-trigger\"\n {...props}\n />\n );\n});\n\ninterface TooltipPopupProps\n extends TooltipPrimitive.Popup.Props,\n Pick<\n TooltipPrimitive.Positioner.Props,\n 'align' | 'alignOffset' | 'side' | 'sideOffset'\n > {\n variant?: TooltipVariant;\n shape?: TooltipShape;\n /** Optional Base UI portal container for the tooltip popup. */\n container?: TooltipPrimitive.Portal.Props['container'];\n /** When true or position is 'none', hides the arrow */\n hideArrow?: boolean;\n}\n\nfunction TooltipPopup({\n className,\n side = 'top',\n sideOffset = 4,\n align = 'center',\n alignOffset = 0,\n variant = 'primary',\n shape = 'default',\n hideArrow = false,\n container,\n children,\n ...props\n}: TooltipPopupProps) {\n return (\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-popup\"\n className={cn(tooltipVariants({ variant, shape }), className)}\n {...props}\n >\n {children}\n {!hideArrow && (\n <TooltipPrimitive.Arrow className={arrowVariants({ variant })} />\n )}\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n}\n\n// =============================================================================\n// Rich Content Sub-components\n// =============================================================================\n\nfunction TooltipIcon({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n data-slot=\"tooltip-icon\"\n className={cn('shrink-0 [&>svg]:size-4', className)}\n >\n {children}\n </span>\n );\n}\nTooltipIcon.displayName = 'Tooltip.Icon';\n\nfunction TooltipAvatar({\n src,\n alt,\n children,\n className,\n}: {\n src?: string;\n alt: string;\n children?: React.ReactNode;\n className?: string;\n}) {\n if (children) {\n return (\n <span data-slot=\"tooltip-avatar\" className={cn('shrink-0', className)}>\n {children}\n </span>\n );\n }\n return (\n <img\n data-slot=\"tooltip-avatar\"\n src={src}\n alt={alt}\n className={cn('size-4 shrink-0 rounded-full object-cover', className)}\n />\n );\n}\nTooltipAvatar.displayName = 'Tooltip.Avatar';\n\nfunction TooltipContent({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <div\n data-slot=\"tooltip-content\"\n className={cn('flex flex-col gap-0.5', className)}\n >\n {children}\n </div>\n );\n}\nTooltipContent.displayName = 'Tooltip.Content';\n\nfunction TooltipTitle({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n data-slot=\"tooltip-title\"\n className={cn('text-xs font-semibold leading-4', className)}\n >\n {children}\n </span>\n );\n}\nTooltipTitle.displayName = 'Tooltip.Title';\n\ninterface TooltipSubtitleProps {\n children: React.ReactNode;\n className?: string;\n /** Variant affects subtitle opacity */\n variant?: TooltipVariant;\n}\n\nfunction TooltipSubtitle({\n children,\n className,\n variant = 'primary',\n}: TooltipSubtitleProps) {\n const subtitleClass =\n variant === 'secondary'\n ? 'text-muted-foreground'\n : 'text-inherit opacity-70';\n\n return (\n <span\n data-slot=\"tooltip-subtitle\"\n className={cn('text-xs font-medium leading-4', subtitleClass, className)}\n >\n {children}\n </span>\n );\n}\nTooltipSubtitle.displayName = 'Tooltip.Subtitle';\n\nfunction TooltipBadge({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span data-slot=\"tooltip-badge\" className={cn('shrink-0', className)}>\n {children}\n </span>\n );\n}\nTooltipBadge.displayName = 'Tooltip.Badge';\n\ninterface TooltipImageProps {\n src: string;\n alt: string;\n layout?: 'vertical' | 'horizontal';\n className?: string;\n}\n\nfunction TooltipImage({\n src,\n alt,\n layout = 'vertical',\n className,\n}: TooltipImageProps) {\n return (\n <img\n data-slot=\"tooltip-image\"\n src={src}\n alt={alt}\n className={cn(\n 'rounded-md object-cover',\n layout === 'vertical' ? 'w-full h-20' : 'w-20 h-14 shrink-0',\n className,\n )}\n />\n );\n}\nTooltipImage.displayName = 'Tooltip.Image';\n\n// =============================================================================\n// High-level Tooltip Wrapper Component\n// =============================================================================\n\ninterface TooltipProps {\n /** The element that triggers the tooltip (required) */\n trigger: React.ReactElement;\n /** The main tooltip text */\n content: React.ReactNode;\n /** Style variant */\n variant?: TooltipVariant;\n /** Shape variant */\n shape?: TooltipShape;\n /** Arrow position - 'none' hides the arrow */\n position?: TooltipPosition;\n /** Alignment of tooltip relative to trigger */\n align?: 'start' | 'center' | 'end';\n /** Delay in ms before showing tooltip */\n delayDuration?: number;\n /** Distance from trigger */\n sideOffset?: number;\n /** Optional icon before content */\n icon?: React.ReactNode;\n /** Optional avatar - string for src or ReactNode for custom */\n avatar?: string | React.ReactNode;\n /** Optional supporting text */\n subtitle?: React.ReactNode;\n /** Optional badge element */\n badge?: React.ReactNode;\n /** Optional image */\n image?: string;\n /** Image layout - auto-detected or override */\n imageLayout?: 'vertical' | 'horizontal';\n /** Optional Base UI portal container. Takes precedence over the trigger owner document. */\n container?: TooltipPrimitive.Portal.Props['container'];\n /** Override content with custom children */\n children?: React.ReactNode;\n}\n\ninterface TooltipRenderedContentProps {\n children?: React.ReactNode;\n content: React.ReactNode;\n variant: TooltipVariant;\n icon?: React.ReactNode;\n avatar?: string | React.ReactNode;\n subtitle?: React.ReactNode;\n badge?: React.ReactNode;\n image?: string;\n imageLayout: 'vertical' | 'horizontal';\n hasRichContent: React.ReactNode;\n contentAlt: string;\n}\n\nfunction TooltipRenderedContent({\n children,\n content,\n variant,\n icon,\n avatar,\n subtitle,\n badge,\n image,\n imageLayout,\n hasRichContent,\n contentAlt,\n}: TooltipRenderedContentProps) {\n if (children) return children;\n\n const subtitleElement = subtitle && (\n <TooltipSubtitle variant={variant}>{subtitle}</TooltipSubtitle>\n );\n\n if (image) {\n return (\n <div\n className={cn(\n 'flex gap-1.5 delight-tooltip-stagger',\n imageLayout === 'vertical' ? 'flex-col' : 'flex-row items-center',\n )}\n >\n <TooltipImage\n src={image}\n alt={contentAlt}\n layout={imageLayout}\n className=\"delight-tooltip-image\"\n />\n <TooltipContent>\n <TooltipTitle>{content}</TooltipTitle>\n {subtitleElement}\n </TooltipContent>\n </div>\n );\n }\n\n if (!hasRichContent) return content;\n\n return (\n <div className=\"flex items-center gap-1.5 delight-tooltip-stagger\">\n {avatar &&\n (typeof avatar === 'string' ? (\n <TooltipAvatar src={avatar} alt={contentAlt} />\n ) : (\n <TooltipAvatar alt={contentAlt}>{avatar}</TooltipAvatar>\n ))}\n {icon && <TooltipIcon>{icon}</TooltipIcon>}\n <TooltipContent>\n <TooltipTitle>{content}</TooltipTitle>\n {subtitleElement}\n </TooltipContent>\n {badge && <TooltipBadge>{badge}</TooltipBadge>}\n </div>\n );\n}\n\nconst Tooltip = ({\n trigger,\n content,\n variant = 'primary',\n shape = 'default',\n position = 'top',\n align = 'center',\n delayDuration,\n sideOffset = 6,\n icon,\n avatar,\n subtitle,\n badge,\n image,\n imageLayout,\n container,\n children,\n}: TooltipProps) => {\n const [triggerElement, setTriggerElement] =\n React.useState<HTMLElement | null>(null);\n const [triggerPortalContainer, setTriggerPortalContainer] =\n React.useState<HTMLElement | null>(null);\n const setTriggerRef = React.useCallback((element: HTMLElement | null) => {\n setTriggerElement((currentElement) =>\n currentElement === element ? currentElement : element,\n );\n }, []);\n\n React.useEffect(() => {\n const nextContainer = triggerElement?.ownerDocument.body ?? null;\n setTriggerPortalContainer((currentContainer) =>\n currentContainer === nextContainer ? currentContainer : nextContainer,\n );\n }, [triggerElement]);\n\n // Determine if we have rich content\n const hasRichContent = icon || avatar || subtitle || badge || image;\n\n const resolvedImageLayout = imageLayout ?? 'vertical';\n const contentAlt = extractText(content);\n const portalContainer =\n container === undefined ? triggerPortalContainer : container;\n\n return (\n <TooltipProvider delay={delayDuration}>\n <TooltipRoot>\n <TooltipTrigger ref={setTriggerRef} render={trigger} />\n <TooltipPopup\n container={portalContainer}\n side={position === 'none' ? 'top' : position}\n align={align}\n sideOffset={sideOffset}\n variant={variant}\n shape={shape}\n hideArrow={position === 'none'}\n className={cn(hasRichContent && 'p-2')}\n >\n <TooltipRenderedContent\n content={content}\n variant={variant}\n icon={icon}\n avatar={avatar}\n subtitle={subtitle}\n badge={badge}\n image={image}\n imageLayout={resolvedImageLayout}\n hasRichContent={hasRichContent}\n contentAlt={contentAlt}\n >\n {children}\n </TooltipRenderedContent>\n </TooltipPopup>\n </TooltipRoot>\n </TooltipProvider>\n );\n};\n\nTooltip.displayName = 'Tooltip';\nTooltipProvider.displayName = 'Tooltip.Provider';\nTooltipRoot.displayName = 'Tooltip.Root';\nTooltipTrigger.displayName = 'Tooltip.Trigger';\nTooltipPopup.displayName = 'Tooltip.Popup';\n\n/**\n * Tooltip component with dot notation for compound parts.\n *\n * @example\n * ```tsx\n * // Simple usage (recommended for most cases)\n * <Tooltip trigger={<Button>Hover me</Button>} content=\"Tooltip text\" />\n *\n * // With variants\n * <Tooltip trigger={<Button>Save</Button>} content=\"Saved!\" variant=\"success\" shape=\"rounded\" />\n *\n * // With rich content\n * <Tooltip trigger={<Button>Info</Button>} content=\"Title\" icon={<InfoIcon />} subtitle=\"Description\" />\n *\n * // Advanced usage with dot notation\n * <Tooltip.Root>\n * <Tooltip.Trigger render={<Button>Hover me</Button>} />\n * <Tooltip.Popup variant=\"info\">\n * <Tooltip.Icon><InfoIcon /></Tooltip.Icon>\n * <Tooltip.Content>\n * <Tooltip.Title>Title</Tooltip.Title>\n * <Tooltip.Subtitle>Description</Tooltip.Subtitle>\n * </Tooltip.Content>\n * </Tooltip.Popup>\n * </Tooltip.Root>\n * ```\n */\nconst TooltipCompound = Object.assign(Tooltip, {\n Root: TooltipRoot,\n Provider: TooltipProvider,\n Trigger: TooltipTrigger,\n Popup: TooltipPopup,\n Icon: TooltipIcon,\n Avatar: TooltipAvatar,\n Content: TooltipContent,\n Title: TooltipTitle,\n Subtitle: TooltipSubtitle,\n Badge: TooltipBadge,\n Image: TooltipImage,\n});\n\nexport type { TooltipPosition, TooltipProps, TooltipShape, TooltipVariant };\nexport {\n arrowVariants,\n TooltipAvatar,\n TooltipBadge,\n TooltipCompound as Tooltip,\n TooltipContent,\n TooltipIcon,\n TooltipImage,\n TooltipPopup,\n TooltipProvider,\n TooltipRoot,\n TooltipSubtitle,\n TooltipTitle,\n TooltipTrigger,\n tooltipVariants,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index188.js","names":[],"sources":["../src/components/organisms/overlays/Tooltip/Tooltip.tsx"],"sourcesContent":["'use client';\n\nimport { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip';\nimport { cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn, extractText } from '@/lib/utils';\n\nconst tooltipVariants = cva(\n 'data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 motion-reduce:animate-none z-50 w-fit max-w-xs origin-(--transform-origin) px-3 py-1.5 text-xs shadow-[var(--shadow-tooltip)]',\n {\n variants: {\n variant: {\n primary: 'bg-foreground text-background',\n secondary:\n 'bg-secondary text-secondary-foreground border border-border shadow-sm',\n info: 'bg-info text-info-foreground',\n success: 'bg-success text-success-foreground',\n warning: 'bg-warning text-warning-foreground',\n destructive: 'bg-destructive text-destructive-foreground',\n },\n shape: {\n default: 'rounded-md',\n rounded: 'rounded-full',\n },\n },\n defaultVariants: {\n variant: 'primary',\n shape: 'default',\n },\n },\n);\n\nconst arrowVariants = cva(\n 'size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5',\n {\n variants: {\n variant: {\n primary: 'bg-foreground fill-foreground',\n secondary: 'bg-secondary fill-secondary',\n info: 'bg-info fill-info',\n success: 'bg-success fill-success',\n warning: 'bg-warning fill-warning',\n destructive: 'bg-destructive fill-destructive',\n },\n },\n defaultVariants: {\n variant: 'primary',\n },\n },\n);\n\ntype TooltipVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype TooltipShape = 'default' | 'rounded';\ntype TooltipPosition = 'top' | 'bottom' | 'left' | 'right' | 'none';\n\n// =============================================================================\n// Base Tooltip Sub-components\n// =============================================================================\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n );\n}\n\nfunction TooltipRoot(props: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n}\n\nconst TooltipTrigger = React.forwardRef<\n HTMLButtonElement,\n TooltipPrimitive.Trigger.Props\n>(function TooltipTrigger(props, ref) {\n return (\n <TooltipPrimitive.Trigger\n ref={ref}\n data-slot=\"tooltip-trigger\"\n {...props}\n />\n );\n});\n\ninterface TooltipPopupProps\n extends TooltipPrimitive.Popup.Props,\n Pick<\n TooltipPrimitive.Positioner.Props,\n 'align' | 'alignOffset' | 'side' | 'sideOffset'\n > {\n variant?: TooltipVariant;\n shape?: TooltipShape;\n /** Optional Base UI portal container for the tooltip popup. */\n container?: TooltipPrimitive.Portal.Props['container'];\n /** When true or position is 'none', hides the arrow */\n hideArrow?: boolean;\n}\n\nfunction TooltipPopup({\n className,\n side = 'top',\n sideOffset = 4,\n align = 'center',\n alignOffset = 0,\n variant = 'primary',\n shape = 'default',\n hideArrow = false,\n container,\n children,\n ...props\n}: TooltipPopupProps) {\n return (\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-popup\"\n className={cn(tooltipVariants({ variant, shape }), className)}\n {...props}\n >\n {children}\n {!hideArrow && (\n <TooltipPrimitive.Arrow className={arrowVariants({ variant })} />\n )}\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n}\n\n// =============================================================================\n// Rich Content Sub-components\n// =============================================================================\n\nfunction TooltipIcon({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n data-slot=\"tooltip-icon\"\n className={cn('shrink-0 [&>svg]:size-4', className)}\n >\n {children}\n </span>\n );\n}\nTooltipIcon.displayName = 'Tooltip.Icon';\n\nfunction TooltipAvatar({\n src,\n alt,\n children,\n className,\n}: {\n src?: string;\n alt: string;\n children?: React.ReactNode;\n className?: string;\n}) {\n if (children) {\n return (\n <span data-slot=\"tooltip-avatar\" className={cn('shrink-0', className)}>\n {children}\n </span>\n );\n }\n return (\n <img\n data-slot=\"tooltip-avatar\"\n src={src}\n alt={alt}\n className={cn('size-4 shrink-0 rounded-full object-cover', className)}\n />\n );\n}\nTooltipAvatar.displayName = 'Tooltip.Avatar';\n\nfunction TooltipContent({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <div\n data-slot=\"tooltip-content\"\n className={cn('flex flex-col gap-0.5', className)}\n >\n {children}\n </div>\n );\n}\nTooltipContent.displayName = 'Tooltip.Content';\n\nfunction TooltipTitle({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n data-slot=\"tooltip-title\"\n className={cn('text-xs font-semibold leading-4', className)}\n >\n {children}\n </span>\n );\n}\nTooltipTitle.displayName = 'Tooltip.Title';\n\ninterface TooltipSubtitleProps {\n children: React.ReactNode;\n className?: string;\n /** Variant affects subtitle opacity */\n variant?: TooltipVariant;\n}\n\nfunction TooltipSubtitle({\n children,\n className,\n variant = 'primary',\n}: TooltipSubtitleProps) {\n const subtitleClass =\n variant === 'secondary'\n ? 'text-muted-foreground'\n : 'text-inherit opacity-70';\n\n return (\n <span\n data-slot=\"tooltip-subtitle\"\n className={cn('text-xs font-medium leading-4', subtitleClass, className)}\n >\n {children}\n </span>\n );\n}\nTooltipSubtitle.displayName = 'Tooltip.Subtitle';\n\nfunction TooltipBadge({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span data-slot=\"tooltip-badge\" className={cn('shrink-0', className)}>\n {children}\n </span>\n );\n}\nTooltipBadge.displayName = 'Tooltip.Badge';\n\ninterface TooltipImageProps {\n src: string;\n alt: string;\n layout?: 'vertical' | 'horizontal';\n className?: string;\n}\n\nfunction TooltipImage({\n src,\n alt,\n layout = 'vertical',\n className,\n}: TooltipImageProps) {\n return (\n <img\n data-slot=\"tooltip-image\"\n src={src}\n alt={alt}\n className={cn(\n 'rounded-md object-cover',\n layout === 'vertical' ? 'w-full h-20' : 'w-20 h-14 shrink-0',\n className,\n )}\n />\n );\n}\nTooltipImage.displayName = 'Tooltip.Image';\n\n// =============================================================================\n// High-level Tooltip Wrapper Component\n// =============================================================================\n\ninterface TooltipProps {\n /** The element that triggers the tooltip (required) */\n trigger: React.ReactElement;\n /** The main tooltip text */\n content: React.ReactNode;\n /** Style variant */\n variant?: TooltipVariant;\n /** Shape variant */\n shape?: TooltipShape;\n /** Arrow position - 'none' hides the arrow */\n position?: TooltipPosition;\n /** Alignment of tooltip relative to trigger */\n align?: 'start' | 'center' | 'end';\n /** Delay in ms before showing tooltip */\n delayDuration?: number;\n /** Distance from trigger */\n sideOffset?: number;\n /** Optional icon before content */\n icon?: React.ReactNode;\n /** Optional avatar - string for src or ReactNode for custom */\n avatar?: string | React.ReactNode;\n /** Optional supporting text */\n subtitle?: React.ReactNode;\n /** Optional badge element */\n badge?: React.ReactNode;\n /** Optional image */\n image?: string;\n /** Image layout - auto-detected or override */\n imageLayout?: 'vertical' | 'horizontal';\n /** Optional Base UI portal container. Takes precedence over the trigger owner document. */\n container?: TooltipPrimitive.Portal.Props['container'];\n /** Override content with custom children */\n children?: React.ReactNode;\n}\n\ninterface TooltipRenderedContentProps {\n children?: React.ReactNode;\n content: React.ReactNode;\n variant: TooltipVariant;\n icon?: React.ReactNode;\n avatar?: string | React.ReactNode;\n subtitle?: React.ReactNode;\n badge?: React.ReactNode;\n image?: string;\n imageLayout: 'vertical' | 'horizontal';\n hasRichContent: React.ReactNode;\n contentAlt: string;\n}\n\nfunction TooltipRenderedContent({\n children,\n content,\n variant,\n icon,\n avatar,\n subtitle,\n badge,\n image,\n imageLayout,\n hasRichContent,\n contentAlt,\n}: TooltipRenderedContentProps) {\n if (children) return children;\n\n const subtitleElement = subtitle && (\n <TooltipSubtitle variant={variant}>{subtitle}</TooltipSubtitle>\n );\n\n if (image) {\n return (\n <div\n className={cn(\n 'flex gap-1.5 delight-tooltip-stagger',\n imageLayout === 'vertical' ? 'flex-col' : 'flex-row items-center',\n )}\n >\n <TooltipImage\n src={image}\n alt={contentAlt}\n layout={imageLayout}\n className=\"delight-tooltip-image\"\n />\n <TooltipContent>\n <TooltipTitle>{content}</TooltipTitle>\n {subtitleElement}\n </TooltipContent>\n </div>\n );\n }\n\n if (!hasRichContent) return content;\n\n return (\n <div className=\"flex items-center gap-1.5 delight-tooltip-stagger\">\n {avatar &&\n (typeof avatar === 'string' ? (\n <TooltipAvatar src={avatar} alt={contentAlt} />\n ) : (\n <TooltipAvatar alt={contentAlt}>{avatar}</TooltipAvatar>\n ))}\n {icon && <TooltipIcon>{icon}</TooltipIcon>}\n <TooltipContent>\n <TooltipTitle>{content}</TooltipTitle>\n {subtitleElement}\n </TooltipContent>\n {badge && <TooltipBadge>{badge}</TooltipBadge>}\n </div>\n );\n}\n\nconst Tooltip = ({\n trigger,\n content,\n variant = 'primary',\n shape = 'default',\n position = 'top',\n align = 'center',\n delayDuration,\n sideOffset = 6,\n icon,\n avatar,\n subtitle,\n badge,\n image,\n imageLayout,\n container,\n children,\n}: TooltipProps) => {\n const [triggerElement, setTriggerElement] =\n React.useState<HTMLElement | null>(null);\n const [triggerPortalContainer, setTriggerPortalContainer] =\n React.useState<HTMLElement | null>(null);\n const setTriggerRef = React.useCallback((element: HTMLElement | null) => {\n setTriggerElement((currentElement) =>\n currentElement === element ? currentElement : element,\n );\n }, []);\n\n React.useEffect(() => {\n const nextContainer = triggerElement?.ownerDocument.body ?? null;\n setTriggerPortalContainer((currentContainer) =>\n currentContainer === nextContainer ? currentContainer : nextContainer,\n );\n }, [triggerElement]);\n\n // Determine if we have rich content\n const hasRichContent = icon || avatar || subtitle || badge || image;\n\n const resolvedImageLayout = imageLayout ?? 'vertical';\n const contentAlt = extractText(content);\n const portalContainer =\n container === undefined ? triggerPortalContainer : container;\n\n return (\n <TooltipProvider delay={delayDuration}>\n <TooltipRoot>\n <TooltipTrigger ref={setTriggerRef} render={trigger} />\n <TooltipPopup\n container={portalContainer}\n side={position === 'none' ? 'top' : position}\n align={align}\n sideOffset={sideOffset}\n variant={variant}\n shape={shape}\n hideArrow={position === 'none'}\n className={cn(hasRichContent && 'p-2')}\n >\n <TooltipRenderedContent\n content={content}\n variant={variant}\n icon={icon}\n avatar={avatar}\n subtitle={subtitle}\n badge={badge}\n image={image}\n imageLayout={resolvedImageLayout}\n hasRichContent={hasRichContent}\n contentAlt={contentAlt}\n >\n {children}\n </TooltipRenderedContent>\n </TooltipPopup>\n </TooltipRoot>\n </TooltipProvider>\n );\n};\n\nTooltip.displayName = 'Tooltip';\nTooltipProvider.displayName = 'Tooltip.Provider';\nTooltipRoot.displayName = 'Tooltip.Root';\nTooltipTrigger.displayName = 'Tooltip.Trigger';\nTooltipPopup.displayName = 'Tooltip.Popup';\n\n/**\n * Tooltip component with dot notation for compound parts.\n *\n * @example\n * ```tsx\n * // Simple usage (recommended for most cases)\n * <Tooltip trigger={<Button>Hover me</Button>} content=\"Tooltip text\" />\n *\n * // With variants\n * <Tooltip trigger={<Button>Save</Button>} content=\"Saved!\" variant=\"success\" shape=\"rounded\" />\n *\n * // With rich content\n * <Tooltip trigger={<Button>Info</Button>} content=\"Title\" icon={<InfoIcon />} subtitle=\"Description\" />\n *\n * // Advanced usage with dot notation\n * <Tooltip.Root>\n * <Tooltip.Trigger render={<Button>Hover me</Button>} />\n * <Tooltip.Popup variant=\"info\">\n * <Tooltip.Icon><InfoIcon /></Tooltip.Icon>\n * <Tooltip.Content>\n * <Tooltip.Title>Title</Tooltip.Title>\n * <Tooltip.Subtitle>Description</Tooltip.Subtitle>\n * </Tooltip.Content>\n * </Tooltip.Popup>\n * </Tooltip.Root>\n * ```\n */\nconst TooltipCompound = Object.assign(Tooltip, {\n Root: TooltipRoot,\n Provider: TooltipProvider,\n Trigger: TooltipTrigger,\n Popup: TooltipPopup,\n Icon: TooltipIcon,\n Avatar: TooltipAvatar,\n Content: TooltipContent,\n Title: TooltipTitle,\n Subtitle: TooltipSubtitle,\n Badge: TooltipBadge,\n Image: TooltipImage,\n});\n\nexport type { TooltipPosition, TooltipProps, TooltipShape, TooltipVariant };\nexport {\n arrowVariants,\n TooltipAvatar,\n TooltipBadge,\n TooltipCompound as Tooltip,\n TooltipContent,\n TooltipIcon,\n TooltipImage,\n TooltipPopup,\n TooltipProvider,\n TooltipRoot,\n TooltipSubtitle,\n TooltipTitle,\n TooltipTrigger,\n tooltipVariants,\n};\n"],"mappings":"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"}
package/dist/index201.js CHANGED
@@ -13,7 +13,7 @@ var stepIndicatorVariants = cva("flex items-center justify-center shrink-0 size-
13
13
  },
14
14
  status: {
15
15
  complete: "bg-primary text-primary-foreground shadow-sm",
16
- active: "bg-primary-foreground border-2 border-primary text-primary shadow-sm",
16
+ active: "bg-background border-2 border-primary text-primary shadow-sm",
17
17
  incomplete: "bg-accent text-muted-foreground"
18
18
  }
19
19
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index201.js","names":[],"sources":["../src/components/organisms/content/Steps/Steps.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Check } from 'lucide-react';\nimport * as React from 'react';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn, extractText } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Types\n * -------------------------------------------------------------------------- */\n\nexport type StepStatus = 'complete' | 'active' | 'incomplete';\n\nexport interface StepData {\n label: string;\n subtext?: string;\n}\n\nexport interface StepsProps {\n /** Steps data for flat API */\n steps?: StepData[];\n /** Current step index (0-based) for flat API */\n currentStep?: number;\n /** Orientation of the steps */\n orientation?: 'horizontal' | 'vertical';\n /** Shape of step indicators */\n shape?: 'rounded' | 'round';\n /** Type of bullet content */\n bulletType?: 'text' | 'icon';\n /** Callback when a step is clicked */\n onStepClick?: (index: number) => void;\n /** Children for compound API */\n children?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsItemProps {\n /** Override auto-calculated status */\n status?: StepStatus;\n /** Click handler for this step */\n onClick?: () => void;\n /** Step label content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsSubtextProps {\n children: React.ReactNode;\n className?: string;\n}\n\n/* -----------------------------------------------------------------------------\n * Variants\n * -------------------------------------------------------------------------- */\n\nconst stepIndicatorVariants = cva(\n 'flex items-center justify-center shrink-0 size-[38px] font-medium text-lg transition-all duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n shape: {\n rounded: 'rounded-lg',\n round: 'rounded-full',\n },\n status: {\n complete: 'bg-primary text-primary-foreground shadow-sm',\n active:\n 'bg-primary-foreground border-2 border-primary text-primary shadow-sm',\n incomplete: 'bg-accent text-muted-foreground',\n },\n },\n defaultVariants: {\n shape: 'rounded',\n status: 'incomplete',\n },\n },\n);\n\nconst stepConnectorVariants = cva(\n 'shrink-0 transition-colors duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n orientation: {\n // Horizontal: fluid width fills available space; mt-[18px] centers 2px line with 38px indicator\n horizontal: 'h-0.5 flex-1 min-w-4 mx-2 mt-[18px]',\n // Vertical: fixed size, centered under 38px indicator\n vertical: 'w-0.5 h-[30px] my-1 ml-[18px]',\n },\n status: {\n complete: 'bg-primary',\n incomplete: 'bg-border',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n status: 'incomplete',\n },\n },\n);\n\nconst stepLabelVariants = cva('text-base leading-6', {\n variants: {\n status: {\n complete: 'text-card-foreground',\n active: 'text-card-foreground',\n incomplete: 'text-muted-foreground',\n },\n },\n defaultVariants: {\n status: 'incomplete',\n },\n});\n\nconst stepSubtextVariants = cva('text-sm leading-5 text-muted-foreground');\n\n/* -----------------------------------------------------------------------------\n * Context\n * -------------------------------------------------------------------------- */\n\ninterface StepsContextValue {\n orientation: 'horizontal' | 'vertical';\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n onStepClick?: (index: number) => void;\n getStepStatus: (index: number) => StepStatus;\n}\n\nconst [StepsContext, useStepsContext] =\n createSafeContext<StepsContextValue>('Steps');\n\n/** Per-item index context — injected by Steps parent via Children.map or flat API */\nconst StepIndexContext = React.createContext<number>(0);\n\n/* -----------------------------------------------------------------------------\n * Sub-components\n * -------------------------------------------------------------------------- */\n\ninterface StepIndicatorProps {\n index: number;\n status: StepStatus;\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n}\n\nfunction StepIndicatorContent({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n if (bulletType === 'icon') {\n if (status === 'complete') {\n return <Check className=\"size-[22px] delight-check-draw\" />;\n }\n if (status === 'active') {\n return (\n <div\n className={cn(\n 'size-5 bg-primary',\n shape === 'rounded' ? 'rounded-sm' : 'rounded-full',\n )}\n />\n );\n }\n\n return <div className=\"size-1.5 rounded-full bg-current\" />;\n }\n\n return index + 1;\n}\n\nfunction StepIndicator({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n return (\n <div\n data-slot=\"steps-indicator\"\n aria-hidden=\"true\"\n className={cn(\n stepIndicatorVariants({ shape, status }),\n status === 'complete' && 'delight-check-bounce',\n status === 'active' && 'delight-pulse-once',\n )}\n >\n <StepIndicatorContent\n index={index}\n status={status}\n shape={shape}\n bulletType={bulletType}\n />\n </div>\n );\n}\n\nStepIndicator.displayName = 'StepIndicator';\n\ninterface StepConnectorProps {\n orientation: 'horizontal' | 'vertical';\n isComplete: boolean;\n}\n\nfunction StepConnector({ orientation, isComplete }: StepConnectorProps) {\n return (\n <div\n data-slot=\"steps-connector\"\n aria-hidden=\"true\"\n className={cn(\n stepConnectorVariants({\n orientation,\n status: isComplete ? 'complete' : 'incomplete',\n }),\n isComplete && 'delight-connector-fill',\n )}\n />\n );\n}\n\nStepConnector.displayName = 'StepConnector';\n\nfunction StepsSubtext({ children, className }: StepsSubtextProps) {\n return (\n <span\n data-slot=\"steps-subtext\"\n className={cn(stepSubtextVariants(), className)}\n >\n {children}\n </span>\n );\n}\n\nStepsSubtext.displayName = 'Steps.Subtext';\n\nfunction StepsItem({\n status: statusOverride,\n onClick,\n children,\n className,\n}: StepsItemProps) {\n const ctx = useStepsContext();\n const index = React.useContext(StepIndexContext);\n const status = statusOverride ?? ctx.getStepStatus(index);\n const isFirst = index === 0;\n const handleClick =\n onClick ?? (ctx.onStepClick ? () => ctx.onStepClick?.(index) : undefined);\n\n // Extract subtext from children\n let label: React.ReactNode = null;\n let subtext: React.ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === StepsSubtext) {\n subtext = child;\n } else if (child != null && child !== false) {\n label = child;\n }\n });\n\n // Connector colored based on previous step's completion (source step, not destination)\n const prevStepStatus = !isFirst ? ctx.getStepStatus(index - 1) : undefined;\n const connector = !isFirst && (\n <StepConnector\n orientation={ctx.orientation}\n isComplete={prevStepStatus === 'complete'}\n />\n );\n\n const isHorizontal = ctx.orientation === 'horizontal';\n\n // Build indicator element\n const indicator = (\n <StepIndicator\n index={index}\n status={status}\n shape={ctx.shape}\n bulletType={ctx.bulletType}\n />\n );\n\n // Build label element\n // In horizontal mode, w-0 ensures the label doesn't affect the indicator column width.\n // The text overflows visually (centered under the 38px indicator) but the layout\n // width stays fixed, keeping all connectors equally spaced (matching Figma spec).\n const labelElement = (\n <div\n data-slot=\"steps-label\"\n className={cn(\n 'flex flex-col',\n isHorizontal\n ? 'items-center gap-0.5 text-center w-0 whitespace-nowrap'\n : 'items-start gap-0.5 ml-2.5',\n )}\n >\n <span className={stepLabelVariants({ status })}>{label}</span>\n {subtext}\n </div>\n );\n\n // Layout differs by orientation:\n // - Horizontal: connector + (indicator column), items-start so indicators align at top\n // - Vertical: connector above, indicator + label in row\n const content = isHorizontal ? (\n <div className=\"flex w-full items-start\">\n {connector}\n <div className=\"flex flex-col items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-start\">\n {connector}\n <div className=\"flex items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n );\n\n const labelText = React.useMemo(() => extractText(label), [label]);\n const statusSuffix =\n status === 'complete'\n ? ', completed'\n : status === 'active'\n ? ', current'\n : '';\n\n return (\n <li\n data-slot=\"steps-item\"\n aria-current={status === 'active' ? 'step' : undefined}\n aria-label={\n !handleClick && labelText\n ? `Step ${index + 1}: ${labelText}${statusSuffix}`\n : undefined\n }\n className={cn(\n isHorizontal && !isFirst && 'flex-1',\n !handleClick && className,\n )}\n >\n {handleClick ? (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label={`Step ${index + 1}: ${labelText || ''}${statusSuffix}`}\n className={cn(\n 'cursor-pointer',\n isHorizontal && 'w-full',\n className,\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-sm',\n )}\n >\n {content}\n </button>\n ) : (\n content\n )}\n </li>\n );\n}\n\nStepsItem.displayName = 'Steps.Item';\n\n/* -----------------------------------------------------------------------------\n * Main Component\n * -------------------------------------------------------------------------- */\n\n/**\n * Steps displays a multi-step progress indicator for wizards and workflows.\n * Supports horizontal/vertical orientation, numbered or icon bullets, and clickable steps.\n *\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n * @example\n * ```tsx\n * <Steps\n * steps={[{ label: 'Details' }, { label: 'Payment' }, { label: 'Confirm' }]}\n * currentStep={1}\n * orientation=\"horizontal\"\n * />\n * ```\n */\nfunction Steps({\n steps,\n currentStep = 0,\n orientation = 'horizontal',\n shape = 'rounded',\n bulletType = 'text',\n onStepClick,\n children,\n className,\n}: StepsProps) {\n const getStepStatus = React.useCallback(\n (index: number): StepStatus => {\n if (index < currentStep) return 'complete';\n if (index === currentStep) return 'active';\n return 'incomplete';\n },\n [currentStep],\n );\n\n const contextValue = React.useMemo<StepsContextValue>(\n () => ({\n orientation,\n shape,\n bulletType,\n onStepClick,\n getStepStatus,\n }),\n [orientation, shape, bulletType, onStepClick, getStepStatus],\n );\n\n // Determine if using flat API or compound API\n const useCompoundAPI = !steps && React.Children.count(children) > 0;\n\n const renderFlatAPI = () => {\n if (!steps || steps.length === 0) return null;\n\n return steps.map((step, index) => (\n <StepIndexContext.Provider key={`${index}-${step.label}`} value={index}>\n <StepsItem>\n {step.label}\n {step.subtext && <StepsSubtext>{step.subtext}</StepsSubtext>}\n </StepsItem>\n </StepIndexContext.Provider>\n ));\n };\n\n const renderCompoundAPI = () => {\n return React.Children.map(children, (child, index) => (\n <StepIndexContext.Provider value={index}>\n {child}\n </StepIndexContext.Provider>\n ));\n };\n\n return (\n <StepsContext.Provider value={contextValue}>\n <nav\n aria-label=\"Progress steps\"\n data-slot=\"steps\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n className={cn(\n 'overflow-x-auto focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <ol\n data-slot=\"steps-list\"\n className={cn(\n 'flex',\n orientation === 'horizontal'\n ? 'flex-row items-start px-4'\n : 'flex-col items-start',\n )}\n >\n {useCompoundAPI ? renderCompoundAPI() : renderFlatAPI()}\n </ol>\n </nav>\n </StepsContext.Provider>\n );\n}\n\nSteps.displayName = 'Steps';\n\n/* -----------------------------------------------------------------------------\n * Compound Export\n * -------------------------------------------------------------------------- */\n\n/**\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n */\nexport const StepsCompound = Object.assign(Steps, {\n Item: StepsItem,\n Subtext: StepsSubtext,\n});\n\nexport {\n StepsCompound as Steps,\n StepsItem,\n StepsSubtext,\n stepConnectorVariants,\n stepIndicatorVariants,\n stepLabelVariants,\n stepSubtextVariants,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index201.js","names":[],"sources":["../src/components/organisms/content/Steps/Steps.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Check } from 'lucide-react';\nimport * as React from 'react';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn, extractText } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Types\n * -------------------------------------------------------------------------- */\n\nexport type StepStatus = 'complete' | 'active' | 'incomplete';\n\nexport interface StepData {\n label: string;\n subtext?: string;\n}\n\nexport interface StepsProps {\n /** Steps data for flat API */\n steps?: StepData[];\n /** Current step index (0-based) for flat API */\n currentStep?: number;\n /** Orientation of the steps */\n orientation?: 'horizontal' | 'vertical';\n /** Shape of step indicators */\n shape?: 'rounded' | 'round';\n /** Type of bullet content */\n bulletType?: 'text' | 'icon';\n /** Callback when a step is clicked */\n onStepClick?: (index: number) => void;\n /** Children for compound API */\n children?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsItemProps {\n /** Override auto-calculated status */\n status?: StepStatus;\n /** Click handler for this step */\n onClick?: () => void;\n /** Step label content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsSubtextProps {\n children: React.ReactNode;\n className?: string;\n}\n\n/* -----------------------------------------------------------------------------\n * Variants\n * -------------------------------------------------------------------------- */\n\nconst stepIndicatorVariants = cva(\n 'flex items-center justify-center shrink-0 size-[38px] font-medium text-lg transition-all duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n shape: {\n rounded: 'rounded-lg',\n round: 'rounded-full',\n },\n status: {\n complete: 'bg-primary text-primary-foreground shadow-sm',\n active: 'bg-background border-2 border-primary text-primary shadow-sm',\n incomplete: 'bg-accent text-muted-foreground',\n },\n },\n defaultVariants: {\n shape: 'rounded',\n status: 'incomplete',\n },\n },\n);\n\nconst stepConnectorVariants = cva(\n 'shrink-0 transition-colors duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n orientation: {\n // Horizontal: fluid width fills available space; mt-[18px] centers 2px line with 38px indicator\n horizontal: 'h-0.5 flex-1 min-w-4 mx-2 mt-[18px]',\n // Vertical: fixed size, centered under 38px indicator\n vertical: 'w-0.5 h-[30px] my-1 ml-[18px]',\n },\n status: {\n complete: 'bg-primary',\n incomplete: 'bg-border',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n status: 'incomplete',\n },\n },\n);\n\nconst stepLabelVariants = cva('text-base leading-6', {\n variants: {\n status: {\n complete: 'text-card-foreground',\n active: 'text-card-foreground',\n incomplete: 'text-muted-foreground',\n },\n },\n defaultVariants: {\n status: 'incomplete',\n },\n});\n\nconst stepSubtextVariants = cva('text-sm leading-5 text-muted-foreground');\n\n/* -----------------------------------------------------------------------------\n * Context\n * -------------------------------------------------------------------------- */\n\ninterface StepsContextValue {\n orientation: 'horizontal' | 'vertical';\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n onStepClick?: (index: number) => void;\n getStepStatus: (index: number) => StepStatus;\n}\n\nconst [StepsContext, useStepsContext] =\n createSafeContext<StepsContextValue>('Steps');\n\n/** Per-item index context — injected by Steps parent via Children.map or flat API */\nconst StepIndexContext = React.createContext<number>(0);\n\n/* -----------------------------------------------------------------------------\n * Sub-components\n * -------------------------------------------------------------------------- */\n\ninterface StepIndicatorProps {\n index: number;\n status: StepStatus;\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n}\n\nfunction StepIndicatorContent({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n if (bulletType === 'icon') {\n if (status === 'complete') {\n return <Check className=\"size-[22px] delight-check-draw\" />;\n }\n if (status === 'active') {\n return (\n <div\n className={cn(\n 'size-5 bg-primary',\n shape === 'rounded' ? 'rounded-sm' : 'rounded-full',\n )}\n />\n );\n }\n\n return <div className=\"size-1.5 rounded-full bg-current\" />;\n }\n\n return index + 1;\n}\n\nfunction StepIndicator({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n return (\n <div\n data-slot=\"steps-indicator\"\n aria-hidden=\"true\"\n className={cn(\n stepIndicatorVariants({ shape, status }),\n status === 'complete' && 'delight-check-bounce',\n status === 'active' && 'delight-pulse-once',\n )}\n >\n <StepIndicatorContent\n index={index}\n status={status}\n shape={shape}\n bulletType={bulletType}\n />\n </div>\n );\n}\n\nStepIndicator.displayName = 'StepIndicator';\n\ninterface StepConnectorProps {\n orientation: 'horizontal' | 'vertical';\n isComplete: boolean;\n}\n\nfunction StepConnector({ orientation, isComplete }: StepConnectorProps) {\n return (\n <div\n data-slot=\"steps-connector\"\n aria-hidden=\"true\"\n className={cn(\n stepConnectorVariants({\n orientation,\n status: isComplete ? 'complete' : 'incomplete',\n }),\n isComplete && 'delight-connector-fill',\n )}\n />\n );\n}\n\nStepConnector.displayName = 'StepConnector';\n\nfunction StepsSubtext({ children, className }: StepsSubtextProps) {\n return (\n <span\n data-slot=\"steps-subtext\"\n className={cn(stepSubtextVariants(), className)}\n >\n {children}\n </span>\n );\n}\n\nStepsSubtext.displayName = 'Steps.Subtext';\n\nfunction StepsItem({\n status: statusOverride,\n onClick,\n children,\n className,\n}: StepsItemProps) {\n const ctx = useStepsContext();\n const index = React.useContext(StepIndexContext);\n const status = statusOverride ?? ctx.getStepStatus(index);\n const isFirst = index === 0;\n const handleClick =\n onClick ?? (ctx.onStepClick ? () => ctx.onStepClick?.(index) : undefined);\n\n // Extract subtext from children\n let label: React.ReactNode = null;\n let subtext: React.ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === StepsSubtext) {\n subtext = child;\n } else if (child != null && child !== false) {\n label = child;\n }\n });\n\n // Connector colored based on previous step's completion (source step, not destination)\n const prevStepStatus = !isFirst ? ctx.getStepStatus(index - 1) : undefined;\n const connector = !isFirst && (\n <StepConnector\n orientation={ctx.orientation}\n isComplete={prevStepStatus === 'complete'}\n />\n );\n\n const isHorizontal = ctx.orientation === 'horizontal';\n\n // Build indicator element\n const indicator = (\n <StepIndicator\n index={index}\n status={status}\n shape={ctx.shape}\n bulletType={ctx.bulletType}\n />\n );\n\n // Build label element\n // In horizontal mode, w-0 ensures the label doesn't affect the indicator column width.\n // The text overflows visually (centered under the 38px indicator) but the layout\n // width stays fixed, keeping all connectors equally spaced (matching Figma spec).\n const labelElement = (\n <div\n data-slot=\"steps-label\"\n className={cn(\n 'flex flex-col',\n isHorizontal\n ? 'items-center gap-0.5 text-center w-0 whitespace-nowrap'\n : 'items-start gap-0.5 ml-2.5',\n )}\n >\n <span className={stepLabelVariants({ status })}>{label}</span>\n {subtext}\n </div>\n );\n\n // Layout differs by orientation:\n // - Horizontal: connector + (indicator column), items-start so indicators align at top\n // - Vertical: connector above, indicator + label in row\n const content = isHorizontal ? (\n <div className=\"flex w-full items-start\">\n {connector}\n <div className=\"flex flex-col items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-start\">\n {connector}\n <div className=\"flex items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n );\n\n const labelText = React.useMemo(() => extractText(label), [label]);\n const statusSuffix =\n status === 'complete'\n ? ', completed'\n : status === 'active'\n ? ', current'\n : '';\n\n return (\n <li\n data-slot=\"steps-item\"\n aria-current={status === 'active' ? 'step' : undefined}\n aria-label={\n !handleClick && labelText\n ? `Step ${index + 1}: ${labelText}${statusSuffix}`\n : undefined\n }\n className={cn(\n isHorizontal && !isFirst && 'flex-1',\n !handleClick && className,\n )}\n >\n {handleClick ? (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label={`Step ${index + 1}: ${labelText || ''}${statusSuffix}`}\n className={cn(\n 'cursor-pointer',\n isHorizontal && 'w-full',\n className,\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-sm',\n )}\n >\n {content}\n </button>\n ) : (\n content\n )}\n </li>\n );\n}\n\nStepsItem.displayName = 'Steps.Item';\n\n/* -----------------------------------------------------------------------------\n * Main Component\n * -------------------------------------------------------------------------- */\n\n/**\n * Steps displays a multi-step progress indicator for wizards and workflows.\n * Supports horizontal/vertical orientation, numbered or icon bullets, and clickable steps.\n *\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n * @example\n * ```tsx\n * <Steps\n * steps={[{ label: 'Details' }, { label: 'Payment' }, { label: 'Confirm' }]}\n * currentStep={1}\n * orientation=\"horizontal\"\n * />\n * ```\n */\nfunction Steps({\n steps,\n currentStep = 0,\n orientation = 'horizontal',\n shape = 'rounded',\n bulletType = 'text',\n onStepClick,\n children,\n className,\n}: StepsProps) {\n const getStepStatus = React.useCallback(\n (index: number): StepStatus => {\n if (index < currentStep) return 'complete';\n if (index === currentStep) return 'active';\n return 'incomplete';\n },\n [currentStep],\n );\n\n const contextValue = React.useMemo<StepsContextValue>(\n () => ({\n orientation,\n shape,\n bulletType,\n onStepClick,\n getStepStatus,\n }),\n [orientation, shape, bulletType, onStepClick, getStepStatus],\n );\n\n // Determine if using flat API or compound API\n const useCompoundAPI = !steps && React.Children.count(children) > 0;\n\n const renderFlatAPI = () => {\n if (!steps || steps.length === 0) return null;\n\n return steps.map((step, index) => (\n <StepIndexContext.Provider key={`${index}-${step.label}`} value={index}>\n <StepsItem>\n {step.label}\n {step.subtext && <StepsSubtext>{step.subtext}</StepsSubtext>}\n </StepsItem>\n </StepIndexContext.Provider>\n ));\n };\n\n const renderCompoundAPI = () => {\n return React.Children.map(children, (child, index) => (\n <StepIndexContext.Provider value={index}>\n {child}\n </StepIndexContext.Provider>\n ));\n };\n\n return (\n <StepsContext.Provider value={contextValue}>\n <nav\n aria-label=\"Progress steps\"\n data-slot=\"steps\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n className={cn(\n 'overflow-x-auto focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <ol\n data-slot=\"steps-list\"\n className={cn(\n 'flex',\n orientation === 'horizontal'\n ? 'flex-row items-start px-4'\n : 'flex-col items-start',\n )}\n >\n {useCompoundAPI ? renderCompoundAPI() : renderFlatAPI()}\n </ol>\n </nav>\n </StepsContext.Provider>\n );\n}\n\nSteps.displayName = 'Steps';\n\n/* -----------------------------------------------------------------------------\n * Compound Export\n * -------------------------------------------------------------------------- */\n\n/**\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n */\nexport const StepsCompound = Object.assign(Steps, {\n Item: StepsItem,\n Subtext: StepsSubtext,\n});\n\nexport {\n StepsCompound as Steps,\n StepsItem,\n StepsSubtext,\n stepConnectorVariants,\n stepIndicatorVariants,\n stepLabelVariants,\n stepSubtextVariants,\n};\n"],"mappings":"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"}
package/dist/index217.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */
3
3
  var APP_SIDEBAR_EXPANDED_WIDTH = "280px";
4
4
  /** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */
5
- var APP_SIDEBAR_COLLAPSED_WIDTH = "116px";
5
+ var APP_SIDEBAR_COLLAPSED_WIDTH = "68px";
6
6
  //#endregion
7
7
  export { APP_SIDEBAR_COLLAPSED_WIDTH, APP_SIDEBAR_EXPANDED_WIDTH };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"index217.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.constants.ts"],"sourcesContent":["/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_EXPANDED_WIDTH = '280px';\n\n/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_COLLAPSED_WIDTH = '116px';\n"],"mappings":";;AACA,IAAa,6BAA6B;;AAG1C,IAAa,8BAA8B"}
1
+ {"version":3,"file":"index217.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.constants.ts"],"sourcesContent":["/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_EXPANDED_WIDTH = '280px';\n\n/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_COLLAPSED_WIDTH = '68px';\n"],"mappings":";;AACA,IAAa,6BAA6B;;AAG1C,IAAa,8BAA8B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index223.js","names":[],"sources":["../src/components/templates/AppShell/AppShell.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { GroupImperativeHandle } from 'react-resizable-panels';\nimport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from '@/components/atoms/layout/Resizable';\nimport { AppShell as AppShellPrimitive } from '@/components/ui/app-shell';\n\nimport { Sheet, SheetContent } from '@/components/ui/sheet';\nimport { SidebarContext } from '@/components/ui/sidebar';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from '../AppSidebar/AppSidebar.constants';\nimport { AppShellContent } from './AppShellContent';\nimport {\n type AppShellContextValue,\n AppShellProvider,\n PanelIndexContext,\n PanelLayoutContext,\n type PanelLayoutInfo,\n type PanelPosition,\n} from './AppShellContext';\nimport { AppShellMobileTabBar } from './AppShellMobileTabBar';\nimport {\n APPSHELL_PANEL_TYPE,\n AppShellPanel,\n type AppShellPanelComponent,\n type AppShellPanelProps,\n} from './AppShellPanel';\nimport {\n DEFAULT_EXPAND_THRESHOLD,\n getExpandedPanelFromLayout,\n layoutMapToTuple,\n normalizePanelSizes,\n toResizableMinSize,\n toResizablePercentageSize,\n} from './AppShellResize';\n\nconst DEFAULT_APP_SHELL_BACKGROUND = 'var(--app-background)';\n\ninterface AppShellPanelMarker {\n __appShellType?: unknown;\n}\n\nfunction isAppShellPanelComponent(\n type: unknown,\n): type is AppShellPanelComponent {\n return (\n typeof type === 'function' &&\n (type as AppShellPanelMarker).__appShellType === APPSHELL_PANEL_TYPE\n );\n}\n\nfunction isAppShellPanelElement(\n child: React.ReactNode,\n): child is React.ReactElement<AppShellPanelProps, AppShellPanelComponent> {\n return React.isValidElement(child) && isAppShellPanelComponent(child.type);\n}\n\nfunction getAppShellPanelIdentity(\n panel: React.ReactElement<AppShellPanelProps>,\n ariaBaseId: string,\n index: number,\n): React.Key {\n return panel.key ?? panel.props.label ?? `${ariaBaseId}-panel-${index}`;\n}\n\ninterface AppShellPanelWithLayoutProps {\n panel: React.ReactElement<AppShellPanelProps>;\n visible: boolean;\n index: number;\n overrides?: Partial<PanelLayoutInfo>;\n isMobile: boolean;\n activePanel: number;\n hasExpanded: boolean;\n hasTabBar: boolean;\n ariaBaseId: string;\n rootExpansionActive: boolean;\n firstExpandedIndex: number | null;\n onExpandedPanelChange: (panelIndex: number | null) => void;\n}\n\nfunction AppShellPanelWithLayout({\n panel,\n visible,\n index,\n overrides = {},\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n ariaBaseId,\n rootExpansionActive,\n firstExpandedIndex,\n onExpandedPanelChange,\n}: AppShellPanelWithLayoutProps) {\n if (isMobile && index !== activePanel) return null;\n\n const layoutInfo: PanelLayoutInfo = {\n visible: isMobile ? true : visible,\n collapseMode: hasExpanded ? 'animated' : 'removed',\n isMobile,\n tabId: hasTabBar ? `${ariaBaseId}-tab-${index}` : undefined,\n panelId: hasTabBar ? `${ariaBaseId}-tabpanel-${index}` : undefined,\n expanded: rootExpansionActive\n ? hasExpanded && index === firstExpandedIndex\n : undefined,\n onExpandedChange: rootExpansionActive\n ? (nextExpanded) => onExpandedPanelChange(nextExpanded ? index : null)\n : undefined,\n ...overrides,\n };\n\n return (\n <PanelIndexContext.Provider value={index}>\n <PanelLayoutContext.Provider value={layoutInfo}>\n {panel}\n </PanelLayoutContext.Provider>\n </PanelIndexContext.Provider>\n );\n}\n\n// ============================================\n// AppShell Root\n// ============================================\n\nexport interface AppShellProps extends React.ComponentProps<'div'> {\n /** Any CSS background value (color, gradient, image). Defaults to var(--app-background). */\n background?: string;\n /** Fixed height, supports CSS calc() */\n height?: string;\n /** Spacing around the inner content in pixels or CSS value */\n padding?: number | string;\n /** Padding on mobile viewports. Defaults to 8px. */\n mobilePadding?: number | string;\n /** Gap between panels in pixels or CSS value. Defaults to 12. */\n gap?: number | string;\n /** Joined-edge mode where panels share borders. Defaults to false. */\n connected?: boolean;\n /** ID of the main content element for skip navigation. */\n skipToId?: string;\n /** Controlled active panel index for mobile tab switching. */\n activePanel?: number;\n /** Callback when active panel changes on mobile. */\n onActivePanelChange?: (index: number) => void;\n /** Default active panel on mobile (default: 0). */\n defaultActivePanel?: number;\n /** Controlled expanded panel index. Use null for no expanded panel. */\n expandedPanel?: number | null;\n /** Initial expanded panel index for uncontrolled root-owned expansion. */\n defaultExpandedPanel?: number | null;\n /** Callback when root-owned expansion changes. */\n onExpandedPanelChange?: (panelIndex: number | null) => void;\n /** Enables root-owned two-panel resizing on desktop. Defaults to true for eligible two-panel layouts. */\n resizablePanels?: boolean;\n /** Initial panel size split in percentages. Defaults to [35, 65]. */\n defaultPanelSizes?: [number, number];\n /** Controlled panel size split in percentages. */\n panelSizes?: [number, number];\n /** Called after the user releases the resize handle. */\n onPanelSizesChange?: (sizes: [number, number]) => void;\n /** Percentage threshold that expands the dominant panel on release. */\n expandThreshold?: number;\n}\n\nfunction AppShellRoot({\n background = DEFAULT_APP_SHELL_BACKGROUND,\n height = '100dvh',\n padding = 16,\n mobilePadding,\n gap = 12,\n connected = false,\n skipToId,\n activePanel: activePanelProp,\n onActivePanelChange,\n defaultActivePanel = 0,\n expandedPanel: expandedPanelProp,\n defaultExpandedPanel,\n onExpandedPanelChange,\n resizablePanels,\n defaultPanelSizes,\n panelSizes,\n onPanelSizesChange,\n expandThreshold = DEFAULT_EXPAND_THRESHOLD,\n className,\n children,\n ...props\n}: AppShellProps): React.ReactElement {\n const isMobile = useIsMobile();\n const ariaBaseId = React.useId();\n const [internalActivePanel, setInternalActivePanel] =\n React.useState(defaultActivePanel);\n const [internalExpandedPanel, setInternalExpandedPanel] = React.useState<\n number | null\n >(defaultExpandedPanel ?? null);\n const [internalPanelSizes, setInternalPanelSizes] = React.useState(() =>\n normalizePanelSizes(defaultPanelSizes),\n );\n const [isResizingPanels, setIsResizingPanels] = React.useState(false);\n const [isRestoringResizablePanels, setIsRestoringResizablePanels] =\n React.useState(false);\n const [internalMobileSidebarOpen, setInternalMobileSidebarOpen] =\n React.useState(false);\n const resizableGroupRef = React.useRef<GroupImperativeHandle | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const allowResizeReleaseExpansionRef = React.useRef(false);\n const suppressControlledLayoutChangeRef = React.useRef(false);\n const previousResizableExpandedRef = React.useRef(false);\n\n const activePanel = activePanelProp ?? internalActivePanel;\n const handleActivePanelChange = React.useCallback(\n (index: number) => {\n if (activePanelProp === undefined) {\n setInternalActivePanel((prev) => (prev === index ? prev : index));\n }\n onActivePanelChange?.(index);\n },\n [activePanelProp, onActivePanelChange],\n );\n\n const rootExpansionRequested =\n expandedPanelProp !== undefined ||\n defaultExpandedPanel !== undefined ||\n onExpandedPanelChange !== undefined;\n const resolvedExpandedPanel =\n expandedPanelProp !== undefined ? expandedPanelProp : internalExpandedPanel;\n const handleExpandedPanelChange = React.useCallback(\n (panelIndex: number | null) => {\n if (expandedPanelProp === undefined) {\n setInternalExpandedPanel(panelIndex);\n }\n onExpandedPanelChange?.(panelIndex);\n },\n [expandedPanelProp, onExpandedPanelChange],\n );\n\n // Classify children (memoized to stabilize downstream references)\n const { panels, panelInfos, sidebarChild, otherChildren } =\n React.useMemo(() => {\n const p: React.ReactElement<AppShellPanelProps>[] = [];\n const infos: { key?: React.Key; label?: string }[] = [];\n let sidebar: React.ReactNode = null;\n const other: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (isAppShellPanelElement(child)) {\n infos.push({\n key: child.key ?? child.props.label,\n label: child.props.label,\n });\n p.push(child);\n return;\n }\n\n if (!React.isValidElement(child)) {\n return;\n }\n\n if (child.type === AppShellSidebar) {\n sidebar = child;\n } else {\n other.push(child);\n }\n });\n\n return {\n panels: p,\n panelInfos: infos,\n sidebarChild: sidebar,\n otherChildren: other,\n };\n }, [children]);\n\n const shouldUseResizablePanels = resizablePanels ?? true;\n\n // Determine which panels are visible\n const firstPanelExpandedIndex = panels.findIndex((p) => p.props.expanded);\n const hasPanelExpansionProps = panels.some(\n (panel) =>\n panel.props.expanded !== undefined ||\n panel.props.onExpandedChange !== undefined,\n );\n const canUseResizablePanelPair =\n shouldUseResizablePanels &&\n !connected &&\n !isMobile &&\n panels.length === 2 &&\n (resizablePanels !== undefined || !hasPanelExpansionProps);\n const rootExpansionActive =\n rootExpansionRequested || canUseResizablePanelPair;\n const validRootExpandedPanel =\n typeof resolvedExpandedPanel === 'number' &&\n Number.isInteger(resolvedExpandedPanel) &&\n resolvedExpandedPanel >= 0 &&\n resolvedExpandedPanel < panels.length\n ? resolvedExpandedPanel\n : null;\n let firstExpandedIndex: number | null = firstPanelExpandedIndex;\n if (rootExpansionActive) {\n firstExpandedIndex = validRootExpandedPanel;\n }\n const hasExpanded = firstExpandedIndex !== -1 && firstExpandedIndex !== null;\n const visibleCount = hasExpanded ? 1 : Math.min(panels.length, 2);\n const canRenderResizablePanels = canUseResizablePanelPair;\n const resolvedPanelSizes = React.useMemo(\n () => normalizePanelSizes(panelSizes ?? internalPanelSizes),\n [panelSizes, internalPanelSizes],\n );\n const resizablePanelSizes = React.useMemo<[number, number]>(() => {\n if (hasExpanded && firstExpandedIndex === 0) return [100, 0];\n if (hasExpanded && firstExpandedIndex === 1) return [0, 100];\n return resolvedPanelSizes;\n }, [firstExpandedIndex, hasExpanded, resolvedPanelSizes]);\n const shouldBypassResizableMinSize =\n hasExpanded ||\n isRestoringResizablePanels ||\n (!hasExpanded && previousResizableExpandedRef.current);\n\n // Dev warnings\n if (process.env.NODE_ENV !== 'production') {\n const expandedPanelPropCount = panels.filter(\n (p) => p.props.expanded,\n ).length;\n if (rootExpansionActive && expandedPanelPropCount > 0) {\n console.warn(\n 'AppShell.Root: root-owned expansion props should not be mixed with AppShell.Panel expanded. Root expansion will be used.',\n );\n }\n if (!rootExpansionActive && expandedPanelPropCount > 1) {\n console.warn(\n 'AppShell.Root: multiple panels have expanded={true}. Only the first expanded panel will be shown.',\n );\n }\n if (\n rootExpansionActive &&\n resolvedExpandedPanel !== null &&\n resolvedExpandedPanel !== undefined &&\n validRootExpandedPanel === null\n ) {\n console.warn(\n `AppShell.Root: expandedPanel index ${resolvedExpandedPanel} is out of range. No panel will be expanded.`,\n );\n }\n if (resizablePanels === true && connected) {\n console.warn(\n 'AppShell.Root: resizablePanels is not supported with connected. Rendering non-resizable panels.',\n );\n }\n if (resizablePanels === true && !connected && panels.length !== 2) {\n console.warn(\n `AppShell.Root: resizablePanels requires exactly 2 Panel children, got ${panels.length}. Rendering non-resizable panels.`,\n );\n }\n if (panels.length > 2 && !hasExpanded) {\n console.warn(\n `AppShell.Root: max 2 Panel children allowed, got ${panels.length}. Only the first 2 will be visible.`,\n );\n }\n }\n\n const handleLayoutChange = React.useCallback(\n (layout: Record<string, number>) => {\n if (hasExpanded || suppressControlledLayoutChangeRef.current) {\n return;\n }\n if (panelSizes === undefined) {\n setInternalPanelSizes(layoutMapToTuple(layout));\n }\n },\n [hasExpanded, panelSizes],\n );\n\n const handleLayoutChanged = React.useCallback(\n (layout: Record<string, number>) => {\n if (\n hasExpanded ||\n !allowResizeReleaseExpansionRef.current ||\n suppressControlledLayoutChangeRef.current\n ) {\n return;\n }\n\n const nextSizes = layoutMapToTuple(layout);\n if (panelSizes === undefined) {\n setInternalPanelSizes(nextSizes);\n }\n onPanelSizesChange?.(nextSizes);\n\n const expandedIndex = getExpandedPanelFromLayout(layout, expandThreshold);\n if (expandedIndex !== null) {\n handleExpandedPanelChange(expandedIndex);\n }\n },\n [\n expandThreshold,\n handleExpandedPanelChange,\n hasExpanded,\n onPanelSizesChange,\n panelSizes,\n ],\n );\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n suppressControlledLayoutChangeRef.current = false;\n previousResizableExpandedRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const wasExpanded = previousResizableExpandedRef.current;\n previousResizableExpandedRef.current = hasExpanded;\n const shouldApplyLayout =\n hasExpanded || wasExpanded || panelSizes !== undefined;\n if (!shouldApplyLayout) {\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n let restoreFrame: number | undefined;\n const [first, second] = resizablePanelSizes;\n if (wasExpanded && !hasExpanded) {\n restoreFrame = ownerWindow.requestAnimationFrame(() => {\n setIsRestoringResizablePanels(true);\n });\n }\n suppressControlledLayoutChangeRef.current = true;\n const nextLayout = { panel0: first, panel1: second };\n resizableGroupRef.current?.setLayout(nextLayout);\n const frame = ownerWindow.requestAnimationFrame(() => {\n resizableGroupRef.current?.setLayout(nextLayout);\n });\n const timeout = ownerWindow.setTimeout(() => {\n suppressControlledLayoutChangeRef.current = false;\n }, 350);\n return () => {\n if (restoreFrame !== undefined) {\n ownerWindow.cancelAnimationFrame(restoreFrame);\n }\n ownerWindow.cancelAnimationFrame(frame);\n ownerWindow.clearTimeout(timeout);\n suppressControlledLayoutChangeRef.current = false;\n };\n }, [canRenderResizablePanels, hasExpanded, panelSizes, resizablePanelSizes]);\n\n React.useEffect(() => {\n if (!isRestoringResizablePanels) return;\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const timeout = ownerWindow.setTimeout(() => {\n setIsRestoringResizablePanels(false);\n }, 350);\n return () => ownerWindow.clearTimeout(timeout);\n }, [isRestoringResizablePanels]);\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n allowResizeReleaseExpansionRef.current = false;\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const frame = ownerWindow.requestAnimationFrame(() => {\n allowResizeReleaseExpansionRef.current = true;\n });\n return () => {\n ownerWindow.cancelAnimationFrame(frame);\n allowResizeReleaseExpansionRef.current = false;\n };\n }, [canRenderResizablePanels]);\n\n React.useEffect(() => {\n if (!isResizingPanels) return;\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const stopResizing = () => setIsResizingPanels(false);\n ownerWindow.addEventListener('pointerup', stopResizing);\n ownerWindow.addEventListener('pointercancel', stopResizing);\n return () => {\n ownerWindow.removeEventListener('pointerup', stopResizing);\n ownerWindow.removeEventListener('pointercancel', stopResizing);\n };\n }, [isResizingPanels]);\n\n const handleResizablePointerDownCapture = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.closest('[data-slot=\"resizable-handle\"]')) {\n setIsResizingPanels(true);\n }\n },\n [],\n );\n\n // Memoize the visibility map to stabilize downstream context values\n const visiblePanels = React.useMemo(\n () =>\n hasExpanded\n ? panels.map((panel, i) => ({\n panel,\n visible: i === firstExpandedIndex,\n index: i,\n }))\n : panels.map((panel, i) => ({\n panel,\n visible: i < 2,\n index: i,\n })),\n [panels, hasExpanded, firstExpandedIndex],\n );\n\n // Whether the tab bar is active (mobile with 2+ panels)\n const hasTabBar = isMobile && panels.length > 1;\n\n // Build context (derive position from stable scalars, not array reference)\n const getPanelPosition = React.useCallback(\n (index: number): PanelPosition => {\n if (visibleCount === 1) return 'only';\n if (hasExpanded) return index === firstExpandedIndex ? 'only' : 'last';\n return index === 0 ? 'first' : 'last';\n },\n [visibleCount, hasExpanded, firstExpandedIndex],\n );\n\n const contextValue: AppShellContextValue = React.useMemo(\n () => ({\n connected,\n panelCount: visibleCount,\n getPanelPosition,\n }),\n [connected, visibleCount, getPanelPosition],\n );\n\n // Sidebar context for mobile drawer integration\n const sidebarContext = React.useContext(SidebarContext);\n const mobileSidebarOpen =\n sidebarContext?.openMobile ?? internalMobileSidebarOpen;\n const setMobileSidebarOpen =\n sidebarContext?.setOpenMobile ?? setInternalMobileSidebarOpen;\n const handleSidebarOpen = React.useCallback(() => {\n setMobileSidebarOpen(true);\n }, [setMobileSidebarOpen]);\n\n const handleSheetOpenChange = React.useCallback(\n (open: boolean) => {\n setMobileSidebarOpen(open);\n },\n [setMobileSidebarOpen],\n );\n\n // Skip navigation link\n const skipLink = skipToId ? (\n <a\n href={`#${skipToId}`}\n className=\"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-sm focus:ring-2 focus:ring-ring\"\n >\n Skip to content\n </a>\n ) : null;\n\n // Render panels with context providers (no cloneElement — panels self-style)\n const renderedPanels = React.useMemo(\n () =>\n visiblePanels.map(({ panel, visible, index }) => (\n <AppShellPanelWithLayout\n key={getAppShellPanelIdentity(panel, ariaBaseId, index)}\n panel={panel}\n visible={visible}\n index={index}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n )),\n [\n visiblePanels,\n ariaBaseId,\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n rootExpansionActive,\n firstExpandedIndex,\n handleExpandedPanelChange,\n ],\n );\n\n const renderedResizablePanels = canRenderResizablePanels ? (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n disabled={hasExpanded}\n groupRef={resizableGroupRef}\n onLayoutChange={handleLayoutChange}\n onLayoutChanged={handleLayoutChanged}\n onPointerDownCapture={handleResizablePointerDownCapture}\n className={cn(\n 'min-h-0 min-w-0 flex-1',\n !isResizingPanels &&\n '[&>[data-slot=resizable-panel]]:transition-[flex-grow] [&>[data-slot=resizable-panel]]:duration-300 [&>[data-slot=resizable-panel]]:ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:[&>[data-slot=resizable-panel]]:transition-none',\n )}\n >\n <ResizablePanel\n id=\"panel0\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[0])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[0].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[0]}\n visible={!hasExpanded || firstExpandedIndex === 0}\n index={0}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n <ResizableHandle\n disabled={hasExpanded}\n className={cn(\n 'z-10 min-w-2 shrink-0 cursor-col-resize w-[var(--app-shell-gap,0px)] bg-transparent after:w-2 hover:bg-transparent',\n 'transition-[width,min-width,opacity,background-color] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none',\n hasExpanded && 'min-w-0 w-0 opacity-0 after:w-0 pointer-events-none',\n )}\n />\n <ResizablePanel\n id=\"panel1\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[1])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[1].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[1]}\n visible={!hasExpanded || firstExpandedIndex === 1}\n index={1}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n </ResizablePanelGroup>\n ) : null;\n\n // Live region for announcing panel changes to screen readers\n const activeLabel =\n hasTabBar && panelInfos[activePanel]\n ? panelInfos[activePanel].label || `Panel ${activePanel + 1}`\n : null;\n\n // Mobile layout\n if (isMobile) {\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={0}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild && (\n <Sheet\n open={mobileSidebarOpen}\n onOpenChange={handleSheetOpenChange}\n >\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"w-[280px] p-0\"\n aria-label=\"Sidebar navigation\"\n >\n {sidebarChild}\n </SheetContent>\n </Sheet>\n )}\n <div className=\"flex h-full min-w-0 flex-1 flex-col overflow-clip\">\n <AppShellMobileTabBar\n panels={panelInfos}\n activeIndex={activePanel}\n onActiveChange={handleActivePanelChange}\n onSidebarOpen={sidebarChild ? handleSidebarOpen : undefined}\n baseId={ariaBaseId}\n />\n <div className=\"flex min-h-0 flex-1\">{renderedPanels}</div>\n </div>\n {/* Live region for panel switch announcements */}\n {activeLabel && (\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {activeLabel} panel active\n </div>\n )}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n }\n\n // Desktop layout\n const effectiveGap = connected || hasExpanded ? 0 : gap;\n\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={effectiveGap}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild}\n {renderedResizablePanels ?? renderedPanels}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n}\n\nAppShellRoot.displayName = 'AppShell';\n\n// ============================================\n// AppShell Sidebar\n// ============================================\n\nexport interface AppShellSidebarProps extends React.ComponentProps<'div'> {\n /**\n * Explicit width override — bypasses auto-detection. Manual widths are\n * protected by AppSidebar's canonical collapsed width to prevent clipping.\n * When omitted, the sidebar auto-sizes based on the child\n * SidebarProvider's expanded/collapsed state.\n */\n width?: string;\n /** Width when sidebar is expanded (auto mode only). @default '280px' */\n expandedWidth?: string;\n /** Width when sidebar is collapsed (auto mode only). @default '116px' */\n collapsedWidth?: string;\n}\n\n/**\n * Layout slot for the sidebar region. Renders a div — the actual aside\n * landmark is provided by AppSidebar/Sidebar primitive inside it.\n *\n * **Auto-detection (default):** When no `width` prop is provided, the sidebar\n * observes the child SidebarProvider's `data-state` attribute via CSS `:has()`\n * and transitions between `collapsedWidth` and `expandedWidth` automatically.\n *\n * **Manual mode:** Pass an explicit `width` to control sizing yourself.\n */\nfunction AppShellSidebar({\n width,\n expandedWidth = APP_SIDEBAR_EXPANDED_WIDTH,\n collapsedWidth = APP_SIDEBAR_COLLAPSED_WIDTH,\n className,\n style,\n children,\n ...props\n}: AppShellSidebarProps) {\n const autoMode = width === undefined;\n\n return (\n <div\n data-slot=\"app-shell-sidebar\"\n style={\n {\n ...(autoMode\n ? {\n '--app-shell-sidebar-collapsed': collapsedWidth,\n '--app-shell-sidebar-expanded': expandedWidth,\n }\n : {\n '--app-shell-sidebar-width': width,\n minWidth: APP_SIDEBAR_COLLAPSED_WIDTH,\n }),\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-full shrink-0 flex-col overflow-clip',\n 'transition-[width] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]',\n 'motion-reduce:transition-none',\n autoMode\n ? [\n 'w-[var(--app-shell-sidebar-collapsed)]',\n '[&:has([data-state=expanded])]:w-[var(--app-shell-sidebar-expanded)]',\n ]\n : 'w-[var(--app-shell-sidebar-width)]',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellSidebar.displayName = 'AppShell.Sidebar';\n\n// ============================================\n// AppShell Header\n// ============================================\n\nexport interface AppShellHeaderProps extends React.ComponentProps<'div'> {}\n\nfunction AppShellHeader({\n className,\n children,\n ...props\n}: AppShellHeaderProps) {\n return (\n <div\n data-slot=\"app-shell-header\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellHeader.displayName = 'AppShell.Header';\n\n// ============================================\n// Preset Background Variants\n// ============================================\n\nconst appShellBackgrounds = {\n transparent: 'transparent',\n appBg: DEFAULT_APP_SHELL_BACKGROUND,\n neutral: 'var(--muted)',\n brandSubtle: 'linear-gradient(135deg, var(--air-50) 0%, var(--air-100) 100%)',\n brand: 'linear-gradient(135deg, var(--air-400) 0%, var(--primary) 100%)',\n brandDeep: 'linear-gradient(135deg, var(--primary) 0%, var(--air-900) 100%)',\n desertMidnight:\n 'linear-gradient(135deg, var(--slate-500) 0%, var(--slate-700) 100%)',\n aqua: 'linear-gradient(135deg, var(--air-400) 0%, var(--air-600) 100%)',\n} as const;\n\n// ============================================\n// Compound Component (Dot Notation)\n// ============================================\n\nconst AppShell = Object.assign(AppShellRoot, {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Header: AppShellHeader,\n Panel: AppShellPanel,\n Content: AppShellContent,\n});\n\n// ============================================\n// Exports\n// ============================================\n\nexport type { AppShellContentProps } from './AppShellContent';\nexport type { AppShellPanelProps } from './AppShellPanel';\n\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n AppShell,\n AppShellContent,\n AppShellHeader,\n AppShellPanel,\n AppShellRoot,\n AppShellSidebar,\n appShellBackgrounds,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index223.js","names":[],"sources":["../src/components/templates/AppShell/AppShell.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { GroupImperativeHandle } from 'react-resizable-panels';\nimport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from '@/components/atoms/layout/Resizable';\nimport { AppShell as AppShellPrimitive } from '@/components/ui/app-shell';\n\nimport { Sheet, SheetContent } from '@/components/ui/sheet';\nimport { SidebarContext } from '@/components/ui/sidebar';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from '../AppSidebar/AppSidebar.constants';\nimport { AppShellContent } from './AppShellContent';\nimport {\n type AppShellContextValue,\n AppShellProvider,\n PanelIndexContext,\n PanelLayoutContext,\n type PanelLayoutInfo,\n type PanelPosition,\n} from './AppShellContext';\nimport { AppShellMobileTabBar } from './AppShellMobileTabBar';\nimport {\n APPSHELL_PANEL_TYPE,\n AppShellPanel,\n type AppShellPanelComponent,\n type AppShellPanelProps,\n} from './AppShellPanel';\nimport {\n DEFAULT_EXPAND_THRESHOLD,\n getExpandedPanelFromLayout,\n layoutMapToTuple,\n normalizePanelSizes,\n toResizableMinSize,\n toResizablePercentageSize,\n} from './AppShellResize';\n\nconst DEFAULT_APP_SHELL_BACKGROUND = 'var(--app-background)';\n\ninterface AppShellPanelMarker {\n __appShellType?: unknown;\n}\n\nfunction isAppShellPanelComponent(\n type: unknown,\n): type is AppShellPanelComponent {\n return (\n typeof type === 'function' &&\n (type as AppShellPanelMarker).__appShellType === APPSHELL_PANEL_TYPE\n );\n}\n\nfunction isAppShellPanelElement(\n child: React.ReactNode,\n): child is React.ReactElement<AppShellPanelProps, AppShellPanelComponent> {\n return React.isValidElement(child) && isAppShellPanelComponent(child.type);\n}\n\nfunction getAppShellPanelIdentity(\n panel: React.ReactElement<AppShellPanelProps>,\n ariaBaseId: string,\n index: number,\n): React.Key {\n return panel.key ?? panel.props.label ?? `${ariaBaseId}-panel-${index}`;\n}\n\ninterface AppShellPanelWithLayoutProps {\n panel: React.ReactElement<AppShellPanelProps>;\n visible: boolean;\n index: number;\n overrides?: Partial<PanelLayoutInfo>;\n isMobile: boolean;\n activePanel: number;\n hasExpanded: boolean;\n hasTabBar: boolean;\n ariaBaseId: string;\n rootExpansionActive: boolean;\n firstExpandedIndex: number | null;\n onExpandedPanelChange: (panelIndex: number | null) => void;\n}\n\nfunction AppShellPanelWithLayout({\n panel,\n visible,\n index,\n overrides = {},\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n ariaBaseId,\n rootExpansionActive,\n firstExpandedIndex,\n onExpandedPanelChange,\n}: AppShellPanelWithLayoutProps) {\n if (isMobile && index !== activePanel) return null;\n\n const layoutInfo: PanelLayoutInfo = {\n visible: isMobile ? true : visible,\n collapseMode: hasExpanded ? 'animated' : 'removed',\n isMobile,\n tabId: hasTabBar ? `${ariaBaseId}-tab-${index}` : undefined,\n panelId: hasTabBar ? `${ariaBaseId}-tabpanel-${index}` : undefined,\n expanded: rootExpansionActive\n ? hasExpanded && index === firstExpandedIndex\n : undefined,\n onExpandedChange: rootExpansionActive\n ? (nextExpanded) => onExpandedPanelChange(nextExpanded ? index : null)\n : undefined,\n ...overrides,\n };\n\n return (\n <PanelIndexContext.Provider value={index}>\n <PanelLayoutContext.Provider value={layoutInfo}>\n {panel}\n </PanelLayoutContext.Provider>\n </PanelIndexContext.Provider>\n );\n}\n\n// ============================================\n// AppShell Root\n// ============================================\n\nexport interface AppShellProps extends React.ComponentProps<'div'> {\n /** Any CSS background value (color, gradient, image). Defaults to var(--app-background). */\n background?: string;\n /** Fixed height, supports CSS calc() */\n height?: string;\n /** Spacing around the inner content in pixels or CSS value */\n padding?: number | string;\n /** Padding on mobile viewports. Defaults to 8px. */\n mobilePadding?: number | string;\n /** Gap between panels in pixels or CSS value. Defaults to 12. */\n gap?: number | string;\n /** Joined-edge mode where panels share borders. Defaults to false. */\n connected?: boolean;\n /** ID of the main content element for skip navigation. */\n skipToId?: string;\n /** Controlled active panel index for mobile tab switching. */\n activePanel?: number;\n /** Callback when active panel changes on mobile. */\n onActivePanelChange?: (index: number) => void;\n /** Default active panel on mobile (default: 0). */\n defaultActivePanel?: number;\n /** Controlled expanded panel index. Use null for no expanded panel. */\n expandedPanel?: number | null;\n /** Initial expanded panel index for uncontrolled root-owned expansion. */\n defaultExpandedPanel?: number | null;\n /** Callback when root-owned expansion changes. */\n onExpandedPanelChange?: (panelIndex: number | null) => void;\n /** Enables root-owned two-panel resizing on desktop. Defaults to true for eligible two-panel layouts. */\n resizablePanels?: boolean;\n /** Initial panel size split in percentages. Defaults to [35, 65]. */\n defaultPanelSizes?: [number, number];\n /** Controlled panel size split in percentages. */\n panelSizes?: [number, number];\n /** Called after the user releases the resize handle. */\n onPanelSizesChange?: (sizes: [number, number]) => void;\n /** Percentage threshold that expands the dominant panel on release. */\n expandThreshold?: number;\n}\n\nfunction AppShellRoot({\n background = DEFAULT_APP_SHELL_BACKGROUND,\n height = '100dvh',\n padding = 16,\n mobilePadding,\n gap = 12,\n connected = false,\n skipToId,\n activePanel: activePanelProp,\n onActivePanelChange,\n defaultActivePanel = 0,\n expandedPanel: expandedPanelProp,\n defaultExpandedPanel,\n onExpandedPanelChange,\n resizablePanels,\n defaultPanelSizes,\n panelSizes,\n onPanelSizesChange,\n expandThreshold = DEFAULT_EXPAND_THRESHOLD,\n className,\n children,\n ...props\n}: AppShellProps): React.ReactElement {\n const isMobile = useIsMobile();\n const ariaBaseId = React.useId();\n const [internalActivePanel, setInternalActivePanel] =\n React.useState(defaultActivePanel);\n const [internalExpandedPanel, setInternalExpandedPanel] = React.useState<\n number | null\n >(defaultExpandedPanel ?? null);\n const [internalPanelSizes, setInternalPanelSizes] = React.useState(() =>\n normalizePanelSizes(defaultPanelSizes),\n );\n const [isResizingPanels, setIsResizingPanels] = React.useState(false);\n const [isRestoringResizablePanels, setIsRestoringResizablePanels] =\n React.useState(false);\n const [internalMobileSidebarOpen, setInternalMobileSidebarOpen] =\n React.useState(false);\n const resizableGroupRef = React.useRef<GroupImperativeHandle | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const allowResizeReleaseExpansionRef = React.useRef(false);\n const suppressControlledLayoutChangeRef = React.useRef(false);\n const previousResizableExpandedRef = React.useRef(false);\n\n const activePanel = activePanelProp ?? internalActivePanel;\n const handleActivePanelChange = React.useCallback(\n (index: number) => {\n if (activePanelProp === undefined) {\n setInternalActivePanel((prev) => (prev === index ? prev : index));\n }\n onActivePanelChange?.(index);\n },\n [activePanelProp, onActivePanelChange],\n );\n\n const rootExpansionRequested =\n expandedPanelProp !== undefined ||\n defaultExpandedPanel !== undefined ||\n onExpandedPanelChange !== undefined;\n const resolvedExpandedPanel =\n expandedPanelProp !== undefined ? expandedPanelProp : internalExpandedPanel;\n const handleExpandedPanelChange = React.useCallback(\n (panelIndex: number | null) => {\n if (expandedPanelProp === undefined) {\n setInternalExpandedPanel(panelIndex);\n }\n onExpandedPanelChange?.(panelIndex);\n },\n [expandedPanelProp, onExpandedPanelChange],\n );\n\n // Classify children (memoized to stabilize downstream references)\n const { panels, panelInfos, sidebarChild, otherChildren } =\n React.useMemo(() => {\n const p: React.ReactElement<AppShellPanelProps>[] = [];\n const infos: { key?: React.Key; label?: string }[] = [];\n let sidebar: React.ReactNode = null;\n const other: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (isAppShellPanelElement(child)) {\n infos.push({\n key: child.key ?? child.props.label,\n label: child.props.label,\n });\n p.push(child);\n return;\n }\n\n if (!React.isValidElement(child)) {\n return;\n }\n\n if (child.type === AppShellSidebar) {\n sidebar = child;\n } else {\n other.push(child);\n }\n });\n\n return {\n panels: p,\n panelInfos: infos,\n sidebarChild: sidebar,\n otherChildren: other,\n };\n }, [children]);\n\n const shouldUseResizablePanels = resizablePanels ?? true;\n\n // Determine which panels are visible\n const firstPanelExpandedIndex = panels.findIndex((p) => p.props.expanded);\n const hasPanelExpansionProps = panels.some(\n (panel) =>\n panel.props.expanded !== undefined ||\n panel.props.onExpandedChange !== undefined,\n );\n const canUseResizablePanelPair =\n shouldUseResizablePanels &&\n !connected &&\n !isMobile &&\n panels.length === 2 &&\n (resizablePanels !== undefined || !hasPanelExpansionProps);\n const rootExpansionActive =\n rootExpansionRequested || canUseResizablePanelPair;\n const validRootExpandedPanel =\n typeof resolvedExpandedPanel === 'number' &&\n Number.isInteger(resolvedExpandedPanel) &&\n resolvedExpandedPanel >= 0 &&\n resolvedExpandedPanel < panels.length\n ? resolvedExpandedPanel\n : null;\n let firstExpandedIndex: number | null = firstPanelExpandedIndex;\n if (rootExpansionActive) {\n firstExpandedIndex = validRootExpandedPanel;\n }\n const hasExpanded = firstExpandedIndex !== -1 && firstExpandedIndex !== null;\n const visibleCount = hasExpanded ? 1 : Math.min(panels.length, 2);\n const canRenderResizablePanels = canUseResizablePanelPair;\n const resolvedPanelSizes = React.useMemo(\n () => normalizePanelSizes(panelSizes ?? internalPanelSizes),\n [panelSizes, internalPanelSizes],\n );\n const resizablePanelSizes = React.useMemo<[number, number]>(() => {\n if (hasExpanded && firstExpandedIndex === 0) return [100, 0];\n if (hasExpanded && firstExpandedIndex === 1) return [0, 100];\n return resolvedPanelSizes;\n }, [firstExpandedIndex, hasExpanded, resolvedPanelSizes]);\n const shouldBypassResizableMinSize =\n hasExpanded ||\n isRestoringResizablePanels ||\n (!hasExpanded && previousResizableExpandedRef.current);\n\n // Dev warnings\n if (process.env.NODE_ENV !== 'production') {\n const expandedPanelPropCount = panels.filter(\n (p) => p.props.expanded,\n ).length;\n if (rootExpansionActive && expandedPanelPropCount > 0) {\n console.warn(\n 'AppShell.Root: root-owned expansion props should not be mixed with AppShell.Panel expanded. Root expansion will be used.',\n );\n }\n if (!rootExpansionActive && expandedPanelPropCount > 1) {\n console.warn(\n 'AppShell.Root: multiple panels have expanded={true}. Only the first expanded panel will be shown.',\n );\n }\n if (\n rootExpansionActive &&\n resolvedExpandedPanel !== null &&\n resolvedExpandedPanel !== undefined &&\n validRootExpandedPanel === null\n ) {\n console.warn(\n `AppShell.Root: expandedPanel index ${resolvedExpandedPanel} is out of range. No panel will be expanded.`,\n );\n }\n if (resizablePanels === true && connected) {\n console.warn(\n 'AppShell.Root: resizablePanels is not supported with connected. Rendering non-resizable panels.',\n );\n }\n if (resizablePanels === true && !connected && panels.length !== 2) {\n console.warn(\n `AppShell.Root: resizablePanels requires exactly 2 Panel children, got ${panels.length}. Rendering non-resizable panels.`,\n );\n }\n if (panels.length > 2 && !hasExpanded) {\n console.warn(\n `AppShell.Root: max 2 Panel children allowed, got ${panels.length}. Only the first 2 will be visible.`,\n );\n }\n }\n\n const handleLayoutChange = React.useCallback(\n (layout: Record<string, number>) => {\n if (hasExpanded || suppressControlledLayoutChangeRef.current) {\n return;\n }\n if (panelSizes === undefined) {\n setInternalPanelSizes(layoutMapToTuple(layout));\n }\n },\n [hasExpanded, panelSizes],\n );\n\n const handleLayoutChanged = React.useCallback(\n (layout: Record<string, number>) => {\n if (\n hasExpanded ||\n !allowResizeReleaseExpansionRef.current ||\n suppressControlledLayoutChangeRef.current\n ) {\n return;\n }\n\n const nextSizes = layoutMapToTuple(layout);\n if (panelSizes === undefined) {\n setInternalPanelSizes(nextSizes);\n }\n onPanelSizesChange?.(nextSizes);\n\n const expandedIndex = getExpandedPanelFromLayout(layout, expandThreshold);\n if (expandedIndex !== null) {\n handleExpandedPanelChange(expandedIndex);\n }\n },\n [\n expandThreshold,\n handleExpandedPanelChange,\n hasExpanded,\n onPanelSizesChange,\n panelSizes,\n ],\n );\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n suppressControlledLayoutChangeRef.current = false;\n previousResizableExpandedRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const wasExpanded = previousResizableExpandedRef.current;\n previousResizableExpandedRef.current = hasExpanded;\n const shouldApplyLayout =\n hasExpanded || wasExpanded || panelSizes !== undefined;\n if (!shouldApplyLayout) {\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n let restoreFrame: number | undefined;\n const [first, second] = resizablePanelSizes;\n if (wasExpanded && !hasExpanded) {\n restoreFrame = ownerWindow.requestAnimationFrame(() => {\n setIsRestoringResizablePanels(true);\n });\n }\n suppressControlledLayoutChangeRef.current = true;\n const nextLayout = { panel0: first, panel1: second };\n resizableGroupRef.current?.setLayout(nextLayout);\n const frame = ownerWindow.requestAnimationFrame(() => {\n resizableGroupRef.current?.setLayout(nextLayout);\n });\n const timeout = ownerWindow.setTimeout(() => {\n suppressControlledLayoutChangeRef.current = false;\n }, 350);\n return () => {\n if (restoreFrame !== undefined) {\n ownerWindow.cancelAnimationFrame(restoreFrame);\n }\n ownerWindow.cancelAnimationFrame(frame);\n ownerWindow.clearTimeout(timeout);\n suppressControlledLayoutChangeRef.current = false;\n };\n }, [canRenderResizablePanels, hasExpanded, panelSizes, resizablePanelSizes]);\n\n React.useEffect(() => {\n if (!isRestoringResizablePanels) return;\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const timeout = ownerWindow.setTimeout(() => {\n setIsRestoringResizablePanels(false);\n }, 350);\n return () => ownerWindow.clearTimeout(timeout);\n }, [isRestoringResizablePanels]);\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n allowResizeReleaseExpansionRef.current = false;\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const frame = ownerWindow.requestAnimationFrame(() => {\n allowResizeReleaseExpansionRef.current = true;\n });\n return () => {\n ownerWindow.cancelAnimationFrame(frame);\n allowResizeReleaseExpansionRef.current = false;\n };\n }, [canRenderResizablePanels]);\n\n React.useEffect(() => {\n if (!isResizingPanels) return;\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const stopResizing = () => setIsResizingPanels(false);\n ownerWindow.addEventListener('pointerup', stopResizing);\n ownerWindow.addEventListener('pointercancel', stopResizing);\n return () => {\n ownerWindow.removeEventListener('pointerup', stopResizing);\n ownerWindow.removeEventListener('pointercancel', stopResizing);\n };\n }, [isResizingPanels]);\n\n const handleResizablePointerDownCapture = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.closest('[data-slot=\"resizable-handle\"]')) {\n setIsResizingPanels(true);\n }\n },\n [],\n );\n\n // Memoize the visibility map to stabilize downstream context values\n const visiblePanels = React.useMemo(\n () =>\n hasExpanded\n ? panels.map((panel, i) => ({\n panel,\n visible: i === firstExpandedIndex,\n index: i,\n }))\n : panels.map((panel, i) => ({\n panel,\n visible: i < 2,\n index: i,\n })),\n [panels, hasExpanded, firstExpandedIndex],\n );\n\n // Whether the tab bar is active (mobile with 2+ panels)\n const hasTabBar = isMobile && panels.length > 1;\n\n // Build context (derive position from stable scalars, not array reference)\n const getPanelPosition = React.useCallback(\n (index: number): PanelPosition => {\n if (visibleCount === 1) return 'only';\n if (hasExpanded) return index === firstExpandedIndex ? 'only' : 'last';\n return index === 0 ? 'first' : 'last';\n },\n [visibleCount, hasExpanded, firstExpandedIndex],\n );\n\n const contextValue: AppShellContextValue = React.useMemo(\n () => ({\n connected,\n panelCount: visibleCount,\n getPanelPosition,\n }),\n [connected, visibleCount, getPanelPosition],\n );\n\n // Sidebar context for mobile drawer integration\n const sidebarContext = React.useContext(SidebarContext);\n const mobileSidebarOpen =\n sidebarContext?.openMobile ?? internalMobileSidebarOpen;\n const setMobileSidebarOpen =\n sidebarContext?.setOpenMobile ?? setInternalMobileSidebarOpen;\n const handleSidebarOpen = React.useCallback(() => {\n setMobileSidebarOpen(true);\n }, [setMobileSidebarOpen]);\n\n const handleSheetOpenChange = React.useCallback(\n (open: boolean) => {\n setMobileSidebarOpen(open);\n },\n [setMobileSidebarOpen],\n );\n\n // Skip navigation link\n const skipLink = skipToId ? (\n <a\n href={`#${skipToId}`}\n className=\"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-sm focus:ring-2 focus:ring-ring\"\n >\n Skip to content\n </a>\n ) : null;\n\n // Render panels with context providers (no cloneElement — panels self-style)\n const renderedPanels = React.useMemo(\n () =>\n visiblePanels.map(({ panel, visible, index }) => (\n <AppShellPanelWithLayout\n key={getAppShellPanelIdentity(panel, ariaBaseId, index)}\n panel={panel}\n visible={visible}\n index={index}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n )),\n [\n visiblePanels,\n ariaBaseId,\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n rootExpansionActive,\n firstExpandedIndex,\n handleExpandedPanelChange,\n ],\n );\n\n const renderedResizablePanels = canRenderResizablePanels ? (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n disabled={hasExpanded}\n groupRef={resizableGroupRef}\n onLayoutChange={handleLayoutChange}\n onLayoutChanged={handleLayoutChanged}\n onPointerDownCapture={handleResizablePointerDownCapture}\n className={cn(\n 'min-h-0 min-w-0 flex-1',\n !isResizingPanels &&\n '[&>[data-slot=resizable-panel]]:transition-[flex-grow] [&>[data-slot=resizable-panel]]:duration-300 [&>[data-slot=resizable-panel]]:ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:[&>[data-slot=resizable-panel]]:transition-none',\n )}\n >\n <ResizablePanel\n id=\"panel0\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[0])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[0].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[0]}\n visible={!hasExpanded || firstExpandedIndex === 0}\n index={0}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n <ResizableHandle\n disabled={hasExpanded}\n className={cn(\n 'z-10 min-w-2 shrink-0 cursor-col-resize w-[var(--app-shell-gap,0px)] bg-transparent after:w-2 hover:bg-transparent',\n 'transition-[width,min-width,opacity,background-color] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none',\n hasExpanded && 'min-w-0 w-0 opacity-0 after:w-0 pointer-events-none',\n )}\n />\n <ResizablePanel\n id=\"panel1\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[1])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[1].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[1]}\n visible={!hasExpanded || firstExpandedIndex === 1}\n index={1}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n </ResizablePanelGroup>\n ) : null;\n\n // Live region for announcing panel changes to screen readers\n const activeLabel =\n hasTabBar && panelInfos[activePanel]\n ? panelInfos[activePanel].label || `Panel ${activePanel + 1}`\n : null;\n\n // Mobile layout\n if (isMobile) {\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={0}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild && (\n <Sheet\n open={mobileSidebarOpen}\n onOpenChange={handleSheetOpenChange}\n >\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"w-[280px] p-0\"\n aria-label=\"Sidebar navigation\"\n >\n {sidebarChild}\n </SheetContent>\n </Sheet>\n )}\n <div className=\"flex h-full min-w-0 flex-1 flex-col overflow-clip\">\n <AppShellMobileTabBar\n panels={panelInfos}\n activeIndex={activePanel}\n onActiveChange={handleActivePanelChange}\n onSidebarOpen={sidebarChild ? handleSidebarOpen : undefined}\n baseId={ariaBaseId}\n />\n <div className=\"flex min-h-0 flex-1\">{renderedPanels}</div>\n </div>\n {/* Live region for panel switch announcements */}\n {activeLabel && (\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {activeLabel} panel active\n </div>\n )}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n }\n\n // Desktop layout\n const effectiveGap = connected || hasExpanded ? 0 : gap;\n\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={effectiveGap}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild}\n {renderedResizablePanels ?? renderedPanels}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n}\n\nAppShellRoot.displayName = 'AppShell';\n\n// ============================================\n// AppShell Sidebar\n// ============================================\n\nexport interface AppShellSidebarProps extends React.ComponentProps<'div'> {\n /**\n * Explicit width override — bypasses auto-detection. Manual widths are\n * protected by AppSidebar's canonical collapsed width to prevent clipping.\n * When omitted, the sidebar auto-sizes based on the child\n * SidebarProvider's expanded/collapsed state.\n */\n width?: string;\n /** Width when sidebar is expanded (auto mode only). @default '280px' */\n expandedWidth?: string;\n /** Width when sidebar is collapsed (auto mode only). @default '68px' */\n collapsedWidth?: string;\n}\n\n/**\n * Layout slot for the sidebar region. Renders a div — the actual aside\n * landmark is provided by AppSidebar/Sidebar primitive inside it.\n *\n * **Auto-detection (default):** When no `width` prop is provided, the sidebar\n * observes the child SidebarProvider's `data-state` attribute via CSS `:has()`\n * and transitions between `collapsedWidth` and `expandedWidth` automatically.\n *\n * **Manual mode:** Pass an explicit `width` to control sizing yourself.\n */\nfunction AppShellSidebar({\n width,\n expandedWidth = APP_SIDEBAR_EXPANDED_WIDTH,\n collapsedWidth = APP_SIDEBAR_COLLAPSED_WIDTH,\n className,\n style,\n children,\n ...props\n}: AppShellSidebarProps) {\n const autoMode = width === undefined;\n\n return (\n <div\n data-slot=\"app-shell-sidebar\"\n style={\n {\n ...(autoMode\n ? {\n '--app-shell-sidebar-collapsed': collapsedWidth,\n '--app-shell-sidebar-expanded': expandedWidth,\n }\n : {\n '--app-shell-sidebar-width': width,\n minWidth: APP_SIDEBAR_COLLAPSED_WIDTH,\n }),\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-full shrink-0 flex-col overflow-clip',\n 'transition-[width] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]',\n 'motion-reduce:transition-none',\n autoMode\n ? [\n 'w-[var(--app-shell-sidebar-collapsed)]',\n '[&:has([data-state=expanded])]:w-[var(--app-shell-sidebar-expanded)]',\n ]\n : 'w-[var(--app-shell-sidebar-width)]',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellSidebar.displayName = 'AppShell.Sidebar';\n\n// ============================================\n// AppShell Header\n// ============================================\n\nexport interface AppShellHeaderProps extends React.ComponentProps<'div'> {}\n\nfunction AppShellHeader({\n className,\n children,\n ...props\n}: AppShellHeaderProps) {\n return (\n <div\n data-slot=\"app-shell-header\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellHeader.displayName = 'AppShell.Header';\n\n// ============================================\n// Preset Background Variants\n// ============================================\n\nconst appShellBackgrounds = {\n transparent: 'transparent',\n appBg: DEFAULT_APP_SHELL_BACKGROUND,\n neutral: 'var(--muted)',\n brandSubtle: 'linear-gradient(135deg, var(--air-50) 0%, var(--air-100) 100%)',\n brand: 'linear-gradient(135deg, var(--air-400) 0%, var(--primary) 100%)',\n brandDeep: 'linear-gradient(135deg, var(--primary) 0%, var(--air-900) 100%)',\n desertMidnight:\n 'linear-gradient(135deg, var(--slate-500) 0%, var(--slate-700) 100%)',\n aqua: 'linear-gradient(135deg, var(--air-400) 0%, var(--air-600) 100%)',\n} as const;\n\n// ============================================\n// Compound Component (Dot Notation)\n// ============================================\n\nconst AppShell = Object.assign(AppShellRoot, {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Header: AppShellHeader,\n Panel: AppShellPanel,\n Content: AppShellContent,\n});\n\n// ============================================\n// Exports\n// ============================================\n\nexport type { AppShellContentProps } from './AppShellContent';\nexport type { AppShellPanelProps } from './AppShellPanel';\n\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n AppShell,\n AppShellContent,\n AppShellHeader,\n AppShellPanel,\n AppShellRoot,\n AppShellSidebar,\n appShellBackgrounds,\n};\n"],"mappings":"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"}
package/dist/index225.js CHANGED
@@ -27,7 +27,7 @@ function getSidebarBgClass(isCollapsed, sidebarBgColor) {
27
27
  return isCollapsed ? "bg-transparent" : sidebarBgColor ?? "bg-[var(--sidebar)]";
28
28
  }
29
29
  function getSidebarSurfaceClass({ isCollapsed, side, rounded, backgroundClass }) {
30
- return cn("flex h-full min-h-0 flex-col items-center pb-4 pt-6", isCollapsed ? "w-full px-6" : ["w-[calc(100%-0.75rem)] px-3", side === "left" ? "mr-3 self-start" : "ml-3 self-end"], backgroundClass, rounded && (side === "left" ? "rounded-r-lg" : "rounded-l-lg"));
30
+ return cn("flex h-full min-h-0 flex-col items-center pb-4 pt-6", isCollapsed ? "w-full px-2" : ["w-[calc(100%-0.75rem)] px-3", side === "left" ? "mr-3 self-start" : "ml-3 self-end"], backgroundClass, rounded && (side === "left" ? "rounded-r-lg" : "rounded-l-lg"));
31
31
  }
32
32
  function getSkeletonCount(count, fallback) {
33
33
  return typeof count === "number" && Number.isFinite(count) && count >= 0 ? Math.floor(count) : fallback;
@@ -676,7 +676,7 @@ function AppSidebarSkeleton({ navCount = 4, chatCount = 5, logo, compactedLogo,
676
676
  }),
677
677
  children: [
678
678
  /* @__PURE__ */ jsx(SidebarHeader, {
679
- className: "h-[68px] w-full p-2",
679
+ className: "h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0",
680
680
  children: /* @__PURE__ */ jsx(AppSidebarLogo, {
681
681
  logo,
682
682
  compactedLogo
@@ -743,7 +743,7 @@ function AppSidebarRoot({ logo, compactedLogo, logoSubtext, collapsible = "icon"
743
743
  }),
744
744
  children: [
745
745
  /* @__PURE__ */ jsx(SidebarHeader, {
746
- className: "h-[68px] w-full p-2",
746
+ className: "h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0",
747
747
  children: /* @__PURE__ */ jsx(AppSidebarLogo, {
748
748
  logo,
749
749
  compactedLogo,