@particle-academy/react-fancy 2.10.0 → 3.0.1
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 +24 -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/package.json
CHANGED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
// src/components/Diagram/diagram.serializers.ts
|
|
2
|
-
function serializeToERD(schema) {
|
|
3
|
-
const lines = [];
|
|
4
|
-
for (const entity of schema.entities) {
|
|
5
|
-
lines.push(`[${entity.name}]`);
|
|
6
|
-
if (entity.fields) {
|
|
7
|
-
for (const field of entity.fields) {
|
|
8
|
-
const parts = [` ${field.name}`];
|
|
9
|
-
if (field.type) parts.push(field.type);
|
|
10
|
-
if (field.primary) parts.push("PK");
|
|
11
|
-
if (field.foreign) parts.push("FK");
|
|
12
|
-
if (field.nullable) parts.push("?");
|
|
13
|
-
lines.push(parts.join(" "));
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
lines.push("");
|
|
17
|
-
}
|
|
18
|
-
for (const rel of schema.relations) {
|
|
19
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
20
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
21
|
-
if (!fromEntity || !toEntity) continue;
|
|
22
|
-
const marker = getERDMarker(rel.type);
|
|
23
|
-
const parts = [fromEntity.name, marker, toEntity.name];
|
|
24
|
-
if (rel.label) parts.push(`: ${rel.label}`);
|
|
25
|
-
lines.push(parts.join(" "));
|
|
26
|
-
}
|
|
27
|
-
return lines.join("\n").trim();
|
|
28
|
-
}
|
|
29
|
-
function getERDMarker(type) {
|
|
30
|
-
switch (type) {
|
|
31
|
-
case "one-to-one":
|
|
32
|
-
return "1--1";
|
|
33
|
-
case "one-to-many":
|
|
34
|
-
return "1--*";
|
|
35
|
-
case "many-to-many":
|
|
36
|
-
return "*--*";
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function serializeToUML(schema) {
|
|
40
|
-
const lines = ["@startuml"];
|
|
41
|
-
for (const entity of schema.entities) {
|
|
42
|
-
lines.push(`class ${entity.name} {`);
|
|
43
|
-
if (entity.fields) {
|
|
44
|
-
for (const field of entity.fields) {
|
|
45
|
-
const typeStr = field.type ?? "any";
|
|
46
|
-
const nullable = field.nullable ? "?" : "";
|
|
47
|
-
const stereotype = field.primary ? " <<PK>>" : field.foreign ? " <<FK>>" : "";
|
|
48
|
-
lines.push(` ${field.name} : ${typeStr}${nullable}${stereotype}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
lines.push("}");
|
|
52
|
-
lines.push("");
|
|
53
|
-
}
|
|
54
|
-
for (const rel of schema.relations) {
|
|
55
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
56
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
57
|
-
if (!fromEntity || !toEntity) continue;
|
|
58
|
-
const arrow = getUMLArrow(rel.type);
|
|
59
|
-
const label = rel.label ? ` : ${rel.label}` : "";
|
|
60
|
-
lines.push(`${fromEntity.name} ${arrow} ${toEntity.name}${label}`);
|
|
61
|
-
}
|
|
62
|
-
lines.push("@enduml");
|
|
63
|
-
return lines.join("\n");
|
|
64
|
-
}
|
|
65
|
-
function getUMLArrow(type) {
|
|
66
|
-
switch (type) {
|
|
67
|
-
case "one-to-one":
|
|
68
|
-
return '"1" -- "1"';
|
|
69
|
-
case "one-to-many":
|
|
70
|
-
return '"1" -- "*"';
|
|
71
|
-
case "many-to-many":
|
|
72
|
-
return '"*" -- "*"';
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function serializeToDFD(schema) {
|
|
76
|
-
const lines = [];
|
|
77
|
-
for (const entity of schema.entities) {
|
|
78
|
-
lines.push(`entity ${entity.name}`);
|
|
79
|
-
}
|
|
80
|
-
lines.push("");
|
|
81
|
-
for (const rel of schema.relations) {
|
|
82
|
-
const fromEntity = schema.entities.find((e) => e.id === rel.from);
|
|
83
|
-
const toEntity = schema.entities.find((e) => e.id === rel.to);
|
|
84
|
-
if (!fromEntity || !toEntity) continue;
|
|
85
|
-
const label = rel.label ? ` "${rel.label}"` : "";
|
|
86
|
-
lines.push(`${fromEntity.name} -> ${toEntity.name}${label}`);
|
|
87
|
-
}
|
|
88
|
-
return lines.join("\n").trim();
|
|
89
|
-
}
|
|
90
|
-
function deserializeSchema(input, format) {
|
|
91
|
-
switch (format) {
|
|
92
|
-
case "erd":
|
|
93
|
-
return deserializeERD(input);
|
|
94
|
-
case "uml":
|
|
95
|
-
return deserializeUML(input);
|
|
96
|
-
case "dfd":
|
|
97
|
-
return deserializeDFD(input);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function deserializeERD(input) {
|
|
101
|
-
const entities = [];
|
|
102
|
-
const relations = [];
|
|
103
|
-
const lines = input.split("\n");
|
|
104
|
-
let currentEntity = null;
|
|
105
|
-
for (const rawLine of lines) {
|
|
106
|
-
const line = rawLine.trim();
|
|
107
|
-
const entityMatch = line.match(/^\[(.+)\]$/);
|
|
108
|
-
if (entityMatch) {
|
|
109
|
-
currentEntity = {
|
|
110
|
-
id: entityMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
111
|
-
name: entityMatch[1],
|
|
112
|
-
fields: []
|
|
113
|
-
};
|
|
114
|
-
entities.push(currentEntity);
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
if (currentEntity && rawLine.startsWith(" ") && line.length > 0) {
|
|
118
|
-
const parts = line.split(/\s+/);
|
|
119
|
-
const field = { name: parts[0] };
|
|
120
|
-
if (parts.length > 1 && !["PK", "FK", "?"].includes(parts[1])) {
|
|
121
|
-
field.type = parts[1];
|
|
122
|
-
}
|
|
123
|
-
if (parts.includes("PK")) field.primary = true;
|
|
124
|
-
if (parts.includes("FK")) field.foreign = true;
|
|
125
|
-
if (parts.includes("?")) field.nullable = true;
|
|
126
|
-
currentEntity.fields.push(field);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const relMatch = line.match(
|
|
130
|
-
/^(\S+)\s+(1--1|1--\*|\*--\*)\s+(\S+)(?:\s*:\s*(.+))?$/
|
|
131
|
-
);
|
|
132
|
-
if (relMatch) {
|
|
133
|
-
currentEntity = null;
|
|
134
|
-
const fromName = relMatch[1];
|
|
135
|
-
const marker = relMatch[2];
|
|
136
|
-
const toName = relMatch[3];
|
|
137
|
-
const label = relMatch[4];
|
|
138
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
139
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
140
|
-
if (fromEntity && toEntity) {
|
|
141
|
-
relations.push({
|
|
142
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
143
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
144
|
-
to: toEntity.id ?? toEntity.name,
|
|
145
|
-
type: parseERDMarker(marker),
|
|
146
|
-
label
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
if (line === "") {
|
|
152
|
-
currentEntity = null;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return { entities, relations };
|
|
156
|
-
}
|
|
157
|
-
function parseERDMarker(marker) {
|
|
158
|
-
switch (marker) {
|
|
159
|
-
case "1--1":
|
|
160
|
-
return "one-to-one";
|
|
161
|
-
case "1--*":
|
|
162
|
-
return "one-to-many";
|
|
163
|
-
case "*--*":
|
|
164
|
-
return "many-to-many";
|
|
165
|
-
default:
|
|
166
|
-
return "one-to-many";
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
function deserializeUML(input) {
|
|
170
|
-
const entities = [];
|
|
171
|
-
const relations = [];
|
|
172
|
-
const lines = input.split("\n");
|
|
173
|
-
let currentEntity = null;
|
|
174
|
-
for (const rawLine of lines) {
|
|
175
|
-
const line = rawLine.trim();
|
|
176
|
-
if (line === "@startuml" || line === "@enduml" || line === "") continue;
|
|
177
|
-
const classMatch = line.match(/^class\s+(\S+)\s*\{$/);
|
|
178
|
-
if (classMatch) {
|
|
179
|
-
currentEntity = {
|
|
180
|
-
id: classMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
181
|
-
name: classMatch[1],
|
|
182
|
-
fields: []
|
|
183
|
-
};
|
|
184
|
-
entities.push(currentEntity);
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
if (line === "}") {
|
|
188
|
-
currentEntity = null;
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
if (currentEntity) {
|
|
192
|
-
const fieldMatch = line.match(
|
|
193
|
-
/^(\S+)\s*:\s*(\S+?)(\?)?(?:\s*<<(PK|FK)>>)?$/
|
|
194
|
-
);
|
|
195
|
-
if (fieldMatch) {
|
|
196
|
-
const field = {
|
|
197
|
-
name: fieldMatch[1],
|
|
198
|
-
type: fieldMatch[2]
|
|
199
|
-
};
|
|
200
|
-
if (fieldMatch[3]) field.nullable = true;
|
|
201
|
-
if (fieldMatch[4] === "PK") field.primary = true;
|
|
202
|
-
if (fieldMatch[4] === "FK") field.foreign = true;
|
|
203
|
-
currentEntity.fields.push(field);
|
|
204
|
-
}
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const relMatch = line.match(
|
|
208
|
-
/^(\S+)\s+"([1*])"\s+--\s+"([1*])"\s+(\S+)(?:\s*:\s*(.+))?$/
|
|
209
|
-
);
|
|
210
|
-
if (relMatch) {
|
|
211
|
-
const fromName = relMatch[1];
|
|
212
|
-
const fromCard = relMatch[2];
|
|
213
|
-
const toCard = relMatch[3];
|
|
214
|
-
const toName = relMatch[4];
|
|
215
|
-
const label = relMatch[5];
|
|
216
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
217
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
218
|
-
if (fromEntity && toEntity) {
|
|
219
|
-
const type = fromCard === "1" && toCard === "1" ? "one-to-one" : fromCard === "1" && toCard === "*" ? "one-to-many" : "many-to-many";
|
|
220
|
-
relations.push({
|
|
221
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
222
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
223
|
-
to: toEntity.id ?? toEntity.name,
|
|
224
|
-
type,
|
|
225
|
-
label
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return { entities, relations };
|
|
231
|
-
}
|
|
232
|
-
function deserializeDFD(input) {
|
|
233
|
-
const entities = [];
|
|
234
|
-
const relations = [];
|
|
235
|
-
const lines = input.split("\n");
|
|
236
|
-
for (const rawLine of lines) {
|
|
237
|
-
const line = rawLine.trim();
|
|
238
|
-
if (line === "") continue;
|
|
239
|
-
const entityMatch = line.match(/^entity\s+(\S+)$/);
|
|
240
|
-
if (entityMatch) {
|
|
241
|
-
entities.push({
|
|
242
|
-
id: entityMatch[1].toLowerCase().replace(/\s+/g, "_"),
|
|
243
|
-
name: entityMatch[1],
|
|
244
|
-
fields: []
|
|
245
|
-
});
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
const flowMatch = line.match(
|
|
249
|
-
/^(\S+)\s+->\s+(\S+)(?:\s+"(.+)")?$/
|
|
250
|
-
);
|
|
251
|
-
if (flowMatch) {
|
|
252
|
-
const fromName = flowMatch[1];
|
|
253
|
-
const toName = flowMatch[2];
|
|
254
|
-
const label = flowMatch[3];
|
|
255
|
-
const fromEntity = entities.find((e) => e.name === fromName);
|
|
256
|
-
const toEntity = entities.find((e) => e.name === toName);
|
|
257
|
-
if (fromEntity && toEntity) {
|
|
258
|
-
relations.push({
|
|
259
|
-
id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,
|
|
260
|
-
from: fromEntity.id ?? fromEntity.name,
|
|
261
|
-
to: toEntity.id ?? toEntity.name,
|
|
262
|
-
type: "one-to-many",
|
|
263
|
-
label
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return { entities, relations };
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export { deserializeSchema, serializeToDFD, serializeToERD, serializeToUML };
|
|
272
|
-
//# sourceMappingURL=diagram.serializers-6RPUO46U.js.map
|
|
273
|
-
//# sourceMappingURL=diagram.serializers-6RPUO46U.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Diagram/diagram.serializers.ts"],"names":[],"mappings":"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","file":"diagram.serializers-6RPUO46U.js","sourcesContent":["import type {\n DiagramSchema,\n DiagramEntityData,\n DiagramRelationData,\n DiagramFieldData,\n ExportFormat,\n RelationType,\n} from \"./Diagram.types\";\n\n/**\n * Serialize a diagram schema to PlantUML-style ERD text.\n *\n * Example output:\n * ```\n * [Users]\n * id int PK\n * email varchar\n *\n * [Posts]\n * id int PK\n * user_id int FK\n *\n * Users 1--* Posts\n * ```\n */\nexport function serializeToERD(schema: DiagramSchema): string {\n const lines: string[] = [];\n\n for (const entity of schema.entities) {\n lines.push(`[${entity.name}]`);\n if (entity.fields) {\n for (const field of entity.fields) {\n const parts = [` ${field.name}`];\n if (field.type) parts.push(field.type);\n if (field.primary) parts.push(\"PK\");\n if (field.foreign) parts.push(\"FK\");\n if (field.nullable) parts.push(\"?\");\n lines.push(parts.join(\" \"));\n }\n }\n lines.push(\"\");\n }\n\n for (const rel of schema.relations) {\n const fromEntity = schema.entities.find((e) => e.id === rel.from);\n const toEntity = schema.entities.find((e) => e.id === rel.to);\n if (!fromEntity || !toEntity) continue;\n\n const marker = getERDMarker(rel.type);\n const parts = [fromEntity.name, marker, toEntity.name];\n if (rel.label) parts.push(`: ${rel.label}`);\n lines.push(parts.join(\" \"));\n }\n\n return lines.join(\"\\n\").trim();\n}\n\nfunction getERDMarker(type: RelationType): string {\n switch (type) {\n case \"one-to-one\":\n return \"1--1\";\n case \"one-to-many\":\n return \"1--*\";\n case \"many-to-many\":\n return \"*--*\";\n }\n}\n\n/**\n * Serialize a diagram schema to PlantUML class diagram text.\n */\nexport function serializeToUML(schema: DiagramSchema): string {\n const lines: string[] = [\"@startuml\"];\n\n for (const entity of schema.entities) {\n lines.push(`class ${entity.name} {`);\n if (entity.fields) {\n for (const field of entity.fields) {\n const typeStr = field.type ?? \"any\";\n const nullable = field.nullable ? \"?\" : \"\";\n const stereotype = field.primary\n ? \" <<PK>>\"\n : field.foreign\n ? \" <<FK>>\"\n : \"\";\n lines.push(` ${field.name} : ${typeStr}${nullable}${stereotype}`);\n }\n }\n lines.push(\"}\");\n lines.push(\"\");\n }\n\n for (const rel of schema.relations) {\n const fromEntity = schema.entities.find((e) => e.id === rel.from);\n const toEntity = schema.entities.find((e) => e.id === rel.to);\n if (!fromEntity || !toEntity) continue;\n\n const arrow = getUMLArrow(rel.type);\n const label = rel.label ? ` : ${rel.label}` : \"\";\n lines.push(`${fromEntity.name} ${arrow} ${toEntity.name}${label}`);\n }\n\n lines.push(\"@enduml\");\n return lines.join(\"\\n\");\n}\n\nfunction getUMLArrow(type: RelationType): string {\n switch (type) {\n case \"one-to-one\":\n return '\"1\" -- \"1\"';\n case \"one-to-many\":\n return '\"1\" -- \"*\"';\n case \"many-to-many\":\n return '\"*\" -- \"*\"';\n }\n}\n\n/**\n * Serialize a diagram schema to a simple DFD text format.\n */\nexport function serializeToDFD(schema: DiagramSchema): string {\n const lines: string[] = [];\n\n for (const entity of schema.entities) {\n lines.push(`entity ${entity.name}`);\n }\n\n lines.push(\"\");\n\n for (const rel of schema.relations) {\n const fromEntity = schema.entities.find((e) => e.id === rel.from);\n const toEntity = schema.entities.find((e) => e.id === rel.to);\n if (!fromEntity || !toEntity) continue;\n\n const label = rel.label ? ` \"${rel.label}\"` : \"\";\n lines.push(`${fromEntity.name} -> ${toEntity.name}${label}`);\n }\n\n return lines.join(\"\\n\").trim();\n}\n\n/**\n * Parse a serialized schema string back into a DiagramSchema.\n */\nexport function deserializeSchema(\n input: string,\n format: ExportFormat,\n): DiagramSchema {\n switch (format) {\n case \"erd\":\n return deserializeERD(input);\n case \"uml\":\n return deserializeUML(input);\n case \"dfd\":\n return deserializeDFD(input);\n }\n}\n\nfunction deserializeERD(input: string): DiagramSchema {\n const entities: DiagramEntityData[] = [];\n const relations: DiagramRelationData[] = [];\n const lines = input.split(\"\\n\");\n\n let currentEntity: DiagramEntityData | null = null;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n\n // Entity header: [EntityName]\n const entityMatch = line.match(/^\\[(.+)\\]$/);\n if (entityMatch) {\n currentEntity = {\n id: entityMatch[1].toLowerCase().replace(/\\s+/g, \"_\"),\n name: entityMatch[1],\n fields: [],\n };\n entities.push(currentEntity);\n continue;\n }\n\n // Field line (indented): name type PK FK ?\n if (currentEntity && rawLine.startsWith(\" \") && line.length > 0) {\n const parts = line.split(/\\s+/);\n const field: DiagramFieldData = { name: parts[0] };\n if (parts.length > 1 && ![\"PK\", \"FK\", \"?\"].includes(parts[1])) {\n field.type = parts[1];\n }\n if (parts.includes(\"PK\")) field.primary = true;\n if (parts.includes(\"FK\")) field.foreign = true;\n if (parts.includes(\"?\")) field.nullable = true;\n currentEntity.fields!.push(field);\n continue;\n }\n\n // Relation: EntityA 1--* EntityB : label\n const relMatch = line.match(\n /^(\\S+)\\s+(1--1|1--\\*|\\*--\\*)\\s+(\\S+)(?:\\s*:\\s*(.+))?$/,\n );\n if (relMatch) {\n currentEntity = null;\n const fromName = relMatch[1];\n const marker = relMatch[2];\n const toName = relMatch[3];\n const label = relMatch[4];\n\n const fromEntity = entities.find((e) => e.name === fromName);\n const toEntity = entities.find((e) => e.name === toName);\n if (fromEntity && toEntity) {\n relations.push({\n id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,\n from: fromEntity.id ?? fromEntity.name,\n to: toEntity.id ?? toEntity.name,\n type: parseERDMarker(marker),\n label,\n });\n }\n continue;\n }\n\n // Empty line resets current entity context\n if (line === \"\") {\n currentEntity = null;\n }\n }\n\n return { entities, relations };\n}\n\nfunction parseERDMarker(marker: string): RelationType {\n switch (marker) {\n case \"1--1\":\n return \"one-to-one\";\n case \"1--*\":\n return \"one-to-many\";\n case \"*--*\":\n return \"many-to-many\";\n default:\n return \"one-to-many\";\n }\n}\n\nfunction deserializeUML(input: string): DiagramSchema {\n const entities: DiagramEntityData[] = [];\n const relations: DiagramRelationData[] = [];\n const lines = input.split(\"\\n\");\n\n let currentEntity: DiagramEntityData | null = null;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n\n if (line === \"@startuml\" || line === \"@enduml\" || line === \"\") continue;\n\n // Class header: class EntityName {\n const classMatch = line.match(/^class\\s+(\\S+)\\s*\\{$/);\n if (classMatch) {\n currentEntity = {\n id: classMatch[1].toLowerCase().replace(/\\s+/g, \"_\"),\n name: classMatch[1],\n fields: [],\n };\n entities.push(currentEntity);\n continue;\n }\n\n // Closing brace\n if (line === \"}\") {\n currentEntity = null;\n continue;\n }\n\n // Field: name : type<<stereotype>>\n if (currentEntity) {\n const fieldMatch = line.match(\n /^(\\S+)\\s*:\\s*(\\S+?)(\\?)?(?:\\s*<<(PK|FK)>>)?$/,\n );\n if (fieldMatch) {\n const field: DiagramFieldData = {\n name: fieldMatch[1],\n type: fieldMatch[2],\n };\n if (fieldMatch[3]) field.nullable = true;\n if (fieldMatch[4] === \"PK\") field.primary = true;\n if (fieldMatch[4] === \"FK\") field.foreign = true;\n currentEntity.fields!.push(field);\n }\n continue;\n }\n\n // Relation: EntityA \"1\" -- \"*\" EntityB : label\n const relMatch = line.match(\n /^(\\S+)\\s+\"([1*])\"\\s+--\\s+\"([1*])\"\\s+(\\S+)(?:\\s*:\\s*(.+))?$/,\n );\n if (relMatch) {\n const fromName = relMatch[1];\n const fromCard = relMatch[2];\n const toCard = relMatch[3];\n const toName = relMatch[4];\n const label = relMatch[5];\n\n const fromEntity = entities.find((e) => e.name === fromName);\n const toEntity = entities.find((e) => e.name === toName);\n if (fromEntity && toEntity) {\n const type: RelationType =\n fromCard === \"1\" && toCard === \"1\"\n ? \"one-to-one\"\n : fromCard === \"1\" && toCard === \"*\"\n ? \"one-to-many\"\n : \"many-to-many\";\n relations.push({\n id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,\n from: fromEntity.id ?? fromEntity.name,\n to: toEntity.id ?? toEntity.name,\n type,\n label,\n });\n }\n }\n }\n\n return { entities, relations };\n}\n\nfunction deserializeDFD(input: string): DiagramSchema {\n const entities: DiagramEntityData[] = [];\n const relations: DiagramRelationData[] = [];\n const lines = input.split(\"\\n\");\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (line === \"\") continue;\n\n // Entity: entity EntityName\n const entityMatch = line.match(/^entity\\s+(\\S+)$/);\n if (entityMatch) {\n entities.push({\n id: entityMatch[1].toLowerCase().replace(/\\s+/g, \"_\"),\n name: entityMatch[1],\n fields: [],\n });\n continue;\n }\n\n // Flow: EntityA -> EntityB \"label\"\n const flowMatch = line.match(\n /^(\\S+)\\s+->\\s+(\\S+)(?:\\s+\"(.+)\")?$/,\n );\n if (flowMatch) {\n const fromName = flowMatch[1];\n const toName = flowMatch[2];\n const label = flowMatch[3];\n\n const fromEntity = entities.find((e) => e.name === fromName);\n const toEntity = entities.find((e) => e.name === toName);\n if (fromEntity && toEntity) {\n relations.push({\n id: `${fromEntity.id ?? fromEntity.name}_${toEntity.id ?? toEntity.name}`,\n from: fromEntity.id ?? fromEntity.name,\n to: toEntity.id ?? toEntity.name,\n type: \"one-to-many\",\n label,\n });\n }\n }\n }\n\n return { entities, relations };\n}\n"]}
|
package/docs/Canvas.md
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# Canvas
|
|
2
|
-
|
|
3
|
-
An infinite pannable and zoomable canvas for positioning nodes with edges between them. Includes minimap and zoom controls.
|
|
4
|
-
|
|
5
|
-
## Import
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { Canvas } from "@particle-academy/react-fancy";
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Basic Usage
|
|
12
|
-
|
|
13
|
-
```tsx
|
|
14
|
-
<Canvas className="h-96 w-full" showGrid>
|
|
15
|
-
<Canvas.Node id="a" x={50} y={50} draggable>
|
|
16
|
-
<div className="rounded border bg-white p-4">Node A</div>
|
|
17
|
-
</Canvas.Node>
|
|
18
|
-
<Canvas.Node id="b" x={300} y={150} draggable>
|
|
19
|
-
<div className="rounded border bg-white p-4">Node B</div>
|
|
20
|
-
</Canvas.Node>
|
|
21
|
-
<Canvas.Edge from="a" to="b" curve="bezier" markerEnd="canvas-arrow" />
|
|
22
|
-
<Canvas.Controls />
|
|
23
|
-
<Canvas.Minimap />
|
|
24
|
-
</Canvas>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Props
|
|
28
|
-
|
|
29
|
-
### Canvas (root)
|
|
30
|
-
|
|
31
|
-
| Prop | Type | Default | Description |
|
|
32
|
-
|------|------|---------|-------------|
|
|
33
|
-
| viewport | `ViewportState` | - | Controlled viewport `{ panX, panY, zoom }` |
|
|
34
|
-
| defaultViewport | `ViewportState` | `{ panX: 0, panY: 0, zoom: 1 }` | Default viewport (uncontrolled) |
|
|
35
|
-
| onViewportChange | `(viewport: ViewportState) => void` | - | Callback when viewport changes |
|
|
36
|
-
| minZoom | `number` | `0.1` | Minimum zoom level |
|
|
37
|
-
| maxZoom | `number` | `3` | Maximum zoom level |
|
|
38
|
-
| pannable | `boolean` | `true` | Enable panning (click+drag on background) |
|
|
39
|
-
| zoomable | `boolean` | `true` | Enable zoom (Ctrl+scroll) |
|
|
40
|
-
| gridSize | `number` | `20` | Grid cell size in canvas-space pixels |
|
|
41
|
-
| showGrid | `boolean` | `false` | Display the canvas grid background |
|
|
42
|
-
| gridStyle | `'dots' \| 'lines' \| 'none'` | `'dots'` | Grid pattern when shown. `'none'` hides the grid even when `showGrid` is true |
|
|
43
|
-
| gridColor | `string` | `'rgb(161 161 170 / 0.3)'` | Any CSS color for grid dots/lines |
|
|
44
|
-
| snapToGrid | `boolean` | `false` | Snap dragged nodes to the grid |
|
|
45
|
-
| fitOnMount | `boolean` | `false` | Auto-fit all nodes into view on mount |
|
|
46
|
-
| className | `string` | - | Additional CSS classes |
|
|
47
|
-
| style | `CSSProperties` | - | Inline styles |
|
|
48
|
-
|
|
49
|
-
### Canvas.Node
|
|
50
|
-
|
|
51
|
-
| Prop | Type | Default | Description |
|
|
52
|
-
|------|------|---------|-------------|
|
|
53
|
-
| id | `string` | - | Unique node identifier (required) |
|
|
54
|
-
| x | `number` | - | X position in canvas coordinates (required) |
|
|
55
|
-
| y | `number` | - | Y position in canvas coordinates (required) |
|
|
56
|
-
| draggable | `boolean` | - | Allow drag-to-move |
|
|
57
|
-
| onPositionChange | `(x: number, y: number) => void` | - | Callback when dragged to a new position |
|
|
58
|
-
| className | `string` | - | Additional CSS classes |
|
|
59
|
-
| style | `CSSProperties` | - | Inline styles |
|
|
60
|
-
|
|
61
|
-
### Canvas.Edge
|
|
62
|
-
|
|
63
|
-
| Prop | Type | Default | Description |
|
|
64
|
-
|------|------|---------|-------------|
|
|
65
|
-
| from | `string` | - | Source node id (required) |
|
|
66
|
-
| to | `string` | - | Target node id (required) |
|
|
67
|
-
| fromAnchor | `EdgeAnchor` | - | Anchor point on source: `"top"`, `"bottom"`, `"left"`, `"right"`, `"center"`, `"auto"` |
|
|
68
|
-
| toAnchor | `EdgeAnchor` | - | Anchor point on target |
|
|
69
|
-
| curve | `"bezier" \| "step" \| "straight"` | - | Path interpolation |
|
|
70
|
-
| color | `string` | - | Stroke color |
|
|
71
|
-
| strokeWidth | `number` | - | Stroke width |
|
|
72
|
-
| dashed | `boolean` | - | Dashed line |
|
|
73
|
-
| animated | `boolean` | - | Animated dash pattern |
|
|
74
|
-
| label | `ReactNode` | - | Label at the midpoint |
|
|
75
|
-
| markerStart | `string` | - | SVG marker id for start (e.g. `"canvas-arrow"`, `"canvas-circle"`, `"canvas-diamond"`) |
|
|
76
|
-
| markerEnd | `string` | - | SVG marker id for end |
|
|
77
|
-
| className | `string` | - | Additional CSS classes |
|
|
78
|
-
|
|
79
|
-
### Canvas.Controls
|
|
80
|
-
|
|
81
|
-
| Prop | Type | Default | Description |
|
|
82
|
-
|------|------|---------|-------------|
|
|
83
|
-
| showZoomIn | `boolean` | - | Show zoom-in button |
|
|
84
|
-
| showZoomOut | `boolean` | - | Show zoom-out button |
|
|
85
|
-
| showReset | `boolean` | - | Show reset-viewport button |
|
|
86
|
-
| showFitAll | `boolean` | - | Show fit-all button |
|
|
87
|
-
| className | `string` | - | Additional CSS classes |
|
|
88
|
-
|
|
89
|
-
### Canvas.Minimap
|
|
90
|
-
|
|
91
|
-
| Prop | Type | Default | Description |
|
|
92
|
-
|------|------|---------|-------------|
|
|
93
|
-
| width | `number` | - | Minimap width in px |
|
|
94
|
-
| height | `number` | - | Minimap height in px |
|
|
95
|
-
| className | `string` | - | Additional CSS classes |
|
|
96
|
-
|
|
97
|
-
### ViewportState
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
{ panX: number; panY: number; zoom: number }
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Built-in SVG Markers
|
|
104
|
-
|
|
105
|
-
The Canvas includes predefined SVG markers for edge endpoints: `"canvas-arrow"`, `"canvas-circle"`, `"canvas-diamond"`, `"canvas-one"`, `"canvas-crow-foot"`.
|
package/docs/Diagram.md
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Diagram
|
|
2
|
-
|
|
3
|
-
A high-level ERD/flowchart diagram built on top of Canvas. Accepts a schema of entities and relations, auto-layouts positions, and supports drag-to-move, export, and import.
|
|
4
|
-
|
|
5
|
-
## Import
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { Diagram } from "@particle-academy/react-fancy";
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Basic Usage (Schema-driven)
|
|
12
|
-
|
|
13
|
-
```tsx
|
|
14
|
-
const schema = {
|
|
15
|
-
entities: [
|
|
16
|
-
{
|
|
17
|
-
name: "users",
|
|
18
|
-
fields: [
|
|
19
|
-
{ name: "id", type: "bigint", primary: true },
|
|
20
|
-
{ name: "name", type: "varchar" },
|
|
21
|
-
{ name: "email", type: "varchar" },
|
|
22
|
-
],
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "posts",
|
|
26
|
-
fields: [
|
|
27
|
-
{ name: "id", type: "bigint", primary: true },
|
|
28
|
-
{ name: "user_id", type: "bigint", foreign: true },
|
|
29
|
-
{ name: "title", type: "varchar" },
|
|
30
|
-
{ name: "body", type: "text", nullable: true },
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
relations: [
|
|
35
|
-
{ from: "users", to: "posts", type: "one-to-many" },
|
|
36
|
-
],
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
<Diagram schema={schema} className="h-[600px]" downloadable minimap />
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Props
|
|
43
|
-
|
|
44
|
-
### Diagram (root)
|
|
45
|
-
|
|
46
|
-
| Prop | Type | Default | Description |
|
|
47
|
-
|------|------|---------|-------------|
|
|
48
|
-
| schema | `DiagramSchema` | - | Declarative schema of entities and relations |
|
|
49
|
-
| type | `"erd" \| "flowchart" \| "general"` | `"general"` | Diagram type (affects relation rendering) |
|
|
50
|
-
| viewport | `ViewportState` | - | Controlled viewport |
|
|
51
|
-
| defaultViewport | `ViewportState` | - | Default viewport (auto-computed from schema if omitted) |
|
|
52
|
-
| onViewportChange | `(viewport: ViewportState) => void` | - | Viewport change callback |
|
|
53
|
-
| downloadable | `boolean` | `false` | Enable download toolbar action |
|
|
54
|
-
| importable | `boolean` | `false` | Enable import toolbar action |
|
|
55
|
-
| exportFormats | `ExportFormat[]` | `["erd"]` | Export format options: `"erd"`, `"uml"`, `"dfd"` |
|
|
56
|
-
| onImport | `(schema: DiagramSchema) => void` | - | Callback when a schema is imported |
|
|
57
|
-
| minimap | `boolean` | `false` | Show minimap overlay |
|
|
58
|
-
| className | `string` | - | Additional CSS classes |
|
|
59
|
-
|
|
60
|
-
### Diagram.Entity
|
|
61
|
-
|
|
62
|
-
| Prop | Type | Default | Description |
|
|
63
|
-
|------|------|---------|-------------|
|
|
64
|
-
| id | `string` | - | Unique identifier (defaults to `name`) |
|
|
65
|
-
| name | `string` | - | Entity name (required) |
|
|
66
|
-
| x | `number` | - | X position |
|
|
67
|
-
| y | `number` | - | Y position |
|
|
68
|
-
| color | `string` | - | Header color |
|
|
69
|
-
| draggable | `boolean` | - | Allow drag-to-move |
|
|
70
|
-
| onPositionChange | `(x: number, y: number) => void` | - | Drag callback |
|
|
71
|
-
| children | `ReactNode` | - | Field children |
|
|
72
|
-
| className | `string` | - | Additional CSS classes |
|
|
73
|
-
|
|
74
|
-
### Diagram.Field
|
|
75
|
-
|
|
76
|
-
| Prop | Type | Default | Description |
|
|
77
|
-
|------|------|---------|-------------|
|
|
78
|
-
| name | `string` | - | Field name (required) |
|
|
79
|
-
| type | `string` | - | Data type label |
|
|
80
|
-
| primary | `boolean` | - | Primary key indicator |
|
|
81
|
-
| foreign | `boolean` | - | Foreign key indicator |
|
|
82
|
-
| nullable | `boolean` | - | Nullable indicator |
|
|
83
|
-
| className | `string` | - | Additional CSS classes |
|
|
84
|
-
|
|
85
|
-
### Diagram.Relation
|
|
86
|
-
|
|
87
|
-
| Prop | Type | Default | Description |
|
|
88
|
-
|------|------|---------|-------------|
|
|
89
|
-
| from | `string` | - | Source entity id (required) |
|
|
90
|
-
| to | `string` | - | Target entity id (required) |
|
|
91
|
-
| fromField | `string` | - | Source field name |
|
|
92
|
-
| toField | `string` | - | Target field name |
|
|
93
|
-
| type | `RelationType` | - | Shorthand that sets `fromMarker` / `toMarker` / `lineStyle`. See **Relation types** below |
|
|
94
|
-
| fromMarker | `MarkerType` | depends on `type` | Marker shape at the source end |
|
|
95
|
-
| toMarker | `MarkerType` | depends on `type` | Marker shape at the target end |
|
|
96
|
-
| lineStyle | `'solid' \| 'dashed' \| 'dotted'` | from `type` | Line stroke style |
|
|
97
|
-
| routing | `'manhattan' \| 'bezier' \| 'straight'` | `'manhattan'` | Path routing algorithm |
|
|
98
|
-
| color | `string` | `'#71717a'` | Stroke color |
|
|
99
|
-
| strokeWidth | `number` | `2` | Stroke width |
|
|
100
|
-
| label | `string` | - | Edge label rendered at the path midpoint |
|
|
101
|
-
| className | `string` | - | Additional CSS classes |
|
|
102
|
-
|
|
103
|
-
### Relation types (`type` shorthand)
|
|
104
|
-
|
|
105
|
-
| Type | fromMarker | toMarker | lineStyle |
|
|
106
|
-
|------|-----------|----------|-----------|
|
|
107
|
-
| `one-to-one` | one | one | solid |
|
|
108
|
-
| `one-to-many` | one | many | solid |
|
|
109
|
-
| `many-to-one` | many | one | solid |
|
|
110
|
-
| `many-to-many` | many | many | solid |
|
|
111
|
-
| `association` | none | arrow | solid |
|
|
112
|
-
| `aggregation` | diamond-open | none | solid |
|
|
113
|
-
| `composition` | diamond | none | solid |
|
|
114
|
-
| `inheritance` | none | triangle-open | solid |
|
|
115
|
-
| `implementation` | none | triangle-open | dashed |
|
|
116
|
-
| `dependency` | none | arrow | dashed |
|
|
117
|
-
| `custom` | (caller's `fromMarker`) | (caller's `toMarker`) | solid |
|
|
118
|
-
|
|
119
|
-
### MarkerType
|
|
120
|
-
|
|
121
|
-
`'none'`, `'arrow'`, `'arrow-open'`, `'circle'`, `'circle-open'`, `'square'`, `'square-open'`, `'diamond'`, `'diamond-open'`, `'triangle'`, `'triangle-open'`, `'one'`, `'many'`, `'optional-one'`, `'optional-many'`, `'cross'`, or any string starting with `emoji:` (e.g. `'emoji:🎯'`) for an emoji/text marker.
|
|
122
|
-
|
|
123
|
-
### Routing
|
|
124
|
-
|
|
125
|
-
- **manhattan** (default) — right-angle elbows. Picks the side of each entity that faces the other, with a vertical (or horizontal) mid-line that automatically dodges entities lying along the path. Best for ERD/UML.
|
|
126
|
-
- **bezier** — smooth cubic curve with horizontal/vertical control points perpendicular to each side.
|
|
127
|
-
- **straight** — direct line between the two anchor points.
|
|
128
|
-
|
|
129
|
-
### Diagram.Toolbar
|
|
130
|
-
|
|
131
|
-
| Prop | Type | Default | Description |
|
|
132
|
-
|------|------|---------|-------------|
|
|
133
|
-
| className | `string` | - | Additional CSS classes |
|
|
134
|
-
|
|
135
|
-
## Declarative Children
|
|
136
|
-
|
|
137
|
-
You can also compose entities and relations as JSX children instead of (or alongside) the schema prop:
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
<Diagram type="erd" className="h-[500px]">
|
|
141
|
-
<Diagram.Entity name="categories" x={0} y={0} draggable>
|
|
142
|
-
<Diagram.Field name="id" type="int" primary />
|
|
143
|
-
<Diagram.Field name="name" type="varchar" />
|
|
144
|
-
</Diagram.Entity>
|
|
145
|
-
<Diagram.Entity name="products" x={300} y={0} draggable>
|
|
146
|
-
<Diagram.Field name="id" type="int" primary />
|
|
147
|
-
<Diagram.Field name="category_id" type="int" foreign />
|
|
148
|
-
</Diagram.Entity>
|
|
149
|
-
<Diagram.Relation from="categories" to="products" type="one-to-many" />
|
|
150
|
-
</Diagram>
|
|
151
|
-
```
|