seat-editor 2.1.2 → 3.0.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.
- package/dist/app/constant.d.ts +232 -0
- package/dist/app/constant.js +3683 -3045
- package/dist/app/new-board/page.js +5 -6
- package/dist/app/only-view/chair.d.ts +1 -0
- package/dist/app/only-view/chair.js +4 -0
- package/dist/app/only-view/constant.d.ts +22 -2
- package/dist/app/only-view/constant.js +4 -4
- package/dist/app/only-view/page.js +74 -37
- package/dist/app/only-view/user.d.ts +1 -0
- package/dist/app/only-view/user.js +4 -0
- package/dist/components/layer-v3/index.d.ts +23 -4
- package/dist/components/layer-v3/index.js +329 -146
- package/dist/components/layer-v4/index.d.ts +20 -0
- package/dist/components/layer-v4/index.js +445 -0
- package/dist/components/lib/index.d.ts +1 -1
- package/dist/components/lib/index.js +1 -1
- package/dist/features/board/index.js +1 -1
- package/dist/features/board-v2/index.js +1 -1
- package/dist/features/board-v3/board-slice.d.ts +1 -0
- package/dist/features/board-v3/board-slice.js +26 -3
- package/dist/features/board-v3/constant.d.ts +5 -0
- package/dist/features/board-v3/constant.js +5 -0
- package/dist/features/board-v3/index copy.d.ts +47 -0
- package/dist/features/board-v3/index copy.js +2073 -0
- package/dist/features/board-v3/index.js +1409 -647
- package/dist/features/board-v3/polygon.d.ts +28 -0
- package/dist/features/board-v3/polygon.js +109 -0
- package/dist/features/board-v3/rect.d.ts +9 -0
- package/dist/features/board-v3/rect.js +152 -0
- package/dist/features/board-v3/resize-element.d.ts +12 -0
- package/dist/features/board-v3/resize-element.js +40 -0
- package/dist/features/board-v3/utils.d.ts +162 -0
- package/dist/features/board-v3/utils.js +787 -0
- package/dist/features/package/index.js +1 -1
- package/dist/features/panel/index.js +130 -20
- package/dist/features/panel/panel-slice.d.ts +5 -0
- package/dist/features/panel/panel-slice.js +15 -0
- package/dist/features/panel/select-tool.js +11 -1
- package/dist/features/panel/selected-group.d.ts +2 -0
- package/dist/features/panel/selected-group.js +7 -0
- package/dist/features/panel/table-seat-square.d.ts +2 -0
- package/dist/features/panel/table-seat-square.js +9 -0
- package/dist/features/side-tool/index.js +13 -6
- package/dist/features/view-only/index.js +0 -1
- package/dist/features/view-only-2/index.js +0 -1
- package/dist/features/view-only-3/index.d.ts +68 -0
- package/dist/features/view-only-3/index.js +510 -0
- package/dist/features/view-only-3/utils.d.ts +1 -0
- package/dist/features/view-only-3/utils.js +3 -0
- package/dist/seat-editor.css +1 -1
- package/dist/utils/constant.d.ts +1 -0
- package/dist/utils/constant.js +11 -0
- package/dist/utils/format.d.ts +2 -0
- package/dist/utils/format.js +29 -0
- package/package.json +3 -1
- package/dist/features/view/index.d.ts +0 -19
- package/dist/features/view/index.js +0 -221
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventHandleType } from "@/dto/event-handler";
|
|
2
|
+
import { PropertiesProps } from "@/dto/table";
|
|
3
|
+
import { TableMatchEvent } from "@/features/view-only-3";
|
|
4
|
+
interface LayersProps {
|
|
5
|
+
components?: PropertiesProps[];
|
|
6
|
+
selectedComponent?: PropertiesProps;
|
|
7
|
+
activeTool?: string;
|
|
8
|
+
onBlur?: () => void;
|
|
9
|
+
selectedTable?: PropertiesProps;
|
|
10
|
+
iconTags?: {
|
|
11
|
+
icon: React.JSX.Element;
|
|
12
|
+
key: string;
|
|
13
|
+
}[];
|
|
14
|
+
eventMatchTable?: TableMatchEvent[];
|
|
15
|
+
onHighlightGroup?: (group: SVGGElement, eventType: EventHandleType) => void;
|
|
16
|
+
onForceRestoreGroup?: (group: SVGGElement, eventType: EventHandleType) => void;
|
|
17
|
+
selectedTableColor?: string;
|
|
18
|
+
}
|
|
19
|
+
declare const Layers: ({ components, selectedTable, iconTags, eventMatchTable, onHighlightGroup, onForceRestoreGroup, selectedTableColor, }: LayersProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export default Layers;
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createElement as _createElement } from "react";
|
|
4
|
+
import { isEmpty, omit } from "lodash";
|
|
5
|
+
import { TABLE_KEYS } from "@/utils/constant";
|
|
6
|
+
import { distributeWithSpacing } from "../layer-v3";
|
|
7
|
+
const Layers = ({ components, selectedTable, iconTags, eventMatchTable, onHighlightGroup, onForceRestoreGroup, selectedTableColor, }) => {
|
|
8
|
+
const renderShape = (item) => {
|
|
9
|
+
var _a, _b, _c, _d, _e;
|
|
10
|
+
const { id, x, y, width, height, fill, opacity, rotate = 0, shape, text, stroke, strokeWidth, labels, fontSize, fontColor, seatFill, src, tags, gapTags, label, } = item;
|
|
11
|
+
const renderTags = (tags) => {
|
|
12
|
+
const gapBetweenTags = gapTags || 0;
|
|
13
|
+
const defaultFontSize = fontSize || 12;
|
|
14
|
+
// Hitung total tinggi semua grup tag (buat center vertikal)
|
|
15
|
+
const totalTagHeight = (tags === null || tags === void 0 ? void 0 : tags.reduce((sum, tag) => {
|
|
16
|
+
var _a;
|
|
17
|
+
const items = tag.items || [];
|
|
18
|
+
const isColumn = (_a = tag.direction) === null || _a === void 0 ? void 0 : _a.includes("column");
|
|
19
|
+
const tagHeight = isColumn
|
|
20
|
+
? items.length * defaultFontSize +
|
|
21
|
+
(items.length - 1) * (Number(tag.gap) || 2)
|
|
22
|
+
: defaultFontSize; // horizontal = 1 line
|
|
23
|
+
return sum + tagHeight + gapBetweenTags;
|
|
24
|
+
}, 0)) - gapBetweenTags;
|
|
25
|
+
const startY = height / 2 - totalTagHeight / 2; // titik awal supaya semua di tengah
|
|
26
|
+
let currentY = startY;
|
|
27
|
+
return tags === null || tags === void 0 ? void 0 : tags.map((tag, tagIndex) => {
|
|
28
|
+
var _a;
|
|
29
|
+
const direction = ((_a = tag.direction) === null || _a === void 0 ? void 0 : _a.includes("column")) ? "column" : "flex";
|
|
30
|
+
const gap = Number(tag.gap) || 2;
|
|
31
|
+
const items = tag.items || [];
|
|
32
|
+
const fontSize = defaultFontSize;
|
|
33
|
+
const isColumn = direction === "column";
|
|
34
|
+
const groupHeight = isColumn
|
|
35
|
+
? items.length * fontSize + (items.length - 1) * gap
|
|
36
|
+
: fontSize;
|
|
37
|
+
const centerX = width / 2;
|
|
38
|
+
const centerY = currentY + groupHeight / 2;
|
|
39
|
+
// naikkan posisi Y untuk grup berikutnya
|
|
40
|
+
currentY += groupHeight + gapBetweenTags;
|
|
41
|
+
// kumpulkan elemen yang akan dirender (bisa mix text + icon)
|
|
42
|
+
const elements = items.map((item, i) => {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
const offsetY = isColumn
|
|
45
|
+
? i * (fontSize + gap) - groupHeight / 2 + fontSize / 2
|
|
46
|
+
: 0;
|
|
47
|
+
const offsetX = !isColumn
|
|
48
|
+
? i * (fontSize + gap) - ((items.length - 1) * (fontSize + gap)) / 2
|
|
49
|
+
: 0;
|
|
50
|
+
const posX = centerX + offsetX + ((_a = tag.offsetX) !== null && _a !== void 0 ? _a : 0);
|
|
51
|
+
const posY = centerY + offsetY + ((_b = tag.offsetY) !== null && _b !== void 0 ? _b : 0);
|
|
52
|
+
const renderSymbol = (symbol) => {
|
|
53
|
+
if (!symbol)
|
|
54
|
+
return null;
|
|
55
|
+
const { position = "right", size = (item === null || item === void 0 ? void 0 : item.fontSize) || 12, gap: symbolGap = 0, } = symbol;
|
|
56
|
+
let offsetSymbolX = 0;
|
|
57
|
+
let offsetSymbolY = 0;
|
|
58
|
+
switch (position) {
|
|
59
|
+
case "right":
|
|
60
|
+
offsetSymbolX = size + symbolGap;
|
|
61
|
+
break;
|
|
62
|
+
case "left":
|
|
63
|
+
offsetSymbolX = -(size + symbolGap);
|
|
64
|
+
break;
|
|
65
|
+
case "top":
|
|
66
|
+
offsetSymbolY = -(size + symbolGap);
|
|
67
|
+
break;
|
|
68
|
+
case "bottom":
|
|
69
|
+
offsetSymbolY = size + symbolGap;
|
|
70
|
+
break;
|
|
71
|
+
case "right-top":
|
|
72
|
+
offsetSymbolX = size + symbolGap;
|
|
73
|
+
offsetSymbolY = -(size / 4);
|
|
74
|
+
break;
|
|
75
|
+
case "right-bottom":
|
|
76
|
+
offsetSymbolX = size + symbolGap;
|
|
77
|
+
offsetSymbolY = size / 4;
|
|
78
|
+
break;
|
|
79
|
+
case "left-top":
|
|
80
|
+
offsetSymbolX = -size - symbolGap;
|
|
81
|
+
offsetSymbolY = -(size / 4);
|
|
82
|
+
break;
|
|
83
|
+
case "left-bottom":
|
|
84
|
+
offsetSymbolX = -size - symbolGap;
|
|
85
|
+
offsetSymbolY = size / 4;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
return (_createElement("tspan", Object.assign({}, symbol, { key: `symbol-${tagIndex}-${i}`, x: posX + offsetSymbolX, y: posY + offsetSymbolY, textAnchor: "middle", dominantBaseline: "middle", transform: `rotate(${rotate} ${posX} ${posY})` }), symbol.value));
|
|
89
|
+
};
|
|
90
|
+
if (item.type === "icon") {
|
|
91
|
+
const iconTag = iconTags === null || iconTags === void 0 ? void 0 : iconTags.find((icon) => icon.key === item.value);
|
|
92
|
+
if (!iconTag)
|
|
93
|
+
return null;
|
|
94
|
+
return (_createElement("g", Object.assign({}, item, { key: `icon-${tagIndex}-${i}`, transform: `translate(${posX - 10}, ${posY - 10})` }), iconTag.icon));
|
|
95
|
+
}
|
|
96
|
+
if (item.type === "text") {
|
|
97
|
+
return (_createElement("text", Object.assign({}, item, { key: `text-${tagIndex}-${i}`, x: posX, y: posY, textAnchor: "middle", dominantBaseline: "middle", transform: `rotate(${rotate} ${posX} ${posY})` }),
|
|
98
|
+
item.value,
|
|
99
|
+
" ",
|
|
100
|
+
renderSymbol(item === null || item === void 0 ? void 0 : item.symbol)));
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
});
|
|
104
|
+
return _jsx("g", { children: elements }, `group-${tagIndex}`);
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
let commonProps = {
|
|
108
|
+
fill,
|
|
109
|
+
opacity,
|
|
110
|
+
stroke,
|
|
111
|
+
strokeWidth,
|
|
112
|
+
};
|
|
113
|
+
const hasSelected = (selectedTable === null || selectedTable === void 0 ? void 0 : selectedTable.id) === id;
|
|
114
|
+
if (hasSelected) {
|
|
115
|
+
const eventSelectedStyles = eventMatchTable === null || eventMatchTable === void 0 ? void 0 : eventMatchTable.find((style) => style.event === "selected");
|
|
116
|
+
commonProps = Object.assign(Object.assign({}, commonProps), eventSelectedStyles === null || eventSelectedStyles === void 0 ? void 0 : eventSelectedStyles.properties);
|
|
117
|
+
}
|
|
118
|
+
// helper: highlight / unhighlight dengan enter-counter
|
|
119
|
+
let properties = {};
|
|
120
|
+
const highlightGroup = (group, eventType) => {
|
|
121
|
+
if (!group)
|
|
122
|
+
return;
|
|
123
|
+
onHighlightGroup === null || onHighlightGroup === void 0 ? void 0 : onHighlightGroup(group, eventType);
|
|
124
|
+
eventMatchTable === null || eventMatchTable === void 0 ? void 0 : eventMatchTable.forEach((styleConfig) => {
|
|
125
|
+
if (styleConfig.event === eventType) {
|
|
126
|
+
properties = styleConfig.properties;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
if (isEmpty(properties))
|
|
130
|
+
return;
|
|
131
|
+
// counter
|
|
132
|
+
const count = Number(group.dataset.dragEnterCount || "0") + 1;
|
|
133
|
+
group.dataset.dragEnterCount = String(count);
|
|
134
|
+
// selalu ubah warna, tapi simpan original hanya sekali
|
|
135
|
+
["rect", "circle"].forEach((selector) => {
|
|
136
|
+
const el = group.querySelector(selector);
|
|
137
|
+
if (!el)
|
|
138
|
+
return;
|
|
139
|
+
Object.entries(properties).forEach(([key]) => {
|
|
140
|
+
el.dataset[key] = el.getAttribute(key) || "";
|
|
141
|
+
});
|
|
142
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
143
|
+
el.setAttribute(key, value);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const unhighlightGroup = (group) => {
|
|
148
|
+
if (!group)
|
|
149
|
+
return;
|
|
150
|
+
const count = Math.max(0, Number(group.dataset.dragEnterCount || "0") - 1);
|
|
151
|
+
group.dataset.dragEnterCount = String(count);
|
|
152
|
+
// restore hanya saat counter = 0
|
|
153
|
+
if (count === 0) {
|
|
154
|
+
["rect", "circle"].forEach((selector) => {
|
|
155
|
+
const el = group.querySelector(selector);
|
|
156
|
+
if (!el)
|
|
157
|
+
return;
|
|
158
|
+
// bersihkan data
|
|
159
|
+
const dataset = el.dataset;
|
|
160
|
+
Object.entries(dataset).forEach(([key, value]) => {
|
|
161
|
+
el.setAttribute(key, value);
|
|
162
|
+
delete el.dataset[key];
|
|
163
|
+
properties = {};
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
delete group.dataset.dragEnterCount;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const forceRestoreGroup = (group, type) => {
|
|
170
|
+
// langsung restore (dipanggil pada drop)
|
|
171
|
+
onForceRestoreGroup === null || onForceRestoreGroup === void 0 ? void 0 : onForceRestoreGroup(group, type);
|
|
172
|
+
["rect", "circle"].forEach((selector) => {
|
|
173
|
+
const el = group === null || group === void 0 ? void 0 : group.querySelector(selector);
|
|
174
|
+
if (!el)
|
|
175
|
+
return;
|
|
176
|
+
const dataset = el.dataset;
|
|
177
|
+
Object.entries(dataset).forEach(([key, value]) => {
|
|
178
|
+
el.setAttribute(key, value);
|
|
179
|
+
delete el.dataset[key];
|
|
180
|
+
properties = {};
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
delete group.dataset.dragEnterCount;
|
|
184
|
+
};
|
|
185
|
+
const transformRotate = `rotate(${rotate} ${x + width / 2} ${y + height / 2})`;
|
|
186
|
+
switch (shape) {
|
|
187
|
+
case "square":
|
|
188
|
+
return (_jsxs("g", { "data-id": id, style: { pointerEvents: "all" }, onContextMenu: (e) => e.preventDefault(), onDragEnter: (e) => {
|
|
189
|
+
const group = e.currentTarget;
|
|
190
|
+
highlightGroup(group, "dragenter");
|
|
191
|
+
}, onDragOver: (e) => {
|
|
192
|
+
e.preventDefault(); // agar drop diterima
|
|
193
|
+
}, onDragLeave: (e) => {
|
|
194
|
+
const group = e.currentTarget;
|
|
195
|
+
unhighlightGroup(group);
|
|
196
|
+
}, onDrop: (e) => {
|
|
197
|
+
const group = e.currentTarget;
|
|
198
|
+
// restore langsung dan reset
|
|
199
|
+
forceRestoreGroup(group, "drop");
|
|
200
|
+
}, onPointerOver: (e) => {
|
|
201
|
+
// e.preventDefault(); // penting
|
|
202
|
+
const group = e.currentTarget;
|
|
203
|
+
highlightGroup(group, "pointerover");
|
|
204
|
+
}, onPointerOut: (e) => {
|
|
205
|
+
const group = e.currentTarget;
|
|
206
|
+
unhighlightGroup(group);
|
|
207
|
+
}, onPointerUp: (e) => {
|
|
208
|
+
const group = e.currentTarget;
|
|
209
|
+
// restore langsung dan reset
|
|
210
|
+
forceRestoreGroup(group, "pointerup");
|
|
211
|
+
}, onPointerDown: (e) => {
|
|
212
|
+
const group = e.currentTarget;
|
|
213
|
+
highlightGroup(group, "pointerdown");
|
|
214
|
+
},
|
|
215
|
+
// onPointerEnter={(e) => {
|
|
216
|
+
// const group = e.currentTarget as SVGGElement;
|
|
217
|
+
// highlightGroup(group, "pointerenter");
|
|
218
|
+
// }}
|
|
219
|
+
onPointerLeave: (e) => {
|
|
220
|
+
const group = e.currentTarget;
|
|
221
|
+
unhighlightGroup(group);
|
|
222
|
+
}, onMouseEnter: (e) => {
|
|
223
|
+
// e.preventDefault(); // penting
|
|
224
|
+
const group = e.currentTarget;
|
|
225
|
+
highlightGroup(group, "mouseenter");
|
|
226
|
+
}, onMouseLeave: (e) => {
|
|
227
|
+
const group = e.currentTarget;
|
|
228
|
+
unhighlightGroup(group);
|
|
229
|
+
}, children: [_jsx("rect", Object.assign({ x: x, y: y, width: width, height: height, fill: fill, className: "blink-2", transform: transformRotate }, omit(item, TABLE_KEYS), commonProps), `${id}-rect`), renderTags(tags), labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
230
|
+
var _a, _b, _c, _d;
|
|
231
|
+
return (_createElement("text", Object.assign({}, omit(commonProps, ["opacity", "stroke", "strokeWidth"]), { key: `${id}-label-${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 }, _), _ === null || _ === void 0 ? void 0 : _.label));
|
|
232
|
+
})] }, id));
|
|
233
|
+
case "circle":
|
|
234
|
+
return (_jsxs("g", { style: { pointerEvents: "all" }, "data-id": id, onContextMenu: (e) => e.preventDefault(), onDragEnter: (e) => {
|
|
235
|
+
e.preventDefault(); // penting
|
|
236
|
+
const group = e.currentTarget;
|
|
237
|
+
highlightGroup(group, "dragenter");
|
|
238
|
+
}, onDragOver: (e) => {
|
|
239
|
+
e.preventDefault(); // agar drop diterima
|
|
240
|
+
}, onDragLeave: (e) => {
|
|
241
|
+
const group = e.currentTarget;
|
|
242
|
+
unhighlightGroup(group);
|
|
243
|
+
}, onDrop: (e) => {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
const group = e.currentTarget;
|
|
246
|
+
// restore langsung dan reset
|
|
247
|
+
forceRestoreGroup(group);
|
|
248
|
+
}, onPointerOver: (e) => {
|
|
249
|
+
e.preventDefault(); // penting
|
|
250
|
+
const group = e.currentTarget;
|
|
251
|
+
highlightGroup(group, "pointerover");
|
|
252
|
+
}, onPointerOut: (e) => {
|
|
253
|
+
const group = e.currentTarget;
|
|
254
|
+
unhighlightGroup(group);
|
|
255
|
+
}, onPointerUp: (e) => {
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
const group = e.currentTarget;
|
|
258
|
+
// restore langsung dan reset
|
|
259
|
+
forceRestoreGroup(group);
|
|
260
|
+
}, onMouseDown: (e) => {
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
const group = e.currentTarget;
|
|
263
|
+
highlightGroup(group, "mousedown");
|
|
264
|
+
}, onMouseEnter: (e) => {
|
|
265
|
+
// e.preventDefault(); // penting
|
|
266
|
+
const group = e.currentTarget;
|
|
267
|
+
highlightGroup(group, "mouseenter");
|
|
268
|
+
}, onMouseLeave: (e) => {
|
|
269
|
+
const group = e.currentTarget;
|
|
270
|
+
unhighlightGroup(group);
|
|
271
|
+
}, children: [_jsx("circle", Object.assign({ cx: x + width / 2, cy: y + height / 2, r: width / 2 }, commonProps), id), renderTags(tags), labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
272
|
+
var _a, _b, _c, _d;
|
|
273
|
+
return (_jsx("text", { 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, children: _ === null || _ === void 0 ? void 0 : _.label }, `${id}-label-${index}`));
|
|
274
|
+
})] }, id));
|
|
275
|
+
case "table-seat-circle": {
|
|
276
|
+
const seatCount = item.seatCount;
|
|
277
|
+
const openSpace = (_a = item.openSpace) !== null && _a !== void 0 ? _a : 0;
|
|
278
|
+
// LOCAL SPACE (tanpa x,y)
|
|
279
|
+
const centerX = width / 2;
|
|
280
|
+
const centerY = height / 2;
|
|
281
|
+
// meja
|
|
282
|
+
const tableRadius = Math.min(width, height) / 2;
|
|
283
|
+
// seat statis
|
|
284
|
+
const seatRadius = 10;
|
|
285
|
+
const fullAngle = Math.PI * 2;
|
|
286
|
+
const availableAngle = fullAngle * (1 - openSpace);
|
|
287
|
+
const angleStart = (fullAngle - availableAngle) / 2;
|
|
288
|
+
const angleStep = availableAngle / seatCount;
|
|
289
|
+
const seatCircles = Array.from({ length: seatCount }, (_, i) => {
|
|
290
|
+
const angle = angleStart + i * angleStep;
|
|
291
|
+
const cx = centerX + (tableRadius + seatRadius) * Math.cos(angle);
|
|
292
|
+
const cy = centerY + (tableRadius + seatRadius) * Math.sin(angle);
|
|
293
|
+
return { cx, cy };
|
|
294
|
+
});
|
|
295
|
+
return (_jsxs("g", { style: { pointerEvents: "all" }, "data-id": id, transform: `translate(${x}, ${y})`,
|
|
296
|
+
// data-table={JSON.stringify(item)}
|
|
297
|
+
// data-id={id}
|
|
298
|
+
onContextMenu: (e) => e.preventDefault(), onDragEnter: (e) => {
|
|
299
|
+
e.preventDefault(); // penting
|
|
300
|
+
const group = e.currentTarget;
|
|
301
|
+
highlightGroup(group, "dragenter");
|
|
302
|
+
}, onDragOver: (e) => {
|
|
303
|
+
e.preventDefault(); // agar drop diterima
|
|
304
|
+
}, onDragLeave: (e) => {
|
|
305
|
+
const group = e.currentTarget;
|
|
306
|
+
unhighlightGroup(group);
|
|
307
|
+
}, onDrop: (e) => {
|
|
308
|
+
e.preventDefault();
|
|
309
|
+
const group = e.currentTarget;
|
|
310
|
+
// restore langsung dan reset
|
|
311
|
+
forceRestoreGroup(group);
|
|
312
|
+
}, onPointerOver: (e) => {
|
|
313
|
+
e.preventDefault(); // penting
|
|
314
|
+
const group = e.currentTarget;
|
|
315
|
+
highlightGroup(group, "pointerover");
|
|
316
|
+
}, onPointerOut: (e) => {
|
|
317
|
+
const group = e.currentTarget;
|
|
318
|
+
unhighlightGroup(group);
|
|
319
|
+
}, onPointerUp: (e) => {
|
|
320
|
+
e.preventDefault();
|
|
321
|
+
const group = e.currentTarget;
|
|
322
|
+
// restore langsung dan reset
|
|
323
|
+
forceRestoreGroup(group);
|
|
324
|
+
}, onMouseDown: (e) => {
|
|
325
|
+
e.preventDefault();
|
|
326
|
+
const group = e.currentTarget;
|
|
327
|
+
highlightGroup(group, "mousedown");
|
|
328
|
+
}, onMouseEnter: (e) => {
|
|
329
|
+
// e.preventDefault(); // penting
|
|
330
|
+
const group = e.currentTarget;
|
|
331
|
+
highlightGroup(group, "mouseenter");
|
|
332
|
+
}, onMouseLeave: (e) => {
|
|
333
|
+
const group = e.currentTarget;
|
|
334
|
+
unhighlightGroup(group);
|
|
335
|
+
}, children: [_jsx("circle", Object.assign({ cx: centerX, cy: centerY, r: tableRadius, fill: selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill }, commonProps)), _jsx("g", { "data-seat": `${id}-seats`, children: seatCircles.map(({ cx, cy }, i) => (_jsx("circle", { cx: cx, cy: cy, r: seatRadius, fill: seatFill || "white" }, `${id}-seat-${i}`))) }), renderTags(tags), labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
336
|
+
var _a, _b, _c, _d;
|
|
337
|
+
return (_jsx("text", { 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, children: _ === null || _ === void 0 ? void 0 : _.label }, `${id}-label-${index}`));
|
|
338
|
+
})] }, id));
|
|
339
|
+
}
|
|
340
|
+
case "table-seat-square": {
|
|
341
|
+
const openSpace = item.openSpace || 0; // from 0 to 0.9
|
|
342
|
+
const r = 10;
|
|
343
|
+
const seatPositions = item.seatPositions;
|
|
344
|
+
const topCount = (_b = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.top) !== null && _b !== void 0 ? _b : 0;
|
|
345
|
+
const bottomCount = (_c = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.bottom) !== null && _c !== void 0 ? _c : 0;
|
|
346
|
+
const leftCount = (_d = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.left) !== null && _d !== void 0 ? _d : 0;
|
|
347
|
+
const rightCount = (_e = seatPositions === null || seatPositions === void 0 ? void 0 : seatPositions.right) !== null && _e !== void 0 ? _e : 0;
|
|
348
|
+
// split seats evenly on top and bottom
|
|
349
|
+
const seatCountTopBottom = Math.ceil(Math.max(topCount, bottomCount) / 2);
|
|
350
|
+
const seatCountLeftRight = Math.ceil(Math.max(leftCount, rightCount) / 2);
|
|
351
|
+
const availableWidth = width * (1 - openSpace);
|
|
352
|
+
const availableHeight = height * (1 - openSpace);
|
|
353
|
+
const spacingWidth = availableWidth / seatCountTopBottom;
|
|
354
|
+
const spacingHeight = availableHeight / seatCountLeftRight;
|
|
355
|
+
const topXs = distributeWithSpacing({
|
|
356
|
+
start: x,
|
|
357
|
+
length: width,
|
|
358
|
+
count: topCount,
|
|
359
|
+
radius: r,
|
|
360
|
+
spacing: spacingWidth,
|
|
361
|
+
});
|
|
362
|
+
const topSeats = topXs.map((cx) => ({ cx, cy: y - r, id: "top" }));
|
|
363
|
+
// TOP
|
|
364
|
+
const bottomSeats = distributeWithSpacing({
|
|
365
|
+
start: x,
|
|
366
|
+
length: width,
|
|
367
|
+
count: bottomCount,
|
|
368
|
+
radius: r,
|
|
369
|
+
spacing: spacingWidth,
|
|
370
|
+
}).map((cx) => ({
|
|
371
|
+
cx: cx,
|
|
372
|
+
cy: y + height + r,
|
|
373
|
+
id: "bottom",
|
|
374
|
+
}));
|
|
375
|
+
const leftYs = distributeWithSpacing({
|
|
376
|
+
start: y,
|
|
377
|
+
length: height,
|
|
378
|
+
count: leftCount,
|
|
379
|
+
radius: r,
|
|
380
|
+
spacing: spacingHeight,
|
|
381
|
+
});
|
|
382
|
+
const leftSeats = leftYs.map((cy) => ({ cx: x - r, cy, id: "left" }));
|
|
383
|
+
const rightSeats = distributeWithSpacing({
|
|
384
|
+
start: y,
|
|
385
|
+
length: height,
|
|
386
|
+
count: rightCount,
|
|
387
|
+
radius: r,
|
|
388
|
+
spacing: spacingHeight,
|
|
389
|
+
}).map((cy) => ({
|
|
390
|
+
cx: x + width + r,
|
|
391
|
+
cy,
|
|
392
|
+
id: "right",
|
|
393
|
+
}));
|
|
394
|
+
return (_jsx("g", { "data-id": id, transform: `translate(${x}, ${y})`, children: _jsxs("g", { transform: `rotate(${rotate}, 0, 0)`, children: [_jsx("rect", Object.assign({ width: width, height: height }, commonProps, { fill: selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill })), renderTags(tags), _jsx("g", { fill: "#e6b9c0", stroke: "#c49ba3", strokeWidth: "1", "data-seat": `${id}-seats`, transform: `translate(${-x}, ${-y})`, children: [...topSeats, ...bottomSeats, ...leftSeats, ...rightSeats].map(({ cx, cy, id }, i) => (_jsx("circle", { id: `seat-${id}`, cx: cx, cy: cy, r: r, fill: seatFill }, `${id}-seat-${i}`))) }, `${id}-seats`), _jsx("text", { x: x + width / 2, y: y + height / 2, fill: fontColor !== null && fontColor !== void 0 ? fontColor : "black", fontSize: `${fontSize !== null && fontSize !== void 0 ? fontSize : 10}px`, fontWeight: "bold", textAnchor: "middle", dominantBaseline: "middle", children: label })] }) }, id));
|
|
395
|
+
}
|
|
396
|
+
case "text":
|
|
397
|
+
return (_jsxs("g", { onContextMenu: (e) => e.preventDefault(), children: [_jsx("rect", { x: x, y: y, width: width, height: height, fill: "transparent", opacity: opacity }), _jsx("text", Object.assign({ x: x + width / 2, y: y + height / 2, textAnchor: "middle", dominantBaseline: "middle", fill: fontColor, fontSize: fontSize !== null && fontSize !== void 0 ? fontSize : height * 0.6, opacity: opacity }, omit(commonProps, ["fill", "opacity"]), { children: text }))] }, id));
|
|
398
|
+
case "image-table":
|
|
399
|
+
return (_jsxs("g", { onContextMenu: (e) => e.preventDefault(), onDragEnter: (e) => {
|
|
400
|
+
e.preventDefault(); // penting
|
|
401
|
+
const group = e.currentTarget;
|
|
402
|
+
highlightGroup(group, "dragenter");
|
|
403
|
+
}, onDragOver: (e) => {
|
|
404
|
+
e.preventDefault(); // agar drop diterima
|
|
405
|
+
}, onDragLeave: (e) => {
|
|
406
|
+
const group = e.currentTarget;
|
|
407
|
+
unhighlightGroup(group);
|
|
408
|
+
}, onDrop: (e) => {
|
|
409
|
+
e.preventDefault();
|
|
410
|
+
const group = e.currentTarget;
|
|
411
|
+
// restore langsung dan reset
|
|
412
|
+
forceRestoreGroup(group);
|
|
413
|
+
}, onPointerOver: (e) => {
|
|
414
|
+
e.preventDefault(); // penting
|
|
415
|
+
const group = e.currentTarget;
|
|
416
|
+
highlightGroup(group, "pointerover");
|
|
417
|
+
}, onPointerOut: (e) => {
|
|
418
|
+
const group = e.currentTarget;
|
|
419
|
+
unhighlightGroup(group);
|
|
420
|
+
}, onPointerUp: (e) => {
|
|
421
|
+
e.preventDefault();
|
|
422
|
+
const group = e.currentTarget;
|
|
423
|
+
// restore langsung dan reset
|
|
424
|
+
forceRestoreGroup(group);
|
|
425
|
+
}, onMouseDown: (e) => {
|
|
426
|
+
e.preventDefault();
|
|
427
|
+
const group = e.currentTarget;
|
|
428
|
+
highlightGroup(group, "mousedown");
|
|
429
|
+
}, children: [_jsx("image", Object.assign({ href: src, x: x, y: y, "data-id": id, width: width, height: height, transform: transformRotate }, commonProps)), labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
430
|
+
var _a, _b, _c, _d;
|
|
431
|
+
return (_jsx("text", { 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, children: _ === null || _ === void 0 ? void 0 : _.label }, index));
|
|
432
|
+
})] }, id));
|
|
433
|
+
case "background":
|
|
434
|
+
return (_jsxs("g", { onContextMenu: (e) => e.preventDefault(), children: [_jsx("image", Object.assign({ href: src, x: x, y: y, width: width, height: height, transform: transformRotate }, commonProps)), labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
435
|
+
var _a, _b, _c, _d;
|
|
436
|
+
return (_jsx("text", { 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, children: _ === null || _ === void 0 ? void 0 : _.label }, index));
|
|
437
|
+
})] }, id));
|
|
438
|
+
default:
|
|
439
|
+
return _jsx("g", {}, id);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
let date = new Date();
|
|
443
|
+
return _jsx("g", { children: components === null || components === void 0 ? void 0 : components.map(renderShape) }, `${date}`);
|
|
444
|
+
};
|
|
445
|
+
export default Layers;
|
|
@@ -4,7 +4,7 @@ import { useEffect } from "react";
|
|
|
4
4
|
import Board from "../../features/board";
|
|
5
5
|
import SideTool from "../../features/side-tool";
|
|
6
6
|
import ControlPanels from "../../features/panel";
|
|
7
|
-
import LayerView from "../../features/view";
|
|
7
|
+
import LayerView from "../../features/view-only";
|
|
8
8
|
import { useAppDispatch } from "../../hooks/use-redux";
|
|
9
9
|
const TableEditor = ({ componentProps = [], extraComponentProps = [], }) => {
|
|
10
10
|
const dispatch = useAppDispatch();
|
|
@@ -6,7 +6,7 @@ import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
|
|
|
6
6
|
import Layers from "../../components/layer";
|
|
7
7
|
import { throttle } from "lodash";
|
|
8
8
|
import ModalPreview from "../../components/modal-preview";
|
|
9
|
-
import LayerView from "../view";
|
|
9
|
+
import LayerView from "../view-only";
|
|
10
10
|
import { isEqual, debounce } from "lodash";
|
|
11
11
|
import { ZoomIn, ZoomOut } from "lucide-react";
|
|
12
12
|
import { Button } from "antd";
|
|
@@ -6,7 +6,7 @@ import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
|
|
|
6
6
|
import Layers from "../../components/layer-v2";
|
|
7
7
|
import { throttle } from "lodash";
|
|
8
8
|
import ModalPreview from "../../components/modal-preview";
|
|
9
|
-
import LayerView from "../view";
|
|
9
|
+
import LayerView from "../view-only-2";
|
|
10
10
|
import { isEqual, debounce } from "lodash";
|
|
11
11
|
import { ZoomIn, ZoomOut } from "lucide-react";
|
|
12
12
|
import { Button } from "antd";
|
|
@@ -10,6 +10,7 @@ export interface InitialState {
|
|
|
10
10
|
flagChange: boolean;
|
|
11
11
|
historyChanges: any[];
|
|
12
12
|
pointer: number;
|
|
13
|
+
updateBy: "global" | "local";
|
|
13
14
|
}
|
|
14
15
|
export declare const addComponent: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "board/addComponent">, removeComponent: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "board/removeComponent">, updateComponent: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "board/updateComponent">, setBackgroundColor: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "board/setBackgroundColor">, removeExtraComponent: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "board/removeExtraComponent">;
|
|
15
16
|
declare const _default: import("redux").Reducer<InitialState>;
|
|
@@ -6,13 +6,17 @@ const initialState = {
|
|
|
6
6
|
extraComponents: [],
|
|
7
7
|
flagChange: false,
|
|
8
8
|
historyChanges: [],
|
|
9
|
-
pointer: 0
|
|
9
|
+
pointer: 0,
|
|
10
|
+
updateBy: "global",
|
|
10
11
|
};
|
|
11
12
|
const MAX_HISTORY_CHANGES = 20;
|
|
12
13
|
const boardSlice = createSlice({
|
|
13
14
|
name: "board",
|
|
14
15
|
initialState,
|
|
15
16
|
reducers: {
|
|
17
|
+
setUpdateBy: (state, action) => {
|
|
18
|
+
state.updateBy = action.payload;
|
|
19
|
+
},
|
|
16
20
|
addComponent: (state, action) => {
|
|
17
21
|
state.components.push(action.payload);
|
|
18
22
|
},
|
|
@@ -39,10 +43,23 @@ const boardSlice = createSlice({
|
|
|
39
43
|
state.extraComponents[indexExtra] = Object.assign(Object.assign({}, state.extraComponents[indexExtra]), action.payload);
|
|
40
44
|
}
|
|
41
45
|
},
|
|
46
|
+
updateAllComponents: (state, action) => {
|
|
47
|
+
[...state.components, ...state.extraComponents].forEach((component) => {
|
|
48
|
+
const updatedComponent = action.payload.find((comp) => comp.id === component.id);
|
|
49
|
+
if (updatedComponent) {
|
|
50
|
+
Object.assign(component, Object.assign(Object.assign({}, component), updatedComponent));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
},
|
|
42
54
|
setBackgroundColor: (state, action) => {
|
|
43
55
|
state.backgroundColor = action.payload;
|
|
44
56
|
},
|
|
45
57
|
setNewComponents: (state, action) => {
|
|
58
|
+
const currentPointer = state.pointer;
|
|
59
|
+
const totalHistory = state.historyChanges.length;
|
|
60
|
+
if (currentPointer < totalHistory) {
|
|
61
|
+
state.historyChanges = state.historyChanges.slice(0, currentPointer + 1);
|
|
62
|
+
}
|
|
46
63
|
state.components = action.payload;
|
|
47
64
|
state.historyChanges.push(state.components);
|
|
48
65
|
if (state.historyChanges.length > MAX_HISTORY_CHANGES) {
|
|
@@ -61,8 +78,14 @@ const boardSlice = createSlice({
|
|
|
61
78
|
},
|
|
62
79
|
undoHistory: (state) => {
|
|
63
80
|
if (state.pointer > 1) {
|
|
64
|
-
state.
|
|
65
|
-
|
|
81
|
+
const lengthHistory = state.historyChanges.length;
|
|
82
|
+
if (lengthHistory === state.pointer) {
|
|
83
|
+
state.pointer = lengthHistory - 2;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
state.pointer -= 1;
|
|
87
|
+
}
|
|
88
|
+
const prev = state.historyChanges[state.pointer];
|
|
66
89
|
state.components = current(prev);
|
|
67
90
|
}
|
|
68
91
|
else if (state.pointer === 1) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
interface BoardTemplateProps {
|
|
2
|
+
onSelectComponent?: (items: any) => void;
|
|
3
|
+
mappingKey?: string;
|
|
4
|
+
viewOnly?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const BoardTemplate: ({ onSelectComponent, viewOnly }: BoardTemplateProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default BoardTemplate;
|
|
8
|
+
export declare function getTranslate(el: any): {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function getSize(el: any): {
|
|
13
|
+
width: any;
|
|
14
|
+
height: any;
|
|
15
|
+
};
|
|
16
|
+
type ResizeSide = string;
|
|
17
|
+
export declare function getPolygonCenter(points: Pt[]): {
|
|
18
|
+
cx: number;
|
|
19
|
+
cy: number;
|
|
20
|
+
};
|
|
21
|
+
type Pt = {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
type ResizeResult = {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
cx: number;
|
|
31
|
+
cy: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function applyResizeToSvgElement(element: SVGGraphicsElement, group: SVGGElement, resize: ResizeResult, inner: any): void;
|
|
34
|
+
type ResizeParams = {
|
|
35
|
+
element: SVGGraphicsElement;
|
|
36
|
+
group: SVGGElement;
|
|
37
|
+
resizeSide: ResizeSide;
|
|
38
|
+
widthOriginal: number;
|
|
39
|
+
heightOriginal: number;
|
|
40
|
+
deltaLocalX: number;
|
|
41
|
+
deltaLocalY: number;
|
|
42
|
+
xOriginal: number;
|
|
43
|
+
yOriginal: number;
|
|
44
|
+
angle: number;
|
|
45
|
+
seats?: any;
|
|
46
|
+
};
|
|
47
|
+
export declare function applyResizeWithRotation({ element, group, resizeSide, widthOriginal, heightOriginal, deltaLocalX, deltaLocalY, xOriginal, yOriginal, angle, seats, }: ResizeParams): void;
|