A sliding panel that emerges from screen edges.
"use client";
import React from "react";
import { Dialog as DialogPrimitives, Portal } from "@ark-ui/react";
import { cva, VariantProps } from "class-variance-authority";
import { IconButton } from "./icon-button";
import { IconX } from "@tabler/icons-react";
export const Drawer = DialogPrimitives.Root;
export const DrawerTrigger = DialogPrimitives.Trigger;
export const DrawerCloseTrigger = DialogPrimitives.CloseTrigger;
export const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div className="text-base-900 flex min-h-8 items-center" {...props} />
);
DrawerHeader.displayName = "DrawerHeader";
export const DrawerBody = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div className="text-base-600 mt-6 flex-1 overflow-y-auto" {...props} />
);
DrawerBody.displayName = "DrawerBody";
export const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className="text-base-900 flex min-h-8 items-center justify-between"
{...props}
/>
);
DrawerFooter.displayName = "DrawerFooter";
export const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitives.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitives.Title
ref={ref}
className="flex-1 text-xl font-semibold"
{...props}
/>
));
DrawerTitle.displayName = "DrawerTitle";
export const DrawerClose = DialogPrimitives.CloseTrigger;
const drawerContentStyle = cva(
"bg-base-0 fixed z-[60] flex flex-col p-4 transition-all duration-500 data-[state=open]:visible data-[state=closed]:invisible",
{
variants: {
side: {
top: "left-0 right-0 top-0 max-h-[90%] min-h-96 data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0",
left: "max-w-screen bottom-0 left-0 top-0 min-w-96 data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0",
right:
"max-w-screen bottom-0 right-0 top-0 min-w-96 data-[state=closed]:translate-x-full data-[state=open]:translate-x-0",
bottom:
"bottom-0 left-0 right-0 max-h-[90%] min-h-96 data-[state=closed]:translate-y-full data-[state=open]:translate-y-0",
},
},
defaultVariants: {
side: "left",
},
},
);
export const DrawerContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitives.Content> &
VariantProps<typeof drawerContentStyle>,
React.ComponentPropsWithoutRef<typeof DialogPrimitives.Content> &
VariantProps<typeof drawerContentStyle>
>(({ className, side, ...props }, ref) => (
<>
<DialogPrimitives.Backdrop className="duration-4000 pointer-events-none fixed inset-0 z-50 block bg-neutral-800 bg-opacity-0 backdrop-blur-sm backdrop-brightness-50 transition-all data-[state=open]:visible data-[state=closed]:invisible data-[state=open]:bg-opacity-50" />
<DialogPrimitives.Positioner className="fixed left-0 top-0 z-50 h-screen w-screen">
<DialogPrimitives.Content
ref={ref}
className={drawerContentStyle({ side })}
{...props}
/>
</DialogPrimitives.Positioner>
</>
));
DrawerContent.displayName = "DrawerContent";
export const DrawerCloseButton = React.forwardRef<
React.ElementRef<typeof DialogPrimitives.CloseTrigger>,
React.ComponentPropsWithoutRef<typeof DialogPrimitives.CloseTrigger>
>(({ className, ...props }, ref) => (
<DialogPrimitives.CloseTrigger ref={ref} asChild {...props}>
<IconButton size="sm" variant="outline" colorScheme="black">
<IconX className="h-4 w-4" />
</IconButton>
</DialogPrimitives.CloseTrigger>
));
DrawerCloseButton.displayName = "DrawerCloseButton";
import {
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "../core/drawer";
import { Button } from "../core/button";
export const DrawerExample = () => {
return (
<Drawer>
<DrawerTrigger asChild>
<Button variant="outline" colorScheme="black">
Open left drawer
</Button>
</DrawerTrigger>
<DrawerContent side="left">
<DrawerHeader>
<DrawerTitle>Title</DrawerTitle>
<DrawerCloseButton />
</DrawerHeader>
<DrawerBody>
<div className="h-screen">A</div>
<div className="h-screen">B</div>
<div className="h-screen">C</div>
<div className="h-screen">D</div>
</DrawerBody>
</DrawerContent>
</Drawer>
);
};