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,217 @@
1
+ // components/ConnectionLayer.tsx
2
+ import React, { useMemo, useState } from "react";
3
+ import { buildCurvePath, getCurveEndAngle, getRectEdge, NODE_WIDTH, NODE_HEIGHT, } from "./utils";
4
+ // ─── Constants ────────────────────────────────────────────────────────────────
5
+ const LEVEL_COLORS = [
6
+ "#22c55e",
7
+ "#f59e0b",
8
+ "#f97316",
9
+ "#ef4444",
10
+ "#a78bfa",
11
+ "#38bdf8",
12
+ ];
13
+ const getLevelColor = (level) => LEVEL_COLORS[Math.min(level, LEVEL_COLORS.length - 1)];
14
+ // ─── BFS flood fill ───────────────────────────────────────────────────────────
15
+ const floodFill = (seedIds, edges) => {
16
+ const levelMap = new Map();
17
+ const queue = [];
18
+ seedIds.forEach((id) => { levelMap.set(id, 0); queue.push({ id, level: 0 }); });
19
+ while (queue.length > 0) {
20
+ const { id, level } = queue.shift();
21
+ edges.forEach((edge) => {
22
+ const neighbors = [];
23
+ if (edge.from === id)
24
+ neighbors.push(edge.to);
25
+ if (edge.to === id)
26
+ neighbors.push(edge.from);
27
+ neighbors.forEach((nId) => {
28
+ if (!levelMap.has(nId)) {
29
+ levelMap.set(nId, level + 1);
30
+ queue.push({ id: nId, level: level + 1 });
31
+ }
32
+ });
33
+ });
34
+ }
35
+ return levelMap;
36
+ };
37
+ // ─── Group edges by source ────────────────────────────────────────────────────
38
+ const groupBySource = (edges) => {
39
+ const map = new Map();
40
+ edges.forEach((edge) => {
41
+ if (!map.has(edge.from))
42
+ map.set(edge.from, []);
43
+ map.get(edge.from).push(edge);
44
+ });
45
+ return map;
46
+ };
47
+ // ─── Component ────────────────────────────────────────────────────────────────
48
+ export const ConnectionLayer = ({ edges, selectedEdge, connecting, mousePos, getNodeById, onSelectEdge,
49
+ // onDeleteEdge,
50
+ }) => {
51
+ const [hoveredEdge, setHoveredEdge] = useState(null);
52
+ // ── Flood fill highlight ──────────────────────────────────────────
53
+ const nodeHighlightMap = useMemo(() => {
54
+ if (!selectedEdge)
55
+ return new Map();
56
+ const sel = edges.find((e) => e.id === selectedEdge);
57
+ if (!sel)
58
+ return new Map();
59
+ return floodFill([sel.from, sel.to], edges);
60
+ }, [selectedEdge, edges]);
61
+ // ── Group by source for shared stem ──────────────────────────────
62
+ const sourceGroups = useMemo(() => groupBySource(edges), [edges]);
63
+ // ── Pre-compute curve data per edge ──────────────────────────────
64
+ const curveData = useMemo(() => {
65
+ const map = new Map();
66
+ edges.forEach((edge) => {
67
+ const fromNode = getNodeById(edge.from);
68
+ const toNode = getNodeById(edge.to);
69
+ if (!fromNode || !toNode)
70
+ return;
71
+ const start = getRectEdge(fromNode, toNode, fromNode.width, fromNode.height);
72
+ const end = getRectEdge(toNode, fromNode, toNode.width, toNode.height);
73
+ const pathD = buildCurvePath(start, end);
74
+ const angle = getCurveEndAngle(start, end);
75
+ // Midpoint arc/elbow → titik belok pertama (elbow kiri/atas)
76
+ const dx = end.x - start.x;
77
+ const dy = end.y - start.y;
78
+ const absDx = Math.abs(dx);
79
+ const absDy = Math.abs(dy);
80
+ let midX;
81
+ let midY;
82
+ if (absDx >= absDy) {
83
+ // Dominan horizontal → elbow di (midX, start.y)
84
+ midX = (start.x + end.x) / 2;
85
+ midY = (start.y + end.y) / 2;
86
+ }
87
+ else {
88
+ // Dominan vertikal → elbow di (start.x, midY)
89
+ midX = (start.x + end.x) / 2;
90
+ midY = (start.y + end.y) / 2;
91
+ }
92
+ map.set(edge.id, { start, end, pathD, angle, midX, midY });
93
+ });
94
+ return map;
95
+ }, [edges, getNodeById]);
96
+ // ── Shared stem exit point per source ────────────────────────────
97
+ const stemData = useMemo(() => {
98
+ const map = new Map();
99
+ sourceGroups.forEach((groupEdges, fromId) => {
100
+ if (groupEdges.length <= 1)
101
+ return;
102
+ const sourceNode = getNodeById(fromId);
103
+ if (!sourceNode)
104
+ return;
105
+ const exits = groupEdges
106
+ .map((edge) => {
107
+ const toNode = getNodeById(edge.to);
108
+ if (!toNode)
109
+ return null;
110
+ return getRectEdge(sourceNode, toNode, sourceNode.width, sourceNode.height);
111
+ })
112
+ .filter(Boolean);
113
+ if (exits.length === 0)
114
+ return;
115
+ map.set(fromId, {
116
+ x: exits.reduce((s, p) => s + p.x, 0) / exits.length,
117
+ y: exits.reduce((s, p) => s + p.y, 0) / exits.length,
118
+ });
119
+ });
120
+ return map;
121
+ }, [sourceGroups, getNodeById]);
122
+ return (<g id="connection-layer">
123
+
124
+ {/* ── Node border highlight (flood fill) ───────────────────────── */}
125
+ {Array.from(nodeHighlightMap.entries()).map(([nodeId, level]) => {
126
+ var _a, _b, _c;
127
+ const node = getNodeById(nodeId);
128
+ if (!node)
129
+ return null;
130
+ const w = (_a = node.width) !== null && _a !== void 0 ? _a : NODE_WIDTH;
131
+ const h = (_b = node.height) !== null && _b !== void 0 ? _b : NODE_HEIGHT;
132
+ const rotation = (_c = node.rotation) !== null && _c !== void 0 ? _c : 0;
133
+ const color = getLevelColor(level);
134
+ const padding = 4;
135
+ return (<g key={`highlight-${nodeId}`} transform={`translate(${node.x}, ${node.y}) rotate(${rotation})`} style={{ pointerEvents: "none" }}>
136
+ <rect x={-w / 2 - padding} y={-h / 2 - padding} width={w + padding * 2} height={h + padding * 2} fill="none" stroke={color} strokeWidth={8} rx={5} opacity={0.08}/>
137
+ <rect x={-w / 2 - padding} y={-h / 2 - padding} width={w + padding * 2} height={h + padding * 2} fill="none" stroke={color} strokeWidth={level === 0 ? 2.5 : 1.5} strokeDasharray={level === 0 ? "none" : "5 3"} rx={5} opacity={level === 0 ? 1 : 0.75}/>
138
+ <g transform={`translate(${w / 2 + padding - 2}, ${-h / 2 - padding})`}>
139
+ <circle r={7} fill={color} opacity={0.9}/>
140
+ <text textAnchor="middle" dominantBaseline="middle" fill="white" fontSize={7} fontFamily="monospace" fontWeight={700} style={{ userSelect: "none" }}>{level}</text>
141
+ </g>
142
+ </g>);
143
+ })}
144
+
145
+ {/* ── Stem dot di shared source exit ───────────────────────────── */}
146
+ {Array.from(stemData.entries()).map(([fromId, stemExit]) => {
147
+ var _a;
148
+ const isStemOfSelected = selectedEdge && ((_a = edges.find((e) => e.id === selectedEdge)) === null || _a === void 0 ? void 0 : _a.from) === fromId;
149
+ const color = isStemOfSelected ? "#a78bfa" : "#38bdf8";
150
+ return (<g key={`stem-dot-${fromId}`} style={{ pointerEvents: "none" }}>
151
+ <circle cx={stemExit.x} cy={stemExit.y} r={5} fill="#0f172a" stroke={color} strokeWidth={1.5}/>
152
+ <circle cx={stemExit.x} cy={stemExit.y} r={2.5} fill={color}/>
153
+ </g>);
154
+ })}
155
+
156
+ {/* ── Render edges ─────────────────────────────────────────────── */}
157
+ {edges.map((edge) => {
158
+ const data = curveData.get(edge.id);
159
+ if (!data)
160
+ return null;
161
+ const { pathD, angle, midX, midY } = data;
162
+ const isSel = selectedEdge === edge.id;
163
+ const isHov = hoveredEdge === edge.id;
164
+ const markerId = `conn-arrow-${edge.id}`;
165
+ const markerSelId = `conn-arrow-sel-${edge.id}`;
166
+ // Warna edge jika dalam network highlight
167
+ const fromLevel = nodeHighlightMap.get(edge.from);
168
+ const toLevel = nodeHighlightMap.get(edge.to);
169
+ const isInNetwork = fromLevel !== undefined && toLevel !== undefined;
170
+ const networkColor = isInNetwork
171
+ ? getLevelColor(Math.max(fromLevel, toLevel))
172
+ : "#38bdf8";
173
+ return (<g key={edge.id}>
174
+ <defs>
175
+ <marker id={markerId} markerWidth="8" markerHeight="8" refX="7" refY="3" orient={`${angle}deg`}>
176
+ <path d="M 0 0 L 8 3 L 0 6 Z" fill={isSel ? "#a78bfa" : isInNetwork && !isSel ? networkColor : "#38bdf8"} opacity={0.9}/>
177
+ </marker>
178
+ </defs>
179
+
180
+ {/* Hit area */}
181
+ <path d={pathD} stroke="transparent" strokeWidth={14} fill="none" style={{ cursor: "pointer" }} onClick={(e) => { e.stopPropagation(); onSelectEdge(edge.id); }} onMouseEnter={() => setHoveredEdge(edge.id)} onMouseLeave={() => setHoveredEdge(null)}/>
182
+
183
+ {/* Glow saat selected/hovered */}
184
+ {(isSel || isHov) && (<path d={pathD} stroke={isSel ? "#a78bfa" : "#38bdf8"} strokeWidth={8} fill="none" opacity={isSel ? 0.12 : 0.06} style={{ pointerEvents: "none" }}/>)}
185
+
186
+ {/* Curve utama */}
187
+ <path d={pathD} stroke={isSel ? "#a78bfa" : isInNetwork && selectedEdge ? networkColor : "#38bdf8"} strokeWidth={isSel ? 2 : isHov ? 2 : 1.5} fill="none" opacity={selectedEdge && !isSel && !isInNetwork ? 0.25 : 0.9} markerEnd={`url(#${markerId})`} style={{ pointerEvents: "none" }}/>
188
+
189
+ {/* DEL badge saat selected */}
190
+ {isSel && (<g style={{ pointerEvents: "none" }}>
191
+ <rect x={midX - 16} y={midY - 10} width={32} height={18} rx={4} fill="#1e1b2e" stroke="#a78bfa" strokeWidth={1} opacity={0.95}/>
192
+ <text x={midX} y={midY} textAnchor="middle" dominantBaseline="middle" fill="#a78bfa" fontSize={9} fontFamily="monospace" fontWeight={600}>
193
+ DEL
194
+ </text>
195
+ </g>)}
196
+ </g>);
197
+ })}
198
+
199
+ {/* ── Preview curve saat connecting ─────────────────────────────── */}
200
+ {connecting && (() => {
201
+ const fromNode = getNodeById(connecting.fromId);
202
+ if (!fromNode)
203
+ return null;
204
+ const start = getRectEdge(fromNode, mousePos, fromNode.width, fromNode.height);
205
+ const pathD = buildCurvePath(start, mousePos);
206
+ const angle = getCurveEndAngle(start, mousePos);
207
+ return (<g>
208
+ <defs>
209
+ <marker id="conn-preview-arrow" markerWidth="8" markerHeight="8" refX="7" refY="3" orient={`${angle}deg`}>
210
+ <path d="M 0 0 L 8 3 L 0 6 Z" fill="#a78bfa" opacity={0.85}/>
211
+ </marker>
212
+ </defs>
213
+ <path d={pathD} stroke="#a78bfa" strokeWidth={1.5} fill="none" strokeDasharray="6 3" markerEnd="url(#conn-preview-arrow)" opacity={0.8} style={{ pointerEvents: "none" }}/>
214
+ </g>);
215
+ })()}
216
+ </g>);
217
+ };
@@ -0,0 +1,99 @@
1
+ import React, { CSSProperties, SVGAttributes } from "react";
2
+ import { ReactZoomPanPinchRef, ReactZoomPanPinchProps, ReactZoomPanPinchContentRef } from "react-zoom-pan-pinch";
3
+ import { PropertiesProps } from "../../dto/table";
4
+ import { EventHandleType } from "../../dto/event-handler";
5
+ import { EdgeType } from "./utils";
6
+ export type TableGhost = {
7
+ table: PropertiesProps;
8
+ event: EventHandleType;
9
+ };
10
+ export type TableMatchKey = {
11
+ key: string | number;
12
+ properties?: PropertiesProps;
13
+ className?: string;
14
+ };
15
+ export type TableMatchEvent = {
16
+ event: EventHandleType;
17
+ properties: PropertiesProps;
18
+ };
19
+ export type ComponentProps<T = undefined> = T extends undefined ? PropertiesProps : Omit<PropertiesProps, keyof T> & T;
20
+ export type OnCurrentStateChange<TMeta = undefined> = ({ components, extraComponents, background, boundingBox, }: {
21
+ components: ComponentProps<TMeta>[];
22
+ extraComponents: ComponentProps[];
23
+ background: string;
24
+ boundingBox: PropertiesProps | null;
25
+ }) => void;
26
+ export type TransformProps = React.ForwardRefExoticComponent<Omit<ReactZoomPanPinchProps, "ref"> & React.RefAttributes<ReactZoomPanPinchContentRef>>;
27
+ export type RefLayerView = {
28
+ svgRef: SVGSVGElement;
29
+ transformRef: ReactZoomPanPinchRef;
30
+ containerRef: HTMLDivElement;
31
+ tableGhost: SVGGElement;
32
+ hoverUnderghost: ComponentProps;
33
+ };
34
+ export type TypeActionProps<TMeta = undefined> = {
35
+ targetTable: ComponentProps<TMeta>;
36
+ sourceTable: ComponentProps<TMeta>;
37
+ };
38
+ export interface LayerViewProps<TMeta = undefined> {
39
+ componentProps?: ComponentProps<TMeta>[];
40
+ extraComponentProps?: ComponentProps[];
41
+ onSelectComponent?: (component: ComponentProps<TMeta>) => void;
42
+ onDoubleClick?: (component: ComponentProps<TMeta>) => void;
43
+ mappingKey?: string;
44
+ tableMatchKey?: TableMatchKey[];
45
+ eventMatchTable?: TableMatchEvent[];
46
+ statusKey?: string;
47
+ defaultBackground?: string;
48
+ transformProps?: ReactZoomPanPinchProps;
49
+ containerProps?: React.HTMLAttributes<HTMLDivElement>;
50
+ svgProps?: SVGAttributes<SVGSVGElement>;
51
+ ghostAttributes?: SVGAttributes<SVGGElement>;
52
+ iconTags?: {
53
+ icon: React.JSX.Element;
54
+ key: string;
55
+ }[];
56
+ privilegedTags?: {
57
+ key: string;
58
+ items: string[];
59
+ }[];
60
+ tooltipProps?: {
61
+ className?: string;
62
+ style?: CSSProperties;
63
+ minWidth?: number;
64
+ children: React.ReactNode;
65
+ };
66
+ dragTableBlockKey?: {
67
+ key: string;
68
+ value: string | number | null;
69
+ }[];
70
+ onRightClick?: (e: MouseEvent, component: ComponentProps<TMeta>) => void;
71
+ allowTooltip?: boolean;
72
+ onDrop?: (e: React.MouseEvent<SVGSVGElement>, component: TypeActionProps<TMeta>) => void;
73
+ onSwitch?: (e: MouseEvent, component: TypeActionProps<TMeta>) => void;
74
+ refs?: React.ForwardedRef<RefLayerView>;
75
+ viewStyles?: {
76
+ paddingTop?: number;
77
+ paddingLeft?: number;
78
+ paddingRight?: number;
79
+ paddingBottom?: number;
80
+ };
81
+ loadingRender?: {
82
+ state: boolean;
83
+ element: React.JSX.Element;
84
+ };
85
+ defaultBoundingBox?: PropertiesProps;
86
+ viewOnly?: boolean;
87
+ actionPrivileged?: {
88
+ select?: boolean;
89
+ move?: boolean;
90
+ switch?: boolean;
91
+ drop?: boolean;
92
+ rightClick?: boolean;
93
+ double?: boolean;
94
+ };
95
+ onEdgesChange?: (edges: EdgeType[], table: PropertiesProps[]) => void;
96
+ keyNode: string;
97
+ }
98
+ declare const LayerView: <TMeta>(props: LayerViewProps<TMeta>) => import("react/jsx-runtime").JSX.Element;
99
+ export default LayerView;