@fragments-sdk/ui 0.17.0 → 0.18.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/dist/assets/ui.css +320 -183
- package/dist/components/Header/Header.module.scss.cjs +42 -21
- package/dist/components/Header/Header.module.scss.js +42 -21
- package/dist/components/Header/index.cjs +121 -3
- package/dist/components/Header/index.d.ts +26 -3
- package/dist/components/Header/index.d.ts.map +1 -1
- package/dist/components/Header/index.js +122 -4
- package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
- package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/fragments.json +1 -1
- package/package.json +3 -3
- package/src/components/Accordion/Accordion.contract.json +169 -0
- package/src/components/Alert/Alert.contract.json +157 -0
- package/src/components/AppShell/AppShell.contract.json +155 -0
- package/src/components/Avatar/Avatar.contract.json +189 -0
- package/src/components/Badge/Badge.contract.json +187 -0
- package/src/components/BentoGrid/BentoGrid.contract.json +135 -0
- package/src/components/Box/Box.contract.json +423 -0
- package/src/components/Breadcrumbs/Breadcrumbs.contract.json +143 -0
- package/src/components/Button/Button.contract.json +205 -0
- package/src/components/ButtonGroup/ButtonGroup.contract.json +140 -0
- package/src/components/Card/Card.contract.json +185 -0
- package/src/components/Chart/Chart.contract.json +129 -0
- package/src/components/Checkbox/Checkbox.contract.json +246 -0
- package/src/components/Chip/Chip.contract.json +212 -0
- package/src/components/CodeBlock/CodeBlock.contract.json +388 -0
- package/src/components/Collapsible/Collapsible.contract.json +154 -0
- package/src/components/ColorPicker/ColorPicker.contract.json +212 -0
- package/src/components/Combobox/Combobox.contract.json +297 -0
- package/src/components/Command/Command.contract.json +165 -0
- package/src/components/ConversationList/ConversationList.contract.json +151 -0
- package/src/components/DataTable/DataTable.contract.json +302 -0
- package/src/components/DatePicker/DatePicker.contract.json +288 -0
- package/src/components/Dialog/Dialog.contract.json +159 -0
- package/src/components/Drawer/Drawer.contract.json +160 -0
- package/src/components/Editor/Editor.contract.json +263 -0
- package/src/components/EmptyState/EmptyState.contract.json +133 -0
- package/src/components/Field/Field.contract.json +157 -0
- package/src/components/Fieldset/Fieldset.contract.json +117 -0
- package/src/components/Form/Form.contract.json +145 -0
- package/src/components/Grid/Grid.contract.json +195 -0
- package/src/components/Header/Header.contract.json +194 -0
- package/src/components/Header/Header.module.scss +99 -0
- package/src/components/Header/index.tsx +191 -10
- package/src/components/Icon/Icon.contract.json +194 -0
- package/src/components/Image/Image.contract.json +209 -0
- package/src/components/Input/Input.contract.json +344 -0
- package/src/components/Link/Link.contract.json +180 -0
- package/src/components/List/List.contract.json +154 -0
- package/src/components/Listbox/Listbox.contract.json +158 -0
- package/src/components/Loading/Loading.contract.json +167 -0
- package/src/components/Markdown/Markdown.contract.json +127 -0
- package/src/components/Menu/Menu.contract.json +177 -0
- package/src/components/Message/Message.contract.json +183 -0
- package/src/components/NavigationMenu/NavigationMenu.contract.json +203 -0
- package/src/components/Pagination/Pagination.contract.json +163 -0
- package/src/components/Popover/Popover.contract.json +163 -0
- package/src/components/Progress/Progress.contract.json +176 -0
- package/src/components/Prompt/Prompt.contract.json +211 -0
- package/src/components/RadioGroup/RadioGroup.contract.json +226 -0
- package/src/components/ScrollArea/ScrollArea.contract.json +131 -0
- package/src/components/Select/Select.contract.json +269 -0
- package/src/components/Separator/Separator.contract.json +143 -0
- package/src/components/Sidebar/Sidebar.contract.json +258 -0
- package/src/components/Sidebar/Sidebar.module.scss +6 -4
- package/src/components/Skeleton/Skeleton.contract.json +166 -0
- package/src/components/Slider/Slider.contract.json +248 -0
- package/src/components/Stack/Stack.contract.json +220 -0
- package/src/components/Table/Table.contract.json +171 -0
- package/src/components/TableOfContents/TableOfContents.contract.json +145 -0
- package/src/components/Tabs/Tabs.contract.json +159 -0
- package/src/components/Text/Text.contract.json +239 -0
- package/src/components/Textarea/Textarea.contract.json +308 -0
- package/src/components/Theme/Theme.contract.json +152 -0
- package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +165 -0
- package/src/components/Toast/Toast.contract.json +181 -0
- package/src/components/Toggle/Toggle.contract.json +231 -0
- package/src/components/ToggleGroup/ToggleGroup.contract.json +206 -0
- package/src/components/Tooltip/Tooltip.contract.json +214 -0
- package/src/components/VisuallyHidden/VisuallyHidden.contract.json +116 -0
- package/src/index.ts +1 -0
- package/src/tokens/_derive.scss +4 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Listbox",
|
|
4
|
+
"description": "Controlled listbox for search results, autocomplete dropdowns, and command menus. Provides Menu-like styling without requiring a trigger.",
|
|
5
|
+
"category": "forms",
|
|
6
|
+
"tags": [
|
|
7
|
+
"listbox",
|
|
8
|
+
"search",
|
|
9
|
+
"autocomplete",
|
|
10
|
+
"combobox",
|
|
11
|
+
"command",
|
|
12
|
+
"dropdown"
|
|
13
|
+
],
|
|
14
|
+
"status": "stable",
|
|
15
|
+
"sourcePath": "src/components/Listbox/index.tsx",
|
|
16
|
+
"exportName": "Listbox",
|
|
17
|
+
"propsSummary": [
|
|
18
|
+
"children: node (required)",
|
|
19
|
+
"style: object",
|
|
20
|
+
"tabIndex: number",
|
|
21
|
+
"onFocus: function",
|
|
22
|
+
"onKeyDown: function"
|
|
23
|
+
],
|
|
24
|
+
"props": {
|
|
25
|
+
"children": {
|
|
26
|
+
"type": "node",
|
|
27
|
+
"description": "Listbox.Item, Listbox.Group, or Listbox.Empty components",
|
|
28
|
+
"required": true
|
|
29
|
+
},
|
|
30
|
+
"style": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"description": "",
|
|
33
|
+
"required": false
|
|
34
|
+
},
|
|
35
|
+
"tabIndex": {
|
|
36
|
+
"type": "number",
|
|
37
|
+
"description": "",
|
|
38
|
+
"required": false
|
|
39
|
+
},
|
|
40
|
+
"onFocus": {
|
|
41
|
+
"type": "function",
|
|
42
|
+
"description": "",
|
|
43
|
+
"required": false
|
|
44
|
+
},
|
|
45
|
+
"onKeyDown": {
|
|
46
|
+
"type": "function",
|
|
47
|
+
"description": "",
|
|
48
|
+
"required": false
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"usage": {
|
|
52
|
+
"when": [
|
|
53
|
+
"Search result dropdowns",
|
|
54
|
+
"Autocomplete suggestions",
|
|
55
|
+
"Command palette results",
|
|
56
|
+
"Keyboard-navigable option lists"
|
|
57
|
+
],
|
|
58
|
+
"whenNot": [
|
|
59
|
+
"Static lists without selection (use List)",
|
|
60
|
+
"Action menus with trigger button (use Menu)",
|
|
61
|
+
"Form field selection (use Select)",
|
|
62
|
+
"Navigation menus (use Sidebar or Tabs)"
|
|
63
|
+
],
|
|
64
|
+
"guidelines": [
|
|
65
|
+
"Control open/close state externally based on input focus or query",
|
|
66
|
+
"Listbox provides arrow/home/end + Enter/Space keyboard navigation when focused",
|
|
67
|
+
"Use Listbox.Empty for no results state",
|
|
68
|
+
"Group related items with Listbox.Group when appropriate"
|
|
69
|
+
],
|
|
70
|
+
"accessibility": [
|
|
71
|
+
"Uses listbox and option ARIA roles",
|
|
72
|
+
"aria-selected indicates current selection",
|
|
73
|
+
"aria-disabled for non-interactive items",
|
|
74
|
+
"Connect to input with aria-controls for full combobox pattern"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"examples": [
|
|
78
|
+
{
|
|
79
|
+
"name": "Default",
|
|
80
|
+
"description": "Basic listbox with selectable items",
|
|
81
|
+
"code": "<Listbox aria-label=\"Options\">\n <Listbox.Item selected>First option</Listbox.Item>\n <Listbox.Item>Second option</Listbox.Item>\n <Listbox.Item>Third option</Listbox.Item>\n</Listbox>"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "Search Results",
|
|
85
|
+
"description": "Typical search results pattern with label and metadata",
|
|
86
|
+
"code": "<Listbox aria-label=\"Search results\">\n <Listbox.Item selected>\n <span style={{ fontWeight: 500 }}>Button</span>\n <span style={{ marginLeft: 'auto', fontSize: '0.75rem', color: 'var(--fui-text-tertiary)' }}>Components</span>\n </Listbox.Item>\n <Listbox.Item>\n <span style={{ fontWeight: 500 }}>Badge</span>\n <span style={{ marginLeft: 'auto', fontSize: '0.75rem', color: 'var(--fui-text-tertiary)' }}>Components</span>\n </Listbox.Item>\n <Listbox.Item>\n <span style={{ fontWeight: 500 }}>Box</span>\n <span style={{ marginLeft: 'auto', fontSize: '0.75rem', color: 'var(--fui-text-tertiary)' }}>Layout</span>\n </Listbox.Item>\n</Listbox>"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "With Groups",
|
|
90
|
+
"description": "Grouped items with labels",
|
|
91
|
+
"code": "<Listbox aria-label=\"Commands\">\n <Listbox.Group label=\"Recent\">\n <Listbox.Item selected>Open file...</Listbox.Item>\n <Listbox.Item>Save as...</Listbox.Item>\n </Listbox.Group>\n <Listbox.Group label=\"Actions\">\n <Listbox.Item>Copy</Listbox.Item>\n <Listbox.Item>Paste</Listbox.Item>\n <Listbox.Item disabled>Cut</Listbox.Item>\n </Listbox.Group>\n</Listbox>"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "Empty State",
|
|
95
|
+
"description": "No results found message",
|
|
96
|
+
"code": "<Listbox aria-label=\"Search results\">\n <Listbox.Empty>No results found</Listbox.Empty>\n</Listbox>"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "With Disabled Items",
|
|
100
|
+
"description": "Mix of enabled and disabled items",
|
|
101
|
+
"code": "<Listbox aria-label=\"Options\">\n <Listbox.Item>Available option</Listbox.Item>\n <Listbox.Item disabled>Disabled option</Listbox.Item>\n <Listbox.Item>Another option</Listbox.Item>\n</Listbox>"
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"relations": [
|
|
105
|
+
{
|
|
106
|
+
"component": "Input",
|
|
107
|
+
"relationship": "sibling",
|
|
108
|
+
"note": "Pair with Input for search/autocomplete patterns"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"component": "Menu",
|
|
112
|
+
"relationship": "alternative",
|
|
113
|
+
"note": "Use Menu when you need a trigger button"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"component": "Select",
|
|
117
|
+
"relationship": "alternative",
|
|
118
|
+
"note": "Use Select for form field selection"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"component": "List",
|
|
122
|
+
"relationship": "alternative",
|
|
123
|
+
"note": "Use List for static, non-interactive lists"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"contract": {
|
|
127
|
+
"propsSummary": [
|
|
128
|
+
"children: ReactNode - Listbox.Item components (required)",
|
|
129
|
+
"aria-label: string - accessible label",
|
|
130
|
+
"Listbox.Item selected: boolean - highlight state",
|
|
131
|
+
"Listbox.Item disabled: boolean - non-interactive"
|
|
132
|
+
],
|
|
133
|
+
"a11yRules": [
|
|
134
|
+
"A11Y_LISTBOX_ROLE",
|
|
135
|
+
"A11Y_OPTION_ROLE"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
"ai": {
|
|
139
|
+
"compositionPattern": "compound",
|
|
140
|
+
"subComponents": [
|
|
141
|
+
"Item",
|
|
142
|
+
"Group",
|
|
143
|
+
"Empty"
|
|
144
|
+
],
|
|
145
|
+
"requiredChildren": [
|
|
146
|
+
"Item"
|
|
147
|
+
],
|
|
148
|
+
"commonPatterns": [
|
|
149
|
+
"<Listbox aria-label=\"Search results\">{results.map(item => <Listbox.Item key={item.id} selected={item.id === selectedId} onClick={() => onSelect(item)}>{item.label}</Listbox.Item>)}</Listbox>"
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
"provenance": {
|
|
153
|
+
"source": "migrated",
|
|
154
|
+
"verified": false,
|
|
155
|
+
"frameworkSupport": "native",
|
|
156
|
+
"extractedAt": "2026-03-13T23:19:05.924Z"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Loading",
|
|
4
|
+
"description": "Versatile loading indicator with multiple variants for showing progress or waiting states",
|
|
5
|
+
"category": "feedback",
|
|
6
|
+
"tags": [
|
|
7
|
+
"loading",
|
|
8
|
+
"spinner",
|
|
9
|
+
"progress",
|
|
10
|
+
"feedback",
|
|
11
|
+
"indicator",
|
|
12
|
+
"async"
|
|
13
|
+
],
|
|
14
|
+
"status": "stable",
|
|
15
|
+
"sourcePath": "src/components/Loading/index.tsx",
|
|
16
|
+
"exportName": "Loading",
|
|
17
|
+
"propsSummary": [
|
|
18
|
+
"size: sm|md|lg|xl (default: md)",
|
|
19
|
+
"variant: spinner|dots|pulse (default: spinner)",
|
|
20
|
+
"label: string (default: Loading...)",
|
|
21
|
+
"centered: boolean (default: false)",
|
|
22
|
+
"fill: boolean (default: false)",
|
|
23
|
+
"overlay: boolean (default: false)",
|
|
24
|
+
"color: accent|current|muted (default: accent)"
|
|
25
|
+
],
|
|
26
|
+
"props": {
|
|
27
|
+
"size": {
|
|
28
|
+
"type": "enum",
|
|
29
|
+
"description": "Size of the loading indicator",
|
|
30
|
+
"default": "md",
|
|
31
|
+
"required": false,
|
|
32
|
+
"values": [
|
|
33
|
+
"sm",
|
|
34
|
+
"md",
|
|
35
|
+
"lg",
|
|
36
|
+
"xl"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"variant": {
|
|
40
|
+
"type": "enum",
|
|
41
|
+
"description": "Visual style of the loading animation",
|
|
42
|
+
"default": "spinner",
|
|
43
|
+
"required": false,
|
|
44
|
+
"values": [
|
|
45
|
+
"spinner",
|
|
46
|
+
"dots",
|
|
47
|
+
"pulse"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"label": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "Accessible label for screen readers",
|
|
53
|
+
"default": "Loading...",
|
|
54
|
+
"required": false
|
|
55
|
+
},
|
|
56
|
+
"centered": {
|
|
57
|
+
"type": "boolean",
|
|
58
|
+
"description": "Whether to center the loading indicator in its container",
|
|
59
|
+
"default": "false",
|
|
60
|
+
"required": false
|
|
61
|
+
},
|
|
62
|
+
"fill": {
|
|
63
|
+
"type": "boolean",
|
|
64
|
+
"description": "Whether to fill the parent container",
|
|
65
|
+
"default": "false",
|
|
66
|
+
"required": false
|
|
67
|
+
},
|
|
68
|
+
"overlay": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "Whether to show with a backdrop overlay",
|
|
71
|
+
"default": "false",
|
|
72
|
+
"required": false
|
|
73
|
+
},
|
|
74
|
+
"color": {
|
|
75
|
+
"type": "enum",
|
|
76
|
+
"description": "Color variant - accent uses theme color, current inherits text color",
|
|
77
|
+
"default": "accent",
|
|
78
|
+
"required": false,
|
|
79
|
+
"values": [
|
|
80
|
+
"accent",
|
|
81
|
+
"current",
|
|
82
|
+
"muted"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"usage": {
|
|
87
|
+
"when": [
|
|
88
|
+
"Indicating content is being fetched or processed",
|
|
89
|
+
"Showing a pending state while waiting for an async operation",
|
|
90
|
+
"Displaying loading state for buttons, forms, or page sections",
|
|
91
|
+
"Full-screen loading during initial app/page load"
|
|
92
|
+
],
|
|
93
|
+
"whenNot": [
|
|
94
|
+
"For showing determinate progress - use Progress component instead",
|
|
95
|
+
"For showing skeleton placeholders - use Skeleton component instead",
|
|
96
|
+
"For AI-specific thinking states - use ThinkingIndicator instead"
|
|
97
|
+
],
|
|
98
|
+
"guidelines": [
|
|
99
|
+
"Use spinner variant for general loading states",
|
|
100
|
+
"Use dots variant for chat/messaging contexts",
|
|
101
|
+
"Use pulse variant for subtle, ambient loading",
|
|
102
|
+
"Always provide a meaningful label for screen readers",
|
|
103
|
+
"Consider using Loading.Screen for initial page loads",
|
|
104
|
+
"Use Loading.Inline when loading indicator should flow with text"
|
|
105
|
+
],
|
|
106
|
+
"accessibility": [
|
|
107
|
+
"Component uses role=\"status\" and aria-live=\"polite\"",
|
|
108
|
+
"Always provide descriptive label prop for screen readers",
|
|
109
|
+
"Animations respect prefers-reduced-motion preference"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
"examples": [
|
|
113
|
+
{
|
|
114
|
+
"name": "Default",
|
|
115
|
+
"description": "Default spinner loading indicator",
|
|
116
|
+
"code": "<Loading />"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "Sizes",
|
|
120
|
+
"description": "Loading indicators in different sizes",
|
|
121
|
+
"code": "<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>\n <Loading size=\"sm\" />\n <Loading size=\"md\" />\n <Loading size=\"lg\" />\n <Loading size=\"xl\" />\n</div>"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "Dots",
|
|
125
|
+
"description": "Bouncing dots animation",
|
|
126
|
+
"code": "<Loading variant=\"dots\" />"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "Pulse",
|
|
130
|
+
"description": "Pulsing circle animation",
|
|
131
|
+
"code": "<Loading variant=\"pulse\" />"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "Colors",
|
|
135
|
+
"description": "Different color variants",
|
|
136
|
+
"code": "<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>\n <Loading color=\"accent\" />\n <Loading color=\"muted\" />\n <span style={{ color: '#3b82f6' }}>\n <Loading color=\"current\" />\n </span>\n</div>"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "Inline",
|
|
140
|
+
"description": "Inline loading indicator that flows with text",
|
|
141
|
+
"code": "<p style={{ margin: 0 }}>\n Processing your request <Loading.Inline /> please wait...\n</p>"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "Centered",
|
|
145
|
+
"description": "Centered in container",
|
|
146
|
+
"code": "<div style={{ width: '200px', height: '100px', border: '1px dashed #ccc', borderRadius: '8px' }}>\n <Loading centered fill />\n</div>"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"name": "Screen",
|
|
150
|
+
"description": "Full-screen loading state with optional label",
|
|
151
|
+
"code": "<div style={{ position: 'relative', width: '300px', height: '200px', border: '1px solid #ccc', borderRadius: '8px', overflow: 'hidden', transform: 'scale(1)' }}>\n <Loading.Screen size=\"lg\" label=\"Loading application...\" showLabel />\n</div>"
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
"ai": {
|
|
155
|
+
"compositionPattern": "compound",
|
|
156
|
+
"subComponents": [
|
|
157
|
+
"Inline",
|
|
158
|
+
"Screen"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
"provenance": {
|
|
162
|
+
"source": "migrated",
|
|
163
|
+
"verified": false,
|
|
164
|
+
"frameworkSupport": "native",
|
|
165
|
+
"extractedAt": "2026-03-13T23:19:05.576Z"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Markdown",
|
|
4
|
+
"description": "Renders markdown strings as styled prose using react-markdown and remark-gfm. Supports headings, lists, tables, code blocks, blockquotes, and more.",
|
|
5
|
+
"category": "display",
|
|
6
|
+
"tags": [
|
|
7
|
+
"markdown",
|
|
8
|
+
"prose",
|
|
9
|
+
"content",
|
|
10
|
+
"text",
|
|
11
|
+
"ai",
|
|
12
|
+
"chat"
|
|
13
|
+
],
|
|
14
|
+
"status": "stable",
|
|
15
|
+
"sourcePath": "src/components/Markdown/index.tsx",
|
|
16
|
+
"exportName": "Markdown",
|
|
17
|
+
"propsSummary": [
|
|
18
|
+
"content: string (required)",
|
|
19
|
+
"components: object",
|
|
20
|
+
"className: string"
|
|
21
|
+
],
|
|
22
|
+
"props": {
|
|
23
|
+
"content": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Markdown string to render",
|
|
26
|
+
"required": true
|
|
27
|
+
},
|
|
28
|
+
"components": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"description": "Override map for markdown element components (e.g., { h1: MyHeading }). Accepts custom renderer component signatures used by react-markdown",
|
|
31
|
+
"required": false
|
|
32
|
+
},
|
|
33
|
+
"className": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Additional CSS class name",
|
|
36
|
+
"required": false
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"usage": {
|
|
40
|
+
"when": [
|
|
41
|
+
"Rendering AI/LLM response content",
|
|
42
|
+
"Displaying user-authored markdown text",
|
|
43
|
+
"Showing documentation or readme content",
|
|
44
|
+
"Rich text display without a WYSIWYG editor"
|
|
45
|
+
],
|
|
46
|
+
"whenNot": [
|
|
47
|
+
"Plain text without formatting (use Text)",
|
|
48
|
+
"Editing markdown (use a markdown editor component)",
|
|
49
|
+
"Rendering trusted HTML directly (use dangerouslySetInnerHTML)"
|
|
50
|
+
],
|
|
51
|
+
"guidelines": [
|
|
52
|
+
"Install react-markdown and remark-gfm as peer dependencies",
|
|
53
|
+
"Use the components prop to override default element rendering",
|
|
54
|
+
"Content is sanitized by react-markdown by default",
|
|
55
|
+
"Falls back to plain text paragraphs if react-markdown is not installed",
|
|
56
|
+
"Standard div props (id, style, aria-*, data-*) are forwarded to the Markdown wrapper"
|
|
57
|
+
],
|
|
58
|
+
"accessibility": [
|
|
59
|
+
"Rendered HTML follows semantic structure (headings, lists, tables)",
|
|
60
|
+
"Links are rendered as proper anchor elements",
|
|
61
|
+
"Images include alt text from markdown syntax",
|
|
62
|
+
"Tables use proper th/td structure for screen readers"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"examples": [
|
|
66
|
+
{
|
|
67
|
+
"name": "Default",
|
|
68
|
+
"description": "Basic markdown with headings, paragraphs, inline code, lists, and blockquote",
|
|
69
|
+
"code": "<Markdown content={`# Hello World\n\nThis is a paragraph with **bold text** and *italic text*.\n\nHere is some \\`inline code\\` within a sentence.\n\n- First item\n- Second item\n- Third item\n\n> A blockquote for emphasis.\n`} />"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "GFM Table",
|
|
73
|
+
"description": "GitHub Flavored Markdown with tables and task lists",
|
|
74
|
+
"code": "<Markdown content={`## Data Overview\n\n| Feature | Status | Priority |\n|------------|-----------|----------|\n| Markdown | Done | High |\n| Tables | Done | Medium |\n| Task Lists | Planned | Low |\n\nNotes:\n- [x] Support GFM tables\n- [x] Support task lists\n- [ ] Syntax highlighting\n`} />"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "Code Block",
|
|
78
|
+
"description": "Markdown with fenced code blocks and inline code",
|
|
79
|
+
"code": "<Markdown content={`## Code Example\\n\\nHere is a JavaScript function:\\n\\n```js\\nfunction greet(name) {\\n return \\`Hello, ${name}!\\`;\\n}\\n```\\n\\nAnd some inline code: \\`const x = 42;\\``} />"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "Mixed Content",
|
|
83
|
+
"description": "Complex markdown mixing headings, lists, tables, blockquotes, and task lists",
|
|
84
|
+
"code": "<Markdown content={`# Project Update\n\n## Summary\n\nThe project is progressing well. Here are the **key highlights**:\n\n1. Completed the *design system* components\n2. Added markdown rendering support\n3. Integrated with the documentation site\n\n### Performance Metrics\n\n| Metric | Before | After |\n|-------------|--------|-------|\n| Bundle Size | 142kb | 98kb |\n| Load Time | 1.2s | 0.8s |\n| Lighthouse | 72 | 95 |\n\n> These improvements were achieved through tree-shaking and code splitting.\n\n### Next Steps\n\n- [ ] Add syntax highlighting\n- [ ] Support custom themes\n- [x] GFM table support\n`} />"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"relations": [
|
|
88
|
+
{
|
|
89
|
+
"component": "Text",
|
|
90
|
+
"relationship": "alternative",
|
|
91
|
+
"note": "Use Text for plain, non-markdown text"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"component": "CodeBlock",
|
|
95
|
+
"relationship": "complementary",
|
|
96
|
+
"note": "CodeBlock can be used via components prop for syntax highlighting"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"component": "Message",
|
|
100
|
+
"relationship": "parent",
|
|
101
|
+
"note": "Message wraps Markdown when markdown prop is true"
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"contract": {
|
|
105
|
+
"propsSummary": [
|
|
106
|
+
"content: string - Markdown string to render",
|
|
107
|
+
"components: object - Override map for element components (react-markdown renderer components)",
|
|
108
|
+
"className: string - Additional CSS class",
|
|
109
|
+
"Forwards standard HTML div attributes to the wrapper element"
|
|
110
|
+
],
|
|
111
|
+
"a11yRules": [
|
|
112
|
+
"A11Y_SEMANTIC_HTML"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"ai": {
|
|
116
|
+
"compositionPattern": "compound",
|
|
117
|
+
"subComponents": [
|
|
118
|
+
"Root"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"provenance": {
|
|
122
|
+
"source": "migrated",
|
|
123
|
+
"verified": false,
|
|
124
|
+
"frameworkSupport": "native",
|
|
125
|
+
"extractedAt": "2026-03-13T23:19:06.091Z"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Menu",
|
|
4
|
+
"description": "Dropdown menu for actions and commands. Supports submenus, check items, radio groups, and keyboard shortcuts.",
|
|
5
|
+
"category": "feedback",
|
|
6
|
+
"tags": [
|
|
7
|
+
"menu",
|
|
8
|
+
"dropdown",
|
|
9
|
+
"actions",
|
|
10
|
+
"context-menu",
|
|
11
|
+
"commands",
|
|
12
|
+
"submenu"
|
|
13
|
+
],
|
|
14
|
+
"status": "stable",
|
|
15
|
+
"sourcePath": "src/components/Menu/index.tsx",
|
|
16
|
+
"exportName": "Menu",
|
|
17
|
+
"propsSummary": [
|
|
18
|
+
"children: node (required)",
|
|
19
|
+
"open: boolean",
|
|
20
|
+
"defaultOpen: boolean",
|
|
21
|
+
"onOpenChange: function",
|
|
22
|
+
"modal: boolean (default: true)"
|
|
23
|
+
],
|
|
24
|
+
"props": {
|
|
25
|
+
"children": {
|
|
26
|
+
"type": "node",
|
|
27
|
+
"description": "Menu trigger and content",
|
|
28
|
+
"required": true
|
|
29
|
+
},
|
|
30
|
+
"open": {
|
|
31
|
+
"type": "boolean",
|
|
32
|
+
"description": "Controlled open state",
|
|
33
|
+
"required": false
|
|
34
|
+
},
|
|
35
|
+
"defaultOpen": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "Default open state (uncontrolled)",
|
|
38
|
+
"default": "false",
|
|
39
|
+
"required": false
|
|
40
|
+
},
|
|
41
|
+
"onOpenChange": {
|
|
42
|
+
"type": "function",
|
|
43
|
+
"description": "Called when open state changes",
|
|
44
|
+
"required": false
|
|
45
|
+
},
|
|
46
|
+
"modal": {
|
|
47
|
+
"type": "boolean",
|
|
48
|
+
"description": "Whether menu is modal",
|
|
49
|
+
"default": "true",
|
|
50
|
+
"required": false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"usage": {
|
|
54
|
+
"when": [
|
|
55
|
+
"Overflow actions that dont fit in the toolbar",
|
|
56
|
+
"Context menus (right-click)",
|
|
57
|
+
"User account menus",
|
|
58
|
+
"Grouped actions with separators",
|
|
59
|
+
"Nested menus with submenus"
|
|
60
|
+
],
|
|
61
|
+
"whenNot": [
|
|
62
|
+
"Selecting from options (use Select)",
|
|
63
|
+
"Navigation (use Tabs or navigation components)",
|
|
64
|
+
"Form selection (use Select or RadioGroup)"
|
|
65
|
+
],
|
|
66
|
+
"guidelines": [
|
|
67
|
+
"Group related actions with Menu.Group",
|
|
68
|
+
"Use separators to divide action categories",
|
|
69
|
+
"Include keyboard shortcuts where applicable",
|
|
70
|
+
"Use danger variant for destructive actions",
|
|
71
|
+
"Keep menu items under 10-12 for usability",
|
|
72
|
+
"Use checked prop on Menu.Item for simple selection state",
|
|
73
|
+
"Use Menu.Submenu for nested secondary options",
|
|
74
|
+
"Menu.Trigger supports asChild for links/router-link components (single valid element child required)"
|
|
75
|
+
],
|
|
76
|
+
"accessibility": [
|
|
77
|
+
"Full keyboard navigation with arrow keys",
|
|
78
|
+
"Type-ahead search for items",
|
|
79
|
+
"Focus returns to trigger on close",
|
|
80
|
+
"Proper ARIA menu roles",
|
|
81
|
+
"ArrowRight opens submenus, ArrowLeft closes them"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"examples": [
|
|
85
|
+
{
|
|
86
|
+
"name": "Default",
|
|
87
|
+
"description": "Basic dropdown menu",
|
|
88
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\">Actions</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item onSelect={() => {}}>Edit</Menu.Item>\n <Menu.Item onSelect={() => {}}>Duplicate</Menu.Item>\n <Menu.Separator />\n <Menu.Item danger onSelect={() => {}}>Delete</Menu.Item>\n </Menu.Content>\n</Menu>"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "With Shortcuts",
|
|
92
|
+
"description": "Menu items with keyboard shortcuts",
|
|
93
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\">Edit</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item shortcut=\"Ctrl+Z\" onSelect={() => {}}>Undo</Menu.Item>\n <Menu.Item shortcut=\"Ctrl+Y\" onSelect={() => {}}>Redo</Menu.Item>\n <Menu.Separator />\n <Menu.Item shortcut=\"Ctrl+C\" onSelect={() => {}}>Copy</Menu.Item>\n <Menu.Item shortcut=\"Ctrl+V\" onSelect={() => {}}>Paste</Menu.Item>\n </Menu.Content>\n</Menu>"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "With Groups",
|
|
97
|
+
"description": "Menu with labeled groups",
|
|
98
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\">Options</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Group>\n <Menu.GroupLabel>View</Menu.GroupLabel>\n <Menu.Item onSelect={() => {}}>Zoom In</Menu.Item>\n <Menu.Item onSelect={() => {}}>Zoom Out</Menu.Item>\n </Menu.Group>\n <Menu.Separator />\n <Menu.Group>\n <Menu.GroupLabel>Layout</Menu.GroupLabel>\n <Menu.Item onSelect={() => {}}>Grid View</Menu.Item>\n <Menu.Item onSelect={() => {}}>List View</Menu.Item>\n </Menu.Group>\n </Menu.Content>\n</Menu>"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "With Checkboxes",
|
|
102
|
+
"description": "Menu with toggleable checkbox options",
|
|
103
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\">Display</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.CheckboxItem defaultChecked>Show Grid</Menu.CheckboxItem>\n <Menu.CheckboxItem defaultChecked>Show Rulers</Menu.CheckboxItem>\n <Menu.CheckboxItem>Show Guides</Menu.CheckboxItem>\n </Menu.Content>\n</Menu>"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "With Checked Items",
|
|
107
|
+
"description": "Filter menu with check marks indicating active selections",
|
|
108
|
+
"code": "<CheckedItemsMenuDemo />"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "With Submenu",
|
|
112
|
+
"description": "Menu with nested submenu for grouped secondary options",
|
|
113
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\">File</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item onSelect={() => {}}>New File</Menu.Item>\n <Menu.Item onSelect={() => {}}>Open</Menu.Item>\n <Menu.Separator />\n <Menu.Submenu>\n <Menu.SubmenuTrigger>Export As</Menu.SubmenuTrigger>\n <Menu.Content side=\"right\" align=\"start\">\n <Menu.Item onSelect={() => {}}>PNG</Menu.Item>\n <Menu.Item onSelect={() => {}}>SVG</Menu.Item>\n <Menu.Item onSelect={() => {}}>PDF</Menu.Item>\n </Menu.Content>\n </Menu.Submenu>\n <Menu.Separator />\n <Menu.Item danger onSelect={() => {}}>Delete</Menu.Item>\n </Menu.Content>\n</Menu>"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "Link Trigger",
|
|
117
|
+
"description": "Use asChild with a non-button trigger element",
|
|
118
|
+
"code": "<Menu>\n <Menu.Trigger asChild>\n <a href=\"#menu-actions\">Open menu</a>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item onSelect={() => {}}>Inspect</Menu.Item>\n <Menu.Item onSelect={() => {}}>Rename</Menu.Item>\n </Menu.Content>\n</Menu>"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"relations": [
|
|
122
|
+
{
|
|
123
|
+
"component": "Select",
|
|
124
|
+
"relationship": "alternative",
|
|
125
|
+
"note": "Use Select for form field selection"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"component": "Popover",
|
|
129
|
+
"relationship": "alternative",
|
|
130
|
+
"note": "Use Popover for rich non-action content"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"contract": {
|
|
134
|
+
"propsSummary": [
|
|
135
|
+
"open: boolean - controlled open state",
|
|
136
|
+
"onOpenChange: (open) => void - state handler",
|
|
137
|
+
"Menu.Trigger asChild supports non-button trigger elements",
|
|
138
|
+
"Menu.Item onSelect: (event) => void - selection callback receives click event",
|
|
139
|
+
"Menu.Item danger: boolean - destructive styling",
|
|
140
|
+
"Menu.Item shortcut: string - keyboard shortcut text",
|
|
141
|
+
"Menu.Item checked: boolean - check indicator for selection state"
|
|
142
|
+
],
|
|
143
|
+
"a11yRules": [
|
|
144
|
+
"A11Y_MENU_KEYBOARD",
|
|
145
|
+
"A11Y_MENU_ROLE"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
"ai": {
|
|
149
|
+
"compositionPattern": "compound",
|
|
150
|
+
"subComponents": [
|
|
151
|
+
"Trigger",
|
|
152
|
+
"Content",
|
|
153
|
+
"Item",
|
|
154
|
+
"CheckboxItem",
|
|
155
|
+
"RadioGroup",
|
|
156
|
+
"RadioItem",
|
|
157
|
+
"Group",
|
|
158
|
+
"GroupLabel",
|
|
159
|
+
"Separator",
|
|
160
|
+
"Submenu",
|
|
161
|
+
"SubmenuTrigger"
|
|
162
|
+
],
|
|
163
|
+
"requiredChildren": [
|
|
164
|
+
"Trigger",
|
|
165
|
+
"Content"
|
|
166
|
+
],
|
|
167
|
+
"commonPatterns": [
|
|
168
|
+
"<Menu><Menu.Trigger asChild><Button>Actions</Button></Menu.Trigger><Menu.Content><Menu.Item>{action1}</Menu.Item><Menu.Separator /><Menu.Item danger>{delete}</Menu.Item></Menu.Content></Menu>"
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
"provenance": {
|
|
172
|
+
"source": "migrated",
|
|
173
|
+
"verified": false,
|
|
174
|
+
"frameworkSupport": "native",
|
|
175
|
+
"extractedAt": "2026-03-13T23:19:00.159Z"
|
|
176
|
+
}
|
|
177
|
+
}
|