-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathuse-mac-webview-drag-bridge.hook.ts
More file actions
122 lines (109 loc) · 3.65 KB
/
Copy pathuse-mac-webview-drag-bridge.hook.ts
File metadata and controls
122 lines (109 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { ShapeType } from '#core/model';
import { useCanvasContext } from '#core/providers';
import {
convertFromDivElementCoordsToKonvaCoords,
getScrollFromDiv,
isScreenPositionInsideDivElement,
portScreenPositionToDivCoordinates,
} from '#pods/canvas/canvas.util';
import { calculateShapeOffsetToXDropCoordinate } from '#pods/canvas/use-monitor.business';
import {
type DragBridgeHostMessage,
DRAG_BRIDGE_MESSAGE_TYPE,
} from '@lemoncode/quickmock-bridge-protocol';
import { useEffect } from 'react';
import {
notifyDragMoveToWebviewShell,
shouldUseMacWebviewDragBridge,
} from './mac-webview-drag-bridge.utils';
// macOS workaround for microsoft/vscode#193558: drag events on the inner
// iframe route to the shell, so the shell-side bridge captures the drop and
// forwards coordinates here; this reproduces the insertion useMonitorShape
// performs natively on other platforms.
type GalleryDropMessage = Extract<
DragBridgeHostMessage,
{ type: typeof DRAG_BRIDGE_MESSAGE_TYPE.GALLERY_DROP }
>;
const isGalleryDropMessage = (data: unknown): data is GalleryDropMessage => {
if (!data || typeof data !== 'object') {
return false;
}
const message = data as {
type?: unknown;
payload?: {
shapeType?: unknown;
clientX?: unknown;
clientY?: unknown;
};
};
return (
message.type === DRAG_BRIDGE_MESSAGE_TYPE.GALLERY_DROP &&
typeof message.payload?.shapeType === 'string' &&
typeof message.payload?.clientX === 'number' &&
typeof message.payload?.clientY === 'number'
);
};
export const useMacWebviewDragBridge = (
dropRef: React.MutableRefObject<null>,
addNewShape: (type: ShapeType, x: number, y: number) => void
) => {
const { stageRef } = useCanvasContext();
useEffect(() => {
if (!shouldUseMacWebviewDragBridge()) {
return;
}
const handleGalleryDrop = (event: MessageEvent): void => {
if (!isGalleryDropMessage(event.data)) {
return;
}
const { shapeType, clientX, clientY } = event.data.payload;
const dropDivElement = dropRef.current as HTMLDivElement | null;
const stageInstance = stageRef.current;
if (!dropDivElement || !stageInstance) {
return;
}
const screenPosition = { x: clientX, y: clientY };
if (!isScreenPositionInsideDivElement(dropDivElement, screenPosition)) {
return;
}
const relativeDivPosition = portScreenPositionToDivCoordinates(
dropDivElement,
screenPosition
);
const { scrollLeft, scrollTop } = getScrollFromDiv(
dropRef as unknown as React.MutableRefObject<HTMLDivElement>
);
const konvaCoordinate = convertFromDivElementCoordsToKonvaCoords(
stageInstance,
{
screenPosition,
relativeDivPosition,
scroll: { x: scrollLeft, y: scrollTop },
}
);
const shapeOffsetX = calculateShapeOffsetToXDropCoordinate(
konvaCoordinate.x,
shapeType as ShapeType
);
const positionX = konvaCoordinate.x - shapeOffsetX;
const positionY = konvaCoordinate.y;
addNewShape(shapeType as ShapeType, positionX, positionY);
};
window.addEventListener('message', handleGalleryDrop);
return () => {
window.removeEventListener('message', handleGalleryDrop);
};
}, []);
useEffect(() => {
if (!shouldUseMacWebviewDragBridge()) {
return;
}
const handleDragOver = (event: DragEvent): void => {
notifyDragMoveToWebviewShell(event.clientX, event.clientY);
};
document.addEventListener('dragover', handleDragOver, true);
return () => {
document.removeEventListener('dragover', handleDragOver, true);
};
}, []);
};