Revert "Modal: drop transform from open animation so clicks don't shift targets"

This reverts commit 4167bf22ce.
This commit is contained in:
Tanish Manku committed 2026-05-01 18:34:53 -07:00
1 parent 4167bf22ce
commit 989d77f520
2 files changed
+86 -13

No files matched your search

@@ -123,6 +123,76 @@ export const PageEditor = () => {
}
};
// TEMP debug: trace click / mousedown / pointerdown events at every
// listenable phase so we can locate whatever is silencing the
// upload-modal file-picker click. Remove once the bug is fixed.
useEffect(() => {
const describe = (t: EventTarget | null): string => {
if (!(t instanceof HTMLElement)) return String(t);
const id = t.id ? `#${t.id}` : "";
const cls =
typeof t.className === "string" && t.className
? `.${t.className.split(/\s+/).slice(0, 2).join(".")}`
: "";
const label =
t.closest("label")?.getAttribute("for") ??
(t.closest("label") ? "(unnamed)" : null);
return `${t.tagName.toLowerCase()}${id}${cls}${label ? ` [in label for=${label}]` : ""}`;
};
const trace = (phase: string, type: string) => (e: Event) => {
// eslint-disable-next-line no-console
console.debug(
`[click-trace] ${type} ${phase}`,
{
target: describe(e.target),
currentTarget: describe(e.currentTarget),
defaultPrevented: e.defaultPrevented,
bubbles: e.bubbles,
composedPath: (e as any).composedPath?.()?.slice(0, 6).map(describe),
},
);
};
const types: Array<
"click" | "mousedown" | "mouseup" | "pointerdown" | "pointerup"
> = ["click", "mousedown", "mouseup", "pointerdown", "pointerup"];
const handlers = types.flatMap((type) => {
const cap = trace("CAPTURE", type);
const bub = trace("BUBBLE", type);
document.addEventListener(type, cap, true);
document.addEventListener(type, bub, false);
return [
() => document.removeEventListener(type, cap, true),
() => document.removeEventListener(type, bub, false),
];
});
// Monkey-patch setPointerCapture to see who's grabbing the pointer
// (a mid-click capture explains the missing click — mouseup fires
// on the captured element instead of the original mousedown target).
const proto = Element.prototype as any;
const originalSet = proto.setPointerCapture;
proto.setPointerCapture = function (id: number) {
// eslint-disable-next-line no-console
console.debug("[click-trace] setPointerCapture", {
on: describe(this),
pointerId: id,
stack: new Error().stack?.split("\n").slice(1, 6).join("\n"),
});
return originalSet.call(this, id);
};
// eslint-disable-next-line no-console
console.debug("[click-trace] installed");
return () => {
handlers.forEach((off) => off());
proto.setPointerCapture = originalSet;
// eslint-disable-next-line no-console
console.debug("[click-trace] removed");
};
}, []);
useEffect(() => {
window.onbeforeunload = () => {
return "You may have unsaved changes.";
@@ -229,19 +229,20 @@ export const Modal = ({
// Track last non-expanded position
const lastNonExpandedPosition = useRef<{ x: number; y: number } | null>(null);
// Animation transitions. Transform (translate / scale) is
// intentionally omitted — when the React tree under the modal is
// busy (e.g. the 3D scene is rendering), the spring takes long
// enough that a quick click on a deep child (like the file
// uploader's "Upload a file" link) lands its mousedown on one
// element and its mouseup on another after the modal shifts under
// the cursor, breaking WebView2's strict same-target rule for
// synthesizing `click`. The file picker then never opens. Opacity
// alone gives the fade without moving any clickable surface.
// Animation transitions
const transitions = useTransition(isOpen, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
from: {
opacity: 0,
transform: "scale(0.95) translateY(-10px)",
},
enter: {
opacity: 1,
transform: "scale(1) translateY(0px)",
},
leave: {
opacity: 0,
transform: "scale(0.95) translateY(10px)",
},
config: {
tension: 300,
friction: 30,
@@ -985,7 +986,9 @@ export const Modal = ({
style={{
...getModalStyle(),
opacity: styles.opacity,
willChange: "opacity",
transform: styles.transform,
transformOrigin: "center center",
willChange: "transform, opacity", // Optimize for animations
outline: "none",
}}
>