@visualli/core 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/animations/index.cjs +146 -0
  2. package/dist/animations/index.cjs.map +1 -0
  3. package/dist/animations/index.d.cts +81 -0
  4. package/dist/animations/index.d.ts +81 -0
  5. package/dist/animations/index.js +35 -0
  6. package/dist/animations/index.js.map +1 -0
  7. package/dist/chunk-6NXADJK2.js +562 -0
  8. package/dist/chunk-6NXADJK2.js.map +1 -0
  9. package/dist/chunk-F36SMC3K.js +106 -0
  10. package/dist/chunk-F36SMC3K.js.map +1 -0
  11. package/dist/chunk-G5H3P4YZ.js +273 -0
  12. package/dist/chunk-G5H3P4YZ.js.map +1 -0
  13. package/dist/chunk-GQMFBYLK.js +81 -0
  14. package/dist/chunk-GQMFBYLK.js.map +1 -0
  15. package/dist/chunk-I75TMOE4.js +108 -0
  16. package/dist/chunk-I75TMOE4.js.map +1 -0
  17. package/dist/chunk-LDJRGT2Q.js +163 -0
  18. package/dist/chunk-LDJRGT2Q.js.map +1 -0
  19. package/dist/chunk-LI3BVD6H.js +98 -0
  20. package/dist/chunk-LI3BVD6H.js.map +1 -0
  21. package/dist/chunk-LJYSKSCE.js +95 -0
  22. package/dist/chunk-LJYSKSCE.js.map +1 -0
  23. package/dist/chunk-LNTJTDB2.js +349 -0
  24. package/dist/chunk-LNTJTDB2.js.map +1 -0
  25. package/dist/chunk-PDP5CVUL.js +139 -0
  26. package/dist/chunk-PDP5CVUL.js.map +1 -0
  27. package/dist/chunk-VLGR5PZX.js +1 -0
  28. package/dist/chunk-VLGR5PZX.js.map +1 -0
  29. package/dist/config/index.cjs +391 -0
  30. package/dist/config/index.cjs.map +1 -0
  31. package/dist/config/index.d.cts +77 -0
  32. package/dist/config/index.d.ts +77 -0
  33. package/dist/config/index.js +38 -0
  34. package/dist/config/index.js.map +1 -0
  35. package/dist/constants/index.cjs +642 -0
  36. package/dist/constants/index.cjs.map +1 -0
  37. package/dist/constants/index.d.cts +448 -0
  38. package/dist/constants/index.d.ts +448 -0
  39. package/dist/constants/index.js +183 -0
  40. package/dist/constants/index.js.map +1 -0
  41. package/dist/document-B3hnNr-F.d.cts +73 -0
  42. package/dist/document-B3hnNr-F.d.ts +73 -0
  43. package/dist/index.cjs +32 -32
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +15 -1044
  46. package/dist/index.d.ts +15 -1044
  47. package/dist/index.js +179 -1747
  48. package/dist/index.js.map +1 -1
  49. package/dist/layout/index.cjs +210 -0
  50. package/dist/layout/index.cjs.map +1 -0
  51. package/dist/layout/index.d.cts +80 -0
  52. package/dist/layout/index.d.ts +80 -0
  53. package/dist/layout/index.js +25 -0
  54. package/dist/layout/index.js.map +1 -0
  55. package/dist/mindmap-DWS0WZT_.d.cts +118 -0
  56. package/dist/mindmap-DWS0WZT_.d.ts +118 -0
  57. package/dist/parser/index.cjs +739 -0
  58. package/dist/parser/index.cjs.map +1 -0
  59. package/dist/parser/index.d.cts +87 -0
  60. package/dist/parser/index.d.ts +87 -0
  61. package/dist/parser/index.js +43 -0
  62. package/dist/parser/index.js.map +1 -0
  63. package/dist/performance/index.cjs +167 -0
  64. package/dist/performance/index.cjs.map +1 -0
  65. package/dist/performance/index.d.cts +40 -0
  66. package/dist/performance/index.d.ts +40 -0
  67. package/dist/performance/index.js +12 -0
  68. package/dist/performance/index.js.map +1 -0
  69. package/dist/types/index.cjs +19 -0
  70. package/dist/types/index.cjs.map +1 -0
  71. package/dist/types/index.d.cts +8 -0
  72. package/dist/types/index.d.ts +8 -0
  73. package/dist/types/index.js +2 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/dist/viewport/index.cjs +131 -0
  76. package/dist/viewport/index.cjs.map +1 -0
  77. package/dist/viewport/index.d.cts +56 -0
  78. package/dist/viewport/index.d.ts +56 -0
  79. package/dist/viewport/index.js +26 -0
  80. package/dist/viewport/index.js.map +1 -0
  81. package/package.json +7 -2
  82. package/src/config/README.md +59 -0
  83. package/src/config/USAGE_EXAMPLES.md +285 -0
  84. package/src/config/index.ts +7 -0
  85. package/src/index.ts +1 -2
