{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "b-popover",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["@base-ui/react", "motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "b-popover.tsx",
      "content": "\"use client\";\n\nimport { Popover as PopoverPrimitive } from \"@base-ui/react/popover\";\nimport { motion } from \"motion/react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst controlCornerClassName =\n  \"rounded-lg supports-[corner-shape:squircle]:corner-squircle supports-[corner-shape:squircle]:rounded-[11px]\";\n\nconst surfaceCornerClassName =\n  \"rounded-lg supports-[corner-shape:squircle]:corner-squircle supports-[corner-shape:squircle]:rounded-[12px]\";\n\nconst popoverThemeClassName =\n  \"[--po-surface:#ffffff] [--po-foreground:#111111] [--po-border:#e3e7ec] [--po-ring:rgba(17,17,17,0.16)] dark:[--po-surface:#111111] dark:[--po-foreground:#f6f3ec] dark:[--po-border:#2b2a25] dark:[--po-ring:rgba(246,243,236,0.18)]\";\n\nconst popoverPanelClassName = cn(\n  surfaceCornerClassName,\n  \"z-50 w-72 transform-gpu border border-[color:var(--po-border)] bg-[color:var(--po-surface)] p-4 text-[color:var(--po-foreground)] shadow-none outline-none\"\n);\n\nconst popoverTriggerClassName = cn(\n  controlCornerClassName,\n  \"inline-flex min-h-11 min-w-11 touch-manipulation items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:color-mix(in_oklch,var(--po-ring),transparent_50%)] focus-visible:ring-offset-2 focus-visible:ring-offset-[color:var(--po-surface)]\"\n);\n\ntype Side = \"top\" | \"right\" | \"bottom\" | \"left\";\ntype Align = \"start\" | \"center\" | \"end\";\ntype CollisionPadding = React.ComponentPropsWithoutRef<\n  typeof PopoverPrimitive.Positioner\n>[\"collisionPadding\"];\n\ntype PopoverContextValue = {\n  actionsRef: React.RefObject<PopoverPrimitive.Root.Actions | null>;\n  open: boolean;\n  contentId: string;\n  triggerId: string;\n  getAnchorNode: () => HTMLElement | null;\n  setAnchorNode: (node: HTMLElement | null) => void;\n  setTriggerNode: (node: HTMLElement | null) => void;\n};\n\ntype PopoverTriggerElementProps = React.HTMLAttributes<HTMLElement> & {\n  className?: string;\n};\n\ntype PopoverTriggerChildElement = React.ReactElement<\n  PopoverTriggerElementProps & React.RefAttributes<HTMLElement>\n>;\n\ntype PopoverAnchorElementProps = React.HTMLAttributes<HTMLElement> & {\n  className?: string;\n};\n\ntype PopoverAnchorChildElement = React.ReactElement<\n  PopoverAnchorElementProps & React.RefAttributes<HTMLElement>\n>;\n\ntype PopupRenderProps = React.HTMLAttributes<HTMLDivElement> & {\n  children?: React.ReactNode;\n  className?: string;\n  ref?: React.Ref<HTMLDivElement>;\n  style?: React.CSSProperties;\n};\n\nconst PopoverContext = React.createContext<PopoverContextValue | null>(null);\n\nconst FLUID_EASE = [0.16, 1, 0.3, 1] as const;\nconst POPOVER_EXIT_EASE = [0.4, 0, 0.6, 1] as const;\n\nconst POPOVER_SPRING = {\n  type: \"spring\" as const,\n  stiffness: 340,\n  damping: 30,\n  mass: 0.72,\n};\n\nfunction getSideMotionOffset(side: Side) {\n  switch (side) {\n    case \"top\":\n      return { x: 0, y: 4 };\n    case \"right\":\n      return { x: -4, y: 0 };\n    case \"left\":\n      return { x: 4, y: 0 };\n    default:\n      return { x: 0, y: -4 };\n  }\n}\n\nfunction getPopoverMotion(side: Side) {\n  const offset = getSideMotionOffset(side);\n\n  return {\n    animate: { opacity: 1, scale: 1, x: 0, y: 0 },\n    closed: { opacity: 0, scale: 0.988, ...offset },\n    initial: { opacity: 0, scale: 0.988, ...offset },\n    openTransition: {\n      opacity: { duration: 0.26, ease: FLUID_EASE },\n      scale: POPOVER_SPRING,\n      x: POPOVER_SPRING,\n      y: POPOVER_SPRING,\n    },\n    closedTransition: {\n      opacity: { duration: 0.16, ease: POPOVER_EXIT_EASE },\n      scale: { duration: 0.16, ease: POPOVER_EXIT_EASE },\n      x: { duration: 0.16, ease: POPOVER_EXIT_EASE },\n      y: { duration: 0.16, ease: POPOVER_EXIT_EASE },\n    },\n  };\n}\n\nconst assignRef = <T,>(ref: React.ForwardedRef<T>, value: T | null) => {\n  if (typeof ref === \"function\") {\n    ref(value);\n    return;\n  }\n\n  if (ref) {\n    ref.current = value;\n  }\n};\n\nconst getElementRef = <T,>(element: React.ReactElement) =>\n  (\n    element as React.ReactElement & {\n      ref?: React.Ref<T>;\n      props: { ref?: React.Ref<T> };\n    }\n  ).ref ??\n  (\n    element as React.ReactElement & {\n      ref?: React.Ref<T>;\n      props: { ref?: React.Ref<T> };\n    }\n  ).props.ref;\n\nconst composeRefs =\n  <T,>(...refs: Array<React.Ref<T> | undefined>) =>\n  (value: T | null) => {\n    for (const ref of refs) {\n      if (typeof ref === \"function\") {\n        ref(value);\n        continue;\n      }\n\n      if (ref) {\n        (ref as React.MutableRefObject<T | null>).current = value;\n      }\n    }\n  };\n\nfunction setRef<T>(ref: React.Ref<T> | undefined, value: T) {\n  if (typeof ref === \"function\") {\n    ref(value);\n    return;\n  }\n\n  if (ref) {\n    (ref as React.MutableRefObject<T>).current = value;\n  }\n}\n\nfunction resolvePopupProps(popupProps: PopupRenderProps) {\n  const {\n    children: _popupChildren,\n    className: popupClassName,\n    onAnimationEnd: _onAnimationEnd,\n    onAnimationIteration: _onAnimationIteration,\n    onAnimationStart: _onAnimationStart,\n    onDrag: _onDrag,\n    onDragEnd: _onDragEnd,\n    onDragEnter: _onDragEnter,\n    onDragExit: _onDragExit,\n    onDragLeave: _onDragLeave,\n    onDragOver: _onDragOver,\n    onDragStart: _onDragStart,\n    onDrop: _onDrop,\n    ref: popupRef,\n    style: popupStyle,\n    ...resolvedPopupProps\n  } = popupProps;\n\n  return {\n    popupClassName,\n    popupRef,\n    popupStyle,\n    resolvedPopupProps,\n  };\n}\n\nconst usePopover = () => {\n  const context = React.useContext(PopoverContext);\n\n  if (!context) {\n    throw new Error(\"Popover components must be used inside Popover\");\n  }\n\n  return context;\n};\n\ntype BasePopoverRootProps = Omit<\n  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>,\n  \"children\" | \"defaultOpen\" | \"onOpenChange\" | \"open\"\n>;\n\ntype PopoverProps = BasePopoverRootProps & {\n  children?: React.ReactNode;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  open?: boolean;\n};\n\nconst Popover = ({\n  children,\n  defaultOpen = false,\n  onOpenChange,\n  open: openProp,\n  ...props\n}: PopoverProps) => {\n  const isControlled = openProp !== undefined;\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);\n  const open = isControlled ? openProp : uncontrolledOpen;\n  const actionsRef = React.useRef<PopoverPrimitive.Root.Actions | null>(null);\n  const triggerRef = React.useRef<HTMLElement | null>(null);\n  const anchorRef = React.useRef<HTMLElement | null>(null);\n  const reactId = React.useId();\n\n  const handleOpenChange = React.useCallback(\n    (nextOpen: boolean) => {\n      if (!isControlled) {\n        setUncontrolledOpen(nextOpen);\n      }\n\n      onOpenChange?.(nextOpen);\n    },\n    [isControlled, onOpenChange]\n  );\n\n  return (\n    <PopoverContext.Provider\n      value={{\n        actionsRef,\n        open,\n        contentId: `${reactId}-content`,\n        triggerId: `${reactId}-trigger`,\n        getAnchorNode: () => anchorRef.current ?? triggerRef.current,\n        setAnchorNode: (node) => {\n          anchorRef.current = node;\n        },\n        setTriggerNode: (node) => {\n          triggerRef.current = node;\n        },\n      }}\n    >\n      <PopoverPrimitive.Root\n        {...props}\n        actionsRef={actionsRef}\n        onOpenChange={(nextOpen) => {\n          handleOpenChange(nextOpen);\n        }}\n        open={open}\n      >\n        {children}\n      </PopoverPrimitive.Root>\n    </PopoverContext.Provider>\n  );\n};\nPopover.displayName = \"Popover\";\n\ntype PopoverTriggerProps = Omit<\n  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>,\n  \"children\" | \"className\" | \"id\" | \"render\"\n> & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n  className?: string;\n};\n\nconst PopoverTrigger = React.forwardRef<HTMLElement, PopoverTriggerProps>(\n  ({ asChild, children, className, nativeButton, ...props }, ref) => {\n    const { triggerId, setTriggerNode } = usePopover();\n\n    if (asChild) {\n      if (!React.isValidElement<PopoverTriggerElementProps>(children)) {\n        throw new Error(\n          \"PopoverTrigger with asChild expects a single React element child.\"\n        );\n      }\n\n      const child = React.Children.only(children) as PopoverTriggerChildElement;\n      const childNativeButton =\n        typeof child.type === \"string\" ? child.type === \"button\" : false;\n\n      return (\n        <PopoverPrimitive.Trigger\n          {...props}\n          className={className}\n          id={triggerId}\n          nativeButton={nativeButton ?? childNativeButton}\n          ref={(node: HTMLElement | null) => {\n            setTriggerNode(node);\n            assignRef(ref, node);\n          }}\n          render={\n            className\n              ? React.cloneElement(child, {\n                  className: cn(className, child.props.className),\n                })\n              : child\n          }\n        />\n      );\n    }\n\n    return (\n      <PopoverPrimitive.Trigger\n        {...props}\n        className={cn(\n          popoverThemeClassName,\n          popoverTriggerClassName,\n          className\n        )}\n        id={triggerId}\n        nativeButton={nativeButton}\n        ref={(node: HTMLElement | null) => {\n          setTriggerNode(node);\n          assignRef(ref, node);\n        }}\n      >\n        {children}\n      </PopoverPrimitive.Trigger>\n    );\n  }\n);\nPopoverTrigger.displayName = \"PopoverTrigger\";\n\ntype PopoverAnchorProps = React.HTMLAttributes<HTMLDivElement> & {\n  asChild?: boolean;\n};\n\nconst PopoverAnchor = React.forwardRef<HTMLElement, PopoverAnchorProps>(\n  ({ asChild, children, ...props }, ref) => {\n    const { setAnchorNode } = usePopover();\n\n    if (asChild) {\n      if (!React.isValidElement<PopoverAnchorElementProps>(children)) {\n        throw new Error(\n          \"PopoverAnchor with asChild expects a single React element child.\"\n        );\n      }\n\n      const child = React.Children.only(children) as PopoverAnchorChildElement;\n      const childRef = getElementRef<HTMLElement>(child);\n\n      return React.cloneElement(child, {\n        ...props,\n        ref: composeRefs<HTMLElement>(\n          childRef,\n          (node: HTMLElement | null) => {\n            setAnchorNode(node);\n          },\n          ref\n        ),\n      } as PopoverAnchorElementProps & React.RefAttributes<HTMLElement>);\n    }\n\n    return (\n      <div\n        {...props}\n        ref={(node: HTMLDivElement | null) => {\n          setAnchorNode(node);\n          assignRef(ref, node);\n        }}\n      >\n        {children}\n      </div>\n    );\n  }\n);\nPopoverAnchor.displayName = \"PopoverAnchor\";\n\ntype PopoverContentProps = {\n  align?: Align;\n  avoidCollisions?: boolean;\n  children?: React.ReactNode;\n  className?: string;\n  collisionPadding?: CollisionPadding;\n  onAnimationComplete?: (definition: unknown) => void;\n  open?: boolean;\n  side?: Side;\n  sideOffset?: number;\n  style?: React.CSSProperties;\n};\n\nconst PopoverContentBody = React.forwardRef<\n  HTMLDivElement,\n  PopoverContentProps\n>(\n  (\n    {\n      align = \"center\",\n      avoidCollisions = true,\n      children,\n      className,\n      collisionPadding = 12,\n      onAnimationComplete,\n      side = \"bottom\",\n      sideOffset = 8,\n      style,\n    },\n    ref\n  ) => {\n    const { actionsRef, contentId, triggerId, open, getAnchorNode } =\n      usePopover();\n\n    return (\n      <PopoverPrimitive.Portal>\n        <PopoverPrimitive.Positioner\n          align={align}\n          anchor={getAnchorNode()}\n          className=\"z-50 outline-none\"\n          collisionAvoidance={\n            avoidCollisions\n              ? undefined\n              : { side: \"none\", align: \"none\", fallbackAxisSide: \"none\" }\n          }\n          collisionPadding={collisionPadding}\n          side={side}\n          sideOffset={sideOffset}\n        >\n          <PopoverPrimitive.Popup\n            finalFocus={false}\n            initialFocus={false}\n            render={(popupProps, popupState) => {\n              const {\n                popupClassName,\n                popupRef,\n                popupStyle,\n                resolvedPopupProps,\n              } = resolvePopupProps(popupProps as PopupRenderProps);\n              const resolvedSide = (popupState.side as Side) ?? side;\n              const popoverMotion = getPopoverMotion(resolvedSide);\n\n              return (\n                <div\n                  {...resolvedPopupProps}\n                  aria-labelledby={triggerId}\n                  id={contentId}\n                  ref={(node) => {\n                    setRef(popupRef, node);\n                    assignRef(ref, node);\n                  }}\n                  role=\"presentation\"\n                  style={{\n                    transformOrigin: \"var(--transform-origin)\",\n                    ...popupStyle,\n                  }}\n                >\n                  <motion.div\n                    animate={\n                      open ? popoverMotion.animate : popoverMotion.closed\n                    }\n                    className={cn(\n                      popoverThemeClassName,\n                      popoverPanelClassName,\n                      popupClassName,\n                      className\n                    )}\n                    data-side={resolvedSide}\n                    data-state={open ? \"open\" : \"closed\"}\n                    initial={\n                      popupState.transitionStatus === \"starting\"\n                        ? popoverMotion.initial\n                        : false\n                    }\n                    layout=\"size\"\n                    onAnimationComplete={(definition) => {\n                      onAnimationComplete?.(definition);\n\n                      if (!open) {\n                        actionsRef.current?.unmount();\n                      }\n                    }}\n                    style={{\n                      pointerEvents: open ? undefined : \"none\",\n                      transformOrigin: \"var(--transform-origin)\",\n                      ...style,\n                    }}\n                    transition={\n                      open\n                        ? popoverMotion.openTransition\n                        : popoverMotion.closedTransition\n                    }\n                  >\n                    {children}\n                  </motion.div>\n                </div>\n              );\n            }}\n          />\n        </PopoverPrimitive.Positioner>\n      </PopoverPrimitive.Portal>\n    );\n  }\n);\nPopoverContentBody.displayName = \"PopoverContentBody\";\n\nconst PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(\n  ({ open: _open, ...props }, ref) => {\n    const { open } = usePopover();\n    const [present, setPresent] = React.useState(open);\n\n    React.useEffect(() => {\n      if (open) {\n        setPresent(true);\n      }\n    }, [open]);\n\n    if (!present) {\n      return null;\n    }\n\n    return (\n      <PopoverContentBody\n        {...props}\n        onAnimationComplete={(definition) => {\n          props.onAnimationComplete?.(definition);\n\n          if (!open) {\n            setPresent(false);\n          }\n        }}\n        ref={ref}\n      />\n    );\n  }\n);\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n",
      "type": "registry:ui"
    }
  ],
  "title": "Popover (Base UI)",
  "description": "Popover with the same Iconiq API layered over Base UI popover primitives, preserving side-aware panel motion, optional anchor support, and size-aware content transitions."
}
