Skip to content

Commit 6bd055c

Browse files
update zoom behavior with zoomable section
1 parent 39529ca commit 6bd055c

File tree

3 files changed

+64
-45
lines changed

3 files changed

+64
-45
lines changed

apps/web/client/public/onlook-preload-script.js

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/client/src/app/project/[id]/_components/main.tsx

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,6 @@ export const Main = observer(() => {
3030
rightPanelRef,
3131
);
3232

33-
useEffect(() => {
34-
function handleGlobalWheel(event: WheelEvent) {
35-
if (!(event.ctrlKey || event.metaKey)) {
36-
return;
37-
}
38-
event.preventDefault();
39-
event.stopPropagation();
40-
}
41-
42-
window.addEventListener('wheel', handleGlobalWheel, { passive: false });
43-
return () => {
44-
window.removeEventListener('wheel', handleGlobalWheel);
45-
};
46-
}, []);
47-
4833
if (error) {
4934
return (
5035
<div className="h-screen w-screen flex items-center justify-center gap-2 flex-col">

apps/web/preload/script/api/events/wheel.ts

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,59 @@ export function listenForWheelZoom() {
66
return;
77
}
88

9-
event.preventDefault();
10-
event.stopPropagation();
11-
12-
if (penpalParent) {
13-
penpalParent
14-
.onFrameWheel({
15-
deltaY: event.deltaY,
16-
clientX: event.clientX,
17-
clientY: event.clientY,
18-
ctrlKey: event.ctrlKey,
19-
metaKey: event.metaKey,
20-
})
21-
.catch(() => {
22-
// ignore
23-
});
9+
const path = event.composedPath() as HTMLElement[];
10+
11+
let zoomHandledInside = false;
12+
13+
for (const el of path) {
14+
if (el instanceof Element) {
15+
try {
16+
const style = window.getComputedStyle(el);
17+
18+
// Heuristic #1: It's explicitly scrollable
19+
const scrollable = /(auto|scroll)/.test(
20+
style.overflow + style.overflowX + style.overflowY,
21+
);
22+
23+
// Heuristic #2: It's explicitly interactive / transforms
24+
const hasTransform = style.transform !== 'none';
25+
26+
// Heuristic #3: Prevents pinch gestures in browser defaults
27+
const disablesDefaultTouch = style.touchAction === 'none';
28+
29+
// Heuristic #4: Specific tag types often used for zoomable content
30+
const zoomableTags = ['CANVAS', 'SVG', 'IMG'];
31+
const isZoomableTag = zoomableTags.includes(el.tagName);
32+
33+
if (scrollable || hasTransform || disablesDefaultTouch || isZoomableTag) {
34+
zoomHandledInside = true;
35+
break;
36+
}
37+
} catch (err) {
38+
console.warn('Could not get computed style for node:', el, err);
39+
}
40+
}
2441
}
25-
}
2642

27-
window.addEventListener('wheel', handleWheel, { passive: false });
28-
}
43+
if (!zoomHandledInside) {
44+
event.preventDefault();
45+
event.stopPropagation();
2946

47+
if (penpalParent) {
48+
penpalParent
49+
.onFrameWheel({
50+
deltaY: event.deltaY,
51+
clientX: event.clientX,
52+
clientY: event.clientY,
53+
ctrlKey: event.ctrlKey,
54+
metaKey: event.metaKey,
55+
})
56+
.catch(() => {
57+
// ignore
58+
});
59+
}
60+
}
61+
}
3062

63+
window.addEventListener('wheel', handleWheel, { passive: false, capture: true });
64+
}

0 commit comments

Comments
 (0)