From f12476344a9356323e393d9ecdb0ebda3af25206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Wed, 11 Nov 2026 22:21:11 +0100 Subject: [PATCH 1/6] feat: add drawer shadcn component --- frontend/app/components/ui/Drawer.tsx | 225 ++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 frontend/app/components/ui/Drawer.tsx diff --git a/frontend/app/components/ui/Drawer.tsx b/frontend/app/components/ui/Drawer.tsx new file mode 100644 index 00000000..d39d8a81 --- /dev/null +++ b/frontend/app/components/ui/Drawer.tsx @@ -0,0 +1,225 @@ +import * as React from "react"; +import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer"; +import { cn } from "cn"; + +type DrawerContextProps = { + hasSnapPoints: boolean; + modal: DrawerPrimitive.Root.Props["modal"]; + showSwipeHandle: boolean; + swipeDirection: NonNullable; +}; + +const DrawerContext = React.createContext(null); + +function useDrawer() { + const context = React.useContext(DrawerContext); + + if (!context) { + throw new Error("useDrawer must be used within a Drawer."); + } + + return context; +} + +function Drawer({ + modal = true, + showSwipeHandle = false, + snapPoints, + swipeDirection = "down", + ...props +}: DrawerPrimitive.Root.Props & { + showSwipeHandle?: boolean; +}) { + const hasSnapPoints = snapPoints != null && snapPoints.length > 0; + const contextValue = React.useMemo( + () => ({ hasSnapPoints, modal, showSwipeHandle, swipeDirection }), + [hasSnapPoints, modal, showSwipeHandle, swipeDirection], + ); + + return ( + + + + ); +} + +function DrawerTrigger({ ...props }: DrawerPrimitive.Trigger.Props) { + return ; +} + +function DrawerPortal({ ...props }: DrawerPrimitive.Portal.Props) { + return ; +} + +function DrawerClose({ ...props }: DrawerPrimitive.Close.Props) { + return ; +} + +function DrawerOverlay({ + className, + ...props +}: DrawerPrimitive.Backdrop.Props) { + return ( + + ); +} + +function DrawerSwipeHandle({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +