@commercetools/nimbus-mcp 3.2.0 → 3.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 (189) hide show
  1. package/README.md +9 -1
  2. package/data/docs/route-manifest.json +806 -41
  3. package/data/docs/routes/components-buttons-button.json +25 -2
  4. package/data/docs/routes/components-chat-chat-message-list.json +448 -0
  5. package/data/docs/routes/components-chat-chat-message.json +580 -0
  6. package/data/docs/routes/components-content-markdown.json +548 -0
  7. package/data/docs/routes/components-feedback-activity-indicator.json +396 -0
  8. package/data/docs/routes/components-feedback-tooltip.json +23 -1
  9. package/data/docs/routes/components-inputs-drop-zone.json +562 -0
  10. package/data/docs/routes/components-inputs-file-trigger.json +421 -0
  11. package/data/docs/routes/components-layout-splitter.json +3 -3
  12. package/data/docs/routes/components-media-avatar.json +16 -5
  13. package/data/docs/routes/components-navigation-menu.json +1 -1
  14. package/data/docs/routes/components-navigation-tabnav.json +80 -14
  15. package/data/docs/routes/components-navigation-tabs.json +44 -11
  16. package/data/docs/routes/components-navigation-tree.json +445 -0
  17. package/data/docs/routes/home-getting-started-mcp-server-overview.json +2 -2
  18. package/data/docs/routes/home-getting-started-mcp-server-setup.json +2 -2
  19. package/data/docs/routes/patterns-buttons-floating-action-button.json +392 -0
  20. package/data/docs/routes/patterns-buttons.json +58 -0
  21. package/data/docs/search-index.json +1 -1
  22. package/data/docs/types/AccordionContent.json +24 -24
  23. package/data/docs/types/AccordionHeader.json +88 -88
  24. package/data/docs/types/AccordionItem.json +20 -20
  25. package/data/docs/types/AccordionRoot.json +14 -14
  26. package/data/docs/types/ActivityIndicator.json +202 -0
  27. package/data/docs/types/AlertDescription.json +8 -8
  28. package/data/docs/types/AlertDismissButton.json +98 -81
  29. package/data/docs/types/AlertTitle.json +8 -8
  30. package/data/docs/types/Avatar.json +19 -2
  31. package/data/docs/types/Badge.json +2 -2
  32. package/data/docs/types/Body.json +6 -6
  33. package/data/docs/types/Box.json +6 -6
  34. package/data/docs/types/Button.json +106 -89
  35. package/data/docs/types/Calendar.json +56 -56
  36. package/data/docs/types/Caption.json +6 -6
  37. package/data/docs/types/CardRoot.json +2 -2
  38. package/data/docs/types/Cell.json +6 -6
  39. package/data/docs/types/ChatMessage.json +12 -0
  40. package/data/docs/types/ChatMessageActions.json +42 -0
  41. package/data/docs/types/ChatMessageAvatar.json +140 -0
  42. package/data/docs/types/ChatMessageBody.json +42 -0
  43. package/data/docs/types/ChatMessageList.json +12 -0
  44. package/data/docs/types/ChatMessageListItem.json +42 -0
  45. package/data/docs/types/ChatMessageListRoot.json +78 -0
  46. package/data/docs/types/ChatMessageMeta.json +42 -0
  47. package/data/docs/types/ChatMessageRoot.json +119 -0
  48. package/data/docs/types/ChatMessageTyping.json +42 -0
  49. package/data/docs/types/Checkbox.json +86 -86
  50. package/data/docs/types/Code.json +11 -11
  51. package/data/docs/types/Column.json +6 -6
  52. package/data/docs/types/ColumnGroup.json +6 -6
  53. package/data/docs/types/ColumnHeader.json +6 -6
  54. package/data/docs/types/ComboBoxListBox.json +70 -70
  55. package/data/docs/types/ComboBoxOption.json +64 -64
  56. package/data/docs/types/ComboBoxPopover.json +91 -70
  57. package/data/docs/types/ComboBoxRoot.json +8 -8
  58. package/data/docs/types/ComboBoxSection.json +24 -24
  59. package/data/docs/types/ComboBoxTrigger.json +6 -6
  60. package/data/docs/types/DataTable.json +2 -2
  61. package/data/docs/types/DataTableBody.json +20 -20
  62. package/data/docs/types/DataTableHeader.json +25 -25
  63. package/data/docs/types/DataTableRoot.json +2 -2
  64. package/data/docs/types/DataTableTable.json +6 -6
  65. package/data/docs/types/DateInput.json +73 -73
  66. package/data/docs/types/DatePicker.json +58 -58
  67. package/data/docs/types/DateRangePicker.json +86 -86
  68. package/data/docs/types/DateRangePickerField.json +86 -86
  69. package/data/docs/types/DefaultPageRoot.json +2 -2
  70. package/data/docs/types/DialogCloseTrigger.json +96 -79
  71. package/data/docs/types/DraggableListField.json +88 -60
  72. package/data/docs/types/DraggableListItem.json +52 -52
  73. package/data/docs/types/DraggableListRoot.json +88 -60
  74. package/data/docs/types/DrawerCloseTrigger.json +96 -79
  75. package/data/docs/types/DropZone.json +161 -0
  76. package/data/docs/types/FieldErrors.json +2 -2
  77. package/data/docs/types/FileTrigger.json +130 -0
  78. package/data/docs/types/Flex.json +22 -22
  79. package/data/docs/types/FloatingActionButton.json +1036 -0
  80. package/data/docs/types/Footer.json +6 -6
  81. package/data/docs/types/FormActionBar.json +1 -1
  82. package/data/docs/types/FormFieldRoot.json +2 -2
  83. package/data/docs/types/Grid.json +24 -24
  84. package/data/docs/types/Group.json +12 -12
  85. package/data/docs/types/Header.json +6 -6
  86. package/data/docs/types/Heading.json +8 -8
  87. package/data/docs/types/Icon.json +4 -4
  88. package/data/docs/types/IconButton.json +106 -89
  89. package/data/docs/types/IconToggleButton.json +71 -71
  90. package/data/docs/types/Image.json +43 -43
  91. package/data/docs/types/Indicator.json +6 -6
  92. package/data/docs/types/InlineSvg.json +2 -2
  93. package/data/docs/types/Item.json +6 -6
  94. package/data/docs/types/Kbd.json +8 -8
  95. package/data/docs/types/Link.json +14 -14
  96. package/data/docs/types/ListIndicator.json +6 -6
  97. package/data/docs/types/ListItem.json +6 -6
  98. package/data/docs/types/ListRoot.json +11 -11
  99. package/data/docs/types/LoadingSpinner.json +2 -2
  100. package/data/docs/types/MakeElementFocusable.json +18 -18
  101. package/data/docs/types/Markdown.json +183 -0
  102. package/data/docs/types/MenuItem.json +62 -62
  103. package/data/docs/types/MenuRoot.json +55 -55
  104. package/data/docs/types/MenuSection.json +30 -30
  105. package/data/docs/types/MenuSubmenuTrigger.json +4 -4
  106. package/data/docs/types/MenuTrigger.json +88 -88
  107. package/data/docs/types/MultilineTextInput.json +104 -104
  108. package/data/docs/types/MultilineTextInputField.json +102 -102
  109. package/data/docs/types/NumberInput.json +86 -86
  110. package/data/docs/types/NumberInputField.json +82 -82
  111. package/data/docs/types/PageContentColumn.json +6 -6
  112. package/data/docs/types/PageContentRoot.json +6 -6
  113. package/data/docs/types/PasswordInput.json +100 -100
  114. package/data/docs/types/PasswordInputField.json +100 -100
  115. package/data/docs/types/ProgressBar.json +13 -13
  116. package/data/docs/types/RadioInputOption.json +56 -56
  117. package/data/docs/types/RadioInputRoot.json +48 -48
  118. package/data/docs/types/RangeCalendar.json +58 -58
  119. package/data/docs/types/Region.json +6 -6
  120. package/data/docs/types/RegionTarget.json +6 -6
  121. package/data/docs/types/RichTextInput.json +2 -2
  122. package/data/docs/types/Root.json +11 -11
  123. package/data/docs/types/Row.json +6 -6
  124. package/data/docs/types/ScrollArea.json +2 -2
  125. package/data/docs/types/SearchInput.json +106 -106
  126. package/data/docs/types/SearchInputField.json +102 -102
  127. package/data/docs/types/SelectOption.json +54 -54
  128. package/data/docs/types/SelectOptionGroup.json +18 -18
  129. package/data/docs/types/SelectOptions.json +64 -64
  130. package/data/docs/types/SelectRoot.json +92 -92
  131. package/data/docs/types/Separator.json +4 -4
  132. package/data/docs/types/SimpleGrid.json +28 -28
  133. package/data/docs/types/SlidingIndicatorGeometry.json +9 -0
  134. package/data/docs/types/SlidingIndicatorRects.json +9 -0
  135. package/data/docs/types/SplitButton.json +16 -20
  136. package/data/docs/types/Stack.json +2 -2
  137. package/data/docs/types/StepsRoot.json +2 -2
  138. package/data/docs/types/Switch.json +34 -34
  139. package/data/docs/types/TabNavItem.json +5 -5
  140. package/data/docs/types/TabNavRoot.json +5 -5
  141. package/data/docs/types/TableBody.json +6 -6
  142. package/data/docs/types/TableCaption.json +6 -6
  143. package/data/docs/types/TableCell.json +6 -6
  144. package/data/docs/types/TableColumn.json +6 -6
  145. package/data/docs/types/TableColumnGroup.json +6 -6
  146. package/data/docs/types/TableColumnHeader.json +6 -6
  147. package/data/docs/types/TableFooter.json +6 -6
  148. package/data/docs/types/TableHeader.json +6 -6
  149. package/data/docs/types/TableRoot.json +19 -19
  150. package/data/docs/types/TableRow.json +6 -6
  151. package/data/docs/types/TableScrollArea.json +6 -6
  152. package/data/docs/types/TabsList.json +2 -2
  153. package/data/docs/types/TabsPanel.json +2 -2
  154. package/data/docs/types/TabsPanels.json +2 -2
  155. package/data/docs/types/TabsRoot.json +3 -3
  156. package/data/docs/types/TabsTab.json +2 -2
  157. package/data/docs/types/TagGroupRoot.json +24 -24
  158. package/data/docs/types/TagGroupTag.json +56 -56
  159. package/data/docs/types/TagGroupTagList.json +14 -14
  160. package/data/docs/types/Text.json +8 -8
  161. package/data/docs/types/TextInput.json +102 -102
  162. package/data/docs/types/TextInputField.json +100 -100
  163. package/data/docs/types/TimeInput.json +68 -68
  164. package/data/docs/types/ToggleButton.json +73 -73
  165. package/data/docs/types/ToggleButtonGroupButton.json +30 -30
  166. package/data/docs/types/ToggleButtonGroupRoot.json +20 -20
  167. package/data/docs/types/Toolbar.json +9 -9
  168. package/data/docs/types/TooltipContent.json +28 -28
  169. package/data/docs/types/TooltipRoot.json +16 -16
  170. package/data/docs/types/Tree.json +12 -0
  171. package/data/docs/types/TreeIndicator.json +828 -0
  172. package/data/docs/types/TreeItem.json +559 -0
  173. package/data/docs/types/TreeItemContent.json +27 -0
  174. package/data/docs/types/TreeRoot.json +636 -0
  175. package/data/docs/types/TreeSubTree.json +40 -0
  176. package/data/docs/types/VisuallyHidden.json +6 -6
  177. package/data/docs/types/createItemsFromCsvDrop.json +4 -4
  178. package/data/docs/types/createItemsFromDirectoryDrop.json +4 -4
  179. package/data/docs/types/createItemsFromFileDrop.json +4 -4
  180. package/data/docs/types/createItemsFromImageDrop.json +4 -4
  181. package/data/docs/types/createItemsFromJsonDrop.json +4 -4
  182. package/data/docs/types/manifest.json +25 -0
  183. package/data/docs/types/useRegion.json +2 -2
  184. package/data/docs/types/useSlidingIndicator.json +145 -0
  185. package/data/docs/types/useTree.json +267 -0
  186. package/data/tokens.json +21 -0
  187. package/data/uikit-tokens.json +894 -0
  188. package/dist/index.js +3298 -109
  189. package/package.json +8 -6
