@humain/ui 2.1.63 → 2.1.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
  2. package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
  3. package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
  4. package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
  5. package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
  6. package/dist/index.js +52 -52
  7. package/dist/index151.js +1 -1
  8. package/dist/index174.js +7 -339
  9. package/dist/index174.js.map +1 -1
  10. package/dist/index175.js +310 -137
  11. package/dist/index175.js.map +1 -1
  12. package/dist/index176.js +148 -174
  13. package/dist/index176.js.map +1 -1
  14. package/dist/index177.js +186 -78
  15. package/dist/index177.js.map +1 -1
  16. package/dist/index178.js +74 -124
  17. package/dist/index178.js.map +1 -1
  18. package/dist/index179.js +133 -1
  19. package/dist/index179.js.map +1 -0
  20. package/dist/index180.js +2 -201
  21. package/dist/index181.js +201 -0
  22. package/dist/{index180.js.map → index181.js.map} +1 -1
  23. package/dist/index183.js +130 -166
  24. package/dist/index183.js.map +1 -1
  25. package/dist/index184.js +195 -983
  26. package/dist/index184.js.map +1 -1
  27. package/dist/index185.js +1069 -369
  28. package/dist/index185.js.map +1 -1
  29. package/dist/index186.js +395 -197
  30. package/dist/index186.js.map +1 -1
  31. package/dist/index187.js +198 -243
  32. package/dist/index187.js.map +1 -1
  33. package/dist/index188.js +263 -3
  34. package/dist/index188.js.map +1 -1
  35. package/dist/index189.js +3 -209
  36. package/dist/index189.js.map +1 -1
  37. package/dist/index190.js +190 -777
  38. package/dist/index190.js.map +1 -1
  39. package/dist/index191.js +771 -252
  40. package/dist/index191.js.map +1 -1
  41. package/dist/index192.js +250 -65
  42. package/dist/index192.js.map +1 -1
  43. package/dist/index193.js +72 -523
  44. package/dist/index193.js.map +1 -1
  45. package/dist/index194.js +537 -144
  46. package/dist/index194.js.map +1 -1
  47. package/dist/index195.js +139 -720
  48. package/dist/index195.js.map +1 -1
  49. package/dist/index196.js +707 -167
  50. package/dist/index196.js.map +1 -1
  51. package/dist/index197.js +175 -151
  52. package/dist/index197.js.map +1 -1
  53. package/dist/index198.js +152 -487
  54. package/dist/index198.js.map +1 -1
  55. package/dist/index199.js +472 -225
  56. package/dist/index199.js.map +1 -1
  57. package/dist/index200.js +236 -260
  58. package/dist/index200.js.map +1 -1
  59. package/dist/index201.js +265 -215
  60. package/dist/index201.js.map +1 -1
  61. package/dist/index202.js +207 -307
  62. package/dist/index202.js.map +1 -1
  63. package/dist/index203.js +302 -135
  64. package/dist/index203.js.map +1 -1
  65. package/dist/index204.js +140 -271
  66. package/dist/index204.js.map +1 -1
  67. package/dist/index205.js +263 -253
  68. package/dist/index205.js.map +1 -1
  69. package/dist/index206.js +244 -137
  70. package/dist/index206.js.map +1 -1
  71. package/dist/index207.js +100 -238
  72. package/dist/index207.js.map +1 -1
  73. package/dist/index208.js +278 -74
  74. package/dist/index208.js.map +1 -1
  75. package/dist/index209.js +56 -97
  76. package/dist/index209.js.map +1 -1
  77. package/dist/index210.js +142 -47
  78. package/dist/index210.js.map +1 -1
  79. package/dist/index211.js +38 -84
  80. package/dist/index211.js.map +1 -1
  81. package/dist/index212.js +72 -252
  82. package/dist/index212.js.map +1 -1
  83. package/dist/index213.js +274 -26
  84. package/dist/index213.js.map +1 -1
  85. package/dist/index214.js +29 -94
  86. package/dist/index214.js.map +1 -1
  87. package/dist/index215.js +98 -25
  88. package/dist/index215.js.map +1 -1
  89. package/dist/index216.js +20 -565
  90. package/dist/index216.js.map +1 -1
  91. package/dist/index217.js +564 -17
  92. package/dist/index217.js.map +1 -1
  93. package/dist/index218.js +20 -23
  94. package/dist/index218.js.map +1 -1
  95. package/dist/index219.js +20 -95
  96. package/dist/index219.js.map +1 -1
  97. package/dist/index220.js +92 -88
  98. package/dist/index220.js.map +1 -1
  99. package/dist/index221.js +97 -29
  100. package/dist/index221.js.map +1 -1
  101. package/dist/index222.js +24 -470
  102. package/dist/index222.js.map +1 -1
  103. package/dist/index223.js +446 -196
  104. package/dist/index223.js.map +1 -1
  105. package/dist/index224.js +199 -729
  106. package/dist/index224.js.map +1 -1
  107. package/dist/index225.js +750 -61
  108. package/dist/index225.js.map +1 -1
  109. package/dist/index226.js +58 -181
  110. package/dist/index226.js.map +1 -1
  111. package/dist/index227.js +175 -259
  112. package/dist/index227.js.map +1 -1
  113. package/dist/index228.js +246 -172
  114. package/dist/index228.js.map +1 -1
  115. package/dist/index229.js +195 -32
  116. package/dist/index229.js.map +1 -1
  117. package/dist/index230.js +12 -40
  118. package/dist/index230.js.map +1 -1
  119. package/dist/index231.js +23 -26
  120. package/dist/index231.js.map +1 -1
  121. package/dist/index232.js +45 -22
  122. package/dist/index232.js.map +1 -1
  123. package/dist/index233.js +27 -48
  124. package/dist/index233.js.map +1 -1
  125. package/dist/index234.js +52 -26
  126. package/dist/index234.js.map +1 -1
  127. package/dist/index235.js +40 -225
  128. package/dist/index235.js.map +1 -1
  129. package/dist/index236.js +217 -39
  130. package/dist/index236.js.map +1 -1
  131. package/dist/index237.js +50 -0
  132. package/dist/index237.js.map +1 -0
  133. package/dist/styles.css +1 -1
  134. package/dist/wc/AIToolCall.js +218 -0
  135. package/dist/wc/AIToolCall.js.map +1 -0
  136. package/dist/wc/hf-ai-tool-call.js +34 -219
  137. package/dist/wc/hf-ai-tool-call.js.map +1 -1
  138. package/dist/wc/hf-ai-tool-run.js +673 -576
  139. package/dist/wc/hf-ai-tool-run.js.map +1 -1
  140. package/dist/wc/workflow-step-renderer.js +79 -78
  141. package/dist/wc/workflow-step-renderer.js.map +1 -1
  142. package/dist/wc-react/AIToolCall.js +218 -0
  143. package/dist/wc-react/AIToolCall.js.map +1 -0
  144. package/dist/wc-react/hf-ai-tool-call.js +32 -217
  145. package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
  146. package/dist/wc-react/hf-ai-tool-run.js +698 -601
  147. package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
  148. package/dist/wc-react/workflow-step-renderer.js +58 -57
  149. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  150. package/package.json +1 -1
  151. package/skills/humain-ui/SKILL.md +1 -1
  152. package/skills/humain-ui-wc/SKILL.md +1 -1
  153. package/skills/humain-ui-wc.skill +0 -0
  154. package/skills/humain-ui.skill +0 -0
  155. package/dist/index182.js +0 -143
  156. package/dist/index182.js.map +0 -1
  157. package/dist/wc/wrench.js +0 -10
  158. package/dist/wc/wrench.js.map +0 -1
  159. package/dist/wc-react/wrench.js +0 -10
  160. package/dist/wc-react/wrench.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"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 { LineChart } from "./index64.js";