@@ -0,0 +1,562 @@
1
+ import {
2
+ LAYOUT_SPACING,
3
+ LEVEL_COLORS,
4
+ getColorForLevel
5
+ } from "./chunk-G5H3P4YZ.js";
6
+ import {
7
+ applyCircularLayout,
8
+ applyLinearHorizontalLayout,
9
+ applyLinearVerticalLayout,
10
+ calculateOptimalRadiusPercentage
11
+ } from "./chunk-GQMFBYLK.js";
12
+
13
+ // src/parser/visualliParser.ts
14
+ function toVisualliLayer(schemaLayer) {
15
+ return {
16
+ type: "layer",
17
+ id: schemaLayer.id,
18
+ level: schemaLayer.level,
19
+ parentLayerId: schemaLayer.parentLayerId,
20
+ parentNodeId: schemaLayer.parentNodeId,
21
+ layout: schemaLayer.layout,
22
+ nodes: schemaLayer.nodes ?? [],
23
+ connections: schemaLayer.connections ?? [],
24
+ containers: schemaLayer.containers ?? []
25
+ };
26
+ }
27
+ var VisualliParseError = class extends Error {
28
+ constructor(message, lineNumber) {
29
+ super(message);
30
+ this.lineNumber = lineNumber;
31
+ this.name = "VisualliParseError";
32
+ }
33
+ };
34
+ function parseVisualliFile(content) {
35
+ const lines = content.trim().split("\n");
36
+ const doc = {
37
+ meta: null,
38
+ layers: /* @__PURE__ */ new Map(),
39
+ layersByLevel: /* @__PURE__ */ new Map(),
40
+ rootLayer: null
41
+ };
42
+ let lineNumber = 0;
43
+ for (const line of lines) {
44
+ lineNumber++;
45
+ if (!line.trim()) continue;
46
+ let obj;
47
+ try {
48
+ obj = JSON.parse(line);
49
+ } catch (err) {
50
+ throw new VisualliParseError(
51
+ `Failed to parse JSON at line ${lineNumber}: ${err}`,
52
+ lineNumber
53
+ );
54
+ }
55
+ if (!obj["type"]) {
56
+ throw new VisualliParseError(
57
+ `Missing 'type' field at line ${lineNumber}`,
58
+ lineNumber
59
+ );
60
+ }
61
+ switch (obj["type"]) {
62
+ case "meta":
63
+ doc.meta = obj;
64
+ break;
65
+ case "layer": {
66
+ const schemaLayer = obj;
67
+ const layer = toVisualliLayer(schemaLayer);
68
+ doc.layers.set(layer.id, layer);
69
+ if (!doc.layersByLevel.has(layer.level)) {
70
+ doc.layersByLevel.set(layer.level, []);
71
+ }
72
+ doc.layersByLevel.get(layer.level).push(layer);
73
+ if (layer.level === 0) {
74
+ doc.rootLayer = layer;
75
+ }
76
+ break;
77
+ }
78
+ default:
79
+ break;
80
+ }
81
+ }
82
+ if (!doc.meta) throw new VisualliParseError("Missing required meta section");
83
+ if (!doc.rootLayer) throw new VisualliParseError("Missing root layer (level 0)");
84
+ return doc;
85
+ }
86
+ async function fetchAndParseVisualli(url) {
87
+ const response = await fetch(url);
88
+ if (!response.ok) {
89
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
90
+ }
91
+ return parseVisualliFile(await response.text());
92
+ }
93
+ function parseVisualliFromMongoDB(visualliJsonl) {
94
+ if (!visualliJsonl || typeof visualliJsonl !== "string") {
95
+ throw new VisualliParseError("Invalid visualli data: expected a JSONL string");
96
+ }
97
+ const trimmed = visualliJsonl.trim();
98
+ if (!trimmed) throw new VisualliParseError("Empty visualli data from MongoDB");
99
+ return parseVisualliFile(trimmed);
100
+ }
101
+ function loadVisualliFileFromFile(file) {
102
+ return new Promise((resolve, reject) => {
103
+ const reader = new FileReader();
104
+ reader.onload = (e) => {
105
+ try {
106
+ resolve(parseVisualliFile(e.target?.result));
107
+ } catch (err) {
108
+ reject(err);
109
+ }
110
+ };
111
+ reader.onerror = () => reject(new Error("Failed to read file"));
112
+ reader.readAsText(file);
113
+ });
114
+ }
115
+ function getChildLayers(doc, nodeId) {
116
+ const result = [];
117
+ for (const layer of doc.layers.values()) {
118
+ if (layer.parentNodeId === nodeId) result.push(layer);
119
+ }
120
+ return result;
121
+ }
122
+ function countLayersBeneath(doc, nodeId, visited = /* @__PURE__ */ new Set()) {
123
+ if (visited.has(nodeId)) return 0;
124
+ visited.add(nodeId);
125
+ const children = getChildLayers(doc, nodeId);
126
+ if (children.length === 0) return 0;
127
+ let maxDepth = 0;
128
+ for (const layer of children) {
129
+ let depth = 1;
130
+ for (const node of layer.nodes) {
131
+ depth = Math.max(depth, 1 + countLayersBeneath(doc, node.id, visited));
132
+ }
133
+ maxDepth = Math.max(maxDepth, depth);
134
+ }
135
+ return maxDepth;
136
+ }
137
+
138
+ // src/parser/visualliConverter.ts
139
+ function doNodesOverlap(n1, n2, padding = 20) {
140
+ return !(n1.x + n1.width / 2 + padding < n2.x - n2.width / 2 - padding || n1.x - n1.width / 2 - padding > n2.x + n2.width / 2 + padding || n1.y + n1.height / 2 + padding < n2.y - n2.height / 2 - padding || n1.y - n1.height / 2 - padding > n2.y + n2.height / 2 + padding);
141
+ }
142
+ function resolveNodeOverlaps(nodes, maxIterations = 10) {
143
+ const padding = 150;
144
+ for (let iter = 0; iter < maxIterations; iter++) {
145
+ let any = false;
146
+ for (let i = 0; i < nodes.length; i++) {
147
+ for (let j = i + 1; j < nodes.length; j++) {
148
+ const n1 = nodes[i];
149
+ const n2 = nodes[j];
150
+ if (!doNodesOverlap(n1, n2, padding)) continue;
151
+ any = true;
152
+ const dx = n2.x - n1.x;
153
+ const dy = n2.y - n1.y;
154
+ const dist = Math.sqrt(dx * dx + dy * dy);
155
+ if (dist < 1) {
156
+ n2.x += n2.width / 2 + padding;
157
+ continue;
158
+ }
159
+ const minDist = (n1.width + n2.width) / 2 + padding;
160
+ if (dist < minDist) {
161
+ const push = (minDist - dist) / 2;
162
+ n1.x -= dx / dist * push;
163
+ n1.y -= dy / dist * push;
164
+ n2.x += dx / dist * push;
165
+ n2.y += dy / dist * push;
166
+ }
167
+ }
168
+ }
169
+ if (!any) break;
170
+ }
171
+ }
172
+ var COLOR_PALETTE = [
173
+ "#12C7D3",
174
+ "#325E8C",
175
+ "#8A70A6",
176
+ "#F54A57",
177
+ "#FF6C4D",
178
+ "#F28C16",
179
+ "#FFD347",
180
+ "#12C7D3",
181
+ "#7F7F7F",
182
+ "#8D8D8D",
183
+ "#12C7D3"
184
+ ];
185
+ function getRandomColorForNode(nodeId) {
186
+ let hash = 0;
187
+ for (let i = 0; i < nodeId.length; i++) {
188
+ hash = nodeId.charCodeAt(i) + ((hash << 5) - hash);
189
+ }
190
+ const index = Math.abs(hash) % COLOR_PALETTE.length;
191
+ return COLOR_PALETTE[index];
192
+ }
193
+ function applyFormation(nodes, formation) {
194
+ if (nodes.length === 0) return;
195
+ if (nodes.length === 1) {
196
+ nodes[0].x = 0;
197
+ nodes[0].y = 0;
198
+ return;
199
+ }
200
+ if (formation === "linear-horizontal" || formation === "linear") {
201
+ applyLinearHorizontalLayout(nodes, { centerX: 0, centerY: 0 });
202
+ } else if (formation === "linear-vertical") {
203
+ applyLinearVerticalLayout(nodes, { centerX: 0, centerY: 0 });
204
+ } else {
205
+ const r = Math.max(250, nodes.length * 70);
206
+ const step = 2 * Math.PI / nodes.length;
207
+ for (let i = 0; i < nodes.length; i++) {
208
+ nodes[i].x = r * Math.cos(i * step);
209
+ nodes[i].y = r * Math.sin(i * step);
210
+ }
211
+ }
212
+ }
213
+ function containerBBox(nodes, padding) {
214
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
215
+ for (const n of nodes) {
216
+ minX = Math.min(minX, n.x - n.width / 2);
217
+ maxX = Math.max(maxX, n.x + n.width / 2);
218
+ minY = Math.min(minY, n.y - n.height / 2);
219
+ maxY = Math.max(maxY, n.y + n.height / 2);
220
+ }
221
+ return { width: maxX - minX + padding * 2, height: maxY - minY + padding * 2 };
222
+ }
223
+ function proxyLinearH(proxies, gap = 180) {
224
+ const total = proxies.reduce((s, p) => s + p.width, 0) + gap * (proxies.length - 1);
225
+ let x = -total / 2;
226
+ for (const p of proxies) {
227
+ p.x = x + p.width / 2;
228
+ p.y = 0;
229
+ x += p.width + gap;
230
+ }
231
+ }
232
+ function proxyLinearV(proxies, gap = 180) {
233
+ const total = proxies.reduce((s, p) => s + p.height, 0) + gap * (proxies.length - 1);
234
+ let y = -total / 2;
235
+ for (const p of proxies) {
236
+ p.x = 0;
237
+ p.y = y + p.height / 2;
238
+ y += p.height + gap;
239
+ }
240
+ }
241
+ function proxyRadial(proxies, radius = 500) {
242
+ if (proxies.length === 1) {
243
+ proxies[0].x = 0;
244
+ proxies[0].y = 0;
245
+ return;
246
+ }
247
+ const startAngle = proxies.length === 2 ? 0 : -Math.PI / 2;
248
+ const step = 2 * Math.PI / proxies.length;
249
+ for (let i = 0; i < proxies.length; i++) {
250
+ const angle = startAngle + i * step;
251
+ proxies[i].x = radius * Math.cos(angle);
252
+ proxies[i].y = radius * Math.sin(angle);
253
+ }
254
+ }
255
+ function calculateNodeWidth(title) {
256
+ return Math.max(200, title.length * 8 + 40);
257
+ }
258
+ function makeFlatNode(nodeId, label, summary, layer, color, branchCount, x = 0, y = 0) {
259
+ return {
260
+ id: nodeId,
261
+ parentId: layer.parentNodeId ?? null,
262
+ x,
263
+ y,
264
+ level: layer.level,
265
+ title: label,
266
+ description: summary,
267
+ color,
268
+ width: calculateNodeWidth(label),
269
+ height: 80,
270
+ isExpanded: branchCount > 0,
271
+ branchCount,
272
+ createdAt: /* @__PURE__ */ new Date(),
273
+ updatedAt: /* @__PURE__ */ new Date()
274
+ };
275
+ }
276
+ function convertLayerWithContainers(layer, doc) {
277
+ const PADDING = 80;
278
+ const flatNodes = [];
279
+ for (const node of layer.nodes) {
280
+ const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
281
+ const branchCount = countLayersBeneath(doc, node.id);
282
+ flatNodes.push(
283
+ makeFlatNode(
284
+ node.id,
285
+ label,
286
+ node.data.summary || "",
287
+ layer,
288
+ node.data.color || getRandomColorForNode(node.id),
289
+ branchCount
290
+ )
291
+ );
292
+ }
293
+ const byId = new Map(flatNodes.map((n) => [n.id, n]));
294
+ const containerNodeIds = /* @__PURE__ */ new Set();
295
+ const containerGroups = /* @__PURE__ */ new Map();
296
+ for (const container of layer.containers) {
297
+ const group = container.nodes.map((id) => byId.get(id)).filter((n) => !!n);
298
+ if (!group.length) continue;
299
+ container.nodes.forEach((id) => containerNodeIds.add(id));
300
+ const formation = container.data?.["formation"] ?? "radial";
301
+ applyFormation(group, formation);
302
+ containerGroups.set(container.id, group);
303
+ }
304
+ const proxies = [];
305
+ for (const node of layer.nodes) {
306
+ if (!containerNodeIds.has(node.id)) {
307
+ const nodeWidth = calculateNodeWidth(node.data.label);
308
+ proxies.push({ id: node.id, x: 0, y: 0, width: nodeWidth, height: 80 });
309
+ }
310
+ }
311
+ for (const container of layer.containers) {
312
+ const group = containerGroups.get(container.id);
313
+ if (!group?.length) continue;
314
+ const bbox = containerBBox(group, PADDING);
315
+ proxies.push({ id: `__c__${container.id}`, x: 0, y: 0, width: bbox.width, height: bbox.height });
316
+ }
317
+ const layout = layer.layout || "radial";
318
+ if (layout === "linear-horizontal") proxyLinearH(proxies, 180);
319
+ else if (layout === "linear-vertical") proxyLinearV(proxies, 180);
320
+ else proxyRadial(proxies, 500);
321
+ for (const proxy of proxies) {
322
+ if (proxy.id.startsWith("__c__")) {
323
+ const group = containerGroups.get(proxy.id.slice(5));
324
+ group?.forEach((n) => {
325
+ n.x += proxy.x;
326
+ n.y += proxy.y;
327
+ });
328
+ } else {
329
+ const fn = byId.get(proxy.id);
330
+ if (fn) {
331
+ fn.x = proxy.x;
332
+ fn.y = proxy.y;
333
+ }
334
+ }
335
+ }
336
+ resolveNodeOverlaps(flatNodes);
337
+ return flatNodes;
338
+ }
339
+ function convertLayerToFlatNodes(layer, doc) {
340
+ if ((layer.containers ?? []).length > 0) {
341
+ return convertLayerWithContainers(layer, doc);
342
+ }
343
+ const flatNodes = [];
344
+ for (const node of layer.nodes) {
345
+ const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
346
+ const branchCount = countLayersBeneath(doc, node.id);
347
+ flatNodes.push(
348
+ makeFlatNode(
349
+ node.id,
350
+ label,
351
+ node.data.summary || "",
352
+ layer,
353
+ node.data.color || getRandomColorForNode(node.id),
354
+ branchCount,
355
+ 0,
356
+ 0
357
+ )
358
+ );
359
+ }
360
+ if (flatNodes.length > 0) {
361
+ const layout = layer.layout || "radial";
362
+ if (layout === "linear-horizontal") {
363
+ applyLinearHorizontalLayout(flatNodes, { centerX: 0, centerY: 0 });
364
+ } else if (layout === "linear-vertical") {
365
+ applyLinearVerticalLayout(flatNodes, { centerX: 0, centerY: 0 });
366
+ } else {
367
+ const pct = calculateOptimalRadiusPercentage(flatNodes.length, 2e3, 2e3, 200, 30);
368
+ applyCircularLayout(flatNodes, {
369
+ radiusPercentage: pct,
370
+ containerWidth: 2e3,
371
+ containerHeight: 2e3,
372
+ centerX: 0,
373
+ centerY: 0
374
+ });
375
+ }
376
+ }
377
+ resolveNodeOverlaps(flatNodes);
378
+ return flatNodes;
379
+ }
380
+ function convertVisualliToFlatNodes(doc) {
381
+ const map = /* @__PURE__ */ new Map();
382
+ for (const layer of doc.layers.values()) {
383
+ for (const node of convertLayerToFlatNodes(layer, doc)) {
384
+ map.set(node.id, node);
385
+ }
386
+ }
387
+ for (const node of map.values()) {
388
+ node.childrenIds = [];
389
+ for (const candidate of map.values()) {
390
+ if (candidate.parentId === node.id) node.childrenIds.push(candidate.id);
391
+ }
392
+ }
393
+ return map;
394
+ }
395
+ function getNodesForLayer(doc, layerId) {
396
+ const layer = doc.layers.get(layerId);
397
+ return layer ? convertLayerToFlatNodes(layer, doc) : [];
398
+ }
399
+
400
+ // src/parser/mindmapUtils.ts
401
+ function flattenNodes(nodes) {
402
+ const result = [];
403
+ const traverse = (list) => {
404
+ for (const n of list) {
405
+ result.push(n);
406
+ if (n.children) traverse(n.children);
407
+ }
408
+ };
409
+ traverse(nodes);
410
+ return result;
411
+ }
412
+ function getVisibleNodes(nodes, zoom, focusedNode) {
413
+ const flat = flattenNodes(nodes);
414
+ if (focusedNode) {
415
+ const focused = flat.find((n) => n.id === focusedNode);
416
+ if (focused) {
417
+ return focused.children ? [focused, ...focused.children] : [focused];
418
+ }
419
+ }
420
+ if (zoom <= 0.7) return flat.filter((n) => n.level === 0);
421
+ const maxLevel = Math.floor((zoom - 0.7) / 0.05);
422
+ return flat.filter((n) => n.level <= maxLevel);
423
+ }
424
+ function getNodeConnections(nodes) {
425
+ const flat = flattenNodes(nodes);
426
+ const result = [];
427
+ for (const n of flat) {
428
+ if (!n.parent) continue;
429
+ const parent = flat.find((p) => p.id === n.parent);
430
+ if (parent) result.push({ from: parent, to: n, label: n.relationshipLabel });
431
+ }
432
+ return result;
433
+ }
434
+ function getTopLevelConnections(nodes, topLevelConnections) {
435
+ const flat = flattenNodes(nodes);
436
+ const result = [];
437
+ for (const conn of topLevelConnections) {
438
+ const from = flat.find((n) => n.id === conn.from);
439
+ const to = flat.find((n) => n.id === conn.to);
440
+ if (from && to) result.push({ from, to, label: conn.label ?? "" });
441
+ }
442
+ return result;
443
+ }
444
+ function calculateDistance(x1, y1, x2, y2) {
445
+ return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
446
+ }
447
+
448
+ // src/parser/configUtils.ts
449
+ function createMindMapConfig(nodes, topLevelConnections, title = "Untitled Mindmap") {
450
+ const now = (/* @__PURE__ */ new Date()).toISOString();
451
+ return {
452
+ metadata: {
453
+ title,
454
+ description: `Interactive mindmap with ${nodes.length} nodes`,
455
+ version: "1.0.0",
456
+ created: now,
457
+ lastModified: now
458
+ },
459
+ nodes,
460
+ topLevelConnections,
461
+ settings: {
462
+ defaultColors: {
463
+ level0: LEVEL_COLORS.level0,
464
+ level1: LEVEL_COLORS.level1,
465
+ level2: LEVEL_COLORS.level2,
466
+ level3: LEVEL_COLORS.level3
467
+ },
468
+ layout: {
469
+ nodeSpacing: LAYOUT_SPACING.nodeSpacing,
470
+ levelSpacing: LAYOUT_SPACING.levelSpacing
471
+ }
472
+ }
473
+ };
474
+ }
475
+ function generateId(prefix, level, index) {
476
+ return `${prefix}-l${level}-${index}`;
477
+ }
478
+ function generateLevelNodes(parentId, level, maxLevels, xOffset = 0, yOffset = 0) {
479
+ if (level >= maxLevels) return [];
480
+ const count = 5;
481
+ const levelSpacing = 200;
482
+ const nodeSpacing = 300;
483
+ const nodes = [];
484
+ for (let i = 0; i < count; i++) {
485
+ const nodeId = parentId ? generateId(`${parentId}-${i}`, level, i) : generateId("root", level, i);
486
+ const x = xOffset + (i - (count - 1) / 2) * nodeSpacing;
487
+ const y = yOffset + level * levelSpacing;
488
+ const node = {
489
+ id: nodeId,
490
+ title: `Level ${level} Node ${i + 1}`,
491
+ level,
492
+ x,
493
+ y,
494
+ color: getColorForLevel(level),
495
+ relationshipLabel: level > 0 ? "child" : void 0,
496
+ parent: parentId ?? void 0
497
+ };
498
+ const children = generateLevelNodes(nodeId, level + 1, maxLevels, x, y + levelSpacing);
499
+ if (children.length > 0) node.children = children;
500
+ nodes.push(node);
501
+ }
502
+ return nodes;
503
+ }
504
+ function generateSampleConfig(maxLevels = 9) {
505
+ const nodes = generateLevelNodes(null, 0, maxLevels, 0, 0);
506
+ const topLevelConnections = nodes.slice(0, -1).map((n, i) => ({
507
+ from: n.id,
508
+ to: nodes[i + 1].id,
509
+ label: "related to"
510
+ }));
511
+ return {
512
+ metadata: {
513
+ id: `mindmap-${Date.now()}`,
514
+ title: "Sample Mind Map",
515
+ description: "A sample mind map",
516
+ version: "1.0.0",
517
+ created: (/* @__PURE__ */ new Date()).toISOString(),
518
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
519
+ },
520
+ nodes,
521
+ topLevelConnections,
522
+ settings: {
523
+ defaultColors: {
524
+ level0: LEVEL_COLORS.level0,
525
+ level1: LEVEL_COLORS.level1,
526
+ level2: LEVEL_COLORS.level2,
527
+ level3: LEVEL_COLORS.level3,
528
+ level4: LEVEL_COLORS.level4,
529
+ level5: LEVEL_COLORS.level5,
530
+ level6: LEVEL_COLORS.level6,
531
+ level7: LEVEL_COLORS.level7,
532
+ level8: LEVEL_COLORS.level8
533
+ },
534
+ layout: {
535
+ nodeSpacing: LAYOUT_SPACING.nodeSpacing,
536
+ levelSpacing: LAYOUT_SPACING.levelSpacing
537
+ }
538
+ }
539
+ };
540
+ }
541
+
542
+ export {
543
+ VisualliParseError,
544
+ parseVisualliFile,
545
+ fetchAndParseVisualli,
546
+ parseVisualliFromMongoDB,
547
+ loadVisualliFileFromFile,
548
+ getChildLayers,
549
+ countLayersBeneath,
550
+ resolveNodeOverlaps,
551
+ convertLayerToFlatNodes,
552
+ convertVisualliToFlatNodes,
553
+ getNodesForLayer,
554
+ flattenNodes,
555
+ getVisibleNodes,
556
+ getNodeConnections,
557
+ getTopLevelConnections,
558
+ calculateDistance,
559
+ createMindMapConfig,
560
+ generateSampleConfig
561
+ };
562
+ //# sourceMappingURL=chunk-6NXADJK2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/parser/visualliParser.ts","../src/parser/visualliConverter.ts","../src/parser/mindmapUtils.ts","../src/parser/configUtils.ts"],"sourcesContent":["// ─── .visualli File Parser ────────────────────────────────────────────────────\n//\n// Reads JSONL (JSON Lines) format and parses into a structured VisualliDocument.\n\nimport type { VisualliDocument } from '../types/document.js';\nimport type { VisualliMeta } from '../types/meta.js';\nimport type { VisualliLayer } from '../types/layer.js';\nimport type { Layer } from '../types/schema.js';\n\n/**\n * Convert schema Layer to VisualliLayer by ensuring required arrays exist.\n */\nfunction toVisualliLayer(schemaLayer: Layer): VisualliLayer {\n return {\n type: 'layer',\n id: schemaLayer.id,\n level: schemaLayer.level,\n parentLayerId: schemaLayer.parentLayerId,\n parentNodeId: schemaLayer.parentNodeId,\n layout: schemaLayer.layout,\n nodes: schemaLayer.nodes ?? [],\n connections: schemaLayer.connections ?? [],\n containers: schemaLayer.containers ?? [],\n };\n}\n\nexport class VisualliParseError extends Error {\n constructor(message: string, public readonly lineNumber?: number) {\n super(message);\n this.name = 'VisualliParseError';\n }\n}\n\n/**\n * Parse a .visualli file content (JSONL format) into a VisualliDocument.\n *\n * @throws VisualliParseError on malformed input\n */\nexport function parseVisualliFile(content: string): VisualliDocument {\n const lines = content.trim().split('\\n');\n\n const doc: VisualliDocument = {\n meta: null as unknown as VisualliMeta,\n layers: new Map(),\n layersByLevel: new Map(),\n rootLayer: null,\n };\n\n let lineNumber = 0;\n\n for (const line of lines) {\n lineNumber++;\n if (!line.trim()) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(line) as Record<string, unknown>;\n } catch (err) {\n throw new VisualliParseError(\n `Failed to parse JSON at line ${lineNumber}: ${err}`,\n lineNumber,\n );\n }\n\n if (!obj['type']) {\n throw new VisualliParseError(\n `Missing 'type' field at line ${lineNumber}`,\n lineNumber,\n );\n }\n\n switch (obj['type']) {\n case 'meta':\n doc.meta = obj as unknown as VisualliMeta;\n break;\n\n case 'layer': {\n // Convert schema Layer to VisualliLayer\n const schemaLayer = obj as unknown as Layer;\n const layer = toVisualliLayer(schemaLayer);\n \n doc.layers.set(layer.id, layer);\n\n if (!doc.layersByLevel.has(layer.level)) {\n doc.layersByLevel.set(layer.level, []);\n }\n doc.layersByLevel.get(layer.level)!.push(layer);\n\n if (layer.level === 0) {\n doc.rootLayer = layer;\n }\n break;\n }\n\n default:\n // Unknown type — silently skip\n break;\n }\n }\n\n if (!doc.meta) throw new VisualliParseError('Missing required meta section');\n if (!doc.rootLayer) throw new VisualliParseError('Missing root layer (level 0)');\n\n return doc;\n}\n\nexport async function fetchAndParseVisualli(url: string): Promise<VisualliDocument> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n return parseVisualliFile(await response.text());\n}\n\n/**\n * Parse .visualli JSONL data as returned from the MongoDB `visualli` field.\n *\n * @throws VisualliParseError\n */\nexport function parseVisualliFromMongoDB(visualliJsonl: string): VisualliDocument {\n if (!visualliJsonl || typeof visualliJsonl !== 'string') {\n throw new VisualliParseError('Invalid visualli data: expected a JSONL string');\n }\n const trimmed = visualliJsonl.trim();\n if (!trimmed) throw new VisualliParseError('Empty visualli data from MongoDB');\n return parseVisualliFile(trimmed);\n}\n\n/**\n * Parse a .visualli file from a browser `File` object.\n * (Browser-only – requires `FileReader`.)\n */\nexport function loadVisualliFileFromFile(file: File): Promise<VisualliDocument> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = e => {\n try {\n resolve(parseVisualliFile(e.target?.result as string));\n } catch (err) {\n reject(err);\n }\n };\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsText(file);\n });\n}\n\n// ── Tree Helpers ──────────────────────────────────────────────────────────────\n\n/** Return all layers whose `parentNodeId` matches the given node ID. */\nexport function getChildLayers(\n doc: VisualliDocument,\n nodeId: string,\n): VisualliLayer[] {\n const result: VisualliLayer[] = [];\n for (const layer of doc.layers.values()) {\n if (layer.parentNodeId === nodeId) result.push(layer);\n }\n return result;\n}\n\n/**\n * Count the maximum depth of layers beneath a node (its \"magnitude\").\n * Returns 0 when the node has no child layers.\n */\nexport function countLayersBeneath(\n doc: VisualliDocument,\n nodeId: string,\n visited = new Set<string>(),\n): number {\n if (visited.has(nodeId)) return 0;\n visited.add(nodeId);\n\n const children = getChildLayers(doc, nodeId);\n if (children.length === 0) return 0;\n\n let maxDepth = 0;\n for (const layer of children) {\n let depth = 1;\n for (const node of layer.nodes) {\n depth = Math.max(depth, 1 + countLayersBeneath(doc, node.id, visited));\n }\n maxDepth = Math.max(maxDepth, depth);\n }\n return maxDepth;\n}\n","// ─── .visualli → FlatNode Converter ──────────────────────────────────────────\n//\n// Transforms the layer-based .visualli format into the flat Map<id, FlatNode>\n// structure consumed by the canvas renderer.\n\nimport type { VisualliDocument } from '../types/document.js';\nimport type { VisualliLayer } from '../types/layer.js';\nimport type { FlatNode, NodeMap } from '../types/mindmap.js';\nimport { countLayersBeneath } from './visualliParser.js';\nimport { applyCircularLayout, calculateOptimalRadiusPercentage } from '../layout/circularLayout.js';\nimport { applyLinearHorizontalLayout, applyLinearVerticalLayout } from '../layout/linearLayout.js';\n\n// ── Overlap Resolution ────────────────────────────────────────────────────────\n\nfunction doNodesOverlap(n1: FlatNode, n2: FlatNode, padding = 20): boolean {\n return !(\n n1.x + n1.width / 2 + padding < n2.x - n2.width / 2 - padding ||\n n1.x - n1.width / 2 - padding > n2.x + n2.width / 2 + padding ||\n n1.y + n1.height / 2 + padding < n2.y - n2.height / 2 - padding ||\n n1.y - n1.height / 2 - padding > n2.y + n2.height / 2 + padding\n );\n}\n\n/** Iteratively push overlapping nodes apart using symmetric force separation. */\nexport function resolveNodeOverlaps(nodes: FlatNode[], maxIterations = 10): void {\n const padding = 150;\n\n for (let iter = 0; iter < maxIterations; iter++) {\n let any = false;\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n const n1 = nodes[i];\n const n2 = nodes[j];\n if (!doNodesOverlap(n1, n2, padding)) continue;\n\n any = true;\n const dx = n2.x - n1.x;\n const dy = n2.y - n1.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < 1) {\n n2.x += n2.width / 2 + padding;\n continue;\n }\n\n const minDist = (n1.width + n2.width) / 2 + padding;\n if (dist < minDist) {\n const push = (minDist - dist) / 2;\n n1.x -= (dx / dist) * push;\n n1.y -= (dy / dist) * push;\n n2.x += (dx / dist) * push;\n n2.y += (dy / dist) * push;\n }\n }\n }\n if (!any) break;\n }\n}\n\n// ── Color Helpers ─────────────────────────────────────────────────────────────\n\nconst COLOR_PALETTE = [\n '#12C7D3', '#325E8C', '#8A70A6', '#F54A57', '#FF6C4D',\n '#F28C16', '#FFD347', '#12C7D3', '#7F7F7F', '#8D8D8D', '#12C7D3',\n];\n\n/**\n * Get a deterministic random color from palette based on node ID\n */\nfunction getRandomColorForNode(nodeId: string): string {\n // Simple hash function to convert string to number\n let hash = 0;\n for (let i = 0; i < nodeId.length; i++) {\n hash = nodeId.charCodeAt(i) + ((hash << 5) - hash);\n }\n \n // Use absolute value and modulo to get palette index\n const index = Math.abs(hash) % COLOR_PALETTE.length;\n return COLOR_PALETTE[index];\n}\n\n// ── Container-formation Layout ────────────────────────────────────────────────\n\ninterface Proxy { id: string; x: number; y: number; width: number; height: number }\n\nfunction applyFormation(nodes: FlatNode[], formation: string): void {\n if (nodes.length === 0) return;\n if (nodes.length === 1) { nodes[0].x = 0; nodes[0].y = 0; return; }\n if (formation === 'linear-horizontal' || formation === 'linear') {\n applyLinearHorizontalLayout(nodes, { centerX: 0, centerY: 0 });\n } else if (formation === 'linear-vertical') {\n applyLinearVerticalLayout(nodes, { centerX: 0, centerY: 0 });\n } else {\n const r = Math.max(250, nodes.length * 70);\n const step = (2 * Math.PI) / nodes.length;\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = r * Math.cos(i * step);\n nodes[i].y = r * Math.sin(i * step);\n }\n }\n}\n\nfunction containerBBox(nodes: FlatNode[], padding: number): { width: number; height: number } {\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const n of nodes) {\n minX = Math.min(minX, n.x - n.width / 2);\n maxX = Math.max(maxX, n.x + n.width / 2);\n minY = Math.min(minY, n.y - n.height / 2);\n maxY = Math.max(maxY, n.y + n.height / 2);\n }\n return { width: maxX - minX + padding * 2, height: maxY - minY + padding * 2 };\n}\n\nfunction proxyLinearH(proxies: Proxy[], gap = 180): void {\n const total = proxies.reduce((s, p) => s + p.width, 0) + gap * (proxies.length - 1);\n let x = -total / 2;\n for (const p of proxies) { p.x = x + p.width / 2; p.y = 0; x += p.width + gap; }\n}\n\nfunction proxyLinearV(proxies: Proxy[], gap = 180): void {\n const total = proxies.reduce((s, p) => s + p.height, 0) + gap * (proxies.length - 1);\n let y = -total / 2;\n for (const p of proxies) { p.x = 0; p.y = y + p.height / 2; y += p.height + gap; }\n}\n\nfunction proxyRadial(proxies: Proxy[], radius = 500): void {\n if (proxies.length === 1) { proxies[0].x = 0; proxies[0].y = 0; return; }\n // Start at top (12 o'clock) for n>=3, horizontal for n=2 (matches circular layout)\n const startAngle = proxies.length === 2 ? 0 : -Math.PI / 2;\n const step = (2 * Math.PI) / proxies.length;\n for (let i = 0; i < proxies.length; i++) {\n const angle = startAngle + i * step;\n proxies[i].x = radius * Math.cos(angle);\n proxies[i].y = radius * Math.sin(angle);\n }\n}\n\n// ── Layer Conversion ──────────────────────────────────────────────────────────\n\n/**\n * Calculate dynamic node width based on title length.\n * Formula matches visualli.ai: max(200, title.length * 8 + 40)\n */\nfunction calculateNodeWidth(title: string): number {\n return Math.max(200, title.length * 8 + 40);\n}\n\nfunction makeFlatNode(\n nodeId: string,\n label: string,\n summary: string,\n layer: VisualliLayer,\n color: string,\n branchCount: number,\n x = 0,\n y = 0,\n): FlatNode {\n return {\n id: nodeId,\n parentId: layer.parentNodeId ?? null,\n x,\n y,\n level: layer.level,\n title: label,\n description: summary,\n color,\n width: calculateNodeWidth(label),\n height: 80,\n isExpanded: branchCount > 0,\n branchCount,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n}\n\nfunction convertLayerWithContainers(\n layer: VisualliLayer,\n doc: VisualliDocument,\n): FlatNode[] {\n const PADDING = 80;\n const flatNodes: FlatNode[] = [];\n\n for (const node of layer.nodes) {\n const label = Array.isArray(node.data.label)\n ? (node.data.label as string[]).join(' ')\n : (node.data.label || 'Untitled');\n const branchCount = countLayersBeneath(doc, node.id);\n flatNodes.push(\n makeFlatNode(\n node.id, label, node.data.summary || '', layer,\n node.data.color || getRandomColorForNode(node.id), branchCount,\n ),\n );\n }\n\n const byId = new Map(flatNodes.map((n: FlatNode) => [n.id, n]));\n const containerNodeIds = new Set<string>();\n const containerGroups = new Map<string, FlatNode[]>();\n\n for (const container of layer.containers) {\n const group = container.nodes.map((id: string) => byId.get(id)).filter((n: FlatNode | undefined): n is FlatNode => !!n);\n if (!group.length) continue;\n container.nodes.forEach((id: string) => containerNodeIds.add(id));\n const formation = ((container.data as unknown as Record<string, unknown> | undefined)?.['formation'] as string | undefined) ?? 'radial';\n applyFormation(group, formation);\n containerGroups.set(container.id, group);\n }\n\n const proxies: Proxy[] = [];\n for (const node of layer.nodes) {\n if (!containerNodeIds.has(node.id)) {\n const nodeWidth = calculateNodeWidth(node.data.label);\n proxies.push({ id: node.id, x: 0, y: 0, width: nodeWidth, height: 80 });\n }\n }\n for (const container of layer.containers) {\n const group = containerGroups.get(container.id);\n if (!group?.length) continue;\n const bbox = containerBBox(group, PADDING);\n proxies.push({ id: `__c__${container.id}`, x: 0, y: 0, width: bbox.width, height: bbox.height });\n }\n\n const layout = layer.layout || 'radial';\n if (layout === 'linear-horizontal') proxyLinearH(proxies, 180);\n else if (layout === 'linear-vertical') proxyLinearV(proxies, 180);\n else proxyRadial(proxies, 500);\n\n for (const proxy of proxies) {\n if (proxy.id.startsWith('__c__')) {\n const group = containerGroups.get(proxy.id.slice(5));\n group?.forEach(n => { n.x += proxy.x; n.y += proxy.y; });\n } else {\n const fn = byId.get(proxy.id);\n if (fn) { fn.x = proxy.x; fn.y = proxy.y; }\n }\n }\n\n resolveNodeOverlaps(flatNodes);\n\n return flatNodes;\n}\n\n/**\n * Convert a single layer to an array of FlatNode objects.\n * Layout algorithm is determined by `layer.layout` (default: radial).\n */\nexport function convertLayerToFlatNodes(\n layer: VisualliLayer,\n doc: VisualliDocument,\n): FlatNode[] {\n if ((layer.containers ?? []).length > 0) {\n return convertLayerWithContainers(layer, doc);\n }\n\n const flatNodes: FlatNode[] = [];\n\n for (const node of layer.nodes) {\n const label = Array.isArray(node.data.label)\n ? (node.data.label as string[]).join(' ')\n : (node.data.label || 'Untitled');\n const branchCount = countLayersBeneath(doc, node.id);\n flatNodes.push(\n makeFlatNode(\n node.id, label, node.data.summary || '', layer,\n node.data.color || getRandomColorForNode(node.id), branchCount,\n 0, 0,\n ),\n );\n }\n\n if (flatNodes.length > 0) {\n const layout = layer.layout || 'radial';\n if (layout === 'linear-horizontal') {\n applyLinearHorizontalLayout(flatNodes, { centerX: 0, centerY: 0 });\n } else if (layout === 'linear-vertical') {\n applyLinearVerticalLayout(flatNodes, { centerX: 0, centerY: 0 });\n } else {\n const pct = calculateOptimalRadiusPercentage(flatNodes.length, 2000, 2000, 200, 30);\n applyCircularLayout(flatNodes, {\n radiusPercentage: pct,\n containerWidth: 2000,\n containerHeight: 2000,\n centerX: 0,\n centerY: 0,\n });\n }\n }\n\n resolveNodeOverlaps(flatNodes);\n\n return flatNodes;\n}\n\n/**\n * Convert an entire .visualli document to a flat NodeMap.\n * All layers are converted and a children-index is built for O(1) tree traversal.\n */\nexport function convertVisualliToFlatNodes(doc: VisualliDocument): NodeMap {\n const map: NodeMap = new Map();\n\n for (const layer of doc.layers.values()) {\n for (const node of convertLayerToFlatNodes(layer, doc)) {\n map.set(node.id, node);\n }\n }\n\n // Build children index\n for (const node of map.values()) {\n node.childrenIds = [];\n for (const candidate of map.values()) {\n if (candidate.parentId === node.id) node.childrenIds.push(candidate.id);\n }\n }\n\n return map;\n}\n\n/**\n * Get flat nodes for a specific layer only.\n *\n * @param doc - Parsed .visualli document\n * @param layerId - Layer ID to extract\n * @returns FlatNode array, or empty array if layer not found\n */\nexport function getNodesForLayer(doc: VisualliDocument, layerId: string): FlatNode[] {\n const layer = doc.layers.get(layerId);\n return layer ? convertLayerToFlatNodes(layer, doc) : [];\n}\n","// ─── Mindmap Tree Utilities ───────────────────────────────────────────────────\n\nimport type { MindMapNode, TopLevelConnection } from '../types/mindmap.js';\n\n/** Flatten a nested MindMapNode tree into a depth-first array. */\nexport function flattenNodes(nodes: MindMapNode[]): MindMapNode[] {\n const result: MindMapNode[] = [];\n const traverse = (list: MindMapNode[]) => {\n for (const n of list) {\n result.push(n);\n if (n.children) traverse(n.children);\n }\n };\n traverse(nodes);\n return result;\n}\n\n/**\n * Return nodes visible at the given zoom level.\n *\n * At lower zoom values only top-level nodes are shown; each 5% zoom increment\n * reveals one additional hierarchy level.\n */\nexport function getVisibleNodes(\n nodes: MindMapNode[],\n zoom: number,\n focusedNode?: string,\n): MindMapNode[] {\n const flat = flattenNodes(nodes);\n\n if (focusedNode) {\n const focused = flat.find(n => n.id === focusedNode);\n if (focused) {\n return focused.children ? [focused, ...focused.children] : [focused];\n }\n }\n\n // Map zoom to max visible level (level 0 at ≤70%, +1 level per 5% increment)\n if (zoom <= 0.70) return flat.filter(n => n.level === 0);\n const maxLevel = Math.floor((zoom - 0.70) / 0.05);\n return flat.filter(n => n.level <= maxLevel);\n}\n\n/** Build parent→child connection pairs from the node tree. */\nexport function getNodeConnections(\n nodes: MindMapNode[],\n): Array<{ from: MindMapNode; to: MindMapNode; label?: string }> {\n const flat = flattenNodes(nodes);\n const result: Array<{ from: MindMapNode; to: MindMapNode; label?: string }> = [];\n for (const n of flat) {\n if (!n.parent) continue;\n const parent = flat.find(p => p.id === n.parent);\n if (parent) result.push({ from: parent, to: n, label: n.relationshipLabel });\n }\n return result;\n}\n\n/** Resolve top-level cross-connections to node pairs. */\nexport function getTopLevelConnections(\n nodes: MindMapNode[],\n topLevelConnections: TopLevelConnection[],\n): Array<{ from: MindMapNode; to: MindMapNode; label: string }> {\n const flat = flattenNodes(nodes);\n const result: Array<{ from: MindMapNode; to: MindMapNode; label: string }> = [];\n for (const conn of topLevelConnections) {\n const from = flat.find(n => n.id === conn.from);\n const to = flat.find(n => n.id === conn.to);\n if (from && to) result.push({ from, to, label: conn.label ?? '' });\n }\n return result;\n}\n\n/** Euclidean distance between two world-space points. */\nexport function calculateDistance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);\n}\n","// ─── MindMapConfig Utilities ──────────────────────────────────────────────────\n//\n// Helpers for creating and generating MindMapConfig objects (pure data, no UI).\n\nimport type { MindMapNode, MindMapConfig, TopLevelConnection } from '../types/mindmap.js';\nimport { LEVEL_COLORS, LAYOUT_SPACING, getColorForLevel } from '../constants/design.js';\n\nexport function createMindMapConfig(\n nodes: MindMapNode[],\n topLevelConnections: TopLevelConnection[],\n title = 'Untitled Mindmap',\n): MindMapConfig {\n const now = new Date().toISOString();\n return {\n metadata: {\n title,\n description: `Interactive mindmap with ${nodes.length} nodes`,\n version: '1.0.0',\n created: now,\n lastModified: now,\n },\n nodes,\n topLevelConnections,\n settings: {\n defaultColors: {\n level0: LEVEL_COLORS.level0,\n level1: LEVEL_COLORS.level1,\n level2: LEVEL_COLORS.level2,\n level3: LEVEL_COLORS.level3,\n },\n layout: {\n nodeSpacing: LAYOUT_SPACING.nodeSpacing,\n levelSpacing: LAYOUT_SPACING.levelSpacing,\n },\n },\n };\n}\n\n// ── Sample Data Generator ─────────────────────────────────────────────────────\n\nfunction generateId(prefix: string, level: number, index: number): string {\n return `${prefix}-l${level}-${index}`;\n}\n\nfunction generateLevelNodes(\n parentId: string | null,\n level: number,\n maxLevels: number,\n xOffset = 0,\n yOffset = 0,\n): MindMapNode[] {\n if (level >= maxLevels) return [];\n\n const count = 5;\n const levelSpacing = 200;\n const nodeSpacing = 300;\n const nodes: MindMapNode[] = [];\n\n for (let i = 0; i < count; i++) {\n const nodeId = parentId\n ? generateId(`${parentId}-${i}`, level, i)\n : generateId('root', level, i);\n\n const x = xOffset + (i - (count - 1) / 2) * nodeSpacing;\n const y = yOffset + level * levelSpacing;\n\n const node: MindMapNode = {\n id: nodeId,\n title: `Level ${level} Node ${i + 1}`,\n level,\n x,\n y,\n color: getColorForLevel(level),\n relationshipLabel: level > 0 ? 'child' : undefined,\n parent: parentId ?? undefined,\n };\n\n const children = generateLevelNodes(nodeId, level + 1, maxLevels, x, y + levelSpacing);\n if (children.length > 0) node.children = children;\n\n nodes.push(node);\n }\n\n return nodes;\n}\n\n/**\n * Generate a sample MindMapConfig with `maxLevels` of hierarchy.\n * Useful for testing and demos.\n */\nexport function generateSampleConfig(maxLevels = 9): MindMapConfig {\n const nodes = generateLevelNodes(null, 0, maxLevels, 0, 0);\n\n const topLevelConnections: TopLevelConnection[] = nodes.slice(0, -1).map((n, i) => ({\n from: n.id,\n to: nodes[i + 1].id,\n label: 'related to',\n }));\n\n return {\n metadata: {\n id: `mindmap-${Date.now()}`,\n title: 'Sample Mind Map',\n description: 'A sample mind map',\n version: '1.0.0',\n created: new Date().toISOString(),\n lastModified: new Date().toISOString(),\n },\n nodes,\n topLevelConnections,\n settings: {\n defaultColors: {\n level0: LEVEL_COLORS.level0,\n level1: LEVEL_COLORS.level1,\n level2: LEVEL_COLORS.level2,\n level3: LEVEL_COLORS.level3,\n level4: LEVEL_COLORS.level4,\n level5: LEVEL_COLORS.level5,\n level6: LEVEL_COLORS.level6,\n level7: LEVEL_COLORS.level7,\n level8: LEVEL_COLORS.level8,\n },\n layout: {\n nodeSpacing: LAYOUT_SPACING.nodeSpacing,\n levelSpacing: LAYOUT_SPACING.levelSpacing,\n },\n },\n };\n}\n"],"mappings":"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","names":[]}