@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,143 @@
1
+ {
2
+ "id": "confirmation",
3
+ "name": "Confirmation",
4
+ "tier": "molecule",
5
+ "description": "Human-in-the-loop approval gate for agent actions. Pauses execution until the user approves or rejects.",
6
+ "designIntent": "Make destructive or consequential tool calls require explicit user consent.",
7
+ "props": [
8
+ {
9
+ "name": "title",
10
+ "type": "string",
11
+ "required": true,
12
+ "description": "Summary of the action requiring approval."
13
+ },
14
+ {
15
+ "name": "description",
16
+ "type": "string",
17
+ "required": false,
18
+ "description": "Detail: affected resource or risk note."
19
+ },
20
+ {
21
+ "name": "toolName",
22
+ "type": "string",
23
+ "required": false,
24
+ "description": "Tool/action name shown as mono text."
25
+ },
26
+ {
27
+ "name": "status",
28
+ "type": "'pending' | 'approved' | 'rejected'",
29
+ "defaultValue": "pending",
30
+ "required": false,
31
+ "description": "Controlled outcome; omit for uncontrolled."
32
+ },
33
+ {
34
+ "name": "variant",
35
+ "type": "'default' | 'warning' | 'destructive' | 'info' | 'success'",
36
+ "defaultValue": "default",
37
+ "required": false,
38
+ "description": "Accent color of the pending card; outcome chips always follow the result.",
39
+ "enum": [
40
+ "default",
41
+ "warning",
42
+ "destructive",
43
+ "info",
44
+ "success"
45
+ ],
46
+ "examples": [
47
+ "destructive",
48
+ "info"
49
+ ]
50
+ },
51
+ {
52
+ "name": "onApprove",
53
+ "type": "() => void",
54
+ "required": false,
55
+ "description": "Called on approval."
56
+ },
57
+ {
58
+ "name": "onReject",
59
+ "type": "() => void",
60
+ "required": false,
61
+ "description": "Called on rejection."
62
+ },
63
+ {
64
+ "name": "labels",
65
+ "type": "object",
66
+ "required": false,
67
+ "description": "Overrides for approve/reject/approved/rejected labels."
68
+ },
69
+ {
70
+ "name": "approveVariant",
71
+ "type": "'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'",
72
+ "defaultValue": "default",
73
+ "required": false,
74
+ "description": "Button variant for the approve action.",
75
+ "enum": [
76
+ "default",
77
+ "destructive",
78
+ "outline",
79
+ "secondary",
80
+ "ghost",
81
+ "link"
82
+ ],
83
+ "examples": [
84
+ "destructive",
85
+ "default"
86
+ ]
87
+ },
88
+ {
89
+ "name": "rejectVariant",
90
+ "type": "'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'",
91
+ "defaultValue": "outline",
92
+ "required": false,
93
+ "description": "Button variant for the reject action.",
94
+ "enum": [
95
+ "default",
96
+ "destructive",
97
+ "outline",
98
+ "secondary",
99
+ "ghost",
100
+ "link"
101
+ ],
102
+ "examples": [
103
+ "ghost"
104
+ ]
105
+ },
106
+ {
107
+ "name": "showActions",
108
+ "type": "boolean",
109
+ "defaultValue": "true",
110
+ "required": false,
111
+ "description": "Hide the action buttons (controlled-only gate; status drives the chip).",
112
+ "examples": [
113
+ "true",
114
+ "false"
115
+ ]
116
+ }
117
+ ],
118
+ "examples": [
119
+ {
120
+ "title": "Gate a destructive tool",
121
+ "code": "<Confirmation title=\"Delete all files?\" toolName=\"delete_all\" onApprove={run} onReject={cancel} />"
122
+ }
123
+ ],
124
+ "antiPatterns": [
125
+ {
126
+ "title": "Do not auto-approve after timeout",
127
+ "explanation": "Silent approval defeats the safety purpose; keep waiting or fail explicitly."
128
+ }
129
+ ],
130
+ "accessibility": [
131
+ {
132
+ "feature": "Dialog semantics",
133
+ "implementation": "Pending state renders role=alertdialog labeled by the title."
134
+ },
135
+ {
136
+ "feature": "Outcome announcement",
137
+ "implementation": "Status chip text announces Approved/Rejected."
138
+ }
139
+ ],
140
+ "package": "@slipstream-ui/ai",
141
+ "importPath": "@slipstream-ui/ai",
142
+ "version": "0.0.1"
143
+ }
@@ -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
+ }