@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.
- package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
- package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
- package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
- package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
- package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
- package/dist/index.js +52 -52
- package/dist/index151.js +1 -1
- package/dist/index174.js +7 -339
- package/dist/index174.js.map +1 -1
- package/dist/index175.js +310 -137
- package/dist/index175.js.map +1 -1
- package/dist/index176.js +148 -174
- package/dist/index176.js.map +1 -1
- package/dist/index177.js +186 -78
- package/dist/index177.js.map +1 -1
- package/dist/index178.js +74 -124
- package/dist/index178.js.map +1 -1
- package/dist/index179.js +133 -1
- package/dist/index179.js.map +1 -0
- package/dist/index180.js +2 -201
- package/dist/index181.js +201 -0
- package/dist/{index180.js.map → index181.js.map} +1 -1
- package/dist/index183.js +130 -166
- package/dist/index183.js.map +1 -1
- package/dist/index184.js +195 -983
- package/dist/index184.js.map +1 -1
- package/dist/index185.js +1069 -369
- package/dist/index185.js.map +1 -1
- package/dist/index186.js +395 -197
- package/dist/index186.js.map +1 -1
- package/dist/index187.js +198 -243
- package/dist/index187.js.map +1 -1
- package/dist/index188.js +263 -3
- package/dist/index188.js.map +1 -1
- package/dist/index189.js +3 -209
- package/dist/index189.js.map +1 -1
- package/dist/index190.js +190 -777
- package/dist/index190.js.map +1 -1
- package/dist/index191.js +771 -252
- package/dist/index191.js.map +1 -1
- package/dist/index192.js +250 -65
- package/dist/index192.js.map +1 -1
- package/dist/index193.js +72 -523
- package/dist/index193.js.map +1 -1
- package/dist/index194.js +537 -144
- package/dist/index194.js.map +1 -1
- package/dist/index195.js +139 -720
- package/dist/index195.js.map +1 -1
- package/dist/index196.js +707 -167
- package/dist/index196.js.map +1 -1
- package/dist/index197.js +175 -151
- package/dist/index197.js.map +1 -1
- package/dist/index198.js +152 -487
- package/dist/index198.js.map +1 -1
- package/dist/index199.js +472 -225
- package/dist/index199.js.map +1 -1
- package/dist/index200.js +236 -260
- package/dist/index200.js.map +1 -1
- package/dist/index201.js +265 -215
- package/dist/index201.js.map +1 -1
- package/dist/index202.js +207 -307
- package/dist/index202.js.map +1 -1
- package/dist/index203.js +302 -135
- package/dist/index203.js.map +1 -1
- package/dist/index204.js +140 -271
- package/dist/index204.js.map +1 -1
- package/dist/index205.js +263 -253
- package/dist/index205.js.map +1 -1
- package/dist/index206.js +244 -137
- package/dist/index206.js.map +1 -1
- package/dist/index207.js +100 -238
- package/dist/index207.js.map +1 -1
- package/dist/index208.js +278 -74
- package/dist/index208.js.map +1 -1
- package/dist/index209.js +56 -97
- package/dist/index209.js.map +1 -1
- package/dist/index210.js +142 -47
- package/dist/index210.js.map +1 -1
- package/dist/index211.js +38 -84
- package/dist/index211.js.map +1 -1
- package/dist/index212.js +72 -252
- package/dist/index212.js.map +1 -1
- package/dist/index213.js +274 -26
- package/dist/index213.js.map +1 -1
- package/dist/index214.js +29 -94
- package/dist/index214.js.map +1 -1
- package/dist/index215.js +98 -25
- package/dist/index215.js.map +1 -1
- package/dist/index216.js +20 -565
- package/dist/index216.js.map +1 -1
- package/dist/index217.js +564 -17
- package/dist/index217.js.map +1 -1
- package/dist/index218.js +20 -23
- package/dist/index218.js.map +1 -1
- package/dist/index219.js +20 -95
- package/dist/index219.js.map +1 -1
- package/dist/index220.js +92 -88
- package/dist/index220.js.map +1 -1
- package/dist/index221.js +97 -29
- package/dist/index221.js.map +1 -1
- package/dist/index222.js +24 -470
- package/dist/index222.js.map +1 -1
- package/dist/index223.js +446 -196
- package/dist/index223.js.map +1 -1
- package/dist/index224.js +199 -729
- package/dist/index224.js.map +1 -1
- package/dist/index225.js +750 -61
- package/dist/index225.js.map +1 -1
- package/dist/index226.js +58 -181
- package/dist/index226.js.map +1 -1
- package/dist/index227.js +175 -259
- package/dist/index227.js.map +1 -1
- package/dist/index228.js +246 -172
- package/dist/index228.js.map +1 -1
- package/dist/index229.js +195 -32
- package/dist/index229.js.map +1 -1
- package/dist/index230.js +12 -40
- package/dist/index230.js.map +1 -1
- package/dist/index231.js +23 -26
- package/dist/index231.js.map +1 -1
- package/dist/index232.js +45 -22
- package/dist/index232.js.map +1 -1
- package/dist/index233.js +27 -48
- package/dist/index233.js.map +1 -1
- package/dist/index234.js +52 -26
- package/dist/index234.js.map +1 -1
- package/dist/index235.js +40 -225
- package/dist/index235.js.map +1 -1
- package/dist/index236.js +217 -39
- package/dist/index236.js.map +1 -1
- package/dist/index237.js +50 -0
- package/dist/index237.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/wc/AIToolCall.js +218 -0
- package/dist/wc/AIToolCall.js.map +1 -0
- package/dist/wc/hf-ai-tool-call.js +34 -219
- package/dist/wc/hf-ai-tool-call.js.map +1 -1
- package/dist/wc/hf-ai-tool-run.js +673 -576
- package/dist/wc/hf-ai-tool-run.js.map +1 -1
- package/dist/wc/workflow-step-renderer.js +79 -78
- package/dist/wc/workflow-step-renderer.js.map +1 -1
- package/dist/wc-react/AIToolCall.js +218 -0
- package/dist/wc-react/AIToolCall.js.map +1 -0
- package/dist/wc-react/hf-ai-tool-call.js +32 -217
- package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
- package/dist/wc-react/hf-ai-tool-run.js +698 -601
- package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
- package/dist/wc-react/workflow-step-renderer.js +58 -57
- package/dist/wc-react/workflow-step-renderer.js.map +1 -1
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
- package/dist/index182.js +0 -143
- package/dist/index182.js.map +0 -1
- package/dist/wc/wrench.js +0 -10
- package/dist/wc/wrench.js.map +0 -1
- package/dist/wc-react/wrench.js +0 -10
- package/dist/wc-react/wrench.js.map +0 -1
package/dist/index202.js.map
CHANGED
|
@@ -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 {
|
|
8
|
-
import {
|
|
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/
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
17
|
-
|
|
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
|
|
24
|
-
|
|
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
|
|
27
|
-
const
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
return
|
|
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
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
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
|
-
}
|
|
168
|
+
});
|
|
91
169
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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": "
|
|
130
|
-
className: cn(
|
|
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:
|
|
135
|
-
children: [
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
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
|
-
|
|
328
|
+
PageHeader.displayName = "PageHeader";
|
|
162
329
|
//#endregion
|
|
163
|
-
export {
|
|
330
|
+
export { PageHeader, bannerVariants, contentVariants, pageHeaderVariants };
|
|
164
331
|
|
|
165
332
|
//# sourceMappingURL=index203.js.map
|