@pixerate/editor-react 0.5.1 → 0.6.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/canvas/index.cjs +824 -0
- package/dist/canvas/index.cjs.map +1 -0
- package/dist/canvas/index.d.cts +150 -0
- package/dist/canvas/index.d.ts +150 -0
- package/dist/canvas/index.js +810 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/index.cjs +39 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/package.json +20 -2
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/canvas/index.ts
|
|
21
|
+
var canvas_exports = {};
|
|
22
|
+
__export(canvas_exports, {
|
|
23
|
+
AgentPresenceLayer: () => AgentPresenceLayer,
|
|
24
|
+
boundsOf: () => import_canvas6.boundsOf,
|
|
25
|
+
calculateDagreReflowDisplacement: () => import_canvas6.calculateDagreReflowDisplacement,
|
|
26
|
+
calculateDirectionalDisplacement: () => import_canvas6.calculateDirectionalDisplacement,
|
|
27
|
+
centerNodes: () => import_canvas6.centerNodes,
|
|
28
|
+
centre: () => import_canvas6.centre,
|
|
29
|
+
computeNodesBoundingBox: () => import_canvas6.computeNodesBoundingBox,
|
|
30
|
+
createBezierTrajectory: () => import_canvas6.createBezierTrajectory,
|
|
31
|
+
createFanOutTrajectory: () => import_canvas6.createFanOutTrajectory,
|
|
32
|
+
defaultEasing: () => import_canvas6.defaultEasing,
|
|
33
|
+
ensureLayout: () => import_canvas6.ensureLayout,
|
|
34
|
+
estimateNodeSize: () => import_canvas6.estimateNodeSize,
|
|
35
|
+
flowSide: () => import_canvas6.flowSide,
|
|
36
|
+
getCenteredNodePosition: () => import_canvas6.getCenteredNodePosition,
|
|
37
|
+
getLayoutedNodes: () => import_canvas6.getLayoutedNodes,
|
|
38
|
+
isEventFromTextInput: () => import_canvas6.isEventFromTextInput,
|
|
39
|
+
isValidCanvasNode: () => import_canvas6.isValidCanvasNode,
|
|
40
|
+
isValidUrl: () => import_canvas6.isValidUrl,
|
|
41
|
+
linearPositionTrajectory: () => import_canvas6.linearPositionTrajectory,
|
|
42
|
+
linearTrajectory: () => import_canvas6.linearTrajectory,
|
|
43
|
+
overlaps: () => import_canvas6.overlaps,
|
|
44
|
+
parseCanvasClipboardData: () => import_canvas6.parseCanvasClipboardData,
|
|
45
|
+
placeBeside: () => import_canvas6.placeBeside,
|
|
46
|
+
remapPastedNodes: () => import_canvas6.remapPastedNodes,
|
|
47
|
+
repositionNodesTo: () => import_canvas6.repositionNodesTo,
|
|
48
|
+
runMultiNodeTransition: () => import_canvas6.runMultiNodeTransition,
|
|
49
|
+
serializeCanvasNodes: () => import_canvas6.serializeCanvasNodes,
|
|
50
|
+
useCanvasClipboard: () => useCanvasClipboard,
|
|
51
|
+
useCanvasDocking: () => useCanvasDocking,
|
|
52
|
+
useCanvasExplosion: () => useCanvasExplosion,
|
|
53
|
+
useCanvasGraph: () => useCanvasGraph,
|
|
54
|
+
useCanvasLayout: () => useCanvasLayout,
|
|
55
|
+
useCanvasShortcuts: () => useCanvasShortcuts,
|
|
56
|
+
useStreamingCanvas: () => useStreamingCanvas
|
|
57
|
+
});
|
|
58
|
+
module.exports = __toCommonJS(canvas_exports);
|
|
59
|
+
|
|
60
|
+
// src/canvas/AgentPresenceLayer.tsx
|
|
61
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
62
|
+
function AgentPresenceLayer({ presences, className = "" }) {
|
|
63
|
+
if (!presences || presences.length === 0) return null;
|
|
64
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
className: `pixerate-agent-presence-layer pointer-events-none absolute inset-0 z-50 overflow-hidden ${className}`,
|
|
68
|
+
"aria-hidden": "true",
|
|
69
|
+
children: presences.map((agent) => {
|
|
70
|
+
if (!agent.cursorPosition) return null;
|
|
71
|
+
const { x, y } = agent.cursorPosition;
|
|
72
|
+
const color = agent.color || "#3b82f6";
|
|
73
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
className: "absolute transition-transform duration-75 ease-out",
|
|
77
|
+
style: {
|
|
78
|
+
transform: `translate3d(${x}px, ${y}px, 0)`
|
|
79
|
+
},
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
82
|
+
"svg",
|
|
83
|
+
{
|
|
84
|
+
className: "h-5 w-5 drop-shadow-md",
|
|
85
|
+
viewBox: "0 0 24 24",
|
|
86
|
+
fill: "none",
|
|
87
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
88
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
89
|
+
"path",
|
|
90
|
+
{
|
|
91
|
+
d: "M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z",
|
|
92
|
+
fill: color,
|
|
93
|
+
stroke: "white",
|
|
94
|
+
strokeWidth: "1"
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
className: "mt-1 flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium text-white shadow-md whitespace-nowrap",
|
|
103
|
+
style: { backgroundColor: color },
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: agent.name }),
|
|
106
|
+
agent.statusMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "opacity-80 text-[10px]", children: [
|
|
107
|
+
"(",
|
|
108
|
+
agent.statusMessage,
|
|
109
|
+
")"
|
|
110
|
+
] })
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
agent.agentId
|
|
117
|
+
);
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/canvas/useStreamingCanvas.ts
|
|
124
|
+
var import_react = require("react");
|
|
125
|
+
var import_canvas = require("@pixerate/editor/canvas");
|
|
126
|
+
function useStreamingCanvas(options) {
|
|
127
|
+
const managerRef = (0, import_react.useRef)(null);
|
|
128
|
+
(0, import_react.useEffect)(() => {
|
|
129
|
+
const manager = new import_canvas.StreamingLayoutManager({
|
|
130
|
+
throttleMs: options.throttleMs,
|
|
131
|
+
glideDurationMs: options.glideDurationMs,
|
|
132
|
+
layoutOptions: options.layoutOptions,
|
|
133
|
+
onLayoutUpdated: options.onPositionsChange
|
|
134
|
+
});
|
|
135
|
+
managerRef.current = manager;
|
|
136
|
+
return () => {
|
|
137
|
+
manager.destroy();
|
|
138
|
+
managerRef.current = null;
|
|
139
|
+
};
|
|
140
|
+
}, [options.throttleMs, options.glideDurationMs, options.onPositionsChange]);
|
|
141
|
+
const pushStreamUpdate = (0, import_react.useCallback)(
|
|
142
|
+
(nodes, edges, currentPositions) => {
|
|
143
|
+
managerRef.current?.pushStreamUpdate(nodes, edges, currentPositions);
|
|
144
|
+
},
|
|
145
|
+
[]
|
|
146
|
+
);
|
|
147
|
+
const flush = (0, import_react.useCallback)(
|
|
148
|
+
(nodes, edges, currentPositions) => {
|
|
149
|
+
managerRef.current?.flush(nodes, edges, currentPositions);
|
|
150
|
+
},
|
|
151
|
+
[]
|
|
152
|
+
);
|
|
153
|
+
return {
|
|
154
|
+
pushStreamUpdate,
|
|
155
|
+
flush
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/canvas/useCanvasGraph.ts
|
|
160
|
+
var import_react2 = require("react");
|
|
161
|
+
function useCanvasGraph(options = {}) {
|
|
162
|
+
const [nodes, setNodesState] = (0, import_react2.useState)(options.initialNodes ?? []);
|
|
163
|
+
const [edges, setEdgesState] = (0, import_react2.useState)(options.initialEdges ?? []);
|
|
164
|
+
const baselineNodesRef = (0, import_react2.useRef)(options.initialNodes ?? []);
|
|
165
|
+
const baselineEdgesRef = (0, import_react2.useRef)(options.initialEdges ?? []);
|
|
166
|
+
const setNodes = (0, import_react2.useCallback)(
|
|
167
|
+
(updater) => {
|
|
168
|
+
setNodesState((prev) => {
|
|
169
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
170
|
+
options.onNodesChange?.(next);
|
|
171
|
+
return next;
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
[options.onNodesChange]
|
|
175
|
+
);
|
|
176
|
+
const setEdges = (0, import_react2.useCallback)(
|
|
177
|
+
(updater) => {
|
|
178
|
+
setEdgesState((prev) => {
|
|
179
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
180
|
+
options.onEdgesChange?.(next);
|
|
181
|
+
return next;
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
[options.onEdgesChange]
|
|
185
|
+
);
|
|
186
|
+
const addNode = (0, import_react2.useCallback)(
|
|
187
|
+
(node) => {
|
|
188
|
+
setNodes((prev) => [...prev, node]);
|
|
189
|
+
},
|
|
190
|
+
[setNodes]
|
|
191
|
+
);
|
|
192
|
+
const removeNodes = (0, import_react2.useCallback)(
|
|
193
|
+
(ids) => {
|
|
194
|
+
const idSet = new Set(ids);
|
|
195
|
+
setNodes((prev) => prev.filter((n) => !idSet.has(n.id)));
|
|
196
|
+
setEdges((prev) => prev.filter((e) => !idSet.has(e.source) && !idSet.has(e.target)));
|
|
197
|
+
},
|
|
198
|
+
[setNodes, setEdges]
|
|
199
|
+
);
|
|
200
|
+
const updateNodeData = (0, import_react2.useCallback)(
|
|
201
|
+
(id, patch) => {
|
|
202
|
+
setNodes(
|
|
203
|
+
(prev) => prev.map((node) => {
|
|
204
|
+
if (node.id !== id) return node;
|
|
205
|
+
return {
|
|
206
|
+
...node,
|
|
207
|
+
data: { ...node.data, ...patch }
|
|
208
|
+
};
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
[setNodes]
|
|
213
|
+
);
|
|
214
|
+
const updateNodePosition = (0, import_react2.useCallback)(
|
|
215
|
+
(id, position) => {
|
|
216
|
+
setNodes(
|
|
217
|
+
(prev) => prev.map((node) => {
|
|
218
|
+
if (node.id !== id) return node;
|
|
219
|
+
return {
|
|
220
|
+
...node,
|
|
221
|
+
position: { ...position }
|
|
222
|
+
};
|
|
223
|
+
})
|
|
224
|
+
);
|
|
225
|
+
},
|
|
226
|
+
[setNodes]
|
|
227
|
+
);
|
|
228
|
+
const addEdge = (0, import_react2.useCallback)(
|
|
229
|
+
(edge) => {
|
|
230
|
+
setEdges((prev) => [...prev, edge]);
|
|
231
|
+
},
|
|
232
|
+
[setEdges]
|
|
233
|
+
);
|
|
234
|
+
const removeEdges = (0, import_react2.useCallback)(
|
|
235
|
+
(ids) => {
|
|
236
|
+
const idSet = new Set(ids);
|
|
237
|
+
setEdges((prev) => prev.filter((e) => !idSet.has(e.id)));
|
|
238
|
+
},
|
|
239
|
+
[setEdges]
|
|
240
|
+
);
|
|
241
|
+
const resetBaseline = (0, import_react2.useCallback)(() => {
|
|
242
|
+
baselineNodesRef.current = nodes;
|
|
243
|
+
baselineEdgesRef.current = edges;
|
|
244
|
+
}, [nodes, edges]);
|
|
245
|
+
const getDifferences = (0, import_react2.useCallback)(() => {
|
|
246
|
+
const currentNodesMap = new Map(nodes.map((n) => [n.id, n]));
|
|
247
|
+
const currentEdgesMap = new Map(edges.map((e) => [e.id, e]));
|
|
248
|
+
const baselineNodesMap = new Map(baselineNodesRef.current.map((n) => [n.id, n]));
|
|
249
|
+
const baselineEdgesMap = new Map(baselineEdgesRef.current.map((e) => [e.id, e]));
|
|
250
|
+
const changedNodes = [];
|
|
251
|
+
const removedNodes = [];
|
|
252
|
+
const changedEdges = [];
|
|
253
|
+
const removedEdges = [];
|
|
254
|
+
for (const [id, node] of currentNodesMap) {
|
|
255
|
+
const base = baselineNodesMap.get(id);
|
|
256
|
+
if (!base || base.position.x !== node.position.x || base.position.y !== node.position.y) {
|
|
257
|
+
changedNodes.push(node);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (const [id, node] of baselineNodesMap) {
|
|
261
|
+
if (!currentNodesMap.has(id)) {
|
|
262
|
+
removedNodes.push(node);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
for (const [id, edge] of currentEdgesMap) {
|
|
266
|
+
const base = baselineEdgesMap.get(id);
|
|
267
|
+
if (!base || base.source !== edge.source || base.target !== edge.target) {
|
|
268
|
+
changedEdges.push(edge);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
for (const [id, edge] of baselineEdgesMap) {
|
|
272
|
+
if (!currentEdgesMap.has(id)) {
|
|
273
|
+
removedEdges.push(edge);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { changedNodes, changedEdges, removedNodes, removedEdges };
|
|
277
|
+
}, [nodes, edges]);
|
|
278
|
+
return {
|
|
279
|
+
nodes,
|
|
280
|
+
edges,
|
|
281
|
+
setNodes,
|
|
282
|
+
setEdges,
|
|
283
|
+
addNode,
|
|
284
|
+
removeNodes,
|
|
285
|
+
updateNodeData,
|
|
286
|
+
updateNodePosition,
|
|
287
|
+
addEdge,
|
|
288
|
+
removeEdges,
|
|
289
|
+
resetBaseline,
|
|
290
|
+
getDifferences
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// src/canvas/useCanvasLayout.ts
|
|
295
|
+
var import_react3 = require("react");
|
|
296
|
+
var import_canvas2 = require("@pixerate/editor/canvas");
|
|
297
|
+
function useCanvasLayout(options) {
|
|
298
|
+
const { nodes, edges, setNodes, getNodesBounds, screenToFlowPosition } = options;
|
|
299
|
+
const applyLayout = (0, import_react3.useCallback)(
|
|
300
|
+
(layoutOptions = {}) => {
|
|
301
|
+
const layouted = (0, import_canvas2.getLayoutedNodes)(nodes, edges, getNodesBounds, layoutOptions);
|
|
302
|
+
setNodes(layouted);
|
|
303
|
+
return layouted;
|
|
304
|
+
},
|
|
305
|
+
[nodes, edges, getNodesBounds, setNodes]
|
|
306
|
+
);
|
|
307
|
+
const applyIncrementalLayout = (0, import_react3.useCallback)(
|
|
308
|
+
(incrementalOptions = {}) => {
|
|
309
|
+
const storedPositions = incrementalOptions.storedPositions ?? Object.fromEntries(nodes.map((n) => [n.id, n.position]));
|
|
310
|
+
const blended = (0, import_canvas2.ensureLayout)(nodes, edges, {
|
|
311
|
+
...incrementalOptions,
|
|
312
|
+
storedPositions
|
|
313
|
+
});
|
|
314
|
+
setNodes(blended);
|
|
315
|
+
return blended;
|
|
316
|
+
},
|
|
317
|
+
[nodes, edges, setNodes]
|
|
318
|
+
);
|
|
319
|
+
const center = (0, import_react3.useCallback)(
|
|
320
|
+
(screenDimensions) => {
|
|
321
|
+
if (!screenToFlowPosition || !getNodesBounds) {
|
|
322
|
+
console.warn(
|
|
323
|
+
"[useCanvasLayout] Centering requires screenToFlowPosition and getNodesBounds options."
|
|
324
|
+
);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const centered = (0, import_canvas2.centerNodes)(nodes, screenToFlowPosition, getNodesBounds, screenDimensions);
|
|
328
|
+
setNodes(centered);
|
|
329
|
+
},
|
|
330
|
+
[nodes, screenToFlowPosition, getNodesBounds, setNodes]
|
|
331
|
+
);
|
|
332
|
+
const getPlacementPosition = (0, import_react3.useCallback)(
|
|
333
|
+
(size, side = "right", nearNodeId, placementOptions = {}) => {
|
|
334
|
+
const rects = {};
|
|
335
|
+
for (const node of nodes) {
|
|
336
|
+
const width = node.measured?.width ?? node.width ?? 200;
|
|
337
|
+
const height = node.measured?.height ?? node.height ?? 60;
|
|
338
|
+
rects[node.id] = {
|
|
339
|
+
x: node.position.x,
|
|
340
|
+
y: node.position.y,
|
|
341
|
+
width,
|
|
342
|
+
height
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return (0, import_canvas2.placeBeside)(rects, size, side, nearNodeId, placementOptions);
|
|
346
|
+
},
|
|
347
|
+
[nodes]
|
|
348
|
+
);
|
|
349
|
+
return {
|
|
350
|
+
applyLayout,
|
|
351
|
+
applyIncrementalLayout,
|
|
352
|
+
center,
|
|
353
|
+
getPlacementPosition,
|
|
354
|
+
getCenteredNodePosition: import_canvas2.getCenteredNodePosition
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/canvas/useCanvasClipboard.ts
|
|
359
|
+
var import_react4 = require("react");
|
|
360
|
+
var import_canvas3 = require("@pixerate/editor/canvas");
|
|
361
|
+
function useCanvasClipboard(options = {}) {
|
|
362
|
+
const copySelectedNodes = (0, import_react4.useCallback)(
|
|
363
|
+
(selectedNodes, connectedEdges, event) => {
|
|
364
|
+
const native = event && "nativeEvent" in event ? event.nativeEvent : event;
|
|
365
|
+
if (native && (0, import_canvas3.isEventFromTextInput)(native)) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
if (selectedNodes.length === 0) return false;
|
|
369
|
+
const serialized = (0, import_canvas3.serializeCanvasNodes)(selectedNodes, connectedEdges);
|
|
370
|
+
const clipboardData = event?.clipboardData || native?.clipboardData;
|
|
371
|
+
if (clipboardData) {
|
|
372
|
+
clipboardData.setData("application/json", serialized);
|
|
373
|
+
clipboardData.setData("text/plain", serialized);
|
|
374
|
+
event?.preventDefault?.();
|
|
375
|
+
} else if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
376
|
+
navigator.clipboard.writeText(serialized).catch(() => {
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return true;
|
|
380
|
+
},
|
|
381
|
+
[]
|
|
382
|
+
);
|
|
383
|
+
const handlePasteEvent = (0, import_react4.useCallback)(
|
|
384
|
+
async (event) => {
|
|
385
|
+
const native = "nativeEvent" in event ? event.nativeEvent : event;
|
|
386
|
+
if ((0, import_canvas3.isEventFromTextInput)(native)) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
const clipboardData = native?.clipboardData || event?.clipboardData;
|
|
390
|
+
if (!clipboardData) return false;
|
|
391
|
+
const prevent = () => {
|
|
392
|
+
event?.preventDefault?.();
|
|
393
|
+
native?.preventDefault?.();
|
|
394
|
+
};
|
|
395
|
+
const jsonText = clipboardData.getData("application/json");
|
|
396
|
+
if (jsonText) {
|
|
397
|
+
const parsed = (0, import_canvas3.parseCanvasClipboardData)(jsonText);
|
|
398
|
+
if (parsed && parsed.nodes.length > 0) {
|
|
399
|
+
prevent();
|
|
400
|
+
const remapped = (0, import_canvas3.remapPastedNodes)(parsed.nodes, parsed.edges);
|
|
401
|
+
await options.onPasteNodes?.(remapped.nodes, remapped.edges);
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const text = clipboardData.getData("text/plain")?.trim();
|
|
406
|
+
if (text) {
|
|
407
|
+
const parsed = (0, import_canvas3.parseCanvasClipboardData)(text);
|
|
408
|
+
if (parsed && parsed.nodes.length > 0) {
|
|
409
|
+
prevent();
|
|
410
|
+
const remapped = (0, import_canvas3.remapPastedNodes)(parsed.nodes, parsed.edges);
|
|
411
|
+
await options.onPasteNodes?.(remapped.nodes, remapped.edges);
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
if ((0, import_canvas3.isValidUrl)(text)) {
|
|
415
|
+
prevent();
|
|
416
|
+
options.onPasteUrl?.(text);
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
if (options.onPasteText) {
|
|
420
|
+
prevent();
|
|
421
|
+
options.onPasteText(text);
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return false;
|
|
426
|
+
},
|
|
427
|
+
[options]
|
|
428
|
+
);
|
|
429
|
+
return {
|
|
430
|
+
copySelectedNodes,
|
|
431
|
+
handlePasteEvent
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/canvas/useCanvasShortcuts.ts
|
|
436
|
+
var import_react5 = require("react");
|
|
437
|
+
var import_canvas4 = require("@pixerate/editor/canvas");
|
|
438
|
+
function useCanvasShortcuts(options = {}) {
|
|
439
|
+
const {
|
|
440
|
+
targetElement,
|
|
441
|
+
enabled = true,
|
|
442
|
+
onCopy,
|
|
443
|
+
onCut,
|
|
444
|
+
onPaste,
|
|
445
|
+
onDelete,
|
|
446
|
+
onDuplicate,
|
|
447
|
+
onSelectAll,
|
|
448
|
+
onGroup,
|
|
449
|
+
onUngroup,
|
|
450
|
+
onZoomIn,
|
|
451
|
+
onZoomOut,
|
|
452
|
+
onFitView,
|
|
453
|
+
getSelectedNodes
|
|
454
|
+
} = options;
|
|
455
|
+
(0, import_react5.useEffect)(() => {
|
|
456
|
+
if (!enabled) return;
|
|
457
|
+
const target = targetElement ?? (typeof window !== "undefined" ? window : null);
|
|
458
|
+
if (!target) return;
|
|
459
|
+
function handleKeyDown(event) {
|
|
460
|
+
const keyboardEvent = event;
|
|
461
|
+
if ((0, import_canvas4.isEventFromTextInput)(keyboardEvent)) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
465
|
+
const isMod = isMac ? keyboardEvent.metaKey : keyboardEvent.ctrlKey;
|
|
466
|
+
const key = keyboardEvent.key.toLowerCase();
|
|
467
|
+
const selectedNodes = getSelectedNodes ? getSelectedNodes() : [];
|
|
468
|
+
if ((keyboardEvent.key === "Backspace" || keyboardEvent.key === "Delete") && !isMod) {
|
|
469
|
+
if (selectedNodes.length > 0 && onDelete) {
|
|
470
|
+
keyboardEvent.preventDefault();
|
|
471
|
+
onDelete(selectedNodes);
|
|
472
|
+
}
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (isMod && key === "d") {
|
|
476
|
+
if (selectedNodes.length > 0 && onDuplicate) {
|
|
477
|
+
keyboardEvent.preventDefault();
|
|
478
|
+
onDuplicate(selectedNodes);
|
|
479
|
+
}
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (isMod && key === "a" && onSelectAll) {
|
|
483
|
+
keyboardEvent.preventDefault();
|
|
484
|
+
onSelectAll();
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (isMod && key === "g" && !keyboardEvent.shiftKey && onGroup) {
|
|
488
|
+
if (selectedNodes.length > 0) {
|
|
489
|
+
keyboardEvent.preventDefault();
|
|
490
|
+
onGroup(selectedNodes);
|
|
491
|
+
}
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (isMod && key === "g" && keyboardEvent.shiftKey && onUngroup) {
|
|
495
|
+
if (selectedNodes.length > 0) {
|
|
496
|
+
keyboardEvent.preventDefault();
|
|
497
|
+
onUngroup(selectedNodes);
|
|
498
|
+
}
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (isMod && (key === "+" || key === "=") && onZoomIn) {
|
|
502
|
+
keyboardEvent.preventDefault();
|
|
503
|
+
onZoomIn();
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (isMod && key === "-" && onZoomOut) {
|
|
507
|
+
keyboardEvent.preventDefault();
|
|
508
|
+
onZoomOut();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (isMod && key === "0" && onFitView) {
|
|
512
|
+
keyboardEvent.preventDefault();
|
|
513
|
+
onFitView();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
target.addEventListener("keydown", handleKeyDown);
|
|
518
|
+
return () => {
|
|
519
|
+
target.removeEventListener("keydown", handleKeyDown);
|
|
520
|
+
};
|
|
521
|
+
}, [
|
|
522
|
+
targetElement,
|
|
523
|
+
enabled,
|
|
524
|
+
onCopy,
|
|
525
|
+
onCut,
|
|
526
|
+
onPaste,
|
|
527
|
+
onDelete,
|
|
528
|
+
onDuplicate,
|
|
529
|
+
onSelectAll,
|
|
530
|
+
onGroup,
|
|
531
|
+
onUngroup,
|
|
532
|
+
onZoomIn,
|
|
533
|
+
onZoomOut,
|
|
534
|
+
onFitView,
|
|
535
|
+
getSelectedNodes
|
|
536
|
+
]);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/canvas/useCanvasDocking.ts
|
|
540
|
+
var import_react6 = require("react");
|
|
541
|
+
function useCanvasDocking(options = {}) {
|
|
542
|
+
const {
|
|
543
|
+
strategy = "center-point",
|
|
544
|
+
dockableTypes,
|
|
545
|
+
targetTypes,
|
|
546
|
+
onDockHover,
|
|
547
|
+
onDockLeave,
|
|
548
|
+
onDockDrop
|
|
549
|
+
} = options;
|
|
550
|
+
const activeDockTargetRef = (0, import_react6.useRef)(null);
|
|
551
|
+
const isDockable = (0, import_react6.useCallback)(
|
|
552
|
+
(node) => {
|
|
553
|
+
if (!dockableTypes || dockableTypes.length === 0) return true;
|
|
554
|
+
return !!node.type && dockableTypes.includes(node.type);
|
|
555
|
+
},
|
|
556
|
+
[dockableTypes]
|
|
557
|
+
);
|
|
558
|
+
const isTarget = (0, import_react6.useCallback)(
|
|
559
|
+
(node) => {
|
|
560
|
+
if (!targetTypes || targetTypes.length === 0) return true;
|
|
561
|
+
return !!node.type && targetTypes.includes(node.type);
|
|
562
|
+
},
|
|
563
|
+
[targetTypes]
|
|
564
|
+
);
|
|
565
|
+
const findDockTarget = (0, import_react6.useCallback)(
|
|
566
|
+
(draggedNode, candidates, cursorPos) => {
|
|
567
|
+
if (!isDockable(draggedNode)) return null;
|
|
568
|
+
const draggedWidth = draggedNode.measured?.width ?? draggedNode.width ?? 200;
|
|
569
|
+
const draggedHeight = draggedNode.measured?.height ?? draggedNode.height ?? 60;
|
|
570
|
+
const draggedCenter = {
|
|
571
|
+
x: draggedNode.position.x + draggedWidth / 2,
|
|
572
|
+
y: draggedNode.position.y + draggedHeight / 2
|
|
573
|
+
};
|
|
574
|
+
const validCandidates = candidates.filter(
|
|
575
|
+
(c) => c.id !== draggedNode.id && isTarget(c)
|
|
576
|
+
);
|
|
577
|
+
let bestTarget = null;
|
|
578
|
+
let maxIntersectionArea = 0;
|
|
579
|
+
let minDistance = Infinity;
|
|
580
|
+
for (const candidate of validCandidates) {
|
|
581
|
+
const candWidth = candidate.measured?.width ?? candidate.width ?? 200;
|
|
582
|
+
const candHeight = candidate.measured?.height ?? candidate.height ?? 60;
|
|
583
|
+
const candRect = {
|
|
584
|
+
x: candidate.position.x,
|
|
585
|
+
y: candidate.position.y,
|
|
586
|
+
width: candWidth,
|
|
587
|
+
height: candHeight
|
|
588
|
+
};
|
|
589
|
+
const overlapX = Math.max(
|
|
590
|
+
0,
|
|
591
|
+
Math.min(draggedNode.position.x + draggedWidth, candRect.x + candRect.width) - Math.max(draggedNode.position.x, candRect.x)
|
|
592
|
+
);
|
|
593
|
+
const overlapY = Math.max(
|
|
594
|
+
0,
|
|
595
|
+
Math.min(draggedNode.position.y + draggedHeight, candRect.y + candRect.height) - Math.max(draggedNode.position.y, candRect.y)
|
|
596
|
+
);
|
|
597
|
+
const overlapArea = overlapX * overlapY;
|
|
598
|
+
if (strategy === "max-overlap") {
|
|
599
|
+
if (overlapArea > maxIntersectionArea) {
|
|
600
|
+
maxIntersectionArea = overlapArea;
|
|
601
|
+
bestTarget = candidate;
|
|
602
|
+
}
|
|
603
|
+
} else if (strategy === "center-point") {
|
|
604
|
+
const candCenter = {
|
|
605
|
+
x: candRect.x + candRect.width / 2,
|
|
606
|
+
y: candRect.y + candRect.height / 2
|
|
607
|
+
};
|
|
608
|
+
const dist = Math.hypot(
|
|
609
|
+
draggedCenter.x - candCenter.x,
|
|
610
|
+
draggedCenter.y - candCenter.y
|
|
611
|
+
);
|
|
612
|
+
if (overlapArea > 0 && dist < minDistance) {
|
|
613
|
+
minDistance = dist;
|
|
614
|
+
bestTarget = candidate;
|
|
615
|
+
}
|
|
616
|
+
} else if (strategy === "first") {
|
|
617
|
+
if (overlapArea > 0) return candidate;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return bestTarget;
|
|
621
|
+
},
|
|
622
|
+
[isDockable, isTarget, strategy]
|
|
623
|
+
);
|
|
624
|
+
const updateDragOver = (0, import_react6.useCallback)(
|
|
625
|
+
(draggedNode, candidates, cursorPos) => {
|
|
626
|
+
const target = findDockTarget(draggedNode, candidates, cursorPos);
|
|
627
|
+
if (target?.id !== activeDockTargetRef.current?.id) {
|
|
628
|
+
if (activeDockTargetRef.current) {
|
|
629
|
+
onDockLeave?.(activeDockTargetRef.current, draggedNode);
|
|
630
|
+
}
|
|
631
|
+
activeDockTargetRef.current = target;
|
|
632
|
+
if (target) {
|
|
633
|
+
onDockHover?.(target, draggedNode);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
[findDockTarget, onDockHover, onDockLeave]
|
|
638
|
+
);
|
|
639
|
+
const finalizeDock = (0, import_react6.useCallback)(
|
|
640
|
+
(draggedNode) => {
|
|
641
|
+
if (activeDockTargetRef.current) {
|
|
642
|
+
onDockDrop?.(activeDockTargetRef.current, draggedNode);
|
|
643
|
+
activeDockTargetRef.current = null;
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
[onDockDrop]
|
|
647
|
+
);
|
|
648
|
+
return {
|
|
649
|
+
findDockTarget,
|
|
650
|
+
updateDragOver,
|
|
651
|
+
finalizeDock,
|
|
652
|
+
getActiveDockTarget: () => activeDockTargetRef.current
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// src/canvas/useCanvasExplosion.ts
|
|
657
|
+
var import_react7 = require("react");
|
|
658
|
+
var import_canvas5 = require("@pixerate/editor/canvas");
|
|
659
|
+
function useCanvasExplosion(target) {
|
|
660
|
+
const snapshotsRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
|
|
661
|
+
const explodeNode = (0, import_react7.useCallback)(
|
|
662
|
+
(parentNodeId, options) => {
|
|
663
|
+
const { nodes, edges, setNodes, setEdges } = target;
|
|
664
|
+
const parent = nodes.find((n) => n.id === parentNodeId);
|
|
665
|
+
if (!parent || options.childNodes.length === 0) return;
|
|
666
|
+
const originPos = { ...parent.position };
|
|
667
|
+
const displacedMap = options.displacementStrategy === "directional" ? (0, import_canvas5.calculateDirectionalDisplacement)({
|
|
668
|
+
existingNodes: nodes,
|
|
669
|
+
originNode: parent,
|
|
670
|
+
childNodes: options.childNodes,
|
|
671
|
+
options: options.directionalOptions
|
|
672
|
+
}) : /* @__PURE__ */ new Map();
|
|
673
|
+
const snapshot = {
|
|
674
|
+
parentId: parentNodeId,
|
|
675
|
+
childNodeIds: options.childNodes.map((c) => c.id),
|
|
676
|
+
childEdgeIds: (options.childEdges ?? []).map((e) => e.id),
|
|
677
|
+
displacedNodes: Array.from(displacedMap.entries()).map(([id]) => {
|
|
678
|
+
const node = nodes.find((n) => n.id === id);
|
|
679
|
+
return { id, originalPosition: { ...node.position } };
|
|
680
|
+
}),
|
|
681
|
+
timestamp: Date.now()
|
|
682
|
+
};
|
|
683
|
+
snapshotsRef.current.set(parentNodeId, snapshot);
|
|
684
|
+
const initialChildren = options.childNodes.map((child) => ({
|
|
685
|
+
...child,
|
|
686
|
+
position: { ...originPos }
|
|
687
|
+
}));
|
|
688
|
+
const mergedNodes = [...nodes, ...initialChildren];
|
|
689
|
+
setNodes(mergedNodes);
|
|
690
|
+
if (options.childEdges && options.childEdges.length > 0) {
|
|
691
|
+
setEdges((prev) => [...prev, ...options.childEdges]);
|
|
692
|
+
}
|
|
693
|
+
const trajectory = options.trajectory ?? (0, import_canvas5.createFanOutTrajectory)();
|
|
694
|
+
const transitions = [];
|
|
695
|
+
options.childNodes.forEach((child, index) => {
|
|
696
|
+
const liveChild = mergedNodes.find((n) => n.id === child.id);
|
|
697
|
+
if (liveChild) {
|
|
698
|
+
transitions.push({
|
|
699
|
+
node: liveChild,
|
|
700
|
+
from: originPos,
|
|
701
|
+
to: child.position,
|
|
702
|
+
trajectory,
|
|
703
|
+
index,
|
|
704
|
+
total: options.childNodes.length,
|
|
705
|
+
duration: options.duration ?? 400,
|
|
706
|
+
easing: options.easing
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
displacedMap.forEach((targetPos, nodeId) => {
|
|
711
|
+
const node = mergedNodes.find((n) => n.id === nodeId);
|
|
712
|
+
if (node) {
|
|
713
|
+
transitions.push({
|
|
714
|
+
node,
|
|
715
|
+
from: { ...node.position },
|
|
716
|
+
to: targetPos,
|
|
717
|
+
trajectory: import_canvas5.linearPositionTrajectory,
|
|
718
|
+
duration: options.duration ?? 400,
|
|
719
|
+
easing: options.easing
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
(0, import_canvas5.runMultiNodeTransition)(transitions, {
|
|
724
|
+
onUpdate: () => setNodes([...mergedNodes]),
|
|
725
|
+
onComplete: options.onComplete
|
|
726
|
+
});
|
|
727
|
+
},
|
|
728
|
+
[target]
|
|
729
|
+
);
|
|
730
|
+
const collapseNode = (0, import_react7.useCallback)(
|
|
731
|
+
(parentNodeId, options = {}) => {
|
|
732
|
+
const { nodes, setNodes, setEdges } = target;
|
|
733
|
+
const snapshot = snapshotsRef.current.get(parentNodeId);
|
|
734
|
+
if (!snapshot) return;
|
|
735
|
+
const parent = nodes.find((n) => n.id === parentNodeId);
|
|
736
|
+
const originPos = parent ? { ...parent.position } : { x: 0, y: 0 };
|
|
737
|
+
const childIdSet = new Set(snapshot.childNodeIds);
|
|
738
|
+
const edgeIdSet = new Set(snapshot.childEdgeIds);
|
|
739
|
+
const transitions = [];
|
|
740
|
+
nodes.forEach((node) => {
|
|
741
|
+
if (childIdSet.has(node.id)) {
|
|
742
|
+
transitions.push({
|
|
743
|
+
node,
|
|
744
|
+
from: { ...node.position },
|
|
745
|
+
to: originPos,
|
|
746
|
+
duration: options.duration ?? 300,
|
|
747
|
+
easing: options.easing,
|
|
748
|
+
trajectory: options.trajectory
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
snapshot.displacedNodes.forEach((disp) => {
|
|
753
|
+
const node = nodes.find((n) => n.id === disp.id);
|
|
754
|
+
if (node) {
|
|
755
|
+
transitions.push({
|
|
756
|
+
node,
|
|
757
|
+
from: { ...node.position },
|
|
758
|
+
to: disp.originalPosition,
|
|
759
|
+
duration: options.duration ?? 300,
|
|
760
|
+
easing: options.easing,
|
|
761
|
+
trajectory: import_canvas5.linearPositionTrajectory
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
(0, import_canvas5.runMultiNodeTransition)(transitions, {
|
|
766
|
+
onUpdate: () => setNodes([...nodes]),
|
|
767
|
+
onComplete: () => {
|
|
768
|
+
setNodes((prev) => prev.filter((n) => !childIdSet.has(n.id)));
|
|
769
|
+
setEdges((prev) => prev.filter((e) => !edgeIdSet.has(e.id)));
|
|
770
|
+
snapshotsRef.current.delete(parentNodeId);
|
|
771
|
+
options.onComplete?.();
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
},
|
|
775
|
+
[target]
|
|
776
|
+
);
|
|
777
|
+
return {
|
|
778
|
+
explodeNode,
|
|
779
|
+
collapseNode,
|
|
780
|
+
isExploded: (parentNodeId) => snapshotsRef.current.has(parentNodeId),
|
|
781
|
+
getSnapshot: (parentNodeId) => snapshotsRef.current.get(parentNodeId)
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/canvas/index.ts
|
|
786
|
+
var import_canvas6 = require("@pixerate/editor/canvas");
|
|
787
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
788
|
+
0 && (module.exports = {
|
|
789
|
+
AgentPresenceLayer,
|
|
790
|
+
boundsOf,
|
|
791
|
+
calculateDagreReflowDisplacement,
|
|
792
|
+
calculateDirectionalDisplacement,
|
|
793
|
+
centerNodes,
|
|
794
|
+
centre,
|
|
795
|
+
computeNodesBoundingBox,
|
|
796
|
+
createBezierTrajectory,
|
|
797
|
+
createFanOutTrajectory,
|
|
798
|
+
defaultEasing,
|
|
799
|
+
ensureLayout,
|
|
800
|
+
estimateNodeSize,
|
|
801
|
+
flowSide,
|
|
802
|
+
getCenteredNodePosition,
|
|
803
|
+
getLayoutedNodes,
|
|
804
|
+
isEventFromTextInput,
|
|
805
|
+
isValidCanvasNode,
|
|
806
|
+
isValidUrl,
|
|
807
|
+
linearPositionTrajectory,
|
|
808
|
+
linearTrajectory,
|
|
809
|
+
overlaps,
|
|
810
|
+
parseCanvasClipboardData,
|
|
811
|
+
placeBeside,
|
|
812
|
+
remapPastedNodes,
|
|
813
|
+
repositionNodesTo,
|
|
814
|
+
runMultiNodeTransition,
|
|
815
|
+
serializeCanvasNodes,
|
|
816
|
+
useCanvasClipboard,
|
|
817
|
+
useCanvasDocking,
|
|
818
|
+
useCanvasExplosion,
|
|
819
|
+
useCanvasGraph,
|
|
820
|
+
useCanvasLayout,
|
|
821
|
+
useCanvasShortcuts,
|
|
822
|
+
useStreamingCanvas
|
|
823
|
+
});
|
|
824
|
+
//# sourceMappingURL=index.cjs.map
|