@neynar/ui 0.1.1 → 0.1.2
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/components/ui/accordion.d.ts +1 -25
- package/dist/components/ui/accordion.d.ts.map +1 -1
- package/dist/components/ui/alert-dialog.d.ts +240 -46
- package/dist/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/components/ui/alert.d.ts +73 -11
- package/dist/components/ui/alert.d.ts.map +1 -1
- package/dist/components/ui/aspect-ratio.d.ts +44 -10
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -1
- package/dist/components/ui/avatar.d.ts +117 -33
- package/dist/components/ui/avatar.d.ts.map +1 -1
- package/dist/components/ui/badge.d.ts +50 -71
- package/dist/components/ui/badge.d.ts.map +1 -1
- package/dist/components/ui/breadcrumb.d.ts +231 -49
- package/dist/components/ui/breadcrumb.d.ts.map +1 -1
- package/dist/components/ui/button.d.ts +189 -71
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/calendar.d.ts +197 -40
- package/dist/components/ui/calendar.d.ts.map +1 -1
- package/dist/components/ui/card.d.ts +7 -22
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/carousel.d.ts +369 -99
- package/dist/components/ui/carousel.d.ts.map +1 -1
- package/dist/components/ui/chart.d.ts.map +1 -1
- package/dist/components/ui/checkbox.d.ts +110 -38
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/collapsible.d.ts +246 -61
- package/dist/components/ui/collapsible.d.ts.map +1 -1
- package/dist/components/ui/combobox.d.ts +207 -159
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/command.d.ts +336 -67
- package/dist/components/ui/command.d.ts.map +1 -1
- package/dist/components/ui/container.d.ts +159 -64
- package/dist/components/ui/container.d.ts.map +1 -1
- package/dist/components/ui/context-menu.d.ts +321 -39
- package/dist/components/ui/context-menu.d.ts.map +1 -1
- package/dist/components/ui/date-picker.d.ts +113 -86
- package/dist/components/ui/date-picker.d.ts.map +1 -1
- package/dist/components/ui/dialog.d.ts +106 -25
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/drawer.d.ts +388 -59
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.d.ts +521 -74
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/empty-state.d.ts +148 -76
- package/dist/components/ui/empty-state.d.ts.map +1 -1
- package/dist/components/ui/hover-card.d.ts +253 -34
- package/dist/components/ui/hover-card.d.ts.map +1 -1
- package/dist/components/ui/input.d.ts +143 -44
- package/dist/components/ui/input.d.ts.map +1 -1
- package/dist/components/ui/label.d.ts +0 -8
- package/dist/components/ui/label.d.ts.map +1 -1
- package/dist/components/ui/menubar.d.ts +288 -46
- package/dist/components/ui/menubar.d.ts.map +1 -1
- package/dist/components/ui/navigation-menu.d.ts +444 -127
- package/dist/components/ui/navigation-menu.d.ts.map +1 -1
- package/dist/components/ui/pagination.d.ts +342 -66
- package/dist/components/ui/pagination.d.ts.map +1 -1
- package/dist/components/ui/popover.d.ts +0 -8
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/progress.d.ts +88 -30
- package/dist/components/ui/progress.d.ts.map +1 -1
- package/dist/components/ui/radio-group.d.ts +189 -45
- package/dist/components/ui/radio-group.d.ts.map +1 -1
- package/dist/components/ui/resizable.d.ts +178 -62
- package/dist/components/ui/resizable.d.ts.map +1 -1
- package/dist/components/ui/scroll-area.d.ts +180 -21
- package/dist/components/ui/scroll-area.d.ts.map +1 -1
- package/dist/components/ui/select.d.ts +382 -60
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/separator.d.ts +52 -39
- package/dist/components/ui/separator.d.ts.map +1 -1
- package/dist/components/ui/sheet.d.ts +144 -27
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts +81 -31
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/skeleton.d.ts +94 -32
- package/dist/components/ui/skeleton.d.ts.map +1 -1
- package/dist/components/ui/slider.d.ts +37 -31
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/sonner.d.ts +280 -46
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/stack.d.ts +289 -148
- package/dist/components/ui/stack.d.ts.map +1 -1
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts +1 -2
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -1
- package/dist/components/ui/stories/container.stories.d.ts +2 -3
- package/dist/components/ui/stories/container.stories.d.ts.map +1 -1
- package/dist/components/ui/stories/empty-state.stories.d.ts +2 -2
- package/dist/components/ui/stories/scroll-area.stories.d.ts +1 -2
- package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -1
- package/dist/components/ui/stories/stack.stories.d.ts +1 -1
- package/dist/components/ui/stories/text-field.stories.d.ts +7 -1
- package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +44 -38
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/table.d.ts +33 -0
- package/dist/components/ui/table.d.ts.map +1 -1
- package/dist/components/ui/tabs.d.ts +4 -22
- package/dist/components/ui/tabs.d.ts.map +1 -1
- package/dist/components/ui/text-field.d.ts +170 -84
- package/dist/components/ui/text-field.d.ts.map +1 -1
- package/dist/components/ui/textarea.d.ts +106 -29
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/components/ui/theme-toggle.d.ts +190 -65
- package/dist/components/ui/theme-toggle.d.ts.map +1 -1
- package/dist/components/ui/theme.d.ts +107 -23
- package/dist/components/ui/theme.d.ts.map +1 -1
- package/dist/components/ui/toggle-group.d.ts +143 -67
- package/dist/components/ui/toggle-group.d.ts.map +1 -1
- package/dist/components/ui/toggle.d.ts +118 -30
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/components/ui/tooltip.d.ts +152 -28
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/typography.d.ts +452 -134
- package/dist/components/ui/typography.d.ts.map +1 -1
- package/dist/index.js +9388 -8281
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/llms.txt +173 -3
- package/package.json +5 -2
- package/src/components/ui/accordion.tsx +112 -27
- package/src/components/ui/alert-dialog.tsx +401 -46
- package/src/components/ui/alert.tsx +114 -11
- package/src/components/ui/aspect-ratio.tsx +69 -14
- package/src/components/ui/avatar.tsx +179 -33
- package/src/components/ui/badge.tsx +74 -75
- package/src/components/ui/breadcrumb.tsx +335 -50
- package/src/components/ui/button.tsx +198 -90
- package/src/components/ui/calendar.tsx +867 -43
- package/src/components/ui/card.tsx +140 -33
- package/src/components/ui/carousel.tsx +529 -98
- package/src/components/ui/chart.tsx +222 -1
- package/src/components/ui/checkbox.tsx +176 -38
- package/src/components/ui/collapsible.tsx +321 -67
- package/src/components/ui/combobox.tsx +284 -83
- package/src/components/ui/command.tsx +527 -67
- package/src/components/ui/container.tsx +217 -65
- package/src/components/ui/context-menu.tsx +716 -51
- package/src/components/ui/date-picker.tsx +228 -38
- package/src/components/ui/dialog.tsx +270 -33
- package/src/components/ui/drawer.tsx +546 -67
- package/src/components/ui/dropdown-menu.tsx +657 -74
- package/src/components/ui/empty-state.tsx +241 -82
- package/src/components/ui/hover-card.tsx +328 -39
- package/src/components/ui/input.tsx +207 -44
- package/src/components/ui/label.tsx +98 -8
- package/src/components/ui/menubar.tsx +587 -54
- package/src/components/ui/navigation-menu.tsx +557 -128
- package/src/components/ui/pagination.tsx +561 -79
- package/src/components/ui/popover.tsx +119 -8
- package/src/components/ui/progress.tsx +131 -29
- package/src/components/ui/radio-group.tsx +260 -51
- package/src/components/ui/resizable.tsx +289 -63
- package/src/components/ui/scroll-area.tsx +377 -66
- package/src/components/ui/select.tsx +545 -60
- package/src/components/ui/separator.tsx +146 -40
- package/src/components/ui/sheet.tsx +348 -31
- package/src/components/ui/sidebar.tsx +471 -29
- package/src/components/ui/skeleton.tsx +114 -32
- package/src/components/ui/slider.tsx +77 -31
- package/src/components/ui/sonner.tsx +574 -46
- package/src/components/ui/stack.tsx +423 -101
- package/src/components/ui/switch.tsx +78 -39
- package/src/components/ui/table.tsx +170 -4
- package/src/components/ui/tabs.tsx +108 -22
- package/src/components/ui/text-field.tsx +226 -81
- package/src/components/ui/textarea.tsx +180 -29
- package/src/components/ui/theme-toggle.tsx +313 -65
- package/src/components/ui/theme.tsx +117 -23
- package/src/components/ui/toggle-group.tsx +280 -69
- package/src/components/ui/toggle.tsx +124 -35
- package/src/components/ui/tooltip.tsx +239 -29
- package/src/components/ui/typography.tsx +1115 -165
|
@@ -3,72 +3,130 @@ import { cn } from "@/lib/utils";
|
|
|
3
3
|
import { Button } from "./button";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Props for
|
|
7
|
-
*
|
|
8
|
-
* Extends standard HTML div attributes to support all native div functionality
|
|
9
|
-
* while providing specific props for empty state content and behavior.
|
|
10
|
-
*
|
|
11
|
-
* @type EmptyStateProps
|
|
12
|
-
* @extends {React.HTMLAttributes<HTMLDivElement>}
|
|
6
|
+
* Props for EmptyState (Documentation only - NOT used in component implementation)
|
|
7
|
+
* These types are for documentation generation and should not replace HTML inferred types
|
|
13
8
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
10
|
+
type EmptyStateDocsProps = {
|
|
11
|
+
/**
|
|
12
|
+
* Main title text displayed prominently in the empty state
|
|
13
|
+
*
|
|
14
|
+
* Rendered as an h3 element for proper heading hierarchy and screen reader navigation.
|
|
15
|
+
* Keep titles concise and descriptive, focusing on what's missing or the current state.
|
|
16
|
+
*
|
|
17
|
+
* @example "No results found", "Your inbox is empty", "No data available"
|
|
18
|
+
*/
|
|
16
19
|
title: string;
|
|
17
|
-
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Optional descriptive text providing additional context or guidance
|
|
23
|
+
*
|
|
24
|
+
* Displayed below the title as body text with muted styling. Use to explain why
|
|
25
|
+
* the empty state occurred or provide helpful next steps for the user. Maximum
|
|
26
|
+
* width is constrained to maintain readability (max-w-sm).
|
|
27
|
+
*
|
|
28
|
+
* @example "Try adjusting your search criteria", "New messages will appear here"
|
|
29
|
+
* @default undefined
|
|
30
|
+
*/
|
|
18
31
|
description?: string;
|
|
19
|
-
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Optional icon, illustration, or React element displayed above the title
|
|
35
|
+
*
|
|
36
|
+
* Should be a meaningful visual representation of the empty state. Recommended
|
|
37
|
+
* size is 48-64px (w-12 h-12 to w-16 h-16) for optimal visual balance. Icons
|
|
38
|
+
* are automatically styled with muted foreground color.
|
|
39
|
+
*
|
|
40
|
+
* @example <Inbox className="w-12 h-12" />, <Search className="w-16 h-16" />
|
|
41
|
+
* @default undefined
|
|
42
|
+
*/
|
|
20
43
|
icon?: React.ReactNode;
|
|
21
|
-
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Optional action button configuration for primary user action
|
|
47
|
+
*
|
|
48
|
+
* When provided, renders a Button component with default styling below the
|
|
49
|
+
* description. The button follows all Button component accessibility patterns
|
|
50
|
+
* and supports keyboard navigation. Use clear, action-oriented labels that
|
|
51
|
+
* indicate what will happen when clicked.
|
|
52
|
+
*
|
|
53
|
+
* @default undefined
|
|
54
|
+
*/
|
|
22
55
|
action?: {
|
|
23
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Text label for the action button
|
|
58
|
+
*
|
|
59
|
+
* Should be specific and action-oriented rather than generic.
|
|
60
|
+
* @example "Create your first post", "Import data", "Try again"
|
|
61
|
+
*/
|
|
24
62
|
label: string;
|
|
25
|
-
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Click handler function executed when the action button is pressed
|
|
66
|
+
*
|
|
67
|
+
* Called when the user activates the button via click or keyboard interaction.
|
|
68
|
+
* Should handle the primary action to resolve the empty state.
|
|
69
|
+
*/
|
|
26
70
|
onClick: () => void;
|
|
27
71
|
};
|
|
28
|
-
|
|
72
|
+
/** Additional CSS classes for custom styling */
|
|
73
|
+
className?: string;
|
|
74
|
+
/** Content to display inside the container (not used - component has fixed structure) */
|
|
75
|
+
children?: React.ReactNode;
|
|
76
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
29
77
|
|
|
30
78
|
/**
|
|
31
|
-
* EmptyState
|
|
79
|
+
* EmptyState - Displays empty or no-data states with consistent UX patterns
|
|
80
|
+
*
|
|
81
|
+
* A comprehensive component for handling empty states across applications. Provides
|
|
82
|
+
* a standardized way to communicate when content is unavailable, data is missing,
|
|
83
|
+
* or initial setup is required. Built with accessibility-first principles and
|
|
84
|
+
* follows established empty state design patterns to guide users toward resolution.
|
|
85
|
+
*
|
|
86
|
+
* **Common Use Cases:**
|
|
87
|
+
* - Search results with no matches
|
|
88
|
+
* - Empty lists, tables, or dashboards
|
|
89
|
+
* - Inbox or notification centers with no items
|
|
90
|
+
* - Data visualization with no data
|
|
91
|
+
* - Onboarding states for new users
|
|
92
|
+
* - Error recovery scenarios
|
|
32
93
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
94
|
+
* **Component Structure:**
|
|
95
|
+
* The component follows a top-down visual hierarchy: Icon → Title → Description → Action.
|
|
96
|
+
* All elements except the title are optional, allowing for flexible implementation
|
|
97
|
+
* across different contexts while maintaining visual consistency.
|
|
37
98
|
*
|
|
38
99
|
* @example
|
|
39
100
|
* ```tsx
|
|
40
|
-
* //
|
|
41
|
-
* <EmptyState
|
|
42
|
-
* title="No results found"
|
|
43
|
-
* description="Try adjusting your search or filters to find what you're looking for"
|
|
44
|
-
* />
|
|
101
|
+
* // Minimal empty state with just title
|
|
102
|
+
* <EmptyState title="No notifications" />
|
|
45
103
|
* ```
|
|
46
104
|
*
|
|
47
105
|
* @example
|
|
48
106
|
* ```tsx
|
|
49
|
-
* //
|
|
107
|
+
* // Search results empty state
|
|
50
108
|
* import { Search } from 'lucide-react';
|
|
51
109
|
*
|
|
52
110
|
* <EmptyState
|
|
53
111
|
* icon={<Search className="w-12 h-12" />}
|
|
54
|
-
* title="No
|
|
55
|
-
* description="
|
|
112
|
+
* title="No results found"
|
|
113
|
+
* description="Try adjusting your search terms or filters"
|
|
56
114
|
* action={{
|
|
57
|
-
* label: "Clear
|
|
58
|
-
* onClick: () =>
|
|
115
|
+
* label: "Clear filters",
|
|
116
|
+
* onClick: () => resetFilters()
|
|
59
117
|
* }}
|
|
60
118
|
* />
|
|
61
119
|
* ```
|
|
62
120
|
*
|
|
63
121
|
* @example
|
|
64
122
|
* ```tsx
|
|
65
|
-
* // Inbox empty state with
|
|
66
|
-
* import { Inbox } from 'lucide-react';
|
|
123
|
+
* // Inbox empty state with call-to-action
|
|
124
|
+
* import { Inbox, Plus } from 'lucide-react';
|
|
67
125
|
*
|
|
68
126
|
* <EmptyState
|
|
69
127
|
* icon={<Inbox className="w-16 h-16" />}
|
|
70
128
|
* title="Your inbox is empty"
|
|
71
|
-
* description="
|
|
129
|
+
* description="New messages and notifications will appear here"
|
|
72
130
|
* action={{
|
|
73
131
|
* label: "Compose message",
|
|
74
132
|
* onClick: () => openComposer()
|
|
@@ -78,67 +136,168 @@ export type EmptyStateProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
78
136
|
*
|
|
79
137
|
* @example
|
|
80
138
|
* ```tsx
|
|
81
|
-
* //
|
|
82
|
-
* import {
|
|
139
|
+
* // Data dashboard empty state with custom styling
|
|
140
|
+
* import { BarChart3, TrendingUp } from 'lucide-react';
|
|
141
|
+
*
|
|
142
|
+
* <EmptyState
|
|
143
|
+
* className="min-h-[400px] bg-gradient-to-br from-muted/20 to-muted/10 rounded-lg border border-dashed border-muted-foreground/20"
|
|
144
|
+
* icon={<BarChart3 className="w-14 h-14 opacity-60" />}
|
|
145
|
+
* title="No analytics data"
|
|
146
|
+
* description="Connect your data source or import historical data to view insights"
|
|
147
|
+
* action={{
|
|
148
|
+
* label: "Connect data source",
|
|
149
|
+
* onClick: () => showDataSourceModal()
|
|
150
|
+
* }}
|
|
151
|
+
* />
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```tsx
|
|
156
|
+
* // File manager empty state
|
|
157
|
+
* import { FolderOpen, Upload } from 'lucide-react';
|
|
158
|
+
*
|
|
159
|
+
* <EmptyState
|
|
160
|
+
* icon={<FolderOpen className="w-12 h-12" />}
|
|
161
|
+
* title="This folder is empty"
|
|
162
|
+
* description="Drag and drop files here or use the upload button"
|
|
163
|
+
* action={{
|
|
164
|
+
* label: "Upload files",
|
|
165
|
+
* onClick: () => triggerFileUpload()
|
|
166
|
+
* }}
|
|
167
|
+
* />
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```tsx
|
|
172
|
+
* // Error recovery empty state
|
|
173
|
+
* import { AlertTriangle, RefreshCw } from 'lucide-react';
|
|
83
174
|
*
|
|
84
175
|
* <EmptyState
|
|
85
|
-
* className="
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* description="Import data or connect a data source to get started"
|
|
176
|
+
* icon={<AlertTriangle className="w-12 h-12 text-destructive" />}
|
|
177
|
+
* title="Failed to load data"
|
|
178
|
+
* description="There was a problem loading your content. Please try again."
|
|
89
179
|
* action={{
|
|
90
|
-
* label: "
|
|
91
|
-
* onClick: () =>
|
|
180
|
+
* label: "Retry",
|
|
181
|
+
* onClick: () => refetchData()
|
|
92
182
|
* }}
|
|
93
183
|
* />
|
|
94
184
|
* ```
|
|
95
185
|
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```tsx
|
|
188
|
+
* // Team members empty state with multiple actions
|
|
189
|
+
* import { Users, UserPlus, Mail } from 'lucide-react';
|
|
190
|
+
*
|
|
191
|
+
* function TeamEmptyState() {
|
|
192
|
+
* return (
|
|
193
|
+
* <div className="space-y-4">
|
|
194
|
+
* <EmptyState
|
|
195
|
+
* icon={<Users className="w-16 h-16" />}
|
|
196
|
+
* title="No team members yet"
|
|
197
|
+
* description="Invite colleagues to collaborate on projects"
|
|
198
|
+
* action={{
|
|
199
|
+
* label: "Invite members",
|
|
200
|
+
* onClick: () => openInviteModal()
|
|
201
|
+
* }}
|
|
202
|
+
* />
|
|
203
|
+
* <div className="flex justify-center gap-2">
|
|
204
|
+
* <Button variant="outline" size="sm" onClick={() => importFromCsv()}>
|
|
205
|
+
* <Mail className="w-4 h-4 mr-2" />
|
|
206
|
+
* Import from CSV
|
|
207
|
+
* </Button>
|
|
208
|
+
* </div>
|
|
209
|
+
* </div>
|
|
210
|
+
* );
|
|
211
|
+
* }
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
96
214
|
* @param props - Component props extending HTMLDivElement attributes
|
|
97
|
-
* @param props.title - Main
|
|
98
|
-
* @param props.description - Optional
|
|
99
|
-
* @param props.icon - Optional icon or React element
|
|
100
|
-
* @param props.action - Optional action button configuration
|
|
101
|
-
* @param props.className - Additional CSS classes for styling
|
|
102
|
-
* @param
|
|
215
|
+
* @param props.title - Main heading text that describes the empty state
|
|
216
|
+
* @param props.description - Optional explanatory text or guidance for users
|
|
217
|
+
* @param props.icon - Optional visual element (icon, illustration, or custom React element)
|
|
218
|
+
* @param props.action - Optional primary action button configuration
|
|
219
|
+
* @param props.className - Additional CSS classes for custom styling
|
|
220
|
+
* @param props.children - Not used; component has fixed content structure
|
|
221
|
+
* @param ref - Forwarded ref to the root div element for DOM access
|
|
222
|
+
*
|
|
223
|
+
* @accessibility
|
|
224
|
+
* - **Semantic Structure**: Uses proper heading hierarchy with h3 for screen readers
|
|
225
|
+
* - **Keyboard Navigation**: Action button fully keyboard accessible with Tab/Enter/Space
|
|
226
|
+
* - **Screen Readers**: Title and description are properly associated and announced
|
|
227
|
+
* - **Focus Management**: Action button receives proper focus indicators (3px ring)
|
|
228
|
+
* - **Landmark Navigation**: No explicit landmark roles; inherits from container context
|
|
229
|
+
* - **Content Flow**: Logical reading order from icon → title → description → action
|
|
230
|
+
* - **Icon Accessibility**: Decorative icons don't interfere with screen readers
|
|
231
|
+
* - **Button Integration**: Inherits full Button component accessibility features
|
|
232
|
+
* - **High Contrast**: Text colors meet WCAG 2.1 AA contrast requirements
|
|
233
|
+
* - **Responsive Design**: Adapts to different viewport sizes maintaining readability
|
|
103
234
|
*
|
|
104
235
|
* @remarks
|
|
105
|
-
* **
|
|
106
|
-
* -
|
|
107
|
-
* -
|
|
108
|
-
* -
|
|
109
|
-
* -
|
|
110
|
-
* -
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* -
|
|
116
|
-
* -
|
|
117
|
-
*
|
|
118
|
-
*
|
|
236
|
+
* **Visual Design:**
|
|
237
|
+
* - Default padding of py-12 px-4 provides generous whitespace
|
|
238
|
+
* - Centered alignment (flex-col items-center justify-center text-center)
|
|
239
|
+
* - Icon rendered with muted foreground color for subtle prominence
|
|
240
|
+
* - Title uses text-lg font-semibold with foreground color for prominence
|
|
241
|
+
* - Description limited to max-w-sm (24rem) for optimal readability
|
|
242
|
+
* - Action button positioned with mb-6 spacing from description
|
|
243
|
+
* - Responsive spacing adapts to content presence (conditional margins)
|
|
244
|
+
*
|
|
245
|
+
* **Performance Considerations:**
|
|
246
|
+
* - Lightweight component with minimal re-renders
|
|
247
|
+
* - Icon rendering optimized for various React element types
|
|
248
|
+
* - Button component lazy-loaded only when action is provided
|
|
249
|
+
* - No state management or effects, purely presentational
|
|
250
|
+
* - Supports React 18 concurrent features
|
|
251
|
+
*
|
|
252
|
+
* **Customization:**
|
|
253
|
+
* - All Tailwind utility classes can be overridden via className
|
|
254
|
+
* - Icon styling can be customized at the element level
|
|
255
|
+
* - Button inherits default variant but supports additional props via composition
|
|
256
|
+
* - Container div accepts all standard HTML attributes for event handling
|
|
257
|
+
* - Supports ref forwarding for programmatic DOM manipulation
|
|
258
|
+
*
|
|
259
|
+
* **Design System Integration:**
|
|
260
|
+
* - Uses design tokens (foreground, muted-foreground, etc.) for consistent theming
|
|
261
|
+
* - Follows spacing scale (mb-2, mb-4, mb-6, py-12, px-4)
|
|
262
|
+
* - Typography scale integration (text-lg for title, default for description)
|
|
263
|
+
* - Color system compatibility with light/dark mode switching
|
|
264
|
+
* - Button component integration maintains design system consistency
|
|
265
|
+
*
|
|
266
|
+
* @see {@link Button} for action button styling, variants, and accessibility
|
|
267
|
+
* @see {@link https://ui.patterns.build/empty-states} Empty state design patterns
|
|
268
|
+
* @see {@link https://www.nngroup.com/articles/empty-state-interface-design/} Nielsen Norman Group empty state guidelines
|
|
119
269
|
* @since 1.0.0
|
|
120
270
|
*/
|
|
121
|
-
const EmptyState = React.forwardRef<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
271
|
+
const EmptyState = React.forwardRef<
|
|
272
|
+
HTMLDivElement,
|
|
273
|
+
React.ComponentProps<"div"> & {
|
|
274
|
+
title: string;
|
|
275
|
+
description?: string;
|
|
276
|
+
icon?: React.ReactNode;
|
|
277
|
+
action?: {
|
|
278
|
+
label: string;
|
|
279
|
+
onClick: () => void;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
>(({ className, title, description, icon, action, ...props }, ref) => {
|
|
283
|
+
return (
|
|
284
|
+
<div
|
|
285
|
+
ref={ref}
|
|
286
|
+
className={cn(
|
|
287
|
+
"flex flex-col items-center justify-center text-center py-12 px-4",
|
|
288
|
+
className,
|
|
289
|
+
)}
|
|
290
|
+
{...props}
|
|
291
|
+
>
|
|
292
|
+
{icon && <div className="mb-4 text-muted-foreground">{icon}</div>}
|
|
293
|
+
<h3 className="text-lg font-semibold text-foreground mb-2">{title}</h3>
|
|
294
|
+
{description && (
|
|
295
|
+
<p className="text-muted-foreground mb-6 max-w-sm">{description}</p>
|
|
296
|
+
)}
|
|
297
|
+
{action && <Button onClick={action.onClick}>{action.label}</Button>}
|
|
298
|
+
</div>
|
|
299
|
+
);
|
|
300
|
+
});
|
|
142
301
|
|
|
143
302
|
EmptyState.displayName = "EmptyState";
|
|
144
303
|
|