ai-design-system 0.1.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 (290) hide show
  1. package/README.md +307 -0
  2. package/components/ai-elements/actions.tsx +65 -0
  3. package/components/ai-elements/artifact.tsx +147 -0
  4. package/components/ai-elements/branch.tsx +212 -0
  5. package/components/ai-elements/canvas.tsx +24 -0
  6. package/components/ai-elements/chain-of-thought.tsx +228 -0
  7. package/components/ai-elements/code-block.tsx +179 -0
  8. package/components/ai-elements/confirmation.tsx +169 -0
  9. package/components/ai-elements/connection.tsx +28 -0
  10. package/components/ai-elements/context.tsx +408 -0
  11. package/components/ai-elements/controls.tsx +18 -0
  12. package/components/ai-elements/conversation.tsx +97 -0
  13. package/components/ai-elements/edge.tsx +140 -0
  14. package/components/ai-elements/image.tsx +24 -0
  15. package/components/ai-elements/inline-citation.tsx +287 -0
  16. package/components/ai-elements/loader.tsx +96 -0
  17. package/components/ai-elements/message.tsx +80 -0
  18. package/components/ai-elements/node.tsx +71 -0
  19. package/components/ai-elements/open-in-chat.tsx +363 -0
  20. package/components/ai-elements/panel.tsx +15 -0
  21. package/components/ai-elements/plan.tsx +142 -0
  22. package/components/ai-elements/prompt-input.tsx +1352 -0
  23. package/components/ai-elements/queue.tsx +274 -0
  24. package/components/ai-elements/reasoning.tsx +178 -0
  25. package/components/ai-elements/response.tsx +22 -0
  26. package/components/ai-elements/shimmer.tsx +64 -0
  27. package/components/ai-elements/sources.tsx +77 -0
  28. package/components/ai-elements/suggestion.tsx +56 -0
  29. package/components/ai-elements/task.tsx +87 -0
  30. package/components/ai-elements/tool.tsx +179 -0
  31. package/components/ai-elements/toolbar.tsx +16 -0
  32. package/components/ai-elements/web-preview.tsx +263 -0
  33. package/components/blocks/AIConversation/AIConversation.stories.tsx +164 -0
  34. package/components/blocks/AIConversation/AIConversation.tsx +186 -0
  35. package/components/blocks/AIConversation/index.ts +8 -0
  36. package/components/blocks/AppSidebar/AppSidebar.stories.tsx +63 -0
  37. package/components/blocks/AppSidebar/AppSidebar.tsx +87 -0
  38. package/components/blocks/AppSidebar/index.ts +2 -0
  39. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.stories.tsx +341 -0
  40. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.tsx +255 -0
  41. package/components/blocks/DocumentEditorWithComments/index.ts +9 -0
  42. package/components/blocks/FileChangeQueue/FileChangeQueue.stories.tsx +207 -0
  43. package/components/blocks/FileChangeQueue/FileChangeQueue.tsx +143 -0
  44. package/components/blocks/FileChangeQueue/index.ts +7 -0
  45. package/components/blocks/LayoutProvider/LayoutProvider.tsx +34 -0
  46. package/components/blocks/LayoutProvider/index.ts +1 -0
  47. package/components/blocks/index.ts +2 -0
  48. package/components/composites/AgentIndicator/AgentIndicator.stories.tsx +154 -0
  49. package/components/composites/AgentIndicator/AgentIndicator.tsx +102 -0
  50. package/components/composites/AgentIndicator/index.ts +8 -0
  51. package/components/composites/AppHeader/AppHeader.stories.tsx +46 -0
  52. package/components/composites/AppHeader/AppHeader.tsx +24 -0
  53. package/components/composites/AppHeader/index.ts +2 -0
  54. package/components/composites/CommentBox/CommentBox.stories.tsx +192 -0
  55. package/components/composites/CommentBox/CommentBox.tsx +364 -0
  56. package/components/composites/CommentBox/index.ts +8 -0
  57. package/components/composites/Confirmation/Confirmation.stories.tsx +151 -0
  58. package/components/composites/Confirmation/Confirmation.tsx +93 -0
  59. package/components/composites/Confirmation/index.ts +7 -0
  60. package/components/composites/DataTable/DataTable.stories.tsx +35 -0
  61. package/components/composites/DataTable/DataTable.tsx +95 -0
  62. package/components/composites/DataTable/index.ts +2 -0
  63. package/components/composites/DocumentEditor/DocumentEditor.css +106 -0
  64. package/components/composites/DocumentEditor/DocumentEditor.stories.tsx +927 -0
  65. package/components/composites/DocumentEditor/DocumentEditor.tsx +279 -0
  66. package/components/composites/DocumentEditor/index.ts +8 -0
  67. package/components/composites/FileQueue/FileQueue.stories.tsx +175 -0
  68. package/components/composites/FileQueue/FileQueue.tsx +161 -0
  69. package/components/composites/FileQueue/FileStatusBadge.tsx +74 -0
  70. package/components/composites/FileQueue/index.ts +24 -0
  71. package/components/composites/InteractiveChart/InteractiveChart.stories.tsx +49 -0
  72. package/components/composites/InteractiveChart/InteractiveChart.tsx +69 -0
  73. package/components/composites/InteractiveChart/index.ts +2 -0
  74. package/components/composites/ModeToggle/ModeToggle.stories.tsx +212 -0
  75. package/components/composites/ModeToggle/ModeToggle.tsx +100 -0
  76. package/components/composites/ModeToggle/index.ts +7 -0
  77. package/components/composites/NavUser/NavUser.stories.tsx +50 -0
  78. package/components/composites/NavUser/NavUser.tsx +60 -0
  79. package/components/composites/NavUser/index.ts +2 -0
  80. package/components/composites/NavigationList/NavigationList.stories.tsx +46 -0
  81. package/components/composites/NavigationList/NavigationList.tsx +46 -0
  82. package/components/composites/NavigationList/index.ts +2 -0
  83. package/components/composites/OrchestratorMessage/OrchestratorMessage.stories.tsx +188 -0
  84. package/components/composites/OrchestratorMessage/OrchestratorMessage.tsx +72 -0
  85. package/components/composites/OrchestratorMessage/index.ts +8 -0
  86. package/components/composites/PageContainer/PageContainer.stories.tsx +41 -0
  87. package/components/composites/PageContainer/PageContainer.tsx +24 -0
  88. package/components/composites/PageContainer/index.ts +2 -0
  89. package/components/composites/PromptInput/PromptInput.stories.tsx +200 -0
  90. package/components/composites/PromptInput/PromptInput.tsx +129 -0
  91. package/components/composites/PromptInput/index.ts +8 -0
  92. package/components/composites/SpecialistMessage/SpecialistMessage.stories.tsx +286 -0
  93. package/components/composites/SpecialistMessage/SpecialistMessage.tsx +107 -0
  94. package/components/composites/SpecialistMessage/index.ts +8 -0
  95. package/components/composites/StatsCard/StatsCard.stories.tsx +76 -0
  96. package/components/composites/StatsCard/StatsCard.tsx +81 -0
  97. package/components/composites/StatsCard/index.ts +2 -0
  98. package/components/composites/TablePagination/TablePagination.stories.tsx +38 -0
  99. package/components/composites/TablePagination/TablePagination.tsx +119 -0
  100. package/components/composites/TablePagination/index.ts +2 -0
  101. package/components/composites/TableToolbar/TableToolbar.stories.tsx +60 -0
  102. package/components/composites/TableToolbar/TableToolbar.tsx +66 -0
  103. package/components/composites/TableToolbar/index.ts +2 -0
  104. package/components/composites/ThemeSelector/ThemeSelector.stories.tsx +48 -0
  105. package/components/composites/ThemeSelector/ThemeSelector.tsx +79 -0
  106. package/components/composites/ThemeSelector/index.ts +2 -0
  107. package/components/composites/ToolCallDisplay/ToolCallDisplay.stories.tsx +49 -0
  108. package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +108 -0
  109. package/components/composites/ToolCallDisplay/index.ts +8 -0
  110. package/components/composites/UserMessage/UserMessage.stories.tsx +59 -0
  111. package/components/composites/UserMessage/UserMessage.tsx +52 -0
  112. package/components/composites/UserMessage/index.ts +8 -0
  113. package/components/composites/index.ts +90 -0
  114. package/components/features/AIDocEditor/AIDocEditor.behaviors.stories.tsx +451 -0
  115. package/components/features/AIDocEditor/AIDocEditor.mocks.ts +96 -0
  116. package/components/features/AIDocEditor/AIDocEditor.stories.tsx +140 -0
  117. package/components/features/AIDocEditor/AIDocEditor.tsx +130 -0
  118. package/components/features/AIDocEditor/index.ts +8 -0
  119. package/components/features/AIDocEditor/useAIDocEditor.d.ts +97 -0
  120. package/components/features/AIDocEditor/useAIDocEditor.mock.ts +83 -0
  121. package/components/features/PageLayout/PageLayout.behaviors.stories.tsx +119 -0
  122. package/components/features/PageLayout/PageLayout.mocks.ts +27 -0
  123. package/components/features/PageLayout/PageLayout.stories.tsx +142 -0
  124. package/components/features/PageLayout/PageLayout.tsx +94 -0
  125. package/components/features/PageLayout/index.ts +4 -0
  126. package/components/features/PageLayout/usePageLayout.d.ts +24 -0
  127. package/components/features/PageLayout/usePageLayout.mock.ts +19 -0
  128. package/components/features/RefinementPanel/README.md +189 -0
  129. package/components/features/RefinementPanel/RefinementPanel.behaviors.stories.tsx +475 -0
  130. package/components/features/RefinementPanel/RefinementPanel.mocks.ts +131 -0
  131. package/components/features/RefinementPanel/RefinementPanel.stories.tsx +141 -0
  132. package/components/features/RefinementPanel/RefinementPanel.tsx +160 -0
  133. package/components/features/RefinementPanel/index.ts +25 -0
  134. package/components/features/RefinementPanel/useRefinementPanel.d.ts +74 -0
  135. package/components/features/RefinementPanel/useRefinementPanel.mock.ts +121 -0
  136. package/components/features/SpecNavigator/SpecNavigator.behaviors.stories.tsx +379 -0
  137. package/components/features/SpecNavigator/SpecNavigator.mocks.ts +131 -0
  138. package/components/features/SpecNavigator/SpecNavigator.stories.tsx +122 -0
  139. package/components/features/SpecNavigator/SpecNavigator.tsx +43 -0
  140. package/components/features/SpecNavigator/index.ts +2 -0
  141. package/components/features/SpecNavigator/useSpecNavigator.d.ts +122 -0
  142. package/components/features/SpecNavigator/useSpecNavigator.mock.ts +93 -0
  143. package/components/features/index.ts +18 -0
  144. package/components/index.ts +14 -0
  145. package/components/primitives/Accordion/Accordion.stories.tsx +87 -0
  146. package/components/primitives/Accordion/Accordion.tsx +66 -0
  147. package/components/primitives/Accordion/index.ts +13 -0
  148. package/components/primitives/Alert/Alert.stories.tsx +422 -0
  149. package/components/primitives/Alert/Alert.tsx +61 -0
  150. package/components/primitives/Alert/index.ts +8 -0
  151. package/components/primitives/AlertDialog/AlertDialog.stories.tsx +367 -0
  152. package/components/primitives/AlertDialog/AlertDialog.tsx +182 -0
  153. package/components/primitives/AlertDialog/index.ts +25 -0
  154. package/components/primitives/Avatar/Avatar.stories.tsx +321 -0
  155. package/components/primitives/Avatar/Avatar.tsx +63 -0
  156. package/components/primitives/Avatar/index.ts +8 -0
  157. package/components/primitives/Badge/Badge.stories.tsx +74 -0
  158. package/components/primitives/Badge/Badge.tsx +49 -0
  159. package/components/primitives/Badge/index.ts +2 -0
  160. package/components/primitives/Button/Button.stories.tsx +445 -0
  161. package/components/primitives/Button/Button.tsx +89 -0
  162. package/components/primitives/Button/index.ts +7 -0
  163. package/components/primitives/Card/Card.stories.tsx +831 -0
  164. package/components/primitives/Card/Card.tsx +242 -0
  165. package/components/primitives/Card/index.ts +30 -0
  166. package/components/primitives/Carousel/Carousel.stories.tsx +32 -0
  167. package/components/primitives/Carousel/Carousel.tsx +63 -0
  168. package/components/primitives/Carousel/index.ts +13 -0
  169. package/components/primitives/Chart/Chart.stories.tsx +346 -0
  170. package/components/primitives/Chart/Chart.tsx +117 -0
  171. package/components/primitives/Chart/index.ts +20 -0
  172. package/components/primitives/Checkbox/Checkbox.stories.tsx +87 -0
  173. package/components/primitives/Checkbox/Checkbox.tsx +38 -0
  174. package/components/primitives/Checkbox/index.ts +2 -0
  175. package/components/primitives/Collapsible/Collapsible.stories.tsx +38 -0
  176. package/components/primitives/Collapsible/Collapsible.tsx +39 -0
  177. package/components/primitives/Collapsible/index.ts +8 -0
  178. package/components/primitives/Command/Command.stories.tsx +150 -0
  179. package/components/primitives/Command/Command.tsx +147 -0
  180. package/components/primitives/Command/index.ts +20 -0
  181. package/components/primitives/Dialog/Dialog.stories.tsx +390 -0
  182. package/components/primitives/Dialog/Dialog.tsx +140 -0
  183. package/components/primitives/Dialog/index.ts +22 -0
  184. package/components/primitives/Drawer/Drawer.stories.tsx +327 -0
  185. package/components/primitives/Drawer/Drawer.tsx +208 -0
  186. package/components/primitives/Drawer/index.ts +27 -0
  187. package/components/primitives/DropdownMenu/DropdownMenu.stories.tsx +150 -0
  188. package/components/primitives/DropdownMenu/DropdownMenu.tsx +73 -0
  189. package/components/primitives/DropdownMenu/index.ts +1 -0
  190. package/components/primitives/HoverCard/HoverCard.stories.tsx +26 -0
  191. package/components/primitives/HoverCard/HoverCard.tsx +39 -0
  192. package/components/primitives/HoverCard/index.ts +8 -0
  193. package/components/primitives/Icon/Icon.stories.tsx +281 -0
  194. package/components/primitives/Icon/Icon.tsx +87 -0
  195. package/components/primitives/Icon/index.ts +8 -0
  196. package/components/primitives/Input/Input.stories.tsx +370 -0
  197. package/components/primitives/Input/Input.tsx +88 -0
  198. package/components/primitives/Input/index.ts +7 -0
  199. package/components/primitives/InputGroup/InputGroup.stories.tsx +40 -0
  200. package/components/primitives/InputGroup/InputGroup.tsx +72 -0
  201. package/components/primitives/InputGroup/index.ts +14 -0
  202. package/components/primitives/Label/Label.stories.tsx +227 -0
  203. package/components/primitives/Label/Label.tsx +53 -0
  204. package/components/primitives/Label/index.ts +7 -0
  205. package/components/primitives/Popover/Popover.stories.tsx +42 -0
  206. package/components/primitives/Popover/Popover.tsx +107 -0
  207. package/components/primitives/Popover/index.ts +2 -0
  208. package/components/primitives/Progress/Progress.stories.tsx +340 -0
  209. package/components/primitives/Progress/Progress.tsx +31 -0
  210. package/components/primitives/Progress/index.ts +1 -0
  211. package/components/primitives/ScrollArea/ScrollArea.stories.tsx +26 -0
  212. package/components/primitives/ScrollArea/ScrollArea.tsx +28 -0
  213. package/components/primitives/ScrollArea/index.ts +6 -0
  214. package/components/primitives/Select/Select.stories.tsx +288 -0
  215. package/components/primitives/Select/Select.tsx +162 -0
  216. package/components/primitives/Select/index.ts +22 -0
  217. package/components/primitives/Separator/Separator.stories.tsx +264 -0
  218. package/components/primitives/Separator/Separator.tsx +48 -0
  219. package/components/primitives/Separator/index.ts +7 -0
  220. package/components/primitives/Sidebar/Sidebar.stories.tsx +358 -0
  221. package/components/primitives/Sidebar/Sidebar.tsx +317 -0
  222. package/components/primitives/Sidebar/index.ts +41 -0
  223. package/components/primitives/Table/Table.stories.tsx +389 -0
  224. package/components/primitives/Table/Table.tsx +191 -0
  225. package/components/primitives/Table/index.ts +26 -0
  226. package/components/primitives/Tabs/Tabs.stories.tsx +129 -0
  227. package/components/primitives/Tabs/Tabs.tsx +70 -0
  228. package/components/primitives/Tabs/index.ts +13 -0
  229. package/components/primitives/Textarea/Textarea.stories.tsx +358 -0
  230. package/components/primitives/Textarea/Textarea.tsx +91 -0
  231. package/components/primitives/Textarea/index.ts +7 -0
  232. package/components/primitives/ToggleGroup/ToggleGroup.stories.tsx +87 -0
  233. package/components/primitives/ToggleGroup/ToggleGroup.tsx +52 -0
  234. package/components/primitives/ToggleGroup/index.ts +6 -0
  235. package/components/primitives/Tooltip/Tooltip.stories.tsx +336 -0
  236. package/components/primitives/Tooltip/Tooltip.tsx +78 -0
  237. package/components/primitives/Tooltip/index.ts +10 -0
  238. package/components/primitives/index.ts +34 -0
  239. package/components/ui/accordion.tsx +66 -0
  240. package/components/ui/alert-dialog.tsx +157 -0
  241. package/components/ui/alert.tsx +66 -0
  242. package/components/ui/avatar.tsx +53 -0
  243. package/components/ui/badge.tsx +46 -0
  244. package/components/ui/button.tsx +60 -0
  245. package/components/ui/card.tsx +117 -0
  246. package/components/ui/carousel.tsx +241 -0
  247. package/components/ui/chart.tsx +334 -0
  248. package/components/ui/checkbox.tsx +32 -0
  249. package/components/ui/collapsible.tsx +33 -0
  250. package/components/ui/command.tsx +184 -0
  251. package/components/ui/dialog.tsx +143 -0
  252. package/components/ui/drawer.tsx +118 -0
  253. package/components/ui/dropdown-menu.tsx +257 -0
  254. package/components/ui/hover-card.tsx +44 -0
  255. package/components/ui/input-group.tsx +170 -0
  256. package/components/ui/input.tsx +48 -0
  257. package/components/ui/label.tsx +26 -0
  258. package/components/ui/popover.tsx +33 -0
  259. package/components/ui/progress.tsx +31 -0
  260. package/components/ui/scroll-area.tsx +58 -0
  261. package/components/ui/select.tsx +187 -0
  262. package/components/ui/separator.tsx +31 -0
  263. package/components/ui/sidebar.tsx +577 -0
  264. package/components/ui/table.tsx +120 -0
  265. package/components/ui/tabs.tsx +66 -0
  266. package/components/ui/textarea.tsx +46 -0
  267. package/components/ui/toggle-group.tsx +83 -0
  268. package/components/ui/toggle.tsx +47 -0
  269. package/components/ui/tooltip.tsx +61 -0
  270. package/dist/index.cjs +7389 -0
  271. package/dist/index.cjs.map +1 -0
  272. package/dist/index.css +75 -0
  273. package/dist/index.css.map +1 -0
  274. package/dist/index.js +7160 -0
  275. package/dist/index.js.map +1 -0
  276. package/hooks/useAIDocReviewer.d.ts +0 -0
  277. package/lib/utils.ts +6 -0
  278. package/package.json +140 -0
  279. package/tokens/color/base.json +14 -0
  280. package/tokens/color/dark.json +40 -0
  281. package/tokens/color/green.json +21 -0
  282. package/tokens/color/light.json +52 -0
  283. package/tokens/color/neutral.json +20 -0
  284. package/tokens/color/violet.json +21 -0
  285. package/tokens/spacing.json +22 -0
  286. package/utils/ai-editor/format-date.ts +41 -0
  287. package/utils/ai-editor/index.ts +22 -0
  288. package/utils/ai-editor/type-guards.ts +72 -0
  289. package/utils/ai-editor/validation.ts +130 -0
  290. package/utils/editor-annotations.ts +122 -0
