@slipstream-ui/ai 0.0.0-stage → 0.3.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 (111) hide show
  1. package/LICENSE +25 -0
  2. package/dist/index.d.mts +579 -0
  3. package/dist/index.d.ts +579 -0
  4. package/dist/index.js +1778 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +1706 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/manifests/attachment.manifest.json +33 -0
  9. package/dist/manifests/branch.manifest.json +65 -0
  10. package/dist/manifests/chain-thought.manifest.json +39 -0
  11. package/dist/manifests/code-block.manifest.json +50 -0
  12. package/dist/manifests/command-palette.manifest.json +80 -0
  13. package/dist/manifests/confirmation.manifest.json +143 -0
  14. package/dist/manifests/conversation.manifest.json +290 -0
  15. package/dist/manifests/inline-citation.manifest.json +46 -0
  16. package/dist/manifests/message-actions.manifest.json +35 -0
  17. package/dist/manifests/message.manifest.json +235 -0
  18. package/dist/manifests/prompt-input.manifest.json +334 -0
  19. package/dist/manifests/reasoning.manifest.json +177 -0
  20. package/dist/manifests/response.manifest.json +51 -0
  21. package/dist/manifests/source.manifest.json +78 -0
  22. package/dist/manifests/streaming-indicator.manifest.json +39 -0
  23. package/dist/manifests/suggestions.manifest.json +45 -0
  24. package/dist/manifests/tool-call.manifest.json +158 -0
  25. package/package.json +61 -3
  26. package/src/adapter/adapter.test.tsx +83 -0
  27. package/src/adapter/hooks.ts +82 -0
  28. package/src/adapter/index.ts +3 -0
  29. package/src/adapter/messages.ts +49 -0
  30. package/src/adapter/types.ts +24 -0
  31. package/src/components/attachment/Attachment.test.tsx +72 -0
  32. package/src/components/attachment/Attachment.tsx +84 -0
  33. package/src/components/attachment/AttachmentList.tsx +30 -0
  34. package/src/components/attachment/index.ts +5 -0
  35. package/src/components/branch/Branch.test.tsx +52 -0
  36. package/src/components/branch/Branch.tsx +77 -0
  37. package/src/components/branch/index.ts +2 -0
  38. package/src/components/chainthought/ChainThought.test.tsx +34 -0
  39. package/src/components/chainthought/ChainThought.tsx +45 -0
  40. package/src/components/chainthought/index.ts +2 -0
  41. package/src/components/code-block/CodeBlock.test.tsx +46 -0
  42. package/src/components/code-block/CodeBlock.tsx +95 -0
  43. package/src/components/code-block/index.ts +2 -0
  44. package/src/components/command-palette/CommandPalette.test.tsx +74 -0
  45. package/src/components/command-palette/CommandPalette.tsx +156 -0
  46. package/src/components/command-palette/index.ts +2 -0
  47. package/src/components/confirmation/Confirmation.test.tsx +97 -0
  48. package/src/components/confirmation/Confirmation.tsx +146 -0
  49. package/src/components/confirmation/index.ts +2 -0
  50. package/src/components/conversation/Conversation.test.tsx +49 -0
  51. package/src/components/conversation/Conversation.tsx +301 -0
  52. package/src/components/conversation/Conversation.welcome.test.tsx +73 -0
  53. package/src/components/conversation/index.ts +2 -0
  54. package/src/components/inline-citation/InlineCitation.test.tsx +42 -0
  55. package/src/components/inline-citation/InlineCitation.tsx +56 -0
  56. package/src/components/inline-citation/index.ts +2 -0
  57. package/src/components/message/Message.error-edit.test.tsx +60 -0
  58. package/src/components/message/Message.test.tsx +80 -0
  59. package/src/components/message/Message.tsx +205 -0
  60. package/src/components/message/index.ts +2 -0
  61. package/src/components/message-actions/MessageActions.test.tsx +77 -0
  62. package/src/components/message-actions/MessageActions.tsx +134 -0
  63. package/src/components/message-actions/index.ts +2 -0
  64. package/src/components/prompt-input/PromptInput.compound.test.tsx +150 -0
  65. package/src/components/prompt-input/PromptInput.test.tsx +74 -0
  66. package/src/components/prompt-input/PromptInput.tsx +584 -0
  67. package/src/components/prompt-input/index.ts +21 -0
  68. package/src/components/reasoning/Reasoning.duration.test.tsx +35 -0
  69. package/src/components/reasoning/Reasoning.test.tsx +58 -0
  70. package/src/components/reasoning/Reasoning.tsx +85 -0
  71. package/src/components/reasoning/index.ts +2 -0
  72. package/src/components/response/Response.test.tsx +69 -0
  73. package/src/components/response/Response.tsx +75 -0
  74. package/src/components/response/close-incomplete-markdown.ts +47 -0
  75. package/src/components/response/index.ts +3 -0
  76. package/src/components/source/Source.tsx +51 -0
  77. package/src/components/source/Sources.tsx +42 -0
  78. package/src/components/source/index.ts +5 -0
  79. package/src/components/source/source.test.tsx +72 -0
  80. package/src/components/streaming/StreamingIndicator.test.tsx +26 -0
  81. package/src/components/streaming/StreamingIndicator.tsx +46 -0
  82. package/src/components/streaming/index.ts +2 -0
  83. package/src/components/suggestion/Suggestion.test.tsx +43 -0
  84. package/src/components/suggestion/Suggestion.tsx +47 -0
  85. package/src/components/suggestion/index.ts +2 -0
  86. package/src/components/tool-call/ToolCall.test.tsx +45 -0
  87. package/src/components/tool-call/ToolCall.tsx +101 -0
  88. package/src/components/tool-call/index.ts +2 -0
  89. package/src/index.ts +29 -0
  90. package/src/manifests/attachment.manifest.json +33 -0
  91. package/src/manifests/branch.manifest.json +65 -0
  92. package/src/manifests/chain-thought.manifest.json +39 -0
  93. package/src/manifests/code-block.manifest.json +50 -0
  94. package/src/manifests/command-palette.manifest.json +80 -0
  95. package/src/manifests/confirmation.manifest.json +143 -0
  96. package/src/manifests/conversation.manifest.json +290 -0
  97. package/src/manifests/inline-citation.manifest.json +46 -0
  98. package/src/manifests/message-actions.manifest.json +35 -0
  99. package/src/manifests/message.manifest.json +235 -0
  100. package/src/manifests/prompt-input.manifest.json +334 -0
  101. package/src/manifests/reasoning.manifest.json +177 -0
  102. package/src/manifests/response.manifest.json +51 -0
  103. package/src/manifests/source.manifest.json +78 -0
  104. package/src/manifests/streaming-indicator.manifest.json +39 -0
  105. package/src/manifests/suggestions.manifest.json +45 -0
  106. package/src/manifests/tool-call.manifest.json +158 -0
  107. package/src/test/jest-axe.d.ts +16 -0
  108. package/src/test/setup.ts +18 -0
  109. package/src/test/vitest-matchers.d.ts +10 -0
  110. package/src/types/index.ts +40 -0
  111. package/README.md +0 -3
