seat-editor 3.4.7 → 3.5.0

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 (108) hide show
  1. package/dist/app/constant.d.ts +1 -1
  2. package/dist/app/graph-view/page.d.ts +1 -0
  3. package/dist/app/graph-view/page.js +343 -0
  4. package/dist/app/graph-view/page.jsx +445 -0
  5. package/dist/app/graph-view-new/constant.d.ts +581 -0
  6. package/dist/app/graph-view-new/constant.js +6973 -0
  7. package/dist/app/graph-view-new/page.d.ts +1 -0
  8. package/dist/app/graph-view-new/page.js +71 -0
  9. package/dist/app/graph-view-new/page.jsx +98 -0
  10. package/dist/app/new-board/page.js +43 -7
  11. package/dist/app/new-board/page.jsx +45 -12
  12. package/dist/components/button-tools/index.js +7 -5
  13. package/dist/components/button-tools/index.jsx +21 -9
  14. package/dist/components/form-tools/label.js +9 -20
  15. package/dist/components/form-tools/label.jsx +38 -28
  16. package/dist/components/form-tools/shape.js +5 -5
  17. package/dist/components/form-tools/shape.jsx +8 -8
  18. package/dist/components/layer-v3/index.js +44 -3
  19. package/dist/components/layer-v3/index.jsx +120 -3
  20. package/dist/components/layer-v4/index.js +3 -2
  21. package/dist/components/layer-v4/index.jsx +3 -2
  22. package/dist/components/layer-v5/constant.d.ts +60 -0
  23. package/dist/components/layer-v5/constant.js +93 -0
  24. package/dist/components/layer-v5/index.d.ts +24 -0
  25. package/dist/components/layer-v5/index.js +927 -0
  26. package/dist/components/layer-v5/index.jsx +1049 -0
  27. package/dist/features/board-v3/index.js +350 -72
  28. package/dist/features/board-v3/index.jsx +369 -75
  29. package/dist/features/board-v3/resize-element.js +5 -0
  30. package/dist/features/board-v3/utils.d.ts +8 -0
  31. package/dist/features/board-v3/utils.js +23 -7
  32. package/dist/features/package/index.d.ts +2 -0
  33. package/dist/features/package/index.js +1 -1
  34. package/dist/features/package/index.jsx +6 -1
  35. package/dist/features/panel/index.d.ts +8 -0
  36. package/dist/features/panel/index.js +160 -38
  37. package/dist/features/panel/index.jsx +173 -46
  38. package/dist/features/panel/polygon.d.ts +2 -0
  39. package/dist/features/panel/polygon.js +44 -0
  40. package/dist/features/panel/polygon.jsx +70 -0
  41. package/dist/features/panel/select-tool.js +3 -0
  42. package/dist/features/panel/select-tool.jsx +3 -0
  43. package/dist/features/panel/selected-group.js +24 -26
  44. package/dist/features/panel/selected-group.jsx +56 -51
  45. package/dist/features/panel/text-tool.js +17 -2
  46. package/dist/features/panel/text-tool.jsx +19 -2
  47. package/dist/features/panel/upload-tool.js +17 -3
  48. package/dist/features/panel/upload-tool.jsx +23 -4
  49. package/dist/features/side-tool/index.js +43 -6
  50. package/dist/features/side-tool/index.jsx +47 -10
  51. package/dist/features/view-only-4/connect-handle.d.ts +13 -0
  52. package/dist/features/view-only-4/connect-handle.js +23 -0
  53. package/dist/features/view-only-4/connect-handle.jsx +30 -0
  54. package/dist/features/view-only-4/connection-layer.d.ts +21 -0
  55. package/dist/features/view-only-4/connection-layer.js +219 -0
  56. package/dist/features/view-only-4/connection-layer.jsx +291 -0
  57. package/dist/features/view-only-4/index.d.ts +99 -0
  58. package/dist/features/view-only-4/index.js +684 -0
  59. package/dist/features/view-only-4/index.jsx +722 -0
  60. package/dist/features/view-only-4/integration-guide.d.ts +0 -0
  61. package/dist/features/view-only-4/integration-guide.js +0 -0
  62. package/dist/features/view-only-4/use-connection-graph.d.ts +41 -0
  63. package/dist/features/view-only-4/use-connection-graph.js +182 -0
  64. package/dist/features/view-only-4/utils.d.ts +74 -0
  65. package/dist/features/view-only-4/utils.js +106 -0
  66. package/dist/features/view-only-5/connect-handle.d.ts +30 -0
  67. package/dist/features/view-only-5/connect-handle.js +88 -0
  68. package/dist/features/view-only-5/connect-handle.jsx +96 -0
  69. package/dist/features/view-only-5/connection-layer.d.ts +34 -0
  70. package/dist/features/view-only-5/connection-layer.js +182 -0
  71. package/dist/features/view-only-5/connection-layer.jsx +265 -0
  72. package/dist/features/view-only-5/index.d.ts +102 -0
  73. package/dist/features/view-only-5/index.js +585 -0
  74. package/dist/features/view-only-5/index.jsx +614 -0
  75. package/dist/features/view-only-5/use-connection-graph.d.ts +57 -0
  76. package/dist/features/view-only-5/use-connection-graph.js +196 -0
  77. package/dist/features/view-only-5/utils.d.ts +52 -0
  78. package/dist/features/view-only-5/utils.js +80 -0
  79. package/dist/features/view-only-6/connect-handle.d.ts +13 -0
  80. package/dist/features/view-only-6/connect-handle.js +20 -0
  81. package/dist/features/view-only-6/connect-handle.jsx +21 -0
  82. package/dist/features/view-only-6/connection-layer.d.ts +22 -0
  83. package/dist/features/view-only-6/connection-layer.js +191 -0
  84. package/dist/features/view-only-6/connection-layer.jsx +244 -0
  85. package/dist/features/view-only-6/index.d.ts +99 -0
  86. package/dist/features/view-only-6/index.js +687 -0
  87. package/dist/features/view-only-6/index.jsx +724 -0
  88. package/dist/features/view-only-6/use-connection-graph.d.ts +26 -0
  89. package/dist/features/view-only-6/use-connection-graph.js +103 -0
  90. package/dist/features/view-only-6/utils.d.ts +66 -0
  91. package/dist/features/view-only-6/utils.js +96 -0
  92. package/dist/features/view-only-7/connect-handle.d.ts +13 -0
  93. package/dist/features/view-only-7/connect-handle.js +23 -0
  94. package/dist/features/view-only-7/connect-handle.jsx +30 -0
  95. package/dist/features/view-only-7/connection-layer.d.ts +22 -0
  96. package/dist/features/view-only-7/connection-layer.js +165 -0
  97. package/dist/features/view-only-7/connection-layer.jsx +217 -0
  98. package/dist/features/view-only-7/index.d.ts +99 -0
  99. package/dist/features/view-only-7/index.js +687 -0
  100. package/dist/features/view-only-7/index.jsx +724 -0
  101. package/dist/features/view-only-7/use-connection-graph.d.ts +26 -0
  102. package/dist/features/view-only-7/use-connection-graph.js +104 -0
  103. package/dist/features/view-only-7/utils.d.ts +69 -0
  104. package/dist/features/view-only-7/utils.js +144 -0
  105. package/dist/index.d.ts +2 -1
  106. package/dist/index.js +2 -1
  107. package/dist/seat-editor.css +1 -1
  108. package/package.json +1 -1
