shadcn-ui-react 0.7.5 → 0.7.7

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,6 +1,6 @@
1
1
  # 🧩 shadcn-ui-react
2
2
 
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.
3
+ A production-ready React UI library that packages `shadcn/ui` components into a single reusable library, with Tailwind CSS styling, Radix UI primitives, form helpers, and ready-to-use demos.
4
4
 
5
5
  ---
6
6
 
@@ -22,11 +22,11 @@ npm install react react-dom
22
22
 
23
23
  ---
24
24
 
25
- ## 🚀 Getting Started
25
+ ## 🚀 Getting started
26
26
 
27
- ### 1. Import global styles
27
+ ### 1. Import the global styles
28
28
 
29
- In your `main.tsx`, `App.tsx`, or layout file:
29
+ Import the package stylesheet once in your app entry file, layout, or root component.
30
30
 
31
31
  ```tsx
32
32
  import 'shadcn-ui-react/dist/style.css';
@@ -39,11 +39,9 @@ import { Button } from 'shadcn-ui-react';
39
39
 
40
40
  export default function App() {
41
41
  return (
42
- <div className="p-6">
42
+ <div className="flex gap-3 p-6">
43
43
  <Button>Save</Button>
44
- <Button variant="outline" className="ml-2">
45
- Cancel
46
- </Button>
44
+ <Button variant="outline">Cancel</Button>
47
45
  </div>
48
46
  );
49
47
  }
@@ -51,46 +49,103 @@ export default function App() {
51
49
 
52
50
  ---
53
51
 
54
- ## 🏭 Production scripts
55
-
56
- ```bash
57
- npm run typecheck
58
- npm run test
59
- npm run build
60
- ```
61
-
62
- The package is configured as an ESM library and exports compiled CSS:
63
-
64
- ```tsx
65
- import 'shadcn-ui-react/dist/style.css';
66
- import { Button, FormField, DataTable } from 'shadcn-ui-react';
67
- ```
52
+ ## 🧱 Available Components
53
+
54
+ ### 📦 UI Primitives
55
+
56
+ - `Accordion`
57
+ - `Alert`
58
+ - `AlertDialog`
59
+ - `Avatar`
60
+ - `Badge`
61
+ - `Breadcrumb`
62
+ - `Button`
63
+ - `IconButton`
64
+ - `Calendar`
65
+ - `Card`
66
+ - `Carousel`
67
+ - `Checkbox`
68
+ - `Collapsible`
69
+ - `Command`
70
+ - `ContextMenu`
71
+ - `Dialog`
72
+ - `Drawer`
73
+ - `DropdownMenu`
74
+ - `HoverCard`
75
+ - `Input`
76
+ - `InputOtp`
77
+ - `Label`
78
+ - `Menubar`
79
+ - `Modal`
80
+ - `NavigationMenu`
81
+ - `Pagination`
82
+ - `Popover`
83
+ - `Progress`
84
+ - `RadioGroup`
85
+ - `Resizable`
86
+ - `ScrollArea`
87
+ - `Select`
88
+ - `Separator`
89
+ - `Sheet`
90
+ - `Skeleton`
91
+ - `Slider`
92
+ - `Sonner`
93
+ - `Switch`
94
+ - `Table`
95
+ - `Tabs`
96
+ - `Textarea`
97
+ - `Toast`
98
+ - `Toaster`
99
+ - `Toggle`
100
+ - `ToggleGroup`
101
+ - `Tooltip`
68
102
 
69
103
  ---
70
104
 
71
- ## 🧱 Available components
72
-
73
- ### UI primitives
105
+ ### 🧠 Forms
106
+
107
+ - `Form`
108
+ - `FormField`
109
+ - `FormSelect`
110
+ - `FormCheckbox`
111
+ - `FormItem`
112
+ - `FormControl`
113
+ - `FormLabel`
114
+ - `FormDescription`
115
+ - `FormMessage`
116
+ - `UiInput`
117
+ - `UiSelect`
118
+ - `UiCheckbox`
74
119
 
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`.
76
-
77
- ### Form helpers
120
+ ---
78
121
 