@@ -0,0 +1,475 @@
1
+ /**
2
+ * RefinementPanel Behavior Tests
3
+ *
4
+ * Tests user interactions and state changes to prevent regressions.
5
+ * These tests validate functionality, not visual appearance.
6
+ */
7
+
8
+ import type { Meta, StoryObj } from '@storybook/react'
9
+ import { expect, fn, userEvent, within, waitFor, screen } from '@storybook/test'
10
+ import { RefinementPanel } from './RefinementPanel'
11
+ import { inputStateMessages, reviewStateMessages, sampleFileChanges } from './RefinementPanel.mocks'
12
+
13
+ const meta: Meta<typeof RefinementPanel> = {
14
+ title: 'Features/RefinementPanel/Behaviors',
15
+ component: RefinementPanel,
16
+ tags: ['test'],
17
+ parameters: {
18
+ layout: 'fullscreen',
19
+ },
20
+ }
21
+
22
+ export default meta
23
+ type Story = StoryObj<typeof RefinementPanel>
24
+
25
+ // ============================================================================
26
+ // CRITICAL PRIORITY TESTS (100% coverage required)
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Test: Submit message triggers callback
31
+ * Verifies that typing and submitting a message calls onSubmit with correct data
32
+ */
33
+ export const SubmitMessageTriggersCallback: Story = {
34
+ args: {
35
+ messages: inputStateMessages,
36
+ onSubmit: fn(),
37
+ placeholder: 'Ask a question or describe a task...',
38
+ },
39
+ play: async ({ canvasElement, args }) => {
40
+ const canvas = within(canvasElement)
41
+
42
+ // Find the input textarea
43
+ const textarea = canvas.getByPlaceholderText('Ask a question or describe a task...')
44
+ expect(textarea).toBeInTheDocument()
45
+
46
+ // Type a message
47
+ await userEvent.type(textarea, 'Please add error handling to the API calls')
48
+
49
+ // Submit the form (find submit button or press Enter)
50
+ const submitButton = canvas.getByRole('button', { name: /send|submit/i })
51
+ await userEvent.click(submitButton)
52
+
53
+ // Verify onSubmit was called
54
+ await waitFor(() => {
55
+ expect(args.onSubmit).toHaveBeenCalled()
56
+ })
57
+
58
+ // Verify the message content
59
+ const calls = (args.onSubmit as ReturnType<typeof fn>).mock.calls
60
+ expect(calls.length).toBeGreaterThan(0)
61
+ const submittedMessage = calls[0][0]
62
+ expect(submittedMessage.text).toBe('Please add error handling to the API calls')
63
+ },
64
+ }
65
+
66
+ /**
67
+ * Test: Approve button triggers callback
68
+ * Verifies that clicking approve button calls onApprove
69
+ */
70
+ export const ApproveButtonTriggersCallback: Story = {
71
+ args: {
72
+ messages: reviewStateMessages,
73
+ fileChanges: sampleFileChanges,
74
+ onSubmit: fn(),
75
+ onApprove: fn(),
76
+ onReject: fn(),
77
+ },
78
+ play: async ({ canvasElement, args }) => {
79
+ const canvas = within(canvasElement)
80
+
81
+ // Wait for file changes to render
82
+ await waitFor(() => {
83
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
84
+ })
85
+
86
+ // Find and click approve button
87
+ const approveButton = canvas.getByRole('button', { name: /approve|accept/i })
88
+ await userEvent.click(approveButton)
89
+
90
+ // Verify onApprove was called
91
+ await waitFor(() => {
92
+ expect(args.onApprove).toHaveBeenCalled()
93
+ })
94
+ },
95
+ }
96
+
97
+ /**
98
+ * Test: Reject button triggers callback
99
+ * Verifies that clicking reject button calls onReject
100
+ */
101
+ export const RejectButtonTriggersCallback: Story = {
102
+ args: {
103
+ messages: reviewStateMessages,
104
+ fileChanges: sampleFileChanges,
105
+ onSubmit: fn(),
106
+ onApprove: fn(),
107
+ onReject: fn(),
108
+ },
109
+ play: async ({ canvasElement, args }) => {
110
+ const canvas = within(canvasElement)
111
+
112
+ // Wait for file changes to render
113
+ await waitFor(() => {
114
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
115
+ })
116
+
117
+ // Find and click reject button
118
+ const rejectButton = canvas.getByRole('button', { name: /reject|decline/i })
119
+ await userEvent.click(rejectButton)
120
+
121
+ // Verify onReject was called
122
+ await waitFor(() => {
123
+ expect(args.onReject).toHaveBeenCalled()
124
+ })
125
+ },
126
+ }
127
+
128
+ /**
129
+ * Test: Messages display correctly
130
+ * Verifies that all messages render with correct content and avatars
131
+ */
132
+ export const MessagesDisplayCorrectly: Story = {
133
+ args: {
134
+ messages: reviewStateMessages,
135
+ onSubmit: fn(),
136
+ },
137
+ play: async ({ canvasElement }) => {
138
+ const canvas = within(canvasElement)
139
+
140
+ // Verify user message is displayed
141
+ await waitFor(() => {
142
+ expect(canvas.getByText(/Refine the Button component/i)).toBeInTheDocument()
143
+ })
144
+
145
+ // Verify orchestrator message is displayed
146
+ expect(canvas.getByText(/coordinate the refinement/i)).toBeInTheDocument()
147
+
148
+ // Verify avatars are present (check for img elements with avatar sources)
149
+ const avatars = canvas.getAllByRole('img')
150
+ expect(avatars.length).toBeGreaterThan(0)
151
+ },
152
+ }
153
+
154
+ // ============================================================================
155
+ // HIGH PRIORITY TESTS (90% coverage required)
156
+ // ============================================================================
157
+
158
+ /**
159
+ * Test: File changes display when provided
160
+ * Verifies that FileChangeQueue is visible when fileChanges are provided
161
+ */
162
+ export const FileChangesDisplayWhenProvided: Story = {
163
+ args: {
164
+ messages: reviewStateMessages,
165
+ fileChanges: sampleFileChanges,
166
+ onSubmit: fn(),
167
+ onApprove: fn(),
168
+ onReject: fn(),
169
+ },
170
+ play: async ({ canvasElement }) => {
171
+ const canvas = within(canvasElement)
172
+
173
+ // Verify file change queue is visible
174
+ await waitFor(() => {
175
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
176
+ })
177
+
178
+ // Verify file names are displayed
179
+ expect(canvas.getByText(/Button\.tsx/i)).toBeInTheDocument()
180
+ expect(canvas.getByText(/Button\.stories\.tsx/i)).toBeInTheDocument()
181
+ expect(canvas.getByText(/button-accessibility\.test\.tsx/i)).toBeInTheDocument()
182
+ },
183
+ }
184
+
185
+ /**
186
+ * Test: Input hidden when file changes present
187
+ * Verifies that PromptInput is hidden when file changes are present
188
+ */
189
+ export const InputHiddenWhenFileChangesPresent: Story = {
190
+ args: {
191
+ messages: reviewStateMessages,
192
+ fileChanges: sampleFileChanges,
193
+ onSubmit: fn(),
194
+ onApprove: fn(),
195
+ onReject: fn(),
196
+ placeholder: 'Ask a question or describe a task...',
197
+ },
198
+ play: async ({ canvasElement }) => {
199
+ const canvas = within(canvasElement)
200
+
201
+ // Wait for file changes to render
202
+ await waitFor(() => {
203
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
204
+ })
205
+
206
+ // Verify input is not visible
207
+ const textarea = canvas.queryByPlaceholderText('Ask a question or describe a task...')
208
+ expect(textarea).not.toBeInTheDocument()
209
+ },
210
+ }
211
+
212
+ /**
213
+ * Test: Input visible when no file changes
214
+ * Verifies that PromptInput is visible when no file changes are provided
215
+ */
216
+ export const InputVisibleWhenNoFileChanges: Story = {
217
+ args: {
218
+ messages: inputStateMessages,
219
+ fileChanges: [],
220
+ onSubmit: fn(),
221
+ placeholder: 'Ask a question or describe a task...',
222
+ },
223
+ play: async ({ canvasElement }) => {
224
+ const canvas = within(canvasElement)
225
+
226
+ // Verify input is visible
227
+ const textarea = canvas.getByPlaceholderText('Ask a question or describe a task...')
228
+ expect(textarea).toBeInTheDocument()
229
+ expect(textarea).toBeVisible()
230
+ },
231
+ }
232
+
233
+ // ============================================================================
234
+ // MEDIUM PRIORITY TESTS (75% coverage required)
235
+ // ============================================================================
236
+
237
+ /**
238
+ * Test: Conversation scrolling behavior
239
+ * Verifies that conversation area handles scrolling with many messages
240
+ */
241
+ export const ConversationScrollingBehavior: Story = {
242
+ args: {
243
+ messages: [
244
+ ...inputStateMessages,
245
+ ...reviewStateMessages,
246
+ {
247
+ id: '3',
248
+ type: 'human',
249
+ role: 'user',
250
+ content: 'Additional message 1',
251
+ },
252
+ {
253
+ id: '4',
254
+ type: 'ai',
255
+ role: 'orchestrator',
256
+ content: 'Response 1',
257
+ },
258
+ {
259
+ id: '5',
260
+ type: 'human',
261
+ role: 'user',
262
+ content: 'Additional message 2',
263
+ },
264
+ {
265
+ id: '6',
266
+ type: 'ai',
267
+ role: 'orchestrator',
268
+ content: 'Response 2',
269
+ },
270
+ ],
271
+ onSubmit: fn(),
272
+ },
273
+ play: async ({ canvasElement }) => {
274
+ const canvas = within(canvasElement)
275
+
276
+ // Verify multiple messages are rendered
277
+ await waitFor(() => {
278
+ expect(canvas.getByText(/Can you help me refactor/i)).toBeInTheDocument()
279
+ })
280
+
281
+ expect(canvas.getByText(/Refine the Button component/i)).toBeInTheDocument()
282
+ expect(canvas.getByText(/Additional message 1/i)).toBeInTheDocument()
283
+ expect(canvas.getByText(/Additional message 2/i)).toBeInTheDocument()
284
+
285
+ // Verify conversation area exists and is scrollable
286
+ // The AIConversation component should handle scroll internally
287
+ const messages = canvas.getAllByText(/message|refactor|refine/i)
288
+ expect(messages.length).toBeGreaterThan(4)
289
+ },
290
+ }
291
+
292
+ /**
293
+ * Test: File change queue scrolling
294
+ * Verifies that file change queue scrolls correctly with many files
295
+ */
296
+ export const FileChangeQueueScrolling: Story = {
297
+ args: {
298
+ messages: reviewStateMessages,
299
+ fileChanges: [
300
+ ...sampleFileChanges,
301
+ {
302
+ id: '4',
303
+ filename: 'Button.test.tsx',
304
+ status: 'modified',
305
+ path: 'src/components/primitives/Button/Button.test.tsx',
306
+ },
307
+ {
308
+ id: '5',
309
+ filename: 'Button.types.ts',
310
+ status: 'created',
311
+ path: 'src/components/primitives/Button/Button.types.ts',
312
+ },
313
+ {
314
+ id: '6',
315
+ filename: 'Button.utils.ts',
316
+ status: 'created',
317
+ path: 'src/components/primitives/Button/Button.utils.ts',
318
+ },
319
+ ],
320
+ onSubmit: fn(),
321
+ onApprove: fn(),
322
+ onReject: fn(),
323
+ },
324
+ play: async ({ canvasElement }) => {
325
+ const canvas = within(canvasElement)
326
+
327
+ // Verify file change queue is visible
328
+ await waitFor(() => {
329
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
330
+ })
331
+
332
+ // Verify multiple files are displayed
333
+ expect(canvas.getByText(/Button\.tsx/i)).toBeInTheDocument()
334
+ expect(canvas.getByText(/Button\.test\.tsx/i)).toBeInTheDocument()
335
+ expect(canvas.getByText(/Button\.types\.ts/i)).toBeInTheDocument()
336
+
337
+ // The file change queue should have max-h-[40vh] and overflow-y-auto
338
+ // This is handled by the component's styling
339
+ },
340
+ }
341
+
342
+ /**
343
+ * Test: Avatar display correctly
344
+ * Verifies that avatars display for messages with avatarSrc
345
+ */
346
+ export const AvatarDisplayCorrectly: Story = {
347
+ args: {
348
+ messages: inputStateMessages,
349
+ onSubmit: fn(),
350
+ },
351
+ play: async ({ canvasElement }) => {
352
+ const canvas = within(canvasElement)
353
+
354
+ // Wait for messages to render
355
+ await waitFor(() => {
356
+ expect(canvas.getByText(/Can you help me refactor/i)).toBeInTheDocument()
357
+ })
358
+
359
+ // Verify avatars are present
360
+ const avatars = canvas.getAllByRole('img')
361
+ expect(avatars.length).toBeGreaterThan(0)
362
+
363
+ // Verify avatar sources are set (check for unsplash URLs)
364
+ const firstAvatar = avatars[0] as HTMLImageElement
365
+ expect(firstAvatar.src).toContain('unsplash')
366
+ },
367
+ }
368
+
369
+ // ============================================================================
370
+ // EDGE CASE TESTS (60% coverage required)
371
+ // ============================================================================
372
+
373
+ /**
374
+ * Test: Empty message submission prevented
375
+ * Verifies that empty messages cannot be submitted
376
+ */
377
+ export const EmptyMessageSubmissionPrevented: Story = {
378
+ args: {
379
+ messages: inputStateMessages,
380
+ onSubmit: fn(),
381
+ placeholder: 'Ask a question or describe a task...',
382
+ },
383
+ play: async ({ canvasElement, args }) => {
384
+ const canvas = within(canvasElement)
385
+
386
+ // Find the input textarea
387
+ const textarea = canvas.getByPlaceholderText('Ask a question or describe a task...')
388
+
389
+ // Try to submit without typing anything
390
+ const submitButton = canvas.getByRole('button', { name: /send|submit/i })
391
+
392
+ // Check if button is disabled or click doesn't trigger callback
393
+ const isDisabled = submitButton.hasAttribute('disabled')
394
+
395
+ if (!isDisabled) {
396
+ await userEvent.click(submitButton)
397
+
398
+ // Verify onSubmit was NOT called (empty submission prevented)
399
+ expect(args.onSubmit).not.toHaveBeenCalled()
400
+ } else {
401
+ // Button is disabled, which is also valid prevention
402
+ expect(isDisabled).toBe(true)
403
+ }
404
+ },
405
+ }
406
+
407
+ /**
408
+ * Test: Rapid approve/reject clicks
409
+ * Verifies that UI remains stable with rapid button clicks
410
+ */
411
+ export const RapidApproveRejectClicks: Story = {
412
+ args: {
413
+ messages: reviewStateMessages,
414
+ fileChanges: sampleFileChanges,
415
+ onSubmit: fn(),
416
+ onApprove: fn(),
417
+ onReject: fn(),
418
+ },
419
+ play: async ({ canvasElement, args }) => {
420
+ const canvas = within(canvasElement)
421
+
422
+ // Wait for file changes to render
423
+ await waitFor(() => {
424
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
425
+ })
426
+
427
+ // Find approve button
428
+ const approveButton = canvas.getByRole('button', { name: /approve|accept/i })
429
+
430
+ // Click multiple times rapidly
431
+ await userEvent.click(approveButton)
432
+ await userEvent.click(approveButton)
433
+ await userEvent.click(approveButton)
434
+
435
+ // Verify onApprove was called (at least once)
436
+ await waitFor(() => {
437
+ expect(args.onApprove).toHaveBeenCalled()
438
+ })
439
+
440
+ // Verify UI is still stable (no crashes)
441
+ expect(canvas.getByText(/Review and approve these file changes/i)).toBeInTheDocument()
442
+ },
443
+ }
444
+
445
+ /**
446
+ * Test: Long message content handled
447
+ * Verifies that very long messages display correctly
448
+ */
449
+ export const LongMessageContentHandled: Story = {
450
+ args: {
451
+ messages: [
452
+ {
453
+ id: '1',
454
+ type: 'human',
455
+ role: 'user',
456
+ content: 'This is a very long message that contains a lot of text to test how the component handles long content. '.repeat(10),
457
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
458
+ avatarName: 'User',
459
+ },
460
+ ],
461
+ onSubmit: fn(),
462
+ },
463
+ play: async ({ canvasElement }) => {
464
+ const canvas = within(canvasElement)
465
+
466
+ // Verify long message is rendered
467
+ await waitFor(() => {
468
+ expect(canvas.getByText(/This is a very long message/i)).toBeInTheDocument()
469
+ })
470
+
471
+ // Verify the message is visible and doesn't break layout
472
+ const messageText = canvas.getByText(/This is a very long message/i)
473
+ expect(messageText).toBeVisible()
474
+ },
475
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Mock data for RefinementPanel stories and tests
3
+ *
4
+ * This file contains reusable mock data that can be imported by:
5
+ * - RefinementPanel.stories.tsx (regular stories)
6
+ * - RefinementPanel.behaviors.stories.tsx (behavior tests)
7
+ * - Any other test files that need RefinementPanel mock data
8
+ */
9
+
10
+ import type { RefinementMessage } from './RefinementPanel'
11
+ import type { FileChangeData } from '@/components/composites/FileQueue'
12
+
13
+ /**
14
+ * Sample conversation history for input state
15
+ */
16
+ export const inputStateMessages: RefinementMessage[] = [
17
+ {
18
+ id: '1',
19
+ type: 'human',
20
+ role: 'user',
21
+ content: 'Can you help me refactor this component to use TypeScript?',
22
+ avatarSrc:
23
+ 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
24
+ avatarName: 'User',
25
+ },
26
+ {
27
+ id: '2',
28
+ type: 'ai',
29
+ role: 'orchestrator',
30
+ content:
31
+ "I'll help you refactor the component to TypeScript. Let me analyze the code and create a plan.",
32
+ avatarSrc:
33
+ 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=32&h=32&fit=crop&crop=face',
34
+ avatarName: 'Coordinator',
35
+ toolCalls: [
36
+ {
37
+ id: 'tool_1',
38
+ name: 'read_file',
39
+ args: { filename: 'Component.jsx' },
40
+ result: 'File read successfully',
41
+ status: 'completed',
42
+ },
43
+ ],
44
+ },
45
+ ]
46
+
47
+ /**
48
+ * Sample messages for multi-agent review state
49
+ */
50
+ export const reviewStateMessages: RefinementMessage[] = [
51
+ {
52
+ id: '1',
53
+ type: 'human',
54
+ role: 'user',
55
+ content: 'Refine the Button component to add better accessibility support',
56
+ avatarSrc:
57
+ 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
58
+ avatarName: 'User',
59
+ },
60
+ {
61
+ id: '2',
62
+ type: 'ai',
63
+ role: 'orchestrator',
64
+ content:
65
+ "I'll coordinate the refinement of the Button component with accessibility improvements. Let me delegate this to specialized agents.",
66
+ avatarSrc:
67
+ 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=32&h=32&fit=crop&crop=face',
68
+ avatarName: 'Coordinator',
69
+ toolCalls: [
70
+ {
71
+ id: 'tool_1',
72
+ name: 'read_file',
73
+ args: { filename: 'Button.tsx', path: 'src/components/primitives/Button/' },
74
+ result: 'File content retrieved',
75
+ status: 'completed',
76
+ },
77
+ {
78
+ id: 'tool_2',
79
+ name: 'analyze_accessibility',
80
+ args: { component: 'Button', standards: ['WCAG 2.1 AA'] },
81
+ result: 'Analysis complete',
82
+ status: 'completed',
83
+ },
84
+ ],
85
+ subAgents: [
86
+ {
87
+ id: 'agent_1',
88
+ name: 'accessibility-specialist',
89
+ subAgentName: 'a11y-agent',
90
+ input:
91
+ 'Review Button component for WCAG 2.1 Level AA compliance. Check keyboard navigation, ARIA attributes, focus management, and screen reader support.',
92
+ output:
93
+ 'Found 3 accessibility issues: missing aria-label for icon-only buttons, insufficient focus indicators, and missing keyboard shortcuts documentation.',
94
+ status: 'completed',
95
+ },
96
+ {
97
+ id: 'agent_2',
98
+ name: 'code-refactor-specialist',
99
+ subAgentName: 'refactor-agent',
100
+ input:
101
+ 'Refactor Button component to add proper ARIA attributes, enhance focus styles, and improve keyboard navigation support.',
102
+ output: undefined,
103
+ status: 'active',
104
+ },
105
+ ],
106
+ },
107
+ ]
108
+
109
+ /**
110
+ * Sample file changes for review state
111
+ */
112
+ export const sampleFileChanges: FileChangeData[] = [
113
+ {
114
+ id: '1',
115
+ filename: 'Button.tsx',
116
+ status: 'modified',
117
+ path: 'src/components/primitives/Button/Button.tsx',
118
+ },
119
+ {
120
+ id: '2',
121
+ filename: 'Button.stories.tsx',
122
+ status: 'modified',
123
+ path: 'src/components/primitives/Button/Button.stories.tsx',
124
+ },
125
+ {
126
+ id: '3',
127
+ filename: 'button-accessibility.test.tsx',
128
+ status: 'created',
129
+ path: 'src/components/primitives/Button/button-accessibility.test.tsx',
130
+ },
131
+ ]