@keboola/design 11.6.1 → 11.9.0

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 (153) hide show
  1. package/AGENTS.md +16 -1
  2. package/CHANGELOG.md +86 -0
  3. package/COMPONENT-API.md +47 -46
  4. package/README.md +1 -1
  5. package/dist/{AIKit-CQxVwyAk.js → AIKit-ELIsegJz.js} +550 -103
  6. package/dist/AIKit-ELIsegJz.js.map +1 -0
  7. package/dist/{Alert-C4Y9IwMI.js → Alert-BsIM_oFK.js} +2 -2
  8. package/dist/{Alert-C4Y9IwMI.js.map → Alert-BsIM_oFK.js.map} +1 -1
  9. package/dist/{BrandEditor-CS9P4r2p.js → BrandEditor-BsTBM3s6.js} +4 -4
  10. package/dist/{BrandEditor-CS9P4r2p.js.map → BrandEditor-BsTBM3s6.js.map} +1 -1
  11. package/dist/{Breadcrumb-D1id7YXd.js → Breadcrumb-xqEUxfwn.js} +2 -2
  12. package/dist/{Breadcrumb-D1id7YXd.js.map → Breadcrumb-xqEUxfwn.js.map} +1 -1
  13. package/dist/{Checkbox-Bqr6zXcW.js → Checkbox-Dq5fPNrO.js} +2 -2
  14. package/dist/{Checkbox-Bqr6zXcW.js.map → Checkbox-Dq5fPNrO.js.map} +1 -1
  15. package/dist/{Clipboard-C2YBRfD8.js → Clipboard-BZitKiSA.js} +2 -2
  16. package/dist/{Clipboard-C2YBRfD8.js.map → Clipboard-BZitKiSA.js.map} +1 -1
  17. package/dist/{ClipboardButton-CrljClL1.js → ClipboardButton-KHQnPEh_.js} +2 -2
  18. package/dist/{ClipboardButton-CrljClL1.js.map → ClipboardButton-KHQnPEh_.js.map} +1 -1
  19. package/dist/{CodeEditor-C9AS8Ch0.js → CodeEditor-BJKJXA0c.js} +4 -4
  20. package/dist/{CodeEditor-C9AS8Ch0.js.map → CodeEditor-BJKJXA0c.js.map} +1 -1
  21. package/dist/{ColorInput-Dg87lKcR.js → ColorInput-Bj3dfPFA.js} +3 -3
  22. package/dist/{ColorInput-Dg87lKcR.js.map → ColorInput-Bj3dfPFA.js.map} +1 -1
  23. package/dist/{ColorModeSwitch-CsWLiTBX.js → ColorModeSwitch-CWt-DZGC.js} +2 -2
  24. package/dist/{ColorModeSwitch-CsWLiTBX.js.map → ColorModeSwitch-CWt-DZGC.js.map} +1 -1
  25. package/dist/{Combobox-BfanUAqY.js → Combobox-D8PrEqTG.js} +3 -3
  26. package/dist/{Combobox-BfanUAqY.js.map → Combobox-D8PrEqTG.js.map} +1 -1
  27. package/dist/{Command-CqxoI_De.js → Command-BDU3C1gg.js} +2 -2
  28. package/dist/{Command-CqxoI_De.js.map → Command-BDU3C1gg.js.map} +1 -1
  29. package/dist/{CopyField-Rx9HPTbJ.js → CopyField-BHRQUyuF.js} +2 -2
  30. package/dist/{CopyField-Rx9HPTbJ.js.map → CopyField-BHRQUyuF.js.map} +1 -1
  31. package/dist/{DateInput-DpifECUQ.js → DateInput-B6N8g0ra.js} +3 -3
  32. package/dist/{DateInput-DpifECUQ.js.map → DateInput-B6N8g0ra.js.map} +1 -1
  33. package/dist/{DateRangeInput-9MIw7P6L.js → DateRangeInput-7M9Z4cVO.js} +3 -3
  34. package/dist/{DateRangeInput-9MIw7P6L.js.map → DateRangeInput-7M9Z4cVO.js.map} +1 -1
  35. package/dist/{DropdownMenu-CASr-jgl.js → DropdownMenu-CgVwhDvl.js} +9 -4
  36. package/dist/DropdownMenu-CgVwhDvl.js.map +1 -0
  37. package/dist/{FieldItem-DtPTzNef.js → FieldItem-DZGIdiXE.js} +3 -3
  38. package/dist/{FieldItem-DtPTzNef.js.map → FieldItem-DZGIdiXE.js.map} +1 -1
  39. package/dist/{Form-DAaatlBk.js → Form-CcK7dRrC.js} +5 -5
  40. package/dist/{Form-DAaatlBk.js.map → Form-CcK7dRrC.js.map} +1 -1
  41. package/dist/{FormGroup-Bl8JmnzJ.js → FormGroup-DR_gZ25-.js} +3 -3
  42. package/dist/{FormGroup-Bl8JmnzJ.js.map → FormGroup-DR_gZ25-.js.map} +1 -1
  43. package/dist/{InputGroup-DcZRlVnN.js → InputGroup-Do8K2hvD.js} +2 -1
  44. package/dist/InputGroup-Do8K2hvD.js.map +1 -0
  45. package/dist/{Kbd-D1Azcc4g.js → Kbd-LCFMumoq.js} +2 -2
  46. package/dist/{Kbd-D1Azcc4g.js.map → Kbd-LCFMumoq.js.map} +1 -1
  47. package/dist/{MermaidDiagram-CujFxVzk.js → MermaidDiagram-ZG0iiDV_.js} +2 -2
  48. package/dist/{MermaidDiagram-CujFxVzk.js.map → MermaidDiagram-ZG0iiDV_.js.map} +1 -1
  49. package/dist/{Modal-Coj-H02o.js → Modal-I3VWk2oo.js} +2 -2
  50. package/dist/{Modal-Coj-H02o.js.map → Modal-I3VWk2oo.js.map} +1 -1
  51. package/dist/{ModalTitle-C76ke2eo.js → ModalTitle-CeLM_mX9.js} +2 -2
  52. package/dist/ModalTitle-CeLM_mX9.js.map +1 -0
  53. package/dist/{MultiActionButtonGroup-CNNoBQbv.js → MultiActionButtonGroup-CYZ8IgSf.js} +2 -2
  54. package/dist/{MultiActionButtonGroup-CNNoBQbv.js.map → MultiActionButtonGroup-CYZ8IgSf.js.map} +1 -1
  55. package/dist/{RadioGroup-CUBsuP7r.js → RadioGroup-Byc2mym4.js} +2 -2
  56. package/dist/{RadioGroup-CUBsuP7r.js.map → RadioGroup-Byc2mym4.js.map} +1 -1
  57. package/dist/{Search-DVpJuzr9.js → Search-Dhig_hPD.js} +2 -2
  58. package/dist/{Search-DVpJuzr9.js.map → Search-Dhig_hPD.js.map} +1 -1
  59. package/dist/{SearchInput-Q85p8Ews.js → SearchInput-92r2bkA7.js} +3 -3
  60. package/dist/{SearchInput-Q85p8Ews.js.map → SearchInput-92r2bkA7.js.map} +1 -1
  61. package/dist/{SectionNav-mpmSM3OC.js → SectionNav-CNLJsiVG.js} +3 -3
  62. package/dist/{SectionNav-mpmSM3OC.js.map → SectionNav-CNLJsiVG.js.map} +1 -1
  63. package/dist/{Sheet-Chf0kX1E.js → Sheet-OparjIi-.js} +2 -2
  64. package/dist/{Sheet-Chf0kX1E.js.map → Sheet-OparjIi-.js.map} +1 -1
  65. package/dist/{Sidebar-CTWsHZhF.js → Sidebar-CLEbBtNY.js} +190 -25
  66. package/dist/Sidebar-CLEbBtNY.js.map +1 -0
  67. package/dist/{Slider-Bv0B6lI0.js → Slider-DLclvRws.js} +2 -2
  68. package/dist/{Slider-Bv0B6lI0.js.map → Slider-DLclvRws.js.map} +1 -1
  69. package/dist/{TextInput-DiEMxVF6.js → TextInput-CFTf4Cz1.js} +5 -4
  70. package/dist/TextInput-CFTf4Cz1.js.map +1 -0
  71. package/dist/{ThemeProvider-BI6JWBdJ.js → ThemeProvider-DAmNn9Sd.js} +2 -2
  72. package/dist/{ThemeProvider-BI6JWBdJ.js.map → ThemeProvider-DAmNn9Sd.js.map} +1 -1
  73. package/dist/{Timeline-BG5Xogxh.js → Timeline-C8-wnRRr.js} +2 -2
  74. package/dist/{Timeline-BG5Xogxh.js.map → Timeline-C8-wnRRr.js.map} +1 -1
  75. package/dist/{ZoomableSvg-U_VH3QRO.js → ZoomableSvg-BZlk3PFJ.js} +3 -3
  76. package/dist/{ZoomableSvg-U_VH3QRO.js.map → ZoomableSvg-BZlk3PFJ.js.map} +1 -1
  77. package/dist/editors.js +2 -2
  78. package/dist/flint.js +1 -1
  79. package/dist/index.d.ts +900 -561
  80. package/dist/index.js +36 -34
  81. package/dist/internal/blocks/AIKit.js +2 -2
  82. package/dist/internal/blocks/BrandEditor.js +1 -1
  83. package/dist/internal/blocks/ChipEditor.js +137 -0
  84. package/dist/internal/blocks/ChipEditor.js.map +1 -0
  85. package/dist/internal/blocks/ClipboardButton.js +1 -1
  86. package/dist/internal/blocks/ColorInput.js +1 -1
  87. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  88. package/dist/internal/blocks/Command.js +1 -1
  89. package/dist/internal/blocks/CopyField.js +1 -1
  90. package/dist/internal/blocks/DateInput.js +1 -1
  91. package/dist/internal/blocks/DateRangeInput.js +1 -1
  92. package/dist/internal/blocks/ExportMenu.js +2 -2
  93. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  94. package/dist/internal/blocks/Form.js +1 -1
  95. package/dist/internal/blocks/FormGroup.js +1 -1
  96. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  97. package/dist/internal/blocks/MultiCombobox.js +18 -28
  98. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  99. package/dist/internal/blocks/NumberInput.js +1 -1
  100. package/dist/internal/blocks/PasswordInput.js +2 -2
  101. package/dist/internal/blocks/SearchInput.js +1 -1
  102. package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
  103. package/dist/internal/blocks/SectionNav.js +1 -1
  104. package/dist/internal/blocks/SplitButton.js +1 -1
  105. package/dist/internal/blocks/TextInput.js +1 -1
  106. package/dist/internal/blocks/Textarea.js +1 -1
  107. package/dist/internal/blocks/TimeInput.js +2 -2
  108. package/dist/internal/components/Alert.js +1 -1
  109. package/dist/internal/components/Avatar.js +1 -1
  110. package/dist/internal/components/Breadcrumb.js +1 -1
  111. package/dist/internal/components/Checkbox.js +1 -1
  112. package/dist/internal/components/Clipboard.js +1 -1
  113. package/dist/internal/components/CollapsiblePanel.js +1 -1
  114. package/dist/internal/components/Combobox.js +1 -1
  115. package/dist/internal/components/DropdownMenu.js +1 -1
  116. package/dist/internal/components/InputGroup.js +1 -1
  117. package/dist/internal/components/Kbd.js +1 -1
  118. package/dist/internal/components/Modal.js +1 -1
  119. package/dist/internal/components/RadioGroup.js +1 -1
  120. package/dist/internal/components/Search.js +1 -1
  121. package/dist/internal/components/Sheet.js +1 -1
  122. package/dist/internal/components/Sidebar.js +1 -1
  123. package/dist/internal/components/Slider.js +1 -1
  124. package/dist/internal/components/StatusDot.js +67 -0
  125. package/dist/internal/components/StatusDot.js.map +1 -0
  126. package/dist/internal/components/ThemeProvider.js +1 -1
  127. package/dist/internal/components/Timeline.js +1 -1
  128. package/dist/internal/components/Tooltip.js +2 -2
  129. package/dist/internal/components/Truncated.js +1 -1
  130. package/dist/internal/components/ZoomableSvg.js +1 -1
  131. package/dist/internal/hooks/useScrollbarPosition.js +1 -1
  132. package/dist/internal/utils/mergeRefs.js +27 -9
  133. package/dist/internal/utils/mergeRefs.js.map +1 -1
  134. package/dist/internal/utils.js +2 -2
  135. package/dist/markdown-editor.js +5 -5
  136. package/dist/mermaid.js +1 -1
  137. package/dist/rjsf.js +9 -9
  138. package/dist/styles.css +1 -1
  139. package/dist/testing.js +1 -1
  140. package/dist/useElement-BK3AAiIf.js +24 -0
  141. package/dist/useElement-BK3AAiIf.js.map +1 -0
  142. package/dist/{utils-DnkrFYqY.js → utils-BW4AE8VP.js} +31 -3
  143. package/dist/utils-BW4AE8VP.js.map +1 -0
  144. package/package.json +2 -1
  145. package/dist/AIKit-CQxVwyAk.js.map +0 -1
  146. package/dist/DropdownMenu-CASr-jgl.js.map +0 -1
  147. package/dist/InputGroup-DcZRlVnN.js.map +0 -1
  148. package/dist/ModalTitle-C76ke2eo.js.map +0 -1
  149. package/dist/Sidebar-CTWsHZhF.js.map +0 -1
  150. package/dist/TextInput-DiEMxVF6.js.map +0 -1
  151. package/dist/useElement-DkF6esWL.js +0 -15
  152. package/dist/useElement-DkF6esWL.js.map +0 -1
  153. package/dist/utils-DnkrFYqY.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AIKit-ELIsegJz.js","names":["renderVariantIcon","LinkIcon","TableIcon","Table"],"sources":["../src/blocks/AIKit/AnswerActions.tsx","../src/blocks/AIKit/CollapsibleBody.tsx","../src/blocks/AIKit/CollapsibleStepHeader.tsx","../src/blocks/AIKit/hasMotion.ts","../src/blocks/AIKit/InlineStepDetail.tsx","../src/blocks/AIKit/InlineStepLabel.tsx","../src/blocks/AIKit/AnswerSummary.tsx","../src/blocks/AIKit/ChatInlineIcon.tsx","../src/blocks/AIKit/InlineStepGroup.tsx","../src/blocks/AIKit/DiagramBlock.tsx","../src/blocks/AIKit/diagramChunk.ts","../src/blocks/AIKit/Markdown.tsx","../src/blocks/AIKit/MarkdownTable.tsx","../src/blocks/AIKit/MessageBubble.tsx","../src/blocks/AIKit/PlanApproval.tsx","../src/blocks/AIKit/PlanRewritingIndicator.tsx","../src/blocks/AIKit/PromptInputAction.tsx","../src/blocks/AIKit/PromptInputCommands.tsx","../src/blocks/AIKit/PromptInputMenuTrigger.tsx","../src/blocks/AIKit/PromptInputSubmit.tsx","../src/blocks/AIKit/PromptInput.tsx","../src/blocks/AIKit/Question.tsx","../src/blocks/AIKit/QuestionBlock.tsx","../src/blocks/AIKit/SuggestedPrompt.tsx","../src/blocks/AIKit/ThinkingIndicator.tsx","../src/blocks/AIKit/ToolCall/ToolCallApproval.tsx","../src/blocks/AIKit/ToolCall/ToolCallChip.tsx","../src/blocks/AIKit/ToolCallStatusHeader.tsx","../src/blocks/AIKit/usageStatsHelpers.ts","../src/blocks/AIKit/UsageBar.tsx","../src/blocks/AIKit/UsageStatsRing.tsx","../src/blocks/AIKit/UsageStats.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { ButtonGroup } from '../../components/ButtonGroup';\nimport { Tooltip } from '../../components/Tooltip';\nimport { ThumbsDown, ThumbsUp } from '../../icons';\nimport { cn } from '../../utils';\nimport { ClipboardButton } from '../ClipboardButton';\n\n/** Which way a reader rated an answer. */\nexport type AnswerVote = 'up' | 'down';\n\nconst VOTE_BUTTONS = [\n { vote: 'up', icon: <ThumbsUp className=\"tw:size-4\" /> },\n { vote: 'down', icon: <ThumbsDown className=\"tw:size-4\" /> },\n] as const;\n\nconst DEFAULT_LABELS = { up: 'Good answer', down: 'Bad answer' } as const;\n\n/** Roomier for a panel a reader sits in; the compact one suits a row inside a dense transcript. */\nconst SIZES = {\n small: { button: 'icon-xs', gap: 'extra-small' },\n medium: { button: 'icon-sm', gap: 'little-small' },\n} as const;\n\ntype Props = {\n /**\n * The answer as the reader would read it, for the clipboard.\n *\n * - Empty or absent draws no copy button: a turn that produced only tool calls has nothing\n * to take away, and a disabled control is a worse answer to that than no control.\n */\n copyText?: string;\n /** The vote already recorded against this answer, or `null` for none. */\n vote: AnswerVote | null;\n onVote: (vote: AnswerVote) => void;\n /** Extra controls for the answer — a report button, say. Drawn beside copy, ahead of it. */\n actions?: ReactNode;\n /** What the thumbs are called. Some surfaces rate a \"response\", others an \"answer\". */\n labels?: { up: string; down: string };\n /**\n * What to say back once a vote lands, if anything.\n *\n * - Announced politely, so a reader who cannot see it still hears the vote registered.\n */\n confirmation?: { up: string; down: string };\n size?: keyof typeof SIZES;\n /**\n * How the row sits under the answer.\n *\n * - `inline` (default) — one group, reading left to right.\n * - `split` — the verdict on the left, what to do with the answer on the right, pushed to the\n * edges of the bubble.\n */\n layout?: 'inline' | 'split';\n /** Fires when the reader takes the answer away; the copy itself is the button's own. */\n onCopy?: () => void;\n};\n\n/**\n * What a reader can do with a finished answer: take it away, and say whether it was any good.\n *\n * - **Always rendered, never hover-only.** A reveal-on-hover row does not exist for anyone\n * reaching it without a pointer. The buttons are quiet (`invisible`) rather than hidden.\n * - Copy sits first: it is the one action with no round trip.\n * - **A vote can be changed but not withdrawn.** `aria-pressed` says which one is recorded, and\n * both buttons stay focusable so a reader can switch. Pressing the pressed one re-sends the\n * same vote.\n * - The recorded vote and the write are the caller's: the two chats vote against different\n * endpoints, and only the caller knows whether a turn is finished enough to rate.\n */\nexport const AnswerActions = ({\n copyText,\n vote,\n onVote,\n onCopy,\n actions,\n labels = DEFAULT_LABELS,\n confirmation,\n size = 'small',\n layout = 'inline',\n}: Props) => {\n const { button, gap } = SIZES[size];\n\n const votes = VOTE_BUTTONS.map(({ vote: candidate, icon }) => {\n const isRecorded = vote === candidate;\n const label = labels[candidate];\n\n return (\n <Tooltip key={candidate} tooltip={label} placement=\"top\" triggerAsChild>\n <Button\n size={button}\n variant=\"invisible\"\n // The recorded vote wears its meaning: green for up, red for down.\n className={cn(\n isRecorded &&\n candidate === 'up' &&\n 'tw:bg-success/10 tw:text-success tw:hover:not-disabled:bg-success/20 tw:hover:not-disabled:text-success',\n isRecorded &&\n candidate === 'down' &&\n 'tw:bg-destructive/10 tw:text-destructive tw:hover:not-disabled:bg-destructive/20 tw:hover:not-disabled:text-destructive',\n )}\n aria-label={label}\n aria-pressed={isRecorded}\n onClick={() => onVote(candidate)}\n >\n {icon}\n </Button>\n </Tooltip>\n );\n });\n\n const copy = copyText ? (\n <ClipboardButton\n text={copyText}\n tooltip=\"Copy answer\"\n size={button}\n variant=\"invisible\"\n onClick={onCopy}\n />\n ) : null;\n\n // Mounted empty and filled on the vote: a live region that arrives with its text already in it\n // is generally not announced, because nothing inside it changed.\n const said = confirmation ? (\n <span\n aria-live=\"polite\"\n className=\"tw:ml-1 tw:text-xs tw:font-medium tw:text-foreground tw:empty:hidden tw:animate-in tw:fade-in tw:slide-in-from-left-1 tw:duration-300\"\n >\n {vote ? confirmation[vote] : ''}\n </span>\n ) : null;\n\n if (layout === 'split') {\n return (\n <div className=\"tw:flex tw:w-full tw:items-center tw:justify-between tw:gap-2\">\n <ButtonGroup space={gap} aria-label=\"Answer actions\">\n {votes}\n {said}\n </ButtonGroup>\n <ButtonGroup space={gap}>\n {actions}\n {copy}\n </ButtonGroup>\n </div>\n );\n }\n\n return (\n <ButtonGroup space={gap} aria-label=\"Answer actions\">\n {copy}\n {votes}\n {actions}\n {said}\n </ButtonGroup>\n );\n};\n","import type { ReactNode, TransitionEvent } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = {\n isExpanded: boolean;\n isClosing: boolean;\n onClosed: () => void;\n children: ReactNode;\n};\n\nexport const CollapsibleBody = ({ isExpanded, isClosing, onClosed, children }: Props) => {\n const handleTransitionEnd = (event: TransitionEvent<HTMLDivElement>) => {\n if (event.target !== event.currentTarget) return;\n if (event.propertyName !== 'grid-template-rows') return;\n if (!isExpanded) onClosed();\n };\n\n return (\n <div\n className={cn(\n 'tw:grid tw:transition-[grid-template-rows] tw:duration-300 tw:ease-out tw:motion-reduce:transition-none',\n isExpanded ? 'tw:grid-rows-[1fr]' : 'tw:grid-rows-[0fr]',\n )}\n onTransitionEnd={handleTransitionEnd}\n >\n <div className=\"tw:min-h-0 tw:overflow-hidden\">{(isExpanded || isClosing) && children}</div>\n </div>\n );\n};\n","import type { ReactNode } from 'react';\n\nimport { ChevronDown, CircleCheck, Loader2, XCircle } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Variant = 'success' | 'error' | 'processing' | 'dismissed';\n\ntype Props = {\n isExpanded: boolean;\n onToggle: () => void;\n label: ReactNode;\n variant?: Variant;\n};\n\n// Chrome speaks grey: step headers are meta-information, so they read in\n// muted ink and darken on hover — blue is reserved for genuinely interactive\n// elements (links, buttons), and status colour lives only in the icon. Error\n// keeps its tinted label: a failed step is content, not chrome.\nconst variantClasses: Record<Variant, string> = {\n success:\n 'tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground',\n error:\n 'tw:text-destructive tw:focus-visible:outline-destructive tw:not-disabled:hover:text-destructive',\n processing:\n 'tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground',\n dismissed:\n 'tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground',\n};\n\n// Icons one step quieter than the label so the row reads text-first.\nconst iconClasses = 'tw:size-3.5 tw:shrink-0 tw:basis-3.5 tw:opacity-70';\n\n// What the icon says, for a reader who is not looking at it. Joins the button's accessible name,\n// so a closed group announces how the run came out and not only what it was called.\nconst variantStatus: Record<Variant, string> = {\n success: 'finished',\n error: 'failed',\n processing: 'running',\n dismissed: 'not run',\n};\n\nconst renderVariantIcon = (variant: Variant) => {\n if (variant === 'processing') {\n return <Loader2 className={cn(iconClasses, 'tw:animate-spin')} />;\n }\n // `error` and `dismissed` share the mark and take their ink from the\n // button's variant class — `destructive` for a real failure,\n // `muted-foreground` for a step the user waved off.\n if (variant === 'error' || variant === 'dismissed') {\n return <XCircle className={iconClasses} />;\n }\n return <CircleCheck className={iconClasses} />;\n};\n\nexport const CollapsibleStepHeader = ({\n isExpanded,\n onToggle,\n label,\n variant = 'success',\n}: Props) => {\n // `data-variant` is how the run came out, for a selector: an E2E test asserting on an outcome\n // would otherwise have to read the icon's shape or the label's ink.\n return (\n <button\n type=\"button\"\n aria-expanded={isExpanded}\n onClick={onToggle}\n data-variant={variant}\n className={cn(\n 'tw:flex tw:w-fit tw:items-center tw:gap-1.5 tw:text-left tw:text-xs tw:font-medium tw:transition-colors tw:focus-visible:outline tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:disabled:opacity-40',\n variantClasses[variant],\n )}\n >\n {renderVariantIcon(variant)}\n <span className=\"tw:min-w-0\">\n {label}\n <span className=\"tw:sr-only\">{` (${variantStatus[variant]})`}</span>\n {/* A word joiner (U+2060) keeps the chevron on the label's last line —\n an inline chevron with nothing binding it to the preceding word\n orphans onto a line of its own at some container widths. */}\n <span className=\"tw:whitespace-nowrap\">\n {'⁠'}\n <ChevronDown\n className={cn(\n 'tw:ml-1.5 tw:inline-block tw:size-3.5 tw:align-middle tw:transition-transform',\n isExpanded && 'tw:rotate-180',\n )}\n />\n </span>\n </span>\n </button>\n );\n};\n","export const hasMotion = () =>\n typeof window.matchMedia === 'function' &&\n !window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n","import type { ReactNode } from 'react';\n\ntype Props = {\n children: ReactNode;\n};\n\nexport const InlineStepDetail = ({ children }: Props) => (\n // `ml-2.5` is half of the `size-5` icon box `InlineStepLabel` puts beside a\n // step, so the rule falls on that icon's centre line rather than 2px inside\n // it. Anything drawing a run of steps can then line its own connector up with\n // the same number.\n <div className=\"tw:ml-2.5 tw:whitespace-pre-wrap tw:border-l tw:border-border tw:pl-3 tw:text-xs tw:text-muted-foreground\">\n {children}\n </div>\n);\n\nexport type { Props as InlineStepDetailProps };\n","import type { ReactNode } from 'react';\n\nimport { CircleCheck, Loader2, XCircle } from '../../icons';\n\ntype Variant = 'processing' | 'success' | 'error' | 'dismissed';\n\ntype Props = {\n variant: Variant;\n children: ReactNode;\n};\n\n// Status lives in the icon alone, and quietly: success/dismissed marks are\n// muted (they are the expected outcome, not news), the spinner is a shade\n// stronger (it reports active work), and only a real error takes the status\n// red. Fixed neutral-* greys were invisible in dark mode; tokens follow it.\nconst renderVariantIcon = (variant: Variant) => {\n if (variant === 'processing') {\n return <Loader2 className=\"tw:size-3.5 tw:animate-spin tw:text-muted-foreground\" />;\n }\n if (variant === 'error') {\n return <XCircle className=\"tw:size-3.5 tw:text-destructive\" />;\n }\n if (variant === 'dismissed') {\n return <XCircle className=\"tw:size-3.5 tw:text-muted-foreground/50\" />;\n }\n return <CircleCheck className=\"tw:size-3.5 tw:text-muted-foreground/50\" />;\n};\n\nexport const InlineStepLabel = ({ variant, children }: Props) => (\n <div className=\"tw:flex tw:min-w-0 tw:items-center tw:gap-1\">\n {/* The icon can punch a gap in a connector drawn behind a run of steps: set\n `--inline-step-surface` on an ancestor to whatever paints behind, and the\n box masks the line across its own height. `relative` is what makes the\n mask work — the connector is absolutely positioned, so it paints above\n static content no matter what colour that content is. Unset the variable\n and the box stays transparent, so a step outside such a list is\n unchanged. */}\n <div className=\"tw:relative tw:flex tw:size-5 tw:shrink-0 tw:items-center tw:justify-center tw:[background:var(--inline-step-surface,transparent)]\">\n {renderVariantIcon(variant)}\n </div>\n <div className=\"tw:flex tw:min-w-0 tw:flex-wrap tw:items-center tw:gap-x-1.5 tw:gap-y-1 tw:text-xs tw:font-medium tw:text-muted-foreground\">\n {children}\n </div>\n </div>\n);\n\nexport type { Variant as InlineStepLabelVariant, Props as InlineStepLabelProps };\n","import { useState } from 'react';\n\nimport { CollapsibleBody } from './CollapsibleBody';\nimport { CollapsibleStepHeader } from './CollapsibleStepHeader';\nimport { hasMotion } from './hasMotion';\nimport { InlineStepDetail } from './InlineStepDetail';\nimport { InlineStepLabel } from './InlineStepLabel';\n\ntype AnswerItem = {\n question: string;\n answer?: string;\n};\n\ntype Variant = 'success' | 'dismissed';\n\ntype Props = {\n items: readonly AnswerItem[];\n variant?: Variant;\n noAnswerLabel?: string;\n onExpandToggle?: (next: boolean) => void;\n};\n\nconst SECTION_LABELS: Record<Variant, string> = {\n success: 'Answered questions',\n dismissed: 'Dismissed questions',\n};\n\nexport const AnswerSummary = ({\n items,\n variant = 'success',\n noAnswerLabel = 'No answer',\n onExpandToggle,\n}: Props) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isClosing, setIsClosing] = useState(false);\n const toggle = () => {\n const next = !isExpanded;\n if (!next) setIsClosing(hasMotion());\n setIsExpanded(next);\n onExpandToggle?.(next);\n };\n const count = items.length;\n const [firstItem] = items;\n const label = count === 1 && firstItem ? firstItem.question : `${count} questions`;\n\n return (\n <section className=\"tw:mt-4 tw:flex tw:flex-col\" aria-label={SECTION_LABELS[variant]}>\n <CollapsibleStepHeader\n isExpanded={isExpanded}\n onToggle={toggle}\n variant={variant}\n label={label}\n />\n\n <CollapsibleBody\n isExpanded={isExpanded}\n isClosing={isClosing}\n onClosed={() => setIsClosing(false)}\n >\n <div className=\"tw:flex tw:flex-col tw:gap-4 tw:pt-4 tw:pl-5\">\n {items.map(({ question, answer }, index) => (\n <div key={`${index}-${question}`} className=\"tw:flex tw:flex-col tw:gap-1\">\n <InlineStepLabel variant={variant}>{question}</InlineStepLabel>\n <InlineStepDetail>\n {answer && answer.length > 0 ? answer : noAnswerLabel}\n </InlineStepDetail>\n </div>\n ))}\n </div>\n </CollapsibleBody>\n </section>\n );\n};\n\nexport type {\n AnswerItem as AnswerSummaryItem,\n Props as AnswerSummaryProps,\n Variant as AnswerSummaryVariant,\n};\n","import type { ChatInlineIconName } from '@keboola/agent-vocabulary';\n\nimport type { LucideIcon } from '../../icons';\nimport {\n AlertCircle,\n ArrowDown,\n ArrowLeft,\n ArrowRight,\n ArrowUp,\n Ban,\n BarChart3,\n Bell,\n Bug,\n Calendar,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n Circle,\n CircleAlert,\n CircleCheck,\n CircleHelp,\n CirclePause,\n CirclePlay,\n CirclePlus,\n CircleStop,\n CircleX,\n Clock,\n Cog,\n Copy,\n Database,\n Download,\n Ellipsis,\n ExternalLink,\n Eye,\n File,\n FilePen,\n FileText,\n Flag,\n Folder,\n Gauge,\n GitBranch,\n GitMerge,\n GitPullRequest,\n Globe,\n Hand,\n History,\n Hourglass,\n Info,\n Key,\n Layers,\n LineChart,\n Link as LinkIcon,\n List,\n ListChecks,\n Loader2,\n Lock,\n Mail,\n Minus,\n Pencil,\n Play,\n Plus,\n RefreshCw,\n Rocket,\n RotateCcw,\n RotateCw,\n Save,\n Search,\n Send,\n Settings,\n Sparkles,\n Star,\n Table as TableIcon,\n ThumbsDown,\n ThumbsUp,\n Trash2,\n TriangleAlert,\n Upload,\n User,\n Users,\n WandSparkles,\n Warehouse,\n Workflow,\n X,\n Zap,\n} from '../../icons';\nimport { cn } from '../../utils';\n\n/**\n * The Lucide component each `icon:<name>` token draws.\n *\n * - The names are FontAwesome-solid ones: kai-agent's prompt teaches that vocabulary, and\n * `@keboola/agent-vocabulary` publishes it as `CHAT_INLINE_ICON_NAMES`.\n * - `satisfies Record<ChatInlineIconName, LucideIcon>` is the drift guard — a name the prompt\n * teaches and this map lacks is a compile error, not a token that silently disappears from an\n * answer.\n * - Several names map to one component on purpose: FA distinguishes `gear` from `cog` and\n * `warning` from `triangle-exclamation`; Lucide draws each pair with one icon.\n * - Read through `Object.hasOwn`, never by plain index: a model-emitted `icon:constructor`\n * otherwise answers with an `Object.prototype` member and React tries to render it.\n */\nconst ICON_REGISTRY: Record<string, LucideIcon | undefined> = {\n 'alert-circle': AlertCircle,\n 'arrow-down': ArrowDown,\n 'arrow-left': ArrowLeft,\n 'arrow-right': ArrowRight,\n 'arrow-rotate-back': RotateCcw,\n 'arrow-rotate-left': RotateCcw,\n 'arrow-rotate-right': RotateCw,\n 'arrow-up': ArrowUp,\n 'arrow-up-right-from-square': ExternalLink,\n 'arrows-rotate': RefreshCw,\n analytics: BarChart3,\n ban: Ban,\n bell: Bell,\n bug: Bug,\n calendar: Calendar,\n changes: FilePen,\n 'chart-line': LineChart,\n check: Check,\n 'check-circle': CircleCheck,\n 'chevron-down': ChevronDown,\n 'chevron-left': ChevronLeft,\n 'chevron-right': ChevronRight,\n 'chevron-up': ChevronUp,\n circle: Circle,\n 'circle-check': CircleCheck,\n 'circle-exclamation': CircleAlert,\n 'circle-info': Info,\n 'circle-pause': CirclePause,\n 'circle-play': CirclePlay,\n 'circle-plus': CirclePlus,\n 'circle-question': CircleHelp,\n 'circle-stop': CircleStop,\n 'circle-xmark': CircleX,\n clock: Clock,\n 'clock-rotate-left': History,\n 'code-branch': GitBranch,\n 'code-merge': GitMerge,\n 'code-pull-request': GitPullRequest,\n cog: Cog,\n configuration: Settings,\n copy: Copy,\n database: Database,\n 'diagram-project': Workflow,\n download: Download,\n ellipsis: Ellipsis,\n envelope: Mail,\n 'exclamation-circle': CircleAlert,\n 'exclamation-triangle': TriangleAlert,\n eye: Eye,\n file: File,\n 'file-lines': FileText,\n flag: Flag,\n folder: Folder,\n gauge: Gauge,\n gear: Settings,\n globe: Globe,\n hand: Hand,\n 'hourglass-half': Hourglass,\n 'info-circle': Info,\n key: Key,\n 'layer-group': Layers,\n link: LinkIcon,\n 'list-check': ListChecks,\n 'list-ul': List,\n lock: Lock,\n 'magnifying-glass': Search,\n minus: Minus,\n 'paper-plane-top': Send,\n pen: Pencil,\n play: Play,\n plus: Plus,\n refresh: RefreshCw,\n rocket: Rocket,\n save: Save,\n 'save-changes': Save,\n search: Search,\n spinner: Loader2,\n sparkles: Sparkles,\n star: Star,\n stop: CircleStop,\n table: TableIcon,\n 'thumbs-down': ThumbsDown,\n 'thumbs-up': ThumbsUp,\n transformation: WandSparkles,\n trash: Trash2,\n 'triangle-exclamation': TriangleAlert,\n upload: Upload,\n user: User,\n 'user-group': Users,\n warning: TriangleAlert,\n warehouse: Warehouse,\n xmark: X,\n zap: Zap,\n} satisfies Record<ChatInlineIconName, LucideIcon>;\n\n/**\n * Extra classes a single name needs on top of the shared list.\n *\n * - `spinner` is the only one: `MAINTAINING.md` maps it to `Loader2` *plus* `tw:animate-spin`,\n * because Lucide draws the arc and leaves the motion to the caller. A still `Loader2` reads as\n * a damaged ring, not as waiting.\n * - Read through `Object.hasOwn`, for the same reason the registry is.\n */\nconst ICON_CLASSES: Record<string, string | undefined> = {\n spinner: 'tw:animate-spin',\n};\n\n/**\n * A whole `icon:<name>` token and nothing else.\n *\n * - Anchored at both ends, and over the same name shape `remarkIconSyntax` (in\n * `@keboola/kai-chat`) matches when it turns bare text into an `inlineCode` node. The two\n * have to agree: a looser reader here accepts inline code the plugin never produced.\n * - That is what keeps ordinary inline code ordinary. A prefix test alone claims\n * `` `icon: database` ``, `` `icon:` `` and a fence body starting `icon:` — text the plugin\n * never turned into a token, and none of it is an icon the author asked for.\n */\nconst TOKEN = /^icon:([a-z][a-z0-9-]*)$/;\n\n/** Built once: an answer is re-parsed per streamed chunk, so `isArriving` runs per code node. */\nconst ICON_NAMES = Object.keys(ICON_REGISTRY);\n\n/**\n * Whether a name is only ever the start of one this registry draws.\n *\n * - Strictly shorter, so a whole name is never read as an unfinished one.\n * - `tabl` → `true` (`table`); `unicorn` and `table-name` → `false`.\n */\nconst isArriving = (name: string): boolean =>\n ICON_NAMES.some((key) => key.length > name.length && key.startsWith(name));\n\n/**\n * The icon name in a code node's text, if the text is a token — drawn, or still arriving.\n *\n * - `icon:table` → `table`; anything else, including `icon: table`, `icon:Table` and\n * `icon:unicorn` → `undefined`.\n * - A name the registry lacks answers `undefined` on purpose, so every call site's own `<code>`\n * fall-through keeps the text its author typed. `icon:` is an ordinary way to name a property,\n * and this renderer draws vendor descriptions and dashboard text as well as agent answers.\n * - A name that only starts one it draws is a token still arriving, answered with so that\n * `<ChatInlineIcon />` draws nothing: an answer streams `icon:t`, `icon:ta`, `icon:tab` before\n * the name lands, and each of those as code is a chip that reflows the line for a frame.\n * - A name that is both — `save`, the start of `save-changes` — is drawn now; waiting would leave\n * a finished token blank for the rest of the answer.\n * - The token reaches a renderer as inline code either because the model wrote it in backticks\n * or because a remark plugin turned the bare text into an `inlineCode` node. Parsing the\n * token is the vocabulary's; producing it is the app's, since the plugin is workspace-internal.\n */\nexport const getChatInlineIconName = (text: string): string | undefined => {\n const name = TOKEN.exec(text)?.[1];\n if (name === undefined) return undefined;\n return Object.hasOwn(ICON_REGISTRY, name) || isArriving(name) ? name : undefined;\n};\n\ntype Props = {\n /** The name from the token, without the `icon:` prefix. */\n name: string;\n};\n\n/**\n * One inline `icon:<name>` token, drawn at the size of the text it leads.\n *\n * - An unknown name renders nothing, which is how a token still arriving (`icon:tabl`) stays\n * blank instead of flashing as a code chip. A name `getChatInlineIconName` withholds keeps its\n * text at the call site's own `<code>` fall-through and never reaches here.\n * - `size-[1em]` tracks the font size, so the icon matches a heading instead of sitting small\n * beside it, and `align-[-0.125em]` on an inline-block optically centres it against the\n * baseline.\n * - `mr` tops up the single source space, which is a word gap and reads as cramped between a\n * glyph and the phrase it labels.\n * - A heavier stroke so an outline icon holds its own next to the bold weight a heading carries.\n * - `spinner` also spins; the mapping owns that, not the caller. See `ICON_CLASSES`.\n * - `aria-hidden`, because the glyph is decorative: the token's text is removed from the answer and\n * nothing replaces it as a label, so a reader that announces unnamed inline SVGs would read an\n * unlabelled graphic before every phrase the agent decorates.\n */\nexport const ChatInlineIcon = ({ name }: Props) => {\n const Icon = Object.hasOwn(ICON_REGISTRY, name) ? ICON_REGISTRY[name] : undefined;\n\n if (Icon === undefined) return null;\n\n return (\n <Icon\n aria-hidden\n className={cn(\n 'tw:mr-[0.15em] tw:inline-block tw:size-[1em] tw:shrink-0 tw:align-[-0.125em] tw:text-muted-foreground',\n Object.hasOwn(ICON_CLASSES, name) ? ICON_CLASSES[name] : undefined,\n )}\n strokeWidth={2.25}\n />\n );\n};\n","import type { CSSProperties, ReactNode } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { CollapsibleStepHeader } from './CollapsibleStepHeader';\nimport type { InlineStepLabelVariant } from './InlineStepLabel';\n\n/**\n * The surface colour, as the custom property the step icons mask against.\n *\n * - Annotated rather than asserted: `CSSProperties` admits no custom property of its own, and\n * an intersection with the one this sets keeps the value type-checked at the assignment.\n */\nconst surfaceStyle = (\n surface: string,\n): CSSProperties & Record<'--inline-step-surface', string> => ({\n '--inline-step-surface': surface,\n});\n\ntype Props = {\n /** The one line the run collapses to. */\n label: ReactNode;\n /** How the whole run reads in one mark. */\n variant?: InlineStepLabelVariant;\n isExpanded: boolean;\n onToggle: () => void;\n /**\n * What paints behind the group, as a CSS colour.\n *\n * - The step icons mask the connector against it, so each mark reads as a break in the rule\n * rather than a chip laid over it.\n * - Wrong value, wrong-coloured notches. A transcript on a panel surface passes that surface,\n * not the page background.\n */\n surface?: string;\n /** Names the group for a screen reader. Without one the run is an unnamed grouping. */\n 'aria-label'?: string;\n /**\n * The hook an E2E suite anchors the group on.\n *\n * - Named by the host, because the name is the host's contract with its own tests.\n * - A selector held in `packages/e2e-testing` breaks silently when this attribute moves.\n */\n 'data-testid'?: string;\n className?: string;\n /** The rows: `InlineStepLabel`, `InlineStepDetail`, and whatever a host draws between them. */\n children: ReactNode;\n};\n\n/**\n * A run of steps an agent took, behind one line that says how far along it is.\n *\n * - The frame only. What a step *says* is the host's — one product names buckets and tables,\n * another must never put those words on screen — so the rows arrive as children and this\n * supplies the header, the collapse, the connector and the rhythm they share.\n * - One rule behind the whole run at the icon centre line: the list's `pl-5` plus half a\n * `size-5` icon box. Drawn once rather than per row, so it does not vanish beside a row that\n * happens to have no icon.\n * - `grid-template-rows` rather than height, because the rows are text of unknown length and a\n * transition needs a number at both ends. The children stay mounted while closed: a group the\n * reader reopens must not re-run whatever mounting a row costs. A closed group is `inert` and\n * `aria-hidden`, so staying mounted does not mean staying reachable.\n * - Expansion is the caller's state. Whether a group opens itself while work is happening, and\n * whether a reader's own toggle outranks that, is a transcript-level decision.\n * - `role=\"group\"` rather than the `<section>`'s own landmark semantics: a transcript draws one\n * of these per run of steps, so a long conversation would hand a screen reader a landmark\n * list of dozens of identically named `region`s and drown the page's real landmarks in it.\n * The name still reads — a named `group` is announced by it — and it is the role the\n * grounding panel already gives its repeated named answer sections.\n */\nexport const InlineStepGroup = ({\n label,\n variant = 'success',\n isExpanded,\n onToggle,\n surface = 'rgb(var(--background))',\n 'aria-label': ariaLabel,\n 'data-testid': testId,\n className,\n children,\n}: Props) => (\n <section\n role=\"group\"\n className={cn('tw:flex tw:flex-col', className)}\n aria-label={ariaLabel}\n data-testid={testId}\n >\n <CollapsibleStepHeader\n isExpanded={isExpanded}\n onToggle={onToggle}\n label={label}\n variant={variant}\n />\n\n <div\n className={cn(\n 'tw:grid tw:transition-[grid-template-rows] tw:duration-200 tw:ease-out tw:motion-reduce:transition-none',\n isExpanded ? 'tw:grid-rows-[1fr]' : 'tw:grid-rows-[0fr]',\n )}\n >\n {/* `inert` + `aria-hidden` because `grid-template-rows: 0fr` and `overflow-hidden` are\n layout only: without them a collapsed run stays in the a11y tree and the tab order,\n so a screen reader reads out steps nobody can see and Tab lands inside a closed\n group. Same pattern as `BreadcrumbDropdownGroup`. */}\n <div\n className=\"tw:min-h-0 tw:overflow-hidden\"\n inert={!isExpanded}\n aria-hidden={isExpanded ? undefined : true}\n >\n <div\n style={surfaceStyle(surface)}\n className=\"tw:relative tw:flex tw:flex-col tw:gap-4 tw:pt-4 tw:pl-5\"\n >\n <span\n aria-hidden=\"true\"\n className=\"tw:pointer-events-none tw:absolute tw:top-4 tw:bottom-0 tw:left-[30px] tw:w-px tw:bg-border\"\n />\n {children}\n </div>\n </div>\n </div>\n </section>\n);\n\nexport type { Props as InlineStepGroupProps };\n","import { useEffect, useState } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\n\nimport type { DiagramComponent, DiagramLoader } from './diagramChunk';\n\n/**\n * One diagram block: a skeleton while its chunk loads, the fence source plus a retry if it fails.\n *\n * - `load` runs once per mount and once per press of the retry button. The loader drops its own\n * rejected promise, so every attempt is a fresh fetch.\n * - Recovery is a gesture, not a timer: nothing on the page can tell when a chunk became\n * reachable again, and a tab left open across a deploy points at a URL that is gone for good —\n * a background loop would retry that one forever.\n * - The failure is already logged by the loader, which knows the chunk's name.\n * - A new `load` resets the block: every fence renders this same component type, so a block that\n * switches dialect would otherwise keep drawing through the dialect it had before.\n * - Both the renderer and the loader are functions held in state, so they go in through the\n * setter form — React runs a bare function as a lazy initializer or an updater instead.\n */\nexport const DiagramBlock = ({ load, code }: { load: DiagramLoader; code: string }) => {\n const [Diagram, setDiagram] = useState<DiagramComponent | null>(null);\n const [failed, setFailed] = useState(false);\n const [attempt, setAttempt] = useState(0);\n\n // Reset in the render pass rather than from an effect, so a dialect change never paints a frame\n // of the previous dialect's renderer.\n const [prevLoad, setPrevLoad] = useState(() => load);\n if (load !== prevLoad) {\n setPrevLoad(() => load);\n setDiagram(null);\n setFailed(false);\n }\n\n useEffect(() => {\n let cancelled = false;\n load().then(\n (component) => {\n if (!cancelled) setDiagram(() => component);\n },\n () => {\n if (!cancelled) setFailed(true);\n },\n );\n return () => {\n cancelled = true;\n };\n // `attempt` is the retry trigger — bumping it re-runs the import.\n }, [load, attempt]);\n\n if (Diagram) return <Diagram code={code} />;\n\n if (failed) {\n return (\n <div>\n <DiagramSource code={code} />\n <Button\n variant=\"inline\"\n size=\"small\"\n className=\"tw:mb-3\"\n onClick={() => {\n setFailed(false);\n setAttempt((count) => count + 1);\n }}\n >\n Try again\n </Button>\n </div>\n );\n }\n\n return <DiagramSkeleton />;\n};\n","import type { ComponentType } from 'react';\n\nexport type DiagramComponent = ComponentType<{ code: string }>;\nexport type DiagramLoader = () => Promise<DiagramComponent>;\n\n/**\n * An on-demand diagram chunk — shared between mounts, and retryable.\n *\n * - `lazy()` is deliberately not used here: it memoizes the settled import for the life of the\n * page, so one failed fetch (a dev server restarting, a stale tab after a deploy, a flaky\n * network) leaves every diagram in that tab rendering raw source until a full reload.\n * - A resolved import is kept, so the chunk is fetched once however many blocks mount.\n * - A failed one is cleared, so the next mount imports again. Same contract as\n * `getFlintRuntime()` one level down, inside `FlintChart`.\n * - The failure is logged here, where the chunk's name is known, so the swap to plain source is\n * never silent and a retry that fails again says so.\n */\nexport const diagramChunk = (name: string, load: DiagramLoader): DiagramLoader => {\n let pending: Promise<DiagramComponent> | null = null;\n return () => {\n pending ??= load().catch((error: unknown) => {\n console.error(`[AIKit] failed to load the ${name} chunk`, error);\n pending = null;\n throw error;\n });\n return pending;\n };\n};\n","import { createContext, isValidElement, use } from 'react';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport type { Components, ExtraProps, Options } from 'react-markdown';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport { Table } from '../../components/Table';\nimport { cn } from '../../utils';\nimport { ClipboardButton } from '../ClipboardButton';\n\nimport { ChatInlineIcon, getChatInlineIconName } from './ChatInlineIcon';\nimport { DiagramBlock } from './DiagramBlock';\nimport type { DiagramLoader } from './diagramChunk';\nimport { diagramChunk } from './diagramChunk';\n\n// beautiful-mermaid pulls elkjs (~442 kB gzip), and vega + vega-lite + flint-chart outweigh the\n// rest of an answer. Most answers carry neither, so both chunks load on demand.\nconst loadMermaid = diagramChunk('MermaidDiagram', () =>\n import('@keboola/design/mermaid').then((module) => module.MermaidDiagram),\n);\n\nconst loadFlint = diagramChunk('FlintChart', () =>\n import('@keboola/design/flint').then((module) => module.FlintChart),\n);\n\n// Code surfaces are painted here rather than left to Tailwind Typography, whose\n// palette is pinned to light-mode values. The fill is the same `--muted` /\n// `--foreground` pair `styles.css` gives `.tw\\:prose blockquote` — the file's\n// idiom for an inset surface — so both follow the colour scheme and the brand.\n//\n// The colour has to be stated on `pre` and on inline `code` separately:\n// `[data-theme='dark'] .tw\\:prose` applies `prose-invert`, whose `code` rules are\n// `:where()`-wrapped, so these utilities win on specificity. Set only the fill\n// and dark mode pairs an inverted light text with it.\nconst proseClass =\n 'tw:prose tw:prose-sm tw:max-w-none tw:break-words tw:[&_pre]:bg-muted tw:[&_pre]:text-foreground tw:[&_:not(pre)>code]:bg-muted tw:[&_:not(pre)>code]:text-foreground tw:[&_:not(pre)>code]:rounded tw:[&_:not(pre)>code]:px-1 tw:[&_:not(pre)>code]:py-0.5 tw:[&_:not(pre)>code]:before:content-none tw:[&_:not(pre)>code]:after:content-none';\n\nconst getText = (node: ReactNode): string => {\n if (typeof node === 'string') return node;\n if (typeof node === 'number') return String(node);\n if (Array.isArray(node)) return node.map(getText).join('');\n if (\n isValidElement(node) &&\n typeof node.props === 'object' &&\n node.props !== null &&\n 'children' in node.props\n ) {\n return getText((node.props as { children: ReactNode }).children);\n }\n return '';\n};\n\nconst getLanguage = (element: ReactNode): string | undefined => {\n if (!isValidElement(element)) return undefined;\n const { props } = element;\n if (typeof props !== 'object' || props === null || !('className' in props)) return undefined;\n if (typeof props.className !== 'string') return undefined;\n return props.className.match(/language-(\\S+)/)?.[1];\n};\n\n/**\n * The plugins this renderer always runs.\n *\n * - GFM is part of its contract: tables route through the design `Table`, and autolinks and\n * task lists are what an assistant answer is written in.\n * - A caller's own plugins are appended to these, never substituted for them.\n */\nconst baseRemarkPlugins: NonNullable<Options['remarkPlugins']> = [remarkGfm];\n\n/**\n * Fence language → the on-demand chunk that draws it.\n *\n * - Both dialects are the agent's, not this package's: kai-agent's prompt tells the model to\n * write ```mermaid for structure and ```flint for quantitative data, so a chat that renders\n * one and not the other drops output the agent was instructed to produce.\n * - `flint-chart` is an alias — it is the fence tag flint's own docs use, so a model emits it\n * unprompted often enough to matter. `markdownComponents.tsx` in kbc-ui carries the same pair.\n * - Read through `Object.hasOwn`, never by plain index: a fence tagged ```constructor or\n * ```valueOf otherwise answers with an `Object.prototype` member, which is truthy, and calling\n * it as a loader throws — taking the whole message subtree down with it.\n */\nconst DIAGRAM_CHUNKS: Record<string, DiagramLoader | undefined> = {\n mermaid: loadMermaid,\n flint: loadFlint,\n 'flint-chart': loadFlint,\n};\n\n/**\n * The fence languages this renderer draws instead of printing.\n *\n * - For a caller that streams: a diagram mounts a lazily loaded chunk, so an answer arriving a\n * token at a time has to keep a fence that is still open an ordinary code block, or every\n * keystroke fetches the chunk. Sharing the list is what keeps that hold-back from missing a\n * dialect this map has and the caller does not.\n * - Frozen, because it is that shared contract: a consumer that pushed onto it would change how\n * every other app in the same bundle holds a fence back.\n */\nexport const DIAGRAM_LANGUAGES: readonly string[] = Object.freeze(Object.keys(DIAGRAM_CHUNKS));\n\n/**\n * Whether the `code` being rendered sits inside a fenced block.\n *\n * - A fence with no info string reaches `code` with no `language-…` class, exactly like inline\n * code, so the class cannot tell the two apart — `pre` is the only boundary that can.\n * - Set by the `pre` renderer, read by `code`: React renders `pre` before its children, so the\n * value is in place by the time the `code` inside it renders.\n */\nconst CodeBlockContext = createContext(false);\n\n/**\n * The `code` renderer: an `icon:<name>` token becomes the icon it names, anything else stays code.\n *\n * - Only inline code is a candidate: a fenced block's body is code the reader asked to see, and\n * swapping it for a glyph would drop it. `CodeBlockContext` is what separates the two — a fence\n * with no info string carries no `language-…` class either, so the class cannot.\n * - The token reaches here as inline code because `remarkIconSyntax` (in `@keboola/kai-chat`)\n * turned the bare text into one, or because the model wrote the backticks itself. Producing the\n * token is the app's, drawing it is this package's.\n * - A name no icon answers to stays code: `getChatInlineIconName` answers only for names the\n * registry can draw or is still receiving, and this renderer draws vendor descriptions and\n * dashboard text too, where `icon:` is an ordinary way to name a property.\n * - A name still arriving draws nothing, so a streamed `icon:tabl` is blank for a frame rather\n * than a code chip that reflows the line.\n * - A component rather than an inline renderer so it can read the context.\n */\nconst MarkdownCode = ({\n children,\n className,\n ...props\n}: ComponentPropsWithoutRef<'code'> & ExtraProps) => {\n const { node: _node, ...rest } = props;\n const isBlock = use(CodeBlockContext);\n const name = isBlock ? undefined : getChatInlineIconName(getText(children));\n if (name !== undefined) return <ChatInlineIcon name={name} />;\n return (\n <code className={className} {...rest}>\n {children}\n </code>\n );\n};\n\n// react-markdown passes a hast `node` to every component; strip it before\n// spreading the rest onto a DOM element.\nconst baseComponents: Components = {\n // Handle mermaid at the `pre` level: react-markdown renders fenced blocks as\n // `<pre><code class=\"language-…\">`, so a diagram (a block `<div>`) must replace\n // the whole `<pre>` — returning it from the `code` override would nest a block\n // element inside `<pre><code>` (invalid HTML).\n pre({ children, ...props }: ComponentPropsWithoutRef<'pre'> & ExtraProps) {\n const child = Array.isArray(children) ? children[0] : children;\n const code = getText(child).replace(/\\n$/, '');\n const language = getLanguage(child);\n const load =\n language !== undefined && Object.hasOwn(DIAGRAM_CHUNKS, language)\n ? DIAGRAM_CHUNKS[language]\n : undefined;\n if (load) {\n if (!code.trim()) return null;\n return <DiagramBlock load={load} code={code} />;\n }\n const { node: _node, ...rest } = props;\n // Wrap so the copy button can reveal on hover/focus, anchored to the block.\n return (\n <div className=\"tw:group tw:relative\">\n <span className=\"tw:absolute tw:right-2 tw:top-2 tw:opacity-0 tw:transition-opacity tw:group-focus-within:opacity-100 tw:group-hover:opacity-100\">\n <ClipboardButton text={code} tooltip=\"Copy\" size=\"icon-xs\" variant=\"outline\" />\n </span>\n <pre {...rest}>\n <CodeBlockContext value={true}>{children}</CodeBlockContext>\n </pre>\n </div>\n );\n },\n code: MarkdownCode,\n // Open absolute http(s) links in a new tab with a safe `rel`; leave relative\n // and anchor links to default in-page navigation.\n a({ children, href, ...props }: ComponentPropsWithoutRef<'a'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n const isExternal = !!href && /^https?:\\/\\//.test(href);\n return (\n <a\n href={href}\n {...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : null)}\n {...rest}\n >\n {children}\n </a>\n );\n },\n // Route GFM tables through the design `Table` so they match the rest of the\n // system; `tw:not-prose` opts the table out of prose typography overrides.\n table({ className, ...props }: ComponentPropsWithoutRef<'table'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return (\n <div className=\"tw:not-prose tw:my-4\">\n <Table bordered className={cn('tw:!mb-0', className)} {...rest} />\n </div>\n );\n },\n thead(props: ComponentPropsWithoutRef<'thead'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return <Table.Header {...rest} />;\n },\n tbody(props: ComponentPropsWithoutRef<'tbody'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return <Table.Body {...rest} />;\n },\n tr(props: ComponentPropsWithoutRef<'tr'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return <Table.Row {...rest} />;\n },\n th(props: ComponentPropsWithoutRef<'th'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return <Table.Head {...rest} />;\n },\n td(props: ComponentPropsWithoutRef<'td'> & ExtraProps) {\n const { node: _node, ...rest } = props;\n return <Table.Cell {...rest} />;\n },\n};\n\ntype Props = {\n /** Markdown source (GFM: tables, task lists, strikethrough, autolinks). Tables\n * render through the design `Table`; fenced ```mermaid and ```flint blocks render\n * as diagrams; every other fenced block gets a hover copy button. */\n children: string;\n className?: string;\n /**\n * Remark plugins run after the built-in GFM one.\n *\n * - Appended to the built-ins, so GFM keeps working whatever a caller adds.\n * - The seam for an app's own inline syntax — an annotation the agent emits alongside a\n * link, say — which is app product knowledge and does not belong in this package.\n * - Hold it in a module constant. react-markdown re-parses on every render, so this\n * component is meant to be memoised by its caller, and a literal built during render\n * defeats that.\n */\n remarkPlugins?: NonNullable<Options['remarkPlugins']>;\n /**\n * Element renderers layered over the built-in ones.\n *\n * - Merged by key, and an override **replaces** that element's renderer rather than\n * wrapping it: a `table` override loses the design `Table`, an `a` override loses the\n * new-tab treatment for absolute links. Restate what you still want.\n * - Hold it in a module constant, for the same reason as `remarkPlugins`.\n */\n components?: Components;\n};\n\n/**\n * Read-only GFM Markdown renderer with design-token typography. Pair with\n * `MessageBubble` to render an assistant message body. Code blocks expose a\n * copy button, so mount a `TooltipProvider` once at the app root.\n */\nexport const Markdown = ({\n children,\n className,\n remarkPlugins,\n components: componentOverrides,\n}: Props) => {\n return (\n <div data-prose className={cn(proseClass, className)}>\n <ReactMarkdown\n remarkPlugins={\n remarkPlugins === undefined ? baseRemarkPlugins : [...baseRemarkPlugins, ...remarkPlugins]\n }\n components={\n componentOverrides === undefined\n ? baseComponents\n : { ...baseComponents, ...componentOverrides }\n }\n >\n {children}\n </ReactMarkdown>\n </div>\n );\n};\n","import { type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Tooltip } from '../../components/Tooltip';\nimport { Maximize2 } from '../../icons';\nimport { cn } from '../../utils';\n\n/** How much wider than its column a table has to be before the column is the wrong surface. */\nconst EXPAND_RATIO = 1.5;\n\n/**\n * The token the host paints the table on, which is the colour the fade has to end in.\n *\n * - A gradient hides the cut-off cells by ending in the surface behind them. End it in any other\n * token and it draws a contrasting strip over the data instead of hiding it.\n * - Full class strings, not a composed `tw:from-${token}`: Tailwind reads literals.\n */\nconst FADE_SURFACE = {\n card: 'tw:from-card',\n background: 'tw:from-background',\n} as const;\n\ntype Surface = keyof typeof FADE_SURFACE;\n\ntype Props = {\n /**\n * The table itself — a `Table bordered`, whose own container is the scrolling element.\n *\n * - It has to be left at its intrinsic width (`tw:min-w-max`). `Table` is `w-full` with auto\n * layout, so on its own the grid shrinks to the column and wraps its cells instead:\n * `scrollWidth` never exceeds `clientWidth`, and neither affordance below can ever appear.\n */\n children: ReactNode;\n /**\n * What the host paints behind the table.\n *\n * - `card` for a table inside a panel or a card, `background` for one on the bare page.\n * - Only the fade reads it, and only to end in the same colour it covers.\n * - The fade is one strip down the whole right edge, so it can end in one colour only. A host\n * that leaves `Table`'s tinted header band in place gives it a second surface to cover and\n * the strip will contrast over the header row; paint the band `surface` too.\n */\n surface?: Surface;\n /**\n * Host controls in the rail, left of the expand action.\n *\n * - Quiet or revealed on hover is the host's call: its own `opacity-0 group-hover:opacity-100`\n * span, plus `tw:group` on `className`.\n */\n actions?: ReactNode;\n /**\n * Where a table too wide for its column goes — a panel to fullscreen, a modal.\n *\n * - Omitted where there is nowhere wider to go: the fade draws, the action does not.\n * - Whether the table is in fact cut off is measured here.\n */\n onExpand?: () => void;\n className?: string;\n};\n\n/**\n * A table in an answer, with the fact that it is cut off on the right said out loud.\n *\n * - `overflow-x: auto` scrolls silently, so nothing on screen says there is more to the right.\n * - The controls sit in a rail above the grid, never over the header row or the last row — the\n * data a reader reaches for them to get at. The rail holds its height, so revealing hover\n * controls or crossing the ratio cannot shift the table under the pointer.\n * - The fade marks the cut edge only while content remains, so it never reads as a border.\n * - A painted gradient rather than the `tw:scroll-fade-x` mask, which needs scroll-driven\n * animations: the build floor is `baseline-widely-available` (Safari 16, Firefox 104), and there\n * the utility either fades both edges of a table that fits or, behind the `supports-` guard\n * `PageLayout` uses, says nothing at all — which is the state this component exists to end. The\n * mask also has to sit on the scrolling element, and that is `Table`'s own container, not ours.\n * - Past `EXPAND_RATIO` the fade is joined by `onExpand`'s action, drawn without waiting for a\n * hover: it reports that content is cut off, which the reader needs before going looking.\n */\nexport const MarkdownTable = ({\n children,\n actions,\n onExpand,\n surface = 'card',\n className,\n}: Props) => {\n const frameRef = useRef<HTMLDivElement>(null);\n const [overflow, setOverflow] = useState({ scrollable: false, atEnd: true, ratio: 1 });\n\n // The scrolling element is the container `Table` renders around the grid — the frame's first\n // child. The frame stays `overflow-visible` so the fade can sit over the grid's edge.\n const measure = useCallback(() => {\n const box = frameRef.current?.firstElementChild;\n if (!box) return;\n\n const { scrollLeft, scrollWidth, clientWidth } = box;\n const hidden = scrollWidth - clientWidth;\n\n setOverflow({\n scrollable: hidden > 1,\n atEnd: scrollLeft >= hidden - 1,\n ratio: clientWidth > 0 ? scrollWidth / clientWidth : 1,\n });\n }, []);\n\n useEffect(() => {\n const box = frameRef.current?.firstElementChild;\n if (!box) return;\n\n measure();\n box.addEventListener('scroll', measure, { passive: true });\n\n // Two widths move independently, and either one changes the answer:\n //\n // 1. The box's, when the surface resizes without the viewport doing so — a panel going\n // fullscreen, a drag handle.\n // 2. The grid's, while an answer streams. A cell taking a longer value widens the table inside\n // a box whose own border box never moves, so watching only the box leaves the fade and the\n // expand action reading the width the table had a few tokens ago.\n const observer = new ResizeObserver(measure);\n observer.observe(box);\n if (box.firstElementChild) observer.observe(box.firstElementChild);\n\n return () => {\n box.removeEventListener('scroll', measure);\n observer.disconnect();\n };\n }, [measure]);\n\n const showExpand = !!onExpand && overflow.scrollable && overflow.ratio >= EXPAND_RATIO;\n\n return (\n <div className={className}>\n {/* No rail where the host has nothing to put in it — an empty band says nothing. */}\n {(actions || onExpand) && (\n // Hover controls sit left of the persistent one: a reveal span keeps its width while\n // hidden, so trailing them would park \"Open wider\" against an invisible gap.\n <div className=\"tw:flex tw:h-8 tw:items-center tw:justify-end tw:gap-1\">\n {actions}\n {showExpand && (\n // A positioned tooltip, not a native `title`: the native one renders under the\n // pointer, i.e. over the header row.\n <Tooltip\n tooltip=\"This table is wider than the space it has\"\n placement=\"top\"\n triggerAsChild\n >\n <Button size=\"small\" variant=\"invisible\" onClick={onExpand}>\n <Maximize2 className=\"tw:size-3.5\" />\n Open wider\n </Button>\n </Tooltip>\n )}\n </div>\n )}\n\n <div ref={frameRef} className=\"tw:relative\">\n {children}\n\n {overflow.scrollable && !overflow.atEnd && (\n <span\n aria-hidden\n data-testid=\"markdown-table-fade\"\n className={cn(\n 'tw:pointer-events-none tw:absolute tw:inset-y-px tw:right-px tw:w-12 tw:rounded-r-[10px] tw:bg-gradient-to-l tw:to-transparent',\n FADE_SURFACE[surface],\n )}\n />\n )}\n </div>\n </div>\n );\n};\n","import type { ComponentProps, PropsWithChildren, ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\n\nimport type { Avatar } from '../../components/Avatar';\n\n// No per-message avatar. In a narrow panel a 30px portrait beside every turn\n// spends width on identity the reader already has — there are two participants\n// — and pushes the bubble into an L-shape beside it. Alignment carries the turn.\nconst containerClasses = cva(['tw:flex', 'tw:max-w-full', 'tw:gap-3'], {\n variants: {\n variant: {\n user: ['tw:justify-end'],\n assistant: ['tw:justify-start', 'tw:w-full'],\n },\n },\n defaultVariants: {\n variant: 'assistant',\n },\n});\n\nconst stackClasses = cva(['tw:flex', 'tw:min-w-0', 'tw:flex-1', 'tw:flex-col', 'tw:gap-2'], {\n variants: {\n variant: {\n user: ['tw:items-end'],\n assistant: [],\n },\n },\n defaultVariants: {\n variant: 'assistant',\n },\n});\n\nconst contentClasses = cva(\n [\n 'tw:flex',\n 'tw:flex-col',\n // Prose supplies its own rhythm between blocks, so a large gap here stacks\n // on top of it and reads as slack rather than structure.\n 'tw:gap-3',\n 'tw:break-words',\n 'tw:leading-relaxed',\n 'tw:text-foreground',\n // Hooks on `data-prose`, not the `tw:prose` class — Tailwind scans raw file\n // bytes, so a `\\:` escape in a TS string reaches the generator doubled.\n 'tw:[&_[data-prose]]:text-foreground',\n ],\n {\n variants: {\n variant: {\n assistant: ['tw:flex-1', 'tw:w-full', 'tw:min-w-0', 'tw:[&>*]:min-w-0'],\n user: [\n // The cap is a share of the column, not a fixed width: it is what\n // leaves a gutter on the left, and that gutter is the whole reason\n // the bubble reads as one side of a conversation. A fixed 640px\n // never engages in a docked panel, and a left margin cannot stand in\n // for it — `w-fit` sizes to the space it has before the margin\n // applies, so the margin pushes the bubble past the column instead\n // of insetting it. The absolute term stops a fullscreen panel from\n // running a line of someone's own words 700px wide.\n 'tw:max-w-[min(85%,40rem)]',\n 'tw:w-fit',\n 'tw:bg-muted',\n // Tighter vertically than horizontally: a short message padded evenly\n // on all four sides reads as a block, not as something someone said.\n // The radius comes down with it — a 16px corner on a one-line bubble\n // is most of its height.\n 'tw:px-3',\n 'tw:py-2',\n 'tw:rounded-xl',\n 'tw:overflow-hidden',\n 'tw:break-anywhere',\n ],\n },\n },\n\n defaultVariants: {\n variant: 'assistant',\n },\n },\n);\n\ntype Props = {\n variant: 'user' | 'assistant';\n actions?: ReactNode;\n createdAt?: string;\n /** @deprecated No avatar is rendered; accepted so existing call sites keep compiling. */\n user?: ComponentProps<typeof Avatar>['user'];\n} & PropsWithChildren;\n\nexport const MessageBubble = ({ variant, children, actions, createdAt }: Props) => {\n return (\n <div className={containerClasses({ variant })} data-testid={`chat-message-${variant}`}>\n <div className={stackClasses({ variant })}>\n {/* The timestamp is reachable on the user's own bubble — where the avatar\n that used to carry it sat. Deliberately not on the assistant's: a\n native tooltip fires from anywhere in the body after a hover pause,\n and an answer's body is full of tables and code it would cover. */}\n <div\n className={contentClasses({ variant })}\n title={variant === 'user' ? createdAt : undefined}\n >\n {children}\n </div>\n {actions}\n </div>\n </div>\n );\n};\n","import { type FormEvent, type KeyboardEvent, type ReactNode, useState } from 'react';\n\nimport { Badge } from '../../components/Badge';\nimport { Button } from '../../components/Button';\nimport {\n FullScreenModal,\n FullScreenModalBody,\n FullScreenModalHeader,\n} from '../../components/FullScreenModal';\nimport { Tooltip } from '../../components/Tooltip';\nimport { ChevronDown, Maximize2, Minimize2, Send, X } from '../../icons';\nimport { cn } from '../../utils';\nimport { Textarea } from '../Textarea';\n\nimport { CollapsibleBody } from './CollapsibleBody';\nimport { hasMotion } from './hasMotion';\n\ntype PlanApprovalStatus = 'pending' | 'approved' | 'dismissed' | 'changes-requested';\n\ntype PlanApprovalProps = {\n status: PlanApprovalStatus;\n title: string;\n summary?: ReactNode;\n stepCount?: number;\n planBody?: ReactNode;\n\n defaultExpanded?: boolean;\n isExpanded?: boolean;\n onExpandToggle?: (next: boolean) => void;\n\n onApprove?: () => void;\n onRequestChanges?: (reason: string) => void;\n onClose?: () => void;\n isSubmitting?: boolean;\n approveTooltip?: ReactNode;\n\n pendingPillLabel?: string;\n approvedPillLabel?: string;\n dismissedPillLabel?: string;\n changesRequestedPillLabel?: string;\n approveLabel?: string;\n requestChangesLabel?: string;\n cancelLabel?: string;\n showMoreLabel?: string;\n showLessLabel?: string;\n closeLabel?: string;\n fullScreenLabel?: string;\n exitFullScreenLabel?: string;\n changeRequestPlaceholder?: string;\n changeRequestSubmitLabel?: string;\n stepCountLabel?: (count: number) => string;\n\n className?: string;\n};\n\nconst defaultStepCountLabel = (count: number) => `${count} step${count === 1 ? '' : 's'}`;\n\nconst StatusPill = ({\n status,\n pendingLabel,\n approvedLabel,\n dismissedLabel,\n changesRequestedLabel,\n}: {\n status: PlanApprovalStatus;\n pendingLabel: string;\n approvedLabel: string;\n dismissedLabel: string;\n changesRequestedLabel: string;\n}) => {\n if (status === 'approved') {\n return (\n <Badge color=\"green\" variant=\"pill\" className=\"tw:normal-case tw:tracking-normal\">\n {approvedLabel}\n </Badge>\n );\n }\n if (status === 'dismissed') {\n return (\n <Badge color=\"gray\" variant=\"pill\" className=\"tw:normal-case tw:tracking-normal\">\n {dismissedLabel}\n </Badge>\n );\n }\n if (status === 'changes-requested') {\n return (\n <Badge color=\"blue\" variant=\"pill\" className=\"tw:normal-case tw:tracking-normal\">\n {changesRequestedLabel}\n </Badge>\n );\n }\n return (\n <Badge color=\"green\" variant=\"pill\" className=\"tw:normal-case tw:tracking-normal\">\n {pendingLabel}\n </Badge>\n );\n};\n\nconst ExpandToggle = ({\n isExpanded,\n onToggle,\n showMoreLabel,\n showLessLabel,\n}: {\n isExpanded: boolean;\n onToggle: () => void;\n showMoreLabel: string;\n showLessLabel: string;\n}) => (\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isExpanded}\n className=\"tw:inline-flex tw:cursor-pointer tw:items-center tw:gap-1 tw:bg-transparent tw:p-0 tw:text-sm tw:font-medium tw:text-secondary-500 tw:hover:text-secondary-600 tw:focus-visible:outline tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:focus-visible:outline-ring tailwindcss-preflight\"\n >\n <span>{isExpanded ? showLessLabel : showMoreLabel}</span>\n <ChevronDown\n className={cn('tw:size-5 tw:transition-transform', isExpanded && 'tw:rotate-180')}\n />\n </button>\n);\n\nconst ChangeRequestForm = ({\n value,\n onValueChange,\n onSubmit,\n onKeyDown,\n placeholder,\n submitLabel,\n formLabel,\n canSubmit,\n isSubmitting,\n}: {\n value: string;\n onValueChange: (value: string) => void;\n onSubmit: (event?: FormEvent) => void;\n onKeyDown: (event: KeyboardEvent<HTMLTextAreaElement>) => void;\n placeholder: string;\n submitLabel: string;\n formLabel: string;\n canSubmit: boolean;\n isSubmitting: boolean;\n}) => (\n <form\n onSubmit={onSubmit}\n className=\"tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:text-card-foreground tw:px-4 tw:py-3\"\n aria-label={formLabel}\n >\n <div className=\"tw:relative\">\n <Textarea\n value={value}\n onValueChange={onValueChange}\n placeholder={placeholder}\n maxRows={4}\n autoFocus\n onKeyDown={onKeyDown}\n containerClassName=\"tw:pr-12\"\n disabled={isSubmitting}\n aria-label={placeholder}\n data-testid=\"plan-change-request-input\"\n />\n <Button\n type=\"submit\"\n variant=\"invisible\"\n size=\"icon-sm\"\n aria-label={submitLabel}\n disabled={!canSubmit}\n className=\"tw:absolute tw:right-2 tw:top-1/2 tw:-translate-y-1/2 tw:[&_svg]:text-secondary-500 tw:not-disabled:hover:[&_svg]:text-secondary-600\"\n data-testid=\"plan-change-request-submit\"\n >\n <Send className=\"tw:size-4\" />\n </Button>\n </div>\n </form>\n);\n\nconst PlanActions = ({\n isRequestingChanges,\n isSubmitting,\n onApprove,\n onRequestChanges,\n onOpenRequestChanges,\n onCancelChangeRequest,\n approveLabel,\n requestChangesLabel,\n cancelLabel,\n approveTooltip,\n}: {\n isRequestingChanges: boolean;\n isSubmitting: boolean;\n onApprove?: () => void;\n onRequestChanges?: (reason: string) => void;\n onOpenRequestChanges: () => void;\n onCancelChangeRequest: () => void;\n approveLabel: string;\n requestChangesLabel: string;\n cancelLabel: string;\n approveTooltip?: ReactNode;\n}) => (\n <div className=\"tw:flex tw:shrink-0 tw:items-center tw:gap-2\">\n {isRequestingChanges ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={onCancelChangeRequest}\n disabled={isSubmitting}\n data-testid=\"plan-cancel-button\"\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {cancelLabel}\n </Button>\n ) : (\n onRequestChanges && (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={onOpenRequestChanges}\n disabled={isSubmitting}\n data-testid=\"plan-request-changes-button\"\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {requestChangesLabel}\n </Button>\n )\n )}\n {onApprove &&\n (approveTooltip ? (\n <Tooltip tooltip={approveTooltip} placement=\"top\" triggerAsChild>\n <Button\n variant=\"primary\"\n size=\"small\"\n onClick={onApprove}\n disabled={isSubmitting || isRequestingChanges}\n data-testid=\"plan-approve-button\"\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {approveLabel}\n </Button>\n </Tooltip>\n ) : (\n <Button\n variant=\"primary\"\n size=\"small\"\n onClick={onApprove}\n disabled={isSubmitting || isRequestingChanges}\n data-testid=\"plan-approve-button\"\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {approveLabel}\n </Button>\n ))}\n </div>\n);\n\nexport const PlanApproval = ({\n status,\n title,\n summary,\n stepCount,\n planBody,\n\n defaultExpanded = false,\n isExpanded: isExpandedProp,\n onExpandToggle,\n\n onApprove,\n onRequestChanges,\n onClose,\n isSubmitting = false,\n approveTooltip,\n\n pendingPillLabel = 'Ready for approval',\n approvedPillLabel = 'Approved',\n dismissedPillLabel = 'Dismissed',\n changesRequestedPillLabel = 'Changes Requested',\n approveLabel = 'Approve',\n requestChangesLabel = 'Request Changes',\n cancelLabel = 'Cancel',\n showMoreLabel = 'Show more',\n showLessLabel = 'Show less',\n closeLabel = 'Dismiss plan',\n fullScreenLabel = 'View full screen',\n exitFullScreenLabel = 'Exit full screen',\n changeRequestPlaceholder = 'What would you like to change in the plan?',\n changeRequestSubmitLabel = 'Send change request',\n stepCountLabel = defaultStepCountLabel,\n\n className,\n}: PlanApprovalProps) => {\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultExpanded);\n const isExpanded = isExpandedProp ?? uncontrolledExpanded;\n const [isRequestingChanges, setIsRequestingChanges] = useState(false);\n const [changeRequest, setChangeRequest] = useState('');\n const [isFullScreen, setIsFullScreen] = useState(false);\n\n const isPending = status === 'pending';\n const showActions = isPending && (onApprove || onRequestChanges);\n const showClose = isPending && Boolean(onClose);\n const canShowPlanBody = planBody != null;\n const trimmedChangeRequest = changeRequest.trim();\n const canSubmitChangeRequest = trimmedChangeRequest.length > 0 && !isSubmitting;\n\n const [isClosing, setIsClosing] = useState(false);\n\n const toggleExpanded = () => {\n const next = !isExpanded;\n if (!next) setIsClosing(hasMotion());\n if (isExpandedProp === undefined) {\n setUncontrolledExpanded(next);\n }\n onExpandToggle?.(next);\n };\n\n const handleOpenRequestChanges = () => {\n setIsRequestingChanges(true);\n if (!isExpanded) {\n toggleExpanded();\n }\n };\n\n const handleCancelChangeRequest = () => {\n setIsRequestingChanges(false);\n setChangeRequest('');\n };\n\n const handleSubmitChangeRequest = (event?: FormEvent) => {\n event?.preventDefault();\n if (!canSubmitChangeRequest) return;\n onRequestChanges?.(trimmedChangeRequest);\n };\n\n const handleTextareaKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n handleSubmitChangeRequest();\n }\n };\n\n const showChangeRequestForm = isRequestingChanges && isPending;\n\n const changeRequestForm = (\n <ChangeRequestForm\n value={changeRequest}\n onValueChange={setChangeRequest}\n onSubmit={handleSubmitChangeRequest}\n onKeyDown={handleTextareaKeyDown}\n placeholder={changeRequestPlaceholder}\n submitLabel={changeRequestSubmitLabel}\n formLabel={requestChangesLabel}\n canSubmit={canSubmitChangeRequest}\n isSubmitting={isSubmitting}\n />\n );\n\n const planActions = (\n <PlanActions\n isRequestingChanges={isRequestingChanges}\n isSubmitting={isSubmitting}\n onApprove={onApprove}\n onRequestChanges={onRequestChanges}\n onOpenRequestChanges={handleOpenRequestChanges}\n onCancelChangeRequest={handleCancelChangeRequest}\n approveLabel={approveLabel}\n requestChangesLabel={requestChangesLabel}\n cancelLabel={cancelLabel}\n approveTooltip={approveTooltip}\n />\n );\n\n return (\n <>\n {/* Two surface tiers, each painting its own ink.\n\n - The shell is `background`, carrying the header and the summary directly.\n - Plan body, change-request form and action bar lift off it on `card`.\n - Whether the shell reads as a recessed tray is the host's call, not this\n component's: against a white page it does, but kbc-ui paints the Kai\n panel `background` too, so there the 1px border alone delimits the card.\n - Each tier pins a foreground beside its background. One that sets only a\n background inherits ink from whatever rendered it, and reads same-on-same\n in one of the schemes. */}\n <section\n aria-label={title}\n className={cn(\n 'tw:flex tw:w-full tw:max-w-[800px] tw:flex-col tw:overflow-hidden tw:rounded-xl tw:border tw:border-solid tw:border-border tw:bg-background tw:text-foreground',\n className,\n )}\n data-testid=\"plan-approval-root\"\n data-plan-status={status}\n >\n <div className=\"tw:flex tw:items-start tw:gap-2 tw:pl-4 tw:pr-2 tw:pt-4\">\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:gap-2 tw:pb-4\">\n <div className=\"tw:flex tw:items-center tw:gap-3\">\n <StatusPill\n status={status}\n pendingLabel={pendingPillLabel}\n approvedLabel={approvedPillLabel}\n dismissedLabel={dismissedPillLabel}\n changesRequestedLabel={changesRequestedPillLabel}\n />\n {/* 12px on `muted-foreground` — knowingly at the AA floor.\n\n - 4.55:1 against the shell's `background` in light; AA asks 4.5:1.\n - `muted-foreground` is the ink for secondary metadata, so darker\n ink here would break the hierarchy to buy the margin.\n - Headroom is a token question, not a call-site one. The ratio is\n pinned in `tokenBlocks.test.ts`, so a nudge to\n `--muted-foreground` fails there rather than passing silently. */}\n {stepCount != null && stepCount > 0 && (\n <span className=\"tw:text-xs tw:leading-4 tw:text-muted-foreground\">\n {stepCountLabel(stepCount)}\n </span>\n )}\n </div>\n <p className=\"tw:m-0 tw:text-base tw:font-semibold tw:leading-6\">{title}</p>\n </div>\n <div className=\"tw:flex tw:items-center tw:gap-2\">\n {canShowPlanBody && !isFullScreen && (\n <Tooltip tooltip={fullScreenLabel} placement=\"top\" triggerAsChild>\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label={fullScreenLabel}\n onClick={() => setIsFullScreen(true)}\n data-testid=\"plan-fullscreen-button\"\n >\n <Maximize2 className=\"tw:size-4\" />\n </Button>\n </Tooltip>\n )}\n {showClose && !isFullScreen && (\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label={closeLabel}\n onClick={onClose}\n disabled={isSubmitting}\n data-testid=\"plan-close-button\"\n >\n <X className=\"tw:size-4\" />\n </Button>\n )}\n </div>\n </div>\n\n {summary != null && (\n <div\n className={cn(\n 'tw:whitespace-pre-wrap tw:border-0 tw:border-t tw:border-solid tw:border-border tw:px-4 tw:pt-4 tw:text-sm',\n isExpanded && canShowPlanBody ? 'tw:pb-4' : 'tw:pb-2',\n )}\n >\n {summary}\n </div>\n )}\n\n {canShowPlanBody && (\n <CollapsibleBody\n isExpanded={isExpanded}\n isClosing={isClosing}\n onClosed={() => setIsClosing(false)}\n >\n <div className=\"tw:max-h-[400px] tw:overflow-y-auto tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:p-4 tw:text-sm tw:text-card-foreground\">\n {planBody}\n </div>\n </CollapsibleBody>\n )}\n\n {!isFullScreen && (\n <>\n {showChangeRequestForm && changeRequestForm}\n\n <div\n className={cn(\n 'tw:flex tw:items-center tw:gap-2 tw:overflow-x-auto tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:px-4 tw:py-3 tw:text-card-foreground',\n canShowPlanBody ? 'tw:justify-between' : 'tw:justify-end',\n )}\n >\n {canShowPlanBody && (\n <div className=\"tw:shrink-0\">\n <ExpandToggle\n isExpanded={isExpanded}\n onToggle={toggleExpanded}\n showMoreLabel={showMoreLabel}\n showLessLabel={showLessLabel}\n />\n </div>\n )}\n\n {showActions && planActions}\n </div>\n </>\n )}\n </section>\n\n {canShowPlanBody && isFullScreen && (\n <FullScreenModal onEscapeKeyDown={() => setIsFullScreen(false)}>\n <FullScreenModalHeader\n title={\n <div className=\"tw:flex tw:min-w-0 tw:items-center tw:gap-3\">\n <StatusPill\n status={status}\n pendingLabel={pendingPillLabel}\n approvedLabel={approvedPillLabel}\n dismissedLabel={dismissedPillLabel}\n changesRequestedLabel={changesRequestedPillLabel}\n />\n <span className=\"tw:truncate\">{title}</span>\n </div>\n }\n onClose={() => setIsFullScreen(false)}\n showPreviousTitle={false}\n >\n <div className=\"tw:flex tw:items-center tw:gap-2\">\n {showClose && (\n <Tooltip tooltip={closeLabel} placement=\"bottom\" triggerAsChild>\n <Button\n variant=\"outline\"\n size=\"icon\"\n aria-label={closeLabel}\n onClick={onClose}\n disabled={isSubmitting}\n data-testid=\"plan-close-button\"\n >\n <X className=\"tw:size-4\" />\n </Button>\n </Tooltip>\n )}\n <Tooltip tooltip={exitFullScreenLabel} placement=\"bottom\" triggerAsChild>\n <Button\n variant=\"outline\"\n size=\"icon\"\n aria-label={exitFullScreenLabel}\n onClick={() => setIsFullScreen(false)}\n data-testid=\"plan-exit-fullscreen-button\"\n >\n <Minimize2 className=\"tw:size-4\" />\n </Button>\n </Tooltip>\n </div>\n </FullScreenModalHeader>\n {/* The modal is portalled to `document.body`, so it inherits nothing\n from the card above — body and footer each pin their own surface\n and ink, on top of the frame's own `background`/`foreground`. */}\n <FullScreenModalBody className=\"tw:bg-card tw:px-6 tw:py-4 tw:text-card-foreground\">\n <div className=\"tw:mx-auto tw:w-full tw:max-w-[800px] tw:text-sm\">{planBody}</div>\n </FullScreenModalBody>\n {(showChangeRequestForm || showActions) && (\n <div className=\"tw:shrink-0 tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:text-card-foreground\">\n <div className=\"tw:mx-auto tw:w-full tw:max-w-[800px]\">\n {showChangeRequestForm && changeRequestForm}\n {showActions && (\n <div className=\"tw:flex tw:justify-end tw:px-4 tw:py-3\">{planActions}</div>\n )}\n </div>\n </div>\n )}\n </FullScreenModal>\n )}\n </>\n );\n};\n\nexport type { PlanApprovalStatus, PlanApprovalProps };\n","import { Loader2 } from '../../icons';\n\ntype PlanRewritingIndicatorProps = {\n label?: string;\n};\n\nexport const PlanRewritingIndicator = ({\n label = 'Rewriting the plan...',\n}: PlanRewritingIndicatorProps) => (\n <div\n className=\"tw:flex tw:items-center tw:gap-2\"\n role=\"status\"\n data-testid=\"plan-rewriting-indicator\"\n >\n <Loader2 className=\"tw:size-4 tw:animate-spin tw:text-secondary-500\" />\n <span className=\"tw:text-sm tw:italic tw:text-secondary-500\">{label}</span>\n </div>\n);\n\nexport type { PlanRewritingIndicatorProps };\n","import type { ComponentProps, MouseEventHandler } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\ntype Props = ComponentProps<'button'>;\n\nexport const PromptInputAction = ({ ref, onMouseDown, ...rest }: Props) => {\n const handleOnMouseDown: MouseEventHandler<HTMLButtonElement> = (event) => {\n // Prevents focus stealing by PromptInput.\n event.stopPropagation();\n onMouseDown?.(event);\n };\n\n return <Slot {...rest} ref={ref} onMouseDown={handleOnMouseDown}></Slot>;\n};\n","import { type ComponentRef, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Truncated } from '../../components/Truncated';\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\nimport { Command } from '../Command';\n\n/** What the menu needs above or below the composer before it will open on that side. */\nconst MENU_HEIGHT = 440;\n\nexport type PromptCommand = {\n label: string;\n value: string;\n description?: string;\n group: string;\n};\n\ntype Props = {\n items: PromptCommand[];\n open: boolean;\n onSelect: (item: PromptCommand) => void;\n filterValue: string;\n emptyText?: string;\n /** Dismiss the menu without picking anything; the × does what Escape does. */\n onClose?: () => void;\n children: ReactNode;\n};\n\nexport const PromptInputCommands = ({\n items,\n open,\n onSelect,\n filterValue,\n emptyText = 'No commands found',\n onClose,\n children,\n}: Props) => {\n const filtered = filterValue\n ? items.filter(\n (item) =>\n item.label.toLowerCase().includes(filterValue.toLowerCase()) ||\n item.value.toLowerCase().includes(filterValue.toLowerCase()),\n )\n : items;\n\n // cmdk only picks a row on its own when its search input changes, and these menus have no\n // input of their own: the textarea drives the filter. So the highlight is held here — the last\n // row the user moved to while it still matches, the first match otherwise — and Enter always\n // has something to pick.\n const [highlighted, setHighlighted] = useState<string>();\n\n /**\n * Which side the menu opens on.\n *\n * - Above by default: a composer usually sits at the foot of its panel.\n * - Below when there is not room above and there is room below — the dashboard composer sits\n * near the top of the page, where opening upward clipped the list against the header.\n * - Re-measured while it is open: the composer grows as the message does, and the transcript\n * above it moves, so the side that fit on open may not fit a moment later.\n */\n const rootRef = useRef<ComponentRef<'div'>>(null);\n const [below, setBelow] = useState(false);\n\n const measure = useCallback(() => {\n const box = rootRef.current?.getBoundingClientRect();\n if (!box) return;\n setBelow(box.top < MENU_HEIGHT && window.innerHeight - box.bottom > MENU_HEIGHT);\n }, []);\n\n // The first measurement rides the ref, not an effect: the node exists exactly when the ref is\n // attached, and measuring there settles the side before the menu is painted rather than after.\n const attachRoot = useCallback(\n (node: ComponentRef<'div'> | null) => {\n rootRef.current = node;\n if (node) measure();\n },\n [measure],\n );\n\n // Only what happens *after* it opens needs an effect: the composer grows as the message does and\n // the transcript above it moves, so the side that fit on open may not fit a moment later.\n useEffect(() => {\n if (!open) return;\n\n const node = rootRef.current;\n const observer = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null;\n if (node) observer?.observe(node);\n window.addEventListener('resize', measure);\n window.addEventListener('scroll', measure, true);\n return () => {\n observer?.disconnect();\n window.removeEventListener('resize', measure);\n window.removeEventListener('scroll', measure, true);\n };\n }, [open, measure]);\n\n const highlightedValue = filtered.some((item) => item.value === highlighted)\n ? highlighted\n : filtered[0]?.value;\n\n const groups = filtered.reduce<Record<string, PromptCommand[]>>((acc, item) => {\n const group = acc[item.group] ?? [];\n group.push(item);\n acc[item.group] = group;\n return acc;\n }, {});\n\n return (\n <Command\n ref={attachRoot}\n loop\n className=\"tw:relative\"\n shouldFilter={false}\n value={highlightedValue ?? ''}\n onValueChange={setHighlighted}\n >\n {open && (\n <div\n className={cn(\n // Left-aligned and capped rather than stretched: a full-width composer would give the\n // list a line length nothing in it needs.\n 'tw:absolute tw:left-0 tw:z-50 tw:w-full tw:max-w-lg',\n below ? 'tw:top-full tw:mt-1' : 'tw:bottom-full tw:mb-1',\n 'tw:rounded-[14px] tw:border tw:border-border tw:bg-popover tw:text-popover-foreground tw:shadow-lg',\n // The rows are inset from the corner rather than tucked into it; their own rounding\n // then sits inside the popup's instead of fighting it.\n 'tw:p-1',\n )}\n >\n {onClose && (\n <Button\n type=\"button\"\n size=\"icon-xs\"\n variant=\"invisible\"\n aria-label=\"Close\"\n // Centred on the first heading's line and no taller than it, so it neither\n // floats above the list nor reaches down over the first row.\n className=\"tw:absolute tw:right-2 tw:top-2 tw:z-10\"\n // The composer keeps focus: a menu dismissed by mouse should not move the caret.\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClose}\n >\n <X />\n </Button>\n )}\n {filtered.length === 0 ? (\n <div className=\"tw:px-4 tw:py-3 tw:text-center tw:text-sm tw:text-muted-foreground\">\n {emptyText}\n </div>\n ) : (\n <Command.List\n className=\"tw:group-data-[variant=argo]/command:px-1 tw:group-data-[variant=argo]/command:pb-1\"\n viewPortClassName=\"tw:max-h-[26rem]\"\n >\n {Object.entries(groups).map(([groupName, groupItems], index) => (\n <Command.Group\n key={groupName}\n heading={groupName}\n // A composer menu is not a command palette: the group name is a quiet label, not\n // a banner, and the rows below it need no rule to separate them.\n className={cn(\n 'tw:[&_[cmdk-group-heading]]:normal-case',\n 'tw:[&_[cmdk-group-heading]]:tracking-normal',\n 'tw:[&_[cmdk-group-heading]]:border-b-0',\n // Spacing is margin alone: 8px above puts the heading's line on the close\n // button's, 4px below keeps it against the rows it names. `!` because\n // `Command.Group` sets a padding on this selector and the two do not merge.\n 'tw:[&_[cmdk-group-heading]]:!py-0',\n 'tw:[&_[cmdk-group-heading]]:mt-2',\n 'tw:[&_[cmdk-group-heading]]:mb-1',\n // Over the labels it groups: the row's own padding, with no icon column to clear.\n 'tw:[&_[cmdk-group-heading]]:pl-2',\n // Clear of the close button in the first group; the rest keep the same inset so\n // every heading starts and ends on the same line.\n 'tw:[&_[cmdk-group-heading]]:pr-9',\n 'tw:[&_[cmdk-group-heading]]:text-xs',\n // Sections read as sections: the gap above a heading is what separates them.\n index > 0 && 'tw:mt-3',\n )}\n >\n {groupItems.map((item) => (\n <Command.Item\n key={item.value}\n value={item.value}\n className=\"tw:rounded-md\"\n onSelect={() => onSelect(item)}\n >\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:flex-col\">\n <span>{item.label}</span>\n {item.description && (\n <Truncated\n text={item.description}\n twoLines\n className=\"tw:text-xs tw:text-muted-foreground\"\n />\n )}\n </div>\n </Command.Item>\n ))}\n </Command.Group>\n ))}\n </Command.List>\n )}\n </div>\n )}\n\n {children}\n </Command>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Plus } from '../../icons';\nimport { cn } from '../../utils';\n\nimport { PromptInputAction } from './PromptInputAction';\n\ntype Props = Omit<ComponentProps<typeof Button>, 'children' | 'size' | 'variant'> & {\n /** Whether the menu this opens is showing; the glyph turns into an × while it is. */\n open?: boolean;\n /** Sized up to match a large composer's send button. */\n large?: boolean;\n};\n\n/**\n * The composer's \"add to message\" button.\n *\n * - One glyph for both states: a plus rotated 45° reads as a close cross, so nothing swaps.\n * - `aria-expanded` mirrors `open`; the accessible name changes with it.\n * - Wrapped in `PromptInputAction` so a click does not hand focus to the textarea.\n */\nexport const PromptInputMenuTrigger = ({\n open = false,\n large = false,\n className,\n ref,\n ...props\n}: Props) => (\n <PromptInputAction>\n <Button\n ref={ref}\n type=\"button\"\n size={large ? 'icon' : 'icon-sm'}\n variant=\"invisible\"\n aria-expanded={open}\n aria-label={open ? 'Close menu' : 'Add to message'}\n data-testid=\"prompt-input-menu-trigger\"\n // Gray like the rest of the row: `invisible` hovers blue, and an open menu's own trigger\n // reads as pressed, not as a link.\n className={cn(\n 'tw:rounded-full',\n 'tw:hover:not-disabled:bg-muted tw:hover:not-disabled:text-foreground tw:hover:not-disabled:border-transparent',\n 'tw:aria-expanded:bg-muted',\n className,\n )}\n {...props}\n >\n {/* One extra quarter turn on the way to the ×: the glyph is symmetric every 90°, so the\n spin costs nothing and lands on the same cross. */}\n <Plus\n className={cn(\n large ? 'tw:size-5' : 'tw:size-4',\n 'tw:transition-transform tw:duration-300 tw:ease-out tw:motion-reduce:transition-none',\n open && 'tw:rotate-135',\n )}\n />\n </Button>\n </PromptInputAction>\n);\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Tooltip } from '../../components/Tooltip';\nimport { CirclePause, Play, Send } from '../../icons';\nimport { cn } from '../../utils';\n\nimport { PromptInputAction } from './PromptInputAction';\n\ntype SubmitStatus = 'submitted' | 'ready' | 'streaming' | 'interrupted';\n\ntype Props = Pick<ComponentProps<typeof Button>, 'disabled' | 'ref'> & {\n status?: SubmitStatus;\n};\n\n// Icon-only button: the tooltip is visual only, so the accessible name must be\n// set separately per status to match what the button actually does (see\n// PromptInput's handleSubmit: ready->onSend, streaming->onAbort, interrupted->onContinue).\nconst ARIA_LABEL_BY_STATUS: Record<SubmitStatus, string> = {\n ready: 'Send message',\n streaming: 'Stop',\n interrupted: 'Continue',\n submitted: 'Sending…',\n};\n\nexport const PromptInputSubmit = ({ ref, disabled, status = 'ready' }: Props) => {\n const icon: ReactNode = (() => {\n if (status === 'streaming') return <CirclePause className=\"tw:size-4\" />;\n if (status === 'interrupted') return <Play className=\"tw:size-4\" />;\n // Optical centring. The paper plane's ink sits up and to the right of the\n // glyph box — its centroid measures ~1.2px right and ~1.3px high at 16px —\n // so a box-centred Send reads as off-centre inside a circle. The nudge pulls\n // the mass back toward the middle; the symmetric pause/play icons need none.\n return <Send className=\"tw:size-4 tw:translate-x-[-1px] tw:translate-y-[1px]\" />;\n })();\n\n const getTooltipText = () => {\n if (status === 'streaming') return 'Stop';\n if (status === 'interrupted') return 'Continue';\n return undefined;\n };\n\n return (\n <Tooltip.Root>\n <Tooltip.Trigger asChild>\n <PromptInputAction>\n <Button\n ref={ref}\n type=\"submit\"\n disabled={disabled}\n aria-label={ARIA_LABEL_BY_STATUS[status]}\n size=\"icon-sm\"\n // The only filled control in the composer, so the one button that\n // submits stays distinct from the several beside it that do not.\n //\n // - Fill is Kai's gradient (`aigradient-600`) — the same sweep the\n // field's focus border paints, so focus and send read as one family.\n // - `variant=\"primary\"` still supplies the white foreground, focus ring\n // and disabled semantics; the gradient covers its background colour.\n // - Disabled until there is content, so the composer shows ready-or-not\n // without needing a label.\n variant=\"primary\"\n isLoading={status === 'submitted'}\n className={cn(\n 'tw:ml-auto tw:flex tw:items-center tw:rounded-full',\n 'tw:bg-gradient-to-br tw:from-[#61E4FF] tw:via-[#1F8FFF] tw:to-[#7C5CFF]',\n 'tw:hover:not-disabled:brightness-110',\n )}\n >\n {/* Suppress the child icon while isLoading — Button already renders\n the spinner; rendering both would double-stack glyphs. */}\n {status !== 'submitted' && icon}\n </Button>\n </PromptInputAction>\n </Tooltip.Trigger>\n\n {getTooltipText() && (\n <Tooltip.Content placement=\"top\" variant=\"action\">\n {getTooltipText()}\n </Tooltip.Content>\n )}\n </Tooltip.Root>\n );\n};\n","import {\n type ChangeEventHandler,\n type ComponentProps,\n type ComponentRef,\n type FormEventHandler,\n type KeyboardEvent,\n type KeyboardEventHandler,\n type MouseEventHandler,\n type ReactNode,\n type RefObject,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport TextareaAutosize from 'react-textarea-autosize';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nimport { TooltipProvider } from '../../components/Tooltip';\nimport { cn } from '../../utils';\n\nimport { PromptInputAction } from './PromptInputAction';\nimport type { PromptCommand } from './PromptInputCommands';\nimport { PromptInputCommands } from './PromptInputCommands';\nimport { PromptInputMenuTrigger } from './PromptInputMenuTrigger';\nimport { PromptInputSubmit } from './PromptInputSubmit';\n\nconst CMDK_HIJACKED_KEYS = new Set(['ArrowUp', 'ArrowDown', 'Home', 'End', 'Enter']);\n\n// Whether cmdk would actually act on this keystroke, and so whether the guard\n// below still needs to hide it from the Command root.\n//\n// cmdk acts on every key in CMDK_HIJACKED_KEYS, modified or not — the arrows\n// branch on metaKey (jump to first/last) and altKey (jump to the adjacent\n// group), and Home/End preventDefault unconditionally. `Enter` is the sole\n// exception: its branch reads no modifier at all, so a modified Enter is the\n// only keystroke the Command root would ignore.\nconst isCmdkNavigation = (event: KeyboardEvent<HTMLTextAreaElement>) =>\n event.key !== 'Enter' || !(event.metaKey || event.ctrlKey || event.altKey);\n\nconst promptInputVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:relative',\n\n 'tw:flex',\n 'tw:gap-2',\n 'tw:justify-center',\n\n // Kai's gradient edge, always on: the composer is the one place the reader\n // addresses Kai, and the gradient is what marks it as Kai's rather than the\n // page's. Drawn by filling the interior over a gradient background so only\n // the 2px edge shows through — `bg-origin-border` puts the gradient under\n // the border box, and the inset shadow paints the card back over everything\n // inside it.\n 'tw:border',\n 'tw:border-2',\n 'tw:border-transparent',\n 'tw:rounded-[14px]',\n 'tw:bg-gradient-to-bl',\n 'tw:from-[#61E4FF]',\n 'tw:via-[#1F8FFF]',\n 'tw:to-[#7C5CFF]',\n 'tw:bg-origin-border',\n 'tw:shadow-[inset_0_100vw_rgb(var(--card))]',\n\n // Focus adds the ring alone. The edge is already the loudest thing the\n // control can be, so focus cannot say it louder — it says it wider, and the\n // border width never changes, so nothing shifts.\n 'tw:has-[textarea:focus]:ring-4',\n 'tw:has-[textarea:focus]:ring-ring/30',\n\n 'tw:cursor-text',\n 'tw:px-2',\n ],\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n // Both are columns: attachments take their own rows above the line, and only that line\n // differs between the two.\n default: ['tw:flex-col', 'tw:pt-3', 'tw:pb-2'],\n inline: ['tw:flex-col', 'tw:py-3'],\n },\n },\n },\n);\n\nconst wrapperVariants = cva(null, {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'tw:rounded-[14px]',\n inline: '',\n },\n },\n});\n\ntype Props = {\n /** The textarea, for a host that has to put the caret back. Not `ref`: that name is the textarea's own. */\n textareaRef?: RefObject<ComponentRef<'textarea'> | null>;\n onSend?: (value: string) => void;\n onAbort?: () => void;\n onContinue?: () => void;\n value?: string;\n onValueChange?: (value: string) => void;\n defaultValue?: string;\n prefix?: ReactNode;\n suffix?: ReactNode;\n /** Images and chips already attached, in rows of their own above the text. */\n attachments?: ReactNode;\n /** Extra classes on the field, e.g. taller padding for a hero placement. */\n className?: string;\n variant?: 'default' | 'inline';\n disableSubmit?: boolean;\n /** `/` menu: pick one and it becomes the start of the message. */\n commands?: PromptCommand[];\n} & VariantProps<typeof promptInputVariants> &\n Pick<\n ComponentProps<typeof TextareaAutosize>,\n 'placeholder' | 'minRows' | 'maxRows' | 'disabled' | 'defaultValue' | 'autoFocus'\n > &\n ComponentProps<typeof PromptInputSubmit>;\n\nexport const PromptInput = ({\n onSend,\n onAbort,\n onContinue,\n prefix,\n variant,\n suffix,\n attachments,\n className,\n disabled,\n disableSubmit,\n value = '',\n onValueChange,\n status = 'ready',\n maxRows = 6,\n minRows,\n commands,\n autoFocus,\n textareaRef: publishedRef,\n ...textareaProps\n}: Props) => {\n const defaultMinRows = variant === 'inline' ? 1 : 2;\n const isDisabled =\n (disabled || disableSubmit || !value.trim()) &&\n status !== 'streaming' &&\n status !== 'interrupted';\n\n const textareaId = useId();\n const textareaRef = useRef<ComponentRef<'textarea'>>(null);\n\n // From the ref callback, not an effect: a host restructure recreates the element while this stays mounted.\n const setTextareaNode = useCallback(\n (node: ComponentRef<'textarea'> | null) => {\n textareaRef.current = node;\n if (publishedRef) publishedRef.current = node;\n },\n [publishedRef],\n );\n const [dismissedValue, setDismissedValue] = useState<string | null>(null);\n\n // `autoFocus` is applied imperatively, never as the DOM attribute.\n // - The attribute focuses with ancestor scrolling: the browser scrolls every\n // scrollable ancestor to reveal the element.\n // - A composer can mount inside a panel that is still sliding in (kbc-ui's Kai\n // rail); scrolling toward its off-canvas box drags the whole page sideways.\n // - `preventScroll` grants the focus without the scroll. Mount-only, matching\n // the attribute's semantics.\n const autoFocusRef = useRef(autoFocus);\n useEffect(() => {\n if (autoFocusRef.current) textareaRef.current?.focus({ preventScroll: true });\n }, []);\n\n // Esc dismisses the menu for the value at that moment; once the value moves away\n // from it, clear the dismissal so the menu can reopen if it re-matches the slash\n // shape. Done during render rather than in an effect, and keyed off\n // `dismissedValue` so state only updates while a dismissal is active — no extra\n // render per keystroke.\n if (dismissedValue !== null && value !== dismissedValue) setDismissedValue(null);\n\n const hasMenus = !!commands && commands.length > 0;\n const valueLooksLikeSlashCommand = value.startsWith('/') && !/\\s/.test(value);\n const menuOpen = hasMenus && valueLooksLikeSlashCommand && value !== dismissedValue;\n const menuItems = commands ?? [];\n const menuFilter = value.slice(1);\n\n const handleSubmit = () => {\n if (isDisabled) return;\n if (status === 'streaming') onAbort?.();\n if (status === 'interrupted') onContinue?.();\n if (status === 'ready') onSend?.(value);\n };\n\n const handleOnSubmit: FormEventHandler<HTMLFormElement> = (event) => {\n event.preventDefault();\n handleSubmit();\n };\n\n const handleOnChange: ChangeEventHandler<HTMLTextAreaElement> = (event) => {\n onValueChange?.(event.target.value);\n };\n\n const handleMenuSelect = (item: PromptCommand) => {\n onValueChange?.(item.value + ' ');\n textareaRef.current?.focus();\n };\n\n const handleOnKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (menuOpen) {\n if (event.key === 'Escape') {\n event.preventDefault();\n setDismissedValue(value);\n return;\n }\n // Don't preventDefault — let cmdk handle ArrowUp/Down/Enter via bubbling\n if (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'Enter') {\n return;\n }\n } else if (hasMenus && CMDK_HIJACKED_KEYS.has(event.key) && isCmdkNavigation(event)) {\n // Keep these from bubbling to the always-mounted cmdk Command root, whose\n // keydown handler preventDefaults them and breaks multiline editing.\n // Keystrokes cmdk ignores (e.g. Cmd+Enter, Alt+Enter) must still reach\n // document-level app hotkeys, so they are deliberately not stopped here.\n event.stopPropagation();\n }\n\n if (event.key === 'Enter' && !event.shiftKey && !event.ctrlKey && !event.metaKey) {\n event.preventDefault();\n if (status !== 'streaming') handleSubmit();\n }\n };\n\n const handleOnMouseDown: MouseEventHandler<HTMLFormElement> = (event) => {\n // don't prevent default if the target is the textarea itself\n if (event.target === textareaRef.current) return;\n\n event.preventDefault();\n textareaRef.current?.focus();\n };\n\n const formEl = (\n <div className={wrapperVariants({ variant })}>\n {/*This is alright, just refocused into a textarea. */}\n {/* oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}\n <form\n data-testid=\"prompt-input\"\n data-status={status}\n onMouseDown={handleOnMouseDown}\n onSubmit={handleOnSubmit}\n className={cn(\n promptInputVariants({ variant }),\n disabled &&\n 'tw:bg-none tw:border-border tw:shadow-[inset_0_100vw_rgb(var(--muted))] tw:cursor-default',\n className,\n )}\n >\n {/* Whatever is already attached, above the line and never mixed into it: a textarea holds\n text, so a chip beside it only ever crowded the first line. */}\n {attachments && <div className=\"tw:flex tw:flex-col tw:gap-2 tw:pb-2\">{attachments}</div>}\n\n <label htmlFor={textareaId} className=\"tw:sr-only\">\n Prompt Input\n </label>\n <div\n className={cn(\n 'tw:flex tw:min-w-0 tw:gap-2',\n variant === 'inline' ? 'tw:flex-row tw:items-center' : 'tw:flex-col',\n )}\n >\n {prefix && <div className=\"tw:flex tw:shrink-0 tw:items-center\">{prefix}</div>}\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:items-center\">\n <TextareaAutosize\n {...textareaProps}\n disabled={disabled}\n minRows={minRows ?? defaultMinRows}\n maxRows={maxRows}\n id={textareaId}\n ref={setTextareaNode}\n value={value}\n onChange={handleOnChange}\n onKeyDown={handleOnKeyDown}\n className={cn(\n 'tw:resize-none',\n 'tw:outline-hidden',\n 'tw:min-w-32 tw:flex-1',\n // Indented by the round menu button's own inset, so the text lines up with that\n // button's glyph rather than with its box. The inline row has no toolbar below it.\n variant === 'inline' ? 'tw:px-0' : 'tw:pl-2 tw:pr-0',\n 'tw:bg-transparent',\n\n // font\n disabled ? 'tw:text-muted-foreground' : 'tw:text-foreground',\n 'tw:text-sm',\n 'tw:font-sans',\n\n 'tw:transition-[width]',\n 'tw:delay-75',\n 'tw:ease-linear',\n 'tw:overflow-auto',\n )}\n />\n </div>\n\n <div\n className={cn(\n // The controls are round and carry their own padding, so a wide gap on top of that\n // reads as three separate things rather than one toolbar.\n 'tw:flex tw:shrink-0 tw:items-center tw:gap-1',\n // Send is the one filled circle among outline ones, and a filled shape eats the space\n // beside it: at the row's gap it sits closer than the others do. The extra 4px is\n // what makes all three read as evenly spaced.\n 'tw:[&>*:last-child]:ml-1',\n // Inline, the send button sits in the field's corner, so it needs more room beside\n // it than above it — at the side padding the text uses it crowded the curve. The\n // text keeps that padding; only the trailing controls step in.\n variant === 'inline' && 'tw:pr-2.5',\n )}\n >\n {suffix}\n <PromptInputSubmit disabled={isDisabled} status={status} />\n </div>\n </div>\n </form>\n </div>\n );\n\n return (\n <TooltipProvider>\n {hasMenus ? (\n <PromptInputCommands\n items={menuItems}\n open={menuOpen}\n onSelect={handleMenuSelect}\n filterValue={menuFilter}\n emptyText=\"No commands found\"\n onClose={() => setDismissedValue(value)}\n >\n {formEl}\n </PromptInputCommands>\n ) : (\n formEl\n )}\n </TooltipProvider>\n );\n};\n\nPromptInput.Action = PromptInputAction;\nPromptInput.MenuTrigger = PromptInputMenuTrigger;\n","import { type KeyboardEvent, type ReactNode, useState } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Checkbox } from '../../components/Checkbox';\nimport { Progress } from '../../components/Progress';\nimport { Tooltip } from '../../components/Tooltip';\nimport { ChevronLeft, ChevronRight, X } from '../../icons';\nimport { cn } from '../../utils';\nimport { TextInput } from '../TextInput';\n\ntype QuestionOption = {\n id: string;\n label: string;\n description?: string;\n preview?: string;\n};\n\ntype Props = {\n question: string;\n header?: string;\n options: readonly QuestionOption[];\n multiSelect?: boolean;\n selectedOptionIds?: readonly string[];\n onSelectionChange?: (selectedIds: readonly string[]) => void;\n customAnswer?: string;\n onCustomAnswerChange?: (value: string) => void;\n onCustomAnswerConfirm?: () => void;\n showCustomAnswer?: boolean;\n customAnswerPlaceholder?: string;\n showSkip?: boolean;\n onSkip?: () => void;\n onClose?: () => void;\n onNext?: () => void;\n submitTooltip?: ReactNode;\n onPrevious?: () => void;\n currentStep?: number;\n totalSteps?: number;\n renderPreview?: (content: string) => ReactNode;\n className?: string;\n};\n\nconst handleKeyDown = (callback: () => void) => (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n callback();\n }\n};\n\nexport const Question = ({\n question,\n header,\n options,\n multiSelect = true,\n selectedOptionIds = [],\n onSelectionChange,\n customAnswer = '',\n onCustomAnswerChange,\n onCustomAnswerConfirm,\n showCustomAnswer = true,\n customAnswerPlaceholder = 'Type your answer…',\n showSkip = true,\n onSkip,\n onClose,\n onNext,\n submitTooltip,\n onPrevious,\n currentStep,\n totalSteps,\n renderPreview,\n className,\n}: Props) => {\n const [isCustomExpanded, setIsCustomExpanded] = useState(false);\n const isCustomSelected = isCustomExpanded || customAnswer.length > 0;\n const hasSteps = currentStep != null && totalSteps != null;\n // A one-question card has nothing to step through: \"1 of 1\" over a full bar, with both\n // chevrons dead, describes a journey that does not exist. `hasSteps` still stands — it is what\n // makes this the last step, and so what makes the action read Submit rather than Next.\n const showStepControls = hasSteps && totalSteps > 1;\n const showSkipButton = showSkip && onSkip != null;\n const showSubmitButton = multiSelect || isCustomSelected;\n // Every slot in the footer is conditional, so the row itself has to be: a bordered strip with\n // nothing in it reads as a control that failed to render.\n const showFooter = showStepControls || showSkipButton || showSubmitButton;\n const progressValue = hasSteps ? (currentStep / totalSteps) * 100 : 0;\n const isFirstStep = currentStep === 1;\n const isLastStep = hasSteps && currentStep === totalSteps;\n\n const handleOptionToggle = (optionId: string) => {\n if (multiSelect) {\n const isSelected = selectedOptionIds.includes(optionId);\n const nextIds = isSelected\n ? selectedOptionIds.filter((id) => id !== optionId)\n : [...selectedOptionIds, optionId];\n onSelectionChange?.(nextIds);\n } else {\n // Single-select: picking a real option deselects \"Other\" and drops any\n // typed custom answer so it can't leak into the submitted answer.\n setIsCustomExpanded(false);\n onCustomAnswerChange?.('');\n onSelectionChange?.([optionId]);\n }\n };\n\n const handleCustomToggle = (checked: boolean) => {\n setIsCustomExpanded(checked);\n if (checked) {\n // Single-select: \"Other\" and a real option are mutually exclusive.\n if (!multiSelect) {\n onSelectionChange?.([]);\n }\n } else {\n onCustomAnswerChange?.('');\n }\n };\n\n // Typing into (or focusing) the custom input selects \"Other\" directly — no\n // need to click the row/checkbox first.\n const handleCustomFocus = () => {\n setIsCustomExpanded(true);\n if (!multiSelect) {\n onSelectionChange?.([]);\n }\n };\n\n const handleCustomRowClick = () => {\n // Multi-select: the row toggles the checkbox. Single-select: clicking only\n // selects (never deselects, so a second click can't wipe typed text) —\n // switch away by picking a real option instead.\n if (multiSelect) {\n handleCustomToggle(!isCustomSelected);\n } else {\n handleCustomFocus();\n }\n };\n\n return (\n <div\n className={cn(\n 'tw:flex tw:max-w-[800px] tw:flex-col tw:gap-4 tw:overflow-hidden tw:rounded-xl tw:border tw:border-solid tw:border-border tw:bg-card tw:text-card-foreground tw:shadow-lg',\n className,\n )}\n data-testid=\"question-root\"\n data-question-step={currentStep}\n data-question-total-steps={totalSteps}\n data-question-multi-select={multiSelect}\n >\n <div className=\"tw:flex tw:items-start tw:gap-2 tw:pl-4 tw:pr-2 tw:pt-4\">\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:gap-1\">\n <p className=\"tw:m-0 tw:text-base tw:font-semibold tw:leading-6\">{question}</p>\n {header && (\n <p className=\"tw:m-0 tw:text-xs tw:leading-4 tw:text-muted-foreground\">{header}</p>\n )}\n </div>\n {onClose && (\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label=\"Close\"\n onClick={onClose}\n data-testid=\"question-close-button\"\n >\n <X className=\"tw:size-4\" />\n </Button>\n )}\n </div>\n\n <div className=\"tw:px-4\">\n <div className=\"tw:flex tw:flex-col tw:gap-4 tw:border-0 tw:border-l tw:border-solid tw:border-primary tw:px-4 tw:py-2\">\n {options.map((option) => (\n <div\n key={option.id}\n className=\"tw:-mx-2 tw:-my-1.5 tw:flex tw:cursor-pointer tw:items-start tw:gap-2 tw:rounded-md tw:px-2 tw:py-1.5 tw:hover:bg-accent\"\n onClick={() => handleOptionToggle(option.id)}\n onKeyDown={handleKeyDown(() => handleOptionToggle(option.id))}\n role=\"button\"\n tabIndex={0}\n data-testid={`question-option-${option.id}`}\n >\n {multiSelect && (\n <Checkbox\n checked={selectedOptionIds.includes(option.id)}\n onCheckedChange={() => handleOptionToggle(option.id)}\n onClick={(e) => e.stopPropagation()}\n className=\"tw:shrink-0\"\n />\n )}\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:items-start tw:gap-3\">\n <div className=\"tw:flex tw:flex-col tw:gap-1.5\">\n <span className=\"tw:text-sm tw:font-medium tw:leading-none\">{option.label}</span>\n {option.description && (\n <span className=\"tw:text-sm tw:font-normal tw:leading-5 tw:text-muted-foreground\">\n {option.description}\n </span>\n )}\n </div>\n {option.preview && (\n <div\n data-testid=\"question-option-preview\"\n className={cn(\n 'tw:ml-auto tw:flex tw:max-h-40 tw:min-w-0 tw:max-w-[50%] tw:flex-col tw:overflow-hidden tw:rounded-md',\n !renderPreview &&\n 'tw:overflow-auto tw:border tw:border-solid tw:border-border tw:bg-muted tw:p-2 tw:text-foreground',\n )}\n >\n {renderPreview ? (\n renderPreview(option.preview)\n ) : (\n // `text-foreground` restates the ink the box above already\n // sets, and is not redundant: consuming apps ship a global\n // `pre { color; background-color; border }` rule that beats\n // inheritance but loses to a utility — the same reason\n // `border-0` and `bg-transparent` are spelled out here.\n <pre className=\"tw:m-0 tw:overflow-visible tw:border-0 tw:bg-transparent tw:p-0 tw:font-mono tw:text-xs tw:leading-5 tw:text-foreground\">\n {option.preview}\n </pre>\n )}\n </div>\n )}\n </div>\n </div>\n ))}\n\n {showCustomAnswer && (\n <div className=\"tw:flex tw:flex-col tw:gap-2\">\n <div\n className=\"tw:-mx-2 tw:-my-1.5 tw:flex tw:cursor-pointer tw:items-start tw:gap-2 tw:rounded-md tw:px-2 tw:py-1.5 tw:hover:bg-accent\"\n onClick={handleCustomRowClick}\n onKeyDown={handleKeyDown(handleCustomRowClick)}\n role=\"button\"\n tabIndex={0}\n >\n {/* Multi-select shows a checkbox alongside the option checkboxes.\n Single-select options auto-advance and carry no indicator, so\n \"Other\" is a plain clickable row that reveals the input below. */}\n {multiSelect && (\n <Checkbox\n checked={isCustomSelected}\n onCheckedChange={handleCustomToggle}\n onClick={(e) => e.stopPropagation()}\n className=\"tw:shrink-0\"\n />\n )}\n <span\n className={cn(\n 'tw:text-sm tw:font-medium tw:leading-none',\n !multiSelect && isCustomSelected && 'tw:text-primary',\n )}\n >\n Other\n </span>\n </div>\n {/* Always rendered and editable: typing or focusing selects \"Other\"\n directly, and keeping it mounted avoids layout shift. */}\n <TextInput\n value={customAnswer}\n onValueChange={(value) => onCustomAnswerChange?.(value)}\n onFocus={handleCustomFocus}\n onKeyDown={\n onCustomAnswerConfirm\n ? (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && !e.shiftKey && !(e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n onCustomAnswerConfirm();\n }\n }\n : undefined\n }\n placeholder={customAnswerPlaceholder}\n sizing=\"small\"\n testId=\"question-custom\"\n />\n </div>\n )}\n </div>\n </div>\n\n <div className=\"tw:flex tw:flex-col\">\n {showStepControls && (\n <Progress size=\"sm\" value={progressValue} className=\"tw:rounded-none\" />\n )}\n\n {showFooter && (\n <div\n className={cn(\n 'tw:flex tw:items-center tw:justify-end tw:gap-4 tw:px-4 tw:py-3',\n !showStepControls && 'tw:border-0 tw:border-t tw:border-solid tw:border-border',\n )}\n >\n {showStepControls && (\n <div className=\"tw:flex tw:items-center tw:gap-2\">\n <button\n type=\"button\"\n disabled={isFirstStep}\n className=\"tw:flex tw:cursor-pointer tw:items-center tw:justify-center tw:bg-transparent tw:p-0 tw:disabled:cursor-default tailwindcss-preflight\"\n onClick={onPrevious}\n aria-label=\"Previous step\"\n >\n <ChevronLeft\n className={cn(\n 'tw:size-5',\n isFirstStep ? 'tw:text-primary/25' : 'tw:text-primary',\n )}\n />\n </button>\n <span className=\"tw:text-xs tw:leading-4 tw:text-muted-foreground\">\n {currentStep} of {totalSteps}\n </span>\n <button\n type=\"button\"\n disabled={currentStep === totalSteps}\n className=\"tw:flex tw:cursor-pointer tw:items-center tw:justify-center tw:bg-transparent tw:p-0 tw:disabled:cursor-default tailwindcss-preflight\"\n onClick={onNext}\n aria-label=\"Next step\"\n >\n <ChevronRight\n className={cn(\n 'tw:size-5',\n currentStep === totalSteps ? 'tw:text-primary/25' : 'tw:text-primary',\n )}\n />\n </button>\n </div>\n )}\n {showSkipButton && (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={onSkip}\n data-testid=\"question-skip-button\"\n >\n Skip\n </Button>\n )}\n {showSubmitButton &&\n (submitTooltip ? (\n <Tooltip tooltip={submitTooltip} placement=\"top\" triggerAsChild>\n <Button\n variant=\"primary\"\n size=\"small\"\n onClick={onNext}\n data-testid=\"question-next-button\"\n >\n {isLastStep ? 'Submit' : 'Next'}\n </Button>\n </Tooltip>\n ) : (\n <Button\n variant=\"primary\"\n size=\"small\"\n onClick={onNext}\n data-testid=\"question-next-button\"\n >\n {isLastStep ? 'Submit' : 'Next'}\n </Button>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport type { QuestionOption, Props as QuestionProps };\n","import { type ReactNode, useState } from 'react';\n\nimport type { QuestionOption } from './Question';\nimport { Question } from './Question';\n\ntype QuestionStep = {\n question: string;\n header?: string;\n options: readonly QuestionOption[];\n multiSelect?: boolean;\n showCustomAnswer?: boolean;\n customAnswerPlaceholder?: string;\n};\n\ntype QuestionAnswers = {\n selections: Record<number, readonly string[]>;\n customAnswers: Record<number, string>;\n};\n\ntype Props = {\n steps: readonly [QuestionStep, ...QuestionStep[]];\n showSkip?: boolean;\n onSubmit?: (answers: QuestionAnswers) => void;\n onClose?: () => void;\n renderPreview?: (content: string) => ReactNode;\n className?: string;\n};\n\nexport const QuestionBlock = ({\n steps,\n showSkip = true,\n onSubmit,\n onClose,\n renderPreview,\n className,\n}: Props) => {\n const [currentStep, setCurrentStep] = useState(1);\n const [selections, setSelections] = useState<Record<number, readonly string[]>>({});\n const [customAnswers, setCustomAnswers] = useState<Record<number, string>>({});\n const stepData = steps[currentStep - 1]!;\n const isLastStep = currentStep === steps.length;\n\n const advance = (updatedSelections?: Record<number, readonly string[]>) => {\n const finalSelections = updatedSelections ?? selections;\n if (isLastStep) {\n onSubmit?.({ selections: finalSelections, customAnswers });\n } else {\n setCurrentStep((s) => Math.min(s + 1, steps.length));\n }\n };\n\n const handleSelectionChange = (ids: readonly string[]) => {\n const updated = { ...selections, [currentStep]: ids };\n setSelections(updated);\n if (!stepData.multiSelect) {\n advance(updated);\n }\n };\n\n return (\n <Question\n key={currentStep}\n {...stepData}\n selectedOptionIds={selections[currentStep] ?? []}\n onSelectionChange={handleSelectionChange}\n customAnswer={customAnswers[currentStep] ?? ''}\n onCustomAnswerChange={(value) =>\n setCustomAnswers((prev) => ({ ...prev, [currentStep]: value }))\n }\n currentStep={currentStep}\n totalSteps={steps.length}\n showSkip={showSkip && !isLastStep}\n onNext={() => advance()}\n onPrevious={() => setCurrentStep((s) => Math.max(s - 1, 1))}\n onSkip={() => setCurrentStep((s) => Math.min(s + 1, steps.length))}\n onClose={onClose}\n renderPreview={renderPreview}\n className={className}\n />\n );\n};\n\nexport type { QuestionStep, QuestionAnswers, Props as QuestionBlockProps };\n","import type { ReactNode } from 'react';\n\nimport { Sparkles } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Props = {\n label: string;\n disabled?: boolean;\n onClick: () => void;\n icon?: ReactNode;\n className?: string;\n};\n\nexport const SuggestedPrompt = ({ label, disabled, onClick, icon, className }: Props) => {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={cn(\n 'tailwindcss-preflight tw:flex tw:items-center tw:justify-start tw:gap-2.5 tw:whitespace-nowrap',\n 'tw:rounded-lg tw:px-3 tw:py-2',\n 'tw:text-left tw:text-sm tw:font-medium tw:text-foreground',\n 'tw:transition-colors tw:not-disabled:hover:bg-accent',\n 'tw:focus-visible:outline-none tw:focus-visible:ring-2 tw:focus-visible:ring-ring tw:focus-visible:ring-offset-1',\n 'tw:disabled:cursor-not-allowed tw:disabled:opacity-50',\n className,\n )}\n onClick={onClick}\n >\n {icon ?? (\n // Lucide icons are stroke-based — paint the visible line with the AI\n // gradient (no fill, so the glyph keeps its outline silhouette instead\n // of becoming a solid block). The `*` selector catches every shape\n // element (path, circle, polyline, …) so multi-part icons don't lose\n // sub-shapes the way `path`-only selectors do.\n <Sparkles className=\"tw:size-4 tw:shrink-0 tw:basis-4 tw:[&_*]:stroke-aigradient-600\" />\n )}\n <div className=\"tw:whitespace-normal tw:text-left\">{label}</div>\n </button>\n );\n};\n","import { Loader2 } from '../../icons';\n\ntype ThinkingIndicatorProps = {\n label?: string;\n};\n\n/**\n * The agent's turn is in flight and has nothing to show yet.\n *\n * - Quiet chrome, matching the step rows it precedes (muted ink, no italic), so the hand-off\n * from \"Thinking...\" to the first step is seamless.\n * - `role=\"status\"` because a spinner is silence to a screen reader, and for much of a turn\n * this is all a transcript shows. The label is the announcement, so it is never decorative.\n * - The icon is hidden from the tree: it says the same thing as the label beside it.\n */\nexport const ThinkingIndicator = ({ label = 'Thinking...' }: ThinkingIndicatorProps) => {\n return (\n <div\n className=\"tw:flex tw:items-center tw:gap-1.5\"\n role=\"status\"\n data-testid=\"chat-thinking-indicator\"\n >\n <Loader2 aria-hidden className=\"tw:size-3.5 tw:animate-spin tw:text-muted-foreground\" />\n <span className=\"tw:text-xs tw:font-medium tw:text-muted-foreground\">{label}</span>\n </div>\n );\n};\n\nexport type { ThinkingIndicatorProps };\n","import { type ReactNode, useEffect } from 'react';\n\nimport { Badge } from '../../../components/Badge';\nimport { Button } from '../../../components/Button';\nimport { cn } from '../../../utils';\n\ntype ToolCallApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';\n\ntype ToolCallApprovalProps = {\n /** The tool being called (e.g. `run_sql`). Rendered as a monospace tag. */\n toolName: string;\n /** Human-readable summary of what the tool will do. */\n title?: ReactNode;\n status: ToolCallApprovalStatus;\n onApprove?: () => void;\n onReject?: () => void;\n /** App-rendered detail — a diff, a `ToolCallChip`, a chart, arguments. */\n children?: ReactNode;\n /**\n * Replaces the default Approve/Reject buttons in the pending state. Use when\n * the call needs bespoke controls (e.g. an inline reason field).\n */\n actions?: ReactNode;\n isSubmitting?: boolean;\n /**\n * Opt into `Enter` = approve / `Escape` = reject while pending. Off by\n * default so the shortcuts never fire unexpectedly in a busy chat.\n */\n enableShortcuts?: boolean;\n approveLabel?: string;\n rejectLabel?: string;\n className?: string;\n};\n\nconst STATUS_BADGE: Record<\n ToolCallApprovalStatus,\n { label: string; color: 'blue' | 'green' | 'red' | 'gray' }\n> = {\n pending: { label: 'Needs approval', color: 'blue' },\n approved: { label: 'Approved', color: 'green' },\n rejected: { label: 'Rejected', color: 'red' },\n expired: { label: 'Expired', color: 'gray' },\n};\n\n/**\n * Per-tool-call approve/reject frame — the granular sibling of `PlanApproval`\n * (which approves a whole plan). Chrome + status + actions only: the app\n * renders the call detail as `children` and owns the SDK/permission wiring.\n */\nexport const ToolCallApproval = ({\n toolName,\n title,\n status,\n onApprove,\n onReject,\n children,\n actions,\n isSubmitting = false,\n enableShortcuts = false,\n approveLabel = 'Approve',\n rejectLabel = 'Reject',\n className,\n}: ToolCallApprovalProps) => {\n const isPending = status === 'pending';\n const hasCustomActions = actions != null;\n const showDefaultActions = isPending && !hasCustomActions && Boolean(onApprove || onReject);\n // Custom actions, like the defaults, only make sense while a decision is\n // still pending — never leave controls visible in a terminal state.\n const showActions = isPending && (showDefaultActions || hasCustomActions);\n const badge = STATUS_BADGE[status];\n\n useEffect(() => {\n if (!enableShortcuts || !isPending || isSubmitting) return;\n\n const isEditableTarget = (target: EventTarget | null) => {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.tagName === 'SELECT'\n );\n };\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Ignore key-repeat and keystrokes typed into a field.\n if (event.repeat || event.defaultPrevented || isEditableTarget(event.target)) return;\n\n if (\n event.key === 'Enter' &&\n !event.shiftKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n onApprove\n ) {\n event.preventDefault();\n onApprove();\n } else if (event.key === 'Escape' && onReject) {\n event.preventDefault();\n onReject();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [enableShortcuts, isPending, isSubmitting, onApprove, onReject]);\n\n return (\n <section\n data-testid=\"tool-call-approval\"\n data-status={status}\n aria-label={typeof title === 'string' ? title : toolName}\n className={cn(\n 'tw:flex tw:w-full tw:max-w-[800px] tw:flex-col tw:gap-3 tw:overflow-hidden tw:rounded-xl tw:border tw:border-solid tw:border-border tw:bg-muted tw:p-4',\n className,\n )}\n >\n <div className=\"tw:flex tw:items-center tw:gap-2\">\n <Badge color={badge.color} variant=\"pill\" className=\"tw:normal-case tw:tracking-normal\">\n {badge.label}\n </Badge>\n <code className=\"tw:rounded tw:bg-background tw:px-1.5 tw:py-0.5 tw:font-mono tw:text-xs tw:text-foreground\">\n {toolName}\n </code>\n </div>\n\n {title != null && (\n <p className=\"tw:m-0 tw:text-sm tw:font-medium tw:text-foreground\">{title}</p>\n )}\n\n {children}\n\n {showActions && (\n <div className=\"tw:flex tw:items-center tw:justify-end tw:gap-2 tw:overflow-x-auto\">\n {actions ?? (\n <>\n {onReject && (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={onReject}\n disabled={isSubmitting}\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {rejectLabel}\n </Button>\n )}\n {onApprove && (\n <Button\n variant=\"primary\"\n size=\"small\"\n onClick={onApprove}\n disabled={isSubmitting}\n className=\"tw:shrink-0 tw:whitespace-nowrap\"\n >\n {approveLabel}\n </Button>\n )}\n </>\n )}\n </div>\n )}\n </section>\n );\n};\n\nexport type { ToolCallApprovalStatus, ToolCallApprovalProps };\n","import type { MouseEventHandler, ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\n\nimport { CircleCheck, CircleX, Loader2 } from '../../../icons';\nimport { cn } from '../../../utils';\n\ntype ToolCallState = 'processing' | 'done' | 'error';\n\ntype ToolCallChipProps = {\n label: ReactNode;\n state: ToolCallState;\n /** Leading icon; defaults to a state glyph (spinner / check / x). */\n icon?: ReactNode;\n /** Trailing node (e.g. a chevron or count). */\n trailing?: ReactNode;\n /** When set, the chip renders as a button and fires this on click. */\n onClick?: MouseEventHandler<HTMLButtonElement>;\n className?: string;\n};\n\nconst chipClasses = cva(\n [\n 'tw:inline-flex tw:items-center tw:gap-1.5 tw:rounded-md tw:border tw:border-solid',\n 'tw:border-border tw:bg-muted tw:px-2 tw:py-1 tw:text-xs tw:text-foreground',\n ],\n {\n variants: {\n interactive: {\n true: 'tw:cursor-pointer tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-ring tw:not-disabled:hover:bg-accent',\n false: '',\n },\n },\n defaultVariants: { interactive: false },\n },\n);\n\nconst StateIcon = ({ state }: { state: ToolCallState }) => {\n if (state === 'processing') {\n return <Loader2 className=\"tw:size-3.5 tw:shrink-0 tw:animate-spin tw:text-muted-foreground\" />;\n }\n if (state === 'error') {\n return <CircleX className=\"tw:size-3.5 tw:shrink-0 tw:text-error-500\" />;\n }\n return <CircleCheck className=\"tw:size-3.5 tw:shrink-0 tw:text-primary\" />;\n};\n\n/**\n * Presentational chip summarising a single tool call (icon + label + optional\n * trailing action). It has **no** URL/router knowledge — wrap it in a `Link`\n * or pass `onClick` for navigation; the app owns deep-linking.\n */\nexport const ToolCallChip = ({\n label,\n state,\n icon,\n trailing,\n onClick,\n className,\n}: ToolCallChipProps) => {\n const content = (\n <>\n {icon ?? <StateIcon state={state} />}\n <span className=\"tw:min-w-0 tw:truncate\">{label}</span>\n {trailing != null && (\n <span className=\"tw:ml-auto tw:inline-flex tw:shrink-0 tw:items-center\">{trailing}</span>\n )}\n </>\n );\n\n if (onClick) {\n return (\n <button\n type=\"button\"\n data-testid=\"tool-call-chip\"\n data-state={state}\n onClick={onClick}\n className={cn('tailwindcss-preflight', chipClasses({ interactive: true }), className)}\n >\n {content}\n </button>\n );\n }\n\n return (\n <span\n data-testid=\"tool-call-chip\"\n data-state={state}\n className={cn(chipClasses({ interactive: false }), className)}\n >\n {content}\n </span>\n );\n};\n\nexport type { ToolCallChipProps, ToolCallState };\n","import type { ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\n\nimport type { LucideIcon } from '../../icons';\nimport { ChevronDown, TriangleAlert } from '../../icons';\nimport { cn } from '../../utils';\n\ntype ToolCallStatus = 'processing' | 'warning' | 'success' | 'error';\n\ntype Props = {\n icon: LucideIcon;\n iconSpin?: boolean;\n status: ToolCallStatus;\n text: ReactNode;\n needsConfirmation?: boolean;\n isCollapsible?: boolean;\n isCollapsed?: boolean;\n onToggleCollapse?: () => void;\n};\n\n// The header stays a neutral band for routine states — a filled saturated bar\n// made every successful tool call shout. Status is carried by the icon and the\n// label tint; the two states that ask for the user's attention (a pending\n// confirmation, a failure) additionally get a soft tint of their status colour\n// so they catch peripheral vision without shouting.\nconst headerVariants = cva(\n 'tw:flex tw:items-center tw:justify-between tw:gap-2 tw:px-2.5 tw:py-1.5',\n {\n variants: {\n // One boundary cue per state, never two: a tinted header is already\n // bounded by where its wash stops, so it takes no rule — the hairline\n // belongs to the untinted states, which would otherwise have no edge.\n status: {\n processing: 'tw:border-b tw:border-border/60',\n warning: 'tw:bg-warning/10',\n success: 'tw:border-b tw:border-border/60',\n error: 'tw:bg-destructive/10',\n },\n },\n defaultVariants: {\n status: 'success',\n },\n },\n);\n\nconst statusInk: Record<ToolCallStatus, string> = {\n processing: 'tw:text-muted-foreground',\n warning: 'tw:text-warning',\n success: 'tw:text-muted-foreground',\n error: 'tw:text-destructive',\n};\n\nconst statusIconInk: Record<ToolCallStatus, string> = {\n processing: 'tw:text-muted-foreground',\n warning: 'tw:text-warning',\n success: 'tw:text-success/70',\n error: 'tw:text-destructive',\n};\n\nexport const ToolCallStatusHeader = ({\n icon: IconComponent,\n iconSpin,\n status,\n text,\n needsConfirmation,\n isCollapsible,\n isCollapsed,\n onToggleCollapse,\n}: Props) => {\n return (\n <div\n role={isCollapsible ? 'button' : undefined}\n tabIndex={isCollapsible ? 0 : undefined}\n aria-expanded={isCollapsible ? !isCollapsed : undefined}\n data-status={status}\n className={cn(headerVariants({ status }), isCollapsible && 'tw:cursor-pointer')}\n onClick={isCollapsible ? onToggleCollapse : undefined}\n onKeyDown={\n isCollapsible\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onToggleCollapse?.();\n }\n }\n : undefined\n }\n >\n <div className=\"tw:flex tw:min-w-0 tw:flex-1 tw:items-center tw:gap-1.5\">\n <IconComponent\n className={cn(\n 'tw:size-3.5 tw:shrink-0',\n statusIconInk[status],\n iconSpin && 'tw:animate-spin',\n )}\n />\n <span\n data-testid=\"tool-status-text\"\n className={cn('tw:truncate tw:pr-0.5 tw:text-xs tw:font-medium', statusInk[status])}\n >\n {text}\n </span>\n </div>\n {(needsConfirmation || isCollapsible) && (\n <div className=\"tw:flex tw:shrink-0 tw:items-center tw:gap-2\">\n {needsConfirmation && (\n <div className=\"tw:flex tw:items-center tw:gap-1\">\n <span\n data-testid=\"tool-confirmation-required\"\n className=\"tw:text-xs tw:font-medium tw:text-warning\"\n >\n Confirmation required\n </span>\n <TriangleAlert className=\"tw:size-3.5 tw:text-warning\" />\n </div>\n )}\n {isCollapsible && (\n <ChevronDown\n className={cn(\n 'tw:size-3.5 tw:shrink-0 tw:text-muted-foreground',\n 'tw:transition-transform tw:duration-300 tw:ease-out tw:motion-reduce:transition-none',\n !isCollapsed && 'tw:rotate-180',\n )}\n />\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport type { Props as ToolCallStatusHeaderProps, ToolCallStatus };\n","/**\n * Clamp a percentage to 0–100 and normalize non-finite input to 0.\n *\n * - `Progress`'s indicator is unclamped, so a value over 100 slides the bar off-screen.\n * - `NaN` normalizes to 0 — `Math.min`/`Math.max` propagate it, and it renders as no bar at all.\n */\nexport const clampPercentage = (value: number) =>\n Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;\n\n/**\n * A percentage as text — `72%`, `0.2%`, `99%`.\n *\n * - Whole numbers from 1% up; a decimal only below 1%, where rounding would read as `0%`.\n * - A non-zero share never prints as `0.0%` — it floors at `0.1%`.\n * - Never `100%` for a value under 100: the text would disagree with the at-limit state computed\n * from the raw value, exactly at the boundary everything else turns on.\n */\nexport const formatPercentage = (value: number) => {\n const oneDecimal = Math.round(value * 10) / 10;\n if (value > 0 && oneDecimal < 1) {\n return `${Math.max(0.1, oneDecimal).toFixed(1)}%`;\n }\n const rounded = Math.round(value);\n return `${value < 100 ? Math.min(rounded, 99) : rounded}%`;\n};\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { Progress } from '../../components/Progress';\nimport { cn } from '../../utils';\n\nimport { clampPercentage, formatPercentage } from './usageStatsHelpers';\n\ntype Props = Omit<ComponentProps<'span'>, 'children'> & {\n /**\n * The share of the budget already SPENT, 0–100.\n *\n * - The bar fills as the budget is used, so it reads the same way as an admin's spend table.\n * - The figure beside the label says what is LEFT, because the reader's question at a ceiling\n * is how much room remains. One value drives both; they cannot disagree.\n */\n value: number;\n /** The budget being measured — \"Project usage\", \"This month's budget for your questions\". */\n label: ReactNode;\n /**\n * The bar's tone, at the host's discretion.\n *\n * - Untoned by default. Which percentage counts as close to a ceiling is a product rule, and\n * the surfaces drawing this do not share one: a meter that escalates beside a banner that\n * also escalates puts a single event on the screen twice.\n */\n variant?: ComponentProps<typeof Progress>['variant'];\n};\n\n/**\n * One budget, as a labelled row over a bar.\n *\n * - The label and the figure sit on one baseline at either end of the row; the bar spans both.\n * - `value` over 100 or `NaN` is clamped by `clampPercentage` — `Progress`'s indicator is\n * unclamped and would otherwise slide off the row.\n */\nexport const UsageBar = ({ value, label, variant, className, ...props }: Props) => (\n <span\n {...props}\n className={cn('tw:flex tw:flex-col tw:gap-1.5 tw:text-xs tw:text-muted-foreground', className)}\n >\n <span className=\"tw:flex tw:items-baseline tw:justify-between tw:gap-2\">\n <span>{label}</span>\n <span>{`${formatPercentage(Math.max(0, 100 - value))} left`}</span>\n </span>\n <Progress size=\"sm\" variant={variant} value={clampPercentage(value)} />\n </span>\n);\n","import { cn } from '../../utils';\n\nimport { clampPercentage } from './usageStatsHelpers';\n\ntype Props = {\n value: number;\n size?: number;\n strokeWidth?: number;\n className?: string;\n};\n\nexport const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }: Props) => {\n const radius = Math.max(0, (size - strokeWidth) / 2 - 1);\n const circumference = 2 * Math.PI * radius;\n const offset = circumference * (1 - clampPercentage(value) / 100);\n\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n className={cn('tw:-rotate-90', className)}\n role=\"presentation\"\n >\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={strokeWidth}\n // The unfilled remainder of the gauge: a muted mark, not a surface.\n className=\"tw:stroke-muted-foreground tw:opacity-50\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n className=\"tw:stroke-primary tw:transition-all\"\n />\n </svg>\n );\n};\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { HoverCard } from '../../components/HoverCard';\nimport { AlertCircle } from '../../icons';\nimport { cn } from '../../utils';\n\nimport { clampPercentage } from './usageStatsHelpers';\nimport { UsageStatsRing } from './UsageStatsRing';\n\ntype Props = {\n value: number;\n /**\n * `true` (or `'error'`) renders the red corner badge; `'warning'` renders\n * it amber for an approaching-limit state that isn't at-limit yet.\n */\n alert?: boolean | 'warning' | 'error';\n children: ReactNode;\n className?: string;\n /**\n * Accessible name for the trigger. Defaults to a value-aware label so\n * screen-reader users get the same information the ring conveys visually.\n */\n ariaLabel?: string;\n align?: ComponentProps<typeof HoverCard.Content>['align'];\n side?: ComponentProps<typeof HoverCard.Content>['side'];\n sideOffset?: ComponentProps<typeof HoverCard.Content>['sideOffset'];\n /** Control the card yourself to hold it open past a pointer leave — e.g. while a popover it contains is up. */\n open?: ComponentProps<typeof HoverCard>['open'];\n onOpenChange?: ComponentProps<typeof HoverCard>['onOpenChange'];\n};\n\nexport const UsageStats = ({\n value,\n alert = false,\n children,\n className,\n ariaLabel,\n align = 'end',\n side = 'top',\n sideOffset = 8,\n open,\n onOpenChange,\n}: Props) => {\n const hasAlert = Boolean(alert);\n const isWarning = alert === 'warning';\n const defaultLabel = `Usage: ${Math.round(clampPercentage(value))}%${hasAlert ? ' (usage alert)' : ''}`;\n return (\n <HoverCard open={open} onOpenChange={onOpenChange}>\n <HoverCard.Trigger asChild>\n {/* A button, not a span: it opens a card, so it takes a pointer rather than a caret, and\n it answers the hover it has always responded to. */}\n <button\n type=\"button\"\n aria-label={ariaLabel ?? defaultLabel}\n // `shrink-0` because the ring is a fixed `size-8`: in a flex row it is the child with\n // no intrinsic content to give, so without this it is the first thing squashed by a\n // sibling that sets `shrink-0` of its own — which the design system's `Button` does.\n className={cn(\n 'tw:relative tw:inline-flex tw:size-8 tw:shrink-0 tw:items-center tw:justify-center',\n 'tw:cursor-pointer tw:rounded-full tw:border-0 tw:bg-transparent tw:p-0',\n 'tw:transition-colors tw:hover:bg-muted',\n 'tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-ring/50',\n className,\n )}\n >\n <UsageStatsRing value={value} />\n {hasAlert && (\n <AlertCircle\n data-testid=\"usage-stats-alert\"\n className={cn(\n 'tw:absolute tw:-right-0.5 tw:-top-0.5 tw:size-3',\n isWarning ? 'tw:text-warning-500' : 'tw:text-error-500',\n )}\n />\n )}\n </button>\n </HoverCard.Trigger>\n\n <HoverCard.Content align={align} side={side} sideOffset={sideOffset}>\n {children}\n </HoverCard.Content>\n </HoverCard>\n );\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { cn } from "./classNames-BzrkDnOD.js";
2
- import { Tooltip } from "./utils-DnkrFYqY.js";
2
+ import { Tooltip } from "./utils-BW4AE8VP.js";
3
3
  import { useArgoDesign } from "./context-D7X470dy.js";
4
4
  import { AlertTriangle, ChevronDown, CircleCheck, Info } from "./icons-Cek151jC.js";
5
5
  import { Collapsible } from "./Collapsible-BQXWEOBC.js";
@@ -130,4 +130,4 @@ const Alert = ({ title, variant = "info", children, hideIcon = false, icon, clas
130
130
  //#endregion
131
131
  export { Alert };
132
132
 
133
- //# sourceMappingURL=Alert-C4Y9IwMI.js.map
133
+ //# sourceMappingURL=Alert-BsIM_oFK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Alert-C4Y9IwMI.js","names":[],"sources":["../src/components/Alert/AlertAction.tsx","../src/components/Alert/AlertCollapsibleIcon.tsx","../src/components/Alert/AlertDescription.tsx","../src/components/Alert/AlertIcon.tsx","../src/components/Alert/AlertRoot.tsx","../src/components/Alert/AlertTitle.tsx","../src/components/Alert/Alert.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const AlertAction = ({ ref, className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n return (\n <Comp\n {...props}\n ref={ref}\n className={cn(\n 'tw:col-start-3',\n 'tw:row-start-1',\n 'tw:self-start',\n 'tw:flex',\n 'tw:gap-2',\n className,\n )}\n />\n );\n};\n","import { ChevronDown } from '../../icons';\nimport { cn } from '../../utils';\nimport { Tooltip } from '../Tooltip';\n\ntype Props = {\n open: boolean;\n};\n\nexport const AlertCollapsibleIcon = ({ open }: Props) => (\n <Tooltip placement=\"top\" tooltip={open ? 'Collapse alert' : 'Expand alert'} triggerAsChild>\n <ChevronDown\n className={cn(\n 'tw:mt-px',\n 'tw:size-5',\n 'tw:text-neutral-400',\n 'tw:group-data-[state=open]/alert:rotate-180',\n\n // Legacy uses the fixed categorical hover scales; argo uses the themeable status tokens.\n 'tw:group-data-[variant=info]/alert:group-hover:text-blue-600',\n 'tw:group-data-[variant=info]/alert:group-data-[argo=true]/alert:group-hover:text-info',\n 'tw:group-data-[variant=warning]/alert:group-hover:text-warning-600',\n 'tw:group-data-[variant=warning]/alert:group-data-[argo=true]/alert:group-hover:text-warning',\n 'tw:group-data-[variant=error]/alert:group-hover:text-error-600',\n 'tw:group-data-[variant=error]/alert:group-data-[argo=true]/alert:group-hover:text-destructive',\n 'tw:group-data-[variant=success]/alert:group-hover:text-green-600',\n 'tw:group-data-[variant=success]/alert:group-data-[argo=true]/alert:group-hover:text-success',\n )}\n />\n </Tooltip>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const AlertDescription = ({ ref, children, className, ...rest }: Props) => (\n <div\n {...rest}\n ref={ref}\n className={cn(\n 'tw:col-start-2',\n 'tw:group-has-[[data-slot=alert-title]]/alert:col-end-[-1]',\n\n // spacer before description when a title exists (pseudo-element so it animates with Collapsible)\n 'tw:group-has-[[data-slot=alert-title]]/alert:before:block',\n 'tw:group-has-[[data-slot=alert-title]]/alert:before:h-4',\n \"tw:group-has-[[data-slot=alert-title]]/alert:before:content-['']\",\n\n 'tw:break-anywhere',\n\n // Default size for nested Lucide icons; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n\n className,\n )}\n >\n {children}\n </div>\n);\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { AlertTriangle, CircleCheck, Info } from '../../icons';\nimport { cn } from '../../utils';\n\nimport type { Variant } from './AlertRoot';\n\nconst VARIANT_ICONS: Record<Variant, ReactNode> = {\n info: <Info />,\n warning: <AlertTriangle />,\n error: <AlertTriangle />,\n success: <CircleCheck />,\n};\n\ntype Props = {\n variant: Variant;\n icon?: ReactNode;\n} & Omit<ComponentProps<'span'>, 'children'>;\n\nexport const AlertIcon = ({ variant, icon, className, ...rest }: Props) => (\n <span\n {...rest}\n data-slot=\"alert-icon\"\n className={cn(\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:self-start',\n 'tw:p-0.5',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-4',\n // Legacy uses the fixed categorical icon scales; argo uses the themeable status tokens.\n 'tw:group-data-[variant=info]/alert:text-blue-500',\n 'tw:group-data-[variant=info]/alert:group-data-[argo=true]/alert:text-info',\n 'tw:group-data-[variant=warning]/alert:text-warning-500',\n 'tw:group-data-[variant=warning]/alert:group-data-[argo=true]/alert:text-warning',\n 'tw:group-data-[variant=error]/alert:text-error-500',\n 'tw:group-data-[variant=error]/alert:group-data-[argo=true]/alert:text-destructive',\n 'tw:group-data-[variant=success]/alert:text-green-500',\n 'tw:group-data-[variant=success]/alert:group-data-[argo=true]/alert:text-success',\n className,\n )}\n >\n {icon ?? VARIANT_ICONS[variant]}\n </span>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nexport type Variant = 'info' | 'warning' | 'error' | 'success';\n\ntype Props = {\n variant?: Variant;\n} & ComponentProps<'div'>;\n\nexport const AlertRoot = ({ ref, children, className, variant, ...rest }: Props) => {\n const renderArgo = useArgoDesign();\n return (\n <div\n {...rest}\n ref={ref}\n data-variant={variant}\n data-argo={renderArgo}\n className={cn(\n 'tw:group/alert',\n\n // layout\n 'tw:grid',\n 'tw:grid-cols-[0_1fr_auto]',\n 'tw:has-[[data-slot=alert-icon]]:grid-cols-[auto_1fr_auto]',\n 'tw:has-[[data-slot=alert-icon]]:gap-x-2',\n\n // fonts\n 'tw:text-sm',\n // Legacy keeps the fixed neutral text; argo uses the semantic foreground\n // so the alert flips with the brand's light/dark palette (the categorical\n // variant tint stays — only the text token becomes brand-aware).\n 'tw:text-neutral-800',\n 'tw:data-[argo=true]:text-foreground',\n 'tw:text-left',\n\n 'tw:p-4',\n\n // border — legacy keeps a fixed radius; argo follows the brand radius token.\n 'tw:rounded',\n 'tw:data-[argo=true]:rounded-[var(--radius-lg,0.25rem)]',\n 'tw:border',\n 'tw:border-solid',\n\n // Variant tint + border. Legacy keeps the fixed categorical scales (solid\n // pastel tint); argo uses the brand-overridable status tokens (bg at 10%,\n // border at 25%) so status re-skins with the brand. The argo tokens carry\n // AA-legible defaults, so the variant icon (AlertIcon, full-strength\n // `tw:text-<role>`) clears ≥4.5:1 on the tint in both light and dark.\n 'tw:data-[variant=info]:bg-blue-100',\n 'tw:data-[variant=info]:border-blue-200',\n 'tw:data-[variant=info]:data-[argo=true]:bg-info/10',\n 'tw:data-[variant=info]:data-[argo=true]:border-info/25',\n\n 'tw:data-[variant=warning]:bg-warning-100',\n 'tw:data-[variant=warning]:border-warning-300',\n 'tw:data-[variant=warning]:data-[argo=true]:bg-warning/10',\n 'tw:data-[variant=warning]:data-[argo=true]:border-warning/25',\n\n 'tw:data-[variant=error]:bg-error-100',\n 'tw:data-[variant=error]:border-error-200',\n 'tw:data-[variant=error]:data-[argo=true]:bg-destructive/10',\n 'tw:data-[variant=error]:data-[argo=true]:border-destructive/25',\n\n 'tw:data-[variant=success]:bg-green-100',\n 'tw:data-[variant=success]:border-green-200',\n 'tw:data-[variant=success]:data-[argo=true]:bg-success/10',\n 'tw:data-[variant=success]:data-[argo=true]:border-success/25',\n className,\n )}\n >\n {children}\n </div>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const AlertTitle = ({ ref, className, ...props }: Props) => (\n <div\n {...props}\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(\n 'tw:group/alert-title',\n 'tw:flex',\n 'tw:col-start-2',\n 'tw:font-medium',\n 'tw:items-center',\n className,\n )}\n />\n);\n","import { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\n\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport { AlertAction } from './AlertAction';\nimport { AlertCollapsibleIcon } from './AlertCollapsibleIcon';\nimport { AlertDescription } from './AlertDescription';\nimport { AlertIcon } from './AlertIcon';\nimport { AlertRoot } from './AlertRoot';\nimport { AlertTitle } from './AlertTitle';\n\ntype CommonProps = {\n hideIcon?: boolean;\n icon?: ReactNode;\n} & Pick<ComponentProps<typeof Collapsible>, 'open' | 'onOpenChange' | 'defaultOpen'> &\n Omit<ComponentProps<typeof AlertRoot>, 'children'>;\n\ntype CollapsibleProps = {\n mode: 'collapsible';\n title: ReactNode;\n children: ReactNode;\n actions?: never;\n};\n\ntype DefaultProps = {\n mode?: 'default';\n title?: ReactNode;\n children?: ReactNode;\n actions?: ReactNode;\n};\n\n/**\n * Props for `Alert`. Discriminated by `mode` — `\"default\"` renders `title` / `children` / `actions`,\n * `\"collapsible\"` requires `title` + `children` (no `actions`) and renders a collapsible disclosure.\n * `variant` (`info` | `success` | `warning` | `error`) is a categorical colour contract.\n */\ntype Props = CommonProps & (CollapsibleProps | DefaultProps);\n\n/**\n * Persistent inline banner for contextual messages tied to the page layout.\n *\n * **When to use:** a message that lives in the page (info banner, warning about a misconfiguration,\n * post-save validation summary). Use `variant` to encode meaning; pass `actions` for inline buttons.\n * `mode=\"collapsible\"` collapses long error details behind a toggle.\n * **When NOT to use:** for transient feedback (save succeeded, job started) use `toast()`; for\n * field-level validation errors use `FormGroup state=\"error\"`; for a confirmation popover use\n * `Popconfirm`.\n * **Composition:** typically rendered at the top of `PageLayout.Content` or above a form section.\n *\n * @see RECIPES.md#alert-with-action — for action-bearing alert composition\n */\nexport const Alert = ({\n title,\n variant = 'info',\n children,\n hideIcon = false,\n icon,\n className,\n actions,\n mode = 'default',\n\n // collapsible props\n defaultOpen = true,\n open: openProp,\n onOpenChange: onOpenChangeProp,\n\n ...rest\n}: Props) => {\n const isControlled = openProp !== undefined;\n\n const [innerOpen, setInnerOpen] = useState(defaultOpen);\n const open = isControlled ? openProp : innerOpen;\n const handleOpenChange = (nextOpen: boolean) => {\n if (!isControlled) {\n setInnerOpen(nextOpen);\n }\n onOpenChangeProp?.(nextOpen);\n };\n\n const isCollapsible = mode === 'collapsible' && !!title && !!children && !actions;\n\n if (isCollapsible)\n return (\n <Collapsible open={open} onOpenChange={handleOpenChange} asChild>\n <AlertRoot {...rest} variant={variant} className={className}>\n <Collapsible.Trigger\n className={cn(\n 'tailwindcss-preflight',\n 'tw:group',\n 'tw:col-span-full',\n 'tw:grid',\n 'tw:grid-cols-subgrid',\n 'tw:rounded-sm',\n 'tw:focus-visible:outline',\n 'tw:focus-visible:outline-2',\n 'tw:focus-visible:outline-ring',\n )}\n >\n {!hideIcon && <AlertIcon variant={variant} icon={icon} />}\n <AlertTitle>{title}</AlertTitle>\n <AlertCollapsibleIcon open={open} />\n </Collapsible.Trigger>\n\n <Collapsible.Content asChild>\n <AlertDescription>{children}</AlertDescription>\n </Collapsible.Content>\n </AlertRoot>\n </Collapsible>\n );\n\n return (\n <AlertRoot {...rest} variant={variant} className={className}>\n {!hideIcon && <AlertIcon variant={variant} icon={icon} />}\n {title && <AlertTitle>{title}</AlertTitle>}\n {children && <AlertDescription>{children}</AlertDescription>}\n {actions && <AlertAction>{actions}</AlertAction>}\n </AlertRoot>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Alert-BsIM_oFK.js","names":[],"sources":["../src/components/Alert/AlertAction.tsx","../src/components/Alert/AlertCollapsibleIcon.tsx","../src/components/Alert/AlertDescription.tsx","../src/components/Alert/AlertIcon.tsx","../src/components/Alert/AlertRoot.tsx","../src/components/Alert/AlertTitle.tsx","../src/components/Alert/Alert.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const AlertAction = ({ ref, className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n return (\n <Comp\n {...props}\n ref={ref}\n className={cn(\n 'tw:col-start-3',\n 'tw:row-start-1',\n 'tw:self-start',\n 'tw:flex',\n 'tw:gap-2',\n className,\n )}\n />\n );\n};\n","import { ChevronDown } from '../../icons';\nimport { cn } from '../../utils';\nimport { Tooltip } from '../Tooltip';\n\ntype Props = {\n open: boolean;\n};\n\nexport const AlertCollapsibleIcon = ({ open }: Props) => (\n <Tooltip placement=\"top\" tooltip={open ? 'Collapse alert' : 'Expand alert'} triggerAsChild>\n <ChevronDown\n className={cn(\n 'tw:mt-px',\n 'tw:size-5',\n 'tw:text-neutral-400',\n 'tw:group-data-[state=open]/alert:rotate-180',\n\n // Legacy uses the fixed categorical hover scales; argo uses the themeable status tokens.\n 'tw:group-data-[variant=info]/alert:group-hover:text-blue-600',\n 'tw:group-data-[variant=info]/alert:group-data-[argo=true]/alert:group-hover:text-info',\n 'tw:group-data-[variant=warning]/alert:group-hover:text-warning-600',\n 'tw:group-data-[variant=warning]/alert:group-data-[argo=true]/alert:group-hover:text-warning',\n 'tw:group-data-[variant=error]/alert:group-hover:text-error-600',\n 'tw:group-data-[variant=error]/alert:group-data-[argo=true]/alert:group-hover:text-destructive',\n 'tw:group-data-[variant=success]/alert:group-hover:text-green-600',\n 'tw:group-data-[variant=success]/alert:group-data-[argo=true]/alert:group-hover:text-success',\n )}\n />\n </Tooltip>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const AlertDescription = ({ ref, children, className, ...rest }: Props) => (\n <div\n {...rest}\n ref={ref}\n className={cn(\n 'tw:col-start-2',\n 'tw:group-has-[[data-slot=alert-title]]/alert:col-end-[-1]',\n\n // spacer before description when a title exists (pseudo-element so it animates with Collapsible)\n 'tw:group-has-[[data-slot=alert-title]]/alert:before:block',\n 'tw:group-has-[[data-slot=alert-title]]/alert:before:h-4',\n \"tw:group-has-[[data-slot=alert-title]]/alert:before:content-['']\",\n\n 'tw:break-anywhere',\n\n // Default size for nested Lucide icons; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n\n className,\n )}\n >\n {children}\n </div>\n);\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { AlertTriangle, CircleCheck, Info } from '../../icons';\nimport { cn } from '../../utils';\n\nimport type { Variant } from './AlertRoot';\n\nconst VARIANT_ICONS: Record<Variant, ReactNode> = {\n info: <Info />,\n warning: <AlertTriangle />,\n error: <AlertTriangle />,\n success: <CircleCheck />,\n};\n\ntype Props = {\n variant: Variant;\n icon?: ReactNode;\n} & Omit<ComponentProps<'span'>, 'children'>;\n\nexport const AlertIcon = ({ variant, icon, className, ...rest }: Props) => (\n <span\n {...rest}\n data-slot=\"alert-icon\"\n className={cn(\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:self-start',\n 'tw:p-0.5',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-4',\n // Legacy uses the fixed categorical icon scales; argo uses the themeable status tokens.\n 'tw:group-data-[variant=info]/alert:text-blue-500',\n 'tw:group-data-[variant=info]/alert:group-data-[argo=true]/alert:text-info',\n 'tw:group-data-[variant=warning]/alert:text-warning-500',\n 'tw:group-data-[variant=warning]/alert:group-data-[argo=true]/alert:text-warning',\n 'tw:group-data-[variant=error]/alert:text-error-500',\n 'tw:group-data-[variant=error]/alert:group-data-[argo=true]/alert:text-destructive',\n 'tw:group-data-[variant=success]/alert:text-green-500',\n 'tw:group-data-[variant=success]/alert:group-data-[argo=true]/alert:text-success',\n className,\n )}\n >\n {icon ?? VARIANT_ICONS[variant]}\n </span>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nexport type Variant = 'info' | 'warning' | 'error' | 'success';\n\ntype Props = {\n variant?: Variant;\n} & ComponentProps<'div'>;\n\nexport const AlertRoot = ({ ref, children, className, variant, ...rest }: Props) => {\n const renderArgo = useArgoDesign();\n return (\n <div\n {...rest}\n ref={ref}\n data-variant={variant}\n data-argo={renderArgo}\n className={cn(\n 'tw:group/alert',\n\n // layout\n 'tw:grid',\n 'tw:grid-cols-[0_1fr_auto]',\n 'tw:has-[[data-slot=alert-icon]]:grid-cols-[auto_1fr_auto]',\n 'tw:has-[[data-slot=alert-icon]]:gap-x-2',\n\n // fonts\n 'tw:text-sm',\n // Legacy keeps the fixed neutral text; argo uses the semantic foreground\n // so the alert flips with the brand's light/dark palette (the categorical\n // variant tint stays — only the text token becomes brand-aware).\n 'tw:text-neutral-800',\n 'tw:data-[argo=true]:text-foreground',\n 'tw:text-left',\n\n 'tw:p-4',\n\n // border — legacy keeps a fixed radius; argo follows the brand radius token.\n 'tw:rounded',\n 'tw:data-[argo=true]:rounded-[var(--radius-lg,0.25rem)]',\n 'tw:border',\n 'tw:border-solid',\n\n // Variant tint + border. Legacy keeps the fixed categorical scales (solid\n // pastel tint); argo uses the brand-overridable status tokens (bg at 10%,\n // border at 25%) so status re-skins with the brand. The argo tokens carry\n // AA-legible defaults, so the variant icon (AlertIcon, full-strength\n // `tw:text-<role>`) clears ≥4.5:1 on the tint in both light and dark.\n 'tw:data-[variant=info]:bg-blue-100',\n 'tw:data-[variant=info]:border-blue-200',\n 'tw:data-[variant=info]:data-[argo=true]:bg-info/10',\n 'tw:data-[variant=info]:data-[argo=true]:border-info/25',\n\n 'tw:data-[variant=warning]:bg-warning-100',\n 'tw:data-[variant=warning]:border-warning-300',\n 'tw:data-[variant=warning]:data-[argo=true]:bg-warning/10',\n 'tw:data-[variant=warning]:data-[argo=true]:border-warning/25',\n\n 'tw:data-[variant=error]:bg-error-100',\n 'tw:data-[variant=error]:border-error-200',\n 'tw:data-[variant=error]:data-[argo=true]:bg-destructive/10',\n 'tw:data-[variant=error]:data-[argo=true]:border-destructive/25',\n\n 'tw:data-[variant=success]:bg-green-100',\n 'tw:data-[variant=success]:border-green-200',\n 'tw:data-[variant=success]:data-[argo=true]:bg-success/10',\n 'tw:data-[variant=success]:data-[argo=true]:border-success/25',\n className,\n )}\n >\n {children}\n </div>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const AlertTitle = ({ ref, className, ...props }: Props) => (\n <div\n {...props}\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(\n 'tw:group/alert-title',\n 'tw:flex',\n 'tw:col-start-2',\n 'tw:font-medium',\n 'tw:items-center',\n className,\n )}\n />\n);\n","import { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\n\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport { AlertAction } from './AlertAction';\nimport { AlertCollapsibleIcon } from './AlertCollapsibleIcon';\nimport { AlertDescription } from './AlertDescription';\nimport { AlertIcon } from './AlertIcon';\nimport { AlertRoot } from './AlertRoot';\nimport { AlertTitle } from './AlertTitle';\n\ntype CommonProps = {\n hideIcon?: boolean;\n icon?: ReactNode;\n} & Pick<ComponentProps<typeof Collapsible>, 'open' | 'onOpenChange' | 'defaultOpen'> &\n Omit<ComponentProps<typeof AlertRoot>, 'children'>;\n\ntype CollapsibleProps = {\n mode: 'collapsible';\n title: ReactNode;\n children: ReactNode;\n actions?: never;\n};\n\ntype DefaultProps = {\n mode?: 'default';\n title?: ReactNode;\n children?: ReactNode;\n actions?: ReactNode;\n};\n\n/**\n * Props for `Alert`. Discriminated by `mode` — `\"default\"` renders `title` / `children` / `actions`,\n * `\"collapsible\"` requires `title` + `children` (no `actions`) and renders a collapsible disclosure.\n * `variant` (`info` | `success` | `warning` | `error`) is a categorical colour contract.\n */\ntype Props = CommonProps & (CollapsibleProps | DefaultProps);\n\n/**\n * Persistent inline banner for contextual messages tied to the page layout.\n *\n * **When to use:** a message that lives in the page (info banner, warning about a misconfiguration,\n * post-save validation summary). Use `variant` to encode meaning; pass `actions` for inline buttons.\n * `mode=\"collapsible\"` collapses long error details behind a toggle.\n * **When NOT to use:** for transient feedback (save succeeded, job started) use `toast()`; for\n * field-level validation errors use `FormGroup state=\"error\"`; for a confirmation popover use\n * `Popconfirm`.\n * **Composition:** typically rendered at the top of `PageLayout.Content` or above a form section.\n *\n * @see RECIPES.md#alert-with-action — for action-bearing alert composition\n */\nexport const Alert = ({\n title,\n variant = 'info',\n children,\n hideIcon = false,\n icon,\n className,\n actions,\n mode = 'default',\n\n // collapsible props\n defaultOpen = true,\n open: openProp,\n onOpenChange: onOpenChangeProp,\n\n ...rest\n}: Props) => {\n const isControlled = openProp !== undefined;\n\n const [innerOpen, setInnerOpen] = useState(defaultOpen);\n const open = isControlled ? openProp : innerOpen;\n const handleOpenChange = (nextOpen: boolean) => {\n if (!isControlled) {\n setInnerOpen(nextOpen);\n }\n onOpenChangeProp?.(nextOpen);\n };\n\n const isCollapsible = mode === 'collapsible' && !!title && !!children && !actions;\n\n if (isCollapsible)\n return (\n <Collapsible open={open} onOpenChange={handleOpenChange} asChild>\n <AlertRoot {...rest} variant={variant} className={className}>\n <Collapsible.Trigger\n className={cn(\n 'tailwindcss-preflight',\n 'tw:group',\n 'tw:col-span-full',\n 'tw:grid',\n 'tw:grid-cols-subgrid',\n 'tw:rounded-sm',\n 'tw:focus-visible:outline',\n 'tw:focus-visible:outline-2',\n 'tw:focus-visible:outline-ring',\n )}\n >\n {!hideIcon && <AlertIcon variant={variant} icon={icon} />}\n <AlertTitle>{title}</AlertTitle>\n <AlertCollapsibleIcon open={open} />\n </Collapsible.Trigger>\n\n <Collapsible.Content asChild>\n <AlertDescription>{children}</AlertDescription>\n </Collapsible.Content>\n </AlertRoot>\n </Collapsible>\n );\n\n return (\n <AlertRoot {...rest} variant={variant} className={className}>\n {!hideIcon && <AlertIcon variant={variant} icon={icon} />}\n {title && <AlertTitle>{title}</AlertTitle>}\n {children && <AlertDescription>{children}</AlertDescription>}\n {actions && <AlertAction>{actions}</AlertAction>}\n </AlertRoot>\n );\n};\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { Button } from "./Button-DsRrU5F1.js";
2
2
  import { ToggleGroup } from "./ToggleGroup-Cy_10Mvu.js";
3
3
  import { Label } from "./internal/components/Label.js";
4
- import { TextInput } from "./TextInput-DiEMxVF6.js";
5
- import { Slider } from "./Slider-Bv0B6lI0.js";
4
+ import { TextInput } from "./TextInput-CFTf4Cz1.js";
5
+ import { Slider } from "./Slider-DLclvRws.js";
6
6
  import { Select } from "./Select-DV3Hak_l.js";
7
7
  import { Badge } from "./Badge-o5jURtpB.js";
8
- import { ColorInput } from "./ColorInput-Dg87lKcR.js";
8
+ import { ColorInput } from "./ColorInput-Bj3dfPFA.js";
9
9
  import { Textarea } from "./internal/blocks/Textarea.js";
10
10
  import { Collapsible } from "./Collapsible-BQXWEOBC.js";
11
11
  import { useId, useMemo } from "react";
@@ -900,4 +900,4 @@ const BrandEditor = ({ value, onChange, colorScheme = "light", onColorSchemeChan
900
900
  //#endregion
901
901
  export { BrandEditor, DEFAULT_FALLBACK_FONT, DEFAULT_FONT_OPTIONS, channelsToHex, contrastRatio, hexToChannels, wcagLevel };
902
902
 
903
- //# sourceMappingURL=BrandEditor-CS9P4r2p.js.map
903
+ //# sourceMappingURL=BrandEditor-BsTBM3s6.js.map