@@ -0,0 +1,290 @@
1
+ {
2
+ "id": "conversation",
3
+ "name": "Conversation",
4
+ "tier": "organism",
5
+ "description": "A container for displaying a list of chat messages with auto-scroll and loading states",
6
+ "designIntent": "The Conversation component manages the display of multiple messages in a chat interface. It handles auto-scrolling to show new messages, distinct avatar configurations for users and assistants, and a loading state when the AI is generating a response.",
7
+ "props": [
8
+ {
9
+ "name": "messages",
10
+ "type": "Message[]",
11
+ "required": true,
12
+ "description": "Array of message objects to display",
13
+ "examples": [
14
+ "[{ id: '1', role: 'user', content: 'Hello' }, { id: '2', role: 'assistant', content: 'Hi!' }]"
15
+ ]
16
+ },
17
+ {
18
+ "name": "showAvatars",
19
+ "type": "boolean",
20
+ "defaultValue": "true",
21
+ "required": false,
22
+ "description": "Whether to show avatars for messages",
23
+ "examples": [
24
+ true,
25
+ false
26
+ ]
27
+ },
28
+ {
29
+ "name": "userAvatarSrc",
30
+ "type": "string",
31
+ "required": false,
32
+ "description": "Custom avatar image URL for user messages",
33
+ "examples": [
34
+ "https://example.com/user-avatar.png"
35
+ ]
36
+ },
37
+ {
38
+ "name": "userAvatarFallback",
39
+ "type": "string",
40
+ "required": false,
41
+ "description": "Fallback text for user avatar",
42
+ "examples": [
43
+ "JD",
44
+ "User"
45
+ ]
46
+ },
47
+ {
48
+ "name": "assistantAvatarSrc",
49
+ "type": "string",
50
+ "required": false,
51
+ "description": "Custom avatar image URL for assistant messages",
52
+ "examples": [
53
+ "https://example.com/ai-avatar.png"
54
+ ]
55
+ },
56
+ {
57
+ "name": "assistantAvatarFallback",
58
+ "type": "string",
59
+ "required": false,
60
+ "description": "Fallback text for assistant avatar",
61
+ "examples": [
62
+ "AI",
63
+ "Bot"
64
+ ]
65
+ },
66
+ {
67
+ "name": "isLoading",
68
+ "type": "boolean",
69
+ "defaultValue": "false",
70
+ "required": false,
71
+ "description": "Whether the assistant is currently generating a response",
72
+ "examples": [
73
+ true,
74
+ false
75
+ ]
76
+ },
77
+ {
78
+ "name": "loadingMessage",
79
+ "type": "string",
80
+ "defaultValue": "Thinking...",
81
+ "required": false,
82
+ "description": "Text to display while loading",
83
+ "examples": [
84
+ "Thinking...",
85
+ "Generating response...",
86
+ "Processing..."
87
+ ]
88
+ },
89
+ {
90
+ "name": "className",
91
+ "type": "string",
92
+ "required": false,
93
+ "description": "Additional CSS classes to apply to the conversation container"
94
+ },
95
+ {
96
+ "name": "renderContent",
97
+ "type": "(content: string) => ReactNode",
98
+ "required": false,
99
+ "description": "Custom renderer applied to every message (e.g. markdown)."
100
+ },
101
+ {
102
+ "name": "streamingMessageId",
103
+ "type": "string",
104
+ "required": false,
105
+ "description": "ID of the message still generating; renders its streaming cursor and auto-scrolls."
106
+ },
107
+ {
108
+ "name": "showScrollButton",
109
+ "type": "boolean",
110
+ "defaultValue": "true",
111
+ "required": false,
112
+ "description": "Show the scroll-to-latest button when the user scrolls up"
113
+ },
114
+ {
115
+ "name": "showDownload",
116
+ "type": "boolean",
117
+ "defaultValue": "true",
118
+ "required": false,
119
+ "description": "Show the transcript download action"
120
+ },
121
+ {
122
+ "name": "messageErrors",
123
+ "type": "Record<string, string>",
124
+ "required": false,
125
+ "description": "Map of message id to error text; renders an error card on that message"
126
+ },
127
+ {
128
+ "name": "onRetryMessage",
129
+ "type": "(message: MessageData) => void",
130
+ "required": false,
131
+ "description": "Called when the user retries a failed message"
132
+ },
133
+ {
134
+ "name": "welcomeTitle",
135
+ "type": "string",
136
+ "required": false,
137
+ "description": "Title shown in the empty/welcome state"
138
+ },
139
+ {
140
+ "name": "welcomeDescription",
141
+ "type": "string",
142
+ "required": false,
143
+ "description": "Supporting text in the welcome state"
144
+ },
145
+ {
146
+ "name": "welcomeSuggestions",
147
+ "type": "string[]",
148
+ "required": false,
149
+ "description": "Starter prompts shown in the welcome state"
150
+ },
151
+ {
152
+ "name": "onWelcomeSelect",
153
+ "type": "(prompt: string) => void",
154
+ "required": false,
155
+ "description": "Called when a welcome suggestion is clicked"
156
+ },
157
+ {
158
+ "name": "hasMoreHistory",
159
+ "type": "boolean",
160
+ "required": false,
161
+ "description": "Whether older history pages exist (enables infinite scroll)"
162
+ },
163
+ {
164
+ "name": "isLoadingMore",
165
+ "type": "boolean",
166
+ "required": false,
167
+ "description": "Whether a history page is currently loading"
168
+ },
169
+ {
170
+ "name": "onLoadMore",
171
+ "type": "() => void",
172
+ "required": false,
173
+ "description": "Called when the user scrolls to the top to load older messages"
174
+ }
175
+ ],
176
+ "examples": [
177
+ {
178
+ "title": "Basic conversation",
179
+ "code": "<Conversation \n messages={[\n { id: '1', role: 'user', content: 'Hello' },\n { id: '2', role: 'assistant', content: 'Hi there!' }\n ]}\n/>",
180
+ "description": "Simple conversation with user and assistant messages"
181
+ },
182
+ {
183
+ "title": "With custom avatars",
184
+ "code": "<Conversation \n messages={messages}\n userAvatarSrc=\"/user.png\"\n userAvatarFallback=\"JD\"\n assistantAvatarSrc=\"/ai.png\"\n assistantAvatarFallback=\"AI\"\n/>",
185
+ "description": "Conversation with custom avatar images and fallbacks"
186
+ },
187
+ {
188
+ "title": "With loading state",
189
+ "code": "<Conversation \n messages={messages}\n isLoading={true}\n loadingMessage=\"Generating your response...\"\n/>",
190
+ "description": "Conversation showing loading indicator while AI responds"
191
+ },
192
+ {
193
+ "title": "Without avatars",
194
+ "code": "<Conversation \n messages={messages}\n showAvatars={false}\n/>",
195
+ "description": "More compact conversation without avatars"
196
+ }
197
+ ],
198
+ "antiPatterns": [
199
+ {
200
+ "title": "Don't manage state inside Conversation",
201
+ "explanation": "Conversation should be a controlled component. State should be managed by the parent.",
202
+ "example": "// Avoid: Conversation managing its own message state\n<Conversation />\n\n// Prefer: Pass messages as props from parent\n<Conversation messages={messages} />"
203
+ },
204
+ {
205
+ "title": "Don't use for non-chat content",
206
+ "explanation": "Conversation is specifically for chat messages, not general data display",
207
+ "example": "// Avoid: Using Conversation for general lists\n<Conversation messages={dataItems} />\n\n// Prefer: Use appropriate list components\n<DataList items={dataItems} />"
208
+ }
209
+ ],
210
+ "accessibility": [
211
+ {
212
+ "feature": "Live regions",
213
+ "implementation": "Consider adding aria-live to the container for screen readers to announce new messages",
214
+ "userRequirements": "For streaming responses, use aria-live='polite' to avoid interrupting users"
215
+ },
216
+ {
217
+ "feature": "Keyboard navigation",
218
+ "implementation": "Container is scrollable with keyboard. Focus management depends on parent component",
219
+ "userRequirements": "Ensure users can navigate through messages with keyboard if needed"
220
+ },
221
+ {
222
+ "feature": "Loading announcement",
223
+ "implementation": "Loading state is visually indicated but not announced to screen readers by default",
224
+ "userRequirements": "Consider adding aria-live region for loading state if needed"
225
+ }
226
+ ],
227
+ "contentGuidelines": [
228
+ {
229
+ "contentType": "Loading message",
230
+ "guidelines": [
231
+ "Keep loading messages brief and informative",
232
+ "Avoid specific time estimates (which are often inaccurate)",
233
+ "Use consistent loading text across the application",
234
+ "Consider the context (what action is being performed)"
235
+ ],
236
+ "goodExamples": [
237
+ "Thinking...",
238
+ "Generating response...",
239
+ "Processing your request"
240
+ ],
241
+ "badExamples": [
242
+ "Please wait about 5 seconds",
243
+ "Loading loading loading",
244
+ "Wait"
245
+ ]
246
+ },
247
+ {
248
+ "contentType": "Avatar fallback text",
249
+ "guidelines": [
250
+ "Use consistent abbreviations for user and assistant",
251
+ "User fallback should be based on user's name or identity",
252
+ "Assistant fallback should clearly indicate it's an AI",
253
+ "Keep to 1-2 characters for best appearance"
254
+ ],
255
+ "goodExamples": [
256
+ "JD",
257
+ "AI",
258
+ "Bot",
259
+ "U"
260
+ ],
261
+ "badExamples": [
262
+ "JohnDoe",
263
+ "Assistant Bot",
264
+ "very-long-text"
265
+ ]
266
+ }
267
+ ],
268
+ "compositionRules": [
269
+ {
270
+ "component": "Message",
271
+ "relationship": "Conversation renders multiple Message components internally",
272
+ "example": "Conversation maps over messages array and renders Message for each item"
273
+ },
274
+ {
275
+ "component": "PromptInput",
276
+ "relationship": "PromptInput is typically used alongside Conversation to submit new messages",
277
+ "example": "Conversation displays messages, PromptInput adds new ones to the messages array"
278
+ }
279
+ ],
280
+ "relatedComponents": [
281
+ "Message",
282
+ "PromptInput",
283
+ "ChatLayout"
284
+ ],
285
+ "package": "@slipstream-ui/ai",
286
+ "importPath": "@slipstream-ui/ai",
287
+ "version": "0.0.1",
288
+ "sourceDir": "conversation",
289
+ "exportName": "Conversation"
290
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "id": "inline-citation",
3
+ "name": "InlineCitation",
4
+ "tier": "atom",
5
+ "description": "Perplexity-style inline citation chip that reveals the source title and snippet on hover or keyboard focus.",
6
+ "designIntent": "Attribute individual claims inside a response to their source without leaving the paragraph.",
7
+ "props": [
8
+ {
9
+ "name": "source",
10
+ "type": "SourceItem",
11
+ "required": true,
12
+ "description": "Cited source powering the preview card."
13
+ },
14
+ {
15
+ "name": "children",
16
+ "type": "ReactNode",
17
+ "required": false,
18
+ "description": "Wrapped text; defaults to the source title."
19
+ }
20
+ ],
21
+ "examples": [
22
+ {
23
+ "title": "Wrap a claim",
24
+ "code": "<InlineCitation source={sources[0]}>as reported</InlineCitation>"
25
+ }
26
+ ],
27
+ "antiPatterns": [
28
+ {
29
+ "title": "Do not stack many citations on one word",
30
+ "explanation": "Use Sources footer for long lists; keep inline citations to one claim each."
31
+ }
32
+ ],
33
+ "accessibility": [
34
+ {
35
+ "feature": "Keyboard access",
36
+ "implementation": "Trigger is a focusable button; card opens on focus-within."
37
+ },
38
+ {
39
+ "feature": "Tooltip semantics",
40
+ "implementation": "Card has role=tooltip linked via aria-describedby."
41
+ }
42
+ ],
43
+ "package": "@slipstream-ui/ai",
44
+ "importPath": "@slipstream-ui/ai",
45
+ "version": "0.0.1"
46
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "message-actions",
3
+ "name": "MessageActions",
4
+ "tier": "atom",
5
+ "description": "Feedback toolbar for an AI response: copy to clipboard, thumbs up/down rating, and regenerate. Every action is a callback; the component holds no conversation state.",
6
+ "designIntent": "Collect user trust signals (copy, rating, regeneration) with minimal API surface; consumers own what happens after each action.",
7
+ "props": [
8
+ { "name": "content", "type": "string", "required": false, "description": "Text to copy; omit to hide the copy action." },
9
+ { "name": "onCopy", "type": "(content: string) => void", "required": false, "description": "Called after copy with the copied text." },
10
+ { "name": "onFeedback", "type": "(rating: 'up' | 'down' | undefined) => void", "required": false, "description": "Rating callback; selecting the active rating again passes undefined." },
11
+ { "name": "onRegenerate", "type": "() => void", "required": false, "description": "Regeneration request; omit to hide the action." },
12
+ { "name": "labels", "type": "{ copy?, copied?, thumbUp?, thumbDown?, regenerate? }", "required": false, "description": "Overrides for all visible labels; enables localization." }
13
+ ],
14
+ "examples": [
15
+ {
16
+ "title": "Full feedback bar",
17
+ "code": "<MessageActions content={message.content} onCopy={copy} onFeedback={(r) => track(r)} onRegenerate={regen} />"
18
+ },
19
+ {
20
+ "title": "Ratings only",
21
+ "code": "<MessageActions onFeedback={(r) => save(r)} />"
22
+ }
23
+ ],
24
+ "antiPatterns": [
25
+ { "title": "Do not place MessageActions inside the message text flow", "explanation": "Render it below the Message bubble so actions remain visually and semantically separate from content." }
26
+ ],
27
+ "accessibility": [
28
+ { "feature": "Toolbar semantics", "implementation": "Root has role=toolbar with an aria-label." },
29
+ { "feature": "Toggle state", "implementation": "Rating buttons expose aria-pressed so screen readers announce selection." },
30
+ { "feature": "Icon buttons", "implementation": "All icon-only controls have accessible labels; labels are localizable." }
31
+ ],
32
+ "package": "@slipstream-ui/ai",
33
+ "importPath": "@slipstream-ui/ai",
34
+ "version": "0.0.1"
35
+ }
@@ -0,0 +1,235 @@
1
+ {
2
+ "id": "message",
3
+ "name": "Message",
4
+ "tier": "molecule",
5
+ "description": "A chat message component that displays messages from users, assistants, or system prompts with optional avatars",
6
+ "designIntent": "The Message component renders individual chat messages with proper styling based on the message role (user, assistant, system, tool). It handles avatar display, timestamps, and different visual treatments to distinguish between message types in a conversation interface.",
7
+ "props": [
8
+ {
9
+ "name": "message",
10
+ "type": "Message",
11
+ "required": true,
12
+ "description": "The message object containing role, content, and optional metadata",
13
+ "examples": [
14
+ "{ id: '1', role: 'user', content: 'Hello' }",
15
+ "{ id: '2', role: 'assistant', content: 'Hi there!' }"
16
+ ]
17
+ },
18
+ {
19
+ "name": "showAvatar",
20
+ "type": "boolean",
21
+ "defaultValue": "true",
22
+ "required": false,
23
+ "description": "Whether to show the avatar for the message",
24
+ "examples": [
25
+ true,
26
+ false
27
+ ]
28
+ },
29
+ {
30
+ "name": "avatarSrc",
31
+ "type": "string",
32
+ "required": false,
33
+ "description": "Optional custom avatar image URL",
34
+ "examples": [
35
+ "https://example.com/avatar.png"
36
+ ]
37
+ },
38
+ {
39
+ "name": "avatarFallback",
40
+ "type": "string",
41
+ "required": false,
42
+ "description": "Fallback text to show when avatar image is not available",
43
+ "examples": [
44
+ "JD",
45
+ "AI",
46
+ "Bot"
47
+ ]
48
+ },
49
+ {
50
+ "name": "className",
51
+ "type": "string",
52
+ "required": false,
53
+ "description": "Additional CSS classes to apply to the message container"
54
+ },
55
+ {
56
+ "name": "renderContent",
57
+ "type": "(content: string) => ReactNode",
58
+ "required": false,
59
+ "description": "Custom renderer (e.g. markdown); replaces default plain-text rendering."
60
+ },
61
+ {
62
+ "name": "isStreaming",
63
+ "type": "boolean",
64
+ "defaultValue": false,
65
+ "required": false,
66
+ "description": "Shows a typing cursor and sets aria-busy while the response is still generating."
67
+ },
68
+ {
69
+ "name": "userLabel",
70
+ "type": "string",
71
+ "defaultValue": "You",
72
+ "required": false,
73
+ "description": "Display name for user messages; enables localization."
74
+ },
75
+ {
76
+ "name": "assistantLabel",
77
+ "type": "string",
78
+ "defaultValue": "Assistant",
79
+ "required": false,
80
+ "description": "Display name for assistant messages; enables localization."
81
+ },
82
+ {
83
+ "name": "error",
84
+ "type": "string",
85
+ "required": false,
86
+ "description": "Error text to render on the message; shows an error card with retry"
87
+ },
88
+ {
89
+ "name": "onRetry",
90
+ "type": "() => void",
91
+ "required": false,
92
+ "description": "Called when the user requests a retry after error; omit to hide the action"
93
+ },
94
+ {
95
+ "name": "labels",
96
+ "type": "{ retry?: string; edit?: string; save?: string; cancel?: string }",
97
+ "required": false,
98
+ "description": "Override button labels in the message actions"
99
+ },
100
+ {
101
+ "name": "onEditContent",
102
+ "type": "(content: string) => void",
103
+ "required": false,
104
+ "description": "Enables edit-and-resubmit; called with the edited content"
105
+ }
106
+ ],
107
+ "examples": [
108
+ {
109
+ "title": "User message",
110
+ "code": "<Message message={{ id: '1', role: 'user', content: 'Hello, how are you?' }} />",
111
+ "description": "Message from the user with default avatar"
112
+ },
113
+ {
114
+ "title": "Assistant message",
115
+ "code": "<Message message={{ id: '2', role: 'assistant', content: 'I\\'m doing well, thank you!' }} />",
116
+ "description": "Message from the AI assistant"
117
+ },
118
+ {
119
+ "title": "System message",
120
+ "code": "<Message message={{ id: '3', role: 'system', content: 'System initialized' }} />",
121
+ "description": "System-level message with distinct styling"
122
+ },
123
+ {
124
+ "title": "With custom avatar",
125
+ "code": "<Message \n message={{ id: '4', role: 'assistant', content: 'Hello' }}\n avatarSrc=\"/ai-avatar.png\"\n avatarFallback=\"AI\"\n/>",
126
+ "description": "Message with custom avatar image and fallback"
127
+ },
128
+ {
129
+ "title": "Without avatar",
130
+ "code": "<Message \n message={{ id: '5', role: 'user', content: 'Quick message' }}\n showAvatar={false}\n/>",
131
+ "description": "Message with avatar hidden for more compact display"
132
+ },
133
+ {
134
+ "title": "Markdown rendering (opt-in)",
135
+ "code": "<Message message={m} renderContent={(c) => <ReactMarkdown>{c}</ReactMarkdown>} />"
136
+ },
137
+ {
138
+ "title": "Streaming response",
139
+ "code": "<Message message={partial} isStreaming />"
140
+ }
141
+ ],
142
+ "antiPatterns": [
143
+ {
144
+ "title": "Don't use for complex content",
145
+ "explanation": "Message content should be plain text. For complex UI, use additional components.",
146
+ "example": "// Avoid: Putting complex UI inside message content\n<Message message={{ \n role: 'assistant', \n content: '<div>Complex HTML</div>' \n}} />\n\n// Prefer: Use separate components for complex content\n<Message message={{ role: 'assistant', content: 'Here is the data:' }} />\n<DataDisplay data={...} />"
147
+ },
148
+ {
149
+ "title": "Don't hardcode message data",
150
+ "explanation": "Messages should come from a conversation state, not be hardcoded",
151
+ "example": "// Avoid: Hardcoded message\n<Message message={{ id: '1', role: 'user', content: 'Fixed text' }} />\n\n// Prefer: Dynamic message from state\n<Message message={messages[currentIndex]} />"
152
+ }
153
+ ],
154
+ "accessibility": [
155
+ {
156
+ "feature": "Screen reader support",
157
+ "implementation": "Message role and content are announced. Avatar has proper alt text from fallback or role",
158
+ "userRequirements": "Ensure avatarFallback is meaningful when avatarSrc is used"
159
+ },
160
+ {
161
+ "feature": "Color contrast",
162
+ "implementation": "User and assistant messages have distinct background colors with proper contrast",
163
+ "userRequirements": "Test color contrast in both light and dark modes"
164
+ },
165
+ {
166
+ "feature": "Semantic structure",
167
+ "implementation": "Message is rendered as a div with proper ARIA attributes for role identification",
168
+ "userRequirements": "Consider adding aria-live regions for streaming messages"
169
+ }
170
+ ],
171
+ "contentGuidelines": [
172
+ {
173
+ "contentType": "Message content",
174
+ "guidelines": [
175
+ "Content should be plain text, not HTML",
176
+ "Support markdown formatting if needed (apply at wrapper level)",
177
+ "Keep messages focused and concise",
178
+ "Use proper punctuation and grammar for assistant messages",
179
+ "For user messages, preserve user's original formatting"
180
+ ],
181
+ "goodExamples": [
182
+ "I can help you with that task.",
183
+ "Here's the code you requested:",
184
+ "Let me explain step by step."
185
+ ],
186
+ "badExamples": [
187
+ "<b>Bold text</b>",
188
+ "Lorem ipsum dolor sit amet",
189
+ "Click here to continue"
190
+ ]
191
+ },
192
+ {
193
+ "contentType": "Avatar fallback",
194
+ "guidelines": [
195
+ "Use 1-2 characters maximum",
196
+ "Use initials for user names",
197
+ "Use meaningful abbreviations for bots",
198
+ "Ensure high contrast with avatar background"
199
+ ],
200
+ "goodExamples": [
201
+ "JD",
202
+ "AI",
203
+ "Bot",
204
+ "S"
205
+ ],
206
+ "badExamples": [
207
+ "John Doe",
208
+ "Assistant",
209
+ "long-text"
210
+ ]
211
+ }
212
+ ],
213
+ "compositionRules": [
214
+ {
215
+ "component": "Conversation",
216
+ "relationship": "Messages are typically rendered within a Conversation component that manages the message list",
217
+ "example": "<Conversation>\n {messages.map(msg => <Message key={msg.id} message={msg} />)}\n</Conversation>"
218
+ },
219
+ {
220
+ "component": "PromptInput",
221
+ "relationship": "New messages from PromptInput should be added to the message list and rendered as Message components",
222
+ "example": "const handleSubmit = (text) => {\n const newMessage = { id: Date.now(), role: 'user', content: text };\n setMessages([...messages, newMessage]);\n}"
223
+ }
224
+ ],
225
+ "relatedComponents": [
226
+ "Conversation",
227
+ "PromptInput",
228
+ "Avatar"
229
+ ],
230
+ "package": "@slipstream-ui/ai",
231
+ "importPath": "@slipstream-ui/ai",
232
+ "version": "0.0.1",
233
+ "sourceDir": "message",
234
+ "exportName": "Message"
235
+ }