@craftzbay/ui 0.5.0 → 0.6.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.
@@ -1,12 +1,150 @@
1
1
  import { ReactNode } from 'react';
2
+ /**
3
+ * Legacy nav keys retained for back-compat. The `active` prop now accepts
4
+ * any string — these are kept as a typed alias for consumers that hard-code
5
+ * one of the original demo values.
6
+ */
2
7
  export type AppShellNavKey = 'home' | 'projects' | 'inbox' | 'members' | 'insights' | 'bookmarks' | 'apps' | 'settings' | 'integrations' | 'help';
8
+ export interface AppShellNavItem {
9
+ /** Active-state identifier — matches AppShell's `active` prop. */
10
+ key: string;
11
+ label: ReactNode;
12
+ /** Leading icon. */
13
+ icon?: ReactNode;
14
+ /** Destination. Renders as <a href>; for SPAs intercept onClick. */
15
+ href?: string;
16
+ /** Right-aligned content (Badge, count). */
17
+ trailing?: ReactNode;
18
+ /** Optional click handler. */
19
+ onClick?: () => void;
20
+ }
21
+ export interface AppShellNavSection {
22
+ /** Section heading shown above the items. */
23
+ label?: ReactNode;
24
+ items: AppShellNavItem[];
25
+ }
26
+ export interface AppShellUser {
27
+ name: ReactNode;
28
+ email?: ReactNode;
29
+ /** 1–2 char initials for the Avatar fallback. */
30
+ initials: string;
31
+ /** Online status — drives the Avatar status dot. */
32
+ status?: 'online' | 'busy' | 'away' | 'offline';
33
+ }
34
+ export interface AppShellNotification {
35
+ id: string;
36
+ who: {
37
+ name: string;
38
+ initials: string;
39
+ };
40
+ action: ReactNode;
41
+ target: ReactNode;
42
+ when: ReactNode;
43
+ unread?: boolean;
44
+ onClick?: () => void;
45
+ }
46
+ export interface AppShellProfileMenuItem {
47
+ label: ReactNode;
48
+ icon?: ReactNode;
49
+ trailing?: ReactNode;
50
+ onSelect?: () => void;
51
+ /** Renders a separator before this item. */
52
+ separatorAbove?: boolean;
53
+ }
3
54
  export interface AppShellProps {
4
55
  /** Page content. */
5
56
  children: ReactNode;
6
57
  /** Logo / wordmark rendered at the top of the sidebar. */
7
58
  brand: ReactNode;
8
- /** Which sidebar item is active. Defaults to `home`. */
9
- active?: AppShellNavKey;
59
+ /** Which sidebar item is active. Matches `AppShellNavItem.key`. Defaults to `'home'`. */
60
+ active?: string;
61
+ /**
62
+ * Sidebar nav sections. Defaults to the built-in demo nav. Pass an empty
63
+ * array to hide the nav entirely, or use `sidebar` for a fully custom rail.
64
+ */
65
+ navSections?: AppShellNavSection[];
66
+ /**
67
+ * Escape hatch: replace the entire Sidebar contents. Takes precedence over
68
+ * `navSections`. Use when you need custom section components, groups, etc.
69
+ */
70
+ sidebar?: ReactNode;
71
+ /** Slot for additional topbar actions (left of notifications). */
72
+ topbarActions?: ReactNode;
73
+ /** Topbar search input — pass `false` to hide. */
74
+ search?: ReactNode | false;
75
+ /** Currently signed-in user, shown in the sidebar footer + profile menu. */
76
+ user?: AppShellUser;
77
+ /** Profile dropdown items. Defaults to the demo Profile / Settings / Sign out menu. */
78
+ profileMenu?: AppShellProfileMenuItem[];
79
+ /** Notification feed. Set to an empty array to hide the bell entirely. */
80
+ notifications?: AppShellNotification[];
81
+ /** Fires when the user clicks "Mark all read". */
82
+ onMarkAllNotificationsRead?: () => void;
83
+ /** Fires when the user clicks "View all" in the notifications menu. */
84
+ onViewAllNotifications?: () => void;
85
+ }
86
+ /**
87
+ * AppShell — sticky sidebar + topbar shell for SaaS dashboards.
88
+ *
89
+ * @example Default — uses the built-in demo nav, user, notifications
90
+ * <AppShell brand={<Logo />} active="home">
91
+ * <Dashboard />
92
+ * </AppShell>
93
+ *
94
+ * @example Custom nav + user
95
+ * <AppShell
96
+ * brand={<Logo />}
97
+ * active="projects"
98
+ * user={{ name: 'Avery Long', email: 'avery@acme.com', initials: 'AL', status: 'online' }}
99
+ * navSections={[
100
+ * { label: 'Workspace', items: [
101
+ * { key: 'home', label: 'Home', icon: <Home />, href: '/' },
102
+ * { key: 'projects', label: 'Projects', icon: <Folder />, href: '/projects',
103
+ * trailing: <Badge tone="neutral">{count}</Badge> },
104
+ * ]},
105
+ * ]}
106
+ * notifications={data?.notifications ?? []}
107
+ * >
108
+ * <ProjectsPage />
109
+ * </AppShell>
110
+ */
111
+ export declare function AppShell({ children, brand, active, navSections, sidebar, topbarActions, search, user, profileMenu, notifications, onMarkAllNotificationsRead, onViewAllNotifications, }: AppShellProps): import("react/jsx-runtime").JSX.Element;
112
+ export interface DashboardStat {
113
+ label: ReactNode;
114
+ value: ReactNode;
115
+ delta?: {
116
+ value: string;
117
+ positive?: boolean;
118
+ };
119
+ }
120
+ export interface DashboardActivityRow {
121
+ id: string;
122
+ who: {
123
+ name: string;
124
+ initials: string;
125
+ };
126
+ action: ReactNode;
127
+ target: ReactNode;
128
+ when: ReactNode;
129
+ }
130
+ export interface DashboardProps {
131
+ /** Top heading. */
132
+ title?: ReactNode;
133
+ /** Subtitle below the heading. */
134
+ subtitle?: ReactNode;
135
+ /** Top-right slot (date-range picker, segmented control, …). */
136
+ headerActions?: ReactNode;
137
+ /** Stat cards rendered in a responsive grid. */
138
+ stats?: DashboardStat[];
139
+ /** Chart card — any ReactNode (Chart component, SVG, image, placeholder). */
140
+ chart?: ReactNode;
141
+ /** Title above the chart. */
142
+ chartTitle?: ReactNode;
143
+ /** Subtitle under the chart title. */
144
+ chartDescription?: ReactNode;
145
+ /** Activity table rows. */
146
+ activity?: DashboardActivityRow[];
147
+ /** Title for the activity table. */
148
+ activityTitle?: ReactNode;
10
149
  }
