{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sheet",
  "title": "Sheet",
  "description": "A panel that slides in from an edge of the screen to complement the main content, built on Base UI.",
  "dependencies": [
    "@base-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "@persianlabsui/button"
  ],
  "files": [
    {
      "path": "registry/base/ui/sheet.tsx",
      "content": "\"use client\"\n\nimport { Dialog as SheetPrimitive } from \"@base-ui/react/dialog\"\nimport { XIcon } from \"lucide-react\"\nimport * as React from \"react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { cn } from \"@/lib/utils\"\n\ntype SheetSide = \"top\" | \"right\" | \"bottom\" | \"left\" | \"start\" | \"end\"\n\n/**\n * SheetContent renders through a Portal, so it doesn't inherit `dir` from a\n * nearby wrapper (only from document.documentElement). SheetTrigger measures\n * the ambient direction where it's actually rendered and pushes it here so\n * SheetContent can apply it explicitly to the portaled popup, and so a\n * logical `side=\"start\"`/`\"end\"` can resolve to the correct physical edge.\n */\nconst SheetDirContext = React.createContext<{\n  dir: \"ltr\" | \"rtl\"\n  setDir: (dir: \"ltr\" | \"rtl\") => void\n}>({ dir: \"ltr\", setDir: () => {} })\n\nfunction Sheet({ ...props }: SheetPrimitive.Root.Props) {\n  const [dir, setDir] = React.useState<\"ltr\" | \"rtl\">(\"ltr\")\n  const contextValue = React.useMemo(() => ({ dir, setDir }), [dir])\n\n  return (\n    <SheetDirContext.Provider value={contextValue}>\n      <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n    </SheetDirContext.Provider>\n  )\n}\n\nfunction SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {\n  const ref = React.useRef<HTMLButtonElement>(null)\n  const { setDir } = React.useContext(SheetDirContext)\n\n  React.useEffect(() => {\n    function update() {\n      if (!ref.current) return\n      setDir(getComputedStyle(ref.current).direction === \"rtl\" ? \"rtl\" : \"ltr\")\n    }\n\n    update()\n\n    const observer = new MutationObserver(update)\n    observer.observe(document.documentElement, {\n      attributes: true,\n      attributeFilter: [\"dir\"],\n      subtree: true,\n    })\n\n    return () => observer.disconnect()\n  }, [setDir])\n\n  return (\n    <SheetPrimitive.Trigger ref={ref} data-slot=\"sheet-trigger\" {...props} />\n  )\n}\n\nfunction SheetClose({ ...props }: SheetPrimitive.Close.Props) {\n  return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {\n  return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {\n  return (\n    <SheetPrimitive.Backdrop\n      data-slot=\"sheet-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetContent({\n  className,\n  children,\n  side = \"end\",\n  showCloseButton = true,\n  ...props\n}: SheetPrimitive.Popup.Props & {\n  side?: SheetSide\n  showCloseButton?: boolean\n}) {\n  const { dir } = React.useContext(SheetDirContext)\n\n  // Resolve logical start/end to the physical edge for the ambient direction.\n  const resolvedSide: Exclude<SheetSide, \"start\" | \"end\"> =\n    side === \"start\"\n      ? dir === \"rtl\"\n        ? \"right\"\n        : \"left\"\n      : side === \"end\"\n        ? dir === \"rtl\"\n          ? \"left\"\n          : \"right\"\n        : side\n\n  return (\n    <SheetPortal>\n      <SheetOverlay />\n      <SheetPrimitive.Popup\n        dir={dir}\n        data-slot=\"sheet-content\"\n        data-side={resolvedSide}\n        className={cn(\n          \"fixed z-50 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition-[opacity,translate] duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm\",\n          className\n        )}\n        {...props}\n      >\n        {/* Safe-area padding lives on this inner, non-animated wrapper rather\n            than the translate-animated Popup above — env() padding on the\n            same element being translated caused visibly laggy open/close\n            transitions. */}\n        <div\n          className={cn(\n            \"flex h-full flex-col gap-4\",\n            resolvedSide === \"bottom\" && \"pb-[env(safe-area-inset-bottom)]\",\n            resolvedSide === \"left\" && \"pl-[env(safe-area-inset-left)]\",\n            resolvedSide === \"right\" && \"pr-[env(safe-area-inset-right)]\"\n          )}\n        >\n          {children}\n        </div>\n        {showCloseButton && (\n          <SheetPrimitive.Close\n            data-slot=\"sheet-close\"\n            render={\n              <Button\n                variant=\"ghost\"\n                className=\"absolute end-3 top-3\"\n                size=\"icon-sm\"\n              />\n            }\n          >\n            <XIcon />\n            <span className=\"sr-only\">Close</span>\n          </SheetPrimitive.Close>\n        )}\n      </SheetPrimitive.Popup>\n    </SheetPortal>\n  )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-header\"\n      className={cn(\"flex flex-col gap-0.5 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-footer\"\n      className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {\n  return (\n    <SheetPrimitive.Title\n      data-slot=\"sheet-title\"\n      className={cn(\n        \"font-heading text-base font-medium text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetDescription({\n  className,\n  ...props\n}: SheetPrimitive.Description.Props) {\n  return (\n    <SheetPrimitive.Description\n      data-slot=\"sheet-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetOverlay,\n  SheetPortal,\n  SheetTitle,\n  SheetTrigger,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}