import { useEffect, useMemo, useRef } from "react"; import { createPortal } from "react-dom"; import { Icon } from "../ui/Icon"; import { windowCloseIcon } from "../ui/icons"; import { VirtualList } from "../virtual/VirtualList"; import type { AdAction, AdSlot } from "./types"; import styles from "./Ads.module.scss"; type AdTextSection = | { key: "intro"; kind: "intro" } | { key: string; kind: "detail"; label: string; value: string }; type FloatingAdProps = { ad: AdSlot; trigger: HTMLButtonElement | null; onClose: () => void; onAction: (action: AdAction) => void; }; export function FloatingAd({ ad, trigger, onClose, onAction }: FloatingAdProps) { const dialog = useRef(null); const textSections = useMemo(() => [ { key: "intro", kind: "intro" }, ...ad.content.details.map((detail, index) => ({ key: `detail-${index}-${detail.label}`, kind: "detail" as const, label: detail.label, value: detail.value, })), ], [ad.content.details]); useEffect(() => { dialog.current?.focus(); const handlePointerDown = (event: PointerEvent) => { const target = event.target as Node; if (!dialog.current?.contains(target) && !trigger?.contains(target)) onClose(); }; const handleKeyDown = (event: KeyboardEvent) => { if (event.key !== "Escape") return; event.preventDefault(); onClose(); trigger?.focus(); }; document.addEventListener("pointerdown", handlePointerDown); document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("pointerdown", handlePointerDown); document.removeEventListener("keydown", handleKeyDown); }; }, [onClose, trigger]); return createPortal(, document.body); }