@markup-canvas/react 1.1.6 → 1.2.0
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 +22 -8
- package/dist/index.cjs.js +91 -234
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +92 -234
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/MarkupCanvas.tsx +2 -2
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useMarkupCanvas.ts +192 -72
- 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,127 +43,227 @@ 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
|
+
}, []);
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
const handleGridVisibilityChange = useCallback((isVisible: boolean) => {
|
|
56
|
+
setShowGridState(isVisible);
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
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
|
|
|
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
|
+
handleZoom(event.data.data);
|
|
131
|
+
break;
|
|
132
|
+
case "pan":
|
|
133
|
+
handlePan(event.data.data);
|
|
134
|
+
break;
|
|
135
|
+
case "ready":
|
|
136
|
+
handleReady(event.data.data);
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
window.addEventListener("message", handleMessage);
|
|
145
|
+
|
|
146
|
+
return () => {
|
|
147
|
+
window.removeEventListener("message", handleMessage);
|
|
148
|
+
};
|
|
149
|
+
}, [canvasName, handleTransform, handleZoom, handlePan, handleReady]);
|
|
150
|
+
|
|
151
|
+
// Action methods
|
|
72
152
|
const zoomIn = useCallback(
|
|
73
153
|
(factor = 0.5) => {
|
|
74
|
-
|
|
154
|
+
canvas?.zoom?.in?.(factor);
|
|
75
155
|
},
|
|
76
|
-
[
|
|
156
|
+
[canvas]
|
|
77
157
|
);
|
|
78
158
|
|
|
79
159
|
const zoomOut = useCallback(
|
|
80
160
|
(factor = 0.5) => {
|
|
81
|
-
|
|
161
|
+
canvas?.zoom?.out?.(factor);
|
|
82
162
|
},
|
|
83
|
-
[
|
|
163
|
+
[canvas]
|
|
84
164
|
);
|
|
85
165
|
|
|
86
166
|
const resetZoom = useCallback(() => {
|
|
87
|
-
|
|
88
|
-
}, [
|
|
167
|
+
canvas?.zoom?.reset?.();
|
|
168
|
+
}, [canvas]);
|
|
169
|
+
|
|
170
|
+
const panLeft = useCallback(
|
|
171
|
+
(distance?: number) => {
|
|
172
|
+
canvas?.pan?.left?.(distance);
|
|
173
|
+
},
|
|
174
|
+
[canvas]
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const panRight = useCallback(
|
|
178
|
+
(distance?: number) => {
|
|
179
|
+
canvas?.pan?.right?.(distance);
|
|
180
|
+
},
|
|
181
|
+
[canvas]
|
|
182
|
+
);
|
|
89
183
|
|
|
90
|
-
const
|
|
91
|
-
(
|
|
92
|
-
|
|
184
|
+
const panUp = useCallback(
|
|
185
|
+
(distance?: number) => {
|
|
186
|
+
canvas?.pan?.up?.(distance);
|
|
93
187
|
},
|
|
94
|
-
[
|
|
188
|
+
[canvas]
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const panDown = useCallback(
|
|
192
|
+
(distance?: number) => {
|
|
193
|
+
canvas?.pan?.down?.(distance);
|
|
194
|
+
},
|
|
195
|
+
[canvas]
|
|
95
196
|
);
|
|
96
197
|
|
|
97
198
|
const fitToContent = useCallback(() => {
|
|
98
|
-
|
|
99
|
-
}, [
|
|
199
|
+
canvas?.zoom?.fitToScreen?.();
|
|
200
|
+
}, [canvas]);
|
|
100
201
|
|
|
101
202
|
const centerContent = useCallback(() => {
|
|
102
|
-
|
|
103
|
-
}, [
|
|
203
|
+
canvas?.pan?.toCenter?.();
|
|
204
|
+
}, [canvas]);
|
|
205
|
+
|
|
206
|
+
const resetView = useCallback(() => {
|
|
207
|
+
canvas?.zoom?.resetToCenter?.();
|
|
208
|
+
}, [canvas]);
|
|
104
209
|
|
|
105
210
|
const setTransitionMode = useCallback(
|
|
106
211
|
(enabled: boolean) => {
|
|
107
|
-
|
|
108
|
-
canvasRef.current.canvas.updateConfig({ enableTransition: enabled });
|
|
109
|
-
}
|
|
212
|
+
canvas?.transition?.set?.(enabled);
|
|
110
213
|
},
|
|
111
|
-
[
|
|
214
|
+
[canvas]
|
|
112
215
|
);
|
|
113
216
|
|
|
114
217
|
const toggleTransitionMode = useCallback(() => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const newEnableTransition = !currentConfig.enableTransition;
|
|
118
|
-
canvasRef.current.canvas.updateConfig({ enableTransition: newEnableTransition });
|
|
119
|
-
return newEnableTransition;
|
|
120
|
-
}
|
|
121
|
-
return false;
|
|
122
|
-
}, [canvasRef]);
|
|
218
|
+
return canvas?.transition?.toggle?.() ?? false;
|
|
219
|
+
}, [canvas]);
|
|
123
220
|
|
|
124
221
|
const updateThemeMode = useCallback(
|
|
125
222
|
(mode: "light" | "dark") => {
|
|
126
223
|
setThemeModeState(mode);
|
|
127
|
-
|
|
224
|
+
canvas?.theme?.update?.(mode);
|
|
128
225
|
},
|
|
129
|
-
[
|
|
226
|
+
[canvas]
|
|
130
227
|
);
|
|
131
228
|
|
|
132
229
|
const toggleThemeMode = useCallback(() => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
230
|
+
canvas?.theme?.toggle?.();
|
|
231
|
+
}, [canvas]);
|
|
232
|
+
|
|
233
|
+
const showRulers = useCallback(() => {
|
|
234
|
+
canvas?.rulers?.show?.();
|
|
235
|
+
}, [canvas]);
|
|
236
|
+
|
|
237
|
+
const hideRulers = useCallback(() => {
|
|
238
|
+
canvas?.rulers?.hide?.();
|
|
239
|
+
}, [canvas]);
|
|
137
240
|
|
|
138
241
|
const toggleRulers = useCallback(() => {
|
|
139
|
-
|
|
140
|
-
}, [
|
|
242
|
+
canvas?.rulers?.toggle?.();
|
|
243
|
+
}, [canvas]);
|
|
141
244
|
|
|
142
245
|
const areRulersVisible = useCallback(() => {
|
|
143
|
-
return
|
|
144
|
-
}, [
|
|
246
|
+
return canvas?.rulers?.isVisible?.() ?? false;
|
|
247
|
+
}, [canvas]);
|
|
248
|
+
|
|
249
|
+
const showGrid = useCallback(() => {
|
|
250
|
+
canvas?.grid?.show?.();
|
|
251
|
+
}, [canvas]);
|
|
252
|
+
|
|
253
|
+
const hideGrid = useCallback(() => {
|
|
254
|
+
canvas?.grid?.hide?.();
|
|
255
|
+
}, [canvas]);
|
|
145
256
|
|
|
146
257
|
const toggleGrid = useCallback(() => {
|
|
147
|
-
|
|
148
|
-
}, [
|
|
258
|
+
canvas?.grid?.toggle?.();
|
|
259
|
+
}, [canvas]);
|
|
149
260
|
|
|
150
261
|
const isGridVisible = useCallback(() => {
|
|
151
|
-
return
|
|
152
|
-
}, [
|
|
262
|
+
return canvas?.grid?.isVisible?.() ?? false;
|
|
263
|
+
}, [canvas]);
|
|
153
264
|
|
|
154
265
|
return {
|
|
155
|
-
canvas:
|
|
156
|
-
initCanvasUtils: handleCanvasInstance,
|
|
266
|
+
canvas: canvas,
|
|
157
267
|
transform,
|
|
158
268
|
zoom,
|
|
159
269
|
pan,
|
|
@@ -161,17 +271,27 @@ export function useMarkupCanvas(canvasRef: RefObject<MarkupCanvasRef | null>, op
|
|
|
161
271
|
zoomIn,
|
|
162
272
|
zoomOut,
|
|
163
273
|
resetZoom,
|
|
164
|
-
|
|
274
|
+
panLeft,
|
|
275
|
+
panRight,
|
|
276
|
+
panUp,
|
|
277
|
+
panDown,
|
|
165
278
|
fitToContent,
|
|
166
279
|
centerContent,
|
|
280
|
+
resetView,
|
|
167
281
|
setTransitionMode,
|
|
168
282
|
toggleTransitionMode,
|
|
169
283
|
themeMode,
|
|
170
284
|
updateThemeMode,
|
|
171
285
|
toggleThemeMode,
|
|
172
286
|
toggleRulers,
|
|
287
|
+
showRulers,
|
|
288
|
+
hideRulers,
|
|
173
289
|
areRulersVisible,
|
|
290
|
+
showRulersState,
|
|
174
291
|
toggleGrid,
|
|
292
|
+
showGrid,
|
|
293
|
+
hideGrid,
|
|
175
294
|
isGridVisible,
|
|
295
|
+
showGridState,
|
|
176
296
|
};
|
|
177
297
|
}
|
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 {};
|