shadcn-ui-react 0.7.1 โ†’ 0.7.5

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/README.md CHANGED
@@ -1,54 +1,48 @@
1
1
  # ๐Ÿงฉ shadcn-ui-react
2
2
 
3
- A simple wrapper for [shadcn/ui](https://github.com/shadcn-ui/ui) to build modern, accessible, and customizable UIs in React with minimal setup.
3
+ A modern React UI kit inspired by shadcn/ui. It includes accessible Radix primitives, production-ready shared components, form helpers for `react-hook-form`, Tailwind CSS styling, and reusable demos you can copy into your app.
4
4
 
5
5
  ---
6
6
 
7
7
  ## ๐Ÿ“ฆ Installation
8
8
 
9
- Install via your preferred package manager:
10
-
11
9
  ```bash
12
10
  npm install shadcn-ui-react
13
11
  # or
14
- yarn add shadcn-ui-react
15
- # or
16
12
  pnpm add shadcn-ui-react
13
+ # or
14
+ yarn add shadcn-ui-react
17
15
  ```
18
16
 
19
- ---
20
-
21
- ### Tailwind IntelliSense (VS Code)
22
-
23
- To enable Tailwind CSS IntelliSense to detect classes within `cn(...)` and other utilities:
17
+ ### Peer dependencies
24
18
 
25
19
  ```bash
26
- npx shadcn-ui-react init-vscode
20
+ npm install react react-dom
27
21
  ```
28
22
 
29
23
  ---
30
24
 
31
25
  ## ๐Ÿš€ Getting Started
32
26
 
33
- ### 1. Import Global Styles
27
+ ### 1. Import global styles
34
28
 
35
- In your `main.tsx` or `App.tsx`:
29
+ In your `main.tsx`, `App.tsx`, or layout file:
36
30
 
37
31
  ```tsx
38
- import "shadcn-ui-react/dist/style.css";
32
+ import 'shadcn-ui-react/dist/style.css';
39
33
  ```
40
34
 
41
- ### 2. Use Components
35
+ ### 2. Use components
42
36
 
43
37
  ```tsx
44
- import { Button } from "shadcn-ui-react";
38
+ import { Button } from 'shadcn-ui-react';
45
39
 
46
40
  export default function App() {
47
41
  return (
48
- <div className="p-4">
49
- <Button variant="default">Click me</Button>
50
- <Button loading className="ml-2">
51
- Loading
42
+ <div className="p-6">
43
+ <Button>Save</Button>
44
+ <Button variant="outline" className="ml-2">
45
+ Cancel
52
46
  </Button>
53
47
  </div>
54
48
  );
@@ -57,121 +51,108 @@ export default function App() {
57
51
 
58
52
  ---
59
53
 
60
- ## ๐Ÿงฑ Available Components
61
-
62
- ### ๐Ÿ“ฆ UI Primitives
63
-
64
- - `Accordion`
65
- - `Alert`
66
- - `Avatar`
67
- - `Badge`
68
- - `Breadcrumb`
69
- - `Button`
70
- - `Calendar`
71
- - `Card`
72
- - `Carousel`
73
- - `Checkbox`
74
- - `Collapsible`
75
- - `Command`
76
- - `ContextMenu`
77
- - `Dialog`
78
- - `Drawer`
79
- - `DropdownMenu`
80
- - `Dropzone`
81
- - `HoverCard`
82
- - `Input`
83
- - `InputOtp`
84
- - `Label`
85
- - `Menubar`
86
- - `Modal`
87
- - `NavigationMenu`
88
- - `Pagination`
89
- - `Popover`
90
- - `Progress`
91
- - `RadioGroup`
92
- - `Resizable`
93
- - `ScrollArea`
94
- - `Select`
95
- - `Separator`
96
- - `Sheet`
97
- - `Skeleton`
98
- - `Slider`
99
- - `Sonner`
100
- - `Switch`
101
- - `Table`
102
- - `Tabs`
103
- - `Textarea`
104
- - `Toast`
105
- - `Toggle`
106
- - `ToggleGroup`
107
- - `Tooltip`
54
+ ## ๐Ÿญ Production scripts
108
55
 
109
- ---
56
+ ```bash
57
+ npm run typecheck
58
+ npm run test
59
+ npm run build
60
+ ```
110
61
 
111
- ### ๐Ÿง  Forms
62
+ The package is configured as an ESM library and exports compiled CSS:
112
63
 
113
- - `Form`
114
- - `FormField`
64
+ ```tsx
65
+ import 'shadcn-ui-react/dist/style.css';
66
+ import { Button, FormField, DataTable } from 'shadcn-ui-react';
67
+ ```
115
68
 
116
69
  ---
117
70
 
118
- ### ๐Ÿ” Inputs
71
+ ## ๐Ÿงฑ Available components
119
72
 
120
- - `SearchInput`
73
+ ### UI primitives
121
74
 
122
- ---
75
+ `Accordion`, `Alert`, `AlertDialog`, `Avatar`, `Badge`, `Breadcrumb`, `Button`, `IconButton`, `Calendar`, `Card`, `Carousel`, `Checkbox`, `Collapsible`, `Command`, `ContextMenu`, `Dialog`, `Drawer`, `DropdownMenu`, `HoverCard`, `Input`, `InputOtp`, `Label`, `Menubar`, `Modal`, `NavigationMenu`, `Pagination`, `Popover`, `Progress`, `RadioGroup`, `Resizable`, `ScrollArea`, `Select`, `Separator`, `Sheet`, `Skeleton`, `Slider`, `Sonner`, `Switch`, `Table`, `Tabs`, `Textarea`, `Toast`, `Toaster`, `Toggle`, `ToggleGroup`, `Tooltip`.
123
76
 
124
- ### ๐Ÿงฉ Utilities
77
+ ### Form helpers
125
78
 
126
- - `UseToast`
127
- - `Icons`
79
+ `Form`, `FormField`, `FormSelect`, `FormCheckbox`, `FormItem`, `FormControl`, `FormLabel`, `FormDescription`, `FormMessage`, `UiInput`, `UiSelect`, `UiCheckbox`.
128
80
 
129
- ---
81
+ ### Shared components
82
+
83
+ `AlertModal`, `Breadcrumbs`, `DataTable`, `DataTableSkeleton`, `Dropzone`, `FileUpload`, `Heading`, `PageHead`, `PaginationSection`, `SearchInput`, `SearchableSelect`.
130
84
 
131
- ### ๐Ÿ›  Shared Components
85
+ ### Utilities
132
86
 
133
- - `AlertModal`
134
- - `Breadcrumbs`
135
- - `DataTable` (with pagination)
136
- - `DataTableSkeleton`
137
- - `FileUpload`
138
- - `Heading`
139
- - `PageHead`
140
- - `PaginationSection`
87
+ `cn`, `useToast`, `toast`, `Icons`, `useSidebar`.
141
88
 
142
89
  ---
143
90
 
144
- ## โœจ Examples
91
+ # โœจ Demos
92
+
93
+ All demos use neutral sample data so they can be published in public documentation without referencing any private product, client, tenant, store, or internal business flow.
145
94
 
146
- ### ๐Ÿ”˜ Button
95
+ ## 1. Button
147
96
 
148
97
  ```tsx
149
- <Button variant="default">Default</Button>
150
- <Button variant="outline">Outline</Button>
151
- <Button loading>Loading...</Button>
98
+ import { Button } from 'shadcn-ui-react';
99
+
100
+ export function ButtonDemo() {
101
+ return (
102
+ <div className="flex flex-wrap gap-3">
103
+ <Button>Default</Button>
104
+ <Button variant="outline">Outline</Button>
105
+ <Button variant="secondary">Secondary</Button>
106
+ <Button variant="destructive">Delete</Button>
107
+ <Button variant="soft">Soft</Button>
108
+ <Button variant="gradient">Gradient</Button>
109
+ <Button loading>Loading</Button>
110
+ </div>
111
+ );
112
+ }
152
113
  ```
153
114
 
154
- ---
115
+ ## 2. IconButton
155
116
 
156
- ### โœ๏ธ UiInput
117
+ ```tsx
118
+ import { Pencil, Trash2 } from 'lucide-react';
119
+ import { IconButton } from 'shadcn-ui-react';
120
+
121
+ export function IconButtonDemo() {
122
+ return (
123
+ <div className="flex gap-2">
124
+ <IconButton aria-label="Edit item" variant="outline">
125
+ <Pencil />
126
+ </IconButton>
127
+
128
+ <IconButton aria-label="Delete item" variant="softDestructive">
129
+ <Trash2 />
130
+ </IconButton>
131
+ </div>
132
+ );
133
+ }
134
+ ```
135
+
136
+ ## 3. UiInput
157
137
 
158
138
  ```tsx
159
- import { UiInput } from "shadcn-ui-react";
139
+ import * as React from 'react';
140
+ import { UiInput } from 'shadcn-ui-react';
160
141
 
161
- export default function Example() {
162
- const [name, setName] = React.useState("");
142
+ export function UiInputDemo() {
143
+ const [name, setName] = React.useState('');
163
144
 
164
145
  return (
165
146
  <UiInput
166
147
  htmlFormItemId="name"
167
- variant="outline"
168
148
  label="Name"
169
- placeholder="Enter name"
149
+ requiredLabel
150
+ placeholder="Enter your name"
170
151
  value={name}
171
- onChange={(e) => setName(e.target.value)}
152
+ onChange={(event) => setName(event.target.value)}
172
153
  errorMessage={
173
154
  name.length > 0 && name.trim().length < 2
174
- ? "Min 2 characters"
155
+ ? 'Minimum 2 characters'
175
156
  : undefined
176
157
  }
177
158
  />
@@ -179,330 +160,463 @@ export default function Example() {
179
160
  }
180
161
  ```
181
162
 
182
- ---
183
-
184
- ### ๐Ÿงพ UiSelect
185
-
186
- Using `items`:
163
+ ## 4. UiSelect
187
164
 
188
165
  ```tsx
189
- import { UiSelect } from "shadcn-ui-react";
166
+ import * as React from 'react';
167
+ import { UiSelect } from 'shadcn-ui-react';
190
168
 
191
- export default function LanguageSelectItemsDemo() {
192
- const [lang, setLang] = React.useState("");
169
+ export function UiSelectDemo() {
170
+ const [language, setLanguage] = React.useState('');
193
171
 
194
172
  return (
195
173
  <UiSelect
196
174
  htmlFormItemId="language"
197
175
  label="Language"
198
176
  placeholder="Select a language"
199
- value={lang}
200
- onChange={setLang}
201
- variant="outline"
202
- size="md"
177
+ value={language}
178
+ onChange={setLanguage}
203
179
  items={[
204
- { label: "Spanish", value: "es" },
205
- { label: "English", value: "en" },
206
- { label: "Portuguese", value: "pt" },
207
- { label: "Chinese", value: "zh" },
208
- { label: "Japanese", value: "ja" },
209
- { label: "Korean (disabled)", value: "ko", disabled: true },
180
+ { label: 'English', value: 'en' },
181
+ { label: 'Spanish', value: 'es' },
182
+ { label: 'Portuguese', value: 'pt' },
183
+ { label: 'French', value: 'fr' },
184
+ { label: 'Japanese', value: 'ja', disabled: true }
210
185
  ]}
211
- errorMessage={!lang ? "Please select a language." : undefined}
186
+ errorMessage={!language ? 'Select a language.' : undefined}
212
187
  />
213
188
  );
214
189
  }
215
190
  ```
216
191
 
217
- Using `children`:
192
+ ## 5. UiCheckbox
218
193
 
219
194
  ```tsx
220
- import {
221
- UiSelect,
222
- SelectGroup,
223
- SelectItem,
224
- SelectLabel,
225
- SelectSeparator,
226
- } from "shadcn-ui-react";
195
+ import * as React from 'react';
196
+ import { UiCheckbox } from 'shadcn-ui-react';
227
197
 
228
- export default function LanguageSelectChildrenDemo() {
229
- const [lang, setLang] = React.useState("");
198
+ export function UiCheckboxDemo() {
199
+ const [accepted, setAccepted] = React.useState(false);
230
200
 
231
201
  return (
232
- <UiSelect
233
- htmlFormItemId="language_children"
234
- label="Language (grouped)"
235
- placeholder="Select a language"
236
- value={lang}
237
- onChange={setLang}
238
- variant="outline"
239
- size="md"
240
- errorMessage={!lang ? "Please select a language." : undefined}
241
- >
242
- <SelectGroup>
243
- <SelectLabel>Common</SelectLabel>
244
- <SelectItem value="es">Spanish</SelectItem>
245
- <SelectItem value="en">English</SelectItem>
246
- <SelectItem value="pt">Portuguese</SelectItem>
247
-
248
- <SelectSeparator />
249
-
250
- <SelectLabel>Asia</SelectLabel>
251
- <SelectItem value="zh">Chinese</SelectItem>
252
- <SelectItem value="ja">Japanese</SelectItem>
253
- <SelectItem value="ko" disabled>
254
- Korean (disabled)
255
- </SelectItem>
256
- </SelectGroup>
257
- </UiSelect>
202
+ <UiCheckbox
203
+ htmlFormItemId="terms"
204
+ checked={accepted}
205
+ onCheckedChange={(value) => setAccepted(value === true)}
206
+ label="I accept the terms and conditions"
207
+ description="You can change this option later from your account settings."
208
+ requiredLabel
209
+ errorMessage={!accepted ? 'You must accept the terms.' : undefined}
210
+ />
258
211
  );
259
212
  }
260
213
  ```
261
214
 
262
- ---
263
-
264
- ### ๐Ÿช„ Accordion
215
+ ## 6. React Hook Form + Zod
265
216
 
266
217
  ```tsx
267
- <Accordion type="single" collapsible>
268
- <AccordionItem value="item-1">
269
- <AccordionTrigger>Click me</AccordionTrigger>
270
- <AccordionContent>Hidden content revealed!</AccordionContent>
271
- </AccordionItem>
272
- </Accordion>
273
- ```
274
-
275
- ---
276
-
277
- ### โš ๏ธ Alert
278
-
279
- ```tsx
280
- <Alert>This is an alert message</Alert>
281
- ```
282
-
283
- ---
284
-
285
- ### ๐Ÿงพ Form
286
-
287
- ```tsx
288
- import { zodResolver } from "@hookform/resolvers/zod";
289
- import { useForm } from "react-hook-form";
218
+ import { zodResolver } from '@hookform/resolvers/zod';
219
+ import { useForm } from 'react-hook-form';
220
+ import { z } from 'zod';
290
221
  import {
291
222
  Button,
292
223
  Form,
293
- FormControl,
224
+ FormCheckbox,
294
225
  FormField,
295
- FormItem,
296
- FormLabel,
297
- FormMessage,
298
- Input,
299
- } from "shadcn-ui-react";
300
- import * as z from "zod";
301
-
302
- const formSchema = z.object({
303
- email: z.email({
304
- pattern: z.regexes.email,
305
- error: "Email is required",
306
- }),
307
- password: z
308
- .string()
309
- .min(8, { message: "Password must be at least 8 characters" }),
310
- gender: z.enum(["male", "female"]).optional().nullable(),
226
+ FormSelect
227
+ } from 'shadcn-ui-react';
228
+
229
+ const schema = z.object({
230
+ name: z.string().min(2, 'Minimum 2 characters'),
231
+ email: z.string().email('Invalid email'),
232
+ password: z.string().min(8, 'Minimum 8 characters'),
233
+ role: z.enum(['owner', 'editor', 'viewer']),
234
+ accepted: z.boolean().refine(Boolean, 'You must accept the terms')
311
235
  });
312
236
 
313
- type UserFormValue = z.infer<typeof formSchema>;
314
-
315
- export default function UserAuthForm() {
316
- const defaultValues = {
317
- email: "demo@domain.com",
318
- };
319
-
320
- const form = useForm<UserFormValue>({
321
- resolver: zodResolver(formSchema),
322
- defaultValues,
237
+ type FormValues = z.infer<typeof schema>;
238
+
239
+ export function FormDemo() {
240
+ const form = useForm<FormValues>({
241
+ resolver: zodResolver(schema),
242
+ defaultValues: {
243
+ name: '',
244
+ email: '',
245
+ password: '',
246
+ role: 'viewer',
247
+ accepted: false
248
+ }
323
249
  });
324
250
 
325
- const onSubmit = async (data: UserFormValue) => {};
251
+ const onSubmit = (values: FormValues) => {
252
+ console.log(values);
253
+ };
326
254
 
327
255
  return (
328
- <Form methods={form} onSubmit={onSubmit}>
256
+ <Form methods={form} onSubmit={onSubmit} formProps={{ className: 'space-y-4' }}>
257
+ <FormField
258
+ control={form.control}
259
+ name="name"
260
+ label="Name"
261
+ placeholder="Jane Doe"
262
+ requiredLabel
263
+ />
264
+
329
265
  <FormField
330
266
  control={form.control}
331
267
  name="email"
332
- type="email"
333
- placeholder="Enter your email"
334
268
  label="Email"
335
- variant="outline" // outline | soft | ghost | filled | flushed | unstyled | link
336
- className="" // your style
269
+ type="email"
270
+ placeholder="jane@example.com"
271
+ requiredLabel
337
272
  />
338
273
 
339
274
  <FormField
340
275
  control={form.control}
341
276
  name="password"
342
- type="password"
343
- placeholder="Enter password"
344
277
  label="Password"
345
- variant="outline" // outline | soft | ghost | filled | flushed | unstyled | link
346
- className="" // your style
278
+ type="password"
279
+ placeholder="โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข"
280
+ requiredLabel
347
281
  />
348
282
 
349
283
  <FormSelect
350
284
  control={form.control}
351
- name="gender"
352
- label="Gender"
353
- variant="outline" // outline | soft | ghost | filled | flushed | unstyled | link
354
- className="" // your style
355
- items={[
356
- { label: "Male", value: "male" },
357
- { label: "Female", value: "female" },
285
+ name="role"
286
+ label="Role"
287
+ placeholder="Select a role"
288
+ options={[
289
+ { label: 'Owner', value: 'owner' },
290
+ { label: 'Editor', value: 'editor' },
291
+ { label: 'Viewer', value: 'viewer' }
358
292
  ]}
359
293
  />
360
294
 
361
- <Button className="ml-auto w-full" type="submit">
362
- Log In
295
+ <FormCheckbox
296
+ control={form.control}
297
+ name="accepted"
298
+ label="I accept the terms"
299
+ description="This field is required to continue."
300
+ />
301
+
302
+ <Button type="submit" className="w-full">
303
+ Create account
363
304
  </Button>
364
305
  </Form>
365
306
  );
366
307
  }
367
308
  ```
368
309
 
369
- ---
310
+ ## 7. SearchableSelect standalone
311
+
312
+ ```tsx
313
+ import * as React from 'react';
314
+ import { SearchableSelect } from 'shadcn-ui-react';
315
+
316
+ export function SearchableSelectDemo() {
317
+ const [fruit, setFruit] = React.useState('');
318
+
319
+ return (
320
+ <SearchableSelect
321
+ value={fruit}
322
+ onValueChange={setFruit}
323
+ placeholder="Select a fruit"
324
+ searchPlaceholder="Search fruit..."
325
+ items={[
326
+ { label: 'Apple', value: 'apple', keywords: 'fruit red green sweet' },
327
+ { label: 'Banana', value: 'banana', keywords: 'fruit yellow tropical' },
328
+ { label: 'Orange', value: 'orange', keywords: 'fruit citrus vitamin c' },
329
+ { label: 'Strawberry', value: 'strawberry', keywords: 'fruit berry red sweet' },
330
+ { label: 'Pineapple', value: 'pineapple', keywords: 'fruit tropical sweet' }
331
+ ]}
332
+ />
333
+ );
334
+ }
335
+ ```
336
+
337
+ ## 8. Accordion
338
+
339
+ ```tsx
340
+ import {
341
+ Accordion,
342
+ AccordionContent,
343
+ AccordionItem,
344
+ AccordionTrigger
345
+ } from 'shadcn-ui-react';
346
+
347
+ export function AccordionDemo() {
348
+ return (
349
+ <Accordion type="single" collapsible className="w-full">
350
+ <AccordionItem value="item-1">
351
+ <AccordionTrigger>What is included?</AccordionTrigger>
352
+ <AccordionContent>
353
+ Accessible components, Tailwind styling, and reusable form helpers.
354
+ </AccordionContent>
355
+ </AccordionItem>
356
+ </Accordion>
357
+ );
358
+ }
359
+ ```
360
+
361
+ ## 9. Dialog
362
+
363
+ ```tsx
364
+ import {
365
+ Button,
366
+ Dialog,
367
+ DialogContent,
368
+ DialogHeader,
369
+ DialogTitle,
370
+ DialogTrigger
371
+ } from 'shadcn-ui-react';
372
+
373
+ export function DialogDemo() {
374
+ return (
375
+ <Dialog>
376
+ <DialogTrigger asChild>
377
+ <Button>Open dialog</Button>
378
+ </DialogTrigger>
379
+
380
+ <DialogContent>
381
+ <DialogHeader>
382
+ <DialogTitle>Create note</DialogTitle>
383
+ </DialogHeader>
384
+
385
+ <p className="text-sm text-muted-foreground">
386
+ Use this area for a form, message, or confirmation content.
387
+ </p>
388
+ </DialogContent>
389
+ </Dialog>
390
+ );
391
+ }
392
+ ```
393
+
394
+ ## 10. AlertModal
395
+
396
+ ```tsx
397
+ import * as React from 'react';
398
+ import { AlertModal, Button } from 'shadcn-ui-react';
399
+
400
+ export function AlertModalDemo() {
401
+ const [open, setOpen] = React.useState(false);
402
+
403
+ return (
404
+ <>
405
+ <Button variant="destructive" onClick={() => setOpen(true)}>
406
+ Delete item
407
+ </Button>
408
+
409
+ <AlertModal
410
+ isOpen={open}
411
+ onClose={() => setOpen(false)}
412
+ onConfirm={() => setOpen(false)}
413
+ loading={false}
414
+ />
415
+ </>
416
+ );
417
+ }
418
+ ```
370
419
 
371
- ### ๐Ÿ“Š DataTable
420
+ ## 11. DataTable
372
421
 
373
422
  ```tsx
374
- import React, { useMemo, useState } from "react";
375
- import type { ColumnDef } from "@tanstack/react-table";
376
- import { DataTable } from "shadcn-ui-react";
423
+ import * as React from 'react';
424
+ import type { ColumnDef } from '@tanstack/react-table';
425
+ import { DataTable } from 'shadcn-ui-react';
377
426
 
378
- type User = {
427
+ type Project = {
379
428
  id: number;
380
429
  name: string;
381
- email: string;
382
- role: "Admin" | "Editor" | "Viewer";
430
+ owner: string;
431
+ status: 'Active' | 'Paused' | 'Completed';
383
432
  };
384
433
 
385
- const columns: ColumnDef<User, any>[] = [
386
- { accessorKey: "id", header: "ID" },
387
- {
388
- accessorKey: "name",
389
- header: "Name",
390
- cell: ({ row }) => (
391
- <div className="flex items-center gap-2">
392
- <div className="h-2 w-2 rounded-full bg-primary" />
393
- <span className="font-medium">{row.original.name}</span>
394
- </div>
395
- ),
396
- },
397
- { accessorKey: "email", header: "Email" },
398
- {
399
- accessorKey: "role",
400
- header: "Role",
401
- cell: ({ row }) => (
402
- <span className="inline-flex items-center rounded-full border px-2 py-0.5 text-xs">
403
- {row.original.role}
404
- </span>
405
- ),
406
- },
434
+ const columns: ColumnDef<Project>[] = [
435
+ { accessorKey: 'id', header: 'ID' },
436
+ { accessorKey: 'name', header: 'Project' },
437
+ { accessorKey: 'owner', header: 'Owner' },
438
+ { accessorKey: 'status', header: 'Status' }
407
439
  ];
408
440
 
409
- const data: User[] = [
410
- { id: 1, name: "John Doe", email: "john@example.com", role: "Admin" },
411
- { id: 2, name: "Jane Smith", email: "jane@example.com", role: "Editor" },
412
- { id: 3, name: "Sam Johnson", email: "sam@example.com", role: "Viewer" },
413
- { id: 4, name: "Alice Brown", email: "alice@example.com", role: "Editor" },
414
- { id: 5, name: "Bob White", email: "bob@example.com", role: "Viewer" },
415
- { id: 6, name: "Charlie Black", email: "charlie@example.com", role: "Admin" },
416
- { id: 7, name: "Diana Green", email: "diana@example.com", role: "Viewer" },
417
- { id: 8, name: "Eve Blue", email: "eve@example.com", role: "Editor" },
418
- { id: 9, name: "Frank Yellow", email: "frank@example.com", role: "Viewer" },
419
- { id: 10, name: "Grace Red", email: "grace@example.com", role: "Admin" },
441
+ const data: Project[] = [
442
+ { id: 1, name: 'Website Redesign', owner: 'Jane Cooper', status: 'Active' },
443
+ { id: 2, name: 'Mobile App', owner: 'Wade Warren', status: 'Paused' },
444
+ { id: 3, name: 'Design System', owner: 'Esther Howard', status: 'Completed' }
420
445
  ];
421
446
 
422
- const Example = () => {
423
- const [page, setPage] = useState(1);
424
- const [perPage, setPerPage] = useState(5);
447
+ export function DataTableDemo() {
448
+ const [page, setPage] = React.useState(1);
449
+ const [perPage, setPerPage] = React.useState(5);
450
+ const pageCount = Math.ceil(data.length / perPage);
451
+ const visibleRows = data.slice((page - 1) * perPage, page * perPage);
452
+
453
+ return (
454
+ <DataTable
455
+ columns={columns}
456
+ data={visibleRows}
457
+ page={page}
458
+ perPage={perPage}
459
+ pageCount={pageCount}
460
+ totalRows={data.length}
461
+ onPageChange={setPage}
462
+ onPageSizeChange={(size) => {
463
+ setPerPage(size);
464
+ setPage(1);
465
+ }}
466
+ template="neo"
467
+ accent="primary"
468
+ stickyHeader
469
+ animate
470
+ heightClassName="h-[420px]"
471
+ />
472
+ );
473
+ }
474
+ ```
475
+
476
+ ## 12. SearchInput
425
477
 
426
- const pageCount = useMemo(() => Math.ceil(data.length / perPage), [perPage]);
478
+ ```tsx
479
+ import * as React from 'react';
480
+ import { SearchInput } from 'shadcn-ui-react';
427
481
 
428
- const paginatedData = useMemo(() => {
429
- const start = (page - 1) * perPage;
430
- const end = page * perPage;
431
- return data.slice(start, end);
432
- }, [page, perPage]);
482
+ export function SearchInputDemo() {
483
+ const [search, setSearch] = React.useState('');
433
484
 
434
485
  return (
435
- <div className="space-y-4">
436
- <div className="space-y-1">
437
- <h1 className="text-xl font-bold">DataTable v2</h1>
438
- <p className="text-sm text-muted-foreground">
439
- Manual pagination + templates + sticky header + accent
440
- </p>
441
- </div>
442
-
443
- <DataTable
444
- columns={columns}
445
- data={paginatedData}
446
- pageCount={pageCount}
447
- page={page}
448
- perPage={perPage}
449
- onPageChange={setPage}
450
- onPageSizeChange={(size) => {
451
- setPerPage(size);
452
- setPage(1);
453
- }}
454
- totalRows={data.length}
455
- isRowsSelected={false}
456
- rowPerPageLabel="Rows per page"
457
- pageLabel="Page"
458
- ofLabel="of"
459
- rowsSelectedLabel="rows selected"
460
- emptyData={<div className="py-10 text-center">No data available</div>}
461
-
462
- // โœจ NEW (v0.6.6)
463
- template="neo" // neo | glass | compact | minimal | clean | elevated | grid | cards
464
- accent="primary" // primary | emerald | indigo | rose | amber | zinc
465
- stickyHeader={true}
466
- headerScroll={false}
467
- animate={true}
468
- heightClassName="h-[420px]" // Important: Define the height for the ScrollArea to work.
469
-
470
- onClick={(row) => {
471
- // demo: click in row
472
- console.log("Row clicked:", row);
473
- }}
486
+ <SearchInput
487
+ value={search}
488
+ placeholder="Search documents..."
489
+ debounceTime={400}
490
+ onSearch={(value) => setSearch(value ?? '')}
491
+ />
492
+ );
493
+ }
494
+ ```
474
495
 
475
- // optional
476
- classNames={{
477
- // root: "border-primary/20",
478
- // th: "text-[10px]",
479
- // td: "py-2",
496
+ ## 13. FileUpload / Dropzone
497
+
498
+ ```tsx
499
+ import { Dropzone } from 'shadcn-ui-react';
500
+
501
+ export function DropzoneDemo() {
502
+ return (
503
+ <Dropzone
504
+ onDrop={(files) => {
505
+ console.log(files);
506
+ }}
507
+ />
508
+ );
509
+ }
510
+ ```
511
+
512
+ ## 14. Toast
513
+
514
+ ```tsx
515
+ import { Button, Toaster, useToast } from 'shadcn-ui-react';
516
+
517
+ export function ToastDemo() {
518
+ const { toast } = useToast();
519
+
520
+ return (
521
+ <>
522
+ <Button
523
+ onClick={() => {
524
+ toast({
525
+ title: 'Saved',
526
+ description: 'Your changes were saved successfully.'
527
+ });
480
528
  }}
481
- />
482
- </div>
529
+ >
530
+ Show toast
531
+ </Button>
532
+
533
+ <Toaster />
534
+ </>
483
535
  );
484
- };
536
+ }
537
+ ```
538
+
539
+ ## 15. Sonner
540
+
541
+ ```tsx
542
+ import { toast } from 'sonner';
543
+ import { Button, ToasterSonner } from 'shadcn-ui-react';
485
544
 
486
- export default Example;
545
+ export function SonnerDemo() {
546
+ return (
547
+ <>
548
+ <Button onClick={() => toast.success('Operation completed')}>
549
+ Notify
550
+ </Button>
551
+ <ToasterSonner />
552
+ </>
553
+ );
554
+ }
487
555
  ```
488
556
 
489
- ---
557
+ ## 16. Card + Badge
490
558
 
491
- ## ๐Ÿ’… Theming & Styling
559
+ ```tsx
560
+ import {
561
+ Badge,
562
+ Card,
563
+ CardContent,
564
+ CardHeader,
565
+ CardTitle
566
+ } from 'shadcn-ui-react';
567
+
568
+ export function CardDemo() {
569
+ return (
570
+ <Card className="max-w-md">
571
+ <CardHeader>
572
+ <CardTitle className="flex items-center justify-between">
573
+ Starter Kit
574
+ <Badge>New</Badge>
575
+ </CardTitle>
576
+ </CardHeader>
577
+ <CardContent className="text-sm text-muted-foreground">
578
+ A simple card example with a title, badge, and supporting description.
579
+ </CardContent>
580
+ </Card>
581
+ );
582
+ }
583
+ ```
492
584
 
493
- - Built with **Tailwind CSS**
494
- - Override styles using your own CSS/Tailwind classes
495
- - Component APIs are designed to be extensible
585
+ ## 17. Tabs
586
+
587
+ ```tsx
588
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from 'shadcn-ui-react';
589
+
590
+ export function TabsDemo() {
591
+ return (
592
+ <Tabs defaultValue="overview">
593
+ <TabsList>
594
+ <TabsTrigger value="overview">Overview</TabsTrigger>
595
+ <TabsTrigger value="settings">Settings</TabsTrigger>
596
+ </TabsList>
597
+ <TabsContent value="overview">General information goes here.</TabsContent>
598
+ <TabsContent value="settings">Preferences and configuration go here.</TabsContent>
599
+ </Tabs>
600
+ );
601
+ }
602
+ ```
496
603
 
497
604
  ---
498
605
 
499
- ## ๐Ÿงช Example Projects
606
+ ## ๐Ÿ’… Theming
607
+
608
+ This package uses Tailwind CSS variables. You can override the default theme from your app CSS:
500
609
 
501
- - Vite + React + Tailwind
502
- - Next.js + TypeScript + shadcn-ui-react
610
+ ```css
611
+ :root {
612
+ --primary: oklch(0.45 0.18 260);
613
+ --primary-foreground: oklch(0.98 0 0);
614
+ --radius: 0.75rem;
615
+ }
616
+ ```
503
617
 
504
618
  ---
505
619
 
506
620
  ## ๐Ÿ“ License
507
621
 
508
- Licensed under the [MIT license](https://github.com/blencm/shadcn-ui-react/blob/main/LICENSE).
622
+ MIT.