@maayan-albert/moab-sdk 1.0.5 → 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/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 html2canvas from 'html2canvas';
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
- var DrawingTool = ({
92
- width,
93
- height,
94
- className = "",
95
- ...props
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 = "#EF4444";
111
+ const brushColor = "#3B82F6";
101
112
  const brushSize = 5;
102
113
  const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
103
- const [enabled, setEnabled] = useState(false);
114
+ const [isOpen, setIsOpen] = useState(false);
115
+ const [isPainting, setIsPainting] = useState(false);
104
116
  const [hasContent, setHasContent] = useState(false);
105
- const [isDragging, setIsDragging] = useState(false);
106
- const [corner, setCorner] = useState("bottom-right");
107
- const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
108
- const [showClearTooltip, setShowClearTooltip] = useState(false);
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 (!enabled) return;
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
- [enabled, getCoordinates]
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.opacity = "0";
248
+ toolbar.style.visibility = "hidden";
197
249
  }
198
- const canvas = await html2canvas(document.body, {
199
- useCORS: true,
200
- logging: false,
201
- windowWidth: window.innerWidth,
202
- windowHeight: window.innerHeight
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.opacity = "";
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 getTargetCorner = useCallback(
237
- (startX, startY, currentX, currentY) => {
238
- const deltaX = currentX - startX;
239
- const deltaY = currentY - startY;
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 viewportWidth = window.innerWidth;
245
- const viewportHeight = window.innerHeight;
246
- const horizontal = currentX < viewportWidth / 2 ? "left" : "right";
247
- const vertical = currentY < viewportHeight / 2 ? "top" : "bottom";
248
- if (vertical === "top" && horizontal === "left") return "top-left";
249
- if (vertical === "top" && horizontal === "right") return "top-right";
250
- if (vertical === "bottom" && horizontal === "left") return "bottom-left";
251
- if (vertical === "bottom" && horizontal === "right")
252
- return "bottom-right";
253
- return null;
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
- if (!isDragging) return;
272
- e.preventDefault();
273
- e.stopPropagation();
274
- const targetCorner = getTargetCorner(
275
- dragStart.x,
276
- dragStart.y,
277
- e.clientX,
278
- e.clientY
279
- );
280
- if (targetCorner) {
281
- setCorner(targetCorner);
282
- } else {
283
- const viewportWidth = window.innerWidth;
284
- const viewportHeight = window.innerHeight;
285
- const horizontal = e.clientX < viewportWidth / 2 ? "left" : "right";
286
- const vertical = e.clientY < viewportHeight / 2 ? "top" : "bottom";
287
- if (vertical === "top" && horizontal === "left") setCorner("top-left");
288
- else if (vertical === "top" && horizontal === "right")
289
- setCorner("top-right");
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 = (e) => {
296
- e.preventDefault();
297
- e.stopPropagation();
298
- setIsDragging(false);
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
- if (isDragging) {
301
- document.addEventListener("mousemove", handleMouseMove, {
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
- }, [isDragging, dragStart, getTargetCorner]);
311
- return /* @__PURE__ */ jsxs("div", { style: { display: "contents" }, children: [
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__ */ jsxs(
420
+ /* @__PURE__ */ jsx(
331
421
  "div",
332
422
  {
333
- ref: toolbarRef,
334
- className: `fixed flex flex-row items-center px-2 py-1.5 bg-neutral-800 rounded-full shadow-lg z-[60] ${isDragging ? "cursor-grabbing" : "cursor-grab"} ${className}`,
335
- style: {
336
- gap: enabled ? "8px" : "0px",
337
- transition: "gap 300ms ease-in-out",
338
- ...corner === "top-left" ? { top: "16px", left: "16px", bottom: "auto", right: "auto" } : corner === "top-right" ? { top: "16px", right: "16px", bottom: "auto", left: "auto" } : corner === "bottom-left" ? { bottom: "16px", left: "16px", top: "auto", right: "auto" } : { bottom: "16px", right: "16px", top: "auto", left: "auto" }
339
- },
340
- onMouseDown: handleMouseDown,
341
- ...props,
342
- onClick: (e) => e.stopPropagation(),
343
- children: [
344
- /* @__PURE__ */ jsx(
345
- "div",
346
- {
347
- className: "overflow-hidden flex-shrink-0",
348
- style: {
349
- maxWidth: enabled ? "100px" : "0px",
350
- opacity: enabled ? 1 : 0,
351
- transition: "max-width 300ms ease-in-out, opacity 300ms ease-in-out"
352
- },
353
- children: /* @__PURE__ */ jsx(
354
- "button",
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
- onClick: (e) => {
357
- e.stopPropagation();
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
- /* @__PURE__ */ jsxs(
386
- "div",
387
- {
388
- className: "overflow-hidden flex-shrink-0 relative",
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
- Trash2,
467
+ "button",
416
468
  {
417
- size: 18,
418
- strokeWidth: 2,
419
- className: "relative z-10 group-hover:text-red-600 transition-colors"
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
- showClearTooltip && hasContent && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-3 py-1.5 bg-neutral-800 rounded-full shadow-lg whitespace-nowrap z-[70]", children: [
426
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
427
- /* @__PURE__ */ jsx("span", { className: "text-white text-sm", children: "Clear all" }),
428
- /* @__PURE__ */ jsx(
429
- "button",
430
- {
431
- onClick: (e) => {
432
- e.stopPropagation();
433
- setShowClearTooltip(false);
434
- },
435
- onMouseDown: (e) => e.stopPropagation(),
436
- className: "text-white hover:text-neutral-300 transition-colors rounded-full",
437
- "aria-label": "Dismiss tooltip",
438
- children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2 })
439
- }
440
- )
441
- ] }),
442
- /* @__PURE__ */ jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-1", children: /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-neutral-800 rotate-45" }) })
443
- ] })
444
- ]
445
- }
446
- ),
447
- /* @__PURE__ */ jsxs("div", { className: "relative flex-shrink-0", children: [
448
- /* @__PURE__ */ jsx(
449
- "button",
450
- {
451
- onClick: (e) => {
452
- e.stopPropagation();
453
- setEnabled(!enabled);
454
- },
455
- className: "p-1.5 text-white hover:bg-neutral-600/30 rounded-full transition-all focus:outline-none",
456
- style: {
457
- opacity: enabled ? 0 : 1,
458
- pointerEvents: enabled ? "none" : "auto",
459
- transition: "opacity 300ms ease-in-out"
460
- },
461
- "aria-label": "Turn on drawing",
462
- children: /* @__PURE__ */ jsxs(
463
- "svg",
464
- {
465
- xmlns: "http://www.w3.org/2000/svg",
466
- width: "18",
467
- height: "18",
468
- viewBox: "0 0 24 24",
469
- fill: "none",
470
- stroke: "currentColor",
471
- strokeWidth: "2",
472
- strokeLinecap: "round",
473
- strokeLinejoin: "round",
474
- className: "lucide lucide-brush",
475
- children: [
476
- /* @__PURE__ */ jsx("path", { d: "m11 10 3 3" }),
477
- /* @__PURE__ */ jsx("path", { d: "M6.5 21A3.5 3.5 0 1 0 3 17.5a2.62 2.62 0 0 1-.708 1.792A1 1 0 0 0 3 21z" }),
478
- /* @__PURE__ */ jsx("path", { d: "M9.969 17.031 21.378 5.624a1 1 0 0 0-3.002-3.002L6.967 14.031" })
479
- ]
480
- }
481
- )
482
- }
483
- ),
484
- /* @__PURE__ */ jsx(
485
- "button",
486
- {
487
- onClick: (e) => {
488
- e.stopPropagation();
489
- setEnabled(false);
490
- },
491
- className: "absolute inset-0 p-1.5 text-white hover:bg-neutral-600/30 rounded-full transition-all focus:outline-none",
492
- style: {
493
- opacity: enabled ? 1 : 0,
494
- pointerEvents: enabled ? "auto" : "none",
495
- transition: "opacity 300ms ease-in-out"
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
  ] });