@duro-app/ui 0.20.1 → 0.22.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 (93) hide show
  1. package/dist/components/ActionBar/ActionBar.meta.d.ts +3 -0
  2. package/dist/components/ActionBar/ActionBar.meta.d.ts.map +1 -0
  3. package/dist/components/ActionBar/ActionBar.stories.d.ts.map +1 -1
  4. package/dist/components/Alert/Alert.meta.d.ts +3 -0
  5. package/dist/components/Alert/Alert.meta.d.ts.map +1 -0
  6. package/dist/components/Badge/Badge.meta.d.ts +3 -0
  7. package/dist/components/Badge/Badge.meta.d.ts.map +1 -0
  8. package/dist/components/Callout/Callout.meta.d.ts +3 -0
  9. package/dist/components/Callout/Callout.meta.d.ts.map +1 -0
  10. package/dist/components/Card/Card.meta.d.ts +3 -0
  11. package/dist/components/Card/Card.meta.d.ts.map +1 -0
  12. package/dist/components/DetailPanel/DetailPanel.d.ts.map +1 -1
  13. package/dist/components/DetailPanel/DetailPanel.meta.d.ts.map +1 -1
  14. package/dist/components/DetailPanel/DetailPanel.stories.d.ts.map +1 -1
  15. package/dist/components/DetailPanel/styles.css.d.ts +4 -0
  16. package/dist/components/DetailPanel/styles.css.d.ts.map +1 -1
  17. package/dist/components/Dialog/Dialog.meta.d.ts.map +1 -1
  18. package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
  19. package/dist/components/EmptyState/EmptyState.meta.d.ts +3 -0
  20. package/dist/components/EmptyState/EmptyState.meta.d.ts.map +1 -0
  21. package/dist/components/Field/Field.stories.d.ts.map +1 -1
  22. package/dist/components/Heading/Heading.meta.d.ts +3 -0
  23. package/dist/components/Heading/Heading.meta.d.ts.map +1 -0
  24. package/dist/components/Icon/Icon.meta.d.ts +3 -0
  25. package/dist/components/Icon/Icon.meta.d.ts.map +1 -0
  26. package/dist/components/InputGroup/InputGroup.meta.d.ts +3 -0
  27. package/dist/components/InputGroup/InputGroup.meta.d.ts.map +1 -0
  28. package/dist/components/List/List.d.ts +46 -0
  29. package/dist/components/List/List.d.ts.map +1 -0
  30. package/dist/components/List/List.meta.d.ts +3 -0
  31. package/dist/components/List/List.meta.d.ts.map +1 -0
  32. package/dist/components/List/List.stories.d.ts +9 -0
  33. package/dist/components/List/List.stories.d.ts.map +1 -0
  34. package/dist/components/List/styles.css.d.ts +77 -0
  35. package/dist/components/List/styles.css.d.ts.map +1 -0
  36. package/dist/components/Panel/Panel.d.ts.map +1 -1
  37. package/dist/components/Panel/Panel.meta.d.ts.map +1 -1
  38. package/dist/components/Panel/Panel.stories.d.ts.map +1 -1
  39. package/dist/components/Panel/styles.css.d.ts +4 -0
  40. package/dist/components/Panel/styles.css.d.ts.map +1 -1
  41. package/dist/components/Spinner/Spinner.meta.d.ts +3 -0
  42. package/dist/components/Spinner/Spinner.meta.d.ts.map +1 -0
  43. package/dist/components/StatusIcon/StatusIcon.meta.d.ts +3 -0
  44. package/dist/components/StatusIcon/StatusIcon.meta.d.ts.map +1 -0
  45. package/dist/components/Table/Table.stories.d.ts.map +1 -1
  46. package/dist/components/Tabs/Tabs.stories.d.ts.map +1 -1
  47. package/dist/components/Text/Text.meta.d.ts +3 -0
  48. package/dist/components/Text/Text.meta.d.ts.map +1 -0
  49. package/dist/components/ThemeProvider/ThemeProvider.meta.d.ts +3 -0
  50. package/dist/components/ThemeProvider/ThemeProvider.meta.d.ts.map +1 -0
  51. package/dist/components/Toggle/styles.css.d.ts +1 -1
  52. package/dist/components/Toggle/styles.css.d.ts.map +1 -1
  53. package/dist/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  54. package/dist/index.css +1 -1
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1386 -1219
  58. package/dist/index.js.map +1 -1
  59. package/package.json +2 -2
  60. package/src/components/ActionBar/ActionBar.meta.ts +20 -0
  61. package/src/components/ActionBar/ActionBar.stories.tsx +10 -0
  62. package/src/components/Alert/Alert.meta.ts +25 -0
  63. package/src/components/Badge/Badge.meta.ts +20 -0
  64. package/src/components/Callout/Callout.meta.ts +22 -0
  65. package/src/components/Card/Card.meta.ts +25 -0
  66. package/src/components/DetailPanel/DetailPanel.meta.ts +4 -1
  67. package/src/components/DetailPanel/DetailPanel.stories.tsx +54 -27
  68. package/src/components/DetailPanel/DetailPanel.tsx +3 -16
  69. package/src/components/DetailPanel/styles.css.ts +5 -0
  70. package/src/components/Dialog/Dialog.meta.ts +8 -2
  71. package/src/components/Drawer/Drawer.meta.ts +4 -1
  72. package/src/components/EmptyState/EmptyState.meta.ts +22 -0
  73. package/src/components/Field/Field.stories.tsx +6 -0
  74. package/src/components/Heading/Heading.meta.ts +24 -0
  75. package/src/components/Icon/Icon.meta.ts +23 -0
  76. package/src/components/InputGroup/InputGroup.meta.ts +28 -0
  77. package/src/components/List/List.meta.ts +39 -0
  78. package/src/components/List/List.stories.tsx +200 -0
  79. package/src/components/List/List.tsx +118 -0
  80. package/src/components/List/styles.css.ts +99 -0
  81. package/src/components/Panel/Panel.meta.ts +12 -3
  82. package/src/components/Panel/Panel.stories.tsx +17 -10
  83. package/src/components/Panel/Panel.tsx +2 -10
  84. package/src/components/Panel/styles.css.ts +5 -0
  85. package/src/components/Spinner/Spinner.meta.ts +19 -0
  86. package/src/components/StatusIcon/StatusIcon.meta.ts +24 -0
  87. package/src/components/Table/Table.stories.tsx +16 -0
  88. package/src/components/Tabs/Tabs.stories.tsx +7 -0
  89. package/src/components/Text/Text.meta.ts +23 -0
  90. package/src/components/ThemeProvider/ThemeProvider.meta.ts +16 -0
  91. package/src/components/Toggle/styles.css.ts +2 -1
  92. package/src/components/Tooltip/Tooltip.stories.tsx +15 -0
  93. package/src/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duro-app/ui",
