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,1678 @@
1
+ "use client";
2
+ import React, { useEffect, useImperativeHandle, useRef, useState } from "react";
3
+ import { TransformWrapper, TransformComponent, } from "react-zoom-pan-pinch";
4
+ import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
5
+ import Layers from "../../components/layer-v3";
6
+ import { isEmpty, isPlainObject, isUndefined } from "lodash";
7
+ import ModalPreview from "../../components/modal-preview";
8
+ import LayerView from "../view-only-3";
9
+ import { isEqual, debounce } from "lodash";
10
+ import { ZoomIn, ZoomOut } from "lucide-react";
11
+ import { Button, Radio } from "antd";
12
+ import { getAttributeElement, getAttributeElements } from "./resize-element";
13
+ import { applyResizeToSvgElement, arrayToSvgPointsAttr, createTableGhost, getGlobalBBox, getRotation, getSvgElementSize, getTranslate, isClosingPolygon, normalizeAngle, pointsStringToArray, resizeBox, resizeSeatCircle, resizeSeatRectCircle, resizeSeatRectSquare, resizeSeatSide, resizeSeatSquare, stabilizeRotation, stabilizeTranslateOnRotate, updateManyComponents, updateSelectionBox, updateSelectionGuides, updateSingleComponent, } from "./utils";
14
+ const toolElement = ["square", "circle", "table-seat-circle"];
15
+ const idSelectionBoxGhost = "selection-box-ghost";
16
+ const nameShapeSelectionBoxGhost = "selection-box";
17
+ const BoardTemplate = ({ refs, loadingRender }) => {
18
+ const dispatch = useAppDispatch();
19
+ const backgroundColor = useAppSelector((state) => state.board.backgroundColor);
20
+ const selectedComponentProps = useAppSelector((state) => state.panel.selectedComponent);
21
+ const activeTool = useAppSelector((state) => state.tool.active);
22
+ const grid = useAppSelector((state) => state.tool.grid);
23
+ const lockBackground = useAppSelector((state) => state.tool.lockBackground);
24
+ const transformRef = useRef(null);
25
+ const svgRef = useRef(null);
26
+ const containerRef = useRef(null);
27
+ const releaseGroupRef = useRef(false);
28
+ useImperativeHandle(refs, () => ({
29
+ svgRef: svgRef === null || svgRef === void 0 ? void 0 : svgRef.current,
30
+ transformRef: transformRef === null || transformRef === void 0 ? void 0 : transformRef.current,
31
+ containerRef: containerRef === null || containerRef === void 0 ? void 0 : containerRef.current,
32
+ }));
33
+ const widthBoardRef = useRef(20000);
34
+ const heightBoardRef = useRef(20000);
35
+ const widthBoard = widthBoardRef.current;
36
+ const heightBoard = heightBoardRef.current;
37
+ const [scale, setScale] = useState(1);
38
+ const boardSizeRef = useRef({ width: 20000, height: 20000 });
39
+ const boardSize = boardSizeRef.current;
40
+ const minCoordsRef = useRef({ x: 0, y: 0 });
41
+ const minCoords = minCoordsRef.current;
42
+ const [hasInitialized, setHasInitialzed] = useState(false);
43
+ const [componentsState, setComponentsState] = useState([]);
44
+ const [extraComponentsState, setExtraComponentsState] = useState([]);
45
+ const [selectedComponent, setSelectedComponent] = useState(null);
46
+ const isSyncingFromRedux = useRef(false);
47
+ const isDragging = useRef(false);
48
+ const moveComponent = useRef(false);
49
+ const ghostRotateElement = useRef(0);
50
+ const isResizeRef = useRef(false);
51
+ const isResizeSelectionRef = useRef(false);
52
+ const hadSelectionRef = useRef(false);
53
+ //FLAGE EVERY HANDLE EVENT
54
+ //CREATE
55
+ const isCreateElementRef = useRef(false);
56
+ //RESIZE
57
+ const onResizeSelectionRef = useRef(false);
58
+ //ROTATE
59
+ const isRotatingRef = useRef(false);
60
+ const rotationSelectionRef = useRef(0);
61
+ //DRAG/MOVE
62
+ //SELECTION
63
+ const onMakeSelectionRef = useRef(false);
64
+ const onMoveSelectionBoxRef = useRef(false);
65
+ const dataElementSelectionGroupRef = useRef([]);
66
+ //polygon
67
+ const polygonElementRef = useRef([]);
68
+ const isOnMakePolygonRef = useRef(false);
69
+ const { components: componentsProps, extraComponents: extraComponentsProps, boundingBox, flagChange, updateBy, isShowTagType, } = useAppSelector((state) => state.board);
70
+ const { selectionLines } = useAppSelector((state) => state.panel);
71
+ const [selectedLines, setSelectedLines] = useState(null);
72
+ useEffect(() => {
73
+ if (activeTool === "select" || activeTool !== "select") {
74
+ handleUnSelectComponent();
75
+ }
76
+ }, [activeTool]);
77
+ useEffect(() => {
78
+ if (selectionLines) {
79
+ setSelectedLines(selectionLines);
80
+ const idSelected = dataElementSelectionGroupRef.current.map((item) => item.id);
81
+ const newSelectionData = [
82
+ ...componentsState,
83
+ ...extraComponentsState,
84
+ ].filter((comp) => idSelected.includes(comp.id));
85
+ dataElementSelectionGroupRef.current = newSelectionData;
86
+ }
87
+ }, [selectionLines]);
88
+ useEffect(() => {
89
+ var _a, _b, _c, _d, _e, _f, _g;
90
+ if (hasInitialized)
91
+ return;
92
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
93
+ // let widthMinX = 0;
94
+ // let heightMinY = 0;
95
+ componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps.forEach((_, i) => {
96
+ let values = _;
97
+ if (values === null || values === void 0 ? void 0 : values.shape) {
98
+ minX = Math.min(minX, values.x);
99
+ minY = Math.min(minY, values.y);
100
+ maxX = Math.max(maxX, values.x + values.width);
101
+ maxY = Math.max(maxY, values.y + values.height);
102
+ }
103
+ if (i === componentsProps.length - 1) {
104
+ minX = minX > 10 ? minX - 10 : minX;
105
+ minY = minY > 10 ? minY - 10 : minY;
106
+ maxX = maxX + 10;
107
+ maxY = maxY + 10;
108
+ }
109
+ });
110
+ extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps.forEach((values, i) => {
111
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
112
+ if (values === null || values === void 0 ? void 0 : values.shape) {
113
+ minX = Math.min(minX, values.x - ((_a = values === null || values === void 0 ? void 0 : values.width) !== null && _a !== void 0 ? _a : 0));
114
+ minY = Math.min(minY, values.y - ((_b = values === null || values === void 0 ? void 0 : values.height) !== null && _b !== void 0 ? _b : 0));
115
+ maxX = Math.max(maxX, values.x + ((_c = values === null || values === void 0 ? void 0 : values.width) !== null && _c !== void 0 ? _c : 0));
116
+ maxY = Math.max(maxY, values.y + ((_d = values === null || values === void 0 ? void 0 : values.height) !== null && _d !== void 0 ? _d : 0));
117
+ }
118
+ if ((_e = values === null || values === void 0 ? void 0 : values.shape) === null || _e === void 0 ? void 0 : _e.includes("polygon")) {
119
+ minX = Math.min(minX, (_f = values === null || values === void 0 ? void 0 : values.points) === null || _f === void 0 ? void 0 : _f.reduce((min, point) => Math.min(min, point.x), Infinity));
120
+ minY = Math.min(minY, (_g = values === null || values === void 0 ? void 0 : values.points) === null || _g === void 0 ? void 0 : _g.reduce((min, point) => Math.min(min, point.y), Infinity));
121
+ maxX = Math.max(maxX, (_h = values === null || values === void 0 ? void 0 : values.points) === null || _h === void 0 ? void 0 : _h.reduce((max, point) => Math.max(max, point.x), -Infinity));
122
+ maxY = Math.max(maxY, (_j = values === null || values === void 0 ? void 0 : values.points) === null || _j === void 0 ? void 0 : _j.reduce((max, point) => Math.max(max, point.y), -Infinity));
123
+ }
124
+ });
125
+ let backgroundHasOne = false;
126
+ if ((extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps.length) === 1 &&
127
+ ((_b = (_a = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _a === void 0 ? void 0 : _a.shape) === null || _b === void 0 ? void 0 : _b.includes("background"))) {
128
+ backgroundHasOne = true;
129
+ minX = (_c = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _c === void 0 ? void 0 : _c.x;
130
+ minY = (_d = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _d === void 0 ? void 0 : _d.y;
131
+ maxX = (_e = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _e === void 0 ? void 0 : _e.width;
132
+ maxY = (_f = extraComponentsProps === null || extraComponentsProps === void 0 ? void 0 : extraComponentsProps[0]) === null || _f === void 0 ? void 0 : _f.height;
133
+ }
134
+ // if (
135
+ // extraComponentsProps?.length < 1 &&
136
+ // ["background", "text"].includes(componentsProps?.[0]?.shape)
137
+ // ) {
138
+ // minX = minX;
139
+ // minY = minY;
140
+ // maxX = maxX;
141
+ // maxY = maxY;
142
+ // }
143
+ const hasBoundingBox = !isEmpty(boundingBox);
144
+ if (hasBoundingBox) {
145
+ minX = boundingBox.x;
146
+ minY = boundingBox.y;
147
+ }
148
+ if ((minX !== Infinity || minY !== Infinity) && !activeTool) {
149
+ // console.log("initialized");
150
+ (_g = transformRef.current) === null || _g === void 0 ? void 0 : _g.setTransform(-minX, -minY, scale);
151
+ setHasInitialzed(true);
152
+ }
153
+ }, [componentsProps, extraComponentsProps]);
154
+ const queueUpdateComponents = (data) => {
155
+ dispatch({
156
+ type: "board/updateComponentsBulk",
157
+ payload: data,
158
+ });
159
+ };
160
+ const queueUpdateExtraComponents = (data) => {
161
+ dispatch({
162
+ type: "board/setNewExtraComponents",
163
+ payload: data,
164
+ });
165
+ };
166
+ const debouncedSyncExtraComponents = useRef(debounce((data) => {
167
+ dispatch({
168
+ type: "board/setNewExtraComponents",
169
+ payload: data,
170
+ });
171
+ }, 1000));
172
+ // Redux → Local
173
+ useEffect(() => {
174
+ if (flagChange && updateBy === "global") {
175
+ if (!isEqual(selectedComponentProps, selectedComponent)) {
176
+ isSyncingFromRedux.current = true;
177
+ setSelectedComponent(selectedComponentProps !== null && selectedComponentProps !== void 0 ? selectedComponentProps : []);
178
+ setSelectedLines(selectionLines);
179
+ }
180
+ if (!isEqual(componentsProps, componentsState)) {
181
+ isSyncingFromRedux.current = true;
182
+ setComponentsState(componentsProps !== null && componentsProps !== void 0 ? componentsProps : []);
183
+ }
184
+ if (!isEqual(extraComponentsProps, extraComponentsState)) {
185
+ isSyncingFromRedux.current = true;
186
+ setExtraComponentsState(extraComponentsProps !== null && extraComponentsProps !== void 0 ? extraComponentsProps : []);
187
+ }
188
+ dispatch({ type: "board/setFlagChange", payload: false });
189
+ }
190
+ }, [componentsProps, extraComponentsProps, selectedComponentProps]);
191
+ const updateComponentAttribute = (component) => {
192
+ if (!component)
193
+ return;
194
+ const updatedComponents = updateSingleComponent(componentsState, component, setComponentsState);
195
+ if (updatedComponents) {
196
+ dispatch({ type: "board/setUpdateBy", payload: "local" });
197
+ queueUpdateComponents(updatedComponents);
198
+ }
199
+ const updatedExtra = updateSingleComponent(extraComponentsState, component, setExtraComponentsState);
200
+ if (updatedExtra) {
201
+ dispatch({ type: "board/setUpdateBy", payload: "local" });
202
+ queueUpdateComponents(updatedExtra);
203
+ }
204
+ };
205
+ const updateComponentsAttribute = (components) => {
206
+ if (!components.length)
207
+ return;
208
+ const nextExtraComponents = updateManyComponents(extraComponentsState, components, setExtraComponentsState);
209
+ if (nextExtraComponents) {
210
+ queueUpdateComponents(nextExtraComponents);
211
+ }
212
+ const nextComponents = updateManyComponents(componentsState, components, setComponentsState);
213
+ if (nextComponents) {
214
+ queueUpdateComponents(nextComponents);
215
+ }
216
+ dispatch({ type: "board/setUpdateBy", payload: "local" });
217
+ };
218
+ const addComponents = (component) => {
219
+ const index = extraComponentsState.findIndex((c) => (c === null || c === void 0 ? void 0 : c.shape) === "bounding-box");
220
+ const nextExtraComponents = index !== -1
221
+ ? extraComponentsState.map((item, i) => i === index ? component : item)
222
+ : [...extraComponentsState, component];
223
+ setExtraComponentsState(nextExtraComponents);
224
+ dispatch({
225
+ type: "board/setNewExtraComponents",
226
+ payload: nextExtraComponents,
227
+ });
228
+ dispatch({ type: "board/setUpdateBy", payload: "local" });
229
+ };
230
+ const getSvgCoords = (e) => {
231
+ var _a;
232
+ const svg = svgRef.current;
233
+ const point = svg.createSVGPoint();
234
+ point.x = e.clientX;
235
+ point.y = e.clientY;
236
+ const transformed = point.matrixTransform((_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
237
+ return { x: transformed.x, y: transformed.y };
238
+ };
239
+ const getCursorStyle = () => {
240
+ if (activeTool === "select" && moveComponent.current) {
241
+ return "grabbing";
242
+ }
243
+ else if (activeTool === "select") {
244
+ return "grab";
245
+ }
246
+ else if (activeTool === "grab") {
247
+ return "grab";
248
+ }
249
+ else if (activeTool === "ruler") {
250
+ return "crosshair";
251
+ }
252
+ };
253
+ const handelZoomIn = () => {
254
+ var _a;
255
+ if (activeTool !== "grab") {
256
+ dispatch({
257
+ type: "tool/setActiveTool",
258
+ payload: "grab",
259
+ });
260
+ }
261
+ (_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.zoomIn();
262
+ };
263
+ const handleZoomOut = () => {
264
+ var _a;
265
+ if (activeTool !== "grab") {
266
+ dispatch({
267
+ type: "tool/setActiveTool",
268
+ payload: "grab",
269
+ });
270
+ }
271
+ (_a = transformRef.current) === null || _a === void 0 ? void 0 : _a.zoomOut();
272
+ };
273
+ const handleUnSelectComponent = () => {
274
+ dispatch({ type: "panel/setSelectedComponent", payload: null });
275
+ setSelectedComponent(null);
276
+ setSelectedLines(null);
277
+ dispatch({ type: "panel/setShow", payload: false });
278
+ dataElementSelectionGroupRef.current = [];
279
+ };
280
+ const stillHoldShift = useRef(false);
281
+ useEffect(() => {
282
+ var _a, _b;
283
+ if (stillHoldShift.current && dataElementSelectionGroupRef.current) {
284
+ const selectionLines = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#selection-lines");
285
+ selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("pointer-events", "none");
286
+ }
287
+ if (!stillHoldShift.current && dataElementSelectionGroupRef.current) {
288
+ const selectionLines = (_b = svgRef.current) === null || _b === void 0 ? void 0 : _b.querySelector("#selection-lines");
289
+ selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("pointer-events", "all");
290
+ }
291
+ }, [stillHoldShift.current, dataElementSelectionGroupRef.current]);
292
+ useEffect(() => {
293
+ const handleKeyDown = (e) => {
294
+ var _a, _b;
295
+ // setPressedKey(e.key);
296
+ const selectionLines = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#selection-lines");
297
+ (_b = svgRef.current) === null || _b === void 0 ? void 0 : _b.querySelector("#selection-lines");
298
+ if (e.key === "Shift") {
299
+ stillHoldShift.current = true;
300
+ selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("pointer-events", "none");
301
+ }
302
+ };
303
+ const handleKeyUp = () => {
304
+ var _a;
305
+ const selectionLines = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#selection-lines");
306
+ stillHoldShift.current = false;
307
+ selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("pointer-events", "all");
308
+ };
309
+ window.addEventListener("keydown", handleKeyDown);
310
+ window.addEventListener("keyup", handleKeyUp);
311
+ return () => {
312
+ window.removeEventListener("keydown", handleKeyDown);
313
+ window.removeEventListener("keyup", handleKeyUp);
314
+ };
315
+ }, [dataElementSelectionGroupRef.current]);
316
+ const handlePointerDown = (e) => {
317
+ var _a, _b, _c, _d, _e, _f, _g, _h;
318
+ const shiftActive = e.shiftKey;
319
+ if (activeTool === "grab") {
320
+ return;
321
+ }
322
+ const svg = svgRef.current;
323
+ if (!e.isPrimary)
324
+ return;
325
+ if (!svg)
326
+ return;
327
+ isDragging.current = false;
328
+ let hasMoved = false;
329
+ releaseGroupRef.current = false;
330
+ const startX = e.clientX;
331
+ const startY = e.clientY;
332
+ const pt = svg.createSVGPoint();
333
+ pt.x = e.clientX;
334
+ pt.y = e.clientY;
335
+ const { x, y } = getSvgCoords(e);
336
+ //CREATE ELEMENT
337
+ const isInitialCreateElemente = toolElement.includes(activeTool) && !isCreateElementRef.current;
338
+ const isInitialCreateBoundingBox = activeTool === "bounding-box";
339
+ const isInitialCreateText = activeTool === "text" && !isCreateElementRef.current;
340
+ if (isInitialCreateElemente) {
341
+ const tables = createTableGhost({
342
+ x,
343
+ y,
344
+ width: 1,
345
+ height: 1,
346
+ fill: "red",
347
+ shape: activeTool,
348
+ });
349
+ // setGhostCreateElement(tables);
350
+ (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.appendChild(tables);
351
+ isCreateElementRef.current = true;
352
+ }
353
+ else if (isInitialCreateBoundingBox) {
354
+ const tables = createTableGhost({
355
+ x,
356
+ y,
357
+ width: 1,
358
+ height: 1,
359
+ fill: "transparent",
360
+ shape: activeTool,
361
+ });
362
+ (_b = svgRef.current) === null || _b === void 0 ? void 0 : _b.appendChild(tables);
363
+ isCreateElementRef.current = true;
364
+ }
365
+ else if (isInitialCreateText) {
366
+ const tables = createTableGhost({
367
+ x,
368
+ y,
369
+ width: 100 * scale,
370
+ height: 50 * scale,
371
+ fill: "#000000",
372
+ shape: activeTool,
373
+ });
374
+ (_c = svgRef.current) === null || _c === void 0 ? void 0 : _c.appendChild(tables);
375
+ isCreateElementRef.current = true;
376
+ }
377
+ const targetSelection = e.target.closest("g[id='selection-lines']");
378
+ //ROTATE
379
+ const targetRotate = e.target.closest("circle[data-role]");
380
+ if (targetRotate) {
381
+ isRotatingRef.current = true;
382
+ }
383
+ const targetSelectionBox = e.target.closest("g[id='selection-lines']");
384
+ // RESIZE
385
+ const targetGroup = e.target.closest("g[data-id]");
386
+ const targetPointPolygon = e.target.closest("circle[data-point]");
387
+ // TARGET ELEMENT
388
+ let idTargetElement = JSON.parse((targetGroup === null || targetGroup === void 0 ? void 0 : targetGroup.getAttribute("data-id")) || "{}");
389
+ const selectionTarget = (_e = (_d = targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.dataset) === null || _d === void 0 ? void 0 : _d.selection) === null || _e === void 0 ? void 0 : _e.replace("selection-", "");
390
+ const activeId = selectionTarget !== null && selectionTarget !== void 0 ? selectionTarget : idTargetElement;
391
+ const isInSelectionTarget = !isUndefined(selectionTarget);
392
+ const isInTargetElement = !isPlainObject(idTargetElement);
393
+ const isSingleSelection = isInSelectionTarget && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) == activeId;
394
+ const { g } = getAttributeElement(svg, activeId);
395
+ if (targetGroup && shiftActive) {
396
+ const findById = [...componentsState, ...extraComponentsState].find((comp) => comp.id == activeId);
397
+ const currentSelection = (_f = dataElementSelectionGroupRef.current) !== null && _f !== void 0 ? _f : [];
398
+ const alreadySelected = currentSelection.some((comp) => comp.id == activeId);
399
+ let newSelection;
400
+ if (alreadySelected) {
401
+ newSelection = currentSelection.filter((comp) => comp.id != activeId);
402
+ }
403
+ else {
404
+ newSelection = [...currentSelection, findById];
405
+ }
406
+ dataElementSelectionGroupRef.current = newSelection;
407
+ }
408
+ const { x: initialXG, y: initialYG } = getTranslate(g);
409
+ const targetDragPosition = e.target.closest("circle[data-position]");
410
+ const { clientX, clientY } = e;
411
+ const hitPoint = document.elementFromPoint(clientX, clientY);
412
+ // CHECK FOR HIT ON SVG FOR SELECTION BOX
413
+ // MAKE AND UNMAKE SELECTION BOX START ------
414
+ const hadSelectionBox = ((_g = dataElementSelectionGroupRef.current) === null || _g === void 0 ? void 0 : _g.length) > 0 && !isSingleSelection;
415
+ const downInSelectionBox = hadSelectionBox && (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) !== "svg";
416
+ const downOutSelectionBox = hadSelectionBox && (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) === "svg";
417
+ const downBeforeHasSelectionBox = !downInSelectionBox &&
418
+ (hitPoint === null || hitPoint === void 0 ? void 0 : hitPoint.nodeName) === "svg" &&
419
+ activeTool === "select";
420
+ const isRotateSelectionBox = targetRotate && hadSelectionBox;
421
+ let currentRotation = 0;
422
+ if (isRotateSelectionBox) {
423
+ currentRotation = rotationSelectionRef.current;
424
+ }
425
+ //move tanpa ada selection single element dan bisa move juga ketika ada selection box
426
+ //JIKA PUNYA SELECTION TAPI DOWN DI ELEMENT LAIN
427
+ if (downInSelectionBox) {
428
+ hadSelectionRef.current = true;
429
+ }
430
+ if (downOutSelectionBox) {
431
+ hadSelectionRef.current = false;
432
+ onMoveSelectionBoxRef.current = false;
433
+ handleUnSelectComponent();
434
+ }
435
+ if (downBeforeHasSelectionBox) {
436
+ // RELEASE SELECT
437
+ releaseGroupRef.current = true;
438
+ // MAKING SELECTION BOX DOWN
439
+ onMakeSelectionRef.current = true;
440
+ onMoveSelectionBoxRef.current = false;
441
+ handleUnSelectComponent();
442
+ const boxSelection = createTableGhost({
443
+ x,
444
+ y,
445
+ width: 1,
446
+ height: 1,
447
+ fill: "transparent",
448
+ shape: nameShapeSelectionBoxGhost,
449
+ id: idSelectionBoxGhost,
450
+ });
451
+ (_h = svgRef.current) === null || _h === void 0 ? void 0 : _h.appendChild(boxSelection);
452
+ }
453
+ // MAKE AND UNMAKE SELECTION BOX END ------
454
+ // RESIZE SELECTION BOX
455
+ const resizeSide = (targetDragPosition === null || targetDragPosition === void 0 ? void 0 : targetDragPosition.dataset.position) || "{}";
456
+ const downAtResizePosition = resizeSide !== "{}";
457
+ const downOutResizePosition = resizeSide === "{}";
458
+ //down in selection box (need check element didalammnya)
459
+ const downOutResizePositionAndInSelectionBox = downOutResizePosition &&
460
+ hadSelectionBox &&
461
+ !downOutSelectionBox &&
462
+ isInSelectionTarget &&
463
+ !isSingleSelection &&
464
+ !isInTargetElement &&
465
+ !isInitialCreateBoundingBox;
466
+ const downAtResizePositionAndHasSelectionBox = downAtResizePosition &&
467
+ hadSelectionBox &&
468
+ !isRotateSelectionBox &&
469
+ !isInitialCreateBoundingBox;
470
+ const isMightResizeElement = !isEmpty(selectedComponent) &&
471
+ downAtResizePosition &&
472
+ downAtResizePosition &&
473
+ !hadSelectionBox &&
474
+ !isInitialCreateBoundingBox;
475
+ const isMightMove = activeId &&
476
+ !targetPointPolygon &&
477
+ isInTargetElement &&
478
+ !isMightResizeElement &&
479
+ !isInitialCreateBoundingBox;
480
+ const isMightMoveOneElementSelection = isSingleSelection && !isMightResizeElement && !isInitialCreateBoundingBox;
481
+ if (downOutResizePositionAndInSelectionBox) {
482
+ onMoveSelectionBoxRef.current = true;
483
+ }
484
+ if (downAtResizePosition) {
485
+ onResizeSelectionRef.current = true;
486
+ }
487
+ const offset = {
488
+ x: x - initialXG,
489
+ y: y - initialYG,
490
+ };
491
+ // create polygon
492
+ const isInitialPolyGon = activeTool === "polygon" && !isCreateElementRef.current;
493
+ if (isInitialPolyGon && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) !== "polygon") {
494
+ const newPolygon = {
495
+ id: `${Date.now()}`,
496
+ shape: "polygon",
497
+ fill: "red",
498
+ points: [{ x, y }],
499
+ rotation: 0,
500
+ };
501
+ polygonElementRef.current = newPolygon;
502
+ // addComponents(newPolygon);
503
+ setSelectedComponent(newPolygon);
504
+ dispatch({
505
+ type: "panel/setSelectedComponent",
506
+ payload: newPolygon,
507
+ });
508
+ dispatch({
509
+ type: "panel/setSelectedGroup",
510
+ payload: null,
511
+ });
512
+ isOnMakePolygonRef.current = true;
513
+ }
514
+ // const selectionLines = svgRef.current?.querySelector(
515
+ // "#selection-lines"
516
+ // ) as SVGGElement;
517
+ // const boxSelection = svgRef.current?.querySelector(
518
+ // "#rect-box-selection"
519
+ // ) as SVGRectElement;
520
+ // const allElementInSelection = svgRef.current?.querySelectorAll(
521
+ // "#ghost-element-has-selection"
522
+ // );
523
+ const pointerHandleMove = (ev) => {
524
+ var _a;
525
+ //SVG POINTER
526
+ const pt = svg.createSVGPoint();
527
+ pt.x = ev.clientX;
528
+ pt.y = ev.clientY;
529
+ const pos = pt.matrixTransform(svg.getScreenCTM().inverse());
530
+ //RESIZE POLYGON
531
+ const onResizePolygon = (pos) => {
532
+ var _a, _b;
533
+ const dx = pos.x - x;
534
+ const dy = pos.y - y;
535
+ const { inner, element } = getAttributeElement(svg, activeId);
536
+ const angleDeg = getRotation(inner.transform.baseVal); // 0–360
537
+ const angleRad = (angleDeg * Math.PI) / 180;
538
+ const cos = Math.cos(-angleRad);
539
+ const sin = Math.sin(-angleRad);
540
+ const localDx = dx * cos - dy * sin;
541
+ const localDy = dx * sin + dy * cos;
542
+ const index = Number(targetPointPolygon.getAttribute("id"));
543
+ const points = element === null || element === void 0 ? void 0 : element.getAttribute("points");
544
+ let arrayPoints = pointsStringToArray(points);
545
+ const pointsStart = (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points) || [];
546
+ arrayPoints[index] = {
547
+ x: ((_a = pointsStart[index]) === null || _a === void 0 ? void 0 : _a.x) + localDx,
548
+ y: ((_b = pointsStart[index]) === null || _b === void 0 ? void 0 : _b.y) + localDy,
549
+ };
550
+ const newPointsAttr = arrayToSvgPointsAttr(arrayPoints);
551
+ element === null || element === void 0 ? void 0 : element.setAttribute("points", newPointsAttr);
552
+ };
553
+ if (targetPointPolygon && targetGroup) {
554
+ onResizePolygon(pos);
555
+ }
556
+ //ROTATE SELECTION BOX
557
+ const onRotateSelectionBox = (pos) => {
558
+ var _a, _b, _c, _d;
559
+ const selectionLines = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#selection-lines");
560
+ const circleHelper = svg.querySelector("#circle-help");
561
+ const lineHelper = svg.querySelector("#line-help");
562
+ const inner = (_b = selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.children) === null || _b === void 0 ? void 0 : _b[0];
563
+ const x0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x) || 0;
564
+ const y0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y) || 0;
565
+ const w0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width) || 0;
566
+ const h0 = (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height) || 0;
567
+ const bbox = getGlobalBBox(svg, inner);
568
+ const cx = bbox.x + bbox.width / 2;
569
+ const cy = bbox.y + bbox.height / 2;
570
+ //start center
571
+ const dx0 = x - cx;
572
+ const dy0 = y - cy;
573
+ // ✅ ANGLE DARI CENTER
574
+ const dx = pos.x - cx;
575
+ const dy = pos.y - cy;
576
+ //start angle
577
+ const startAngle = Math.atan2(dy0, dx0);
578
+ const currentAngle = Math.atan2(dy, dx);
579
+ const newAngle = normalizeAngle(0 + ((currentAngle - startAngle) * 180) / Math.PI);
580
+ const angle = (0 * Math.PI) / 180;
581
+ // helper line
582
+ const centerX = w0 / 2;
583
+ const centerY = h0 / 2;
584
+ const cos = Math.cos(angle);
585
+ const sin = Math.sin(angle);
586
+ // GLOBAL → LOCAL
587
+ const localDx = dx * cos + dy * sin;
588
+ const localDy = -dx * sin + dy * cos;
589
+ // helper (LOCAL SPACE)
590
+ const x2 = centerX + localDx;
591
+ const y2 = centerY + localDy;
592
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x1", `${centerX}`);
593
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y1", `${centerY}`);
594
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x2", `${x2}`);
595
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y2", `${y2}`);
596
+ circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cx", `${x2}`);
597
+ circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cy", `${y2}`);
598
+ (_c = selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.children) === null || _c === void 0 ? void 0 : _c[0].setAttribute("transform", `rotate(${newAngle}, 0, 0)`);
599
+ const { tx, ty } = stabilizeRotation(x0, y0, w0, h0, 0, newAngle);
600
+ selectionLines === null || selectionLines === void 0 ? void 0 : selectionLines.setAttribute("transform", `translate(${tx}, ${ty}) `);
601
+ // ROTATE ALL ELEMENT IN SELECTION
602
+ const allID = (_d = dataElementSelectionGroupRef.current) === null || _d === void 0 ? void 0 : _d.map((el) => el.id);
603
+ const deltaAngle = newAngle - 0;
604
+ const rad = (deltaAngle * Math.PI) / 180;
605
+ const cosA = Math.cos(rad);
606
+ const sinA = Math.sin(rad);
607
+ const allGroupsAtrribute = getAttributeElements(svg, allID);
608
+ allGroupsAtrribute.forEach(({ g, inner }, i) => {
609
+ var _a;
610
+ const el = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a[i];
611
+ if (!el)
612
+ return;
613
+ const rotateBefore = normalizeAngle(el.rotation);
614
+ const ex = el.x;
615
+ const ey = el.y;
616
+ // 🔑 ROTATE AROUND SELECTION CENTER
617
+ const dx = ex - cx;
618
+ const dy = ey - cy;
619
+ const nx = cx + dx * cosA - dy * sinA;
620
+ const ny = cy + dx * sinA + dy * cosA;
621
+ g.setAttribute("data-is-rotating", "1");
622
+ inner.setAttribute("transform", `rotate(${normalizeAngle(rotateBefore + deltaAngle)}, 0, 0)`);
623
+ g.setAttribute("transform", `translate(${nx}, ${ny})`);
624
+ });
625
+ };
626
+ if (isRotateSelectionBox) {
627
+ onRotateSelectionBox(pos);
628
+ }
629
+ //RESIZE SELECTION BOX
630
+ const onResizeSelectionBox = () => {
631
+ var _a, _b;
632
+ const dx = pos.x - x;
633
+ const dy = pos.y - y;
634
+ isResizeSelectionRef.current = true;
635
+ const oldSel = {
636
+ x: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x,
637
+ y: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y,
638
+ width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
639
+ height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
640
+ };
641
+ const allID = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a.map((el) => el.id);
642
+ const allDataRealSelection = (_b = [
643
+ ...componentsState,
644
+ ...(lockBackground ? [] : extraComponentsState),
645
+ ]) === null || _b === void 0 ? void 0 : _b.filter((el) => allID.includes(el.id));
646
+ const allGroupsAttribute = getAttributeElements(svg, allID);
647
+ const resultSelection = resizeBox({
648
+ box: oldSel,
649
+ dx,
650
+ dy,
651
+ rotate: 0,
652
+ handle: resizeSide,
653
+ });
654
+ updateSelectionBox(svg, resultSelection);
655
+ const scaleX = resultSelection.width / oldSel.width;
656
+ const scaleY = resultSelection.height / oldSel.height;
657
+ allGroupsAttribute.forEach(({ g, element, seatGroup, seats }, i) => {
658
+ var _a, _b;
659
+ const activeId = JSON.parse(g === null || g === void 0 ? void 0 : g.getAttribute("data-id"));
660
+ const elementOld = allDataRealSelection === null || allDataRealSelection === void 0 ? void 0 : allDataRealSelection.find((el) => el.id == activeId);
661
+ const newWidth = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.width) * scaleX;
662
+ const newHeight = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.height) * scaleY;
663
+ // Jarak relatif element dari pojok kiri atas selection (sebelum resize)
664
+ const relativeX = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.x) - oldSel.x;
665
+ const relativeY = (elementOld === null || elementOld === void 0 ? void 0 : elementOld.y) - oldSel.y;
666
+ // Jarak relatif baru (sesudah resize)
667
+ const newX = resultSelection.x + relativeX * scaleX;
668
+ const newY = resultSelection.y + relativeY * scaleY;
669
+ const relativePoinst = ((_a = elementOld === null || elementOld === void 0 ? void 0 : elementOld.points) === null || _a === void 0 ? void 0 : _a.length) !== 0 &&
670
+ ((_b = elementOld === null || elementOld === void 0 ? void 0 : elementOld.points) === null || _b === void 0 ? void 0 : _b.map((point) => {
671
+ const { x, y } = point;
672
+ const relativeX = x - oldSel.x;
673
+ const relativeY = y - oldSel.y;
674
+ return {
675
+ x: resultSelection.x + relativeX * scaleX,
676
+ y: resultSelection.y + relativeY * scaleY,
677
+ };
678
+ }));
679
+ const newElement = {
680
+ x: newX,
681
+ y: newY,
682
+ width: newWidth,
683
+ height: newHeight,
684
+ points: relativePoinst,
685
+ };
686
+ if (seats.length !== 0) {
687
+ const seatsPositions = elementOld === null || elementOld === void 0 ? void 0 : elementOld.seatPositions;
688
+ const openSpace = elementOld === null || elementOld === void 0 ? void 0 : elementOld.openSpace;
689
+ if ((elementOld === null || elementOld === void 0 ? void 0 : elementOld.shape) === "table-seat-circle") {
690
+ resizeSeatCircle({
691
+ seatCount: elementOld === null || elementOld === void 0 ? void 0 : elementOld.seatCount,
692
+ r: 10,
693
+ openSpace,
694
+ newElement,
695
+ seats,
696
+ seatGroup,
697
+ });
698
+ }
699
+ else if ((elementOld === null || elementOld === void 0 ? void 0 : elementOld.shape) === "table-seat-square") {
700
+ resizeSeatSquare({
701
+ seatsPositions,
702
+ r: 10,
703
+ openSpace,
704
+ newElement,
705
+ seats,
706
+ seatGroup,
707
+ });
708
+ }
709
+ }
710
+ applyResizeToSvgElement(element, g, newElement);
711
+ });
712
+ };
713
+ if (downAtResizePositionAndHasSelectionBox)
714
+ onResizeSelectionBox();
715
+ //SELECTION BOX MOVE
716
+ const onMoveSelectionBox = () => {
717
+ var _a, _b;
718
+ const allID = (_a = dataElementSelectionGroupRef.current) === null || _a === void 0 ? void 0 : _a.map((el) => el.id);
719
+ const allDataRealSelection = (_b = [
720
+ ...componentsState,
721
+ ...(lockBackground ? [] : extraComponentsState),
722
+ ]) === null || _b === void 0 ? void 0 : _b.filter((el) => allID.includes(el.id));
723
+ allDataRealSelection.forEach((item) => {
724
+ const { g } = getAttributeElement(svg, item.id);
725
+ const newX = pos.x - x;
726
+ const newY = pos.y - y;
727
+ g.setAttribute("transform", `translate(${item.x + newX}, ${item.y + newY})`);
728
+ });
729
+ const newX = pos.x - x;
730
+ const newY = pos.y - y;
731
+ const selection = {
732
+ x: (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x) + newX,
733
+ y: (selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y) + newY,
734
+ width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
735
+ height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
736
+ };
737
+ updateSelectionBox(svg, selection);
738
+ updateSelectionGuides(svg, selection, {
739
+ vLeft: "v-left",
740
+ vCenter: "v-center",
741
+ vRight: "v-right",
742
+ hTop: "h-top",
743
+ hCenter: "h-center",
744
+ hBottom: "h-bottom",
745
+ });
746
+ };
747
+ if (downOutResizePositionAndInSelectionBox && !isRotateSelectionBox)
748
+ onMoveSelectionBox();
749
+ // MAKING SELECTION BOX MOVE
750
+ const onMakeSelectionBox = (ev) => {
751
+ var _a, _b;
752
+ let selectionBoxGhost = svg.querySelector("#selection-box-ghost");
753
+ const selX = Math.min(pos.x, x);
754
+ const selY = Math.min(pos.y, y);
755
+ const selW = Math.abs(pos.x - x);
756
+ const selH = Math.abs(pos.y - y);
757
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("x", String(selX));
758
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("y", String(selY));
759
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("width", String(selW));
760
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("height", String(selH));
761
+ // FIND ALL COMPONENTS INSIDE SELECTION BOX
762
+ const allGroups = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("g[data-id]");
763
+ const selLeft = selX;
764
+ const selTop = selY;
765
+ const selectedIds = [...allGroups]
766
+ .map((g) => JSON === null || JSON === void 0 ? void 0 : JSON.parse((g === null || g === void 0 ? void 0 : g.getAttribute("data-id")) || "{}"))
767
+ .filter((d) => {
768
+ const { element } = getAttributeElement(svg, d);
769
+ const box = getGlobalBBox(svg, element);
770
+ return ((box === null || box === void 0 ? void 0 : box.x) < selLeft + selW &&
771
+ (box === null || box === void 0 ? void 0 : box.x) + box.width > selLeft &&
772
+ (box === null || box === void 0 ? void 0 : box.y) < selTop + selH &&
773
+ (box === null || box === void 0 ? void 0 : box.y) + box.height > selTop);
774
+ })
775
+ .map((d) => `${d}`);
776
+ if (selectedIds.length === 0)
777
+ return;
778
+ const selectedComps = (_b = [
779
+ ...componentsState,
780
+ ...(lockBackground ? [] : extraComponentsState),
781
+ ]
782
+ .filter((c) => selectedIds.map(String).includes(String(c.id)))) === null || _b === void 0 ? void 0 : _b.map((item) => {
783
+ const { g } = getAttributeElement(svg, item.id);
784
+ // const { x, y } = getTranslate(g);
785
+ const box = getGlobalBBox(svg, g);
786
+ return Object.assign(Object.assign({}, item), {
787
+ // x: box.x,
788
+ // y: box.y,
789
+ width: box.width, height: box.height });
790
+ });
791
+ dataElementSelectionGroupRef.current = selectedComps;
792
+ };
793
+ if (downBeforeHasSelectionBox)
794
+ onMakeSelectionBox(ev);
795
+ const onCreateBoudingBox = () => {
796
+ let selectionBoxGhost = svg.querySelector("#selection-box-ghost");
797
+ const selX = Math.min(pos.x, x);
798
+ const selY = Math.min(pos.y, y);
799
+ const selW = Math.abs(pos.x - x);
800
+ const selH = Math.abs(pos.y - y);
801
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("x", String(selX));
802
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("y", String(selY));
803
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("width", String(selW));
804
+ selectionBoxGhost === null || selectionBoxGhost === void 0 ? void 0 : selectionBoxGhost.setAttribute("height", String(selH));
805
+ };
806
+ if (isInitialCreateBoundingBox) {
807
+ onCreateBoudingBox();
808
+ }
809
+ // CREATE GHOST ELEMENT ---
810
+ const onDrawNewElements = (toolElement.includes(activeTool) || activeTool === "bounding-box") &&
811
+ isCreateElementRef.current;
812
+ if (onDrawNewElements) {
813
+ const ghost = (_a = svgRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("#ghost-element-create");
814
+ if (!ghost)
815
+ return;
816
+ const data = JSON.parse(ghost.getAttribute("data-table") || "{}");
817
+ const { x: ox, y: oy } = data;
818
+ // ---- HITUNG RECT BARU ----
819
+ const x1 = Math.min(ox, pos.x);
820
+ const y1 = Math.min(oy, pos.y);
821
+ const x2 = Math.max(ox, pos.x);
822
+ const y2 = Math.max(oy, pos.y);
823
+ const newX = x1;
824
+ const newY = y1;
825
+ const newW = x2 - x1;
826
+ const newH = y2 - y1;
827
+ // ---- RECT ----
828
+ if (["square", "table-seat-circle", "bounding-box"].includes(activeTool)) {
829
+ ghost.setAttribute("x", String(newX));
830
+ ghost.setAttribute("y", String(newY));
831
+ ghost.setAttribute("width", String(newW));
832
+ ghost.setAttribute("height", String(newH));
833
+ }
834
+ // ---- CIRCLE (ambil dari bounding box) ----
835
+ if (activeTool === "circle") {
836
+ const cx = newX + newW / 2;
837
+ const cy = newY + newH / 2;
838
+ const r = Math.min(newW, newH) / 2;
839
+ ghost.setAttribute("cx", String(cx));
840
+ ghost.setAttribute("cy", String(cy));
841
+ ghost.setAttribute("r", String(r));
842
+ }
843
+ // ---- UPDATE DATA TABLE ----
844
+ ghost.setAttribute("data-table", JSON.stringify(Object.assign(Object.assign({}, data), { x: newX, y: newY, width: newW, height: newH })));
845
+ }
846
+ // RESIZE GHOST SINGLE ELEMENT ---
847
+ const onResize = () => {
848
+ var _a, _b;
849
+ const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
850
+ const svg = svgRef.current;
851
+ const { g, element, seats, seatGroup } = getAttributeElement(svg, activeId);
852
+ const elementSelect = {
853
+ x: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.x,
854
+ y: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.y,
855
+ width: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.width,
856
+ height: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.height,
857
+ seatPositions: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.seatPositions,
858
+ seatCount: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.seatCount,
859
+ openSpace: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.openSpace,
860
+ points: selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points,
861
+ };
862
+ const oldSel = {
863
+ x: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.x,
864
+ y: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.y,
865
+ width: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.width,
866
+ height: selectedLines === null || selectedLines === void 0 ? void 0 : selectedLines.height,
867
+ };
868
+ const dx = pos.x - x;
869
+ const dy = pos.y - y;
870
+ const resultSelection = resizeBox({
871
+ box: oldSel,
872
+ dx,
873
+ dy,
874
+ rotate: 0,
875
+ handle: resizeSide,
876
+ });
877
+ updateSelectionGuides(svg, resultSelection, {
878
+ vLeft: "v-left",
879
+ vCenter: "v-center",
880
+ vRight: "v-right",
881
+ hTop: "h-top",
882
+ hCenter: "h-center",
883
+ hBottom: "h-bottom",
884
+ });
885
+ updateSelectionBox(svg, resultSelection, activeId);
886
+ const scaleX = resultSelection.width / oldSel.width;
887
+ const scaleY = resultSelection.height / oldSel.height;
888
+ const newWidth = elementSelect.width * scaleX;
889
+ const newHeight = elementSelect.height * scaleY;
890
+ // Jarak relatif element dari pojok kiri atas selection (sebelum resize)
891
+ const relativeX = elementSelect.x - oldSel.x;
892
+ const relativeY = elementSelect.y - oldSel.y;
893
+ // Jarak relatif baru (sesudah resize)
894
+ const newX = resultSelection.x + relativeX * scaleX;
895
+ const newY = resultSelection.y + relativeY * scaleY;
896
+ const relativePoinst = ((_a = elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.points) === null || _a === void 0 ? void 0 : _a.length) !== 0 &&
897
+ ((_b = elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.points) === null || _b === void 0 ? void 0 : _b.map((point) => {
898
+ const { x, y } = point;
899
+ const relativeX = x - oldSel.x;
900
+ const relativeY = y - oldSel.y;
901
+ return {
902
+ x: resultSelection.x + relativeX * scaleX,
903
+ y: resultSelection.y + relativeY * scaleY,
904
+ };
905
+ }));
906
+ const newElement = {
907
+ x: newX,
908
+ y: newY,
909
+ width: newWidth,
910
+ height: newHeight,
911
+ points: relativePoinst,
912
+ };
913
+ if (seats.length !== 0) {
914
+ if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-circle") {
915
+ resizeSeatCircle({
916
+ seatCount: elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.seatCount,
917
+ r: 10,
918
+ openSpace: elementSelect === null || elementSelect === void 0 ? void 0 : elementSelect.openSpace,
919
+ newElement,
920
+ seats,
921
+ seatGroup,
922
+ });
923
+ }
924
+ else if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-square") {
925
+ resizeSeatSquare({
926
+ seatsPositions: elementSelect.seatPositions,
927
+ r: 10,
928
+ newElement,
929
+ openSpace: elementSelect.openSpace,
930
+ seats,
931
+ seatGroup,
932
+ });
933
+ }
934
+ else if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-half-square") {
935
+ resizeSeatSide({
936
+ seatsPositions: elementSelect.seatPositions,
937
+ r: 10,
938
+ newElement,
939
+ openSpace: elementSelect.openSpace,
940
+ seats,
941
+ seatGroup,
942
+ });
943
+ }
944
+ else if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-rect-square") {
945
+ resizeSeatRectSquare({
946
+ seatsPositions: elementSelect.seatPositions,
947
+ r: 10,
948
+ newElement,
949
+ openSpace: elementSelect.openSpace,
950
+ seats,
951
+ seatGroup,
952
+ });
953
+ }
954
+ else if ((selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "table-seat-rect-circle") {
955
+ resizeSeatRectCircle({
956
+ seatsPositions: elementSelect.seatPositions,
957
+ r: 10,
958
+ newElement,
959
+ openSpace: elementSelect.openSpace,
960
+ seats,
961
+ seatGroup,
962
+ });
963
+ }
964
+ }
965
+ applyResizeToSvgElement(element, g, newElement);
966
+ isResizeRef.current = true;
967
+ };
968
+ // const hasSelectedOneElement =
969
+ // !isEmpty(selectedComponent) &&
970
+ // onResizeSelectionRef.current &&
971
+ // downAtResizePosition;
972
+ if (!isEmpty(selectedComponent) && isMightResizeElement)
973
+ onResize();
974
+ //ROTATE
975
+ const onRotate = () => {
976
+ const svg = svgRef.current;
977
+ if (!svg || !selectedComponent)
978
+ return;
979
+ const lineHelper = svg.querySelector("#line-help");
980
+ const circleHelper = svg.querySelector("#circle-help");
981
+ const { inner, g } = getAttributeElement(svg, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
982
+ if (!inner || !g)
983
+ return;
984
+ // mouse → SVG space
985
+ // 🔴 GLOBAL BBOX (INI KUNCI)
986
+ const bbox = getGlobalBBox(svg, inner);
987
+ const boxSelection = getGlobalBBox(svg, g);
988
+ if (!bbox)
989
+ return;
990
+ const cx = bbox.x + bbox.width / 2;
991
+ const cy = bbox.y + bbox.height / 2;
992
+ // vector awal & sekarang (GLOBAL)
993
+ const dx0 = x - cx;
994
+ const dy0 = y - cy;
995
+ const dx = pos.x - cx;
996
+ const dy = pos.y - cy;
997
+ const startAngle = Math.atan2(dy0, dx0);
998
+ const currentAngle = Math.atan2(dy, dx);
999
+ const newAngle = (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.rotation) +
1000
+ ((currentAngle - startAngle) * 180) / Math.PI;
1001
+ // helper line
1002
+ const centerX = selectedLines.width / 2;
1003
+ const centerY = selectedLines.height / 2;
1004
+ const angle = (0 * Math.PI) / 180;
1005
+ const cos = Math.cos(angle);
1006
+ const sin = Math.sin(angle);
1007
+ // GLOBAL → LOCAL
1008
+ const localDx = dx * cos + dy * sin;
1009
+ const localDy = -dx * sin + dy * cos;
1010
+ // helper (LOCAL SPACE)
1011
+ const x2 = centerX + localDx;
1012
+ const y2 = centerY + localDy;
1013
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x1", `${centerX}`);
1014
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y1", `${centerY}`);
1015
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("x2", `${x2}`);
1016
+ lineHelper === null || lineHelper === void 0 ? void 0 : lineHelper.setAttribute("y2", `${y2}`);
1017
+ circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cx", `${x2}`);
1018
+ circleHelper === null || circleHelper === void 0 ? void 0 : circleHelper.setAttribute("cy", `${y2}`);
1019
+ // rotate di local space
1020
+ inner.setAttribute("transform", `rotate(${newAngle}, 0, 0)`);
1021
+ // stabilize translate
1022
+ const { tx, ty } = selectedComponent.shape === "polygon"
1023
+ ? stabilizeTranslateOnRotate({
1024
+ points: selectedComponentProps === null || selectedComponentProps === void 0 ? void 0 : selectedComponentProps.points,
1025
+ oldAngle: selectedComponent.rotation,
1026
+ newAngle,
1027
+ tx: selectedComponent.x,
1028
+ ty: selectedComponent.y,
1029
+ })
1030
+ : stabilizeRotation(selectedComponent.x, selectedComponent.y, selectedComponent.width, selectedComponent.height, selectedComponent.rotation, newAngle);
1031
+ g.setAttribute("transform", `translate(${tx}, ${ty})`);
1032
+ updateSelectionGuides(svg, boxSelection, {
1033
+ vLeft: "v-left",
1034
+ vCenter: "v-center",
1035
+ vRight: "v-right",
1036
+ hTop: "h-top",
1037
+ hCenter: "h-center",
1038
+ hBottom: "h-bottom",
1039
+ });
1040
+ ghostRotateElement.current = newAngle;
1041
+ updateSelectionBox(svg, boxSelection, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id, true);
1042
+ };
1043
+ if (targetRotate && !isRotateSelectionBox)
1044
+ onRotate();
1045
+ const onMove = (ev) => {
1046
+ // const selectionLines = svg.querySelector("#selection-lines");
1047
+ const dx = ev.clientX - startX;
1048
+ const dy = ev.clientY - startY;
1049
+ const distance = Math.sqrt(dx * dx + dy * dy);
1050
+ // onPanning(ev);
1051
+ if (!hasMoved && distance > 0) {
1052
+ // only move ghost if the mouse has moved more than 5 pixels
1053
+ hasMoved = true;
1054
+ }
1055
+ const newX = pos.x - offset.x;
1056
+ const newY = pos.y - offset.y;
1057
+ // let activeId = JSON.parse(targetGroup?.getAttribute("data-id") || "{}");
1058
+ const isMatchWithSelection = activeId === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
1059
+ const { g } = getAttributeElement(svg, activeId);
1060
+ const boxSelection = getGlobalBBox(svg, g);
1061
+ g === null || g === void 0 ? void 0 : g.setAttribute("transform", `translate(${newX}, ${newY})`);
1062
+ updateSelectionGuides(svg, boxSelection, {
1063
+ vLeft: "v-left",
1064
+ vCenter: "v-center",
1065
+ vRight: "v-right",
1066
+ hTop: "h-top",
1067
+ hCenter: "h-center",
1068
+ hBottom: "h-bottom",
1069
+ });
1070
+ if (isMatchWithSelection) {
1071
+ updateSelectionBox(svg, boxSelection, activeId);
1072
+ }
1073
+ };
1074
+ const moveSingleElement = (isMightMove &&
1075
+ !(!isEmpty(selectedComponent) && !isMightResizeElement) &&
1076
+ !targetRotate) ||
1077
+ (isMightMoveOneElementSelection && !isMightResizeElement) ||
1078
+ (isMightMove && !isEmpty(selectedComponent) && !isMightResizeElement);
1079
+ if (moveSingleElement) {
1080
+ onMove(ev);
1081
+ }
1082
+ };
1083
+ const pointerHandleUp = (e) => {
1084
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
1085
+ updateSelectionGuides(svg, {
1086
+ x: 0,
1087
+ y: 0,
1088
+ width: 0,
1089
+ height: 0,
1090
+ }, {
1091
+ vLeft: "v-left",
1092
+ vCenter: "v-center",
1093
+ vRight: "v-right",
1094
+ hTop: "h-top",
1095
+ hCenter: "h-center",
1096
+ hBottom: "h-bottom",
1097
+ });
1098
+ //POLYGON RESIZE
1099
+ if (targetSelection) {
1100
+ //show
1101
+ dispatch({ type: "panel/setShow", payload: true });
1102
+ }
1103
+ if (targetPointPolygon && targetGroup) {
1104
+ const { element } = getAttributeElement(svg, targetGroup.dataset.id);
1105
+ const points = element === null || element === void 0 ? void 0 : element.getAttribute("points");
1106
+ const pointsArray = pointsStringToArray(points);
1107
+ const findById = [...componentsState, ...extraComponentsState].find((c) => c.id == targetGroup.dataset.id);
1108
+ const newDataComponent = Object.assign(Object.assign({}, findById), { points: pointsArray });
1109
+ updateComponentAttribute(newDataComponent);
1110
+ setSelectedComponent(newDataComponent);
1111
+ dispatch({
1112
+ type: "panel/setSelectedComponent",
1113
+ payload: newDataComponent,
1114
+ });
1115
+ dispatch({
1116
+ type: "panel/setSelectedGroup",
1117
+ payload: null,
1118
+ });
1119
+ }
1120
+ //POLYGON
1121
+ const isInitialPolyGon = activeTool === "polygon" && (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.shape) === "polygon";
1122
+ if (isInitialPolyGon) {
1123
+ const closing = isClosingPolygon(x, y, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points);
1124
+ const newCoord = closing
1125
+ ? {
1126
+ x: (_a = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points[0]) === null || _a === void 0 ? void 0 : _a.x,
1127
+ y: (_b = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points[0]) === null || _b === void 0 ? void 0 : _b.y,
1128
+ }
1129
+ : { x, y };
1130
+ const newPoints = Object.assign(Object.assign({}, selectedComponent), { points: [...selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points, newCoord] });
1131
+ (_c = svg.querySelector("#polyline-helper")) === null || _c === void 0 ? void 0 : _c.setAttribute("opacity", "1");
1132
+ if (closing && ((_d = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points) === null || _d === void 0 ? void 0 : _d.length) > 2) {
1133
+ const { g, inner } = getAttributeElement(svg, selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id);
1134
+ const { height, width } = getGlobalBBox(svg, inner);
1135
+ isOnMakePolygonRef.current = false;
1136
+ setSelectedComponent(null);
1137
+ dispatch({
1138
+ type: "panel/setSelectedComponent",
1139
+ payload: null,
1140
+ });
1141
+ polygonElementRef.current = [];
1142
+ addComponents(Object.assign(Object.assign({}, newPoints), { x: 0, y: 0, width, height }));
1143
+ (_e = svg.querySelector("#selection-box-ghost")) === null || _e === void 0 ? void 0 : _e.remove();
1144
+ const polyline = svg.querySelector("#polyline-helper");
1145
+ (_f = svg.querySelector("#polyline-helper")) === null || _f === void 0 ? void 0 : _f.setAttribute("opacity", "0");
1146
+ }
1147
+ else {
1148
+ setSelectedComponent(newPoints);
1149
+ dispatch({
1150
+ type: "panel/setSelectedComponent",
1151
+ payload: newPoints,
1152
+ });
1153
+ dispatch({
1154
+ type: "panel/setSelectedGroup",
1155
+ payload: null,
1156
+ });
1157
+ polygonElementRef.current = newPoints;
1158
+ }
1159
+ }
1160
+ // ROTATE
1161
+ if (targetRotate && !isRotateSelectionBox) {
1162
+ const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
1163
+ const { g } = getAttributeElement(svg, activeId);
1164
+ const boxLines = getGlobalBBox(svg, g);
1165
+ const findById = [...componentsState, ...extraComponentsState].find((c) => c.id == activeId);
1166
+ const { x, y } = getTranslate(g);
1167
+ const newDataComponent = Object.assign(Object.assign({}, findById), { x,
1168
+ y, rotation: ghostRotateElement.current });
1169
+ const boxSelection = Object.assign(Object.assign(Object.assign({ shape: "selection-box", id: `${Date.now()}` }, findById), boxLines), { rotation: 0 });
1170
+ if (boxLines)
1171
+ setSelectedLines(boxSelection);
1172
+ updateComponentAttribute(newDataComponent);
1173
+ setSelectedComponent(newDataComponent);
1174
+ dispatch({
1175
+ type: "panel/setSelectedComponent",
1176
+ payload: newDataComponent,
1177
+ });
1178
+ dispatch({
1179
+ type: "panel/setSelectedGroup",
1180
+ payload: null,
1181
+ });
1182
+ //LOGIC FOR SET SHOW
1183
+ dispatch({ type: "panel/setShow", payload: false });
1184
+ }
1185
+ //CREATE NEW ELEMENT
1186
+ if (toolElement.includes(activeTool) && isCreateElementRef.current) {
1187
+ const ghostElementNew = (_g = svgRef.current) === null || _g === void 0 ? void 0 : _g.querySelector("#ghost-element-create");
1188
+ if (!ghostElementNew)
1189
+ return;
1190
+ const dataOriginal = JSON.parse(ghostElementNew.getAttribute("data-table") || "{}");
1191
+ const newComponent = Object.assign(Object.assign({ id: `${Date.now()}` }, dataOriginal), { seatCount: 4 });
1192
+ const newExtraComponent = [...extraComponentsState, newComponent];
1193
+ //ADD TO REDUX
1194
+ setExtraComponentsState(newExtraComponent);
1195
+ // setComponentsState(newComponentState);
1196
+ addComponents(newComponent);
1197
+ // syncFromLocalToRedux(newComponentState);
1198
+ //REMOVE GHOST ELEMENT
1199
+ (_h = svgRef.current) === null || _h === void 0 ? void 0 : _h.querySelectorAll("#ghost-element-create").forEach((el) => el.remove());
1200
+ isCreateElementRef.current = false;
1201
+ }
1202
+ // CREATE POLYGON
1203
+ const hasSelectedOneElement = !isEmpty(selectedComponent) &&
1204
+ onResizeSelectionRef.current &&
1205
+ downAtResizePosition;
1206
+ const idDataset = targetGroup === null || targetGroup === void 0 ? void 0 : targetGroup.dataset.id;
1207
+ const isSelectElement = !hasMoved &&
1208
+ !releaseGroupRef.current &&
1209
+ !targetRotate &&
1210
+ !hasSelectedOneElement &&
1211
+ idDataset &&
1212
+ activeTool === "select";
1213
+ if (isSelectElement) {
1214
+ //KLIK UP
1215
+ const findById = [...componentsState, ...extraComponentsState].find((component) => component.id == idDataset);
1216
+ if (!findById) {
1217
+ return;
1218
+ }
1219
+ const { g } = getAttributeElement(svg, idDataset);
1220
+ if (shiftActive) {
1221
+ const allElementSelectionGroup = dataElementSelectionGroupRef.current;
1222
+ // HITUNG BOUNDING BOX
1223
+ let xs = [];
1224
+ let ys = [];
1225
+ let x2 = [];
1226
+ let y2 = [];
1227
+ allElementSelectionGroup.forEach((element) => {
1228
+ const activeId = element.id;
1229
+ const { g } = getAttributeElement(svg, activeId);
1230
+ const { x, y, width, height } = getGlobalBBox(svg, g);
1231
+ xs.push(x);
1232
+ ys.push(y);
1233
+ x2.push(x + width);
1234
+ y2.push(y + height);
1235
+ });
1236
+ const selectionBox = {
1237
+ x: Math.min(...xs),
1238
+ y: Math.min(...ys),
1239
+ width: Math.max(...x2) - Math.min(...xs),
1240
+ height: Math.max(...y2) - Math.min(...ys),
1241
+ stroke: "red",
1242
+ shape: "selection-box",
1243
+ fill: "transparent",
1244
+ id: `${Date.now()}`,
1245
+ rotation: 0,
1246
+ };
1247
+ setSelectedLines(selectionBox);
1248
+ dispatch({
1249
+ type: "panel/setSelectedGroup",
1250
+ payload: allElementSelectionGroup,
1251
+ });
1252
+ setSelectedComponent(null);
1253
+ dispatch({
1254
+ type: "panel/setSelectedComponent",
1255
+ payload: null,
1256
+ });
1257
+ }
1258
+ else {
1259
+ dataElementSelectionGroupRef.current = [];
1260
+ const boxGroup = getGlobalBBox(svg, g);
1261
+ let boxSelection = Object.assign(Object.assign(Object.assign({}, findById), boxGroup), { shape: "selection-box", rotation: 0 });
1262
+ if ((boxSelection === null || boxSelection === void 0 ? void 0 : boxSelection.width) && (boxSelection === null || boxSelection === void 0 ? void 0 : boxSelection.height)) {
1263
+ setSelectedLines(boxSelection);
1264
+ setSelectedComponent(findById);
1265
+ dispatch({
1266
+ type: "panel/setSelectedComponent",
1267
+ payload: findById,
1268
+ });
1269
+ dispatch({
1270
+ type: "panel/setSelectedGroup",
1271
+ payload: null,
1272
+ });
1273
+ }
1274
+ }
1275
+ //LOGIC FOR SET SHOW
1276
+ dispatch({ type: "panel/setShow", payload: true });
1277
+ }
1278
+ //UPDATE DATASET TO STATE IF RESIZE
1279
+ if (isMightResizeElement) {
1280
+ const activeId = selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id;
1281
+ const svg = svgRef.current;
1282
+ const { g, element, points } = getAttributeElement(svg, activeId);
1283
+ const selectionBox = getGlobalBBox(svg, g);
1284
+ const { width, height } = getSvgElementSize(element);
1285
+ const { x, y } = getTranslate(g);
1286
+ const newSelectedComponent = Object.assign(Object.assign({}, selectedComponent), { x: x, y: y, width: width, height: height, points: points });
1287
+ const newSelection = Object.assign({ shape: "selection-box", id: `${Date.now()}` }, selectionBox);
1288
+ setSelectedLines(newSelection);
1289
+ // dragGhostRef.current = false;
1290
+ setSelectedComponent(newSelectedComponent);
1291
+ dispatch({
1292
+ type: "panel/setSelectedComponent",
1293
+ payload: newSelectedComponent,
1294
+ });
1295
+ dispatch({
1296
+ type: "panel/setSelectedGroup",
1297
+ payload: null,
1298
+ });
1299
+ updateComponentAttribute(newSelectedComponent);
1300
+ //LOGIC FOR SET SHOW
1301
+ dispatch({ type: "panel/setShow", payload: false });
1302
+ // isResizeRef.current = false;
1303
+ }
1304
+ //MAKING SELECTION BOX UP
1305
+ const isMakingSelectionBoxUp = downBeforeHasSelectionBox && activeTool === "select";
1306
+ if (isMakingSelectionBoxUp) {
1307
+ const allElementSelectionGroup = dataElementSelectionGroupRef.current;
1308
+ let xs = [];
1309
+ let ys = [];
1310
+ let x2 = [];
1311
+ let y2 = [];
1312
+ allElementSelectionGroup.forEach((element) => {
1313
+ const activeId = element.id;
1314
+ const { g, inner, element: el } = getAttributeElement(svg, activeId);
1315
+ const { x, y, width, height } = getGlobalBBox(svg, g);
1316
+ xs.push(x);
1317
+ ys.push(y);
1318
+ x2.push(x + width);
1319
+ y2.push(y + height);
1320
+ });
1321
+ const selectionBox = {
1322
+ x: Math.min(...xs),
1323
+ y: Math.min(...ys),
1324
+ width: Math.max(...x2) - Math.min(...xs),
1325
+ height: Math.max(...y2) - Math.min(...ys),
1326
+ stroke: "red",
1327
+ shape: "selection-box",
1328
+ fill: "transparent",
1329
+ id: `${Date.now()}`,
1330
+ rotation: 0,
1331
+ };
1332
+ function hasInvalidNumber(obj) {
1333
+ return Object.values(obj).some((v) => typeof v === "number" && !Number.isFinite(v));
1334
+ }
1335
+ if (!hasInvalidNumber(selectionBox)) {
1336
+ setSelectedLines(selectionBox);
1337
+ dispatch({
1338
+ type: "panel/setSelectedGroup",
1339
+ payload: allElementSelectionGroup,
1340
+ });
1341
+ }
1342
+ setSelectedComponent(null);
1343
+ dispatch({
1344
+ type: "panel/setSelectedComponent",
1345
+ payload: null,
1346
+ });
1347
+ rotationSelectionRef.current = 0;
1348
+ (_k = (_j = svgRef.current) === null || _j === void 0 ? void 0 : _j.querySelectorAll("#selection-box-ghost")) === null || _k === void 0 ? void 0 : _k.forEach((el) => el.remove());
1349
+ isCreateElementRef.current = false;
1350
+ }
1351
+ if (isInitialCreateBoundingBox) {
1352
+ const ghost = svg.querySelector("#ghost-element-create");
1353
+ const getBBox = getGlobalBBox(svg, ghost);
1354
+ dispatch({
1355
+ type: "board/setBoundingBox",
1356
+ payload: Object.assign(Object.assign({}, getBBox), { id: `${Date.now()}`, shape: "bounding-box", fill: "transparent" }),
1357
+ });
1358
+ (_m = (_l = svgRef.current) === null || _l === void 0 ? void 0 : _l.querySelectorAll("#ghost-element-create")) === null || _m === void 0 ? void 0 : _m.forEach((el) => el.remove());
1359
+ }
1360
+ if (isInitialCreateText) {
1361
+ const ghost = svg.querySelector("#ghost-element-create");
1362
+ const getBBox = getGlobalBBox(svg, ghost);
1363
+ const text = Object.assign(Object.assign({}, getBBox), { id: `${Date.now()}`, shape: "text", fill: "#000000", text: "Text", fontSize: 14 });
1364
+ addComponents(text);
1365
+ dispatch({
1366
+ type: "panel/setShow",
1367
+ payload: true,
1368
+ });
1369
+ dispatch({
1370
+ type: "panel/setSelectedComponent",
1371
+ payload: text,
1372
+ });
1373
+ (_p = (_o = svgRef.current) === null || _o === void 0 ? void 0 : _o.querySelectorAll("#ghost-element-create")) === null || _p === void 0 ? void 0 : _p.forEach((el) => el.remove());
1374
+ isCreateElementRef.current = false;
1375
+ }
1376
+ //RESIZE SELECTION BOX UP
1377
+ if (downAtResizePositionAndHasSelectionBox || isRotateSelectionBox) {
1378
+ isResizeSelectionRef.current = false;
1379
+ const results = (_q = dataElementSelectionGroupRef.current) === null || _q === void 0 ? void 0 : _q.map((item) => {
1380
+ const { g, element, inner, points } = getAttributeElement(svg, item.id);
1381
+ const { x, y } = getTranslate(g);
1382
+ const { width, height } = getSvgElementSize(element);
1383
+ const rotate = getRotation(inner.transform.baseVal);
1384
+ const selectionBox = getGlobalBBox(svg, g);
1385
+ const newDataComponent = Object.assign(Object.assign({}, item), { points,
1386
+ x,
1387
+ y,
1388
+ width,
1389
+ height, rotation: rotate });
1390
+ const newDataSelection = Object.assign(Object.assign({}, newDataComponent), { x: selectionBox.x, y: selectionBox.y, width: selectionBox.width, height: selectionBox.height, shape: "selection-box", id: `${Date.now()}`, rotate: 0 });
1391
+ return {
1392
+ newDataComponent,
1393
+ newDataSelection,
1394
+ };
1395
+ });
1396
+ const newDataComponent = results.map((r) => r.newDataComponent);
1397
+ const dataSelection = results.map((r) => r.newDataSelection);
1398
+ updateComponentsAttribute(newDataComponent);
1399
+ const newDataSelection = {
1400
+ x: Math.min(...dataSelection.map((d) => d.x)),
1401
+ y: Math.min(...dataSelection.map((d) => d.y)),
1402
+ width: Math.max(...dataSelection.map((d) => d.x + d.width)) -
1403
+ Math.min(...dataSelection.map((d) => d.x)),
1404
+ height: Math.max(...dataSelection.map((d) => d.y + d.height)) -
1405
+ Math.min(...dataSelection.map((d) => d.y)),
1406
+ shape: "selection-box",
1407
+ id: `${Date.now()}`,
1408
+ };
1409
+ dispatch({
1410
+ type: "panel/setSelectedGroup",
1411
+ payload: newDataComponent,
1412
+ });
1413
+ setSelectedComponent(null);
1414
+ dispatch({
1415
+ type: "panel/setSelectedComponent",
1416
+ payload: null,
1417
+ });
1418
+ setSelectedLines(newDataSelection);
1419
+ dataElementSelectionGroupRef.current = newDataComponent;
1420
+ hadSelectionRef.current = false;
1421
+ }
1422
+ //MOVE SELECTION BOX UP
1423
+ if (downOutResizePositionAndInSelectionBox &&
1424
+ !shiftActive &&
1425
+ !isRotateSelectionBox) {
1426
+ isResizeSelectionRef.current = false;
1427
+ const results = (_r = dataElementSelectionGroupRef.current) === null || _r === void 0 ? void 0 : _r.map((item) => {
1428
+ const { g } = getAttributeElement(svg, item.id);
1429
+ const { x, y } = getTranslate(g);
1430
+ const getBBox = getGlobalBBox(svg, g);
1431
+ const findComponent = [
1432
+ ...componentsState,
1433
+ ...extraComponentsState,
1434
+ ].find((c) => c.id == item.id);
1435
+ const newDataComponent = Object.assign(Object.assign({}, findComponent), { x,
1436
+ y });
1437
+ const newDataSelection = Object.assign({}, getBBox);
1438
+ return {
1439
+ newDataComponent,
1440
+ newDataSelection,
1441
+ };
1442
+ });
1443
+ const newDataComponent = results.map((r) => r.newDataComponent);
1444
+ const dataSelection = results.map((r) => r.newDataSelection);
1445
+ const newSelection = {
1446
+ x: Math.min(...dataSelection.map((d) => d.x)),
1447
+ y: Math.min(...dataSelection.map((d) => d.y)),
1448
+ width: Math.max(...dataSelection.map((d) => d.x + d.width)) -
1449
+ Math.min(...dataSelection.map((d) => d.x)),
1450
+ height: Math.max(...dataSelection.map((d) => d.y + d.height)) -
1451
+ Math.min(...dataSelection.map((d) => d.y)),
1452
+ };
1453
+ updateComponentsAttribute(newDataComponent);
1454
+ const newDataSelection = Object.assign(Object.assign({}, newSelection), { shape: "selection-box", id: `${Date.now()}-from-move`, rotation: 0 });
1455
+ dispatch({
1456
+ type: "panel/setSelectedGroup",
1457
+ payload: newDataComponent,
1458
+ });
1459
+ setSelectedComponent(null);
1460
+ dispatch({
1461
+ type: "panel/setSelectedComponent",
1462
+ payload: null,
1463
+ });
1464
+ setSelectedLines(newDataSelection);
1465
+ dataElementSelectionGroupRef.current = newDataComponent;
1466
+ hadSelectionRef.current = false;
1467
+ }
1468
+ //DELETE GHOST ELEMENT BISA MEMBU
1469
+ (_s = svgRef.current) === null || _s === void 0 ? void 0 : _s.querySelectorAll("#ghost-element").forEach((el) => el.remove());
1470
+ //UPDATE DATASET TO STATE IF MOVEk
1471
+ // if (releaseGroupRef.current) return;
1472
+ if ((isMightMove &&
1473
+ !isMakingSelectionBoxUp &&
1474
+ !isSelectElement &&
1475
+ !isMightResizeElement) ||
1476
+ isMightMoveOneElementSelection) {
1477
+ const findData = [...componentsState, ...extraComponentsState].find((item) => item.id == activeId);
1478
+ const { g } = getAttributeElement(svg, activeId);
1479
+ const bbox = getGlobalBBox(svg, g);
1480
+ const bboxSelection = getTranslate(g);
1481
+ const updateComponent = Object.assign(Object.assign({}, findData), { x: bboxSelection === null || bboxSelection === void 0 ? void 0 : bboxSelection.x, y: bboxSelection === null || bboxSelection === void 0 ? void 0 : bboxSelection.y });
1482
+ const selectionLines = Object.assign(Object.assign(Object.assign({}, selectedLines), bbox), { shape: "selection-box" });
1483
+ if (findData) {
1484
+ if (isSingleSelection) {
1485
+ setSelectedLines(selectionLines);
1486
+ setSelectedComponent(updateComponent);
1487
+ dispatch({
1488
+ type: "panel/updateSelectedComponent",
1489
+ payload: updateComponent,
1490
+ });
1491
+ }
1492
+ updateComponentAttribute(updateComponent);
1493
+ }
1494
+ }
1495
+ window.removeEventListener("pointermove", pointerHandleMove);
1496
+ window.removeEventListener("pointerup", pointerHandleUp);
1497
+ };
1498
+ window.addEventListener("pointermove", pointerHandleMove);
1499
+ window.addEventListener("pointerup", pointerHandleUp);
1500
+ };
1501
+ const positionRef = useRef({ x: 0, y: 0 });
1502
+ const handlePointerMove = (e) => {
1503
+ const svg = svgRef.current;
1504
+ const pt = svg.createSVGPoint();
1505
+ pt.x = e.clientX;
1506
+ pt.y = e.clientY;
1507
+ const pos = pt.matrixTransform(svg.getScreenCTM().inverse());
1508
+ // const lineHorizontal = svg?.querySelector("#line-horizontal");
1509
+ // const lineVertical = svg?.querySelector("#line-vertical");
1510
+ // lineHorizontal?.setAttribute("x1", `${-10000}`);
1511
+ // lineHorizontal?.setAttribute("x2", `${10000}`);
1512
+ // lineHorizontal?.setAttribute("y1", `${pos.y}`);
1513
+ // lineHorizontal?.setAttribute("y2", `${pos.y}`);
1514
+ // lineVertical?.setAttribute("y1", `${-10000}`);
1515
+ // lineVertical?.setAttribute("y2", `${10000}`);
1516
+ // lineVertical?.setAttribute("x1", `${pos.x}`);
1517
+ // lineVertical?.setAttribute("x2", `${pos.x}`);
1518
+ if (isOnMakePolygonRef === null || isOnMakePolygonRef === void 0 ? void 0 : isOnMakePolygonRef.current) {
1519
+ const polylineHelper = svg === null || svg === void 0 ? void 0 : svg.querySelector("#polyline-helper");
1520
+ // const startPoint =
1521
+ // selectedComponent?.points[selectedComponent?.points?.length - 1];
1522
+ const newPoints = [...selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.points, { x: pos.x, y: pos.y }];
1523
+ const points = newPoints.map((item) => `${item.x},${item.y}`).join(" ");
1524
+ polylineHelper === null || polylineHelper === void 0 ? void 0 : polylineHelper.setAttribute("points", points);
1525
+ //lin helper from start to move
1526
+ }
1527
+ };
1528
+ const handleCheckPreview = (e) => {
1529
+ const type = e.target.value;
1530
+ if (type === "type-1") {
1531
+ dispatch({
1532
+ type: "board/setTagType",
1533
+ payload: type,
1534
+ });
1535
+ }
1536
+ if (type === "type-2") {
1537
+ dispatch({
1538
+ type: "board/setTagType",
1539
+ payload: type,
1540
+ });
1541
+ }
1542
+ if (type === "default") {
1543
+ dispatch({
1544
+ type: "board/setTagType",
1545
+ payload: type,
1546
+ });
1547
+ }
1548
+ };
1549
+ return (<>
1550
+ <ModalPreview>
1551
+ <LayerView statusKey="status" loadingRender={loadingRender}/>
1552
+ <div className="flex gap-2 mt-2">
1553
+ <Radio.Group value={isShowTagType} onChange={handleCheckPreview}>
1554
+ <Radio value="default">Default</Radio>
1555
+ <Radio value="type-1">Type 1</Radio>
1556
+ <Radio value="type-2">Type 2</Radio>
1557
+ </Radio.Group>
1558
+ </div>
1559
+ </ModalPreview>
1560
+ <div className="relative w-full h-screen flex-1 overflow-hidden" ref={containerRef}>
1561
+ <div className="absolute bottom-5 left-1/2 transform -translate-x-1/2 z-10">
1562
+ <div className="flex gap-2">
1563
+ <Button icon={<ZoomIn />} onClick={handelZoomIn}/>
1564
+ <Button icon={<ZoomOut />} onClick={handleZoomOut}/>
1565
+ </div>
1566
+ </div>
1567
+ <TransformWrapper ref={transformRef}
1568
+ // limitToBounds={true}
1569
+ panning={{
1570
+ disabled: [
1571
+ "node",
1572
+ "select",
1573
+ "square",
1574
+ "circle",
1575
+ "table-seat-circle",
1576
+ "table-seat-square",
1577
+ "bounding-box",
1578
+ ].includes(activeTool),
1579
+ }}
1580
+ // centerZoomedOut={true}
1581
+ // onTransformed={handleTransformed}
1582
+ minScale={0.1} // sangat kecil = bisa zoom out jauh
1583
+ maxScale={1000} initialScale={scale} pinch={{ step: 1 }} wheel={{ disabled: true }} smooth={true} doubleClick={{ step: 1, disabled: activeTool === "select" }} disablePadding centerOnInit>
1584
+ {/* {scale !== 1 && ( */}
1585
+ {/* <div className="absolute bottom-[60px] left-1/2 transform -translate-x-1/2 z-10"> */}
1586
+ {/* {renderMiniMap()} */}
1587
+ {/* </div> */}
1588
+ {/* )} */}
1589
+ <TransformComponent wrapperStyle={{
1590
+ width: "100%",
1591
+ height: "100%",
1592
+ }} contentStyle={{ width: boardSize.width, height: boardSize.height }}>
1593
+ <svg id="workspace" ref={svgRef} width={boardSize.width} height={boardSize.height} viewBox={`${minCoords.x} ${minCoords.y} ${boardSize.width} ${boardSize.height}`} onPointerDown={handlePointerDown} onPointerMove={handlePointerMove} xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style={{
1594
+ background: backgroundColor,
1595
+ display: "block",
1596
+ cursor: activeTool === "ruler" ? "crosshair" : "auto",
1597
+ touchAction: "none",
1598
+ pointerEvents: "all",
1599
+ userSelect: "none",
1600
+ }}>
1601
+ <Layers components={[
1602
+ ...extraComponentsState,
1603
+ ...componentsState,
1604
+ polygonElementRef === null || polygonElementRef === void 0 ? void 0 : polygonElementRef.current,
1605
+ ...(!isEmpty(boundingBox) ? [boundingBox] : []),
1606
+ ]}
1607
+ // style={{
1608
+ // cursor: getCursorStyle(),
1609
+ // }}
1610
+ selectedComponent={selectedComponent} selectionLines={selectedLines} activeTool={activeTool}/>
1611
+ {/* <polygon
1612
+ points={nodes.map((n) => `${n.x},${n.y}`).join(" ")}
1613
+ fill="transparent"
1614
+ stroke="blue"
1615
+ /> */}
1616
+ {/* Nodes */}
1617
+ {/* {nodes.map((node, index) => (
1618
+ <circle
1619
+ key={index}
1620
+ cx={node.x}
1621
+ cy={node.y}
1622
+ r={10}
1623
+ fill="red"
1624
+ onMouseDown={onTouchStartLine}
1625
+ onTouchStart={onTouchStartLine}
1626
+ onTouchEnd={onTouchEndLine}
1627
+ />
1628
+ ))} */}
1629
+ {activeTool === "polygon" && (<polyline id="polyline-helper" stroke="#4a90e2" fill="transparent" strokeWidth={2}/>)}
1630
+ {activeTool === "ruler" && (<>
1631
+ <g id="horizontal-ruler">
1632
+ <rect x="0" y="0" width={window.innerWidth} height="30" fill="#e0e0e0"/>
1633
+ <g stroke="#888" font-size="10" text-anchor="middle">
1634
+ {Array.from({ length: window.innerWidth / 50 }, (_, i) => (<g key={i}>
1635
+ <line x1={i * 50} y1="0" x2={i * 50} y2="10"/>
1636
+ <text x={i * 50} y="15">
1637
+ {i * 50}
1638
+ </text>
1639
+ </g>))}
1640
+ </g>
1641
+ </g>
1642
+ <g id="vertical-ruler">
1643
+ <rect x="0" y="0" width="30" height={window.innerHeight} fill="#e0e0e0"/>
1644
+ <g stroke="#888" font-size="10" text-anchor="middle">
1645
+ {Array.from({ length: window.innerHeight / 10 }, (_, i) => (<g key={i}>
1646
+ <line x1="0" y1={i * 50} x2="10" y2={i * 50}/>
1647
+ <text x="15" y={i * 50}>
1648
+ {i * 50}
1649
+ </text>
1650
+ </g>))}
1651
+ </g>
1652
+ </g>
1653
+ </>)}
1654
+ {grid && (<g stroke="#ddd" strokeWidth={0.5}>
1655
+ {/* Vertical lines */}
1656
+ {Array.from({ length: widthBoard / (10 * scale) }, (_, i) => (<line key={`v-${i}`} x1={i * 10 * scale} y1={0} x2={i * 10 * scale} y2={heightBoard / scale}/>))}
1657
+
1658
+ {/* Horizontal lines */}
1659
+ {Array.from({ length: heightBoard / (10 * scale) }, (_, i) => (<line key={`h-${i}`} x1={0} y1={i * 10 * scale} x2={widthBoard / scale} y2={i * 10 * scale}/>))}
1660
+ </g>)}
1661
+ <g id="selection-guides" stroke="#4A90E2" strokeWidth={1} pointerEvents="none">
1662
+ {/* vertical */}
1663
+ <line id="v-left"/>
1664
+ <line id="v-center"/>
1665
+ <line id="v-right"/>
1666
+
1667
+ {/* horizontal */}
1668
+ <line id="h-top"/>
1669
+ <line id="h-center"/>
1670
+ <line id="h-bottom"/>
1671
+ </g>
1672
+ </svg>
1673
+ </TransformComponent>
1674
+ </TransformWrapper>
1675
+ </div>
1676
+ </>);
1677
+ };
1678
+ export default BoardTemplate;