@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,263 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Editor",
|
|
4
|
+
"description": "Rich text editor with formatting toolbar, auto-save, and word count",
|
|
5
|
+
"category": "forms",
|
|
6
|
+
"tags": [
|
|
7
|
+
"editor",
|
|
8
|
+
"rich-text",
|
|
9
|
+
"markdown",
|
|
10
|
+
"toolbar",
|
|
11
|
+
"writing",
|
|
12
|
+
"blog",
|
|
13
|
+
"content"
|
|
14
|
+
],
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"sourcePath": "src/components/Editor/index.tsx",
|
|
17
|
+
"exportName": "Editor",
|
|
18
|
+
"propsSummary": [
|
|
19
|
+
"children: node",
|
|
20
|
+
"value: string",
|
|
21
|
+
"defaultValue: string (default: )",
|
|
22
|
+
"onValueChange: function",
|
|
23
|
+
"placeholder: string (default: Start typing...)",
|
|
24
|
+
"disabled: boolean (default: false)",
|
|
25
|
+
"readOnly: boolean (default: false)",
|
|
26
|
+
"formats: array",
|
|
27
|
+
"toolbar: boolean (default: true)",
|
|
28
|
+
"statusBar: boolean (default: true)",
|
|
29
|
+
"onAutoSave: function",
|
|
30
|
+
"autoSaveInterval: number (default: 30000)",
|
|
31
|
+
"size: sm|md|lg (default: md)",
|
|
32
|
+
"maxLength: number",
|
|
33
|
+
"toolbarIcons: object"
|
|
34
|
+
],
|
|
35
|
+
"props": {
|
|
36
|
+
"children": {
|
|
37
|
+
"type": "node",
|
|
38
|
+
"description": "",
|
|
39
|
+
"required": false
|
|
40
|
+
},
|
|
41
|
+
"value": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Controlled editor value",
|
|
44
|
+
"required": false
|
|
45
|
+
},
|
|
46
|
+
"defaultValue": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"description": "Default value for uncontrolled usage",
|
|
49
|
+
"default": "",
|
|
50
|
+
"required": false
|
|
51
|
+
},
|
|
52
|
+
"onValueChange": {
|
|
53
|
+
"type": "function",
|
|
54
|
+
"description": "Called when content changes",
|
|
55
|
+
"required": false
|
|
56
|
+
},
|
|
57
|
+
"placeholder": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Placeholder text shown when empty",
|
|
60
|
+
"default": "Start typing...",
|
|
61
|
+
"required": false
|
|
62
|
+
},
|
|
63
|
+
"disabled": {
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"description": "Disable the editor",
|
|
66
|
+
"default": "false",
|
|
67
|
+
"required": false
|
|
68
|
+
},
|
|
69
|
+
"readOnly": {
|
|
70
|
+
"type": "boolean",
|
|
71
|
+
"description": "Make the editor read-only",
|
|
72
|
+
"default": "false",
|
|
73
|
+
"required": false
|
|
74
|
+
},
|
|
75
|
+
"formats": {
|
|
76
|
+
"type": "array",
|
|
77
|
+
"description": "Which format buttons to show in the toolbar",
|
|
78
|
+
"default": "[\"bold\", \"italic\", \"strikethrough\", \"link\", \"code\", \"bulletList\"]",
|
|
79
|
+
"required": false
|
|
80
|
+
},
|
|
81
|
+
"toolbar": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"description": "Show default toolbar",
|
|
84
|
+
"default": "true",
|
|
85
|
+
"required": false
|
|
86
|
+
},
|
|
87
|
+
"statusBar": {
|
|
88
|
+
"type": "boolean",
|
|
89
|
+
"description": "Show default status bar with word/character counts",
|
|
90
|
+
"default": "true",
|
|
91
|
+
"required": false
|
|
92
|
+
},
|
|
93
|
+
"onAutoSave": {
|
|
94
|
+
"type": "function",
|
|
95
|
+
"description": "Auto-save callback, called at autoSaveInterval (may be async)",
|
|
96
|
+
"required": false
|
|
97
|
+
},
|
|
98
|
+
"autoSaveInterval": {
|
|
99
|
+
"type": "number",
|
|
100
|
+
"description": "Auto-save interval in milliseconds",
|
|
101
|
+
"default": "30000",
|
|
102
|
+
"required": false
|
|
103
|
+
},
|
|
104
|
+
"size": {
|
|
105
|
+
"type": "enum",
|
|
106
|
+
"description": "Editor size preset: \"sm\" (120px), \"md\" (200px), or \"lg\" (400px)",
|
|
107
|
+
"default": "md",
|
|
108
|
+
"required": false,
|
|
109
|
+
"values": [
|
|
110
|
+
"sm",
|
|
111
|
+
"md",
|
|
112
|
+
"lg"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"maxLength": {
|
|
116
|
+
"type": "number",
|
|
117
|
+
"description": "Maximum character count. Shows counter in status bar with warning (90%) and error (over limit) states",
|
|
118
|
+
"required": false
|
|
119
|
+
},
|
|
120
|
+
"toolbarIcons": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"description": "Optional toolbar icon overrides keyed by format/action (e.g. bold, italic, undo). Values can be React nodes or render functions.",
|
|
123
|
+
"required": false
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"usage": {
|
|
127
|
+
"when": [
|
|
128
|
+
"Building blog post or article editors",
|
|
129
|
+
"Need rich text editing with formatting controls",
|
|
130
|
+
"Content management with auto-save and word count",
|
|
131
|
+
"Markdown or WYSIWYG editing interfaces"
|
|
132
|
+
],
|
|
133
|
+
"whenNot": [
|
|
134
|
+
"Simple single-line text input (use Input)",
|
|
135
|
+
"Plain multi-line without formatting (use Textarea)",
|
|
136
|
+
"Chat/AI prompt input (use Prompt)",
|
|
137
|
+
"Code editing (use CodeBlock)"
|
|
138
|
+
],
|
|
139
|
+
"guidelines": [
|
|
140
|
+
"Use compound pattern for custom toolbar layouts",
|
|
141
|
+
"Install @tiptap/react, @tiptap/starter-kit, and @tiptap/extension-link for rich text mode",
|
|
142
|
+
"Falls back to a markdown-aware textarea when TipTap is not installed",
|
|
143
|
+
"Use onAutoSave for periodic content persistence",
|
|
144
|
+
"onAutoSave may return a Promise; save status updates after the async save resolves/rejects",
|
|
145
|
+
"Use size prop (sm/md/lg) to control editor height",
|
|
146
|
+
"Use maxLength to show character limit with visual warning states",
|
|
147
|
+
"New formats (headings, blockquote, orderedList, undo, redo) are opt-in via the formats prop",
|
|
148
|
+
"Use toolbarIcons to swap in icons from any icon package without changing toolbar button labels or accessibility behavior"
|
|
149
|
+
],
|
|
150
|
+
"accessibility": [
|
|
151
|
+
"Toolbar has role=\"toolbar\" with aria-label",
|
|
152
|
+
"Format buttons use aria-pressed to indicate active state",
|
|
153
|
+
"Action buttons (undo/redo) omit aria-pressed since they are not toggles",
|
|
154
|
+
"Status indicator uses aria-live=\"polite\" for save status announcements",
|
|
155
|
+
"Keyboard shortcuts match standard text editor conventions (Ctrl+B, Ctrl+I, etc.)",
|
|
156
|
+
"Global shortcuts (e.g., Sidebar Ctrl+B) automatically yield when focus is inside the Editor",
|
|
157
|
+
"Focus ring appears on the editor container when any child element is focused"
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
"examples": [
|
|
161
|
+
{
|
|
162
|
+
"name": "Default",
|
|
163
|
+
"description": "Editor with default toolbar and status bar",
|
|
164
|
+
"code": "<Editor placeholder=\"Start typing your masterpiece here...\" />"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"name": "With Auto-Save and Publish",
|
|
168
|
+
"description": "Full compound usage with custom toolbar, auto-save indicator, and publish button",
|
|
169
|
+
"code": "<Editor\n placeholder=\"Start typing your masterpiece here...\"\n onValueChange={(v) => console.log(v)}\n>\n <Editor.Toolbar>\n <Editor.ToolbarGroup aria-label=\"Text formatting\">\n <Editor.ToolbarButton format=\"bold\" />\n <Editor.ToolbarButton format=\"italic\" />\n <Editor.ToolbarButton format=\"strikethrough\" />\n <Editor.ToolbarButton format=\"link\" />\n <Editor.ToolbarButton format=\"code\" />\n <Editor.ToolbarButton format=\"bulletList\" />\n </Editor.ToolbarGroup>\n <Editor.ToolbarGroup aria-label=\"Actions\">\n <Editor.StatusIndicator status=\"saved\" />\n <Button variant=\"accent\" size=\"sm\">\n Publish\n </Button>\n </Editor.ToolbarGroup>\n </Editor.Toolbar>\n <Editor.Content />\n <Editor.StatusBar showWordCount showCharCount />\n</Editor>"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "Minimal",
|
|
173
|
+
"description": "Editor with subset of formats",
|
|
174
|
+
"code": "<Editor\n placeholder=\"Quick note...\"\n formats={['bold', 'italic', 'code']}\n/>"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"name": "Disabled",
|
|
178
|
+
"description": "Non-interactive editor with content",
|
|
179
|
+
"code": "<Editor\n defaultValue=\"This content cannot be edited.\"\n disabled\n/>"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "Read Only",
|
|
183
|
+
"description": "Visible content, non-editable",
|
|
184
|
+
"code": "<Editor\n defaultValue=\"This content is read-only. You can select and copy text but cannot modify it.\"\n readOnly\n/>"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"name": "Custom Toolbar",
|
|
188
|
+
"description": "Compound usage with custom toolbar layout and separator",
|
|
189
|
+
"code": "<Editor\n placeholder=\"Write your blog post...\"\n onValueChange={(v) => console.log(v)}\n>\n <Editor.Toolbar>\n <Editor.ToolbarGroup aria-label=\"Basic formatting\">\n <Editor.ToolbarButton format=\"bold\" />\n <Editor.ToolbarButton format=\"italic\" />\n </Editor.ToolbarGroup>\n <Editor.Separator />\n <Editor.ToolbarGroup aria-label=\"Advanced formatting\">\n <Editor.ToolbarButton format=\"link\" />\n <Editor.ToolbarButton format=\"code\" />\n <Editor.ToolbarButton format=\"bulletList\" />\n </Editor.ToolbarGroup>\n <Editor.ToolbarGroup aria-label=\"Status\">\n <Editor.StatusIndicator status=\"saving\" />\n </Editor.ToolbarGroup>\n </Editor.Toolbar>\n <Editor.Content />\n <Editor.StatusBar showWordCount showCharCount />\n</Editor>"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "Full Formatting",
|
|
193
|
+
"description": "All format options including headings, blockquote, ordered list, undo/redo",
|
|
194
|
+
"code": "<Editor\n placeholder=\"Write an article...\"\n size=\"lg\"\n>\n <Editor.Toolbar>\n <Editor.ToolbarGroup aria-label=\"History\">\n <Editor.ToolbarButton format=\"undo\" />\n <Editor.ToolbarButton format=\"redo\" />\n </Editor.ToolbarGroup>\n <Editor.Separator />\n <Editor.ToolbarGroup aria-label=\"Headings\">\n <Editor.ToolbarButton format=\"heading1\" />\n <Editor.ToolbarButton format=\"heading2\" />\n <Editor.ToolbarButton format=\"heading3\" />\n </Editor.ToolbarGroup>\n <Editor.Separator />\n <Editor.ToolbarGroup aria-label=\"Text formatting\">\n <Editor.ToolbarButton format=\"bold\" />\n <Editor.ToolbarButton format=\"italic\" />\n <Editor.ToolbarButton format=\"strikethrough\" />\n <Editor.ToolbarButton format=\"code\" />\n </Editor.ToolbarGroup>\n <Editor.Separator />\n <Editor.ToolbarGroup aria-label=\"Block formatting\">\n <Editor.ToolbarButton format=\"bulletList\" />\n <Editor.ToolbarButton format=\"orderedList\" />\n <Editor.ToolbarButton format=\"blockquote\" />\n <Editor.ToolbarButton format=\"link\" />\n </Editor.ToolbarGroup>\n </Editor.Toolbar>\n <Editor.Content />\n <Editor.StatusBar showWordCount showCharCount />\n</Editor>"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"name": "With Character Limit",
|
|
198
|
+
"description": "Editor with maxLength showing character count indicator with warning and error states",
|
|
199
|
+
"code": "<Editor\n placeholder=\"Write a tweet-sized message...\"\n maxLength={280}\n size=\"sm\"\n formats={['bold', 'italic', 'link']}\n/>"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "Small Size",
|
|
203
|
+
"description": "Compact editor with sm size preset (120px min-height)",
|
|
204
|
+
"code": "<Editor\n placeholder=\"Quick note...\"\n size=\"sm\"\n formats={['bold', 'italic', 'code']}\n/>"
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
"relations": [
|
|
208
|
+
{
|
|
209
|
+
"component": "Prompt",
|
|
210
|
+
"relationship": "sibling",
|
|
211
|
+
"note": "Prompt is for AI/chat input; Editor is for long-form content editing"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"component": "Textarea",
|
|
215
|
+
"relationship": "alternative",
|
|
216
|
+
"note": "Use Textarea for simple multi-line input without formatting toolbar"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"component": "Input",
|
|
220
|
+
"relationship": "alternative",
|
|
221
|
+
"note": "Use Input for single-line text input"
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
"contract": {
|
|
225
|
+
"propsSummary": [
|
|
226
|
+
"value: string - controlled editor value",
|
|
227
|
+
"onValueChange: (value: string) => void - change callback",
|
|
228
|
+
"placeholder: string - hint text (default: \"Start typing...\")",
|
|
229
|
+
"disabled: boolean - disables interaction",
|
|
230
|
+
"readOnly: boolean - prevents editing",
|
|
231
|
+
"formats: EditorFormat[] - toolbar buttons (default: all 6)",
|
|
232
|
+
"toolbar: boolean - show default toolbar (default: true)",
|
|
233
|
+
"statusBar: boolean - show word/char counts (default: true)",
|
|
234
|
+
"onAutoSave: (value: string) => void | Promise<void> - auto-save handler",
|
|
235
|
+
"size: \"sm\" | \"md\" | \"lg\" - editor height preset (default: \"md\")",
|
|
236
|
+
"maxLength: number - character limit with visual indicator",
|
|
237
|
+
"toolbarIcons: Partial<Record<EditorFormat, ReactNode | (state) => ReactNode>> - custom toolbar icons"
|
|
238
|
+
],
|
|
239
|
+
"a11yRules": [
|
|
240
|
+
"A11Y_TOOLBAR_ROLE",
|
|
241
|
+
"A11Y_BUTTON_LABEL",
|
|
242
|
+
"A11Y_LIVE_REGION"
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
"ai": {
|
|
246
|
+
"compositionPattern": "compound",
|
|
247
|
+
"subComponents": [
|
|
248
|
+
"Toolbar",
|
|
249
|
+
"ToolbarGroup",
|
|
250
|
+
"ToolbarButton",
|
|
251
|
+
"Separator",
|
|
252
|
+
"StatusIndicator",
|
|
253
|
+
"Content",
|
|
254
|
+
"StatusBar"
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
"provenance": {
|
|
258
|
+
"source": "migrated",
|
|
259
|
+
"verified": false,
|
|
260
|
+
"frameworkSupport": "native",
|
|
261
|
+
"extractedAt": "2026-03-13T23:18:56.748Z"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "EmptyState",
|
|
4
|
+
"description": "Placeholder for empty content areas. Provides context, guidance, and actions when no data is available.",
|
|
5
|
+
"category": "feedback",
|
|
6
|
+
"tags": [
|
|
7
|
+
"empty",
|
|
8
|
+
"placeholder",
|
|
9
|
+
"no-data",
|
|
10
|
+
"zero-state",
|
|
11
|
+
"blank-slate"
|
|
12
|
+
],
|
|
13
|
+
"status": "stable",
|
|
14
|
+
"sourcePath": "src/components/EmptyState/index.tsx",
|
|
15
|
+
"exportName": "EmptyState",
|
|
16
|
+
"propsSummary": [
|
|
17
|
+
"children: node (required)",
|
|
18
|
+
"size: sm|md|lg (default: md)"
|
|
19
|
+
],
|
|
20
|
+
"props": {
|
|
21
|
+
"children": {
|
|
22
|
+
"type": "node",
|
|
23
|
+
"description": "EmptyState content - use EmptyState.Icon, EmptyState.Title, EmptyState.Description, EmptyState.Actions sub-components",
|
|
24
|
+
"required": true
|
|
25
|
+
},
|
|
26
|
+
"size": {
|
|
27
|
+
"type": "enum",
|
|
28
|
+
"description": "Size variant",
|
|
29
|
+
"default": "md",
|
|
30
|
+
"required": false,
|
|
31
|
+
"values": [
|
|
32
|
+
"sm",
|
|
33
|
+
"md",
|
|
34
|
+
"lg"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"usage": {
|
|
39
|
+
"when": [
|
|
40
|
+
"Empty lists, tables, or search results",
|
|
41
|
+
"New user onboarding (no content yet)",
|
|
42
|
+
"Filtered views with no matches",
|
|
43
|
+
"Error states where content failed to load"
|
|
44
|
+
],
|
|
45
|
+
"whenNot": [
|
|
46
|
+
"Loading states (use skeleton or spinner)",
|
|
47
|
+
"Error messages with retry (use Alert)",
|
|
48
|
+
"Temporary messages (use Toast)"
|
|
49
|
+
],
|
|
50
|
+
"guidelines": [
|
|
51
|
+
"Always explain why the area is empty",
|
|
52
|
+
"Provide a clear action to resolve the empty state",
|
|
53
|
+
"Use appropriate icons to reinforce the message",
|
|
54
|
+
"Keep messaging positive and actionable",
|
|
55
|
+
"EmptyState compound sub-components forward DOM props for ids, aria attributes, and handlers"
|
|
56
|
+
],
|
|
57
|
+
"accessibility": [
|
|
58
|
+
"Empty state content is accessible to screen readers",
|
|
59
|
+
"Action buttons follow button accessibility guidelines"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
"examples": [
|
|
63
|
+
{
|
|
64
|
+
"name": "Default",
|
|
65
|
+
"description": "Basic empty state with action",
|
|
66
|
+
"code": "<EmptyState>\n <EmptyState.Icon><FolderIcon /></EmptyState.Icon>\n <EmptyState.Title>No projects yet</EmptyState.Title>\n <EmptyState.Description>Get started by creating your first project.</EmptyState.Description>\n <EmptyState.Actions>\n <Button>Create Project</Button>\n </EmptyState.Actions>\n</EmptyState>"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "No Results",
|
|
70
|
+
"description": "Empty search results",
|
|
71
|
+
"code": "<EmptyState>\n <EmptyState.Icon><SearchIcon /></EmptyState.Icon>\n <EmptyState.Title>No results found</EmptyState.Title>\n <EmptyState.Description>Try adjusting your search terms or filters.</EmptyState.Description>\n <EmptyState.Actions>\n <Button variant=\"secondary\">Clear Filters</Button>\n </EmptyState.Actions>\n</EmptyState>"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "With Secondary Action",
|
|
75
|
+
"description": "Empty state with two actions",
|
|
76
|
+
"code": "<EmptyState>\n <EmptyState.Icon><InboxIcon /></EmptyState.Icon>\n <EmptyState.Title>Inbox is empty</EmptyState.Title>\n <EmptyState.Description>You have no new messages.</EmptyState.Description>\n <EmptyState.Actions>\n <Button>Compose Message</Button>\n <Button variant=\"secondary\">View Archive</Button>\n </EmptyState.Actions>\n</EmptyState>"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "Small",
|
|
80
|
+
"description": "Compact empty state for inline use",
|
|
81
|
+
"code": "<EmptyState size=\"sm\">\n <EmptyState.Title>No items</EmptyState.Title>\n <EmptyState.Description>Add items to see them here.</EmptyState.Description>\n</EmptyState>"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "Large",
|
|
85
|
+
"description": "Prominent empty state for full-page use",
|
|
86
|
+
"code": "<EmptyState size=\"lg\">\n <EmptyState.Icon><FolderIcon /></EmptyState.Icon>\n <EmptyState.Title>Welcome to your workspace</EmptyState.Title>\n <EmptyState.Description>\n This is where your projects will appear. Create your first project to get started.\n </EmptyState.Description>\n <EmptyState.Actions>\n <Button>Create Your First Project</Button>\n </EmptyState.Actions>\n</EmptyState>"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"relations": [
|
|
90
|
+
{
|
|
91
|
+
"component": "Alert",
|
|
92
|
+
"relationship": "alternative",
|
|
93
|
+
"note": "Use Alert for error states with retry"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"component": "Progress",
|
|
97
|
+
"relationship": "alternative",
|
|
98
|
+
"note": "Use Progress/Spinner for loading states"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"contract": {
|
|
102
|
+
"propsSummary": [
|
|
103
|
+
"size: sm|md|lg (default: md)",
|
|
104
|
+
"Sub-components: EmptyState.Icon, EmptyState.Title, EmptyState.Description, EmptyState.Actions",
|
|
105
|
+
"Compound sub-components forward DOM props to their rendered elements"
|
|
106
|
+
],
|
|
107
|
+
"a11yRules": [
|
|
108
|
+
"A11Y_EMPTY_STATE_CONTENT"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"ai": {
|
|
112
|
+
"compositionPattern": "compound",
|
|
113
|
+
"subComponents": [
|
|
114
|
+
"Icon",
|
|
115
|
+
"Title",
|
|
116
|
+
"Description",
|
|
117
|
+
"Actions"
|
|
118
|
+
],
|
|
119
|
+
"requiredChildren": [
|
|
120
|
+
"Title"
|
|
121
|
+
],
|
|
122
|
+
"commonPatterns": [
|
|
123
|
+
"<EmptyState><EmptyState.Title>{title}</EmptyState.Title><EmptyState.Description>{description}</EmptyState.Description></EmptyState>",
|
|
124
|
+
"<EmptyState><EmptyState.Icon>{icon}</EmptyState.Icon><EmptyState.Title>{title}</EmptyState.Title><EmptyState.Description>{description}</EmptyState.Description><EmptyState.Actions><Button>{action}</Button></EmptyState.Actions></EmptyState>"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
"provenance": {
|
|
128
|
+
"source": "migrated",
|
|
129
|
+
"verified": false,
|
|
130
|
+
"frameworkSupport": "native",
|
|
131
|
+
"extractedAt": "2026-03-13T23:18:56.922Z"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "Field",
|
|
4
|
+
"description": "Compositional form field wrapper providing validation, labels, descriptions, and error messages. Use for advanced form needs beyond baked-in Input/Textarea props.",
|
|
5
|
+
"category": "forms",
|
|
6
|
+
"tags": [
|
|
7
|
+
"form",
|
|
8
|
+
"field",
|
|
9
|
+
"validation",
|
|
10
|
+
"label",
|
|
11
|
+
"error",
|
|
12
|
+
"input",
|
|
13
|
+
"accessible"
|
|
14
|
+
],
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"sourcePath": "src/components/Field/index.tsx",
|
|
17
|
+
"exportName": "Field",
|
|
18
|
+
"propsSummary": [
|
|
19
|
+
"children: node (required)",
|
|
20
|
+
"name: string",
|
|
21
|
+
"disabled: boolean",
|
|
22
|
+
"invalid: boolean",
|
|
23
|
+
"validate: function",
|
|
24
|
+
"validationMode: onSubmit|onBlur|onChange",
|
|
25
|
+
"validationDebounceTime: number"
|
|
26
|
+
],
|
|
27
|
+
"props": {
|
|
28
|
+
"children": {
|
|
29
|
+
"type": "node",
|
|
30
|
+
"description": "Field content (Label, Control, Description, Error)",
|
|
31
|
+
"required": true
|
|
32
|
+
},
|
|
33
|
+
"name": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Field name, used for error distribution from Form",
|
|
36
|
+
"required": false
|
|
37
|
+
},
|
|
38
|
+
"disabled": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"description": "Disables the field and its control",
|
|
41
|
+
"required": false
|
|
42
|
+
},
|
|
43
|
+
"invalid": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"description": "Marks the field as invalid",
|
|
46
|
+
"required": false
|
|
47
|
+
},
|
|
48
|
+
"validate": {
|
|
49
|
+
"type": "function",
|
|
50
|
+
"description": "Custom validation function returning error string(s) or null",
|
|
51
|
+
"required": false
|
|
52
|
+
},
|
|
53
|
+
"validationMode": {
|
|
54
|
+
"type": "enum",
|
|
55
|
+
"description": "When to trigger validation",
|
|
56
|
+
"required": false,
|
|
57
|
+
"values": [
|
|
58
|
+
"onSubmit",
|
|
59
|
+
"onBlur",
|
|
60
|
+
"onChange"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"validationDebounceTime": {
|
|
64
|
+
"type": "number",
|
|
65
|
+
"description": "Debounce time in ms for onChange validation",
|
|
66
|
+
"required": false
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"usage": {
|
|
70
|
+
"when": [
|
|
71
|
+
"You need granular validation with match-based error messages",
|
|
72
|
+
"Custom form controls need accessible labels and descriptions",
|
|
73
|
+
"Server-side errors need to be distributed to specific fields",
|
|
74
|
+
"You need dirty/touched tracking or custom validation logic"
|
|
75
|
+
],
|
|
76
|
+
"whenNot": [
|
|
77
|
+
"Simple inputs with basic label and helper text (use Input with label prop)",
|
|
78
|
+
"Standalone selects or textareas with built-in error display"
|
|
79
|
+
],
|
|
80
|
+
"guidelines": [
|
|
81
|
+
"Always provide a Field.Label for accessibility",
|
|
82
|
+
"Wrap any form control in Field.Control to connect it to the field context",
|
|
83
|
+
"Use match prop on Field.Error for granular native validation messages",
|
|
84
|
+
"Wrap in Form to enable server-side error distribution by field name"
|
|
85
|
+
],
|
|
86
|
+
"accessibility": [
|
|
87
|
+
"Label automatically linked to control via aria-labelledby",
|
|
88
|
+
"Description linked via aria-describedby",
|
|
89
|
+
"Error messages announced to screen readers",
|
|
90
|
+
"Supports data-disabled and data-invalid attributes for styling"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"examples": [
|
|
94
|
+
{
|
|
95
|
+
"name": "Single field",
|
|
96
|
+
"description": "A single field with label, control, and description",
|
|
97
|
+
"code": "<Field name=\"email\">\n <Field.Label>Email address</Field.Label>\n <Field.Control>\n <Input type=\"email\" placeholder=\"jane@example.com\" />\n </Field.Control>\n <Field.Description>We will never share your email.</Field.Description>\n</Field>"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "Two-column layout",
|
|
101
|
+
"description": "Fields arranged in a two-column grid",
|
|
102
|
+
"code": "<Grid columns={2} gap=\"md\">\n <Field name=\"firstName\">\n <Field.Label>First Name</Field.Label>\n <Field.Control>\n <Input placeholder=\"Jane\" />\n </Field.Control>\n </Field>\n <Field name=\"lastName\">\n <Field.Label>Last Name</Field.Label>\n <Field.Control>\n <Input placeholder=\"Doe\" />\n </Field.Control>\n </Field>\n <Grid.Item colSpan=\"full\">\n <Field name=\"email\">\n <Field.Label>Email</Field.Label>\n <Field.Control>\n <Input type=\"email\" placeholder=\"jane@example.com\" />\n </Field.Control>\n <Field.Error match=\"typeMismatch\">Enter a valid email address</Field.Error>\n </Field>\n </Grid.Item>\n</Grid>"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "Custom validation",
|
|
106
|
+
"description": "Field with custom validate function",
|
|
107
|
+
"code": "<Field\n name=\"age\"\n validate={(value) => {\n const num = Number(value);\n if (isNaN(num) || num < 18) return 'Must be 18 or older';\n return null;\n }}\n validationMode=\"onChange\"\n validationDebounceTime={500}\n>\n <Field.Label>Age</Field.Label>\n <Field.Control>\n <Input type=\"number\" placeholder=\"18\" />\n </Field.Control>\n <Field.Description>You must be at least 18 years old.</Field.Description>\n <Field.Error match=\"customError\" />\n</Field>"
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"relations": [
|
|
111
|
+
{
|
|
112
|
+
"component": "Input",
|
|
113
|
+
"relationship": "alternative",
|
|
114
|
+
"note": "Use Input for simple fields with built-in label/error"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"component": "Form",
|
|
118
|
+
"relationship": "parent",
|
|
119
|
+
"note": "Wrap in Form for server-side error distribution"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"component": "Fieldset",
|
|
123
|
+
"relationship": "sibling",
|
|
124
|
+
"note": "Use Fieldset to group related fields"
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"contract": {
|
|
128
|
+
"propsSummary": [
|
|
129
|
+
"name: string - field name for error distribution",
|
|
130
|
+
"validate: (value) => string | null - custom validation",
|
|
131
|
+
"validationMode: onSubmit|onBlur|onChange - validation trigger",
|
|
132
|
+
"Field.Control: wraps any form component (Input, Textarea, etc.)",
|
|
133
|
+
"Field.Error match: valueMissing|typeMismatch|customError|... - granular errors"
|
|
134
|
+
],
|
|
135
|
+
"a11yRules": [
|
|
136
|
+
"A11Y_FIELD_LABEL",
|
|
137
|
+
"A11Y_FIELD_ERROR",
|
|
138
|
+
"A11Y_FIELD_DESCRIPTION"
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
"ai": {
|
|
142
|
+
"compositionPattern": "compound",
|
|
143
|
+
"subComponents": [
|
|
144
|
+
"Label",
|
|
145
|
+
"Control",
|
|
146
|
+
"Description",
|
|
147
|
+
"Error",
|
|
148
|
+
"Validity"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"provenance": {
|
|
152
|
+
"source": "migrated",
|
|
153
|
+
"verified": false,
|
|
154
|
+
"frameworkSupport": "native",
|
|
155
|
+
"extractedAt": "2026-03-13T23:18:59.733Z"
|
|
156
|
+
}
|
|
157
|
+
}
|