{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "extends": "none",
  "name": "drawer",
  "title": "drawer",
  "description": "drawer",
  "dependencies": [
    "motion",
    "react-aria-components",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://intentui.com/r/primitive",
    "https://intentui.com/r/button"
  ],
  "files": [
    {
      "path": "src/components/ui/drawer.tsx",
      "content": "'use client'\n\nimport { AnimatePresence, motion } from 'motion/react'\nimport { use } from 'react'\nimport { Button as ButtonPrimitive } from 'react-aria-components/Button'\nimport type { DialogProps, DialogTriggerProps } from 'react-aria-components/Dialog'\nimport { Dialog, DialogTrigger, OverlayTriggerStateContext } from 'react-aria-components/Dialog'\nimport { Heading, type HeadingProps } from 'react-aria-components/Heading'\nimport {\n  Modal as ModalPrimitive,\n  ModalOverlay,\n  type ModalOverlayProps,\n} from 'react-aria-components/Modal'\nimport { Text, type TextProps } from 'react-aria-components/Text'\nimport { twJoin, twMerge } from 'tailwind-merge'\nimport { cx } from '@/lib/primitive'\nimport { Button, type ButtonProps } from './button'\n\nconst DrawerRoot = motion.create(ModalPrimitive)\nconst DrawerOverlay = motion.create(ModalOverlay)\n\nconst Drawer = (props: DialogTriggerProps) => <DialogTrigger {...props} />\n\ninterface DrawerContentProps\n  extends\n    Omit<ModalOverlayProps, 'className' | 'children' | 'isDismissable'>,\n    Pick<DialogProps, 'aria-label' | 'aria-labelledby' | 'role' | 'children' | 'className'> {\n  isFloat?: boolean\n  className?: string\n  overlay?: Pick<ModalOverlayProps, 'className'>\n  side?: 'top' | 'bottom' | 'left' | 'right'\n  notch?: boolean\n}\n\nconst DrawerContent = ({\n  side = 'bottom',\n  isFloat = false,\n  notch = true,\n  children,\n  className,\n  overlay,\n  ...props\n}: DrawerContentProps) => {\n  const state = use(OverlayTriggerStateContext)!\n  const isOpen = props.isOpen ?? state?.isOpen ?? false\n  const onOpenChange = props.onOpenChange ?? state?.setOpen\n\n  return (\n    <AnimatePresence>\n      {isOpen && (\n        <DrawerOverlay\n          isDismissable\n          isOpen={isOpen}\n          onOpenChange={onOpenChange}\n          initial={{\n            backgroundColor: 'rgba(0, 0, 0, 0)',\n            backdropFilter: 'blur(0px)',\n          }}\n          animate={{\n            backgroundColor: 'rgba(0, 0, 0, 0.2)',\n            backdropFilter: 'blur(1px)',\n          }}\n          exit={{\n            backgroundColor: 'rgba(0, 0, 0, 0)',\n            backdropFilter: 'blur(0px)',\n          }}\n          transition={{ duration: 0.15, ease: 'easeInOut' }}\n          className={cx(\n            'fixed inset-0 z-50 will-change-auto [--visual-viewport-vertical-padding:32px]',\n            'motion-reduce:backdrop-blur-none',\n            overlay?.className\n          )}\n        >\n          {({ state }) => (\n            <DrawerRoot\n              className={twJoin(\n                'fixed max-h-full touch-none overflow-hidden bg-bg align-middle text-fg ring ring-input will-change-transform',\n                side === 'top' &&\n                  (isFloat ? 'inset-x-2 top-2 rounded-lg' : 'inset-x-0 top-0 rounded-b-2xl'),\n                side === 'right' && [\n                  'w-full max-w-xs overflow-y-auto',\n                  '**:[[slot=header]]:text-start',\n                  isFloat ? 'inset-y-2 right-2 rounded-lg' : 'inset-y-0 right-0 h-auto',\n                ],\n                side === 'bottom' &&\n                  (isFloat ? 'inset-x-2 bottom-2 rounded-lg' : 'inset-x-0 bottom-0 rounded-t-2xl'),\n                side === 'left' && [\n                  'w-full max-w-xs overflow-y-auto',\n                  '**:[[slot=header]]:text-start',\n                  isFloat ? 'inset-y-2 left-2 rounded-lg' : 'inset-y-0 left-0 h-auto',\n                ],\n                className\n              )}\n              animate={{ x: 0, y: 0 }}\n              initial={{\n                x: side === 'left' ? '-100%' : side === 'right' ? '100%' : 0,\n                y: side === 'top' ? '-100%' : side === 'bottom' ? '100%' : 0,\n              }}\n              exit={{\n                x: side === 'left' ? '-100%' : side === 'right' ? '100%' : 0,\n                y: side === 'top' ? '-100%' : side === 'bottom' ? '100%' : 0,\n              }}\n              drag={side === 'left' || side === 'right' ? 'x' : 'y'}\n              whileDrag={{ cursor: 'grabbing' }}\n              dragConstraints={{\n                top: 0,\n                bottom: 0,\n                left: 0,\n                right: 0,\n              }}\n              dragTransition={{\n                bounceStiffness: 600,\n                bounceDamping: 20,\n              }}\n              transition={{ duration: 0.15, ease: 'easeInOut' }}\n              onDragEnd={(_, { offset, velocity }) => {\n                if (side === 'bottom' && (velocity.y > 150 || offset.y > screen.height * 0.25)) {\n                  state.close()\n                }\n                if (side === 'top' && (velocity.y < -150 || offset.y < screen.height * 0.25)) {\n                  state.close()\n                }\n                if (side === 'left' && velocity.x < -150) {\n                  state.close()\n                }\n                if (side === 'right' && velocity.x > 150) {\n                  state.close()\n                }\n              }}\n              dragElastic={{\n                top: side === 'top' ? 1 : 0,\n                bottom: side === 'bottom' ? 1 : 0,\n                left: side === 'left' ? 1 : 0,\n                right: side === 'right' ? 1 : 0,\n              }}\n              dragPropagation\n            >\n              <Dialog\n                aria-label=\"Drawer\"\n                role=\"dialog\"\n                className={twJoin(\n                  'relative flex flex-col overflow-hidden outline-hidden will-change-auto',\n                  side === 'top' || side === 'bottom'\n                    ? 'mx-auto max-h-[calc(var(--visual-viewport-height)-var(--visual-viewport-vertical-padding))] max-w-lg'\n                    : 'h-full'\n                )}\n              >\n                {notch && side === 'bottom' && (\n                  <div className=\"notch sticky top-0 mx-auto mt-2.5 h-1.5 w-10 shrink-0 touch-pan-y rounded-full bg-fg/20\" />\n                )}\n                {children as React.ReactNode}\n                {notch && side === 'top' && (\n                  <div className=\"notch sticky bottom-0 mx-auto mb-2.5 h-1.5 w-10 shrink-0 touch-pan-y rounded-full bg-fg/20\" />\n                )}\n              </Dialog>\n            </DrawerRoot>\n          )}\n        </DrawerOverlay>\n      )}\n    </AnimatePresence>\n  )\n}\n\nconst DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => {\n  return (\n    <div\n      slot=\"header\"\n      className={twMerge('flex flex-col p-4 text-center sm:text-start', className)}\n      {...props}\n    />\n  )\n}\n\nconst DrawerTitle = ({ className, ...props }: HeadingProps) => (\n  <Heading slot=\"title\" className={twMerge('font-semibold text-lg/8', className)} {...props} />\n)\n\nconst DrawerDescription = ({ className, ...props }: TextProps) => (\n  <Text slot=\"description\" className={twMerge('text-muted-fg text-sm', className)} {...props} />\n)\n\nconst DrawerBody = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    slot=\"body\"\n    className={twMerge(\n      'isolate flex max-h-[calc(var(--visual-viewport-height)-var(--visual-viewport-vertical-padding))] flex-col overflow-auto px-4 py-1 will-change-scroll',\n      className\n    )}\n    {...props}\n  />\n)\n\nconst DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => {\n  return (\n    <div\n      slot=\"footer\"\n      className={twMerge(\n        'isolate mt-auto flex flex-col-reverse justify-end gap-2 p-4 sm:flex-row',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst DrawerClose = ({ className, intent = 'outline', ref, ...props }: ButtonProps) => {\n  return <Button slot=\"close\" className={className} ref={ref} intent={intent} {...props} />\n}\n\nconst DrawerTrigger = ButtonPrimitive\n\nexport type { DrawerContentProps }\nexport {\n  Drawer,\n  DrawerBody,\n  DrawerClose,\n  DrawerContent,\n  DrawerDescription,\n  DrawerFooter,\n  DrawerHeader,\n  DrawerTitle,\n  DrawerTrigger,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}