@@ -0,0 +1,1049 @@
1
+ "use client";
2
+ import { isEmpty, omit } from "lodash";
3
+ import { arcByDirection, distributeWithSpacing } from "../layer-v3/utils";
4
+ import { PRIVILEGED_TAGS, tagsDummy } from "./constant";
5
+ import { useAppSelector } from "../../hooks/use-redux";
6
+ import { RsvpIcons } from "../../features/board-v3/icons";
7
+ const toKebabCase = (str) => str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
8
+ const iconNames = [
9
+ "upcoming",
10
+ "late",
11
+ "overtime",
12
+ "overlapping",
13
+ "hold",
14
+ "reserved",
15
+ "armchair",
16
+ "cheque",
17
+ "people",
18
+ ];
19
+ const dummyIconTags = iconNames === null || iconNames === void 0 ? void 0 : iconNames.map((item) => {
20
+ const Icon = RsvpIcons === null || RsvpIcons === void 0 ? void 0 : RsvpIcons[item];
21
+ return {
22
+ key: item,
23
+ icon: <Icon />,
24
+ };
25
+ });
26
+ const getIconFromId = (data) => {
27
+ const id = String(data);
28
+ let hash = 0;
29
+ for (let i = 0; i < id.length; i++) {
30
+ hash += id.charCodeAt(i);
31
+ }
32
+ return iconNames[hash % iconNames.length];
33
+ };
34
+ const Layers = ({ components, selectedTable, iconTags, eventMatchTable, onHighlightGroup, onForceRestoreGroup, selectedTableColor, privilegedTags = [], }) => {
35
+ const { isShowTagType } = useAppSelector((state) => state.board);
36
+ const showLabels = !["type-1", "type-2"].includes(isShowTagType) && !iconTags;
37
+ const renderShape = (item) => {
38
+ var _a, _b, _c, _d, _e, _f, _g;
39
+ const { id, x, y, width, height, fill, opacity, rotate = 0, rotation, shape, text, stroke, strokeWidth, labels, fontSize, fontColor, seatFill, src, tags, gapTags, label, points, seatPositions, radius, } = item;
40
+ const fontSizeFromLabel = (_a = labels === null || labels === void 0 ? void 0 : labels[0]) === null || _a === void 0 ? void 0 : _a.fontSize;
41
+ const renderTags = (data) => {
42
+ var _a;
43
+ const tags = data !== null && data !== void 0 ? data : tagsDummy(((_a = labels === null || labels === void 0 ? void 0 : labels[0]) === null || _a === void 0 ? void 0 : _a.label) || "Table", getIconFromId(id));
44
+ const privileged = !isEmpty(privilegedTags)
45
+ ? privilegedTags
46
+ : isShowTagType === "type-1"
47
+ ? PRIVILEGED_TAGS["CURRENT_TIME"]
48
+ : isShowTagType === "type-2"
49
+ ? PRIVILEGED_TAGS["NEXT_3_RESERVATION"]
50
+ : undefined;
51
+ if (tags && (tags === null || tags === void 0 ? void 0 : tags.length) > 0) {
52
+ const scaleDefault = Number(fontSize || fontSizeFromLabel || 12) / 12;
53
+ const gapBetweenTags = Number(gapTags || 20) * scaleDefault;
54
+ const defaultFontSize = Number(fontSize || fontSizeFromLabel || 12);
55
+ // Hitung total tinggi semua grup tag (buat center vertikal)
56
+ const totalTagHeight = (tags === null || tags === void 0 ? void 0 : tags.filter((tag) => privileged === null || privileged === void 0 ? void 0 : privileged.find((p) => p.key === tag.key)).reduce((sum, tag) => {
57
+ var _a;
58
+ const items = tag.items || [];
59
+ const isColumn = (_a = tag.direction) === null || _a === void 0 ? void 0 : _a.includes("column");
60
+ const tagHeight = isColumn
61
+ ? items.length * defaultFontSize + 2 * (Number(tag.gap) || 2)
62
+ : defaultFontSize; // horizontal = 1 line
63
+ return sum + tagHeight + gapBetweenTags;
64
+ }, 0)) - gapBetweenTags;
65
+ const startY = Number(height) / 4 - totalTagHeight / 3; // titik awal supaya semua di tengah
66
+ let currentY = startY;
67
+ return tags
68
+ .filter((tag) => privileged === null || privileged === void 0 ? void 0 : privileged.find((p) => p.key === tag.key))
69
+ .map((tag, tagIndex) => {
70
+ var _a;
71
+ const itemsPriv = privileged[tagIndex].items;
72
+ const direction = ((_a = tag.direction) === null || _a === void 0 ? void 0 : _a.includes("column"))
73
+ ? "column"
74
+ : "flex";
75
+ const gap = Number(tag.gap || 2) * scaleDefault;
76
+ const items = tag.items || [];
77
+ const fontSize = Number(defaultFontSize);
78
+ const isColumn = direction === "column";
79
+ const groupHeight = isColumn
80
+ ? items.length * fontSize + 2 * gap
81
+ : fontSize;
82
+ const centerX = width / 2;
83
+ const centerY = currentY + groupHeight;
84
+ // naikkan posisi Y untuk grup berikutnya
85
+ currentY += groupHeight + gapBetweenTags;
86
+ const elements = items
87
+ .filter((item) => itemsPriv.includes(item.type))
88
+ .map((item, i) => {
89
+ var _a, _b;
90
+ const offsetY = isColumn
91
+ ? i * (fontSize + gap) - groupHeight / 2 + fontSize / 2
92
+ : 0;
93
+ const offsetX = !isColumn
94
+ ? i * (fontSize + gap) - (1 * (fontSize + gap)) / 2
95
+ : 0;
96
+ const posX = centerX + offsetX + Number((_a = tag.offsetX) !== null && _a !== void 0 ? _a : 0);
97
+ const posY = centerY + offsetY + Number((_b = tag.offsetY) !== null && _b !== void 0 ? _b : 0);
98
+ const renderSymbol = (symbol) => {
99
+ if (!symbol)
100
+ return null;
101
+ const { position = "right", size = (item === null || item === void 0 ? void 0 : item.fontSize) || Number(fontSize), gap: symbolGap = 0, } = symbol;
102
+ const sizeFont = (item === null || item === void 0 ? void 0 : item.fontSize) || Number(fontSize) / 3;
103
+ let offsetSymbolX = 0;
104
+ let offsetSymbolY = 0;
105
+ switch (position) {
106
+ case "right":
107
+ offsetSymbolX = size + symbolGap;
108
+ break;
109
+ case "left":
110
+ offsetSymbolX = -(size + symbolGap);
111
+ break;
112
+ case "top":
113
+ offsetSymbolY = -(size + symbolGap);
114
+ break;
115
+ case "bottom":
116
+ offsetSymbolY = size + symbolGap;
117
+ break;
118
+ case "right-top":
119
+ offsetSymbolX = size + symbolGap;
120
+ offsetSymbolY = -(size / 4);
121
+ break;
122
+ case "right-bottom":
123
+ offsetSymbolX = size + symbolGap;
124
+ offsetSymbolY = size / 4;
125
+ break;
126
+ case "left-top":
127
+ offsetSymbolX = -size - symbolGap;
128
+ offsetSymbolY = -(size / 4);
129
+ break;
130
+ case "left-bottom":
131
+ offsetSymbolX = -size - symbolGap;
132
+ offsetSymbolY = size / 4;
133
+ break;
134
+ }
135
+ return (<tspan {...symbol} key={`symbol-${tagIndex}-${i}`} x={posX + offsetSymbolX} y={posY + offsetSymbolY} textAnchor="middle" dominantBaseline="middle" fontSize={`${sizeFont}px`}>
136
+ {symbol.value}
137
+ </tspan>);
138
+ };
139
+ if (item.type === "icon") {
140
+ const icons = iconTags !== null && iconTags !== void 0 ? iconTags : dummyIconTags;
141
+ const iconTag = icons === null || icons === void 0 ? void 0 : icons.find((icon) => icon.key === item.value);
142
+ if (!iconTag)
143
+ return null;
144
+ const scale = defaultFontSize / 12;
145
+ return (<g {...item} key={`icon-${tagIndex}-${i}`} transform={`translate(${posX - defaultFontSize}, ${posY - defaultFontSize / 2}) scale(${scale})`}>
146
+ {iconTag.icon}
147
+ </g>);
148
+ }
149
+ if (item.type === "text") {
150
+ return (<text {...item} key={`text-${tagIndex}-${i}`} x={posX} y={posY} textAnchor="middle" dominantBaseline="middle" fontSize={defaultFontSize}>
151
+ {item.value} {renderSymbol(item === null || item === void 0 ? void 0 : item.symbol)}
152
+ </text>);
153
+ }
154
+ return null;
155
+ });
156
+ return (<g key={`group-${tagIndex}`} pointerEvents="none">
157
+ {elements}
158
+ </g>);
159
+ });
160
+ }
161
+ };
162
+ let commonProps = {
163
+ fill,
164
+ opacity,
165
+ stroke,
166
+ strokeWidth,
167
+ };
168
+ const hasSelected = (selectedTable === null || selectedTable === void 0 ? void 0 : selectedTable.id) === id;
169
+ if (hasSelected) {
170
+ const eventSelectedStyles = eventMatchTable === null || eventMatchTable === void 0 ? void 0 : eventMatchTable.find((style) => style.event === "selected");
171
+ commonProps = Object.assign(Object.assign({}, commonProps), eventSelectedStyles === null || eventSelectedStyles === void 0 ? void 0 : eventSelectedStyles.properties);
172
+ }
173
+ // helper: highlight / unhighlight dengan enter-counter
174
+ let properties = {};
175
+ const highlightGroup = (group, eventType) => {
176
+ if (!group)
177
+ return;
178
+ onHighlightGroup === null || onHighlightGroup === void 0 ? void 0 : onHighlightGroup(group, eventType);
179
+ eventMatchTable === null || eventMatchTable === void 0 ? void 0 : eventMatchTable.forEach((styleConfig) => {
180
+ if (styleConfig.event === eventType) {
181
+ properties = omit(styleConfig.properties || {}, "points");
182
+ const hasStroke = (properties === null || properties === void 0 ? void 0 : properties.stroke) || (commonProps === null || commonProps === void 0 ? void 0 : commonProps.stroke);
183
+ const hasStrokeWidth = properties === null || properties === void 0 ? void 0 : properties.strokeWidth;
184
+ if (hasStrokeWidth && !hasStroke) {
185
+ properties.stroke = "#E1E3EA";
186
+ }
187
+ }
188
+ });
189
+ if (isEmpty(properties))
190
+ return;
191
+ // counter
192
+ const count = Number(group.dataset.dragEnterCount || "0") + 1;
193
+ group.dataset.dragEnterCount = String(count);
194
+ // selalu ubah warna, tapi simpan original hanya sekali
195
+ ["rect", "circle"].forEach((selector) => {
196
+ const el = group.querySelector(selector);
197
+ if (!el)
198
+ return;
199
+ Object.entries(properties).forEach(([key]) => {
200
+ el.dataset[key] = el.getAttribute(key) || "";
201
+ });
202
+ Object.entries(properties).forEach(([key, value]) => {
203
+ el.setAttribute(toKebabCase(key), value);
204
+ });
205
+ });
206
+ };
207
+ const unhighlightGroup = (group) => {
208
+ if (!group)
209
+ return;
210
+ const count = Math.max(0, Number(group.dataset.dragEnterCount || "0") - 1);
211
+ group.dataset.dragEnterCount = String(count);
212
+ // restore hanya saat counter = 0
213
+ if (count === 0) {
214
+ ["rect", "circle"].forEach((selector) => {
215
+ const el = group.querySelector(selector);
216
+ if (!el)
217
+ return;
218
+ // bersihkan data
219
+ const dataset = el.dataset;
220
+ Object.entries(dataset).forEach(([key, value]) => {
221
+ el.setAttribute(toKebabCase(key), value);
222
+ delete el.dataset[key];
223
+ properties = {};
224
+ });
225
+ });
226
+ delete group.dataset.dragEnterCount;
227
+ }
228
+ };
229
+ const forceRestoreGroup = (group, type) => {
230
+ // langsung restore (dipanggil pada drop)
231
+ onForceRestoreGroup === null || onForceRestoreGroup === void 0 ? void 0 : onForceRestoreGroup(group, type);
232
+ ["rect", "circle"].forEach((selector) => {
233
+ const el = group === null || group === void 0 ? void 0 : group.querySelector(selector);
234
+ if (!el)
235
+ return;
236
+ const dataset = el.dataset;
237
+ Object.entries(dataset).forEach(([key, value]) => {
238
+ el.setAttribute(toKebabCase(key), value);
239
+ delete el.dataset[key];
240
+ properties = {};
241
+ });
242
+ });
243
+ delete group.dataset.dragEnterCount;
244
+ };
245
+ const transformRotate = `rotate(${rotate} ${x + width / 2} ${y + height / 2})`;
246
+ switch (shape) {
247
+ case "square":
248
+ return (<g key={id} id={`${id}`} data-id={id} transform={`translate(${x}, ${y})`} style={{ pointerEvents: "all" }} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
249
+ const group = e.currentTarget;
250
+ highlightGroup(group, "dragenter");
251
+ }} onDragOver={(e) => {
252
+ e.preventDefault(); // agar drop diterima
253
+ }} onDragLeave={(e) => {
254
+ const group = e.currentTarget;
255
+ unhighlightGroup(group);
256
+ }} onDrop={(e) => {
257
+ const group = e.currentTarget;
258
+ // restore langsung dan reset
259
+ forceRestoreGroup(group, "drop");
260
+ }} onPointerOver={(e) => {
261
+ // e.preventDefault(); // penting
262
+ const group = e.currentTarget;
263
+ highlightGroup(group, "pointerover");
264
+ }} onPointerOut={(e) => {
265
+ const group = e.currentTarget;
266
+ unhighlightGroup(group);
267
+ }} onPointerUp={(e) => {
268
+ const group = e.currentTarget;
269
+ // restore langsung dan reset
270
+ forceRestoreGroup(group, "pointerup");
271
+ }} onPointerDown={(e) => {
272
+ const group = e.currentTarget;
273
+ highlightGroup(group, "pointerdown");
274
+ }}
275
+ // onPointerEnter={(e) => {
276
+ // const group = e.currentTarget as SVGGElement;
277
+ // highlightGroup(group, "pointerenter");
278
+ // }}
279
+ onPointerLeave={(e) => {
280
+ const group = e.currentTarget;
281
+ unhighlightGroup(group);
282
+ }} onMouseEnter={(e) => {
283
+ // e.preventDefault(); // penting
284
+ const group = e.currentTarget;
285
+ highlightGroup(group, "mouseenter");
286
+ }} onMouseLeave={(e) => {
287
+ const group = e.currentTarget;
288
+ unhighlightGroup(group);
289
+ }}>
290
+ <g transform={`rotate(${rotation}, 0,0)`}>
291
+ <rect key={`${id}-rect`} width={width} height={height} fill={fill} rx={radius} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])} {...commonProps}/>
292
+ {renderTags(tags)}
293
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`} pointerEvents="none">
294
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
295
+ var _a, _b, _c, _d, _e, _f, _g;
296
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
297
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
298
+ return (<text pointerEvents="none" {...omit(commonProps, [
299
+ "opacity",
300
+ "stroke",
301
+ "strokeWidth",
302
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
303
+ {_ === null || _ === void 0 ? void 0 : _.label}
304
+ </text>);
305
+ })}
306
+ </g>)}
307
+ </g>
308
+ </g>);
309
+ case "polygon":
310
+ const finalPoint = points.map((p) => `${p.x},${p.y}`).join(" ");
311
+ return (<g key={id} data-id={id} transform={`translate(${x}, ${y})`}>
312
+ <g transform={`rotate(${rotation}, 0, 0)`}>
313
+ <polygon {...commonProps} key={id} points={finalPoint} x="0" y="0"/>
314
+ </g>
315
+ </g>);
316
+ case "circle":
317
+ return (<g key={id} style={{ pointerEvents: "all" }} data-id={id} transform={`translate(${x}, ${y})`} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
318
+ e.preventDefault(); // penting
319
+ const group = e.currentTarget;
320
+ highlightGroup(group, "dragenter");
321
+ }} onDragOver={(e) => {
322
+ e.preventDefault(); // agar drop diterima
323
+ }} onDragLeave={(e) => {
324
+ const group = e.currentTarget;
325
+ unhighlightGroup(group);
326
+ }} onDrop={(e) => {
327
+ e.preventDefault();
328
+ const group = e.currentTarget;
329
+ // restore langsung dan reset
330
+ forceRestoreGroup(group);
331
+ }} onPointerOver={(e) => {
332
+ e.preventDefault(); // penting
333
+ const group = e.currentTarget;
334
+ highlightGroup(group, "pointerover");
335
+ }} onPointerOut={(e) => {
336
+ const group = e.currentTarget;
337
+ unhighlightGroup(group);
338
+ }} onPointerUp={(e) => {
339
+ e.preventDefault();
340
+ const group = e.currentTarget;
341
+ // restore langsung dan reset
342
+ forceRestoreGroup(group);
343
+ }} onMouseDown={(e) => {
344
+ e.preventDefault();
345
+ const group = e.currentTarget;
346
+ highlightGroup(group, "mousedown");
347
+ }} onMouseEnter={(e) => {
348
+ // e.preventDefault(); // penting
349
+ const group = e.currentTarget;
350
+ highlightGroup(group, "mouseenter");
351
+ }} onMouseLeave={(e) => {
352
+ const group = e.currentTarget;
353
+ unhighlightGroup(group);
354
+ }}>
355
+ {" "}
356
+ <g transform={`rotate(${-rotation}, 0, 0)`}>
357
+ <circle key={id} cx={width / 2} cy={height / 2} r={Math.min(height, width) / 2} fill={fill} {...commonProps} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])}/>
358
+ {renderTags(tags)}
359
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
360
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
361
+ var _a, _b, _c, _d, _e, _f, _g;
362
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
363
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
364
+ return (<text {...omit(commonProps, [
365
+ "opacity",
366
+ "stroke",
367
+ "strokeWidth",
368
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
369
+ {_ === null || _ === void 0 ? void 0 : _.label}
370
+ </text>);
371
+ })}
372
+ </g>)}
373
+ </g>
374
+ </g>);
375
+ case "table-seat-circle": {
376
+ const seatCount = item.seatCount;
377
+ const openSpace = (_b = item.openSpace) !== null && _b !== void 0 ? _b : 0;
378
+ // LOCAL SPACE (tanpa x,y)
379
+ const centerX = width / 2;
380
+ const centerY = height / 2;
381
+ // meja
382
+ const tableRadius = Math.min(width, height) / 2;
383
+ // seat statis
384
+ const seatRadius = 10;
385
+ const fullAngle = Math.PI * 2;
386
+ const availableAngle = fullAngle * (1 - openSpace);
387
+ const angleStart = (fullAngle - availableAngle) / 2;
388
+ const angleStep = availableAngle / seatCount;
389
+ const seatCircles = Array.from({ length: seatCount }, (_, i) => {
390
+ const angle = angleStart + i * angleStep;
391
+ const cx = centerX + (tableRadius + seatRadius) * Math.cos(angle);
392
+ const cy = centerY + (tableRadius + seatRadius) * Math.sin(angle);
393
+ return { cx, cy };
394
+ });
395
+ return (<g key={id} style={{ pointerEvents: "all" }} data-id={id} id={`${id}`} transform={`translate(${x}, ${y})`} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
396
+ e.preventDefault(); // penting
397
+ const group = e.currentTarget;
398
+ highlightGroup(group, "dragenter");
399
+ }} onDragOver={(e) => {
400
+ e.preventDefault(); // agar drop diterima
401
+ }} onDragLeave={(e) => {
402
+ const group = e.currentTarget;
403
+ unhighlightGroup(group);
404
+ }} onDrop={(e) => {
405
+ e.preventDefault();
406
+ const group = e.currentTarget;
407
+ // restore langsung dan reset
408
+ forceRestoreGroup(group);
409
+ }} onPointerOver={(e) => {
410
+ e.preventDefault(); // penting
411
+ const group = e.currentTarget;
412
+ highlightGroup(group, "pointerover");
413
+ }} onPointerOut={(e) => {
414
+ const group = e.currentTarget;
415
+ unhighlightGroup(group);
416
+ }} onPointerUp={(e) => {
417
+ e.preventDefault();
418
+ const group = e.currentTarget;
419
+ // restore langsung dan reset
420
+ forceRestoreGroup(group);
421
+ }} onMouseDown={(e) => {
422
+ e.preventDefault();
423
+ const group = e.currentTarget;
424
+ highlightGroup(group, "mousedown");
425
+ }} onMouseEnter={(e) => {
426
+ // e.preventDefault(); // penting
427
+ const group = e.currentTarget;
428
+ highlightGroup(group, "mouseenter");
429
+ }} onMouseLeave={(e) => {
430
+ const group = e.currentTarget;
431
+ unhighlightGroup(group);
432
+ }}>
433
+ <g transform={`rotate(${rotation}, 0, 0)`}>
434
+ <circle cx={centerX} cy={centerY} r={tableRadius} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])} {...commonProps}/>
435
+ <g data-seat={`${id}-seats`}>
436
+ {seatCircles.map(({ cx, cy }, i) => (<circle key={`${id}-seat-${i}`} cx={cx} cy={cy} r={seatRadius} fill={seatFill} className={item === null || item === void 0 ? void 0 : item.className}/>))}
437
+ </g>
438
+
439
+ {renderTags(tags)}
440
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
441
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
442
+ var _a, _b, _c, _d;
443
+ return (<text key={`${id}-label-${index}`} x={width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={transformRotate}>
444
+ {_ === null || _ === void 0 ? void 0 : _.label}
445
+ </text>);
446
+ })}
447
+ </g>)}
448
+ </g>
449
+ </g>);
450
+ }
451
+ case "table-seat-rect-circle": {
452
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
453
+ const base = clamp(Math.min(width, height) * 0.08, 12, 28);
454
+ const tableRadius = Math.min(width, height) / 2;
455
+ const seatSizeTB = {
456
+ w: base * 1.8, // lebih panjang
457
+ h: base * 0.9, // lebih tipis
458
+ };
459
+ const seatSizeLR = {
460
+ w: base * 0.9, // lebih tipis
461
+ h: base * 1.8, // lebih panjang
462
+ };
463
+ const openSpace = item.openSpace || 0;
464
+ const seatRadius = Math.min(width, height) * 0.2;
465
+ const top = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.top) || 0;
466
+ const right = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.right) || 0;
467
+ const bottom = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.bottom) || 0;
468
+ const left = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.left) || 0;
469
+ // split seats evenly on top and bottom
470
+ const seatCountTopBottom = Math.ceil(Math.max(top, bottom) / 2);
471
+ const seatCountLeftRight = Math.ceil(Math.max(left, left) / 2);
472
+ const availableWidth = width * (1 - openSpace);
473
+ const availableHeight = height * (1 - openSpace);
474
+ const spacingWidth = availableWidth / seatCountTopBottom;
475
+ const spacingHeight = availableHeight / seatCountLeftRight;
476
+ const topSeats = distributeWithSpacing({
477
+ start: 0,
478
+ length: width,
479
+ count: top,
480
+ radius: seatRadius,
481
+ spacing: spacingWidth,
482
+ }).map((cx) => ({
483
+ x: cx - seatSizeTB.w / 2,
484
+ y: -seatSizeTB.h,
485
+ width: seatSizeTB.w,
486
+ height: seatSizeTB.h,
487
+ id: "top",
488
+ }));
489
+ const bottomSeats = distributeWithSpacing({
490
+ start: 0,
491
+ length: width,
492
+ count: bottom,
493
+ radius: seatRadius,
494
+ spacing: spacingWidth,
495
+ }).map((cx) => ({
496
+ x: cx - seatSizeTB.w / 2,
497
+ y: height,
498
+ width: seatSizeTB.w,
499
+ height: seatSizeTB.h,
500
+ id: "bottom",
501
+ }));
502
+ const leftSeats = distributeWithSpacing({
503
+ start: 0,
504
+ length: height,
505
+ count: left,
506
+ radius: seatRadius,
507
+ spacing: spacingHeight,
508
+ }).map((cy) => ({
509
+ x: -seatSizeLR.w,
510
+ y: cy - seatSizeLR.h / 2,
511
+ width: seatSizeLR.w,
512
+ height: seatSizeLR.h,
513
+ id: "left",
514
+ }));
515
+ const rightSeats = distributeWithSpacing({
516
+ start: 0,
517
+ length: height,
518
+ count: right,
519
+ radius: seatRadius,
520
+ spacing: spacingHeight,
521
+ }).map((cy) => ({
522
+ x: width,
523
+ y: cy - seatSizeLR.h / 2,
524
+ width: seatSizeLR.w,
525
+ height: seatSizeLR.h,
526
+ id: "right",
527
+ }));
528
+ const seats = [
529
+ ...topSeats,
530
+ ...bottomSeats,
531
+ ...leftSeats,
532
+ ...rightSeats,
533
+ ];
534
+ return (<g key={id} transform={`translate(${x}, ${y})`} data-id={id} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
535
+ e.preventDefault(); // penting
536
+ const group = e.currentTarget;
537
+ highlightGroup(group, "dragenter");
538
+ }} onDragOver={(e) => {
539
+ e.preventDefault(); // agar drop diterima
540
+ }} onDragLeave={(e) => {
541
+ const group = e.currentTarget;
542
+ unhighlightGroup(group);
543
+ }} onDrop={(e) => {
544
+ e.preventDefault();
545
+ const group = e.currentTarget;
546
+ // restore langsung dan reset
547
+ forceRestoreGroup(group);
548
+ }} onPointerOver={(e) => {
549
+ e.preventDefault(); // penting
550
+ const group = e.currentTarget;
551
+ highlightGroup(group, "pointerover");
552
+ }} onPointerOut={(e) => {
553
+ const group = e.currentTarget;
554
+ unhighlightGroup(group);
555
+ }} onPointerUp={(e) => {
556
+ e.preventDefault();
557
+ const group = e.currentTarget;
558
+ // restore langsung dan reset
559
+ forceRestoreGroup(group);
560
+ }} onMouseDown={(e) => {
561
+ e.preventDefault();
562
+ const group = e.currentTarget;
563
+ highlightGroup(group, "mousedown");
564
+ }} onMouseEnter={(e) => {
565
+ // e.preventDefault(); // penting
566
+ const group = e.currentTarget;
567
+ highlightGroup(group, "mouseenter");
568
+ }} onMouseLeave={(e) => {
569
+ const group = e.currentTarget;
570
+ unhighlightGroup(group);
571
+ }}>
572
+ <g transform={`rotate(${rotation}, 0, 0)`}>
573
+ {/* Seats */}
574
+ <circle cx={width / 2} cy={height / 2} r={tableRadius} fill={fill} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])} {...commonProps}/>
575
+ <g key={`${id}-seats`} data-seat={`${id}-seats`}>
576
+ {seats === null || seats === void 0 ? void 0 : seats.map(({ height, width, x, y, id }, i) => (<rect x={x} y={y} key={`${id}-seat-${i}`} id={`seat-${id}`} height={height} width={width} rx={radius / 4} fill={seatFill} className={item === null || item === void 0 ? void 0 : item.className}/>))}
577
+ </g>
578
+ {renderTags(tags)}
579
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
580
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
581
+ var _a, _b, _c, _d, _e, _f, _g;
582
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
583
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
584
+ return (<text {...omit(commonProps, [
585
+ "opacity",
586
+ "stroke",
587
+ "strokeWidth",
588
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
589
+ {_ === null || _ === void 0 ? void 0 : _.label}
590
+ </text>);
591
+ })}
592
+ </g>)}
593
+ </g>
594
+ </g>);
595
+ }
596
+ case "table-seat-square": {
597
+ const openSpace = item.openSpace || 0; // from 0 to 0.9
598
+ const r = 10;
599
+ const seatPositions = item.seatPositions;
600
+ const topCount = (_c = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.top) !== null && _c !== void 0 ? _c : 0;
601
+ const bottomCount = (_d = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.bottom) !== null && _d !== void 0 ? _d : 0;
602
+ const leftCount = (_e = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.left) !== null && _e !== void 0 ? _e : 0;
603
+ const rightCount = (_f = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.right) !== null && _f !== void 0 ? _f : 0;
604
+ // split seats evenly on top and bottom
605
+ const seatCountTopBottom = Math.ceil(Math.max(topCount, bottomCount) / 2);
606
+ const seatCountLeftRight = Math.ceil(Math.max(leftCount, rightCount) / 2);
607
+ const availableWidth = width * (1 - openSpace);
608
+ const availableHeight = height * (1 - openSpace);
609
+ const spacingWidth = availableWidth / seatCountTopBottom;
610
+ const spacingHeight = availableHeight / seatCountLeftRight;
611
+ const topXs = distributeWithSpacing({
612
+ start: x,
613
+ length: width,
614
+ count: topCount,
615
+ radius: r,
616
+ spacing: spacingWidth,
617
+ });
618
+ const topSeats = topXs.map((cx) => ({ cx, cy: y - r, id: "top" }));
619
+ // TOP
620
+ const bottomSeats = distributeWithSpacing({
621
+ start: x,
622
+ length: width,
623
+ count: bottomCount,
624
+ radius: r,
625
+ spacing: spacingWidth,
626
+ }).map((cx) => ({
627
+ cx: cx,
628
+ cy: y + height + r,
629
+ id: "bottom",
630
+ }));
631
+ const leftYs = distributeWithSpacing({
632
+ start: y,
633
+ length: height,
634
+ count: leftCount,
635
+ radius: r,
636
+ spacing: spacingHeight,
637
+ });
638
+ const leftSeats = leftYs.map((cy) => ({ cx: x - r, cy, id: "left" }));
639
+ const rightSeats = distributeWithSpacing({
640
+ start: y,
641
+ length: height,
642
+ count: rightCount,
643
+ radius: r,
644
+ spacing: spacingHeight,
645
+ }).map((cy) => ({
646
+ cx: x + width + r,
647
+ cy,
648
+ id: "right",
649
+ }));
650
+ return (<g key={id} data-id={id} transform={`translate(${x}, ${y})`} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
651
+ e.preventDefault(); // penting
652
+ const group = e.currentTarget;
653
+ highlightGroup(group, "dragenter");
654
+ }} onDragOver={(e) => {
655
+ e.preventDefault(); // agar drop diterima
656
+ }} onDragLeave={(e) => {
657
+ const group = e.currentTarget;
658
+ unhighlightGroup(group);
659
+ }} onDrop={(e) => {
660
+ e.preventDefault();
661
+ const group = e.currentTarget;
662
+ // restore langsung dan reset
663
+ forceRestoreGroup(group);
664
+ }} onPointerOver={(e) => {
665
+ e.preventDefault(); // penting
666
+ const group = e.currentTarget;
667
+ highlightGroup(group, "pointerover");
668
+ }} onPointerOut={(e) => {
669
+ const group = e.currentTarget;
670
+ unhighlightGroup(group);
671
+ }} onPointerUp={(e) => {
672
+ e.preventDefault();
673
+ const group = e.currentTarget;
674
+ // restore langsung dan reset
675
+ forceRestoreGroup(group);
676
+ }} onMouseDown={(e) => {
677
+ e.preventDefault();
678
+ const group = e.currentTarget;
679
+ highlightGroup(group, "mousedown");
680
+ }} onMouseEnter={(e) => {
681
+ // e.preventDefault(); // penting
682
+ const group = e.currentTarget;
683
+ highlightGroup(group, "mouseenter");
684
+ }} onMouseLeave={(e) => {
685
+ const group = e.currentTarget;
686
+ unhighlightGroup(group);
687
+ }}>
688
+ <g transform={`rotate(${rotate}, 0, 0)`}>
689
+ {/* Square Table */}
690
+ <rect width={width} height={height} {...commonProps} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])}/>
691
+ {renderTags(tags)}
692
+
693
+ {/* Seats */}
694
+ <g key={`${id}-seats`} data-seat={`${id}-seats`} transform={`translate(${-x}, ${-y})`}>
695
+ {[...topSeats, ...bottomSeats, ...leftSeats, ...rightSeats].map(({ cx, cy, id }, i) => (<circle key={`${id}-seat-${i}`} id={`seat-${id}`} cx={cx} cy={cy} r={r} fill={seatFill} className={item === null || item === void 0 ? void 0 : item.className}/>))}
696
+ </g>
697
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
698
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
699
+ var _a, _b, _c, _d, _e, _f, _g;
700
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
701
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
702
+ return (<text {...omit(commonProps, [
703
+ "opacity",
704
+ "stroke",
705
+ "strokeWidth",
706
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
707
+ {_ === null || _ === void 0 ? void 0 : _.label}
708
+ </text>);
709
+ })}
710
+ </g>)}
711
+ </g>
712
+ </g>);
713
+ }
714
+ case "table-seat-half-square": {
715
+ const openSpace = item.openSpace || 0;
716
+ const seatRadius = Math.min(width, height) * 0.15;
717
+ const top = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.top) || 0;
718
+ const right = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.right) || 0;
719
+ const bottom = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.bottom) || 0;
720
+ const left = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.left) || 0;
721
+ // split seats evenly on top and bottom
722
+ const seatCountTopBottom = Math.ceil(Math.max(top, bottom) / 2);
723
+ const seatCountLeftRight = Math.ceil(Math.max(left, left) / 2);
724
+ const availableWidth = width * (1 - openSpace);
725
+ const availableHeight = height * (1 - openSpace);
726
+ const spacingWidth = availableWidth / seatCountTopBottom;
727
+ const spacingHeight = availableHeight / seatCountLeftRight;
728
+ const topSeats = distributeWithSpacing({
729
+ start: 0,
730
+ length: width,
731
+ count: top,
732
+ radius: seatRadius,
733
+ spacing: spacingWidth,
734
+ }).map((cx) => ({ cx, cy: seatRadius * 0.1, id: "top" }));
735
+ const bottomSeats = distributeWithSpacing({
736
+ start: 0,
737
+ length: width,
738
+ count: bottom,
739
+ radius: seatRadius,
740
+ spacing: spacingWidth,
741
+ }).map((cx) => ({
742
+ cx,
743
+ cy: height - seatRadius * 0.1,
744
+ id: "bottom",
745
+ }));
746
+ const leftSeats = distributeWithSpacing({
747
+ start: 0,
748
+ length: height,
749
+ count: left,
750
+ radius: seatRadius,
751
+ spacing: spacingHeight,
752
+ }).map((cy) => ({ cx: seatRadius * 0.1, cy, id: "left" }));
753
+ const rightSeats = distributeWithSpacing({
754
+ start: 0,
755
+ length: height,
756
+ count: right,
757
+ radius: seatRadius,
758
+ spacing: spacingHeight,
759
+ }).map((cy) => ({ cx: width - seatRadius * 0.1, cy, id: "right" }));
760
+ const seats = (_g = [
761
+ ...topSeats,
762
+ ...bottomSeats,
763
+ ...leftSeats,
764
+ ...rightSeats,
765
+ ]) === null || _g === void 0 ? void 0 : _g.map((seat) => (Object.assign(Object.assign({}, seat), { d: arcByDirection({
766
+ cx: seat.cx,
767
+ cy: seat.cy,
768
+ r: seatRadius,
769
+ direction: seat.id,
770
+ fraction: 0.4,
771
+ }) })));
772
+ return (<g key={id} transform={`translate(${x}, ${y})`} data-id={id} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
773
+ e.preventDefault(); // penting
774
+ const group = e.currentTarget;
775
+ highlightGroup(group, "dragenter");
776
+ }} onDragOver={(e) => {
777
+ e.preventDefault(); // agar drop diterima
778
+ }} onDragLeave={(e) => {
779
+ const group = e.currentTarget;
780
+ unhighlightGroup(group);
781
+ }} onDrop={(e) => {
782
+ e.preventDefault();
783
+ const group = e.currentTarget;
784
+ // restore langsung dan reset
785
+ forceRestoreGroup(group);
786
+ }} onPointerOver={(e) => {
787
+ e.preventDefault(); // penting
788
+ const group = e.currentTarget;
789
+ highlightGroup(group, "pointerover");
790
+ }} onPointerOut={(e) => {
791
+ const group = e.currentTarget;
792
+ unhighlightGroup(group);
793
+ }} onPointerUp={(e) => {
794
+ e.preventDefault();
795
+ const group = e.currentTarget;
796
+ // restore langsung dan reset
797
+ forceRestoreGroup(group);
798
+ }} onMouseDown={(e) => {
799
+ e.preventDefault();
800
+ const group = e.currentTarget;
801
+ highlightGroup(group, "mousedown");
802
+ }} onMouseEnter={(e) => {
803
+ // e.preventDefault(); // penting
804
+ const group = e.currentTarget;
805
+ highlightGroup(group, "mouseenter");
806
+ }} onMouseLeave={(e) => {
807
+ const group = e.currentTarget;
808
+ unhighlightGroup(group);
809
+ }}>
810
+ <g transform={`rotate(${rotation}, 0, 0)`}>
811
+ {/* Seats */}
812
+ <rect width={width} height={height} rx={radius} {...commonProps} fill={fill} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])}/>
813
+ <g key={`${id}-seats`} data-seat={`${id}-seats`}>
814
+ {seats === null || seats === void 0 ? void 0 : seats.map(({ d, id }, i) => (<path key={`${id}-seat-${i}`} id={`seat-${id}`} d={d} fill={seatFill} className={item === null || item === void 0 ? void 0 : item.className}/>))}
815
+ </g>
816
+ {renderTags(tags)}
817
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
818
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
819
+ var _a, _b, _c, _d, _e, _f, _g;
820
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
821
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
822
+ return (<text {...omit(commonProps, [
823
+ "opacity",
824
+ "stroke",
825
+ "strokeWidth",
826
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
827
+ {_ === null || _ === void 0 ? void 0 : _.label}
828
+ </text>);
829
+ })}
830
+ </g>)}
831
+ </g>
832
+ </g>);
833
+ }
834
+ case "table-seat-rect-square": {
835
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
836
+ const base = clamp(Math.min(width, height) * 0.08, 12, 28);
837
+ const seatSizeTB = {
838
+ w: base * 1.8, // lebih panjang
839
+ h: base * 0.9, // lebih tipis
840
+ };
841
+ const seatSizeLR = {
842
+ w: base * 0.9, // lebih tipis
843
+ h: base * 1.8, // lebih panjang
844
+ };
845
+ const openSpace = item.openSpace || 0;
846
+ const seatRadius = Math.min(width, height) * 0.2;
847
+ const top = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.top) || 0;
848
+ const right = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.right) || 0;
849
+ const bottom = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.bottom) || 0;
850
+ const left = (seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.left) || 0;
851
+ // split seats evenly on top and bottom
852
+ const seatCountTopBottom = Math.ceil(Math.max(top, bottom) / 2);
853
+ const seatCountLeftRight = Math.ceil(Math.max(left, left) / 2);
854
+ const availableWidth = width * (1 - openSpace);
855
+ const availableHeight = height * (1 - openSpace);
856
+ const spacingWidth = availableWidth / seatCountTopBottom;
857
+ const spacingHeight = availableHeight / seatCountLeftRight;
858
+ const topSeats = distributeWithSpacing({
859
+ start: x,
860
+ length: width,
861
+ count: top,
862
+ radius: seatRadius,
863
+ spacing: spacingWidth,
864
+ }).map((cx) => ({
865
+ x: cx - seatSizeTB.w / 2,
866
+ y: y - seatSizeTB.h,
867
+ width: seatSizeTB.w,
868
+ height: seatSizeTB.h,
869
+ id: "top",
870
+ }));
871
+ const bottomSeats = distributeWithSpacing({
872
+ start: x,
873
+ length: width,
874
+ count: bottom,
875
+ radius: seatRadius,
876
+ spacing: spacingWidth,
877
+ }).map((cx) => ({
878
+ x: cx - seatSizeTB.w / 2,
879
+ y: y + height,
880
+ width: seatSizeTB.w,
881
+ height: seatSizeTB.h,
882
+ id: "bottom",
883
+ }));
884
+ const leftSeats = distributeWithSpacing({
885
+ start: 0,
886
+ length: height,
887
+ count: left,
888
+ radius: seatRadius,
889
+ spacing: spacingHeight,
890
+ }).map((cy) => ({
891
+ x: x - seatSizeLR.w,
892
+ y: y + cy - seatSizeLR.h / 2,
893
+ width: seatSizeLR.w,
894
+ height: seatSizeLR.h,
895
+ id: "left",
896
+ }));
897
+ const rightSeats = distributeWithSpacing({
898
+ start: 0,
899
+ length: height,
900
+ count: right,
901
+ radius: seatRadius,
902
+ spacing: spacingHeight,
903
+ }).map((cy) => ({
904
+ x: x + width,
905
+ y: y + cy - seatSizeLR.h / 2,
906
+ width: seatSizeLR.w,
907
+ height: seatSizeLR.h,
908
+ id: "right",
909
+ }));
910
+ const seats = [
911
+ ...topSeats,
912
+ ...bottomSeats,
913
+ ...leftSeats,
914
+ ...rightSeats,
915
+ ];
916
+ return (<g key={id} transform={`translate(${x}, ${y})`} data-id={id} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
917
+ e.preventDefault(); // penting
918
+ const group = e.currentTarget;
919
+ highlightGroup(group, "dragenter");
920
+ }} onDragOver={(e) => {
921
+ e.preventDefault(); // agar drop diterima
922
+ }} onDragLeave={(e) => {
923
+ const group = e.currentTarget;
924
+ unhighlightGroup(group);
925
+ }} onDrop={(e) => {
926
+ e.preventDefault();
927
+ const group = e.currentTarget;
928
+ // restore langsung dan reset
929
+ forceRestoreGroup(group);
930
+ }} onPointerOver={(e) => {
931
+ e.preventDefault(); // penting
932
+ const group = e.currentTarget;
933
+ highlightGroup(group, "pointerover");
934
+ }} onPointerOut={(e) => {
935
+ const group = e.currentTarget;
936
+ unhighlightGroup(group);
937
+ }} onPointerUp={(e) => {
938
+ e.preventDefault();
939
+ const group = e.currentTarget;
940
+ // restore langsung dan reset
941
+ forceRestoreGroup(group);
942
+ }} onMouseDown={(e) => {
943
+ e.preventDefault();
944
+ const group = e.currentTarget;
945
+ highlightGroup(group, "mousedown");
946
+ }} onMouseEnter={(e) => {
947
+ // e.preventDefault(); // penting
948
+ const group = e.currentTarget;
949
+ highlightGroup(group, "mouseenter");
950
+ }} onMouseLeave={(e) => {
951
+ const group = e.currentTarget;
952
+ unhighlightGroup(group);
953
+ }}>
954
+ <g transform={`rotate(${rotation}, 0, 0)`}>
955
+ {/* Seats */}
956
+ <rect width={width} height={height} rx={radius} {...commonProps} fill={fill} {...omit(item, ["x", "y", "label", "points", "tags", "seatCount"])}/>
957
+ <g key={`${id}-seats`} data-seat={`${id}-seats`} transform={`translate(${-x}, ${-y})`}>
958
+ {seats === null || seats === void 0 ? void 0 : seats.map(({ height, width, x, y, id }, i) => (<rect x={x} y={y} key={`${id}-seat-${i}`} id={`seat-${id}`} height={height} width={width} rx={radius / 4} fill={seatFill}/>))}
959
+ </g>
960
+ {renderTags(tags)}
961
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
962
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
963
+ var _a, _b, _c, _d, _e, _f, _g;
964
+ const cx = width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0);
965
+ const cy = height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0);
966
+ return (<text {...omit(commonProps, [
967
+ "opacity",
968
+ "stroke",
969
+ "strokeWidth",
970
+ ])} transform={`rotate(${(_c = _ === null || _ === void 0 ? void 0 : _.rotation) !== null && _c !== void 0 ? _c : 0}, ${cx},${cy})`} key={`${id}-label-${index}`} x={width / 2 + ((_d = _ === null || _ === void 0 ? void 0 : _.x) !== null && _d !== void 0 ? _d : 0)} y={height / 2 + ((_e = _ === null || _ === void 0 ? void 0 : _.y) !== null && _e !== void 0 ? _e : 0)} fill={(_f = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _f !== void 0 ? _f : "black"} fontSize={`${(_g = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _g !== void 0 ? _g : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
971
+ {_ === null || _ === void 0 ? void 0 : _.label}
972
+ </text>);
973
+ })}
974
+ </g>)}
975
+ </g>
976
+ </g>);
977
+ }
978
+ case "text":
979
+ return (<g key={id} onContextMenu={(e) => e.preventDefault()} data-id={id} transform={`translate(${x}, ${y})`}>
980
+ <g transform={`rotate(${rotation}, 0, 0)`}>
981
+ <rect width={width} height={height} fill="transparent" opacity={opacity}/>
982
+ <text x={width / 2} y={height / 2} textAnchor="middle" dominantBaseline="middle" fill={fill !== null && fill !== void 0 ? fill : fontColor} fontSize={fontSize !== null && fontSize !== void 0 ? fontSize : height * 0.6} opacity={opacity} {...omit(commonProps, ["fill", "opacity"])}>
983
+ {text}
984
+ </text>
985
+ </g>
986
+ </g>);
987
+ case "image-table":
988
+ return (<g key={id} id={`${id}`} data-id={id} transform={`translate(${x}, ${y})`} onContextMenu={(e) => e.preventDefault()} onDragEnter={(e) => {
989
+ e.preventDefault(); // penting
990
+ const group = e.currentTarget;
991
+ highlightGroup(group, "dragenter");
992
+ }} onDragOver={(e) => {
993
+ e.preventDefault(); // agar drop diterima
994
+ }} onDragLeave={(e) => {
995
+ const group = e.currentTarget;
996
+ unhighlightGroup(group);
997
+ }} onDrop={(e) => {
998
+ e.preventDefault();
999
+ const group = e.currentTarget;
1000
+ // restore langsung dan reset
1001
+ forceRestoreGroup(group);
1002
+ }} onPointerOver={(e) => {
1003
+ e.preventDefault(); // penting
1004
+ const group = e.currentTarget;
1005
+ highlightGroup(group, "pointerover");
1006
+ }} onPointerOut={(e) => {
1007
+ const group = e.currentTarget;
1008
+ unhighlightGroup(group);
1009
+ }} onPointerUp={(e) => {
1010
+ e.preventDefault();
1011
+ const group = e.currentTarget;
1012
+ // restore langsung dan reset
1013
+ forceRestoreGroup(group);
1014
+ }} onMouseDown={(e) => {
1015
+ e.preventDefault();
1016
+ const group = e.currentTarget;
1017
+ highlightGroup(group, "mousedown");
1018
+ }}>
1019
+ <g transform={`rotate(${rotation}, 0, 0)`}>
1020
+ <image href={src} width={width} height={height} transform={transformRotate} {...commonProps}/>
1021
+ {renderTags(tags)}
1022
+ {showLabels && (<g transform={`rotate(${-rotation}, ${width / 2}, ${height / 2})`}>
1023
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
1024
+ var _a, _b, _c, _d;
1025
+ return (<text key={index} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={transformRotate}>
1026
+ {_ === null || _ === void 0 ? void 0 : _.label}
1027
+ </text>);
1028
+ })}
1029
+ </g>)}
1030
+ </g>
1031
+ </g>);
1032
+ case "background":
1033
+ return (<g key={id} onContextMenu={(e) => e.preventDefault()}>
1034
+ <image href={src} x={x} y={y} width={width} height={height} transform={transformRotate} {...commonProps}/>
1035
+ {labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
1036
+ var _a, _b, _c, _d;
1037
+ return (<text key={index} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={transformRotate}>
1038
+ {_ === null || _ === void 0 ? void 0 : _.label}
1039
+ </text>);
1040
+ })}
1041
+ </g>);
1042
+ default:
1043
+ return <g key={id}/>;
1044
+ }
1045
+ };
1046
+ let date = new Date();
1047
+ return <g key={`${date}`}>{components === null || components === void 0 ? void 0 : components.map(renderShape)}</g>;
1048
+ };
1049
+ export default Layers;