3
- import { BarChart } from "./index65.js";
2
+ import { Button } from "./index5.js";
3
+ import { Input } from "./index33.js";
4
4
  import { cva } from "class-variance-authority";
5
- import { ArrowDown, ArrowUp } from "lucide-react";
6
- import { useEffect, useMemo, useRef, useState } from "react";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
- //#region src/components/organisms/content/MetricCard/MetricCard.tsx
9
- var metricCardVariants = cva("bg-background border border-border rounded-xl shadow-sm flex flex-col w-full", {
10
- variants: { size: {
11
- sm: "gap-3 p-3",
12
- md: "gap-5 p-5",
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: { size: "md" }
14
+ defaultVariants: { variant: "bordered" }
16
15
  });
17
- var titleSizeClasses = {
18
- sm: "text-sm",
19
- md: "text-md",
20
- lg: "text-lg"
21
- };
22
- var valueSizeClasses = {
23
- sm: "text-display-xs",
24
- md: "text-display-sm",
25
- lg: "text-display-md"
26
- };
27
- var changeSizeClasses = {
28
- sm: "text-xs",
29
- md: "text-sm",
30
- lg: "text-base"
31
- };
32
- var changeSentimentColors = {
33
- positive: "text-success",
34
- negative: "text-destructive",
35
- neutral: "text-muted-foreground"
36
- };
37
- function getFiniteMetricValue(value) {
38
- return Number.isFinite(value) ? value : 0;
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 MetricCardMiniChart({ data, series, chartType, strokeWidth, showArea, showDots, curveType }) {
41
- if (!data || !series) return null;
42
- const sharedProps = {
43
- data,
44
- series,
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
- if (chartType === "bar") return /* @__PURE__ */ jsx(BarChart, { ...sharedProps });
52
- return /* @__PURE__ */ jsx(LineChart, {
53
- ...sharedProps,
54
- strokeWidth,
55
- showDots,
56
- curveType,
57
- showArea: chartType === "area" || showArea
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 MetricCard({ value, title, description = "vs last month", change, changeOverride, changeSentiment = "neutral", data, series, chartType = "line", strokeWidth = 2, showArea = true, showDots = false, curveType = "smooth", valueFormatter = (n) => n.toLocaleString(), changeFormatter = (n) => {
61
- return `${Math.abs(n).toFixed(0)}%`;
62
- }, size = "md", className, ...props }) {
63
- const safeValue = getFiniteMetricValue(value);
64
- const [displayValue, setDisplayValue] = useState(0);
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: [title && /* @__PURE__ */ jsx("h3", {
118
- className: cn("font-semibold text-foreground", titleSizeClasses[size || "md"]),
119
- children: title
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 items-end gap-4",
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-3 flex-1 min-w-0",
124
- children: [/* @__PURE__ */ jsx("div", {
125
- className: cn("font-semibold text-foreground", valueSizeClasses[size || "md"]),
126
- children: valueFormatter(displayValue)
127
- }), calculatedChange !== void 0 && /* @__PURE__ */ jsxs("div", {
128
- className: "flex items-center gap-2",
129
- children: [/* @__PURE__ */ jsxs("div", {
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
- }), data && series && /* @__PURE__ */ jsx("div", {
151
- "aria-hidden": "true",
152
- inert: true,
153
- children: /* @__PURE__ */ jsx(MetricCardMiniChart, {
154
- data,
155
- series,
156
- chartType,
157
- strokeWidth,
158
- showArea,
159
- showDots,
160
- curveType
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
- MetricCard.displayName = "MetricCard";
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 { MetricCard, metricCardVariants };
192
+ export { InlineCTA, inlineCTAVariants };
169
193
 
170
194
  //# sourceMappingURL=index197.js.map
@@ -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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"}