@fragments-sdk/ui 0.17.1 → 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.
Files changed (69) hide show
  1. package/fragments.json +1 -1
  2. package/package.json +3 -3
  3. package/src/components/Accordion/Accordion.contract.json +169 -0
  4. package/src/components/Alert/Alert.contract.json +157 -0
  5. package/src/components/AppShell/AppShell.contract.json +155 -0
  6. package/src/components/Avatar/Avatar.contract.json +189 -0
  7. package/src/components/Badge/Badge.contract.json +187 -0
  8. package/src/components/BentoGrid/BentoGrid.contract.json +135 -0
  9. package/src/components/Box/Box.contract.json +423 -0
  10. package/src/components/Breadcrumbs/Breadcrumbs.contract.json +143 -0
  11. package/src/components/Button/Button.contract.json +205 -0
  12. package/src/components/ButtonGroup/ButtonGroup.contract.json +140 -0
  13. package/src/components/Card/Card.contract.json +185 -0
  14. package/src/components/Chart/Chart.contract.json +129 -0
  15. package/src/components/Checkbox/Checkbox.contract.json +246 -0
  16. package/src/components/Chip/Chip.contract.json +212 -0
  17. package/src/components/CodeBlock/CodeBlock.contract.json +388 -0
  18. package/src/components/Collapsible/Collapsible.contract.json +154 -0
  19. package/src/components/ColorPicker/ColorPicker.contract.json +212 -0
  20. package/src/components/Combobox/Combobox.contract.json +297 -0
  21. package/src/components/Command/Command.contract.json +165 -0
  22. package/src/components/ConversationList/ConversationList.contract.json +151 -0
  23. package/src/components/DataTable/DataTable.contract.json +302 -0
  24. package/src/components/DatePicker/DatePicker.contract.json +288 -0
  25. package/src/components/Dialog/Dialog.contract.json +159 -0
  26. package/src/components/Drawer/Drawer.contract.json +160 -0
  27. package/src/components/Editor/Editor.contract.json +263 -0
  28. package/src/components/EmptyState/EmptyState.contract.json +133 -0
  29. package/src/components/Field/Field.contract.json +157 -0
  30. package/src/components/Fieldset/Fieldset.contract.json +117 -0
  31. package/src/components/Form/Form.contract.json +145 -0
  32. package/src/components/Grid/Grid.contract.json +195 -0
  33. package/src/components/Header/Header.contract.json +194 -0
  34. package/src/components/Icon/Icon.contract.json +194 -0
  35. package/src/components/Image/Image.contract.json +209 -0
  36. package/src/components/Input/Input.contract.json +344 -0
  37. package/src/components/Link/Link.contract.json +180 -0
  38. package/src/components/List/List.contract.json +154 -0
  39. package/src/components/Listbox/Listbox.contract.json +158 -0
  40. package/src/components/Loading/Loading.contract.json +167 -0
  41. package/src/components/Markdown/Markdown.contract.json +127 -0
  42. package/src/components/Menu/Menu.contract.json +177 -0
  43. package/src/components/Message/Message.contract.json +183 -0
  44. package/src/components/NavigationMenu/NavigationMenu.contract.json +203 -0
  45. package/src/components/Pagination/Pagination.contract.json +163 -0
  46. package/src/components/Popover/Popover.contract.json +163 -0
  47. package/src/components/Progress/Progress.contract.json +176 -0
  48. package/src/components/Prompt/Prompt.contract.json +211 -0
  49. package/src/components/RadioGroup/RadioGroup.contract.json +226 -0
  50. package/src/components/ScrollArea/ScrollArea.contract.json +131 -0
  51. package/src/components/Select/Select.contract.json +269 -0
  52. package/src/components/Separator/Separator.contract.json +143 -0
  53. package/src/components/Sidebar/Sidebar.contract.json +258 -0
  54. package/src/components/Skeleton/Skeleton.contract.json +166 -0
  55. package/src/components/Slider/Slider.contract.json +248 -0
  56. package/src/components/Stack/Stack.contract.json +220 -0
  57. package/src/components/Table/Table.contract.json +171 -0
  58. package/src/components/TableOfContents/TableOfContents.contract.json +145 -0
  59. package/src/components/Tabs/Tabs.contract.json +159 -0
  60. package/src/components/Text/Text.contract.json +239 -0
  61. package/src/components/Textarea/Textarea.contract.json +308 -0
  62. package/src/components/Theme/Theme.contract.json +152 -0
  63. package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +165 -0
  64. package/src/components/Toast/Toast.contract.json +181 -0
  65. package/src/components/Toggle/Toggle.contract.json +231 -0
  66. package/src/components/ToggleGroup/ToggleGroup.contract.json +206 -0
  67. package/src/components/Tooltip/Tooltip.contract.json +214 -0
  68. package/src/components/VisuallyHidden/VisuallyHidden.contract.json +116 -0
  69. package/src/tokens/_derive.scss +4 -1
