@craftzbay/ui 0.1.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist-lib/components/patterns/AppShell.d.ts +9 -0
  4. package/dist-lib/components/patterns/Authentication.d.ts +45 -0
  5. package/dist-lib/components/patterns/DataTablePage.d.ts +1 -0
  6. package/dist-lib/components/patterns/FirstRunEmpty.d.ts +1 -0
  7. package/dist-lib/components/patterns/Onboarding.d.ts +1 -0
  8. package/dist-lib/components/patterns/Pricing.d.ts +1 -0
  9. package/dist-lib/components/patterns/RecordDetail.d.ts +1 -0
  10. package/dist-lib/components/patterns/Settings.d.ts +1 -0
  11. package/dist-lib/components/ui/Accordion.d.ts +21 -0
  12. package/dist-lib/components/ui/Alert.d.ts +35 -0
  13. package/dist-lib/components/ui/Avatar.d.ts +52 -0
  14. package/dist-lib/components/ui/Badge.d.ts +24 -0
  15. package/dist-lib/components/ui/Breadcrumbs.d.ts +31 -0
  16. package/dist-lib/components/ui/Button.d.ts +50 -0
  17. package/dist-lib/components/ui/Card.d.ts +37 -0
  18. package/dist-lib/components/ui/Checkbox.d.ts +28 -0
  19. package/dist-lib/components/ui/Combobox.d.ts +58 -0
  20. package/dist-lib/components/ui/CommandPalette.d.ts +109 -0
  21. package/dist-lib/components/ui/ContextMenu.d.ts +45 -0
  22. package/dist-lib/components/ui/DataGrid.d.ts +66 -0
  23. package/dist-lib/components/ui/DatePicker.d.ts +42 -0
  24. package/dist-lib/components/ui/Dialog.d.ts +62 -0
  25. package/dist-lib/components/ui/DropdownMenu.d.ts +47 -0
  26. package/dist-lib/components/ui/EmptyState.d.ts +31 -0
  27. package/dist-lib/components/ui/ErrorState.d.ts +29 -0
  28. package/dist-lib/components/ui/Form.d.ts +22 -0
  29. package/dist-lib/components/ui/IconButton.d.ts +34 -0
  30. package/dist-lib/components/ui/Input.d.ts +49 -0
  31. package/dist-lib/components/ui/Kbd.d.ts +16 -0
  32. package/dist-lib/components/ui/MultiSelect.d.ts +62 -0
  33. package/dist-lib/components/ui/Pagination.d.ts +32 -0
  34. package/dist-lib/components/ui/Popover.d.ts +16 -0
  35. package/dist-lib/components/ui/Progress.d.ts +40 -0
  36. package/dist-lib/components/ui/RadioGroup.d.ts +27 -0
  37. package/dist-lib/components/ui/ScrollArea.d.ts +13 -0
  38. package/dist-lib/components/ui/Select.d.ts +56 -0
  39. package/dist-lib/components/ui/Separator.d.ts +13 -0
  40. package/dist-lib/components/ui/Sheet.d.ts +46 -0
  41. package/dist-lib/components/ui/Sidebar.d.ts +67 -0
  42. package/dist-lib/components/ui/Skeleton.d.ts +26 -0
  43. package/dist-lib/components/ui/Slider.d.ts +33 -0
  44. package/dist-lib/components/ui/Spinner.d.ts +23 -0
  45. package/dist-lib/components/ui/Stepper.d.ts +34 -0
  46. package/dist-lib/components/ui/Switch.d.ts +33 -0
  47. package/dist-lib/components/ui/Table.d.ts +35 -0
  48. package/dist-lib/components/ui/Tabs.d.ts +32 -0
  49. package/dist-lib/components/ui/Textarea.d.ts +34 -0
  50. package/dist-lib/components/ui/Toast.d.ts +33 -0
  51. package/dist-lib/components/ui/Tooltip.d.ts +35 -0
  52. package/dist-lib/components/ui/TopNav.d.ts +33 -0
  53. package/dist-lib/hooks/use-media-query.d.ts +9 -0
  54. package/dist-lib/hooks/use-toast.d.ts +43 -0
  55. package/dist-lib/icons/index.d.ts +11 -0
  56. package/dist-lib/index.cjs +8 -0
  57. package/dist-lib/index.cjs.map +1 -0
  58. package/dist-lib/index.d.ts +58 -0
  59. package/dist-lib/index.js +4336 -0
  60. package/dist-lib/index.js.map +1 -0
  61. package/dist-lib/lib/cva.d.ts +6 -0
  62. package/dist-lib/lib/utils.d.ts +12 -0
  63. package/dist-lib/styles.css +1 -0
  64. package/package.json +118 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 craftzbay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @craftzbay/ui
