@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/index174.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index174.js","names":[],"sources":["../src/components/organisms/ai/_shared/workflow-step-renderer.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport {\n AlertCircle,\n Check,\n ChevronDown,\n ChevronRight,\n Loader,\n Pause,\n} from 'lucide-react';\nimport { AnimatePresence, motion, useReducedMotion } from 'motion/react';\nimport * as React from 'react';\nimport { assertNever, cn } from '@/lib/utils';\n\nexport type WorkflowStepStatus =\n | 'pending'\n | 'running'\n | 'suspended'\n | 'completed'\n | 'error';\n\nexport type WorkflowStepAppearance = 'contained' | 'embedded' | 'timeline';\n\nexport interface WorkflowStepViewModel {\n id: string;\n title: string;\n description?: string;\n status: WorkflowStepStatus;\n content?: React.ReactNode;\n durationMs?: number;\n error?: string;\n}\n\nexport interface WorkflowStepRendererProps {\n steps: readonly WorkflowStepViewModel[];\n appearance?: WorkflowStepAppearance;\n itemSlot?: string;\n expandable?: boolean;\n activeStepId?: string;\n expandedStepIds?: readonly string[];\n defaultExpandedStepIds?: readonly string[];\n onExpandedStepIdsChange?: (ids: readonly string[]) => void;\n className?: string;\n}\n\ninterface PrivateWorkflowStepRendererProps extends WorkflowStepRendererProps {\n renderItems?: boolean;\n}\n\nconst workflowStepItemStatusClasses = {\n pending: 'text-muted-foreground',\n running: 'text-primary',\n suspended: 'text-warning',\n completed: 'text-success',\n error: 'text-destructive',\n} as const satisfies Record<WorkflowStepStatus, string>;\n\nconst workflowStepIconStatusClasses = {\n pending: 'bg-accent text-muted-foreground',\n running: 'bg-primary/20 text-primary',\n suspended: 'bg-warning/20 text-warning',\n completed: 'bg-success/20 text-success',\n error: 'bg-destructive/20 text-destructive',\n} as const satisfies Record<WorkflowStepStatus, string>;\n\nexport const workflowStepItemVariants = cva(\n 'flex items-start gap-3 px-4 py-3 transition-colors motion-reduce:transition-none',\n {\n variants: {\n status: workflowStepItemStatusClasses,\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nexport const workflowStepIconVariants = cva(\n 'size-5 shrink-0 flex items-center justify-center rounded-full',\n {\n variants: {\n status: workflowStepIconStatusClasses,\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nconst workflowStepAppearanceConfig = {\n contained: {\n rootClassName: 'relative',\n hasDivider: true,\n hasConnector: false,\n },\n embedded: {\n rootClassName: 'relative',\n hasDivider: true,\n hasConnector: false,\n },\n timeline: {\n rootClassName: 'relative',\n hasDivider: false,\n hasConnector: true,\n },\n} as const satisfies Record<\n WorkflowStepAppearance,\n { rootClassName: string; hasDivider: boolean; hasConnector: boolean }\n>;\n\nexport function normalizeExpandedWorkflowStepIds(\n ids: readonly string[],\n steps: readonly WorkflowStepViewModel[],\n): string[] {\n const requested = new Set(ids);\n return steps.flatMap((step) => (requested.has(step.id) ? [step.id] : []));\n}\n\nfunction areWorkflowStepIdsEqual(\n left: readonly string[],\n right: readonly string[],\n): boolean {\n return (\n left.length === right.length &&\n left.every((id, index) => id === right[index])\n );\n}\n\nfunction formatWorkflowStepDuration(durationMs: number): string {\n if (durationMs < 1000) return `${durationMs}ms`;\n if (durationMs < 60_000) return `${(durationMs / 1000).toFixed(1)}s`;\n\n const totalSeconds = Math.floor(durationMs / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n return [\n hours > 0 ? `${hours}h` : null,\n minutes > 0 ? `${minutes}m` : null,\n seconds > 0 ? `${seconds}s` : null,\n ]\n .filter((part): part is string => part !== null)\n .join(' ');\n}\n\nfunction isIterableWorkflowStepContent(\n content: React.ReactNode,\n): content is Iterable<React.ReactNode> {\n return (\n typeof content === 'object' &&\n content !== null &&\n Symbol.iterator in content &&\n typeof (content as Iterable<React.ReactNode>)[Symbol.iterator] ===\n 'function'\n );\n}\n\nfunction isIteratorWorkflowStepContent(\n content: unknown,\n): content is Iterator<React.ReactNode> {\n return (\n typeof (content as Partial<Iterator<React.ReactNode>>).next === 'function'\n );\n}\n\ninterface NormalizedWorkflowStepContent {\n content: React.ReactNode;\n hasRenderableContent: boolean;\n changed: boolean;\n}\n\nconst normalizedOneShotWorkflowStepContent = new WeakMap<\n object,\n NormalizedWorkflowStepContent\n>();\n\nfunction normalizeIterableWorkflowStepContent(\n content: Iterable<React.ReactNode>,\n iterator: Iterator<React.ReactNode>,\n): NormalizedWorkflowStepContent {\n const normalizedChildren: React.ReactNode[] = [];\n let hasRenderableContent = false;\n let changed = !Array.isArray(content);\n\n for (let result = iterator.next(); !result.done; result = iterator.next()) {\n const normalizedChild = normalizeWorkflowStepContent(result.value);\n normalizedChildren.push(normalizedChild.content);\n hasRenderableContent ||= normalizedChild.hasRenderableContent;\n changed ||= normalizedChild.changed;\n }\n\n return {\n content: changed ? normalizedChildren : content,\n hasRenderableContent,\n changed,\n };\n}\n\nfunction normalizeWorkflowStepContent(\n content: React.ReactNode,\n): NormalizedWorkflowStepContent {\n if (\n content === null ||\n content === undefined ||\n typeof content === 'boolean' ||\n content === ''\n ) {\n return { content, hasRenderableContent: false, changed: false };\n }\n\n if (\n typeof content === 'string' ||\n typeof content === 'number' ||\n typeof content === 'bigint'\n ) {\n return { content, hasRenderableContent: true, changed: false };\n }\n\n if (React.isValidElement<{ children?: React.ReactNode }>(content)) {\n if (content.type !== React.Fragment) {\n return { content, hasRenderableContent: true, changed: false };\n }\n\n const normalizedChildren = normalizeWorkflowStepContent(\n content.props.children,\n );\n return {\n content: normalizedChildren.changed\n ? React.cloneElement(content, undefined, normalizedChildren.content)\n : content,\n hasRenderableContent: normalizedChildren.hasRenderableContent,\n changed: normalizedChildren.changed,\n };\n }\n\n if (isIterableWorkflowStepContent(content)) {\n const iterator = content[Symbol.iterator]();\n const oneShotCacheKey = isIteratorWorkflowStepContent(iterator)\n ? (iterator as object)\n : null;\n\n if (oneShotCacheKey !== null) {\n const cached = normalizedOneShotWorkflowStepContent.get(oneShotCacheKey);\n if (cached !== undefined) return cached;\n }\n\n const normalized = normalizeIterableWorkflowStepContent(content, iterator);\n if (oneShotCacheKey !== null) {\n normalizedOneShotWorkflowStepContent.set(oneShotCacheKey, normalized);\n }\n return normalized;\n }\n\n return { content, hasRenderableContent: true, changed: false };\n}\n\nfunction getNonBlankWorkflowStepError(\n error: string | undefined,\n): string | undefined {\n return error?.trim() ? error : undefined;\n}\n\nfunction getWorkflowStepStatusLabel(status: WorkflowStepStatus): string {\n switch (status) {\n case 'pending':\n return 'Pending';\n case 'running':\n return 'Running';\n case 'suspended':\n return 'Paused';\n case 'completed':\n return 'Completed';\n case 'error':\n return 'Error';\n default:\n return assertNever(status);\n }\n}\n\nexport interface WorkflowStepStatusIconProps {\n status: WorkflowStepStatus;\n index: number;\n className?: string;\n}\n\nexport function WorkflowStepStatusIcon({\n status,\n index,\n className,\n}: WorkflowStepStatusIconProps) {\n const iconClass = cn(workflowStepIconVariants({ status }), className);\n\n switch (status) {\n case 'pending':\n return (\n <div data-slot=\"workflow-step-icon\" className={iconClass}>\n <span className=\"text-xs font-medium\">{index + 1}</span>\n </div>\n );\n case 'running':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(\n iconClass,\n 'delight-status-pulse motion-reduce:!animate-none',\n )}\n >\n <Loader className=\"size-3 animate-spin motion-reduce:animate-none\" />\n </div>\n );\n case 'suspended':\n return (\n <div data-slot=\"workflow-step-icon\" className={iconClass}>\n <Pause className=\"size-3\" />\n </div>\n );\n case 'completed':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(\n iconClass,\n 'delight-check-bounce motion-reduce:!animate-none',\n )}\n >\n <Check className=\"size-3\" />\n </div>\n );\n case 'error':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(iconClass, 'delight-shake motion-reduce:!animate-none')}\n >\n <AlertCircle className=\"size-3\" />\n </div>\n );\n default:\n return assertNever(status);\n }\n}\n\nWorkflowStepStatusIcon.displayName = 'WorkflowStepStatusIcon';\n\nexport interface WorkflowStepItemProps {\n step: WorkflowStepViewModel;\n index: number;\n isLast: boolean;\n appearance?: WorkflowStepAppearance;\n itemSlot?: string;\n expandable?: boolean;\n expanded: boolean;\n active?: boolean;\n onExpandedChange: () => void;\n}\n\nexport function WorkflowStepItem({\n step,\n index,\n isLast,\n appearance = 'contained',\n itemSlot = 'workflow-step-item',\n expandable = true,\n expanded,\n active = false,\n onExpandedChange,\n}: WorkflowStepItemProps) {\n const contentId = React.useId();\n const errorDescriptionId = React.useId();\n const normalizedContent = normalizeWorkflowStepContent(step.content);\n const hasContent = normalizedContent.hasRenderableContent;\n const error = getNonBlankWorkflowStepError(step.error);\n const hasError = error !== undefined;\n const hasExpandableDetails = hasContent || hasError;\n const isDisclosureControl = hasExpandableDetails && expandable;\n const prefersReducedMotion = useReducedMotion();\n const appearanceConfig = workflowStepAppearanceConfig[appearance];\n const disclosureTransition = {\n duration: prefersReducedMotion ? 0 : 0.2,\n };\n const stepContent = (\n <>\n <WorkflowStepStatusIcon status={step.status} index={index} />\n\n <div className=\"min-w-0 flex-1 text-start\">\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'text-sm font-medium',\n step.status === 'pending'\n ? 'text-text-quaternary'\n : 'text-foreground',\n )}\n >\n {step.title}\n </span>\n <span className=\"text-xs text-secondary-foreground\">\n {getWorkflowStepStatusLabel(step.status)}\n </span>\n {step.durationMs !== undefined && (\n <span className=\"text-xs text-muted-foreground\">\n {formatWorkflowStepDuration(step.durationMs)}\n </span>\n )}\n </div>\n {step.description && (\n <p className=\"mt-0.5 text-xs text-text-quaternary\">\n {step.description}\n </p>\n )}\n </div>\n\n {isDisclosureControl && (\n <div className=\"shrink-0\">\n {expanded ? (\n <ChevronDown className=\"size-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"size-4 text-muted-foreground rtl:rotate-180\" />\n )}\n </div>\n )}\n </>\n );\n\n return (\n <div\n data-slot={itemSlot}\n data-step-status={step.status}\n data-appearance={appearance}\n className={cn(\n appearanceConfig.rootClassName,\n appearanceConfig.hasDivider && !isLast && 'border-b border-border',\n )}\n >\n {isDisclosureControl ? (\n <button\n type=\"button\"\n onClick={onExpandedChange}\n aria-current={active ? 'step' : undefined}\n aria-expanded={expanded}\n aria-controls={contentId}\n aria-describedby={hasError ? errorDescriptionId : undefined}\n className={cn(\n workflowStepItemVariants({ status: step.status }),\n 'w-full cursor-pointer hover:bg-muted focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n )}\n >\n {stepContent}\n </button>\n ) : (\n <div\n aria-current={active ? 'step' : undefined}\n aria-describedby={hasError ? errorDescriptionId : undefined}\n className={cn(\n workflowStepItemVariants({ status: step.status }),\n 'w-full',\n )}\n >\n {stepContent}\n </div>\n )}\n\n <AnimatePresence initial={false}>\n {expanded && hasExpandableDetails && (\n <motion.div\n id={contentId}\n data-slot=\"workflow-step-panel\"\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={disclosureTransition}\n className=\"overflow-hidden motion-reduce:transition-none\"\n >\n <div className=\"px-4 pb-3 ps-12\">\n {hasError && (\n <div className=\"rounded-lg border border-destructive/50 bg-destructive/10 p-3\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle className=\"mt-0.5 size-4 shrink-0 text-destructive\" />\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n </div>\n )}\n {hasContent && (\n <div className={hasError ? 'mt-3' : undefined}>\n {normalizedContent.content}\n </div>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {hasError && (\n <span id={errorDescriptionId} className=\"sr-only\">\n {error}\n </span>\n )}\n\n {appearanceConfig.hasConnector && !isLast && (\n <div\n data-slot=\"workflow-step-connector\"\n aria-hidden=\"true\"\n className=\"absolute top-8 -bottom-3 start-6 w-px bg-border\"\n />\n )}\n </div>\n );\n}\n\nWorkflowStepItem.displayName = 'WorkflowStepItem';\n\nexport function WorkflowStepRenderer({\n steps,\n appearance = 'contained',\n itemSlot = 'workflow-step-item',\n expandable = true,\n activeStepId,\n expandedStepIds: controlledExpandedStepIds,\n defaultExpandedStepIds = [],\n onExpandedStepIdsChange,\n className,\n renderItems = true,\n}: PrivateWorkflowStepRendererProps) {\n const isControlled = controlledExpandedStepIds !== undefined;\n const controlledSnapshot = isControlled\n ? [...controlledExpandedStepIds]\n : undefined;\n const [uncontrolledExpandedStepIds, setUncontrolledExpandedStepIds] =\n React.useState<readonly string[]>(() =>\n normalizeExpandedWorkflowStepIds(defaultExpandedStepIds, steps),\n );\n const lastControlledExpandedStepIdsRef = React.useRef<readonly string[]>(\n controlledSnapshot ?? [],\n );\n const wasControlledRef = React.useRef(isControlled);\n const rawExpandedStepIds = isControlled\n ? controlledExpandedStepIds\n : uncontrolledExpandedStepIds;\n const visibleExpandedStepIds = normalizeExpandedWorkflowStepIds(\n rawExpandedStepIds,\n steps,\n );\n const expandedSet = new Set(visibleExpandedStepIds);\n\n React.useLayoutEffect(() => {\n if (controlledSnapshot !== undefined) {\n lastControlledExpandedStepIdsRef.current = controlledSnapshot;\n }\n }, [controlledSnapshot]);\n\n React.useLayoutEffect(() => {\n const wasControlled = wasControlledRef.current;\n wasControlledRef.current = isControlled;\n if (isControlled) return;\n\n setUncontrolledExpandedStepIds((current) => {\n const source = wasControlled\n ? lastControlledExpandedStepIdsRef.current\n : current;\n const reconciled = normalizeExpandedWorkflowStepIds(source, steps);\n return areWorkflowStepIdsEqual(reconciled, current)\n ? current\n : reconciled;\n });\n }, [isControlled, steps]);\n\n const toggleStep = (id: string) => {\n const next = new Set(visibleExpandedStepIds);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n const normalizedNext = normalizeExpandedWorkflowStepIds([...next], steps);\n if (!isControlled) {\n setUncontrolledExpandedStepIds([...normalizedNext]);\n }\n onExpandedStepIdsChange?.([...normalizedNext]);\n };\n\n if (!renderItems) return null;\n\n return (\n <ol\n data-slot=\"workflow-step-list\"\n data-appearance={appearance}\n className={cn('m-0 list-none p-0', className)}\n >\n {steps.map((step, index) => (\n <li key={step.id}>\n <WorkflowStepItem\n step={step}\n index={index}\n isLast={index === steps.length - 1}\n appearance={appearance}\n itemSlot={itemSlot}\n expandable={expandable}\n expanded={expandedSet.has(step.id)}\n active={activeStepId === step.id}\n onExpandedChange={() => toggleStep(step.id)}\n />\n </li>\n ))}\n </ol>\n );\n}\n\nWorkflowStepRenderer.displayName = 'WorkflowStepRenderer';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index174.js","names":[],"sources":["../src/components/organisms/ai/_shared/format-ai-duration.ts"],"sourcesContent":["export function formatAIDuration(durationMs: number): string {\n const totalSeconds = Math.max(0, Math.round(durationMs / 1000));\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) {\n return [hours ? `${hours}h` : '', minutes ? `${minutes}m` : '']\n .filter(Boolean)\n .join(' ');\n }\n if (minutes > 0) {\n return `${minutes}m${seconds ? ` ${seconds}s` : ''}`;\n }\n return `${totalSeconds}s`;\n}\n"],"mappings":";AAAA,SAAgB,iBAAiB,YAA4B;CAC3D,MAAM,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,aAAa,GAAI,CAAC;CAC9D,MAAM,QAAQ,KAAK,MAAM,eAAe,IAAI;CAC5C,MAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;CACrD,MAAM,UAAU,eAAe;CAE/B,IAAI,QAAQ,GACV,OAAO,CAAC,QAAQ,GAAG,MAAM,KAAK,IAAI,UAAU,GAAG,QAAQ,KAAK,EAAE,CAAC,CAC5D,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEb,IAAI,UAAU,GACZ,OAAO,GAAG,QAAQ,GAAG,UAAU,IAAI,QAAQ,KAAK;CAElD,OAAO,GAAG,aAAa;AACzB"}
|
package/dist/index175.js
CHANGED
|
@@ -1,166 +1,339 @@
|
|
|
1
|
-
import { cn } from "./index2.js";
|
|
2
|
-
import {
|
|
1
|
+
import { assertNever, cn } from "./index2.js";
|
|
2
|
+
import { formatAIDuration } from "./index174.js";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
|
-
import { AlertCircle, Check, ChevronDown, ChevronRight,
|
|
4
|
+
import { AlertCircle, Check, ChevronDown, ChevronRight, Loader, Pause } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
|
8
|
-
//#region src/components/organisms/ai/
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
//#region src/components/organisms/ai/_shared/workflow-step-renderer.tsx
|
|
9
|
+
var workflowStepItemStatusClasses = {
|
|
10
|
+
pending: "text-muted-foreground",
|
|
11
|
+
running: "text-primary",
|
|
12
|
+
suspended: "text-warning",
|
|
13
|
+
completed: "text-success",
|
|
14
|
+
error: "text-destructive"
|
|
15
|
+
};
|
|
16
|
+
var workflowStepIconStatusClasses = {
|
|
17
|
+
pending: "bg-accent text-muted-foreground",
|
|
18
|
+
running: "bg-primary/20 text-primary",
|
|
19
|
+
suspended: "bg-warning/20 text-warning",
|
|
20
|
+
completed: "bg-success/20 text-success",
|
|
21
|
+
error: "bg-destructive/20 text-destructive"
|
|
22
|
+
};
|
|
23
|
+
var workflowStepItemVariants = cva("flex items-start gap-3 px-4 py-3 transition-colors motion-reduce:transition-none", {
|
|
24
|
+
variants: { status: workflowStepItemStatusClasses },
|
|
23
25
|
defaultVariants: { status: "pending" }
|
|
24
26
|
});
|
|
25
|
-
var
|
|
26
|
-
variants: { status:
|
|
27
|
-
pending: "bg-accent text-muted-foreground",
|
|
28
|
-
running: "bg-primary/20 text-primary",
|
|
29
|
-
completed: "bg-success/20 text-success",
|
|
30
|
-
error: "bg-destructive/20 text-destructive"
|
|
31
|
-
} },
|
|
27
|
+
var workflowStepIconVariants = cva("size-5 shrink-0 flex items-center justify-center rounded-full", {
|
|
28
|
+
variants: { status: workflowStepIconStatusClasses },
|
|
32
29
|
defaultVariants: { status: "pending" }
|
|
33
30
|
});
|
|
34
|
-
var
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
var workflowStepAppearanceConfig = {
|
|
32
|
+
contained: {
|
|
33
|
+
rootClassName: "relative",
|
|
34
|
+
hasDivider: true,
|
|
35
|
+
hasConnector: false
|
|
36
|
+
},
|
|
37
|
+
embedded: {
|
|
38
|
+
rootClassName: "relative",
|
|
39
|
+
hasDivider: true,
|
|
40
|
+
hasConnector: false
|
|
41
|
+
},
|
|
42
|
+
timeline: {
|
|
43
|
+
rootClassName: "relative",
|
|
44
|
+
hasDivider: false,
|
|
45
|
+
hasConnector: true
|
|
46
|
+
}
|
|
39
47
|
};
|
|
40
|
-
function
|
|
41
|
-
|
|
48
|
+
function normalizeExpandedWorkflowStepIds(ids, steps) {
|
|
49
|
+
const requested = new Set(ids);
|
|
50
|
+
return steps.flatMap((step) => requested.has(step.id) ? [step.id] : []);
|
|
51
|
+
}
|
|
52
|
+
function areWorkflowStepIdsEqual(left, right) {
|
|
53
|
+
return left.length === right.length && left.every((id, index) => id === right[index]);
|
|
54
|
+
}
|
|
55
|
+
function isIterableWorkflowStepContent(content) {
|
|
56
|
+
return typeof content === "object" && content !== null && Symbol.iterator in content && typeof content[Symbol.iterator] === "function";
|
|
57
|
+
}
|
|
58
|
+
function isIteratorWorkflowStepContent(content) {
|
|
59
|
+
return typeof content.next === "function";
|
|
42
60
|
}
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
var normalizedOneShotWorkflowStepContent = /* @__PURE__ */ new WeakMap();
|
|
62
|
+
function normalizeIterableWorkflowStepContent(content, iterator) {
|
|
63
|
+
const normalizedChildren = [];
|
|
64
|
+
let hasRenderableContent = false;
|
|
65
|
+
let changed = !Array.isArray(content);
|
|
66
|
+
for (let result = iterator.next(); !result.done; result = iterator.next()) {
|
|
67
|
+
const normalizedChild = normalizeWorkflowStepContent(result.value);
|
|
68
|
+
normalizedChildren.push(normalizedChild.content);
|
|
69
|
+
hasRenderableContent ||= normalizedChild.hasRenderableContent;
|
|
70
|
+
changed ||= normalizedChild.changed;
|
|
71
|
+
}
|
|
45
72
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
status: toWorkflowStepStatus(step.status),
|
|
50
|
-
content: error === void 0 ? step.content : void 0,
|
|
51
|
-
durationMs: step.status === "completed" ? step.duration : void 0,
|
|
52
|
-
error
|
|
73
|
+
content: changed ? normalizedChildren : content,
|
|
74
|
+
hasRenderableContent,
|
|
75
|
+
changed
|
|
53
76
|
};
|
|
54
77
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
78
|
+
function normalizeWorkflowStepContent(content) {
|
|
79
|
+
if (content === null || content === void 0 || typeof content === "boolean" || content === "") return {
|
|
80
|
+
content,
|
|
81
|
+
hasRenderableContent: false,
|
|
82
|
+
changed: false
|
|
83
|
+
};
|
|
84
|
+
if (typeof content === "string" || typeof content === "number" || typeof content === "bigint") return {
|
|
85
|
+
content,
|
|
86
|
+
hasRenderableContent: true,
|
|
87
|
+
changed: false
|
|
88
|
+
};
|
|
89
|
+
if (React.isValidElement(content)) {
|
|
90
|
+
if (content.type !== React.Fragment) return {
|
|
91
|
+
content,
|
|
92
|
+
hasRenderableContent: true,
|
|
93
|
+
changed: false
|
|
94
|
+
};
|
|
95
|
+
const normalizedChildren = normalizeWorkflowStepContent(content.props.children);
|
|
96
|
+
return {
|
|
97
|
+
content: normalizedChildren.changed ? React.cloneElement(content, void 0, normalizedChildren.content) : content,
|
|
98
|
+
hasRenderableContent: normalizedChildren.hasRenderableContent,
|
|
99
|
+
changed: normalizedChildren.changed
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (isIterableWorkflowStepContent(content)) {
|
|
103
|
+
const iterator = content[Symbol.iterator]();
|
|
104
|
+
const oneShotCacheKey = isIteratorWorkflowStepContent(iterator) ? iterator : null;
|
|
105
|
+
if (oneShotCacheKey !== null) {
|
|
106
|
+
const cached = normalizedOneShotWorkflowStepContent.get(oneShotCacheKey);
|
|
107
|
+
if (cached !== void 0) return cached;
|
|
108
|
+
}
|
|
109
|
+
const normalized = normalizeIterableWorkflowStepContent(content, iterator);
|
|
110
|
+
if (oneShotCacheKey !== null) normalizedOneShotWorkflowStepContent.set(oneShotCacheKey, normalized);
|
|
111
|
+
return normalized;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
content,
|
|
115
|
+
hasRenderableContent: true,
|
|
116
|
+
changed: false
|
|
117
|
+
};
|
|
61
118
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
function getNonBlankWorkflowStepError(error) {
|
|
120
|
+
return error?.trim() ? error : void 0;
|
|
121
|
+
}
|
|
122
|
+
function getWorkflowStepStatusLabel(status) {
|
|
123
|
+
switch (status) {
|
|
124
|
+
case "pending": return "Pending";
|
|
125
|
+
case "running": return "Running";
|
|
126
|
+
case "suspended": return "Paused";
|
|
127
|
+
case "completed": return "Completed";
|
|
128
|
+
case "error": return "Error";
|
|
129
|
+
default: return assertNever(status);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function WorkflowStepStatusIcon({ status, index, className }) {
|
|
133
|
+
const iconClass = cn(workflowStepIconVariants({ status }), className);
|
|
134
|
+
switch (status) {
|
|
135
|
+
case "pending": return /* @__PURE__ */ jsx("div", {
|
|
136
|
+
"data-slot": "workflow-step-icon",
|
|
137
|
+
className: iconClass,
|
|
138
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
139
|
+
className: "text-xs font-medium",
|
|
140
|
+
children: index + 1
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
case "running": return /* @__PURE__ */ jsx("div", {
|
|
144
|
+
"data-slot": "workflow-step-icon",
|
|
145
|
+
className: cn(iconClass, "delight-status-pulse motion-reduce:!animate-none"),
|
|
146
|
+
children: /* @__PURE__ */ jsx(Loader, { className: "size-3 animate-spin motion-reduce:animate-none" })
|
|
147
|
+
});
|
|
148
|
+
case "suspended": return /* @__PURE__ */ jsx("div", {
|
|
149
|
+
"data-slot": "workflow-step-icon",
|
|
150
|
+
className: iconClass,
|
|
151
|
+
children: /* @__PURE__ */ jsx(Pause, { className: "size-3" })
|
|
152
|
+
});
|
|
153
|
+
case "completed": return /* @__PURE__ */ jsx("div", {
|
|
154
|
+
"data-slot": "workflow-step-icon",
|
|
155
|
+
className: cn(iconClass, "delight-check-bounce motion-reduce:!animate-none"),
|
|
156
|
+
children: /* @__PURE__ */ jsx(Check, { className: "size-3" })
|
|
157
|
+
});
|
|
158
|
+
case "error": return /* @__PURE__ */ jsx("div", {
|
|
159
|
+
"data-slot": "workflow-step-icon",
|
|
160
|
+
className: cn(iconClass, "delight-shake motion-reduce:!animate-none"),
|
|
161
|
+
children: /* @__PURE__ */ jsx(AlertCircle, { className: "size-3" })
|
|
162
|
+
});
|
|
163
|
+
default: return assertNever(status);
|
|
164
|
+
}
|
|
75
165
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
* steps={[
|
|
87
|
-
* { label: 'Analyzing', status: 'complete', duration: '2s' },
|
|
88
|
-
* { label: 'Generating', status: 'running' },
|
|
89
|
-
* ]}
|
|
90
|
-
* />
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
function AISteps({ steps, title, variant, collapsible = true, defaultExpanded = true, stepsExpandable = true, className }) {
|
|
94
|
-
const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
|
|
166
|
+
WorkflowStepStatusIcon.displayName = "WorkflowStepStatusIcon";
|
|
167
|
+
function WorkflowStepItem({ step, index, isLast, appearance = "contained", itemSlot = "workflow-step-item", expandable = true, expanded, active = false, onExpandedChange }) {
|
|
168
|
+
const contentId = React.useId();
|
|
169
|
+
const errorDescriptionId = React.useId();
|
|
170
|
+
const normalizedContent = normalizeWorkflowStepContent(step.content);
|
|
171
|
+
const hasContent = normalizedContent.hasRenderableContent;
|
|
172
|
+
const error = getNonBlankWorkflowStepError(step.error);
|
|
173
|
+
const hasError = error !== void 0;
|
|
174
|
+
const hasExpandableDetails = hasContent || hasError;
|
|
175
|
+
const isDisclosureControl = hasExpandableDetails && expandable;
|
|
95
176
|
const prefersReducedMotion = useReducedMotion();
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
type: "button",
|
|
106
|
-
onClick: () => collapsible && setIsExpanded(!isExpanded),
|
|
107
|
-
disabled: !collapsible,
|
|
108
|
-
"aria-expanded": collapsible ? isExpanded : void 0,
|
|
109
|
-
className: cn("flex items-center justify-between w-full px-4 py-3 border-b border-border", collapsible && "hover:bg-muted cursor-pointer", "focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring"),
|
|
177
|
+
const appearanceConfig = workflowStepAppearanceConfig[appearance];
|
|
178
|
+
const disclosureTransition = { duration: prefersReducedMotion ? 0 : .2 };
|
|
179
|
+
const stepContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
180
|
+
/* @__PURE__ */ jsx(WorkflowStepStatusIcon, {
|
|
181
|
+
status: step.status,
|
|
182
|
+
index
|
|
183
|
+
}),
|
|
184
|
+
/* @__PURE__ */ jsxs("div", {
|
|
185
|
+
className: "min-w-0 flex-1 text-start",
|
|
110
186
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
111
|
-
className: "flex items-center gap-2",
|
|
187
|
+
className: "flex flex-wrap items-center gap-2",
|
|
112
188
|
children: [
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
189
|
+
step.contextLabel && /* @__PURE__ */ jsx("span", {
|
|
190
|
+
"data-slot": "workflow-step-context",
|
|
191
|
+
className: "rounded-full border border-border px-2 py-0.5 text-[0.6875rem] font-medium leading-none text-secondary-foreground",
|
|
192
|
+
children: step.contextLabel
|
|
193
|
+
}),
|
|
116
194
|
/* @__PURE__ */ jsx("span", {
|
|
117
|
-
className: "text-sm font-medium text-foreground",
|
|
118
|
-
children: title
|
|
195
|
+
className: cn("text-sm font-medium", step.status === "pending" ? "text-text-quaternary" : "text-foreground"),
|
|
196
|
+
children: step.title
|
|
119
197
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
121
|
-
className: "text-xs text-
|
|
122
|
-
children:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
")"
|
|
128
|
-
]
|
|
198
|
+
/* @__PURE__ */ jsx("span", {
|
|
199
|
+
className: "text-xs text-secondary-foreground",
|
|
200
|
+
children: getWorkflowStepStatusLabel(step.status)
|
|
201
|
+
}),
|
|
202
|
+
step.durationMs !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
203
|
+
className: "text-xs text-muted-foreground",
|
|
204
|
+
children: formatAIDuration(step.durationMs)
|
|
129
205
|
})
|
|
130
206
|
]
|
|
131
|
-
}),
|
|
132
|
-
className: "
|
|
133
|
-
children:
|
|
207
|
+
}), step.description && /* @__PURE__ */ jsx("p", {
|
|
208
|
+
className: "mt-0.5 text-xs text-text-quaternary",
|
|
209
|
+
children: step.description
|
|
134
210
|
})]
|
|
135
|
-
}),
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
211
|
+
}),
|
|
212
|
+
isDisclosureControl && /* @__PURE__ */ jsx("div", {
|
|
213
|
+
className: "shrink-0",
|
|
214
|
+
children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 text-muted-foreground rtl:rotate-180" })
|
|
215
|
+
})
|
|
216
|
+
] });
|
|
217
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
218
|
+
"data-slot": itemSlot,
|
|
219
|
+
"data-step-status": step.status,
|
|
220
|
+
"data-appearance": appearance,
|
|
221
|
+
className: cn(appearanceConfig.rootClassName, appearanceConfig.hasDivider && !isLast && "border-b border-border"),
|
|
222
|
+
children: [
|
|
223
|
+
isDisclosureControl ? /* @__PURE__ */ jsx("button", {
|
|
224
|
+
type: "button",
|
|
225
|
+
onClick: onExpandedChange,
|
|
226
|
+
"aria-current": active ? "step" : void 0,
|
|
227
|
+
"aria-expanded": expanded,
|
|
228
|
+
"aria-controls": contentId,
|
|
229
|
+
"aria-describedby": hasError ? errorDescriptionId : void 0,
|
|
230
|
+
className: cn(workflowStepItemVariants({ status: step.status }), "w-full cursor-pointer hover:bg-muted focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring"),
|
|
231
|
+
children: stepContent
|
|
232
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
233
|
+
"aria-current": active ? "step" : void 0,
|
|
234
|
+
"aria-describedby": hasError ? errorDescriptionId : void 0,
|
|
235
|
+
className: cn(workflowStepItemVariants({ status: step.status }), "w-full"),
|
|
236
|
+
children: stepContent
|
|
237
|
+
}),
|
|
238
|
+
/* @__PURE__ */ jsx(AnimatePresence, {
|
|
239
|
+
initial: false,
|
|
240
|
+
children: expanded && hasExpandableDetails && /* @__PURE__ */ jsx(motion.div, {
|
|
241
|
+
id: contentId,
|
|
242
|
+
"data-slot": "workflow-step-panel",
|
|
243
|
+
initial: {
|
|
244
|
+
height: 0,
|
|
245
|
+
opacity: 0
|
|
246
|
+
},
|
|
247
|
+
animate: {
|
|
248
|
+
height: "auto",
|
|
249
|
+
opacity: 1
|
|
250
|
+
},
|
|
251
|
+
exit: {
|
|
252
|
+
height: 0,
|
|
253
|
+
opacity: 0
|
|
254
|
+
},
|
|
255
|
+
transition: disclosureTransition,
|
|
256
|
+
className: "overflow-hidden motion-reduce:transition-none",
|
|
257
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
258
|
+
className: "px-4 pb-3 ps-12",
|
|
259
|
+
children: [hasError && /* @__PURE__ */ jsx("div", {
|
|
260
|
+
className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3",
|
|
261
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
262
|
+
className: "flex items-start gap-2",
|
|
263
|
+
children: [/* @__PURE__ */ jsx(AlertCircle, { className: "mt-0.5 size-4 shrink-0 text-destructive" }), /* @__PURE__ */ jsx("p", {
|
|
264
|
+
className: "text-sm text-destructive",
|
|
265
|
+
children: error
|
|
266
|
+
})]
|
|
267
|
+
})
|
|
268
|
+
}), hasContent && /* @__PURE__ */ jsx("div", {
|
|
269
|
+
className: hasError ? "mt-3" : void 0,
|
|
270
|
+
children: normalizedContent.content
|
|
271
|
+
})]
|
|
272
|
+
})
|
|
157
273
|
})
|
|
274
|
+
}),
|
|
275
|
+
hasError && /* @__PURE__ */ jsx("span", {
|
|
276
|
+
id: errorDescriptionId,
|
|
277
|
+
className: "sr-only",
|
|
278
|
+
children: error
|
|
279
|
+
}),
|
|
280
|
+
appearanceConfig.hasConnector && !isLast && /* @__PURE__ */ jsx("div", {
|
|
281
|
+
"data-slot": "workflow-step-connector",
|
|
282
|
+
"aria-hidden": "true",
|
|
283
|
+
className: "absolute top-8 -bottom-3 start-6 w-px bg-border"
|
|
158
284
|
})
|
|
159
|
-
|
|
285
|
+
]
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
WorkflowStepItem.displayName = "WorkflowStepItem";
|
|
289
|
+
function WorkflowStepRenderer({ steps, appearance = "contained", itemSlot = "workflow-step-item", expandable = true, activeStepId, expandedStepIds: controlledExpandedStepIds, defaultExpandedStepIds = [], onExpandedStepIdsChange, className, renderItems = true }) {
|
|
290
|
+
const isControlled = controlledExpandedStepIds !== void 0;
|
|
291
|
+
const controlledSnapshot = isControlled ? [...controlledExpandedStepIds] : void 0;
|
|
292
|
+
const [uncontrolledExpandedStepIds, setUncontrolledExpandedStepIds] = React.useState(() => normalizeExpandedWorkflowStepIds(defaultExpandedStepIds, steps));
|
|
293
|
+
const lastControlledExpandedStepIdsRef = React.useRef(controlledSnapshot ?? []);
|
|
294
|
+
const wasControlledRef = React.useRef(isControlled);
|
|
295
|
+
const visibleExpandedStepIds = normalizeExpandedWorkflowStepIds(isControlled ? controlledExpandedStepIds : uncontrolledExpandedStepIds, steps);
|
|
296
|
+
const expandedSet = new Set(visibleExpandedStepIds);
|
|
297
|
+
React.useLayoutEffect(() => {
|
|
298
|
+
if (controlledSnapshot !== void 0) lastControlledExpandedStepIdsRef.current = controlledSnapshot;
|
|
299
|
+
}, [controlledSnapshot]);
|
|
300
|
+
React.useLayoutEffect(() => {
|
|
301
|
+
const wasControlled = wasControlledRef.current;
|
|
302
|
+
wasControlledRef.current = isControlled;
|
|
303
|
+
if (isControlled) return;
|
|
304
|
+
setUncontrolledExpandedStepIds((current) => {
|
|
305
|
+
const reconciled = normalizeExpandedWorkflowStepIds(wasControlled ? lastControlledExpandedStepIdsRef.current : current, steps);
|
|
306
|
+
return areWorkflowStepIdsEqual(reconciled, current) ? current : reconciled;
|
|
307
|
+
});
|
|
308
|
+
}, [isControlled, steps]);
|
|
309
|
+
const toggleStep = (id) => {
|
|
310
|
+
const next = new Set(visibleExpandedStepIds);
|
|
311
|
+
if (next.has(id)) next.delete(id);
|
|
312
|
+
else next.add(id);
|
|
313
|
+
const normalizedNext = normalizeExpandedWorkflowStepIds([...next], steps);
|
|
314
|
+
if (!isControlled) setUncontrolledExpandedStepIds([...normalizedNext]);
|
|
315
|
+
onExpandedStepIdsChange?.([...normalizedNext]);
|
|
316
|
+
};
|
|
317
|
+
if (!renderItems) return null;
|
|
318
|
+
return /* @__PURE__ */ jsx("ol", {
|
|
319
|
+
"data-slot": "workflow-step-list",
|
|
320
|
+
"data-appearance": appearance,
|
|
321
|
+
className: cn("m-0 list-none p-0", className),
|
|
322
|
+
children: steps.map((step, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(WorkflowStepItem, {
|
|
323
|
+
step,
|
|
324
|
+
index,
|
|
325
|
+
isLast: index === steps.length - 1,
|
|
326
|
+
appearance,
|
|
327
|
+
itemSlot,
|
|
328
|
+
expandable,
|
|
329
|
+
expanded: expandedSet.has(step.id),
|
|
330
|
+
active: activeStepId === step.id,
|
|
331
|
+
onExpandedChange: () => toggleStep(step.id)
|
|
332
|
+
}) }, step.id))
|
|
160
333
|
});
|
|
161
334
|
}
|
|
162
|
-
|
|
335
|
+
WorkflowStepRenderer.displayName = "WorkflowStepRenderer";
|
|
163
336
|
//#endregion
|
|
164
|
-
export {
|
|
337
|
+
export { WorkflowStepItem, WorkflowStepRenderer, WorkflowStepStatusIcon, normalizeExpandedWorkflowStepIds, workflowStepIconVariants, workflowStepItemVariants };
|
|
165
338
|
|
|
166
339
|
//# sourceMappingURL=index175.js.map
|
package/dist/index175.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index175.js","names":[],"sources":["../src/components/organisms/ai/AISteps/AISteps.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport {\n AlertCircle,\n Check,\n ChevronDown,\n ChevronRight,\n Clock,\n} from 'lucide-react';\nimport { AnimatePresence, motion, useReducedMotion } from 'motion/react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\nimport {\n WorkflowStepItem,\n WorkflowStepRenderer,\n type WorkflowStepStatus,\n WorkflowStepStatusIcon,\n type WorkflowStepViewModel,\n} from '../_shared/workflow-step-renderer';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst stepsContainerVariants = cva('overflow-hidden rounded-xl border', {\n variants: {\n variant: {\n default: 'border-border bg-background',\n subtle: 'border-border bg-muted',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\nconst stepItemVariants = cva(\n 'flex items-start gap-3 px-4 py-3 transition-colors',\n {\n variants: {\n status: {\n pending: 'text-muted-foreground',\n running: 'text-primary',\n completed: 'text-success',\n error: 'text-destructive',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nconst stepIconVariants = cva(\n 'size-5 shrink-0 flex items-center justify-center rounded-full',\n {\n variants: {\n status: {\n pending: 'bg-accent text-muted-foreground',\n running: 'bg-primary/20 text-primary',\n completed: 'bg-success/20 text-success',\n error: 'bg-destructive/20 text-destructive',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type StepStatus = 'pending' | 'running' | 'completed' | 'error';\n\nexport interface StepData {\n /** Unique step ID */\n id: string;\n /** Step title */\n title: string;\n /** Step description */\n description?: string;\n /** Step status */\n status: StepStatus;\n /** Optional content to show when expanded */\n content?: React.ReactNode;\n /** Duration in ms (for completed steps) */\n duration?: number;\n /** Error message if status is error */\n error?: string;\n}\n\ntype AIStepsWorkflowStatus = Exclude<WorkflowStepStatus, 'suspended'>;\n\nconst WORKFLOW_STATUS_BY_STEP_STATUS = {\n pending: 'pending',\n running: 'running',\n completed: 'completed',\n error: 'error',\n} as const satisfies Record<StepStatus, AIStepsWorkflowStatus>;\n\nfunction toWorkflowStepStatus(status: StepStatus): AIStepsWorkflowStatus {\n return WORKFLOW_STATUS_BY_STEP_STATUS[status];\n}\n\nfunction toWorkflowStep(step: StepData): WorkflowStepViewModel {\n const error = step.error?.trim() ? step.error : undefined;\n\n return {\n id: step.id,\n title: step.title,\n description: step.description,\n status: toWorkflowStepStatus(step.status),\n content: error === undefined ? step.content : undefined,\n durationMs: step.status === 'completed' ? step.duration : undefined,\n error,\n };\n}\n\n// =============================================================================\n// Step Icon Component\n// =============================================================================\n\ninterface StepIconProps {\n status: StepStatus;\n index: number;\n className?: string;\n}\n\nfunction StepIcon({ status, index, className }: StepIconProps) {\n return (\n <WorkflowStepStatusIcon\n status={toWorkflowStepStatus(status)}\n index={index}\n className={className}\n />\n );\n}\n\nStepIcon.displayName = 'StepIcon';\n\n// =============================================================================\n// Single Step Item\n// =============================================================================\n\ninterface AIStepItemProps {\n step: StepData;\n index: number;\n isLast: boolean;\n expandable?: boolean;\n defaultExpanded?: boolean;\n}\n\nfunction AIStepItem({\n step,\n index,\n isLast,\n expandable = true,\n defaultExpanded = false,\n}: AIStepItemProps) {\n const [expanded, setExpanded] = React.useState(defaultExpanded);\n\n return (\n <WorkflowStepItem\n step={toWorkflowStep(step)}\n index={index}\n isLast={isLast}\n appearance=\"contained\"\n itemSlot=\"ai-step-item\"\n expandable={expandable}\n expanded={expanded}\n onExpandedChange={() => setExpanded((value) => !value)}\n />\n );\n}\n\nAIStepItem.displayName = 'AIStepItem';\n\n// =============================================================================\n// Main AISteps Component\n// =============================================================================\n\nexport interface AIStepsProps\n extends VariantProps<typeof stepsContainerVariants> {\n /** Array of steps */\n steps: StepData[];\n /** Title for the steps container */\n title?: string;\n /** Whether the container is collapsible */\n collapsible?: boolean;\n /** Whether the container is expanded by default */\n defaultExpanded?: boolean;\n /** Whether individual steps are expandable */\n stepsExpandable?: boolean;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * AISteps displays a multi-step progress indicator for AI workflows.\n * Shows step status (pending, running, complete, error) with expandable details and timing.\n *\n * @llms Multi-step AI progress with status icons, timing, expandable details\n * @example\n * ```tsx\n * <AISteps\n * title=\"Processing\"\n * steps={[\n * { label: 'Analyzing', status: 'complete', duration: '2s' },\n * { label: 'Generating', status: 'running' },\n * ]}\n * />\n * ```\n */\nexport function AISteps({\n steps,\n title,\n variant,\n collapsible = true,\n defaultExpanded = true,\n stepsExpandable = true,\n className,\n}: AIStepsProps) {\n const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);\n const prefersReducedMotion = useReducedMotion();\n\n // Calculate summary stats\n const completedCount = steps.filter((s) => s.status === 'completed').length;\n const totalCount = steps.length;\n const hasError = steps.some((s) => s.status === 'error');\n const isRunning = steps.some((s) => s.status === 'running');\n\n return (\n <section\n data-slot=\"ai-steps\"\n aria-label={title || 'Steps'}\n className={cn(stepsContainerVariants({ variant }), className)}\n >\n {/* Header */}\n {(title || collapsible) && (\n <button\n type=\"button\"\n onClick={() => collapsible && setIsExpanded(!isExpanded)}\n disabled={!collapsible}\n aria-expanded={collapsible ? isExpanded : undefined}\n className={cn(\n 'flex items-center justify-between w-full px-4 py-3 border-b border-border',\n collapsible && 'hover:bg-muted cursor-pointer',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n )}\n >\n <div className=\"flex items-center gap-2\">\n {isRunning && (\n <Clock className=\"size-4 text-primary animate-pulse motion-reduce:animate-none\" />\n )}\n {hasError && !isRunning && (\n <AlertCircle className=\"size-4 text-destructive\" />\n )}\n {!isRunning && !hasError && completedCount === totalCount && (\n <Check className=\"size-4 text-success\" />\n )}\n <span className=\"text-sm font-medium text-foreground\">\n {title || 'Steps'}\n </span>\n <span className=\"text-xs text-text-quaternary\">\n ({completedCount}/{totalCount})\n </span>\n </div>\n\n {collapsible && (\n <div className=\"shrink-0\">\n {isExpanded ? (\n <ChevronDown className=\"size-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"size-4 text-muted-foreground rtl:rotate-180\" />\n )}\n </div>\n )}\n </button>\n )}\n\n {/* Steps List */}\n <AnimatePresence initial={false}>\n {isExpanded && (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: prefersReducedMotion ? 0 : 0.2 }}\n className=\"overflow-hidden\"\n >\n <WorkflowStepRenderer\n appearance=\"contained\"\n steps={steps.map(toWorkflowStep)}\n itemSlot=\"ai-step-item\"\n expandable={stepsExpandable}\n />\n </motion.div>\n )}\n </AnimatePresence>\n </section>\n );\n}\n\nAISteps.displayName = 'AISteps';\n\nexport {\n AIStepItem,\n StepIcon,\n stepIconVariants,\n stepItemVariants,\n stepsContainerVariants,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index175.js","names":[],"sources":["../src/components/organisms/ai/_shared/workflow-step-renderer.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport {\n AlertCircle,\n Check,\n ChevronDown,\n ChevronRight,\n Loader,\n Pause,\n} from 'lucide-react';\nimport { AnimatePresence, motion, useReducedMotion } from 'motion/react';\nimport * as React from 'react';\nimport { assertNever, cn } from '@/lib/utils';\nimport { formatAIDuration } from './format-ai-duration';\n\nexport type WorkflowStepStatus =\n | 'pending'\n | 'running'\n | 'suspended'\n | 'completed'\n | 'error';\n\nexport type WorkflowStepAppearance = 'contained' | 'embedded' | 'timeline';\n\nexport interface WorkflowStepViewModel {\n id: string;\n title: string;\n description?: string;\n contextLabel?: string;\n status: WorkflowStepStatus;\n content?: React.ReactNode;\n durationMs?: number;\n error?: string;\n}\n\nexport interface WorkflowStepRendererProps {\n steps: readonly WorkflowStepViewModel[];\n appearance?: WorkflowStepAppearance;\n itemSlot?: string;\n expandable?: boolean;\n activeStepId?: string;\n expandedStepIds?: readonly string[];\n defaultExpandedStepIds?: readonly string[];\n onExpandedStepIdsChange?: (ids: readonly string[]) => void;\n className?: string;\n}\n\ninterface PrivateWorkflowStepRendererProps extends WorkflowStepRendererProps {\n renderItems?: boolean;\n}\n\nconst workflowStepItemStatusClasses = {\n pending: 'text-muted-foreground',\n running: 'text-primary',\n suspended: 'text-warning',\n completed: 'text-success',\n error: 'text-destructive',\n} as const satisfies Record<WorkflowStepStatus, string>;\n\nconst workflowStepIconStatusClasses = {\n pending: 'bg-accent text-muted-foreground',\n running: 'bg-primary/20 text-primary',\n suspended: 'bg-warning/20 text-warning',\n completed: 'bg-success/20 text-success',\n error: 'bg-destructive/20 text-destructive',\n} as const satisfies Record<WorkflowStepStatus, string>;\n\nexport const workflowStepItemVariants = cva(\n 'flex items-start gap-3 px-4 py-3 transition-colors motion-reduce:transition-none',\n {\n variants: {\n status: workflowStepItemStatusClasses,\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nexport const workflowStepIconVariants = cva(\n 'size-5 shrink-0 flex items-center justify-center rounded-full',\n {\n variants: {\n status: workflowStepIconStatusClasses,\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nconst workflowStepAppearanceConfig = {\n contained: {\n rootClassName: 'relative',\n hasDivider: true,\n hasConnector: false,\n },\n embedded: {\n rootClassName: 'relative',\n hasDivider: true,\n hasConnector: false,\n },\n timeline: {\n rootClassName: 'relative',\n hasDivider: false,\n hasConnector: true,\n },\n} as const satisfies Record<\n WorkflowStepAppearance,\n { rootClassName: string; hasDivider: boolean; hasConnector: boolean }\n>;\n\nexport function normalizeExpandedWorkflowStepIds(\n ids: readonly string[],\n steps: readonly WorkflowStepViewModel[],\n): string[] {\n const requested = new Set(ids);\n return steps.flatMap((step) => (requested.has(step.id) ? [step.id] : []));\n}\n\nfunction areWorkflowStepIdsEqual(\n left: readonly string[],\n right: readonly string[],\n): boolean {\n return (\n left.length === right.length &&\n left.every((id, index) => id === right[index])\n );\n}\n\nfunction isIterableWorkflowStepContent(\n content: React.ReactNode,\n): content is Iterable<React.ReactNode> {\n return (\n typeof content === 'object' &&\n content !== null &&\n Symbol.iterator in content &&\n typeof (content as Iterable<React.ReactNode>)[Symbol.iterator] ===\n 'function'\n );\n}\n\nfunction isIteratorWorkflowStepContent(\n content: unknown,\n): content is Iterator<React.ReactNode> {\n return (\n typeof (content as Partial<Iterator<React.ReactNode>>).next === 'function'\n );\n}\n\ninterface NormalizedWorkflowStepContent {\n content: React.ReactNode;\n hasRenderableContent: boolean;\n changed: boolean;\n}\n\nconst normalizedOneShotWorkflowStepContent = new WeakMap<\n object,\n NormalizedWorkflowStepContent\n>();\n\nfunction normalizeIterableWorkflowStepContent(\n content: Iterable<React.ReactNode>,\n iterator: Iterator<React.ReactNode>,\n): NormalizedWorkflowStepContent {\n const normalizedChildren: React.ReactNode[] = [];\n let hasRenderableContent = false;\n let changed = !Array.isArray(content);\n\n for (let result = iterator.next(); !result.done; result = iterator.next()) {\n const normalizedChild = normalizeWorkflowStepContent(result.value);\n normalizedChildren.push(normalizedChild.content);\n hasRenderableContent ||= normalizedChild.hasRenderableContent;\n changed ||= normalizedChild.changed;\n }\n\n return {\n content: changed ? normalizedChildren : content,\n hasRenderableContent,\n changed,\n };\n}\n\nfunction normalizeWorkflowStepContent(\n content: React.ReactNode,\n): NormalizedWorkflowStepContent {\n if (\n content === null ||\n content === undefined ||\n typeof content === 'boolean' ||\n content === ''\n ) {\n return { content, hasRenderableContent: false, changed: false };\n }\n\n if (\n typeof content === 'string' ||\n typeof content === 'number' ||\n typeof content === 'bigint'\n ) {\n return { content, hasRenderableContent: true, changed: false };\n }\n\n if (React.isValidElement<{ children?: React.ReactNode }>(content)) {\n if (content.type !== React.Fragment) {\n return { content, hasRenderableContent: true, changed: false };\n }\n\n const normalizedChildren = normalizeWorkflowStepContent(\n content.props.children,\n );\n return {\n content: normalizedChildren.changed\n ? React.cloneElement(content, undefined, normalizedChildren.content)\n : content,\n hasRenderableContent: normalizedChildren.hasRenderableContent,\n changed: normalizedChildren.changed,\n };\n }\n\n if (isIterableWorkflowStepContent(content)) {\n const iterator = content[Symbol.iterator]();\n const oneShotCacheKey = isIteratorWorkflowStepContent(iterator)\n ? (iterator as object)\n : null;\n\n if (oneShotCacheKey !== null) {\n const cached = normalizedOneShotWorkflowStepContent.get(oneShotCacheKey);\n if (cached !== undefined) return cached;\n }\n\n const normalized = normalizeIterableWorkflowStepContent(content, iterator);\n if (oneShotCacheKey !== null) {\n normalizedOneShotWorkflowStepContent.set(oneShotCacheKey, normalized);\n }\n return normalized;\n }\n\n return { content, hasRenderableContent: true, changed: false };\n}\n\nfunction getNonBlankWorkflowStepError(\n error: string | undefined,\n): string | undefined {\n return error?.trim() ? error : undefined;\n}\n\nfunction getWorkflowStepStatusLabel(status: WorkflowStepStatus): string {\n switch (status) {\n case 'pending':\n return 'Pending';\n case 'running':\n return 'Running';\n case 'suspended':\n return 'Paused';\n case 'completed':\n return 'Completed';\n case 'error':\n return 'Error';\n default:\n return assertNever(status);\n }\n}\n\nexport interface WorkflowStepStatusIconProps {\n status: WorkflowStepStatus;\n index: number;\n className?: string;\n}\n\nexport function WorkflowStepStatusIcon({\n status,\n index,\n className,\n}: WorkflowStepStatusIconProps) {\n const iconClass = cn(workflowStepIconVariants({ status }), className);\n\n switch (status) {\n case 'pending':\n return (\n <div data-slot=\"workflow-step-icon\" className={iconClass}>\n <span className=\"text-xs font-medium\">{index + 1}</span>\n </div>\n );\n case 'running':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(\n iconClass,\n 'delight-status-pulse motion-reduce:!animate-none',\n )}\n >\n <Loader className=\"size-3 animate-spin motion-reduce:animate-none\" />\n </div>\n );\n case 'suspended':\n return (\n <div data-slot=\"workflow-step-icon\" className={iconClass}>\n <Pause className=\"size-3\" />\n </div>\n );\n case 'completed':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(\n iconClass,\n 'delight-check-bounce motion-reduce:!animate-none',\n )}\n >\n <Check className=\"size-3\" />\n </div>\n );\n case 'error':\n return (\n <div\n data-slot=\"workflow-step-icon\"\n className={cn(iconClass, 'delight-shake motion-reduce:!animate-none')}\n >\n <AlertCircle className=\"size-3\" />\n </div>\n );\n default:\n return assertNever(status);\n }\n}\n\nWorkflowStepStatusIcon.displayName = 'WorkflowStepStatusIcon';\n\nexport interface WorkflowStepItemProps {\n step: WorkflowStepViewModel;\n index: number;\n isLast: boolean;\n appearance?: WorkflowStepAppearance;\n itemSlot?: string;\n expandable?: boolean;\n expanded: boolean;\n active?: boolean;\n onExpandedChange: () => void;\n}\n\nexport function WorkflowStepItem({\n step,\n index,\n isLast,\n appearance = 'contained',\n itemSlot = 'workflow-step-item',\n expandable = true,\n expanded,\n active = false,\n onExpandedChange,\n}: WorkflowStepItemProps) {\n const contentId = React.useId();\n const errorDescriptionId = React.useId();\n const normalizedContent = normalizeWorkflowStepContent(step.content);\n const hasContent = normalizedContent.hasRenderableContent;\n const error = getNonBlankWorkflowStepError(step.error);\n const hasError = error !== undefined;\n const hasExpandableDetails = hasContent || hasError;\n const isDisclosureControl = hasExpandableDetails && expandable;\n const prefersReducedMotion = useReducedMotion();\n const appearanceConfig = workflowStepAppearanceConfig[appearance];\n const disclosureTransition = {\n duration: prefersReducedMotion ? 0 : 0.2,\n };\n const stepContent = (\n <>\n <WorkflowStepStatusIcon status={step.status} index={index} />\n\n <div className=\"min-w-0 flex-1 text-start\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {step.contextLabel && (\n <span\n data-slot=\"workflow-step-context\"\n className=\"rounded-full border border-border px-2 py-0.5 text-[0.6875rem] font-medium leading-none text-secondary-foreground\"\n >\n {step.contextLabel}\n </span>\n )}\n <span\n className={cn(\n 'text-sm font-medium',\n step.status === 'pending'\n ? 'text-text-quaternary'\n : 'text-foreground',\n )}\n >\n {step.title}\n </span>\n <span className=\"text-xs text-secondary-foreground\">\n {getWorkflowStepStatusLabel(step.status)}\n </span>\n {step.durationMs !== undefined && (\n <span className=\"text-xs text-muted-foreground\">\n {formatAIDuration(step.durationMs)}\n </span>\n )}\n </div>\n {step.description && (\n <p className=\"mt-0.5 text-xs text-text-quaternary\">\n {step.description}\n </p>\n )}\n </div>\n\n {isDisclosureControl && (\n <div className=\"shrink-0\">\n {expanded ? (\n <ChevronDown className=\"size-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"size-4 text-muted-foreground rtl:rotate-180\" />\n )}\n </div>\n )}\n </>\n );\n\n return (\n <div\n data-slot={itemSlot}\n data-step-status={step.status}\n data-appearance={appearance}\n className={cn(\n appearanceConfig.rootClassName,\n appearanceConfig.hasDivider && !isLast && 'border-b border-border',\n )}\n >\n {isDisclosureControl ? (\n <button\n type=\"button\"\n onClick={onExpandedChange}\n aria-current={active ? 'step' : undefined}\n aria-expanded={expanded}\n aria-controls={contentId}\n aria-describedby={hasError ? errorDescriptionId : undefined}\n className={cn(\n workflowStepItemVariants({ status: step.status }),\n 'w-full cursor-pointer hover:bg-muted focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n )}\n >\n {stepContent}\n </button>\n ) : (\n <div\n aria-current={active ? 'step' : undefined}\n aria-describedby={hasError ? errorDescriptionId : undefined}\n className={cn(\n workflowStepItemVariants({ status: step.status }),\n 'w-full',\n )}\n >\n {stepContent}\n </div>\n )}\n\n <AnimatePresence initial={false}>\n {expanded && hasExpandableDetails && (\n <motion.div\n id={contentId}\n data-slot=\"workflow-step-panel\"\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={disclosureTransition}\n className=\"overflow-hidden motion-reduce:transition-none\"\n >\n <div className=\"px-4 pb-3 ps-12\">\n {hasError && (\n <div className=\"rounded-lg border border-destructive/50 bg-destructive/10 p-3\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle className=\"mt-0.5 size-4 shrink-0 text-destructive\" />\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n </div>\n )}\n {hasContent && (\n <div className={hasError ? 'mt-3' : undefined}>\n {normalizedContent.content}\n </div>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {hasError && (\n <span id={errorDescriptionId} className=\"sr-only\">\n {error}\n </span>\n )}\n\n {appearanceConfig.hasConnector && !isLast && (\n <div\n data-slot=\"workflow-step-connector\"\n aria-hidden=\"true\"\n className=\"absolute top-8 -bottom-3 start-6 w-px bg-border\"\n />\n )}\n </div>\n );\n}\n\nWorkflowStepItem.displayName = 'WorkflowStepItem';\n\nexport function WorkflowStepRenderer({\n steps,\n appearance = 'contained',\n itemSlot = 'workflow-step-item',\n expandable = true,\n activeStepId,\n expandedStepIds: controlledExpandedStepIds,\n defaultExpandedStepIds = [],\n onExpandedStepIdsChange,\n className,\n renderItems = true,\n}: PrivateWorkflowStepRendererProps) {\n const isControlled = controlledExpandedStepIds !== undefined;\n const controlledSnapshot = isControlled\n ? [...controlledExpandedStepIds]\n : undefined;\n const [uncontrolledExpandedStepIds, setUncontrolledExpandedStepIds] =\n React.useState<readonly string[]>(() =>\n normalizeExpandedWorkflowStepIds(defaultExpandedStepIds, steps),\n );\n const lastControlledExpandedStepIdsRef = React.useRef<readonly string[]>(\n controlledSnapshot ?? [],\n );\n const wasControlledRef = React.useRef(isControlled);\n const rawExpandedStepIds = isControlled\n ? controlledExpandedStepIds\n : uncontrolledExpandedStepIds;\n const visibleExpandedStepIds = normalizeExpandedWorkflowStepIds(\n rawExpandedStepIds,\n steps,\n );\n const expandedSet = new Set(visibleExpandedStepIds);\n\n React.useLayoutEffect(() => {\n if (controlledSnapshot !== undefined) {\n lastControlledExpandedStepIdsRef.current = controlledSnapshot;\n }\n }, [controlledSnapshot]);\n\n React.useLayoutEffect(() => {\n const wasControlled = wasControlledRef.current;\n wasControlledRef.current = isControlled;\n if (isControlled) return;\n\n setUncontrolledExpandedStepIds((current) => {\n const source = wasControlled\n ? lastControlledExpandedStepIdsRef.current\n : current;\n const reconciled = normalizeExpandedWorkflowStepIds(source, steps);\n return areWorkflowStepIdsEqual(reconciled, current)\n ? current\n : reconciled;\n });\n }, [isControlled, steps]);\n\n const toggleStep = (id: string) => {\n const next = new Set(visibleExpandedStepIds);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n const normalizedNext = normalizeExpandedWorkflowStepIds([...next], steps);\n if (!isControlled) {\n setUncontrolledExpandedStepIds([...normalizedNext]);\n }\n onExpandedStepIdsChange?.([...normalizedNext]);\n };\n\n if (!renderItems) return null;\n\n return (\n <ol\n data-slot=\"workflow-step-list\"\n data-appearance={appearance}\n className={cn('m-0 list-none p-0', className)}\n >\n {steps.map((step, index) => (\n <li key={step.id}>\n <WorkflowStepItem\n step={step}\n index={index}\n isLast={index === steps.length - 1}\n appearance={appearance}\n itemSlot={itemSlot}\n expandable={expandable}\n expanded={expandedSet.has(step.id)}\n active={activeStepId === step.id}\n onExpandedChange={() => toggleStep(step.id)}\n />\n </li>\n ))}\n </ol>\n );\n}\n\nWorkflowStepRenderer.displayName = 'WorkflowStepRenderer';\n"],"mappings":"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"}
|