79
- `Form`, `FormField`, `FormSelect`, `FormCheckbox`, `FormItem`, `FormControl`, `FormLabel`, `FormDescription`, `FormMessage`, `UiInput`, `UiSelect`, `UiCheckbox`.
122
+ ### 🧩 Shared Components
80
123
 
81
- ### Shared components
124
+ - `AlertModal`
125
+ - `Breadcrumbs`
126
+ - `DataTable`
127
+ - `DataTableSkeleton`
128
+ - `Dropzone`
129
+ - `FileUpload`
130
+ - `Heading`
131
+ - `PageHead`
132
+ - `PaginationSection`
133
+ - `SearchInput`
134
+ - `SearchableSelect`
82
135
 
83
- `AlertModal`, `Breadcrumbs`, `DataTable`, `DataTableSkeleton`, `Dropzone`, `FileUpload`, `Heading`, `PageHead`, `PaginationSection`, `SearchInput`, `SearchableSelect`.
136
+ ---
84
137
 
85
- ### Utilities
138
+ ### 🛠️ Utilities
86
139
 
87
- `cn`, `useToast`, `toast`, `Icons`, `useSidebar`.
140
+ - `cn`
141
+ - `useToast`
142
+ - `toast`
143
+ - `Icons`
144
+ - `useSidebar`
88
145
 
89
146
  ---
90
147
 
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.
148
+ ## ✨ Demos
94
149
 
95
150
  ## 1. Button
96
151
 
