seat-editor 1.4.20 → 1.4.21

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.
@@ -0,0 +1,654 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { TransformWrapper, TransformComponent, MiniMap, } from "react-zoom-pan-pinch";
4
+ import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
5
+ import Layers from "../../components/layer";
6
+ import { throttle } from "lodash";
7
+ import ModalPreview from "../../components/modal-preview";
8
+ import LayerView from "../view";
9
+ import { isEqual, debounce } from "lodash";
10
+ import { ZoomIn, ZoomOut } from "lucide-react";
11
+ import { Button } from "antd";
12
+ const BoardTemplate = ({ onSelectComponent }) => {
13
+ const dispatch = useAppDispatch();
14
+ const theme = useAppSelector((state) => state.theme);
15
+ const transformRef = useRef(null);
16
+ const containerRef = useRef(null);
17
+ const [widthBoard, setWidthBoard] = useState(0);
18
+ const [heightBoard, setHeightBoard] = useState(0);
19
+ const svgRef = useRef(null);
20
+ const [shadowShape, setShadowShape] = useState([]);
21
+ const [startPoint, setStartPoint] = useState(null);
22
+ const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
23
+ const [moveComponent, setMoveComponent] = useState(false);
24
+ const [scale, setScale] = useState(1);
25
+ const activeTool = useAppSelector((state) => state.tool.active);
26
+ const { components: componentsProps, extraComponents: extraComponentsProps, flagChange, } = useAppSelector((state) => state.board);
27
+ const isTouching = useRef(false);
28
+ const [isDragging, setIsDragging] = useState(false);
29
+ const [resizeDirection, setResizeDirection] = useState(null);
30
+ const backgroundColor = useAppSelector((state) => state.board.backgroundColor);
31
+ const selectedComponentProps = useAppSelector((state) => state.panel.selectedComponent);
32
+ const screenCTMRef = useRef(null);
33
+ const dragIndex = useRef(null);
34
+ const [componentsState, setComponentsState] = useState([]);
35
+ const [extraComponentsState, setExtraComponentsState] = useState([]);
36
+ const [selectedComponent, setSelectedComponent] = useState(null);
37
+ const isSyncingFromRedux = useRef(false);
38
+ const debouncedSyncToReduxSelected = useRef(debounce((data) => {
39
+ throttledDispatch(data);
40
+ }, 300)).current;
41
+ const debouncedSyncComponents = useRef(debounce((data) => {
42
+ dispatch({
43
+ type: "board/setNewComponents",
44
+ payload: data,
45
+ });
46
+ }, 300));
47
+ const debouncedSyncExtraComponents = useRef(debounce((data) => {
48
+ dispatch({
49
+ type: "board/setNewExtraComponents",
50
+ payload: data,
51
+ });
52
+ }, 300));
53
+ // Redux → Local
54
+ useEffect(() => {
55
+ if (flagChange) {
56
+ if (!isEqual(componentsProps, componentsState)) {
57
+ isSyncingFromRedux.current = true;
58
+ setComponentsState(componentsProps);
59
+ }
60
+ if (!isEqual(extraComponentsProps, extraComponentsState)) {
61
+ isSyncingFromRedux.current = true;
62
+ setExtraComponentsState(extraComponentsProps);
63
+ }
64
+ if (!isEqual(selectedComponentProps, selectedComponent)) {
65
+ isSyncingFromRedux.current = true;
66
+ setSelectedComponent(selectedComponentProps);
67
+ }
68
+ dispatch({ type: "board/setFlagChange", payload: false });
69
+ }
70
+ }, [
71
+ componentsProps,
72
+ extraComponentsProps,
73
+ selectedComponentProps,
74
+ flagChange,
75
+ ]);
76
+ // Local → Redux
77
+ useEffect(() => {
78
+ if (isSyncingFromRedux.current) {
79
+ isSyncingFromRedux.current = false;
80
+ return;
81
+ }
82
+ if (!isEqual(componentsState, componentsProps)) {
83
+ debouncedSyncComponents.current(componentsState);
84
+ }
85
+ if (!isEqual(extraComponentsState, extraComponentsProps)) {
86
+ debouncedSyncExtraComponents.current(extraComponentsState);
87
+ }
88
+ }, [componentsState, extraComponentsState]);
89
+ const handleAddComponent = (shape) => {
90
+ dispatch({
91
+ type: activeTool === "text"
92
+ ? "board/setExtraComponent"
93
+ : "board/addComponent",
94
+ payload: Object.assign(Object.assign({}, shape), { fill: theme === null || theme === void 0 ? void 0 : theme.primaryColor }),
95
+ });
96
+ const payload = Object.assign(Object.assign({}, shape), { fill: theme === null || theme === void 0 ? void 0 : theme.primaryColor });
97
+ if (activeTool === "text") {
98
+ setExtraComponentsState((prev) => [...prev, payload]);
99
+ }
100
+ else {
101
+ setComponentsState((prev) => [...prev, payload]);
102
+ }
103
+ };
104
+ const getSvgCoords = (e) => {
105
+ var _a;
106
+ const svg = svgRef.current;
107
+ const point = svg.createSVGPoint();
108
+ point.x = e.clientX;
109
+ point.y = e.clientY;
110
+ const transformed = point.matrixTransform((_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
111
+ return { x: transformed.x, y: transformed.y };
112
+ };
113
+ const createShape = (x, y, fill) => ({
114
+ x,
115
+ y,
116
+ width: 50,
117
+ height: 50,
118
+ shape: activeTool,
119
+ id: Date.now(),
120
+ fill,
121
+ rotation: activeTool === "diamond" ? 45 : 0,
122
+ seatCount: activeTool === "table-seat-circle" ? 6 : 0,
123
+ openSpace: activeTool === "table-seat-circle" ? 0 : undefined,
124
+ seatFill: activeTool === "table-seat-circle" ? "#DADADA" : undefined,
125
+ text: activeTool === "text" ? "Text" : "",
126
+ fontColor: activeTool === "text" ? "#DADADA" : undefined,
127
+ });
128
+ const handleMouseDown = (e, item, direction) => {
129
+ if (activeTool === "select" && direction) {
130
+ setResizeDirection(direction);
131
+ setIsDragging(true);
132
+ }
133
+ if (activeTool === "select" && !direction && !moveComponent) {
134
+ if (e) {
135
+ dispatch({ type: "panel/setShow", payload: false });
136
+ setMoveComponent(true);
137
+ setIsDragging(true);
138
+ // dispatch({ type: "panel/setSelectedComponent", payload: null });
139
+ // setSelectedComponent(null)
140
+ const rectBox = (e === null || e === void 0 ? void 0 : e.target).getBoundingClientRect();
141
+ setDragOffset({
142
+ x: e.clientX - rectBox.left,
143
+ y: e.clientY - rectBox.top,
144
+ });
145
+ }
146
+ }
147
+ };
148
+ const handleMouseUp = () => {
149
+ if (activeTool === "select" && selectedComponent && (moveComponent || isDragging)) {
150
+ setMoveComponent(false);
151
+ dispatch({ type: "panel/setShow", payload: false });
152
+ dispatch({ type: "panel/setSelectedComponent", payload: null });
153
+ setSelectedComponent(null);
154
+ setIsDragging(false);
155
+ setResizeDirection(null);
156
+ }
157
+ };
158
+ const handleMouseEnter = () => {
159
+ if (![
160
+ "square",
161
+ "circle",
162
+ "diamond",
163
+ "table-seat-circle",
164
+ "table-seat-square",
165
+ "text",
166
+ ].includes(activeTool))
167
+ return;
168
+ };
169
+ const handleMouseLeave = () => {
170
+ if (![
171
+ "square",
172
+ "circle",
173
+ "diamond",
174
+ "table-seat-circle",
175
+ "table-seat-square",
176
+ "text",
177
+ ].includes(activeTool))
178
+ return;
179
+ setShadowShape([]);
180
+ };
181
+ const handleMouseClick = (e) => {
182
+ if (![
183
+ "square",
184
+ "circle",
185
+ "diamond",
186
+ "table-seat-circle",
187
+ "table-seat-square",
188
+ "text",
189
+ ].includes(activeTool)) {
190
+ return;
191
+ }
192
+ const { x, y } = getSvgCoords(e);
193
+ setStartPoint({ x, y });
194
+ handleAddComponent(createShape(x, y, theme === null || theme === void 0 ? void 0 : theme.primaryColor));
195
+ };
196
+ const throttledDispatch = useCallback(throttle((component) => {
197
+ // dispatch({
198
+ // type: "board/updateComponent",
199
+ // payload: component,
200
+ // });
201
+ dispatch({
202
+ type: "panel/updateSelectedComponent",
203
+ payload: component,
204
+ });
205
+ }, 16), // 16ms ≈ 60fps
206
+ [dispatch]);
207
+ const handleMouseMove = (e) => {
208
+ if ([
209
+ "square",
210
+ "circle",
211
+ "diamond",
212
+ "table-seat-circle",
213
+ "table-seat-square",
214
+ "text",
215
+ ].includes(activeTool)) {
216
+ const { x, y } = getSvgCoords(e);
217
+ setShadowShape([createShape(x, y, theme === null || theme === void 0 ? void 0 : theme.primaryColor)]);
218
+ return;
219
+ }
220
+ if (activeTool === "select" &&
221
+ selectedComponent &&
222
+ moveComponent &&
223
+ dragOffset &&
224
+ // !isTouching.current &&
225
+ !resizeDirection) {
226
+ const workspaceRect = e.currentTarget.getBoundingClientRect();
227
+ const newX = e.clientX - workspaceRect.left - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.x);
228
+ const newY = e.clientY - workspaceRect.top - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.y);
229
+ let newPosition = {
230
+ x: newX,
231
+ y: newY,
232
+ };
233
+ requestAnimationFrame(() => {
234
+ setComponentsState((prev) => {
235
+ return prev.map((component) => {
236
+ if (component.id === selectedComponent.id) {
237
+ return Object.assign(Object.assign({}, component), { x: newPosition.x, y: newPosition.y });
238
+ }
239
+ return component;
240
+ });
241
+ });
242
+ setExtraComponentsState((prev) => {
243
+ return prev.map((component) => {
244
+ if (component.id === selectedComponent.id) {
245
+ return Object.assign(Object.assign({}, component), { x: newPosition.x, y: newPosition.y });
246
+ }
247
+ return component;
248
+ });
249
+ });
250
+ setSelectedComponent((prev) => {
251
+ return Object.assign(Object.assign({}, prev), { x: newPosition.x, y: newPosition.y });
252
+ });
253
+ });
254
+ debouncedSyncToReduxSelected(Object.assign(Object.assign({}, selectedComponent), newPosition));
255
+ return;
256
+ }
257
+ if (activeTool === "select" && resizeDirection) {
258
+ const workspaceRect = e.currentTarget.getBoundingClientRect();
259
+ const currentX = e.clientX - workspaceRect.left;
260
+ const currentY = e.clientY - workspaceRect.top;
261
+ const { x, y, width, height } = selectedComponent;
262
+ let newShape = Object.assign({}, selectedComponent);
263
+ if (!["table-seat-circle", "table-seat-square"].includes(selectedComponent.shape)) {
264
+ switch (resizeDirection) {
265
+ case "top-left":
266
+ newShape.width = width + (x - currentX);
267
+ newShape.height = height + (y - currentY);
268
+ newShape.x = currentX;
269
+ newShape.y = currentY;
270
+ break;
271
+ case "top-right":
272
+ newShape.width = currentX - newShape.x;
273
+ newShape.height = newShape.height + (newShape.y - currentY);
274
+ newShape.y = currentY;
275
+ break;
276
+ case "bottom-left":
277
+ newShape.width += newShape.x - currentX;
278
+ newShape.height = currentY - newShape.y;
279
+ newShape.x = currentX;
280
+ break;
281
+ case "bottom-right":
282
+ newShape.width = currentX - newShape.x;
283
+ newShape.height = currentY - newShape.y;
284
+ break;
285
+ case "left-center":
286
+ newShape.width += newShape.x - currentX;
287
+ newShape.x = currentX;
288
+ break;
289
+ case "right-center":
290
+ newShape.width = currentX - newShape.x;
291
+ break;
292
+ case "top-center":
293
+ newShape.height += newShape.y - currentY;
294
+ newShape.y = currentY;
295
+ break;
296
+ case "bottom-center":
297
+ newShape.height = currentY - newShape.y;
298
+ break;
299
+ default:
300
+ break;
301
+ }
302
+ }
303
+ else if (["table-seat-circle", "table-seat-square"].includes(selectedComponent.shape)) {
304
+ switch (resizeDirection) {
305
+ case "top-left":
306
+ newShape.width = width + (x - currentX);
307
+ newShape.height = height + (y - currentY);
308
+ newShape.x = currentX;
309
+ newShape.y = currentY;
310
+ break;
311
+ case "top-right":
312
+ newShape.width = currentX - newShape.x;
313
+ newShape.height = newShape.height + (newShape.y - currentY);
314
+ newShape.y = currentY;
315
+ break;
316
+ case "bottom-left":
317
+ newShape.width += newShape.x - currentX;
318
+ newShape.height = currentY - newShape.y;
319
+ newShape.x = currentX;
320
+ break;
321
+ case "bottom-right":
322
+ newShape.width = currentX - newShape.x;
323
+ newShape.height = currentY - newShape.y;
324
+ break;
325
+ default:
326
+ break;
327
+ }
328
+ }
329
+ // updateComponentRef({
330
+ // ...(typeof selectedComponent === "object" && selectedComponent !== null
331
+ // ? selectedComponent
332
+ // : {}),
333
+ // ...newShape,
334
+ // });
335
+ requestAnimationFrame(() => {
336
+ setComponentsState((prev) => {
337
+ return prev.map((component) => {
338
+ if (component.id === selectedComponent.id) {
339
+ return Object.assign(Object.assign({}, component), newShape);
340
+ }
341
+ return component;
342
+ });
343
+ });
344
+ setExtraComponentsState((prev) => {
345
+ return prev.map((component) => {
346
+ if (component.id === selectedComponent.id) {
347
+ return Object.assign(Object.assign({}, component), newShape);
348
+ }
349
+ return component;
350
+ });
351
+ });
352
+ setSelectedComponent(newShape);
353
+ });
354
+ debouncedSyncToReduxSelected(newShape);
355
+ }
356
+ };
357
+ const handleSelectComponent = (items) => {
358
+ if (activeTool === "select") {
359
+ setIsDragging(true);
360
+ setMoveComponent(false);
361
+ onSelectComponent && onSelectComponent(items);
362
+ setSelectedComponent(items);
363
+ dispatch({ type: "panel/setSelectedComponent", payload: items });
364
+ // selectedComponentRef.current = items;
365
+ dispatch({ type: "panel/setShow", payload: true });
366
+ }
367
+ };
368
+ useEffect(() => {
369
+ if (containerRef.current) {
370
+ setWidthBoard(containerRef.current.offsetWidth);
371
+ setHeightBoard(containerRef.current.offsetHeight);
372
+ }
373
+ });
374
+ const handleUnSelectComponent = () => {
375
+ dispatch({ type: "panel/setSelectedComponent", payload: null });
376
+ setSelectedComponent(null);
377
+ // selectedComponentRef.current = null;
378
+ };
379
+ const handleTouchStart = (e, items, direction) => {
380
+ var _a, _b, _c, _d;
381
+ if (activeTool === "select" && !direction) {
382
+ // dispatch({ type: "panel/setShow", payload: false });
383
+ setMoveComponent(true);
384
+ isTouching.current = true;
385
+ // dispatch({ type: "panel/setSelectedComponent", payload: item });
386
+ onSelectComponent && onSelectComponent(items);
387
+ dispatch({ type: "panel/setSelectedComponent", payload: items });
388
+ setSelectedComponent(items);
389
+ // selectedComponentRef.current = items;
390
+ const touch = e.touches[0];
391
+ const svg = e.currentTarget.ownerSVGElement;
392
+ const pt = svg.createSVGPoint();
393
+ if (!svg)
394
+ return;
395
+ pt.x = touch.clientX;
396
+ pt.y = touch.clientY;
397
+ const cursorpt = pt.matrixTransform((_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
398
+ screenCTMRef.current = ((_b = svg.getScreenCTM()) === null || _b === void 0 ? void 0 : _b.inverse()) || null;
399
+ setDragOffset({
400
+ x: cursorpt.x - items.x,
401
+ y: cursorpt.y - items.y,
402
+ });
403
+ // dragOffset.current = {
404
+ // x: cursorpt.x - items.x,
405
+ // y: cursorpt.y - items.y
406
+ // }
407
+ }
408
+ else if (activeTool === "select" && direction) {
409
+ setResizeDirection(direction);
410
+ setIsDragging(true);
411
+ setMoveComponent(true);
412
+ isTouching.current = true;
413
+ const touch = e.touches[0];
414
+ const svg = e.currentTarget.ownerSVGElement;
415
+ const pt = svg.createSVGPoint();
416
+ if (!svg)
417
+ return;
418
+ pt.x = touch.clientX;
419
+ pt.y = touch.clientY;
420
+ const cursorpt = pt.matrixTransform((_c = svg.getScreenCTM()) === null || _c === void 0 ? void 0 : _c.inverse());
421
+ screenCTMRef.current = ((_d = svg.getScreenCTM()) === null || _d === void 0 ? void 0 : _d.inverse()) || null;
422
+ setDragOffset({
423
+ x: cursorpt.x - items.x,
424
+ y: cursorpt.y - items.y,
425
+ });
426
+ // dragOffset.current = {
427
+ // x: cursorpt.x - items.x,
428
+ // y: cursorpt.y - items.y
429
+ // }
430
+ }
431
+ };
432
+ const [isMove, setIsMove] = useState(false);
433
+ const handleTouchMove = (e) => {
434
+ if (activeTool === "select" &&
435
+ moveComponent &&
436
+ isTouching.current &&
437
+ !resizeDirection) {
438
+ setIsDragging(true);
439
+ setIsMove(true);
440
+ const touch = e.touches[0];
441
+ const svg = e.currentTarget.ownerSVGElement;
442
+ if (!svg)
443
+ return;
444
+ const pt = svg.createSVGPoint();
445
+ pt.x = touch.clientX;
446
+ pt.y = touch.clientY;
447
+ const cursorpt = pt.matrixTransform(screenCTMRef.current);
448
+ requestAnimationFrame(() => {
449
+ if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) != "background") {
450
+ setComponentsState((prev) => {
451
+ return prev.map((component) => {
452
+ if (component.id === selectedComponent.id) {
453
+ return Object.assign(Object.assign({}, component), { x: cursorpt.x - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.x), y: cursorpt.y - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.y) });
454
+ }
455
+ return component;
456
+ });
457
+ });
458
+ }
459
+ if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) == "background") {
460
+ setExtraComponentsState((prev) => {
461
+ return prev.map((component) => {
462
+ if (component.id === selectedComponent.id) {
463
+ return Object.assign(Object.assign({}, component), { x: cursorpt.x - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.x), y: cursorpt.y - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.y) });
464
+ }
465
+ return component;
466
+ });
467
+ });
468
+ }
469
+ setSelectedComponent(Object.assign(Object.assign({}, selectedComponent), { x: cursorpt.x - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.x), y: cursorpt.y - (dragOffset === null || dragOffset === void 0 ? void 0 : dragOffset.y) }));
470
+ });
471
+ // updateComponentRef({
472
+ // ...(typeof selectedComponent === "object" && selectedComponent !== null
473
+ // ? selectedComponent
474
+ // : {}),
475
+ // x: cursorpt.x - dragOffset?.current.x,
476
+ // y: cursorpt.y - dragOffset?.current.y,
477
+ // });
478
+ }
479
+ else if (activeTool === "select" &&
480
+ moveComponent &&
481
+ isTouching.current &&
482
+ resizeDirection) {
483
+ setIsDragging(true);
484
+ const touch = e.touches[0];
485
+ const svg = e.currentTarget.ownerSVGElement;
486
+ if (!svg)
487
+ return;
488
+ const pt = svg.createSVGPoint();
489
+ pt.x = touch.clientX;
490
+ pt.y = touch.clientY;
491
+ const cursorpt = pt.matrixTransform(screenCTMRef.current);
492
+ let newShape = Object.assign({}, selectedComponent);
493
+ switch (resizeDirection) {
494
+ case "top-left":
495
+ newShape.width = newShape.width + (newShape.x - cursorpt.x);
496
+ newShape.height = newShape.height + (newShape.y - cursorpt.y);
497
+ newShape.x = cursorpt.x;
498
+ newShape.y = cursorpt.y;
499
+ break;
500
+ case "top-right":
501
+ newShape.width = cursorpt.x - newShape.x;
502
+ newShape.height = newShape.height + (newShape.y - cursorpt.y);
503
+ newShape.y = cursorpt.y;
504
+ break;
505
+ case "bottom-left":
506
+ newShape.width = newShape.width + (newShape.x - cursorpt.x);
507
+ newShape.height = cursorpt.y - newShape.y;
508
+ newShape.x = cursorpt.x;
509
+ break;
510
+ case "bottom-right":
511
+ newShape.width = cursorpt.x - newShape.x;
512
+ newShape.height = cursorpt.y - newShape.y;
513
+ break;
514
+ case "top-center":
515
+ newShape.height = newShape.height + (newShape.y - cursorpt.y);
516
+ newShape.y = cursorpt.y;
517
+ break;
518
+ case "bottom-center":
519
+ newShape.height = cursorpt.y - newShape.y;
520
+ break;
521
+ case "right-center":
522
+ newShape.width = cursorpt.x - newShape.x;
523
+ break;
524
+ case "left-center":
525
+ newShape.width = newShape.width + (newShape.x - cursorpt.x);
526
+ newShape.x = cursorpt.x;
527
+ break;
528
+ default:
529
+ break;
530
+ }
531
+ // updateComponentRef({
532
+ // ...(typeof selectedComponent === "object" && selectedComponent !== null
533
+ // ? selectedComponent
534
+ // : {}),
535
+ // ...newShape,
536
+ // });
537
+ requestAnimationFrame(() => {
538
+ setComponentsState((prev) => {
539
+ return prev.map((component) => {
540
+ if (component.id === selectedComponent.id) {
541
+ return Object.assign(Object.assign({}, component), newShape);
542
+ }
543
+ return component;
544
+ });
545
+ });
546
+ setExtraComponentsState((prev) => {
547
+ return prev.map((component) => {
548
+ if (component.id === selectedComponent.id) {
549
+ return Object.assign(Object.assign({}, component), newShape);
550
+ }
551
+ return component;
552
+ });
553
+ });
554
+ setSelectedComponent(Object.assign(Object.assign({}, selectedComponent), newShape));
555
+ });
556
+ debouncedSyncToReduxSelected(newShape);
557
+ }
558
+ };
559
+ const handleTouchEnd = () => {
560
+ setMoveComponent(false);
561
+ setIsDragging(false);
562
+ isTouching.current = false;
563
+ setResizeDirection(null);
564
+ };
565
+ const getCursorStyle = () => {
566
+ if (activeTool === "select" && moveComponent) {
567
+ return "grabbing";
568
+ }
569
+ else if (activeTool === "select" && resizeDirection) {
570
+ return "grab";
571
+ }
572
+ else if (activeTool === "grab") {
573
+ return "grab";
574
+ }
575
+ };
576
+ const renderMiniMap = () => {
577
+ return (<MiniMap width={250} height={250}>
578
+ <div className="w-full h-full">
579
+ <svg id="workspace" width="100%" height="100%" viewBox={`0 0 ${widthBoard} ${heightBoard}`} className="h-screen w-full" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style={{
580
+ background: "#f5f5f5",
581
+ display: "block",
582
+ }}>
583
+ <Layers shadowShape={shadowShape} components={[...extraComponentsState, ...componentsState]} activeTool={activeTool} onClick={handleSelectComponent} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp}
584
+ // onBlur={handleUnSelectComponent}
585
+ selectedComponent={selectedComponent} onTouchStart={(e, item, direction) => handleTouchStart(e, item, direction)} onTouchMove={(e) => handleTouchMove(e)} onTouchEnd={handleTouchEnd}/>
586
+ </svg>
587
+ </div>
588
+ </MiniMap>);
589
+ };
590
+ const handelZoomIn = () => {
591
+ var _a;
592
+ if (activeTool !== "grab") {
593
+ dispatch({
594
+ type: "tool/setActiveTool",
595
+ payload: "grab",
596
+ });
597
+ }
598
+ (_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.zoomIn();
599
+ };
600
+ const handleZoomOut = () => {
601
+ var _a;
602
+ if (activeTool !== "grab") {
603
+ dispatch({
604
+ type: "tool/setActiveTool",
605
+ payload: "grab",
606
+ });
607
+ }
608
+ (_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.zoomOut();
609
+ };
610
+ // activeTool === "select" &&
611
+ // moveComponent &&
612
+ // isTouching.current &&
613
+ // !resizeDirection
614
+ return (<>
615
+ <ModalPreview>
616
+ <LayerView statusKey="status"/>
617
+ </ModalPreview>
618
+ <div className="relative w-full h-screen flex-1 overflow-hidden" style={{
619
+ cursor: getCursorStyle(),
620
+ }} ref={containerRef}>
621
+ <div className="absolute bottom-5 left-1/2 transform -translate-x-1/2 z-10">
622
+ <div className="flex gap-2">
623
+ <Button icon={<ZoomIn />} onClick={handelZoomIn}/>
624
+ <Button icon={<ZoomOut />} onClick={handleZoomOut}/>
625
+ </div>
626
+ </div>
627
+ <TransformWrapper ref={transformRef} panning={{ disabled: activeTool === "select" }} centerZoomedOut={true} onTransformed={({ state: { scale } }) => setScale(scale)} minScale={1} // sangat kecil = bisa zoom out jauh
628
+ maxScale={1000} initialScale={1} pinch={{ step: 1 }} smooth={true} doubleClick={{ step: 1, disabled: activeTool === "select" }} disablePadding>
629
+ {scale > 1 && (<div className="absolute bottom-[60px] left-1/2 transform -translate-x-1/2 z-10">
630
+ {renderMiniMap()}
631
+ </div>)}
632
+ <TransformComponent wrapperStyle={{
633
+ width: "100%",
634
+ height: "100%",
635
+ overflow: "hidden",
636
+ }} contentStyle={{
637
+ width: "100%",
638
+ height: "100%",
639
+ }}>
640
+ <svg id="workspace" ref={svgRef} width="100%" height="100%" viewBox={`0 0 ${widthBoard} ${heightBoard}`} className="h-screen" onMouseUp={handleMouseUp} onMouseMove={handleMouseMove} onMouseEnter={handleMouseEnter} onClick={(e) => {
641
+ e.stopPropagation();
642
+ handleMouseClick(e);
643
+ }} onMouseLeave={handleMouseLeave} xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style={{
644
+ background: backgroundColor,
645
+ display: "block",
646
+ }}>
647
+ <Layers shadowShape={shadowShape} components={[...extraComponentsState, ...componentsState]} onClick={handleSelectComponent} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} onBlur={handleUnSelectComponent} selectedComponent={selectedComponent} activeTool={activeTool} onTouchStart={(e, item, direction) => handleTouchStart(e, item, direction)} onTouchMove={(e) => handleTouchMove(e)} onTouchEnd={handleTouchEnd}/>
648
+ </svg>
649
+ </TransformComponent>
650
+ </TransformWrapper>
651
+ </div>
652
+ </>);
653
+ };
654
+ export default BoardTemplate;
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ const Navbar = () => {
3
+ return <div>Navbar</div>;
4
+ };
5
+ export default Navbar;