@maayan-albert/moab-sdk 1.0.4 → 1.0.6
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/components/DrawingTool.d.ts.map +1 -1
- package/dist/components.js +341 -291
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +326 -276
- package/dist/components.mjs.map +1 -1
- package/dist/index.js +341 -290
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +326 -275
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
3
|
-
import { Trash2, X } from 'lucide-react';
|
|
4
|
-
import
|
|
2
|
+
import React, { useRef, useState, useLayoutEffect, useEffect, useCallback } from 'react';
|
|
3
|
+
import { Palette, Brush, Trash2, X } from 'lucide-react';
|
|
4
|
+
import { toPng } from 'html-to-image';
|
|
5
5
|
|
|
6
6
|
var __defProp = Object.defineProperty;
|
|
7
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -88,24 +88,76 @@ var Input = ({
|
|
|
88
88
|
] });
|
|
89
89
|
};
|
|
90
90
|
var Input_default = Input;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
height,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
|
|
92
|
+
// src/components/DrawingTool.module.scss
|
|
93
|
+
var css = '@keyframes moab__toolbarEnter___kVde9 {\n from {\n opacity: 0;\n transform: scale(0.5) rotate(90deg);\n }\n to {\n opacity: 1;\n transform: scale(1) rotate(0deg);\n }\n}\n@keyframes moab__scaleIn___bOiIm {\n from {\n opacity: 0;\n transform: scale(0.85);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n@keyframes moab__scaleOut___wrtHU {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.85);\n }\n}\n.moab__toolbar___GXd-P {\n position: fixed;\n bottom: 1.25rem;\n right: 1.25rem;\n z-index: 100000;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\n pointer-events: none;\n transition: left 0s, top 0s, right 0s, bottom 0s;\n}\n\n.moab__toolbarContainer___sQuuF {\n user-select: none;\n margin-left: auto;\n align-self: flex-end;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #1a1a1a;\n color: #fff;\n border: none;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1);\n pointer-events: auto;\n cursor: grab;\n transition: width 0.4s cubic-bezier(0.19, 1, 0.22, 1), transform 0.4s cubic-bezier(0.19, 1, 0.22, 1);\n}\n.moab__toolbarContainer___sQuuF.moab__dragging___c6CuY {\n transition: width 0.4s cubic-bezier(0.19, 1, 0.22, 1);\n cursor: grabbing;\n}\n.moab__toolbarContainer___sQuuF.moab__entrance___kTkKT {\n animation: moab__toolbarEnter___kVde9 0.5s cubic-bezier(0.34, 1.2, 0.64, 1) forwards;\n}\n.moab__toolbarContainer___sQuuF.moab__collapsed___xYm1N {\n width: 44px;\n height: 44px;\n border-radius: 22px;\n padding: 0;\n cursor: pointer;\n}\n.moab__toolbarContainer___sQuuF.moab__collapsed___xYm1N svg {\n margin-top: -1px;\n}\n.moab__toolbarContainer___sQuuF.moab__collapsed___xYm1N:hover {\n background: #2a2a2a;\n}\n.moab__toolbarContainer___sQuuF.moab__collapsed___xYm1N:active {\n transform: scale(0.95);\n}\n.moab__toolbarContainer___sQuuF.moab__expanded___Gshmq {\n width: calc-size(auto, size);\n height: 44px;\n border-radius: 1.5rem;\n padding: 0.375rem;\n}\n@supports not (width: calc-size(auto, size)) {\n .moab__toolbarContainer___sQuuF.moab__expanded___Gshmq {\n width: auto;\n }\n}\n\n.moab__toggleContent___KfJ0y {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: opacity 0.1s cubic-bezier(0.19, 1, 0.22, 1);\n}\n.moab__toggleContent___KfJ0y.moab__visible___1M9br {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n}\n.moab__toggleContent___KfJ0y.moab__hidden___Zdoqy {\n opacity: 0;\n pointer-events: none;\n}\n\n.moab__controlsContent___KGEHS {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n transition: filter 0.8s cubic-bezier(0.19, 1, 0.22, 1), opacity 0.8s cubic-bezier(0.19, 1, 0.22, 1), transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);\n}\n.moab__controlsContent___KGEHS.moab__visible___1M9br {\n opacity: 1;\n filter: blur(0px);\n transform: scale(1);\n visibility: visible;\n pointer-events: auto;\n}\n.moab__controlsContent___KGEHS.moab__hidden___Zdoqy {\n opacity: 0;\n filter: blur(10px);\n transform: scale(0.4);\n pointer-events: none;\n}\n\n.moab__buttonWrapper___ZDZWf {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.moab__controlButton___AYQcE {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n margin: 0;\n border: none;\n background: transparent;\n color: rgba(255, 255, 255, 0.5);\n border-radius: 999px;\n cursor: pointer;\n transition: background 0.2s cubic-bezier(0.25, 1, 0.5, 1), color 0.2s cubic-bezier(0.25, 1, 0.5, 1), transform 0.15s cubic-bezier(0.25, 1, 0.5, 1);\n}\n.moab__controlButton___AYQcE:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n}\n.moab__controlButton___AYQcE[data-active=true]:hover:not(:disabled) {\n background: rgba(60, 130, 247, 0.35);\n color: #3c82f7;\n}\n.moab__controlButton___AYQcE:active:not(:disabled) {\n transform: scale(0.95);\n}\n.moab__controlButton___AYQcE:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n}\n.moab__controlButton___AYQcE[data-active=true] {\n color: #3c82f7;\n background: rgba(60, 130, 247, 0.25);\n}\n.moab__controlButton___AYQcE[data-danger]:hover:not(:disabled) {\n background: rgba(255, 59, 48, 0.15);\n color: #ff3b30;\n}\n\n.moab__buttonTooltip___ZUL58 {\n position: absolute;\n bottom: calc(100% + 0.5rem);\n left: 50%;\n transform: translateX(-50%);\n padding: 0.375rem 0.625rem;\n background: #383838;\n color: rgba(255, 255, 255, 0.7);\n font-size: 0.6875rem;\n font-weight: 400;\n line-height: 1.2;\n border-radius: 0.5rem;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition: opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease;\n z-index: 100001;\n box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.28);\n}\n.moab__buttonTooltip___ZUL58::after {\n content: "";\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n width: 0;\n height: 0;\n border-left: 4px solid transparent;\n border-right: 4px solid transparent;\n border-top: 4px solid #383838;\n}\n\n.moab__buttonWrapper___ZDZWf:hover .moab__buttonTooltip___ZUL58 {\n opacity: 1;\n visibility: visible;\n}\n\n.moab__divider___o4mDB {\n width: 1px;\n height: 24px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 0.125rem;\n}\n\n.moab__light___s-xQ4.moab__toolbarContainer___sQuuF {\n background: #fff;\n color: rgba(0, 0, 0, 0.85);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 4px 16px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.04);\n}\n.moab__light___s-xQ4.moab__toolbarContainer___sQuuF.moab__collapsed___xYm1N:hover {\n background: #f5f5f5;\n}\n.moab__light___s-xQ4.moab__controlButton___AYQcE {\n color: rgba(0, 0, 0, 0.5);\n}\n.moab__light___s-xQ4.moab__controlButton___AYQcE:hover:not(:disabled) {\n background: rgba(0, 0, 0, 0.06);\n color: rgba(0, 0, 0, 0.85);\n}\n.moab__light___s-xQ4.moab__controlButton___AYQcE[data-active=true]:hover:not(:disabled) {\n background: rgba(60, 130, 247, 0.25);\n color: #3c82f7;\n}\n.moab__light___s-xQ4.moab__controlButton___AYQcE[data-active=true] {\n color: #3c82f7;\n background: rgba(60, 130, 247, 0.15);\n}\n.moab__light___s-xQ4.moab__controlButton___AYQcE[data-danger]:hover:not(:disabled) {\n background: rgba(255, 59, 48, 0.15);\n color: #ff3b30;\n}\n.moab__light___s-xQ4.moab__buttonTooltip___ZUL58 {\n background: #fff;\n color: rgba(0, 0, 0, 0.85);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 4px 16px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.04);\n}\n.moab__light___s-xQ4.moab__buttonTooltip___ZUL58::after {\n background: #fff;\n}\n.moab__light___s-xQ4.moab__divider___o4mDB {\n background: rgba(0, 0, 0, 0.1);\n}\n\n.moab-drawing-canvas {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 50 !important;\n touch-action: none !important;\n}';
|
|
94
|
+
var classNames = { "toolbar": "moab__toolbar___GXd-P", "toolbarContainer": "moab__toolbarContainer___sQuuF", "dragging": "moab__dragging___c6CuY", "entrance": "moab__entrance___kTkKT", "collapsed": "moab__collapsed___xYm1N", "expanded": "moab__expanded___Gshmq", "toggleContent": "moab__toggleContent___KfJ0y", "visible": "moab__visible___1M9br", "hidden": "moab__hidden___Zdoqy", "controlsContent": "moab__controlsContent___KGEHS", "buttonWrapper": "moab__buttonWrapper___ZDZWf", "controlButton": "moab__controlButton___AYQcE", "buttonTooltip": "moab__buttonTooltip___ZUL58", "divider": "moab__divider___o4mDB", "light": "moab__light___s-xQ4"};
|
|
95
|
+
if (typeof document !== "undefined") {
|
|
96
|
+
let style = document.getElementById("moab-components-DrawingTool");
|
|
97
|
+
if (!style) {
|
|
98
|
+
style = document.createElement("style");
|
|
99
|
+
style.id = "moab-components-DrawingTool";
|
|
100
|
+
document.head.appendChild(style);
|
|
101
|
+
}
|
|
102
|
+
style.textContent = css;
|
|
103
|
+
}
|
|
104
|
+
var DrawingTool_module_default = classNames;
|
|
105
|
+
var TOOLBAR_POSITION_STORAGE_KEY = "moab-drawing-toolbar-position";
|
|
106
|
+
var DrawingTool = () => {
|
|
97
107
|
const canvasRef = useRef(null);
|
|
98
108
|
const toolbarRef = useRef(null);
|
|
109
|
+
const toolbarWrapperRef = useRef(null);
|
|
99
110
|
const [isDrawing, setIsDrawing] = useState(false);
|
|
100
|
-
const brushColor = "#
|
|
111
|
+
const brushColor = "#3B82F6";
|
|
101
112
|
const brushSize = 5;
|
|
102
113
|
const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
|
|
103
|
-
const [
|
|
114
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
115
|
+
const [isPainting, setIsPainting] = useState(false);
|
|
104
116
|
const [hasContent, setHasContent] = useState(false);
|
|
105
|
-
const [
|
|
106
|
-
const [
|
|
107
|
-
const [
|
|
108
|
-
const [
|
|
117
|
+
const [isDraggingToolbar, setIsDraggingToolbar] = useState(false);
|
|
118
|
+
const [toolbarPosition, setToolbarPosition] = useState(null);
|
|
119
|
+
const [isToolbarReady, setIsToolbarReady] = useState(false);
|
|
120
|
+
const [dragStartPos, setDragStartPos] = useState(null);
|
|
121
|
+
const [dragRotation, setDragRotation] = useState(0);
|
|
122
|
+
const justFinishedToolbarDragRef = useRef(false);
|
|
123
|
+
useLayoutEffect(() => {
|
|
124
|
+
const toolbarWrapper = toolbarWrapperRef.current;
|
|
125
|
+
if (!toolbarWrapper) return;
|
|
126
|
+
const restorePosition = () => {
|
|
127
|
+
try {
|
|
128
|
+
const stored = localStorage.getItem(TOOLBAR_POSITION_STORAGE_KEY);
|
|
129
|
+
if (stored) {
|
|
130
|
+
const parsed = JSON.parse(stored);
|
|
131
|
+
if (typeof parsed?.x === "number" && typeof parsed?.y === "number") {
|
|
132
|
+
setToolbarPosition({ x: parsed.x, y: parsed.y });
|
|
133
|
+
setIsToolbarReady(true);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
const rect = toolbarWrapper.getBoundingClientRect();
|
|
140
|
+
const padding = 20;
|
|
141
|
+
const startX = padding;
|
|
142
|
+
const startY = Math.max(
|
|
143
|
+
padding,
|
|
144
|
+
window.innerHeight - rect.height - padding
|
|
145
|
+
);
|
|
146
|
+
setToolbarPosition({ x: startX, y: startY });
|
|
147
|
+
setIsToolbarReady(true);
|
|
148
|
+
};
|
|
149
|
+
restorePosition();
|
|
150
|
+
}, []);
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
if (!toolbarPosition) return;
|
|
153
|
+
try {
|
|
154
|
+
localStorage.setItem(
|
|
155
|
+
TOOLBAR_POSITION_STORAGE_KEY,
|
|
156
|
+
JSON.stringify(toolbarPosition)
|
|
157
|
+
);
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}, [toolbarPosition]);
|
|
109
161
|
useEffect(() => {
|
|
110
162
|
const updateSize = () => {
|
|
111
163
|
setCanvasSize({
|
|
@@ -153,7 +205,7 @@ var DrawingTool = ({
|
|
|
153
205
|
);
|
|
154
206
|
const startDrawing = useCallback(
|
|
155
207
|
(e) => {
|
|
156
|
-
if (!
|
|
208
|
+
if (!isPainting) return;
|
|
157
209
|
e.preventDefault();
|
|
158
210
|
const canvas = canvasRef.current;
|
|
159
211
|
const ctx = canvas?.getContext("2d");
|
|
@@ -163,7 +215,7 @@ var DrawingTool = ({
|
|
|
163
215
|
ctx.moveTo(x, y);
|
|
164
216
|
setIsDrawing(true);
|
|
165
217
|
},
|
|
166
|
-
[
|
|
218
|
+
[isPainting, getCoordinates]
|
|
167
219
|
);
|
|
168
220
|
const draw = useCallback(
|
|
169
221
|
(e) => {
|
|
@@ -190,40 +242,52 @@ var DrawingTool = ({
|
|
|
190
242
|
setHasContent(false);
|
|
191
243
|
}, []);
|
|
192
244
|
const takeScreenshot = useCallback(async () => {
|
|
245
|
+
const toolbar = toolbarRef.current;
|
|
193
246
|
try {
|
|
194
|
-
const toolbar = toolbarRef.current;
|
|
195
247
|
if (toolbar) {
|
|
196
|
-
toolbar.style.
|
|
248
|
+
toolbar.style.visibility = "hidden";
|
|
197
249
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
251
|
+
const dataUrl = await toPng(document.body, {
|
|
252
|
+
width: window.innerWidth,
|
|
253
|
+
height: window.innerHeight,
|
|
254
|
+
style: {
|
|
255
|
+
transform: `translate(-${window.scrollX}px, -${window.scrollY}px)`
|
|
256
|
+
},
|
|
257
|
+
filter: (node) => {
|
|
258
|
+
if (node instanceof HTMLElement) {
|
|
259
|
+
if (node.closest?.("[data-drawing-toolbar]")) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
203
265
|
});
|
|
204
266
|
if (toolbar) {
|
|
205
|
-
toolbar.style.
|
|
267
|
+
toolbar.style.visibility = "";
|
|
268
|
+
}
|
|
269
|
+
const response = await fetch(dataUrl);
|
|
270
|
+
const blob = await response.blob();
|
|
271
|
+
try {
|
|
272
|
+
await navigator.clipboard.write([
|
|
273
|
+
new ClipboardItem({
|
|
274
|
+
"image/png": blob
|
|
275
|
+
})
|
|
276
|
+
]);
|
|
277
|
+
} catch (err) {
|
|
278
|
+
console.error("Failed to copy to clipboard:", err);
|
|
279
|
+
const url = URL.createObjectURL(blob);
|
|
280
|
+
const a = document.createElement("a");
|
|
281
|
+
a.href = url;
|
|
282
|
+
a.download = "screenshot.png";
|
|
283
|
+
a.click();
|
|
284
|
+
URL.revokeObjectURL(url);
|
|
206
285
|
}
|
|
207
|
-
canvas.toBlob(async (blob) => {
|
|
208
|
-
if (!blob) return;
|
|
209
|
-
try {
|
|
210
|
-
await navigator.clipboard.write([
|
|
211
|
-
new ClipboardItem({
|
|
212
|
-
"image/png": blob
|
|
213
|
-
})
|
|
214
|
-
]);
|
|
215
|
-
} catch (err) {
|
|
216
|
-
console.error("Failed to copy to clipboard:", err);
|
|
217
|
-
const url = URL.createObjectURL(blob);
|
|
218
|
-
const a = document.createElement("a");
|
|
219
|
-
a.href = url;
|
|
220
|
-
a.download = "screenshot.png";
|
|
221
|
-
a.click();
|
|
222
|
-
URL.revokeObjectURL(url);
|
|
223
|
-
}
|
|
224
|
-
}, "image/png");
|
|
225
286
|
} catch (error) {
|
|
226
287
|
console.error("Failed to take screenshot:", error);
|
|
288
|
+
if (toolbar) {
|
|
289
|
+
toolbar.style.visibility = "";
|
|
290
|
+
}
|
|
227
291
|
}
|
|
228
292
|
}, []);
|
|
229
293
|
useEffect(() => {
|
|
@@ -233,86 +297,109 @@ var DrawingTool = ({
|
|
|
233
297
|
ctx.strokeStyle = brushColor;
|
|
234
298
|
ctx.lineWidth = brushSize;
|
|
235
299
|
}, [brushColor, brushSize]);
|
|
236
|
-
const
|
|
237
|
-
(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const threshold = 50;
|
|
241
|
-
if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold) {
|
|
242
|
-
return null;
|
|
300
|
+
const handleToolbarMouseDown = useCallback(
|
|
301
|
+
(e) => {
|
|
302
|
+
if (e.target.closest("button")) {
|
|
303
|
+
return;
|
|
243
304
|
}
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
305
|
+
const toolbarWrapper = toolbarWrapperRef.current;
|
|
306
|
+
if (!toolbarWrapper) return;
|
|
307
|
+
e.preventDefault();
|
|
308
|
+
e.stopPropagation();
|
|
309
|
+
const rect = toolbarWrapper.getBoundingClientRect();
|
|
310
|
+
const randomRotation = (Math.random() - 0.5) * 10;
|
|
311
|
+
setDragRotation(randomRotation);
|
|
312
|
+
setDragStartPos({
|
|
313
|
+
x: e.clientX,
|
|
314
|
+
y: e.clientY,
|
|
315
|
+
toolbarX: toolbarPosition?.x ?? rect.left,
|
|
316
|
+
toolbarY: toolbarPosition?.y ?? rect.top,
|
|
317
|
+
toolbarWidth: rect.width,
|
|
318
|
+
toolbarHeight: rect.height
|
|
319
|
+
});
|
|
254
320
|
},
|
|
255
|
-
[]
|
|
321
|
+
[toolbarPosition]
|
|
256
322
|
);
|
|
257
|
-
const handleMouseDown = useCallback((e) => {
|
|
258
|
-
if (e.target.closest("button")) {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
e.preventDefault();
|
|
262
|
-
e.stopPropagation();
|
|
263
|
-
setIsDragging(true);
|
|
264
|
-
setDragStart({
|
|
265
|
-
x: e.clientX,
|
|
266
|
-
y: e.clientY
|
|
267
|
-
});
|
|
268
|
-
}, []);
|
|
269
323
|
useEffect(() => {
|
|
324
|
+
if (!dragStartPos) return;
|
|
325
|
+
const DRAG_THRESHOLD = 5;
|
|
270
326
|
const handleMouseMove = (e) => {
|
|
271
|
-
|
|
272
|
-
e.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
else if (vertical === "bottom" && horizontal === "left")
|
|
291
|
-
setCorner("bottom-left");
|
|
292
|
-
else setCorner("bottom-right");
|
|
327
|
+
const deltaX = e.clientX - dragStartPos.x;
|
|
328
|
+
const deltaY = e.clientY - dragStartPos.y;
|
|
329
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
330
|
+
if (!isDraggingToolbar && distance > DRAG_THRESHOLD) {
|
|
331
|
+
setIsDraggingToolbar(true);
|
|
332
|
+
}
|
|
333
|
+
if (isDraggingToolbar || distance > DRAG_THRESHOLD) {
|
|
334
|
+
const padding = 20;
|
|
335
|
+
const maxX = window.innerWidth - dragStartPos.toolbarWidth - padding;
|
|
336
|
+
const maxY = window.innerHeight - dragStartPos.toolbarHeight - padding;
|
|
337
|
+
const newX = Math.max(
|
|
338
|
+
padding,
|
|
339
|
+
Math.min(maxX, dragStartPos.toolbarX + deltaX)
|
|
340
|
+
);
|
|
341
|
+
const newY = Math.max(
|
|
342
|
+
padding,
|
|
343
|
+
Math.min(maxY, dragStartPos.toolbarY + deltaY)
|
|
344
|
+
);
|
|
345
|
+
setToolbarPosition({ x: newX, y: newY });
|
|
293
346
|
}
|
|
294
347
|
};
|
|
295
|
-
const handleMouseUp = (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
348
|
+
const handleMouseUp = () => {
|
|
349
|
+
if (isDraggingToolbar) {
|
|
350
|
+
justFinishedToolbarDragRef.current = true;
|
|
351
|
+
setTimeout(() => {
|
|
352
|
+
justFinishedToolbarDragRef.current = false;
|
|
353
|
+
}, 50);
|
|
354
|
+
}
|
|
355
|
+
setIsDraggingToolbar(false);
|
|
356
|
+
setDragStartPos(null);
|
|
299
357
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
passive: false
|
|
303
|
-
});
|
|
304
|
-
document.addEventListener("mouseup", handleMouseUp, { passive: false });
|
|
305
|
-
}
|
|
358
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
359
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
306
360
|
return () => {
|
|
307
361
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
308
362
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
309
363
|
};
|
|
310
|
-
}, [
|
|
311
|
-
|
|
364
|
+
}, [dragStartPos, isDraggingToolbar]);
|
|
365
|
+
useEffect(() => {
|
|
366
|
+
if (!toolbarPosition) return;
|
|
367
|
+
const constrainPosition = () => {
|
|
368
|
+
const toolbarWrapper = toolbarWrapperRef.current;
|
|
369
|
+
const rect = toolbarWrapper?.getBoundingClientRect();
|
|
370
|
+
const width = rect?.width ?? 44;
|
|
371
|
+
const height = rect?.height ?? 44;
|
|
372
|
+
const padding = 20;
|
|
373
|
+
const maxX = window.innerWidth - width - padding;
|
|
374
|
+
const maxY = window.innerHeight - height - padding;
|
|
375
|
+
const newX = Math.max(padding, Math.min(maxX, toolbarPosition.x));
|
|
376
|
+
const newY = Math.max(padding, Math.min(maxY, toolbarPosition.y));
|
|
377
|
+
if (newX !== toolbarPosition.x || newY !== toolbarPosition.y) {
|
|
378
|
+
setToolbarPosition({ x: newX, y: newY });
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
constrainPosition();
|
|
382
|
+
window.addEventListener("resize", constrainPosition);
|
|
383
|
+
return () => window.removeEventListener("resize", constrainPosition);
|
|
384
|
+
}, [toolbarPosition, isOpen]);
|
|
385
|
+
const [showEntranceAnimation, setShowEntranceAnimation] = useState(false);
|
|
386
|
+
const [isDarkMode] = useState(true);
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
setShowEntranceAnimation(true);
|
|
389
|
+
const timer = setTimeout(() => setShowEntranceAnimation(false), 500);
|
|
390
|
+
return () => clearTimeout(timer);
|
|
391
|
+
}, []);
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
if (!isPainting) {
|
|
394
|
+
setIsDrawing(false);
|
|
395
|
+
}
|
|
396
|
+
}, [isPainting]);
|
|
397
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
312
398
|
/* @__PURE__ */ jsx(
|
|
313
399
|
"canvas",
|
|
314
400
|
{
|
|
315
401
|
ref: canvasRef,
|
|
402
|
+
className: "moab-drawing-canvas",
|
|
316
403
|
onMouseDown: startDrawing,
|
|
317
404
|
onMouseMove: draw,
|
|
318
405
|
onMouseUp: stopDrawing,
|
|
@@ -320,186 +407,150 @@ var DrawingTool = ({
|
|
|
320
407
|
onTouchStart: startDrawing,
|
|
321
408
|
onTouchMove: draw,
|
|
322
409
|
onTouchEnd: stopDrawing,
|
|
323
|
-
className: `fixed top-0 left-0 touch-none z-50 transition-opacity ${enabled && !isDragging ? "cursor-crosshair pointer-events-auto opacity-100" : "pointer-events-none opacity-0"}`,
|
|
324
410
|
style: {
|
|
325
411
|
width: `${canvasSize.width}px`,
|
|
326
|
-
height: `${canvasSize.height}px
|
|
412
|
+
height: `${canvasSize.height}px`,
|
|
413
|
+
cursor: isPainting && !isDraggingToolbar ? "crosshair" : "default",
|
|
414
|
+
pointerEvents: isPainting && !isDraggingToolbar ? "auto" : "none",
|
|
415
|
+
opacity: isPainting && !isDraggingToolbar ? 1 : 0,
|
|
416
|
+
transition: "opacity 300ms ease-in-out"
|
|
327
417
|
}
|
|
328
418
|
}
|
|
329
419
|
),
|
|
330
|
-
/* @__PURE__ */
|
|
420
|
+
/* @__PURE__ */ jsx(
|
|
331
421
|
"div",
|
|
332
422
|
{
|
|
333
|
-
ref:
|
|
334
|
-
className:
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
children:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
423
|
+
ref: toolbarWrapperRef,
|
|
424
|
+
className: DrawingTool_module_default.toolbar,
|
|
425
|
+
"data-drawing-toolbar": true,
|
|
426
|
+
style: toolbarPosition ? {
|
|
427
|
+
left: toolbarPosition.x,
|
|
428
|
+
top: toolbarPosition.y,
|
|
429
|
+
right: "auto",
|
|
430
|
+
bottom: "auto",
|
|
431
|
+
visibility: isToolbarReady ? "visible" : "hidden"
|
|
432
|
+
} : { visibility: "hidden" },
|
|
433
|
+
children: /* @__PURE__ */ jsxs(
|
|
434
|
+
"div",
|
|
435
|
+
{
|
|
436
|
+
ref: toolbarRef,
|
|
437
|
+
className: `${DrawingTool_module_default.toolbarContainer} ${isOpen ? DrawingTool_module_default.expanded : DrawingTool_module_default.collapsed} ${showEntranceAnimation ? DrawingTool_module_default.entrance : ""} ${isDraggingToolbar ? DrawingTool_module_default.dragging : ""} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
|
|
438
|
+
onClick: !isOpen ? (e) => {
|
|
439
|
+
if (justFinishedToolbarDragRef.current) {
|
|
440
|
+
e.preventDefault();
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
setIsOpen(true);
|
|
444
|
+
} : void 0,
|
|
445
|
+
onMouseDown: handleToolbarMouseDown,
|
|
446
|
+
role: !isOpen ? "button" : void 0,
|
|
447
|
+
tabIndex: !isOpen ? 0 : -1,
|
|
448
|
+
style: isDraggingToolbar ? {
|
|
449
|
+
cursor: "grabbing",
|
|
450
|
+
transform: `scale(1.05) rotate(${dragRotation}deg)`
|
|
451
|
+
} : void 0,
|
|
452
|
+
children: [
|
|
453
|
+
/* @__PURE__ */ jsx(
|
|
454
|
+
"div",
|
|
355
455
|
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
takeScreenshot();
|
|
359
|
-
},
|
|
360
|
-
className: "p-2 text-white hover:bg-neutral-600/30 rounded-full transition-colors focus:outline-none whitespace-nowrap",
|
|
361
|
-
"aria-label": "Take screenshot",
|
|
362
|
-
children: /* @__PURE__ */ jsxs(
|
|
363
|
-
"svg",
|
|
364
|
-
{
|
|
365
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
366
|
-
width: "18",
|
|
367
|
-
height: "18",
|
|
368
|
-
viewBox: "0 0 24 24",
|
|
369
|
-
fill: "none",
|
|
370
|
-
stroke: "currentColor",
|
|
371
|
-
strokeWidth: "2",
|
|
372
|
-
strokeLinecap: "round",
|
|
373
|
-
strokeLinejoin: "round",
|
|
374
|
-
className: "lucide lucide-camera",
|
|
375
|
-
children: [
|
|
376
|
-
/* @__PURE__ */ jsx("path", { d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z" }),
|
|
377
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
378
|
-
]
|
|
379
|
-
}
|
|
380
|
-
)
|
|
456
|
+
className: `${DrawingTool_module_default.toggleContent} ${!isOpen ? DrawingTool_module_default.visible : DrawingTool_module_default.hidden}`,
|
|
457
|
+
children: /* @__PURE__ */ jsx(Palette, { size: 20, strokeWidth: 2 })
|
|
381
458
|
}
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
style: {
|
|
390
|
-
maxWidth: enabled ? "100px" : "0px",
|
|
391
|
-
opacity: enabled ? 1 : 0,
|
|
392
|
-
transition: "max-width 300ms ease-in-out, opacity 300ms ease-in-out"
|
|
393
|
-
},
|
|
394
|
-
children: [
|
|
395
|
-
/* @__PURE__ */ jsxs(
|
|
396
|
-
"button",
|
|
397
|
-
{
|
|
398
|
-
onClick: (e) => {
|
|
399
|
-
e.stopPropagation();
|
|
400
|
-
clearCanvas();
|
|
401
|
-
setShowClearTooltip(false);
|
|
402
|
-
},
|
|
403
|
-
onMouseEnter: () => {
|
|
404
|
-
if (hasContent) {
|
|
405
|
-
setShowClearTooltip(true);
|
|
406
|
-
}
|
|
407
|
-
},
|
|
408
|
-
onMouseLeave: () => setShowClearTooltip(false),
|
|
409
|
-
disabled: !hasContent,
|
|
410
|
-
className: "p-2 text-white rounded-full focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed relative group",
|
|
411
|
-
"aria-label": "Clear canvas",
|
|
412
|
-
children: [
|
|
413
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-red-600/30 opacity-0 group-hover:opacity-100 transition-opacity disabled:group-hover:opacity-0" }),
|
|
459
|
+
),
|
|
460
|
+
/* @__PURE__ */ jsxs(
|
|
461
|
+
"div",
|
|
462
|
+
{
|
|
463
|
+
className: `${DrawingTool_module_default.controlsContent} ${isOpen ? DrawingTool_module_default.visible : DrawingTool_module_default.hidden}`,
|
|
464
|
+
children: [
|
|
465
|
+
/* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
|
|
414
466
|
/* @__PURE__ */ jsx(
|
|
415
|
-
|
|
467
|
+
"button",
|
|
416
468
|
{
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
469
|
+
className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
|
|
470
|
+
onClick: (e) => {
|
|
471
|
+
e.stopPropagation();
|
|
472
|
+
setIsPainting((prev) => !prev);
|
|
473
|
+
},
|
|
474
|
+
"data-active": isPainting,
|
|
475
|
+
"aria-label": "Toggle draw mode",
|
|
476
|
+
"aria-pressed": isPainting,
|
|
477
|
+
children: /* @__PURE__ */ jsx(Brush, { size: 18, strokeWidth: 2 })
|
|
420
478
|
}
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
className:
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
},
|
|
497
|
-
"aria-label": "Close",
|
|
498
|
-
children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2.5 })
|
|
499
|
-
}
|
|
500
|
-
)
|
|
501
|
-
] })
|
|
502
|
-
]
|
|
479
|
+
),
|
|
480
|
+
/* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Draw" })
|
|
481
|
+
] }),
|
|
482
|
+
/* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
|
|
483
|
+
/* @__PURE__ */ jsx(
|
|
484
|
+
"button",
|
|
485
|
+
{
|
|
486
|
+
className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
|
|
487
|
+
onClick: (e) => {
|
|
488
|
+
e.stopPropagation();
|
|
489
|
+
takeScreenshot();
|
|
490
|
+
},
|
|
491
|
+
"aria-label": "Take screenshot",
|
|
492
|
+
children: /* @__PURE__ */ jsxs(
|
|
493
|
+
"svg",
|
|
494
|
+
{
|
|
495
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
496
|
+
width: "18",
|
|
497
|
+
height: "18",
|
|
498
|
+
viewBox: "0 0 24 24",
|
|
499
|
+
fill: "none",
|
|
500
|
+
stroke: "currentColor",
|
|
501
|
+
strokeWidth: "2",
|
|
502
|
+
strokeLinecap: "round",
|
|
503
|
+
strokeLinejoin: "round",
|
|
504
|
+
children: [
|
|
505
|
+
/* @__PURE__ */ jsx("path", { d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z" }),
|
|
506
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
507
|
+
]
|
|
508
|
+
}
|
|
509
|
+
)
|
|
510
|
+
}
|
|
511
|
+
),
|
|
512
|
+
/* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Take screenshot" })
|
|
513
|
+
] }),
|
|
514
|
+
/* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
|
|
515
|
+
/* @__PURE__ */ jsx(
|
|
516
|
+
"button",
|
|
517
|
+
{
|
|
518
|
+
className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
|
|
519
|
+
onClick: (e) => {
|
|
520
|
+
e.stopPropagation();
|
|
521
|
+
clearCanvas();
|
|
522
|
+
},
|
|
523
|
+
disabled: !hasContent,
|
|
524
|
+
"data-danger": true,
|
|
525
|
+
"aria-label": "Clear",
|
|
526
|
+
children: /* @__PURE__ */ jsx(Trash2, { size: 18, strokeWidth: 2 })
|
|
527
|
+
}
|
|
528
|
+
),
|
|
529
|
+
/* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Clear" })
|
|
530
|
+
] }),
|
|
531
|
+
/* @__PURE__ */ jsx("div", { className: `${DrawingTool_module_default.divider} ${!isDarkMode ? DrawingTool_module_default.light : ""}` }),
|
|
532
|
+
/* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
|
|
533
|
+
/* @__PURE__ */ jsx(
|
|
534
|
+
"button",
|
|
535
|
+
{
|
|
536
|
+
className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
|
|
537
|
+
onClick: (e) => {
|
|
538
|
+
e.stopPropagation();
|
|
539
|
+
setIsOpen(false);
|
|
540
|
+
setIsPainting(false);
|
|
541
|
+
},
|
|
542
|
+
"aria-label": "Close",
|
|
543
|
+
children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2.5 })
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Close" })
|
|
547
|
+
] })
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
)
|
|
503
554
|
}
|
|
504
555
|
)
|
|
505
556
|
] });
|