Skip to content

Instantly share code, notes, and snippets.

@borispoehland
Last active July 8, 2024 04:26
Show Gist options
  • Save borispoehland/6d533e630b5fe1fdc095c75af41d99c2 to your computer and use it in GitHub Desktop.
Save borispoehland/6d533e630b5fe1fdc095c75af41d99c2 to your computer and use it in GitHub Desktop.
import {
ElementRef,
ForwardRefExoticComponent,
createElement,
forwardRef,
} from "react";
import { cn } from "./utils";
export function extend<T extends { className?: string }>(
Component: ForwardRefExoticComponent<T>,
defaultProps: T
) {
return forwardRef<ElementRef<typeof Component>, T>(function ExtendComponent(
props,
ref
) {
return (
<Component
ref={ref}
{...defaultProps}
{...props}
className={cn(defaultProps.className, props.className)}
/>
);
});
}
export function create<T extends keyof HTMLElementTagNameMap>(tag: T) {
return forwardRef<HTMLElementTagNameMap[T], JSX.IntrinsicElements[T]>(
function CreateComponent(props, ref) {
return createElement(tag, { ...props, ref });
}
);
}
import {
DialogBody,
DialogDescription,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export default function Page() {
return (
<DialogRoot>
<DialogTrigger>Open</DialogTrigger>
<DialogBody>
<DialogHeader>
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogBody>
</DialogRoot>
);
}
"use client";
import { create, extend } from "@/lib/components";
import * as Dialog from "@radix-ui/react-dialog";
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react";
import { IoMdClose } from "react-icons/io";
const DialogPortal = Dialog.Portal;
const DialogClose = Dialog.Close;
const DialogOverlay = extend(Dialog.Overlay, {
className:
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
});
const DialogContent = extend(Dialog.Content, {
className:
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
});
export const DialogRoot = Dialog.Root;
export const DialogTrigger = Dialog.Trigger;
export const DialogTitle = extend(Dialog.Title, {
className: "text-lg font-semibold leading-none tracking-tight",
});
export const DialogDescription = extend(Dialog.Description, {
className: "text-sm text-muted-foreground",
});
export const DialogHeader = extend(create("div"), {
className: "flex flex-col space-y-1.5 text-center sm:text-left",
});
export const DialogFooter = extend(create("div"), {
className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
});
export const DialogBody = forwardRef<
ElementRef<typeof DialogContent>,
ComponentPropsWithoutRef<typeof DialogContent>
>(function DialogBody({ children, ...props }, ref) {
return (
<DialogPortal>
<DialogOverlay />
<DialogContent ref={ref} {...props}>
{children}
<DialogClose className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:muted">
<IoMdClose className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment