@particle-academy/react-fancy 2.10.0 → 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/README.md +20 -0
- package/dist/index.cjs +1 -1941
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -294
- package/dist/index.d.ts +40 -294
- package/dist/index.js +2 -1649
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/diagram.serializers-6RPUO46U.js +0 -273
- package/dist/diagram.serializers-6RPUO46U.js.map +0 -1
- package/docs/Canvas.md +0 -105
- package/docs/Diagram.md +0 -151
package/dist/index.cjs
CHANGED
|
@@ -28,296 +28,7 @@ function _interopNamespace(e) {
|
|
|
28
28
|
|
|
29
29
|
var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
33
|
-
var __esm = (fn, res) => function __init() {
|
|
34
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
35
|
-
};
|
|
36
|
-
var __export = (target, all) => {
|
|
37
|
-
for (var name in all)
|
|
38
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// src/components/Diagram/diagram.serializers.ts
|
|
42
|
-
var diagram_serializers_exports = {};
|
|
43
|
-
__export(diagram_serializers_exports, {
|
|
44
|
-
deserializeSchema: () => deserializeSchema,
|
|
45
|
-
serializeToDFD: () => serializeToDFD,
|
|
46
|
-
serializeToERD: () => serializeToERD,
|
|
47
|
-
serializeToUML: () => serializeToUML
|
|
48
|
-
});
|
|
49
|
-
function serializeToERD(schema) {
|
|
50
|
-
const lines = [];
|
|
51
|
-
for (const entity of schema.entities) {
|
|
52
|
-
lines.push(`[${entity.name}]`);
|
|
53
|
-
if (entity.fields) {
|
|
54
|
-
for (const field of entity.fields) {
|
|
55
|
-
const parts = [` ${field.name}`];
|
|
56
|
-
if (field.type) parts.push(field.type);
|
|
57
|
-
if (field.primary) parts.push("PK");
|
|
58
|
-
if (field.foreign) parts.push("FK");
|
|
59
|
-
if (field.nullable) parts.push("?");
|
|
60
|
-
lines.push(parts.join(" "));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
lines.push("");
|
|
64
|
-
}
|
|
65
|
-
for (const rel of schema.relations) {
|
|
66
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
67
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
68
|
-
if (!fromEntity || !toEntity) continue;
|
|
69
|
-
const marker = getERDMarker(rel.type);
|
|
70
|
-
const parts = [fromEntity.name, marker, toEntity.name];
|
|
71
|
-
if (rel.label) parts.push(`: ${rel.label}`);
|
|
72
|
-
lines.push(parts.join(" "));
|
|
73
|
-
}
|
|
74
|
-
return lines.join("\n").trim();
|
|
75
|
-
}
|
|
76
|
-
function getERDMarker(type) {
|
|
77
|
-
switch (type) {
|
|
78
|
-
case "one-to-one":
|
|
79
|
-
return "1--1";
|
|
80
|
-
case "one-to-many":
|
|
81
|
-
return "1--*";
|
|
82
|
-
case "many-to-many":
|
|
83
|
-
return "*--*";
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function serializeToUML(schema) {
|
|
87
|
-
const lines = ["@startuml"];
|
|
88
|
-
for (const entity of schema.entities) {
|
|
89
|
-
lines.push(`class ${entity.name} {`);
|
|
90
|
-
if (entity.fields) {
|
|
91
|
-
for (const field of entity.fields) {
|
|
92
|
-
const typeStr = field.type ?? "any";
|
|
93
|
-
const nullable = field.nullable ? "?" : "";
|
|
94
|
-
const stereotype = field.primary ? " <<PK>>" : field.foreign ? " <<FK>>" : "";
|
|
95
|
-
lines.push(` ${field.name} : ${typeStr}${nullable}${stereotype}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
lines.push("}");
|
|
99
|
-
lines.push("");
|
|
100
|
-
}
|
|
101
|
-
for (const rel of schema.relations) {
|
|
102
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
103
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
104
|
-
if (!fromEntity || !toEntity) continue;
|
|
105
|
-
const arrow = getUMLArrow(rel.type);
|
|
106
|
-
const label = rel.label ? ` : ${rel.label}` : "";
|
|
107
|
-
lines.push(`${fromEntity.name} ${arrow} ${toEntity.name}${label}`);
|
|
108
|
-
}
|
|
109
|
-
lines.push("@enduml");
|
|
110
|
-
return lines.join("\n");
|
|
111
|
-
}
|
|
112
|
-
function getUMLArrow(type) {
|
|
113
|
-
switch (type) {
|
|
114
|
-
case "one-to-one":
|
|
115
|
-
return '"1" -- "1"';
|
|
116
|
-
case "one-to-many":
|
|
117
|
-
return '"1" -- "*"';
|
|
118
|
-
case "many-to-many":
|
|
119
|
-
return '"*" -- "*"';
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function serializeToDFD(schema) {
|
|
123
|
-
const lines = [];
|
|
124
|
-
for (const entity of schema.entities) {
|
|
125
|
-
lines.push(`entity ${entity.name}`);
|
|
126
|
-
}
|
|
127
|
-
lines.push("");
|
|
128
|
-
for (const rel of schema.relations) {
|
|
129
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
130
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
131
|
-
if (!fromEntity || !toEntity) continue;
|
|
132
|
-
const label = rel.label ? ` "${rel.label}"` : "";
|
|
133
|
-
lines.push(`${fromEntity.name} -> ${toEntity.name}${label}`);
|
|
134
|
-
}
|
|
135
|
-
return lines.join("\n").trim();
|
|
136
|
-
}
|
|
137
|
-
function deserializeSchema(input, format) {
|
|
138
|
-
switch (format) {
|
|
139
|
-
case "erd":
|
|
140
|
-
return deserializeERD(input);
|
|
141
|
-
case "uml":
|
|
142
|
-
return deserializeUML(input);
|
|
143
|
-
case "dfd":
|
|
144
|
-
return deserializeDFD(input);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function deserializeERD(input) {
|
|
148
|
-
const entities = [];
|
|
149
|
-
const relations = [];
|
|
150
|
-
const lines = input.split("\n");
|
|
151
|
-
let currentEntity = null;
|
|
152
|
-
for (const rawLine of lines) {
|
|
153
|
-
const line = rawLine.trim();
|
|
154
|
-
const entityMatch = line.match(/^\[(.+)\]$/);
|
|
155
|
-
if (entityMatch) {
|
|
156
|
-
currentEntity = {
|
|
157
|
-
id: entityMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
158
|
-
name: entityMatch[1],
|
|
159
|
-
fields: []
|
|
160
|
-
};
|
|
161
|
-
entities.push(currentEntity);
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
if (currentEntity && rawLine.startsWith(" ") && line.length > 0) {
|
|
165
|
-
const parts = line.split(/\s+/);
|
|
166
|
-
const field = { name: parts[0] };
|
|
167
|
-
if (parts.length > 1 && !["PK", "FK", "?"].includes(parts[1])) {
|
|
168
|
-
field.type = parts[1];
|
|
169
|
-
}
|
|
170
|
-
if (parts.includes("PK")) field.primary = true;
|
|
171
|
-
if (parts.includes("FK")) field.foreign = true;
|
|
172
|
-
if (parts.includes("?")) field.nullable = true;
|
|
173
|
-
currentEntity.fields.push(field);
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
const relMatch = line.match(
|
|
177
|
-
/^(\S+)\s+(1--1|1--\*|\*--\*)\s+(\S+)(?:\s*:\s*(.+))?$/
|
|
178
|
-
);
|
|
179
|
-
if (relMatch) {
|
|
180
|
-
currentEntity = null;
|
|
181
|
-
const fromName = relMatch[1];
|
|
182
|
-
const marker = relMatch[2];
|
|
183
|
-
const toName = relMatch[3];
|
|
184
|
-
const label = relMatch[4];
|
|
185
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
186
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
187
|
-
if (fromEntity && toEntity) {
|
|
188
|
-
relations.push({
|
|
189
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
190
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
191
|
-
to: toEntity.id ?? toEntity.name,
|
|
192
|
-
type: parseERDMarker(marker),
|
|
193
|
-
label
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (line === "") {
|
|
199
|
-
currentEntity = null;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return { entities, relations };
|
|
203
|
-
}
|
|
204
|
-
function parseERDMarker(marker) {
|
|
205
|
-
switch (marker) {
|
|
206
|
-
case "1--1":
|
|
207
|
-
return "one-to-one";
|
|
208
|
-
case "1--*":
|
|
209
|
-
return "one-to-many";
|
|
210
|
-
case "*--*":
|
|
211
|
-
return "many-to-many";
|
|
212
|
-
default:
|
|
213
|
-
return "one-to-many";
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function deserializeUML(input) {
|
|
217
|
-
const entities = [];
|
|
218
|
-
const relations = [];
|
|
219
|
-
const lines = input.split("\n");
|
|
220
|
-
let currentEntity = null;
|
|
221
|
-
for (const rawLine of lines) {
|
|
222
|
-
const line = rawLine.trim();
|
|
223
|
-
if (line === "@startuml" || line === "@enduml" || line === "") continue;
|
|
224
|
-
const classMatch = line.match(/^class\s+(\S+)\s*\{$/);
|
|
225
|
-
if (classMatch) {
|
|
226
|
-
currentEntity = {
|
|
227
|
-
id: classMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
228
|
-
name: classMatch[1],
|
|
229
|
-
fields: []
|
|
230
|
-
};
|
|
231
|
-
entities.push(currentEntity);
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (line === "}") {
|
|
235
|
-
currentEntity = null;
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
if (currentEntity) {
|
|
239
|
-
const fieldMatch = line.match(
|
|
240
|
-
/^(\S+)\s*:\s*(\S+?)(\?)?(?:\s*<<(PK|FK)>>)?$/
|
|
241
|
-
);
|
|
242
|
-
if (fieldMatch) {
|
|
243
|
-
const field = {
|
|
244
|
-
name: fieldMatch[1],
|
|
245
|
-
type: fieldMatch[2]
|
|
246
|
-
};
|
|
247
|
-
if (fieldMatch[3]) field.nullable = true;
|
|
248
|
-
if (fieldMatch[4] === "PK") field.primary = true;
|
|
249
|
-
if (fieldMatch[4] === "FK") field.foreign = true;
|
|
250
|
-
currentEntity.fields.push(field);
|
|
251
|
-
}
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const relMatch = line.match(
|
|
255
|
-
/^(\S+)\s+"([1*])"\s+--\s+"([1*])"\s+(\S+)(?:\s*:\s*(.+))?$/
|
|
256
|
-
);
|
|
257
|
-
if (relMatch) {
|
|
258
|
-
const fromName = relMatch[1];
|
|
259
|
-
const fromCard = relMatch[2];
|
|
260
|
-
const toCard = relMatch[3];
|
|
261
|
-
const toName = relMatch[4];
|
|
262
|
-
const label = relMatch[5];
|
|
263
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
264
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
265
|
-
if (fromEntity && toEntity) {
|
|
266
|
-
const type = fromCard === "1" && toCard === "1" ? "one-to-one" : fromCard === "1" && toCard === "*" ? "one-to-many" : "many-to-many";
|
|
267
|
-
relations.push({
|
|
268
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
269
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
270
|
-
to: toEntity.id ?? toEntity.name,
|
|
271
|
-
type,
|
|
272
|
-
label
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return { entities, relations };
|
|
278
|
-
}
|
|
279
|
-
function deserializeDFD(input) {
|
|
280
|
-
const entities = [];
|
|
281
|
-
const relations = [];
|
|
282
|
-
const lines = input.split("\n");
|
|
283
|
-
for (const rawLine of lines) {
|
|
284
|
-
const line = rawLine.trim();
|
|
285
|
-
if (line === "") continue;
|
|
286
|
-
const entityMatch = line.match(/^entity\s+(\S+)$/);
|
|
287
|
-
if (entityMatch) {
|
|
288
|
-
entities.push({
|
|
289
|
-
id: entityMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
290
|
-
name: entityMatch[1],
|
|
291
|
-
fields: []
|
|
292
|
-
});
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
const flowMatch = line.match(
|
|
296
|
-
/^(\S+)\s+->\s+(\S+)(?:\s+"(.+)")?$/
|
|
297
|
-
);
|
|
298
|
-
if (flowMatch) {
|
|
299
|
-
const fromName = flowMatch[1];
|
|
300
|
-
const toName = flowMatch[2];
|
|
301
|
-
const label = flowMatch[3];
|
|
302
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
303
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
304
|
-
if (fromEntity && toEntity) {
|
|
305
|
-
relations.push({
|
|
306
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
307
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
308
|
-
to: toEntity.id ?? toEntity.name,
|
|
309
|
-
type: "one-to-many",
|
|
310
|
-
label
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return { entities, relations };
|
|
316
|
-
}
|
|
317
|
-
var init_diagram_serializers = __esm({
|
|
318
|
-
"src/components/Diagram/diagram.serializers.ts"() {
|
|
319
|
-
}
|
|
320
|
-
});
|
|
31
|
+
// src/components/Action/Action.tsx
|
|
321
32
|
function cn(...inputs) {
|
|
322
33
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
323
34
|
}
|
|
@@ -11764,1653 +11475,6 @@ var Kanban = Object.assign(KanbanRoot, {
|
|
|
11764
11475
|
Card: KanbanCard,
|
|
11765
11476
|
ColumnHandle: KanbanColumnHandle
|
|
11766
11477
|
});
|
|
11767
|
-
var CanvasContext = react.createContext(null);
|
|
11768
|
-
function useCanvas() {
|
|
11769
|
-
const ctx = react.useContext(CanvasContext);
|
|
11770
|
-
if (!ctx) throw new Error("useCanvas must be used within a Canvas component");
|
|
11771
|
-
return ctx;
|
|
11772
|
-
}
|
|
11773
|
-
function CanvasNode({ children, id, x, y, draggable, onPositionChange, className, style }) {
|
|
11774
|
-
const { registerNode, unregisterNode, viewport, gridSize, snapToGrid } = useCanvas();
|
|
11775
|
-
const nodeRef = react.useRef(null);
|
|
11776
|
-
const isDragging = react.useRef(false);
|
|
11777
|
-
const dragStart = react.useRef({ mouseX: 0, mouseY: 0, nodeX: 0, nodeY: 0 });
|
|
11778
|
-
react.useEffect(() => {
|
|
11779
|
-
const el = nodeRef.current;
|
|
11780
|
-
if (!el) return;
|
|
11781
|
-
const updateRect = () => {
|
|
11782
|
-
registerNode(id, { x, y, width: el.offsetWidth, height: el.offsetHeight });
|
|
11783
|
-
};
|
|
11784
|
-
updateRect();
|
|
11785
|
-
const observer = new ResizeObserver(updateRect);
|
|
11786
|
-
observer.observe(el);
|
|
11787
|
-
return () => {
|
|
11788
|
-
observer.disconnect();
|
|
11789
|
-
unregisterNode(id);
|
|
11790
|
-
};
|
|
11791
|
-
}, [id, x, y, registerNode, unregisterNode]);
|
|
11792
|
-
const handlePointerDown = react.useCallback(
|
|
11793
|
-
(e) => {
|
|
11794
|
-
if (!draggable || e.button !== 0) return;
|
|
11795
|
-
e.stopPropagation();
|
|
11796
|
-
isDragging.current = true;
|
|
11797
|
-
dragStart.current = { mouseX: e.clientX, mouseY: e.clientY, nodeX: x, nodeY: y };
|
|
11798
|
-
e.target.setPointerCapture(e.pointerId);
|
|
11799
|
-
},
|
|
11800
|
-
[draggable, x, y]
|
|
11801
|
-
);
|
|
11802
|
-
const handlePointerMove = react.useCallback(
|
|
11803
|
-
(e) => {
|
|
11804
|
-
if (!isDragging.current) return;
|
|
11805
|
-
const dx = (e.clientX - dragStart.current.mouseX) / viewport.zoom;
|
|
11806
|
-
const dy = (e.clientY - dragStart.current.mouseY) / viewport.zoom;
|
|
11807
|
-
let nx = dragStart.current.nodeX + dx;
|
|
11808
|
-
let ny = dragStart.current.nodeY + dy;
|
|
11809
|
-
if (snapToGrid && gridSize > 0) {
|
|
11810
|
-
nx = Math.round(nx / gridSize) * gridSize;
|
|
11811
|
-
ny = Math.round(ny / gridSize) * gridSize;
|
|
11812
|
-
}
|
|
11813
|
-
onPositionChange?.(nx, ny);
|
|
11814
|
-
},
|
|
11815
|
-
[viewport.zoom, onPositionChange, snapToGrid, gridSize]
|
|
11816
|
-
);
|
|
11817
|
-
const handlePointerUp = react.useCallback(() => {
|
|
11818
|
-
isDragging.current = false;
|
|
11819
|
-
}, []);
|
|
11820
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11821
|
-
"div",
|
|
11822
|
-
{
|
|
11823
|
-
ref: nodeRef,
|
|
11824
|
-
"data-react-fancy-canvas-node": "",
|
|
11825
|
-
"data-node-id": id,
|
|
11826
|
-
className: cn("absolute", draggable && "cursor-grab active:cursor-grabbing", className),
|
|
11827
|
-
style: { left: x, top: y, ...style },
|
|
11828
|
-
onPointerDown: handlePointerDown,
|
|
11829
|
-
onPointerMove: handlePointerMove,
|
|
11830
|
-
onPointerUp: handlePointerUp,
|
|
11831
|
-
children
|
|
11832
|
-
}
|
|
11833
|
-
);
|
|
11834
|
-
}
|
|
11835
|
-
CanvasNode.displayName = "CanvasNode";
|
|
11836
|
-
|
|
11837
|
-
// src/components/Canvas/canvas.utils.ts
|
|
11838
|
-
function getAnchorPoint(rect, anchor, otherRect) {
|
|
11839
|
-
const cx = rect.x + rect.width / 2;
|
|
11840
|
-
const cy = rect.y + rect.height / 2;
|
|
11841
|
-
if (anchor === "auto" && otherRect) {
|
|
11842
|
-
const ocx = otherRect.x + otherRect.width / 2;
|
|
11843
|
-
const ocy = otherRect.y + otherRect.height / 2;
|
|
11844
|
-
const dx = ocx - cx;
|
|
11845
|
-
const dy = ocy - cy;
|
|
11846
|
-
if (Math.abs(dx) > Math.abs(dy)) {
|
|
11847
|
-
return dx > 0 ? { x: rect.x + rect.width, y: cy } : { x: rect.x, y: cy };
|
|
11848
|
-
}
|
|
11849
|
-
return dy > 0 ? { x: cx, y: rect.y + rect.height } : { x: cx, y: rect.y };
|
|
11850
|
-
}
|
|
11851
|
-
switch (anchor) {
|
|
11852
|
-
case "top":
|
|
11853
|
-
return { x: cx, y: rect.y };
|
|
11854
|
-
case "bottom":
|
|
11855
|
-
return { x: cx, y: rect.y + rect.height };
|
|
11856
|
-
case "left":
|
|
11857
|
-
return { x: rect.x, y: cy };
|
|
11858
|
-
case "right":
|
|
11859
|
-
return { x: rect.x + rect.width, y: cy };
|
|
11860
|
-
case "center":
|
|
11861
|
-
return { x: cx, y: cy };
|
|
11862
|
-
default:
|
|
11863
|
-
return { x: cx, y: cy };
|
|
11864
|
-
}
|
|
11865
|
-
}
|
|
11866
|
-
function bezierPath(from, to) {
|
|
11867
|
-
const dx = Math.abs(to.x - from.x);
|
|
11868
|
-
const dy = Math.abs(to.y - from.y);
|
|
11869
|
-
if (dx > dy) {
|
|
11870
|
-
const offset2 = dx * 0.5;
|
|
11871
|
-
const cp1x = from.x + (to.x > from.x ? offset2 : -offset2);
|
|
11872
|
-
const cp2x = to.x + (to.x > from.x ? -offset2 : offset2);
|
|
11873
|
-
return `M${from.x},${from.y} C${cp1x},${from.y} ${cp2x},${to.y} ${to.x},${to.y}`;
|
|
11874
|
-
}
|
|
11875
|
-
const offset = Math.max(dy * 0.5, 30);
|
|
11876
|
-
const cp1y = from.y + (to.y > from.y ? offset : -offset);
|
|
11877
|
-
const cp2y = to.y + (to.y > from.y ? -offset : offset);
|
|
11878
|
-
return `M${from.x},${from.y} C${from.x},${cp1y} ${to.x},${cp2y} ${to.x},${to.y}`;
|
|
11879
|
-
}
|
|
11880
|
-
function stepPath(from, to) {
|
|
11881
|
-
const midX = (from.x + to.x) / 2;
|
|
11882
|
-
return `M${from.x},${from.y} H${midX} V${to.y} H${to.x}`;
|
|
11883
|
-
}
|
|
11884
|
-
function straightPath(from, to) {
|
|
11885
|
-
return `M${from.x},${from.y} L${to.x},${to.y}`;
|
|
11886
|
-
}
|
|
11887
|
-
function getEdgePath(from, to, curve = "bezier") {
|
|
11888
|
-
switch (curve) {
|
|
11889
|
-
case "bezier":
|
|
11890
|
-
return bezierPath(from, to);
|
|
11891
|
-
case "step":
|
|
11892
|
-
return stepPath(from, to);
|
|
11893
|
-
case "straight":
|
|
11894
|
-
return straightPath(from, to);
|
|
11895
|
-
}
|
|
11896
|
-
}
|
|
11897
|
-
function CanvasEdge({
|
|
11898
|
-
from,
|
|
11899
|
-
to,
|
|
11900
|
-
fromAnchor = "auto",
|
|
11901
|
-
toAnchor = "auto",
|
|
11902
|
-
curve = "bezier",
|
|
11903
|
-
color = "currentColor",
|
|
11904
|
-
strokeWidth = 2,
|
|
11905
|
-
dashed = false,
|
|
11906
|
-
animated = false,
|
|
11907
|
-
label,
|
|
11908
|
-
className,
|
|
11909
|
-
markerStart,
|
|
11910
|
-
markerEnd
|
|
11911
|
-
}) {
|
|
11912
|
-
const { nodeRects, registryVersion } = useCanvas();
|
|
11913
|
-
const path = react.useMemo(() => {
|
|
11914
|
-
const fromRect = nodeRects.get(from);
|
|
11915
|
-
const toRect = nodeRects.get(to);
|
|
11916
|
-
if (!fromRect || !toRect) return null;
|
|
11917
|
-
const fromPt = getAnchorPoint(fromRect, fromAnchor, toRect);
|
|
11918
|
-
const toPt = getAnchorPoint(toRect, toAnchor, fromRect);
|
|
11919
|
-
return {
|
|
11920
|
-
d: getEdgePath(fromPt, toPt, curve),
|
|
11921
|
-
midX: (fromPt.x + toPt.x) / 2,
|
|
11922
|
-
midY: (fromPt.y + toPt.y) / 2
|
|
11923
|
-
};
|
|
11924
|
-
}, [from, to, fromAnchor, toAnchor, curve, nodeRects, registryVersion]);
|
|
11925
|
-
if (!path) return null;
|
|
11926
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-react-fancy-canvas-edge": "", className: cn("text-zinc-300 dark:text-zinc-600", className), children: [
|
|
11927
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11928
|
-
"path",
|
|
11929
|
-
{
|
|
11930
|
-
d: path.d,
|
|
11931
|
-
fill: "none",
|
|
11932
|
-
stroke: color,
|
|
11933
|
-
strokeWidth,
|
|
11934
|
-
strokeDasharray: dashed ? "6 4" : void 0,
|
|
11935
|
-
markerStart: markerStart ? `url(#${markerStart})` : void 0,
|
|
11936
|
-
markerEnd: markerEnd ? `url(#${markerEnd})` : void 0,
|
|
11937
|
-
className: animated ? "animate-[dash_1s_linear_infinite]" : "",
|
|
11938
|
-
style: animated ? { strokeDasharray: "8 4" } : void 0
|
|
11939
|
-
}
|
|
11940
|
-
),
|
|
11941
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: path.midX - 40, y: path.midY - 12, width: 80, height: 24, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center text-xs text-zinc-500", children: label }) })
|
|
11942
|
-
] });
|
|
11943
|
-
}
|
|
11944
|
-
CanvasEdge.displayName = "CanvasEdge";
|
|
11945
|
-
function CanvasMinimap({ width = 150, height = 100, className }) {
|
|
11946
|
-
const { nodeRects, registryVersion, viewport } = useCanvas();
|
|
11947
|
-
const bounds = react.useMemo(() => {
|
|
11948
|
-
if (nodeRects.size === 0) return { minX: 0, minY: 0, maxX: 500, maxY: 300 };
|
|
11949
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
11950
|
-
nodeRects.forEach((r) => {
|
|
11951
|
-
minX = Math.min(minX, r.x);
|
|
11952
|
-
minY = Math.min(minY, r.y);
|
|
11953
|
-
maxX = Math.max(maxX, r.x + r.width);
|
|
11954
|
-
maxY = Math.max(maxY, r.y + r.height);
|
|
11955
|
-
});
|
|
11956
|
-
const padding = 50;
|
|
11957
|
-
return { minX: minX - padding, minY: minY - padding, maxX: maxX + padding, maxY: maxY + padding };
|
|
11958
|
-
}, [nodeRects, registryVersion]);
|
|
11959
|
-
const scaleX = width / (bounds.maxX - bounds.minX || 1);
|
|
11960
|
-
const scaleY = height / (bounds.maxY - bounds.minY || 1);
|
|
11961
|
-
const scale = Math.min(scaleX, scaleY);
|
|
11962
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11963
|
-
"div",
|
|
11964
|
-
{
|
|
11965
|
-
"data-react-fancy-canvas-minimap": "",
|
|
11966
|
-
className: cn(
|
|
11967
|
-
"absolute right-3 bottom-3 overflow-hidden rounded-lg border border-zinc-200 bg-white/90 dark:border-zinc-700 dark:bg-zinc-900/90",
|
|
11968
|
-
className
|
|
11969
|
-
),
|
|
11970
|
-
style: { width, height },
|
|
11971
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width, height, children: [
|
|
11972
|
-
Array.from(nodeRects.entries()).map(([id, rect]) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11973
|
-
"rect",
|
|
11974
|
-
{
|
|
11975
|
-
x: (rect.x - bounds.minX) * scale,
|
|
11976
|
-
y: (rect.y - bounds.minY) * scale,
|
|
11977
|
-
width: Math.max(rect.width * scale, 4),
|
|
11978
|
-
height: Math.max(rect.height * scale, 3),
|
|
11979
|
-
rx: 1,
|
|
11980
|
-
className: "fill-blue-400/60"
|
|
11981
|
-
},
|
|
11982
|
-
id
|
|
11983
|
-
)),
|
|
11984
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11985
|
-
"rect",
|
|
11986
|
-
{
|
|
11987
|
-
x: (-viewport.panX / viewport.zoom - bounds.minX) * scale,
|
|
11988
|
-
y: (-viewport.panY / viewport.zoom - bounds.minY) * scale,
|
|
11989
|
-
width: (width / viewport.zoom / scale > 0 ? width / viewport.zoom : width) * scale / (bounds.maxX - bounds.minX || 1) * (bounds.maxX - bounds.minX),
|
|
11990
|
-
height: (height / viewport.zoom / scale > 0 ? height / viewport.zoom : height) * scale / (bounds.maxY - bounds.minY || 1) * (bounds.maxY - bounds.minY),
|
|
11991
|
-
fill: "none",
|
|
11992
|
-
stroke: "currentColor",
|
|
11993
|
-
strokeWidth: 1,
|
|
11994
|
-
className: "text-blue-500"
|
|
11995
|
-
}
|
|
11996
|
-
)
|
|
11997
|
-
] })
|
|
11998
|
-
}
|
|
11999
|
-
);
|
|
12000
|
-
}
|
|
12001
|
-
CanvasMinimap.displayName = "CanvasMinimap";
|
|
12002
|
-
function CanvasControls({
|
|
12003
|
-
className,
|
|
12004
|
-
showZoomIn = true,
|
|
12005
|
-
showZoomOut = true,
|
|
12006
|
-
showReset = true,
|
|
12007
|
-
showFitAll = true
|
|
12008
|
-
}) {
|
|
12009
|
-
const { setViewport, nodeRects, containerRef } = useCanvas();
|
|
12010
|
-
const zoomIn = () => setViewport((v) => ({ ...v, zoom: Math.min(3, v.zoom * 1.25) }));
|
|
12011
|
-
const zoomOut = () => setViewport((v) => ({ ...v, zoom: Math.max(0.1, v.zoom / 1.25) }));
|
|
12012
|
-
const reset = () => setViewport({ panX: 0, panY: 0, zoom: 1 });
|
|
12013
|
-
const fitAll = () => {
|
|
12014
|
-
const container = containerRef.current;
|
|
12015
|
-
if (!container || nodeRects.size === 0) return reset();
|
|
12016
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
12017
|
-
nodeRects.forEach((r) => {
|
|
12018
|
-
minX = Math.min(minX, r.x);
|
|
12019
|
-
minY = Math.min(minY, r.y);
|
|
12020
|
-
maxX = Math.max(maxX, r.x + r.width);
|
|
12021
|
-
maxY = Math.max(maxY, r.y + r.height);
|
|
12022
|
-
});
|
|
12023
|
-
const padding = 40;
|
|
12024
|
-
const contentW = maxX - minX + padding * 2;
|
|
12025
|
-
const contentH = maxY - minY + padding * 2;
|
|
12026
|
-
const cw = container.clientWidth;
|
|
12027
|
-
const ch = container.clientHeight;
|
|
12028
|
-
const zoom = Math.min(cw / contentW, ch / contentH, 1.5);
|
|
12029
|
-
const panX = (cw - contentW * zoom) / 2 - minX * zoom + padding * zoom;
|
|
12030
|
-
const panY = (ch - contentH * zoom) / 2 - minY * zoom + padding * zoom;
|
|
12031
|
-
setViewport({ panX, panY, zoom });
|
|
12032
|
-
};
|
|
12033
|
-
const btnClass = "flex h-8 w-8 items-center justify-center rounded-md text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-300 transition-colors";
|
|
12034
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12035
|
-
"div",
|
|
12036
|
-
{
|
|
12037
|
-
"data-react-fancy-canvas-controls": "",
|
|
12038
|
-
className: cn(
|
|
12039
|
-
"absolute bottom-3 left-3 flex gap-1 rounded-lg border border-zinc-200 bg-white/90 p-1 shadow-sm dark:border-zinc-700 dark:bg-zinc-900/90",
|
|
12040
|
-
className
|
|
12041
|
-
),
|
|
12042
|
-
children: [
|
|
12043
|
-
showZoomIn && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: zoomIn, className: btnClass, "aria-label": "Zoom in", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ZoomIn, { size: 16 }) }),
|
|
12044
|
-
showZoomOut && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: zoomOut, className: btnClass, "aria-label": "Zoom out", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ZoomOut, { size: 16 }) }),
|
|
12045
|
-
showReset && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: reset, className: btnClass, "aria-label": "Reset view", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.RotateCcw, { size: 16 }) }),
|
|
12046
|
-
showFitAll && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: fitAll, className: btnClass, "aria-label": "Fit all", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Maximize, { size: 16 }) })
|
|
12047
|
-
]
|
|
12048
|
-
}
|
|
12049
|
-
);
|
|
12050
|
-
}
|
|
12051
|
-
CanvasControls.displayName = "CanvasControls";
|
|
12052
|
-
var DEFAULT_VIEWPORT = { panX: 0, panY: 0, zoom: 1 };
|
|
12053
|
-
function CanvasRoot({
|
|
12054
|
-
children,
|
|
12055
|
-
viewport: controlledViewport,
|
|
12056
|
-
defaultViewport = DEFAULT_VIEWPORT,
|
|
12057
|
-
onViewportChange,
|
|
12058
|
-
minZoom = 0.1,
|
|
12059
|
-
maxZoom = 3,
|
|
12060
|
-
pannable = true,
|
|
12061
|
-
zoomable = true,
|
|
12062
|
-
showGrid = false,
|
|
12063
|
-
gridStyle = "dots",
|
|
12064
|
-
gridSize = 20,
|
|
12065
|
-
gridColor = "rgb(161 161 170 / 0.3)",
|
|
12066
|
-
snapToGrid = false,
|
|
12067
|
-
fitOnMount = false,
|
|
12068
|
-
className,
|
|
12069
|
-
style
|
|
12070
|
-
}) {
|
|
12071
|
-
const containerRef = react.useRef(null);
|
|
12072
|
-
const [viewport, setViewport] = useControllableState(controlledViewport, defaultViewport, onViewportChange);
|
|
12073
|
-
const { registerNode, unregisterNode, nodeRects, version: registryVersion } = useNodeRegistry();
|
|
12074
|
-
const { containerProps } = usePanZoom({
|
|
12075
|
-
viewport,
|
|
12076
|
-
setViewport,
|
|
12077
|
-
minZoom,
|
|
12078
|
-
maxZoom,
|
|
12079
|
-
pannable,
|
|
12080
|
-
zoomable,
|
|
12081
|
-
containerRef
|
|
12082
|
-
});
|
|
12083
|
-
const ctx = react.useMemo(
|
|
12084
|
-
() => ({ viewport, setViewport, registerNode, unregisterNode, nodeRects, registryVersion, containerRef, gridSize, snapToGrid }),
|
|
12085
|
-
[viewport, setViewport, registerNode, unregisterNode, nodeRects, registryVersion, gridSize, snapToGrid]
|
|
12086
|
-
);
|
|
12087
|
-
const hasFitted = react.useRef(false);
|
|
12088
|
-
react.useEffect(() => {
|
|
12089
|
-
if (!fitOnMount || hasFitted.current || nodeRects.size === 0) return;
|
|
12090
|
-
const container = containerRef.current;
|
|
12091
|
-
if (!container || container.clientWidth === 0) return;
|
|
12092
|
-
hasFitted.current = true;
|
|
12093
|
-
requestAnimationFrame(() => {
|
|
12094
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
12095
|
-
nodeRects.forEach((r) => {
|
|
12096
|
-
minX = Math.min(minX, r.x);
|
|
12097
|
-
minY = Math.min(minY, r.y);
|
|
12098
|
-
maxX = Math.max(maxX, r.x + r.width);
|
|
12099
|
-
maxY = Math.max(maxY, r.y + r.height);
|
|
12100
|
-
});
|
|
12101
|
-
const padding = 40;
|
|
12102
|
-
const contentW = maxX - minX + padding * 2;
|
|
12103
|
-
const contentH = maxY - minY + padding * 2;
|
|
12104
|
-
const cw = container.clientWidth;
|
|
12105
|
-
const ch = container.clientHeight;
|
|
12106
|
-
const zoom = Math.min(cw / contentW, ch / contentH, 1.5);
|
|
12107
|
-
const panX = (cw - contentW * zoom) / 2 - minX * zoom + padding * zoom;
|
|
12108
|
-
const panY = (ch - contentH * zoom) / 2 - minY * zoom + padding * zoom;
|
|
12109
|
-
setViewport({ panX, panY, zoom });
|
|
12110
|
-
});
|
|
12111
|
-
}, [fitOnMount, nodeRects, registryVersion, setViewport]);
|
|
12112
|
-
const edges = [];
|
|
12113
|
-
const others = [];
|
|
12114
|
-
const overlays = [];
|
|
12115
|
-
react.Children.forEach(children, (child) => {
|
|
12116
|
-
const el = child;
|
|
12117
|
-
if (!el || !el.type) return;
|
|
12118
|
-
const elType = el.type;
|
|
12119
|
-
if (elType === CanvasEdge || elType?._isCanvasEdge) {
|
|
12120
|
-
edges.push(el);
|
|
12121
|
-
} else if (elType === CanvasMinimap || elType === CanvasControls) {
|
|
12122
|
-
overlays.push(el);
|
|
12123
|
-
} else {
|
|
12124
|
-
others.push(el);
|
|
12125
|
-
}
|
|
12126
|
-
});
|
|
12127
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CanvasContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12128
|
-
"div",
|
|
12129
|
-
{
|
|
12130
|
-
ref: containerRef,
|
|
12131
|
-
"data-react-fancy-canvas": "",
|
|
12132
|
-
className: cn("relative overflow-hidden", className),
|
|
12133
|
-
style: { touchAction: "none", ...style },
|
|
12134
|
-
...containerProps,
|
|
12135
|
-
children: [
|
|
12136
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12137
|
-
"div",
|
|
12138
|
-
{
|
|
12139
|
-
"data-canvas-bg": "",
|
|
12140
|
-
className: "absolute inset-0",
|
|
12141
|
-
style: showGrid && gridStyle !== "none" ? gridStyle === "lines" ? {
|
|
12142
|
-
backgroundImage: `linear-gradient(to right, ${gridColor} 1px, transparent 1px), linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)`,
|
|
12143
|
-
backgroundSize: `${gridSize * viewport.zoom}px ${gridSize * viewport.zoom}px`,
|
|
12144
|
-
backgroundPosition: `${viewport.panX}px ${viewport.panY}px`
|
|
12145
|
-
} : {
|
|
12146
|
-
backgroundImage: `radial-gradient(circle, ${gridColor} 1px, transparent 1px)`,
|
|
12147
|
-
backgroundSize: `${gridSize * viewport.zoom}px ${gridSize * viewport.zoom}px`,
|
|
12148
|
-
backgroundPosition: `${viewport.panX}px ${viewport.panY}px`
|
|
12149
|
-
} : void 0
|
|
12150
|
-
}
|
|
12151
|
-
),
|
|
12152
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12153
|
-
"div",
|
|
12154
|
-
{
|
|
12155
|
-
className: "absolute origin-top-left",
|
|
12156
|
-
style: {
|
|
12157
|
-
transform: `translate(${viewport.panX}px, ${viewport.panY}px) scale(${viewport.zoom})`
|
|
12158
|
-
},
|
|
12159
|
-
children: others
|
|
12160
|
-
}
|
|
12161
|
-
),
|
|
12162
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12163
|
-
"svg",
|
|
12164
|
-
{
|
|
12165
|
-
className: "pointer-events-none absolute inset-0 h-full w-full",
|
|
12166
|
-
style: {
|
|
12167
|
-
transform: `translate(${viewport.panX}px, ${viewport.panY}px) scale(${viewport.zoom})`,
|
|
12168
|
-
transformOrigin: "0 0"
|
|
12169
|
-
},
|
|
12170
|
-
children: [
|
|
12171
|
-
/* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
|
|
12172
|
-
/* @__PURE__ */ jsxRuntime.jsx("marker", { id: "canvas-arrow", viewBox: "0 0 10 10", refX: "10", refY: "5", markerWidth: "8", markerHeight: "8", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L10,5 L0,10 Z", fill: "#71717a" }) }),
|
|
12173
|
-
/* @__PURE__ */ jsxRuntime.jsx("marker", { id: "canvas-circle", viewBox: "0 0 10 10", refX: "5", refY: "5", markerWidth: "8", markerHeight: "8", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5", cy: "5", r: "3.5", fill: "#71717a" }) }),
|
|
12174
|
-
/* @__PURE__ */ jsxRuntime.jsx("marker", { id: "canvas-diamond", viewBox: "0 0 12 12", refX: "6", refY: "6", markerWidth: "10", markerHeight: "10", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "6,0 12,6 6,12 0,6", fill: "none", stroke: "#71717a", strokeWidth: "1.5" }) }),
|
|
12175
|
-
/* @__PURE__ */ jsxRuntime.jsx("marker", { id: "canvas-one", viewBox: "0 0 2 16", refX: "1", refY: "8", markerWidth: "2", markerHeight: "14", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "0", x2: "1", y2: "16", stroke: "#71717a", strokeWidth: "2" }) }),
|
|
12176
|
-
/* @__PURE__ */ jsxRuntime.jsxs("marker", { id: "canvas-crow-foot", viewBox: "0 0 16 16", refX: "16", refY: "8", markerWidth: "14", markerHeight: "14", orient: "auto", children: [
|
|
12177
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "8", x2: "0", y2: "0", stroke: "#71717a", strokeWidth: "2", strokeLinecap: "round" }),
|
|
12178
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "8", x2: "0", y2: "8", stroke: "#71717a", strokeWidth: "2", strokeLinecap: "round" }),
|
|
12179
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "8", x2: "0", y2: "16", stroke: "#71717a", strokeWidth: "2", strokeLinecap: "round" }),
|
|
12180
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "0", x2: "16", y2: "16", stroke: "#71717a", strokeWidth: "2", strokeLinecap: "round" })
|
|
12181
|
-
] })
|
|
12182
|
-
] }),
|
|
12183
|
-
edges
|
|
12184
|
-
]
|
|
12185
|
-
}
|
|
12186
|
-
),
|
|
12187
|
-
overlays
|
|
12188
|
-
]
|
|
12189
|
-
}
|
|
12190
|
-
) });
|
|
12191
|
-
}
|
|
12192
|
-
var Canvas = Object.assign(CanvasRoot, {
|
|
12193
|
-
Node: CanvasNode,
|
|
12194
|
-
Edge: CanvasEdge,
|
|
12195
|
-
Minimap: CanvasMinimap,
|
|
12196
|
-
Controls: CanvasControls
|
|
12197
|
-
});
|
|
12198
|
-
var DiagramContext = react.createContext(null);
|
|
12199
|
-
function useDiagram() {
|
|
12200
|
-
const ctx = react.useContext(DiagramContext);
|
|
12201
|
-
if (!ctx) {
|
|
12202
|
-
throw new Error("useDiagram must be used within a <Diagram> component");
|
|
12203
|
-
}
|
|
12204
|
-
return ctx;
|
|
12205
|
-
}
|
|
12206
|
-
function DiagramField({
|
|
12207
|
-
name,
|
|
12208
|
-
type,
|
|
12209
|
-
primary = false,
|
|
12210
|
-
foreign = false,
|
|
12211
|
-
nullable = false,
|
|
12212
|
-
className
|
|
12213
|
-
}) {
|
|
12214
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12215
|
-
"div",
|
|
12216
|
-
{
|
|
12217
|
-
"data-react-fancy-diagram-field": "",
|
|
12218
|
-
className: cn(
|
|
12219
|
-
"flex items-center justify-between gap-2 border-t border-zinc-200 px-3 py-1 text-sm dark:border-zinc-700",
|
|
12220
|
-
className
|
|
12221
|
-
),
|
|
12222
|
-
children: [
|
|
12223
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
12224
|
-
primary && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded bg-blue-100 px-1 py-0.5 text-[10px] font-semibold leading-none text-blue-700 dark:bg-blue-900/50 dark:text-blue-300", children: "PK" }),
|
|
12225
|
-
foreign && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded bg-amber-100 px-1 py-0.5 text-[10px] font-semibold leading-none text-amber-700 dark:bg-amber-900/50 dark:text-amber-300", children: "FK" }),
|
|
12226
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-800 dark:text-zinc-200", children: name })
|
|
12227
|
-
] }),
|
|
12228
|
-
type && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-xs text-zinc-400 dark:text-zinc-500", children: [
|
|
12229
|
-
type,
|
|
12230
|
-
nullable && "?"
|
|
12231
|
-
] })
|
|
12232
|
-
]
|
|
12233
|
-
}
|
|
12234
|
-
);
|
|
12235
|
-
}
|
|
12236
|
-
DiagramField.displayName = "DiagramField";
|
|
12237
|
-
function DiagramEntity({
|
|
12238
|
-
children,
|
|
12239
|
-
id: idProp,
|
|
12240
|
-
name,
|
|
12241
|
-
x = 0,
|
|
12242
|
-
y = 0,
|
|
12243
|
-
color = "bg-blue-600 dark:bg-blue-500",
|
|
12244
|
-
draggable,
|
|
12245
|
-
onPositionChange,
|
|
12246
|
-
className
|
|
12247
|
-
}) {
|
|
12248
|
-
const id = idProp ?? name;
|
|
12249
|
-
const fields = [];
|
|
12250
|
-
const other = [];
|
|
12251
|
-
react.Children.forEach(children, (child) => {
|
|
12252
|
-
const el = child;
|
|
12253
|
-
if (!el || !el.type) return;
|
|
12254
|
-
if (el.type === DiagramField) {
|
|
12255
|
-
fields.push(el);
|
|
12256
|
-
} else {
|
|
12257
|
-
other.push(el);
|
|
12258
|
-
}
|
|
12259
|
-
});
|
|
12260
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Canvas.Node, { id, x, y, draggable, onPositionChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12261
|
-
"div",
|
|
12262
|
-
{
|
|
12263
|
-
"data-react-fancy-diagram-entity": "",
|
|
12264
|
-
"data-entity-id": id,
|
|
12265
|
-
className: cn(
|
|
12266
|
-
"w-[220px] overflow-hidden rounded-lg border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-800",
|
|
12267
|
-
className
|
|
12268
|
-
),
|
|
12269
|
-
children: [
|
|
12270
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12271
|
-
"div",
|
|
12272
|
-
{
|
|
12273
|
-
className: cn(
|
|
12274
|
-
"px-3 py-2 text-sm font-semibold text-white",
|
|
12275
|
-
color
|
|
12276
|
-
),
|
|
12277
|
-
children: name
|
|
12278
|
-
}
|
|
12279
|
-
),
|
|
12280
|
-
fields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { children: fields }),
|
|
12281
|
-
other
|
|
12282
|
-
]
|
|
12283
|
-
}
|
|
12284
|
-
) });
|
|
12285
|
-
}
|
|
12286
|
-
DiagramEntity.displayName = "DiagramEntity";
|
|
12287
|
-
|
|
12288
|
-
// src/components/Diagram/diagram.markers.ts
|
|
12289
|
-
function defaultMarkersForType(type) {
|
|
12290
|
-
switch (type) {
|
|
12291
|
-
case "one-to-one":
|
|
12292
|
-
return { fromMarker: "one", toMarker: "one", lineStyle: "solid" };
|
|
12293
|
-
case "one-to-many":
|
|
12294
|
-
return { fromMarker: "one", toMarker: "many", lineStyle: "solid" };
|
|
12295
|
-
case "many-to-one":
|
|
12296
|
-
return { fromMarker: "many", toMarker: "one", lineStyle: "solid" };
|
|
12297
|
-
case "many-to-many":
|
|
12298
|
-
return { fromMarker: "many", toMarker: "many", lineStyle: "solid" };
|
|
12299
|
-
case "association":
|
|
12300
|
-
return { fromMarker: "none", toMarker: "arrow", lineStyle: "solid" };
|
|
12301
|
-
case "aggregation":
|
|
12302
|
-
return { fromMarker: "diamond-open", toMarker: "none", lineStyle: "solid" };
|
|
12303
|
-
case "composition":
|
|
12304
|
-
return { fromMarker: "diamond", toMarker: "none", lineStyle: "solid" };
|
|
12305
|
-
case "inheritance":
|
|
12306
|
-
return { fromMarker: "none", toMarker: "triangle-open", lineStyle: "solid" };
|
|
12307
|
-
case "implementation":
|
|
12308
|
-
return { fromMarker: "none", toMarker: "triangle-open", lineStyle: "dashed" };
|
|
12309
|
-
case "dependency":
|
|
12310
|
-
return { fromMarker: "none", toMarker: "arrow", lineStyle: "dashed" };
|
|
12311
|
-
default:
|
|
12312
|
-
return { fromMarker: "none", toMarker: "none", lineStyle: "solid" };
|
|
12313
|
-
}
|
|
12314
|
-
}
|
|
12315
|
-
var SIZE = 12;
|
|
12316
|
-
function renderMarker(marker, pt, direction) {
|
|
12317
|
-
if (typeof marker === "string" && marker.startsWith("emoji:")) {
|
|
12318
|
-
return { paths: [], text: marker.slice(6) };
|
|
12319
|
-
}
|
|
12320
|
-
switch (marker) {
|
|
12321
|
-
case "none":
|
|
12322
|
-
return null;
|
|
12323
|
-
case "arrow":
|
|
12324
|
-
return { paths: [{ d: arrowPath(pt, direction), fill: "stroke" }] };
|
|
12325
|
-
case "arrow-open":
|
|
12326
|
-
return { paths: [{ d: arrowPath(pt, direction), fill: "none" }] };
|
|
12327
|
-
case "circle":
|
|
12328
|
-
return { paths: [{ d: circlePath(pt), fill: "stroke" }] };
|
|
12329
|
-
case "circle-open":
|
|
12330
|
-
return { paths: [{ d: circlePath(pt), fill: "background" }] };
|
|
12331
|
-
case "square":
|
|
12332
|
-
return { paths: [{ d: squarePath(pt, direction), fill: "stroke" }] };
|
|
12333
|
-
case "square-open":
|
|
12334
|
-
return { paths: [{ d: squarePath(pt, direction), fill: "background" }] };
|
|
12335
|
-
case "diamond":
|
|
12336
|
-
return { paths: [{ d: diamondPath(pt, direction), fill: "stroke" }] };
|
|
12337
|
-
case "diamond-open":
|
|
12338
|
-
return { paths: [{ d: diamondPath(pt, direction), fill: "background" }] };
|
|
12339
|
-
case "triangle":
|
|
12340
|
-
return { paths: [{ d: trianglePath(pt, direction), fill: "stroke" }] };
|
|
12341
|
-
case "triangle-open":
|
|
12342
|
-
return { paths: [{ d: trianglePath(pt, direction), fill: "background" }] };
|
|
12343
|
-
case "cross":
|
|
12344
|
-
return { paths: [{ d: crossPath(pt, direction), fill: "none" }] };
|
|
12345
|
-
case "one":
|
|
12346
|
-
return { paths: [{ d: oneSymbol(pt, direction), fill: "none" }] };
|
|
12347
|
-
case "many":
|
|
12348
|
-
return { paths: [{ d: crowFootSymbol(pt, direction), fill: "none" }] };
|
|
12349
|
-
case "optional-one":
|
|
12350
|
-
return {
|
|
12351
|
-
paths: [
|
|
12352
|
-
{ d: circleOuter(pt, direction), fill: "background" },
|
|
12353
|
-
{ d: oneSymbolOffset(pt, direction), fill: "none" }
|
|
12354
|
-
]
|
|
12355
|
-
};
|
|
12356
|
-
case "optional-many":
|
|
12357
|
-
return {
|
|
12358
|
-
paths: [
|
|
12359
|
-
{ d: circleOuter(pt, direction), fill: "background" },
|
|
12360
|
-
{ d: crowFootSymbolOffset(pt, direction), fill: "none" }
|
|
12361
|
-
]
|
|
12362
|
-
};
|
|
12363
|
-
default:
|
|
12364
|
-
if (typeof marker === "string" && marker !== "") {
|
|
12365
|
-
return { paths: [], text: marker };
|
|
12366
|
-
}
|
|
12367
|
-
return null;
|
|
12368
|
-
}
|
|
12369
|
-
}
|
|
12370
|
-
function markerInset(marker) {
|
|
12371
|
-
if (marker === "none" || marker === void 0) return 0;
|
|
12372
|
-
if (typeof marker === "string" && (marker.startsWith("emoji:") || !KNOWN_MARKERS.has(marker))) {
|
|
12373
|
-
return SIZE;
|
|
12374
|
-
}
|
|
12375
|
-
switch (marker) {
|
|
12376
|
-
case "circle":
|
|
12377
|
-
case "circle-open":
|
|
12378
|
-
return SIZE * 0.6;
|
|
12379
|
-
case "one":
|
|
12380
|
-
return 0;
|
|
12381
|
-
// bar sits AT endpoint
|
|
12382
|
-
case "many":
|
|
12383
|
-
return SIZE;
|
|
12384
|
-
case "optional-one":
|
|
12385
|
-
return SIZE * 1.2;
|
|
12386
|
-
case "optional-many":
|
|
12387
|
-
return SIZE * 1.8;
|
|
12388
|
-
default:
|
|
12389
|
-
return SIZE;
|
|
12390
|
-
}
|
|
12391
|
-
}
|
|
12392
|
-
var KNOWN_MARKERS = /* @__PURE__ */ new Set([
|
|
12393
|
-
"none",
|
|
12394
|
-
"arrow",
|
|
12395
|
-
"arrow-open",
|
|
12396
|
-
"circle",
|
|
12397
|
-
"circle-open",
|
|
12398
|
-
"square",
|
|
12399
|
-
"square-open",
|
|
12400
|
-
"diamond",
|
|
12401
|
-
"diamond-open",
|
|
12402
|
-
"triangle",
|
|
12403
|
-
"triangle-open",
|
|
12404
|
-
"one",
|
|
12405
|
-
"many",
|
|
12406
|
-
"optional-one",
|
|
12407
|
-
"optional-many",
|
|
12408
|
-
"cross"
|
|
12409
|
-
]);
|
|
12410
|
-
function dirVec(direction) {
|
|
12411
|
-
switch (direction) {
|
|
12412
|
-
case "left":
|
|
12413
|
-
return [-1, 0];
|
|
12414
|
-
case "right":
|
|
12415
|
-
return [1, 0];
|
|
12416
|
-
case "up":
|
|
12417
|
-
return [0, -1];
|
|
12418
|
-
case "down":
|
|
12419
|
-
return [0, 1];
|
|
12420
|
-
}
|
|
12421
|
-
}
|
|
12422
|
-
function perpVec(direction) {
|
|
12423
|
-
switch (direction) {
|
|
12424
|
-
case "left":
|
|
12425
|
-
case "right":
|
|
12426
|
-
return [0, 1];
|
|
12427
|
-
case "up":
|
|
12428
|
-
case "down":
|
|
12429
|
-
return [1, 0];
|
|
12430
|
-
}
|
|
12431
|
-
}
|
|
12432
|
-
function arrowPath(pt, direction, _filled) {
|
|
12433
|
-
const [dx, dy] = dirVec(direction);
|
|
12434
|
-
const [px, py] = perpVec(direction);
|
|
12435
|
-
const tipX = pt.x + dx * SIZE;
|
|
12436
|
-
const tipY = pt.y + dy * SIZE;
|
|
12437
|
-
const baseAX = pt.x + px * (SIZE * 0.55);
|
|
12438
|
-
const baseAY = pt.y + py * (SIZE * 0.55);
|
|
12439
|
-
const baseBX = pt.x - px * (SIZE * 0.55);
|
|
12440
|
-
const baseBY = pt.y - py * (SIZE * 0.55);
|
|
12441
|
-
return `M${baseAX},${baseAY} L${tipX},${tipY} L${baseBX},${baseBY} Z`;
|
|
12442
|
-
}
|
|
12443
|
-
function circlePath(pt, _filled) {
|
|
12444
|
-
const r = SIZE * 0.45;
|
|
12445
|
-
return `M${pt.x - r},${pt.y} a${r},${r} 0 1 0 ${r * 2},0 a${r},${r} 0 1 0 ${-r * 2},0 Z`;
|
|
12446
|
-
}
|
|
12447
|
-
function squarePath(pt, direction, _filled) {
|
|
12448
|
-
const [dx, dy] = dirVec(direction);
|
|
12449
|
-
const [px, py] = perpVec(direction);
|
|
12450
|
-
const half = SIZE * 0.5;
|
|
12451
|
-
const cx = pt.x + dx * half;
|
|
12452
|
-
const cy = pt.y + dy * half;
|
|
12453
|
-
const tlX = cx - px * half - dx * half;
|
|
12454
|
-
const tlY = cy - py * half - dy * half;
|
|
12455
|
-
const trX = cx + px * half - dx * half;
|
|
12456
|
-
const trY = cy + py * half - dy * half;
|
|
12457
|
-
const brX = cx + px * half + dx * half;
|
|
12458
|
-
const brY = cy + py * half + dy * half;
|
|
12459
|
-
const blX = cx - px * half + dx * half;
|
|
12460
|
-
const blY = cy - py * half + dy * half;
|
|
12461
|
-
return `M${tlX},${tlY} L${trX},${trY} L${brX},${brY} L${blX},${blY} Z`;
|
|
12462
|
-
}
|
|
12463
|
-
function diamondPath(pt, direction, _filled) {
|
|
12464
|
-
const [dx, dy] = dirVec(direction);
|
|
12465
|
-
const [px, py] = perpVec(direction);
|
|
12466
|
-
const len = SIZE * 1.2;
|
|
12467
|
-
const cx = pt.x + dx * (len / 2);
|
|
12468
|
-
const cy = pt.y + dy * (len / 2);
|
|
12469
|
-
const aX = pt.x;
|
|
12470
|
-
const aY = pt.y;
|
|
12471
|
-
const bX = cx + px * (SIZE * 0.45);
|
|
12472
|
-
const bY = cy + py * (SIZE * 0.45);
|
|
12473
|
-
const tX = pt.x + dx * len;
|
|
12474
|
-
const tY = pt.y + dy * len;
|
|
12475
|
-
const dX = cx - px * (SIZE * 0.45);
|
|
12476
|
-
const dY = cy - py * (SIZE * 0.45);
|
|
12477
|
-
return `M${aX},${aY} L${bX},${bY} L${tX},${tY} L${dX},${dY} Z`;
|
|
12478
|
-
}
|
|
12479
|
-
function trianglePath(pt, direction, _filled) {
|
|
12480
|
-
const [dx, dy] = dirVec(direction);
|
|
12481
|
-
const [px, py] = perpVec(direction);
|
|
12482
|
-
const len = SIZE * 1.1;
|
|
12483
|
-
const baseCX = pt.x + dx * len;
|
|
12484
|
-
const baseCY = pt.y + dy * len;
|
|
12485
|
-
const baseAX = baseCX + px * (SIZE * 0.6);
|
|
12486
|
-
const baseAY = baseCY + py * (SIZE * 0.6);
|
|
12487
|
-
const baseBX = baseCX - px * (SIZE * 0.6);
|
|
12488
|
-
const baseBY = baseCY - py * (SIZE * 0.6);
|
|
12489
|
-
return `M${pt.x},${pt.y} L${baseAX},${baseAY} L${baseBX},${baseBY} Z`;
|
|
12490
|
-
}
|
|
12491
|
-
function crossPath(pt, direction) {
|
|
12492
|
-
const [dx, dy] = dirVec(direction);
|
|
12493
|
-
const [px, py] = perpVec(direction);
|
|
12494
|
-
const s = SIZE * 0.5;
|
|
12495
|
-
const cx = pt.x + dx * (SIZE * 0.5);
|
|
12496
|
-
const cy = pt.y + dy * (SIZE * 0.5);
|
|
12497
|
-
return [
|
|
12498
|
-
`M${cx - s * (px + dx)},${cy - s * (py + dy)} L${cx + s * (px + dx)},${cy + s * (py + dy)}`,
|
|
12499
|
-
`M${cx - s * (px - dx)},${cy - s * (py - dy)} L${cx + s * (px - dx)},${cy + s * (py - dy)}`
|
|
12500
|
-
].join(" ");
|
|
12501
|
-
}
|
|
12502
|
-
function oneSymbol(pt, direction) {
|
|
12503
|
-
const [, py] = perpVec(direction);
|
|
12504
|
-
const [px] = perpVec(direction);
|
|
12505
|
-
const half = SIZE * 0.6;
|
|
12506
|
-
return `M${pt.x - px * half},${pt.y - py * half} L${pt.x + px * half},${pt.y + py * half}`;
|
|
12507
|
-
}
|
|
12508
|
-
function crowFootSymbol(pt, direction) {
|
|
12509
|
-
const [dx, dy] = dirVec(direction);
|
|
12510
|
-
const [px, py] = perpVec(direction);
|
|
12511
|
-
const tipX = pt.x + dx * SIZE;
|
|
12512
|
-
const tipY = pt.y + dy * SIZE;
|
|
12513
|
-
const spread = SIZE * 0.8;
|
|
12514
|
-
const aX = pt.x + px * spread, aY = pt.y + py * spread;
|
|
12515
|
-
const cX = pt.x - px * spread, cY = pt.y - py * spread;
|
|
12516
|
-
return [
|
|
12517
|
-
`M${aX},${aY} L${tipX},${tipY}`,
|
|
12518
|
-
`M${pt.x},${pt.y} L${tipX},${tipY}`,
|
|
12519
|
-
`M${cX},${cY} L${tipX},${tipY}`,
|
|
12520
|
-
`M${aX},${aY} L${cX},${cY}`
|
|
12521
|
-
].join(" ");
|
|
12522
|
-
}
|
|
12523
|
-
function circleOuter(pt, direction) {
|
|
12524
|
-
const [dx, dy] = dirVec(direction);
|
|
12525
|
-
const r = SIZE * 0.4;
|
|
12526
|
-
const cx = pt.x + dx * (SIZE * 0.4 + r);
|
|
12527
|
-
const cy = pt.y + dy * (SIZE * 0.4 + r);
|
|
12528
|
-
return `M${cx - r},${cy} a${r},${r} 0 1 0 ${r * 2},0 a${r},${r} 0 1 0 ${-r * 2},0 Z`;
|
|
12529
|
-
}
|
|
12530
|
-
function oneSymbolOffset(pt, direction) {
|
|
12531
|
-
const [px, py] = perpVec(direction);
|
|
12532
|
-
const half = SIZE * 0.6;
|
|
12533
|
-
return `M${pt.x - px * half},${pt.y - py * half} L${pt.x + px * half},${pt.y + py * half}`;
|
|
12534
|
-
}
|
|
12535
|
-
function crowFootSymbolOffset(pt, direction) {
|
|
12536
|
-
const [dx, dy] = dirVec(direction);
|
|
12537
|
-
const [px, py] = perpVec(direction);
|
|
12538
|
-
const inset = SIZE * 0.8;
|
|
12539
|
-
const startX = pt.x + dx * inset;
|
|
12540
|
-
const startY = pt.y + dy * inset;
|
|
12541
|
-
const tipX = pt.x + dx * (inset + SIZE);
|
|
12542
|
-
const tipY = pt.y + dy * (inset + SIZE);
|
|
12543
|
-
const spread = SIZE * 0.8;
|
|
12544
|
-
const aX = startX + px * spread, aY = startY + py * spread;
|
|
12545
|
-
const cX = startX - px * spread, cY = startY - py * spread;
|
|
12546
|
-
return [
|
|
12547
|
-
`M${aX},${aY} L${tipX},${tipY}`,
|
|
12548
|
-
`M${startX},${startY} L${tipX},${tipY}`,
|
|
12549
|
-
`M${cX},${cY} L${tipX},${tipY}`
|
|
12550
|
-
].join(" ");
|
|
12551
|
-
}
|
|
12552
|
-
|
|
12553
|
-
// src/components/Diagram/diagram.routing.ts
|
|
12554
|
-
var STUB = 24;
|
|
12555
|
-
var DODGE_PADDING = 16;
|
|
12556
|
-
var MAX_DODGE_ITERATIONS = 6;
|
|
12557
|
-
function pickAnchors(from, to, fromY, toY) {
|
|
12558
|
-
const fcx = from.x + from.width / 2;
|
|
12559
|
-
const fcy = from.y + from.height / 2;
|
|
12560
|
-
const tcx = to.x + to.width / 2;
|
|
12561
|
-
const tcy = to.y + to.height / 2;
|
|
12562
|
-
const dx = tcx - fcx;
|
|
12563
|
-
const dy = tcy - fcy;
|
|
12564
|
-
let fromSide, toSide;
|
|
12565
|
-
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
12566
|
-
fromSide = dx >= 0 ? "right" : "left";
|
|
12567
|
-
toSide = dx >= 0 ? "left" : "right";
|
|
12568
|
-
} else {
|
|
12569
|
-
fromSide = dy >= 0 ? "bottom" : "top";
|
|
12570
|
-
toSide = dy >= 0 ? "top" : "bottom";
|
|
12571
|
-
}
|
|
12572
|
-
return {
|
|
12573
|
-
from: anchorOnSide(from, fromSide, fromY),
|
|
12574
|
-
to: anchorOnSide(to, toSide, toY)
|
|
12575
|
-
};
|
|
12576
|
-
}
|
|
12577
|
-
function anchorOnSide(box, side, fieldY) {
|
|
12578
|
-
switch (side) {
|
|
12579
|
-
case "right":
|
|
12580
|
-
return { side, x: box.x + box.width, y: box.y + (fieldY ?? box.height / 2) };
|
|
12581
|
-
case "left":
|
|
12582
|
-
return { side, x: box.x, y: box.y + (fieldY ?? box.height / 2) };
|
|
12583
|
-
case "top":
|
|
12584
|
-
return { side, x: box.x + box.width / 2, y: box.y };
|
|
12585
|
-
case "bottom":
|
|
12586
|
-
return { side, x: box.x + box.width / 2, y: box.y + box.height };
|
|
12587
|
-
}
|
|
12588
|
-
}
|
|
12589
|
-
function stubOut(a, distance2 = STUB) {
|
|
12590
|
-
switch (a.side) {
|
|
12591
|
-
case "right":
|
|
12592
|
-
return { x: a.x + distance2, y: a.y };
|
|
12593
|
-
case "left":
|
|
12594
|
-
return { x: a.x - distance2, y: a.y };
|
|
12595
|
-
case "top":
|
|
12596
|
-
return { x: a.x, y: a.y - distance2 };
|
|
12597
|
-
case "bottom":
|
|
12598
|
-
return { x: a.x, y: a.y + distance2 };
|
|
12599
|
-
}
|
|
12600
|
-
}
|
|
12601
|
-
function manhattanPath(from, to, obstacles = []) {
|
|
12602
|
-
const f = { x: from.x, y: from.y };
|
|
12603
|
-
const t = { x: to.x, y: to.y };
|
|
12604
|
-
const fs = stubOut(from);
|
|
12605
|
-
const ts = stubOut(to);
|
|
12606
|
-
const fHoriz = from.side === "left" || from.side === "right";
|
|
12607
|
-
const tHoriz = to.side === "left" || to.side === "right";
|
|
12608
|
-
if (fHoriz && tHoriz) {
|
|
12609
|
-
const midX = pickClearMidX((fs.x + ts.x) / 2, fs.y, ts.y, obstacles);
|
|
12610
|
-
return uniqPath([
|
|
12611
|
-
f,
|
|
12612
|
-
fs,
|
|
12613
|
-
{ x: midX, y: fs.y },
|
|
12614
|
-
{ x: midX, y: ts.y },
|
|
12615
|
-
ts,
|
|
12616
|
-
t
|
|
12617
|
-
]);
|
|
12618
|
-
}
|
|
12619
|
-
if (!fHoriz && !tHoriz) {
|
|
12620
|
-
const midY = pickClearMidY((fs.y + ts.y) / 2, fs.x, ts.x, obstacles);
|
|
12621
|
-
return uniqPath([
|
|
12622
|
-
f,
|
|
12623
|
-
fs,
|
|
12624
|
-
{ x: fs.x, y: midY },
|
|
12625
|
-
{ x: ts.x, y: midY },
|
|
12626
|
-
ts,
|
|
12627
|
-
t
|
|
12628
|
-
]);
|
|
12629
|
-
}
|
|
12630
|
-
if (fHoriz) {
|
|
12631
|
-
return uniqPath([
|
|
12632
|
-
f,
|
|
12633
|
-
fs,
|
|
12634
|
-
{ x: ts.x, y: fs.y },
|
|
12635
|
-
ts,
|
|
12636
|
-
t
|
|
12637
|
-
]);
|
|
12638
|
-
}
|
|
12639
|
-
return uniqPath([
|
|
12640
|
-
f,
|
|
12641
|
-
fs,
|
|
12642
|
-
{ x: fs.x, y: ts.y },
|
|
12643
|
-
ts,
|
|
12644
|
-
t
|
|
12645
|
-
]);
|
|
12646
|
-
}
|
|
12647
|
-
function pickClearMidX(idealX, y1, y2, obstacles) {
|
|
12648
|
-
if (obstacles.length === 0) return idealX;
|
|
12649
|
-
const yMin = Math.min(y1, y2);
|
|
12650
|
-
const yMax = Math.max(y1, y2);
|
|
12651
|
-
let midX = idealX;
|
|
12652
|
-
for (let i = 0; i < 4; i++) {
|
|
12653
|
-
let shifted = false;
|
|
12654
|
-
for (const ob of obstacles) {
|
|
12655
|
-
if (ob.y + ob.height + DODGE_PADDING < yMin) continue;
|
|
12656
|
-
if (ob.y - DODGE_PADDING > yMax) continue;
|
|
12657
|
-
const left = ob.x - DODGE_PADDING;
|
|
12658
|
-
const right = ob.x + ob.width + DODGE_PADDING;
|
|
12659
|
-
if (midX > left && midX < right) {
|
|
12660
|
-
midX = Math.abs(midX - left) <= Math.abs(midX - right) ? left - 1 : right + 1;
|
|
12661
|
-
shifted = true;
|
|
12662
|
-
}
|
|
12663
|
-
}
|
|
12664
|
-
if (!shifted) break;
|
|
12665
|
-
}
|
|
12666
|
-
return midX;
|
|
12667
|
-
}
|
|
12668
|
-
function pickClearMidY(idealY, x1, x2, obstacles) {
|
|
12669
|
-
if (obstacles.length === 0) return idealY;
|
|
12670
|
-
const xMin = Math.min(x1, x2);
|
|
12671
|
-
const xMax = Math.max(x1, x2);
|
|
12672
|
-
let midY = idealY;
|
|
12673
|
-
for (let i = 0; i < 4; i++) {
|
|
12674
|
-
let shifted = false;
|
|
12675
|
-
for (const ob of obstacles) {
|
|
12676
|
-
if (ob.x + ob.width + DODGE_PADDING < xMin) continue;
|
|
12677
|
-
if (ob.x - DODGE_PADDING > xMax) continue;
|
|
12678
|
-
const top = ob.y - DODGE_PADDING;
|
|
12679
|
-
const bot = ob.y + ob.height + DODGE_PADDING;
|
|
12680
|
-
if (midY > top && midY < bot) {
|
|
12681
|
-
midY = Math.abs(midY - top) <= Math.abs(midY - bot) ? top - 1 : bot + 1;
|
|
12682
|
-
shifted = true;
|
|
12683
|
-
}
|
|
12684
|
-
}
|
|
12685
|
-
if (!shifted) break;
|
|
12686
|
-
}
|
|
12687
|
-
return midY;
|
|
12688
|
-
}
|
|
12689
|
-
function uniqPath(points) {
|
|
12690
|
-
const out = [];
|
|
12691
|
-
for (const p of points) {
|
|
12692
|
-
const last = out[out.length - 1];
|
|
12693
|
-
if (!last || Math.abs(last.x - p.x) > 0.5 || Math.abs(last.y - p.y) > 0.5) {
|
|
12694
|
-
out.push(p);
|
|
12695
|
-
}
|
|
12696
|
-
}
|
|
12697
|
-
return out;
|
|
12698
|
-
}
|
|
12699
|
-
function dodgeObstacles(path, obstacles, padding = DODGE_PADDING) {
|
|
12700
|
-
if (obstacles.length === 0 || path.length < 2) return path;
|
|
12701
|
-
let working = path.slice();
|
|
12702
|
-
for (let iter = 0; iter < MAX_DODGE_ITERATIONS; iter++) {
|
|
12703
|
-
let dodged = false;
|
|
12704
|
-
const result = [working[0]];
|
|
12705
|
-
for (let i = 1; i < working.length; i++) {
|
|
12706
|
-
const a = result[result.length - 1];
|
|
12707
|
-
const b = working[i];
|
|
12708
|
-
const detour = detourAround(a, b, obstacles, padding);
|
|
12709
|
-
if (detour.length === 0) {
|
|
12710
|
-
result.push(b);
|
|
12711
|
-
} else {
|
|
12712
|
-
for (const p of detour) result.push(p);
|
|
12713
|
-
result.push(b);
|
|
12714
|
-
dodged = true;
|
|
12715
|
-
}
|
|
12716
|
-
}
|
|
12717
|
-
working = uniqPath(result);
|
|
12718
|
-
if (!dodged) break;
|
|
12719
|
-
}
|
|
12720
|
-
return working;
|
|
12721
|
-
}
|
|
12722
|
-
function detourAround(a, b, obstacles, padding) {
|
|
12723
|
-
const isHorizontal = Math.abs(a.y - b.y) < 0.5;
|
|
12724
|
-
const isVertical = Math.abs(a.x - b.x) < 0.5;
|
|
12725
|
-
if (!isHorizontal && !isVertical) return [];
|
|
12726
|
-
let best = null;
|
|
12727
|
-
for (const r of obstacles) {
|
|
12728
|
-
const expanded = expandRect(r, padding);
|
|
12729
|
-
if (!segmentCrossesRect(a, b, expanded)) continue;
|
|
12730
|
-
let entry, exit;
|
|
12731
|
-
if (isHorizontal) {
|
|
12732
|
-
entry = b.x > a.x ? expanded.x : expanded.x + expanded.width;
|
|
12733
|
-
exit = b.x > a.x ? expanded.x + expanded.width : expanded.x;
|
|
12734
|
-
} else {
|
|
12735
|
-
entry = b.y > a.y ? expanded.y : expanded.y + expanded.height;
|
|
12736
|
-
exit = b.y > a.y ? expanded.y + expanded.height : expanded.y;
|
|
12737
|
-
}
|
|
12738
|
-
const dist = isHorizontal ? Math.abs(entry - a.x) : Math.abs(entry - a.y);
|
|
12739
|
-
if (!best || dist < (isHorizontal ? Math.abs(best.entry - a.x) : Math.abs(best.entry - a.y))) {
|
|
12740
|
-
best = { rect: expanded, entry, exit };
|
|
12741
|
-
}
|
|
12742
|
-
}
|
|
12743
|
-
if (!best) return [];
|
|
12744
|
-
if (isHorizontal) {
|
|
12745
|
-
const aboveY = best.rect.y - 1;
|
|
12746
|
-
const belowY = best.rect.y + best.rect.height + 1;
|
|
12747
|
-
const detourY = Math.abs(a.y - aboveY) <= Math.abs(a.y - belowY) ? aboveY : belowY;
|
|
12748
|
-
return [
|
|
12749
|
-
{ x: best.entry, y: a.y },
|
|
12750
|
-
{ x: best.entry, y: detourY },
|
|
12751
|
-
{ x: best.exit, y: detourY },
|
|
12752
|
-
{ x: best.exit, y: a.y }
|
|
12753
|
-
];
|
|
12754
|
-
} else {
|
|
12755
|
-
const leftX = best.rect.x - 1;
|
|
12756
|
-
const rightX = best.rect.x + best.rect.width + 1;
|
|
12757
|
-
const detourX = Math.abs(a.x - leftX) <= Math.abs(a.x - rightX) ? leftX : rightX;
|
|
12758
|
-
return [
|
|
12759
|
-
{ x: a.x, y: best.entry },
|
|
12760
|
-
{ x: detourX, y: best.entry },
|
|
12761
|
-
{ x: detourX, y: best.exit },
|
|
12762
|
-
{ x: a.x, y: best.exit }
|
|
12763
|
-
];
|
|
12764
|
-
}
|
|
12765
|
-
}
|
|
12766
|
-
function expandRect(r, padding) {
|
|
12767
|
-
return {
|
|
12768
|
-
x: r.x - padding,
|
|
12769
|
-
y: r.y - padding,
|
|
12770
|
-
width: r.width + padding * 2,
|
|
12771
|
-
height: r.height + padding * 2
|
|
12772
|
-
};
|
|
12773
|
-
}
|
|
12774
|
-
function segmentCrossesRect(a, b, rect) {
|
|
12775
|
-
const xMin = Math.min(a.x, b.x);
|
|
12776
|
-
const xMax = Math.max(a.x, b.x);
|
|
12777
|
-
const yMin = Math.min(a.y, b.y);
|
|
12778
|
-
const yMax = Math.max(a.y, b.y);
|
|
12779
|
-
if (xMax < rect.x) return false;
|
|
12780
|
-
if (xMin > rect.x + rect.width) return false;
|
|
12781
|
-
if (yMax < rect.y) return false;
|
|
12782
|
-
if (yMin > rect.y + rect.height) return false;
|
|
12783
|
-
if (a.x >= rect.x + 1 && a.x <= rect.x + rect.width - 1 && a.y >= rect.y + 1 && a.y <= rect.y + rect.height - 1) return false;
|
|
12784
|
-
if (b.x >= rect.x + 1 && b.x <= rect.x + rect.width - 1 && b.y >= rect.y + 1 && b.y <= rect.y + rect.height - 1) return false;
|
|
12785
|
-
return true;
|
|
12786
|
-
}
|
|
12787
|
-
function pathFromPoints(points, cornerRadius = 8) {
|
|
12788
|
-
if (points.length === 0) return "";
|
|
12789
|
-
if (points.length === 1) return `M${points[0].x},${points[0].y}`;
|
|
12790
|
-
if (points.length === 2 || cornerRadius <= 0) {
|
|
12791
|
-
return points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
|
|
12792
|
-
}
|
|
12793
|
-
let d = `M${points[0].x},${points[0].y}`;
|
|
12794
|
-
for (let i = 1; i < points.length - 1; i++) {
|
|
12795
|
-
const prev = points[i - 1];
|
|
12796
|
-
const curr = points[i];
|
|
12797
|
-
const next = points[i + 1];
|
|
12798
|
-
const r = Math.min(
|
|
12799
|
-
cornerRadius,
|
|
12800
|
-
distance(prev, curr) / 2,
|
|
12801
|
-
distance(curr, next) / 2
|
|
12802
|
-
);
|
|
12803
|
-
if (r < 1) {
|
|
12804
|
-
d += ` L${curr.x},${curr.y}`;
|
|
12805
|
-
continue;
|
|
12806
|
-
}
|
|
12807
|
-
const beforeX = curr.x + Math.sign(prev.x - curr.x) * r;
|
|
12808
|
-
const beforeY = curr.y + Math.sign(prev.y - curr.y) * r;
|
|
12809
|
-
const afterX = curr.x + Math.sign(next.x - curr.x) * r;
|
|
12810
|
-
const afterY = curr.y + Math.sign(next.y - curr.y) * r;
|
|
12811
|
-
d += ` L${beforeX},${beforeY} Q${curr.x},${curr.y} ${afterX},${afterY}`;
|
|
12812
|
-
}
|
|
12813
|
-
const last = points[points.length - 1];
|
|
12814
|
-
d += ` L${last.x},${last.y}`;
|
|
12815
|
-
return d;
|
|
12816
|
-
}
|
|
12817
|
-
function distance(a, b) {
|
|
12818
|
-
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
12819
|
-
}
|
|
12820
|
-
function bezierPath2(from, to) {
|
|
12821
|
-
const fs = stubOut(from, Math.max(40, distance(from, to) * 0.3));
|
|
12822
|
-
const ts = stubOut(to, Math.max(40, distance(from, to) * 0.3));
|
|
12823
|
-
return `M${from.x},${from.y} C${fs.x},${fs.y} ${ts.x},${ts.y} ${to.x},${to.y}`;
|
|
12824
|
-
}
|
|
12825
|
-
function midPoint(points) {
|
|
12826
|
-
if (points.length === 0) return { x: 0, y: 0 };
|
|
12827
|
-
if (points.length === 1) return points[0];
|
|
12828
|
-
let total = 0;
|
|
12829
|
-
const segLens = [];
|
|
12830
|
-
for (let i = 1; i < points.length; i++) {
|
|
12831
|
-
const len = distance(points[i - 1], points[i]);
|
|
12832
|
-
segLens.push(len);
|
|
12833
|
-
total += len;
|
|
12834
|
-
}
|
|
12835
|
-
let target = total / 2;
|
|
12836
|
-
for (let i = 0; i < segLens.length; i++) {
|
|
12837
|
-
if (target <= segLens[i]) {
|
|
12838
|
-
const t = segLens[i] === 0 ? 0 : target / segLens[i];
|
|
12839
|
-
const a = points[i];
|
|
12840
|
-
const b = points[i + 1];
|
|
12841
|
-
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
12842
|
-
}
|
|
12843
|
-
target -= segLens[i];
|
|
12844
|
-
}
|
|
12845
|
-
return points[points.length - 1];
|
|
12846
|
-
}
|
|
12847
|
-
function insetEndpoints(points, inset) {
|
|
12848
|
-
if (points.length < 2) return points;
|
|
12849
|
-
const result = points.slice();
|
|
12850
|
-
if (inset.from > 0) {
|
|
12851
|
-
const a = result[0];
|
|
12852
|
-
const b = result[1];
|
|
12853
|
-
const len = distance(a, b);
|
|
12854
|
-
if (len > inset.from) {
|
|
12855
|
-
const t = inset.from / len;
|
|
12856
|
-
result[0] = { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
12857
|
-
}
|
|
12858
|
-
}
|
|
12859
|
-
if (inset.to > 0) {
|
|
12860
|
-
const lastIdx = result.length - 1;
|
|
12861
|
-
const a = result[lastIdx];
|
|
12862
|
-
const b = result[lastIdx - 1];
|
|
12863
|
-
const len = distance(a, b);
|
|
12864
|
-
if (len > inset.to) {
|
|
12865
|
-
const t = inset.to / len;
|
|
12866
|
-
result[lastIdx] = { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
12867
|
-
}
|
|
12868
|
-
}
|
|
12869
|
-
return result;
|
|
12870
|
-
}
|
|
12871
|
-
var HEADER_HEIGHT = 36;
|
|
12872
|
-
var FIELD_HEIGHT = 29;
|
|
12873
|
-
var DEFAULT_COLOR2 = "#71717a";
|
|
12874
|
-
function markerDirection(side) {
|
|
12875
|
-
switch (side) {
|
|
12876
|
-
case "left":
|
|
12877
|
-
return "right";
|
|
12878
|
-
// entity body is to the right of a left-side anchor
|
|
12879
|
-
case "right":
|
|
12880
|
-
return "left";
|
|
12881
|
-
case "top":
|
|
12882
|
-
return "down";
|
|
12883
|
-
case "bottom":
|
|
12884
|
-
return "up";
|
|
12885
|
-
}
|
|
12886
|
-
}
|
|
12887
|
-
function strokeDashArray(style) {
|
|
12888
|
-
switch (style) {
|
|
12889
|
-
case "dashed":
|
|
12890
|
-
return "8 4";
|
|
12891
|
-
case "dotted":
|
|
12892
|
-
return "2 4";
|
|
12893
|
-
default:
|
|
12894
|
-
return void 0;
|
|
12895
|
-
}
|
|
12896
|
-
}
|
|
12897
|
-
function DiagramRelation({
|
|
12898
|
-
from,
|
|
12899
|
-
to,
|
|
12900
|
-
fromField: fromFieldProp,
|
|
12901
|
-
toField: toFieldProp,
|
|
12902
|
-
type,
|
|
12903
|
-
fromMarker: fromMarkerProp,
|
|
12904
|
-
toMarker: toMarkerProp,
|
|
12905
|
-
lineStyle: lineStyleProp,
|
|
12906
|
-
routing = "manhattan",
|
|
12907
|
-
color = DEFAULT_COLOR2,
|
|
12908
|
-
strokeWidth = 2,
|
|
12909
|
-
label
|
|
12910
|
-
}) {
|
|
12911
|
-
const { nodeRects, registryVersion } = useCanvas();
|
|
12912
|
-
const { schema } = useDiagram();
|
|
12913
|
-
const result = react.useMemo(() => {
|
|
12914
|
-
const fromRect = nodeRects.get(from);
|
|
12915
|
-
const toRect = nodeRects.get(to);
|
|
12916
|
-
if (!fromRect || !toRect) return null;
|
|
12917
|
-
const defaults = defaultMarkersForType(type);
|
|
12918
|
-
const fromMarker = fromMarkerProp ?? defaults.fromMarker;
|
|
12919
|
-
const toMarker = toMarkerProp ?? defaults.toMarker;
|
|
12920
|
-
const lineStyle = lineStyleProp ?? defaults.lineStyle;
|
|
12921
|
-
const fromEntity = schema.entities.find((e) => (e.id ?? e.name) === from);
|
|
12922
|
-
const toEntity = schema.entities.find((e) => (e.id ?? e.name) === to);
|
|
12923
|
-
const fromFieldY = resolveFieldY(fromRect, fromEntity?.fields, fromFieldProp, true);
|
|
12924
|
-
const toFieldY = resolveFieldY(toRect, toEntity?.fields, toFieldProp, false, fromEntity?.name ?? from);
|
|
12925
|
-
const anchors = pickAnchors(fromRect, toRect, fromFieldY, toFieldY);
|
|
12926
|
-
if (anchors.from.side === "top" || anchors.from.side === "bottom") {
|
|
12927
|
-
anchors.from.x = fromRect.x + fromRect.width / 2;
|
|
12928
|
-
}
|
|
12929
|
-
if (anchors.to.side === "top" || anchors.to.side === "bottom") {
|
|
12930
|
-
anchors.to.x = toRect.x + toRect.width / 2;
|
|
12931
|
-
}
|
|
12932
|
-
let points;
|
|
12933
|
-
if (routing === "straight") {
|
|
12934
|
-
points = [
|
|
12935
|
-
{ x: anchors.from.x, y: anchors.from.y },
|
|
12936
|
-
{ x: anchors.to.x, y: anchors.to.y }
|
|
12937
|
-
];
|
|
12938
|
-
} else if (routing === "bezier") {
|
|
12939
|
-
points = [];
|
|
12940
|
-
} else {
|
|
12941
|
-
const obstacles = [];
|
|
12942
|
-
nodeRects.forEach((rect, id) => {
|
|
12943
|
-
if (id === from || id === to) return;
|
|
12944
|
-
obstacles.push(rect);
|
|
12945
|
-
});
|
|
12946
|
-
const initial = manhattanPath(anchors.from, anchors.to, obstacles);
|
|
12947
|
-
points = dodgeObstacles(initial, obstacles);
|
|
12948
|
-
}
|
|
12949
|
-
const insetAmount = { from: markerInset(fromMarker), to: markerInset(toMarker) };
|
|
12950
|
-
if (routing !== "bezier") {
|
|
12951
|
-
points = insetEndpoints(points, insetAmount);
|
|
12952
|
-
}
|
|
12953
|
-
const linePath = routing === "bezier" ? bezierPath2(anchors.from, anchors.to) : pathFromPoints(points);
|
|
12954
|
-
const fromMarkerRenderable = renderMarker(
|
|
12955
|
-
fromMarker,
|
|
12956
|
-
{ x: anchors.from.x, y: anchors.from.y },
|
|
12957
|
-
markerDirection(anchors.from.side)
|
|
12958
|
-
);
|
|
12959
|
-
const toMarkerRenderable = renderMarker(
|
|
12960
|
-
toMarker,
|
|
12961
|
-
{ x: anchors.to.x, y: anchors.to.y },
|
|
12962
|
-
markerDirection(anchors.to.side)
|
|
12963
|
-
);
|
|
12964
|
-
const mid = routing === "bezier" ? { x: (anchors.from.x + anchors.to.x) / 2, y: (anchors.from.y + anchors.to.y) / 2 } : midPoint(points);
|
|
12965
|
-
return {
|
|
12966
|
-
linePath,
|
|
12967
|
-
fromMarker: fromMarkerRenderable,
|
|
12968
|
-
toMarker: toMarkerRenderable,
|
|
12969
|
-
fromAnchor: anchors.from,
|
|
12970
|
-
toAnchor: anchors.to,
|
|
12971
|
-
mid,
|
|
12972
|
-
lineStyle
|
|
12973
|
-
};
|
|
12974
|
-
}, [
|
|
12975
|
-
from,
|
|
12976
|
-
to,
|
|
12977
|
-
fromFieldProp,
|
|
12978
|
-
toFieldProp,
|
|
12979
|
-
type,
|
|
12980
|
-
fromMarkerProp,
|
|
12981
|
-
toMarkerProp,
|
|
12982
|
-
lineStyleProp,
|
|
12983
|
-
routing,
|
|
12984
|
-
schema,
|
|
12985
|
-
nodeRects,
|
|
12986
|
-
registryVersion
|
|
12987
|
-
]);
|
|
12988
|
-
if (!result) return null;
|
|
12989
|
-
const dashArray = strokeDashArray(result.lineStyle);
|
|
12990
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-react-fancy-diagram-relation": "", children: [
|
|
12991
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12992
|
-
"path",
|
|
12993
|
-
{
|
|
12994
|
-
d: result.linePath,
|
|
12995
|
-
fill: "none",
|
|
12996
|
-
stroke: color,
|
|
12997
|
-
strokeWidth,
|
|
12998
|
-
strokeDasharray: dashArray,
|
|
12999
|
-
strokeLinecap: "round",
|
|
13000
|
-
strokeLinejoin: "round"
|
|
13001
|
-
}
|
|
13002
|
-
),
|
|
13003
|
-
result.fromMarker?.paths.map((shape, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13004
|
-
"path",
|
|
13005
|
-
{
|
|
13006
|
-
d: shape.d,
|
|
13007
|
-
fill: shape.fill === "stroke" ? color : shape.fill === "background" ? "#ffffff" : "none",
|
|
13008
|
-
stroke: color,
|
|
13009
|
-
strokeWidth,
|
|
13010
|
-
strokeLinecap: "round",
|
|
13011
|
-
strokeLinejoin: "round"
|
|
13012
|
-
},
|
|
13013
|
-
`fm-${i}`
|
|
13014
|
-
)),
|
|
13015
|
-
result.fromMarker?.text && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13016
|
-
"text",
|
|
13017
|
-
{
|
|
13018
|
-
x: result.fromAnchor.x,
|
|
13019
|
-
y: result.fromAnchor.y,
|
|
13020
|
-
fontSize: 16,
|
|
13021
|
-
textAnchor: "middle",
|
|
13022
|
-
dominantBaseline: "middle",
|
|
13023
|
-
style: { userSelect: "none" },
|
|
13024
|
-
children: result.fromMarker.text
|
|
13025
|
-
}
|
|
13026
|
-
),
|
|
13027
|
-
result.toMarker?.text && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13028
|
-
"text",
|
|
13029
|
-
{
|
|
13030
|
-
x: result.toAnchor.x,
|
|
13031
|
-
y: result.toAnchor.y,
|
|
13032
|
-
fontSize: 16,
|
|
13033
|
-
textAnchor: "middle",
|
|
13034
|
-
dominantBaseline: "middle",
|
|
13035
|
-
style: { userSelect: "none" },
|
|
13036
|
-
children: result.toMarker.text
|
|
13037
|
-
}
|
|
13038
|
-
),
|
|
13039
|
-
result.toMarker?.paths.map((shape, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13040
|
-
"path",
|
|
13041
|
-
{
|
|
13042
|
-
d: shape.d,
|
|
13043
|
-
fill: shape.fill === "stroke" ? color : shape.fill === "background" ? "#ffffff" : "none",
|
|
13044
|
-
stroke: color,
|
|
13045
|
-
strokeWidth,
|
|
13046
|
-
strokeLinecap: "round",
|
|
13047
|
-
strokeLinejoin: "round"
|
|
13048
|
-
},
|
|
13049
|
-
`tm-${i}`
|
|
13050
|
-
)),
|
|
13051
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: result.mid.x - 50, y: result.mid.y - 12, width: 100, height: 24, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center text-xs text-zinc-500", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-white/90 px-1.5 py-0.5 dark:bg-zinc-900/90", children: label }) }) })
|
|
13052
|
-
] });
|
|
13053
|
-
}
|
|
13054
|
-
function resolveFieldY(rect, fields, fieldProp, isFrom, fromName) {
|
|
13055
|
-
if (!fields || fields.length === 0) return void 0;
|
|
13056
|
-
let idx = -1;
|
|
13057
|
-
if (fieldProp) {
|
|
13058
|
-
idx = fields.findIndex((f) => f.name === fieldProp);
|
|
13059
|
-
} else if (isFrom) {
|
|
13060
|
-
idx = fields.findIndex((f) => f.primary);
|
|
13061
|
-
} else {
|
|
13062
|
-
const lower = (fromName ?? "").toLowerCase();
|
|
13063
|
-
idx = fields.findIndex(
|
|
13064
|
-
(f) => f.foreign && (f.name === `${lower}_id` || f.name === `${lower}Id`)
|
|
13065
|
-
);
|
|
13066
|
-
if (idx === -1) idx = fields.findIndex((f) => f.foreign);
|
|
13067
|
-
}
|
|
13068
|
-
if (idx < 0) return void 0;
|
|
13069
|
-
return HEADER_HEIGHT + idx * FIELD_HEIGHT + FIELD_HEIGHT / 2;
|
|
13070
|
-
}
|
|
13071
|
-
DiagramRelation._isCanvasEdge = true;
|
|
13072
|
-
DiagramRelation.displayName = "DiagramRelation";
|
|
13073
|
-
var FORMAT_LABELS = {
|
|
13074
|
-
erd: "ERD",
|
|
13075
|
-
uml: "UML",
|
|
13076
|
-
dfd: "DFD"
|
|
13077
|
-
};
|
|
13078
|
-
var FORMAT_EXTENSIONS = {
|
|
13079
|
-
erd: "erd",
|
|
13080
|
-
uml: "puml",
|
|
13081
|
-
dfd: "dfd"
|
|
13082
|
-
};
|
|
13083
|
-
function DiagramToolbar({ className }) {
|
|
13084
|
-
const { schema, downloadableRef, importableRef, exportFormats, onImport } = useDiagram();
|
|
13085
|
-
const fileInputRef = react.useRef(null);
|
|
13086
|
-
const canDownload = downloadableRef.current;
|
|
13087
|
-
const canImport = importableRef.current;
|
|
13088
|
-
const handleDownload = react.useCallback(
|
|
13089
|
-
async (format) => {
|
|
13090
|
-
const { serializeToERD: serializeToERD2, serializeToUML: serializeToUML2, serializeToDFD: serializeToDFD2 } = await Promise.resolve().then(() => (init_diagram_serializers(), diagram_serializers_exports));
|
|
13091
|
-
let content;
|
|
13092
|
-
switch (format) {
|
|
13093
|
-
case "erd":
|
|
13094
|
-
content = serializeToERD2(schema);
|
|
13095
|
-
break;
|
|
13096
|
-
case "uml":
|
|
13097
|
-
content = serializeToUML2(schema);
|
|
13098
|
-
break;
|
|
13099
|
-
case "dfd":
|
|
13100
|
-
content = serializeToDFD2(schema);
|
|
13101
|
-
break;
|
|
13102
|
-
}
|
|
13103
|
-
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
|
13104
|
-
const url = URL.createObjectURL(blob);
|
|
13105
|
-
const a = document.createElement("a");
|
|
13106
|
-
a.href = url;
|
|
13107
|
-
a.download = `diagram.${FORMAT_EXTENSIONS[format]}`;
|
|
13108
|
-
document.body.appendChild(a);
|
|
13109
|
-
a.click();
|
|
13110
|
-
document.body.removeChild(a);
|
|
13111
|
-
URL.revokeObjectURL(url);
|
|
13112
|
-
},
|
|
13113
|
-
[schema]
|
|
13114
|
-
);
|
|
13115
|
-
const handleFileChange = react.useCallback(
|
|
13116
|
-
async (e) => {
|
|
13117
|
-
const file = e.target.files?.[0];
|
|
13118
|
-
if (!file || !onImport) return;
|
|
13119
|
-
const text = await file.text();
|
|
13120
|
-
const ext = file.name.split(".").pop()?.toLowerCase();
|
|
13121
|
-
const { deserializeSchema: deserializeSchema2 } = await Promise.resolve().then(() => (init_diagram_serializers(), diagram_serializers_exports));
|
|
13122
|
-
let format = "erd";
|
|
13123
|
-
if (ext === "puml" || ext === "uml") format = "uml";
|
|
13124
|
-
else if (ext === "dfd") format = "dfd";
|
|
13125
|
-
const parsed = deserializeSchema2(text, format);
|
|
13126
|
-
onImport(parsed);
|
|
13127
|
-
if (fileInputRef.current) {
|
|
13128
|
-
fileInputRef.current.value = "";
|
|
13129
|
-
}
|
|
13130
|
-
},
|
|
13131
|
-
[onImport]
|
|
13132
|
-
);
|
|
13133
|
-
if (!canDownload && !canImport) return null;
|
|
13134
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13135
|
-
"div",
|
|
13136
|
-
{
|
|
13137
|
-
"data-react-fancy-diagram-toolbar": "",
|
|
13138
|
-
className: cn(
|
|
13139
|
-
"absolute right-3 top-3 z-10 flex items-center gap-1 rounded-lg border border-zinc-200 bg-white/90 p-1 shadow-sm backdrop-blur-sm dark:border-zinc-700 dark:bg-zinc-800/90",
|
|
13140
|
-
className
|
|
13141
|
-
),
|
|
13142
|
-
children: [
|
|
13143
|
-
canDownload && exportFormats.map((format) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13144
|
-
"button",
|
|
13145
|
-
{
|
|
13146
|
-
type: "button",
|
|
13147
|
-
onClick: () => handleDownload(format),
|
|
13148
|
-
className: "rounded px-2 py-1 text-xs font-medium text-zinc-600 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-700 dark:hover:text-zinc-200",
|
|
13149
|
-
children: FORMAT_LABELS[format]
|
|
13150
|
-
},
|
|
13151
|
-
format
|
|
13152
|
-
)),
|
|
13153
|
-
canImport && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13154
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13155
|
-
"button",
|
|
13156
|
-
{
|
|
13157
|
-
type: "button",
|
|
13158
|
-
onClick: () => fileInputRef.current?.click(),
|
|
13159
|
-
className: "rounded px-2 py-1 text-xs font-medium text-zinc-600 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-700 dark:hover:text-zinc-200",
|
|
13160
|
-
children: "Import"
|
|
13161
|
-
}
|
|
13162
|
-
),
|
|
13163
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13164
|
-
"input",
|
|
13165
|
-
{
|
|
13166
|
-
ref: fileInputRef,
|
|
13167
|
-
type: "file",
|
|
13168
|
-
accept: ".erd,.puml,.uml,.dfd,.txt",
|
|
13169
|
-
className: "hidden",
|
|
13170
|
-
onChange: handleFileChange
|
|
13171
|
-
}
|
|
13172
|
-
)
|
|
13173
|
-
] })
|
|
13174
|
-
]
|
|
13175
|
-
}
|
|
13176
|
-
);
|
|
13177
|
-
}
|
|
13178
|
-
DiagramToolbar.displayName = "DiagramToolbar";
|
|
13179
|
-
|
|
13180
|
-
// src/components/Diagram/diagram.layout.ts
|
|
13181
|
-
var ENTITY_WIDTH = 220;
|
|
13182
|
-
var HEADER_HEIGHT2 = 40;
|
|
13183
|
-
var FIELD_HEIGHT2 = 28;
|
|
13184
|
-
var HORIZONTAL_GAP = 80;
|
|
13185
|
-
var VERTICAL_GAP = 60;
|
|
13186
|
-
function getEntityHeight(fieldCount) {
|
|
13187
|
-
return HEADER_HEIGHT2 + Math.max(fieldCount, 1) * FIELD_HEIGHT2;
|
|
13188
|
-
}
|
|
13189
|
-
function resolveEntityId(entity) {
|
|
13190
|
-
return entity.id ?? entity.name;
|
|
13191
|
-
}
|
|
13192
|
-
function computeDiagramLayout(schema) {
|
|
13193
|
-
const positions = /* @__PURE__ */ new Map();
|
|
13194
|
-
const entityIds = new Set(schema.entities.map(resolveEntityId));
|
|
13195
|
-
const incoming = /* @__PURE__ */ new Map();
|
|
13196
|
-
for (const id of entityIds) {
|
|
13197
|
-
incoming.set(id, /* @__PURE__ */ new Set());
|
|
13198
|
-
}
|
|
13199
|
-
for (const rel of schema.relations) {
|
|
13200
|
-
if (entityIds.has(rel.from) && entityIds.has(rel.to)) {
|
|
13201
|
-
incoming.get(rel.to).add(rel.from);
|
|
13202
|
-
}
|
|
13203
|
-
}
|
|
13204
|
-
const rowAssignment = /* @__PURE__ */ new Map();
|
|
13205
|
-
const assigned = /* @__PURE__ */ new Set();
|
|
13206
|
-
const queue = [];
|
|
13207
|
-
for (const id of entityIds) {
|
|
13208
|
-
if (incoming.get(id).size === 0) {
|
|
13209
|
-
rowAssignment.set(id, 0);
|
|
13210
|
-
assigned.add(id);
|
|
13211
|
-
queue.push(id);
|
|
13212
|
-
}
|
|
13213
|
-
}
|
|
13214
|
-
if (queue.length === 0 && entityIds.size > 0) {
|
|
13215
|
-
const firstId = resolveEntityId(schema.entities[0]);
|
|
13216
|
-
rowAssignment.set(firstId, 0);
|
|
13217
|
-
assigned.add(firstId);
|
|
13218
|
-
queue.push(firstId);
|
|
13219
|
-
}
|
|
13220
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
13221
|
-
for (const id of entityIds) {
|
|
13222
|
-
outgoing.set(id, []);
|
|
13223
|
-
}
|
|
13224
|
-
for (const rel of schema.relations) {
|
|
13225
|
-
if (entityIds.has(rel.from) && entityIds.has(rel.to)) {
|
|
13226
|
-
outgoing.get(rel.from).push(rel.to);
|
|
13227
|
-
}
|
|
13228
|
-
}
|
|
13229
|
-
let head = 0;
|
|
13230
|
-
while (head < queue.length) {
|
|
13231
|
-
const current = queue[head++];
|
|
13232
|
-
const currentRow = rowAssignment.get(current);
|
|
13233
|
-
for (const neighbor of outgoing.get(current) ?? []) {
|
|
13234
|
-
if (!assigned.has(neighbor)) {
|
|
13235
|
-
rowAssignment.set(neighbor, currentRow + 1);
|
|
13236
|
-
assigned.add(neighbor);
|
|
13237
|
-
queue.push(neighbor);
|
|
13238
|
-
}
|
|
13239
|
-
}
|
|
13240
|
-
}
|
|
13241
|
-
for (const id of entityIds) {
|
|
13242
|
-
if (!assigned.has(id)) {
|
|
13243
|
-
rowAssignment.set(id, 0);
|
|
13244
|
-
}
|
|
13245
|
-
}
|
|
13246
|
-
const rows = /* @__PURE__ */ new Map();
|
|
13247
|
-
for (const [id, row] of rowAssignment) {
|
|
13248
|
-
if (!rows.has(row)) {
|
|
13249
|
-
rows.set(row, []);
|
|
13250
|
-
}
|
|
13251
|
-
rows.get(row).push(id);
|
|
13252
|
-
}
|
|
13253
|
-
const fieldCounts = /* @__PURE__ */ new Map();
|
|
13254
|
-
for (const entity of schema.entities) {
|
|
13255
|
-
fieldCounts.set(resolveEntityId(entity), entity.fields?.length ?? 0);
|
|
13256
|
-
}
|
|
13257
|
-
const sortedRows = Array.from(rows.keys()).sort((a, b) => a - b);
|
|
13258
|
-
let currentY = 0;
|
|
13259
|
-
for (const rowIndex of sortedRows) {
|
|
13260
|
-
const rowEntities = rows.get(rowIndex);
|
|
13261
|
-
const totalWidth = rowEntities.length * ENTITY_WIDTH + (rowEntities.length - 1) * HORIZONTAL_GAP;
|
|
13262
|
-
const startX = -totalWidth / 2 + ENTITY_WIDTH / 2;
|
|
13263
|
-
let maxHeight = 0;
|
|
13264
|
-
for (let i = 0; i < rowEntities.length; i++) {
|
|
13265
|
-
const entityId = rowEntities[i];
|
|
13266
|
-
const x = startX + i * (ENTITY_WIDTH + HORIZONTAL_GAP) - ENTITY_WIDTH / 2;
|
|
13267
|
-
positions.set(entityId, { x, y: currentY });
|
|
13268
|
-
const height = getEntityHeight(fieldCounts.get(entityId) ?? 0);
|
|
13269
|
-
if (height > maxHeight) {
|
|
13270
|
-
maxHeight = height;
|
|
13271
|
-
}
|
|
13272
|
-
}
|
|
13273
|
-
currentY += maxHeight + VERTICAL_GAP;
|
|
13274
|
-
}
|
|
13275
|
-
return positions;
|
|
13276
|
-
}
|
|
13277
|
-
function DiagramRoot({
|
|
13278
|
-
children,
|
|
13279
|
-
schema,
|
|
13280
|
-
type = "general",
|
|
13281
|
-
viewport,
|
|
13282
|
-
defaultViewport,
|
|
13283
|
-
onViewportChange,
|
|
13284
|
-
downloadable = false,
|
|
13285
|
-
importable = false,
|
|
13286
|
-
exportFormats = ["erd"],
|
|
13287
|
-
onImport,
|
|
13288
|
-
minimap = false,
|
|
13289
|
-
className
|
|
13290
|
-
}) {
|
|
13291
|
-
const downloadableRef = react.useRef(downloadable);
|
|
13292
|
-
const importableRef = react.useRef(importable);
|
|
13293
|
-
const normalizedSchema = react.useMemo(() => {
|
|
13294
|
-
if (!schema) return { entities: [], relations: [] };
|
|
13295
|
-
const entities = schema.entities.map((e) => ({
|
|
13296
|
-
...e,
|
|
13297
|
-
id: e.id ?? e.name
|
|
13298
|
-
}));
|
|
13299
|
-
const relations = schema.relations.map((r, i) => ({
|
|
13300
|
-
...r,
|
|
13301
|
-
id: r.id ?? `rel-${i}`
|
|
13302
|
-
}));
|
|
13303
|
-
return { entities, relations };
|
|
13304
|
-
}, [schema]);
|
|
13305
|
-
const initialPositions = react.useMemo(() => {
|
|
13306
|
-
if (normalizedSchema.entities.length === 0) return /* @__PURE__ */ new Map();
|
|
13307
|
-
const layout = computeDiagramLayout(normalizedSchema);
|
|
13308
|
-
const positions = /* @__PURE__ */ new Map();
|
|
13309
|
-
for (const entity of normalizedSchema.entities) {
|
|
13310
|
-
if (entity.x !== void 0 && entity.y !== void 0) {
|
|
13311
|
-
positions.set(entity.id, { x: entity.x, y: entity.y });
|
|
13312
|
-
} else {
|
|
13313
|
-
const pos = layout.get(entity.id);
|
|
13314
|
-
positions.set(entity.id, pos ?? { x: 0, y: 0 });
|
|
13315
|
-
}
|
|
13316
|
-
}
|
|
13317
|
-
return positions;
|
|
13318
|
-
}, [normalizedSchema]);
|
|
13319
|
-
const computedDefaultViewport = react.useMemo(() => {
|
|
13320
|
-
if (defaultViewport) return defaultViewport;
|
|
13321
|
-
if (initialPositions.size === 0) return { panX: 0, panY: 0, zoom: 1 };
|
|
13322
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
13323
|
-
initialPositions.forEach((pos) => {
|
|
13324
|
-
minX = Math.min(minX, pos.x);
|
|
13325
|
-
minY = Math.min(minY, pos.y);
|
|
13326
|
-
maxX = Math.max(maxX, pos.x + 220);
|
|
13327
|
-
maxY = Math.max(maxY, pos.y + 200);
|
|
13328
|
-
});
|
|
13329
|
-
const padding = 40;
|
|
13330
|
-
const panX = -minX + padding;
|
|
13331
|
-
const panY = -minY + padding;
|
|
13332
|
-
return { panX, panY, zoom: 1 };
|
|
13333
|
-
}, [defaultViewport, initialPositions]);
|
|
13334
|
-
const [entityPositions, setEntityPositions] = react.useState(initialPositions);
|
|
13335
|
-
const handleEntityMove = react.useCallback((entityId, x, y) => {
|
|
13336
|
-
setEntityPositions((prev) => {
|
|
13337
|
-
const next = new Map(prev);
|
|
13338
|
-
next.set(entityId, { x, y });
|
|
13339
|
-
return next;
|
|
13340
|
-
});
|
|
13341
|
-
}, []);
|
|
13342
|
-
const ctx = react.useMemo(
|
|
13343
|
-
() => ({
|
|
13344
|
-
diagramType: type,
|
|
13345
|
-
schema: normalizedSchema,
|
|
13346
|
-
downloadableRef,
|
|
13347
|
-
importableRef,
|
|
13348
|
-
exportFormats,
|
|
13349
|
-
onImport
|
|
13350
|
-
}),
|
|
13351
|
-
[type, normalizedSchema, exportFormats, onImport]
|
|
13352
|
-
);
|
|
13353
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DiagramContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-react-fancy-diagram": "", className: "relative h-full w-full", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13354
|
-
Canvas,
|
|
13355
|
-
{
|
|
13356
|
-
viewport,
|
|
13357
|
-
defaultViewport: computedDefaultViewport,
|
|
13358
|
-
onViewportChange,
|
|
13359
|
-
showGrid: true,
|
|
13360
|
-
fitOnMount: true,
|
|
13361
|
-
className: cn("h-full w-full", className),
|
|
13362
|
-
children: [
|
|
13363
|
-
normalizedSchema.entities.map((entity) => {
|
|
13364
|
-
const pos = entityPositions.get(entity.id) ?? { x: 0, y: 0 };
|
|
13365
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13366
|
-
DiagramEntity,
|
|
13367
|
-
{
|
|
13368
|
-
id: entity.id,
|
|
13369
|
-
name: entity.name,
|
|
13370
|
-
x: pos.x,
|
|
13371
|
-
y: pos.y,
|
|
13372
|
-
draggable: true,
|
|
13373
|
-
onPositionChange: (nx, ny) => handleEntityMove(entity.id, nx, ny),
|
|
13374
|
-
children: entity.fields?.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13375
|
-
DiagramField,
|
|
13376
|
-
{
|
|
13377
|
-
name: field.name,
|
|
13378
|
-
type: field.type,
|
|
13379
|
-
primary: field.primary,
|
|
13380
|
-
foreign: field.foreign,
|
|
13381
|
-
nullable: field.nullable
|
|
13382
|
-
},
|
|
13383
|
-
field.name
|
|
13384
|
-
))
|
|
13385
|
-
},
|
|
13386
|
-
entity.id
|
|
13387
|
-
);
|
|
13388
|
-
}),
|
|
13389
|
-
normalizedSchema.relations.map((rel) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13390
|
-
DiagramRelation,
|
|
13391
|
-
{
|
|
13392
|
-
from: rel.from,
|
|
13393
|
-
to: rel.to,
|
|
13394
|
-
fromField: rel.fromField,
|
|
13395
|
-
toField: rel.toField,
|
|
13396
|
-
type: rel.type,
|
|
13397
|
-
label: rel.label
|
|
13398
|
-
},
|
|
13399
|
-
rel.id
|
|
13400
|
-
)),
|
|
13401
|
-
children,
|
|
13402
|
-
/* @__PURE__ */ jsxRuntime.jsx(Canvas.Controls, {}),
|
|
13403
|
-
minimap && /* @__PURE__ */ jsxRuntime.jsx(Canvas.Minimap, {})
|
|
13404
|
-
]
|
|
13405
|
-
}
|
|
13406
|
-
) }) });
|
|
13407
|
-
}
|
|
13408
|
-
var Diagram = Object.assign(DiagramRoot, {
|
|
13409
|
-
Entity: DiagramEntity,
|
|
13410
|
-
Field: DiagramField,
|
|
13411
|
-
Relation: DiagramRelation,
|
|
13412
|
-
Toolbar: DiagramToolbar
|
|
13413
|
-
});
|
|
13414
11478
|
var TreeNavContext = react.createContext(null);
|
|
13415
11479
|
function useTreeNav() {
|
|
13416
11480
|
const ctx = react.useContext(TreeNavContext);
|
|
@@ -13790,7 +11854,6 @@ exports.Brand = Brand;
|
|
|
13790
11854
|
exports.Breadcrumbs = Breadcrumbs;
|
|
13791
11855
|
exports.Calendar = Calendar;
|
|
13792
11856
|
exports.Callout = Callout;
|
|
13793
|
-
exports.Canvas = Canvas;
|
|
13794
11857
|
exports.Card = Card;
|
|
13795
11858
|
exports.Carousel = Carousel;
|
|
13796
11859
|
exports.Chart = Chart;
|
|
@@ -13802,7 +11865,6 @@ exports.Composer = Composer;
|
|
|
13802
11865
|
exports.ContentRenderer = ContentRenderer;
|
|
13803
11866
|
exports.ContextMenu = ContextMenu;
|
|
13804
11867
|
exports.DatePicker = DatePicker;
|
|
13805
|
-
exports.Diagram = Diagram;
|
|
13806
11868
|
exports.Dropdown = Dropdown;
|
|
13807
11869
|
exports.EMOJI_CATEGORY_ORDER = EMOJI_CATEGORY_ORDER;
|
|
13808
11870
|
exports.EMOJI_DATA = EMOJI_DATA;
|
|
@@ -13863,12 +11925,10 @@ exports.useAccordion = useAccordion;
|
|
|
13863
11925
|
exports.useAccordionPanel = useAccordionPanel;
|
|
13864
11926
|
exports.useAccordionSection = useAccordionSection;
|
|
13865
11927
|
exports.useAnimation = useAnimation;
|
|
13866
|
-
exports.useCanvas = useCanvas;
|
|
13867
11928
|
exports.useCarousel = useCarousel;
|
|
13868
11929
|
exports.useCommand = useCommand;
|
|
13869
11930
|
exports.useContextMenu = useContextMenu;
|
|
13870
11931
|
exports.useControllableState = useControllableState;
|
|
13871
|
-
exports.useDiagram = useDiagram;
|
|
13872
11932
|
exports.useDropdown = useDropdown;
|
|
13873
11933
|
exports.useEditor = useEditor;
|
|
13874
11934
|
exports.useEscapeKey = useEscapeKey;
|