{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "drawer",
  "title": "Drawer",
  "description": "Slides in from any edge on a spring; its grip stretches while you drag it.",
  "dependencies": [
    "@ui-sdk/core@0.1.0-beta.2",
    "@ui-sdk/react@0.1.0-beta.2"
  ],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/drawer.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/drawer`: same parts, same props. Swap the import and keep\n   your code. This file adds motion only. Colours, radii, shadows and spacing stay yours.\n   The sheet itself moves on UI SDK's own spring, which follows the finger; nothing here touches\n   its translate or the backdrop's opacity. */\n\nimport {\n  DrawerClose as DrawerClosePart,\n  DrawerContent as DrawerContentPart,\n  DrawerTrigger as DrawerTriggerPart,\n} from \"@ui-sdk/react/drawer\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/drawer\"\n\n/* Press: the key gives under the finger and springs back on release. */\nconst press =\n  \"transition-[scale] duration-[calc(200ms*var(--kf-speed,1))] ease-pop not-data-disabled:not-data-pending:active:scale-[0.96] motion-reduce:transition-none!\"\n\n/* Cascade: each direct child of the sheet rises in out of a blur a little after the one before\n   it, while the sheet slides up. A keyframe animation, since the children have no earlier style\n   to transition from when the sheet first appears. Close buttons are left out. */\nconst cascadeKeyframes = \"@keyframes kf-cascade{from{opacity:0;translate:0 8px;filter:blur(4px)}}@media (prefers-reduced-motion:reduce){@keyframes kf-cascade{from{opacity:0}}}\"\n\nfunction DrawerTrigger({ className, ...props }: React.ComponentProps<typeof DrawerTriggerPart>) {\n  return <DrawerTriggerPart className={cn(press, className)} {...props} />\n}\n\nfunction DrawerClose({ className, ...props }: React.ComponentProps<typeof DrawerClosePart>) {\n  return <DrawerClosePart className={cn(press, className)} {...props} />\n}\n\nfunction DrawerContent({ className, ...props }: React.ComponentProps<typeof DrawerContentPart>) {\n  return (\n    <>\n      <style href=\"kf-cascade\" precedence=\"default\">\n        {cascadeKeyframes}\n      </style>\n      <DrawerContentPart\n        className={cn(\n          \"[&>*:not([data-slot$=-close],[data-slot$=-arrow])]:animate-[kf-cascade_calc(420ms*var(--kf-speed,1))_var(--ease-spring)_backwards]\",\n          \"[&>*:not([data-slot$=-close],[data-slot$=-arrow])]:[animation-delay:calc(calc(60ms*var(--kf-speed,1))+(min(sibling-index(),10)-1)*calc(40ms*var(--kf-speed,1)))]\",\n          /* While the sheet is dragged away, what is inside fades back with it. --drawer-progress\n             does not inherit, so it is copied into a variable that does. */\n          \"[--kf-sheet-progress:var(--drawer-progress,1)] *:opacity-[calc(0.55+var(--kf-sheet-progress,1)*0.45)]\",\n          \"motion-reduce:[&>*]:animate-none\",\n          className,\n        )}\n        {...props}\n      />\n    </>\n  )\n}\n\nexport { DrawerClose, DrawerContent, DrawerTrigger }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/drawer.tsx"
    },
    {
      "path": "registry/components/keyframery/drawer.tsx",
      "content": "\"use client\"\n\n/* Styled drawer: the animated primitive plus the Keyframery look. */\n\nimport {\n  Drawer as DrawerRoot,\n  DrawerBackdrop as DrawerBackdropPart,\n  DrawerClose as DrawerClosePart,\n  DrawerContent as DrawerContentPart,\n  DrawerDescription as DrawerDescriptionPart,\n  DrawerHandle as DrawerHandlePart,\n  DrawerOutlet as DrawerOutletPart,\n  DrawerShortcut as DrawerShortcutPart,\n  DrawerTitle as DrawerTitlePart,\n  DrawerTrigger as DrawerTriggerPart,\n} from \"@/components/keyframery/primitives/drawer\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype DrawerCloseVariant = \"default\" | \"primary\"\n\nconst keyBase = cn(\n  \"inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 leading-none font-medium whitespace-nowrap outline-none select-none [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  /* The primitive presses the key; colour and shadow ride the same 200ms pop. */\n  \"transition-[color,background-color,box-shadow,opacity,scale] duration-[calc(200ms*var(--kf-speed,1))] ease-pop\",\n  \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n  \"data-disabled:cursor-not-allowed data-disabled:opacity-50 data-pending:cursor-progress data-pending:opacity-70\",\n  \"motion-reduce:transition-none!\",\n)\n\nconst keySurface = cn(\n  \"bg-background text-foreground dark:bg-accent\",\n  \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_1px_1px_rgb(0_0_0/0.05),0_3px_6px_-2px_rgb(0_0_0/0.1)]\",\n  \"dark:shadow-[0_0_0_1px_rgb(255_255_255/0.07),inset_0_1px_0_rgb(255_255_255/0.08),0_2px_6px_-1px_rgb(0_0_0/0.6)]\",\n  \"not-data-disabled:hover:bg-[color-mix(in_oklab,var(--background),var(--foreground)_3%)]\",\n  \"dark:not-data-disabled:hover:bg-[color-mix(in_oklab,var(--accent),var(--foreground)_7%)]\",\n  \"not-data-disabled:hover:shadow-[0_0_0_1px_rgb(0_0_0/0.1),0_1px_1px_rgb(0_0_0/0.05),0_4px_8px_-2px_rgb(0_0_0/0.12)]\",\n  \"dark:not-data-disabled:hover:shadow-[0_0_0_1px_rgb(255_255_255/0.12),inset_0_1px_0_rgb(255_255_255/0.1),0_2px_6px_-1px_rgb(0_0_0/0.6)]\",\n  \"not-data-disabled:active:shadow-[0_0_0_1px_rgb(0_0_0/0.1),0_1px_1px_rgb(0_0_0/0.04),0_1px_2px_-1px_rgb(0_0_0/0.06)]\",\n  \"dark:not-data-disabled:active:shadow-[0_0_0_1px_rgb(255_255_255/0.09),inset_0_1px_0_rgb(255_255_255/0.04),0_1px_2px_-1px_rgb(0_0_0/0.6)]\",\n)\n\nconst primarySurface = cn(\n  \"bg-primary text-primary-foreground\",\n  \"shadow-[inset_0_1px_0_rgb(255_255_255/0.14),0_1px_2px_rgb(0_0_0/0.25)]\",\n  \"dark:shadow-[inset_0_1px_0_rgb(255_255_255/0.7),0_1px_2px_rgb(0_0_0/0.5)]\",\n  \"not-data-disabled:hover:bg-[color-mix(in_oklab,var(--primary),var(--background)_14%)]\",\n  \"not-data-disabled:active:shadow-[inset_0_1px_0_rgb(255_255_255/0.08),0_0_1px_rgb(0_0_0/0.3)]\",\n)\n\n/* The pill you grab. While the sheet is dragged it stretches wide and darkens on a spring,\n   and closes up again when let go. */\nconst grip = cn(\n  \"mx-auto block h-1 w-9 shrink-0 rounded-full bg-foreground/15\",\n  \"transition-[width,background-color] duration-[calc(380ms*var(--kf-speed,1))] ease-spring\",\n  \"group-data-dragging/drawer:w-16 group-data-dragging/drawer:bg-foreground/35\",\n  \"group-data-[side=left]/drawer:hidden group-data-[side=right]/drawer:hidden\",\n  \"motion-reduce:transition-none!\",\n)\n\nfunction Drawer(props: React.ComponentProps<typeof DrawerRoot>) {\n  return <DrawerRoot {...props} />\n}\n\n/* A key by default. Pass `render` to use a button of your own instead. */\nfunction DrawerTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerTriggerPart>) {\n  return (\n    <DrawerTriggerPart\n      className={cn(\n        !props.render && [keyBase, keySurface, \"h-8 rounded-[9px] px-3 text-[13px] [&_svg]:size-4\"],\n        props.render && \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The drawer sets this layer's opacity from how far the sheet is open, so the dim and the\n   blur behind it follow a drag frame by frame. Only its colour and blur are set here. */\nfunction DrawerBackdrop({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerBackdropPart>) {\n  return (\n    <DrawerBackdropPart\n      className={cn(\n        \"fixed inset-0 bg-black/30 backdrop-blur-[3px] dark:bg-black/60\",\n        \"data-interactive:backdrop-blur-none\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The sheet. The drawer owns its position and translate; this gives it a size, a surface\n   and corners for whichever edge it comes from. */\nfunction DrawerContent({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof DrawerContentPart>) {\n  return (\n    <DrawerContentPart\n      className={cn(\n        \"group/drawer flex flex-col border-0 bg-popover text-popover-foreground outline-none\",\n        \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_-8px_32px_-8px_rgb(0_0_0/0.18)]\",\n        \"dark:shadow-[0_0_0_1px_rgb(255_255_255/0.08),0_-8px_32px_-8px_rgb(0_0_0/0.7)]\",\n        /* Bottom and top: a centred sheet, rounded on its free edge. A strip below the edge\n           covers the gap when it is pulled past its rest. */\n        \"data-[side=bottom]:mx-auto data-[side=bottom]:max-h-[calc(100dvh-48px)] data-[side=bottom]:w-full data-[side=bottom]:max-w-[480px] data-[side=bottom]:rounded-t-[18px] data-[side=bottom]:pb-[max(20px,env(safe-area-inset-bottom))]\",\n        \"data-[side=bottom]:after:absolute data-[side=bottom]:after:inset-x-0 data-[side=bottom]:after:top-full data-[side=bottom]:after:h-24 data-[side=bottom]:after:bg-popover\",\n        \"data-[side=top]:mx-auto data-[side=top]:max-h-[calc(100dvh-48px)] data-[side=top]:w-full data-[side=top]:max-w-[480px] data-[side=top]:rounded-b-[18px]\",\n        \"data-[side=left]:h-full data-[side=left]:w-[min(380px,calc(100vw-48px))] data-[side=left]:rounded-r-[18px]\",\n        \"data-[side=right]:h-full data-[side=right]:w-[min(380px,calc(100vw-48px))] data-[side=right]:rounded-l-[18px]\",\n        /* A sheet opened from this one rises over it: this one steps back. */\n        \"origin-top scale-[calc(1-var(--drawer-stack,0)*0.04)]\",\n        \"data-dragging:cursor-grabbing\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </DrawerContentPart>\n  )\n}\n\n/* A decorative grip for a sheet with one resting point. */\nfunction DrawerGrip({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div data-slot=\"drawer-grip\" aria-hidden className={cn(\"pt-2.5 pb-1\", className)} {...props}>\n      <span className={grip} />\n    </div>\n  )\n}\n\n/* The grip as a button, for sheets with several snap points: a press moves to the next\n   one, arrow keys, Home and End choose one. Give it an aria-label. */\nfunction DrawerHandle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerHandlePart>) {\n  return (\n    <DrawerHandlePart\n      className={cn(\n        \"group/handle mx-auto mt-1 block cursor-grab rounded-full px-4 pt-1.5 pb-2 outline-none\",\n        \"focus-visible:ring-2 focus-visible:ring-ring\",\n        \"hover:[&>span]:bg-foreground/25\",\n        className,\n      )}\n      {...props}\n    >\n      <span className={grip} />\n    </DrawerHandlePart>\n  )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div data-slot=\"drawer-header\" className={cn(\"flex flex-col gap-1 px-5 pt-3\", className)} {...props} />\n  )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"drawer-footer\"\n      className={cn(\"mt-auto flex flex-col gap-2 px-5 pt-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DrawerTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerTitlePart>) {\n  return (\n    <DrawerTitlePart\n      className={cn(\"text-[15px] leading-5 font-semibold tracking-tight\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DrawerDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerDescriptionPart>) {\n  return (\n    <DrawerDescriptionPart\n      className={cn(\"text-[13px] leading-5 text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\n/* A full-width key by default. Pass `render` for a button of your own. */\nfunction DrawerClose({\n  className,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof DrawerClosePart> & { variant?: DrawerCloseVariant }) {\n  return (\n    <DrawerClosePart\n      data-variant={variant}\n      className={cn(\n        !props.render && [\n          keyBase,\n          \"h-9 rounded-[10px] px-4 text-[14px] [&_svg]:size-4\",\n          variant === \"primary\" ? primarySurface : keySurface,\n        ],\n        props.render && \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DrawerShortcut({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerShortcutPart>) {\n  return (\n    <DrawerShortcutPart\n      className={cn(\n        \"ms-1 text-[12px] leading-none tracking-[0.04em] text-muted-foreground tabular-nums\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Something on the page that follows the sheet, like the app behind it scaling back. Its\n   `keyframes` run from closed to fully open. */\nfunction DrawerOutlet({\n  className,\n  ...props\n}: React.ComponentProps<typeof DrawerOutletPart>) {\n  return <DrawerOutletPart className={cn(\"origin-top\", className)} {...props} />\n}\n\nexport {\n  Drawer,\n  DrawerBackdrop,\n  DrawerClose,\n  DrawerContent,\n  DrawerDescription,\n  DrawerFooter,\n  DrawerGrip,\n  DrawerHandle,\n  DrawerHeader,\n  DrawerOutlet,\n  DrawerShortcut,\n  DrawerTitle,\n  DrawerTrigger,\n}\n",
      "type": "registry:component",
      "target": "components/keyframery/drawer.tsx"
    }
  ],
  "type": "registry:component"
}