@@ -0,0 +1,580 @@
1
+ {
2
+ "meta": {
3
+ "id": "Components-ChatMessage",
4
+ "title": "Chat message",
5
+ "exportName": "ChatMessage",
6
+ "description": "A single message in an AI chat conversation, pairing a sender avatar with a message body and optional actions, meta, and typing indicator.",
7
+ "lifecycleState": "Experimental",
8
+ "order": 999,
9
+ "repoPath": "packages/nimbus/src/components/chat-message/chat-message.mdx",
10
+ "menu": [
11
+ "Components",
12
+ "Chat",
13
+ "Chat message"
14
+ ],
15
+ "route": "components/chat/chat-message",
16
+ "tags": [
17
+ "component",
18
+ "chat",
19
+ "message",
20
+ "body",
21
+ "ai",
22
+ "conversation"
23
+ ],
24
+ "toc": [
25
+ {
26
+ "value": "Overview",
27
+ "href": "#overview",
28
+ "depth": 2,
29
+ "numbering": [
30
+ 1,
31
+ 1
32
+ ],
33
+ "parent": "root"
34
+ },
35
+ {
36
+ "value": "Resources",
37
+ "href": "#resources",
38
+ "depth": 3,
39
+ "numbering": [
40
+ 1,
41
+ 1,
42
+ 1
43
+ ],
44
+ "parent": "root"
45
+ },
46
+ {
47
+ "value": "Variables",
48
+ "href": "#variables",
49
+ "depth": 2,
50
+ "numbering": [
51
+ 1,
52
+ 2
53
+ ],
54
+ "parent": "root"
55
+ },
56
+ {
57
+ "value": "Senders",
58
+ "href": "#senders",
59
+ "depth": 3,
60
+ "numbering": [
61
+ 1,
62
+ 2,
63
+ 1
64
+ ],
65
+ "parent": "root"
66
+ },
67
+ {
68
+ "value": "Tone",
69
+ "href": "#tone",
70
+ "depth": 3,
71
+ "numbering": [
72
+ 1,
73
+ 2,
74
+ 2
75
+ ],
76
+ "parent": "root"
77
+ },
78
+ {
79
+ "value": "Actions",
80
+ "href": "#actions",
81
+ "depth": 3,
82
+ "numbering": [
83
+ 1,
84
+ 2,
85
+ 3
86
+ ],
87
+ "parent": "root"
88
+ },
89
+ {
90
+ "value": "Meta",
91
+ "href": "#meta",
92
+ "depth": 3,
93
+ "numbering": [
94
+ 1,
95
+ 2,
96
+ 4
97
+ ],
98
+ "parent": "root"
99
+ },
100
+ {
101
+ "value": "Typing / streaming",
102
+ "href": "#typing--streaming",
103
+ "depth": 3,
104
+ "numbering": [
105
+ 1,
106
+ 2,
107
+ 5
108
+ ],
109
+ "parent": "root"
110
+ }
111
+ ],
112
+ "figmaLink": "https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system?node-id=10601-14469",
113
+ "layout": "app-frame",
114
+ "tabs": [
115
+ {
116
+ "key": "overview",
117
+ "title": "Overview",
118
+ "order": 0
119
+ },
120
+ {
121
+ "key": "dev",
122
+ "title": "Implementation",
123
+ "order": 3
124
+ },
125
+ {
126
+ "key": "a11y",
127
+ "title": "Accessibility",
128
+ "order": 4
129
+ }
130
+ ]
131
+ },
132
+ "mdx": "\n## Overview\n\n`ChatMessage` renders **one message** in an AI chat conversation — an avatar\npaired with a message body, plus optional actions, a meta row, and a typing\nindicator for streaming replies. It does not compose the surrounding feed:\nstacking messages, scrolling, and the live region that announces new content are\nthe transcript's job (see `ChatMessageList`).\n\nThe `sender` prop drives which participant the message is from and controls both\nthe layout direction and the body/avatar styling:\n\n- `user` — the human; avatar trails the body.\n- `agent` (default) — the agent; avatar leads the body.\n\n`sender` denotes only _who_ sent the message. System notices are out of scope\nhere — a system notice isn't a message, and it isn't a standardized component\neither; consumers render their own content (for example inside a\n`ChatMessageList.Item`). Tool/function output is content _inside_ an `agent`\nmessage. Neither is a `sender` value.\n\n`tone=\"error\"` is independent of `sender` — it tints the body to flag a failed\ngeneration, since an agent message can still fail.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system?node-id=10601-14469)\n\n## Variables\n\nGet familiar with the features.\n\n### Senders\n\nEach sender has its own layout direction and surface: `user` places the body\nbefore the avatar, `agent` places the avatar before the body. A system\nnotice (not standardized in this release, so a consumer renders their own\ncentered, subdued content) can sit between turns as an interjection.\n\n```jsx live\nconst App = () => (\n <Stack gap=\"600\">\n <ChatMessage.Root sender=\"user\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n <Box mx=\"auto\" textAlign=\"center\" color=\"neutral.11\" textStyle=\"sm\">\n Conversation history was cleared.\n </Box>\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12% week-over-week.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Stack>\n);\n```\n\n### Tone\n\n`tone=\"error\"` tints the body with the critical palette to flag a failed\ngeneration, on top of whatever `sender` styling already applies.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" tone=\"error\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Something went wrong generating this response.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Retry\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Actions\n\n`ChatMessage.Actions` is a right-aligned row of buttons rendered inside the\nbody. Place it last so the actions pin to the bottom of the card.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>I drafted the date range for your report. Approve to apply.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Save as draft\n </Button>\n <Button variant=\"solid\" colorPalette=\"primary\">\n Approve\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Meta\n\n`ChatMessage.Meta` is a `space-between` row rendered below the body, for a\ntimestamp, a trust/provenance link, or reaction icons.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Here is the summary you asked for.</Text>\n </ChatMessage.Body>\n <ChatMessage.Meta>\n <Link href=\"#\">How was this generated?</Link>\n <Stack direction=\"row\" alignItems=\"center\" gap=\"100\">\n <Text color=\"neutral.11\">Apr 13, 11:56pm</Text>\n <IconButton aria-label=\"Good response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbUp />\n </IconButton>\n <IconButton aria-label=\"Bad response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbDown />\n </IconButton>\n <IconButton aria-label=\"Copy\" variant=\"ghost\" size=\"xs\">\n <Icons.ContentCopy />\n </IconButton>\n </Stack>\n </ChatMessage.Meta>\n </ChatMessage.Root>\n);\n```\n\n### Typing / streaming\n\n`ChatMessage.Typing` shows an animated \"generating…\" indicator as the body's\npayload while a reply streams. Pair it with `isStreaming` on the root, which\nsets `aria-busy`.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" isStreaming>\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <ChatMessage.Typing>\n <Text color=\"neutral.11\">Agent is typing…</Text>\n </ChatMessage.Typing>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n",
133
+ "views": {
134
+ "overview": {
135
+ "mdx": "\n## Overview\n\n`ChatMessage` renders **one message** in an AI chat conversation — an avatar\npaired with a message body, plus optional actions, a meta row, and a typing\nindicator for streaming replies. It does not compose the surrounding feed:\nstacking messages, scrolling, and the live region that announces new content are\nthe transcript's job (see `ChatMessageList`).\n\nThe `sender` prop drives which participant the message is from and controls both\nthe layout direction and the body/avatar styling:\n\n- `user` — the human; avatar trails the body.\n- `agent` (default) — the agent; avatar leads the body.\n\n`sender` denotes only _who_ sent the message. System notices are out of scope\nhere — a system notice isn't a message, and it isn't a standardized component\neither; consumers render their own content (for example inside a\n`ChatMessageList.Item`). Tool/function output is content _inside_ an `agent`\nmessage. Neither is a `sender` value.\n\n`tone=\"error\"` is independent of `sender` — it tints the body to flag a failed\ngeneration, since an agent message can still fail.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system?node-id=10601-14469)\n\n## Variables\n\nGet familiar with the features.\n\n### Senders\n\nEach sender has its own layout direction and surface: `user` places the body\nbefore the avatar, `agent` places the avatar before the body. A system\nnotice (not standardized in this release, so a consumer renders their own\ncentered, subdued content) can sit between turns as an interjection.\n\n```jsx live\nconst App = () => (\n <Stack gap=\"600\">\n <ChatMessage.Root sender=\"user\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n <Box mx=\"auto\" textAlign=\"center\" color=\"neutral.11\" textStyle=\"sm\">\n Conversation history was cleared.\n </Box>\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12% week-over-week.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Stack>\n);\n```\n\n### Tone\n\n`tone=\"error\"` tints the body with the critical palette to flag a failed\ngeneration, on top of whatever `sender` styling already applies.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" tone=\"error\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Something went wrong generating this response.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Retry\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Actions\n\n`ChatMessage.Actions` is a right-aligned row of buttons rendered inside the\nbody. Place it last so the actions pin to the bottom of the card.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>I drafted the date range for your report. Approve to apply.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Save as draft\n </Button>\n <Button variant=\"solid\" colorPalette=\"primary\">\n Approve\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Meta\n\n`ChatMessage.Meta` is a `space-between` row rendered below the body, for a\ntimestamp, a trust/provenance link, or reaction icons.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Here is the summary you asked for.</Text>\n </ChatMessage.Body>\n <ChatMessage.Meta>\n <Link href=\"#\">How was this generated?</Link>\n <Stack direction=\"row\" alignItems=\"center\" gap=\"100\">\n <Text color=\"neutral.11\">Apr 13, 11:56pm</Text>\n <IconButton aria-label=\"Good response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbUp />\n </IconButton>\n <IconButton aria-label=\"Bad response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbDown />\n </IconButton>\n <IconButton aria-label=\"Copy\" variant=\"ghost\" size=\"xs\">\n <Icons.ContentCopy />\n </IconButton>\n </Stack>\n </ChatMessage.Meta>\n </ChatMessage.Root>\n);\n```\n\n### Typing / streaming\n\n`ChatMessage.Typing` shows an animated \"generating…\" indicator as the body's\npayload while a reply streams. Pair it with `isStreaming` on the root, which\nsets `aria-busy`.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" isStreaming>\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <ChatMessage.Typing>\n <Text color=\"neutral.11\">Agent is typing…</Text>\n </ChatMessage.Typing>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n",
136
+ "toc": [
137
+ {
138
+ "value": "Overview",
139
+ "href": "#overview",
140
+ "depth": 2,
141
+ "numbering": [
142
+ 1,
143
+ 1
144
+ ],
145
+ "parent": "root"
146
+ },
147
+ {
148
+ "value": "Resources",
149
+ "href": "#resources",
150
+ "depth": 3,
151
+ "numbering": [
152
+ 1,
153
+ 1,
154
+ 1
155
+ ],
156
+ "parent": "root"
157
+ },
158
+ {
159
+ "value": "Variables",
160
+ "href": "#variables",
161
+ "depth": 2,
162
+ "numbering": [
163
+ 1,
164
+ 2
165
+ ],
166
+ "parent": "root"
167
+ },
168
+ {
169
+ "value": "Senders",
170
+ "href": "#senders",
171
+ "depth": 3,
172
+ "numbering": [
173
+ 1,
174
+ 2,
175
+ 1
176
+ ],
177
+ "parent": "root"
178
+ },
179
+ {
180
+ "value": "Tone",
181
+ "href": "#tone",
182
+ "depth": 3,
183
+ "numbering": [
184
+ 1,
185
+ 2,
186
+ 2
187
+ ],
188
+ "parent": "root"
189
+ },
190
+ {
191
+ "value": "Actions",
192
+ "href": "#actions",
193
+ "depth": 3,
194
+ "numbering": [
195
+ 1,
196
+ 2,
197
+ 3
198
+ ],
199
+ "parent": "root"
200
+ },
201
+ {
202
+ "value": "Meta",
203
+ "href": "#meta",
204
+ "depth": 3,
205
+ "numbering": [
206
+ 1,
207
+ 2,
208
+ 4
209
+ ],
210
+ "parent": "root"
211
+ },
212
+ {
213
+ "value": "Typing / streaming",
214
+ "href": "#typing--streaming",
215
+ "depth": 3,
216
+ "numbering": [
217
+ 1,
218
+ 2,
219
+ 5
220
+ ],
221
+ "parent": "root"
222
+ }
223
+ ]
224
+ },
225
+ "a11y": {
226
+ "mdx": "\n## Accessibility\n\n`ChatMessage` renders a **single message**. It intentionally does not own the\nsurrounding feed's container semantics or its live region — those are the\nconsumer's to compose. This page documents both halves: what the component does\nfor you, and what you're responsible for wiring up around it.\n\n```jsx live\nconst App = () => (\n <ChatMessage.Root sender=\"user\" aria-label=\"Message from Ada Lovelace\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Naming a message\n\n`ChatMessage.Root` renders a semantic `<article>` by default (a feed item, per\nthe ARIA APG), so each message is a discrete node in the accessibility tree. An\n`<article>` needs its own accessible name — give it one explicitly with\n`aria-label` or `aria-labelledby`. Don't rely on the avatar to convey who sent\nthe message: it is decorative by default (see below), and even when named, a\nrepeated \"Avatar\" node is a worse accessible name for the message than a label\non the message itself.\n\n### The avatar is decorative by default\n\n`ChatMessage.Avatar` sets `aria-hidden` unless you pass `firstName`/`lastName` or\nan explicit `aria-label`. This is deliberate: an unnamed avatar would otherwise\nannounce a generic, unhelpful label (or leak initials/an icon with no context),\nand the sender is already better conveyed by the message's own accessible name\nand position. Because the avatar is not the accessible-name carrier, it must\nnever be the _only_ place sender identity is expressed — pair it with a named\n`Root`, not instead of one.\n\n### Composing the transcript: `log` vs. `feed`\n\nTwo ARIA container roles fit a message transcript, and they are not\ninterchangeable:\n\n- **`role=\"log\"` with `aria-live=\"polite\"`** (recommended) — a live region that\n announces appended content, including streamed replies, without re-announcing\n the whole history on every token. It has no constraint on child roles, so a\n log can validly contain `<article>` messages, dividers, date separators, or\n anything else you need.\n- **`role=\"feed\"`** — the ARIA APG's dedicated pattern for scrollable article\n collections, with built-in \"read next/previous article\" keyboard support. Its\n trade-off: `feed` has an `aria-required-children` constraint — **every** child\n must have role `article`. Nesting a `log`, a plain `div` with non-article\n content, or a date separator inside a `feed` is an accessibility violation,\n not just a lint warning.\n\nUnless you're building the feed's article-to-article keyboard navigation,\n`role=\"log\"` is the simpler, safer default:\n\n```jsx live\nconst App = () => (\n <Box\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Conversation with the agent\"\n display=\"flex\"\n flexDirection=\"column\"\n gap=\"600\"\n >\n <ChatMessage.Root sender=\"user\" aria-label=\"Message from Ada Lovelace\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n\n <ChatMessage.Root sender=\"agent\" aria-label=\"Message from the agent\">\n <ChatMessage.Avatar aria-label=\"Agent\">\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12% week-over-week.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Box>\n);\n```\n\nIf you do reach for `role=\"feed\"`, keep every direct child an `<article>` —\n`ChatMessage.Root`'s default element already satisfies that — and don't mix in\nnon-article children.\n\n### Streaming state\n\n`isStreaming` on `ChatMessage.Root` sets `aria-busy=\"true\"`, flagging the\nmessage's content as still in flux. It intentionally does **not** create its own\nlive region: a live region mounted at the same time as its content is not\nannounced reliably by every screen reader (the region must already exist before\nits content changes). Keep the live region on your transcript container\n(`role=\"log\"` `aria-live=\"polite\"`, as above) so it persists across messages,\nand use `ChatMessage.Typing`'s `children` for a visible \"Agent is typing…\"\naffordance while streaming.\n\n### Conveying the sender\n\nSender is visually encoded by body color and column position (leading vs.\ntrailing vs. centered) — neither of which reaches assistive technology on its\nown. Per **WCAG 1.4.1 (Use of Color)** and **WCAG 1.3.1 (Info and\nRelationships)**, that information must also be available through another\nchannel: the message's accessible name (`aria-label`/`aria-labelledby`) is that\nchannel. Always name messages rather than depending on their look.\n\n### Reading order\n\nThe root's layout is CSS Grid with explicit per-slot placement, and the `sender`\nvariant swaps which grid column the avatar and body occupy — for\n`sender=\"user\"` the body is visually first and the avatar trails, independent\nof DOM order. Because grid placement doesn't reorder the underlying DOM,\nscreen-reader reading order follows DOM order, not visual order. Keeping the\navatar non-interactive (no focusable content, decorative by default) means this\ndivergence never affects keyboard tab order or gets in the way of reading the\nmessage content; it's only a concern if you make the avatar interactive, which\nisn't a supported pattern.\n\n### Accessibility standards\n\n- **Name, role, value:** `ChatMessage.Root` is an `<article>` by default; always\n give it an accessible name via `aria-label` or `aria-labelledby`.\n- **Info and relationships:** Sender and status information conveyed visually\n (body color, column position) must also be exposed through the message's\n accessible name, not color/position alone.\n- **Use of color:** `tone=\"error\"` is a visual cue only — pair it with visible\n text describing the failure (as in the error-tone example), not color alone.\n- **Non-text content:** The avatar is decorative (`aria-hidden`) unless named;\n when named, its label should identify the sender, not restate \"avatar\".\n- **Status messages:** Compose the transcript with `role=\"log\"`\n `aria-live=\"polite\"` (or a fully-`article`-only `role=\"feed\"`) so new and\n streamed messages are announced without the consumer building custom\n live-region logic.\n- **Focus order / no keyboard trap:** The avatar carries no focusable content,\n so the sender-dependent column swap never disrupts tab order.\n\n### Resources\n\n- [ARIA APG: Feed Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/feed/)\n- [WAI-ARIA: `log` role](https://www.w3.org/TR/wai-aria-1.2/#log)\n- [WCAG 2.1: Use of Color (1.4.1)](https://www.w3.org/WAI/WCAG21/Understanding/use-of-color.html)\n- [WCAG 2.1: Info and Relationships (1.3.1)](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)\n",
227
+ "toc": [
228
+ {
229
+ "value": "Accessibility",
230
+ "href": "#accessibility",
231
+ "depth": 2,
232
+ "numbering": [
233
+ 1,
234
+ 1
235
+ ],
236
+ "parent": "root"
237
+ },
238
+ {
239
+ "value": "Naming a message",
240
+ "href": "#naming-a-message",
241
+ "depth": 3,
242
+ "numbering": [
243
+ 1,
244
+ 1,
245
+ 1
246
+ ],
247
+ "parent": "root"
248
+ },
249
+ {
250
+ "value": "The avatar is decorative by default",
251
+ "href": "#the-avatar-is-decorative-by-default",
252
+ "depth": 3,
253
+ "numbering": [
254
+ 1,
255
+ 1,
256
+ 2
257
+ ],
258
+ "parent": "root"
259
+ },
260
+ {
261
+ "value": "Composing the transcript: log vs. feed",
262
+ "href": "#composing-the-transcript-log-vs-feed",
263
+ "depth": 3,
264
+ "numbering": [
265
+ 1,
266
+ 1,
267
+ 3
268
+ ],
269
+ "parent": "root"
270
+ },
271
+ {
272
+ "value": "Streaming state",
273
+ "href": "#streaming-state",
274
+ "depth": 3,
275
+ "numbering": [
276
+ 1,
277
+ 1,
278
+ 4
279
+ ],
280
+ "parent": "root"
281
+ },
282
+ {
283
+ "value": "Conveying the sender",
284
+ "href": "#conveying-the-sender",
285
+ "depth": 3,
286
+ "numbering": [
287
+ 1,
288
+ 1,
289
+ 5
290
+ ],
291
+ "parent": "root"
292
+ },
293
+ {
294
+ "value": "Reading order",
295
+ "href": "#reading-order",
296
+ "depth": 3,
297
+ "numbering": [
298
+ 1,
299
+ 1,
300
+ 6
301
+ ],
302
+ "parent": "root"
303
+ },
304
+ {
305
+ "value": "Accessibility standards",
306
+ "href": "#accessibility-standards",
307
+ "depth": 3,
308
+ "numbering": [
309
+ 1,
310
+ 1,
311
+ 7
312
+ ],
313
+ "parent": "root"
314
+ },
315
+ {
316
+ "value": "Resources",
317
+ "href": "#resources",
318
+ "depth": 3,
319
+ "numbering": [
320
+ 1,
321
+ 1,
322
+ 8
323
+ ],
324
+ "parent": "root"
325
+ }
326
+ ]
327
+ },
328
+ "dev": {
329
+ "mdx": "\n## Getting started\n\n### Import\n\n```tsx\nimport { ChatMessage, type ChatMessageProps } from \"@commercetools/nimbus\";\n```\n\n### Basic usage\n\n`ChatMessage` is a compound component: wrap `ChatMessage.Avatar` and\n`ChatMessage.Body` in `ChatMessage.Root`. `sender` defaults to `\"agent\"`.\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Here is the summary you asked for.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n## Usage examples\n\n### User and agent messages\n\n`sender=\"user\"` trails the avatar and uses the `colorPalette.2` surface\n(`primary` by default);\n`sender=\"agent\"` (the default) leads with the avatar. Name a message with\n`aria-label` (or `aria-labelledby`) — the avatar itself stays decorative unless\nyou give it `firstName`/`lastName` or its own `aria-label`.\n\n```jsx live-dev\nconst App = () => (\n <Stack gap=\"600\">\n <ChatMessage.Root sender=\"user\" aria-label=\"Message from Ada Lovelace\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders for me?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n <ChatMessage.Root sender=\"agent\" aria-label=\"Message from the agent\">\n <ChatMessage.Avatar aria-label=\"Agent\">\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12% week-over-week.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Stack>\n);\n```\n\n### System notices\n\nSystem notices and dividers aren't standardized in this release. There's no\ndedicated Nimbus component for them — because `ChatMessageList` is\ncontent-agnostic, a consumer renders their own centered, subdued content inside a\n`ChatMessageList.Item`.\n\n```jsx live-dev\nconst App = () => (\n <Box mx=\"auto\" textAlign=\"center\" color=\"neutral.11\" textStyle=\"sm\">\n Conversation history was cleared.\n </Box>\n);\n```\n\n### Tool output\n\nTool / function-call output is content _inside_ an `agent` message (there is no\n`sender=\"tool\"`) — for example a JSON code block rendered by `Markdown`.\n\n````jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Markdown>\n {[\"```json\", '{ \"orders\": 42, \"revenue\": 12890 }', \"```\"].join(\"\\n\")}\n </Markdown>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n````\n\n### Error tone\n\n`tone=\"error\"` is orthogonal to `sender` — it tints the body to flag a failed\ngeneration, so an `agent` message can be both `sender=\"agent\"` and\n`tone=\"error\"`.\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" tone=\"error\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Something went wrong generating this response.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Retry\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Actions\n\n`ChatMessage.Actions` renders a right-aligned button row inside the body.\nPlace it as the last child of `ChatMessage.Body` so it pins to the bottom of\nthe card.\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>I drafted the date range for your report. Approve to apply.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" colorPalette=\"primary\">\n Save as draft\n </Button>\n <Button variant=\"solid\" colorPalette=\"primary\">\n Approve\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Meta: timestamp and reactions\n\n`ChatMessage.Meta` renders a `space-between` row below the body — a trust link\non the start side, a timestamp and reaction `IconButton`s on the end side. With\na single child, `space-between` leaves it at the start of the row.\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Here is the summary you asked for.</Text>\n </ChatMessage.Body>\n <ChatMessage.Meta>\n <Link href=\"#\">How was this generated?</Link>\n <Stack direction=\"row\" alignItems=\"center\" gap=\"100\">\n <Text color=\"neutral.11\">Apr 13, 11:56pm</Text>\n <IconButton aria-label=\"Good response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbUp />\n </IconButton>\n <IconButton aria-label=\"Bad response\" variant=\"ghost\" size=\"xs\">\n <Icons.ThumbDown />\n </IconButton>\n <IconButton aria-label=\"Copy\" variant=\"ghost\" size=\"xs\">\n <Icons.ContentCopy />\n </IconButton>\n </Stack>\n </ChatMessage.Meta>\n </ChatMessage.Root>\n);\n```\n\n### Markdown payload\n\nThe body's payload is arbitrary content — render a `Markdown` string for\nformatted replies (lists, links, inline code, code blocks).\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Markdown>\n {[\n \"Here's what I found:\",\n \"\",\n \"- **Revenue** is up 12% week-over-week\",\n \"- Top SKU: `ABC-123`\",\n \"\",\n \"See the [full report](#) for details.\",\n ].join(\"\\n\")}\n </Markdown>\n <ChatMessage.Actions>\n <Button variant=\"solid\" colorPalette=\"primary\">\n Approve\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Streaming replies\n\nWhile a reply generates, set `isStreaming` on `ChatMessage.Root` (which sets\n`aria-busy`). Before the first token, render `ChatMessage.Typing` as the\nbody's payload; once text starts streaming, render it with\n`<Markdown isStreaming>` — the `Markdown` component owns safe incremental\nrendering (completing unterminated markdown, re-parsing only the final block per\ntoken), so `ChatMessage` never re-implements streamed-text rendering itself.\n\n```jsx live-dev\nconst App = () => (\n <ChatMessage.Root sender=\"agent\" isStreaming>\n <ChatMessage.Avatar>\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <ChatMessage.Typing>\n <Text color=\"neutral.11\">Agent is typing…</Text>\n </ChatMessage.Typing>\n </ChatMessage.Body>\n </ChatMessage.Root>\n);\n```\n\n### Accessible transcript (recommended composition)\n\n`ChatMessage` renders one message; you compose the transcript. Wrap the messages\nin a `role=\"log\"` `aria-live=\"polite\"` container so streamed replies are\nannounced without per-token spam, and name each message for assistive tech. See\nthe Accessibility tab for the full rationale, including why `role=\"feed\"` is not\na drop-in replacement here.\n\n```jsx live-dev\nconst App = () => (\n <Box\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Conversation with the agent\"\n display=\"flex\"\n flexDirection=\"column\"\n gap=\"600\"\n >\n <ChatMessage.Root sender=\"user\" aria-label=\"Message from Ada Lovelace\">\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Can you summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n\n <ChatMessage.Root sender=\"agent\" aria-label=\"Message from the agent\">\n <ChatMessage.Avatar aria-label=\"Agent\">\n <Icons.AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12% week-over-week.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Box>\n);\n```\n\n## Component requirements\n\n- Render `ChatMessage.Avatar` and `ChatMessage.Body` as direct children of\n `ChatMessage.Root`; add `ChatMessage.Meta` as a sibling after the body for a\n below-body row.\n- Nest `ChatMessage.Actions` inside `ChatMessage.Body`, as the last child, so\n it pins to the bottom of the card.\n- Non-message interjections (system notices, dividers) aren't standardized in\n this release — render your own centered, subdued content inside a\n `ChatMessageList.Item`; it is not a `sender` variant.\n- `ChatMessage.Root` renders a semantic `<article>` by default; override the\n element with `as` (for example `as=\"li\"` inside a list) when composing a\n transcript that needs a different tag.\n\n## Accessibility\n\n`ChatMessage` is a single-message primitive — it does not own the surrounding\nfeed's container semantics or live region. In brief: name each message with\n`aria-label`/`aria-labelledby`, keep the avatar decorative unless you give it a\nreal name, and set `isStreaming` for streamed replies (it sets `aria-busy`). See\nthe **Accessibility tab** for the full guidance on composing an accessible\ntranscript.\n\n## API reference\n\n<PropsTable id=\"ChatMessage\" />\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using\nChatMessage within your application. As the component's internal functionality\nis already tested by Nimbus, these patterns help you verify your integration and\napplication-specific logic.\n\n### Basic rendering\n\nCompose a single agent message from the ChatMessage parts.\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n ChatMessage,\n NimbusProvider,\n Text,\n Button,\n Link,\n Box,\n} from \"@commercetools/nimbus\";\nimport { AutoAwesome } from \"@commercetools/nimbus-icons\";\n\ndescribe(\"ChatMessage - Basic rendering\", () => {\n it(\"composes an agent message from its parts\", () => {\n render(\n <NimbusProvider>\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Avatar>\n <AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Here is the summary you asked for.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n expect(\n screen.getByText(\"Here is the summary you asked for.\")\n ).toBeInTheDocument();\n });\n});\n```\n\n### Senders and tone\n\nEach sender lays out differently; `tone=\"error\"` flags a failed generation.\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n ChatMessage,\n NimbusProvider,\n Text,\n Button,\n Link,\n Box,\n} from \"@commercetools/nimbus\";\nimport { AutoAwesome } from \"@commercetools/nimbus-icons\";\n\ndescribe(\"ChatMessage - Senders and tone\", () => {\n it.each([\"user\", \"agent\"] as const)(\"renders the %s sender\", (sender) => {\n render(\n <NimbusProvider>\n <ChatMessage.Root sender={sender} data-testid=\"body\">\n <ChatMessage.Body>\n <Text>{sender} message</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n expect(screen.getByTestId(\"body\")).toHaveTextContent(`${sender} message`);\n });\n\n it(\"renders an error-toned agent message with a retry action\", () => {\n render(\n <NimbusProvider>\n <ChatMessage.Root sender=\"agent\" tone=\"error\" data-testid=\"body\">\n <ChatMessage.Body>\n <Text>Something went wrong.</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\">Retry</Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n expect(screen.getByTestId(\"body\")).toHaveTextContent(\n \"Something went wrong.\"\n );\n expect(screen.getByRole(\"button\", { name: \"Retry\" })).toBeInTheDocument();\n });\n});\n```\n\n### Actions and meta\n\nWire action buttons to your own handlers; the meta row sits below the body.\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n ChatMessage,\n NimbusProvider,\n Text,\n Button,\n Link,\n Box,\n} from \"@commercetools/nimbus\";\nimport { AutoAwesome } from \"@commercetools/nimbus-icons\";\n\ndescribe(\"ChatMessage - Actions and meta\", () => {\n it(\"wires action buttons to consumer handlers\", async () => {\n const user = userEvent.setup();\n const onApprove = vi.fn();\n const onDismiss = vi.fn();\n\n render(\n <NimbusProvider>\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Body>\n <Text>Apply the suggested changes?</Text>\n <ChatMessage.Actions>\n <Button variant=\"outline\" onPress={onDismiss}>\n Dismiss\n </Button>\n <Button variant=\"solid\" onPress={onApprove}>\n Approve\n </Button>\n </ChatMessage.Actions>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n await user.click(screen.getByRole(\"button\", { name: \"Approve\" }));\n expect(onApprove).toHaveBeenCalledTimes(1);\n expect(onDismiss).not.toHaveBeenCalled();\n\n await user.click(screen.getByRole(\"button\", { name: \"Dismiss\" }));\n expect(onDismiss).toHaveBeenCalledTimes(1);\n });\n\n it(\"renders meta content below the body\", () => {\n render(\n <NimbusProvider>\n <ChatMessage.Root sender=\"agent\">\n <ChatMessage.Body>\n <Text>Done.</Text>\n </ChatMessage.Body>\n <ChatMessage.Meta>\n <Link href=\"#\">How was this generated?</Link>\n <Text>Apr 13, 11:56pm</Text>\n </ChatMessage.Meta>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"link\", { name: \"How was this generated?\" })\n ).toBeInTheDocument();\n expect(screen.getByText(\"Apr 13, 11:56pm\")).toBeInTheDocument();\n });\n});\n```\n\n### Streaming replies\n\nWhile generating, render ChatMessage.Typing and set isStreaming.\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n ChatMessage,\n NimbusProvider,\n Text,\n Button,\n Link,\n Box,\n} from \"@commercetools/nimbus\";\nimport { AutoAwesome } from \"@commercetools/nimbus-icons\";\n\ndescribe(\"ChatMessage - Streaming\", () => {\n it(\"shows a typing affordance while streaming\", () => {\n render(\n <NimbusProvider>\n <ChatMessage.Root sender=\"agent\" isStreaming>\n <ChatMessage.Avatar>\n <AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <ChatMessage.Typing>\n <Text>Agent is typing…</Text>\n </ChatMessage.Typing>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </NimbusProvider>\n );\n\n expect(screen.getByText(\"Agent is typing…\")).toBeInTheDocument();\n });\n});\n```\n\n### Accessible transcript\n\nChatMessage renders one message; name each message and compose several inside a live log region.\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n ChatMessage,\n NimbusProvider,\n Text,\n Button,\n Link,\n Box,\n} from \"@commercetools/nimbus\";\nimport { AutoAwesome } from \"@commercetools/nimbus-icons\";\n\ndescribe(\"ChatMessage - Accessible transcript\", () => {\n it(\"composes several named messages into a transcript\", () => {\n render(\n <NimbusProvider>\n <Box role=\"log\" aria-live=\"polite\" aria-label=\"Conversation\">\n <ChatMessage.Root\n sender=\"user\"\n aria-label=\"Message from Ada Lovelace\"\n >\n <ChatMessage.Avatar firstName=\"Ada\" lastName=\"Lovelace\" />\n <ChatMessage.Body>\n <Text>Summarise last week's orders?</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n\n <ChatMessage.Root sender=\"agent\" aria-label=\"Message from the agent\">\n <ChatMessage.Avatar>\n <AutoAwesome />\n </ChatMessage.Avatar>\n <ChatMessage.Body>\n <Text>Revenue is up 12%.</Text>\n </ChatMessage.Body>\n </ChatMessage.Root>\n </Box>\n </NimbusProvider>\n );\n\n expect(\n screen.getByText(\"Summarise last week's orders?\")\n ).toBeInTheDocument();\n expect(screen.getByText(\"Revenue is up 12%.\")).toBeInTheDocument();\n });\n});\n```\n\n\n## Resources\n\n- [Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-chatmessage--docs)\n",
330
+ "toc": [
331
+ {
332
+ "value": "Getting started",
333
+ "href": "#getting-started",
334
+ "depth": 2,
335
+ "numbering": [
336
+ 1,
337
+ 1
338
+ ],
339
+ "parent": "root"
340
+ },
341
+ {
342
+ "value": "Import",
343
+ "href": "#import",
344
+ "depth": 3,
345
+ "numbering": [
346
+ 1,
347
+ 1,
348
+ 1
349
+ ],
350
+ "parent": "root"
351
+ },
352
+ {
353
+ "value": "Basic usage",
354
+ "href": "#basic-usage",
355
+ "depth": 3,
356
+ "numbering": [
357
+ 1,
358
+ 1,
359
+ 2
360
+ ],
361
+ "parent": "root"
362
+ },
363
+ {
364
+ "value": "Usage examples",
365
+ "href": "#usage-examples",
366
+ "depth": 2,
367
+ "numbering": [
368
+ 1,
369
+ 2
370
+ ],
371
+ "parent": "root"
372
+ },
373
+ {
374
+ "value": "User and agent messages",
375
+ "href": "#user-and-agent-messages",
376
+ "depth": 3,
377
+ "numbering": [
378
+ 1,
379
+ 2,
380
+ 1
381
+ ],
382
+ "parent": "root"
383
+ },
384
+ {
385
+ "value": "System notices",
386
+ "href": "#system-notices",
387
+ "depth": 3,
388
+ "numbering": [
389
+ 1,
390
+ 2,
391
+ 2
392
+ ],
393
+ "parent": "root"
394
+ },
395
+ {
396
+ "value": "Tool output",
397
+ "href": "#tool-output",
398
+ "depth": 3,
399
+ "numbering": [
400
+ 1,
401
+ 2,
402
+ 3
403
+ ],
404
+ "parent": "root"
405
+ },
406
+ {
407
+ "value": "Error tone",
408
+ "href": "#error-tone",
409
+ "depth": 3,
410
+ "numbering": [
411
+ 1,
412
+ 2,
413
+ 4
414
+ ],
415
+ "parent": "root"
416
+ },
417
+ {
418
+ "value": "Actions",
419
+ "href": "#actions",
420
+ "depth": 3,
421
+ "numbering": [
422
+ 1,
423
+ 2,
424
+ 5
425
+ ],
426
+ "parent": "root"
427
+ },
428
+ {
429
+ "value": "Meta: timestamp and reactions",
430
+ "href": "#meta-timestamp-and-reactions",
431
+ "depth": 3,
432
+ "numbering": [
433
+ 1,
434
+ 2,
435
+ 6
436
+ ],
437
+ "parent": "root"
438
+ },
439
+ {
440
+ "value": "Markdown payload",
441
+ "href": "#markdown-payload",
442
+ "depth": 3,
443
+ "numbering": [
444
+ 1,
445
+ 2,
446
+ 7
447
+ ],
448
+ "parent": "root"
449
+ },
450
+ {
451
+ "value": "Streaming replies",
452
+ "href": "#streaming-replies",
453
+ "depth": 3,
454
+ "numbering": [
455
+ 1,
456
+ 2,
457
+ 8
458
+ ],
459
+ "parent": "root"
460
+ },
461
+ {
462
+ "value": "Accessible transcript (recommended composition)",
463
+ "href": "#accessible-transcript-recommended-composition",
464
+ "depth": 3,
465
+ "numbering": [
466
+ 1,
467
+ 2,
468
+ 9
469
+ ],
470
+ "parent": "root"
471
+ },
472
+ {
473
+ "value": "Component requirements",
474
+ "href": "#component-requirements",
475
+ "depth": 2,
476
+ "numbering": [
477
+ 1,
478
+ 3
479
+ ],
480
+ "parent": "root"
481
+ },
482
+ {
483
+ "value": "Accessibility",
484
+ "href": "#accessibility",
485
+ "depth": 2,
486
+ "numbering": [
487
+ 1,
488
+ 4
489
+ ],
490
+ "parent": "root"
491
+ },
492
+ {
493
+ "value": "API reference",
494
+ "href": "#api-reference",
495
+ "depth": 2,
496
+ "numbering": [
497
+ 1,
498
+ 5
499
+ ],
500
+ "parent": "root"
501
+ },
502
+ {
503
+ "value": "Testing your implementation",
504
+ "href": "#testing-your-implementation",
505
+ "depth": 2,
506
+ "numbering": [
507
+ 1,
508
+ 6
509
+ ],
510
+ "parent": "root"
511
+ },
512
+ {
513
+ "value": "Basic rendering",
514
+ "href": "#basic-rendering",
515
+ "depth": 3,
516
+ "numbering": [
517
+ 1,
518
+ 6,
519
+ 1
520
+ ],
521
+ "parent": "root"
522
+ },
523
+ {
524
+ "value": "Senders and tone",
525
+ "href": "#senders-and-tone",
526
+ "depth": 3,
527
+ "numbering": [
528
+ 1,
529
+ 6,
530
+ 2
531
+ ],
532
+ "parent": "root"
533
+ },
534
+ {
535
+ "value": "Actions and meta",
536
+ "href": "#actions-and-meta",
537
+ "depth": 3,
538
+ "numbering": [
539
+ 1,
540
+ 6,
541
+ 3
542
+ ],
543
+ "parent": "root"
544
+ },
545
+ {
546
+ "value": "Streaming replies",
547
+ "href": "#streaming-replies-1",
548
+ "depth": 3,
549
+ "numbering": [
550
+ 1,
551
+ 6,
552
+ 4
553
+ ],
554
+ "parent": "root"
555
+ },
556
+ {
557
+ "value": "Accessible transcript",
558
+ "href": "#accessible-transcript",
559
+ "depth": 3,
560
+ "numbering": [
561
+ 1,
562
+ 6,
563
+ 5
564
+ ],
565
+ "parent": "root"
566
+ },
567
+ {
568
+ "value": "Resources",
569
+ "href": "#resources",
570
+ "depth": 2,
571
+ "numbering": [
572
+ 1,
573
+ 7
574
+ ],
575
+ "parent": "root"
576
+ }
577
+ ]
578
+ }
579
+ }
580
+ }