{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-headless-disclosure",
  "title": "Headless Disclosure",
  "description": "A simple, accessible foundation for building custom UIs that show and hide content, like togglable accordion panels.",
  "dependencies": [
    "motion",
    "@headlessui/react"
  ],
  "registryDependencies": [
    "@odysseyui/lib-get-strict-context"
  ],
  "files": [
    {
      "path": "registry/primitives/headless/disclosure/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport {\n  Disclosure as DisclosurePrimitive,\n  DisclosureButton as DisclosureButtonPrimitive,\n  DisclosurePanel as DisclosurePanelPrimitive,\n  type DisclosureProps as DisclosurePrimitiveProps,\n  type DisclosureButtonProps as DisclosureButtonPrimitiveProps,\n  type DisclosurePanelProps as DisclosurePanelPrimitiveProps,\n} from '@headlessui/react';\nimport { motion, AnimatePresence, type HTMLMotionProps } from 'motion/react';\n\nimport { getStrictContext } from '@/lib/get-strict-context';\n\ntype DisclosureContextType = {\n  isOpen: boolean;\n};\n\nconst [DisclosureProvider, useDisclosure] =\n  getStrictContext<DisclosureContextType>('DisclosureContext');\n\ntype DisclosureProps<TTag extends React.ElementType = 'div'> =\n  DisclosurePrimitiveProps<TTag> & {\n    as?: TTag;\n    className?: string;\n  };\n\nfunction Disclosure<TTag extends React.ElementType = 'div'>({\n  children,\n  ...props\n}: DisclosureProps<TTag>) {\n  type DisclosureRenderBag = Parameters<\n    Exclude<DisclosurePrimitiveProps<TTag>['children'], React.ReactNode>\n  >[0];\n\n  return (\n    <DisclosurePrimitive data-slot=\"disclosure\" {...props}>\n      {(bag: DisclosureRenderBag) => (\n        <DisclosureProvider value={{ isOpen: bag.open }}>\n          {typeof children === 'function' ? children(bag) : children}\n        </DisclosureProvider>\n      )}\n    </DisclosurePrimitive>\n  );\n}\n\ntype DisclosureButtonProps<TTag extends React.ElementType = 'button'> =\n  DisclosureButtonPrimitiveProps<TTag> & {\n    as?: TTag;\n  };\n\nfunction DisclosureButton<TTag extends React.ElementType = 'button'>(\n  props: DisclosureButtonProps<TTag>,\n) {\n  return <DisclosureButtonPrimitive data-slot=\"disclosure-button\" {...props} />;\n}\n\ntype DisclosurePanelProps<TTag extends React.ElementType = typeof motion.div> =\n  Partial<Pick<DisclosurePanelPrimitiveProps<TTag>, 'static' | 'unmount'>> &\n    Pick<DisclosurePanelPrimitiveProps<TTag>, 'children'> &\n    Omit<HTMLMotionProps<'div'>, 'children'> & {\n      as?: TTag;\n      keepRendered?: boolean;\n    };\n\nfunction DisclosurePanel<TTag extends React.ElementType = typeof motion.div>(\n  props: DisclosurePanelProps<TTag>,\n) {\n  type DisclosurePanelRenderBag = Parameters<\n    Exclude<DisclosurePanelPrimitiveProps<TTag>['children'], React.ReactNode>\n  >[0];\n\n  const {\n    children,\n    transition = { duration: 0.35, ease: 'easeInOut' },\n    as = motion.div,\n    unmount,\n    keepRendered = false,\n    ...rest\n  } = props;\n  const { isOpen } = useDisclosure();\n\n  return (\n    <AnimatePresence>\n      {keepRendered ? (\n        <DisclosurePanelPrimitive\n          static\n          as={as as React.ElementType}\n          unmount={unmount}\n        >\n          {(bag: DisclosurePanelRenderBag) => (\n            <motion.div\n              key=\"disclosure-panel\"\n              data-slot=\"disclosure-panel\"\n              initial={{ height: 0, opacity: 0, '--mask-stop': '0%', y: 20 }}\n              animate={\n                isOpen\n                  ? { height: 'auto', opacity: 1, '--mask-stop': '100%', y: 0 }\n                  : { height: 0, opacity: 0, '--mask-stop': '0%', y: 20 }\n              }\n              transition={transition}\n              style={{\n                maskImage:\n                  'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',\n                WebkitMaskImage:\n                  'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',\n                overflow: 'hidden',\n              }}\n              {...rest}\n            >\n              {typeof children === 'function' ? children(bag) : children}\n            </motion.div>\n          )}\n        </DisclosurePanelPrimitive>\n      ) : (\n        isOpen && (\n          <DisclosurePanelPrimitive\n            static\n            as={as as React.ElementType}\n            unmount={unmount}\n          >\n            {(bag: DisclosurePanelRenderBag) => (\n              <motion.div\n                key=\"disclosure-panel\"\n                data-slot=\"disclosure-panel\"\n                initial={{ height: 0, opacity: 0, '--mask-stop': '0%', y: 20 }}\n                animate={{\n                  height: 'auto',\n                  opacity: 1,\n                  '--mask-stop': '100%',\n                  y: 0,\n                }}\n                exit={{ height: 0, opacity: 0, '--mask-stop': '0%', y: 20 }}\n                transition={transition}\n                style={{\n                  maskImage:\n                    'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',\n                  WebkitMaskImage:\n                    'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',\n                  overflow: 'hidden',\n                }}\n                {...rest}\n              >\n                {typeof children === 'function' ? children(bag) : children}\n              </motion.div>\n            )}\n          </DisclosurePanelPrimitive>\n        )\n      )}\n    </AnimatePresence>\n  );\n}\n\nexport {\n  Disclosure,\n  DisclosureButton,\n  DisclosurePanel,\n  useDisclosure,\n  type DisclosureProps,\n  type DisclosureButtonProps,\n  type DisclosurePanelProps,\n};\n",
      "type": "registry:ui",
      "target": "components/odysseyui/primitives/headless/disclosure.tsx"
    }
  ],
  "type": "registry:ui"
}