@humain/ui 2.1.63 → 2.1.65

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 (160) hide show
  1. package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
  2. package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
  3. package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
  4. package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
  5. package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
  6. package/dist/index.js +52 -52
  7. package/dist/index151.js +1 -1
  8. package/dist/index174.js +7 -339
  9. package/dist/index174.js.map +1 -1
  10. package/dist/index175.js +310 -137
  11. package/dist/index175.js.map +1 -1
  12. package/dist/index176.js +148 -174
  13. package/dist/index176.js.map +1 -1
  14. package/dist/index177.js +186 -78
  15. package/dist/index177.js.map +1 -1
  16. package/dist/index178.js +74 -124
  17. package/dist/index178.js.map +1 -1
  18. package/dist/index179.js +133 -1
  19. package/dist/index179.js.map +1 -0
  20. package/dist/index180.js +2 -201
  21. package/dist/index181.js +201 -0
  22. package/dist/{index180.js.map → index181.js.map} +1 -1
  23. package/dist/index183.js +130 -166
  24. package/dist/index183.js.map +1 -1
  25. package/dist/index184.js +195 -983
  26. package/dist/index184.js.map +1 -1
  27. package/dist/index185.js +1069 -369
  28. package/dist/index185.js.map +1 -1
  29. package/dist/index186.js +395 -197
  30. package/dist/index186.js.map +1 -1
  31. package/dist/index187.js +198 -243
  32. package/dist/index187.js.map +1 -1
  33. package/dist/index188.js +263 -3
  34. package/dist/index188.js.map +1 -1
  35. package/dist/index189.js +3 -209
  36. package/dist/index189.js.map +1 -1
  37. package/dist/index190.js +190 -777
  38. package/dist/index190.js.map +1 -1
  39. package/dist/index191.js +771 -252
  40. package/dist/index191.js.map +1 -1
  41. package/dist/index192.js +250 -65
  42. package/dist/index192.js.map +1 -1
  43. package/dist/index193.js +72 -523
  44. package/dist/index193.js.map +1 -1
  45. package/dist/index194.js +537 -144
  46. package/dist/index194.js.map +1 -1
  47. package/dist/index195.js +139 -720
  48. package/dist/index195.js.map +1 -1
  49. package/dist/index196.js +707 -167
  50. package/dist/index196.js.map +1 -1
  51. package/dist/index197.js +175 -151
  52. package/dist/index197.js.map +1 -1
  53. package/dist/index198.js +152 -487
  54. package/dist/index198.js.map +1 -1
  55. package/dist/index199.js +472 -225
  56. package/dist/index199.js.map +1 -1
  57. package/dist/index200.js +236 -260
  58. package/dist/index200.js.map +1 -1
  59. package/dist/index201.js +265 -215
  60. package/dist/index201.js.map +1 -1
  61. package/dist/index202.js +207 -307
  62. package/dist/index202.js.map +1 -1
  63. package/dist/index203.js +302 -135
  64. package/dist/index203.js.map +1 -1
  65. package/dist/index204.js +140 -271
  66. package/dist/index204.js.map +1 -1
  67. package/dist/index205.js +263 -253
  68. package/dist/index205.js.map +1 -1
  69. package/dist/index206.js +244 -137
  70. package/dist/index206.js.map +1 -1
  71. package/dist/index207.js +100 -238
  72. package/dist/index207.js.map +1 -1
  73. package/dist/index208.js +278 -74
  74. package/dist/index208.js.map +1 -1
  75. package/dist/index209.js +56 -97
  76. package/dist/index209.js.map +1 -1
  77. package/dist/index210.js +142 -47
  78. package/dist/index210.js.map +1 -1
  79. package/dist/index211.js +38 -84
  80. package/dist/index211.js.map +1 -1
  81. package/dist/index212.js +72 -252
  82. package/dist/index212.js.map +1 -1
  83. package/dist/index213.js +274 -26
  84. package/dist/index213.js.map +1 -1
  85. package/dist/index214.js +29 -94
  86. package/dist/index214.js.map +1 -1
  87. package/dist/index215.js +98 -25
  88. package/dist/index215.js.map +1 -1
  89. package/dist/index216.js +20 -565
  90. package/dist/index216.js.map +1 -1
  91. package/dist/index217.js +564 -17
  92. package/dist/index217.js.map +1 -1
  93. package/dist/index218.js +20 -23
  94. package/dist/index218.js.map +1 -1
  95. package/dist/index219.js +20 -95
  96. package/dist/index219.js.map +1 -1
  97. package/dist/index220.js +92 -88
  98. package/dist/index220.js.map +1 -1
  99. package/dist/index221.js +97 -29
  100. package/dist/index221.js.map +1 -1
  101. package/dist/index222.js +24 -470
  102. package/dist/index222.js.map +1 -1
  103. package/dist/index223.js +446 -196
  104. package/dist/index223.js.map +1 -1
  105. package/dist/index224.js +199 -729
  106. package/dist/index224.js.map +1 -1
  107. package/dist/index225.js +750 -61
  108. package/dist/index225.js.map +1 -1
  109. package/dist/index226.js +58 -181
  110. package/dist/index226.js.map +1 -1
  111. package/dist/index227.js +175 -259
  112. package/dist/index227.js.map +1 -1
  113. package/dist/index228.js +246 -172
  114. package/dist/index228.js.map +1 -1
  115. package/dist/index229.js +195 -32
  116. package/dist/index229.js.map +1 -1
  117. package/dist/index230.js +12 -40
  118. package/dist/index230.js.map +1 -1
  119. package/dist/index231.js +23 -26
  120. package/dist/index231.js.map +1 -1
  121. package/dist/index232.js +45 -22
  122. package/dist/index232.js.map +1 -1
  123. package/dist/index233.js +27 -48
  124. package/dist/index233.js.map +1 -1
  125. package/dist/index234.js +52 -26
  126. package/dist/index234.js.map +1 -1
  127. package/dist/index235.js +40 -225
  128. package/dist/index235.js.map +1 -1
  129. package/dist/index236.js +217 -39
  130. package/dist/index236.js.map +1 -1
  131. package/dist/index237.js +50 -0
  132. package/dist/index237.js.map +1 -0
  133. package/dist/styles.css +1 -1
  134. package/dist/wc/AIToolCall.js +218 -0
  135. package/dist/wc/AIToolCall.js.map +1 -0
  136. package/dist/wc/hf-ai-tool-call.js +34 -219
  137. package/dist/wc/hf-ai-tool-call.js.map +1 -1
  138. package/dist/wc/hf-ai-tool-run.js +673 -576
  139. package/dist/wc/hf-ai-tool-run.js.map +1 -1
  140. package/dist/wc/workflow-step-renderer.js +79 -78
  141. package/dist/wc/workflow-step-renderer.js.map +1 -1
  142. package/dist/wc-react/AIToolCall.js +218 -0
  143. package/dist/wc-react/AIToolCall.js.map +1 -0
  144. package/dist/wc-react/hf-ai-tool-call.js +32 -217
  145. package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
  146. package/dist/wc-react/hf-ai-tool-run.js +698 -601
  147. package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
  148. package/dist/wc-react/workflow-step-renderer.js +58 -57
  149. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  150. package/package.json +1 -1
  151. package/skills/humain-ui/SKILL.md +1 -1
  152. package/skills/humain-ui-wc/SKILL.md +1 -1
  153. package/skills/humain-ui-wc.skill +0 -0
  154. package/skills/humain-ui.skill +0 -0
  155. package/dist/index182.js +0 -143
  156. package/dist/index182.js.map +0 -1
  157. package/dist/wc/wrench.js +0 -10
  158. package/dist/wc/wrench.js.map +0 -1
  159. package/dist/wc-react/wrench.js +0 -10
  160. package/dist/wc-react/wrench.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index202.js","names":[],"sources":["../src/components/organisms/layout/PageHeader/PageHeader.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowLeft, MoreHorizontal, Search } from 'lucide-react';\nimport * as React from 'react';\nimport { Button, type ButtonProps } from '@/components/atoms/buttons/Button';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport { Avatar, type AvatarProps } from '@/components/molecules/data/Avatar';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbHomeLink,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from '@/components/molecules/navigation/Breadcrumb';\nimport {\n DropdownMenu,\n type DropdownMenuItemProps,\n} from '@/components/organisms/menus/DropdownMenu';\nimport { cn } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Types\n * -------------------------------------------------------------------------- */\n\nexport interface BreadcrumbItemType {\n /** Display label for the breadcrumb */\n label: string;\n /** URL for the breadcrumb link */\n href?: string;\n /** Whether this is the current/active page */\n isCurrent?: boolean;\n}\n\nexport type PageHeaderActionButtonProps = Omit<\n ButtonProps,\n 'variant' | 'onClick' | 'children'\n>;\n\nexport type PageHeaderOverflowActionProps = Pick<\n DropdownMenuItemProps,\n | 'aria-describedby'\n | 'aria-label'\n | 'className'\n | 'disabled'\n | 'icon'\n | 'id'\n | 'title'\n> &\n Partial<Record<`data-${string}`, unknown>>;\n\nexport interface PageHeaderAction {\n /** Button label */\n label: string;\n /** Button variant */\n variant?: ButtonProps['variant'];\n /** Click handler */\n onClick?: () => void;\n /**\n * Additional props applied only when the action renders as a visible Button.\n * Use overflowProps for actions that move into the More actions menu.\n */\n buttonProps?: PageHeaderActionButtonProps;\n /**\n * Additional props applied only when the action renders as an overflow menu item.\n * Menu icons are intentionally explicit so button endIcon values do not become\n * misleading leading menu icons.\n */\n overflowProps?: PageHeaderOverflowActionProps;\n}\n\n/* -----------------------------------------------------------------------------\n * Variants\n * -------------------------------------------------------------------------- */\n\nconst pageHeaderVariants = cva('flex flex-col w-full', {\n variants: {\n variant: {\n simple: 'gap-5',\n avatar: 'gap-5',\n 'banner-avatar': 'gap-0',\n 'banner-simple': 'gap-0',\n 'banner-avatar-centered': 'gap-0',\n 'banner-simple-centered': 'gap-0',\n },\n },\n defaultVariants: {\n variant: 'simple',\n },\n});\n\nconst contentVariants = cva('flex flex-wrap items-start w-full', {\n variants: {\n variant: {\n simple: 'gap-4',\n avatar: 'gap-4 md:gap-5',\n 'banner-avatar': 'gap-4 md:gap-6',\n 'banner-simple': 'gap-4 md:gap-6',\n 'banner-avatar-centered':\n 'flex-col items-center text-center gap-4 md:gap-6',\n 'banner-simple-centered':\n 'flex-col items-center text-center gap-4 md:gap-6',\n },\n },\n defaultVariants: {\n variant: 'simple',\n },\n});\n\nconst bannerVariants = cva(\n 'relative w-full overflow-hidden bg-gradient-to-br from-secondary to-muted',\n {\n variants: {\n variant: {\n default: 'h-40 md:h-60', // 160px mobile, 240px desktop\n centered: 'h-40 md:h-60',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nconst MAX_VISIBLE_HEADER_ACTIONS = 2;\n\ntype IndexedPageHeaderAction = PageHeaderAction & {\n originalIndex: number;\n};\n\nfunction getPageHeaderActionVariant(\n action: PageHeaderAction,\n index: number,\n actionCount: number,\n): ButtonProps['variant'] {\n return (\n action.variant ?? (index === actionCount - 1 ? 'primary' : 'secondary')\n );\n}\n\nfunction isPriorityHeaderAction(\n action: IndexedPageHeaderAction,\n actionCount: number,\n): boolean {\n return (\n getPageHeaderActionVariant(action, action.originalIndex, actionCount) ===\n 'primary'\n );\n}\n\nfunction splitPageHeaderActions(actions: PageHeaderAction[]): {\n visibleActions: IndexedPageHeaderAction[];\n overflowActions: IndexedPageHeaderAction[];\n} {\n const indexedActions = actions.map((action, originalIndex) => ({\n ...action,\n originalIndex,\n }));\n\n if (indexedActions.length <= MAX_VISIBLE_HEADER_ACTIONS) {\n return {\n visibleActions: indexedActions,\n overflowActions: [],\n };\n }\n\n const defaultVisibleActions = indexedActions.slice(\n 0,\n MAX_VISIBLE_HEADER_ACTIONS,\n );\n\n if (\n defaultVisibleActions.some((action) =>\n isPriorityHeaderAction(action, indexedActions.length),\n )\n ) {\n return {\n visibleActions: defaultVisibleActions,\n overflowActions: indexedActions.slice(MAX_VISIBLE_HEADER_ACTIONS),\n };\n }\n\n const priorityAction = [...indexedActions]\n .reverse()\n .find((action) => isPriorityHeaderAction(action, indexedActions.length));\n\n if (!priorityAction) {\n return {\n visibleActions: defaultVisibleActions,\n overflowActions: indexedActions.slice(MAX_VISIBLE_HEADER_ACTIONS),\n };\n }\n\n const visibleActions = [indexedActions[0], priorityAction].sort(\n (left, right) => left.originalIndex - right.originalIndex,\n );\n const visibleIndexes = new Set(\n visibleActions.map((action) => action.originalIndex),\n );\n\n return {\n visibleActions,\n overflowActions: indexedActions.filter(\n (action) => !visibleIndexes.has(action.originalIndex),\n ),\n };\n}\n\nfunction getOverflowActionItemProps(\n action: PageHeaderAction,\n): Partial<PageHeaderOverflowActionProps> {\n const disabled = Boolean(\n action.overflowProps?.disabled ||\n action.buttonProps?.disabled ||\n action.buttonProps?.loading,\n );\n\n return {\n ...action.overflowProps,\n disabled,\n };\n}\n\n/* -----------------------------------------------------------------------------\n * PageHeader Component\n * -------------------------------------------------------------------------- */\n\nexport interface PageHeaderProps\n extends VariantProps<typeof pageHeaderVariants> {\n /** Page title */\n title: string;\n /** Supporting text/description */\n supportingText?: string;\n /** Breadcrumb items for desktop navigation */\n breadcrumbs?: BreadcrumbItemType[];\n /** Action buttons */\n actions?: PageHeaderAction[];\n /** Search placeholder text - enables search input when provided */\n searchPlaceholder?: string;\n /** Keyboard shortcut to display in search input */\n searchShortcut?: string;\n /** Search callback */\n onSearch?: (value: string) => void;\n /** Show bottom divider */\n showDivider?: boolean;\n /** Avatar props for avatar variants */\n avatarSrc?: string;\n /** Avatar fallback text (e.g., name for initials) */\n avatarFallback?: string;\n /** Avatar indicator */\n avatarStatusIcon?: AvatarProps['indicator'];\n /** Back button click handler (mobile) */\n onBackClick?: () => void;\n /** Back button label (mobile) */\n backLabel?: string;\n /** Additional className */\n className?: string;\n}\n\nfunction PageHeaderBreadcrumbs({\n breadcrumbs,\n}: {\n breadcrumbs: PageHeaderProps['breadcrumbs'];\n}) {\n if (!breadcrumbs || breadcrumbs.length === 0) return null;\n\n return (\n <Breadcrumb className=\"hidden md:flex delight-fade-in motion-reduce:!animate-none\">\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbHomeLink href=\"/\" />\n </BreadcrumbItem>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const hasEllipsis = breadcrumbs.length > 3;\n\n if (hasEllipsis && index === 1) {\n return (\n <React.Fragment key={`ellipsis-${index}`}>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbEllipsis />\n </BreadcrumbItem>\n </React.Fragment>\n );\n }\n\n if (hasEllipsis && index > 1 && !isLast) {\n return null;\n }\n\n return (\n <React.Fragment key={item.label}>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n {isLast || item.isCurrent ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n\nfunction PageHeaderBackButton({\n breadcrumbs,\n onBackClick,\n backLabel,\n}: {\n breadcrumbs: PageHeaderProps['breadcrumbs'];\n onBackClick?: () => void;\n backLabel: string;\n}) {\n if (!onBackClick || !breadcrumbs || breadcrumbs.length === 0) return null;\n\n return (\n <Button\n appearance=\"link\"\n variant=\"primary\"\n size=\"sm\"\n startIcon={<ArrowLeft className=\"size-5\" />}\n onClick={onBackClick}\n aria-label={`Go back: ${backLabel}`}\n className=\"md:hidden text-secondary-foreground px-0 hover:no-underline\"\n >\n {backLabel}\n </Button>\n );\n}\n\nfunction PageHeaderActions({\n actions,\n}: {\n actions: PageHeaderProps['actions'];\n}) {\n if (!actions || actions.length === 0) return null;\n\n const { visibleActions, overflowActions } = splitPageHeaderActions(actions);\n\n return (\n <div\n className=\"flex items-center gap-3 delight-stagger motion-reduce:!animate-none\"\n style={{ '--delight-delay': '120ms' } as React.CSSProperties}\n >\n {visibleActions.map((action) => (\n <Button\n key={`${action.label}-${action.originalIndex}`}\n variant={\n action.variant ??\n getPageHeaderActionVariant(\n action,\n action.originalIndex,\n actions.length,\n )\n }\n onClick={action.onClick}\n {...action.buttonProps}\n >\n {action.label}\n </Button>\n ))}\n {overflowActions.length > 0 && (\n <DropdownMenu>\n <DropdownMenu.Trigger\n render={\n <Button appearance=\"ghost\" size=\"icon\" aria-label=\"More actions\">\n <MoreHorizontal className=\"size-5\" />\n </Button>\n }\n />\n <DropdownMenu.Popup align=\"end\" sideOffset={4}>\n <DropdownMenu.Items>\n {overflowActions.map((action) => (\n <DropdownMenu.Item\n key={`${action.label}-${action.originalIndex}`}\n {...getOverflowActionItemProps(action)}\n onClick={action.onClick}\n variant={\n action.variant === 'destructive' ? 'destructive' : 'default'\n }\n >\n {action.label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Items>\n </DropdownMenu.Popup>\n </DropdownMenu>\n )}\n </div>\n );\n}\n\nfunction PageHeaderSearch({\n searchId,\n searchPlaceholder,\n searchShortcut,\n onSearch,\n}: {\n searchId: string;\n searchPlaceholder?: string;\n searchShortcut?: string;\n onSearch?: (query: string) => void;\n}) {\n if (!searchPlaceholder) return null;\n\n return (\n <search\n className=\"relative flex-1 min-w-0 max-w-xs delight-stagger motion-reduce:!animate-none\"\n style={{ '--delight-delay': '180ms' } as React.CSSProperties}\n >\n <div className=\"group/search relative\">\n <Search\n className=\"absolute start-3 top-1/2 -translate-y-1/2 size-5 text-text-quaternary pointer-events-none transition-colors duration-150 group-focus-within/search:text-primary motion-reduce:transition-none\"\n aria-hidden=\"true\"\n />\n <input\n id={searchId}\n type=\"text\"\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n onChange={(e) => onSearch?.(e.target.value)}\n className={cn(\n 'peer w-full rounded-lg border border-border bg-background py-2.5 pe-10 ps-10',\n 'text-base text-foreground placeholder:text-muted-foreground',\n 'shadow-xs transition-[border-color,box-shadow] duration-150 motion-reduce:transition-none',\n 'focus-visible:border-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary',\n )}\n />\n {searchShortcut && (\n <Kbd\n variant=\"outline\"\n size=\"xs\"\n className=\"absolute end-3 top-1/2 -translate-y-1/2 transition-opacity duration-150 peer-focus-visible:opacity-0 motion-reduce:transition-none\"\n aria-hidden=\"true\"\n >\n {searchShortcut}\n </Kbd>\n )}\n </div>\n </search>\n );\n}\n\nfunction getPageHeaderInitials(name?: string) {\n if (!name) return '';\n const words = name.split(' ').filter(Boolean);\n if (words.length >= 2) {\n return `${words[0][0]}${words[1][0]}`.toUpperCase();\n }\n return name.slice(0, 2).toUpperCase();\n}\n\nfunction PageHeaderAvatar({\n hasAvatar,\n isBanner,\n avatarSrc,\n avatarFallback,\n avatarStatusIcon,\n}: {\n hasAvatar: boolean;\n isBanner: boolean;\n avatarSrc?: string;\n avatarFallback?: string;\n avatarStatusIcon: PageHeaderProps['avatarStatusIcon'];\n}) {\n if (!hasAvatar) return null;\n\n if (isBanner) {\n return (\n <div\n className={cn(\n 'relative shrink-0 rounded-full ring-4 ring-bg-primary shadow-lg',\n 'size-24 md:size-40',\n 'delight-fade-in motion-reduce:!animate-none',\n )}\n >\n {avatarSrc ? (\n <img\n src={avatarSrc}\n alt={avatarFallback || ''}\n className=\"size-full rounded-full object-cover\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center rounded-full bg-accent text-2xl font-semibold text-muted-foreground md:text-4xl\">\n {getPageHeaderInitials(avatarFallback)}\n </div>\n )}\n {avatarStatusIcon === 'verified' && (\n <div className=\"absolute bottom-0 end-0 flex size-6 items-center justify-center rounded-full border-2 border-primary bg-primary/10 md:size-10\">\n <svg\n className=\"size-3 text-primary md:size-5\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <title>Verified</title>\n <path\n fillRule=\"evenodd\"\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n )}\n </div>\n );\n }\n\n return (\n <Avatar\n src={avatarSrc}\n fallback={avatarFallback}\n alt={avatarFallback}\n size=\"xl\"\n indicator={avatarStatusIcon}\n />\n );\n}\n\nfunction PageHeaderTextContent({\n title,\n supportingText,\n isCentered,\n}: {\n title: React.ReactNode;\n supportingText?: string;\n isCentered: boolean;\n}) {\n return (\n <div\n className={cn(\n 'flex flex-col min-w-0',\n isCentered ? 'items-center' : 'flex-1',\n )}\n >\n <h1\n className=\"text-xl font-semibold text-foreground leading-relaxed delight-stagger motion-reduce:!animate-none\"\n style={{ '--delight-delay': '0ms' } as React.CSSProperties}\n >\n {title}\n </h1>\n {supportingText && (\n <p\n className=\"text-base text-muted-foreground leading-6 max-w-prose delight-stagger motion-reduce:!animate-none\"\n style={{ '--delight-delay': '60ms' } as React.CSSProperties}\n >\n {supportingText}\n </p>\n )}\n </div>\n );\n}\n\nconst PageHeader = React.forwardRef<HTMLElement, PageHeaderProps>(\n (\n {\n variant = 'simple',\n title,\n supportingText,\n breadcrumbs,\n actions,\n searchPlaceholder,\n searchShortcut = '⌘K',\n onSearch,\n showDivider = true,\n avatarSrc,\n avatarFallback,\n avatarStatusIcon = 'verified',\n onBackClick,\n backLabel = 'Back',\n className,\n },\n ref,\n ) => {\n const searchId = React.useId();\n const resolvedVariant = variant ?? 'simple';\n const isBanner = resolvedVariant.startsWith('banner');\n const isCentered = resolvedVariant.includes('centered');\n const hasAvatar = resolvedVariant.includes('avatar');\n\n // Banner variants\n if (isBanner) {\n return (\n <header\n ref={ref}\n data-slot=\"page-header\"\n className={cn(\n pageHeaderVariants({ variant: resolvedVariant }),\n className,\n )}\n >\n {/* Banner image area with avatar overlap */}\n <div className=\"relative\">\n <div\n className={bannerVariants({\n variant: isCentered ? 'centered' : 'default',\n })}\n aria-hidden=\"true\"\n />\n\n {/* Avatar positioned to overlap banner bottom */}\n {hasAvatar && (\n <div\n className={cn(\n 'absolute inset-x-0 px-4 md:px-8',\n // Position avatar to overlap banner: -48px mobile, -40px desktop from bottom\n '-bottom-12 md:-bottom-20',\n isCentered && 'flex justify-center',\n )}\n >\n <PageHeaderAvatar\n hasAvatar={hasAvatar}\n isBanner={isBanner}\n avatarSrc={avatarSrc}\n avatarFallback={avatarFallback}\n avatarStatusIcon={avatarStatusIcon}\n />\n </div>\n )}\n </div>\n\n {/* Main content below banner */}\n <div\n className={cn(\n 'px-4 md:px-8',\n // Padding top to account for avatar overlap: 64px mobile, 96px desktop\n hasAvatar ? 'pt-16 md:pt-24' : 'pt-6',\n isCentered && 'flex flex-col items-center',\n )}\n >\n {/* Back button for mobile */}\n <div className=\"md:hidden mb-4\">\n <PageHeaderBackButton\n breadcrumbs={breadcrumbs}\n onBackClick={onBackClick}\n backLabel={backLabel}\n />\n </div>\n\n {/* Breadcrumbs for desktop */}\n {!isCentered && (\n <div className=\"hidden md:block\">\n <PageHeaderBreadcrumbs breadcrumbs={breadcrumbs} />\n </div>\n )}\n\n <div\n className={cn(\n contentVariants({ variant: resolvedVariant }),\n 'mt-4 md:mt-6',\n )}\n >\n {/* Text content */}\n <PageHeaderTextContent\n title={title}\n supportingText={supportingText}\n isCentered={isCentered}\n />\n\n {/* Actions */}\n <PageHeaderActions actions={actions} />\n\n {/* Search */}\n <PageHeaderSearch\n searchId={searchId}\n searchPlaceholder={searchPlaceholder}\n searchShortcut={searchShortcut}\n onSearch={onSearch}\n />\n </div>\n </div>\n\n {/* Divider */}\n {showDivider && (\n <Separator className=\"mt-5 delight-connector-fill motion-reduce:!animate-none\" />\n )}\n </header>\n );\n }\n\n // Non-banner variants (simple, avatar)\n return (\n <header\n ref={ref}\n data-slot=\"page-header\"\n className={cn(\n pageHeaderVariants({ variant: resolvedVariant }),\n className,\n )}\n >\n {/* Navigation: Breadcrumbs (desktop) / Back button (mobile) */}\n {breadcrumbs && breadcrumbs.length > 0 && (\n <div>\n <PageHeaderBreadcrumbs breadcrumbs={breadcrumbs} />\n <PageHeaderBackButton\n breadcrumbs={breadcrumbs}\n onBackClick={onBackClick}\n backLabel={backLabel}\n />\n </div>\n )}\n\n {/* Main content */}\n <div className={cn(contentVariants({ variant: resolvedVariant }))}>\n {/* Avatar + Text group */}\n <div\n className={cn(\n 'flex gap-4 items-center flex-1 min-w-0',\n hasAvatar && 'flex-row',\n )}\n >\n <PageHeaderAvatar\n hasAvatar={hasAvatar}\n isBanner={isBanner}\n avatarSrc={avatarSrc}\n avatarFallback={avatarFallback}\n avatarStatusIcon={avatarStatusIcon}\n />\n <PageHeaderTextContent\n title={title}\n supportingText={supportingText}\n isCentered={isCentered}\n />\n </div>\n\n {/* Actions */}\n <PageHeaderActions actions={actions} />\n\n {/* Search */}\n <PageHeaderSearch\n searchId={searchId}\n searchPlaceholder={searchPlaceholder}\n searchShortcut={searchShortcut}\n onSearch={onSearch}\n />\n </div>\n\n {/* Divider */}\n {showDivider && (\n <Separator className=\"delight-connector-fill motion-reduce:!animate-none\" />\n )}\n </header>\n );\n },\n);\n\nPageHeader.displayName = 'PageHeader';\n\nexport { bannerVariants, contentVariants, PageHeader, pageHeaderVariants };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index202.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'\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/index203.js CHANGED
@@ -1,165 +1,332 @@
1
- "use client";
2
1
  import { cn } from "./index2.js";
3
2
  import { Button } from "./index5.js";
4
- import { ButtonGroup as ButtonGroupCompound } from "./index8.js";
5
- import { Input } from "./index33.js";
6
3
  import { Separator } from "./index51.js";
7
- import { Tabs } from "./index137.js";
8
- import { Search } from "lucide-react";
4
+ import { Avatar } from "./index70.js";
5
+ import { Kbd } from "./index106.js";
6
+ import { Breadcrumb as BreadcrumbCompound, BreadcrumbEllipsis, BreadcrumbHomeLink, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "./index131.js";
7
+ import { DropdownMenu } from "./index192.js";
8
+ import { cva } from "class-variance-authority";
9
+ import { ArrowLeft, MoreHorizontal, Search } from "lucide-react";
9
10
  import * as React from "react";
10
11
  import { jsx, jsxs } from "react/jsx-runtime";
11
- //#region src/components/organisms/layout/SectionHeader/SectionHeader.tsx
12
- var controlTouchTargetClassName = "min-h-11 min-w-11 shrink-0";
13
- function getHeadingTag(headingLevel) {
14
- return `h${headingLevel}`;
12
+ //#region src/components/organisms/layout/PageHeader/PageHeader.tsx
13
+ var pageHeaderVariants = cva("flex flex-col w-full", {
14
+ variants: { variant: {
15
+ simple: "gap-5",
16
+ avatar: "gap-5",
17
+ "banner-avatar": "gap-0",
18
+ "banner-simple": "gap-0",
19
+ "banner-avatar-centered": "gap-0",
20
+ "banner-simple-centered": "gap-0"
21
+ } },
22
+ defaultVariants: { variant: "simple" }
23
+ });
24
+ var contentVariants = cva("flex flex-wrap items-start w-full", {
25
+ variants: { variant: {
26
+ simple: "gap-4",
27
+ avatar: "gap-4 md:gap-5",
28
+ "banner-avatar": "gap-4 md:gap-6",
29
+ "banner-simple": "gap-4 md:gap-6",
30
+ "banner-avatar-centered": "flex-col items-center text-center gap-4 md:gap-6",
31
+ "banner-simple-centered": "flex-col items-center text-center gap-4 md:gap-6"
32
+ } },
33
+ defaultVariants: { variant: "simple" }
34
+ });
35
+ var bannerVariants = cva("relative w-full overflow-hidden bg-gradient-to-br from-secondary to-muted", {
36
+ variants: { variant: {
37
+ default: "h-40 md:h-60",
38
+ centered: "h-40 md:h-60"
39
+ } },
40
+ defaultVariants: { variant: "default" }
41
+ });
42
+ var MAX_VISIBLE_HEADER_ACTIONS = 2;
43
+ function getPageHeaderActionVariant(action, index, actionCount) {
44
+ return action.variant ?? (index === actionCount - 1 ? "primary" : "secondary");
15
45
  }
16
- function SectionHeaderTouchTargetControl({ control }) {
17
- if (React.isValidElement(control)) return React.cloneElement(control, { className: cn(control.props.className, controlTouchTargetClassName) });
18
- return /* @__PURE__ */ jsx("span", {
19
- className: cn("inline-flex items-center justify-center", controlTouchTargetClassName),
20
- children: control
21
- });
46
+ function isPriorityHeaderAction(action, actionCount) {
47
+ return getPageHeaderActionVariant(action, action.originalIndex, actionCount) === "primary";
22
48
  }
23
- function getSectionHeaderActionKey(action, index, prefix = "section-header-action") {
24
- return typeof action.label === "string" ? `${action.label}-${index}` : `${prefix}-${index}`;
49
+ function splitPageHeaderActions(actions) {
50
+ const indexedActions = actions.map((action, originalIndex) => ({
51
+ ...action,
52
+ originalIndex
53
+ }));
54
+ if (indexedActions.length <= MAX_VISIBLE_HEADER_ACTIONS) return {
55
+ visibleActions: indexedActions,
56
+ overflowActions: []
57
+ };
58
+ const defaultVisibleActions = indexedActions.slice(0, MAX_VISIBLE_HEADER_ACTIONS);
59
+ if (defaultVisibleActions.some((action) => isPriorityHeaderAction(action, indexedActions.length))) return {
60
+ visibleActions: defaultVisibleActions,
61
+ overflowActions: indexedActions.slice(MAX_VISIBLE_HEADER_ACTIONS)
62
+ };
63
+ const priorityAction = [...indexedActions].reverse().find((action) => isPriorityHeaderAction(action, indexedActions.length));
64
+ if (!priorityAction) return {
65
+ visibleActions: defaultVisibleActions,
66
+ overflowActions: indexedActions.slice(MAX_VISIBLE_HEADER_ACTIONS)
67
+ };
68
+ const visibleActions = [indexedActions[0], priorityAction].sort((left, right) => left.originalIndex - right.originalIndex);
69
+ const visibleIndexes = new Set(visibleActions.map((action) => action.originalIndex));
70
+ return {
71
+ visibleActions,
72
+ overflowActions: indexedActions.filter((action) => !visibleIndexes.has(action.originalIndex))
73
+ };
25
74
  }
26
- function SectionHeaderActionButton({ action, className }) {
27
- const { label, className: actionClassName, ...buttonProps } = action;
28
- return /* @__PURE__ */ jsx(Button, {
29
- appearance: "solid",
30
- size: "default",
31
- shape: "rounded",
32
- className: cn("h-10 rounded-xl px-2 text-xs font-medium", actionClassName, className),
33
- ...buttonProps,
34
- children: label
75
+ function getOverflowActionItemProps(action) {
76
+ const disabled = Boolean(action.overflowProps?.disabled || action.buttonProps?.disabled || action.buttonProps?.loading);
77
+ return {
78
+ ...action.overflowProps,
79
+ disabled
80
+ };
81
+ }
82
+ function PageHeaderBreadcrumbs({ breadcrumbs }) {
83
+ if (!breadcrumbs || breadcrumbs.length === 0) return null;
84
+ return /* @__PURE__ */ jsx(BreadcrumbCompound, {
85
+ className: "hidden md:flex delight-fade-in motion-reduce:!animate-none",
86
+ children: /* @__PURE__ */ jsxs(BreadcrumbList, { children: [/* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx(BreadcrumbHomeLink, { href: "/" }) }), breadcrumbs.map((item, index) => {
87
+ const isLast = index === breadcrumbs.length - 1;
88
+ const hasEllipsis = breadcrumbs.length > 3;
89
+ if (hasEllipsis && index === 1) return /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx(BreadcrumbEllipsis, {}) })] }, `ellipsis-${index}`);
90
+ if (hasEllipsis && index > 1 && !isLast) return null;
91
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, { children: isLast || item.isCurrent ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
92
+ href: item.href,
93
+ children: item.label
94
+ }) })] }, item.label);
95
+ })] })
35
96
  });
36
97
  }
37
- function SectionHeaderButtonGroup({ actions }) {
38
- return /* @__PURE__ */ jsx(ButtonGroupCompound, {
39
- "aria-label": "Section header controls",
40
- shape: "rounded",
41
- className: "overflow-hidden rounded-xl",
42
- children: actions.map((action, index) => {
43
- const { label, className, ...buttonProps } = action;
44
- return /* @__PURE__ */ jsx(Button, {
45
- appearance: buttonProps.appearance ?? "soft",
46
- variant: buttonProps.variant ?? "primary",
47
- size: "md",
48
- shape: "rounded",
49
- className: cn("border-transparent px-3 text-xs font-medium shadow-none", className),
50
- ...buttonProps,
51
- children: label
52
- }, getSectionHeaderActionKey(action, index, "section-header-group-action"));
53
- })
98
+ function PageHeaderBackButton({ breadcrumbs, onBackClick, backLabel }) {
99
+ if (!onBackClick || !breadcrumbs || breadcrumbs.length === 0) return null;
100
+ return /* @__PURE__ */ jsx(Button, {
101
+ appearance: "link",
102
+ variant: "primary",
103
+ size: "sm",
104
+ startIcon: /* @__PURE__ */ jsx(ArrowLeft, { className: "size-5" }),
105
+ onClick: onBackClick,
106
+ "aria-label": `Go back: ${backLabel}`,
107
+ className: "md:hidden text-secondary-foreground px-0 hover:no-underline",
108
+ children: backLabel
54
109
  });
55
110
  }
56
- function getTabValue(tab, index) {
57
- if (tab.value !== void 0) return tab.value;
58
- if (typeof tab.label === "string") return `${tab.label}-${index}`;
59
- return `section-header-tab-${index}`;
111
+ function PageHeaderActions({ actions }) {
112
+ if (!actions || actions.length === 0) return null;
113
+ const { visibleActions, overflowActions } = splitPageHeaderActions(actions);
114
+ return /* @__PURE__ */ jsxs("div", {
115
+ className: "flex items-center gap-3 delight-stagger motion-reduce:!animate-none",
116
+ style: { "--delight-delay": "120ms" },
117
+ children: [visibleActions.map((action) => /* @__PURE__ */ jsx(Button, {
118
+ variant: action.variant ?? getPageHeaderActionVariant(action, action.originalIndex, actions.length),
119
+ onClick: action.onClick,
120
+ ...action.buttonProps,
121
+ children: action.label
122
+ }, `${action.label}-${action.originalIndex}`)), overflowActions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenu.Trigger, { render: /* @__PURE__ */ jsx(Button, {
123
+ appearance: "ghost",
124
+ size: "icon",
125
+ "aria-label": "More actions",
126
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-5" })
127
+ }) }), /* @__PURE__ */ jsx(DropdownMenu.Popup, {
128
+ align: "end",
129
+ sideOffset: 4,
130
+ children: /* @__PURE__ */ jsx(DropdownMenu.Items, { children: overflowActions.map((action) => /* @__PURE__ */ jsx(DropdownMenu.Item, {
131
+ ...getOverflowActionItemProps(action),
132
+ onClick: action.onClick,
133
+ variant: action.variant === "destructive" ? "destructive" : "default",
134
+ children: action.label
135
+ }, `${action.label}-${action.originalIndex}`)) })
136
+ })] })]
137
+ });
60
138
  }
61
- function SectionHeaderTabs({ tabs }) {
62
- const tabValues = tabs.map((tab, index) => getTabValue(tab, index));
63
- const tabListKey = JSON.stringify(tabValues);
64
- const activeIndex = tabs.findIndex((tab) => tab.active);
65
- const activeValue = activeIndex >= 0 ? tabValues[activeIndex] : void 0;
66
- return /* @__PURE__ */ jsx(Tabs, {
67
- value: activeValue,
68
- defaultValue: activeValue ?? tabValues[0],
69
- className: "w-full",
70
- children: /* @__PURE__ */ jsx(Tabs.List, {
71
- variant: "boxed",
72
- size: "sm",
73
- align: "stretch",
74
- "aria-label": "Section header tabs",
75
- className: "w-full overflow-x-auto overflow-y-hidden rounded-[8px] border border-border bg-card p-1 shadow-sm",
76
- children: tabs.map((tab, index) => {
77
- const value = tabValues[index];
78
- return /* @__PURE__ */ jsx(Tabs.Trigger, {
79
- value,
80
- icon: tab.leadingIcon,
81
- className: "min-w-max flex-1 rounded-[10px] px-3 py-1",
82
- onClick: tab.onClick,
83
- children: /* @__PURE__ */ jsx("span", {
84
- className: "whitespace-nowrap",
85
- children: tab.label
86
- })
87
- }, value);
88
- })
139
+ function PageHeaderSearch({ searchId, searchPlaceholder, searchShortcut, onSearch }) {
140
+ if (!searchPlaceholder) return null;
141
+ return /* @__PURE__ */ jsx("search", {
142
+ className: "relative flex-1 min-w-0 max-w-xs delight-stagger motion-reduce:!animate-none",
143
+ style: { "--delight-delay": "180ms" },
144
+ children: /* @__PURE__ */ jsxs("div", {
145
+ className: "group/search relative",
146
+ children: [
147
+ /* @__PURE__ */ jsx(Search, {
148
+ className: "absolute start-3 top-1/2 -translate-y-1/2 size-5 text-text-quaternary pointer-events-none transition-colors duration-150 group-focus-within/search:text-primary motion-reduce:transition-none",
149
+ "aria-hidden": "true"
150
+ }),
151
+ /* @__PURE__ */ jsx("input", {
152
+ id: searchId,
153
+ type: "text",
154
+ placeholder: searchPlaceholder,
155
+ "aria-label": searchPlaceholder,
156
+ onChange: (e) => onSearch?.(e.target.value),
157
+ className: cn("peer w-full rounded-lg border border-border bg-background py-2.5 pe-10 ps-10", "text-base text-foreground placeholder:text-muted-foreground", "shadow-xs transition-[border-color,box-shadow] duration-150 motion-reduce:transition-none", "focus-visible:border-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary")
158
+ }),
159
+ searchShortcut && /* @__PURE__ */ jsx(Kbd, {
160
+ variant: "outline",
161
+ size: "xs",
162
+ className: "absolute end-3 top-1/2 -translate-y-1/2 transition-opacity duration-150 peer-focus-visible:opacity-0 motion-reduce:transition-none",
163
+ "aria-hidden": "true",
164
+ children: searchShortcut
165
+ })
166
+ ]
89
167
  })
90
- }, tabListKey);
168
+ });
91
169
  }
92
- function SectionHeaderControls({ actions, buttonGroup, search }) {
93
- return /* @__PURE__ */ jsxs(React.Fragment, { children: [
94
- search ? /* @__PURE__ */ jsx(SectionHeaderSearchField, { search }) : null,
95
- buttonGroup?.length ? /* @__PURE__ */ jsx(SectionHeaderButtonGroup, { actions: buttonGroup }) : null,
96
- actions?.length ? /* @__PURE__ */ jsx("div", {
97
- className: "flex flex-wrap items-center gap-3 md:flex-nowrap",
98
- children: actions.map((action, index) => /* @__PURE__ */ jsx(SectionHeaderActionButton, { action }, getSectionHeaderActionKey(action, index)))
99
- }) : null
100
- ] });
170
+ function getPageHeaderInitials(name) {
171
+ if (!name) return "";
172
+ const words = name.split(" ").filter(Boolean);
173
+ if (words.length >= 2) return `${words[0][0]}${words[1][0]}`.toUpperCase();
174
+ return name.slice(0, 2).toUpperCase();
101
175
  }
102
- function SectionHeaderSearchField({ search }) {
103
- const { className: searchClassName, placeholder, ariaLabel, filterButton, ...searchProps } = search;
104
- const searchInput = /* @__PURE__ */ jsx(Input, {
105
- size: "md",
106
- shape: "rounded",
107
- "aria-label": ariaLabel ?? "Search",
108
- placeholder: placeholder ?? "Search",
109
- startIcon: /* @__PURE__ */ jsx(Search, { className: "size-4" }),
110
- className: cn(filterButton ? "min-w-0 flex-1" : "w-full max-w-[320px]", searchClassName),
111
- ...searchProps
176
+ function PageHeaderAvatar({ hasAvatar, isBanner, avatarSrc, avatarFallback, avatarStatusIcon }) {
177
+ if (!hasAvatar) return null;
178
+ if (isBanner) return /* @__PURE__ */ jsxs("div", {
179
+ className: cn("relative shrink-0 rounded-full ring-4 ring-bg-primary shadow-lg", "size-24 md:size-40", "delight-fade-in motion-reduce:!animate-none"),
180
+ children: [avatarSrc ? /* @__PURE__ */ jsx("img", {
181
+ src: avatarSrc,
182
+ alt: avatarFallback || "",
183
+ className: "size-full rounded-full object-cover"
184
+ }) : /* @__PURE__ */ jsx("div", {
185
+ className: "flex size-full items-center justify-center rounded-full bg-accent text-2xl font-semibold text-muted-foreground md:text-4xl",
186
+ children: getPageHeaderInitials(avatarFallback)
187
+ }), avatarStatusIcon === "verified" && /* @__PURE__ */ jsx("div", {
188
+ className: "absolute bottom-0 end-0 flex size-6 items-center justify-center rounded-full border-2 border-primary bg-primary/10 md:size-10",
189
+ children: /* @__PURE__ */ jsxs("svg", {
190
+ className: "size-3 text-primary md:size-5",
191
+ fill: "currentColor",
192
+ viewBox: "0 0 20 20",
193
+ "aria-hidden": "true",
194
+ children: [/* @__PURE__ */ jsx("title", { children: "Verified" }), /* @__PURE__ */ jsx("path", {
195
+ fillRule: "evenodd",
196
+ d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
197
+ clipRule: "evenodd"
198
+ })]
199
+ })
200
+ })]
112
201
  });
113
- if (filterButton) return /* @__PURE__ */ jsxs("div", {
114
- "data-slot": "section-header-search",
115
- className: "flex w-full max-w-[376px] items-center gap-2",
116
- children: [searchInput, /* @__PURE__ */ jsx(SectionHeaderTouchTargetControl, { control: filterButton })]
202
+ return /* @__PURE__ */ jsx(Avatar, {
203
+ src: avatarSrc,
204
+ fallback: avatarFallback,
205
+ alt: avatarFallback,
206
+ size: "xl",
207
+ indicator: avatarStatusIcon
117
208
  });
118
- return searchInput;
119
209
  }
120
- var SectionHeader = React.forwardRef(({ title, supportingText, size = "md", headingLevel = 2, actions, buttonGroup, search, tabs, menuButton = null, showDivider = true, className, ...props }, ref) => {
121
- const hasSearch = Boolean(search);
122
- const hasButtonGroup = Boolean(buttonGroup?.length);
123
- const hasActions = Boolean(actions?.length);
124
- const hasInlineControls = hasSearch || hasButtonGroup || hasActions;
125
- const hasHeaderControls = hasInlineControls || Boolean(menuButton);
126
- const HeadingTag = getHeadingTag(headingLevel);
210
+ function PageHeaderTextContent({ title, supportingText, isCentered }) {
211
+ return /* @__PURE__ */ jsxs("div", {
212
+ className: cn("flex flex-col min-w-0", isCentered ? "items-center" : "flex-1"),
213
+ children: [/* @__PURE__ */ jsx("h1", {
214
+ className: "text-xl font-semibold text-foreground leading-relaxed delight-stagger motion-reduce:!animate-none",
215
+ style: { "--delight-delay": "0ms" },
216
+ children: title
217
+ }), supportingText && /* @__PURE__ */ jsx("p", {
218
+ className: "text-base text-muted-foreground leading-6 max-w-prose delight-stagger motion-reduce:!animate-none",
219
+ style: { "--delight-delay": "60ms" },
220
+ children: supportingText
221
+ })]
222
+ });
223
+ }
224
+ var PageHeader = React.forwardRef(({ variant = "simple", title, supportingText, breadcrumbs, actions, searchPlaceholder, searchShortcut = "⌘K", onSearch, showDivider = true, avatarSrc, avatarFallback, avatarStatusIcon = "verified", onBackClick, backLabel = "Back", className }, ref) => {
225
+ const searchId = React.useId();
226
+ const resolvedVariant = variant ?? "simple";
227
+ const isBanner = resolvedVariant.startsWith("banner");
228
+ const isCentered = resolvedVariant.includes("centered");
229
+ const hasAvatar = resolvedVariant.includes("avatar");
230
+ if (isBanner) return /* @__PURE__ */ jsxs("header", {
231
+ ref,
232
+ "data-slot": "page-header",
233
+ className: cn(pageHeaderVariants({ variant: resolvedVariant }), className),
234
+ children: [
235
+ /* @__PURE__ */ jsxs("div", {
236
+ className: "relative",
237
+ children: [/* @__PURE__ */ jsx("div", {
238
+ className: bannerVariants({ variant: isCentered ? "centered" : "default" }),
239
+ "aria-hidden": "true"
240
+ }), hasAvatar && /* @__PURE__ */ jsx("div", {
241
+ className: cn("absolute inset-x-0 px-4 md:px-8", "-bottom-12 md:-bottom-20", isCentered && "flex justify-center"),
242
+ children: /* @__PURE__ */ jsx(PageHeaderAvatar, {
243
+ hasAvatar,
244
+ isBanner,
245
+ avatarSrc,
246
+ avatarFallback,
247
+ avatarStatusIcon
248
+ })
249
+ })]
250
+ }),
251
+ /* @__PURE__ */ jsxs("div", {
252
+ className: cn("px-4 md:px-8", hasAvatar ? "pt-16 md:pt-24" : "pt-6", isCentered && "flex flex-col items-center"),
253
+ children: [
254
+ /* @__PURE__ */ jsx("div", {
255
+ className: "md:hidden mb-4",
256
+ children: /* @__PURE__ */ jsx(PageHeaderBackButton, {
257
+ breadcrumbs,
258
+ onBackClick,
259
+ backLabel
260
+ })
261
+ }),
262
+ !isCentered && /* @__PURE__ */ jsx("div", {
263
+ className: "hidden md:block",
264
+ children: /* @__PURE__ */ jsx(PageHeaderBreadcrumbs, { breadcrumbs })
265
+ }),
266
+ /* @__PURE__ */ jsxs("div", {
267
+ className: cn(contentVariants({ variant: resolvedVariant }), "mt-4 md:mt-6"),
268
+ children: [
269
+ /* @__PURE__ */ jsx(PageHeaderTextContent, {
270
+ title,
271
+ supportingText,
272
+ isCentered
273
+ }),
274
+ /* @__PURE__ */ jsx(PageHeaderActions, { actions }),
275
+ /* @__PURE__ */ jsx(PageHeaderSearch, {
276
+ searchId,
277
+ searchPlaceholder,
278
+ searchShortcut,
279
+ onSearch
280
+ })
281
+ ]
282
+ })
283
+ ]
284
+ }),
285
+ showDivider && /* @__PURE__ */ jsx(Separator, { className: "mt-5 delight-connector-fill motion-reduce:!animate-none" })
286
+ ]
287
+ });
127
288
  return /* @__PURE__ */ jsxs("header", {
128
289
  ref,
129
- "data-slot": "section-header",
130
- className: cn("relative flex w-full flex-col gap-4", className),
131
- ...props,
290
+ "data-slot": "page-header",
291
+ className: cn(pageHeaderVariants({ variant: resolvedVariant }), className),
132
292
  children: [
293
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(PageHeaderBreadcrumbs, { breadcrumbs }), /* @__PURE__ */ jsx(PageHeaderBackButton, {
294
+ breadcrumbs,
295
+ onBackClick,
296
+ backLabel
297
+ })] }),
133
298
  /* @__PURE__ */ jsxs("div", {
134
- className: "grid w-full grid-cols-[minmax(0,1fr)_auto] items-start gap-x-4 gap-y-3",
135
- children: [/* @__PURE__ */ jsxs("div", {
136
- className: cn("col-start-1 row-start-1 flex min-w-0 flex-col justify-center gap-0.5", menuButton ? "pe-8 md:pe-0" : null),
137
- children: [/* @__PURE__ */ jsx(HeadingTag, {
138
- className: cn("line-clamp-2 w-full break-words font-semibold text-foreground", size === "sm" ? "text-[14px] leading-5" : "text-[18px] leading-7"),
139
- children: title
140
- }), supportingText ? /* @__PURE__ */ jsx("p", {
141
- className: "line-clamp-2 w-full break-words text-sm leading-5 text-secondary-foreground",
142
- children: supportingText
143
- }) : null]
144
- }), hasHeaderControls ? /* @__PURE__ */ jsxs("div", {
145
- className: cn("col-span-2 row-start-2 flex flex-wrap items-center gap-3 md:col-span-1 md:col-start-2 md:row-start-1 md:flex-nowrap md:justify-end", !hasInlineControls && "contents md:flex"),
146
- children: [/* @__PURE__ */ jsx(SectionHeaderControls, {
147
- actions,
148
- buttonGroup,
149
- search
150
- }), menuButton ? /* @__PURE__ */ jsx("div", {
151
- className: "absolute end-0 top-0 md:static",
152
- children: /* @__PURE__ */ jsx(SectionHeaderTouchTargetControl, { control: menuButton })
153
- }) : null]
154
- }) : null]
299
+ className: cn(contentVariants({ variant: resolvedVariant })),
300
+ children: [
301
+ /* @__PURE__ */ jsxs("div", {
302
+ className: cn("flex gap-4 items-center flex-1 min-w-0", hasAvatar && "flex-row"),
303
+ children: [/* @__PURE__ */ jsx(PageHeaderAvatar, {
304
+ hasAvatar,
305
+ isBanner,
306
+ avatarSrc,
307
+ avatarFallback,
308
+ avatarStatusIcon
309
+ }), /* @__PURE__ */ jsx(PageHeaderTextContent, {
310
+ title,
311
+ supportingText,
312
+ isCentered
313
+ })]
314
+ }),
315
+ /* @__PURE__ */ jsx(PageHeaderActions, { actions }),
316
+ /* @__PURE__ */ jsx(PageHeaderSearch, {
317
+ searchId,
318
+ searchPlaceholder,
319
+ searchShortcut,
320
+ onSearch
321
+ })
322
+ ]
155
323
  }),
156
- tabs?.length ? /* @__PURE__ */ jsx(SectionHeaderTabs, { tabs }) : null,
157
- showDivider ? /* @__PURE__ */ jsx(Separator, { "aria-hidden": "true" }) : null
324
+ showDivider && /* @__PURE__ */ jsx(Separator, { className: "delight-connector-fill motion-reduce:!animate-none" })
158
325
  ]
159
326
  });
160
327
  });
161
- SectionHeader.displayName = "SectionHeader";
328
+ PageHeader.displayName = "PageHeader";
162
329
  //#endregion
163
- export { SectionHeader };
330
+ export { PageHeader, bannerVariants, contentVariants, pageHeaderVariants };
164
331
 
165
332
  //# sourceMappingURL=index203.js.map