3
- "version": "0.20.1",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,7 +52,7 @@
52
52
  }
53
53
  },
54
54
  "dependencies": {
55
- "@duro-app/tokens": "^0.20.1"
55
+ "@duro-app/tokens": "^0.22.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@babel/preset-typescript": "^7.28.0",
@@ -0,0 +1,20 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Floating toolbar that appears at the bottom of the viewport when items are selected. Shows selection count and bulk actions. Animates in/out. Use with Table checkboxes for bulk operations.',
6
+ whenToUse: [
7
+ 'Bulk actions on table selections (delete, revoke, export)',
8
+ 'Multi-select workflows where actions apply to all selected items',
9
+ ],
10
+ whenNotToUse: [
11
+ 'Single-item actions — use inline buttons or a Menu',
12
+ 'Persistent toolbars — use Inline with buttons',
13
+ ],
14
+ relatedTo: [
15
+ {component: 'Table', relationship: 'Common pattern: Table checkboxes + ActionBar for bulk ops'},
16
+ ],
17
+ example: `<ActionBar selectedItemCount={selected.size} onClearSelection={() => setSelected(new Set())}>
18
+ <Button variant="danger" size="small" onClick={handleDelete}>Delete</Button>
19
+ </ActionBar>`,
20
+ }
@@ -13,6 +13,16 @@ interface ActionBarStoryArgs {
13
13
 
14
14
  const meta: Meta<ActionBarStoryArgs> = {
15
15
  title: 'Components/ActionBar',
16
+ argTypes: {
17
+ selectedItemCount: {
18
+ control: 'number',
19
+ description: 'Number of selected items displayed in the action bar',
20
+ },
21
+ isEmphasized: {
22
+ control: 'boolean',
23
+ description: 'Whether the action bar uses the emphasized (inverse) style',
24
+ },
25
+ },
16
26
  }
17
27
 
18
28
  export default meta
@@ -0,0 +1,25 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Inline status message with icon. Compact, single-line feedback for form validation results, API responses, or status updates. For block-level prominent messages, use Callout instead.',
6
+ whenToUse: [
7
+ 'Form submission feedback (success, error)',
8
+ 'API response status messages',
9
+ 'Inline warnings or info notices',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Block-level prominent messages — use Callout',
13
+ 'Toast notifications — use a toast system',
14
+ 'Form field errors — use Field.Error',
15
+ ],
16
+ relatedTo: [
17
+ {component: 'Callout', relationship: 'Callout for larger block-level messages; Alert for compact inline'},
18
+ ],
19
+ example: `<Stack gap="sm">
20
+ <Alert variant="success">Settings saved successfully.</Alert>
21
+ <Alert variant="error">Failed to connect. Please retry.</Alert>
22
+ <Alert variant="warning">Your session expires in 5 minutes.</Alert>
23
+ <Alert variant="info">New version available.</Alert>
24
+ </Stack>`,
25
+ }
@@ -0,0 +1,20 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Small label or tag for status indicators, counts, or categories. Renders inline. Use for metadata annotations next to text or in table cells.',
6
+ whenToUse: [
7
+ 'Status indicators (active, expired, pending)',
8
+ 'Category tags or labels',
9
+ 'Count indicators next to items',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Interactive toggleable tags — use Toggle or ToggleGroup',
13
+ 'Long descriptive messages — use Alert or Callout',
14
+ ],
15
+ example: `<Inline gap="xs">
16
+ <Badge variant="success">Active</Badge>
17
+ <Badge variant="error">Expired</Badge>
18
+ <Badge variant="default">Draft</Badge>
19
+ </Inline>`,
20
+ }
@@ -0,0 +1,22 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Block-level informational message with icon and colored background. More prominent than Alert. Use for important notices, onboarding tips, or contextual guidance that should stand out.',
6
+ whenToUse: [
7
+ 'Important notices that need visual prominence',
8
+ 'Onboarding tips or contextual guidance',
9
+ 'Warning messages before destructive actions',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Compact inline feedback — use Alert',
13
+ 'Form field errors — use Field.Error',
14
+ 'Toast notifications — use a toast system',
15
+ ],
16
+ relatedTo: [
17
+ {component: 'Alert', relationship: 'Alert for compact inline; Callout for block-level prominent'},
18
+ ],
19
+ example: `<Callout variant="warning">
20
+ Your subscription expires in 3 days. Renew now to avoid service interruption.
21
+ </Callout>`,
22
+ }
@@ -0,0 +1,25 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Container with visual styling (elevation, border, or fill). Groups related content with consistent spacing and background. For structural containers with Header/Body/Footer slots, use Panel instead.',
6
+ whenToUse: [
7
+ 'Grouping related content visually (settings sections, dashboard widgets)',
8
+ 'Clickable content cards with hover state (interactive variant)',
9
+ 'Content containers with elevation or borders',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Structural containers with Header/Body/Footer — use Panel',
13
+ 'Page-level layout — use PageShell',
14
+ 'Simple spacing — use Stack or Inline',
15
+ ],
16
+ relatedTo: [
17
+ {component: 'Panel', relationship: 'Panel for structural Header/Body/Footer; Card for visual container'},
18
+ ],
19
+ example: `<Card variant="elevated" size="md">
20
+ <Stack gap="md">
21
+ <Heading level={3}>Account</Heading>
22
+ <Text>Manage your account settings.</Text>
23
+ </Stack>
24
+ </Card>`,
25
+ }
@@ -18,7 +18,10 @@ export const meta: ComponentMeta = {
18
18
  optional: ['Title', 'Footer', 'Close'],
19
19
  },
