zebflow 0.6.1

Reactive web automation platform — pipelines, templates, and real-time collaboration in a single binary.
Documentation
import { cx } from "zeb";
import { useState, useRef } from "zeb";
import { useClickAway } from "zeb/use";

interface PopoverProps {
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
  children?: any;
  [key: string]: any;
}

export function Popover({ open, defaultOpen = false, onOpenChange, children }: PopoverProps) {
  const [internal, setInternal] = useState(defaultOpen);
  const controlled = open !== undefined;
  const isOpen = controlled ? open : internal;

  const toggle = (v: boolean) => {
    if (!controlled) setInternal(v);
    onOpenChange?.(v);
  };

  const containerRef = useRef<HTMLDivElement>(null);
  useClickAway(containerRef, () => toggle(false));

  const items = Array.isArray(children) ? children : [children];
  const enhanced = items.map((child: any) => {
    if (!child || typeof child !== "object") return child;
    return { ...child, props: { ...child.props, _isOpen: isOpen, _onOpen: () => toggle(true), _onClose: () => toggle(false) } };
  });

  return (
    <div ref={containerRef} className="relative inline-block">
      {enhanced}
    </div>
  );
}

export function PopoverTrigger({ children, _onOpen, asChild, className, ...rest }: any) {
  const handleClick = () => _onOpen?.();
  if (asChild && children && typeof children === "object") {
    return { ...children, props: { ...children.props, onClick: handleClick } };
  }
  return (
    <button type="button" onClick={handleClick} className={cx("", className)} {...rest}>
      {children}
    </button>
  );
}

export function PopoverContent({ className, children, _isOpen, align = "center", sideOffset = 4, ...rest }: any) {
  if (!_isOpen) return null;

  const alignClass = align === "start" ? "left-0" : align === "end" ? "right-0" : "left-1/2 -translate-x-1/2";

  return (
    <div
      role="dialog"
      className={cx(
        `absolute z-50 w-72 rounded-md border border-gray-200 bg-white p-4 shadow-md outline-none top-full mt-${sideOffset}`,
        alignClass,
        className
      )}
      style={{ marginTop: `${sideOffset}px` }}
      {...rest}
    >
      {children}
    </div>
  );
}

export default Popover;