@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.
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/dist-lib/components/patterns/AppShell.d.ts +9 -0
- package/dist-lib/components/patterns/Authentication.d.ts +45 -0
- package/dist-lib/components/patterns/DataTablePage.d.ts +1 -0
- package/dist-lib/components/patterns/FirstRunEmpty.d.ts +1 -0
- package/dist-lib/components/patterns/Onboarding.d.ts +1 -0
- package/dist-lib/components/patterns/Pricing.d.ts +1 -0
- package/dist-lib/components/patterns/RecordDetail.d.ts +1 -0
- package/dist-lib/components/patterns/Settings.d.ts +1 -0
- package/dist-lib/components/ui/Accordion.d.ts +21 -0
- package/dist-lib/components/ui/Alert.d.ts +35 -0
- package/dist-lib/components/ui/Avatar.d.ts +52 -0
- package/dist-lib/components/ui/Badge.d.ts +24 -0
- package/dist-lib/components/ui/Breadcrumbs.d.ts +31 -0
- package/dist-lib/components/ui/Button.d.ts +50 -0
- package/dist-lib/components/ui/Card.d.ts +37 -0
- package/dist-lib/components/ui/Checkbox.d.ts +28 -0
- package/dist-lib/components/ui/Combobox.d.ts +58 -0
- package/dist-lib/components/ui/CommandPalette.d.ts +109 -0
- package/dist-lib/components/ui/ContextMenu.d.ts +45 -0
- package/dist-lib/components/ui/DataGrid.d.ts +66 -0
- package/dist-lib/components/ui/DatePicker.d.ts +42 -0
- package/dist-lib/components/ui/Dialog.d.ts +62 -0
- package/dist-lib/components/ui/DropdownMenu.d.ts +47 -0
- package/dist-lib/components/ui/EmptyState.d.ts +31 -0
- package/dist-lib/components/ui/ErrorState.d.ts +29 -0
- package/dist-lib/components/ui/Form.d.ts +22 -0
- package/dist-lib/components/ui/IconButton.d.ts +34 -0
- package/dist-lib/components/ui/Input.d.ts +49 -0
- package/dist-lib/components/ui/Kbd.d.ts +16 -0
- package/dist-lib/components/ui/MultiSelect.d.ts +62 -0
- package/dist-lib/components/ui/Pagination.d.ts +32 -0
- package/dist-lib/components/ui/Popover.d.ts +16 -0
- package/dist-lib/components/ui/Progress.d.ts +40 -0
- package/dist-lib/components/ui/RadioGroup.d.ts +27 -0
- package/dist-lib/components/ui/ScrollArea.d.ts +13 -0
- package/dist-lib/components/ui/Select.d.ts +56 -0
- package/dist-lib/components/ui/Separator.d.ts +13 -0
- package/dist-lib/components/ui/Sheet.d.ts +46 -0
- package/dist-lib/components/ui/Sidebar.d.ts +67 -0
- package/dist-lib/components/ui/Skeleton.d.ts +26 -0
- package/dist-lib/components/ui/Slider.d.ts +33 -0
- package/dist-lib/components/ui/Spinner.d.ts +23 -0
- package/dist-lib/components/ui/Stepper.d.ts +34 -0
- package/dist-lib/components/ui/Switch.d.ts +33 -0
- package/dist-lib/components/ui/Table.d.ts +35 -0
- package/dist-lib/components/ui/Tabs.d.ts +32 -0
- package/dist-lib/components/ui/Textarea.d.ts +34 -0
- package/dist-lib/components/ui/Toast.d.ts +33 -0
- package/dist-lib/components/ui/Tooltip.d.ts +35 -0
- package/dist-lib/components/ui/TopNav.d.ts +33 -0
- package/dist-lib/hooks/use-media-query.d.ts +9 -0
- package/dist-lib/hooks/use-toast.d.ts +43 -0
- package/dist-lib/icons/index.d.ts +11 -0
- package/dist-lib/index.cjs +8 -0
- package/dist-lib/index.cjs.map +1 -0
- package/dist-lib/index.d.ts +58 -0
- package/dist-lib/index.js +4336 -0
- package/dist-lib/index.js.map +1 -0
- package/dist-lib/lib/cva.d.ts +6 -0
- package/dist-lib/lib/utils.d.ts +12 -0
- package/dist-lib/styles.css +1 -0
- 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>>;
|