@@ -0,0 +1,165 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "Command",
4
+ "description": "A searchable command palette for quick actions. Combines an input with a filterable, keyboard-navigable list of actions.",
5
+ "category": "navigation",
6
+ "tags": [
7
+ "command",
8
+ "palette",
9
+ "search",
10
+ "spotlight",
11
+ "quick-actions",
12
+ "cmdk"
13
+ ],
14
+ "status": "stable",
15
+ "sourcePath": "src/components/Command/index.tsx",
16
+ "exportName": "Command",
17
+ "propsSummary": [
18
+ "children: node (required)",
19
+ "search: string",
20
+ "defaultSearch: string (default: )",
21
+ "onSearchChange: function",
22
+ "filter: function",
23
+ "loop: boolean (default: true)"
24
+ ],
25
+ "props": {
26
+ "children": {
27
+ "type": "node",
28
+ "description": "Command.Input, Command.List, and other sub-components",
29
+ "required": true
30
+ },
31
+ "search": {
32
+ "type": "string",
33
+ "description": "Controlled search value",
34
+ "required": false
35
+ },
36
+ "defaultSearch": {
37
+ "type": "string",
38
+ "description": "Default search value (uncontrolled)",
39
+ "default": "",
40
+ "required": false
41
+ },
42
+ "onSearchChange": {
43
+ "type": "function",
44
+ "description": "Called when search input changes",
45
+ "required": false
46
+ },
47
+ "filter": {
48
+ "type": "function",
49
+ "description": "Custom filter function. Return 0 to hide, >0 to show.",
50
+ "required": false
51
+ },
52
+ "loop": {
53
+ "type": "boolean",
54
+ "description": "Whether to loop keyboard navigation",
55
+ "default": "true",
56
+ "required": false
57
+ }
58
+ },
59
+ "usage": {
60
+ "when": [
61
+ "Quick-access command palettes (Ctrl+K)",
62
+ "Searchable action menus",
63
+ "Inline command lists with filtering",
64
+ "Application-wide search interfaces"
65
+ ],
66
+ "whenNot": [
67
+ "Simple dropdown menus (use Menu)",
68
+ "Form field selection (use Select or Combobox)",
69
+ "Static navigation (use Sidebar or Tabs)",
70
+ "Search with complex result types (build custom)"
71
+ ],
72
+ "guidelines": [
73
+ "Compose inside Dialog for modal command palette usage",
74
+ "Use Command.Group to organize items by category",
75
+ "Provide Command.Empty for no-results feedback",
76
+ "Use keywords prop for items that should match on aliases",
77
+ "Keep item labels short and action-oriented"
78
+ ],
79
+ "accessibility": [
80
+ "Uses combobox + listbox ARIA pattern",
81
+ "Keyboard navigation with ArrowUp/ArrowDown, Enter to select",
82
+ "Home/End jump to first/last item",
83
+ "aria-activedescendant tracks focused item"
84
+ ]
85
+ },
86
+ "examples": [
87
+ {
88
+ "name": "Default",
89
+ "description": "Inline command list with search",
90
+ "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"Type a command...\" />\n <Command.List>\n <Command.Item onItemSelect={() => {}}>Open File</Command.Item>\n <Command.Item onItemSelect={() => {}}>Save Document</Command.Item>\n <Command.Item onItemSelect={() => {}}>Print</Command.Item>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
91
+ },
92
+ {
93
+ "name": "Dialog Command Palette",
94
+ "description": "Command palette inside a Dialog",
95
+ "code": "<Dialog>\n <Dialog.Trigger asChild>\n <Button variant=\"secondary\">Open Command Palette</Button>\n </Dialog.Trigger>\n <Dialog.Content size=\"sm\">\n <Command>\n <Command.Input placeholder=\"Search commands...\" />\n <Command.List>\n <Command.Group heading=\"Actions\">\n <Command.Item onItemSelect={() => {}}>New File</Command.Item>\n <Command.Item onItemSelect={() => {}}>Open Recent</Command.Item>\n </Command.Group>\n <Command.Separator />\n <Command.Group heading=\"Settings\">\n <Command.Item onItemSelect={() => {}}>Preferences</Command.Item>\n <Command.Item onItemSelect={() => {}}>Keyboard Shortcuts</Command.Item>\n </Command.Group>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n </Dialog.Content>\n</Dialog>"
96
+ },
97
+ {
98
+ "name": "With Groups",
99
+ "description": "Organized by category groups",
100
+ "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"Search...\" />\n <Command.List>\n <Command.Group heading=\"Suggestions\">\n <Command.Item onItemSelect={() => {}}>Calendar</Command.Item>\n <Command.Item onItemSelect={() => {}}>Calculator</Command.Item>\n </Command.Group>\n <Command.Separator />\n <Command.Group heading=\"Settings\">\n <Command.Item onItemSelect={() => {}}>Profile</Command.Item>\n <Command.Item onItemSelect={() => {}}>Billing</Command.Item>\n <Command.Item disabled onItemSelect={() => {}}>\n Team (coming soon)\n </Command.Item>\n </Command.Group>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
101
+ },
102
+ {
103
+ "name": "With Icons",
104
+ "description": "Items with leading icons",
105
+ "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"What do you need?\" />\n <Command.List>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>+</span> New Document\n </Command.Item>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>{'>'}</span> Open Folder\n </Command.Item>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>?</span> Search\n </Command.Item>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
106
+ }
107
+ ],
108
+ "relations": [
109
+ {
110
+ "component": "Dialog",
111
+ "relationship": "sibling",
112
+ "note": "Compose inside Dialog for modal command palette"
113
+ },
114
+ {
115
+ "component": "Listbox",
116
+ "relationship": "sibling",
117
+ "note": "Command uses Listbox-like keyboard navigation internally"
118
+ },
119
+ {
120
+ "component": "Combobox",
121
+ "relationship": "alternative",
122
+ "note": "Use Combobox for form field selection with search"
123
+ }
124
+ ],
125
+ "contract": {
126
+ "propsSummary": [
127
+ "search: string - controlled search value",
128
+ "onSearchChange: (search) => void - search change handler",
129
+ "filter: (value, search, keywords?) => number - custom filter",
130
+ "loop: boolean - loop keyboard navigation (default: true)",
131
+ "Command.Item value: string - filter match value",
132
+ "Command.Item keywords: string[] - extra filter terms",
133
+ "Command.Item onItemSelect: (value, event) => void - selection handler"
134
+ ],
135
+ "a11yRules": [
136
+ "A11Y_COMBOBOX_ROLE",
137
+ "A11Y_LISTBOX_ROLE",
138
+ "A11Y_ACTIVE_DESCENDANT"
139
+ ]
140
+ },
141
+ "ai": {
142
+ "compositionPattern": "compound",
143
+ "subComponents": [
144
+ "Input",
145
+ "List",
146
+ "Item",
147
+ "Group",
148
+ "Empty",
149
+ "Separator"
150
+ ],
151
+ "requiredChildren": [
152
+ "Input",
153
+ "List"
154
+ ],
155
+ "commonPatterns": [
156
+ "<Dialog><Dialog.Trigger><Button>Open Palette</Button></Dialog.Trigger><Dialog.Content size=\"sm\"><Command><Command.Input placeholder=\"Search...\" /><Command.List><Command.Group heading=\"Actions\"><Command.Item onItemSelect={() => {}}>Action 1</Command.Item></Command.Group><Command.Empty>No results.</Command.Empty></Command.List></Command></Dialog.Content></Dialog>"
157
+ ]
158
+ },
159
+ "provenance": {
160
+ "source": "migrated",
161
+ "verified": false,
162
+ "frameworkSupport": "native",
163
+ "extractedAt": "2026-03-13T23:18:53.723Z"
164
+ }
165
+ }
@@ -0,0 +1,151 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "ConversationList",
4
+ "description": "Scrollable message container with auto-scroll and history loading",
5
+ "category": "ai",
6
+ "tags": [
7
+ "conversation",
8
+ "chat",
9
+ "messages",
10
+ "scroll",
11
+ "ai",
12
+ "list"
13
+ ],
14
+ "status": "stable",
15
+ "sourcePath": "src/components/ConversationList/index.tsx",
16
+ "exportName": "ConversationList",
17
+ "propsSummary": [
18
+ "children: node (required)",
19
+ "autoScroll: union (default: smart)",
20
+ "onScrollTop: function",
21
+ "loadingHistory: boolean (default: false)",
22
+ "emptyState: node",
23
+ "scrollTopThreshold: number (default: 50)",
24
+ "scrollBottomThreshold: number (default: 100)"
25
+ ],
26
+ "props": {
27
+ "children": {
28
+ "type": "node",
29
+ "description": "Message components",
30
+ "required": true
31
+ },
32
+ "autoScroll": {
33
+ "type": "union",
34
+ "description": "Auto-scroll behavior: true (always), false (never), or \"smart\" (only when near bottom)",
35
+ "default": "smart",
36
+ "required": false
37
+ },
38
+ "onScrollTop": {
39
+ "type": "function",
40
+ "description": "Callback when user scrolls to top (for loading history). Receives the scroll event.",
41
+ "required": false
42
+ },
43
+ "loadingHistory": {
44
+ "type": "boolean",
45
+ "description": "Show loading spinner at top when loading history",
46
+ "default": "false",
47
+ "required": false
48
+ },
49
+ "emptyState": {
50
+ "type": "node",
51
+ "description": "Content to show when conversation is empty",
52
+ "required": false
53
+ },
54
+ "scrollTopThreshold": {
55
+ "type": "number",
56
+ "description": "Pixels from top to trigger onScrollTop",
57
+ "default": "50",
58
+ "required": false
59
+ },
60
+ "scrollBottomThreshold": {
61
+ "type": "number",
62
+ "description": "Pixels from bottom for smart auto-scroll",
63
+ "default": "100",
64
+ "required": false
65
+ }
66
+ },
67
+ "usage": {
68
+ "when": [
69
+ "Building a chat interface with multiple messages",
70
+ "Need auto-scroll behavior when new messages arrive",
71
+ "Require infinite scroll for loading message history",
72
+ "Want date separators between message groups"
73
+ ],
74
+ "whenNot": [
75
+ "Simple list of items without chat context (use List)",
76
+ "Single message display (use Message directly)",
77
+ "Non-scrolling message layout"
78
+ ],
79
+ "guidelines": [
80
+ "Use autoScroll=\"smart\" for best UX (only auto-scrolls when near bottom)",
81
+ "Implement onScrollTop for loading older messages",
82
+ "ConversationList composes your onScroll handler with internal auto-scroll/history logic",
83
+ "Provide an emptyState for new conversations",
84
+ "Use DateSeparator between messages from different days"
85
+ ],
86
+ "accessibility": [
87
+ "Uses proper ARIA roles for separators",
88
+ "Typing indicator has aria-label",
89
+ "Smooth scroll respects reduced motion preferences",
90
+ "Keyboard navigation works within scrollable container"
91
+ ]
92
+ },
93
+ "examples": [
94
+ {
95
+ "name": "Basic",
96
+ "description": "Simple conversation with messages",
97
+ "code": "<ConversationList>\n <Message role=\"user\">\n <Message.Content>Hello!</Message.Content>\n </Message>\n <Message role=\"assistant\">\n <Message.Content>Hi there! How can I help you today?</Message.Content>\n </Message>\n <Message role=\"user\">\n <Message.Content>Can you explain React hooks?</Message.Content>\n </Message>\n</ConversationList>"
98
+ },
99
+ {
100
+ "name": "With Date Separators",
101
+ "description": "Messages grouped by date",
102
+ "code": "<ConversationList>\n <ConversationList.DateSeparator date={new Date(Date.now() - 86400000)} />\n <Message role=\"user\">\n <Message.Content>A message from yesterday</Message.Content>\n </Message>\n <ConversationList.DateSeparator date={new Date()} />\n <Message role=\"assistant\">\n <Message.Content>And a message from today!</Message.Content>\n </Message>\n</ConversationList>"
103
+ },
104
+ {
105
+ "name": "With Typing Indicator",
106
+ "description": "Shows assistant is typing",
107
+ "code": "<ConversationList>\n <Message role=\"user\">\n <Message.Content>What is TypeScript?</Message.Content>\n </Message>\n <ConversationList.TypingIndicator name=\"Assistant\" />\n</ConversationList>"
108
+ },
109
+ {
110
+ "name": "Loading History",
111
+ "description": "Loading older messages",
112
+ "code": "<ConversationList loadingHistory>\n <Message role=\"user\">\n <Message.Content>This is the latest message</Message.Content>\n </Message>\n</ConversationList>"
113
+ }
114
+ ],
115
+ "relations": [
116
+ {
117
+ "component": "Message",
118
+ "relationship": "child",
119
+ "note": "ConversationList contains Message components"
120
+ },
121
+ {
122
+ "component": "ThinkingIndicator",
123
+ "relationship": "child",
124
+ "note": "Show ThinkingIndicator at bottom while awaiting response"
125
+ },
126
+ {
127
+ "component": "Prompt",
128
+ "relationship": "sibling",
129
+ "note": "Typically paired with Prompt for input"
130
+ }
131
+ ],
132
+ "contract": {
133
+ "propsSummary": [
134
+ "children: ReactNode - Message components",
135
+ "autoScroll: boolean | \"smart\" - scroll behavior (default: \"smart\")",
136
+ "onScrollTop: (event?) => void - callback for loading history (receives scroll event)",
137
+ "loadingHistory: boolean - show history loading spinner",
138
+ "emptyState: ReactNode - empty conversation content"
139
+ ],
140
+ "a11yRules": [
141
+ "A11Y_ARIA_ROLES",
142
+ "A11Y_MOTION_PREFERENCE"
143
+ ]
144
+ },
145
+ "provenance": {
146
+ "source": "migrated",
147
+ "verified": false,
148
+ "frameworkSupport": "native",
149
+ "extractedAt": "2026-03-13T23:18:53.889Z"
150
+ }
151
+ }
@@ -0,0 +1,302 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "DataTable",
4
+ "description": "Data table with sorting, selection, and column management. Powered by TanStack Table.",
5
+ "category": "display",
6
+ "tags": [
7
+ "table",
8
+ "data",
9
+ "grid",
10
+ "list",
11
+ "sorting",
12
+ "tanstack"
13
+ ],
14
+ "status": "stable",
15
+ "sourcePath": "src/components/DataTable/index.tsx",
16
+ "exportName": "DataTable",
17
+ "propsSummary": [
18
+ "columns: array (required)",
19
+ "data: array (required)",
20
+ "getRowId: function",
21
+ "sortable: boolean (default: false)",
22
+ "sorting: array",
23
+ "onSortingChange: function",
24
+ "selectable: boolean (default: false)",
25
+ "showCheckbox: boolean (default: false)",
26
+ "rowSelection: object",
27
+ "onRowSelectionChange: function",
28
+ "onRowClick: function",
29
+ "getSubRows: function",
30
+ "expanded: union",
31
+ "onExpandedChange: function",
32
+ "emptyMessage: string (default: No data available)",
33
+ "size: sm|md (default: md)",
34
+ "caption: string",
35
+ "captionHidden: boolean (default: false)",
36
+ "striped: boolean (default: false)",
37
+ "bordered: boolean (default: false)",
38
+ "wrapperClassName: string",
39
+ "wrapperProps: object"
40
+ ],
41
+ "props": {
42
+ "columns": {
43
+ "type": "array",
44
+ "description": "Column definitions",
45
+ "required": true
46
+ },
47
+ "data": {
48
+ "type": "array",
49
+ "description": "Data rows to display",
50
+ "required": true
51
+ },
52
+ "getRowId": {
53
+ "type": "function",
54
+ "description": "Unique key extractor for each row",
55
+ "required": false
56
+ },
57
+ "sortable": {
58
+ "type": "boolean",
59
+ "description": "Enable column sorting",
60
+ "default": "false",
61
+ "required": false
62
+ },
63
+ "sorting": {
64
+ "type": "array",
65
+ "description": "Controlled sorting state",
66
+ "required": false
67
+ },
68
+ "onSortingChange": {
69
+ "type": "function",
70
+ "description": "Sorting change handler",
71
+ "required": false
72
+ },
73
+ "selectable": {
74
+ "type": "boolean",
75
+ "description": "Enable row selection",
76
+ "default": "false",
77
+ "required": false
78
+ },
79
+ "showCheckbox": {
80
+ "type": "boolean",
81
+ "description": "Show checkbox column for row selection (requires selectable)",
82
+ "default": "false",
83
+ "required": false
84
+ },
85
+ "rowSelection": {
86
+ "type": "object",
87
+ "description": "Controlled row selection state",
88
+ "required": false
89
+ },
90
+ "onRowSelectionChange": {
91
+ "type": "function",
92
+ "description": "Row selection change handler",
93
+ "required": false
94
+ },
95
+ "onRowClick": {
96
+ "type": "function",
97
+ "description": "Handler for row clicks/keyboard activation. Called as (row, event)",
98
+ "required": false
99
+ },
100
+ "getSubRows": {
101
+ "type": "function",
102
+ "description": "Extract sub-rows for expandable tree tables",
103
+ "required": false
104
+ },
105
+ "expanded": {
106
+ "type": "union",
107
+ "description": "Controlled expanded state",
108
+ "required": false
109
+ },
110
+ "onExpandedChange": {
111
+ "type": "function",
112
+ "description": "Expanded state change handler",
113
+ "required": false
114
+ },
115
+ "emptyMessage": {
116
+ "type": "string",
117
+ "description": "Message when no data",
118
+ "default": "No data available",
119
+ "required": false
120
+ },
121
+ "size": {
122
+ "type": "enum",
123
+ "description": "Table density",
124
+ "default": "md",
125
+ "required": false,
126
+ "values": [
127
+ "sm",
128
+ "md"
129
+ ]
130
+ },
131
+ "caption": {
132
+ "type": "string",
133
+ "description": "Visible caption for the table",
134
+ "required": false
135
+ },
136
+ "captionHidden": {
137
+ "type": "boolean",
138
+ "description": "Hide caption visually but keep it for screen readers",
139
+ "default": "false",
140
+ "required": false
141
+ },
142
+ "striped": {
143
+ "type": "boolean",
144
+ "description": "Show alternating row backgrounds",
145
+ "default": "false",
146
+ "required": false
147
+ },
148
+ "bordered": {
149
+ "type": "boolean",
150
+ "description": "Wrap table in a bordered container",
151
+ "default": "false",
152
+ "required": false
153
+ },
154
+ "wrapperClassName": {
155
+ "type": "string",
156
+ "description": "Additional class name for the outer wrapper div",
157
+ "required": false
158
+ },
159
+ "wrapperProps": {
160
+ "type": "object",
161
+ "description": "Props forwarded to the outer wrapper div (id, aria-*, data-*, handlers)",
162
+ "required": false
163
+ }
164
+ },
165
+ "usage": {
166
+ "when": [
167
+ "Displaying structured, tabular data with sorting",
168
+ "Data that users need to scan, compare, and act upon",
169
+ "Lists with multiple attributes per item that need sorting or selection",
170
+ "Data-rich tables requiring column sizing and row clicks",
171
+ "Hierarchical data with expandable sub-rows"
172
+ ],
173
+ "whenNot": [
174
+ "Simple static tables (use Table component)",
175
+ "Simple lists (use List component)",
176
+ "Card-based layouts (use Grid with Cards)",
177
+ "Small screens (consider card or list view)"
178
+ ],
179
+ "guidelines": [
180
+ "Keep columns to a reasonable number (5-7 max)",
181
+ "Use consistent alignment (numbers right, text left)",
182
+ "Provide meaningful empty states",
183
+ "Consider mobile responsiveness",
184
+ "Use showCheckbox for bulk selection workflows"
185
+ ],
186
+ "accessibility": [
187
+ "Proper table semantics with headers",
188
+ "Sortable columns are keyboard accessible",
189
+ "Row selection checkboxes include aria-labels",
190
+ "Expand/collapse buttons have aria-expanded state"
191
+ ]
192
+ },
193
+ "examples": [
194
+ {
195
+ "name": "Default",
196
+ "description": "Basic data table with status badges and role columns",
197
+ "code": "<DataTable\n columns={basicColumns}\n data={sampleUsers}\n aria-label=\"Team members\"\n/>"
198
+ },
199
+ {
200
+ "name": "Rich Cells",
201
+ "description": "Custom cells with avatars, stacked text, and column sizing",
202
+ "code": "<DataTable\n columns={richColumns}\n data={sampleUsers}\n bordered\n aria-label=\"Team members\"\n/>"
203
+ },
204
+ {
205
+ "name": "Sortable",
206
+ "description": "Click column headers to sort ascending or descending",
207
+ "code": "<DataTable\n columns={transactionColumns}\n data={sampleTransactions}\n sortable\n bordered\n caption=\"Recent transactions\"\n captionHidden\n aria-label=\"Transactions\"\n/>"
208
+ },
209
+ {
210
+ "name": "Checkbox Selection",
211
+ "description": "Select rows with header checkbox for select-all and individual row checkboxes",
212
+ "code": "function TeamTable() {\n const [selection, setSelection] = useState({});\n const selectedCount = Object.values(selection).filter(Boolean).length;\n\n return (\n <Stack gap=\"sm\">\n <Stack direction=\"row\" justify=\"between\" align=\"center\">\n <Text size=\"sm\" color=\"secondary\">\n {selectedCount > 0 ? `${selectedCount} selected` : 'Select rows with checkboxes'}\n </Text>\n {selectedCount > 0 && (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setSelection({})}>\n Clear\n </Button>\n )}\n </Stack>\n <DataTable\n columns={columns}\n data={users}\n selectable\n showCheckbox\n rowSelection={selection}\n onRowSelectionChange={setSelection}\n getRowId={(row) => row.id}\n bordered\n aria-label=\"Team members\"\n />\n </Stack>\n );\n}"
213
+ },
214
+ {
215
+ "name": "Expandable Rows",
216
+ "description": "Hierarchical data with collapsible sub-rows, like a file tree",
217
+ "code": "const fileTreeData = [\n {\n id: '1', name: 'src', type: 'folder', modified: 'Feb 18, 2026',\n subRows: [\n { id: '1.1', name: 'components', type: 'folder', modified: 'Feb 18, 2026',\n subRows: [\n { id: '1.1.1', name: 'Button.tsx', type: 'file', size: '4.2 KB', modified: 'Feb 17, 2026' },\n { id: '1.1.2', name: 'Card.tsx', type: 'file', size: '3.8 KB', modified: 'Feb 16, 2026' },\n ],\n },\n ],\n },\n { id: '2', name: 'package.json', type: 'file', size: '1.2 KB', modified: 'Feb 18, 2026' },\n];\n\n<DataTable\n columns={fileColumns}\n data={fileTreeData}\n getSubRows={(row) => row.subRows}\n getRowId={(row) => row.id}\n bordered\n size=\"sm\"\n aria-label=\"File tree\"\n/>"
218
+ },
219
+ {
220
+ "name": "With Filters",
221
+ "description": "Combine with search input and menu dropdowns for filtered views",
222
+ "code": "function FilteredTable() {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState(null);\n\n const filteredData = useMemo(() => {\n return users.filter((user) => {\n if (search && !user.name.toLowerCase().includes(search.toLowerCase())) return false;\n if (statusFilter && user.status !== statusFilter) return false;\n return true;\n });\n }, [search, statusFilter]);\n\n return (\n <Stack gap=\"sm\">\n <Stack direction=\"row\" gap=\"sm\" align=\"center\">\n <Input placeholder=\"Search...\" size=\"sm\" value={search} onChange={(e) => setSearch(e.target.value)} />\n <Menu>\n <Menu.Trigger asChild>\n <Button variant=\"secondary\" size=\"sm\">Status</Button>\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item onClick={() => setStatusFilter(null)}>All</Menu.Item>\n <Menu.Item onClick={() => setStatusFilter('active')}>Active</Menu.Item>\n <Menu.Item onClick={() => setStatusFilter('pending')}>Pending</Menu.Item>\n </Menu.Content>\n </Menu>\n </Stack>\n <DataTable\n columns={columns}\n data={filteredData}\n sortable\n bordered\n emptyMessage=\"No users match the current filters\"\n aria-label=\"Filtered team members\"\n />\n </Stack>\n );\n}"
223
+ },
224
+ {
225
+ "name": "Clickable Rows",
226
+ "description": "Rows respond to click and keyboard activation",
227
+ "code": "<DataTable\n columns={endpointColumns}\n data={sampleEndpoints}\n onRowClick={(row) => alert(`${row.method} ${row.path}`)}\n size=\"sm\"\n aria-label=\"API endpoints\"\n/>"
228
+ },
229
+ {
230
+ "name": "Striped",
231
+ "description": "Alternating row backgrounds for dense data",
232
+ "code": "<DataTable\n columns={endpointColumns}\n data={sampleEndpoints}\n striped\n size=\"sm\"\n sortable\n aria-label=\"API endpoints\"\n/>"
233
+ },
234
+ {
235
+ "name": "Empty State",
236
+ "description": "Display when no data matches the current filters",
237
+ "code": "<DataTable\n columns={basicColumns}\n data={[]}\n emptyMessage=\"No users match your search criteria\"\n aria-label=\"Search results\"\n/>"
238
+ }
239
+ ],
240
+ "relations": [
241
+ {
242
+ "component": "Table",
243
+ "relationship": "alternative",
244
+ "note": "Use Table for simple semantic HTML tables"
245
+ },
246
+ {
247
+ "component": "EmptyState",
248
+ "relationship": "sibling",
249
+ "note": "Use EmptyState for empty table states"
250
+ },
251
+ {
252
+ "component": "Badge",
253
+ "relationship": "sibling",
254
+ "note": "Use Badge for status columns"
255
+ },
256
+ {
257
+ "component": "Menu",
258
+ "relationship": "sibling",
259
+ "note": "Use Menu for filter dropdowns"
260
+ },
261
+ {
262
+ "component": "Checkbox",
263
+ "relationship": "sibling",
264
+ "note": "Built-in checkbox selection via showCheckbox"
265
+ }
266
+ ],
267
+ "contract": {
268
+ "propsSummary": [
269
+ "columns: ColumnDef[] - column definitions",
270
+ "data: T[] - row data array",
271
+ "sortable: boolean - enable sorting",
272
+ "selectable: boolean - enable row selection",
273
+ "showCheckbox: boolean - add checkbox column",
274
+ "getSubRows: (row) => T[] - enable expandable rows",
275
+ "onRowClick: (row, event) => void - row activation handler with event access",
276
+ "size: sm|md - table density",
277
+ "striped: boolean - alternating row backgrounds",
278
+ "bordered: boolean - bordered container",
279
+ "wrapperClassName / wrapperProps - style and configure the outer wrapper div"
280
+ ],
281
+ "a11yRules": [
282
+ "A11Y_TABLE_HEADERS",
283
+ "A11Y_TABLE_SORT"
284
+ ]
285
+ },
286
+ "ai": {
287
+ "compositionPattern": "simple",
288
+ "subComponents": [
289
+ "Root",
290
+ "Columns"
291
+ ],
292
+ "commonPatterns": [
293
+ "<DataTable columns={createColumns([{key:\"name\",header:\"Name\"},{key:\"status\",header:\"Status\"}])} data={[{name:\"Item 1\",status:\"Active\"}]} />"
294
+ ]
295
+ },
296
+ "provenance": {
297
+ "source": "migrated",
298
+ "verified": false,
299
+ "frameworkSupport": "native",
300
+ "extractedAt": "2026-03-13T23:18:54.097Z"
301
+ }
302
+ }