seat-editor 3.3.13 → 3.3.15

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