Fortura/apps/www/public/r/base-preview-card.json
2025-08-20 04:12:49 -06:00

19 lines
5.0 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "base-preview-card",
"type": "registry:ui",
"title": "Base Preview Card",
"description": "A popup that appears when a link is hovered, showing a preview for sighted users.",
"dependencies": [
"motion",
"@base-ui-components/react"
],
"files": [
{
"path": "registry/base/preview-card/index.tsx",
"content": "'use client';\n\nimport * as React from 'react';\nimport { PreviewCard as PreviewCardPrimitives } from '@base-ui-components/react/preview-card';\nimport {\n AnimatePresence,\n motion,\n type HTMLMotionProps,\n type Transition,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\ntype PreviewCardContextType = {\n isOpen: boolean;\n};\n\nconst PreviewCardContext = React.createContext<\n PreviewCardContextType | undefined\n>(undefined);\n\nconst usePreviewCard = (): PreviewCardContextType => {\n const context = React.useContext(PreviewCardContext);\n if (!context) {\n throw new Error('usePreviewCard must be used within a PreviewCard');\n }\n return context;\n};\n\ntype Side = React.ComponentPropsWithoutRef<\n typeof PreviewCardPrimitives.Positioner\n>['side'];\n\ntype Align = React.ComponentPropsWithoutRef<\n typeof PreviewCardPrimitives.Positioner\n>['align'];\n\nconst getInitialPosition = (side: Side) => {\n switch (side) {\n case 'top':\n return { y: 15 };\n case 'bottom':\n return { y: -15 };\n case 'left':\n case 'inline-start':\n return { x: 15 };\n case 'right':\n case 'inline-end':\n return { x: -15 };\n }\n};\n\ntype PreviewCardProps = React.ComponentProps<typeof PreviewCardPrimitives.Root>;\n\nfunction PreviewCard(props: PreviewCardProps) {\n const [isOpen, setIsOpen] = React.useState(\n props?.open ?? props?.defaultOpen ?? false,\n );\n\n React.useEffect(() => {\n if (props?.open !== undefined) setIsOpen(props.open);\n }, [props?.open]);\n\n const handleOpenChange = React.useCallback(\n (\n open: boolean,\n event: Event | undefined,\n reason: Parameters<NonNullable<PreviewCardProps['onOpenChange']>>[2],\n ) => {\n setIsOpen(open);\n props.onOpenChange?.(open, event, reason);\n },\n [props],\n );\n\n return (\n <PreviewCardContext.Provider value={{ isOpen }}>\n <PreviewCardPrimitives.Root\n data-slot=\"preview-card\"\n {...props}\n onOpenChange={handleOpenChange}\n />\n </PreviewCardContext.Provider>\n );\n}\n\ntype PreviewCardTriggerProps = React.ComponentProps<\n typeof PreviewCardPrimitives.Trigger\n>;\n\nfunction PreviewCardTrigger(props: PreviewCardTriggerProps) {\n return (\n <PreviewCardPrimitives.Trigger\n data-slot=\"preview-card-trigger\"\n {...props}\n />\n );\n}\n\ntype PreviewCardContentProps = React.ComponentProps<\n typeof PreviewCardPrimitives.Positioner\n> & {\n transition?: Transition;\n popupProps?: typeof PreviewCardPrimitives.Popup;\n motionProps?: HTMLMotionProps<'div'>;\n positionerClassName?: string;\n};\n\nfunction PreviewCardContent({\n className,\n popupProps,\n motionProps,\n positionerClassName,\n side = 'bottom',\n sideOffset = 10,\n transition = { type: 'spring', stiffness: 300, damping: 25 },\n children,\n ...props\n}: PreviewCardContentProps) {\n const { isOpen } = usePreviewCard();\n const initialPosition = getInitialPosition(side);\n\n return (\n <AnimatePresence>\n {isOpen && (\n <PreviewCardPrimitives.Portal\n keepMounted\n data-slot=\"preview-card-portal\"\n >\n <PreviewCardPrimitives.Positioner\n data-slot=\"preview-card-positioner\"\n side={side}\n sideOffset={sideOffset}\n className={cn('z-50', positionerClassName)}\n {...props}\n >\n <PreviewCardPrimitives.Popup\n data-slot=\"preview-card-popup\"\n {...popupProps}\n className={cn(\n 'w-64 rounded-lg border bg-popover p-4 text-popover-foreground shadow-md outline-none',\n className,\n )}\n render={\n <motion.div\n key=\"preview-card-content\"\n initial={{ opacity: 0, scale: 0.5, ...initialPosition }}\n animate={{ opacity: 1, scale: 1, x: 0, y: 0 }}\n exit={{ opacity: 0, scale: 0.5, ...initialPosition }}\n transition={transition}\n {...motionProps}\n />\n }\n >\n {children}\n </PreviewCardPrimitives.Popup>\n </PreviewCardPrimitives.Positioner>\n </PreviewCardPrimitives.Portal>\n )}\n </AnimatePresence>\n );\n}\n\nexport {\n PreviewCard,\n PreviewCardTrigger,\n PreviewCardContent,\n usePreviewCard,\n type PreviewCardProps,\n type PreviewCardTriggerProps,\n type PreviewCardContentProps,\n type Side,\n type Align,\n};\n",
"type": "registry:ui",
"target": "components/animate-ui/base/preview-card.tsx"
}
]
}