{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sheet",
  "title": "Sheet",
  "description": "A sheet component.",
  "dependencies": [
    "class-variance-authority",
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "registryDependencies": [
    "@cubby-ui/button",
    "@cubby-ui/scroll-area",
    "@cubby-ui/elevated"
  ],
  "files": [
    {
      "path": "registry/default/sheet/sheet.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Dialog as BaseSheet } from \"@base-ui/react/dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/registry/default/button/button\";\nimport {\n  INNER_EDGE_FROM_ATTACH_SIDE,\n  elevatedSurface,\n  flushSurface,\n  type SurfaceLevel,\n} from \"@/registry/default/lib/elevated\";\nimport {\n  ScrollArea,\n  type ScrollAreaProps,\n} from \"@/registry/default/scroll-area/scroll-area\";\n\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Cancel01Icon } from \"@hugeicons/core-free-icons\";\nconst sheetContentVariants = cva(\n  [\n    \"text-popover-foreground fixed z-50 flex max-h-full min-h-0 w-full max-w-full min-w-0 flex-col outline-hidden\",\n    \"ease-[cubic-bezier(.32,.72,0,1)] transition-all duration-400\",\n    // Nested sheet support\n    \"scale-[calc(1-0.05*var(--nested-dialogs))]\",\n    // Nested sheet overlay — uses ::before (not ::after, that's the rim) at z-3 so it paints above content AND above the rim\n    \"before:pointer-events-none before:absolute before:inset-0 before:z-3 before:hidden before:rounded-[inherit] before:bg-black/15 before:opacity-0 before:transition-[opacity,display] before:duration-300 before:transition-discrete\",\n    \"data-nested-dialog-open:before:block data-nested-dialog-open:before:opacity-100\",\n    \"starting:data-nested-dialog-open:before:opacity-0\",\n  ],\n  {\n    variants: {\n      variant: {\n        // `default` no longer needs its own shadow/ring — the elevation system provides that\n        default: \"\",\n        floating:\n          \"max-h-[calc(100%-2rem)] w-[calc(100%-2rem)] max-w-[calc(100%-2rem)] rounded-2xl\",\n      },\n      side: {\n        top: \"\",\n        right: \"sm:max-w-md\",\n        bottom: \"\",\n        left: \"sm:max-w-md\",\n      },\n    },\n    compoundVariants: [\n      // Floating variants\n      {\n        variant: \"floating\",\n        side: \"right\",\n        class:\n          \"inset-y-4 right-4 -translate-x-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:translate-x-[calc(100%+1rem)] data-starting-style:translate-x-[calc(100%+1rem)]\",\n      },\n      {\n        variant: \"floating\",\n        side: \"left\",\n        class:\n          \"inset-y-4 left-4 translate-x-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:-translate-x-[calc(100%+1rem)] data-starting-style:-translate-x-[calc(100%+1rem)]\",\n      },\n      {\n        variant: \"floating\",\n        side: \"top\",\n        class:\n          \"inset-x-4 top-4 translate-y-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:-translate-y-[calc(100%+1rem)] data-starting-style:-translate-y-[calc(100%+1rem)]\",\n      },\n      {\n        variant: \"floating\",\n        side: \"bottom\",\n        class:\n          \"inset-x-4 bottom-4 -translate-y-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:translate-y-[calc(100%+1rem)] data-starting-style:translate-y-[calc(100%+1rem)]\",\n      },\n      // Default variants\n      {\n        variant: \"default\",\n        side: \"right\",\n        class:\n          \"inset-y-0 right-0 -translate-x-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:translate-x-full data-starting-style:translate-x-full\",\n      },\n      {\n        variant: \"default\",\n        side: \"left\",\n        class:\n          \"inset-y-0 left-0 translate-x-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:-translate-x-full data-starting-style:-translate-x-full\",\n      },\n      {\n        variant: \"default\",\n        side: \"top\",\n        class:\n          \"inset-x-0 top-0 translate-y-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:-translate-y-full data-starting-style:-translate-y-full\",\n      },\n      {\n        variant: \"default\",\n        side: \"bottom\",\n        class:\n          \"inset-x-0 bottom-0 -translate-y-[calc(1.5rem*var(--nested-dialogs))] data-ending-style:translate-y-full data-starting-style:translate-y-full\",\n      },\n    ],\n    defaultVariants: {\n      variant: \"default\",\n      side: \"right\",\n    },\n  },\n);\n\ninterface SheetConfigContextValue {\n  modal: boolean | \"trap-focus\";\n}\n\nconst SheetConfigContext = React.createContext<SheetConfigContextValue>({\n  modal: true,\n});\n\nfunction Sheet<Payload>({\n  modal = true,\n  disablePointerDismissal,\n  ...props\n}: BaseSheet.Root.Props<Payload>) {\n  const configValue = React.useMemo(() => ({ modal }), [modal]);\n  return (\n    <SheetConfigContext.Provider value={configValue}>\n      <BaseSheet.Root\n        modal={modal}\n        disablePointerDismissal={disablePointerDismissal ?? modal !== true}\n        {...props}\n      />\n    </SheetConfigContext.Provider>\n  );\n}\n\nconst createSheetHandle = BaseSheet.createHandle;\n\nfunction SheetTrigger({ ...props }: BaseSheet.Trigger.Props) {\n  return <BaseSheet.Trigger data-slot=\"sheet-trigger\" {...props} />;\n}\n\nfunction SheetClose({ ...props }: BaseSheet.Close.Props) {\n  return <BaseSheet.Close data-slot=\"sheet-close\" {...props} />;\n}\n\nfunction SheetPortal({ ...props }: BaseSheet.Portal.Props) {\n  return <BaseSheet.Portal data-slot=\"sheet-portal\" {...props} />;\n}\n\nfunction SheetBackdrop({ className, ...props }: BaseSheet.Backdrop.Props) {\n  return (\n    <BaseSheet.Backdrop\n      data-slot=\"sheet-backdrop\"\n      className={cn(\n        \"fixed inset-0 min-h-dvh bg-black/40 transition-all duration-300 supports-[-webkit-touch-callout:none]:absolute\",\n        \"backdrop-blur-sm data-ending-style:opacity-0 data-starting-style:opacity-0\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SheetViewport({ className, ...props }: BaseSheet.Viewport.Props) {\n  return (\n    <BaseSheet.Viewport\n      data-slot=\"sheet-viewport\"\n      className={cn(\"fixed inset-0 overflow-hidden\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SheetContent({\n  className,\n  children,\n  side = \"right\",\n  variant = \"default\",\n  footerVariant = \"default\",\n  showCloseButton = true,\n  level = 5,\n  shadowLevel = 5,\n  ...props\n}: BaseSheet.Popup.Props &\n  VariantProps<typeof sheetContentVariants> & {\n    footerVariant?: \"default\" | \"inset\";\n    showCloseButton?: boolean;\n    /** Surface elevation level for the sheet bg (1-8). Defaults to 5 — the dialog/sheet tier. */\n    level?: SurfaceLevel;\n    /** Shadow weight (1-8). Pinned to 5 by default — heavy enough to anchor the sheet against the page. */\n    shadowLevel?: SurfaceLevel;\n  }) {\n  const { modal } = React.useContext(SheetConfigContext);\n  const isModal = modal === true;\n  return (\n    <SheetPortal>\n      {isModal && <SheetBackdrop />}\n      <SheetViewport className={cn(!isModal && \"pointer-events-none\")}>\n        <BaseSheet.Popup\n          data-slot=\"sheet-content\"\n          data-side={side}\n          data-variant={variant}\n          data-footer-variant={footerVariant}\n          data-level={level}\n          className={cn(\n            // Surface elevation — floating variants get the full 4-edge rim\n            // overlay; flush (`default`) variants get a single-edge rim only\n            // on the inner-facing edge so the other edges don't show a 1px\n            // line at the viewport boundary.\n            variant === \"floating\"\n              ? elevatedSurface(level, shadowLevel)\n              : flushSurface(\n                  level,\n                  INNER_EDGE_FROM_ATTACH_SIDE[side ?? \"right\"],\n                ),\n            sheetContentVariants({ variant, side }),\n            !isModal && \"pointer-events-auto\",\n            className,\n          )}\n          {...props}\n        >\n          {children}\n          {showCloseButton && (\n            <SheetClose\n              aria-label=\"Close\"\n              className=\"absolute end-2 top-2\"\n              render={<Button size=\"icon_sm\" variant=\"ghost\" />}\n            >\n              <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} />\n            </SheetClose>\n          )}\n        </BaseSheet.Popup>\n      </SheetViewport>\n    </SheetPortal>\n  );\n}\n\n// Slot-presence padding uses ancestor `:has()` on `[data-slot=sheet-content]`\n// so header/body/footer can be wrapped in forms, ErrorBoundaries, or fragments\n// without breaking spacing — adjacent-sibling selectors wouldn't reach through.\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-header\"\n      className={cn(\n        \"flex flex-col gap-2 px-6 pt-6 pb-3\",\n        // Header alone with footer (no body anywhere in content)\n        \"in-[[data-slot=sheet-content]:not(:has([data-slot=sheet-body])):has([data-slot=sheet-footer])]:pb-6\",\n        // Header alone (no body, no footer)\n        \"in-[[data-slot=sheet-content]:not(:has([data-slot=sheet-body])):not(:has([data-slot=sheet-footer]))]:pb-6\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SheetBody({\n  className,\n  nativeScroll = false,\n  fadeEdges = true,\n  scrollbarGutter = false,\n  persistScrollbar,\n  hideScrollbar,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  nativeScroll?: boolean;\n} & Pick<\n    ScrollAreaProps,\n    \"fadeEdges\" | \"scrollbarGutter\" | \"persistScrollbar\" | \"hideScrollbar\"\n  >) {\n  return (\n    <div\n      data-slot=\"sheet-body\"\n      className={cn(\n        \"flex min-h-0 flex-1 flex-col overflow-hidden\",\n        // No header anywhere in content → body needs its own top padding\n        \"in-[[data-slot=sheet-content]:not(:has([data-slot=sheet-header]))]:pt-5\",\n        // No footer anywhere in content → body needs its own bottom padding\n        \"in-[[data-slot=sheet-content]:not(:has([data-slot=sheet-footer]))]:pb-5\",\n        // Inset footer variant: still need bottom padding when a footer follows\n        // so the body's content doesn't crowd the footer's top border\n        \"in-data-[footer-variant=inset]:in-[[data-slot=sheet-content]:has([data-slot=sheet-footer])]:pb-5\",\n      )}\n    >\n      <ScrollArea\n        className=\"flex-1\"\n        fadeEdges={fadeEdges}\n        scrollbarGutter={scrollbarGutter}\n        persistScrollbar={persistScrollbar}\n        hideScrollbar={hideScrollbar}\n        nativeScroll={nativeScroll}\n      >\n        <div className={cn(\"px-6 py-1\", className)} {...props}>\n          {children}\n        </div>\n      </ScrollArea>\n    </div>\n  );\n}\n\nfunction SheetTitle({ className, ...props }: BaseSheet.Title.Props) {\n  return (\n    <BaseSheet.Title\n      data-slot=\"sheet-title\"\n      className={cn(\n        \"text-foreground text-lg leading-none font-semibold tracking-tight text-balance\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SheetDescription({\n  className,\n  ...props\n}: BaseSheet.Description.Props) {\n  return (\n    <BaseSheet.Description\n      data-slot=\"sheet-description\"\n      className={cn(\"text-muted-foreground text-sm text-pretty\", 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(\n        \"mt-auto flex flex-col-reverse gap-2 px-6 pt-4 pb-6 sm:flex-row sm:justify-end\",\n        // No header AND no body → footer alone, needs its own top padding\n        \"in-[[data-slot=sheet-content]:not(:has([data-slot=sheet-header])):not(:has([data-slot=sheet-body]))]:pt-6\",\n        // Reduce top padding when body is present\n        \"not-in-data-[footer-variant=inset]:in-[[data-slot=sheet-content]:has([data-slot=sheet-body])]:pt-3\",\n        // Inset variant: muted background with top border for separation\n        \"in-data-[footer-variant=inset]:border-border in-data-[footer-variant=inset]:bg-muted in-data-[footer-variant=inset]:border-t in-data-[footer-variant=inset]:pt-4 in-data-[footer-variant=inset]:pb-4\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Sheet,\n  SheetTrigger,\n  SheetContent,\n  SheetHeader,\n  SheetBody,\n  SheetFooter,\n  SheetTitle,\n  SheetDescription,\n  SheetClose,\n  SheetPortal,\n  SheetBackdrop,\n  SheetViewport,\n  createSheetHandle,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/sheet.tsx"
    }
  ],
  "type": "registry:ui"
}