@@ -228,7 +283,7 @@ import {
228
283
 
229
284
  const schema = z.object({
230
285
  name: z.string().min(2, 'Minimum 2 characters'),
231
- email: z.string().email('Invalid email'),
286
+ email: z.string().email('Invalid email address'),
232
287
  password: z.string().min(8, 'Minimum 8 characters'),
233
288
  role: z.enum(['owner', 'editor', 'viewer']),
234
289
  accepted: z.boolean().refine(Boolean, 'You must accept the terms')
@@ -253,7 +308,11 @@ export function FormDemo() {
253
308
  };
254
309
 
255
310
  return (
256
- <Form methods={form} onSubmit={onSubmit} formProps={{ className: 'space-y-4' }}>
311
+ <Form
312
+ methods={form}
313
+ onSubmit={onSubmit}
314
+ formProps={{ className: 'space-y-4' }}
315
+ >
257
316
  <FormField
258
317
  control={form.control}
259
318
  name="name"
@@ -326,8 +385,16 @@ export function SearchableSelectDemo() {
326
385
  { label: 'Apple', value: 'apple', keywords: 'fruit red green sweet' },
327
386
  { label: 'Banana', value: 'banana', keywords: 'fruit yellow tropical' },
328
387
  { 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' }
388
+ {
389
+ label: 'Strawberry',
390
+ value: 'strawberry',
391
+ keywords: 'fruit berry red sweet'
392
+ },
393
+ {
394
+ label: 'Pineapple',
395
+ value: 'pineapple',
396
+ keywords: 'fruit tropical sweet'
397
+ }
331
398
  ]}
332
399
  />
333
400
  );
@@ -350,7 +417,7 @@ export function AccordionDemo() {
350
417
  <AccordionItem value="item-1">
351
418
  <AccordionTrigger>What is included?</AccordionTrigger>
352
419
  <AccordionContent>
353
- Accessible components, Tailwind styling, and reusable form helpers.
420
+ Accessible components, Tailwind CSS styling, and reusable form helpers.
354
421
  </AccordionContent>
355
422
  </AccordionItem>
356
423
  </Accordion>
@@ -447,6 +514,7 @@ const data: Project[] = [
447
514
  export function DataTableDemo() {
448
515
  const [page, setPage] = React.useState(1);
449
516
  const [perPage, setPerPage] = React.useState(5);
517
+
450
518
  const pageCount = Math.ceil(data.length / perPage);
451
519
  const visibleRows = data.slice((page - 1) * perPage, page * perPage);
452
520
 
@@ -540,7 +608,7 @@ export function ToastDemo() {
540
608
 
541
609
  ```tsx
542
610
  import { toast } from 'sonner';
543
- import { Button, ToasterSonner } from 'shadcn-ui-react';
611
+ import { Button, Sonner } from 'shadcn-ui-react';
544
612
 
545
613
  export function SonnerDemo() {
546
614
  return (
@@ -548,7 +616,8 @@ export function SonnerDemo() {
548
616
  <Button onClick={() => toast.success('Operation completed')}>
549
617
  Notify
550
618
  </Button>
551
- <ToasterSonner />
619
+
620
+ <Sonner />
552
621
  </>
553
622
  );
554
623
  }
@@ -569,11 +638,12 @@ export function CardDemo() {
569
638
  return (
570
639
  <Card className="max-w-md">
571
640
  <CardHeader>
572
- <CardTitle className="flex items-center justify-between">
641
+ <CardTitle className="flex items-center justify-between gap-4">
573
642
  Starter Kit
574
643
  <Badge>New</Badge>
575
644
  </CardTitle>
576
645
  </CardHeader>
646
+
577
647
  <CardContent className="text-sm text-muted-foreground">
578
648
  A simple card example with a title, badge, and supporting description.
579
649
  </CardContent>
@@ -594,6 +664,7 @@ export function TabsDemo() {
594
664
  <TabsTrigger value="overview">Overview</TabsTrigger>
595
665
  <TabsTrigger value="settings">Settings</TabsTrigger>
596
666
  </TabsList>
667
+
597
668
  <TabsContent value="overview">General information goes here.</TabsContent>
598
669
  <TabsContent value="settings">Preferences and configuration go here.</TabsContent>
599
670
  </Tabs>
@@ -605,12 +676,28 @@ export function TabsDemo() {
605
676
 
606
677
  ## 💅 Theming
607
678
 
608
- This package uses Tailwind CSS variables. You can override the default theme from your app CSS:
679
+ This package uses Tailwind CSS variables. You can override the default theme from your app CSS.
609
680
 
610
681
  ```css
611
682
  :root {
612
- --primary: oklch(0.45 0.18 260);
613
- --primary-foreground: oklch(0.98 0 0);
683
+ --card: oklch(1 0 0);
684
+ --card-foreground: oklch(0.145 0 0);
685
+ --popover: oklch(1 0 0);
686
+ --popover-foreground: oklch(0.145 0 0);
687
+ --primary: oklch(0.205 0 0);
688
+ --primary-foreground: oklch(0.985 0 0);
689
+ --secondary: oklch(0.97 0 0);
690
+ --secondary-foreground: oklch(0.205 0 0);
691
+ --muted: oklch(0.97 0 0);
692
+ --muted-foreground: oklch(0.556 0 0);
693
+ --accent: oklch(0.97 0 0);
694
+ --accent-foreground: oklch(0.205 0 0);
695
+ --destructive: oklch(64.12% 0.209 16.22);
696
+ --destructive-foreground: oklch(97.913% 0.00011 271.152);
697
+ --border: oklch(0.922 0 0);
698
+ --input: #fdfdfd;
699
+ --ring: 221.2 83.2% 53.3%;
700
+
614
701
  --radius: 0.75rem;
615
702
  }
616
703
  ```
@@ -619,4 +706,4 @@ This package uses Tailwind CSS variables. You can override the default theme fro
619
706
 
620
707
  ## 📝 License
621
708
 
622
- MIT.
709
+ MIT.
package/dist/index.cjs CHANGED
@@ -440,11 +440,11 @@ var React3 = __toESM(require("react"), 1);
440
440
  var import_jsx_runtime3 = require("react/jsx-runtime");
441
441
  var buttonVariants = (0, import_class_variance_authority2.cva)(
442
442
  [
443
- "inline-flex items-center justify-center gap-2 whitespace-nowrap",
443
+ "inline-flex min-w-max shrink-0 items-center justify-center whitespace-nowrap",
444
444
  "rounded-md text-sm font-medium",
445
445
  "transition-all duration-200 active:scale-95",
446
446
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2",
447
- "disabled:pointer-events-none disabled:opacity-50",
447
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
448
448
  "cursor-pointer select-none",
449
449
  "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0"
450
450
  ].join(" "),
@@ -453,7 +453,7 @@ var buttonVariants = (0, import_class_variance_authority2.cva)(
453
453
  variant: {
454
454
  default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
455
455
  destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
456
- outline: "border border-primary bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
456
+ outline: "border border-input bg-background text-foreground shadow-sm hover:bg-accent hover:text-accent-foreground",
457
457
  secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
458
458
  ghost: "bg-transparent hover:bg-accent hover:text-accent-foreground",
459
459
  link: "h-auto p-0 text-primary underline-offset-4 shadow-none hover:underline",
@@ -539,39 +539,29 @@ var Button = React3.forwardRef(
539
539
  className
540
540
  );
541
541
  const isDisabled = loading || disabled;
542
- const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
542
+ const Comp = asChild ? import_react_slot.Slot : "button";
543
+ const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "inline-flex min-w-max flex-row items-center justify-center gap-2 whitespace-nowrap leading-none", children: [
543
544
  loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
544
545
  import_lucide_react.Loader2,
545
546
  {
546
- className: cn("size-4 animate-spin", loaderClassName),
547
+ className: cn("size-4 shrink-0 animate-spin", loaderClassName),
547
548
  "aria-hidden": "true"
548
549
  }
549
550
  ) : null,
550
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn(loading && "opacity-90"), children })
551
+ children
551
552
  ] });
552
- if (asChild) {
553
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
554
- import_react_slot.Slot,
555
- __spreadProps(__spreadValues({
556
- ref,
557
- className: classes,
558
- "aria-disabled": isDisabled,
559
- "data-loading": loading ? "true" : void 0
560
- }, props), {
561
- children
562
- })
563
- );
564
- }
565
553
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
566
- "button",
554
+ Comp,
567
555
  __spreadProps(__spreadValues({
568
556
  ref,
569
- type,
557
+ type: asChild ? void 0 : type,
570
558
  className: classes,
571
- disabled: isDisabled,
559
+ disabled: asChild ? void 0 : isDisabled,
560
+ "aria-disabled": asChild ? isDisabled : void 0,
561
+ "aria-busy": loading ? true : void 0,
572
562
  "data-loading": loading ? "true" : void 0
573
563
  }, props), {
574
- children: content
564
+ children: asChild ? children : content
575
565
  })
576
566
  );
577
567
  }
package/dist/index.js CHANGED
@@ -153,14 +153,14 @@ import { Slot } from "@radix-ui/react-slot";
153
153
  import { cva as cva2 } from "class-variance-authority";
154
154
  import { Loader2 } from "lucide-react";
155
155
  import * as React3 from "react";
156
- import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
156
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
157
157
  var buttonVariants = cva2(
158
158
  [
159
- "inline-flex items-center justify-center gap-2 whitespace-nowrap",
159
+ "inline-flex min-w-max shrink-0 items-center justify-center whitespace-nowrap",
160
160
  "rounded-md text-sm font-medium",
161
161
  "transition-all duration-200 active:scale-95",
162
162
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2",
163
- "disabled:pointer-events-none disabled:opacity-50",
163
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
164
164
  "cursor-pointer select-none",
165
165
  "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0"
166
166
  ].join(" "),
@@ -169,7 +169,7 @@ var buttonVariants = cva2(
169
169
  variant: {
170
170
  default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
171
171
  destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
172
- outline: "border border-primary bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
172
+ outline: "border border-input bg-background text-foreground shadow-sm hover:bg-accent hover:text-accent-foreground",
173
173
  secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
174
174
  ghost: "bg-transparent hover:bg-accent hover:text-accent-foreground",
175
175
  link: "h-auto p-0 text-primary underline-offset-4 shadow-none hover:underline",
@@ -255,39 +255,29 @@ var Button = React3.forwardRef(
255
255
  className
256
256
  );
257
257
  const isDisabled = loading || disabled;
258
- const content = /* @__PURE__ */ jsxs2(Fragment, { children: [
258
+ const Comp = asChild ? Slot : "button";
259
+ const content = /* @__PURE__ */ jsxs2("span", { className: "inline-flex min-w-max flex-row items-center justify-center gap-2 whitespace-nowrap leading-none", children: [
259
260
  loading ? /* @__PURE__ */ jsx3(
260
261
  Loader2,
261
262
  {
262
- className: cn("size-4 animate-spin", loaderClassName),
263
+ className: cn("size-4 shrink-0 animate-spin", loaderClassName),
263
264
  "aria-hidden": "true"
264
265
  }
265
266
  ) : null,
266
- /* @__PURE__ */ jsx3("span", { className: cn(loading && "opacity-90"), children })
267
+ children
267
268
  ] });
268
- if (asChild) {
269
- return /* @__PURE__ */ jsx3(
270
- Slot,
271
- __spreadProps(__spreadValues({
272
- ref,
273
- className: classes,
274
- "aria-disabled": isDisabled,
275
- "data-loading": loading ? "true" : void 0
276
- }, props), {
277
- children
278
- })
279
- );
280
- }
281
269
  return /* @__PURE__ */ jsx3(
282
- "button",
270
+ Comp,
283
271
  __spreadProps(__spreadValues({
284
272
  ref,
285
- type,
273
+ type: asChild ? void 0 : type,
286
274
  className: classes,
287
- disabled: isDisabled,
275
+ disabled: asChild ? void 0 : isDisabled,
276
+ "aria-disabled": asChild ? isDisabled : void 0,
277
+ "aria-busy": loading ? true : void 0,
288
278
  "data-loading": loading ? "true" : void 0
289
279
  }, props), {
290
- children: content
280
+ children: asChild ? children : content
291
281
  })
292
282
  );
293
283
  }
@@ -9267,7 +9257,7 @@ var AlertModal = ({
9267
9257
 
9268
9258
  // src/shared/breadcrumbs.tsx
9269
9259
  import { Slash } from "lucide-react";
9270
- import { Fragment as Fragment2 } from "react";
9260
+ import { Fragment } from "react";
9271
9261
  import { jsx as jsx56, jsxs as jsxs29 } from "react/jsx-runtime";
9272
9262
  function Breadcrumbs({
9273
9263
  items,
@@ -9278,7 +9268,7 @@ function Breadcrumbs({
9278
9268
  return /* @__PURE__ */ jsx56(Breadcrumb, { className, children: /* @__PURE__ */ jsx56(BreadcrumbList, { className: classNameList, children: items.map((item, index) => {
9279
9269
  var _a;
9280
9270
  const isLast = index === items.length - 1;
9281
- return /* @__PURE__ */ jsxs29(Fragment2, { children: [
9271
+ return /* @__PURE__ */ jsxs29(Fragment, { children: [
9282
9272
  !isLast ? /* @__PURE__ */ jsx56(BreadcrumbItem, { className: item.className, children: /* @__PURE__ */ jsx56(BreadcrumbLink, { href: (_a = item.link) != null ? _a : "#", children: item.title }) }) : /* @__PURE__ */ jsx56(BreadcrumbItem, { className: item.className, children: /* @__PURE__ */ jsx56(BreadcrumbPage, { children: item.title }) }),
9283
9273
  !isLast ? /* @__PURE__ */ jsx56(BreadcrumbSeparator, { children: separator }) : null
9284
9274
  ] }, `${item.title}-${index}`);
package/dist/style.css CHANGED
@@ -506,9 +506,6 @@
506
506
  .ml-1 {
507
507
  margin-left: calc(var(--spacing) * 1);
508
508
  }
509
- .ml-2 {
510
- margin-left: calc(var(--spacing) * 2);
511
- }
512
509
  .ml-auto {
513
510
  margin-left: auto;
514
511
  }
@@ -747,6 +744,10 @@
747
744
  .min-w-full {
748
745
  min-width: 100%;
749
746
  }
747
+ .min-w-max {
748
+ min-width: -moz-max-content;
749
+ min-width: max-content;
750
+ }
750
751
  .flex-1 {
751
752
  flex: 1;
752
753
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadcn-ui-react",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "private": false,
5
5
  "author": "Bleker <bleker@gliyen.com>",
6
6
  "description": "A collection of components for building beautiful and accessible user interfaces with React and Tailwind CSS.",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@babel/core": "^7.29.0",
55
- "@babel/preset-env": "^7.29.3",
55
+ "@babel/preset-env": "^7.29.5",
56
56
  "@babel/preset-react": "^7.28.5",
57
57
  "@babel/preset-typescript": "^7.28.5",
58
58
  "@eslint/config-array": "^0.23.5",