diff --git a/components/social/comment/comment-menu.tsx b/components/social/comment/comment-menu.tsx index 37ef252d..83657192 100644 --- a/components/social/comment/comment-menu.tsx +++ b/components/social/comment/comment-menu.tsx @@ -97,7 +97,10 @@ export function CommentMenu({ ref={menuRef} role="menu" style={{ position: "fixed", top: pos.top, right: pos.right }} - className="z-[101] min-w-40 rounded-lg border border-border bg-card shadow-lg py-1 animate-in fade-in-0 zoom-in-95" + // pointer-events-auto: the comments drawer is modal (vaul sets + // body { pointer-events: none } while open); this portaled menu + // would be click-through without re-enabling it here. + className="pointer-events-auto z-[101] min-w-40 rounded-lg border border-border bg-card shadow-lg py-1 animate-in fade-in-0 zoom-in-95" > {canPin ? ( (null); const btnRef = useRef(null); + const panelRef = useRef(null); + + // Dismiss on any outside pointer-down or Escape. Deferred a tick so the + // opening click doesn't immediately re-close it; capture phase so it fires + // wherever the target lives. No close-on-scroll here — the panel scrolls + // internally, so a scroll inside it must NOT dismiss. + useEffect(() => { + if (!open) return; + function onDown(e: PointerEvent) { + const t = e.target as Node; + if (panelRef.current?.contains(t) || btnRef.current?.contains(t)) return; + setOpen(false); + } + function onKey(e: KeyboardEvent) { + if (e.key === "Escape") setOpen(false); + } + const id = window.setTimeout(() => { + document.addEventListener("pointerdown", onDown, true); + document.addEventListener("keydown", onKey); + }, 0); + return () => { + window.clearTimeout(id); + document.removeEventListener("pointerdown", onDown, true); + document.removeEventListener("keydown", onKey); + }; + }, [open]); function toggle() { if (open) { @@ -108,59 +134,53 @@ export function EmojiPicker({ {open && pos && typeof document !== "undefined" ? createPortal( - <> +
{ - e.stopPropagation(); - setOpen(false); - }} - /> -
e.stopPropagation()} + onTouchMove={(e) => e.stopPropagation()} > -
e.stopPropagation()} - onTouchMove={(e) => e.stopPropagation()} - > - {EMOJI_GROUPS.map((g) => ( -
-

- {g.label} -

-
- {g.emojis.map((e, i) => ( - - ))} -
+ {EMOJI_GROUPS.map((g) => ( +
+

+ {g.label} +

+
+ {g.emojis.map((e, i) => ( + + ))}
- ))} -
+
+ ))}
- , +
, document.body, ) : null}