@commercetools/nimbus-mcp 3.1.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.
- package/README.md +9 -1
- package/data/docs/route-manifest.json +806 -41
- package/data/docs/routes/components-buttons-button.json +25 -2
- package/data/docs/routes/components-chat-chat-message-list.json +448 -0
- package/data/docs/routes/components-chat-chat-message.json +580 -0
- package/data/docs/routes/components-content-markdown.json +548 -0
- package/data/docs/routes/components-feedback-activity-indicator.json +396 -0
- package/data/docs/routes/components-feedback-tooltip.json +23 -1
- package/data/docs/routes/components-inputs-drop-zone.json +562 -0
- package/data/docs/routes/components-inputs-file-trigger.json +421 -0
- package/data/docs/routes/components-layout-splitter.json +3 -3
- package/data/docs/routes/components-media-avatar.json +16 -5
- package/data/docs/routes/components-navigation-menu.json +1 -1
- package/data/docs/routes/components-navigation-tabnav.json +80 -14
- package/data/docs/routes/components-navigation-tabs.json +44 -11
- package/data/docs/routes/components-navigation-tree.json +445 -0
- package/data/docs/routes/home-getting-started-mcp-server-overview.json +2 -2
- package/data/docs/routes/home-getting-started-mcp-server-setup.json +2 -2
- package/data/docs/routes/patterns-buttons-floating-action-button.json +392 -0
- package/data/docs/routes/patterns-buttons.json +58 -0
- package/data/docs/search-index.json +1 -1
- package/data/docs/types/AccordionContent.json +27 -27
- package/data/docs/types/AccordionHeader.json +89 -89
- package/data/docs/types/AccordionItem.json +22 -22
- package/data/docs/types/AccordionRoot.json +14 -14
- package/data/docs/types/ActivityIndicator.json +202 -0
- package/data/docs/types/AlertDescription.json +8 -8
- package/data/docs/types/AlertDismissButton.json +98 -81
- package/data/docs/types/AlertTitle.json +8 -8
- package/data/docs/types/Avatar.json +19 -2
- package/data/docs/types/Badge.json +2 -2
- package/data/docs/types/Body.json +6 -6
- package/data/docs/types/Box.json +6 -6
- package/data/docs/types/Button.json +106 -89
- package/data/docs/types/Calendar.json +56 -56
- package/data/docs/types/Caption.json +6 -6
- package/data/docs/types/CardRoot.json +2 -2
- package/data/docs/types/Cell.json +20 -20
- package/data/docs/types/ChatMessage.json +12 -0
- package/data/docs/types/ChatMessageActions.json +42 -0
- package/data/docs/types/ChatMessageAvatar.json +140 -0
- package/data/docs/types/ChatMessageBody.json +42 -0
- package/data/docs/types/ChatMessageList.json +12 -0
- package/data/docs/types/ChatMessageListItem.json +42 -0
- package/data/docs/types/ChatMessageListRoot.json +78 -0
- package/data/docs/types/ChatMessageMeta.json +42 -0
- package/data/docs/types/ChatMessageRoot.json +119 -0
- package/data/docs/types/ChatMessageTyping.json +42 -0
- package/data/docs/types/Checkbox.json +88 -88
- package/data/docs/types/Code.json +11 -11
- package/data/docs/types/CollapsibleMotionContent.json +2 -2
- package/data/docs/types/CollapsibleMotionRoot.json +2 -2
- package/data/docs/types/CollapsibleMotionTrigger.json +4 -4
- package/data/docs/types/Column.json +8 -8
- package/data/docs/types/ColumnGroup.json +8 -8
- package/data/docs/types/ColumnHeader.json +18 -18
- package/data/docs/types/ComboBoxListBox.json +70 -70
- package/data/docs/types/ComboBoxOption.json +64 -64
- package/data/docs/types/ComboBoxPopover.json +91 -70
- package/data/docs/types/ComboBoxRoot.json +8 -8
- package/data/docs/types/ComboBoxSection.json +25 -25
- package/data/docs/types/ComboBoxTrigger.json +6 -6
- package/data/docs/types/Content.json +2 -2
- package/data/docs/types/DataTable.json +2 -2
- package/data/docs/types/DataTableBody.json +21 -21
- package/data/docs/types/DataTableHeader.json +27 -27
- package/data/docs/types/DataTableRoot.json +2 -2
- package/data/docs/types/DataTableTable.json +20 -20
- package/data/docs/types/DateInput.json +73 -73
- package/data/docs/types/DatePicker.json +58 -58
- package/data/docs/types/DateRangePicker.json +86 -86
- package/data/docs/types/DateRangePickerField.json +86 -86
- package/data/docs/types/DefaultPageBackLink.json +16 -16
- package/data/docs/types/DefaultPageRoot.json +2 -2
- package/data/docs/types/DialogCloseTrigger.json +96 -79
- package/data/docs/types/DialogTrigger.json +2 -2
- package/data/docs/types/DraggableListField.json +88 -60
- package/data/docs/types/DraggableListItem.json +53 -53
- package/data/docs/types/DraggableListRoot.json +88 -60
- package/data/docs/types/DrawerCloseTrigger.json +96 -79
- package/data/docs/types/DrawerTrigger.json +2 -2
- package/data/docs/types/DropZone.json +161 -0
- package/data/docs/types/FieldErrors.json +2 -2
- package/data/docs/types/FileTrigger.json +130 -0
- package/data/docs/types/Flex.json +22 -22
- package/data/docs/types/FloatingActionButton.json +1036 -0
- package/data/docs/types/Footer.json +6 -6
- package/data/docs/types/FormActionBar.json +1 -1
- package/data/docs/types/FormFieldRoot.json +2 -2
- package/data/docs/types/Grid.json +24 -24
- package/data/docs/types/Group.json +12 -12
- package/data/docs/types/Header.json +6 -6
- package/data/docs/types/Heading.json +8 -8
- package/data/docs/types/Icon.json +4 -4
- package/data/docs/types/IconButton.json +106 -89
- package/data/docs/types/IconToggleButton.json +73 -73
- package/data/docs/types/Image.json +63 -63
- package/data/docs/types/Indicator.json +6 -6
- package/data/docs/types/InlineSvg.json +2 -2
- package/data/docs/types/Item.json +6 -6
- package/data/docs/types/Kbd.json +8 -8
- package/data/docs/types/Link.json +30 -30
- package/data/docs/types/ListIndicator.json +6 -6
- package/data/docs/types/ListItem.json +6 -6
- package/data/docs/types/ListRoot.json +11 -11
- package/data/docs/types/LoadingSpinner.json +2 -2
- package/data/docs/types/MakeElementFocusable.json +18 -18
- package/data/docs/types/Markdown.json +183 -0
- package/data/docs/types/MenuItem.json +63 -63
- package/data/docs/types/MenuRoot.json +57 -57
- package/data/docs/types/MenuSection.json +31 -31
- package/data/docs/types/MenuSubmenuTrigger.json +4 -4
- package/data/docs/types/MenuTrigger.json +89 -89
- package/data/docs/types/MultilineTextInput.json +104 -104
- package/data/docs/types/MultilineTextInputField.json +102 -102
- package/data/docs/types/NumberInput.json +86 -86
- package/data/docs/types/NumberInputField.json +82 -82
- package/data/docs/types/PageContentColumn.json +6 -6
- package/data/docs/types/PageContentRoot.json +6 -6
- package/data/docs/types/PasswordInput.json +100 -100
- package/data/docs/types/PasswordInputField.json +100 -100
- package/data/docs/types/ProgressBar.json +13 -13
- package/data/docs/types/RadioInputOption.json +56 -56
- package/data/docs/types/RadioInputRoot.json +48 -48
- package/data/docs/types/RangeCalendar.json +58 -58
- package/data/docs/types/Region.json +6 -6
- package/data/docs/types/RegionTarget.json +6 -6
- package/data/docs/types/RichTextInput.json +2 -2
- package/data/docs/types/Root.json +11 -11
- package/data/docs/types/Row.json +6 -6
- package/data/docs/types/ScrollArea.json +2 -2
- package/data/docs/types/SearchInput.json +106 -106
- package/data/docs/types/SearchInputField.json +102 -102
- package/data/docs/types/SelectOption.json +54 -54
- package/data/docs/types/SelectOptionGroup.json +18 -18
- package/data/docs/types/SelectOptions.json +64 -64
- package/data/docs/types/SelectRoot.json +92 -92
- package/data/docs/types/Separator.json +4 -4
- package/data/docs/types/SimpleGrid.json +28 -28
- package/data/docs/types/SlidingIndicatorGeometry.json +9 -0
- package/data/docs/types/SlidingIndicatorRects.json +9 -0
- package/data/docs/types/SplitButton.json +16 -20
- package/data/docs/types/SplitterRoot.json +2 -2
- package/data/docs/types/Stack.json +2 -2
- package/data/docs/types/StepsNextTrigger.json +2 -2
- package/data/docs/types/StepsPrevTrigger.json +2 -2
- package/data/docs/types/StepsRoot.json +2 -2
- package/data/docs/types/StepsTrigger.json +2 -2
- package/data/docs/types/Switch.json +36 -36
- package/data/docs/types/TabNavItem.json +21 -21
- package/data/docs/types/TabNavRoot.json +5 -5
- package/data/docs/types/TableBody.json +6 -6
- package/data/docs/types/TableCaption.json +6 -6
- package/data/docs/types/TableCell.json +20 -20
- package/data/docs/types/TableColumn.json +8 -8
- package/data/docs/types/TableColumnGroup.json +8 -8
- package/data/docs/types/TableColumnHeader.json +18 -18
- package/data/docs/types/TableFooter.json +6 -6
- package/data/docs/types/TableHeader.json +6 -6
- package/data/docs/types/TableRoot.json +33 -33
- package/data/docs/types/TableRow.json +6 -6
- package/data/docs/types/TableScrollArea.json +6 -6
- package/data/docs/types/TabsList.json +2 -2
- package/data/docs/types/TabsPanel.json +2 -2
- package/data/docs/types/TabsPanels.json +2 -2
- package/data/docs/types/TabsRoot.json +3 -3
- package/data/docs/types/TabsTab.json +4 -4
- package/data/docs/types/TagGroupRoot.json +24 -24
- package/data/docs/types/TagGroupTag.json +56 -56
- package/data/docs/types/TagGroupTagList.json +15 -15
- package/data/docs/types/Text.json +8 -8
- package/data/docs/types/TextInput.json +102 -102
- package/data/docs/types/TextInputField.json +100 -100
- package/data/docs/types/TimeInput.json +68 -68
- package/data/docs/types/ToggleButton.json +75 -75
- package/data/docs/types/ToggleButtonGroupButton.json +32 -32
- package/data/docs/types/ToggleButtonGroupRoot.json +20 -20
- package/data/docs/types/Toolbar.json +9 -9
- package/data/docs/types/TooltipContent.json +28 -28
- package/data/docs/types/TooltipRoot.json +16 -16
- package/data/docs/types/Tree.json +12 -0
- package/data/docs/types/TreeIndicator.json +828 -0
- package/data/docs/types/TreeItem.json +559 -0
- package/data/docs/types/TreeItemContent.json +27 -0
- package/data/docs/types/TreeRoot.json +636 -0
- package/data/docs/types/TreeSubTree.json +40 -0
- package/data/docs/types/Trigger.json +4 -4
- package/data/docs/types/VisuallyHidden.json +6 -6
- package/data/docs/types/createItemsFromCsvDrop.json +4 -4
- package/data/docs/types/createItemsFromDirectoryDrop.json +4 -4
- package/data/docs/types/createItemsFromFileDrop.json +4 -4
- package/data/docs/types/createItemsFromImageDrop.json +4 -4
- package/data/docs/types/createItemsFromJsonDrop.json +4 -4
- package/data/docs/types/manifest.json +26 -0
- package/data/docs/types/useFocusInputOnFieldClick.json +11 -0
- package/data/docs/types/useRegion.json +2 -2
- package/data/docs/types/useSlidingIndicator.json +145 -0
- package/data/docs/types/useTree.json +267 -0
- package/data/tokens.json +21 -0
- package/data/uikit-tokens.json +894 -0
- package/dist/index.js +3298 -109
- package/package.json +8 -6
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"id": "Components-Markdown",
|
|
4
|
+
"title": "Markdown",
|
|
5
|
+
"exportName": "Markdown",
|
|
6
|
+
"description": "Renders a Markdown string into Nimbus-styled, accessible React elements with per-element overrides, custom renderers, and safe streaming for AI output.",
|
|
7
|
+
"lifecycleState": "Beta",
|
|
8
|
+
"order": 999,
|
|
9
|
+
"repoPath": "packages/nimbus/src/components/markdown/markdown.mdx",
|
|
10
|
+
"menu": [
|
|
11
|
+
"Components",
|
|
12
|
+
"Content",
|
|
13
|
+
"Markdown"
|
|
14
|
+
],
|
|
15
|
+
"route": "components/content/markdown",
|
|
16
|
+
"tags": [
|
|
17
|
+
"component",
|
|
18
|
+
"markdown",
|
|
19
|
+
"content",
|
|
20
|
+
"streaming",
|
|
21
|
+
"ai",
|
|
22
|
+
"llm"
|
|
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": "Key features",
|
|
37
|
+
"href": "#key-features",
|
|
38
|
+
"depth": 3,
|
|
39
|
+
"numbering": [
|
|
40
|
+
1,
|
|
41
|
+
1,
|
|
42
|
+
1
|
|
43
|
+
],
|
|
44
|
+
"parent": "root"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"value": "Basic usage",
|
|
48
|
+
"href": "#basic-usage",
|
|
49
|
+
"depth": 2,
|
|
50
|
+
"numbering": [
|
|
51
|
+
1,
|
|
52
|
+
2
|
|
53
|
+
],
|
|
54
|
+
"parent": "root"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"value": "Custom component tags",
|
|
58
|
+
"href": "#custom-component-tags",
|
|
59
|
+
"depth": 2,
|
|
60
|
+
"numbering": [
|
|
61
|
+
1,
|
|
62
|
+
3
|
|
63
|
+
],
|
|
64
|
+
"parent": "root"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"value": "Safe by default",
|
|
68
|
+
"href": "#safe-by-default",
|
|
69
|
+
"depth": 2,
|
|
70
|
+
"numbering": [
|
|
71
|
+
1,
|
|
72
|
+
4
|
|
73
|
+
],
|
|
74
|
+
"parent": "root"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"value": "Streaming",
|
|
78
|
+
"href": "#streaming",
|
|
79
|
+
"depth": 2,
|
|
80
|
+
"numbering": [
|
|
81
|
+
1,
|
|
82
|
+
5
|
|
83
|
+
],
|
|
84
|
+
"parent": "root"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"layout": "app-frame",
|
|
88
|
+
"tabs": [
|
|
89
|
+
{
|
|
90
|
+
"key": "overview",
|
|
91
|
+
"title": "Overview",
|
|
92
|
+
"order": 0
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"key": "guidelines",
|
|
96
|
+
"title": "Guidelines",
|
|
97
|
+
"order": 2
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"key": "dev",
|
|
101
|
+
"title": "Implementation",
|
|
102
|
+
"order": 3
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"key": "a11y",
|
|
106
|
+
"title": "Accessibility",
|
|
107
|
+
"order": 4
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"mdx": "\n## Overview\n\nMarkdown turns a Markdown source string into Nimbus-styled, accessible React\nelements. It is built on the headless [`react-markdown`](https://github.com/remarkjs/react-markdown)\nengine (remark/rehype/unified), so all styling is owned by Nimbus — there is no\nforeign CSS. GitHub Flavored Markdown (tables, task lists, strikethrough,\nautolinks) is on by default.\n\nIts primary use case is rendering **agentic / LLM streaming output** in chat and\nassistant UIs; it also renders authored content like release notes and\ndescriptions.\n\n> [!NOTE]\\\n> Markdown is in **beta**. Code blocks render as semantic, token-styled\n> `pre`/`code` without syntax highlighting or a copy button in v1 — a richer\n> `CodeBlock` is a planned fast-follow.\n\n### Key features\n\n- **Default Nimbus renderers** for every standard element, composed from\n existing design tokens (the Figma `Markdown/*` typography scale).\n- **Per-element overrides** — pass `components={{ a: MyLink }}` to replace any\n element's renderer; all other defaults stay intact.\n- **Custom component tags** — register a non-standard key\n (`components={{ SearchQueryResultCard: Card }}`) and embed that tag in the\n source; its attributes arrive as props. Self-closing and paired-with-children\n are both supported, any casing preserved.\n- **Safe by default** — raw HTML is never rendered, rendering is restricted to a\n safe element allowlist, and dangerous URLs are neutralized.\n- **Streaming-aware** — `isStreaming` completes half-written tokens, memoizes\n settled blocks, and manages an accessible busy/announcement model.\n\n## Basic usage\n\n```jsx live\nconst App = () => (\n <Markdown>\n {`# Hello\n\nThis is **Markdown** rendered with _Nimbus_ styling and a [link](https://commercetools.com).\n\n- Task lists\n- Tables\n- Code: \\`const x = 1\\``}\n </Markdown>\n);\n```\n\n## Custom component tags\n\nTo render your own components inside Markdown, register them in `components`\nunder the tag name you want to use, then embed that tag in the source:\n\n```jsx live\nconst App = () => (\n <Markdown\n components={{\n SearchQueryResultCard: ({ id }) => (\n <Box border=\"solid-25\" borderColor=\"primary.6\" borderRadius=\"200\" p=\"400\">\n <Text fontWeight=\"600\">Result for SKU {id}</Text>\n </Box>\n ),\n }}\n >\n {`Here is what I found:\n\n<SearchQueryResultCard id=\"sku-42\" />`}\n </Markdown>\n);\n```\n\nThe tag's string attributes are passed as props. Only registered tags are\nrendered — unregistered tags stay inert — so this stays safe by default.\n\n## Safe by default\n\nMarkdown has a single, safe security posture: raw HTML is never rendered, only a\nsafe element allowlist is rendered, and dangerous URLs (`javascript:`,\n`vbscript:`, `file:`) are neutralized. Image-host security is delegated to the\napplication's Content-Security-Policy, matching the Merchant Center convention.\nEmbed application components via custom component tags rather than raw HTML.\n\n## Streaming\n\nFor LLM output, set `isStreaming` while tokens arrive. Unterminated bold,\nitalic, inline code, and links are completed on the fly so the output never\nflashes literal `**` or `[` characters, and only the final block re-parses per\ntoken.\n",
|
|
112
|
+
"views": {
|
|
113
|
+
"overview": {
|
|
114
|
+
"mdx": "\n## Overview\n\nMarkdown turns a Markdown source string into Nimbus-styled, accessible React\nelements. It is built on the headless [`react-markdown`](https://github.com/remarkjs/react-markdown)\nengine (remark/rehype/unified), so all styling is owned by Nimbus — there is no\nforeign CSS. GitHub Flavored Markdown (tables, task lists, strikethrough,\nautolinks) is on by default.\n\nIts primary use case is rendering **agentic / LLM streaming output** in chat and\nassistant UIs; it also renders authored content like release notes and\ndescriptions.\n\n> [!NOTE]\\\n> Markdown is in **beta**. Code blocks render as semantic, token-styled\n> `pre`/`code` without syntax highlighting or a copy button in v1 — a richer\n> `CodeBlock` is a planned fast-follow.\n\n### Key features\n\n- **Default Nimbus renderers** for every standard element, composed from\n existing design tokens (the Figma `Markdown/*` typography scale).\n- **Per-element overrides** — pass `components={{ a: MyLink }}` to replace any\n element's renderer; all other defaults stay intact.\n- **Custom component tags** — register a non-standard key\n (`components={{ SearchQueryResultCard: Card }}`) and embed that tag in the\n source; its attributes arrive as props. Self-closing and paired-with-children\n are both supported, any casing preserved.\n- **Safe by default** — raw HTML is never rendered, rendering is restricted to a\n safe element allowlist, and dangerous URLs are neutralized.\n- **Streaming-aware** — `isStreaming` completes half-written tokens, memoizes\n settled blocks, and manages an accessible busy/announcement model.\n\n## Basic usage\n\n```jsx live\nconst App = () => (\n <Markdown>\n {`# Hello\n\nThis is **Markdown** rendered with _Nimbus_ styling and a [link](https://commercetools.com).\n\n- Task lists\n- Tables\n- Code: \\`const x = 1\\``}\n </Markdown>\n);\n```\n\n## Custom component tags\n\nTo render your own components inside Markdown, register them in `components`\nunder the tag name you want to use, then embed that tag in the source:\n\n```jsx live\nconst App = () => (\n <Markdown\n components={{\n SearchQueryResultCard: ({ id }) => (\n <Box border=\"solid-25\" borderColor=\"primary.6\" borderRadius=\"200\" p=\"400\">\n <Text fontWeight=\"600\">Result for SKU {id}</Text>\n </Box>\n ),\n }}\n >\n {`Here is what I found:\n\n<SearchQueryResultCard id=\"sku-42\" />`}\n </Markdown>\n);\n```\n\nThe tag's string attributes are passed as props. Only registered tags are\nrendered — unregistered tags stay inert — so this stays safe by default.\n\n## Safe by default\n\nMarkdown has a single, safe security posture: raw HTML is never rendered, only a\nsafe element allowlist is rendered, and dangerous URLs (`javascript:`,\n`vbscript:`, `file:`) are neutralized. Image-host security is delegated to the\napplication's Content-Security-Policy, matching the Merchant Center convention.\nEmbed application components via custom component tags rather than raw HTML.\n\n## Streaming\n\nFor LLM output, set `isStreaming` while tokens arrive. Unterminated bold,\nitalic, inline code, and links are completed on the fly so the output never\nflashes literal `**` or `[` characters, and only the final block re-parses per\ntoken.\n",
|
|
115
|
+
"toc": [
|
|
116
|
+
{
|
|
117
|
+
"value": "Overview",
|
|
118
|
+
"href": "#overview",
|
|
119
|
+
"depth": 2,
|
|
120
|
+
"numbering": [
|
|
121
|
+
1,
|
|
122
|
+
1
|
|
123
|
+
],
|
|
124
|
+
"parent": "root"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"value": "Key features",
|
|
128
|
+
"href": "#key-features",
|
|
129
|
+
"depth": 3,
|
|
130
|
+
"numbering": [
|
|
131
|
+
1,
|
|
132
|
+
1,
|
|
133
|
+
1
|
|
134
|
+
],
|
|
135
|
+
"parent": "root"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"value": "Basic usage",
|
|
139
|
+
"href": "#basic-usage",
|
|
140
|
+
"depth": 2,
|
|
141
|
+
"numbering": [
|
|
142
|
+
1,
|
|
143
|
+
2
|
|
144
|
+
],
|
|
145
|
+
"parent": "root"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"value": "Custom component tags",
|
|
149
|
+
"href": "#custom-component-tags",
|
|
150
|
+
"depth": 2,
|
|
151
|
+
"numbering": [
|
|
152
|
+
1,
|
|
153
|
+
3
|
|
154
|
+
],
|
|
155
|
+
"parent": "root"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"value": "Safe by default",
|
|
159
|
+
"href": "#safe-by-default",
|
|
160
|
+
"depth": 2,
|
|
161
|
+
"numbering": [
|
|
162
|
+
1,
|
|
163
|
+
4
|
|
164
|
+
],
|
|
165
|
+
"parent": "root"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"value": "Streaming",
|
|
169
|
+
"href": "#streaming",
|
|
170
|
+
"depth": 2,
|
|
171
|
+
"numbering": [
|
|
172
|
+
1,
|
|
173
|
+
5
|
|
174
|
+
],
|
|
175
|
+
"parent": "root"
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
"a11y": {
|
|
180
|
+
"mdx": "\n## Accessibility\n\nAccessibility ensures rendered Markdown is usable by everyone, including people\nwho rely on assistive technology. The default renderers enforce WCAG 2.1 AA for\nthe content they produce; a consumer override or a custom component tag owns the\naccessibility of whatever it renders.\n\n```jsx live\nconst App = () => (\n <Markdown>\n {`Visit the [Nimbus docs](https://nimbus-documentation.vercel.app) — external links automatically get a visible icon, an \"(opens in new tab)\" label for assistive technology, and \\`rel=\"noopener noreferrer\"\\`.`}\n </Markdown>\n);\n```\n\n### Headings (1.3.1, 2.4.6)\n\n- Headings render as semantic `<h1>`–`<h6>`. Use `headingOffset` to nest\n rendered headings beneath the host page's outline.\n- The component never adds a heading-level skip, and it renders author skips\n faithfully — a skip emits a development-mode warning rather than silently\n rewriting structure.\n\n### Links (2.4.4, 1.4.1, 1.4.11)\n\n- External links get `rel=\"noopener noreferrer\"`, `target=\"_blank\"`, an i18n\n \"(opens in new tab)\" label for assistive technology, and a visible icon\n indicator that is conveyed by shape (not color alone) and meets ≥3:1 non-text\n contrast.\n\n### Images (1.1.1)\n\n- Author `alt` text is preserved. A missing alt renders `alt=\"\"` (decorative)\n and warns in development. Images carry `loading=\"lazy\"` and\n `referrerpolicy=\"no-referrer\"`.\n\n### Tables (1.3.1)\n\n- Tables use real `<table>` / `<thead>` / `<th scope=\"col\">` semantics.\n\n### Lists & code\n\n- Real `<ul>` / `<ol>` and semantic `<pre><code>` are produced. GFM task-list\n checkboxes are read-only with an accessible name derived from the item text.\n\n### Streaming (4.1.3)\n\n- While `isStreaming` is set, the root carries `aria-busy=\"true\"`. When the\n stream settles, `aria-busy` clears and a single coalesced completion message\n is announced via a polite live region — no per-token announcement spam, and no\n ARIA wiring required from the consumer.\n\n### Color & motion\n\n- All default styles use AA-compliant tokens, and no streaming reveal animation\n is introduced.\n",
|
|
181
|
+
"toc": [
|
|
182
|
+
{
|
|
183
|
+
"value": "Accessibility",
|
|
184
|
+
"href": "#accessibility",
|
|
185
|
+
"depth": 2,
|
|
186
|
+
"numbering": [
|
|
187
|
+
1,
|
|
188
|
+
1
|
|
189
|
+
],
|
|
190
|
+
"parent": "root"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"value": "Headings (1.3.1, 2.4.6)",
|
|
194
|
+
"href": "#headings-131-246",
|
|
195
|
+
"depth": 3,
|
|
196
|
+
"numbering": [
|
|
197
|
+
1,
|
|
198
|
+
1,
|
|
199
|
+
1
|
|
200
|
+
],
|
|
201
|
+
"parent": "root"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"value": "Links (2.4.4, 1.4.1, 1.4.11)",
|
|
205
|
+
"href": "#links-244-141-1411",
|
|
206
|
+
"depth": 3,
|
|
207
|
+
"numbering": [
|
|
208
|
+
1,
|
|
209
|
+
1,
|
|
210
|
+
2
|
|
211
|
+
],
|
|
212
|
+
"parent": "root"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"value": "Images (1.1.1)",
|
|
216
|
+
"href": "#images-111",
|
|
217
|
+
"depth": 3,
|
|
218
|
+
"numbering": [
|
|
219
|
+
1,
|
|
220
|
+
1,
|
|
221
|
+
3
|
|
222
|
+
],
|
|
223
|
+
"parent": "root"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"value": "Tables (1.3.1)",
|
|
227
|
+
"href": "#tables-131",
|
|
228
|
+
"depth": 3,
|
|
229
|
+
"numbering": [
|
|
230
|
+
1,
|
|
231
|
+
1,
|
|
232
|
+
4
|
|
233
|
+
],
|
|
234
|
+
"parent": "root"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"value": "Lists & code",
|
|
238
|
+
"href": "#lists--code",
|
|
239
|
+
"depth": 3,
|
|
240
|
+
"numbering": [
|
|
241
|
+
1,
|
|
242
|
+
1,
|
|
243
|
+
5
|
|
244
|
+
],
|
|
245
|
+
"parent": "root"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"value": "Streaming (4.1.3)",
|
|
249
|
+
"href": "#streaming-413",
|
|
250
|
+
"depth": 3,
|
|
251
|
+
"numbering": [
|
|
252
|
+
1,
|
|
253
|
+
1,
|
|
254
|
+
6
|
|
255
|
+
],
|
|
256
|
+
"parent": "root"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"value": "Color & motion",
|
|
260
|
+
"href": "#color--motion",
|
|
261
|
+
"depth": 3,
|
|
262
|
+
"numbering": [
|
|
263
|
+
1,
|
|
264
|
+
1,
|
|
265
|
+
7
|
|
266
|
+
],
|
|
267
|
+
"parent": "root"
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
"dev": {
|
|
272
|
+
"mdx": "\n## Getting started\n\n`Markdown` renders a Markdown source string into Nimbus-styled, accessible React\nelements. It is a single entry point (not a compound component) plus a default\nrenderer map, built on the headless `react-markdown` engine with `remark-gfm`\nenabled by default.\n\n### Import\n\n```tsx\nimport { Markdown, type MarkdownProps } from \"@commercetools/nimbus\";\n```\n\n### Basic usage\n\nPass the Markdown source as the single string child. GitHub Flavored Markdown —\ntables, task lists, strikethrough, autolinks — is on by default.\n\n```jsx live-dev\nconst App = () => (\n <Markdown maxW=\"60ch\">\n {`# Release notes\n\nWe shipped **streaming** support and [GFM tables](https://github.github.com/gfm/).\n\n- A task list item\n- Inline code: \\`const x = 1\\`\n\n| Feature | Status |\n| --------- | ------ |\n| Streaming | Beta |\n`}\n </Markdown>\n);\n```\n\n## Usage examples\n\n### Overriding an element renderer\n\nPass a `components` entry keyed by HTML element name to replace that one\nrenderer; every other default stays intact. Every renderer also receives the\noriginal hast `node` — destructure it out before spreading onto a DOM element.\n\n```jsx live-dev\nconst App = () => (\n <Markdown\n components={{\n a: ({ children, href }) => (\n <Link href={href} fontColor=\"primary\">\n {children}\n </Link>\n ),\n }}\n >\n {`Route links through the app router, e.g. the [Nimbus docs](https://nimbus-documentation.vercel.app).`}\n </Markdown>\n);\n```\n\n### Custom component tags\n\nRegister a non-standard key in `components` and you can embed that tag directly\nin the Markdown source. The tag's string attributes are passed to the component\nas props, and tag names match by exact case (PascalCase preserved). Both\nself-closing (`<Tag />`) and paired (`<Tag>…</Tag>`) forms are supported; keep\nblank lines around a block-level paired tag so its content parses as markdown.\n\n```jsx live-dev\nconst App = () => (\n <Markdown\n components={{\n SearchResultCard: ({ id }) => (\n <Box border=\"solid-25\" borderColor=\"primary.6\" borderRadius=\"200\" p=\"400\">\n <Text fontWeight=\"600\">Result for SKU {id}</Text>\n </Box>\n ),\n }}\n >\n {`Here is what I found:\n\n<SearchResultCard id=\"sku-42\" />`}\n </Markdown>\n);\n```\n\n### Preserving the page outline\n\nWhen embedding Markdown beneath host-page headings, set `headingOffset` so the\nrendered headings nest rather than compete. Markdown heading level `L` renders as\n`min(L + headingOffset, 6)`.\n\n```jsx live-dev\nconst App = () => (\n <Markdown headingOffset={1}>\n {`# Looks like an h1 in source\n\nRenders as an h2, so it nests beneath a host page's h1.`}\n </Markdown>\n);\n```\n\n### Constraining the measure with style props\n\nStyle props forward to the outer root container, so you can set `maxW`, color,\nspacing, `lineClamp`, etc.\n\n```jsx live-dev\nconst App = () => (\n <Markdown maxW=\"48ch\" color=\"neutral.11\">\n {`Forwarding a \\`maxW\\` keeps long paragraphs at a comfortable line length. This paragraph wraps at roughly 48 characters so the measure stays readable instead of stretching the full container width.`}\n </Markdown>\n);\n```\n\n### Restricting the element set\n\nPass `allowedElements` to render only an explicit set of elements (mutually\nexclusive with `disallowedElements`). Filtered elements are dropped while their\ntext content is preserved.\n\n```jsx live-dev\nconst App = () => (\n <Markdown allowedElements={[\"p\", \"strong\", \"em\"]}>\n {`# This heading is filtered out\n\nOnly **paragraphs** and _inline emphasis_ survive the allowlist.`}\n </Markdown>\n);\n```\n\n### Rendering streamed (LLM) output\n\nSet `isStreaming` while tokens arrive. Unterminated constructs are completed via\n`remend`, content is split into memoized blocks (only the final block re-parses\nper token), the root sets `aria-busy`, and a single coalesced completion\nannouncement is made when the stream settles. Consumers never manage ARIA.\n\n```jsx live-dev\nconst FULL = `# Streaming demo\n\nThis text is revealed **token by token**, and half-written constructs never flash raw markup.`;\n\nconst App = () => {\n const [n, setN] = useState(0);\n const streaming = n < FULL.length;\n\n useEffect(() => {\n if (!streaming) return;\n const id = setTimeout(() => setN((v) => Math.min(v + 3, FULL.length)), 40);\n return () => clearTimeout(id);\n }, [n, streaming]);\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <Button size=\"xs\" alignSelf=\"start\" onPress={() => setN(0)}>\n Replay\n </Button>\n <Markdown isStreaming={streaming}>{FULL.slice(0, n)}</Markdown>\n </Stack>\n );\n};\n```\n\n## Default renderers\n\nOut of the box every standard element maps to a Nimbus-styled renderer using the\nFigma `Markdown/*` typography scale. Headings `#`–`####` map to the heading\nscale; `#####`/`######` fold to the smallest. External links automatically get\n`target=\"_blank\"`, `rel=\"noopener noreferrer\"`, an \"(opens in new tab)\" label,\nand a visible icon indicator. Images render with `loading=\"lazy\"` and\n`referrerpolicy=\"no-referrer\"`.\n\n## Safe by default\n\nRaw HTML is never rendered as live markup: it is skipped, rendering is restricted\nto a safe element allowlist, and dangerous URLs (`javascript:`, `vbscript:`,\n`file:`) are neutralized. Image-host security is the application CSP's\nresponsibility (`img-src`). To render application components, register them as\ncustom component tags (above) rather than embedding raw HTML.\n\n```jsx live-dev\nconst App = () => (\n <Markdown>\n {`Raw HTML is skipped: <script>alert(1)</script> renders nothing.\n\nA [dangerous link](javascript:alert(1)) is neutralized.`}\n </Markdown>\n);\n```\n\n## Accessibility\n\nThe default renderers enforce WCAG 2.1 AA and the component owns its own ARIA —\nincluding the streaming busy state and completion announcement, so no ARIA wiring\nis required from you. The two consumer-actionable items are:\n\n- **Preserve the outline** — set `headingOffset` when embedding beneath host\n headings so rendered headings nest correctly.\n- **Author meaningful `alt`** — a missing image alt renders `alt=\"\"` and warns in\n development.\n\nA consumer override or custom component tag owns the accessibility of whatever it\nrenders. See the **Accessibility** tab for the full per-element breakdown.\n\n## API reference\n\n<PropsTable id=\"Markdown\" />\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using Markdown in\nyour application. As the component's internal functionality is already tested by\nNimbus, these patterns help you verify your integration and application-specific\nlogic.\n\n### Basic rendering\n\nRender a Markdown string into Nimbus-styled, semantic elements\n\n```tsx\nimport { describe, it, expect } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport { Markdown, NimbusProvider } from \"@commercetools/nimbus\";\nimport type { MarkdownComponents } from \"./markdown.types\";\n\ndescribe(\"Markdown - Basic rendering\", () => {\n it(\"renders headings, paragraphs, and inline formatting\", () => {\n render(\n <NimbusProvider>\n <Markdown>{`# Release notes\\n\\nWe shipped **streaming** support.`}</Markdown>\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"heading\", { level: 1, name: \"Release notes\" })\n ).toBeInTheDocument();\n expect(screen.getByText(\"streaming\").tagName).toBe(\"STRONG\");\n });\n});\n```\n\n### Overriding an element renderer\n\nReplace a single element's renderer; all other defaults stay intact\n\n```tsx\nimport { describe, it, expect } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport { Markdown, NimbusProvider } from \"@commercetools/nimbus\";\nimport type { MarkdownComponents } from \"./markdown.types\";\n\ndescribe(\"Markdown - Per-element override\", () => {\n it(\"renders anchors with a custom component\", () => {\n const components: MarkdownComponents = {\n a: ({ children, href }) => (\n <a data-tracking=\"external\" href={href}>\n {children}\n </a>\n ),\n };\n\n render(\n <NimbusProvider>\n <Markdown components={components}>\n {`Read the [docs](https://docs.example.com).`}\n </Markdown>\n </NimbusProvider>\n );\n\n const link = screen.getByRole(\"link\", { name: \"docs\" });\n expect(link).toHaveAttribute(\"data-tracking\", \"external\");\n });\n});\n```\n\n### Embedding custom component tags\n\nRegister a tag in `components`, then embed it in the source; its attributes arrive as props\n\n```tsx\nimport { describe, it, expect } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport { Markdown, NimbusProvider } from \"@commercetools/nimbus\";\nimport type { MarkdownComponents } from \"./markdown.types\";\n\ndescribe(\"Markdown - Custom component tags\", () => {\n it(\"renders a registered custom tag with its attributes as props\", () => {\n const components: MarkdownComponents = {\n SearchQueryResultCard: (props: { id?: string; node?: unknown }) => (\n <div data-testid=\"result-card\" data-id={props.id} />\n ),\n };\n\n render(\n <NimbusProvider>\n <Markdown components={components}>\n {`Top result:\\n\\n<SearchQueryResultCard id=\"sku-42\" />`}\n </Markdown>\n </NimbusProvider>\n );\n\n expect(screen.getByTestId(\"result-card\")).toHaveAttribute(\n \"data-id\",\n \"sku-42\"\n );\n });\n\n it(\"leaves an unregistered tag inert\", () => {\n const { container } = render(\n <NimbusProvider>\n <Markdown>{`Before <UnknownWidget /> after.`}</Markdown>\n </NimbusProvider>\n );\n\n const root = container.querySelector(\".nimbus-markdown\");\n expect(root?.querySelector(\"unknownwidget\")).toBeNull();\n expect(screen.getByText(/Before/)).toBeInTheDocument();\n });\n});\n```\n\n### Safe by default\n\nRaw HTML is never rendered as live markup, and dangerous URLs are neutralized\n\n```tsx\nimport { describe, it, expect } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport { Markdown, NimbusProvider } from \"@commercetools/nimbus\";\nimport type { MarkdownComponents } from \"./markdown.types\";\n\ndescribe(\"Markdown - Safe by default\", () => {\n it(\"does not render raw HTML\", () => {\n const { container } = render(\n <NimbusProvider>\n <Markdown>{`Hello <script>alert(1)</script> world.`}</Markdown>\n </NimbusProvider>\n );\n\n const root = container.querySelector(\".nimbus-markdown\");\n expect(root?.querySelector(\"script\")).toBeNull();\n expect(screen.getByText(/Hello/)).toBeInTheDocument();\n });\n});\n```\n\n### Rendering streamed (LLM) output\n\nSet `isStreaming` so partial tokens render cleanly while a response streams in\n\n```tsx\nimport { describe, it, expect } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport { Markdown, NimbusProvider } from \"@commercetools/nimbus\";\nimport type { MarkdownComponents } from \"./markdown.types\";\n\ndescribe(\"Markdown - Streaming\", () => {\n it(\"completes an unterminated construct so it renders as formatted content\", () => {\n render(\n <NimbusProvider>\n {/* A model has emitted a half-written bold span. */}\n <Markdown isStreaming>{`A sentence with **bold tex`}</Markdown>\n </NimbusProvider>\n );\n\n expect(screen.getByText(\"bold tex\").tagName).toBe(\"STRONG\");\n });\n});\n```\n\n\n## Resources\n\n- [Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-content-markdown--docs)\n- [react-markdown](https://github.com/remarkjs/react-markdown)\n- [remark-gfm (GitHub Flavored Markdown)](https://github.com/remarkjs/remark-gfm)\n- [GitHub alerts syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)\n",
|
|
273
|
+
"toc": [
|
|
274
|
+
{
|
|
275
|
+
"value": "Getting started",
|
|
276
|
+
"href": "#getting-started",
|
|
277
|
+
"depth": 2,
|
|
278
|
+
"numbering": [
|
|
279
|
+
1,
|
|
280
|
+
1
|
|
281
|
+
],
|
|
282
|
+
"parent": "root"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"value": "Import",
|
|
286
|
+
"href": "#import",
|
|
287
|
+
"depth": 3,
|
|
288
|
+
"numbering": [
|
|
289
|
+
1,
|
|
290
|
+
1,
|
|
291
|
+
1
|
|
292
|
+
],
|
|
293
|
+
"parent": "root"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"value": "Basic usage",
|
|
297
|
+
"href": "#basic-usage",
|
|
298
|
+
"depth": 3,
|
|
299
|
+
"numbering": [
|
|
300
|
+
1,
|
|
301
|
+
1,
|
|
302
|
+
2
|
|
303
|
+
],
|
|
304
|
+
"parent": "root"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"value": "Usage examples",
|
|
308
|
+
"href": "#usage-examples",
|
|
309
|
+
"depth": 2,
|
|
310
|
+
"numbering": [
|
|
311
|
+
1,
|
|
312
|
+
2
|
|
313
|
+
],
|
|
314
|
+
"parent": "root"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"value": "Overriding an element renderer",
|
|
318
|
+
"href": "#overriding-an-element-renderer",
|
|
319
|
+
"depth": 3,
|
|
320
|
+
"numbering": [
|
|
321
|
+
1,
|
|
322
|
+
2,
|
|
323
|
+
1
|
|
324
|
+
],
|
|
325
|
+
"parent": "root"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"value": "Custom component tags",
|
|
329
|
+
"href": "#custom-component-tags",
|
|
330
|
+
"depth": 3,
|
|
331
|
+
"numbering": [
|
|
332
|
+
1,
|
|
333
|
+
2,
|
|
334
|
+
2
|
|
335
|
+
],
|
|
336
|
+
"parent": "root"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"value": "Preserving the page outline",
|
|
340
|
+
"href": "#preserving-the-page-outline",
|
|
341
|
+
"depth": 3,
|
|
342
|
+
"numbering": [
|
|
343
|
+
1,
|
|
344
|
+
2,
|
|
345
|
+
3
|
|
346
|
+
],
|
|
347
|
+
"parent": "root"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"value": "Constraining the measure with style props",
|
|
351
|
+
"href": "#constraining-the-measure-with-style-props",
|
|
352
|
+
"depth": 3,
|
|
353
|
+
"numbering": [
|
|
354
|
+
1,
|
|
355
|
+
2,
|
|
356
|
+
4
|
|
357
|
+
],
|
|
358
|
+
"parent": "root"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"value": "Restricting the element set",
|
|
362
|
+
"href": "#restricting-the-element-set",
|
|
363
|
+
"depth": 3,
|
|
364
|
+
"numbering": [
|
|
365
|
+
1,
|
|
366
|
+
2,
|
|
367
|
+
5
|
|
368
|
+
],
|
|
369
|
+
"parent": "root"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"value": "Rendering streamed (LLM) output",
|
|
373
|
+
"href": "#rendering-streamed-llm-output",
|
|
374
|
+
"depth": 3,
|
|
375
|
+
"numbering": [
|
|
376
|
+
1,
|
|
377
|
+
2,
|
|
378
|
+
6
|
|
379
|
+
],
|
|
380
|
+
"parent": "root"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"value": "Default renderers",
|
|
384
|
+
"href": "#default-renderers",
|
|
385
|
+
"depth": 2,
|
|
386
|
+
"numbering": [
|
|
387
|
+
1,
|
|
388
|
+
3
|
|
389
|
+
],
|
|
390
|
+
"parent": "root"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"value": "Safe by default",
|
|
394
|
+
"href": "#safe-by-default",
|
|
395
|
+
"depth": 2,
|
|
396
|
+
"numbering": [
|
|
397
|
+
1,
|
|
398
|
+
4
|
|
399
|
+
],
|
|
400
|
+
"parent": "root"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"value": "Accessibility",
|
|
404
|
+
"href": "#accessibility",
|
|
405
|
+
"depth": 2,
|
|
406
|
+
"numbering": [
|
|
407
|
+
1,
|
|
408
|
+
5
|
|
409
|
+
],
|
|
410
|
+
"parent": "root"
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"value": "API reference",
|
|
414
|
+
"href": "#api-reference",
|
|
415
|
+
"depth": 2,
|
|
416
|
+
"numbering": [
|
|
417
|
+
1,
|
|
418
|
+
6
|
|
419
|
+
],
|
|
420
|
+
"parent": "root"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"value": "Testing your implementation",
|
|
424
|
+
"href": "#testing-your-implementation",
|
|
425
|
+
"depth": 2,
|
|
426
|
+
"numbering": [
|
|
427
|
+
1,
|
|
428
|
+
7
|
|
429
|
+
],
|
|
430
|
+
"parent": "root"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"value": "Basic rendering",
|
|
434
|
+
"href": "#basic-rendering",
|
|
435
|
+
"depth": 3,
|
|
436
|
+
"numbering": [
|
|
437
|
+
1,
|
|
438
|
+
7,
|
|
439
|
+
1
|
|
440
|
+
],
|
|
441
|
+
"parent": "root"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"value": "Overriding an element renderer",
|
|
445
|
+
"href": "#overriding-an-element-renderer-1",
|
|
446
|
+
"depth": 3,
|
|
447
|
+
"numbering": [
|
|
448
|
+
1,
|
|
449
|
+
7,
|
|
450
|
+
2
|
|
451
|
+
],
|
|
452
|
+
"parent": "root"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"value": "Embedding custom component tags",
|
|
456
|
+
"href": "#embedding-custom-component-tags",
|
|
457
|
+
"depth": 3,
|
|
458
|
+
"numbering": [
|
|
459
|
+
1,
|
|
460
|
+
7,
|
|
461
|
+
3
|
|
462
|
+
],
|
|
463
|
+
"parent": "root"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"value": "Safe by default",
|
|
467
|
+
"href": "#safe-by-default-1",
|
|
468
|
+
"depth": 3,
|
|
469
|
+
"numbering": [
|
|
470
|
+
1,
|
|
471
|
+
7,
|
|
472
|
+
4
|
|
473
|
+
],
|
|
474
|
+
"parent": "root"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"value": "Rendering streamed (LLM) output",
|
|
478
|
+
"href": "#rendering-streamed-llm-output-1",
|
|
479
|
+
"depth": 3,
|
|
480
|
+
"numbering": [
|
|
481
|
+
1,
|
|
482
|
+
7,
|
|
483
|
+
5
|
|
484
|
+
],
|
|
485
|
+
"parent": "root"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"value": "Resources",
|
|
489
|
+
"href": "#resources",
|
|
490
|
+
"depth": 2,
|
|
491
|
+
"numbering": [
|
|
492
|
+
1,
|
|
493
|
+
8
|
|
494
|
+
],
|
|
495
|
+
"parent": "root"
|
|
496
|
+
}
|
|
497
|
+
]
|
|
498
|
+
},
|
|
499
|
+
"guidelines": {
|
|
500
|
+
"mdx": "\n## Guidelines\n\nMarkdown guidelines ensure rendered rich text stays consistent, readable, and\naccessible across the product — whether the source is authored content or live\nAI output.\n\n### Best practices\n\n- **Register only trusted components:** custom component tags render only when\n you register them in `components`, so register components you control and that\n are safe to drive from the rendered source. Unregistered tags stay inert.\n- **Preserve the page outline:** when embedding Markdown inside a page that\n already has headings, set `headingOffset` so the rendered headings nest\n beneath the host heading rather than competing with it.\n- **Constrain measure for readability:** forward a `maxW` (e.g. `60ch`) so long\n paragraphs wrap at a comfortable line length.\n- **Stream for AI:** set `isStreaming` while a model response is arriving so\n partial tokens render cleanly and screen-reader users get a coherent\n loading → done model.\n- **Provide alt text:** author images with meaningful `alt`. Decorative-only\n images should still be intentional — a missing alt warns in development.\n\n### Usage\n\n- **Do** override individual element renderers when you need product-specific\n behavior (e.g. routing links through your app router).\n- **Do** embed your own components with custom component tags (e.g. result\n cards in chat output) instead of reaching for raw HTML.\n- **Do** keep code output simple in v1 — a plain styled code block is rendered;\n rich code chrome is a fast-follow.\n- **Don't** rely on raw HTML in the source — it is never rendered as live markup.\n- **Don't** reimplement image-host allowlisting in the component — that is the\n application Content-Security-Policy's job.\n\n### Content\n\n- Keep headings hierarchical; don't skip levels (a skip warns in development).\n- Use tables for tabular data only; GFM cannot express complex multi-header\n tables.\n- Prefer descriptive link text over \"click here\".\n",
|
|
501
|
+
"toc": [
|
|
502
|
+
{
|
|
503
|
+
"value": "Guidelines",
|
|
504
|
+
"href": "#guidelines",
|
|
505
|
+
"depth": 2,
|
|
506
|
+
"numbering": [
|
|
507
|
+
1,
|
|
508
|
+
1
|
|
509
|
+
],
|
|
510
|
+
"parent": "root"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"value": "Best practices",
|
|
514
|
+
"href": "#best-practices",
|
|
515
|
+
"depth": 3,
|
|
516
|
+
"numbering": [
|
|
517
|
+
1,
|
|
518
|
+
1,
|
|
519
|
+
1
|
|
520
|
+
],
|
|
521
|
+
"parent": "root"
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
"value": "Usage",
|
|
525
|
+
"href": "#usage",
|
|
526
|
+
"depth": 3,
|
|
527
|
+
"numbering": [
|
|
528
|
+
1,
|
|
529
|
+
1,
|
|
530
|
+
2
|
|
531
|
+
],
|
|
532
|
+
"parent": "root"
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
"value": "Content",
|
|
536
|
+
"href": "#content",
|
|
537
|
+
"depth": 3,
|
|
538
|
+
"numbering": [
|
|
539
|
+
1,
|
|
540
|
+
1,
|
|
541
|
+
3
|
|
542
|
+
],
|
|
543
|
+
"parent": "root"
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|