@srcroot/ui 0.0.49 → 0.0.53

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/dist/index.js CHANGED
@@ -27,7 +27,8 @@ var THEME_METADATA = {
27
27
  rose: { name: "Rose", description: "Soft and elegant pinkish-red" },
28
28
  blue: { name: "Blue", description: "Trustworthy corporate blue" },
29
29
  green: { name: "Green", description: "Nature and success green" },
30
- orange: { name: "Orange", description: "Energetic and creative orange" }
30
+ orange: { name: "Orange", description: "Energetic and creative orange" },
31
+ glass: { name: "Glass", description: "Modern glassmorphic aesthetic" }
31
32
  };
32
33
  var ThemeService = class {
33
34
  registryThemesPath;
@@ -397,7 +398,7 @@ var REGISTRY = {
397
398
  file: "ui/button.tsx",
398
399
  description: "Polymorphic button with variants",
399
400
  category: "Core",
400
- dependencies: []
401
+ dependencies: ["slot"]
401
402
  },
402
403
  badge: {
403
404
  file: "ui/badge.tsx",
@@ -529,37 +530,37 @@ var REGISTRY = {
529
530
  file: "ui/dialog.tsx",
530
531
  description: "Modal dialog",
531
532
  category: "Overlay / Feedback",
532
- dependencies: []
533
+ dependencies: ["slot"]
533
534
  },
534
535
  "alert-dialog": {
535
536
  file: "ui/alert-dialog.tsx",
536
537
  description: "Confirmation dialog",
537
538
  category: "Overlay / Feedback",
538
- dependencies: ["dialog"]
539
+ dependencies: ["dialog", "slot"]
539
540
  },
540
541
  sheet: {
541
542
  file: "ui/sheet.tsx",
542
543
  description: "Slide-in panel",
543
544
  category: "Overlay / Feedback",
544
- dependencies: []
545
+ dependencies: ["slot"]
545
546
  },
546
547
  popover: {
547
548
  file: "ui/popover.tsx",
548
549
  description: "Floating content",
549
550
  category: "Overlay / Feedback",
550
- dependencies: []
551
+ dependencies: ["slot"]
551
552
  },
552
553
  tooltip: {
553
554
  file: "ui/tooltip.tsx",
554
555
  description: "Hover tooltip",
555
556
  category: "Overlay / Feedback",
556
- dependencies: []
557
+ dependencies: ["slot"]
557
558
  },
558
559
  "dropdown-menu": {
559
560
  file: "ui/dropdown-menu.tsx",
560
561
  description: "Action dropdown",
561
562
  category: "Overlay / Feedback",
562
- dependencies: []
563
+ dependencies: ["slot"]
563
564
  },
564
565
  toast: {
565
566
  file: "ui/toast.tsx",
@@ -578,7 +579,7 @@ var REGISTRY = {
578
579
  file: "ui/breadcrumb.tsx",
579
580
  description: "Breadcrumb navigation",
580
581
  category: "Navigation",
581
- dependencies: []
582
+ dependencies: ["slot"]
582
583
  },
583
584
  pagination: {
584
585
  file: "ui/pagination.tsx",
@@ -627,7 +628,7 @@ var REGISTRY = {
627
628
  file: "ui/collapsible.tsx",
628
629
  description: "Expandable section",
629
630
  category: "Data Display",
630
- dependencies: []
631
+ dependencies: ["slot"]
631
632
  },
632
633
  carousel: {
633
634
  file: "ui/carousel.tsx",
@@ -645,7 +646,7 @@ var REGISTRY = {
645
646
  file: "ui/sidebar.tsx",
646
647
  description: "Responsive sidebar with mobile drawer",
647
648
  category: "Layout",
648
- dependencies: ["sheet", "button"]
649
+ dependencies: ["sheet", "button", "slot"]
649
650
  },
650
651
  // Added Components
651
652
  combobox: {
@@ -682,13 +683,14 @@ var REGISTRY = {
682
683
  file: "ui/date-picker.tsx",
683
684
  description: "Date picker with calendar",
684
685
  category: "Forms",
685
- dependencies: ["calendar", "popover", "button"]
686
+ dependencies: ["calendar", "popover", "button"],
687
+ registryDependencies: ["date-fns"]
686
688
  },
687
689
  drawer: {
688
690
  file: "ui/drawer.tsx",
689
691
  description: "Bottom/top sheet drawer",
690
692
  category: "Overlay / Feedback",
691
- dependencies: []
693
+ dependencies: ["slot"]
692
694
  },
693
695
  "file-upload": {
694
696
  file: "ui/file-upload.tsx",
@@ -700,7 +702,7 @@ var REGISTRY = {
700
702
  file: "ui/hover-card.tsx",
701
703
  description: "Hover-triggered popover",
702
704
  category: "Overlay / Feedback",
703
- dependencies: []
705
+ dependencies: ["slot"]
704
706
  },
705
707
  kbd: {
706
708
  file: "ui/kbd.tsx",
@@ -786,6 +788,12 @@ var REGISTRY = {
786
788
  category: "Data Display",
787
789
  dependencies: [],
788
790
  registryDependencies: ["recharts"]
791
+ },
792
+ slot: {
793
+ file: "ui/slot.tsx",
794
+ description: "Slot utility for polymorphic components",
795
+ category: "Core",
796
+ dependencies: []
789
797
  }
790
798
  };
791
799
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srcroot/ui",
3
- "version": "0.0.49",
3
+ "version": "0.0.53",
4
4
  "description": "A UI library with polymorphic, accessible React components",
5
5
  "author": "Shifaul Islam",
6
6
  "license": "MIT",
@@ -36,6 +36,7 @@
36
36
  "@types/fs-extra": "^11.0.4",
37
37
  "@types/node": "^22.10.1",
38
38
  "@types/prompts": "^2.4.9",
39
+ "@types/react": "^19.2.7",
39
40
  "class-variance-authority": "^0.7.1",
40
41
  "clsx": "^2.1.1",
41
42
  "cmdk": "^1.0.0",
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @srcroot/ui - Glass Theme (Tailwind 3)
3
+ * Glassmorphic transparent aesthetic
4
+ */
5
+
6
+ @tailwind base;
7
+ @tailwind components;
8
+ @tailwind utilities;
9
+
10
+ @layer base {
11
+ :root {
12
+ --background: 0 0% 100%;
13
+ --foreground: 240 10% 3.9%;
14
+
15
+ --card: 0 0% 100% / 0.7;
16
+ --card-foreground: 240 10% 3.9%;
17
+
18
+ --popover: 0 0% 100% / 0.7;
19
+ --popover-foreground: 240 10% 3.9%;
20
+
21
+ --primary: 240 5.9% 10%;
22
+ --primary-foreground: 0 0% 98%;
23
+
24
+ --secondary: 240 4.8% 95.9% / 0.7;
25
+ --secondary-foreground: 240 5.9% 10%;
26
+
27
+ --muted: 240 4.8% 95.9% / 0.7;
28
+ --muted-foreground: 240 3.8% 46.1%;
29
+
30
+ --accent: 240 4.8% 95.9% / 0.7;
31
+ --accent-foreground: 240 5.9% 10%;
32
+
33
+ --destructive: 0 84.2% 60.2%;
34
+ --destructive-foreground: 0 0% 98%;
35
+
36
+ --success: 142.1 76.2% 36.3%;
37
+ --success-foreground: 0 0% 100%;
38
+
39
+ --warning: 45.4 93.4% 47.5%;
40
+ --warning-foreground: 240 10% 3.9%;
41
+
42
+ --info: 201.3 96.3% 32.2%;
43
+ --info-foreground: 0 0% 100%;
44
+
45
+ --border: 240 5.9% 90% / 0.5;
46
+ --input: 240 5.9% 90% / 0.5;
47
+ --ring: 240 10% 3.9%;
48
+
49
+ --radius: 0.5rem;
50
+
51
+ --sidebar-width: 16rem;
52
+ --sidebar-width-mobile: 18rem;
53
+ --sidebar-width-collapsed: 3rem;
54
+ --sidebar-width-icon: 3rem;
55
+ --header-height: 3.5rem;
56
+
57
+ --sidebar-background: 0 0% 98% / 0.7;
58
+ --sidebar-foreground: 240 5.3% 26.1%;
59
+ --sidebar-primary: 240 5.9% 10%;
60
+ --sidebar-primary-foreground: 0 0% 98%;
61
+ --sidebar-accent: 240 4.8% 95.9%;
62
+ --sidebar-accent-foreground: 240 5.9% 10%;
63
+ --sidebar-border: 220 13% 91% / 0.5;
64
+ --sidebar-ring: 217.2 91.2% 59.8%;
65
+ }
66
+
67
+ .dark {
68
+ --background: 240 10% 3.9%;
69
+ --foreground: 0 0% 98%;
70
+
71
+ --card: 240 10% 3.9% / 0.7;
72
+ --card-foreground: 0 0% 98%;
73
+
74
+ --popover: 240 10% 3.9% / 0.7;
75
+ --popover-foreground: 0 0% 98%;
76
+
77
+ --primary: 0 0% 98%;
78
+ --primary-foreground: 240 5.9% 10%;
79
+
80
+ --secondary: 240 3.7% 15.9% / 0.7;
81
+ --secondary-foreground: 0 0% 98%;
82
+
83
+ --muted: 240 3.7% 15.9% / 0.7;
84
+ --muted-foreground: 240 5% 64.9%;
85
+
86
+ --accent: 240 3.7% 15.9% / 0.7;
87
+ --accent-foreground: 0 0% 98%;
88
+
89
+ --destructive: 0 62.8% 30.6%;
90
+ --destructive-foreground: 0 0% 98%;
91
+
92
+ --success: 142.1 70.6% 45.3%;
93
+ --success-foreground: 0 0% 100%;
94
+
95
+ --warning: 48 96.5% 53.1%;
96
+ --warning-foreground: 0 0% 98%;
97
+
98
+ --info: 199.4 95.5% 53.8%;
99
+ --info-foreground: 0 0% 98%;
100
+
101
+ --border: 240 3.7% 15.9% / 0.5;
102
+ --input: 240 3.7% 15.9% / 0.5;
103
+ --ring: 240 4.9% 83.9%;
104
+
105
+ --sidebar-background: 240 10% 3.9% / 0.7;
106
+ --sidebar-foreground: 240 4.8% 95.9%;
107
+ --sidebar-primary: 224.3 76.3% 48%;
108
+ --sidebar-primary-foreground: 0 0% 100%;
109
+ --sidebar-accent: 240 3.7% 15.9%;
110
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
111
+ --sidebar-border: 240 3.7% 15.9% / 0.5;
112
+ --sidebar-ring: 217.2 91.2% 59.8%;
113
+ }
114
+ }
115
+
116
+ @layer base {
117
+ * {
118
+ @apply border-border;
119
+ }
120
+
121
+ body {
122
+ @apply bg-background text-foreground;
123
+ }
124
+ }
125
+
126
+ @layer utilities {
127
+ @keyframes accordion-down {
128
+ from {
129
+ height: 0;
130
+ }
131
+
132
+ to {
133
+ height: var(--radix-accordion-content-height);
134
+ }
135
+ }
136
+
137
+ @keyframes accordion-up {
138
+ from {
139
+ height: var(--radix-accordion-content-height);
140
+ }
141
+
142
+ to {
143
+ height: 0;
144
+ }
145
+ }
146
+
147
+ .animate-accordion-down {
148
+ animation: accordion-down 0.2s ease-out;
149
+ }
150
+
151
+ .animate-accordion-up {
152
+ animation: accordion-up 0.2s ease-out;
153
+ }
154
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * @srcroot/ui - Glass Theme (Tailwind 4)
3
+ * Glassmorphic transparent aesthetic
4
+ */
5
+
6
+ @import "tailwindcss";
7
+
8
+ :root {
9
+ --background: hsl(0 0% 100%);
10
+ --foreground: hsl(240 10% 3.9%);
11
+
12
+ --card: hsl(0 0% 100% / 0.7);
13
+ --card-foreground: hsl(240 10% 3.9%);
14
+
15
+ --popover: hsl(0 0% 100% / 0.7);
16
+ --popover-foreground: hsl(240 10% 3.9%);
17
+
18
+ --primary: hsl(240 5.9% 10%);
19
+ --primary-foreground: hsl(0 0% 98%);
20
+
21
+ --secondary: hsl(240 4.8% 95.9% / 0.7);
22
+ --secondary-foreground: hsl(240 5.9% 10%);
23
+
24
+ --muted: hsl(240 4.8% 95.9% / 0.7);
25
+ --muted-foreground: hsl(240 3.8% 46.1%);
26
+
27
+ --accent: hsl(240 4.8% 95.9% / 0.7);
28
+ --accent-foreground: hsl(240 5.9% 10%);
29
+
30
+ --destructive: hsl(0 84.2% 60.2%);
31
+ --destructive-foreground: hsl(0 0% 98%);
32
+
33
+ --success: hsl(142.1 76.2% 36.3%);
34
+ --success-foreground: hsl(0 0% 100%);
35
+
36
+ --warning: hsl(45.4 93.4% 47.5%);
37
+ --warning-foreground: hsl(240 10% 3.9%);
38
+
39
+ --info: hsl(201.3 96.3% 32.2%);
40
+ --info-foreground: hsl(0 0% 100%);
41
+
42
+ --border: hsl(240 5.9% 90% / 0.5);
43
+ --input: hsl(240 5.9% 90% / 0.5);
44
+ --ring: hsl(240 10% 3.9%);
45
+
46
+ --radius: 0.5rem;
47
+
48
+ --sidebar-width: 16rem;
49
+ --sidebar-width-mobile: 18rem;
50
+ --sidebar-width-collapsed: 3rem;
51
+ --sidebar-width-icon: 3rem;
52
+ --header-height: 3.5rem;
53
+
54
+ --sidebar-background: hsl(0 0% 98% / 0.7);
55
+ --sidebar-foreground: hsl(240 5.3% 26.1%);
56
+ --sidebar-primary: hsl(240 5.9% 10%);
57
+ --sidebar-primary-foreground: hsl(0 0% 98%);
58
+ --sidebar-accent: hsl(240 4.8% 95.9%);
59
+ --sidebar-accent-foreground: hsl(240 5.9% 10%);
60
+ --sidebar-border: hsl(220 13% 91% / 0.5);
61
+ --sidebar-ring: hsl(217.2 91.2% 59.8%);
62
+ }
63
+
64
+ @theme inline {
65
+ --color-border: var(--border);
66
+ --color-input: var(--input);
67
+ --color-ring: var(--ring);
68
+ --color-background: var(--background);
69
+ --color-foreground: var(--foreground);
70
+
71
+ --color-primary: var(--primary);
72
+ --color-primary-foreground: var(--primary-foreground);
73
+
74
+ --color-secondary: var(--secondary);
75
+ --color-secondary-foreground: var(--secondary-foreground);
76
+
77
+ --color-destructive: var(--destructive);
78
+ --color-destructive-foreground: var(--destructive-foreground);
79
+
80
+ --color-muted: var(--muted);
81
+ --color-muted-foreground: var(--muted-foreground);
82
+
83
+ --color-accent: var(--accent);
84
+ --color-accent-foreground: var(--accent-foreground);
85
+
86
+ --color-popover: var(--popover);
87
+ --color-popover-foreground: var(--popover-foreground);
88
+
89
+ --color-card: var(--card);
90
+ --color-card-foreground: var(--card-foreground);
91
+
92
+ --color-sidebar: var(--sidebar-background);
93
+ --color-sidebar-foreground: var(--sidebar-foreground);
94
+ --color-sidebar-primary: var(--sidebar-primary);
95
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
96
+ --color-sidebar-accent: var(--sidebar-accent);
97
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
98
+ --color-sidebar-border: var(--sidebar-border);
99
+ --color-sidebar-ring: var(--sidebar-ring);
100
+
101
+ --radius-lg: var(--radius);
102
+ --radius-md: calc(var(--radius) - 2px);
103
+ --radius-sm: calc(var(--radius) - 4px);
104
+
105
+ --animate-accordion-down: accordion-down 0.2s ease-out;
106
+ --animate-accordion-up: accordion-up 0.2s ease-out;
107
+
108
+ @keyframes accordion-down {
109
+ from {
110
+ height: 0;
111
+ }
112
+
113
+ to {
114
+ height: var(--radix-accordion-content-height);
115
+ }
116
+ }
117
+
118
+ @keyframes accordion-up {
119
+ from {
120
+ height: var(--radix-accordion-content-height);
121
+ }
122
+
123
+ to {
124
+ height: 0;
125
+ }
126
+ }
127
+ }
128
+
129
+ .dark {
130
+ --background: hsl(240 10% 3.9%);
131
+ --foreground: hsl(0 0% 98%);
132
+
133
+ --card: hsl(240 10% 3.9% / 0.7);
134
+ --card-foreground: hsl(0 0% 98%);
135
+
136
+ --popover: hsl(240 10% 3.9% / 0.7);
137
+ --popover-foreground: hsl(0 0% 98%);
138
+
139
+ --primary: hsl(0 0% 98%);
140
+ --primary-foreground: hsl(240 5.9% 10%);
141
+
142
+ --secondary: hsl(240 3.7% 15.9% / 0.7);
143
+ --secondary-foreground: hsl(0 0% 98%);
144
+
145
+ --muted: hsl(240 3.7% 15.9% / 0.7);
146
+ --muted-foreground: hsl(240 5% 64.9%);
147
+
148
+ --accent: hsl(240 3.7% 15.9% / 0.7);
149
+ --accent-foreground: hsl(0 0% 98%);
150
+
151
+ --destructive: hsl(0 62.8% 30.6%);
152
+ --destructive-foreground: hsl(0 0% 98%);
153
+
154
+ --success: hsl(142.1 70.6% 45.3%);
155
+ --success-foreground: hsl(0 0% 100%);
156
+
157
+ --warning: hsl(48 96.5% 53.1%);
158
+ --warning-foreground: hsl(0 0% 98%);
159
+
160
+ --info: hsl(199.4 95.5% 53.8%);
161
+ --info-foreground: hsl(0 0% 98%);
162
+
163
+ --border: hsl(240 3.7% 15.9% / 0.5);
164
+ --input: hsl(240 3.7% 15.9% / 0.5);
165
+ --ring: hsl(240 4.9% 83.9%);
166
+
167
+ --sidebar-background: hsl(240 10% 3.9% / 0.7);
168
+ --sidebar-foreground: hsl(240 4.8% 95.9%);
169
+ --sidebar-primary: hsl(224.3 76.3% 48%);
170
+ --sidebar-primary-foreground: hsl(0 0% 100%);
171
+ --sidebar-accent: hsl(240 3.7% 15.9%);
172
+ --sidebar-accent-foreground: hsl(240 4.8% 95.9%);
173
+ --sidebar-border: hsl(240 3.7% 15.9% / 0.5);
174
+ --sidebar-ring: hsl(217.2 91.2% 59.8%);
175
+ }
176
+
177
+ body {
178
+ background: var(--background);
179
+ color: var(--foreground);
180
+ font-family: Arial, Helvetica, sans-serif;
181
+ }
@@ -1,5 +1,7 @@
1
1
  import * as React from "react"
2
+ import { createPortal } from "react-dom"
2
3
  import { cn } from "@/lib/utils"
4
+ import { Slot } from "@/components/ui/slot"
3
5
 
4
6
  interface AlertDialogContextValue {
5
7
  open: boolean
@@ -63,17 +65,12 @@ const AlertDialogTrigger = React.forwardRef<HTMLButtonElement, AlertDialogTrigge
63
65
  context.onOpenChange(true)
64
66
  }
65
67
 
66
- if (asChild && React.isValidElement(children)) {
67
- return React.cloneElement(children as React.ReactElement<any>, {
68
- onClick: handleClick,
69
- ref,
70
- })
71
- }
68
+ const Comp = asChild ? Slot : "button"
72
69
 
73
70
  return (
74
- <button ref={ref} onClick={handleClick} {...props}>
71
+ <Comp ref={ref} onClick={handleClick} {...props}>
75
72
  {children}
76
- </button>
73
+ </Comp>
77
74
  )
78
75
  }
79
76
  )
@@ -95,9 +92,16 @@ const AlertDialogContent = React.forwardRef<
95
92
  }
96
93
  }, [context.open])
97
94
 
95
+ const [mounted, setMounted] = React.useState(false)
96
+
97
+ React.useEffect(() => {
98
+ setMounted(true)
99
+ }, [])
100
+
98
101
  if (!context.open) return null
102
+ if (!mounted) return null
99
103
 
100
- return (
104
+ return createPortal(
101
105
  <>
102
106
  <div className="fixed inset-0 z-50 bg-black/80" />
103
107
  <div
@@ -112,7 +116,8 @@ const AlertDialogContent = React.forwardRef<
112
116
  >
113
117
  {children}
114
118
  </div>
115
- </>
119
+ </>,
120
+ document.body
116
121
  )
117
122
  })
118
123
  AlertDialogContent.displayName = "AlertDialogContent"
@@ -1,5 +1,6 @@
1
1
  import * as React from "react"
2
2
  import { cn } from "@/lib/utils"
3
+ import { Slot } from "@/components/ui/slot"
3
4
 
4
5
  /**
5
6
  * Breadcrumb navigation component
@@ -59,21 +60,16 @@ interface BreadcrumbLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorEleme
59
60
 
60
61
  const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
61
62
  ({ asChild, className, children, ...props }, ref) => {
62
- if (asChild && React.isValidElement(children)) {
63
- return React.cloneElement(children as React.ReactElement<any>, {
64
- ref,
65
- className: cn("transition-colors hover:text-foreground", className),
66
- })
67
- }
63
+ const Comp = asChild ? Slot : "a"
68
64
 
69
65
  return (
70
- <a
66
+ <Comp
71
67
  ref={ref}
72
68
  className={cn("transition-colors hover:text-foreground", className)}
73
69
  {...props}
74
70
  >
75
71
  {children}
76
- </a>
72
+ </Comp>
77
73
  )
78
74
  }
79
75
  )
@@ -50,24 +50,17 @@ interface ButtonProps
50
50
  * <LoadingSpinner /> Processing...
51
51
  * </Button>
52
52
  */
53
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
54
- ({ className, variant, size, asChild = false, children, ...props }, ref) => {
55
- if (asChild && React.isValidElement(children)) {
56
- return React.cloneElement(children as React.ReactElement<any>, {
57
- ref,
58
- className: cn(buttonVariants({ variant, size }), className),
59
- ...props,
60
- })
61
- }
53
+ import { Slot } from "@/components/ui/slot"
62
54
 
55
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
56
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
57
+ const Comp = asChild ? Slot : "button"
63
58
  return (
64
- <button
65
- ref={ref}
59
+ <Comp
66
60
  className={cn(buttonVariants({ variant, size }), className)}
61
+ ref={ref}
67
62
  {...props}
68
- >
69
- {children}
70
- </button>
63
+ />
71
64
  )
72
65
  }
73
66
  )
@@ -1,5 +1,6 @@
1
1
  import * as React from "react"
2
2
  import { cn } from "@/lib/utils"
3
+ import { Slot } from "@/components/ui/slot"
3
4
 
4
5
  interface CollapsibleContextValue {
5
6
  open: boolean
@@ -59,16 +60,10 @@ const CollapsibleTrigger = React.forwardRef<HTMLButtonElement, CollapsibleTrigge
59
60
  context.onOpenChange(!context.open)
60
61
  }
61
62
 
62
- if (asChild && React.isValidElement(children)) {
63
- return React.cloneElement(children as React.ReactElement<any>, {
64
- onClick: handleClick,
65
- "aria-expanded": context.open,
66
- ref,
67
- })
68
- }
63
+ const Comp = asChild ? Slot : "button"
69
64
 
70
65
  return (
71
- <button
66
+ <Comp
72
67
  ref={ref}
73
68
  type="button"
74
69
  aria-expanded={context.open}
@@ -77,7 +72,7 @@ const CollapsibleTrigger = React.forwardRef<HTMLButtonElement, CollapsibleTrigge
77
72
  {...props}
78
73
  >
79
74
  {children}
80
- </button>
75
+ </Comp>
81
76
  )
82
77
  }
