{
  "$schema": "https://blode.co/ui/schema/registry-item.json",
  "name": "popover",
  "title": "Popover",
  "author": "Matthew Blode",
  "description": "A floating panel that appears next to a trigger element.",
  "dependencies": ["@base-ui/react"],
  "files": [
    {
      "path": "ui/popover.tsx",
      "content": "\"use client\";\n\nimport { Popover as PopoverPrimitive } from \"@base-ui/react/popover\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype PopoverInteractOutsideEvent = Event & {\n  preventDefault: () => void;\n};\n\ninterface PopoverContextType {\n  anchor: HTMLElement | null;\n  setAnchor: (anchor: HTMLElement | null) => void;\n  setOnInteractOutside: (handler?: (event: PopoverInteractOutsideEvent) => void) => void;\n}\n\nconst PopoverContext = React.createContext<PopoverContextType | undefined>(undefined);\n\nconst usePopoverContext = () => React.useContext(PopoverContext);\n\nconst setRef = <T,>(ref: React.Ref<T> | undefined, value: T) => {\n  if (typeof ref === \"function\") {\n    ref(value);\n    return;\n  }\n\n  if (ref && \"current\" in ref) {\n    ref.current = value;\n  }\n};\n\nconst Popover = ({\n  onOpenChange,\n  ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) => {\n  const [anchor, setAnchor] = React.useState<HTMLElement | null>(null);\n  const onInteractOutsideRef = React.useRef<\n    ((event: PopoverInteractOutsideEvent) => void) | undefined\n    // oxlint-disable-next-line unicorn/no-useless-undefined -- React 19's useRef requires an explicit initial value\n  >(undefined);\n\n  const handleOpenChange = React.useCallback<\n    NonNullable<React.ComponentProps<typeof PopoverPrimitive.Root>[\"onOpenChange\"]>\n  >(\n    (open, eventDetails) => {\n      if (!open && eventDetails.reason === \"outside-press\") {\n        const interactHandler = onInteractOutsideRef.current;\n\n        if (interactHandler) {\n          const wrappedEvent = Object.create(eventDetails.event) as PopoverInteractOutsideEvent;\n          wrappedEvent.preventDefault = () => eventDetails.cancel();\n          interactHandler(wrappedEvent);\n        }\n      }\n\n      onOpenChange?.(open, eventDetails);\n    },\n    [onOpenChange],\n  );\n\n  const contextValue = React.useMemo<PopoverContextType>(\n    () => ({\n      anchor,\n      setAnchor,\n      setOnInteractOutside: (handler) => {\n        onInteractOutsideRef.current = handler;\n      },\n    }),\n    [anchor],\n  );\n\n  return (\n    <PopoverContext.Provider value={contextValue}>\n      <PopoverPrimitive.Root data-slot=\"popover\" onOpenChange={handleOpenChange} {...props} />\n    </PopoverContext.Provider>\n  );\n};\n\nconst PopoverTrigger = ({\n  asChild = false,\n  children,\n  ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger> & {\n  asChild?: boolean;\n}) => {\n  const render =\n    asChild && React.isValidElement(children) ? (children as React.ReactElement) : undefined;\n\n  return (\n    <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" render={render} {...props}>\n      {asChild ? null : children}\n    </PopoverPrimitive.Trigger>\n  );\n};\n\ntype PopoverContentProps = React.ComponentProps<typeof PopoverPrimitive.Popup> &\n  Pick<\n    React.ComponentProps<typeof PopoverPrimitive.Positioner>,\n    \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n  > & {\n    asChild?: boolean;\n    onInteractOutside?: (event: PopoverInteractOutsideEvent) => void;\n    onOpenAutoFocus?: (event: Event) => void;\n  };\n\nconst PopoverContent = ({\n  asChild = false,\n  children,\n  className,\n  align = \"center\",\n  alignOffset = 0,\n  side = \"bottom\",\n  sideOffset = 4,\n  initialFocus,\n  onInteractOutside,\n  onOpenAutoFocus,\n  ...props\n}: PopoverContentProps) => {\n  const popoverContext = usePopoverContext();\n\n  React.useEffect(() => {\n    popoverContext?.setOnInteractOutside(onInteractOutside);\n\n    return () => {\n      popoverContext?.setOnInteractOutside(undefined);\n    };\n  }, [onInteractOutside, popoverContext]);\n\n  React.useEffect(() => {\n    if (!onOpenAutoFocus) {\n      return;\n    }\n\n    const event = new Event(\"openAutoFocus\", { cancelable: true });\n    onOpenAutoFocus(event);\n  }, [onOpenAutoFocus]);\n\n  const render =\n    asChild && React.isValidElement(children) ? (children as React.ReactElement) : undefined;\n\n  return (\n    <PopoverPrimitive.Portal>\n      <PopoverPrimitive.Positioner\n        align={align}\n        alignOffset={alignOffset}\n        anchor={popoverContext?.anchor}\n        className=\"isolate z-50\"\n        side={side}\n        sideOffset={sideOffset}\n      >\n        <PopoverPrimitive.Popup\n          className={cn(\n            \"data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-soft outline-hidden data-closed:animate-out data-open:animate-in\",\n            className,\n          )}\n          data-slot=\"popover-content\"\n          initialFocus={onOpenAutoFocus ? false : initialFocus}\n          render={render}\n          {...props}\n        >\n          {asChild ? null : children}\n        </PopoverPrimitive.Popup>\n      </PopoverPrimitive.Positioner>\n    </PopoverPrimitive.Portal>\n  );\n};\n\nconst PopoverAnchor = ({\n  asChild = false,\n  children,\n  ref,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  asChild?: boolean;\n}) => {\n  const popoverContext = usePopoverContext();\n\n  const handleRef = React.useCallback(\n    (node: HTMLElement | null) => {\n      popoverContext?.setAnchor(node);\n      setRef(ref as React.Ref<HTMLElement> | undefined, node);\n    },\n    [popoverContext, ref],\n  );\n\n  const child =\n    asChild && React.isValidElement(children) ? (children as React.ReactElement) : undefined;\n\n  return useRender({\n    defaultTagName: \"div\",\n    props: child ? props : { \"data-slot\": \"popover-anchor\", ...props, children },\n    ref: handleRef,\n    render: child,\n  });\n};\n\nconst PopoverHeader = ({ className, ...props }: React.ComponentProps<\"div\">) => (\n  <div\n    className={cn(\"flex flex-col gap-1 text-sm\", className)}\n    data-slot=\"popover-header\"\n    {...props}\n  />\n);\n\nconst PopoverTitle = ({ className, ...props }: React.ComponentProps<\"h2\">) => (\n  <div className={cn(\"font-medium\", className)} data-slot=\"popover-title\" {...props} />\n);\n\nconst PopoverDescription = ({ className, ...props }: React.ComponentProps<\"p\">) => (\n  <p\n    className={cn(\"text-muted-foreground\", className)}\n    data-slot=\"popover-description\"\n    {...props}\n  />\n);\n\nexport {\n  Popover,\n  PopoverTrigger,\n  PopoverContent,\n  PopoverAnchor,\n  PopoverHeader,\n  PopoverTitle,\n  PopoverDescription,\n};\n",
      "type": "registry:ui",
      "target": ""
    }
  ],
  "type": "registry:ui"
}
