@pixerate/editor 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +563 -0
- package/dist/agent/index.cjs.map +1 -0
- package/dist/agent/index.d.cts +436 -0
- package/dist/agent/index.d.ts +436 -0
- package/dist/agent/index.js +520 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/canvas/index.cjs +960 -0
- package/dist/canvas/index.cjs.map +1 -0
- package/dist/canvas/index.d.cts +277 -0
- package/dist/canvas/index.d.ts +277 -0
- package/dist/canvas/index.js +886 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/index.cjs +1296 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +1251 -4
- package/dist/index.js.map +1 -1
- package/dist/types-lGtRobRV.d.cts +213 -0
- package/dist/types-lGtRobRV.d.ts +213 -0
- package/package.json +13 -1
package/dist/index.cjs
CHANGED
|
@@ -31,9 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
ColorHighlighter: () => ColorHighlighter,
|
|
34
|
+
DEFAULT_NODE_HEIGHT: () => DEFAULT_NODE_HEIGHT,
|
|
35
|
+
DEFAULT_NODE_WIDTH: () => DEFAULT_NODE_WIDTH,
|
|
36
|
+
DEFAULT_PLACEMENT_GAP: () => DEFAULT_PLACEMENT_GAP,
|
|
34
37
|
DataSourceBinder: () => DataSourceBinder,
|
|
35
38
|
DependencyGraph: () => DependencyGraph,
|
|
36
39
|
DirtyTracker: () => DirtyTracker,
|
|
40
|
+
EDITOR_MCP_TOOLS: () => EDITOR_MCP_TOOLS,
|
|
41
|
+
EXPORT_EXCLUDED_SELECTORS: () => EXPORT_EXCLUDED_SELECTORS,
|
|
37
42
|
EditorController: () => EditorController,
|
|
38
43
|
FontSize: () => FontSize,
|
|
39
44
|
FormulaEvaluator: () => FormulaEvaluator,
|
|
@@ -44,23 +49,44 @@ __export(src_exports, {
|
|
|
44
49
|
Image: () => Image2,
|
|
45
50
|
LoadingNode: () => LoadingNode,
|
|
46
51
|
MARKDOWN_MENTION_SPLIT_REGEX: () => MARKDOWN_MENTION_SPLIT_REGEX,
|
|
52
|
+
MCP_TOOL_EDIT_CANVAS: () => MCP_TOOL_EDIT_CANVAS,
|
|
53
|
+
MCP_TOOL_EDIT_PROMPT: () => MCP_TOOL_EDIT_PROMPT,
|
|
54
|
+
MCP_TOOL_GET_EDITOR_STATE: () => MCP_TOOL_GET_EDITOR_STATE,
|
|
55
|
+
MCP_TOOL_VIEW_EDITOR: () => MCP_TOOL_VIEW_EDITOR,
|
|
47
56
|
MENTION_REGEX: () => MENTION_REGEX,
|
|
57
|
+
ManualClock: () => ManualClock,
|
|
48
58
|
Markdown: () => Markdown2,
|
|
49
59
|
Mention: () => Mention,
|
|
50
60
|
SlashCommands: () => SlashCommands,
|
|
51
61
|
SmilieReplacer: () => SmilieReplacer,
|
|
52
62
|
SpreadsheetController: () => SpreadsheetController,
|
|
63
|
+
StreamingLayoutManager: () => StreamingLayoutManager,
|
|
53
64
|
TEMPLATE_REGEX: () => TEMPLATE_REGEX,
|
|
54
65
|
TemplateSuggestions: () => TemplateSuggestions,
|
|
55
66
|
VARIABLE_REGEX: () => VARIABLE_REGEX,
|
|
67
|
+
blendLayout: () => blendLayout,
|
|
68
|
+
boundsOf: () => boundsOf,
|
|
69
|
+
calculateDagreReflowDisplacement: () => calculateDagreReflowDisplacement,
|
|
70
|
+
calculateDirectionalDisplacement: () => calculateDirectionalDisplacement,
|
|
71
|
+
canvasHeight: () => canvasHeight,
|
|
72
|
+
centerNodes: () => centerNodes,
|
|
73
|
+
centre: () => centre,
|
|
56
74
|
colNameToIndex: () => colNameToIndex,
|
|
75
|
+
computeNodesBoundingBox: () => computeNodesBoundingBox,
|
|
76
|
+
connectedOnly: () => connectedOnly,
|
|
77
|
+
createBezierTrajectory: () => createBezierTrajectory,
|
|
57
78
|
createDirtyTracker: () => createDirtyTracker,
|
|
58
79
|
createEditor: () => createEditor,
|
|
80
|
+
createFanOutTrajectory: () => createFanOutTrajectory,
|
|
59
81
|
createHistoryManager: () => createHistoryManager,
|
|
60
82
|
createMentionExtension: () => createMentionExtension,
|
|
61
83
|
createRichTextPreset: () => createRichTextPreset,
|
|
84
|
+
defaultEasing: () => defaultEasing,
|
|
62
85
|
defaultIsEqual: () => defaultIsEqual,
|
|
86
|
+
ensureLayout: () => ensureLayout,
|
|
63
87
|
escapeHtml: () => escapeHtml,
|
|
88
|
+
estimateCanvasHeight: () => estimateCanvasHeight,
|
|
89
|
+
estimateNodeSize: () => estimateNodeSize,
|
|
64
90
|
extractCellDependencies: () => extractCellDependencies,
|
|
65
91
|
extractInstructionNames: () => extractInstructionNames,
|
|
66
92
|
extractMentions: () => extractMentions,
|
|
@@ -68,29 +94,48 @@ __export(src_exports, {
|
|
|
68
94
|
extractTemplateNames: () => extractTemplateNames,
|
|
69
95
|
extractVariableNames: () => extractVariableNames,
|
|
70
96
|
findHexColors: () => findHexColors,
|
|
97
|
+
flowSide: () => flowSide,
|
|
98
|
+
getCenteredNodePosition: () => getCenteredNodePosition,
|
|
71
99
|
getEditorMarkdown: () => getEditorMarkdown,
|
|
72
100
|
getEditorText: () => getEditorText,
|
|
73
101
|
getLatestVersion: () => getLatestVersion,
|
|
102
|
+
getLayoutedNodes: () => getLayoutedNodes,
|
|
74
103
|
handleImageInsertion: () => handleImageInsertion,
|
|
75
104
|
htmlToPlainText: () => htmlToPlainText,
|
|
76
105
|
imagePastePluginKey: () => imagePastePluginKey,
|
|
77
106
|
indexToColName: () => indexToColName,
|
|
78
107
|
insertImageNode: () => insertImageNode,
|
|
79
108
|
instructionRegex: () => instructionRegex,
|
|
109
|
+
isEventFromTextInput: () => isEventFromTextInput,
|
|
110
|
+
isValidCanvasNode: () => isValidCanvasNode,
|
|
111
|
+
isValidUrl: () => isValidUrl,
|
|
112
|
+
layoutBounds: () => layoutBounds,
|
|
113
|
+
linearPositionTrajectory: () => linearPositionTrajectory,
|
|
114
|
+
linearTrajectory: () => linearTrajectory,
|
|
80
115
|
mapRawOffsetToResolved: () => mapRawOffsetToResolved,
|
|
81
116
|
mapResolvedOffsetToRaw: () => mapResolvedOffsetToRaw,
|
|
82
117
|
markdownToTipTapHtml: () => markdownToTipTapHtml,
|
|
118
|
+
overlaps: () => overlaps,
|
|
119
|
+
pageHidden: () => pageHidden,
|
|
120
|
+
parseCanvasClipboardData: () => parseCanvasClipboardData,
|
|
83
121
|
parseCellReference: () => parseCellReference,
|
|
84
122
|
parseFormula: () => parseFormula,
|
|
85
123
|
parseMentionSegments: () => parseMentionSegments,
|
|
86
124
|
parseRange: () => parseRange,
|
|
125
|
+
placeBeside: () => placeBeside,
|
|
87
126
|
plainTextToTipTapHtml: () => plainTextToTipTapHtml,
|
|
127
|
+
planAgentCommand: () => planAgentCommand,
|
|
88
128
|
preprocessMarkdownFileLinks: () => preprocessMarkdownFileLinks,
|
|
89
129
|
preprocessMarkdownMentions: () => preprocessMarkdownMentions,
|
|
130
|
+
realClock: () => realClock,
|
|
131
|
+
remapPastedNodes: () => remapPastedNodes,
|
|
90
132
|
removeImageNode: () => removeImageNode,
|
|
133
|
+
repositionNodesTo: () => repositionNodesTo,
|
|
91
134
|
resolveTemplates: () => resolveTemplates,
|
|
92
135
|
resolveTemplatesWithMapping: () => resolveTemplatesWithMapping,
|
|
93
136
|
resolveVariables: () => resolveVariables,
|
|
137
|
+
runMultiNodeTransition: () => runMultiNodeTransition,
|
|
138
|
+
serializeCanvasNodes: () => serializeCanvasNodes,
|
|
94
139
|
stripMarkdownCode: () => stripMarkdownCode,
|
|
95
140
|
templateRegex: () => templateRegex,
|
|
96
141
|
tokenizeFormula: () => tokenizeFormula,
|
|
@@ -129,10 +174,10 @@ function tokenizePrompt(text) {
|
|
|
129
174
|
while ((match = varRegex.exec(text)) !== null) {
|
|
130
175
|
const start = match.index;
|
|
131
176
|
const end = start + match[0].length;
|
|
132
|
-
const
|
|
177
|
+
const overlaps2 = rawMatches.some(
|
|
133
178
|
(m) => !(end <= m.start || start >= m.end)
|
|
134
179
|
);
|
|
135
|
-
if (!
|
|
180
|
+
if (!overlaps2) {
|
|
136
181
|
rawMatches.push({
|
|
137
182
|
type: "variable",
|
|
138
183
|
raw: match[0],
|
|
@@ -149,10 +194,10 @@ function tokenizePrompt(text) {
|
|
|
149
194
|
while ((match = instRegex.exec(text)) !== null) {
|
|
150
195
|
const start = match.index;
|
|
151
196
|
const end = start + match[0].length;
|
|
152
|
-
const
|
|
197
|
+
const overlaps2 = rawMatches.some(
|
|
153
198
|
(m) => !(end <= m.start || start >= m.end)
|
|
154
199
|
);
|
|
155
|
-
if (!
|
|
200
|
+
if (!overlaps2) {
|
|
156
201
|
rawMatches.push({
|
|
157
202
|
type: "instruction",
|
|
158
203
|
raw: match[0],
|
|
@@ -4343,12 +4388,1219 @@ var HistoryManager = class {
|
|
|
4343
4388
|
function createHistoryManager(options = {}) {
|
|
4344
4389
|
return new HistoryManager(options);
|
|
4345
4390
|
}
|
|
4391
|
+
|
|
4392
|
+
// src/canvas/layout.ts
|
|
4393
|
+
var import_dagre = __toESM(require("@dagrejs/dagre"), 1);
|
|
4394
|
+
var DEFAULT_NODE_WIDTH = 200;
|
|
4395
|
+
var DEFAULT_NODE_HEIGHT = 60;
|
|
4396
|
+
var DEFAULT_PLACEMENT_GAP = 48;
|
|
4397
|
+
function getCenteredNodePosition(width = 0, height = 0, screenToFlowPosition, screenDimensions) {
|
|
4398
|
+
const rect = screenDimensions ?? (typeof document !== "undefined" ? { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight } : { width: 1920, height: 1080 });
|
|
4399
|
+
const flowPos = screenToFlowPosition({ x: rect.width / 2, y: rect.height / 2 });
|
|
4400
|
+
return {
|
|
4401
|
+
x: flowPos.x - width / 2,
|
|
4402
|
+
y: flowPos.y - height / 2
|
|
4403
|
+
};
|
|
4404
|
+
}
|
|
4405
|
+
function centerNodes(nodes, screenToFlowPosition, getNodesBounds, screenDimensions) {
|
|
4406
|
+
if (nodes.length === 0) {
|
|
4407
|
+
return [];
|
|
4408
|
+
}
|
|
4409
|
+
const bounds = getNodesBounds(nodes);
|
|
4410
|
+
const boundingBoxOrigin = { x: bounds.x, y: bounds.y };
|
|
4411
|
+
const centeredPosition = getCenteredNodePosition(
|
|
4412
|
+
bounds.width,
|
|
4413
|
+
bounds.height,
|
|
4414
|
+
screenToFlowPosition,
|
|
4415
|
+
screenDimensions
|
|
4416
|
+
);
|
|
4417
|
+
const deltaX = centeredPosition.x - boundingBoxOrigin.x;
|
|
4418
|
+
const deltaY = centeredPosition.y - boundingBoxOrigin.y;
|
|
4419
|
+
return nodes.map((node) => ({
|
|
4420
|
+
...node,
|
|
4421
|
+
position: {
|
|
4422
|
+
x: node.position.x + deltaX,
|
|
4423
|
+
y: node.position.y + deltaY
|
|
4424
|
+
}
|
|
4425
|
+
}));
|
|
4426
|
+
}
|
|
4427
|
+
function getLayoutedNodes(nodes, edges, getNodesBounds, options = {}) {
|
|
4428
|
+
if (nodes.length === 0) return [];
|
|
4429
|
+
const {
|
|
4430
|
+
direction = "LR",
|
|
4431
|
+
ranksep = 100,
|
|
4432
|
+
nodesep = 25,
|
|
4433
|
+
defaultNodeWidth = DEFAULT_NODE_WIDTH,
|
|
4434
|
+
defaultNodeHeight = DEFAULT_NODE_HEIGHT
|
|
4435
|
+
} = options;
|
|
4436
|
+
const dagreGraph = new import_dagre.default.graphlib.Graph();
|
|
4437
|
+
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
|
4438
|
+
dagreGraph.setGraph({ rankdir: direction, ranksep, nodesep });
|
|
4439
|
+
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
4440
|
+
nodes.forEach((node) => {
|
|
4441
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
4442
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
4443
|
+
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
|
|
4444
|
+
});
|
|
4445
|
+
edges.forEach((edge) => {
|
|
4446
|
+
if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
|
|
4447
|
+
dagreGraph.setEdge(edge.source, edge.target);
|
|
4448
|
+
}
|
|
4449
|
+
});
|
|
4450
|
+
import_dagre.default.layout(dagreGraph);
|
|
4451
|
+
return nodes.map((node) => {
|
|
4452
|
+
const nodeWithPosition = dagreGraph.node(node.id);
|
|
4453
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
4454
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
4455
|
+
return {
|
|
4456
|
+
...node,
|
|
4457
|
+
position: {
|
|
4458
|
+
x: nodeWithPosition.x - nodeWidth / 2,
|
|
4459
|
+
y: nodeWithPosition.y - nodeHeight / 2
|
|
4460
|
+
}
|
|
4461
|
+
};
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
function estimateNodeSize(node, defaultWidth = DEFAULT_NODE_WIDTH, defaultHeight = DEFAULT_NODE_HEIGHT) {
|
|
4465
|
+
const label = String(node.data?.label ?? node.data?.title ?? node.id ?? "");
|
|
4466
|
+
const lines = label.split(/\n|<br\s*\/?>/);
|
|
4467
|
+
const longest = Math.max(...lines.map((l) => l.replace(/<[^>]+>/g, "").length), 1);
|
|
4468
|
+
const width = Math.min(480, Math.max(defaultWidth, longest * 8 + 48));
|
|
4469
|
+
const height = Math.max(defaultHeight, lines.length * 20 + 24);
|
|
4470
|
+
return { width, height };
|
|
4471
|
+
}
|
|
4472
|
+
function boundsOf(rects) {
|
|
4473
|
+
if (!rects.length) return null;
|
|
4474
|
+
const minX = Math.min(...rects.map((r) => r.x));
|
|
4475
|
+
const minY = Math.min(...rects.map((r) => r.y));
|
|
4476
|
+
const maxX = Math.max(...rects.map((r) => r.x + r.width));
|
|
4477
|
+
const maxY = Math.max(...rects.map((r) => r.y + r.height));
|
|
4478
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
4479
|
+
}
|
|
4480
|
+
function centre(r) {
|
|
4481
|
+
return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
|
|
4482
|
+
}
|
|
4483
|
+
function overlaps(a, b, pad = 16) {
|
|
4484
|
+
return a.x < b.x + b.width + pad && a.x + a.width + pad > b.x && a.y < b.y + b.height + pad && a.y + a.height + pad > b.y;
|
|
4485
|
+
}
|
|
4486
|
+
function flowSide(direction = "LR") {
|
|
4487
|
+
switch (direction) {
|
|
4488
|
+
case "LR":
|
|
4489
|
+
return "right";
|
|
4490
|
+
case "RL":
|
|
4491
|
+
return "left";
|
|
4492
|
+
case "BT":
|
|
4493
|
+
return "above";
|
|
4494
|
+
case "TB":
|
|
4495
|
+
default:
|
|
4496
|
+
return "below";
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
function ensureLayout(nodes, edges, options = {}) {
|
|
4500
|
+
if (nodes.length === 0) return [];
|
|
4501
|
+
const stored = options.storedPositions ?? {};
|
|
4502
|
+
const missing = nodes.filter((n) => !stored[n.id]);
|
|
4503
|
+
if (missing.length === 0) {
|
|
4504
|
+
return nodes.map((n) => ({
|
|
4505
|
+
...n,
|
|
4506
|
+
position: { ...stored[n.id] }
|
|
4507
|
+
}));
|
|
4508
|
+
}
|
|
4509
|
+
const autoLayouted = getLayoutedNodes(nodes, edges, void 0, options);
|
|
4510
|
+
const autoMap = new Map(
|
|
4511
|
+
autoLayouted.map((n) => [n.id, n.position])
|
|
4512
|
+
);
|
|
4513
|
+
const both = nodes.filter((n) => stored[n.id] && autoMap.has(n.id));
|
|
4514
|
+
if (both.length === 0) {
|
|
4515
|
+
return autoLayouted;
|
|
4516
|
+
}
|
|
4517
|
+
let dx = 0;
|
|
4518
|
+
let dy = 0;
|
|
4519
|
+
for (const n of both) {
|
|
4520
|
+
const s = stored[n.id];
|
|
4521
|
+
const a = autoMap.get(n.id);
|
|
4522
|
+
dx += s.x - a.x;
|
|
4523
|
+
dy += s.y - a.y;
|
|
4524
|
+
}
|
|
4525
|
+
dx /= both.length;
|
|
4526
|
+
dy /= both.length;
|
|
4527
|
+
return nodes.map((node) => {
|
|
4528
|
+
if (stored[node.id]) {
|
|
4529
|
+
return {
|
|
4530
|
+
...node,
|
|
4531
|
+
position: { ...stored[node.id] }
|
|
4532
|
+
};
|
|
4533
|
+
}
|
|
4534
|
+
const autoPos = autoMap.get(node.id) ?? { x: 0, y: 0 };
|
|
4535
|
+
return {
|
|
4536
|
+
...node,
|
|
4537
|
+
position: {
|
|
4538
|
+
x: Math.round(autoPos.x + dx),
|
|
4539
|
+
y: Math.round(autoPos.y + dy)
|
|
4540
|
+
}
|
|
4541
|
+
};
|
|
4542
|
+
});
|
|
4543
|
+
}
|
|
4544
|
+
function placeBeside(rects, size, side, nearNodeId, options = {}) {
|
|
4545
|
+
const {
|
|
4546
|
+
gap = DEFAULT_PLACEMENT_GAP,
|
|
4547
|
+
ignore = [],
|
|
4548
|
+
maxAttempts = 32
|
|
4549
|
+
} = options;
|
|
4550
|
+
const skip = new Set([nearNodeId, ...ignore].filter(Boolean));
|
|
4551
|
+
const obstacles = Object.entries(rects).filter(([id]) => !skip.has(id)).map(([, r]) => r);
|
|
4552
|
+
const anchor = nearNodeId && rects[nearNodeId] || boundsOf(Object.values(rects)) || { x: 0, y: 0, width: 0, height: 0 };
|
|
4553
|
+
const anchorCenter = centre(anchor);
|
|
4554
|
+
let baseX;
|
|
4555
|
+
let baseY;
|
|
4556
|
+
switch (side) {
|
|
4557
|
+
case "right":
|
|
4558
|
+
baseX = anchor.x + anchor.width + gap;
|
|
4559
|
+
baseY = anchorCenter.y - size.height / 2;
|
|
4560
|
+
break;
|
|
4561
|
+
case "left":
|
|
4562
|
+
baseX = anchor.x - gap - size.width;
|
|
4563
|
+
baseY = anchorCenter.y - size.height / 2;
|
|
4564
|
+
break;
|
|
4565
|
+
case "above":
|
|
4566
|
+
baseX = anchorCenter.x - size.width / 2;
|
|
4567
|
+
baseY = anchor.y - gap - size.height;
|
|
4568
|
+
break;
|
|
4569
|
+
case "below":
|
|
4570
|
+
default:
|
|
4571
|
+
baseX = anchorCenter.x - size.width / 2;
|
|
4572
|
+
baseY = anchor.y + anchor.height + gap;
|
|
4573
|
+
break;
|
|
4574
|
+
}
|
|
4575
|
+
const isHorizontal = side === "right" || side === "left";
|
|
4576
|
+
const step = (isHorizontal ? size.height : size.width) + 20;
|
|
4577
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
4578
|
+
const offset = i === 0 ? 0 : Math.ceil(i / 2) * step * (i % 2 === 1 ? 1 : -1);
|
|
4579
|
+
const candidateBox = {
|
|
4580
|
+
x: isHorizontal ? baseX : baseX + offset,
|
|
4581
|
+
y: isHorizontal ? baseY + offset : baseY,
|
|
4582
|
+
width: size.width,
|
|
4583
|
+
height: size.height
|
|
4584
|
+
};
|
|
4585
|
+
if (!obstacles.some((obstacle) => overlaps(candidateBox, obstacle, 8))) {
|
|
4586
|
+
return {
|
|
4587
|
+
x: Math.round(candidateBox.x),
|
|
4588
|
+
y: Math.round(candidateBox.y)
|
|
4589
|
+
};
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
return {
|
|
4593
|
+
x: Math.round(baseX),
|
|
4594
|
+
y: Math.round(baseY)
|
|
4595
|
+
};
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
// src/canvas/clock.ts
|
|
4599
|
+
var pageHidden = () => typeof document !== "undefined" && document.hidden;
|
|
4600
|
+
var realClock = {
|
|
4601
|
+
live: true,
|
|
4602
|
+
now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
4603
|
+
frame: () => new Promise((resolve) => {
|
|
4604
|
+
if (typeof requestAnimationFrame === "function" && !pageHidden()) {
|
|
4605
|
+
requestAnimationFrame(() => resolve());
|
|
4606
|
+
} else {
|
|
4607
|
+
setTimeout(resolve, 16);
|
|
4608
|
+
}
|
|
4609
|
+
}),
|
|
4610
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)))
|
|
4611
|
+
};
|
|
4612
|
+
var settle = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
4613
|
+
var ManualClock = class {
|
|
4614
|
+
live = false;
|
|
4615
|
+
time;
|
|
4616
|
+
frames = [];
|
|
4617
|
+
sleepers = [];
|
|
4618
|
+
seq = 0;
|
|
4619
|
+
constructor(start = 0) {
|
|
4620
|
+
this.time = start;
|
|
4621
|
+
}
|
|
4622
|
+
now() {
|
|
4623
|
+
return this.time;
|
|
4624
|
+
}
|
|
4625
|
+
frame() {
|
|
4626
|
+
return new Promise((resolve) => this.frames.push(resolve));
|
|
4627
|
+
}
|
|
4628
|
+
sleep(ms) {
|
|
4629
|
+
return new Promise(
|
|
4630
|
+
(resolve) => this.sleepers.push({
|
|
4631
|
+
at: this.time + Math.max(0, ms),
|
|
4632
|
+
seq: this.seq++,
|
|
4633
|
+
resolve
|
|
4634
|
+
})
|
|
4635
|
+
);
|
|
4636
|
+
}
|
|
4637
|
+
/** Whether any frames or sleep timers are currently pending. */
|
|
4638
|
+
get pending() {
|
|
4639
|
+
return this.frames.length > 0 || this.sleepers.length > 0;
|
|
4640
|
+
}
|
|
4641
|
+
/** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */
|
|
4642
|
+
async advance(ms) {
|
|
4643
|
+
const end = this.time + Math.max(0, ms);
|
|
4644
|
+
await settle();
|
|
4645
|
+
while (true) {
|
|
4646
|
+
let next;
|
|
4647
|
+
for (const s of this.sleepers) {
|
|
4648
|
+
if (s.at <= end && (!next || s.at < next.at || s.at === next.at && s.seq < next.seq)) {
|
|
4649
|
+
next = s;
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
if (!next) break;
|
|
4653
|
+
this.sleepers.splice(this.sleepers.indexOf(next), 1);
|
|
4654
|
+
this.time = Math.max(this.time, next.at);
|
|
4655
|
+
next.resolve();
|
|
4656
|
+
await settle();
|
|
4657
|
+
}
|
|
4658
|
+
this.time = end;
|
|
4659
|
+
const dueFrames = this.frames.splice(0, this.frames.length);
|
|
4660
|
+
for (const resolveFrame of dueFrames) {
|
|
4661
|
+
resolveFrame();
|
|
4662
|
+
}
|
|
4663
|
+
await settle();
|
|
4664
|
+
}
|
|
4665
|
+
/** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */
|
|
4666
|
+
async tick(fps = 60) {
|
|
4667
|
+
await this.advance(Math.round(1e3 / fps));
|
|
4668
|
+
}
|
|
4669
|
+
};
|
|
4670
|
+
|
|
4671
|
+
// src/canvas/trajectory.ts
|
|
4672
|
+
var defaultEasing = (t) => --t * t * t + 1;
|
|
4673
|
+
var linearTrajectory = (origin, target, progress) => {
|
|
4674
|
+
return {
|
|
4675
|
+
position: {
|
|
4676
|
+
x: origin.x + (target.x - origin.x) * progress,
|
|
4677
|
+
y: origin.y + (target.y - origin.y) * progress
|
|
4678
|
+
},
|
|
4679
|
+
scale: progress,
|
|
4680
|
+
opacity: Math.min(1, progress * 1.5)
|
|
4681
|
+
};
|
|
4682
|
+
};
|
|
4683
|
+
var linearPositionTrajectory = (origin, target, progress) => {
|
|
4684
|
+
return {
|
|
4685
|
+
position: {
|
|
4686
|
+
x: origin.x + (target.x - origin.x) * progress,
|
|
4687
|
+
y: origin.y + (target.y - origin.y) * progress
|
|
4688
|
+
}
|
|
4689
|
+
};
|
|
4690
|
+
};
|
|
4691
|
+
function createFanOutTrajectory(options = {}) {
|
|
4692
|
+
const {
|
|
4693
|
+
curvature = 0.4,
|
|
4694
|
+
startScale = 0,
|
|
4695
|
+
endScale = 1,
|
|
4696
|
+
startOpacity = 0,
|
|
4697
|
+
endOpacity = 1
|
|
4698
|
+
} = options;
|
|
4699
|
+
return (origin, target, progress, index, total) => {
|
|
4700
|
+
const dx = target.x - origin.x;
|
|
4701
|
+
const dy = target.y - origin.y;
|
|
4702
|
+
const normIndex = total > 1 ? (index - (total - 1) / 2) / ((total - 1) / 2) : 0;
|
|
4703
|
+
const midX = origin.x + dx * 0.4;
|
|
4704
|
+
const midY = origin.y + dy * 0.1 - normIndex * Math.abs(dx) * 0.15 * curvature;
|
|
4705
|
+
const t = progress;
|
|
4706
|
+
const oneMinusT = 1 - t;
|
|
4707
|
+
const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;
|
|
4708
|
+
const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;
|
|
4709
|
+
const scale = startScale + (endScale - startScale) * progress;
|
|
4710
|
+
const opacity = startOpacity + (endOpacity - startOpacity) * progress;
|
|
4711
|
+
return {
|
|
4712
|
+
position: { x, y },
|
|
4713
|
+
scale,
|
|
4714
|
+
opacity
|
|
4715
|
+
};
|
|
4716
|
+
};
|
|
4717
|
+
}
|
|
4718
|
+
function createBezierTrajectory(getControlPoint) {
|
|
4719
|
+
return (origin, target, progress) => {
|
|
4720
|
+
const cp = getControlPoint(origin, target);
|
|
4721
|
+
const t = progress;
|
|
4722
|
+
const oneMinusT = 1 - t;
|
|
4723
|
+
const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * cp.x + t * t * target.x;
|
|
4724
|
+
const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * cp.y + t * t * target.y;
|
|
4725
|
+
return {
|
|
4726
|
+
position: { x, y },
|
|
4727
|
+
scale: progress,
|
|
4728
|
+
opacity: progress
|
|
4729
|
+
};
|
|
4730
|
+
};
|
|
4731
|
+
}
|
|
4732
|
+
function runMultiNodeTransition(transitions, options = {}) {
|
|
4733
|
+
if (transitions.length === 0) {
|
|
4734
|
+
options.onComplete?.();
|
|
4735
|
+
return () => {
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4738
|
+
const {
|
|
4739
|
+
defaultDuration = 400,
|
|
4740
|
+
defaultEasing: easingFunc = defaultEasing,
|
|
4741
|
+
clock = realClock,
|
|
4742
|
+
onUpdate,
|
|
4743
|
+
onComplete
|
|
4744
|
+
} = options;
|
|
4745
|
+
let isCancelled = false;
|
|
4746
|
+
const startTime = clock.now();
|
|
4747
|
+
const items = transitions.map((tr, i) => ({
|
|
4748
|
+
...tr,
|
|
4749
|
+
index: tr.index ?? i,
|
|
4750
|
+
total: tr.total ?? transitions.length,
|
|
4751
|
+
duration: tr.duration ?? defaultDuration,
|
|
4752
|
+
easing: tr.easing ?? easingFunc,
|
|
4753
|
+
delay: tr.delay ?? 0,
|
|
4754
|
+
trajectory: tr.trajectory ?? linearTrajectory
|
|
4755
|
+
}));
|
|
4756
|
+
function frame() {
|
|
4757
|
+
if (isCancelled) return;
|
|
4758
|
+
const now = clock.now();
|
|
4759
|
+
let allCompleted = true;
|
|
4760
|
+
for (let i = 0; i < items.length; i++) {
|
|
4761
|
+
const item = items[i];
|
|
4762
|
+
const elapsed = now - (startTime + item.delay);
|
|
4763
|
+
if (elapsed < 0) {
|
|
4764
|
+
allCompleted = false;
|
|
4765
|
+
continue;
|
|
4766
|
+
}
|
|
4767
|
+
const rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);
|
|
4768
|
+
const progress = item.duration <= 0 ? 1 : item.easing(rawProgress);
|
|
4769
|
+
const point = item.trajectory(item.from, item.to, progress, item.index, item.total);
|
|
4770
|
+
item.node.position = { ...point.position };
|
|
4771
|
+
if (point.scale !== void 0 || point.opacity !== void 0) {
|
|
4772
|
+
if (!item.node.data) {
|
|
4773
|
+
item.node.data = {};
|
|
4774
|
+
}
|
|
4775
|
+
if (point.scale !== void 0) {
|
|
4776
|
+
item.node.data.scale = point.scale;
|
|
4777
|
+
}
|
|
4778
|
+
if (point.opacity !== void 0) {
|
|
4779
|
+
item.node.data.opacity = point.opacity;
|
|
4780
|
+
const currentStyle = (item.node.style || "").replace(/opacity:\s*[^;]+;?/g, "").trim();
|
|
4781
|
+
item.node.style = `${currentStyle ? currentStyle + "; " : ""}opacity: ${point.opacity};`;
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
if (rawProgress < 1) {
|
|
4785
|
+
allCompleted = false;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
onUpdate?.();
|
|
4789
|
+
if (!allCompleted) {
|
|
4790
|
+
clock.frame().then(frame);
|
|
4791
|
+
} else {
|
|
4792
|
+
onComplete?.();
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
frame();
|
|
4796
|
+
return () => {
|
|
4797
|
+
isCancelled = true;
|
|
4798
|
+
};
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
// src/canvas/displacement.ts
|
|
4802
|
+
var import_dagre2 = __toESM(require("@dagrejs/dagre"), 1);
|
|
4803
|
+
function computeNodesBoundingBox(nodes, defaultWidth = 200, defaultHeight = 60) {
|
|
4804
|
+
if (nodes.length === 0) {
|
|
4805
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
4806
|
+
}
|
|
4807
|
+
let minX = Infinity;
|
|
4808
|
+
let minY = Infinity;
|
|
4809
|
+
let maxX = -Infinity;
|
|
4810
|
+
let maxY = -Infinity;
|
|
4811
|
+
for (const node of nodes) {
|
|
4812
|
+
const width = node.measured?.width ?? node.width ?? defaultWidth;
|
|
4813
|
+
const height = node.measured?.height ?? node.height ?? defaultHeight;
|
|
4814
|
+
minX = Math.min(minX, node.position.x);
|
|
4815
|
+
minY = Math.min(minY, node.position.y);
|
|
4816
|
+
maxX = Math.max(maxX, node.position.x + width);
|
|
4817
|
+
maxY = Math.max(maxY, node.position.y + height);
|
|
4818
|
+
}
|
|
4819
|
+
return {
|
|
4820
|
+
x: minX,
|
|
4821
|
+
y: minY,
|
|
4822
|
+
width: maxX - minX,
|
|
4823
|
+
height: maxY - minY
|
|
4824
|
+
};
|
|
4825
|
+
}
|
|
4826
|
+
function calculateDirectionalDisplacement(params) {
|
|
4827
|
+
const {
|
|
4828
|
+
existingNodes,
|
|
4829
|
+
originNode,
|
|
4830
|
+
childNodes: childNodes2,
|
|
4831
|
+
getNodesBounds,
|
|
4832
|
+
options = {}
|
|
4833
|
+
} = params;
|
|
4834
|
+
const {
|
|
4835
|
+
direction = "right",
|
|
4836
|
+
gap = 40,
|
|
4837
|
+
spreadSiblingLanes = false,
|
|
4838
|
+
siblingTolerance = 50,
|
|
4839
|
+
minY
|
|
4840
|
+
} = options;
|
|
4841
|
+
const displacedMap = /* @__PURE__ */ new Map();
|
|
4842
|
+
if (childNodes2.length === 0 || existingNodes.length === 0) {
|
|
4843
|
+
return displacedMap;
|
|
4844
|
+
}
|
|
4845
|
+
const childBounds = getNodesBounds ? getNodesBounds(childNodes2) : computeNodesBoundingBox(childNodes2);
|
|
4846
|
+
const originWidth = originNode.measured?.width ?? originNode.width ?? 200;
|
|
4847
|
+
const originHeight = originNode.measured?.height ?? originNode.height ?? 60;
|
|
4848
|
+
const deltaPrimary = direction === "right" || direction === "left" ? childBounds.width + gap : childBounds.height + gap;
|
|
4849
|
+
const deltaUp = Math.max(0, originNode.position.y - childBounds.y + gap);
|
|
4850
|
+
const deltaDown = Math.max(
|
|
4851
|
+
0,
|
|
4852
|
+
childBounds.y + childBounds.height - (originNode.position.y + originHeight) + gap
|
|
4853
|
+
);
|
|
4854
|
+
const equalDelta = Math.max(deltaUp, deltaDown);
|
|
4855
|
+
for (const node of existingNodes) {
|
|
4856
|
+
if (node.id === originNode.id) continue;
|
|
4857
|
+
const isSiblingRow = Math.abs(node.position.y - originNode.position.y) < siblingTolerance;
|
|
4858
|
+
switch (direction) {
|
|
4859
|
+
case "right": {
|
|
4860
|
+
if (node.position.x > originNode.position.x) {
|
|
4861
|
+
displacedMap.set(node.id, {
|
|
4862
|
+
x: node.position.x + deltaPrimary,
|
|
4863
|
+
y: node.position.y
|
|
4864
|
+
});
|
|
4865
|
+
}
|
|
4866
|
+
break;
|
|
4867
|
+
}
|
|
4868
|
+
case "left": {
|
|
4869
|
+
if (node.position.x < originNode.position.x) {
|
|
4870
|
+
displacedMap.set(node.id, {
|
|
4871
|
+
x: node.position.x - deltaPrimary,
|
|
4872
|
+
y: node.position.y
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
break;
|
|
4876
|
+
}
|
|
4877
|
+
case "down": {
|
|
4878
|
+
if (node.position.y > originNode.position.y) {
|
|
4879
|
+
displacedMap.set(node.id, {
|
|
4880
|
+
x: node.position.x,
|
|
4881
|
+
y: node.position.y + deltaPrimary
|
|
4882
|
+
});
|
|
4883
|
+
}
|
|
4884
|
+
break;
|
|
4885
|
+
}
|
|
4886
|
+
case "up": {
|
|
4887
|
+
if (node.position.y < originNode.position.y) {
|
|
4888
|
+
displacedMap.set(node.id, {
|
|
4889
|
+
x: node.position.x,
|
|
4890
|
+
y: node.position.y - deltaPrimary
|
|
4891
|
+
});
|
|
4892
|
+
}
|
|
4893
|
+
break;
|
|
4894
|
+
}
|
|
4895
|
+
case "vertical": {
|
|
4896
|
+
if (isSiblingRow) break;
|
|
4897
|
+
if (node.position.y < originNode.position.y) {
|
|
4898
|
+
displacedMap.set(node.id, {
|
|
4899
|
+
x: node.position.x,
|
|
4900
|
+
y: node.position.y - equalDelta
|
|
4901
|
+
});
|
|
4902
|
+
} else if (node.position.y > originNode.position.y) {
|
|
4903
|
+
displacedMap.set(node.id, {
|
|
4904
|
+
x: node.position.x,
|
|
4905
|
+
y: node.position.y + equalDelta
|
|
4906
|
+
});
|
|
4907
|
+
}
|
|
4908
|
+
break;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
if (spreadSiblingLanes && (direction === "right" || direction === "left")) {
|
|
4913
|
+
for (const [nodeId, pos] of displacedMap.entries()) {
|
|
4914
|
+
const node = existingNodes.find((n) => n.id === nodeId);
|
|
4915
|
+
if (node && Math.abs(node.position.y - originNode.position.y) < siblingTolerance) {
|
|
4916
|
+
const isAbove = node.position.y < originNode.position.y;
|
|
4917
|
+
displacedMap.set(nodeId, {
|
|
4918
|
+
x: pos.x,
|
|
4919
|
+
y: pos.y + (isAbove ? -deltaUp : deltaDown)
|
|
4920
|
+
});
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
if (minY !== void 0) {
|
|
4925
|
+
for (const [nodeId, pos] of displacedMap.entries()) {
|
|
4926
|
+
if (pos.y < minY) {
|
|
4927
|
+
displacedMap.set(nodeId, { x: pos.x, y: minY });
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
return displacedMap;
|
|
4932
|
+
}
|
|
4933
|
+
function calculateDagreReflowDisplacement(params) {
|
|
4934
|
+
const {
|
|
4935
|
+
currentNodes,
|
|
4936
|
+
futureNodes,
|
|
4937
|
+
futureEdges,
|
|
4938
|
+
options
|
|
4939
|
+
} = params;
|
|
4940
|
+
const {
|
|
4941
|
+
anchorNodeId,
|
|
4942
|
+
direction = "LR",
|
|
4943
|
+
ranksep = 100,
|
|
4944
|
+
nodesep = 25,
|
|
4945
|
+
defaultNodeWidth = 200,
|
|
4946
|
+
defaultNodeHeight = 60
|
|
4947
|
+
} = options;
|
|
4948
|
+
const anchorNode = currentNodes.find((n) => n.id === anchorNodeId);
|
|
4949
|
+
if (!anchorNode) return /* @__PURE__ */ new Map();
|
|
4950
|
+
const g = new import_dagre2.default.graphlib.Graph();
|
|
4951
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
4952
|
+
g.setGraph({ rankdir: direction, ranksep, nodesep });
|
|
4953
|
+
const nodeIds = new Set(futureNodes.map((n) => n.id));
|
|
4954
|
+
futureNodes.forEach((node) => {
|
|
4955
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
4956
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
4957
|
+
g.setNode(node.id, { width: nodeWidth, height: nodeHeight });
|
|
4958
|
+
});
|
|
4959
|
+
futureEdges.forEach((edge) => {
|
|
4960
|
+
if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
|
|
4961
|
+
g.setEdge(edge.source, edge.target);
|
|
4962
|
+
}
|
|
4963
|
+
});
|
|
4964
|
+
import_dagre2.default.layout(g);
|
|
4965
|
+
const anchorLayoutPos = g.node(anchorNodeId);
|
|
4966
|
+
if (!anchorLayoutPos) return /* @__PURE__ */ new Map();
|
|
4967
|
+
const anchorWidth = anchorNode.measured?.width ?? anchorNode.width ?? defaultNodeWidth;
|
|
4968
|
+
const anchorHeight = anchorNode.measured?.height ?? anchorNode.height ?? defaultNodeHeight;
|
|
4969
|
+
const anchorLayoutUpperLeft = {
|
|
4970
|
+
x: anchorLayoutPos.x - anchorWidth / 2,
|
|
4971
|
+
y: anchorLayoutPos.y - anchorHeight / 2
|
|
4972
|
+
};
|
|
4973
|
+
const deltaX = anchorNode.position.x - anchorLayoutUpperLeft.x;
|
|
4974
|
+
const deltaY = anchorNode.position.y - anchorLayoutUpperLeft.y;
|
|
4975
|
+
const displacementMap = /* @__PURE__ */ new Map();
|
|
4976
|
+
currentNodes.forEach((node) => {
|
|
4977
|
+
if (node.id === anchorNodeId) return;
|
|
4978
|
+
const layoutNode = g.node(node.id);
|
|
4979
|
+
if (!layoutNode) return;
|
|
4980
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
4981
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
4982
|
+
const upperLeftX = layoutNode.x - nodeWidth / 2 + deltaX;
|
|
4983
|
+
const upperLeftY = layoutNode.y - nodeHeight / 2 + deltaY;
|
|
4984
|
+
if (Math.abs(upperLeftX - node.position.x) > 1 || Math.abs(upperLeftY - node.position.y) > 1) {
|
|
4985
|
+
displacementMap.set(node.id, { x: upperLeftX, y: upperLeftY });
|
|
4986
|
+
}
|
|
4987
|
+
});
|
|
4988
|
+
return displacementMap;
|
|
4989
|
+
}
|
|
4990
|
+
|
|
4991
|
+
// src/canvas/clipboard.ts
|
|
4992
|
+
function isEventFromTextInput(event) {
|
|
4993
|
+
const target = event.target;
|
|
4994
|
+
if (!target) return false;
|
|
4995
|
+
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable || target.closest?.('[contenteditable="true"]') || target.closest?.(".ProseMirror")) {
|
|
4996
|
+
return true;
|
|
4997
|
+
}
|
|
4998
|
+
return false;
|
|
4999
|
+
}
|
|
5000
|
+
function isValidCanvasNode(obj) {
|
|
5001
|
+
return typeof obj === "object" && obj !== null && "id" in obj && typeof obj.id === "string" && "position" in obj && typeof obj.position === "object" && obj.position !== null && "x" in obj.position && "y" in obj.position;
|
|
5002
|
+
}
|
|
5003
|
+
function isValidUrl(url) {
|
|
5004
|
+
try {
|
|
5005
|
+
const parsed = new URL(url);
|
|
5006
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
5007
|
+
} catch {
|
|
5008
|
+
return false;
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
function serializeCanvasNodes(nodes, edges) {
|
|
5012
|
+
const payload = {
|
|
5013
|
+
version: 1,
|
|
5014
|
+
nodes,
|
|
5015
|
+
edges
|
|
5016
|
+
};
|
|
5017
|
+
return JSON.stringify(payload);
|
|
5018
|
+
}
|
|
5019
|
+
function parseCanvasClipboardData(raw) {
|
|
5020
|
+
try {
|
|
5021
|
+
const parsed = JSON.parse(raw);
|
|
5022
|
+
if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.nodes) && parsed.nodes.length > 0 && parsed.nodes.every(isValidCanvasNode)) {
|
|
5023
|
+
return parsed;
|
|
5024
|
+
}
|
|
5025
|
+
} catch {
|
|
5026
|
+
}
|
|
5027
|
+
return null;
|
|
5028
|
+
}
|
|
5029
|
+
function remapPastedNodes(nodes, edges = [], offset = { x: 30, y: 30 }, idGenerator = () => `node-${Math.random().toString(36).substring(2, 9)}`) {
|
|
5030
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
5031
|
+
const newNodes = nodes.map((node) => {
|
|
5032
|
+
const newId = idGenerator();
|
|
5033
|
+
idMap.set(node.id, newId);
|
|
5034
|
+
return {
|
|
5035
|
+
...node,
|
|
5036
|
+
id: newId,
|
|
5037
|
+
position: {
|
|
5038
|
+
x: node.position.x + offset.x,
|
|
5039
|
+
y: node.position.y + offset.y
|
|
5040
|
+
},
|
|
5041
|
+
selected: true
|
|
5042
|
+
};
|
|
5043
|
+
});
|
|
5044
|
+
const newEdges = edges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((edge) => ({
|
|
5045
|
+
...edge,
|
|
5046
|
+
id: `edge-${Math.random().toString(36).substring(2, 9)}`,
|
|
5047
|
+
source: idMap.get(edge.source),
|
|
5048
|
+
target: idMap.get(edge.target),
|
|
5049
|
+
selected: false
|
|
5050
|
+
}));
|
|
5051
|
+
return { nodes: newNodes, edges: newEdges };
|
|
5052
|
+
}
|
|
5053
|
+
function repositionNodesTo(nodes, targetOrigin) {
|
|
5054
|
+
if (nodes.length === 0) return [];
|
|
5055
|
+
const minX = Math.min(...nodes.map((n) => n.position.x));
|
|
5056
|
+
const minY = Math.min(...nodes.map((n) => n.position.y));
|
|
5057
|
+
const deltaX = targetOrigin.x - minX;
|
|
5058
|
+
const deltaY = targetOrigin.y - minY;
|
|
5059
|
+
return nodes.map((n) => ({
|
|
5060
|
+
...n,
|
|
5061
|
+
position: {
|
|
5062
|
+
x: n.position.x + deltaX,
|
|
5063
|
+
y: n.position.y + deltaY
|
|
5064
|
+
}
|
|
5065
|
+
}));
|
|
5066
|
+
}
|
|
5067
|
+
|
|
5068
|
+
// src/canvas/view.ts
|
|
5069
|
+
function clampHeight(contentHeight, options = {}) {
|
|
5070
|
+
const { min = 320, max = 560, padding = 48 } = options;
|
|
5071
|
+
return Math.round(Math.min(max, Math.max(min, contentHeight + padding)));
|
|
5072
|
+
}
|
|
5073
|
+
function layoutBounds(nodes) {
|
|
5074
|
+
if (nodes.length === 0) return null;
|
|
5075
|
+
let minX = Infinity;
|
|
5076
|
+
let minY = Infinity;
|
|
5077
|
+
let maxX = -Infinity;
|
|
5078
|
+
let maxY = -Infinity;
|
|
5079
|
+
for (const node of nodes) {
|
|
5080
|
+
const x = node.position.x;
|
|
5081
|
+
const y = node.position.y;
|
|
5082
|
+
const width = node.width ?? 180;
|
|
5083
|
+
const height = node.height ?? 80;
|
|
5084
|
+
minX = Math.min(minX, x);
|
|
5085
|
+
minY = Math.min(minY, y);
|
|
5086
|
+
maxX = Math.max(maxX, x + width);
|
|
5087
|
+
maxY = Math.max(maxY, y + height);
|
|
5088
|
+
}
|
|
5089
|
+
if (minX === Infinity) return null;
|
|
5090
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
5091
|
+
}
|
|
5092
|
+
function canvasHeight(nodes, options) {
|
|
5093
|
+
return clampHeight(layoutBounds(nodes)?.height ?? 0, options);
|
|
5094
|
+
}
|
|
5095
|
+
var DEFAULT_RANK_HEIGHT = 80 + 72;
|
|
5096
|
+
var NODES_PER_RANK = 2;
|
|
5097
|
+
function estimateCanvasHeight(nodes, edges, options) {
|
|
5098
|
+
const ranks = Math.max(1, Math.ceil(nodes.length / NODES_PER_RANK));
|
|
5099
|
+
return clampHeight(ranks * DEFAULT_RANK_HEIGHT, options);
|
|
5100
|
+
}
|
|
5101
|
+
function mix(a, b, t) {
|
|
5102
|
+
return a + (b - a) * t;
|
|
5103
|
+
}
|
|
5104
|
+
function blendLayout(from, to, t) {
|
|
5105
|
+
if (t >= 1) return to;
|
|
5106
|
+
const fromMap = new Map(from.map((n) => [n.id, n]));
|
|
5107
|
+
return to.map((target) => {
|
|
5108
|
+
const origin = fromMap.get(target.id);
|
|
5109
|
+
if (!origin) return target;
|
|
5110
|
+
return {
|
|
5111
|
+
...target,
|
|
5112
|
+
position: {
|
|
5113
|
+
x: mix(origin.position.x, target.position.x, t),
|
|
5114
|
+
y: mix(origin.position.y, target.position.y, t)
|
|
5115
|
+
},
|
|
5116
|
+
width: origin.width !== void 0 && target.width !== void 0 ? mix(origin.width, target.width, t) : target.width,
|
|
5117
|
+
height: origin.height !== void 0 && target.height !== void 0 ? mix(origin.height, target.height, t) : target.height
|
|
5118
|
+
};
|
|
5119
|
+
});
|
|
5120
|
+
}
|
|
5121
|
+
function connectedOnly(nodes, edges) {
|
|
5122
|
+
if (edges.length === 0) return nodes;
|
|
5123
|
+
const linkedNodeIds = /* @__PURE__ */ new Set();
|
|
5124
|
+
for (const edge of edges) {
|
|
5125
|
+
linkedNodeIds.add(edge.source);
|
|
5126
|
+
linkedNodeIds.add(edge.target);
|
|
5127
|
+
}
|
|
5128
|
+
const filtered = nodes.filter((node) => linkedNodeIds.has(node.id));
|
|
5129
|
+
return filtered.length > 0 ? filtered : nodes;
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
// src/canvas/streaming.ts
|
|
5133
|
+
var StreamingLayoutManager = class {
|
|
5134
|
+
throttleMs;
|
|
5135
|
+
glideDurationMs;
|
|
5136
|
+
connectedOnly;
|
|
5137
|
+
clock;
|
|
5138
|
+
layoutOptions;
|
|
5139
|
+
onLayoutUpdated;
|
|
5140
|
+
pendingTimer = null;
|
|
5141
|
+
activeTransitionCancel = null;
|
|
5142
|
+
targetPositions = /* @__PURE__ */ new Map();
|
|
5143
|
+
constructor(options = {}) {
|
|
5144
|
+
this.throttleMs = options.throttleMs ?? 200;
|
|
5145
|
+
this.glideDurationMs = options.glideDurationMs ?? 300;
|
|
5146
|
+
this.connectedOnly = options.connectedOnly ?? false;
|
|
5147
|
+
this.clock = options.clock ?? realClock;
|
|
5148
|
+
this.layoutOptions = options.layoutOptions ?? { direction: "LR" };
|
|
5149
|
+
this.onLayoutUpdated = options.onLayoutUpdated;
|
|
5150
|
+
}
|
|
5151
|
+
/**
|
|
5152
|
+
* Feed incoming nodes and edges into the streaming manager.
|
|
5153
|
+
* Coalesces rapid streaming bursts and triggers smooth layout gliding.
|
|
5154
|
+
*/
|
|
5155
|
+
pushStreamUpdate(nodes, edges, currentPositions) {
|
|
5156
|
+
if (this.pendingTimer) {
|
|
5157
|
+
clearTimeout(this.pendingTimer);
|
|
5158
|
+
}
|
|
5159
|
+
this.pendingTimer = setTimeout(() => {
|
|
5160
|
+
this.pendingTimer = null;
|
|
5161
|
+
this.recalculateAndGlide(nodes, edges, currentPositions);
|
|
5162
|
+
}, this.throttleMs);
|
|
5163
|
+
}
|
|
5164
|
+
/**
|
|
5165
|
+
* Forces immediate calculation and cancels pending throttled timers.
|
|
5166
|
+
*/
|
|
5167
|
+
flush(nodes, edges, currentPositions) {
|
|
5168
|
+
if (this.pendingTimer) {
|
|
5169
|
+
clearTimeout(this.pendingTimer);
|
|
5170
|
+
this.pendingTimer = null;
|
|
5171
|
+
}
|
|
5172
|
+
this.recalculateAndGlide(nodes, edges, currentPositions);
|
|
5173
|
+
}
|
|
5174
|
+
recalculateAndGlide(nodes, edges, currentPositions) {
|
|
5175
|
+
const targetNodes = this.connectedOnly ? connectedOnly(nodes, edges) : nodes;
|
|
5176
|
+
if (targetNodes.length === 0) return;
|
|
5177
|
+
if (this.activeTransitionCancel) {
|
|
5178
|
+
this.activeTransitionCancel();
|
|
5179
|
+
this.activeTransitionCancel = null;
|
|
5180
|
+
}
|
|
5181
|
+
const stored = {};
|
|
5182
|
+
for (const [id, pos] of currentPositions.entries()) {
|
|
5183
|
+
stored[id] = pos;
|
|
5184
|
+
}
|
|
5185
|
+
const layouted = ensureLayout(targetNodes, edges, {
|
|
5186
|
+
...this.layoutOptions,
|
|
5187
|
+
storedPositions: stored
|
|
5188
|
+
});
|
|
5189
|
+
const nextPositions = /* @__PURE__ */ new Map();
|
|
5190
|
+
const transitions = [];
|
|
5191
|
+
for (const node of layouted) {
|
|
5192
|
+
const target = node.position;
|
|
5193
|
+
nextPositions.set(node.id, target);
|
|
5194
|
+
const current = currentPositions.get(node.id) ?? target;
|
|
5195
|
+
const distance = Math.hypot(target.x - current.x, target.y - current.y);
|
|
5196
|
+
if (distance > 2) {
|
|
5197
|
+
transitions.push({
|
|
5198
|
+
node,
|
|
5199
|
+
from: current,
|
|
5200
|
+
to: target,
|
|
5201
|
+
trajectory: linearPositionTrajectory,
|
|
5202
|
+
duration: this.glideDurationMs
|
|
5203
|
+
});
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
this.targetPositions = nextPositions;
|
|
5207
|
+
if (transitions.length > 0) {
|
|
5208
|
+
this.activeTransitionCancel = runMultiNodeTransition(transitions, {
|
|
5209
|
+
clock: this.clock,
|
|
5210
|
+
onUpdate: () => {
|
|
5211
|
+
const liveMap = new Map(currentPositions);
|
|
5212
|
+
for (const trans of transitions) {
|
|
5213
|
+
liveMap.set(trans.node.id, { ...trans.node.position });
|
|
5214
|
+
}
|
|
5215
|
+
this.onLayoutUpdated?.(liveMap);
|
|
5216
|
+
},
|
|
5217
|
+
onComplete: () => {
|
|
5218
|
+
this.activeTransitionCancel = null;
|
|
5219
|
+
this.onLayoutUpdated?.(nextPositions);
|
|
5220
|
+
}
|
|
5221
|
+
});
|
|
5222
|
+
} else {
|
|
5223
|
+
this.onLayoutUpdated?.(nextPositions);
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
destroy() {
|
|
5227
|
+
if (this.pendingTimer) {
|
|
5228
|
+
clearTimeout(this.pendingTimer);
|
|
5229
|
+
this.pendingTimer = null;
|
|
5230
|
+
}
|
|
5231
|
+
if (this.activeTransitionCancel) {
|
|
5232
|
+
this.activeTransitionCancel();
|
|
5233
|
+
this.activeTransitionCancel = null;
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
};
|
|
5237
|
+
|
|
5238
|
+
// src/agent/planner.ts
|
|
5239
|
+
function planAgentCommand(command, snapshot, options = {}) {
|
|
5240
|
+
const defaultNodeSize = options.defaultNodeSize ?? { width: 200, height: 60 };
|
|
5241
|
+
const idGen = options.idGenerator ?? (() => `node-${Math.random().toString(36).substring(2, 9)}`);
|
|
5242
|
+
const edgeIdGen = () => `edge-${Math.random().toString(36).substring(2, 9)}`;
|
|
5243
|
+
const nodes = snapshot.canvas?.nodes ?? [];
|
|
5244
|
+
const edges = snapshot.canvas?.edges ?? [];
|
|
5245
|
+
switch (command.type) {
|
|
5246
|
+
case "canvas:add_node": {
|
|
5247
|
+
let pos = command.node.position;
|
|
5248
|
+
if (!pos) {
|
|
5249
|
+
if (command.nearNodeId) {
|
|
5250
|
+
const rects = {};
|
|
5251
|
+
for (const n of nodes) {
|
|
5252
|
+
rects[n.id] = {
|
|
5253
|
+
x: n.position.x,
|
|
5254
|
+
y: n.position.y,
|
|
5255
|
+
width: n.measured?.width ?? n.width ?? defaultNodeSize.width,
|
|
5256
|
+
height: n.measured?.height ?? n.height ?? defaultNodeSize.height
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
pos = placeBeside(
|
|
5260
|
+
rects,
|
|
5261
|
+
defaultNodeSize,
|
|
5262
|
+
command.side ?? "right",
|
|
5263
|
+
command.nearNodeId
|
|
5264
|
+
);
|
|
5265
|
+
} else if (nodes.length > 0) {
|
|
5266
|
+
const lastNode = nodes[nodes.length - 1];
|
|
5267
|
+
const rects = {};
|
|
5268
|
+
for (const n of nodes) {
|
|
5269
|
+
rects[n.id] = {
|
|
5270
|
+
x: n.position.x,
|
|
5271
|
+
y: n.position.y,
|
|
5272
|
+
width: n.measured?.width ?? n.width ?? defaultNodeSize.width,
|
|
5273
|
+
height: n.measured?.height ?? n.height ?? defaultNodeSize.height
|
|
5274
|
+
};
|
|
5275
|
+
}
|
|
5276
|
+
pos = placeBeside(rects, defaultNodeSize, "right", lastNode.id);
|
|
5277
|
+
} else {
|
|
5278
|
+
pos = { x: 100, y: 100 };
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
const fullNode = {
|
|
5282
|
+
...command.node,
|
|
5283
|
+
id: command.node.id || idGen(),
|
|
5284
|
+
position: pos
|
|
5285
|
+
};
|
|
5286
|
+
const steps = [
|
|
5287
|
+
{
|
|
5288
|
+
type: "step:canvas_add_node",
|
|
5289
|
+
node: fullNode
|
|
5290
|
+
}
|
|
5291
|
+
];
|
|
5292
|
+
if (command.nearNodeId) {
|
|
5293
|
+
steps.push({
|
|
5294
|
+
type: "step:canvas_add_edge",
|
|
5295
|
+
edge: {
|
|
5296
|
+
id: edgeIdGen(),
|
|
5297
|
+
source: command.nearNodeId,
|
|
5298
|
+
target: fullNode.id
|
|
5299
|
+
}
|
|
5300
|
+
});
|
|
5301
|
+
}
|
|
5302
|
+
return steps;
|
|
5303
|
+
}
|
|
5304
|
+
case "canvas:remove_nodes": {
|
|
5305
|
+
return [
|
|
5306
|
+
{
|
|
5307
|
+
type: "step:canvas_remove_nodes",
|
|
5308
|
+
nodeIds: command.nodeIds
|
|
5309
|
+
}
|
|
5310
|
+
];
|
|
5311
|
+
}
|
|
5312
|
+
case "canvas:connect": {
|
|
5313
|
+
return [
|
|
5314
|
+
{
|
|
5315
|
+
type: "step:canvas_add_edge",
|
|
5316
|
+
edge: {
|
|
5317
|
+
id: edgeIdGen(),
|
|
5318
|
+
source: command.source,
|
|
5319
|
+
target: command.target,
|
|
5320
|
+
label: command.label
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5323
|
+
];
|
|
5324
|
+
}
|
|
5325
|
+
case "canvas:update_node": {
|
|
5326
|
+
return [
|
|
5327
|
+
{
|
|
5328
|
+
type: "step:canvas_update_node",
|
|
5329
|
+
id: command.id,
|
|
5330
|
+
data: command.data
|
|
5331
|
+
}
|
|
5332
|
+
];
|
|
5333
|
+
}
|
|
5334
|
+
case "canvas:layout": {
|
|
5335
|
+
const dir = command.direction ?? "LR";
|
|
5336
|
+
let layouted;
|
|
5337
|
+
if (command.incremental) {
|
|
5338
|
+
const stored = {};
|
|
5339
|
+
for (const n of nodes) {
|
|
5340
|
+
if (n.position && (n.position.x !== 0 || n.position.y !== 0)) {
|
|
5341
|
+
stored[n.id] = { ...n.position };
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5344
|
+
layouted = ensureLayout(nodes, edges, {
|
|
5345
|
+
direction: dir,
|
|
5346
|
+
storedPositions: stored
|
|
5347
|
+
});
|
|
5348
|
+
} else {
|
|
5349
|
+
layouted = getLayoutedNodes(nodes, edges, void 0, { direction: dir });
|
|
5350
|
+
}
|
|
5351
|
+
const positions = {};
|
|
5352
|
+
for (const node of layouted) {
|
|
5353
|
+
positions[node.id] = { ...node.position };
|
|
5354
|
+
}
|
|
5355
|
+
return [
|
|
5356
|
+
{
|
|
5357
|
+
type: "step:canvas_move_nodes",
|
|
5358
|
+
positions
|
|
5359
|
+
}
|
|
5360
|
+
];
|
|
5361
|
+
}
|
|
5362
|
+
case "canvas:select": {
|
|
5363
|
+
return [
|
|
5364
|
+
{
|
|
5365
|
+
type: "step:canvas_select",
|
|
5366
|
+
nodeIds: command.nodeIds
|
|
5367
|
+
}
|
|
5368
|
+
];
|
|
5369
|
+
}
|
|
5370
|
+
case "canvas:highlight": {
|
|
5371
|
+
return [
|
|
5372
|
+
{
|
|
5373
|
+
type: "step:canvas_highlight",
|
|
5374
|
+
nodeIds: command.nodeIds,
|
|
5375
|
+
color: command.color ?? "#3b82f6",
|
|
5376
|
+
durationMs: command.durationMs ?? 2e3
|
|
5377
|
+
}
|
|
5378
|
+
];
|
|
5379
|
+
}
|
|
5380
|
+
case "prompt:insert_text": {
|
|
5381
|
+
return [
|
|
5382
|
+
{
|
|
5383
|
+
type: "step:prompt_insert",
|
|
5384
|
+
text: command.text,
|
|
5385
|
+
at: command.at
|
|
5386
|
+
}
|
|
5387
|
+
];
|
|
5388
|
+
}
|
|
5389
|
+
case "prompt:replace_range": {
|
|
5390
|
+
return [
|
|
5391
|
+
{
|
|
5392
|
+
type: "step:prompt_replace",
|
|
5393
|
+
from: command.from,
|
|
5394
|
+
to: command.to,
|
|
5395
|
+
text: command.text
|
|
5396
|
+
}
|
|
5397
|
+
];
|
|
5398
|
+
}
|
|
5399
|
+
case "prompt:set_variable": {
|
|
5400
|
+
return [
|
|
5401
|
+
{
|
|
5402
|
+
type: "step:prompt_set_variable",
|
|
5403
|
+
name: command.name,
|
|
5404
|
+
value: command.value
|
|
5405
|
+
}
|
|
5406
|
+
];
|
|
5407
|
+
}
|
|
5408
|
+
case "prompt:select": {
|
|
5409
|
+
return [
|
|
5410
|
+
{
|
|
5411
|
+
type: "step:prompt_select",
|
|
5412
|
+
from: command.from,
|
|
5413
|
+
to: command.to
|
|
5414
|
+
}
|
|
5415
|
+
];
|
|
5416
|
+
}
|
|
5417
|
+
case "choreography:say": {
|
|
5418
|
+
return [
|
|
5419
|
+
{
|
|
5420
|
+
type: "step:say",
|
|
5421
|
+
text: command.text,
|
|
5422
|
+
atNodeId: command.atNodeId,
|
|
5423
|
+
position: command.position
|
|
5424
|
+
}
|
|
5425
|
+
];
|
|
5426
|
+
}
|
|
5427
|
+
case "choreography:wait": {
|
|
5428
|
+
return [
|
|
5429
|
+
{
|
|
5430
|
+
type: "step:wait",
|
|
5431
|
+
ms: command.ms
|
|
5432
|
+
}
|
|
5433
|
+
];
|
|
5434
|
+
}
|
|
5435
|
+
default: {
|
|
5436
|
+
return [];
|
|
5437
|
+
}
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5440
|
+
|
|
5441
|
+
// src/agent/tools.ts
|
|
5442
|
+
var MCP_TOOL_GET_EDITOR_STATE = {
|
|
5443
|
+
name: "get_editor_state",
|
|
5444
|
+
description: "Retrieves the current state of the document, variables, selection, and canvas graph (nodes and edges).",
|
|
5445
|
+
inputSchema: {
|
|
5446
|
+
type: "object",
|
|
5447
|
+
properties: {
|
|
5448
|
+
includeDocument: {
|
|
5449
|
+
type: "boolean",
|
|
5450
|
+
description: "Whether to include the prompt document text and variables (default: true)."
|
|
5451
|
+
},
|
|
5452
|
+
includeCanvas: {
|
|
5453
|
+
type: "boolean",
|
|
5454
|
+
description: "Whether to include the canvas nodes and edges (default: true)."
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
};
|
|
5459
|
+
var MCP_TOOL_EDIT_CANVAS = {
|
|
5460
|
+
name: "edit_canvas",
|
|
5461
|
+
description: "Applies high-level structural operations to the visual canvas (adding nodes, connecting edges, organizing layout, or moving elements).",
|
|
5462
|
+
inputSchema: {
|
|
5463
|
+
type: "object",
|
|
5464
|
+
properties: {
|
|
5465
|
+
operation: {
|
|
5466
|
+
type: "string",
|
|
5467
|
+
enum: [
|
|
5468
|
+
"add_node",
|
|
5469
|
+
"remove_nodes",
|
|
5470
|
+
"connect",
|
|
5471
|
+
"update_node",
|
|
5472
|
+
"layout",
|
|
5473
|
+
"select",
|
|
5474
|
+
"highlight"
|
|
5475
|
+
],
|
|
5476
|
+
description: "The canvas operation to execute."
|
|
5477
|
+
},
|
|
5478
|
+
node: {
|
|
5479
|
+
type: "object",
|
|
5480
|
+
description: "Node definition when operation is add_node. Can omit position to auto-place."
|
|
5481
|
+
},
|
|
5482
|
+
nearNodeId: {
|
|
5483
|
+
type: "string",
|
|
5484
|
+
description: "Anchor node ID to position beside using collision-aware placement."
|
|
5485
|
+
},
|
|
5486
|
+
side: {
|
|
5487
|
+
type: "string",
|
|
5488
|
+
enum: ["top", "right", "bottom", "left"],
|
|
5489
|
+
description: "Side of the anchor node to place the new node beside."
|
|
5490
|
+
},
|
|
5491
|
+
nodeIds: {
|
|
5492
|
+
type: "array",
|
|
5493
|
+
items: { type: "string" },
|
|
5494
|
+
description: "Array of node IDs for remove_nodes, select, or highlight."
|
|
5495
|
+
},
|
|
5496
|
+
source: {
|
|
5497
|
+
type: "string",
|
|
5498
|
+
description: "Source node ID for connect operation."
|
|
5499
|
+
},
|
|
5500
|
+
target: {
|
|
5501
|
+
type: "string",
|
|
5502
|
+
description: "Target node ID for connect operation."
|
|
5503
|
+
},
|
|
5504
|
+
label: {
|
|
5505
|
+
type: "string",
|
|
5506
|
+
description: "Optional edge label for connect operation."
|
|
5507
|
+
},
|
|
5508
|
+
direction: {
|
|
5509
|
+
type: "string",
|
|
5510
|
+
enum: ["LR", "TB", "RL", "BT"],
|
|
5511
|
+
description: "Layout direction (default LR)."
|
|
5512
|
+
},
|
|
5513
|
+
incremental: {
|
|
5514
|
+
type: "boolean",
|
|
5515
|
+
description: "Preserve existing node coordinates and blend layout (default true)."
|
|
5516
|
+
}
|
|
5517
|
+
},
|
|
5518
|
+
required: ["operation"]
|
|
5519
|
+
}
|
|
5520
|
+
};
|
|
5521
|
+
var MCP_TOOL_EDIT_PROMPT = {
|
|
5522
|
+
name: "edit_prompt",
|
|
5523
|
+
description: "Applies edits to the prompt template document, including inserting text, replacing ranges, and setting variables.",
|
|
5524
|
+
inputSchema: {
|
|
5525
|
+
type: "object",
|
|
5526
|
+
properties: {
|
|
5527
|
+
operation: {
|
|
5528
|
+
type: "string",
|
|
5529
|
+
enum: ["insert_text", "replace_range", "set_variable", "select"],
|
|
5530
|
+
description: "The prompt operation to execute."
|
|
5531
|
+
},
|
|
5532
|
+
text: {
|
|
5533
|
+
type: "string",
|
|
5534
|
+
description: "Text to insert or replace."
|
|
5535
|
+
},
|
|
5536
|
+
at: {
|
|
5537
|
+
type: "number",
|
|
5538
|
+
description: "Position to insert text at."
|
|
5539
|
+
},
|
|
5540
|
+
from: {
|
|
5541
|
+
type: "number",
|
|
5542
|
+
description: "Start offset for replace_range or select."
|
|
5543
|
+
},
|
|
5544
|
+
to: {
|
|
5545
|
+
type: "number",
|
|
5546
|
+
description: "End offset for replace_range or select."
|
|
5547
|
+
},
|
|
5548
|
+
name: {
|
|
5549
|
+
type: "string",
|
|
5550
|
+
description: "Variable name for set_variable."
|
|
5551
|
+
},
|
|
5552
|
+
value: {
|
|
5553
|
+
description: "Variable value for set_variable."
|
|
5554
|
+
}
|
|
5555
|
+
},
|
|
5556
|
+
required: ["operation"]
|
|
5557
|
+
}
|
|
5558
|
+
};
|
|
5559
|
+
var MCP_TOOL_VIEW_EDITOR = {
|
|
5560
|
+
name: "view_editor",
|
|
5561
|
+
description: "Captures a visual image snapshot (JPEG or PNG) of the editor canvas or viewport for multimodal evaluation. Active agent cursor indicators are automatically excluded from the snapshot.",
|
|
5562
|
+
inputSchema: {
|
|
5563
|
+
type: "object",
|
|
5564
|
+
properties: {
|
|
5565
|
+
scope: {
|
|
5566
|
+
type: "string",
|
|
5567
|
+
enum: ["viewport", "canvas"],
|
|
5568
|
+
description: "Whether to capture only the visible viewport or the full canvas bounding box (default: viewport)."
|
|
5569
|
+
},
|
|
5570
|
+
format: {
|
|
5571
|
+
type: "string",
|
|
5572
|
+
enum: ["jpeg", "png"],
|
|
5573
|
+
description: "Image format of the base64 snapshot (default: jpeg)."
|
|
5574
|
+
},
|
|
5575
|
+
maxEdge: {
|
|
5576
|
+
type: "integer",
|
|
5577
|
+
description: "Maximum width or height dimension in pixels (default: 1024)."
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
};
|
|
5582
|
+
var EXPORT_EXCLUDED_SELECTORS = [
|
|
5583
|
+
".pixerate-presence",
|
|
5584
|
+
".agent-presence",
|
|
5585
|
+
".ursula-presence"
|
|
5586
|
+
];
|
|
5587
|
+
var EDITOR_MCP_TOOLS = [
|
|
5588
|
+
MCP_TOOL_GET_EDITOR_STATE,
|
|
5589
|
+
MCP_TOOL_EDIT_CANVAS,
|
|
5590
|
+
MCP_TOOL_EDIT_PROMPT,
|
|
5591
|
+
MCP_TOOL_VIEW_EDITOR
|
|
5592
|
+
];
|
|
4346
5593
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4347
5594
|
0 && (module.exports = {
|
|
4348
5595
|
ColorHighlighter,
|
|
5596
|
+
DEFAULT_NODE_HEIGHT,
|
|
5597
|
+
DEFAULT_NODE_WIDTH,
|
|
5598
|
+
DEFAULT_PLACEMENT_GAP,
|
|
4349
5599
|
DataSourceBinder,
|
|
4350
5600
|
DependencyGraph,
|
|
4351
5601
|
DirtyTracker,
|
|
5602
|
+
EDITOR_MCP_TOOLS,
|
|
5603
|
+
EXPORT_EXCLUDED_SELECTORS,
|
|
4352
5604
|
EditorController,
|
|
4353
5605
|
FontSize,
|
|
4354
5606
|
FormulaEvaluator,
|
|
@@ -4359,23 +5611,44 @@ function createHistoryManager(options = {}) {
|
|
|
4359
5611
|
Image,
|
|
4360
5612
|
LoadingNode,
|
|
4361
5613
|
MARKDOWN_MENTION_SPLIT_REGEX,
|
|
5614
|
+
MCP_TOOL_EDIT_CANVAS,
|
|
5615
|
+
MCP_TOOL_EDIT_PROMPT,
|
|
5616
|
+
MCP_TOOL_GET_EDITOR_STATE,
|
|
5617
|
+
MCP_TOOL_VIEW_EDITOR,
|
|
4362
5618
|
MENTION_REGEX,
|
|
5619
|
+
ManualClock,
|
|
4363
5620
|
Markdown,
|
|
4364
5621
|
Mention,
|
|
4365
5622
|
SlashCommands,
|
|
4366
5623
|
SmilieReplacer,
|
|
4367
5624
|
SpreadsheetController,
|
|
5625
|
+
StreamingLayoutManager,
|
|
4368
5626
|
TEMPLATE_REGEX,
|
|
4369
5627
|
TemplateSuggestions,
|
|
4370
5628
|
VARIABLE_REGEX,
|
|
5629
|
+
blendLayout,
|
|
5630
|
+
boundsOf,
|
|
5631
|
+
calculateDagreReflowDisplacement,
|
|
5632
|
+
calculateDirectionalDisplacement,
|
|
5633
|
+
canvasHeight,
|
|
5634
|
+
centerNodes,
|
|
5635
|
+
centre,
|
|
4371
5636
|
colNameToIndex,
|
|
5637
|
+
computeNodesBoundingBox,
|
|
5638
|
+
connectedOnly,
|
|
5639
|
+
createBezierTrajectory,
|
|
4372
5640
|
createDirtyTracker,
|
|
4373
5641
|
createEditor,
|
|
5642
|
+
createFanOutTrajectory,
|
|
4374
5643
|
createHistoryManager,
|
|
4375
5644
|
createMentionExtension,
|
|
4376
5645
|
createRichTextPreset,
|
|
5646
|
+
defaultEasing,
|
|
4377
5647
|
defaultIsEqual,
|
|
5648
|
+
ensureLayout,
|
|
4378
5649
|
escapeHtml,
|
|
5650
|
+
estimateCanvasHeight,
|
|
5651
|
+
estimateNodeSize,
|
|
4379
5652
|
extractCellDependencies,
|
|
4380
5653
|
extractInstructionNames,
|
|
4381
5654
|
extractMentions,
|
|
@@ -4383,29 +5656,48 @@ function createHistoryManager(options = {}) {
|
|
|
4383
5656
|
extractTemplateNames,
|
|
4384
5657
|
extractVariableNames,
|
|
4385
5658
|
findHexColors,
|
|
5659
|
+
flowSide,
|
|
5660
|
+
getCenteredNodePosition,
|
|
4386
5661
|
getEditorMarkdown,
|
|
4387
5662
|
getEditorText,
|
|
4388
5663
|
getLatestVersion,
|
|
5664
|
+
getLayoutedNodes,
|
|
4389
5665
|
handleImageInsertion,
|
|
4390
5666
|
htmlToPlainText,
|
|
4391
5667
|
imagePastePluginKey,
|
|
4392
5668
|
indexToColName,
|
|
4393
5669
|
insertImageNode,
|
|
4394
5670
|
instructionRegex,
|
|
5671
|
+
isEventFromTextInput,
|
|
5672
|
+
isValidCanvasNode,
|
|
5673
|
+
isValidUrl,
|
|
5674
|
+
layoutBounds,
|
|
5675
|
+
linearPositionTrajectory,
|
|
5676
|
+
linearTrajectory,
|
|
4395
5677
|
mapRawOffsetToResolved,
|
|
4396
5678
|
mapResolvedOffsetToRaw,
|
|
4397
5679
|
markdownToTipTapHtml,
|
|
5680
|
+
overlaps,
|
|
5681
|
+
pageHidden,
|
|
5682
|
+
parseCanvasClipboardData,
|
|
4398
5683
|
parseCellReference,
|
|
4399
5684
|
parseFormula,
|
|
4400
5685
|
parseMentionSegments,
|
|
4401
5686
|
parseRange,
|
|
5687
|
+
placeBeside,
|
|
4402
5688
|
plainTextToTipTapHtml,
|
|
5689
|
+
planAgentCommand,
|
|
4403
5690
|
preprocessMarkdownFileLinks,
|
|
4404
5691
|
preprocessMarkdownMentions,
|
|
5692
|
+
realClock,
|
|
5693
|
+
remapPastedNodes,
|
|
4405
5694
|
removeImageNode,
|
|
5695
|
+
repositionNodesTo,
|
|
4406
5696
|
resolveTemplates,
|
|
4407
5697
|
resolveTemplatesWithMapping,
|
|
4408
5698
|
resolveVariables,
|
|
5699
|
+
runMultiNodeTransition,
|
|
5700
|
+
serializeCanvasNodes,
|
|
4409
5701
|
stripMarkdownCode,
|
|
4410
5702
|
templateRegex,
|
|
4411
5703
|
tokenizeFormula,
|