83
78
  )
@@ -1,5 +1,7 @@
1
1
  import * as React from "react"
2
+ import { createPortal } from "react-dom"
2
3
  import { cn } from "@/lib/utils"
4
+ import { Slot } from "@/components/ui/slot"
3
5
 
4
6
  interface DialogContextValue {
5
7
  open: boolean
@@ -71,17 +73,12 @@ const DialogTrigger = React.forwardRef<HTMLButtonElement, DialogTriggerProps>(
71
73
  onOpenChange(true)
72
74
  }
73
75
 
74
- if (asChild && React.isValidElement(children)) {
75
- return React.cloneElement(children as React.ReactElement<any>, {
76
- onClick: handleClick,
77
- ref,
78
- })
79
- }
76
+ const Comp = asChild ? Slot : "button"
80
77
 
81
78
  return (
82
- <button ref={ref} onClick={handleClick} {...props}>
79
+ <Comp ref={ref} onClick={handleClick} {...props}>
83
80
  {children}
84
- </button>
81
+ </Comp>
85
82
  )
86
83
  }
87
84
  )
@@ -89,10 +86,16 @@ DialogTrigger.displayName = "DialogTrigger"
89
86
 
90
87
  const DialogPortal = ({ children }: { children: React.ReactNode }) => {
91
88
  const { open } = useDialogContext()
89
+ const [mounted, setMounted] = React.useState(false)
90
+
91
+ React.useEffect(() => {
92
+ setMounted(true)
93
+ }, [])
92
94
 
93
95
  if (!open) return null
96
+ if (!mounted) return null
94
97
 
95
- return <>{children}</>
98
+ return createPortal(children, document.body)
96
99
  }
97
100
 
98
101
  const DialogOverlay = React.forwardRef<
@@ -171,7 +174,7 @@ const DialogContent = React.forwardRef<
171
174
  <DialogOverlay onClick={() => onOpenChange(false)} />
172
175
  <div
173
176
  ref={(node) => {
174
- (contentRef as React.MutableRefObject<HTMLDivElement | null>).current = node
177
+ (contentRef as any).current = node
175
178
  if (typeof ref === "function") ref(node)
176
179
  else if (ref) ref.current = node
177
180
  }}