{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "mobile-bottom-sheet",
  "type": "registry:ui",
  "title": "Mobile bottom sheet",
  "description": "Presents mobile actions and detail in a draggable, focus-managed bottom sheet.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "overlays-surfaces"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/mobile-bottom-sheet/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "medium",
    "signature": "Snap, backdrop, focus, and dismissal stay coordinated",
    "sceneFamily": "product-mono",
    "motionRole": "ui",
    "primaryState": "Action trigger in closed state",
    "assetProvenance": "self-contained"
  },
  "files": [
    {
      "path": "src/registry/components/mobile-bottom-sheet.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/mobile-bottom-sheet.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { motion, useDragControls, useReducedMotion } from \"motion/react\";\n\nexport type MobileBottomSheetProps = { title: string; children: ReactNode; triggerLabel?: string; defaultOpen?: boolean; className?: string };\n\nexport function MobileBottomSheet({ title, children, triggerLabel = \"Open actions\", defaultOpen = false, className = \"\" }: MobileBottomSheetProps) {\n  const reduced = useReducedMotion() === true; const titleId = useId(); const triggerRef = useRef<HTMLButtonElement>(null); const sheetRef = useRef<HTMLDivElement>(null); const controls = useDragControls(); const [open, setOpen] = useState(defaultOpen);\n  useEffect(() => { if (!open) return; const previous = document.activeElement; requestAnimationFrame(() => sheetRef.current?.focus()); const key = (event: KeyboardEvent) => { if (event.key === \"Escape\") setOpen(false); }; document.addEventListener(\"keydown\", key); return () => { document.removeEventListener(\"keydown\", key); if (previous instanceof HTMLElement && previous.isConnected) previous.focus(); }; }, [open]);\n  return <div className={className}><button ref={triggerRef} type=\"button\" onClick={() => setOpen(true)} className=\"min-h-11 rounded-full bg-[#242424] px-4 text-[12px] text-white outline-none hover:bg-[#3b3b3b] focus-visible:ring-2 focus-visible:ring-[#4568FF]\">{triggerLabel}</button>{typeof document !== \"undefined\" && open ? createPortal(<div className=\"fixed inset-0 z-[100] grid items-end\" role=\"presentation\"><button type=\"button\" aria-label=\"Close sheet\" onClick={() => setOpen(false)} className=\"absolute inset-0 bg-black/35\" /><motion.div ref={sheetRef} role=\"dialog\" aria-modal=\"true\" aria-labelledby={titleId} tabIndex={-1} drag=\"y\" dragControls={controls} dragListener={false} dragConstraints={{ top: 0, bottom: 0 }} dragElastic={{ top: 0, bottom: .7 }} onDragEnd={(_, info) => { if (info.offset.y > 96 || info.velocity.y > 520) setOpen(false); }} initial={reduced ? false : { y: \"100%\" }} animate={{ y: 0 }} exit={{ y: \"100%\" }} transition={{ duration: reduced ? 0 : .28, ease: [0.22, 1, 0.36, 1] }} className=\"relative max-h-[82vh] rounded-t-[22px] bg-white p-4 shadow-[0_-20px_55px_-22px_rgba(0,0,0,.4)] outline-none\"><button type=\"button\" onPointerDown={(event) => controls.start(event)} aria-label=\"Drag sheet\" className=\"mx-auto block h-7 w-14 cursor-grab rounded-full outline-none before:mx-auto before:block before:h-1.5 before:w-10 before:rounded-full before:bg-neutral-300 focus-visible:ring-2 focus-visible:ring-[#4568FF]\" /><div className=\"flex items-center justify-between gap-3\"><h3 id={titleId} className=\"text-[15px] font-medium text-[#292929]\">{title}</h3><button type=\"button\" onClick={() => setOpen(false)} className=\"grid size-11 place-items-center rounded-full outline-none hover:bg-neutral-100 focus-visible:ring-2 focus-visible:ring-[#4568FF]\">×</button></div><div className=\"mt-4 overflow-auto\">{children}</div></motion.div></div>, document.body) : null}</div>;\n}\n"
    }
  ]
}
