@slipstream-ui/core 0.3.0 → 0.4.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/index.d.mts +672 -52
- package/dist/index.d.ts +672 -52
- package/dist/index.js +1860 -657
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1836 -655
- package/dist/index.mjs.map +1 -1
- package/dist/manifests/app-shell.manifest.json +156 -0
- package/dist/manifests/auth-layout.manifest.json +99 -0
- package/dist/manifests/autocomplete.manifest.json +53 -5
- package/dist/manifests/badge.manifest.json +12 -0
- package/dist/manifests/button.manifest.json +6 -2
- package/dist/manifests/card.manifest.json +53 -6
- package/dist/manifests/date-picker.manifest.json +87 -0
- package/dist/manifests/dialog.manifest.json +49 -4
- package/dist/manifests/drawer.manifest.json +18 -4
- package/dist/manifests/empty-state.manifest.json +108 -0
- package/dist/manifests/file-upload.manifest.json +103 -0
- package/dist/manifests/filter-bar.manifest.json +100 -0
- package/dist/manifests/menu.manifest.json +13 -1
- package/dist/manifests/metric-card.manifest.json +105 -0
- package/dist/manifests/page-header.manifest.json +94 -0
- package/dist/manifests/pagination.manifest.json +62 -34
- package/dist/manifests/password-input.manifest.json +75 -0
- package/dist/manifests/select-menu.manifest.json +142 -0
- package/dist/manifests/select.manifest.json +49 -12
- package/dist/manifests/stepper.manifest.json +95 -0
- package/dist/manifests/table-card.manifest.json +123 -0
- package/dist/manifests/time-picker.manifest.json +86 -0
- package/dist/manifests/timeline.manifest.json +69 -0
- package/dist/manifests/toast.manifest.json +101 -25
- package/package.json +1 -1
- package/src/components/app-shell/AppShell.test.tsx +100 -0
- package/src/components/app-shell/AppShell.tsx +162 -0
- package/src/components/app-shell/index.ts +1 -0
- package/src/components/auth-layout/AuthLayout.test.tsx +34 -0
- package/src/components/auth-layout/AuthLayout.tsx +47 -0
- package/src/components/auth-layout/index.ts +1 -0
- package/src/components/autocomplete/Autocomplete.test.tsx +53 -0
- package/src/components/autocomplete/Autocomplete.tsx +160 -41
- package/src/components/badge/Badge.test.tsx +14 -0
- package/src/components/badge/Badge.tsx +10 -4
- package/src/components/button/Button.test.tsx +29 -0
- package/src/components/button/Button.tsx +10 -0
- package/src/components/button-group/ButtonGroup.test.tsx +6 -8
- package/src/components/button-group/ButtonGroup.tsx +17 -9
- package/src/components/card/Card.test.tsx +14 -0
- package/src/components/card/Card.tsx +15 -8
- package/src/components/date-picker/DatePicker.test.tsx +30 -0
- package/src/components/date-picker/DatePicker.tsx +57 -0
- package/src/components/date-picker/index.ts +1 -0
- package/src/components/dialog/Dialog.test.tsx +64 -1
- package/src/components/dialog/Dialog.tsx +113 -23
- package/src/components/dialog/index.ts +1 -2
- package/src/components/drawer/Drawer.test.tsx +50 -0
- package/src/components/drawer/Drawer.tsx +44 -6
- package/src/components/empty-state/EmptyState.test.tsx +30 -0
- package/src/components/empty-state/EmptyState.tsx +48 -0
- package/src/components/empty-state/index.ts +1 -0
- package/src/components/file-upload/FileUpload.test.tsx +43 -0
- package/src/components/file-upload/FileUpload.tsx +143 -0
- package/src/components/file-upload/index.ts +1 -0
- package/src/components/filter-bar/FilterBar.test.tsx +32 -0
- package/src/components/filter-bar/FilterBar.tsx +71 -0
- package/src/components/filter-bar/index.ts +1 -0
- package/src/components/input-group/InputGroup.test.tsx +6 -3
- package/src/components/input-group/InputGroup.tsx +9 -6
- package/src/components/menu/Menu.test.tsx +21 -0
- package/src/components/menu/Menu.tsx +8 -3
- package/src/components/metric-card/MetricCard.test.tsx +28 -0
- package/src/components/metric-card/MetricCard.tsx +54 -0
- package/src/components/metric-card/index.ts +1 -0
- package/src/components/page-header/PageHeader.test.tsx +31 -0
- package/src/components/page-header/PageHeader.tsx +37 -0
- package/src/components/page-header/index.ts +1 -0
- package/src/components/pagination/Pagination.test.tsx +25 -0
- package/src/components/pagination/Pagination.tsx +53 -12
- package/src/components/password-input/PasswordInput.test.tsx +29 -0
- package/src/components/password-input/PasswordInput.tsx +41 -0
- package/src/components/password-input/index.ts +1 -0
- package/src/components/select/Select.test.tsx +40 -1
- package/src/components/select/Select.tsx +52 -14
- package/src/components/select/index.ts +1 -1
- package/src/components/select-menu/SelectMenu.test.tsx +105 -0
- package/src/components/select-menu/SelectMenu.tsx +368 -0
- package/src/components/select-menu/index.ts +1 -0
- package/src/components/stepper/Stepper.test.tsx +35 -0
- package/src/components/stepper/Stepper.tsx +91 -0
- package/src/components/stepper/index.ts +1 -0
- package/src/components/table-card/TableCard.test.tsx +59 -0
- package/src/components/table-card/TableCard.tsx +48 -0
- package/src/components/table-card/index.ts +1 -0
- package/src/components/time-picker/TimePicker.test.tsx +30 -0
- package/src/components/time-picker/TimePicker.tsx +56 -0
- package/src/components/time-picker/index.ts +1 -0
- package/src/components/timeline/Timeline.test.tsx +26 -0
- package/src/components/timeline/Timeline.tsx +53 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/toast/Toast.test.tsx +5 -0
- package/src/components/toast/Toast.tsx +2 -16
- package/src/components/toast/Toaster.test.tsx +84 -0
- package/src/components/toast/Toaster.tsx +116 -0
- package/src/components/toast/index.ts +4 -0
- package/src/components/toast/toast-store.ts +117 -0
- package/src/index.ts +14 -0
- package/src/manifests/app-shell.manifest.json +156 -0
- package/src/manifests/auth-layout.manifest.json +99 -0
- package/src/manifests/autocomplete.manifest.json +53 -5
- package/src/manifests/badge.manifest.json +12 -0
- package/src/manifests/button.manifest.json +6 -2
- package/src/manifests/card.manifest.json +53 -6
- package/src/manifests/date-picker.manifest.json +87 -0
- package/src/manifests/dialog.manifest.json +49 -4
- package/src/manifests/drawer.manifest.json +18 -4
- package/src/manifests/empty-state.manifest.json +108 -0
- package/src/manifests/file-upload.manifest.json +103 -0
- package/src/manifests/filter-bar.manifest.json +100 -0
- package/src/manifests/menu.manifest.json +13 -1
- package/src/manifests/metric-card.manifest.json +105 -0
- package/src/manifests/page-header.manifest.json +94 -0
- package/src/manifests/pagination.manifest.json +62 -34
- package/src/manifests/password-input.manifest.json +75 -0
- package/src/manifests/select-menu.manifest.json +142 -0
- package/src/manifests/select.manifest.json +49 -12
- package/src/manifests/stepper.manifest.json +95 -0
- package/src/manifests/table-card.manifest.json +123 -0
- package/src/manifests/time-picker.manifest.json +86 -0
- package/src/manifests/timeline.manifest.json +69 -0
- package/src/manifests/toast.manifest.json +101 -25
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "empty-state",
|
|
3
|
+
"name": "EmptyState",
|
|
4
|
+
"tier": "molecule",
|
|
5
|
+
"description": "Placeholder for empty collections, zero-result searches and unconfigured features, with title, description and action slots.",
|
|
6
|
+
"designIntent": "Empty states are where users decide what to do next. A consistent icon/title/description/action hierarchy beats ad-hoc 'No data' strings, and a stable structure is easier for screen readers and tests.",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "title",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"required": true,
|
|
12
|
+
"description": "Primary message.",
|
|
13
|
+
"examples": [
|
|
14
|
+
"No classes yet"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "description",
|
|
19
|
+
"type": "string",
|
|
20
|
+
"required": false,
|
|
21
|
+
"description": "Supporting line explaining the next step."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "icon",
|
|
25
|
+
"type": "ReactNode",
|
|
26
|
+
"required": false,
|
|
27
|
+
"description": "Decorative icon/illustration above the title."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "action",
|
|
31
|
+
"type": "ReactNode",
|
|
32
|
+
"required": false,
|
|
33
|
+
"description": "Primary action (Button or link)."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "secondaryAction",
|
|
37
|
+
"type": "ReactNode",
|
|
38
|
+
"required": false,
|
|
39
|
+
"description": "Secondary action beside the primary one."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "size",
|
|
43
|
+
"type": "'sm' | 'md'",
|
|
44
|
+
"required": false,
|
|
45
|
+
"defaultValue": "md",
|
|
46
|
+
"description": "Compact padding for panels/table bodies.",
|
|
47
|
+
"enum": [
|
|
48
|
+
"sm",
|
|
49
|
+
"md"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"examples": [
|
|
54
|
+
{
|
|
55
|
+
"title": "Empty collection",
|
|
56
|
+
"code": "<EmptyState\n title=\"No classes yet\"\n description=\"Create your first class to get started.\"\n action={<Button>New class</Button>}\n/>",
|
|
57
|
+
"description": "Title, explanation and one primary action."
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"antiPatterns": [
|
|
61
|
+
{
|
|
62
|
+
"title": "Don't use it for errors",
|
|
63
|
+
"explanation": "Empty is a normal state; failures need Alert/ErrorAlert with retry affordances.",
|
|
64
|
+
"example": "// Avoid\n<EmptyState title=\"Failed to load\" />\n\n// Prefer\n<Alert variant=\"destructive\">Failed to load. <Button>Retry</Button></Alert>"
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"accessibility": [
|
|
68
|
+
{
|
|
69
|
+
"feature": "Action targets",
|
|
70
|
+
"implementation": "Actions are whatever you pass — use Button/link components so they stay focusable and announced",
|
|
71
|
+
"userRequirements": "Always provide a real control, not a bare sentence"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"contentGuidelines": [
|
|
75
|
+
{
|
|
76
|
+
"contentType": "Copy",
|
|
77
|
+
"guidelines": [
|
|
78
|
+
"Say what is missing",
|
|
79
|
+
"Say what to do next",
|
|
80
|
+
"Avoid blaming the user"
|
|
81
|
+
],
|
|
82
|
+
"goodExamples": [
|
|
83
|
+
"No classes yet — create your first class"
|
|
84
|
+
],
|
|
85
|
+
"badExamples": [
|
|
86
|
+
"Empty",
|
|
87
|
+
"Nothing here"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"compositionRules": [
|
|
92
|
+
{
|
|
93
|
+
"component": "Card",
|
|
94
|
+
"relationship": "Often rendered inside a Card body or a DataTable empty slot",
|
|
95
|
+
"example": "<Card><CardContent><EmptyState … /></CardContent></Card>"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"relatedComponents": [
|
|
99
|
+
"Alert",
|
|
100
|
+
"Card",
|
|
101
|
+
"DataTable"
|
|
102
|
+
],
|
|
103
|
+
"package": "@slipstream-ui/core",
|
|
104
|
+
"importPath": "@slipstream-ui/core",
|
|
105
|
+
"version": "0.1.0",
|
|
106
|
+
"sourceDir": "empty-state",
|
|
107
|
+
"exportName": "EmptyState"
|
|
108
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "file-upload",
|
|
3
|
+
"name": "FileUpload",
|
|
4
|
+
"tier": "organism",
|
|
5
|
+
"description": "Drag-and-drop file picker with a removable file list and per-file progress bars.",
|
|
6
|
+
"designIntent": "File inputs are hard to style and easy to make inaccessible. FileUpload keeps the native input as the real control, adds a drop zone as an enhancement, and exposes plain File objects so the transport and progress stay yours.",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "files",
|
|
10
|
+
"type": "File[]",
|
|
11
|
+
"required": false,
|
|
12
|
+
"description": "Controlled selection."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "defaultFiles",
|
|
16
|
+
"type": "File[]",
|
|
17
|
+
"required": false,
|
|
18
|
+
"description": "Initial selection when uncontrolled."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "onFilesChange",
|
|
22
|
+
"type": "(files: File[]) => void",
|
|
23
|
+
"required": false,
|
|
24
|
+
"description": "Fired on add, drop, remove."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "label",
|
|
28
|
+
"type": "string",
|
|
29
|
+
"required": false,
|
|
30
|
+
"defaultValue": "Drop files here or click to browse",
|
|
31
|
+
"description": "Drop-zone copy."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "hint",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"required": false,
|
|
37
|
+
"description": "Helper line under the drop zone."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "progress",
|
|
41
|
+
"type": "Record<string, number>",
|
|
42
|
+
"required": false,
|
|
43
|
+
"description": "Per-file progress 0-100 keyed by file name; renders progress bars."
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"examples": [
|
|
47
|
+
{
|
|
48
|
+
"title": "Attachments with progress",
|
|
49
|
+
"code": "<FileUpload\n aria-label=\"Attachments\"\n accept=\".pdf,.csv\"\n progress={{ 'report.pdf': 42 }}\n onFilesChange={setFiles}\n/>",
|
|
50
|
+
"description": "Native input + drop zone + progress."
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"antiPatterns": [
|
|
54
|
+
{
|
|
55
|
+
"title": "Don't hide the input from the a11y tree",
|
|
56
|
+
"explanation": "The label targets the real input, keeping keyboard and mobile file dialogs working.",
|
|
57
|
+
"example": "// Avoid: tabIndex={-1} display:none input\n// Prefer: <FileUpload /> (input is sr-only but focusable)"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"accessibility": [
|
|
61
|
+
{
|
|
62
|
+
"feature": "Native control",
|
|
63
|
+
"implementation": "Visible label targets a real (sr-only) file input",
|
|
64
|
+
"userRequirements": "Provide aria-label or wrap in FormField"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"feature": "Progress",
|
|
68
|
+
"implementation": "Each uploading file exposes role=progressbar with a name",
|
|
69
|
+
"userRequirements": "Keep progress keyed by file name"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"contentGuidelines": [
|
|
73
|
+
{
|
|
74
|
+
"contentType": "Hints",
|
|
75
|
+
"guidelines": [
|
|
76
|
+
"State accepted types and size limits"
|
|
77
|
+
],
|
|
78
|
+
"goodExamples": [
|
|
79
|
+
"PDF or CSV, up to 10 MB"
|
|
80
|
+
],
|
|
81
|
+
"badExamples": [
|
|
82
|
+
"Upload"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"compositionRules": [
|
|
87
|
+
{
|
|
88
|
+
"component": "FormField",
|
|
89
|
+
"relationship": "Wrap for label/error wiring",
|
|
90
|
+
"example": "<FormField id=\"files\" label=\"Attachments\"><FileUpload /></FormField>"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"relatedComponents": [
|
|
94
|
+
"Attachment",
|
|
95
|
+
"FormField",
|
|
96
|
+
"Progress"
|
|
97
|
+
],
|
|
98
|
+
"package": "@slipstream-ui/core",
|
|
99
|
+
"importPath": "@slipstream-ui/core",
|
|
100
|
+
"version": "0.1.0",
|
|
101
|
+
"sourceDir": "file-upload",
|
|
102
|
+
"exportName": "FileUpload"
|
|
103
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "filter-bar",
|
|
3
|
+
"name": "FilterBar",
|
|
4
|
+
"tier": "molecule",
|
|
5
|
+
"description": "List-page filter strip: search field, filter controls, reset affordance and trailing actions.",
|
|
6
|
+
"designIntent": "Filter rows drift: some pages wrap, some scroll, resets appear inconsistently. FilterBar fixes the order (search → filters → reset → trailing) and keeps the strip compact on narrow screens.",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "searchValue",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"required": false,
|
|
12
|
+
"description": "Controlled search text."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "onSearchChange",
|
|
16
|
+
"type": "(value: string) => void",
|
|
17
|
+
"required": false,
|
|
18
|
+
"description": "Fires on each keystroke; hides the search box when omitted."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "searchPlaceholder",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"required": false,
|
|
24
|
+
"defaultValue": "Search…",
|
|
25
|
+
"description": "Search input placeholder (also its accessible name)."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "onReset",
|
|
29
|
+
"type": "() => void",
|
|
30
|
+
"required": false,
|
|
31
|
+
"description": "Shows a reset button when provided."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "activeCount",
|
|
35
|
+
"type": "number",
|
|
36
|
+
"required": false,
|
|
37
|
+
"defaultValue": "0",
|
|
38
|
+
"description": "Active filter count appended to the reset label."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "trailing",
|
|
42
|
+
"type": "ReactNode",
|
|
43
|
+
"required": false,
|
|
44
|
+
"description": "Far-right actions (bulk actions, column settings)."
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"examples": [
|
|
48
|
+
{
|
|
49
|
+
"title": "List filters",
|
|
50
|
+
"code": "<FilterBar\n searchValue={query}\n onSearchChange={setQuery}\n searchPlaceholder=\"Search students\"\n onReset={resetFilters}\n activeCount={activeFilters}\n>\n <Select label=\"Status\" options={statusOptions} />\n</FilterBar>",
|
|
51
|
+
"description": "Search, filters, reset and count in one strip."
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"antiPatterns": [
|
|
55
|
+
{
|
|
56
|
+
"title": "Don't put the primary action in the bar",
|
|
57
|
+
"explanation": "FilterBar is for narrowing; creation actions belong in PageHeader actions.",
|
|
58
|
+
"example": "// Avoid\n<FilterBar trailing={<Button>New class</Button>} />\n\n// Prefer\n<PageHeader actions={<Button>New class</Button>} />"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"accessibility": [
|
|
62
|
+
{
|
|
63
|
+
"feature": "Search landmark",
|
|
64
|
+
"implementation": "Wraps controls in role=search; the search input is labelled by its placeholder",
|
|
65
|
+
"userRequirements": "Provide a descriptive placeholder"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"contentGuidelines": [
|
|
69
|
+
{
|
|
70
|
+
"contentType": "Placeholder",
|
|
71
|
+
"guidelines": [
|
|
72
|
+
"Name the collection being searched"
|
|
73
|
+
],
|
|
74
|
+
"goodExamples": [
|
|
75
|
+
"Search students"
|
|
76
|
+
],
|
|
77
|
+
"badExamples": [
|
|
78
|
+
"Search…"
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"compositionRules": [
|
|
83
|
+
{
|
|
84
|
+
"component": "Select",
|
|
85
|
+
"relationship": "Filter controls render in children",
|
|
86
|
+
"example": "<FilterBar><Select … /></FilterBar>"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"relatedComponents": [
|
|
90
|
+
"DataTable",
|
|
91
|
+
"Select",
|
|
92
|
+
"Input",
|
|
93
|
+
"PageHeader"
|
|
94
|
+
],
|
|
95
|
+
"package": "@slipstream-ui/core",
|
|
96
|
+
"importPath": "@slipstream-ui/core",
|
|
97
|
+
"version": "0.1.0",
|
|
98
|
+
"sourceDir": "filter-bar",
|
|
99
|
+
"exportName": "FilterBar"
|
|
100
|
+
}
|
|
@@ -35,9 +35,21 @@
|
|
|
35
35
|
"defaultValue": "false",
|
|
36
36
|
"required": false,
|
|
37
37
|
"type": "boolean"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "asChild",
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"required": false,
|
|
43
|
+
"defaultValue": "false",
|
|
44
|
+
"description": "Render the child element (e.g. an <a>) as the menu item (MenuItem)."
|
|
38
45
|
}
|
|
39
46
|
],
|
|
40
47
|
"examples": [
|
|
48
|
+
{
|
|
49
|
+
"title": "Link menu item",
|
|
50
|
+
"code": "<MenuItem asChild>\n <a href=\"/settings\">Settings</a>\n</MenuItem>",
|
|
51
|
+
"description": "Navigation items keep menuitem semantics."
|
|
52
|
+
},
|
|
41
53
|
{
|
|
42
54
|
"title": "Actions menu",
|
|
43
55
|
"code": "<Menu>\n <MenuTrigger>Options</MenuTrigger>\n <MenuContent>\n <MenuLabel>Actions</MenuLabel>\n <MenuItem>Profile</MenuItem>\n <MenuItem>Settings</MenuItem>\n <MenuSeparator />\n <MenuItem destructive>Sign out</MenuItem>\n </MenuContent>\n</Menu>",
|
|
@@ -111,4 +123,4 @@
|
|
|
111
123
|
"version": "0.1.0",
|
|
112
124
|
"sourceDir": "menu",
|
|
113
125
|
"exportName": "Menu"
|
|
114
|
-
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "metric-card",
|
|
3
|
+
"name": "MetricCard",
|
|
4
|
+
"tier": "molecule",
|
|
5
|
+
"description": "KPI tile: label, value, directional delta (arrow + color) and supporting hint.",
|
|
6
|
+
"designIntent": "Dashboards need comparable tiles. MetricCard standardizes tabular numbers, delta direction (never color-only) and the label/value/hint hierarchy so rows of KPIs align.",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "label",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"required": true,
|
|
12
|
+
"description": "Metric name."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "value",
|
|
16
|
+
"type": "string | number",
|
|
17
|
+
"required": true,
|
|
18
|
+
"description": "Primary number/value; rendered tabular."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "delta",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"required": false,
|
|
24
|
+
"description": "Signed change, e.g. +12.4%."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "trend",
|
|
28
|
+
"type": "'up' | 'down' | 'flat'",
|
|
29
|
+
"required": false,
|
|
30
|
+
"defaultValue": "flat",
|
|
31
|
+
"description": "Delta direction color + arrow glyph.",
|
|
32
|
+
"enum": [
|
|
33
|
+
"up",
|
|
34
|
+
"down",
|
|
35
|
+
"flat"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "hint",
|
|
40
|
+
"type": "string",
|
|
41
|
+
"required": false,
|
|
42
|
+
"description": "Comparison context (vs last month)."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "icon",
|
|
46
|
+
"type": "ReactNode",
|
|
47
|
+
"required": false,
|
|
48
|
+
"description": "Decorative icon."
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"examples": [
|
|
52
|
+
{
|
|
53
|
+
"title": "KPI row",
|
|
54
|
+
"code": "<div className=\"grid gap-4 sm:grid-cols-3\">\n <MetricCard label=\"Revenue\" value=\"$12,480\" delta=\"+12.4%\" trend=\"up\" hint=\"vs last month\" />\n <MetricCard label=\"Churn\" value=\"2.1%\" delta=\"-0.4\" trend=\"down\" />\n</div>",
|
|
55
|
+
"description": "Deltas carry arrows as well as color."
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"antiPatterns": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Don't encode meaning in color alone",
|
|
61
|
+
"explanation": "Always pass trend so the arrow glyph accompanies the color.",
|
|
62
|
+
"example": "// Avoid\n<MetricCard label=\"Churn\" value=\"2.1%\" delta=\"-0.4\" />\n\n// Prefer\n<MetricCard label=\"Churn\" value=\"2.1%\" delta=\"-0.4\" trend=\"down\" />"
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"accessibility": [
|
|
66
|
+
{
|
|
67
|
+
"feature": "Color-independent direction",
|
|
68
|
+
"implementation": "Delta renders ↑/↓/→ glyphs alongside color",
|
|
69
|
+
"userRequirements": "Include the sign in the delta string"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"contentGuidelines": [
|
|
73
|
+
{
|
|
74
|
+
"contentType": "Labels",
|
|
75
|
+
"guidelines": [
|
|
76
|
+
"Short metric names",
|
|
77
|
+
"State the unit in value or hint"
|
|
78
|
+
],
|
|
79
|
+
"goodExamples": [
|
|
80
|
+
"Revenue",
|
|
81
|
+
"Active students"
|
|
82
|
+
],
|
|
83
|
+
"badExamples": [
|
|
84
|
+
"Total revenue generated across all locations"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"compositionRules": [
|
|
89
|
+
{
|
|
90
|
+
"component": "Grid",
|
|
91
|
+
"relationship": "Lay KPI rows out with Grid for even columns",
|
|
92
|
+
"example": "<Grid columns={3} gap=\"md\"><MetricCard … /></Grid>"
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"relatedComponents": [
|
|
96
|
+
"Card",
|
|
97
|
+
"Grid",
|
|
98
|
+
"Progress"
|
|
99
|
+
],
|
|
100
|
+
"package": "@slipstream-ui/core",
|
|
101
|
+
"importPath": "@slipstream-ui/core",
|
|
102
|
+
"version": "0.1.0",
|
|
103
|
+
"sourceDir": "metric-card",
|
|
104
|
+
"exportName": "MetricCard"
|
|
105
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "page-header",
|
|
3
|
+
"name": "PageHeader",
|
|
4
|
+
"tier": "molecule",
|
|
5
|
+
"description": "Standard page heading: optional breadcrumbs, level-1 title, description, right-aligned actions and a sub-row slot.",
|
|
6
|
+
"designIntent": "Every list/detail page repeats breadcrumb + title + description + actions with drifting spacing. PageHeader fixes the hierarchy (one h1 per page) and the responsive wrap, so pages stay consistent.",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "title",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"required": true,
|
|
12
|
+
"description": "Page heading rendered as h1."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "description",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"required": false,
|
|
18
|
+
"description": "Supporting summary under the title."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "breadcrumbs",
|
|
22
|
+
"type": "ReactNode",
|
|
23
|
+
"required": false,
|
|
24
|
+
"description": "Trail rendered above the title."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "actions",
|
|
28
|
+
"type": "ReactNode",
|
|
29
|
+
"required": false,
|
|
30
|
+
"description": "Right-aligned actions (buttons, menus)."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "children",
|
|
34
|
+
"type": "ReactNode",
|
|
35
|
+
"required": false,
|
|
36
|
+
"description": "Sub-row under the title (tabs, filters)."
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"examples": [
|
|
40
|
+
{
|
|
41
|
+
"title": "List page header",
|
|
42
|
+
"code": "<PageHeader\n title=\"Classes\"\n description=\"Manage your weekly schedule.\"\n breadcrumbs={<Breadcrumb … />}\n actions={<Button>New class</Button>}\n/>",
|
|
43
|
+
"description": "One h1, one action cluster."
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"antiPatterns": [
|
|
47
|
+
{
|
|
48
|
+
"title": "Don't stack multiple h1s",
|
|
49
|
+
"explanation": "PageHeader renders the page's h1; section headings inside the page should be h2 via Heading.",
|
|
50
|
+
"example": "// Avoid\n<PageHeader title=\"A\" /><PageHeader title=\"B\" />\n\n// Prefer one PageHeader per page"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"accessibility": [
|
|
54
|
+
{
|
|
55
|
+
"feature": "Heading hierarchy",
|
|
56
|
+
"implementation": "Renders exactly one level-1 heading",
|
|
57
|
+
"userRequirements": "Use Heading level={2} for sections below"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"contentGuidelines": [
|
|
61
|
+
{
|
|
62
|
+
"contentType": "Titles",
|
|
63
|
+
"guidelines": [
|
|
64
|
+
"Noun or noun phrase",
|
|
65
|
+
"Sentence case",
|
|
66
|
+
"Under 60 characters"
|
|
67
|
+
],
|
|
68
|
+
"goodExamples": [
|
|
69
|
+
"Classes",
|
|
70
|
+
"Billing settings"
|
|
71
|
+
],
|
|
72
|
+
"badExamples": [
|
|
73
|
+
"Here you can manage all of your classes"
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"compositionRules": [
|
|
78
|
+
{
|
|
79
|
+
"component": "Breadcrumb",
|
|
80
|
+
"relationship": "Pass a Breadcrumb as breadcrumbs for hierarchy context",
|
|
81
|
+
"example": "<PageHeader breadcrumbs={<Breadcrumb items={trail} />} title=\"Detail\" />"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"relatedComponents": [
|
|
85
|
+
"Breadcrumb",
|
|
86
|
+
"Heading",
|
|
87
|
+
"Tabs"
|
|
88
|
+
],
|
|
89
|
+
"package": "@slipstream-ui/core",
|
|
90
|
+
"importPath": "@slipstream-ui/core",
|
|
91
|
+
"version": "0.1.0",
|
|
92
|
+
"sourceDir": "page-header",
|
|
93
|
+
"exportName": "PageHeader"
|
|
94
|
+
}
|
|
@@ -2,81 +2,109 @@
|
|
|
2
2
|
"id": "pagination",
|
|
3
3
|
"name": "Pagination",
|
|
4
4
|
"tier": "molecule",
|
|
5
|
-
"description": "Numeric pagination with prev/next
|
|
5
|
+
"description": "Numeric pagination with prev/next and boundary jumps; accepts page/pageCount or currentPage/totalPages and derives the count (plus a Showing X-Y of Z summary) from total/pageSize.",
|
|
6
6
|
"designIntent": "Pagination lets users navigate through paged content. It shows page numbers with ellipsis for large ranges, prev/next buttons, and marks the current page with aria-current=page.",
|
|
7
7
|
"props": [
|
|
8
8
|
{
|
|
9
9
|
"name": "page",
|
|
10
10
|
"type": "number",
|
|
11
|
-
"required":
|
|
12
|
-
"
|
|
11
|
+
"required": false,
|
|
12
|
+
"defaultValue": "1",
|
|
13
|
+
"description": "Current page (1-based). Alias: currentPage."
|
|
13
14
|
},
|
|
14
15
|
{
|
|
15
16
|
"name": "pageCount",
|
|
16
17
|
"type": "number",
|
|
17
|
-
"required":
|
|
18
|
-
"description": "Total
|
|
18
|
+
"required": false,
|
|
19
|
+
"description": "Total pages. Alias: totalPages, or derived from total/pageSize."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "currentPage",
|
|
23
|
+
"type": "number",
|
|
24
|
+
"required": false,
|
|
25
|
+
"description": "Alias for page (migration-friendly)."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "totalPages",
|
|
29
|
+
"type": "number",
|
|
30
|
+
"required": false,
|
|
31
|
+
"description": "Alias for pageCount."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "pageSize",
|
|
35
|
+
"type": "number",
|
|
36
|
+
"required": false,
|
|
37
|
+
"description": "Rows per page; with total enables the summary and derives pageCount."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "total",
|
|
41
|
+
"type": "number",
|
|
42
|
+
"required": false,
|
|
43
|
+
"description": "Total item count for the summary."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "itemLabel",
|
|
47
|
+
"type": "string",
|
|
48
|
+
"required": false,
|
|
49
|
+
"defaultValue": "items",
|
|
50
|
+
"description": "Noun used in the summary."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "showSummary",
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"required": false,
|
|
56
|
+
"description": "Force the summary on/off (defaults on when total and pageSize are set)."
|
|
19
57
|
},
|
|
20
58
|
{
|
|
21
59
|
"name": "onPageChange",
|
|
22
60
|
"type": "(page: number) => void",
|
|
23
61
|
"required": false,
|
|
24
|
-
"description": "Called with the new page number"
|
|
62
|
+
"description": "Called with the new page number."
|
|
25
63
|
},
|
|
26
64
|
{
|
|
27
65
|
"name": "siblings",
|
|
28
66
|
"type": "number",
|
|
29
|
-
"defaultValue": "1",
|
|
30
67
|
"required": false,
|
|
31
|
-
"
|
|
68
|
+
"defaultValue": "1",
|
|
69
|
+
"description": "Page buttons shown around the current page."
|
|
32
70
|
},
|
|
33
71
|
{
|
|
34
72
|
"name": "showBoundaries",
|
|
35
73
|
"type": "boolean",
|
|
36
|
-
"defaultValue": "false",
|
|
37
74
|
"required": false,
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"true",
|
|
41
|
-
"false"
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"name": "className",
|
|
46
|
-
"type": "string",
|
|
47
|
-
"required": false,
|
|
48
|
-
"description": "Additional CSS classes to apply"
|
|
75
|
+
"defaultValue": "false",
|
|
76
|
+
"description": "Show first/last jump buttons."
|
|
49
77
|
},
|
|
50
78
|
{
|
|
51
79
|
"name": "showFirst",
|
|
52
80
|
"type": "boolean",
|
|
53
|
-
"defaultValue": "showBoundaries",
|
|
54
81
|
"required": false,
|
|
55
|
-
"description": "Force-show the first-page button
|
|
56
|
-
"examples": [
|
|
57
|
-
"true",
|
|
58
|
-
"false"
|
|
59
|
-
]
|
|
82
|
+
"description": "Force-show the first-page button."
|
|
60
83
|
},
|
|
61
84
|
{
|
|
62
85
|
"name": "showLast",
|
|
63
86
|
"type": "boolean",
|
|
64
|
-
"defaultValue": "showBoundaries",
|
|
65
87
|
"required": false,
|
|
66
|
-
"description": "Force-show the last-page button
|
|
67
|
-
"examples": [
|
|
68
|
-
"true",
|
|
69
|
-
"false"
|
|
70
|
-
]
|
|
88
|
+
"description": "Force-show the last-page button."
|
|
71
89
|
},
|
|
72
90
|
{
|
|
73
91
|
"name": "icons",
|
|
74
|
-
"type": "
|
|
92
|
+
"type": "PaginationIcons",
|
|
75
93
|
"required": false,
|
|
76
|
-
"description": "Replace the default
|
|
94
|
+
"description": "Replace the default glyphs."
|
|
77
95
|
}
|
|
78
96
|
],
|
|
79
97
|
"examples": [
|
|
98
|
+
{
|
|
99
|
+
"title": "Summary + derived pages",
|
|
100
|
+
"code": "<Pagination\n page={page}\n pageSize={25}\n total={312}\n itemLabel=\"students\"\n onPageChange={setPage}\n/>",
|
|
101
|
+
"description": "Renders \"Showing 26–50 of 312 students\" and derives 13 pages."
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"title": "Migration aliases",
|
|
105
|
+
"code": "<Pagination currentPage={page} totalPages={pages} onPageChange={setPage} />",
|
|
106
|
+
"description": "currentPage/totalPages map onto page/pageCount."
|
|
107
|
+
},
|
|
80
108
|
{
|
|
81
109
|
"title": "Basic pagination",
|
|
82
110
|
"code": "<Pagination page={3} pageCount={10} onPageChange={setPage} />",
|