2
+
3
+ A refined-minimal Tailwind v4 + React design system. Production-grade
4
+ primitives — Button through DataGrid — plus composed patterns
5
+ (authentication, app shell, settings, etc.).
6
+
7
+ - **Showcase:** [design.runestonetechnologies.com](https://design.runestonetechnologies.com)
8
+ - **Storybook:** [storybook.runestonetechnologies.com](https://storybook.runestonetechnologies.com)
9
+
10
+ > **Aesthetic direction:** Linear / Vercel / Stripe Dashboard / Notion / Raycast.
11
+ > Neutral-dominant, one accent, hairline borders, generous whitespace, fast quiet
12
+ > motion. See [`docs/PHILOSOPHY.md`](./docs/PHILOSOPHY.md).
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pnpm add @craftzbay/ui
18
+ ```
19
+
20
+ ```tsx
21
+ import { Button, Dialog, Toast } from '@craftzbay/ui';
22
+ import '@craftzbay/ui/styles.css';
23
+
24
+ export function App() {
25
+ return <Button variant="primary">Save</Button>;
26
+ }
27
+ ```
28
+
29
+ Peer dependencies: `react@>=18`, `react-dom@>=18`.
30
+
31
+ ## Local development
32
+
33
+ ```bash
34
+ pnpm install
35
+ pnpm dev # Vite showcase at localhost:5173
36
+ pnpm storybook # Storybook at localhost:6006
37
+ pnpm build:lib # Build library → dist-lib/
38
+ ```
39
+
40
+ ## Tech stack
41
+
42
+ - **Tailwind CSS v4** — tokens defined in `@theme` in `src/styles/globals.css`
43
+ - **React 18** + **TypeScript 5.7**
44
+ - **Radix UI** primitives for accessibility-correct overlays
45
+ - **class-variance-authority** + `cn()` (`clsx` + `tailwind-merge`)
46
+ - **Lucide** icons (16 / 20px, 1.5 stroke)
47
+ - **Geist** sans + **Geist Mono** monospace
48
+
49
+ ## Project structure
50
+
51
+ ```
52
+ src/
53
+ ├── styles/
54
+ │ └── globals.css # @theme tokens, semantic vars, base layer
55
+ ├── lib/
56
+ │ ├── utils.ts # cn() + uid()
57
+ │ └── cva.ts
58
+ ├── components/
59
+ │ ├── ui/ # primitives — 40 components
60
+ │ └── patterns/ # composed layouts
61
+ ├── hooks/
62
+ │ ├── use-toast.ts
63
+ │ └── use-media-query.ts
64
+ └── icons/ # curated Lucide re-exports
65
+ docs/
66
+ ├── PHILOSOPHY.md # the 6 refined-minimal principles
67
+ ├── VOICE.md # content + tone of voice
68
+ └── ACCESSIBILITY.md # WCAG checklist + contrast ratios
69
+ ```
70
+
71
+ ## Component index
72
+
73
+ ### Inputs
74
+ - [Input](./src/components/ui/Input.tsx) — text / email / password / number / search with prefix, suffix, error
75
+ - [Textarea](./src/components/ui/Textarea.tsx) — auto-resize multi-line input
76
+ - [Select](./src/components/ui/Select.tsx) — single-choice menu (Radix)
77
+ - [MultiSelect](./src/components/ui/MultiSelect.tsx) — chip-based multi-choice picker
78
+ - [Combobox](./src/components/ui/Combobox.tsx) — searchable single-select, sync or async
79
+ - [Checkbox](./src/components/ui/Checkbox.tsx) — including indeterminate
80
+ - [RadioGroup](./src/components/ui/RadioGroup.tsx) — mutually-exclusive choices
81
+ - [Switch](./src/components/ui/Switch.tsx) — instant-apply binary toggle
82
+ - [Slider](./src/components/ui/Slider.tsx) — single + range
83
+ - [DatePicker](./src/components/ui/DatePicker.tsx) — single + range
84
+ - [Form primitives](./src/components/ui/Form.tsx) — react-hook-form bindings
85
+
86
+ ### Buttons
87
+ - [Button](./src/components/ui/Button.tsx) — primary · secondary · outline · ghost · destructive · link
88
+ - [IconButton](./src/components/ui/IconButton.tsx) — square icon-only variant
89
+ - [Pagination](./src/components/ui/Pagination.tsx) — numbered + jumps + page-size
90
+
91
+ ### Feedback
92
+ - [Alert](./src/components/ui/Alert.tsx) — inline banner, dismissible
93
+ - [Toast](./src/components/ui/Toast.tsx) + `useToast` hook
94
+ - [Spinner](./src/components/ui/Spinner.tsx) — accent / neutral / on-accent tones
95
+ - [Progress](./src/components/ui/Progress.tsx) — linear + circular, determinate + indeterminate
96
+ - [Skeleton](./src/components/ui/Skeleton.tsx) — text, avatar, card variants
97
+ - [EmptyState](./src/components/ui/EmptyState.tsx)
98
+ - [ErrorState](./src/components/ui/ErrorState.tsx) — 404 / 500 / generic
99
+
100
+ ### Navigation
101
+ - [TopNav](./src/components/ui/TopNav.tsx) + `TopNavLink`
102
+ - [Sidebar](./src/components/ui/Sidebar.tsx) + `SidebarSection` + `SidebarItem` + `SidebarGroup`
103
+ - [Breadcrumbs](./src/components/ui/Breadcrumbs.tsx) — with overflow ellipsis
104
+ - [Tabs](./src/components/ui/Tabs.tsx) — underline + pills variants
105
+ - [Stepper](./src/components/ui/Stepper.tsx) — horizontal + vertical
106
+
107
+ ### Layout
108
+ - [Card](./src/components/ui/Card.tsx) + `CardHeader/Title/Description/Content/Footer`
109
+ - [Separator](./src/components/ui/Separator.tsx)
110
+ - [ScrollArea](./src/components/ui/ScrollArea.tsx) — Radix-backed styled scroll
111
+ - [Accordion](./src/components/ui/Accordion.tsx) — single + multiple
112
+
113
+ ### Overlays
114
+ - [Dialog](./src/components/ui/Dialog.tsx) + `ConfirmationDialog`
115
+ - [Sheet](./src/components/ui/Sheet.tsx) — left / right / top / bottom
116
+ - [Popover](./src/components/ui/Popover.tsx)
117
+ - [Tooltip](./src/components/ui/Tooltip.tsx) — 500ms delay default
118
+ - [DropdownMenu](./src/components/ui/DropdownMenu.tsx) — submenus, separators, kbd
119
+ - [ContextMenu](./src/components/ui/ContextMenu.tsx) — right-click menu
120
+ - [CommandPalette](./src/components/ui/CommandPalette.tsx) — ⌘K palette
121
+
122
+ ### Data display
123
+ - [Table](./src/components/ui/Table.tsx) + `TableSortHeader`
124
+ - [DataGrid](./src/components/ui/DataGrid.tsx) — column visibility, filter, sortable
125
+ - [Badge](./src/components/ui/Badge.tsx) — subtle + outline, 6 tones
126
+ - [Avatar](./src/components/ui/Avatar.tsx) + `AvatarGroup`
127
+
128
+ ### Typography
129
+ - [Kbd](./src/components/ui/Kbd.tsx) — keyboard shortcut indicator
130
+
131
+ ## Patterns (composed layouts)
132
+
133
+ - [Authentication](./src/components/patterns/Authentication.tsx) — sign-in, sign-up, forgot, magic-link
134
+ - [AppShell + Dashboard](./src/components/patterns/AppShell.tsx) — sidebar + topnav shell, 4 stat cards + chart + activity table
135
+ - [Settings](./src/components/patterns/Settings.tsx) — sub-nav + 5 sections
136
+ - [DataTablePage](./src/components/patterns/DataTablePage.tsx) — filter / search / bulk actions / pagination
137
+ - [RecordDetail](./src/components/patterns/RecordDetail.tsx) — header + tabs + side panel
138
+ - [Onboarding](./src/components/patterns/Onboarding.tsx) — 4-step stepper flow
139
+ - [Pricing](./src/components/patterns/Pricing.tsx) — 3-tier comparison
140
+ - [FirstRunEmpty](./src/components/patterns/FirstRunEmpty.tsx) — hero + 3 next-step cards
141
+
142
+ ## Documentation
143
+
144
+ - [`docs/PHILOSOPHY.md`](./docs/PHILOSOPHY.md) — the six principles + forbidden list
145
+ - [`docs/VOICE.md`](./docs/VOICE.md) — tone of voice, button labels, error copy formula
146
+ - [`docs/ACCESSIBILITY.md`](./docs/ACCESSIBILITY.md) — WCAG AA contrast table, keyboard map
147
+
148
+ ## Contributing
149
+
150
+ 1. Read [`docs/PHILOSOPHY.md`](./docs/PHILOSOPHY.md) first — the forbidden list is
151
+ non-negotiable.
152
+ 2. Components reference semantic tokens (`bg-card`, `text-accent`), never raw
153
+ palette steps (`bg-indigo-500`).
154
+ 3. Every interactive element ships with: default, hover, focus-visible, active,
155
+ disabled, loading, and (where applicable) error / success states.
156
+ 4. Forward refs correctly; set `displayName`.
157
+ 5. Run `pnpm typecheck && pnpm lint` before opening a PR.
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ export interface AppShellProps {
3
+ /** Page content. */
4
+ children: ReactNode;
5
+ /** Logo / wordmark for the TopNav. */
6
+ brand: ReactNode;
7
+ }
8
+ export declare function AppShell({ children, brand }: AppShellProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function Dashboard(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,45 @@
1
+ import { ReactNode } from 'react';
2
+ export interface AuthLayoutProps {
3
+ /** Brand mark shown above the title. */
4
+ brand?: ReactNode;
5
+ /** Page heading. */
6
+ title: ReactNode;
7
+ /** Secondary line under the title. */
8
+ subtitle?: ReactNode;
9
+ /** Form / content. */
10
+ children: ReactNode;
11
+ /** Footer slot — "Don't have an account? Sign up". */
12
+ footer?: ReactNode;
13
+ }
14
+ export declare function AuthLayout({ brand, title, subtitle, children, footer }: AuthLayoutProps): import("react/jsx-runtime").JSX.Element;
15
+ export interface SignInFormProps {
16
+ onSubmit: (data: {
17
+ email: string;
18
+ password: string;
19
+ }) => void | Promise<void>;
20
+ loading?: boolean;
21
+ error?: ReactNode;
22
+ forgotHref?: string;
23
+ }
24
+ export declare function SignInForm({ onSubmit, loading, error, forgotHref }: SignInFormProps): import("react/jsx-runtime").JSX.Element;
25
+ export interface SignUpFormProps {
26
+ onSubmit: (data: {
27
+ name: string;
28
+ email: string;
29
+ password: string;
30
+ }) => void | Promise<void>;
31
+ loading?: boolean;
32
+ error?: ReactNode;
33
+ }
34
+ export declare function SignUpForm({ onSubmit, loading, error }: SignUpFormProps): import("react/jsx-runtime").JSX.Element;
35
+ export interface ForgotPasswordFormProps {
36
+ onSubmit: (email: string) => void | Promise<void>;
37
+ loading?: boolean;
38
+ error?: ReactNode;
39
+ }
40
+ export declare function ForgotPasswordForm({ onSubmit, loading, error }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
41
+ export interface MagicLinkSentProps {
42
+ email: string;
43
+ onResend?: () => void;
44
+ }
45
+ export declare function MagicLinkSent({ email, onResend }: MagicLinkSentProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function DataTablePage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function FirstRunEmpty(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function Onboarding(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function Pricing(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function RecordDetail(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function SettingsPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
2
+ /**
3
+ * Accessible disclosure list. Supports single (`type="single"`) and multiple
4
+ * (`type="multiple"`) open behaviour — both come from Radix.
5
+ *
6
+ * @example FAQ
7
+ * <Accordion type="single" collapsible>
8
+ * <AccordionItem value="q1">
9
+ * <AccordionTrigger>Can I cancel anytime?</AccordionTrigger>
10
+ * <AccordionContent>Yes — usage stops at the end of the billing period.</AccordionContent>
11
+ * </AccordionItem>
12
+ * …
13
+ * </Accordion>
14
+ *
15
+ * @do Use for FAQs, settings groups, and progressive-disclosure forms.
16
+ * @dont Nest accordions inside accordions — the focus order becomes opaque.
17
+ */
18
+ export declare const Accordion: import('react').ForwardRefExoticComponent<(AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps) & import('react').RefAttributes<HTMLDivElement>>;
19
+ export declare const AccordionItem: import('react').ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionItemProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
20
+ export declare const AccordionTrigger: import('react').ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionTriggerProps & import('react').RefAttributes<HTMLButtonElement>, "ref"> & import('react').RefAttributes<HTMLButtonElement>>;
21
+ export declare const AccordionContent: import('react').ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionContentProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,35 @@
1
+ import { HTMLAttributes, ReactNode } from 'react';
2
+ import { VariantProps } from '../../lib/cva';
3
+ declare const alert: (props?: ({
4
+ variant?: "default" | "success" | "warning" | "danger" | "info" | null | undefined;
5
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
6
+ export interface AlertProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof alert> {
7
+ /** Heading. Renders bold above the description. */
8
+ title?: ReactNode;
9
+ /** Show a dismiss (×) button. */
10
+ dismissible?: boolean;
11
+ /** Called when the user dismisses. */
12
+ onDismiss?: () => void;
13
+ /** Override the variant's default icon. Pass `false` to suppress the icon. */
14
+ icon?: ReactNode | false;
15
+ }
16
+ /**
17
+ * Inline banner for static page-level or section-level state. For transient
18
+ * notifications use `Toast` instead.
19
+ *
20
+ * @example Inline error
21
+ * <Alert variant="danger" title="Payment failed">
22
+ * Your card was declined. Update your billing info to retry.
23
+ * </Alert>
24
+ *
25
+ * @example Dismissible info
26
+ * <Alert variant="info" dismissible onDismiss={dismiss}>
27
+ * We're improving search — give us feedback at #search-feedback.
28
+ * </Alert>
29
+ *
30
+ * @do Use the closest semantic variant — `info` for neutral facts,
31
+ * `warning` for "watch out", `danger` for "this is broken".
32
+ * @dont Use Alert for one-time confirmations — that's Toast.
33
+ */
34
+ export declare const Alert: import('react').ForwardRefExoticComponent<AlertProps & import('react').RefAttributes<HTMLDivElement>>;
35
+ export {};
@@ -0,0 +1,52 @@
1
+ import { ComponentPropsWithoutRef, HTMLAttributes, ReactNode } from 'react';
2
+ import { VariantProps } from '../../lib/cva';
3
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
4
+ declare const sizeMap: {
5
+ readonly xs: "size-5 text-[10px]";
6
+ readonly sm: "size-6 text-xs";
7
+ readonly md: "size-8 text-xs";
8
+ readonly lg: "size-10 text-sm";
9
+ readonly xl: "size-12 text-base";
10
+ };
11
+ declare const avatar: (props?: ({
12
+ size?: "md" | "xs" | "sm" | "lg" | "xl" | null | undefined;
13
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
14
+ export interface AvatarProps extends ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>, VariantProps<typeof avatar> {
15
+ /** Image URL. If absent or fails to load, fallback initials are shown. */
16
+ src?: string;
17
+ /** Alt text for the image; falls back to fallback when there's no `src`. */
18
+ alt?: string;
19
+ /** Initials shown when image is missing or loading. Pass at most 2 characters. */
20
+ fallback?: string;
21
+ /** Status dot rendered on the bottom-right. */
22
+ status?: 'online' | 'busy' | 'away' | 'offline';
23
+ }
24
+ /**
25
+ * Avatar with image, initials fallback, and optional status dot.
26
+ *
27
+ * @example
28
+ * <Avatar src={user.photo} alt={user.name} fallback={getInitials(user.name)} status="online" />
29
+ *
30
+ * @example AvatarGroup
31
+ * <AvatarGroup max={3}>
32
+ * {users.map(u => <Avatar key={u.id} src={u.photo} fallback={getInitials(u.name)} />)}
33
+ * </AvatarGroup>
34
+ *
35
+ * @do Provide `alt` for image avatars and meaningful initials for the
36
+ * fallback so screen readers announce something useful.
37
+ * @dont Use the status dot without a tooltip explaining what it means.
38
+ */
39
+ export declare const Avatar: import('react').ForwardRefExoticComponent<AvatarProps & import('react').RefAttributes<HTMLSpanElement>>;
40
+ export interface AvatarGroupProps extends HTMLAttributes<HTMLDivElement> {
41
+ /** Maximum visible avatars before showing a "+N" overflow chip. */
42
+ max?: number;
43
+ /** Avatar size applied to children + overflow. */
44
+ size?: keyof typeof sizeMap;
45
+ /** Children — Avatars. */
46
+ children: ReactNode;
47
+ }
48
+ /**
49
+ * Overlapping avatars with overflow indicator. Pass plain `<Avatar>` children.
50
+ */
51
+ export declare const AvatarGroup: import('react').ForwardRefExoticComponent<AvatarGroupProps & import('react').RefAttributes<HTMLDivElement>>;
52
+ export {};
@@ -0,0 +1,24 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { VariantProps } from '../../lib/cva';
3
+ declare const badge: (props?: ({
4
+ variant?: "subtle" | "outline" | null | undefined;
5
+ tone?: "success" | "warning" | "danger" | "info" | "neutral" | "accent" | null | undefined;
6
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badge> {
8
+ /** Show a leading status dot in the same tone. */
9
+ dot?: boolean;
10
+ }
11
+ /**
12
+ * Status pill. Use `subtle` for high-volume contexts (table cells, lists);
13
+ * `outline` when the badge sits on a busy or coloured background.
14
+ *
15
+ * @example
16
+ * <Badge tone="success" dot>Active</Badge>
17
+ * <Badge tone="danger" variant="outline">Failed</Badge>
18
+ *
19
+ * @do Use badges to summarise state, not to label categories — for taxonomies
20
+ * pick a tone palette and stick with it.
21
+ * @dont Use a badge as a button. Wrap it in a Button or use a Toggle.
22
+ */
23
+ export declare const Badge: import('react').ForwardRefExoticComponent<BadgeProps & import('react').RefAttributes<HTMLSpanElement>>;
24
+ export {};
@@ -0,0 +1,31 @@
1
+ import { HTMLAttributes, ReactNode } from 'react';
2
+ export interface BreadcrumbItem {
3
+ /** Visible label. */
4
+ label: ReactNode;
5
+ /** Optional URL. Last item is treated as current page even if href is set. */
6
+ href?: string;
7
+ }
8
+ export interface BreadcrumbsProps extends HTMLAttributes<HTMLElement> {
9
+ items: BreadcrumbItem[];
10
+ /** Collapse to first + ellipsis + last `n` when items.length exceeds this. */
11
+ maxItems?: number;
12
+ /** Custom link renderer (for next/link, react-router, etc.). */
13
+ renderLink?: (href: string, children: ReactNode) => ReactNode;
14
+ }
15
+ /**
16
+ * Breadcrumb trail. Collapses with an ellipsis when there are too many crumbs.
17
+ *
18
+ * @example
19
+ * <Breadcrumbs items={[
20
+ * { label: 'Projects', href: '/projects' },
21
+ * { label: 'Nova', href: '/projects/nova' },
22
+ * { label: 'Settings' },
23
+ * ]} />
24
+ *
25
+ * @example With react-router
26
+ * <Breadcrumbs items={trail} renderLink={(href, c) => <Link to={href}>{c}</Link>} />
27
+ *
28
+ * @do Always omit `href` on the last item — it represents the current page.
29
+ * @dont Use Breadcrumbs for flat navigation. Use TopNav links instead.
30
+ */
31
+ export declare const Breadcrumbs: import('react').ForwardRefExoticComponent<BreadcrumbsProps & import('react').RefAttributes<HTMLElement>>;
@@ -0,0 +1,50 @@
1
+ import { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ import { VariantProps } from '../../lib/cva';
3
+ declare const button: (props?: ({
4
+ variant?: "link" | "outline" | "primary" | "secondary" | "ghost" | "destructive" | null | undefined;
5
+ size?: "icon" | "md" | "sm" | "lg" | null | undefined;
6
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof button> {
8
+ /**
9
+ * Render as a different element via Radix Slot. Useful when wrapping a
10
+ * link: `<Button asChild><a href="…">…</a></Button>`.
11
+ * @default false
12
+ */
13
+ asChild?: boolean;
14
+ /**
15
+ * Show a spinner in place of the leading icon and disable the button.
16
+ * Use for async actions where the user must wait.
17
+ * @default false
18
+ */
19
+ loading?: boolean;
20
+ /** Icon rendered before the label. Replaced by a spinner when loading. */
21
+ leadingIcon?: ReactNode;
22
+ /** Icon rendered after the label. Hidden while loading. */
23
+ trailingIcon?: ReactNode;
24
+ }
25
+ /**
26
+ * Primary interactive element. Variants:
27
+ *
28
+ * - `primary` — accent fill, the single most prominent action on a screen.
29
+ * - `secondary` — neutral fill, sits next to a primary or stands alone for
30
+ * secondary actions.
31
+ * - `outline` — border only, transparent fill. Use when next to a primary.
32
+ * - `ghost` — no border, hover background. Use in dense toolbars and tables.
33
+ * - `destructive` — danger fill, reserved for irreversible actions.
34
+ * - `link` — text styled as a link.
35
+ *
36
+ * @example Two-button row
37
+ * <div className="flex gap-2 justify-end">
38
+ * <Button variant="outline">Cancel</Button>
39
+ * <Button>Save changes</Button>
40
+ * </div>
41
+ *
42
+ * @example Loading state
43
+ * <Button loading leadingIcon={<Mail />}>Sending…</Button>
44
+ *
45
+ * @do Use one primary button per major surface. Verb-first labels.
46
+ * @dont Stack three primary buttons in a row — only the most important
47
+ * action gets the primary variant.
48
+ */
49
+ export declare const Button: import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
50
+ export {};
@@ -0,0 +1,37 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { VariantProps } from '../../lib/cva';
3
+ declare const card: (props?: ({
4
+ variant?: "default" | "interactive" | null | undefined;
5
+ padding?: "none" | "md" | "sm" | "lg" | null | undefined;
6
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
+ export interface CardProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof card> {
8
+ }
9
+ /**
10
+ * Bounded surface used to group related content. Per the refined-minimal
11
+ * rules, cards on the page have a hairline border and no shadow.
12
+ *
13
+ * @example Header + content + footer
14
+ * <Card>
15
+ * <CardHeader>
16
+ * <CardTitle>Storage</CardTitle>
17
+ * <CardDescription>Usage across all projects.</CardDescription>
18
+ * </CardHeader>
19
+ * <CardContent>…</CardContent>
20
+ * <CardFooter><Button>Upgrade</Button></CardFooter>
21
+ * </Card>
22
+ *
23
+ * @example Clickable list row
24
+ * <Card variant="interactive" onClick={open}>…</Card>
25
+ *
26
+ * @do Use the `border` style. If a card needs to "float" (modal, dropdown),
27
+ * it isn't a Card — it's a Popover/Dialog.
28
+ * @dont Add `shadow-lg` to Cards. Shadows on inline surfaces violate the
29
+ * refined-minimal direction.
30
+ */
31
+ export declare const Card: import('react').ForwardRefExoticComponent<CardProps & import('react').RefAttributes<HTMLDivElement>>;
32
+ export declare const CardHeader: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import('react').RefAttributes<HTMLDivElement>>;
33
+ export declare const CardTitle: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLHeadingElement> & import('react').RefAttributes<HTMLHeadingElement>>;
34
+ export declare const CardDescription: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & import('react').RefAttributes<HTMLParagraphElement>>;
35
+ export declare const CardContent: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import('react').RefAttributes<HTMLDivElement>>;
36
+ export declare const CardFooter: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import('react').RefAttributes<HTMLDivElement>>;
37
+ export {};
@@ -0,0 +1,28 @@
1
+ import { ComponentPropsWithoutRef, ReactNode } from 'react';
2
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
+ export interface CheckboxProps extends Omit<ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, 'asChild'> {
4
+ /** Visible label rendered to the right of the box. */
5
+ label?: ReactNode;
6
+ /** Secondary description rendered below the label. */
7
+ description?: ReactNode;
8
+ /** Validation error message. */
9
+ error?: ReactNode;
10
+ /** Hide the label visually while keeping it in the a11y tree. */
11
+ hideLabel?: boolean;
12
+ }
13
+ /**
14
+ * Checkbox with optional inline label + description. Pass `checked="indeterminate"`
15
+ * for the indeterminate state — Radix renders a `Minus` icon automatically.
16
+ *
17
+ * @example Single
18
+ * <Checkbox label="I agree to the terms" checked={ok} onCheckedChange={setOk} />
19
+ *
20
+ * @example Tri-state header
21
+ * <Checkbox aria-label="Select all"
22
+ * checked={allSelected ? true : someSelected ? 'indeterminate' : false}
23
+ * onCheckedChange={toggleAll} />
24
+ *
25
+ * @do Use indeterminate to summarise child rows in a table header.
26
+ * @dont Use a Checkbox for mutually exclusive choices — use RadioGroup.
27
+ */
28
+ export declare const Checkbox: import('react').ForwardRefExoticComponent<CheckboxProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,58 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ComboboxOption {
3
+ value: string;
4
+ label: string;
5
+ description?: string;
6
+ disabled?: boolean;
7
+ }
8
+ export interface ComboboxProps {
9
+ /** Currently selected value (controlled). */
10
+ value: string | null;
11
+ /** Called when a value is picked or cleared. */
12
+ onChange: (value: string | null) => void;
13
+ /** Static options. Ignored if `loadOptions` is provided. */
14
+ options?: ComboboxOption[];
15
+ /**
16
+ * Async loader called with the current query each time it changes.
17
+ * Use for server-side search.
18
+ */
19
+ loadOptions?: (query: string) => Promise<ComboboxOption[]>;
20
+ /** Visible label above the field. */
21
+ label?: ReactNode;
22
+ /** Hint below the field. Hidden when `error` is set. */
23
+ helperText?: ReactNode;
24
+ /** Validation error. */
25
+ error?: ReactNode;
26
+ /** Placeholder shown when no value is selected. */
27
+ placeholder?: string;
28
+ /** Search placeholder inside the popover. */
29
+ searchPlaceholder?: string;
30
+ /** Empty state copy when nothing matches. */
31
+ emptyText?: string;
32
+ /** Allow clearing the selection with an inline ×. */
33
+ clearable?: boolean;
34
+ /** Disable the entire field. */
35
+ disabled?: boolean;
36
+ /** Field size, matches Input. */
37
+ size?: 'sm' | 'md' | 'lg';
38
+ className?: string;
39
+ }
40
+ /**
41
+ * Single-select with typeahead. Use `options` for client-side filtering or
42
+ * `loadOptions` for server-side search.
43
+ *
44
+ * @example Client-side
45
+ * <Combobox label="Country" options={countries} value={c} onChange={setC} />
46
+ *
47
+ * @example Server-side
48
+ * <Combobox label="Assignee"
49
+ * value={user}
50
+ * onChange={setUser}
51
+ * loadOptions={async (q) => api.searchUsers(q)} />
52
+ *
53
+ * @do Use Combobox over Select for >12 options or when the user is expected
54
+ * to know what they want.
55
+ * @dont Re-query on every keystroke without debouncing — pass a debounced
56
+ * `loadOptions` to avoid hammering the server.
57
+ */
58
+ export declare const Combobox: import('react').ForwardRefExoticComponent<ComboboxProps & import('react').RefAttributes<HTMLDivElement>>;