@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.
@@ -1,9 +1,8 @@
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
- // src/components/Button.tsx
7
6
  var Button = ({
8
7
  children,
9
8
  variant = "primary",
@@ -86,24 +85,76 @@ var Input = ({
86
85
  ] });
87
86
  };
88
87
  var Input_default = Input;
89
- var DrawingTool = ({
90
- width,
91
- height,
92
- className = "",
93
- ...props
94
- }) => {
88
+
89
+ // src/components/DrawingTool.module.scss
90
+ 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}';
91
+ 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"};
92
+ if (typeof document !== "undefined") {
93
+ let style = document.getElementById("moab-components-DrawingTool");
94
+ if (!style) {
95
+ style = document.createElement("style");
96
+ style.id = "moab-components-DrawingTool";
97
+ document.head.appendChild(style);
98
+ }
99
+ style.textContent = css;
100
+ }
101
+ var DrawingTool_module_default = classNames;
102
+ var TOOLBAR_POSITION_STORAGE_KEY = "moab-drawing-toolbar-position";
103
+ var DrawingTool = () => {
95
104
  const canvasRef = useRef(null);
96
105
  const toolbarRef = useRef(null);
106
+ const toolbarWrapperRef = useRef(null);
97
107
  const [isDrawing, setIsDrawing] = useState(false);
98
- const brushColor = "#EF4444";
108
+ const brushColor = "#3B82F6";
99
109
  const brushSize = 5;
100
110
  const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
101
- const [enabled, setEnabled] = useState(false);
111
+ const [isOpen, setIsOpen] = useState(false);
112
+ const [isPainting, setIsPainting] = useState(false);
102
113
  const [hasContent, setHasContent] = useState(false);
103
- const [isDragging, setIsDragging] = useState(false);
104
- const [corner, setCorner] = useState("bottom-right");
105
- const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
106
- const [showClearTooltip, setShowClearTooltip] = useState(false);
114
+ const [isDraggingToolbar, setIsDraggingToolbar] = useState(false);
115
+ const [toolbarPosition, setToolbarPosition] = useState(null);
116
+ const [isToolbarReady, setIsToolbarReady] = useState(false);
117
+ const [dragStartPos, setDragStartPos] = useState(null);
118
+ const [dragRotation, setDragRotation] = useState(0);
119
+ const justFinishedToolbarDragRef = useRef(false);
120
+ useLayoutEffect(() => {
121
+ const toolbarWrapper = toolbarWrapperRef.current;
122
+ if (!toolbarWrapper) return;
123
+ const restorePosition = () => {
124
+ try {
125
+ const stored = localStorage.getItem(TOOLBAR_POSITION_STORAGE_KEY);
126
+ if (stored) {
127
+ const parsed = JSON.parse(stored);
128
+ if (typeof parsed?.x === "number" && typeof parsed?.y === "number") {
129
+ setToolbarPosition({ x: parsed.x, y: parsed.y });
130
+ setIsToolbarReady(true);
131
+ return;
132
+ }
133
+ }
134
+ } catch {
135
+ }
136
+ const rect = toolbarWrapper.getBoundingClientRect();
137
+ const padding = 20;
138
+ const startX = padding;
139
+ const startY = Math.max(
140
+ padding,
141
+ window.innerHeight - rect.height - padding
142
+ );
143
+ setToolbarPosition({ x: startX, y: startY });
144
+ setIsToolbarReady(true);
145
+ };
146
+ restorePosition();
147
+ }, []);
148
+ useEffect(() => {
149
+ if (!toolbarPosition) return;
150
+ try {
151
+ localStorage.setItem(
152
+ TOOLBAR_POSITION_STORAGE_KEY,
153
+ JSON.stringify(toolbarPosition)
154
+ );
155
+ } catch {
156
+ }
157
+ }, [toolbarPosition]);
107
158
  useEffect(() => {
108
159
  const updateSize = () => {
109
160
  setCanvasSize({
@@ -151,7 +202,7 @@ var DrawingTool = ({
151
202
  );
152
203
  const startDrawing = useCallback(
153
204
  (e) => {
154
- if (!enabled) return;
205
+ if (!isPainting) return;
155
206
  e.preventDefault();
156
207
  const canvas = canvasRef.current;
157
208
  const ctx = canvas?.getContext("2d");
@@ -161,7 +212,7 @@ var DrawingTool = ({
161
212
  ctx.moveTo(x, y);
162
213
  setIsDrawing(true);
163
214
  },
164
- [enabled, getCoordinates]
215
+ [isPainting, getCoordinates]
165
216
  );
166
217
  const draw = useCallback(
167
218
  (e) => {
@@ -188,40 +239,52 @@ var DrawingTool = ({
188
239
  setHasContent(false);
189
240
  }, []);
190
241
  const takeScreenshot = useCallback(async () => {
242
+ const toolbar = toolbarRef.current;
191
243
  try {
192
- const toolbar = toolbarRef.current;
193
244
  if (toolbar) {
194
- toolbar.style.opacity = "0";
245
+ toolbar.style.visibility = "hidden";
195
246
  }
196
- const canvas = await html2canvas(document.body, {
197
- useCORS: true,
198
- logging: false,
199
- windowWidth: window.innerWidth,
200
- windowHeight: window.innerHeight
247
+ await new Promise((resolve) => setTimeout(resolve, 50));
248
+ const dataUrl = await toPng(document.body, {
249
+ width: window.innerWidth,
250
+ height: window.innerHeight,
251
+ style: {
252
+ transform: `translate(-${window.scrollX}px, -${window.scrollY}px)`
253
+ },
254
+ filter: (node) => {
255
+ if (node instanceof HTMLElement) {
256
+ if (node.closest?.("[data-drawing-toolbar]")) {
257
+ return false;
258
+ }
259
+ }
260
+ return true;
261
+ }
201
262
  });
202
263
  if (toolbar) {
203
- toolbar.style.opacity = "";
264
+ toolbar.style.visibility = "";
265
+ }
266
+ const response = await fetch(dataUrl);
267
+ const blob = await response.blob();
268
+ try {
269
+ await navigator.clipboard.write([
270
+ new ClipboardItem({
271
+ "image/png": blob
272
+ })
273
+ ]);
274
+ } catch (err) {
275
+ console.error("Failed to copy to clipboard:", err);
276
+ const url = URL.createObjectURL(blob);
277
+ const a = document.createElement("a");
278
+ a.href = url;
279
+ a.download = "screenshot.png";
280
+ a.click();
281
+ URL.revokeObjectURL(url);
204
282
  }
205
- canvas.toBlob(async (blob) => {
206
- if (!blob) return;
207
- try {
208
- await navigator.clipboard.write([
209
- new ClipboardItem({
210
- "image/png": blob
211
- })
212
- ]);
213
- } catch (err) {
214
- console.error("Failed to copy to clipboard:", err);
215
- const url = URL.createObjectURL(blob);
216
- const a = document.createElement("a");
217
- a.href = url;
218
- a.download = "screenshot.png";
219
- a.click();
220
- URL.revokeObjectURL(url);
221
- }
222
- }, "image/png");
223
283
  } catch (error) {
224
284
  console.error("Failed to take screenshot:", error);
285
+ if (toolbar) {
286
+ toolbar.style.visibility = "";
287
+ }
225
288
  }
226
289
  }, []);
227
290
  useEffect(() => {
@@ -231,86 +294,109 @@ var DrawingTool = ({
231
294
  ctx.strokeStyle = brushColor;
232
295
  ctx.lineWidth = brushSize;
233
296
  }, [brushColor, brushSize]);
234
- const getTargetCorner = useCallback(
235
- (startX, startY, currentX, currentY) => {
236
- const deltaX = currentX - startX;
237
- const deltaY = currentY - startY;
238
- const threshold = 50;
239
- if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold) {
240
- return null;
297
+ const handleToolbarMouseDown = useCallback(
298
+ (e) => {
299
+ if (e.target.closest("button")) {
300
+ return;
241
301
  }
242
- const viewportWidth = window.innerWidth;
243
- const viewportHeight = window.innerHeight;
244
- const horizontal = currentX < viewportWidth / 2 ? "left" : "right";
245
- const vertical = currentY < viewportHeight / 2 ? "top" : "bottom";
246
- if (vertical === "top" && horizontal === "left") return "top-left";
247
- if (vertical === "top" && horizontal === "right") return "top-right";
248
- if (vertical === "bottom" && horizontal === "left") return "bottom-left";
249
- if (vertical === "bottom" && horizontal === "right")
250
- return "bottom-right";
251
- return null;
302
+ const toolbarWrapper = toolbarWrapperRef.current;
303
+ if (!toolbarWrapper) return;
304
+ e.preventDefault();
305
+ e.stopPropagation();
306
+ const rect = toolbarWrapper.getBoundingClientRect();
307
+ const randomRotation = (Math.random() - 0.5) * 10;
308
+ setDragRotation(randomRotation);
309
+ setDragStartPos({
310
+ x: e.clientX,
311
+ y: e.clientY,
312
+ toolbarX: toolbarPosition?.x ?? rect.left,
313
+ toolbarY: toolbarPosition?.y ?? rect.top,
314
+ toolbarWidth: rect.width,
315
+ toolbarHeight: rect.height
316
+ });
252
317
  },
253
- []
318
+ [toolbarPosition]
254
319
  );
255
- const handleMouseDown = useCallback((e) => {
256
- if (e.target.closest("button")) {
257
- return;
258
- }
259
- e.preventDefault();
260
- e.stopPropagation();
261
- setIsDragging(true);
262
- setDragStart({
263
- x: e.clientX,
264
- y: e.clientY
265
- });
266
- }, []);
267
320
  useEffect(() => {
321
+ if (!dragStartPos) return;
322
+ const DRAG_THRESHOLD = 5;
268
323
  const handleMouseMove = (e) => {
269
- if (!isDragging) return;
270
- e.preventDefault();
271
- e.stopPropagation();
272
- const targetCorner = getTargetCorner(
273
- dragStart.x,
274
- dragStart.y,
275
- e.clientX,
276
- e.clientY
277
- );
278
- if (targetCorner) {
279
- setCorner(targetCorner);
280
- } else {
281
- const viewportWidth = window.innerWidth;
282
- const viewportHeight = window.innerHeight;
283
- const horizontal = e.clientX < viewportWidth / 2 ? "left" : "right";
284
- const vertical = e.clientY < viewportHeight / 2 ? "top" : "bottom";
285
- if (vertical === "top" && horizontal === "left") setCorner("top-left");
286
- else if (vertical === "top" && horizontal === "right")
287
- setCorner("top-right");
288
- else if (vertical === "bottom" && horizontal === "left")
289
- setCorner("bottom-left");
290
- else setCorner("bottom-right");
324
+ const deltaX = e.clientX - dragStartPos.x;
325
+ const deltaY = e.clientY - dragStartPos.y;
326
+ const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
327
+ if (!isDraggingToolbar && distance > DRAG_THRESHOLD) {
328
+ setIsDraggingToolbar(true);
329
+ }
330
+ if (isDraggingToolbar || distance > DRAG_THRESHOLD) {
331
+ const padding = 20;
332
+ const maxX = window.innerWidth - dragStartPos.toolbarWidth - padding;
333
+ const maxY = window.innerHeight - dragStartPos.toolbarHeight - padding;
334
+ const newX = Math.max(
335
+ padding,
336
+ Math.min(maxX, dragStartPos.toolbarX + deltaX)
337
+ );
338
+ const newY = Math.max(
339
+ padding,
340
+ Math.min(maxY, dragStartPos.toolbarY + deltaY)
341
+ );
342
+ setToolbarPosition({ x: newX, y: newY });
291
343
  }
292
344
  };
293
- const handleMouseUp = (e) => {
294
- e.preventDefault();
295
- e.stopPropagation();
296
- setIsDragging(false);
345
+ const handleMouseUp = () => {
346
+ if (isDraggingToolbar) {
347
+ justFinishedToolbarDragRef.current = true;
348
+ setTimeout(() => {
349
+ justFinishedToolbarDragRef.current = false;
350
+ }, 50);
351
+ }
352
+ setIsDraggingToolbar(false);
353
+ setDragStartPos(null);
297
354
  };
298
- if (isDragging) {
299
- document.addEventListener("mousemove", handleMouseMove, {
300
- passive: false
301
- });
302
- document.addEventListener("mouseup", handleMouseUp, { passive: false });
303
- }
355
+ document.addEventListener("mousemove", handleMouseMove);
356
+ document.addEventListener("mouseup", handleMouseUp);
304
357
  return () => {
305
358
  document.removeEventListener("mousemove", handleMouseMove);
306
359
  document.removeEventListener("mouseup", handleMouseUp);
307
360
  };
308
- }, [isDragging, dragStart, getTargetCorner]);
309
- return /* @__PURE__ */ jsxs("div", { style: { display: "contents" }, children: [
361
+ }, [dragStartPos, isDraggingToolbar]);
362
+ useEffect(() => {
363
+ if (!toolbarPosition) return;
364
+ const constrainPosition = () => {
365
+ const toolbarWrapper = toolbarWrapperRef.current;
366
+ const rect = toolbarWrapper?.getBoundingClientRect();
367
+ const width = rect?.width ?? 44;
368
+ const height = rect?.height ?? 44;
369
+ const padding = 20;
370
+ const maxX = window.innerWidth - width - padding;
371
+ const maxY = window.innerHeight - height - padding;
372
+ const newX = Math.max(padding, Math.min(maxX, toolbarPosition.x));
373
+ const newY = Math.max(padding, Math.min(maxY, toolbarPosition.y));
374
+ if (newX !== toolbarPosition.x || newY !== toolbarPosition.y) {
375
+ setToolbarPosition({ x: newX, y: newY });
376
+ }
377
+ };
378
+ constrainPosition();
379
+ window.addEventListener("resize", constrainPosition);
380
+ return () => window.removeEventListener("resize", constrainPosition);
381
+ }, [toolbarPosition, isOpen]);
382
+ const [showEntranceAnimation, setShowEntranceAnimation] = useState(false);
383
+ const [isDarkMode] = useState(true);
384
+ useEffect(() => {
385
+ setShowEntranceAnimation(true);
386
+ const timer = setTimeout(() => setShowEntranceAnimation(false), 500);
387
+ return () => clearTimeout(timer);
388
+ }, []);
389
+ useEffect(() => {
390
+ if (!isPainting) {
391
+ setIsDrawing(false);
392
+ }
393
+ }, [isPainting]);
394
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
310
395
  /* @__PURE__ */ jsx(
311
396
  "canvas",
312
397
  {
313
398
  ref: canvasRef,
399
+ className: "moab-drawing-canvas",
314
400
  onMouseDown: startDrawing,
315
401
  onMouseMove: draw,
316
402
  onMouseUp: stopDrawing,
@@ -318,186 +404,150 @@ var DrawingTool = ({
318
404
  onTouchStart: startDrawing,
319
405
  onTouchMove: draw,
320
406
  onTouchEnd: stopDrawing,
321
- 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"}`,
322
407
  style: {
323
408
  width: `${canvasSize.width}px`,
324
- height: `${canvasSize.height}px`
409
+ height: `${canvasSize.height}px`,
410
+ cursor: isPainting && !isDraggingToolbar ? "crosshair" : "default",
411
+ pointerEvents: isPainting && !isDraggingToolbar ? "auto" : "none",
412
+ opacity: isPainting && !isDraggingToolbar ? 1 : 0,
413
+ transition: "opacity 300ms ease-in-out"
325
414
  }
326
415
  }
327
416
  ),
328
- /* @__PURE__ */ jsxs(
417
+ /* @__PURE__ */ jsx(
329
418
  "div",
330
419
  {
331
- ref: toolbarRef,
332
- 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}`,
333
- style: {
334
- gap: enabled ? "8px" : "0px",
335
- transition: "gap 300ms ease-in-out",
336
- ...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" }
337
- },
338
- onMouseDown: handleMouseDown,
339
- ...props,
340
- onClick: (e) => e.stopPropagation(),
341
- children: [
342
- /* @__PURE__ */ jsx(
343
- "div",
344
- {
345
- className: "overflow-hidden flex-shrink-0",
346
- style: {
347
- maxWidth: enabled ? "100px" : "0px",
348
- opacity: enabled ? 1 : 0,
349
- transition: "max-width 300ms ease-in-out, opacity 300ms ease-in-out"
350
- },
351
- children: /* @__PURE__ */ jsx(
352
- "button",
420
+ ref: toolbarWrapperRef,
421
+ className: DrawingTool_module_default.toolbar,
422
+ "data-drawing-toolbar": true,
423
+ style: toolbarPosition ? {
424
+ left: toolbarPosition.x,
425
+ top: toolbarPosition.y,
426
+ right: "auto",
427
+ bottom: "auto",
428
+ visibility: isToolbarReady ? "visible" : "hidden"
429
+ } : { visibility: "hidden" },
430
+ children: /* @__PURE__ */ jsxs(
431
+ "div",
432
+ {
433
+ ref: toolbarRef,
434
+ 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 : ""}`,
435
+ onClick: !isOpen ? (e) => {
436
+ if (justFinishedToolbarDragRef.current) {
437
+ e.preventDefault();
438
+ return;
439
+ }
440
+ setIsOpen(true);
441
+ } : void 0,
442
+ onMouseDown: handleToolbarMouseDown,
443
+ role: !isOpen ? "button" : void 0,
444
+ tabIndex: !isOpen ? 0 : -1,
445
+ style: isDraggingToolbar ? {
446
+ cursor: "grabbing",
447
+ transform: `scale(1.05) rotate(${dragRotation}deg)`
448
+ } : void 0,
449
+ children: [
450
+ /* @__PURE__ */ jsx(
451
+ "div",
353
452
  {
354
- onClick: (e) => {
355
- e.stopPropagation();
356
- takeScreenshot();
357
- },
358
- className: "p-2 text-white hover:bg-neutral-600/30 rounded-full transition-colors focus:outline-none whitespace-nowrap",
359
- "aria-label": "Take screenshot",
360
- children: /* @__PURE__ */ jsxs(
361
- "svg",
362
- {
363
- xmlns: "http://www.w3.org/2000/svg",
364
- width: "18",
365
- height: "18",
366
- viewBox: "0 0 24 24",
367
- fill: "none",
368
- stroke: "currentColor",
369
- strokeWidth: "2",
370
- strokeLinecap: "round",
371
- strokeLinejoin: "round",
372
- className: "lucide lucide-camera",
373
- children: [
374
- /* @__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" }),
375
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
376
- ]
377
- }
378
- )
453
+ className: `${DrawingTool_module_default.toggleContent} ${!isOpen ? DrawingTool_module_default.visible : DrawingTool_module_default.hidden}`,
454
+ children: /* @__PURE__ */ jsx(Palette, { size: 20, strokeWidth: 2 })
379
455
  }
380
- )
381
- }
382
- ),
383
- /* @__PURE__ */ jsxs(
384
- "div",
385
- {
386
- className: "overflow-hidden flex-shrink-0 relative",
387
- style: {
388
- maxWidth: enabled ? "100px" : "0px",
389
- opacity: enabled ? 1 : 0,
390
- transition: "max-width 300ms ease-in-out, opacity 300ms ease-in-out"
391
- },
392
- children: [
393
- /* @__PURE__ */ jsxs(
394
- "button",
395
- {
396
- onClick: (e) => {
397
- e.stopPropagation();
398
- clearCanvas();
399
- setShowClearTooltip(false);
400
- },
401
- onMouseEnter: () => {
402
- if (hasContent) {
403
- setShowClearTooltip(true);
404
- }
405
- },
406
- onMouseLeave: () => setShowClearTooltip(false),
407
- disabled: !hasContent,
408
- className: "p-2 text-white rounded-full focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed relative group",
409
- "aria-label": "Clear canvas",
410
- children: [
411
- /* @__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" }),
456
+ ),
457
+ /* @__PURE__ */ jsxs(
458
+ "div",
459
+ {
460
+ className: `${DrawingTool_module_default.controlsContent} ${isOpen ? DrawingTool_module_default.visible : DrawingTool_module_default.hidden}`,
461
+ children: [
462
+ /* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
412
463
  /* @__PURE__ */ jsx(
413
- Trash2,
464
+ "button",
414
465
  {
415
- size: 18,
416
- strokeWidth: 2,
417
- className: "relative z-10 group-hover:text-red-600 transition-colors"
466
+ className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
467
+ onClick: (e) => {
468
+ e.stopPropagation();
469
+ setIsPainting((prev) => !prev);
470
+ },
471
+ "data-active": isPainting,
472
+ "aria-label": "Toggle draw mode",
473
+ "aria-pressed": isPainting,
474
+ children: /* @__PURE__ */ jsx(Brush, { size: 18, strokeWidth: 2 })
418
475
  }
419
- )
420
- ]
421
- }
422
- ),
423
- 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: [
424
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
425
- /* @__PURE__ */ jsx("span", { className: "text-white text-sm", children: "Clear all" }),
426
- /* @__PURE__ */ jsx(
427
- "button",
428
- {
429
- onClick: (e) => {
430
- e.stopPropagation();
431
- setShowClearTooltip(false);
432
- },
433
- onMouseDown: (e) => e.stopPropagation(),
434
- className: "text-white hover:text-neutral-300 transition-colors rounded-full",
435
- "aria-label": "Dismiss tooltip",
436
- children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2 })
437
- }
438
- )
439
- ] }),
440
- /* @__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" }) })
441
- ] })
442
- ]
443
- }
444
- ),
445
- /* @__PURE__ */ jsxs("div", { className: "relative flex-shrink-0", children: [
446
- /* @__PURE__ */ jsx(
447
- "button",
448
- {
449
- onClick: (e) => {
450
- e.stopPropagation();
451
- setEnabled(!enabled);
452
- },
453
- className: "p-1.5 text-white hover:bg-neutral-600/30 rounded-full transition-all focus:outline-none",
454
- style: {
455
- opacity: enabled ? 0 : 1,
456
- pointerEvents: enabled ? "none" : "auto",
457
- transition: "opacity 300ms ease-in-out"
458
- },
459
- "aria-label": "Turn on drawing",
460
- children: /* @__PURE__ */ jsxs(
461
- "svg",
462
- {
463
- xmlns: "http://www.w3.org/2000/svg",
464
- width: "18",
465
- height: "18",
466
- viewBox: "0 0 24 24",
467
- fill: "none",
468
- stroke: "currentColor",
469
- strokeWidth: "2",
470
- strokeLinecap: "round",
471
- strokeLinejoin: "round",
472
- className: "lucide lucide-brush",
473
- children: [
474
- /* @__PURE__ */ jsx("path", { d: "m11 10 3 3" }),
475
- /* @__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" }),
476
- /* @__PURE__ */ jsx("path", { d: "M9.969 17.031 21.378 5.624a1 1 0 0 0-3.002-3.002L6.967 14.031" })
477
- ]
478
- }
479
- )
480
- }
481
- ),
482
- /* @__PURE__ */ jsx(
483
- "button",
484
- {
485
- onClick: (e) => {
486
- e.stopPropagation();
487
- setEnabled(false);
488
- },
489
- className: "absolute inset-0 p-1.5 text-white hover:bg-neutral-600/30 rounded-full transition-all focus:outline-none",
490
- style: {
491
- opacity: enabled ? 1 : 0,
492
- pointerEvents: enabled ? "auto" : "none",
493
- transition: "opacity 300ms ease-in-out"
494
- },
495
- "aria-label": "Close",
496
- children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2.5 })
497
- }
498
- )
499
- ] })
500
- ]
476
+ ),
477
+ /* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Draw" })
478
+ ] }),
479
+ /* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
480
+ /* @__PURE__ */ jsx(
481
+ "button",
482
+ {
483
+ className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
484
+ onClick: (e) => {
485
+ e.stopPropagation();
486
+ takeScreenshot();
487
+ },
488
+ "aria-label": "Take screenshot",
489
+ children: /* @__PURE__ */ jsxs(
490
+ "svg",
491
+ {
492
+ xmlns: "http://www.w3.org/2000/svg",
493
+ width: "18",
494
+ height: "18",
495
+ viewBox: "0 0 24 24",
496
+ fill: "none",
497
+ stroke: "currentColor",
498
+ strokeWidth: "2",
499
+ strokeLinecap: "round",
500
+ strokeLinejoin: "round",
501
+ children: [
502
+ /* @__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" }),
503
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
504
+ ]
505
+ }
506
+ )
507
+ }
508
+ ),
509
+ /* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Take screenshot" })
510
+ ] }),
511
+ /* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
512
+ /* @__PURE__ */ jsx(
513
+ "button",
514
+ {
515
+ className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
516
+ onClick: (e) => {
517
+ e.stopPropagation();
518
+ clearCanvas();
519
+ },
520
+ disabled: !hasContent,
521
+ "data-danger": true,
522
+ "aria-label": "Clear",
523
+ children: /* @__PURE__ */ jsx(Trash2, { size: 18, strokeWidth: 2 })
524
+ }
525
+ ),
526
+ /* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Clear" })
527
+ ] }),
528
+ /* @__PURE__ */ jsx("div", { className: `${DrawingTool_module_default.divider} ${!isDarkMode ? DrawingTool_module_default.light : ""}` }),
529
+ /* @__PURE__ */ jsxs("div", { className: DrawingTool_module_default.buttonWrapper, children: [
530
+ /* @__PURE__ */ jsx(
531
+ "button",
532
+ {
533
+ className: `${DrawingTool_module_default.controlButton} ${!isDarkMode ? DrawingTool_module_default.light : ""}`,
534
+ onClick: (e) => {
535
+ e.stopPropagation();
536
+ setIsOpen(false);
537
+ setIsPainting(false);
538
+ },
539
+ "aria-label": "Close",
540
+ children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2.5 })
541
+ }
542
+ ),
543
+ /* @__PURE__ */ jsx("span", { className: DrawingTool_module_default.buttonTooltip, children: "Close" })
544
+ ] })
545
+ ]
546
+ }
547
+ )
548
+ ]
549
+ }
550
+ )
501
551
  }
502
552
  )
503
553
  ] });