19 lines
4.3 KiB
JSON
19 lines
4.3 KiB
JSON
{
|
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
"name": "headless-disclosure",
|
|
"type": "registry:ui",
|
|
"title": "Headless Disclosure",
|
|
"description": "A simple, accessible foundation for building custom UIs that show and hide content, like togglable accordion panels.",
|
|
"dependencies": [
|
|
"@headlessui/react",
|
|
"motion"
|
|
],
|
|
"files": [
|
|
{
|
|
"path": "registry/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 {\n AnimatePresence,\n motion,\n type HTMLMotionProps,\n type Transition,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\ntype DisclosureContextType = {\n isOpen: boolean;\n};\n\nconst DisclosureContext = React.createContext<\n DisclosureContextType | undefined\n>(undefined);\n\nconst useDisclosure = (): DisclosureContextType => {\n const context = React.useContext(DisclosureContext);\n if (!context) {\n throw new Error('useDisclosure must be used within a Disclosure');\n }\n return context;\n};\n\ntype DisclosureProps<TTag extends React.ElementType = 'div'> =\n DisclosurePrimitiveProps<TTag> & {\n as?: TTag;\n };\n\nfunction Disclosure<TTag extends React.ElementType = 'div'>({\n children,\n ...props\n}: DisclosureProps<TTag>) {\n return (\n <DisclosurePrimitive data-slot=\"disclosure\" {...props}>\n {(bag) => (\n <DisclosureContext.Provider value={{ isOpen: bag.open }}>\n {typeof children === 'function' ? children(bag) : children}\n </DisclosureContext.Provider>\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 Pick<DisclosurePanelPrimitiveProps<TTag>, 'static' | 'unmount' | 'children'> &\n Omit<HTMLMotionProps<'div'>, 'children'> & {\n transition?: Transition;\n as?: TTag;\n };\n\nfunction DisclosurePanel<TTag extends React.ElementType = typeof motion.div>(\n props: DisclosurePanelProps<TTag>,\n) {\n const {\n className,\n children,\n transition = { type: 'spring', stiffness: 150, damping: 22 },\n as = motion.div,\n unmount,\n ...rest\n } = props;\n const { isOpen } = useDisclosure();\n\n return (\n <AnimatePresence>\n {isOpen && (\n <DisclosurePanelPrimitive\n static\n as={as as React.ElementType}\n unmount={unmount}\n >\n {(bag) => (\n <motion.div\n key=\"disclosure-panel\"\n data-slot=\"disclosure-panel\"\n initial={{ height: 0, opacity: 0, '--mask-stop': '0%' }}\n animate={{ height: 'auto', opacity: 1, '--mask-stop': '100%' }}\n exit={{ height: 0, opacity: 0, '--mask-stop': '0%' }}\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 }}\n className={cn('overflow-hidden', className)}\n {...rest}\n >\n {typeof children === 'function' ? children(bag) : children}\n </motion.div>\n )}\n </DisclosurePanelPrimitive>\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/animate-ui/headless/disclosure.tsx"
|
|
}
|
|
]
|
|
} |