kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1"use client";
2
3import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
4import { XIcon } from "lucide-react";
5import * as React from "react";
6import { Button } from "@/components/ui/button";
7import { ScrollArea } from "@/components/ui/scroll-area";
8import { cn } from "@/lib/cn";
9
10const DialogCreateHandle = DialogPrimitive.createHandle;
11
12const Dialog = DialogPrimitive.Root;
13
14const DialogPortal = DialogPrimitive.Portal;
15
16function DialogTrigger({
17 asChild = false,
18 children,
19 render,
20 ...props
21}: DialogPrimitive.Trigger.Props & { asChild?: boolean }) {
22 const resolvedRender =
23 asChild && React.isValidElement(children) ? children : render;
24
25 return (
26 <DialogPrimitive.Trigger
27 data-slot="dialog-trigger"
28 render={resolvedRender}
29 {...props}
30 >
31 {asChild ? undefined : children}
32 </DialogPrimitive.Trigger>
33 );
34}
35
36function DialogClose({
37 asChild = false,
38 children,
39 render,
40 ...props
41}: DialogPrimitive.Close.Props & { asChild?: boolean }) {
42 const resolvedRender =
43 asChild && React.isValidElement(children) ? children : render;
44
45 return (
46 <DialogPrimitive.Close
47 data-slot="dialog-close"
48 render={resolvedRender}
49 {...props}
50 >
51 {asChild ? undefined : children}
52 </DialogPrimitive.Close>
53 );
54}
55
56function DialogBackdrop({
57 className,
58 ...props
59}: DialogPrimitive.Backdrop.Props) {
60 return (
61 <DialogPrimitive.Backdrop
62 className={cn(
63 "fixed inset-0 z-50 bg-black/32 backdrop-blur-sm transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0",
64 className,
65 )}
66 data-slot="dialog-backdrop"
67 {...props}
68 />
69 );
70}
71
72function DialogViewport({
73 className,
74 ...props
75}: DialogPrimitive.Viewport.Props) {
76 return (
77 <DialogPrimitive.Viewport
78 className={cn(
79 "fixed inset-0 z-50 grid grid-rows-[1fr_auto_3fr] justify-items-center p-4",
80 className,
81 )}
82 data-slot="dialog-viewport"
83 {...props}
84 />
85 );
86}
87
88function DialogPopup({
89 className,
90 children,
91 showCloseButton = true,
92 bottomStickOnMobile = true,
93 ...props
94}: DialogPrimitive.Popup.Props & {
95 showCloseButton?: boolean;
96 bottomStickOnMobile?: boolean;
97}) {
98 return (
99 <DialogPortal>
100 <DialogBackdrop />
101 <DialogViewport
102 className={cn(
103 bottomStickOnMobile &&
104 "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12",
105 )}
106 >
107 <DialogPrimitive.Popup
108 className={cn(
109 "-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
110 bottomStickOnMobile &&
111 "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none",
112 className,
113 )}
114 data-slot="dialog-popup"
115 {...props}
116 >
117 {children}
118 {showCloseButton && (
119 <DialogPrimitive.Close
120 aria-label="Close"
121 className="absolute end-2 top-2"
122 render={<Button size="icon" variant="ghost" />}
123 >
124 <XIcon />
125 </DialogPrimitive.Close>
126 )}
127 </DialogPrimitive.Popup>
128 </DialogViewport>
129 </DialogPortal>
130 );
131}
132
133function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
134 return (
135 <div
136 className={cn(
137 "flex flex-col gap-2 p-6 in-[[data-slot=dialog-popup]:has([data-slot=dialog-panel])]:pb-3 max-sm:pb-4",
138 className,
139 )}
140 data-slot="dialog-header"
141 {...props}
142 />
143 );
144}
145
146function DialogFooter({
147 className,
148 variant = "default",
149 ...props
150}: React.ComponentProps<"div"> & {
151 variant?: "default" | "bare";
152}) {
153 return (
154 <div
155 className={cn(
156 "flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end sm:rounded-b-[calc(var(--radius-2xl)-1px)]",
157 variant === "default" && "border-t bg-muted/72 py-4",
158 variant === "bare" &&
159 "in-[[data-slot=dialog-popup]:has([data-slot=dialog-panel])]:pt-3 pt-4 pb-6",
160 className,
161 )}
162 data-slot="dialog-footer"
163 {...props}
164 />
165 );
166}
167
168function DialogTitle({
169 asChild = false,
170 className,
171 children,
172 render,
173 ...props
174}: DialogPrimitive.Title.Props & { asChild?: boolean }) {
175 const resolvedRender =
176 asChild && React.isValidElement(children) ? children : render;
177
178 return (
179 <DialogPrimitive.Title
180 className={cn(
181 "font-heading font-semibold text-xl leading-none",
182 className,
183 )}
184 data-slot="dialog-title"
185 render={resolvedRender}
186 {...props}
187 >
188 {asChild ? undefined : children}
189 </DialogPrimitive.Title>
190 );
191}
192
193function DialogDescription({
194 className,
195 ...props
196}: DialogPrimitive.Description.Props) {
197 return (
198 <DialogPrimitive.Description
199 className={cn("text-muted-foreground text-sm", className)}
200 data-slot="dialog-description"
201 {...props}
202 />
203 );
204}
205
206function DialogPanel({
207 className,
208 scrollFade = true,
209 ...props
210}: React.ComponentProps<"div"> & { scrollFade?: boolean }) {
211 return (
212 <ScrollArea scrollFade={scrollFade}>
213 <div
214 className={cn(
215 "p-6 in-[[data-slot=dialog-popup]:has([data-slot=dialog-header])]:pt-1 in-[[data-slot=dialog-popup]:has([data-slot=dialog-footer]:not(.border-t))]:pb-1",
216 className,
217 )}
218 data-slot="dialog-panel"
219 {...props}
220 />
221 </ScrollArea>
222 );
223}
224
225export {
226 DialogCreateHandle,
227 Dialog,
228 DialogTrigger,
229 DialogPortal,
230 DialogClose,
231 DialogBackdrop,
232 DialogBackdrop as DialogOverlay,
233 DialogPopup,
234 DialogPopup as DialogContent,
235 DialogHeader,
236 DialogFooter,
237 DialogTitle,
238 DialogDescription,
239 DialogPanel,
240 DialogViewport,
241};