@markup-canvas/react 1.1.7 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/useMarkupCanvas.d.ts +24 -10
- package/dist/index.cjs.js +90 -232
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +91 -232
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useMarkupCanvas.ts +201 -74
- package/src/index.ts +1 -1
- package/dist/hooks/useMarkupCanvasWindow.d.ts +0 -43
- package/src/hooks/useMarkupCanvasWindow.ts +0 -304
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
1
|
+
import type { Transform, WindowAPI } from "@markup-canvas/core";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import type { UseMarkupCanvasOptions } from "../types/index.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
interface UseMarkupCanvasHookOptions extends Omit<UseMarkupCanvasOptions, "onReady"> {
|
|
6
|
+
canvasName?: string;
|
|
7
|
+
onError?: () => void;
|
|
8
|
+
onReady?: (canvas: WindowAPI) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useMarkupCanvas(options: UseMarkupCanvasHookOptions = {}) {
|
|
12
|
+
const { canvasName = "markupCanvas" } = options;
|
|
13
|
+
|
|
14
|
+
const [canvas, setCanvas] = useState<WindowAPI | null>(null);
|
|
7
15
|
const [transform, setTransform] = useState<Transform>({ scale: 1, translateX: 0, translateY: 0 });
|
|
8
16
|
const [zoom, setZoom] = useState(1);
|
|
9
17
|
const [pan, setPan] = useState({ x: 0, y: 0 });
|
|
10
18
|
const [isReady, setIsReady] = useState(false);
|
|
11
19
|
const [themeMode, setThemeModeState] = useState<"light" | "dark">("light");
|
|
20
|
+
const [showRulersState, setShowRulersState] = useState(false);
|
|
21
|
+
const [showGridState, setShowGridState] = useState(false);
|
|
12
22
|
|
|
13
23
|
const optionsRef = useRef(options);
|
|
14
24
|
optionsRef.current = options;
|
|
15
25
|
|
|
16
|
-
const handleCanvasInstance = useCallback((
|
|
17
|
-
|
|
18
|
-
optionsRef.current.onReady?.(
|
|
26
|
+
const handleCanvasInstance = useCallback((canvasInstance: WindowAPI) => {
|
|
27
|
+
setCanvas(canvasInstance);
|
|
28
|
+
optionsRef.current.onReady?.(canvasInstance);
|
|
19
29
|
}, []);
|
|
20
30
|
|
|
21
31
|
const handleTransform = useCallback((newTransform: Transform) => {
|
|
@@ -33,121 +43,228 @@ export function useMarkupCanvas(canvasRef: RefObject<MarkupCanvasRef | null>, op
|
|
|
33
43
|
optionsRef.current.onPanChange?.(newPan);
|
|
34
44
|
}, []);
|
|
35
45
|
|
|
36
|
-
const handleReady = useCallback((
|
|
46
|
+
const handleReady = useCallback((canvasInstance: WindowAPI) => {
|
|
37
47
|
setIsReady(true);
|
|
38
|
-
optionsRef.current.onReady?.(
|
|
48
|
+
optionsRef.current.onReady?.(canvasInstance);
|
|
39
49
|
}, []);
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
const handleRulersVisibilityChange = useCallback((isVisible: boolean) => {
|
|
52
|
+
setShowRulersState(isVisible);
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const handleGridVisibilityChange = useCallback((isVisible: boolean) => {
|
|
56
|
+
setShowGridState(isVisible);
|
|
57
|
+
}, []);
|
|
43
58
|
|
|
44
|
-
|
|
59
|
+
// Get instance from window binding
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (typeof window === "undefined") {
|
|
62
|
+
optionsRef.current.onError?.();
|
|
45
63
|
return;
|
|
46
64
|
}
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
const windowCanvas = (window as unknown as Record<string, unknown>)[canvasName] as WindowAPI;
|
|
67
|
+
|
|
68
|
+
if (windowCanvas && typeof windowCanvas === "object") {
|
|
69
|
+
handleCanvasInstance(windowCanvas);
|
|
70
|
+
optionsRef.current.onReady?.(windowCanvas);
|
|
71
|
+
|
|
72
|
+
// Set initial state from instance
|
|
73
|
+
if (windowCanvas.state?.transform) {
|
|
74
|
+
const transform = windowCanvas.state.transform;
|
|
75
|
+
setTransform(transform);
|
|
76
|
+
setZoom(transform.scale);
|
|
77
|
+
setPan({ x: transform.translateX, y: transform.translateY });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (windowCanvas.state?.isReady) {
|
|
81
|
+
setIsReady(true);
|
|
82
|
+
optionsRef.current.onReady?.(windowCanvas);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setThemeModeState((windowCanvas?.theme?.current as "light" | "dark" | undefined) || "light");
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
87
|
+
if (windowCanvas.rulers?.isVisible?.()) {
|
|
88
|
+
setShowRulersState(true);
|
|
89
|
+
}
|
|
90
|
+
if (windowCanvas.grid?.isVisible?.()) {
|
|
91
|
+
setShowGridState(true);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
optionsRef.current.onError?.();
|
|
57
95
|
}
|
|
96
|
+
}, [canvasName, handleCanvasInstance]);
|
|
58
97
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
// Set up event listeners on canvas instance
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!canvas) {
|
|
101
|
+
return;
|
|
62
102
|
}
|
|
63
103
|
|
|
104
|
+
canvas.event.on("transform", handleTransform);
|
|
105
|
+
canvas.event.on("zoom", handleZoom);
|
|
106
|
+
canvas.event.on("pan", handlePan);
|
|
107
|
+
canvas.event.on("ready", handleReady);
|
|
108
|
+
canvas.event.on("rulersVisibility", handleRulersVisibilityChange);
|
|
109
|
+
canvas.event.on("gridVisibility", handleGridVisibilityChange);
|
|
110
|
+
|
|
64
111
|
return () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
112
|
+
canvas.event.off("transform", handleTransform);
|
|
113
|
+
canvas.event.off("zoom", handleZoom);
|
|
114
|
+
canvas.event.off("pan", handlePan);
|
|
115
|
+
canvas.event.off("ready", handleReady);
|
|
116
|
+
canvas.event.off("rulersVisibility", handleRulersVisibilityChange);
|
|
117
|
+
canvas.event.off("gridVisibility", handleGridVisibilityChange);
|
|
69
118
|
};
|
|
70
|
-
}, [
|
|
119
|
+
}, [canvas, handleTransform, handleZoom, handlePan, handleReady, handleRulersVisibilityChange, handleGridVisibilityChange]);
|
|
71
120
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
121
|
+
// Listen to window messages for state updates
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const handleMessage = (event: MessageEvent) => {
|
|
124
|
+
if (event.data.source === "markup-canvas" && event.data.canvasName === canvasName) {
|
|
125
|
+
switch (event.data.event) {
|
|
126
|
+
case "transform":
|
|
127
|
+
handleTransform(event.data.data);
|
|
128
|
+
break;
|
|
129
|
+
case "zoom":
|
|
130
|
+
console.log("zoom", event.data.data);
|
|
131
|
+
handleZoom(event.data.data);
|
|
132
|
+
break;
|
|
133
|
+
case "pan":
|
|
134
|
+
handlePan(event.data.data);
|
|
135
|
+
break;
|
|
136
|
+
case "ready":
|
|
137
|
+
handleReady(event.data.data);
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
75
144
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
145
|
+
window.addEventListener("message", handleMessage);
|
|
146
|
+
|
|
147
|
+
return () => {
|
|
148
|
+
window.removeEventListener("message", handleMessage);
|
|
149
|
+
};
|
|
150
|
+
}, [canvasName, handleTransform, handleZoom, handlePan, handleReady]);
|
|
151
|
+
|
|
152
|
+
// Action methods
|
|
153
|
+
const zoomIn = useCallback(
|
|
154
|
+
(factor = 0.5) => {
|
|
155
|
+
canvas?.zoom?.in?.(factor);
|
|
156
|
+
},
|
|
157
|
+
[canvas]
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const zoomOut = useCallback(
|
|
161
|
+
(factor = 0.5) => {
|
|
162
|
+
canvas?.zoom?.out?.(factor);
|
|
163
|
+
},
|
|
164
|
+
[canvas]
|
|
165
|
+
);
|
|
79
166
|
|
|
80
167
|
const resetZoom = useCallback(() => {
|
|
81
|
-
|
|
82
|
-
}, [
|
|
168
|
+
canvas?.zoom?.reset?.();
|
|
169
|
+
}, [canvas]);
|
|
170
|
+
|
|
171
|
+
const panLeft = useCallback(
|
|
172
|
+
(distance?: number) => {
|
|
173
|
+
canvas?.pan?.left?.(distance);
|
|
174
|
+
},
|
|
175
|
+
[canvas]
|
|
176
|
+
);
|
|
83
177
|
|
|
84
|
-
const
|
|
85
|
-
(
|
|
86
|
-
|
|
178
|
+
const panRight = useCallback(
|
|
179
|
+
(distance?: number) => {
|
|
180
|
+
canvas?.pan?.right?.(distance);
|
|
87
181
|
},
|
|
88
|
-
[
|
|
182
|
+
[canvas]
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const panUp = useCallback(
|
|
186
|
+
(distance?: number) => {
|
|
187
|
+
canvas?.pan?.up?.(distance);
|
|
188
|
+
},
|
|
189
|
+
[canvas]
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const panDown = useCallback(
|
|
193
|
+
(distance?: number) => {
|
|
194
|
+
canvas?.pan?.down?.(distance);
|
|
195
|
+
},
|
|
196
|
+
[canvas]
|
|
89
197
|
);
|
|
90
198
|
|
|
91
199
|
const fitToContent = useCallback(() => {
|
|
92
|
-
|
|
93
|
-
}, [
|
|
200
|
+
canvas?.zoom?.fitToScreen?.();
|
|
201
|
+
}, [canvas]);
|
|
94
202
|
|
|
95
203
|
const centerContent = useCallback(() => {
|
|
96
|
-
|
|
97
|
-
}, [
|
|
204
|
+
canvas?.pan?.toCenter?.();
|
|
205
|
+
}, [canvas]);
|
|
206
|
+
|
|
207
|
+
const resetView = useCallback(() => {
|
|
208
|
+
canvas?.zoom?.resetToCenter?.();
|
|
209
|
+
}, [canvas]);
|
|
98
210
|
|
|
99
211
|
const setTransitionMode = useCallback(
|
|
100
212
|
(enabled: boolean) => {
|
|
101
|
-
|
|
102
|
-
canvasRef.current.canvas.updateConfig({ enableTransition: enabled });
|
|
103
|
-
}
|
|
213
|
+
canvas?.transition?.set?.(enabled);
|
|
104
214
|
},
|
|
105
|
-
[
|
|
215
|
+
[canvas]
|
|
106
216
|
);
|
|
107
217
|
|
|
108
218
|
const toggleTransitionMode = useCallback(() => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const newEnableTransition = !currentConfig.enableTransition;
|
|
112
|
-
canvasRef.current.canvas.updateConfig({ enableTransition: newEnableTransition });
|
|
113
|
-
return newEnableTransition;
|
|
114
|
-
}
|
|
115
|
-
return false;
|
|
116
|
-
}, [canvasRef]);
|
|
219
|
+
return canvas?.transition?.toggle?.() ?? false;
|
|
220
|
+
}, [canvas]);
|
|
117
221
|
|
|
118
222
|
const updateThemeMode = useCallback(
|
|
119
223
|
(mode: "light" | "dark") => {
|
|
120
224
|
setThemeModeState(mode);
|
|
121
|
-
|
|
225
|
+
canvas?.theme?.update?.(mode);
|
|
122
226
|
},
|
|
123
|
-
[
|
|
227
|
+
[canvas]
|
|
124
228
|
);
|
|
125
229
|
|
|
126
230
|
const toggleThemeMode = useCallback(() => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
231
|
+
canvas?.theme?.toggle?.();
|
|
232
|
+
}, [canvas]);
|
|
233
|
+
|
|
234
|
+
const showRulers = useCallback(() => {
|
|
235
|
+
canvas?.rulers?.show?.();
|
|
236
|
+
}, [canvas]);
|
|
237
|
+
|
|
238
|
+
const hideRulers = useCallback(() => {
|
|
239
|
+
canvas?.rulers?.hide?.();
|
|
240
|
+
}, [canvas]);
|
|
131
241
|
|
|
132
242
|
const toggleRulers = useCallback(() => {
|
|
133
|
-
|
|
134
|
-
}, [
|
|
243
|
+
canvas?.rulers?.toggle?.();
|
|
244
|
+
}, [canvas]);
|
|
135
245
|
|
|
136
246
|
const areRulersVisible = useCallback(() => {
|
|
137
|
-
return
|
|
138
|
-
}, [
|
|
247
|
+
return canvas?.rulers?.isVisible?.() ?? false;
|
|
248
|
+
}, [canvas]);
|
|
249
|
+
|
|
250
|
+
const showGrid = useCallback(() => {
|
|
251
|
+
canvas?.grid?.show?.();
|
|
252
|
+
}, [canvas]);
|
|
253
|
+
|
|
254
|
+
const hideGrid = useCallback(() => {
|
|
255
|
+
canvas?.grid?.hide?.();
|
|
256
|
+
}, [canvas]);
|
|
139
257
|
|
|
140
258
|
const toggleGrid = useCallback(() => {
|
|
141
|
-
|
|
142
|
-
}, [
|
|
259
|
+
canvas?.grid?.toggle?.();
|
|
260
|
+
}, [canvas]);
|
|
143
261
|
|
|
144
262
|
const isGridVisible = useCallback(() => {
|
|
145
|
-
return
|
|
146
|
-
}, [
|
|
263
|
+
return canvas?.grid?.isVisible?.() ?? false;
|
|
264
|
+
}, [canvas]);
|
|
147
265
|
|
|
148
266
|
return {
|
|
149
|
-
canvas:
|
|
150
|
-
initCanvasUtils: handleCanvasInstance,
|
|
267
|
+
canvas: canvas,
|
|
151
268
|
transform,
|
|
152
269
|
zoom,
|
|
153
270
|
pan,
|
|
@@ -155,17 +272,27 @@ export function useMarkupCanvas(canvasRef: RefObject<MarkupCanvasRef | null>, op
|
|
|
155
272
|
zoomIn,
|
|
156
273
|
zoomOut,
|
|
157
274
|
resetZoom,
|
|
158
|
-
|
|
275
|
+
panLeft,
|
|
276
|
+
panRight,
|
|
277
|
+
panUp,
|
|
278
|
+
panDown,
|
|
159
279
|
fitToContent,
|
|
160
280
|
centerContent,
|
|
281
|
+
resetView,
|
|
161
282
|
setTransitionMode,
|
|
162
283
|
toggleTransitionMode,
|
|
163
284
|
themeMode,
|
|
164
285
|
updateThemeMode,
|
|
165
286
|
toggleThemeMode,
|
|
166
287
|
toggleRulers,
|
|
288
|
+
showRulers,
|
|
289
|
+
hideRulers,
|
|
167
290
|
areRulersVisible,
|
|
291
|
+
showRulersState,
|
|
168
292
|
toggleGrid,
|
|
293
|
+
showGrid,
|
|
294
|
+
hideGrid,
|
|
169
295
|
isGridVisible,
|
|
296
|
+
showGridState,
|
|
170
297
|
};
|
|
171
298
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,6 @@ export type { MarkupCanvas as CoreMarkupCanvas, MarkupCanvasConfig, Transform }
|
|
|
3
3
|
export type { MarkupCanvasProps } from "./components/index.js";
|
|
4
4
|
export { MarkupCanvas } from "./components/index.js";
|
|
5
5
|
// Hooks
|
|
6
|
-
export { useMarkupCanvas
|
|
6
|
+
export { useMarkupCanvas } from "./hooks/index.js";
|
|
7
7
|
// Types
|
|
8
8
|
export type { CanvasEventHandlers, MarkupCanvasRef, UseMarkupCanvasOptions } from "./types/index.js";
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { MarkupCanvas, Transform } from "@markup-canvas/core";
|
|
2
|
-
import type { UseMarkupCanvasOptions } from "../types/index.js";
|
|
3
|
-
interface UseMarkupCanvasWindowOptions extends UseMarkupCanvasOptions {
|
|
4
|
-
canvasName?: string;
|
|
5
|
-
onCanvasReady?: (canvas: MarkupCanvas) => void;
|
|
6
|
-
onCanvasUnavailable?: () => void;
|
|
7
|
-
}
|
|
8
|
-
export declare function useMarkupCanvasWindow(options?: UseMarkupCanvasWindowOptions): {
|
|
9
|
-
canvas: MarkupCanvas | null;
|
|
10
|
-
transform: Transform;
|
|
11
|
-
zoom: number;
|
|
12
|
-
pan: {
|
|
13
|
-
x: number;
|
|
14
|
-
y: number;
|
|
15
|
-
};
|
|
16
|
-
isReady: boolean;
|
|
17
|
-
zoomIn: (factor?: number) => void;
|
|
18
|
-
zoomOut: (factor?: number) => void;
|
|
19
|
-
resetZoom: () => void;
|
|
20
|
-
panLeft: (distance?: number) => void;
|
|
21
|
-
panRight: (distance?: number) => void;
|
|
22
|
-
panUp: (distance?: number) => void;
|
|
23
|
-
panDown: (distance?: number) => void;
|
|
24
|
-
fitToContent: () => void;
|
|
25
|
-
centerContent: () => void;
|
|
26
|
-
resetView: () => void;
|
|
27
|
-
setTransitionMode: (enabled: boolean) => void;
|
|
28
|
-
toggleTransitionMode: () => boolean;
|
|
29
|
-
themeMode: "light" | "dark";
|
|
30
|
-
updateThemeMode: (mode: "light" | "dark") => void;
|
|
31
|
-
toggleThemeMode: () => "light" | "dark";
|
|
32
|
-
toggleRulers: () => void;
|
|
33
|
-
showRulers: () => void;
|
|
34
|
-
hideRulers: () => void;
|
|
35
|
-
areRulersVisible: () => boolean;
|
|
36
|
-
showRulersState: boolean;
|
|
37
|
-
toggleGrid: () => void;
|
|
38
|
-
showGrid: () => void;
|
|
39
|
-
hideGrid: () => void;
|
|
40
|
-
isGridVisible: () => boolean;
|
|
41
|
-
showGridState: boolean;
|
|
42
|
-
};
|
|
43
|
-
export {};
|