refactor(base-drawer): rewrite base drawer wrapper for @base-ui/react/drawer

Replace vaul with @base-ui/react/drawer as the primitive behind the
base drawer wrapper.

Keep the public API aligned with the radix drawer shape while
rewriting DrawerContent to compose Backdrop, Viewport, Popup, and
Content internally.

Keep the registry dependency change in the same commit so the wrapper
rewrite lands as one source-level migration step.
This commit is contained in:
coi
2026-04-18 03:10:23 +09:00
parent 84d1d476b1
commit 07ab679555
2 changed files with 37 additions and 35 deletions

View File

@@ -351,7 +351,7 @@ export const ui: Registry["items"] = [
{
name: "drawer",
type: "registry:ui",
dependencies: ["vaul"],
dependencies: ["@base-ui/react"],
files: [
{
path: "ui/drawer.tsx",
@@ -363,7 +363,7 @@ export const ui: Registry["items"] = [
docs: "https://ui.shadcn.com/docs/components/base/drawer",
examples:
"https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/drawer-example.tsx",
api: "https://vaul.emilkowal.ski/getting-started",
api: "https://base-ui.com/react/components/drawer.md",
},
},
},

View File

@@ -1,42 +1,37 @@
"use client"
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer"
import { cn } from "@/registry/bases/base/lib/utils"
function Drawer({
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) {
function Drawer({ ...props }: DrawerPrimitive.Root.Props) {
return <DrawerPrimitive.Root data-slot="drawer" {...props} />
}
function DrawerTrigger({
...props
}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
function DrawerTrigger({ ...props }: DrawerPrimitive.Trigger.Props) {
return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />
}
function DrawerPortal({
...props
}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
function DrawerPortal({ ...props }: DrawerPrimitive.Portal.Props) {
return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />
}
function DrawerClose({
...props
}: React.ComponentProps<typeof DrawerPrimitive.Close>) {
function DrawerClose({ ...props }: DrawerPrimitive.Close.Props) {
return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />
}
function DrawerOverlay({
className,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
}: DrawerPrimitive.Backdrop.Props) {
return (
<DrawerPrimitive.Overlay
<DrawerPrimitive.Backdrop
data-slot="drawer-overlay"
className={cn("cn-drawer-overlay fixed inset-0 z-50", className)}
className={cn(
"cn-drawer-overlay fixed inset-0 z-50 opacity-[calc(1-var(--drawer-swipe-progress))] transition-opacity duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] data-ending-style:opacity-0 data-starting-style:opacity-0 data-swiping:duration-0",
className
)}
{...props}
/>
)
@@ -46,21 +41,28 @@ function DrawerContent({
className,
children,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Content>) {
}: DrawerPrimitive.Popup.Props) {
return (
<DrawerPortal data-slot="drawer-portal">
<DrawerOverlay />
<DrawerPrimitive.Content
data-slot="drawer-content"
className={cn(
"cn-drawer-content group/drawer-content fixed z-50",
className
)}
{...props}
<DrawerPrimitive.Viewport
data-slot="drawer-viewport"
className="pointer-events-none fixed inset-0 z-50"
>
<div className="cn-drawer-handle mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
{children}
</DrawerPrimitive.Content>
<DrawerPrimitive.Popup
data-slot="drawer-content"
className={cn(
"cn-drawer-content group/drawer-content pointer-events-auto fixed z-50 transform-(--drawer-transform) overflow-hidden transition-transform duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] will-change-transform [--drawer-bleed-x:3rem] [--drawer-bleed-y:3rem] data-ending-style:transform-(--drawer-closed-transform) data-starting-style:transform-(--drawer-closed-transform) data-swiping:duration-0 data-swiping:select-none data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:mt-24 data-[swipe-direction=down]:-mb-(--drawer-bleed-y) data-[swipe-direction=down]:max-h-[calc(80vh+var(--drawer-bleed-y))] data-[swipe-direction=down]:pb-(--drawer-bleed-y) data-[swipe-direction=down]:[--drawer-closed-transform:translate3d(0,100%,0)] data-[swipe-direction=down]:[--drawer-transform:translate3d(0,var(--drawer-swipe-movement-y),0)] data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:-ml-(--drawer-bleed-x) data-[swipe-direction=left]:w-[calc(75%+var(--drawer-bleed-x))] data-[swipe-direction=left]:pl-(--drawer-bleed-x) data-[swipe-direction=left]:[--drawer-closed-transform:translate3d(-100%,0,0)] data-[swipe-direction=left]:[--drawer-transform:translate3d(var(--drawer-swipe-movement-x),0,0)] data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:-mr-(--drawer-bleed-x) data-[swipe-direction=right]:w-[calc(75%+var(--drawer-bleed-x))] data-[swipe-direction=right]:pr-(--drawer-bleed-x) data-[swipe-direction=right]:[--drawer-closed-transform:translate3d(100%,0,0)] data-[swipe-direction=right]:[--drawer-transform:translate3d(var(--drawer-swipe-movement-x),0,0)] data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:-mt-(--drawer-bleed-y) data-[swipe-direction=up]:mb-24 data-[swipe-direction=up]:max-h-[calc(80vh+var(--drawer-bleed-y))] data-[swipe-direction=up]:pt-(--drawer-bleed-y) data-[swipe-direction=up]:[--drawer-closed-transform:translate3d(0,-100%,0)] data-[swipe-direction=up]:[--drawer-transform:translate3d(0,var(--drawer-swipe-movement-y),0)] data-[swipe-direction=left]:sm:w-[calc(24rem+var(--drawer-bleed-x))] data-[swipe-direction=right]:sm:w-[calc(24rem+var(--drawer-bleed-x))]",
className
)}
{...props}
>
<div className="cn-drawer-handle mx-auto hidden shrink-0 group-data-[swipe-direction=down]/drawer-content:block" />
<DrawerPrimitive.Content className="flex min-h-0 flex-1 flex-col">
{children}
</DrawerPrimitive.Content>
</DrawerPrimitive.Popup>
</DrawerPrimitive.Viewport>
</DrawerPortal>
)
}
@@ -69,7 +71,10 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="drawer-header"
className={cn("cn-drawer-header flex flex-col", className)}
className={cn(
"cn-drawer-header flex flex-col group-data-[swipe-direction=down]/drawer-content:text-center group-data-[swipe-direction=up]/drawer-content:text-center",
className
)}
{...props}
/>
)
@@ -85,10 +90,7 @@ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
)
}
function DrawerTitle({
className,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Title>) {
function DrawerTitle({ className, ...props }: DrawerPrimitive.Title.Props) {
return (
<DrawerPrimitive.Title
data-slot="drawer-title"
@@ -101,7 +103,7 @@ function DrawerTitle({
function DrawerDescription({
className,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
}: DrawerPrimitive.Description.Props) {
return (
<DrawerPrimitive.Description
data-slot="drawer-description"