-
-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: export useDrawerContext #467
base: main
Are you sure you want to change the base?
Conversation
@@ -1112,3 +1112,5 @@ export const Drawer = { | |||
Title: DialogPrimitive.Title, | |||
Description: DialogPrimitive.Description, | |||
}; | |||
|
|||
export { DrawerContext, useDrawerContext }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to export DrawerContext
? This can't be used externally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emilkowalski Hi, Is it any way to get access to context to close drawer?
Hey @emilkowalski, you're right that My use case requires knowing the value of the
I'm currently using a custom Here's the full implementation for context. It builds upon the shadcn/ui Drawer component. components/ui/drawer.tsx'use client';
import * as React from 'react';
import { Cross2Icon } from '@radix-ui/react-icons';
import { cva } from 'class-variance-authority';
import { Drawer as DrawerPrimitive } from 'vaul';
import { cn } from '@/lib/utils';
type DrawerContextValue = Pick<DrawerProps, 'direction'>;
const DrawerContext = React.createContext<DrawerContextValue>({});
const useDrawerContext = () => {
const context = React.useContext(DrawerContext);
if (!context) {
throw new Error('useDrawerContext must be used within a Drawer.Root');
}
return context;
};
export type DrawerProps = React.ComponentProps<typeof DrawerPrimitive.Root>;
const Drawer = ({
shouldScaleBackground = true,
direction = 'bottom',
...props
}: DrawerProps) => (
<DrawerContext.Provider value={{ direction }}>
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
direction={direction}
{...props}
/>
</DrawerContext.Provider>
);
Drawer.displayName = 'Drawer';
const DrawerTrigger = DrawerPrimitive.Trigger;
const DrawerPortal = DrawerPrimitive.Portal;
const DrawerClose = DrawerPrimitive.Close;
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn('fixed inset-0 z-50 bg-black/80', className)}
{...props}
/>
));
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
const drawContentVariants = cva(
'fixed z-50 flex flex-col bg-background outline-none',
{
variants: {
direction: {
top: 'inset-x-0 top-0 mb-24 h-auto max-h-[90%] rounded-b-[10px]',
bottom: 'inset-x-0 bottom-0 mt-24 h-auto max-h-[90%] rounded-t-[10px]',
left: 'inset-y-0 left-0 mr-24 w-full max-w-[85%] rounded-r-[10px] lg:max-w-3xl',
right:
'inset-y-0 right-0 ml-24 w-full max-w-[85%] rounded-l-[10px] lg:max-w-3xl',
},
},
defaultVariants: {
direction: 'bottom',
},
},
);
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => {
const { direction } = useDrawerContext();
const isHorizontal = direction === 'left' || direction === 'right';
return (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(drawContentVariants({ direction }), className)}
{...props}
>
{direction === 'bottom' && <DrawerHandle />}
<div
className={cn(
'flex-grow overflow-y-auto',
direction !== 'bottom' && 'pt-3',
)}
>
{children}
</div>
{direction === 'top' && <DrawerHandle />}
{isHorizontal && (
<DrawerClose className="absolute right-6 top-6 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]:text-muted-foreground">
<Cross2Icon className="size-5" />
<span className="sr-only">Close</span>
</DrawerClose>
)}
</DrawerPrimitive.Content>
</DrawerPortal>
);
});
DrawerContent.displayName = 'DrawerContent';
const DrawerHandle = () => (
<div className="pb-2 pt-1.5">
<DrawerPrimitive.Handle />
</div>
);
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn('grid gap-1.5 p-4 text-left sm:px-6', className)}
{...props}
/>
);
DrawerHeader.displayName = 'DrawerHeader';
const DrawerBody = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn('mt-auto flex flex-col px-4 sm:px-6', className)}
{...props}
/>
);
DrawerBody.displayName = 'DrawerBody';
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
{...props}
/>
);
DrawerFooter.displayName = 'DrawerFooter';
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
'text-lg font-semibold leading-none tracking-tight',
className,
)}
{...props}
/>
));
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
));
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}; This workaround is sufficient, so feel free to close this PR if there are specific issues with exporting |
I also have a need to access |
Is there anything blocking merging this? I have the exact use case as the author |
Vaul doesn't currently export the
useDrawerContext
hook, which would be helpful for getting thedirection
of the<Drawer.Root>
to style the<Drawer.Content>
appropriately.For context, I'm updating my instance of the shadcn/ui Drawer component to support all directions (similar to the Sheet component).
This PR exports
useDrawerContext
andDrawerContext
, and includes some format fixes for the new JSDocs.