20
20
  relatedTo: [
21
- {component: 'Drawer', relationship: 'Drawer is modal with backdrop; DetailPanel is non-modal and in-flow'},
21
+ {
22
+ component: 'Drawer',
23
+ relationship: 'Drawer is modal with backdrop; DetailPanel is non-modal and in-flow',
24
+ },
22
25
  {component: 'Panel', relationship: 'DetailPanel uses Panel structure internally'},
23
26
  {component: 'Table', relationship: 'Common pattern: Table + DetailPanel for master-detail'},
24
27
  ],
@@ -2,6 +2,7 @@ import type {Meta, StoryObj} from '@storybook/react'
2
2
  import {useState} from 'react'
3
3
  import {css, html} from 'react-strict-dom'
4
4
  import {DetailPanel} from './DetailPanel'
5
+ import {Panel} from '../Panel/Panel'
5
6
  import {Button} from '../Button/Button'
6
7
  import {Text} from '../Text/Text'
7
8
  import {Heading} from '../Heading/Heading'
@@ -56,9 +57,8 @@ function DefaultDemo() {
56
57
  </DetailPanel.Header>
57
58
  <DetailPanel.Body>
58
59
  <Text>
59
- This is a non-modal detail panel. The content behind it
60
- remains interactive — you can still click, scroll, and
61
- interact with the main area.
60
+ This is a non-modal detail panel. The content behind it remains interactive — you can
61
+ still click, scroll, and interact with the main area.
62
62
  </Text>
63
63
  </DetailPanel.Body>
64
64
  <DetailPanel.Footer>
@@ -137,9 +137,15 @@ function TableSelectionDemo() {
137
137
  <Heading level={3}>Users</Heading>
138
138
  <html.div>
139
139
  <html.div style={tableStyles.headerRow}>
140
- <html.span style={tableStyles.cellText}><Text variant="label">Name</Text></html.span>
141
- <html.span style={tableStyles.cellText}><Text variant="label">Role</Text></html.span>
142
- <html.span style={tableStyles.cellText}><Text variant="label">Status</Text></html.span>
140
+ <html.span style={tableStyles.cellText}>
141
+ <Text variant="label">Name</Text>
142
+ </html.span>
143
+ <html.span style={tableStyles.cellText}>
144
+ <Text variant="label">Role</Text>
145
+ </html.span>
146
+ <html.span style={tableStyles.cellText}>
147
+ <Text variant="label">Status</Text>
148
+ </html.span>
143
149
  </html.div>
144
150
  {users.map((user) => (
145
151
  <html.div
@@ -147,9 +153,15 @@ function TableSelectionDemo() {
147
153
  style={[tableStyles.row, selectedId === user.id && tableStyles.rowSelected]}
148
154
  onClick={() => setSelectedId(selectedId === user.id ? null : user.id)}
149
155
  >
150
- <html.span style={tableStyles.cellText}><Text>{user.name}</Text></html.span>
151
- <html.span style={tableStyles.cellText}><Text>{user.role}</Text></html.span>
152
- <html.span style={tableStyles.cellText}><Text>{user.status}</Text></html.span>
156
+ <html.span style={tableStyles.cellText}>
157
+ <Text>{user.name}</Text>
158
+ </html.span>
159
+ <html.span style={tableStyles.cellText}>
160
+ <Text>{user.role}</Text>
161
+ </html.span>
162
+ <html.span style={tableStyles.cellText}>
163
+ <Text>{user.status}</Text>
164
+ </html.span>
153
165
  </html.div>
154
166
  ))}
155
167
  </html.div>
@@ -170,22 +182,37 @@ function TableSelectionDemo() {
170
182
  <DetailPanel.Body>
171
183
  {selectedUser && (
172
184
  <Stack gap="md">
173
- <Stack gap="xs">
174
- <Text variant="label">Email</Text>
175
- <Text variant="bodySm">{selectedUser.email}</Text>
176
- </Stack>
177
- <Stack gap="xs">
178
- <Text variant="label">Role</Text>
179
- <Text variant="bodySm">{selectedUser.role}</Text>
180
- </Stack>
181
- <Stack gap="xs">
182
- <Text variant="label">Status</Text>
183
- <Inline gap="sm">
184
- <Badge variant={selectedUser.status === 'Active' ? 'success' : 'default'}>
185
- {selectedUser.status}
186
- </Badge>
187
- </Inline>
188
- </Stack>
185
+ <Panel.Root>
186
+ <Panel.Header>
187
+ <Text variant="label">Contact</Text>
188
+ </Panel.Header>
189
+ <Panel.Body>
190
+ <Stack gap="xs">
191
+ <Text variant="caption">Email</Text>
192
+ <Text variant="bodySm">{selectedUser.email}</Text>
193
+ </Stack>
194
+ </Panel.Body>
195
+ </Panel.Root>
196
+
197
+ <Panel.Root>
198
+ <Panel.Header>
199
+ <Text variant="label">Role &amp; Status</Text>
200
+ </Panel.Header>
201
+ <Panel.Body>
202
+ <Stack gap="sm">
203
+ <Inline gap="sm" align="center">
204
+ <Text variant="caption">Role</Text>
205
+ <Text variant="bodySm">{selectedUser.role}</Text>
206
+ </Inline>
207
+ <Inline gap="sm" align="center">
208
+ <Text variant="caption">Status</Text>
209
+ <Badge variant={selectedUser.status === 'Active' ? 'success' : 'default'}>
210
+ {selectedUser.status}
211
+ </Badge>
212
+ </Inline>
213
+ </Stack>
214
+ </Panel.Body>
215
+ </Panel.Root>
189
216
  </Stack>
190
217
  )}
191
218
  </DetailPanel.Body>
@@ -225,8 +252,8 @@ function MediumSizeDemo() {
225
252
  </DetailPanel.Header>
226
253
  <DetailPanel.Body>
227
254
  <Text>
228
- This panel is 480px wide, providing more room for complex
229
- content like forms or detailed information.
255
+ This panel is 480px wide, providing more room for complex content like forms or
256
+ detailed information.
230
257
  </Text>
231
258
  </DetailPanel.Body>
232
259
  </DetailPanel.Content>
@@ -194,12 +194,7 @@ function Content({children, size = 'sm', label}: ContentProps) {
194
194
  if (!present) return null
195
195
 
196
196
  return (
197
- <html.div
198
- style={[
199
- styles.wrapper,
200
- closing ? wrapperCloseMap[size] : wrapperOpenMap[size],
201
- ]}
202
- >
197
+ <html.div style={[styles.wrapper, closing ? wrapperCloseMap[size] : wrapperOpenMap[size]]}>
203
198
  <html.div
204
199
  ref={panelRef}
205
200
  role="complementary"
@@ -250,11 +245,7 @@ interface BodyProps {
250
245
  }
251
246
 
252
247
  function Body({children, padded = true}: BodyProps) {
253
- return (
254
- <html.div style={[styles.body, padded && styles.bodyPadded]}>
255
- {children}
256
- </html.div>
257
- )
248
+ return <html.div style={[styles.body, padded && styles.bodyPadded]}>{children}</html.div>
258
249
  }
259
250
 
260
251
  // --- Footer ---
@@ -282,11 +273,7 @@ function Close({children, 'aria-label': ariaLabel = 'Close'}: CloseProps) {
282
273
  }
283
274
 
284
275
  return (
285
- <html.button
286
- onClick={requestClose}
287
- aria-label={ariaLabel}
288
- style={styles.closeButton}
289
- >
276
+ <html.button onClick={requestClose} aria-label={ariaLabel} style={styles.closeButton}>
290
277
  <svg width={16} height={16} viewBox="0 0 16 16" fill="none">
291
278
  <path
292
279
  d="M4 4l8 8M12 4l-8 8"
@@ -137,6 +137,11 @@ export const styles = css.create({
137
137
  body: {
138
138
  flex: 1,
139
139
  overflowY: 'auto',
140
+ // Minimal inset prevents child borders from touching panel structural borders
141
+ paddingTop: spacing.sm,
142
+ paddingBottom: spacing.sm,
143
+ paddingLeft: spacing.sm,
144
+ paddingRight: spacing.sm,
140
145
  },
141
146
  bodyPadded: {
142
147
  paddingTop: spacing.lg,
@@ -20,8 +20,14 @@ export const meta: ComponentMeta = {
20
20
  optional: ['Trigger', 'Header', 'Title', 'Description', 'Body', 'Footer', 'Close'],
21
21
  },
22
22
  relatedTo: [
23
- {component: 'Drawer', relationship: 'Drawer slides from an edge; Dialog is centered with scale animation'},
24
- {component: 'DetailPanel', relationship: 'DetailPanel is non-modal and in-flow; Dialog is modal with backdrop'},
23
+ {
24
+ component: 'Drawer',
25
+ relationship: 'Drawer slides from an edge; Dialog is centered with scale animation',
26
+ },
27
+ {
28
+ component: 'DetailPanel',
29
+ relationship: 'DetailPanel is non-modal and in-flow; Dialog is modal with backdrop',
30
+ },
25
31
  ],
26
32
  example: `<Dialog.Root open={open} onOpenChange={setOpen}>
27
33
  <Dialog.Trigger>
@@ -21,7 +21,10 @@ export const meta: ComponentMeta = {
21
21
  },
22
22
  relatedTo: [
23
23
  {component: 'Dialog', relationship: 'Dialog is centered modal; Drawer slides from an edge'},
24
- {component: 'DetailPanel', relationship: 'DetailPanel is non-modal and in-flow; Drawer is modal with backdrop'},
24
+ {
25
+ component: 'DetailPanel',
26
+ relationship: 'DetailPanel is non-modal and in-flow; Drawer is modal with backdrop',
27
+ },
25
28
  ],
26
29
  example: `<Drawer.Root anchor="right" open={open} onOpenChange={setOpen}>
27
30
  <Drawer.Trigger>
@@ -0,0 +1,22 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Placeholder for empty content areas. Shows an icon, message, and optional action button. Use when a list, table, or section has no data to display.',
6
+ whenToUse: [
7
+ 'Empty tables or lists with no results',
8
+ 'Search results with no matches',
9
+ 'First-time use before any data exists',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Loading states — use Spinner',
13
+ 'Error states — use Alert or Callout',
14
+ ],
15
+ example: `<Card>
16
+ <EmptyState
17
+ icon={<Icon name="info-circle" size={48} />}
18
+ message="No results found"
19
+ action={<Button variant="secondary">Clear filters</Button>}
20
+ />
21
+ </Card>`,
22
+ }
@@ -6,6 +6,12 @@ import {Input} from '../Input/Input'
6
6
 
7
7
  const meta: Meta = {
8
8
  title: 'Components/Field',
9
+ argTypes: {
10
+ invalid: {
11
+ control: 'boolean',
12
+ description: 'Whether the field is in an invalid/error state',
13
+ },
14
+ },
9
15
  }
10
16
 
11
17
  export default meta
@@ -0,0 +1,24 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Semantic heading element (h1-h6) with typography presets. Always use the correct level for document hierarchy. Visual size can differ from semantic level via the variant prop.',
6
+ whenToUse: [
7
+ 'Page titles (level 1)',
8
+ 'Section headers (level 2-3)',
9
+ 'Card or panel titles (level 3-4)',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Body text — use Text',
13
+ 'Form labels — use Field.Label',
14
+ 'Non-semantic bold text — use Text with weight',
15
+ ],
16
+ relatedTo: [
17
+ {component: 'Text', relationship: 'Text for body/label; Heading for semantic headings'},
18
+ ],
19
+ example: `<Stack gap="md">
20
+ <Heading level={1}>Page Title</Heading>
21
+ <Heading level={2} variant="headingMd">Section</Heading>
22
+ <Heading level={3}>Subsection</Heading>
23
+ </Stack>`,
24
+ }
@@ -0,0 +1,23 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'SVG icon component. Renders stroke or filled icons from the design system icon set. Size scales with the size prop. Use inside buttons, badges, or standalone.',
6
+ whenToUse: [
7
+ 'Button icons (inside Button children)',
8
+ 'Status indicators alongside text',
9
+ 'Navigation or action indicators',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Decorative images — use img elements',
13
+ 'Complex illustrations — use custom SVGs',
14
+ ],
15
+ relatedTo: [
16
+ {component: 'StatusIcon', relationship: 'StatusIcon wraps Icon with a colored background circle'},
17
+ ],
18
+ example: `<Inline gap="sm" align="center">
19
+ <Icon name="check-circle" size={20} />
20
+ <Icon name="alert-triangle" size={20} />
21
+ <Icon name="shield-filled" size={20} />
22
+ </Inline>`,
23
+ }
@@ -0,0 +1,28 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Wraps an Input with prefix and/or suffix addons (icons, text, buttons). Addons are visually attached to the input edges.',
6
+ whenToUse: [
7
+ 'Inputs with units (e.g. "$" prefix, "kg" suffix)',
8
+ 'Search inputs with an icon prefix',
9
+ 'URL inputs with protocol prefix',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Standalone inputs without addons — use Input directly',
13
+ 'Form field labels — use Field.Label',
14
+ ],
15
+ anatomy: {
16
+ required: ['Root'],
17
+ optional: ['Addon'],
18
+ },
19
+ relatedTo: [
20
+ {component: 'Input', relationship: 'InputGroup enhances Input with addons'},
21
+ {component: 'Field', relationship: 'Field provides label/error; InputGroup provides visual addons'},
22
+ ],
23
+ example: `<InputGroup.Root>
24
+ <InputGroup.Addon>$</InputGroup.Addon>
25
+ <Input type="number" placeholder="0.00" />
26
+ <InputGroup.Addon>USD</InputGroup.Addon>
27
+ </InputGroup.Root>`,
28
+ }
@@ -0,0 +1,39 @@
1
+ import type {ComponentMeta} from '../component-meta'
2
+
3
+ export const meta: ComponentMeta = {
4
+ description:
5
+ 'Vertical list of interactive items. Ideal for narrow spaces (detail panels, sidebars) where Table would truncate. Supports selection, descriptions, and action slots.',
6
+ whenToUse: [
7
+ 'Displaying items in a narrow container (< 480px)',
8
+ 'Detail panels, drawers, and sidebars',
9
+ 'Lists needing selection (single or multiple) with compact layout',
10
+ ],
11
+ whenNotToUse: [
12
+ 'Tabular data with many columns — use Table',
13
+ 'Navigation menus — use SideNav or Menu',
14
+ 'Simple text lists without interaction — use Stack with Text',
15
+ ],
16
+ anatomy: {
17
+ required: ['Root', 'Item', 'Content', 'Text'],
18
+ optional: ['Description', 'Actions', 'Empty'],
19
+ },
20
+ relatedTo: [
21
+ {component: 'Table', relationship: 'Table for wide multi-column data; List for narrow compact items'},
22
+ {component: 'DetailPanel', relationship: 'List fits naturally inside DetailPanel.Body'},
23
+ {component: 'Menu', relationship: 'Menu for action menus; List for data display with selection'},
24
+ ],
25
+ example: `<List.Root selectionMode="multiple" aria-label="Certificates">
26
+ <List.Item selected onClick={toggle}>
27
+ <Checkbox checked />
28
+ <List.Content>
29
+ <List.Text>web-server-prod-2024.pem</List.Text>
30
+ <List.Description>Issued: Jan 15, 2024 · Expires: Jan 15, 2025</List.Description>
31
+ </List.Content>
32
+ <List.Actions>
33
+ <Badge variant="success">Active</Badge>
34
+ <Button variant="danger" size="small">Revoke</Button>
35
+ </List.Actions>
36
+ </List.Item>
37
+ <List.Empty>No certificates found.</List.Empty>
38
+ </List.Root>`,
39
+ }