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