@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/index196.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index196.js","names":[],"sources":["../src/components/organisms/content/InlineCTA/InlineCTA.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { Mail } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { Input } from '@/components/atoms/forms/Input';\nimport { cn } from '@/lib/utils';\n\nconst inlineCTAVariants = cva(\n 'relative bg-background overflow-hidden shadow-xs',\n {\n variants: {\n variant: {\n bordered: 'border border-border rounded-xl',\n 'full-width': 'border-y border-border',\n },\n },\n defaultVariants: {\n variant: 'bordered',\n },\n },\n);\n\ninterface InlineCTABaseProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSubmit'>,\n VariantProps<typeof inlineCTAVariants> {\n /** Title text for the CTA */\n title: React.ReactNode;\n /** Supporting description text */\n description?: React.ReactNode;\n}\n\n// ============================================================================\n// Actions Type - Simple CTA with title, description, and action buttons\n// ============================================================================\n\nexport interface InlineCTAActionsProps extends InlineCTABaseProps {\n type: 'actions';\n /** Primary action button label */\n primaryLabel?: string;\n /** Callback when primary button is clicked */\n onPrimaryClick?: () => void;\n /** Secondary action button label */\n secondaryLabel?: string;\n /** Callback when secondary button is clicked */\n onSecondaryClick?: () => void;\n /** Stack buttons vertically (for mobile) */\n stackedActions?: boolean;\n}\n\nfunction InlineCTAActions({\n title,\n description,\n primaryLabel = 'Changelog',\n onPrimaryClick,\n secondaryLabel = 'Dismiss',\n onSecondaryClick,\n stackedActions = false,\n variant,\n className,\n ...props\n}: InlineCTAActionsProps) {\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Call to action'}\n className={cn(\n inlineCTAVariants({ variant }),\n 'flex flex-col gap-5 p-6',\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <div\n className={cn(\n 'flex gap-3',\n stackedActions ? 'flex-col w-full' : 'flex-row items-center',\n )}\n >\n {stackedActions ? (\n <>\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n className=\"w-full\"\n >\n {primaryLabel}\n </Button>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n className=\"w-full\"\n >\n {secondaryLabel}\n </Button>\n )}\n </>\n ) : (\n <>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n >\n {secondaryLabel}\n </Button>\n )}\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n >\n {primaryLabel}\n </Button>\n </>\n )}\n </div>\n </section>\n );\n}\n\n// ============================================================================\n// Email Type - Subscribe form with email input\n// ============================================================================\n\nexport interface InlineCTAEmailProps extends InlineCTABaseProps {\n type: 'email';\n /** Label for the email input field */\n inputLabel?: string;\n /** Placeholder for the email input */\n inputPlaceholder?: string;\n /** Submit button label */\n submitLabel?: string;\n /** Callback when form is submitted */\n onSubmit?: (email: string) => void;\n /** Stack input and button vertically (for mobile) */\n stackedLayout?: boolean;\n /** Default email value */\n defaultValue?: string;\n /** Loading state for the submit button */\n loading?: boolean;\n}\n\nfunction InlineCTAEmail({\n title,\n description,\n inputLabel = 'Subscribe to updates',\n inputPlaceholder = 'you@humain.ai',\n submitLabel = 'Subscribe',\n onSubmit,\n stackedLayout = false,\n defaultValue = '',\n loading = false,\n variant,\n className,\n ...props\n}: InlineCTAEmailProps) {\n const [email, setEmail] = React.useState(defaultValue);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onSubmit?.(email);\n };\n\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Subscribe'}\n className={cn(\n inlineCTAVariants({ variant }),\n 'flex flex-col gap-5 p-6',\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <form\n onSubmit={handleSubmit}\n className={cn(\n 'flex gap-4',\n stackedLayout ? 'flex-col w-full' : 'flex-row items-end max-w-md',\n )}\n >\n <div className={cn(stackedLayout ? 'w-full' : 'flex-1')}>\n <Input\n type=\"email\"\n label={inputLabel}\n placeholder={inputPlaceholder}\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n startIcon={<Mail />}\n required\n />\n </div>\n <Button\n type=\"submit\"\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"lg\"\n loading={loading}\n className={cn(stackedLayout && 'w-full')}\n >\n {submitLabel}\n </Button>\n </form>\n </section>\n );\n}\n\n// ============================================================================\n// Image Type - CTA with featured image\n// ============================================================================\n\nexport interface InlineCTAImageProps extends InlineCTABaseProps {\n type: 'image';\n /** Image source URL */\n imageSrc: string;\n /** Image alt text */\n imageAlt?: string;\n /** Show play button overlay on image */\n showPlayButton?: boolean;\n /** Callback when play button is clicked */\n onPlayClick?: () => void;\n /** Primary action button label */\n primaryLabel?: string;\n /** Callback when primary button is clicked */\n onPrimaryClick?: () => void;\n /** Secondary action button label */\n secondaryLabel?: string;\n /** Callback when secondary button is clicked */\n onSecondaryClick?: () => void;\n /** Stack buttons vertically (for mobile) */\n stackedActions?: boolean;\n}\n\nfunction InlineCTAImage({\n title,\n description,\n imageSrc,\n imageAlt = 'Featured image',\n showPlayButton = false,\n onPlayClick,\n primaryLabel = 'Changelog',\n onPrimaryClick,\n secondaryLabel = 'Dismiss',\n onSecondaryClick,\n stackedActions = false,\n variant,\n className,\n ...props\n}: InlineCTAImageProps) {\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Call to action'}\n className={cn(inlineCTAVariants({ variant }), 'flex flex-col', className)}\n {...props}\n >\n <div className=\"relative aspect-video w-full overflow-hidden\">\n <img\n src={imageSrc}\n alt={imageAlt}\n loading=\"lazy\"\n className=\"absolute inset-0 size-full object-cover\"\n />\n <div className=\"absolute inset-0 border border-border rounded-t-xl\" />\n {showPlayButton && (\n <button\n type=\"button\"\n onClick={onPlayClick}\n className=\"absolute bottom-3 start-3 size-11 rounded-full bg-card/80 supports-backdrop-filter:backdrop-blur-sm flex items-center justify-center hover:bg-background transition-colors\"\n aria-label=\"Play video\"\n >\n <svg\n className=\"size-4 ms-0.5 text-foreground\"\n fill=\"currentColor\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M4 3.5v9l8-4.5-8-4.5z\" />\n </svg>\n </button>\n )}\n </div>\n\n <div className=\"flex flex-col gap-5 p-4 border-x border-b border-border rounded-b-xl\">\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <div\n className={cn(\n 'flex gap-3',\n stackedActions ? 'flex-col w-full' : 'flex-row items-center',\n )}\n >\n {stackedActions ? (\n <>\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n className=\"w-full\"\n >\n {primaryLabel}\n </Button>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n className=\"w-full\"\n >\n {secondaryLabel}\n </Button>\n )}\n </>\n ) : (\n <>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n >\n {secondaryLabel}\n </Button>\n )}\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n >\n {primaryLabel}\n </Button>\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\n// ============================================================================\n// Compound Component Export\n// ============================================================================\n\nexport type InlineCTAProps =\n | InlineCTAActionsProps\n | InlineCTAEmailProps\n | InlineCTAImageProps;\n\nfunction InlineCTA(props: InlineCTAProps) {\n switch (props.type) {\n case 'actions':\n return <InlineCTAActions {...props} />;\n case 'email':\n return <InlineCTAEmail {...props} />;\n case 'image':\n return <InlineCTAImage {...props} />;\n default:\n return null;\n }\n}\n\nInlineCTA.displayName = 'InlineCTA';\n\nexport { InlineCTA, inlineCTAVariants };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index196.js","names":[],"sources":["../src/components/organisms/content/History/History.tsx"],"sourcesContent":["import {\n ArrowDown,\n ArrowUp,\n ChevronsUp,\n Filter,\n type LucideIcon,\n Maximize2,\n MessageSquare,\n Minus,\n Paperclip,\n Pencil,\n Plus,\n Tag,\n Trash2,\n UserRound,\n X,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { Badge } from '@/components/atoms/display/Badge';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { FileTypeIcon } from '@/components/molecules/files/FileTypeIcon';\nimport { assertNever, cn } from '@/lib/utils';\n\n/* -------------------------------------------------------------------------------------------------\n * History Types\n * -------------------------------------------------------------------------------------------------*/\n\nexport type HistoryEventType =\n | 'create'\n | 'update-fields'\n | 'reassign'\n | 'tags'\n | 'attachment'\n | 'comment'\n | 'delete-comment'\n | 'delete-record';\n\nexport type HistoryActorKind = 'person' | 'external' | 'bot';\nexport type HistoryTone =\n | 'primary'\n | 'success'\n | 'info'\n | 'warning'\n | 'destructive'\n | 'muted';\nexport type HistoryPriority = 'low' | 'medium' | 'important' | 'urgent';\nexport type HistoryValueState = 'current' | 'previous' | 'added' | 'removed';\nexport type HistoryHeaderActionId = 'filter' | 'expand' | 'close';\n\nexport interface HistoryActor {\n id: string;\n name: string;\n avatarSrc?: string;\n fallback?: string;\n kind?: HistoryActorKind;\n}\n\nexport interface HistoryPersonValue {\n id: string;\n name: string;\n avatarSrc?: string;\n fallback?: string;\n}\n\nexport type HistoryValueToken =\n | {\n type: 'status';\n label: string;\n tone?: Exclude<HistoryTone, 'primary'>;\n }\n | {\n type: 'priority';\n label: string;\n priority?: HistoryPriority;\n }\n | {\n type: 'person';\n person: HistoryPersonValue;\n }\n | {\n type: 'date';\n value: string;\n }\n | {\n type: 'number';\n value: number | string;\n unit?: string;\n }\n | {\n type: 'tag';\n label: string;\n tone?: HistoryTone;\n }\n | {\n type: 'boolean';\n value: boolean;\n trueLabel?: string;\n falseLabel?: string;\n }\n | {\n type: 'file';\n name: string;\n extension?: string;\n }\n | {\n type: 'text';\n value: string;\n }\n | {\n type: 'empty';\n label?: string;\n };\n\nexport interface HistoryFieldChange {\n id: string;\n label: string;\n from?: HistoryValueToken;\n to?: HistoryValueToken;\n added?: HistoryValueToken[];\n removed?: HistoryValueToken[];\n}\n\ninterface HistoryEventBase {\n id: string;\n actor: HistoryActor;\n timestamp: string;\n dateTime?: string;\n actorFlags?: string[];\n defaultExpanded?: boolean;\n}\n\nexport interface HistoryCreateEvent extends HistoryEventBase {\n type: 'create';\n actionLabel?: string;\n target: string;\n}\n\nexport interface HistoryDeleteRecordEvent extends HistoryEventBase {\n type: 'delete-record';\n actionLabel?: string;\n target: string;\n}\n\nexport interface HistoryUpdateFieldsEvent extends HistoryEventBase {\n type: 'update-fields';\n summaryLabel?: string;\n changes: HistoryFieldChange[];\n}\n\nexport interface HistoryReassignEvent extends HistoryEventBase {\n type: 'reassign';\n fieldLabel?: string;\n from?: HistoryPersonValue[];\n to: HistoryPersonValue[];\n}\n\nexport interface HistoryTagsEvent extends HistoryEventBase {\n type: 'tags';\n fieldLabel?: string;\n added?: HistoryValueToken[];\n removed?: HistoryValueToken[];\n}\n\nexport interface HistoryAttachmentEvent extends HistoryEventBase {\n type: 'attachment';\n fieldLabel?: string;\n added?: HistoryValueToken[];\n removed?: HistoryValueToken[];\n}\n\nexport interface HistoryCommentEvent extends HistoryEventBase {\n type: 'comment';\n comment: string;\n}\n\nexport interface HistoryDeleteCommentEvent extends HistoryEventBase {\n type: 'delete-comment';\n commentAuthor: HistoryPersonValue;\n originalText?: string;\n actionLabel?: string;\n}\n\nexport type HistoryEvent =\n | HistoryCreateEvent\n | HistoryUpdateFieldsEvent\n | HistoryReassignEvent\n | HistoryTagsEvent\n | HistoryAttachmentEvent\n | HistoryCommentEvent\n | HistoryDeleteCommentEvent\n | HistoryDeleteRecordEvent;\n\nexport interface HistoryGroup {\n id: string;\n label: string;\n events: HistoryEvent[];\n}\n\nexport interface HistoryHeaderAction {\n id: HistoryHeaderActionId;\n label?: string;\n onClick?: () => void;\n disabled?: boolean;\n}\n\nexport interface HistoryProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n title?: string;\n groups: HistoryGroup[];\n actions?: HistoryHeaderAction[];\n loading?: boolean;\n ariaLabel?: string;\n emptyMessage?: string;\n collapsibleChangeThreshold?: number;\n autoExpandNewestLargeEdit?: boolean;\n expandedEventIds?: string[];\n defaultExpandedEventIds?: string[];\n onExpandedEventIdsChange?: (ids: string[]) => void;\n}\n\ninterface HistoryEventCategoryConfig {\n label: string;\n Icon: LucideIcon;\n badgeClassName: string;\n actionClassName: string;\n}\n\nconst historyEventCategoryConfig = {\n create: {\n label: 'Create',\n Icon: Plus,\n badgeClassName: 'bg-success/10 text-success ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n 'update-fields': {\n label: 'Update fields',\n Icon: Pencil,\n badgeClassName: 'bg-info/10 text-info ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n reassign: {\n label: 'Reassign people',\n Icon: UserRound,\n badgeClassName: 'bg-primary/10 text-primary ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n tags: {\n label: 'Tags',\n Icon: Tag,\n badgeClassName: 'bg-info/10 text-info ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n attachment: {\n label: 'Attachment',\n Icon: Paperclip,\n badgeClassName: 'bg-info/10 text-info ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n comment: {\n label: 'Comment',\n Icon: MessageSquare,\n badgeClassName: 'bg-warning/10 text-warning ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n 'delete-comment': {\n label: 'Delete comment',\n Icon: Trash2,\n badgeClassName:\n 'bg-destructive/10 text-destructive ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n 'delete-record': {\n label: 'Delete record',\n Icon: Trash2,\n badgeClassName:\n 'bg-destructive/10 text-destructive ring-background dark:ring-card',\n actionClassName: 'text-card-foreground',\n },\n} satisfies Record<HistoryEventType, HistoryEventCategoryConfig>;\n\nconst historyHeaderActionConfig = {\n filter: { label: 'Filter history', Icon: Filter },\n expand: { label: 'Expand history panel', Icon: Maximize2 },\n close: { label: 'Close history panel', Icon: X },\n} satisfies Record<HistoryHeaderActionId, { label: string; Icon: LucideIcon }>;\n\nconst toneTextClass = {\n primary: 'text-card-foreground',\n success: 'text-card-foreground',\n info: 'text-card-foreground',\n warning: 'text-card-foreground',\n destructive: 'text-card-foreground',\n muted: 'text-card-foreground',\n} satisfies Record<HistoryTone, string>;\n\nconst toneDotClass = {\n primary: 'bg-primary',\n success: 'bg-success',\n info: 'bg-info',\n warning: 'bg-warning',\n destructive: 'bg-destructive',\n muted: 'bg-muted-foreground',\n} satisfies Record<HistoryTone, string>;\n\nconst priorityConfig = {\n low: { Icon: ArrowDown, className: 'text-card-foreground' },\n medium: { Icon: Minus, className: 'text-card-foreground' },\n important: { Icon: ChevronsUp, className: 'text-card-foreground' },\n urgent: { Icon: ArrowUp, className: 'text-card-foreground' },\n} satisfies Record<HistoryPriority, { Icon: LucideIcon; className: string }>;\n\nconst historyDisclosureRevealClassName =\n 'motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-top-1 motion-safe:duration-150';\n\n/* -------------------------------------------------------------------------------------------------\n * Helpers\n * -------------------------------------------------------------------------------------------------*/\n\nfunction getActorFallback(actor: HistoryActor | HistoryPersonValue) {\n return actor.fallback ?? actor.name;\n}\n\nfunction getEventCount(groups: HistoryGroup[]) {\n return groups.reduce((count, group) => count + group.events.length, 0);\n}\n\nfunction getEventPositions(groups: HistoryGroup[]) {\n const positions = new Map<string, number>();\n let position = 1;\n\n for (const group of groups) {\n for (const event of group.events) {\n positions.set(event.id, position);\n position += 1;\n }\n }\n\n return positions;\n}\n\nfunction getCollectionEventValueCount(\n event: HistoryTagsEvent | HistoryAttachmentEvent,\n) {\n return (event.added?.length ?? 0) + (event.removed?.length ?? 0);\n}\n\nfunction getCollapsibleSummary(\n event: HistoryEvent,\n threshold: number,\n): string | null {\n switch (event.type) {\n case 'update-fields':\n return event.changes.length >= threshold\n ? `${event.changes.length} Fields`\n : null;\n case 'tags': {\n const total = getCollectionEventValueCount(event);\n return total >= threshold\n ? getDeltaSummary(event.added, event.removed)\n : null;\n }\n case 'attachment': {\n const total = getCollectionEventValueCount(event);\n return total >= threshold\n ? getDeltaSummary(event.added, event.removed)\n : null;\n }\n case 'delete-comment':\n return event.originalText ? 'deleted comment' : null;\n case 'create':\n case 'reassign':\n case 'comment':\n case 'delete-record':\n return null;\n default:\n return assertNever(event);\n }\n}\n\nfunction isCollapsibleEvent(event: HistoryEvent, threshold: number) {\n return getCollapsibleSummary(event, threshold) !== null;\n}\n\nfunction getDefaultExpandedEventIds(\n groups: HistoryGroup[],\n threshold: number,\n autoExpandNewestLargeEdit: boolean,\n) {\n const ids = new Set<string>();\n let didAutoExpandLargeEdit = false;\n\n for (const group of groups) {\n for (const event of group.events) {\n if (\n event.defaultExpanded === true &&\n isCollapsibleEvent(event, threshold)\n ) {\n ids.add(event.id);\n }\n\n if (\n autoExpandNewestLargeEdit &&\n !didAutoExpandLargeEdit &&\n event.defaultExpanded !== false &&\n event.type === 'update-fields' &&\n event.changes.length >= threshold\n ) {\n ids.add(event.id);\n didAutoExpandLargeEdit = true;\n }\n }\n }\n\n return Array.from(ids);\n}\n\nfunction getDeltaSummary(\n added: HistoryValueToken[] | undefined,\n removed: HistoryValueToken[] | undefined,\n) {\n const parts: string[] = [];\n\n if (added?.length) {\n parts.push(`+${added.length}`);\n }\n\n if (removed?.length) {\n parts.push(`-${removed.length}`);\n }\n\n return parts.join(' ');\n}\n\nfunction useExpandedEventIds({\n groups,\n threshold,\n autoExpandNewestLargeEdit,\n expandedEventIds,\n defaultExpandedEventIds,\n onExpandedEventIdsChange,\n}: {\n groups: HistoryGroup[];\n threshold: number;\n autoExpandNewestLargeEdit: boolean;\n expandedEventIds?: string[];\n defaultExpandedEventIds?: string[];\n onExpandedEventIdsChange?: (ids: string[]) => void;\n}) {\n const computedDefaultIds = React.useMemo(\n () =>\n defaultExpandedEventIds ??\n getDefaultExpandedEventIds(groups, threshold, autoExpandNewestLargeEdit),\n [autoExpandNewestLargeEdit, defaultExpandedEventIds, groups, threshold],\n );\n const [internalIds, setInternalIds] = React.useState(computedDefaultIds);\n const isControlled = expandedEventIds !== undefined;\n const activeIds = isControlled ? expandedEventIds : internalIds;\n\n const setExpanded = React.useCallback(\n (eventId: string, nextExpanded: boolean) => {\n const next = new Set(activeIds);\n\n if (nextExpanded) {\n next.add(eventId);\n } else {\n next.delete(eventId);\n }\n\n const nextIds = Array.from(next);\n\n if (!isControlled) {\n setInternalIds(nextIds);\n }\n\n onExpandedEventIdsChange?.(nextIds);\n },\n [activeIds, isControlled, onExpandedEventIdsChange],\n );\n\n return {\n expandedIdSet: React.useMemo(() => new Set(activeIds), [activeIds]),\n setExpanded,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Value Tokens\n * -------------------------------------------------------------------------------------------------*/\n\ninterface HistoryValueProps {\n value: HistoryValueToken;\n state?: HistoryValueState;\n className?: string;\n}\n\nfunction HistoryMiniPerson({ person }: { person: HistoryPersonValue }) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1\">\n <span\n data-slot=\"history-mini-person-avatar\"\n aria-hidden=\"true\"\n className=\"shrink-0\"\n >\n <Avatar\n src={person.avatarSrc}\n fallback={getActorFallback(person)}\n alt=\"\"\n size=\"xs\"\n shape=\"circle\"\n className=\"size-4\"\n />\n </span>\n <span className=\"truncate\">{person.name}</span>\n </span>\n );\n}\n\nfunction HistoryValue({\n value,\n state = 'current',\n className,\n}: HistoryValueProps) {\n const isPrevious = state === 'previous' || state === 'removed';\n const stateClassName = cn(\n isPrevious &&\n 'text-secondary-foreground line-through decoration-current/60',\n state === 'added' && 'text-card-foreground',\n state === 'removed' && 'text-secondary-foreground',\n );\n\n switch (value.type) {\n case 'status': {\n const tone = value.tone ?? 'info';\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center gap-1 font-medium',\n toneTextClass[tone],\n stateClassName,\n className,\n )}\n >\n <span\n aria-hidden=\"true\"\n className={cn('size-1.5 rounded-full', toneDotClass[tone])}\n />\n <span className=\"truncate\">{value.label}</span>\n </span>\n );\n }\n\n case 'priority': {\n const priority = value.priority ?? 'medium';\n const { Icon, className: priorityClassName } = priorityConfig[priority];\n\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center gap-1 font-medium',\n priorityClassName,\n stateClassName,\n className,\n )}\n >\n <Icon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{value.label}</span>\n </span>\n );\n }\n\n case 'person':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center font-medium text-card-foreground',\n stateClassName,\n className,\n )}\n >\n <HistoryMiniPerson person={value.person} />\n </span>\n );\n\n case 'date':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-block min-w-0 truncate font-mono text-card-foreground',\n stateClassName,\n className,\n )}\n >\n {value.value}\n </span>\n );\n\n case 'number':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-baseline gap-1 font-mono text-card-foreground',\n stateClassName,\n className,\n )}\n >\n <span>{value.value}</span>\n {value.unit && (\n <span className=\"text-secondary-foreground\">{value.unit}</span>\n )}\n </span>\n );\n\n case 'tag': {\n const tone = value.tone ?? 'primary';\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center gap-0.5 font-medium',\n toneTextClass[tone],\n stateClassName,\n className,\n )}\n >\n <span aria-hidden=\"true\">#</span>\n <span className=\"truncate\">{value.label}</span>\n </span>\n );\n }\n\n case 'boolean': {\n const label = value.value\n ? (value.trueLabel ?? 'On')\n : (value.falseLabel ?? 'Off');\n const tone: HistoryTone = value.value ? 'success' : 'muted';\n\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center gap-1 font-medium',\n toneTextClass[tone],\n stateClassName,\n className,\n )}\n >\n <span\n aria-hidden=\"true\"\n className={cn('size-1.5 rounded-full', toneDotClass[tone])}\n />\n <span>{label}</span>\n </span>\n );\n }\n\n case 'file':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-flex min-w-0 items-center gap-1 font-medium text-card-foreground',\n stateClassName,\n className,\n )}\n >\n <span aria-hidden=\"true\" className=\"shrink-0\">\n <FileTypeIcon\n extension={value.extension}\n fileType={value.extension ? undefined : 'document'}\n size=\"xs\"\n />\n </span>\n <span className=\"truncate\">{value.name}</span>\n </span>\n );\n\n case 'text':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-block min-w-0 truncate text-card-foreground',\n stateClassName,\n className,\n )}\n >\n {value.value}\n </span>\n );\n\n case 'empty':\n return (\n <span\n data-slot=\"history-value\"\n className={cn(\n 'inline-block min-w-0 truncate italic text-secondary-foreground',\n className,\n )}\n >\n {value.label ?? 'Empty'}\n </span>\n );\n\n default:\n return assertNever(value);\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Body Renderers\n * -------------------------------------------------------------------------------------------------*/\n\nfunction HistoryFieldChangeRow({ change }: { change: HistoryFieldChange }) {\n const hasDelta =\n (change.added?.length ?? 0) + (change.removed?.length ?? 0) > 0;\n\n return (\n <div\n data-slot=\"history-field-change\"\n className=\"flex min-w-0 items-start gap-2 text-sm leading-5\"\n >\n <span className=\"min-w-[72px] shrink-0 font-semibold text-secondary-foreground\">\n {change.label}\n </span>\n <span className=\"flex min-w-0 flex-1 flex-wrap items-center gap-x-2 gap-y-1\">\n {hasDelta ? (\n <>\n {change.added?.map((value, index) => (\n <span\n key={`added:${change.id}:${index}`}\n className=\"inline-flex min-w-0 items-center gap-1\"\n >\n <span className=\"font-mono font-semibold text-secondary-foreground\">\n +\n </span>\n <HistoryValue value={value} state=\"added\" />\n </span>\n ))}\n {change.removed?.map((value, index) => (\n <span\n key={`removed:${change.id}:${index}`}\n className=\"inline-flex min-w-0 items-center gap-1\"\n >\n <span className=\"font-mono font-semibold text-secondary-foreground\">\n -\n </span>\n <HistoryValue value={value} state=\"removed\" />\n </span>\n ))}\n </>\n ) : (\n <>\n {change.from && (\n <HistoryValue value={change.from} state=\"previous\" />\n )}\n {change.to && <HistoryValue value={change.to} />}\n </>\n )}\n </span>\n </div>\n );\n}\n\nfunction HistoryCollectionChange({\n label,\n added,\n removed,\n}: {\n label: string;\n added?: HistoryValueToken[];\n removed?: HistoryValueToken[];\n}) {\n const change: HistoryFieldChange = {\n id: label.toLowerCase().replace(/\\s+/g, '-'),\n label,\n added,\n removed,\n };\n\n return <HistoryFieldChangeRow change={change} />;\n}\n\nfunction HistoryCollapsedSummaryButton({\n event,\n expanded,\n summary,\n controlsId,\n onToggle,\n}: {\n event: HistoryEvent;\n expanded: boolean;\n summary: string;\n controlsId: string;\n onToggle: () => void;\n}) {\n const isDeleteComment = event.type === 'delete-comment';\n const buttonLabel = isDeleteComment\n ? expanded\n ? 'Hide'\n : 'View'\n : expanded\n ? 'Show less'\n : 'Show all';\n\n return (\n <button\n type=\"button\"\n data-slot=\"history-collapse-trigger\"\n aria-expanded={expanded}\n aria-controls={controlsId}\n onClick={onToggle}\n className={cn(\n 'group/history-collapse flex min-h-11 w-full min-w-0 items-center gap-2 rounded-lg border border-border px-2.5 py-2 text-left text-sm leading-5 sm:min-h-0 sm:py-1',\n 'transition-[background-color,border-color,box-shadow,transform] duration-150 ease-out motion-reduce:transition-none',\n 'hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background active:scale-[0.99] motion-reduce:active:scale-100',\n isDeleteComment\n ? 'hover:border-destructive/30'\n : 'hover:border-primary/30',\n isDeleteComment && 'border-dashed py-3',\n )}\n >\n {isDeleteComment ? (\n <Trash2\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 text-destructive motion-safe:transition-transform motion-safe:duration-150 motion-safe:group-hover/history-collapse:scale-105\"\n />\n ) : (\n <ChevronIndicator expanded={expanded} />\n )}\n <span className=\"min-w-0 flex-1 text-secondary-foreground\">\n {isDeleteComment ? summary : event.type === 'tags' ? 'Tags' : 'Updated'}\n </span>\n {!isDeleteComment && (\n <span className=\"min-w-0 flex-1 truncate font-semibold text-foreground\">\n {summary}\n </span>\n )}\n <span className=\"shrink-0 text-xs font-medium text-secondary-foreground motion-safe:transition-transform motion-safe:duration-150 motion-safe:group-hover/history-collapse:translate-x-0.5\">\n {buttonLabel}\n </span>\n </button>\n );\n}\n\nfunction ChevronIndicator({ expanded }: { expanded: boolean }) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-[color,transform] duration-150 ease-out motion-reduce:transition-none group-hover/history-collapse:text-primary',\n expanded && 'rotate-180',\n )}\n >\n <path\n d=\"M4 6l4 4 4-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.5\"\n />\n </svg>\n );\n}\n\ninterface HistoryEventBodyProps {\n event: HistoryEvent;\n threshold: number;\n expanded: boolean;\n contentId: string;\n onToggleExpanded: () => void;\n}\n\nfunction HistoryEventBody({\n event,\n threshold,\n expanded,\n contentId,\n onToggleExpanded,\n}: HistoryEventBodyProps) {\n const category = historyEventCategoryConfig[event.type];\n const summary = getCollapsibleSummary(event, threshold);\n\n switch (event.type) {\n case 'create':\n return (\n <p className=\"min-w-0 text-sm font-medium leading-5\">\n <span className={category.actionClassName}>\n {event.actionLabel ?? 'Created the project'}\n </span>{' '}\n <span className=\"text-card-foreground\">\"{event.target}\"</span>\n </p>\n );\n\n case 'delete-record':\n return (\n <p className=\"min-w-0 text-sm font-medium leading-5\">\n <span className={category.actionClassName}>\n {event.actionLabel ?? 'Deleted the record'}\n </span>{' '}\n <span className=\"text-card-foreground\">\"{event.target}\"</span>\n </p>\n );\n\n case 'update-fields':\n if (summary !== null) {\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <HistoryCollapsedSummaryButton\n event={event}\n expanded={expanded}\n summary={summary}\n controlsId={contentId}\n onToggle={onToggleExpanded}\n />\n <div\n id={contentId}\n hidden={!expanded}\n className={cn(\n 'flex min-w-0 flex-col gap-2 ps-2',\n historyDisclosureRevealClassName,\n )}\n >\n {expanded &&\n event.changes.map((change) => (\n <HistoryFieldChangeRow key={change.id} change={change} />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n {event.changes.map((change) => (\n <HistoryFieldChangeRow key={change.id} change={change} />\n ))}\n </div>\n );\n\n case 'reassign':\n return (\n <HistoryFieldChangeRow\n change={{\n id: `${event.id}:reassign`,\n label: event.fieldLabel ?? 'Assignee',\n removed: event.from?.map((person) => ({ type: 'person', person })),\n added: event.to.map((person) => ({ type: 'person', person })),\n }}\n />\n );\n\n case 'tags':\n if (summary !== null) {\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <HistoryCollapsedSummaryButton\n event={event}\n expanded={expanded}\n summary={summary}\n controlsId={contentId}\n onToggle={onToggleExpanded}\n />\n <div\n id={contentId}\n hidden={!expanded}\n className={historyDisclosureRevealClassName}\n >\n {expanded && (\n <HistoryCollectionChange\n label={event.fieldLabel ?? 'Tags'}\n added={event.added}\n removed={event.removed}\n />\n )}\n </div>\n </div>\n );\n }\n\n return (\n <HistoryCollectionChange\n label={event.fieldLabel ?? 'Tags'}\n added={event.added}\n removed={event.removed}\n />\n );\n\n case 'attachment':\n if (summary !== null) {\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <HistoryCollapsedSummaryButton\n event={event}\n expanded={expanded}\n summary={summary}\n controlsId={contentId}\n onToggle={onToggleExpanded}\n />\n <div\n id={contentId}\n hidden={!expanded}\n className={historyDisclosureRevealClassName}\n >\n {expanded && (\n <HistoryCollectionChange\n label={event.fieldLabel ?? 'Attachment'}\n added={event.added}\n removed={event.removed}\n />\n )}\n </div>\n </div>\n );\n }\n\n return (\n <HistoryCollectionChange\n label={event.fieldLabel ?? 'Attachment'}\n added={event.added}\n removed={event.removed}\n />\n );\n\n case 'comment':\n return (\n <blockquote className=\"rounded-xl border border-warning/20 bg-warning/10 px-3 py-2 text-sm leading-5 text-card-foreground\">\n {event.comment}\n </blockquote>\n );\n\n case 'delete-comment': {\n const summaryText =\n event.actionLabel ??\n `Comment by ${event.commentAuthor.name} was deleted`;\n\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <HistoryCollapsedSummaryButton\n event={event}\n expanded={expanded}\n summary={summaryText}\n controlsId={contentId}\n onToggle={onToggleExpanded}\n />\n <div\n id={contentId}\n hidden={!expanded}\n className={historyDisclosureRevealClassName}\n >\n {expanded && event.originalText && (\n <blockquote className=\"rounded-lg border border-dashed border-border bg-muted/40 px-3 py-2 text-sm leading-5 text-secondary-foreground\">\n {event.originalText}\n </blockquote>\n )}\n </div>\n </div>\n );\n }\n\n default:\n return assertNever(event);\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Structure\n * -------------------------------------------------------------------------------------------------*/\n\nfunction HistoryActorNode({\n actor,\n type,\n showConnector,\n}: {\n actor: HistoryActor;\n type: HistoryEventType;\n showConnector: boolean;\n}) {\n const category = historyEventCategoryConfig[type];\n const Icon = category.Icon;\n\n return (\n <div\n data-slot=\"history-event-node\"\n aria-hidden=\"true\"\n className=\"relative flex w-8 shrink-0 self-stretch justify-center\"\n >\n <Avatar\n src={actor.avatarSrc}\n fallback={getActorFallback(actor)}\n alt=\"\"\n size=\"sm\"\n shape=\"circle\"\n className=\"relative z-10\"\n />\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute left-[22px] top-[21px] z-20 flex size-4 items-center justify-center rounded-full ring-1 motion-safe:transition-[box-shadow,transform] motion-safe:duration-150 motion-safe:group-hover/history-event:scale-105 group-hover/history-event:shadow-sm',\n category.badgeClassName,\n )}\n >\n <Icon className=\"size-3\" />\n </span>\n {showConnector && (\n <span\n aria-hidden=\"true\"\n className=\"absolute bottom-[-12px] top-9 w-px rounded-full bg-border\"\n />\n )}\n </div>\n );\n}\n\nfunction HistoryActorFlags({ flags }: { flags?: string[] }) {\n if (!flags?.length) {\n return null;\n }\n\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1\">\n {flags.map((flag) => (\n <Badge key={flag} variant=\"soft\" color=\"purple\" size=\"xs\">\n {flag}\n </Badge>\n ))}\n </span>\n );\n}\n\ninterface HistoryItemProps {\n event: HistoryEvent;\n threshold: number;\n isLastInGroup: boolean;\n position: number;\n total: number;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n}\n\nfunction HistoryItem({\n event,\n threshold,\n isLastInGroup,\n position,\n total,\n expanded,\n onExpandedChange,\n}: HistoryItemProps) {\n const category = historyEventCategoryConfig[event.type];\n const headerId = React.useId();\n const contentId = React.useId();\n\n return (\n <article\n data-slot=\"history-event\"\n aria-labelledby={headerId}\n aria-setsize={total}\n aria-posinset={position}\n className=\"group/history-event flex min-w-0 gap-4 rounded-lg py-1 transition-colors duration-150 ease-out motion-reduce:transition-none hover:bg-muted/20\"\n >\n <HistoryActorNode\n actor={event.actor}\n type={event.type}\n showConnector={!isLastInGroup}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <div\n id={headerId}\n className=\"flex min-w-0 items-center gap-1.5 font-bold text-sm leading-5 text-card-foreground\"\n >\n <span className=\"truncate\">{event.actor.name}</span>\n <HistoryActorFlags flags={event.actorFlags} />\n <span className=\"sr-only\">{category.label}</span>\n </div>\n {event.dateTime ? (\n <time\n dateTime={event.dateTime}\n className=\"ms-auto shrink-0 text-xs leading-4 text-secondary-foreground\"\n >\n {event.timestamp}\n </time>\n ) : (\n <span className=\"ms-auto shrink-0 text-xs leading-4 text-secondary-foreground\">\n {event.timestamp}\n </span>\n )}\n </div>\n <HistoryEventBody\n event={event}\n threshold={threshold}\n expanded={expanded}\n contentId={contentId}\n onToggleExpanded={() => onExpandedChange(!expanded)}\n />\n </div>\n </article>\n );\n}\n\nfunction HistoryGroupSeparator({ label }: { label: string }) {\n return (\n <div\n data-slot=\"history-group-separator\"\n className=\"flex w-full items-center gap-2 text-sm font-medium leading-5 text-secondary-foreground\"\n >\n <span>{label}</span>\n <span aria-hidden=\"true\" className=\"h-px min-w-0 flex-1 bg-border\" />\n </div>\n );\n}\n\nfunction HistoryHeader({\n title,\n actions,\n}: {\n title: string;\n actions?: HistoryHeaderAction[];\n}) {\n return (\n <div\n data-slot=\"history-header\"\n className=\"flex min-w-0 items-start gap-3 pb-2\"\n >\n <h2 className=\"min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h2>\n {actions?.length ? (\n <div className=\"flex shrink-0 items-center gap-1\">\n {actions.map((action) => {\n const config = historyHeaderActionConfig[action.id];\n const Icon = config.Icon;\n\n return (\n <Button\n key={action.id}\n type=\"button\"\n appearance=\"ghost\"\n variant=\"secondary\"\n size=\"icon-xs\"\n shape=\"rounded\"\n iconOnly\n disabled={action.disabled}\n aria-label={action.label ?? config.label}\n onClick={action.onClick}\n className=\"size-11 text-secondary-foreground hover:text-foreground sm:size-6\"\n >\n <Icon aria-hidden=\"true\" className=\"size-4\" />\n </Button>\n );\n })}\n </div>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * History\n * -------------------------------------------------------------------------------------------------*/\n\nconst History = React.forwardRef<HTMLDivElement, HistoryProps>(\n (\n {\n title = 'History',\n groups,\n actions,\n loading,\n ariaLabel,\n emptyMessage = 'No history events',\n collapsibleChangeThreshold = 5,\n autoExpandNewestLargeEdit = true,\n expandedEventIds,\n defaultExpandedEventIds,\n onExpandedEventIdsChange,\n className,\n ...props\n },\n ref,\n ) => {\n const totalEvents = React.useMemo(() => getEventCount(groups), [groups]);\n const eventPositions = React.useMemo(\n () => getEventPositions(groups),\n [groups],\n );\n const { expandedIdSet, setExpanded } = useExpandedEventIds({\n groups,\n threshold: collapsibleChangeThreshold,\n autoExpandNewestLargeEdit,\n expandedEventIds,\n defaultExpandedEventIds,\n onExpandedEventIdsChange,\n });\n\n return (\n <div\n ref={ref}\n data-slot=\"history\"\n role=\"feed\"\n aria-label={ariaLabel ?? title}\n aria-busy={loading || undefined}\n className={cn(\n 'flex w-full max-w-[400px] min-w-0 flex-col gap-4 overflow-hidden rounded-[var(--borderradius-rounded-box,12px)] border border-border bg-background p-6 shadow-lg',\n className,\n )}\n {...props}\n >\n <HistoryHeader title={title} actions={actions} />\n {loading && totalEvents === 0 ? (\n <p\n role=\"status\"\n aria-live=\"polite\"\n className=\"text-sm leading-5 text-secondary-foreground\"\n >\n Loading history\n </p>\n ) : totalEvents === 0 ? (\n <p className=\"text-sm leading-5 text-secondary-foreground\">\n {emptyMessage}\n </p>\n ) : (\n <div\n data-slot=\"history-groups\"\n className=\"flex min-w-0 flex-col gap-4\"\n >\n {groups.map((group) => (\n <section\n key={group.id}\n data-slot=\"history-group\"\n aria-label={group.label}\n className=\"flex min-w-0 flex-col gap-2\"\n >\n <HistoryGroupSeparator label={group.label} />\n <div className=\"flex min-w-0 flex-col gap-4\">\n {group.events.map((event, index) => (\n <HistoryItem\n key={event.id}\n event={event}\n threshold={collapsibleChangeThreshold}\n isLastInGroup={index === group.events.length - 1}\n position={eventPositions.get(event.id) ?? 1}\n total={totalEvents}\n expanded={expandedIdSet.has(event.id)}\n onExpandedChange={(nextExpanded) =>\n setExpanded(event.id, nextExpanded)\n }\n />\n ))}\n </div>\n </section>\n ))}\n </div>\n )}\n </div>\n );\n },\n);\n\nHistory.displayName = 'History';\n\nexport {\n History,\n HistoryValue,\n historyEventCategoryConfig,\n historyHeaderActionConfig,\n};\n"],"mappings":"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"}
|
package/dist/index197.js
CHANGED
|
@@ -1,170 +1,194 @@
|
|
|
1
1
|
import { cn } from "./index2.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Button } from "./index5.js";
|
|
3
|
+
import { Input } from "./index33.js";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
//#region src/components/organisms/content/
|
|
9
|
-
var
|
|
10
|
-
variants: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
lg: "gap-6 p-6"
|
|
5
|
+
import { Mail } from "lucide-react";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/components/organisms/content/InlineCTA/InlineCTA.tsx
|
|
9
|
+
var inlineCTAVariants = cva("relative bg-background overflow-hidden shadow-xs", {
|
|
10
|
+
variants: { variant: {
|
|
11
|
+
bordered: "border border-border rounded-xl",
|
|
12
|
+
"full-width": "border-y border-border"
|
|
14
13
|
} },
|
|
15
|
-
defaultVariants: {
|
|
14
|
+
defaultVariants: { variant: "bordered" }
|
|
16
15
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
16
|
+
function InlineCTAActions({ title, description, primaryLabel = "Changelog", onPrimaryClick, secondaryLabel = "Dismiss", onSecondaryClick, stackedActions = false, variant, className, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
18
|
+
"data-slot": "inline-cta",
|
|
19
|
+
"aria-label": typeof title === "string" ? title : "Call to action",
|
|
20
|
+
className: cn(inlineCTAVariants({ variant }), "flex flex-col gap-5 p-6", className),
|
|
21
|
+
...props,
|
|
22
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
23
|
+
className: "flex flex-col gap-0.5",
|
|
24
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
25
|
+
className: "text-lg font-semibold leading-7 text-foreground",
|
|
26
|
+
children: title
|
|
27
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
28
|
+
className: "text-sm leading-5 text-muted-foreground",
|
|
29
|
+
children: description
|
|
30
|
+
})]
|
|
31
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
32
|
+
className: cn("flex gap-3", stackedActions ? "flex-col w-full" : "flex-row items-center"),
|
|
33
|
+
children: stackedActions ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
34
|
+
appearance: "gradient",
|
|
35
|
+
variant: "primary",
|
|
36
|
+
size: "md",
|
|
37
|
+
onClick: onPrimaryClick,
|
|
38
|
+
className: "w-full",
|
|
39
|
+
children: primaryLabel
|
|
40
|
+
}), secondaryLabel && /* @__PURE__ */ jsx(Button, {
|
|
41
|
+
appearance: "outline",
|
|
42
|
+
variant: "secondary",
|
|
43
|
+
size: "md",
|
|
44
|
+
onClick: onSecondaryClick,
|
|
45
|
+
className: "w-full",
|
|
46
|
+
children: secondaryLabel
|
|
47
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [secondaryLabel && /* @__PURE__ */ jsx(Button, {
|
|
48
|
+
appearance: "outline",
|
|
49
|
+
variant: "secondary",
|
|
50
|
+
size: "md",
|
|
51
|
+
onClick: onSecondaryClick,
|
|
52
|
+
children: secondaryLabel
|
|
53
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
54
|
+
appearance: "gradient",
|
|
55
|
+
variant: "primary",
|
|
56
|
+
size: "md",
|
|
57
|
+
onClick: onPrimaryClick,
|
|
58
|
+
children: primaryLabel
|
|
59
|
+
})] })
|
|
60
|
+
})]
|
|
61
|
+
});
|
|
39
62
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
size: "sm",
|
|
46
|
-
showYAxis: false,
|
|
47
|
-
showXAxis: false,
|
|
48
|
-
showTooltip: false,
|
|
49
|
-
className: "h-14 w-28"
|
|
63
|
+
function InlineCTAEmail({ title, description, inputLabel = "Subscribe to updates", inputPlaceholder = "you@humain.ai", submitLabel = "Subscribe", onSubmit, stackedLayout = false, defaultValue = "", loading = false, variant, className, ...props }) {
|
|
64
|
+
const [email, setEmail] = React.useState(defaultValue);
|
|
65
|
+
const handleSubmit = (e) => {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
onSubmit?.(email);
|
|
50
68
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
69
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
70
|
+
"data-slot": "inline-cta",
|
|
71
|
+
"aria-label": typeof title === "string" ? title : "Subscribe",
|
|
72
|
+
className: cn(inlineCTAVariants({ variant }), "flex flex-col gap-5 p-6", className),
|
|
73
|
+
...props,
|
|
74
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
75
|
+
className: "flex flex-col gap-0.5",
|
|
76
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
77
|
+
className: "text-lg font-semibold leading-7 text-foreground",
|
|
78
|
+
children: title
|
|
79
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
80
|
+
className: "text-sm leading-5 text-muted-foreground",
|
|
81
|
+
children: description
|
|
82
|
+
})]
|
|
83
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
84
|
+
onSubmit: handleSubmit,
|
|
85
|
+
className: cn("flex gap-4", stackedLayout ? "flex-col w-full" : "flex-row items-end max-w-md"),
|
|
86
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
87
|
+
className: cn(stackedLayout ? "w-full" : "flex-1"),
|
|
88
|
+
children: /* @__PURE__ */ jsx(Input, {
|
|
89
|
+
type: "email",
|
|
90
|
+
label: inputLabel,
|
|
91
|
+
placeholder: inputPlaceholder,
|
|
92
|
+
value: email,
|
|
93
|
+
onChange: (e) => setEmail(e.target.value),
|
|
94
|
+
startIcon: /* @__PURE__ */ jsx(Mail, {}),
|
|
95
|
+
required: true
|
|
96
|
+
})
|
|
97
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
98
|
+
type: "submit",
|
|
99
|
+
appearance: "gradient",
|
|
100
|
+
variant: "primary",
|
|
101
|
+
size: "lg",
|
|
102
|
+
loading,
|
|
103
|
+
className: cn(stackedLayout && "w-full"),
|
|
104
|
+
children: submitLabel
|
|
105
|
+
})]
|
|
106
|
+
})]
|
|
58
107
|
});
|
|
59
108
|
}
|
|
60
|
-
function
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const hasAnimated = useRef(false);
|
|
66
|
-
const rootRef = useRef(null);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (hasAnimated.current) {
|
|
69
|
-
setDisplayValue(safeValue);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
hasAnimated.current = true;
|
|
73
|
-
const win = rootRef.current?.ownerDocument.defaultView;
|
|
74
|
-
if (!win) {
|
|
75
|
-
setDisplayValue(safeValue);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (win.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
79
|
-
setDisplayValue(safeValue);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const duration = 600;
|
|
83
|
-
const startTime = win.performance.now();
|
|
84
|
-
let frameId;
|
|
85
|
-
const animate = (now) => {
|
|
86
|
-
const elapsed = now - startTime;
|
|
87
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
88
|
-
const eased = 1 - (1 - progress) ** 3;
|
|
89
|
-
setDisplayValue(Math.round(eased * safeValue));
|
|
90
|
-
if (progress < 1) frameId = win.requestAnimationFrame(animate);
|
|
91
|
-
else setDisplayValue(safeValue);
|
|
92
|
-
};
|
|
93
|
-
frameId = win.requestAnimationFrame(animate);
|
|
94
|
-
return () => win.cancelAnimationFrame(frameId);
|
|
95
|
-
}, [safeValue]);
|
|
96
|
-
const calculatedChange = useMemo(() => {
|
|
97
|
-
if (changeOverride !== void 0) return getFiniteMetricValue(changeOverride);
|
|
98
|
-
if (change !== void 0) return getFiniteMetricValue(change);
|
|
99
|
-
if (!data || data.length < 2 || !series || series.length === 0) return void 0;
|
|
100
|
-
const seriesId = series[0].id;
|
|
101
|
-
const firstValue = data[0].values[seriesId];
|
|
102
|
-
const lastValue = data[data.length - 1].values[seriesId];
|
|
103
|
-
if (firstValue === 0 || firstValue === void 0 || !Number.isFinite(firstValue) || !Number.isFinite(lastValue)) return void 0;
|
|
104
|
-
return (lastValue - firstValue) / firstValue * 100;
|
|
105
|
-
}, [
|
|
106
|
-
data,
|
|
107
|
-
series,
|
|
108
|
-
change,
|
|
109
|
-
changeOverride
|
|
110
|
-
]);
|
|
111
|
-
const changeDirection = calculatedChange && calculatedChange > 0 ? "up" : "down";
|
|
112
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
113
|
-
ref: rootRef,
|
|
114
|
-
"data-slot": "metric-card",
|
|
115
|
-
className: cn(metricCardVariants({ size }), "transition-shadow duration-200 ease-out hover:shadow-md motion-reduce:transition-none", className),
|
|
109
|
+
function InlineCTAImage({ title, description, imageSrc, imageAlt = "Featured image", showPlayButton = false, onPlayClick, primaryLabel = "Changelog", onPrimaryClick, secondaryLabel = "Dismiss", onSecondaryClick, stackedActions = false, variant, className, ...props }) {
|
|
110
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
111
|
+
"data-slot": "inline-cta",
|
|
112
|
+
"aria-label": typeof title === "string" ? title : "Call to action",
|
|
113
|
+
className: cn(inlineCTAVariants({ variant }), "flex flex-col", className),
|
|
116
114
|
...props,
|
|
117
|
-
children: [
|
|
118
|
-
className:
|
|
119
|
-
children:
|
|
115
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
116
|
+
className: "relative aspect-video w-full overflow-hidden",
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsx("img", {
|
|
119
|
+
src: imageSrc,
|
|
120
|
+
alt: imageAlt,
|
|
121
|
+
loading: "lazy",
|
|
122
|
+
className: "absolute inset-0 size-full object-cover"
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 border border-border rounded-t-xl" }),
|
|
125
|
+
showPlayButton && /* @__PURE__ */ jsx("button", {
|
|
126
|
+
type: "button",
|
|
127
|
+
onClick: onPlayClick,
|
|
128
|
+
className: "absolute bottom-3 start-3 size-11 rounded-full bg-card/80 supports-backdrop-filter:backdrop-blur-sm flex items-center justify-center hover:bg-background transition-colors",
|
|
129
|
+
"aria-label": "Play video",
|
|
130
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
131
|
+
className: "size-4 ms-0.5 text-foreground",
|
|
132
|
+
fill: "currentColor",
|
|
133
|
+
viewBox: "0 0 16 16",
|
|
134
|
+
children: /* @__PURE__ */ jsx("path", { d: "M4 3.5v9l8-4.5-8-4.5z" })
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
]
|
|
120
138
|
}), /* @__PURE__ */ jsxs("div", {
|
|
121
|
-
className: "flex
|
|
139
|
+
className: "flex flex-col gap-5 p-4 border-x border-b border-border rounded-b-xl",
|
|
122
140
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
123
|
-
className: "flex flex-col gap-
|
|
124
|
-
children: [/* @__PURE__ */ jsx("
|
|
125
|
-
className:
|
|
126
|
-
children:
|
|
127
|
-
}),
|
|
128
|
-
className: "
|
|
129
|
-
children:
|
|
130
|
-
className: cn("inline-flex items-center gap-0.5 font-medium", changeSizeClasses[size || "md"], changeSentimentColors[changeSentiment]),
|
|
131
|
-
children: [
|
|
132
|
-
changeDirection === "up" ? /* @__PURE__ */ jsx(ArrowUp, {
|
|
133
|
-
className: "size-4",
|
|
134
|
-
"aria-hidden": "true"
|
|
135
|
-
}) : /* @__PURE__ */ jsx(ArrowDown, {
|
|
136
|
-
className: "size-4",
|
|
137
|
-
"aria-hidden": "true"
|
|
138
|
-
}),
|
|
139
|
-
/* @__PURE__ */ jsx("span", {
|
|
140
|
-
className: "sr-only",
|
|
141
|
-
children: changeDirection === "up" ? "Increased" : "Decreased"
|
|
142
|
-
}),
|
|
143
|
-
/* @__PURE__ */ jsx("span", { children: changeFormatter(calculatedChange) })
|
|
144
|
-
]
|
|
145
|
-
}), description && /* @__PURE__ */ jsx("span", {
|
|
146
|
-
className: cn("font-medium text-muted-foreground", changeSizeClasses[size || "md"]),
|
|
147
|
-
children: description
|
|
148
|
-
})]
|
|
141
|
+
className: "flex flex-col gap-0.5",
|
|
142
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
143
|
+
className: "text-lg font-semibold leading-7 text-foreground",
|
|
144
|
+
children: title
|
|
145
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
146
|
+
className: "text-sm leading-5 text-muted-foreground",
|
|
147
|
+
children: description
|
|
149
148
|
})]
|
|
150
|
-
}),
|
|
151
|
-
"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
149
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
150
|
+
className: cn("flex gap-3", stackedActions ? "flex-col w-full" : "flex-row items-center"),
|
|
151
|
+
children: stackedActions ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
152
|
+
appearance: "gradient",
|
|
153
|
+
variant: "primary",
|
|
154
|
+
size: "md",
|
|
155
|
+
onClick: onPrimaryClick,
|
|
156
|
+
className: "w-full",
|
|
157
|
+
children: primaryLabel
|
|
158
|
+
}), secondaryLabel && /* @__PURE__ */ jsx(Button, {
|
|
159
|
+
appearance: "outline",
|
|
160
|
+
variant: "secondary",
|
|
161
|
+
size: "md",
|
|
162
|
+
onClick: onSecondaryClick,
|
|
163
|
+
className: "w-full",
|
|
164
|
+
children: secondaryLabel
|
|
165
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [secondaryLabel && /* @__PURE__ */ jsx(Button, {
|
|
166
|
+
appearance: "outline",
|
|
167
|
+
variant: "secondary",
|
|
168
|
+
size: "md",
|
|
169
|
+
onClick: onSecondaryClick,
|
|
170
|
+
children: secondaryLabel
|
|
171
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
172
|
+
appearance: "gradient",
|
|
173
|
+
variant: "primary",
|
|
174
|
+
size: "md",
|
|
175
|
+
onClick: onPrimaryClick,
|
|
176
|
+
children: primaryLabel
|
|
177
|
+
})] })
|
|
162
178
|
})]
|
|
163
179
|
})]
|
|
164
180
|
});
|
|
165
181
|
}
|
|
166
|
-
|
|
182
|
+
function InlineCTA(props) {
|
|
183
|
+
switch (props.type) {
|
|
184
|
+
case "actions": return /* @__PURE__ */ jsx(InlineCTAActions, { ...props });
|
|
185
|
+
case "email": return /* @__PURE__ */ jsx(InlineCTAEmail, { ...props });
|
|
186
|
+
case "image": return /* @__PURE__ */ jsx(InlineCTAImage, { ...props });
|
|
187
|
+
default: return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
InlineCTA.displayName = "InlineCTA";
|
|
167
191
|
//#endregion
|
|
168
|
-
export {
|
|
192
|
+
export { InlineCTA, inlineCTAVariants };
|
|
169
193
|
|
|
170
194
|
//# sourceMappingURL=index197.js.map
|
package/dist/index197.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index197.js","names":[],"sources":["../src/components/organisms/content/MetricCard/MetricCard.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowDown, ArrowUp } from 'lucide-react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { BarChart } from '@/components/molecules/charts/BarChart';\nimport {\n type ChartDataPoint,\n type ChartSeries,\n LineChart,\n} from '@/components/molecules/charts/LineChart';\nimport { cn } from '@/lib/utils';\n\nconst metricCardVariants = cva(\n 'bg-background border border-border rounded-xl shadow-sm flex flex-col w-full',\n {\n variants: {\n size: {\n sm: 'gap-3 p-3', // Compact: 12px padding, 12px gap\n md: 'gap-5 p-5', // Default: 20px padding, 20px gap (Figma)\n lg: 'gap-6 p-6', // Spacious: 24px padding, 24px gap\n },\n },\n defaultVariants: {\n size: 'md',\n },\n },\n);\n\n// Title sizes\nconst titleSizeClasses = {\n sm: 'text-sm', // 14px\n md: 'text-md', // 16px (matches Figma)\n lg: 'text-lg', // 18px\n};\n\n// Value sizes\nconst valueSizeClasses = {\n sm: 'text-display-xs',\n md: 'text-display-sm',\n lg: 'text-display-md',\n};\n\n// Change indicator sizes\nconst changeSizeClasses = {\n sm: 'text-xs', // 12px\n md: 'text-sm', // 14px (matches Figma)\n lg: 'text-base', // 16px\n};\n\n// Change sentiment colors\nconst changeSentimentColors = {\n positive: 'text-success',\n negative: 'text-destructive',\n neutral: 'text-muted-foreground',\n};\n\nfunction getFiniteMetricValue(value: number): number {\n return Number.isFinite(value) ? value : 0;\n}\n\nexport interface MetricCardProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof metricCardVariants> {\n // Required\n /** The primary metric value to display */\n value: number;\n\n // Optional core elements\n /** Title displayed above the metric */\n title?: string;\n /** Description text (e.g., \"vs last month\") */\n description?: string;\n\n // Change indicator (hybrid approach)\n /** Change value (auto-calculated if omitted but data provided) */\n change?: number;\n /** Explicit override for change value */\n changeOverride?: number;\n /** Sentiment for change indicator color */\n changeSentiment?: 'positive' | 'negative' | 'neutral';\n\n // Chart data (standardized format)\n /** Chart data points */\n data?: ChartDataPoint[];\n /** Chart series configuration */\n series?: ChartSeries[];\n /** Type of chart to display */\n chartType?: 'line' | 'bar' | 'area';\n\n // Chart customization (moderate control)\n /** Stroke width for line/area charts */\n strokeWidth?: number;\n /** Show area fill under lines (for line/area charts) */\n showArea?: boolean;\n /** Show dots on data points (for line charts) */\n showDots?: boolean;\n /** Curve type for line/area charts */\n curveType?: 'linear' | 'smooth';\n\n // Formatting\n /** Custom formatter for the value */\n valueFormatter?: (n: number) => string;\n /** Custom formatter for the change indicator */\n changeFormatter?: (n: number) => string;\n}\n\ninterface MetricCardMiniChartProps {\n data?: ChartDataPoint[];\n series?: ChartSeries[];\n chartType: NonNullable<MetricCardProps['chartType']>;\n strokeWidth: number;\n showArea: boolean;\n showDots: boolean;\n curveType: NonNullable<MetricCardProps['curveType']>;\n}\n\nfunction MetricCardMiniChart({\n data,\n series,\n chartType,\n strokeWidth,\n showArea,\n showDots,\n curveType,\n}: MetricCardMiniChartProps) {\n if (!data || !series) return null;\n\n const sharedProps = {\n data,\n series,\n size: 'sm' as const,\n showYAxis: false,\n showXAxis: false,\n showTooltip: false,\n className: 'h-14 w-28',\n };\n\n if (chartType === 'bar') {\n return <BarChart {...sharedProps} />;\n }\n\n return (\n <LineChart\n {...sharedProps}\n strokeWidth={strokeWidth}\n showDots={showDots}\n curveType={curveType}\n showArea={chartType === 'area' || showArea}\n />\n );\n}\n\nfunction MetricCard({\n value,\n title,\n description = 'vs last month',\n change,\n changeOverride,\n changeSentiment = 'neutral',\n data,\n series,\n chartType = 'line',\n strokeWidth = 2,\n showArea = true,\n showDots = false,\n curveType = 'smooth',\n valueFormatter = (n) => n.toLocaleString(),\n changeFormatter = (n) => {\n return `${Math.abs(n).toFixed(0)}%`;\n },\n size = 'md',\n className,\n ...props\n}: MetricCardProps) {\n // Count-up animation on mount\n const safeValue = getFiniteMetricValue(value);\n const [displayValue, setDisplayValue] = useState(0);\n const hasAnimated = useRef(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (hasAnimated.current) {\n setDisplayValue(safeValue);\n return;\n }\n hasAnimated.current = true;\n\n // Respect reduced motion preference (SSR-safe via ownerDocument.defaultView)\n const win = rootRef.current?.ownerDocument.defaultView;\n if (!win) {\n setDisplayValue(safeValue);\n return;\n }\n\n const prefersReducedMotion = win.matchMedia(\n '(prefers-reduced-motion: reduce)',\n ).matches;\n if (prefersReducedMotion) {\n setDisplayValue(safeValue);\n return;\n }\n\n const duration = 600;\n const startTime = win.performance.now();\n let frameId: number;\n\n const animate = (now: number) => {\n const elapsed = now - startTime;\n const progress = Math.min(elapsed / duration, 1);\n // Ease-out cubic for smooth deceleration\n const eased = 1 - (1 - progress) ** 3;\n setDisplayValue(Math.round(eased * safeValue));\n\n if (progress < 1) {\n frameId = win.requestAnimationFrame(animate);\n } else {\n setDisplayValue(safeValue);\n }\n };\n\n frameId = win.requestAnimationFrame(animate);\n return () => win.cancelAnimationFrame(frameId);\n }, [safeValue]);\n\n // Calculate change from data if not explicitly provided\n const calculatedChange = useMemo(() => {\n // Priority: override > explicit > auto-calculate\n if (changeOverride !== undefined)\n return getFiniteMetricValue(changeOverride);\n if (change !== undefined) return getFiniteMetricValue(change);\n if (!data || data.length < 2 || !series || series.length === 0)\n return undefined;\n\n // Compare first and last data points using the first series id\n const seriesId = series[0].id;\n const firstValue = data[0].values[seriesId];\n const lastValue = data[data.length - 1].values[seriesId];\n\n if (\n firstValue === 0 ||\n firstValue === undefined ||\n !Number.isFinite(firstValue) ||\n !Number.isFinite(lastValue)\n )\n return undefined; // Avoid division by zero and invalid calculations\n\n return ((lastValue - firstValue) / firstValue) * 100;\n }, [data, series, change, changeOverride]);\n\n const changeDirection =\n calculatedChange && calculatedChange > 0 ? 'up' : 'down';\n\n return (\n <div\n ref={rootRef}\n data-slot=\"metric-card\"\n className={cn(\n metricCardVariants({ size }),\n 'transition-shadow duration-200 ease-out hover:shadow-md motion-reduce:transition-none',\n className,\n )}\n {...props}\n >\n {/* Title */}\n {title && (\n <h3\n className={cn(\n 'font-semibold text-foreground',\n titleSizeClasses[size || 'md'],\n )}\n >\n {title}\n </h3>\n )}\n\n {/* Bottom row: Value + Change on left, Chart on right */}\n <div className=\"flex items-end gap-4\">\n {/* Left side: Value + Change badge */}\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n {/* Value */}\n <div\n className={cn(\n 'font-semibold text-foreground',\n valueSizeClasses[size || 'md'],\n )}\n >\n {valueFormatter(displayValue)}\n </div>\n\n {/* Change indicator + Description */}\n {calculatedChange !== undefined && (\n <div className=\"flex items-center gap-2\">\n {/* Change badge */}\n <div\n className={cn(\n 'inline-flex items-center gap-0.5 font-medium',\n changeSizeClasses[size || 'md'],\n changeSentimentColors[changeSentiment],\n )}\n >\n {changeDirection === 'up' ? (\n <ArrowUp className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowDown className=\"size-4\" aria-hidden=\"true\" />\n )}\n <span className=\"sr-only\">\n {changeDirection === 'up' ? 'Increased' : 'Decreased'}\n </span>\n <span>{changeFormatter(calculatedChange)}</span>\n </div>\n\n {/* Description */}\n {description && (\n <span\n className={cn(\n 'font-medium text-muted-foreground',\n changeSizeClasses[size || 'md'],\n )}\n >\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Right side: Mini chart (decorative sparkline) */}\n {data && series && (\n <div aria-hidden=\"true\" inert={true}>\n <MetricCardMiniChart\n data={data}\n series={series}\n chartType={chartType}\n strokeWidth={strokeWidth}\n showArea={showArea}\n showDots={showDots}\n curveType={curveType}\n />\n </div>\n )}\n </div>\n </div>\n );\n}\n\nMetricCard.displayName = 'MetricCard';\n\nexport { MetricCard, metricCardVariants };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index197.js","names":[],"sources":["../src/components/organisms/content/InlineCTA/InlineCTA.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { Mail } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { Input } from '@/components/atoms/forms/Input';\nimport { cn } from '@/lib/utils';\n\nconst inlineCTAVariants = cva(\n 'relative bg-background overflow-hidden shadow-xs',\n {\n variants: {\n variant: {\n bordered: 'border border-border rounded-xl',\n 'full-width': 'border-y border-border',\n },\n },\n defaultVariants: {\n variant: 'bordered',\n },\n },\n);\n\ninterface InlineCTABaseProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSubmit'>,\n VariantProps<typeof inlineCTAVariants> {\n /** Title text for the CTA */\n title: React.ReactNode;\n /** Supporting description text */\n description?: React.ReactNode;\n}\n\n// ============================================================================\n// Actions Type - Simple CTA with title, description, and action buttons\n// ============================================================================\n\nexport interface InlineCTAActionsProps extends InlineCTABaseProps {\n type: 'actions';\n /** Primary action button label */\n primaryLabel?: string;\n /** Callback when primary button is clicked */\n onPrimaryClick?: () => void;\n /** Secondary action button label */\n secondaryLabel?: string;\n /** Callback when secondary button is clicked */\n onSecondaryClick?: () => void;\n /** Stack buttons vertically (for mobile) */\n stackedActions?: boolean;\n}\n\nfunction InlineCTAActions({\n title,\n description,\n primaryLabel = 'Changelog',\n onPrimaryClick,\n secondaryLabel = 'Dismiss',\n onSecondaryClick,\n stackedActions = false,\n variant,\n className,\n ...props\n}: InlineCTAActionsProps) {\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Call to action'}\n className={cn(\n inlineCTAVariants({ variant }),\n 'flex flex-col gap-5 p-6',\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <div\n className={cn(\n 'flex gap-3',\n stackedActions ? 'flex-col w-full' : 'flex-row items-center',\n )}\n >\n {stackedActions ? (\n <>\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n className=\"w-full\"\n >\n {primaryLabel}\n </Button>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n className=\"w-full\"\n >\n {secondaryLabel}\n </Button>\n )}\n </>\n ) : (\n <>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n >\n {secondaryLabel}\n </Button>\n )}\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n >\n {primaryLabel}\n </Button>\n </>\n )}\n </div>\n </section>\n );\n}\n\n// ============================================================================\n// Email Type - Subscribe form with email input\n// ============================================================================\n\nexport interface InlineCTAEmailProps extends InlineCTABaseProps {\n type: 'email';\n /** Label for the email input field */\n inputLabel?: string;\n /** Placeholder for the email input */\n inputPlaceholder?: string;\n /** Submit button label */\n submitLabel?: string;\n /** Callback when form is submitted */\n onSubmit?: (email: string) => void;\n /** Stack input and button vertically (for mobile) */\n stackedLayout?: boolean;\n /** Default email value */\n defaultValue?: string;\n /** Loading state for the submit button */\n loading?: boolean;\n}\n\nfunction InlineCTAEmail({\n title,\n description,\n inputLabel = 'Subscribe to updates',\n inputPlaceholder = 'you@humain.ai',\n submitLabel = 'Subscribe',\n onSubmit,\n stackedLayout = false,\n defaultValue = '',\n loading = false,\n variant,\n className,\n ...props\n}: InlineCTAEmailProps) {\n const [email, setEmail] = React.useState(defaultValue);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onSubmit?.(email);\n };\n\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Subscribe'}\n className={cn(\n inlineCTAVariants({ variant }),\n 'flex flex-col gap-5 p-6',\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <form\n onSubmit={handleSubmit}\n className={cn(\n 'flex gap-4',\n stackedLayout ? 'flex-col w-full' : 'flex-row items-end max-w-md',\n )}\n >\n <div className={cn(stackedLayout ? 'w-full' : 'flex-1')}>\n <Input\n type=\"email\"\n label={inputLabel}\n placeholder={inputPlaceholder}\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n startIcon={<Mail />}\n required\n />\n </div>\n <Button\n type=\"submit\"\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"lg\"\n loading={loading}\n className={cn(stackedLayout && 'w-full')}\n >\n {submitLabel}\n </Button>\n </form>\n </section>\n );\n}\n\n// ============================================================================\n// Image Type - CTA with featured image\n// ============================================================================\n\nexport interface InlineCTAImageProps extends InlineCTABaseProps {\n type: 'image';\n /** Image source URL */\n imageSrc: string;\n /** Image alt text */\n imageAlt?: string;\n /** Show play button overlay on image */\n showPlayButton?: boolean;\n /** Callback when play button is clicked */\n onPlayClick?: () => void;\n /** Primary action button label */\n primaryLabel?: string;\n /** Callback when primary button is clicked */\n onPrimaryClick?: () => void;\n /** Secondary action button label */\n secondaryLabel?: string;\n /** Callback when secondary button is clicked */\n onSecondaryClick?: () => void;\n /** Stack buttons vertically (for mobile) */\n stackedActions?: boolean;\n}\n\nfunction InlineCTAImage({\n title,\n description,\n imageSrc,\n imageAlt = 'Featured image',\n showPlayButton = false,\n onPlayClick,\n primaryLabel = 'Changelog',\n onPrimaryClick,\n secondaryLabel = 'Dismiss',\n onSecondaryClick,\n stackedActions = false,\n variant,\n className,\n ...props\n}: InlineCTAImageProps) {\n return (\n <section\n data-slot=\"inline-cta\"\n aria-label={typeof title === 'string' ? title : 'Call to action'}\n className={cn(inlineCTAVariants({ variant }), 'flex flex-col', className)}\n {...props}\n >\n <div className=\"relative aspect-video w-full overflow-hidden\">\n <img\n src={imageSrc}\n alt={imageAlt}\n loading=\"lazy\"\n className=\"absolute inset-0 size-full object-cover\"\n />\n <div className=\"absolute inset-0 border border-border rounded-t-xl\" />\n {showPlayButton && (\n <button\n type=\"button\"\n onClick={onPlayClick}\n className=\"absolute bottom-3 start-3 size-11 rounded-full bg-card/80 supports-backdrop-filter:backdrop-blur-sm flex items-center justify-center hover:bg-background transition-colors\"\n aria-label=\"Play video\"\n >\n <svg\n className=\"size-4 ms-0.5 text-foreground\"\n fill=\"currentColor\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M4 3.5v9l8-4.5-8-4.5z\" />\n </svg>\n </button>\n )}\n </div>\n\n <div className=\"flex flex-col gap-5 p-4 border-x border-b border-border rounded-b-xl\">\n <div className=\"flex flex-col gap-0.5\">\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"text-sm leading-5 text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n\n <div\n className={cn(\n 'flex gap-3',\n stackedActions ? 'flex-col w-full' : 'flex-row items-center',\n )}\n >\n {stackedActions ? (\n <>\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n className=\"w-full\"\n >\n {primaryLabel}\n </Button>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n className=\"w-full\"\n >\n {secondaryLabel}\n </Button>\n )}\n </>\n ) : (\n <>\n {secondaryLabel && (\n <Button\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"md\"\n onClick={onSecondaryClick}\n >\n {secondaryLabel}\n </Button>\n )}\n <Button\n appearance=\"gradient\"\n variant=\"primary\"\n size=\"md\"\n onClick={onPrimaryClick}\n >\n {primaryLabel}\n </Button>\n </>\n )}\n </div>\n </div>\n </section>\n );\n}\n\n// ============================================================================\n// Compound Component Export\n// ============================================================================\n\nexport type InlineCTAProps =\n | InlineCTAActionsProps\n | InlineCTAEmailProps\n | InlineCTAImageProps;\n\nfunction InlineCTA(props: InlineCTAProps) {\n switch (props.type) {\n case 'actions':\n return <InlineCTAActions {...props} />;\n case 'email':\n return <InlineCTAEmail {...props} />;\n case 'image':\n return <InlineCTAImage {...props} />;\n default:\n return null;\n }\n}\n\nInlineCTA.displayName = 'InlineCTA';\n\nexport { InlineCTA, inlineCTAVariants };\n"],"mappings":"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"}
|