11
- export declare function AppShell({ children, brand, active }: AppShellProps): import("react/jsx-runtime").JSX.Element;
12
- export declare function Dashboard(): import("react/jsx-runtime").JSX.Element;
150
+ export declare function Dashboard({ title, subtitle, headerActions, stats, chart, chartTitle, chartDescription, activity, activityTitle, }?: DashboardProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,16 @@
1
1
  import { HTMLAttributes, ReactNode } from 'react';
2
2
  export interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
3
- /** Visual marker — small Lucide icon or custom illustration. */
3
+ /**
4
+ * Small Lucide-sized icon rendered inside a 48px circular container.
5
+ * Use for compact empty states (table cells, sidebar panes, cards).
6
+ */
4
7
  icon?: ReactNode;
8
+ /**
9
+ * Full-size illustration rendered without the icon container. Takes
10
+ * precedence over `icon`. If neither is set, the default `InboxEmpty`
11
+ * line illustration is used.
12
+ */
13
+ illustration?: ReactNode;
5
14
  /** Heading. One short sentence. */
6
15
  title: ReactNode;
7
16
  /** Description. One or two sentences max. */
@@ -15,17 +24,23 @@ export interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 't
15
24
  * Shown when a list / dataset / surface has no content yet. Tone is helpful,
16
25
  * never apologetic.
17
26
  *
18
- * @example
27
+ * @example Default — uses the built-in InboxEmpty illustration
19
28
  * <EmptyState
20
- * icon={<Folder className="size-6" />}
21
29
  * title="No projects yet"
22
30
  * description="Create a project to start tracking work."
23
31
  * action={<Button>New project</Button>}
24
32
  * />
25
33
  *
26
- * @do Lead with the next action. The icon is decoration; the button is the
27
- * point.
28
- * @dont Use elaborate illustrations on internal product surfaces — they
29
- * break the refined-minimal direction.
34
+ * @example Compact small Lucide icon for dense layouts
35
+ * <EmptyState
36
+ * icon={<Folder className="size-6" />}
37
+ * title="No items"
38
+ * />
39
+ *
40
+ * @example Custom illustration
41
+ * <EmptyState
42
+ * illustration={<Illustrations.NoSearchResults className="size-32" />}
43
+ * title="No results"
44
+ * />
30
45
  */
31
46
  export declare const EmptyState: import('react').ForwardRefExoticComponent<EmptyStateProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -6,6 +6,11 @@ export interface ErrorStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 't
6
6
  title?: ReactNode;
7
7
  /** Override the default description. */
8
8
  description?: ReactNode;
9
+ /**
10
+ * Override the variant's default illustration. Pass any ReactNode (e.g.
11
+ * `<Illustrations.Construction className="size-32" />`).
12
+ */
13
+ illustration?: ReactNode;
9
14
  /** Custom action node. Replaces the default retry button. */
10
15
  action?: ReactNode;
11
16
  /** When provided, renders a default "Try again" button calling this handler. */
@@ -14,13 +19,19 @@ export interface ErrorStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 't
14
19
  /**
15
20
  * Page-level error placeholder. Pair with `onRetry` for transient failures.
16
21
  *
17
- * @example 500
22
+ * @example 404 (uses built-in line illustration)
23
+ * <ErrorState variant="404" />
24
+ *
25
+ * @example 500 with retry
18
26
  * <ErrorState variant="500" onRetry={refetch} />
19
27
  *
20
28
  * @example Custom
21
- * <ErrorState title="Quota exceeded"
22
- * description="Your plan allows 1,000 events/day."
23
- * action={<Button>Upgrade plan</Button>} />
29
+ * <ErrorState
30
+ * title="Quota exceeded"
31
+ * description="Your plan allows 1,000 events/day."
32
+ * illustration={<Illustrations.Construction className="size-32" />}
33
+ * action={<Button>Upgrade plan</Button>}
34
+ * />
24
35
  *
25
36
  * @do Match the tone to the cause — server errors apologise, user errors
26
37
  * explain. Always offer a next step.