{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "Drawer",
  "dependencies": [
    "@base-ui/react",
    "cn",
    "rescript-base-ui"
  ],
  "files": [
    {
      "path": "registry/base/ui/Drawer.res",
      "content": "@@directive(\"'use client'\")\n\n@@jsxConfig({version: 4, mode: \"automatic\", module_: \"BaseUi.BaseUiJsxDOM\"})\n\n@module(\"cn\")\nexternal cn: (string, option<string>) => string = \"cn\"\n\nmodule SwipeDirection = {\n  @unboxed\n  type t = BaseUi.Drawer.swipeDirection =\n    | @as(\"down\") Down\n    | @as(\"up\") Up\n    | @as(\"left\") Left\n    | @as(\"right\") Right\n}\n\nmodule SnapPoint = {\n  @unboxed\n  type t = BaseUi.Drawer.snapPoint =\n    | Pixels(string)\n    | Ratio(float)\n}\n\ntype context = {\n  hasSnapPoints: bool,\n  modal: BaseUi.Types.Modal.t,\n  showSwipeHandle: bool,\n  swipeDirection: SwipeDirection.t,\n}\n\nlet drawerContext = React.createContext(Nullable.null)\n\nmodule ContextProvider = {\n  let make = React.Context.provider(drawerContext)\n}\n\nlet use = () =>\n  switch React.useContext(drawerContext) {\n  | Value(context) => context\n  | Null | Undefined => throw(Invalid_argument(\"useDrawer must be used within a Drawer.\"))\n  }\n\ntype props = {\n  ...BaseUi.Drawer.Root.props,\n  showSwipeHandle?: bool,\n}\n\nlet rootProps: props => BaseUi.Drawer.Root.props = %raw(`({showSwipeHandle, ...props}) => props`)\n\n@react.componentWithProps(props)\nlet make = (props: props) => {\n  let modal = props.modal->Option.getOr(BaseUi.Types.Modal.True)\n  let showSwipeHandle = props.showSwipeHandle->Option.getOr(false)\n  let swipeDirection = props.swipeDirection->Option.getOr(SwipeDirection.Down)\n  let hasSnapPoints =\n    props.snapPoints->Option.mapOr(false, snapPoints => snapPoints->Array.length > 0)\n  let value = {hasSnapPoints, modal, showSwipeHandle, swipeDirection}\n\n  <ContextProvider value={value->Nullable.make}>\n    <BaseUi.Drawer.Root\n      {...props->rootProps} dataSlot={props.dataSlot->Option.getOr(\"drawer\")} modal swipeDirection\n    />\n  </ContextProvider>\n}\n\nmodule Trigger = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Trigger {...props} dataSlot={props.dataSlot->Option.getOr(\"drawer-trigger\")} />\n}\n\nmodule Portal = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Portal {...props} dataSlot={props.dataSlot->Option.getOr(\"drawer-portal\")} />\n}\n\nmodule Close = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Close {...props} dataSlot={props.dataSlot->Option.getOr(\"drawer-close\")} />\n}\n\nmodule Overlay = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Backdrop\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-overlay\")}\n      className={cn(\n        \"bg-black/10 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50 min-h-dvh opacity-[max(var(--drawer-overlay-min-opacity,0),calc(1-var(--drawer-swipe-progress)))] transition-opacity duration-450 ease-[cubic-bezier(0.32,0.72,0,1)] select-none data-ending-style:pointer-events-none data-ending-style:opacity-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-snap-points:[--drawer-overlay-min-opacity:0.5] data-starting-style:opacity-0 data-swiping:duration-0 supports-[-webkit-touch-callout:none]:absolute\",\n        props.className,\n      )}\n    />\n}\n\nmodule SwipeHandle = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-swipe-handle\")}\n      ariaHidden={props.ariaHidden->Option.getOr(true)}\n      className={cn(\n        \"after:block after:shrink-0 after:rounded-full after:bg-muted group-data-[swipe-axis=y]/drawer-popup:h-3 group-data-[swipe-axis=y]/drawer-popup:w-full group-data-[swipe-axis=y]/drawer-popup:justify-center group-data-[swipe-axis=y]/drawer-popup:after:h-1 group-data-[swipe-axis=y]/drawer-popup:after:w-24 group-data-[swipe-direction=down]/drawer-popup:items-end group-data-[swipe-direction=up]/drawer-popup:items-start group-data-[swipe-axis=x]/drawer-popup:h-full group-data-[swipe-axis=x]/drawer-popup:w-3 group-data-[swipe-axis=x]/drawer-popup:items-center group-data-[swipe-axis=x]/drawer-popup:after:h-24 group-data-[swipe-axis=x]/drawer-popup:after:w-1 group-data-[swipe-direction=left]/drawer-popup:justify-start group-data-[swipe-direction=right]/drawer-popup:justify-end relative z-10 flex shrink-0 cursor-grab transition-opacity duration-200 group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-[swipe-direction=left]/drawer-popup:order-last group-data-[swipe-direction=up]/drawer-popup:order-last active:cursor-grabbing\",\n        props.className,\n      )}\n    />\n}\n\nlet popupClass = \"bg-popover text-popover-foreground text-sm data-[swipe-direction=down]:rounded-t-xl data-[swipe-direction=down]:border-t data-[swipe-direction=left]:rounded-r-xl data-[swipe-direction=left]:border-r data-[swipe-direction=right]:rounded-l-xl data-[swipe-direction=right]:border-l data-[swipe-direction=up]:rounded-b-xl data-[swipe-direction=up]:border-b group/drawer-popup pointer-events-auto fixed z-50 m-(--drawer-inset,0px) flex h-(--drawer-content-height) max-h-(--drawer-content-max-height,none) min-h-0 w-(--drawer-content-width,auto) transform-[translate3d(var(--translate-x,0px),var(--translate-y,0px),0)_scale(var(--stack-scale))] flex-col transition-[transform,height,opacity,filter] duration-450 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform outline-none select-none [interpolate-size:allow-keywords] data-nested-drawer-open:overflow-hidden data-nested-drawer-open:brightness-95 after:pointer-events-none after:absolute after:bg-(--drawer-bleed-background,var(--color-popover)) data-[swipe-axis=x]:after:inset-y-0 data-[swipe-axis=x]:after:w-(--bleed) data-[swipe-axis=y]:after:inset-x-0 data-[swipe-axis=y]:after:h-(--bleed) data-[swipe-direction=down]:after:top-full data-[swipe-direction=left]:after:right-full data-[swipe-direction=right]:after:left-full data-[swipe-direction=up]:after:bottom-full [--drawer-content-height:var(--drawer-height,auto)] data-[swipe-axis=x]:[--drawer-content-width:75%] data-[swipe-axis=y]:[--drawer-content-max-height:calc(100dvh-6rem)] data-[swipe-axis=y]:data-snap-points:[--drawer-content-height:100dvh] data-[swipe-axis=x]:sm:[--drawer-content-width:24rem] [--bleed:3rem] [--peek:1rem] [--stack-height:var(--drawer-frontmost-height,var(--drawer-height,0px))] [--stack-peek-offset:max(0px,calc((var(--nested-drawers)-var(--stack-progress))*var(--peek)))] [--stack-progress:clamp(0,var(--drawer-swipe-progress),1)] [--stack-scale-base:max(0,calc(1-(var(--nested-drawers)*var(--stack-step))))] [--stack-scale:clamp(0,calc(var(--stack-scale-base)+(var(--stack-step)*var(--stack-progress))),1)] [--stack-shrink:calc(1-var(--stack-scale))] [--stack-step:0.05] data-ending-style:transform-(--closed-transform) data-ending-style:opacity-[0.9999] data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-nested-drawer-swiping:duration-0 data-ending-style:data-nested-drawer-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-starting-style:transform-(--closed-transform) data-swiping:duration-0 data-ending-style:data-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-[swipe-axis=y]:inset-x-0 data-[swipe-axis=y]:data-nested-drawer-open:h-(--stack-height) data-[swipe-axis=x]:inset-y-0 data-[swipe-axis=x]:flex-row data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:origin-bottom data-[swipe-direction=down]:[--closed-transform:translate3d(0,calc(100%+var(--drawer-inset,0px)+2px),0)] data-[swipe-direction=down]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)-var(--stack-peek-offset)-(var(--stack-shrink)*var(--stack-height)))] data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:origin-top data-[swipe-direction=up]:[--closed-transform:translate3d(0,calc(-100%-var(--drawer-inset,0px)-2px),0)] data-[swipe-direction=up]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)+var(--stack-peek-offset)+(var(--stack-shrink)*var(--stack-height)))] data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:origin-left data-[swipe-direction=left]:[--closed-transform:translate3d(calc(-100%-var(--drawer-inset,0px)-2px),0,0)] data-[swipe-direction=left]:[--translate-x:calc(var(--drawer-swipe-movement-x)+var(--stack-peek-offset)+(var(--stack-shrink)*100%))] data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:origin-right data-[swipe-direction=right]:[--closed-transform:translate3d(calc(100%+var(--drawer-inset,0px)+2px),0,0)] data-[swipe-direction=right]:[--translate-x:calc(var(--drawer-swipe-movement-x)-var(--stack-peek-offset)-(var(--stack-shrink)*100%))]\"\n\nmodule Content = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) => {\n    let drawer = use()\n    let swipeAxis = switch drawer.swipeDirection {\n    | Down | Up => \"y\"\n    | Left | Right => \"x\"\n    }\n    let dataSnapPoints = drawer.hasSnapPoints ? Some(\"\") : None\n    let isModal = switch drawer.modal {\n    | True => true\n    | False | TrapFocus => false\n    }\n\n    <Portal>\n      {isModal ? <Overlay dataSnapPoints=?dataSnapPoints /> : React.null}\n      <BaseUi.Drawer.Viewport\n        dataSlot=\"drawer-viewport\"\n        dataModal=drawer.modal\n        className=\"pointer-events-none fixed inset-0 z-50 select-none data-[modal=true]:pointer-events-auto\"\n      >\n        <BaseUi.Drawer.Popup\n          {...props}\n          dataSlot={props.dataSlot->Option.getOr(\"drawer-popup\")}\n          dataSwipeAxis=swipeAxis\n          dataSnapPoints=?dataSnapPoints\n          className={cn(popupClass, props.className)}\n        >\n          {drawer.showSwipeHandle ? <SwipeHandle /> : React.null}\n          <BaseUi.Drawer.Content\n            dataSlot=\"drawer-content\"\n            className=\"flex min-h-0 flex-1 flex-col overflow-hidden overscroll-contain rounded-[inherit] transition-opacity duration-300 ease-[cubic-bezier(0.45,1.005,0,1.005)] select-text group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-swiping/drawer-popup:select-none\"\n          >\n            {props.children->Option.getOr(React.null)}\n          </BaseUi.Drawer.Content>\n        </BaseUi.Drawer.Popup>\n      </BaseUi.Drawer.Viewport>\n    </Portal>\n  }\n}\n\nmodule Header = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-header\")}\n      className={cn(\n        \"gap-0.5 p-4 pb-0 md:gap-0.5 md:text-left flex shrink-0 flex-col group-data-[swipe-axis=y]/drawer-popup:text-center\",\n        props.className,\n      )}\n    />\n}\n\nmodule Footer = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-footer\")}\n      className={cn(\"gap-2 p-4 pt-0 mt-auto flex shrink-0 flex-col\", props.className)}\n    />\n}\n\nmodule Title = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Title\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-title\")}\n      className={cn(\"text-foreground text-base font-medium font-heading\", props.className)}\n    />\n}\n\nmodule Description = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Drawer.Description\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"drawer-description\")}\n      className={cn(\"text-muted-foreground text-sm text-balance\", props.className)}\n    />\n}\n",
      "type": "registry:file",
      "target": "@ui/Drawer.res"
    }
  ],
  "type": "registry:ui"
}