@pixerate/editor-svelte 0.15.3 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +83 -0
  2. package/dist/BubbleMenu.svelte.d.ts +14 -0
  3. package/dist/BubbleMenu.svelte.d.ts.map +1 -0
  4. package/{src → dist}/EditableTextNodeEditor.svelte +1 -1
  5. package/dist/EditableTextNodeEditor.svelte.d.ts +26 -0
  6. package/dist/EditableTextNodeEditor.svelte.d.ts.map +1 -0
  7. package/dist/TemplateRenderer.svelte.d.ts +14 -0
  8. package/dist/TemplateRenderer.svelte.d.ts.map +1 -0
  9. package/dist/canvas/AgentPresenceLayer.svelte.d.ts +9 -0
  10. package/dist/canvas/AgentPresenceLayer.svelte.d.ts.map +1 -0
  11. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts +9 -0
  12. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts.map +1 -0
  13. package/dist/canvas/createCanvasClipboard.svelte.d.ts +32 -0
  14. package/dist/canvas/createCanvasClipboard.svelte.d.ts.map +1 -0
  15. package/dist/canvas/createCanvasClipboard.svelte.js +171 -0
  16. package/dist/canvas/createCanvasDisplacement.d.ts +32 -0
  17. package/dist/canvas/createCanvasDisplacement.d.ts.map +1 -0
  18. package/dist/canvas/createCanvasDisplacement.js +170 -0
  19. package/dist/canvas/createCanvasDocking.svelte.d.ts +56 -0
  20. package/dist/canvas/createCanvasDocking.svelte.d.ts.map +1 -0
  21. package/dist/canvas/createCanvasDocking.svelte.js +227 -0
  22. package/dist/canvas/createCanvasExplosion.svelte.d.ts +31 -0
  23. package/dist/canvas/createCanvasExplosion.svelte.d.ts.map +1 -0
  24. package/dist/canvas/createCanvasExplosion.svelte.js +346 -0
  25. package/dist/canvas/createCanvasGraph.svelte.d.ts +62 -0
  26. package/dist/canvas/createCanvasGraph.svelte.d.ts.map +1 -0
  27. package/dist/canvas/createCanvasGraph.svelte.js +223 -0
  28. package/dist/canvas/createCanvasInteractions.svelte.d.ts +28 -0
  29. package/dist/canvas/createCanvasInteractions.svelte.d.ts.map +1 -0
  30. package/dist/canvas/createCanvasInteractions.svelte.js +95 -0
  31. package/dist/canvas/createCanvasLayout.d.ts +22 -0
  32. package/dist/canvas/createCanvasLayout.d.ts.map +1 -0
  33. package/dist/canvas/createCanvasLayout.js +76 -0
  34. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts +61 -0
  35. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts.map +1 -0
  36. package/dist/canvas/createCanvasMultiDrag.svelte.js +105 -0
  37. package/dist/canvas/createCanvasNodeSync.svelte.d.ts +58 -0
  38. package/dist/canvas/createCanvasNodeSync.svelte.d.ts.map +1 -0
  39. package/dist/canvas/createCanvasNodeSync.svelte.js +82 -0
  40. package/dist/canvas/createCanvasSelection.svelte.d.ts +26 -0
  41. package/dist/canvas/createCanvasSelection.svelte.d.ts.map +1 -0
  42. package/dist/canvas/createCanvasSelection.svelte.js +26 -0
  43. package/dist/canvas/createCanvasShortcuts.d.ts +9 -0
  44. package/dist/canvas/createCanvasShortcuts.d.ts.map +1 -0
  45. package/dist/canvas/createCanvasShortcuts.js +97 -0
  46. package/dist/canvas/createCanvasTrajectory.d.ts +31 -0
  47. package/dist/canvas/createCanvasTrajectory.d.ts.map +1 -0
  48. package/dist/canvas/createCanvasTrajectory.js +141 -0
  49. package/dist/canvas/createStreamingCanvas.svelte.d.ts +19 -0
  50. package/dist/canvas/createStreamingCanvas.svelte.d.ts.map +1 -0
  51. package/dist/canvas/createStreamingCanvas.svelte.js +32 -0
  52. package/dist/canvas/index.d.ts +18 -688
  53. package/dist/canvas/index.d.ts.map +1 -0
  54. package/dist/canvas/index.js +34 -1839
  55. package/dist/canvas/types.d.ts +183 -0
  56. package/dist/canvas/types.d.ts.map +1 -0
  57. package/dist/canvas/types.js +1 -0
  58. package/dist/createNavigationGuard.svelte.d.ts +24 -0
  59. package/dist/createNavigationGuard.svelte.d.ts.map +1 -0
  60. package/dist/createNavigationGuard.svelte.js +65 -0
  61. package/dist/editor.svelte.d.ts +23 -0
  62. package/dist/editor.svelte.d.ts.map +1 -0
  63. package/dist/editor.svelte.js +41 -0
  64. package/dist/history/createHistoryShortcuts.d.ts +24 -0
  65. package/dist/history/createHistoryShortcuts.d.ts.map +1 -0
  66. package/dist/history/createHistoryShortcuts.js +57 -0
  67. package/dist/history/history.svelte.d.ts +18 -0
  68. package/dist/history/history.svelte.d.ts.map +1 -0
  69. package/dist/history/history.svelte.js +43 -0
  70. package/dist/history/index.d.ts +3 -0
  71. package/dist/history/index.d.ts.map +1 -0
  72. package/dist/history/index.js +2 -0
  73. package/{src → dist}/image-editor/ImageEditor.svelte +1 -1
  74. package/dist/image-editor/ImageEditor.svelte.d.ts +17 -0
  75. package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -0
  76. package/dist/image-editor/imageEditorState.svelte.d.ts +50 -0
  77. package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -0
  78. package/dist/image-editor/imageEditorState.svelte.js +132 -0
  79. package/dist/image-editor/index.d.ts +6 -16
  80. package/dist/image-editor/index.d.ts.map +1 -0
  81. package/dist/image-editor/index.js +2 -9
  82. package/dist/index.d.ts +20 -249
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +10 -1119
  85. package/dist/navigationGuard.d.ts +21 -0
  86. package/dist/navigationGuard.d.ts.map +1 -0
  87. package/dist/navigationGuard.js +59 -0
  88. package/{src → dist}/spreadsheet/FormulaBar.svelte +1 -1
  89. package/dist/spreadsheet/FormulaBar.svelte.d.ts +17 -0
  90. package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -0
  91. package/{src → dist}/spreadsheet/SpreadsheetEditor.svelte +1 -1
  92. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +22 -0
  93. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -0
  94. package/dist/spreadsheet/index.d.ts +9 -0
  95. package/dist/spreadsheet/index.d.ts.map +1 -0
  96. package/{src/spreadsheet/index.ts → dist/spreadsheet/index.js} +1 -1
  97. package/dist/spreadsheet/spreadsheet.svelte.d.ts +33 -0
  98. package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -0
  99. package/dist/spreadsheet/spreadsheet.svelte.js +160 -0
  100. package/package.json +14 -16
  101. package/dist/canvas/index.js.map +0 -1
  102. package/dist/chunk-HEOI4UNF.js +0 -1191
  103. package/dist/chunk-HEOI4UNF.js.map +0 -1
  104. package/dist/image-editor/index.js.map +0 -1
  105. package/dist/index.css +0 -50
  106. package/dist/index.css.map +0 -1
  107. package/dist/index.js.map +0 -1
  108. package/src/canvas/__tests__/canvas-clipboard.test.ts +0 -154
  109. package/src/canvas/__tests__/canvas-docking.test.ts +0 -288
  110. package/src/canvas/__tests__/canvas-explosion.test.ts +0 -634
  111. package/src/canvas/__tests__/canvas-graph.test.ts +0 -159
  112. package/src/canvas/__tests__/canvas-interactions.test.ts +0 -86
  113. package/src/canvas/__tests__/canvas-layout.test.ts +0 -75
  114. package/src/canvas/__tests__/canvas-multi-drag.test.ts +0 -112
  115. package/src/canvas/__tests__/canvas-node-sync.svelte.test.ts +0 -104
  116. package/src/canvas/__tests__/canvas-shortcuts.test.ts +0 -59
  117. package/src/canvas/createCanvasClipboard.svelte.ts +0 -219
  118. package/src/canvas/createCanvasDisplacement.ts +0 -253
  119. package/src/canvas/createCanvasDocking.svelte.ts +0 -355
  120. package/src/canvas/createCanvasExplosion.svelte.ts +0 -457
  121. package/src/canvas/createCanvasGraph.svelte.ts +0 -330
  122. package/src/canvas/createCanvasInteractions.svelte.ts +0 -112
  123. package/src/canvas/createCanvasLayout.ts +0 -129
  124. package/src/canvas/createCanvasMultiDrag.svelte.ts +0 -175
  125. package/src/canvas/createCanvasNodeSync.svelte.ts +0 -150
  126. package/src/canvas/createCanvasSelection.svelte.ts +0 -51
  127. package/src/canvas/createCanvasShortcuts.ts +0 -99
  128. package/src/canvas/createCanvasTrajectory.ts +0 -207
  129. package/src/canvas/createStreamingCanvas.svelte.ts +0 -56
  130. package/src/canvas/index.d.ts +0 -688
  131. package/src/canvas/index.ts +0 -126
  132. package/src/canvas/types.ts +0 -223
  133. package/src/createNavigationGuard.svelte.ts +0 -97
  134. package/src/editor.svelte.ts +0 -65
  135. package/src/history/createHistoryShortcuts.ts +0 -95
  136. package/src/history/history.svelte.ts +0 -68
  137. package/src/history/index.ts +0 -2
  138. package/src/image-editor/imageEditorState.svelte.ts +0 -151
  139. package/src/image-editor/index.d.ts +0 -16
  140. package/src/image-editor/index.ts +0 -2
  141. package/src/index.d.ts +0 -249
  142. package/src/index.ts +0 -89
  143. package/src/navigationGuard.ts +0 -82
  144. package/src/spreadsheet/spreadsheet.svelte.ts +0 -176
  145. package/src/svelte.d.ts +0 -5
  146. /package/{src → dist}/BubbleMenu.svelte +0 -0
  147. /package/{src → dist}/TemplateRenderer.svelte +0 -0
  148. /package/{src → dist}/canvas/AgentPresenceLayer.svelte +0 -0
  149. /package/{src → dist}/canvas/FloatingHorizontalScrollbar.svelte +0 -0
  150. /package/{src → dist}/canvas/README.md +0 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Headless Svelte 5 rune orchestrating multi-node drag operations with stacked visual fanning,
3
+ * dynamic z-index layering, and position restoration.
4
+ */
5
+ export function createCanvasMultiDrag(options = {}) {
6
+ const stepX = options.stackOffsetStepX ?? 4;
7
+ const stepY = options.stackOffsetStepY ?? 4;
8
+ const angles = options.rotationAngles ?? [-2, 2.5, -3, 3];
9
+ const baseZIndex = options.baseZIndex ?? 50;
10
+ let dragState = $state(null);
11
+ function startMultiDrag(leadNodeId, selectedNodeIds, nodes) {
12
+ const selectedSet = selectedNodeIds instanceof Set ? selectedNodeIds : new Set(selectedNodeIds);
13
+ if (selectedSet.size <= 1 || !selectedSet.has(leadNodeId)) {
14
+ dragState = null;
15
+ return null;
16
+ }
17
+ const nodeMap = nodes instanceof Map ? nodes : new Map(nodes.map((n) => [n.id, n]));
18
+ const leadNode = nodeMap.get(leadNodeId);
19
+ if (!leadNode) {
20
+ dragState = null;
21
+ return null;
22
+ }
23
+ const leadPos = leadNode.position ?? { x: 0, y: 0 };
24
+ const offsets = {};
25
+ let followerIndex = 0;
26
+ for (const id of selectedSet) {
27
+ if (id === leadNodeId)
28
+ continue;
29
+ const follower = nodeMap.get(id);
30
+ const fPos = follower?.position ?? { x: 0, y: 0 };
31
+ const angle = angles[followerIndex % angles.length];
32
+ offsets[id] = {
33
+ deltaX: fPos.x - leadPos.x,
34
+ deltaY: fPos.y - leadPos.y,
35
+ originalPosition: { ...fPos },
36
+ stackOffsetX: (followerIndex + 1) * stepX,
37
+ stackOffsetY: (followerIndex + 1) * stepY,
38
+ rotationDeg: angle
39
+ };
40
+ followerIndex++;
41
+ }
42
+ const state = {
43
+ leadId: leadNodeId,
44
+ offsets,
45
+ count: selectedSet.size
46
+ };
47
+ dragState = state;
48
+ return state;
49
+ }
50
+ function getFollowerTransform(nodeId) {
51
+ if (!dragState || !(nodeId in dragState.offsets)) {
52
+ return {
53
+ isFollower: false,
54
+ stackOffsetX: 0,
55
+ stackOffsetY: 0,
56
+ rotationDeg: 0,
57
+ zIndex: 0
58
+ };
59
+ }
60
+ const offset = dragState.offsets[nodeId];
61
+ const followerKeys = Object.keys(dragState.offsets);
62
+ const index = followerKeys.indexOf(nodeId);
63
+ return {
64
+ isFollower: true,
65
+ stackOffsetX: offset.stackOffsetX,
66
+ stackOffsetY: offset.stackOffsetY,
67
+ rotationDeg: offset.rotationDeg,
68
+ zIndex: baseZIndex - (index + 1)
69
+ };
70
+ }
71
+ function cancelMultiDrag(applyRestore) {
72
+ if (!dragState)
73
+ return [];
74
+ const restores = Object.entries(dragState.offsets).map(([id, offset]) => ({
75
+ id,
76
+ originalPosition: { ...offset.originalPosition }
77
+ }));
78
+ if (applyRestore) {
79
+ applyRestore(restores);
80
+ }
81
+ dragState = null;
82
+ return restores;
83
+ }
84
+ function commitMultiDrag() {
85
+ dragState = null;
86
+ }
87
+ return {
88
+ get dragState() {
89
+ return dragState;
90
+ },
91
+ get isMultiDrag() {
92
+ return Boolean(dragState && dragState.count > 1);
93
+ },
94
+ get count() {
95
+ return dragState ? dragState.count : 0;
96
+ },
97
+ get leadId() {
98
+ return dragState?.leadId ?? null;
99
+ },
100
+ startMultiDrag,
101
+ getFollowerTransform,
102
+ cancelMultiDrag,
103
+ commitMultiDrag
104
+ };
105
+ }
@@ -0,0 +1,58 @@
1
+ import type { Position } from '@xyflow/svelte';
2
+ import type { CanvasNode, CanvasEdge } from './types.js';
3
+ export interface HandleConfig {
4
+ id?: string | null;
5
+ type: 'source' | 'target';
6
+ position: Position;
7
+ x?: number;
8
+ y?: number;
9
+ width?: number;
10
+ height?: number;
11
+ }
12
+ export interface NodeMeasurement {
13
+ width: number;
14
+ height: number;
15
+ }
16
+ /**
17
+ * Preserves cached .measured dimensions from existing nodes to newly constructed nodes.
18
+ * Resolves measurements without subscribing to reactive updates on the existing collection.
19
+ */
20
+ export declare function preserveNodeMeasurements<TNode extends CanvasNode = CanvasNode>(newNodes: TNode[], existingNodes: TNode[] | Map<string, TNode>): TNode[];
21
+ /**
22
+ * Pre-populates handle geometry on a node to prevent @xyflow/system's getNodesInside
23
+ * from evaluating `forceInitialRender = !node.internals.handleBounds` and triggering
24
+ * a false full-canvas selection on the first frame of marquee drag-selection.
25
+ */
26
+ export declare function normalizeNodeHandles<TNode extends CanvasNode = CanvasNode>(node: TNode, handles?: HandleConfig[]): TNode;
27
+ export interface CreateCanvasNodeSyncOptions<TItem, TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
28
+ /**
29
+ * Reactive getter returning raw domain items.
30
+ */
31
+ items: () => TItem[];
32
+ /**
33
+ * Factory function converting a domain item into a CanvasNode.
34
+ */
35
+ toNode: (item: TItem, index: number, context: {
36
+ existingNode?: TNode;
37
+ prevNodesMap: Map<string, TNode>;
38
+ }) => TNode;
39
+ /**
40
+ * Optional factory function converting domain items and generated nodes into CanvasEdges.
41
+ */
42
+ toEdges?: (items: TItem[], nodes: TNode[]) => TEdge[];
43
+ /**
44
+ * Optional default handle configuration provider for connectable nodes.
45
+ */
46
+ defaultHandles?: (node: TNode) => HandleConfig[] | undefined;
47
+ }
48
+ /**
49
+ * Headless Svelte 5 rune that synchronizes reactive domain items with SvelteFlow nodes/edges,
50
+ * automatically untracking previous node reads, caching .measured dimensions, and normalizing
51
+ * handle bounds to prevent Svelte 5 effect_update_depth_exceeded and marquee drag flashes.
52
+ */
53
+ export declare function createCanvasNodeSync<TItem, TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(options: CreateCanvasNodeSyncOptions<TItem, TNode, TEdge>): {
54
+ nodes: TNode[];
55
+ edges: TEdge[];
56
+ updateNodeMeasurements(id: string, width: number, height: number): void;
57
+ };
58
+ //# sourceMappingURL=createCanvasNodeSync.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCanvasNodeSync.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasNodeSync.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC5B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAC7E,QAAQ,EAAE,KAAK,EAAE,EACjB,aAAa,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GACzC,KAAK,EAAE,CAaT;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EACzE,IAAI,EAAE,KAAK,EACX,OAAO,GAAE,YAAY,EAAO,GAC1B,KAAK,CAGP;AAED,MAAM,WAAW,2BAA2B,CAC3C,KAAK,EACL,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU;IAErC;;OAEG;IACH,KAAK,EAAE,MAAM,KAAK,EAAE,CAAC;IACrB;;OAEG;IACH,MAAM,EAAE,CACP,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,YAAY,CAAC,EAAE,KAAK,CAAC;QAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;KAAE,KAC/D,KAAK,CAAC;IACX;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,CAAC;IACtD;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,YAAY,EAAE,GAAG,SAAS,CAAC;CAC7D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EACL,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU,EACpC,OAAO,EAAE,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;WA2CxC,KAAK,EAAE;WAMP,KAAK,EAAE;+BAGG,MAAM,SAAS,MAAM,UAAU,MAAM;EAOjE"}
@@ -0,0 +1,82 @@
1
+ import { untrack } from 'svelte';
2
+ /**
3
+ * Preserves cached .measured dimensions from existing nodes to newly constructed nodes.
4
+ * Resolves measurements without subscribing to reactive updates on the existing collection.
5
+ */
6
+ export function preserveNodeMeasurements(newNodes, existingNodes) {
7
+ const map = existingNodes instanceof Map
8
+ ? existingNodes
9
+ : new Map(existingNodes.map((n) => [n.id, n]));
10
+ for (const node of newNodes) {
11
+ const prev = map.get(node.id);
12
+ if (prev && prev.measured) {
13
+ node.measured = { ...prev.measured };
14
+ }
15
+ }
16
+ return newNodes;
17
+ }
18
+ /**
19
+ * Pre-populates handle geometry on a node to prevent @xyflow/system's getNodesInside
20
+ * from evaluating `forceInitialRender = !node.internals.handleBounds` and triggering
21
+ * a false full-canvas selection on the first frame of marquee drag-selection.
22
+ */
23
+ export function normalizeNodeHandles(node, handles = []) {
24
+ node.handles = handles;
25
+ return node;
26
+ }
27
+ /**
28
+ * Headless Svelte 5 rune that synchronizes reactive domain items with SvelteFlow nodes/edges,
29
+ * automatically untracking previous node reads, caching .measured dimensions, and normalizing
30
+ * handle bounds to prevent Svelte 5 effect_update_depth_exceeded and marquee drag flashes.
31
+ */
32
+ export function createCanvasNodeSync(options) {
33
+ let nodes = $state([]);
34
+ let edges = $state([]);
35
+ $effect.pre(() => {
36
+ const rawItems = options.items();
37
+ // Untrack the read of current nodes to avoid recursive effect loops
38
+ const existingNodesMap = untrack(() => new Map(nodes.map((n) => [n.id, n])));
39
+ const newNodes = rawItems.map((item, index) => {
40
+ const existing = existingNodesMap.get(item?.id);
41
+ const node = options.toNode(item, index, {
42
+ existingNode: existing,
43
+ prevNodesMap: existingNodesMap
44
+ });
45
+ // Automatically preserve measured dimensions if available
46
+ if (existing && existing.measured && !node.measured) {
47
+ node.measured = { ...existing.measured };
48
+ }
49
+ // Pre-populate handles if provided
50
+ if (options.defaultHandles && !node.handles) {
51
+ const handles = options.defaultHandles(node);
52
+ if (handles) {
53
+ node.handles = handles;
54
+ }
55
+ }
56
+ return node;
57
+ });
58
+ const newEdges = options.toEdges ? options.toEdges(rawItems, newNodes) : [];
59
+ nodes = newNodes;
60
+ edges = newEdges;
61
+ });
62
+ return {
63
+ get nodes() {
64
+ return nodes;
65
+ },
66
+ set nodes(value) {
67
+ nodes = value;
68
+ },
69
+ get edges() {
70
+ return edges;
71
+ },
72
+ set edges(value) {
73
+ edges = value;
74
+ },
75
+ updateNodeMeasurements(id, width, height) {
76
+ const node = nodes.find((n) => n.id === id);
77
+ if (node) {
78
+ node.measured = { width, height };
79
+ }
80
+ }
81
+ };
82
+ }
@@ -0,0 +1,26 @@
1
+ import type { CanvasInteractionPresetConfig } from './types.js';
2
+ export interface CanvasSelectionOptions {
3
+ /**
4
+ * Whether spacebar panning is currently active (suspends marquee selection).
5
+ */
6
+ isSpacebarPanning?: boolean;
7
+ /**
8
+ * Selection mode: 'partial' (default) selects nodes intersected by selection box,
9
+ * 'full' requires nodes to be fully enclosed.
10
+ */
11
+ selectionMode?: 'partial' | 'full';
12
+ /**
13
+ * Additional keys that trigger multi-selection (default: ['Shift', 'Meta']).
14
+ */
15
+ multiSelectionKey?: string[];
16
+ }
17
+ /**
18
+ * Generates an interaction preset configured for left-click marquee drag-selection
19
+ * while preserving middle-mouse and spacebar panning.
20
+ */
21
+ export declare function getMarqueeSelectionPreset(options?: CanvasSelectionOptions): CanvasInteractionPresetConfig;
22
+ /**
23
+ * Keyboard listener helper to deselect nodes on Escape.
24
+ */
25
+ export declare function handleDeselectOnEscape(event: KeyboardEvent, onDeselect: () => void): boolean;
26
+ //# sourceMappingURL=createCanvasSelection.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCanvasSelection.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasSelection.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACnC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACxC,OAAO,GAAE,sBAA2B,GAClC,6BAA6B,CAY/B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,aAAa,EACpB,UAAU,EAAE,MAAM,IAAI,GACpB,OAAO,CAMT"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Generates an interaction preset configured for left-click marquee drag-selection
3
+ * while preserving middle-mouse and spacebar panning.
4
+ */
5
+ export function getMarqueeSelectionPreset(options = {}) {
6
+ const isSpacebarPanning = options.isSpacebarPanning ?? false;
7
+ return {
8
+ snapGrid: [25, 25],
9
+ panOnDrag: isSpacebarPanning ? [0, 1, 2] : [1, 2],
10
+ panOnScroll: false,
11
+ selectionOnDrag: !isSpacebarPanning,
12
+ colorMode: 'system',
13
+ multiSelectionKey: options.multiSelectionKey ?? ['Shift', 'Meta'],
14
+ selectionMode: (options.selectionMode ?? 'partial')
15
+ };
16
+ }
17
+ /**
18
+ * Keyboard listener helper to deselect nodes on Escape.
19
+ */
20
+ export function handleDeselectOnEscape(event, onDeselect) {
21
+ if (event.key === 'Escape' || event.code === 'Escape') {
22
+ onDeselect();
23
+ return true;
24
+ }
25
+ return false;
26
+ }
@@ -0,0 +1,9 @@
1
+ import type { CanvasNode, CanvasShortcutsOptions } from './types.js';
2
+ /**
3
+ * Attaches keyboard shortcut handlers for canvas interaction.
4
+ * Automatically ignores shortcuts when the user is typing into text inputs, textareas, or rich editors.
5
+ *
6
+ * @returns A cleanup function to remove event listeners.
7
+ */
8
+ export declare function createCanvasShortcuts<TNode extends CanvasNode = CanvasNode>(options: CanvasShortcutsOptions<TNode>): () => void;
9
+ //# sourceMappingURL=createCanvasShortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCanvasShortcuts.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasShortcuts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAErE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAC1E,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,GACpC,MAAM,IAAI,CAuFZ"}
@@ -0,0 +1,97 @@
1
+ import { isEventFromTextInput } from './createCanvasClipboard.svelte.js';
2
+ /**
3
+ * Attaches keyboard shortcut handlers for canvas interaction.
4
+ * Automatically ignores shortcuts when the user is typing into text inputs, textareas, or rich editors.
5
+ *
6
+ * @returns A cleanup function to remove event listeners.
7
+ */
8
+ export function createCanvasShortcuts(options) {
9
+ const target = options.targetElement ?? (typeof window !== 'undefined' ? window : null);
10
+ if (!target)
11
+ return () => { };
12
+ function handleKeyDown(event) {
13
+ const keyboardEvent = event;
14
+ if (isEventFromTextInput(keyboardEvent)) {
15
+ return;
16
+ }
17
+ const isMod = keyboardEvent.metaKey || keyboardEvent.ctrlKey;
18
+ const isShift = keyboardEvent.shiftKey;
19
+ const key = keyboardEvent.key;
20
+ const selectedNodes = options.getSelectedNodes ? options.getSelectedNodes() : [];
21
+ if (key === 'Backspace' || key === 'Delete') {
22
+ if (options.onDelete && selectedNodes.length > 0) {
23
+ keyboardEvent.preventDefault();
24
+ options.onDelete(selectedNodes);
25
+ }
26
+ return;
27
+ }
28
+ if (isMod) {
29
+ const lowerKey = key.toLowerCase();
30
+ if (lowerKey === 'c' && !isShift) {
31
+ if (options.onCopy) {
32
+ // We let the native copy event fire or call onCopy
33
+ options.onCopy();
34
+ }
35
+ }
36
+ else if (lowerKey === 'x' && !isShift) {
37
+ if (options.onCut) {
38
+ options.onCut();
39
+ }
40
+ }
41
+ else if (lowerKey === 'd' && !isShift) {
42
+ if (options.onDuplicate && selectedNodes.length > 0) {
43
+ keyboardEvent.preventDefault();
44
+ options.onDuplicate(selectedNodes);
45
+ }
46
+ }
47
+ else if (lowerKey === 'a' && !isShift) {
48
+ if (options.onSelectAll) {
49
+ keyboardEvent.preventDefault();
50
+ options.onSelectAll();
51
+ }
52
+ }
53
+ else if (lowerKey === 'g') {
54
+ if (isShift) {
55
+ if (options.onUngroup && selectedNodes.length > 0) {
56
+ keyboardEvent.preventDefault();
57
+ options.onUngroup(selectedNodes);
58
+ }
59
+ }
60
+ else {
61
+ if (options.onGroup && selectedNodes.length > 0) {
62
+ keyboardEvent.preventDefault();
63
+ options.onGroup(selectedNodes);
64
+ }
65
+ }
66
+ }
67
+ else if (key === '=' || key === '+') {
68
+ if (options.onZoomIn) {
69
+ keyboardEvent.preventDefault();
70
+ options.onZoomIn();
71
+ }
72
+ }
73
+ else if (key === '-') {
74
+ if (options.onZoomOut) {
75
+ keyboardEvent.preventDefault();
76
+ options.onZoomOut();
77
+ }
78
+ }
79
+ else if (key === '0') {
80
+ if (options.onFitView) {
81
+ keyboardEvent.preventDefault();
82
+ options.onFitView();
83
+ }
84
+ }
85
+ else if (lowerKey === 'f') {
86
+ if (options.onSearch) {
87
+ keyboardEvent.preventDefault();
88
+ options.onSearch();
89
+ }
90
+ }
91
+ }
92
+ }
93
+ target.addEventListener('keydown', handleKeyDown);
94
+ return () => {
95
+ target.removeEventListener('keydown', handleKeyDown);
96
+ };
97
+ }
@@ -0,0 +1,31 @@
1
+ import type { XYPosition } from '@xyflow/svelte';
2
+ import type { CanvasNode, FanOutTrajectoryOptions, NodeTransition, TrajectoryFunction } from './types.js';
3
+ /**
4
+ * Standard linear trajectory: straight line interpolation with linear scale & opacity progression.
5
+ */
6
+ export declare const linearTrajectory: TrajectoryFunction;
7
+ /**
8
+ * Linear position trajectory: pure position interpolation without altering scale or opacity.
9
+ * Used for displaced sibling nodes to ensure their visibility remains unaltered.
10
+ */
11
+ export declare const linearPositionTrajectory: TrajectoryFunction;
12
+ /**
13
+ * Creates a fan-out trajectory where nodes arc outward from origin to target.
14
+ * Matches the curved distribution shown in multi-node branching diagrams.
15
+ */
16
+ export declare function createFanOutTrajectory(options?: FanOutTrajectoryOptions): TrajectoryFunction;
17
+ /**
18
+ * Creates a custom quadratic Bezier trajectory with a specified or dynamically calculated control point.
19
+ */
20
+ export declare function createBezierTrajectory(getControlPoint: (origin: XYPosition, target: XYPosition) => XYPosition): TrajectoryFunction;
21
+ /**
22
+ * Coordinates and animates multiple node transitions simultaneously with zero per-frame array allocations.
23
+ * Directly mutates node positions and data (scale, opacity) in-place during the animation loop.
24
+ */
25
+ export declare function runMultiNodeTransition<TNode extends CanvasNode = CanvasNode>(transitions: NodeTransition<TNode>[], options?: {
26
+ defaultDuration?: number;
27
+ defaultEasing?: (t: number) => number;
28
+ onUpdate?: () => void;
29
+ onComplete?: () => void;
30
+ }): () => void;
31
+ //# sourceMappingURL=createCanvasTrajectory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCanvasTrajectory.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasTrajectory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EACX,UAAU,EACV,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAElB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,kBAa9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,kBAWtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,kBAAkB,CA0ChG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACrC,eAAe,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,KAAK,UAAU,GACrE,kBAAkB,CAepB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAC3E,WAAW,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,EACpC,OAAO,GAAE;IACR,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACnB,GACJ,MAAM,IAAI,CA+EZ"}
@@ -0,0 +1,141 @@
1
+ import { cubicOut } from 'svelte/easing';
2
+ /**
3
+ * Standard linear trajectory: straight line interpolation with linear scale & opacity progression.
4
+ */
5
+ export const linearTrajectory = (origin, target, progress) => {
6
+ return {
7
+ position: {
8
+ x: origin.x + (target.x - origin.x) * progress,
9
+ y: origin.y + (target.y - origin.y) * progress
10
+ },
11
+ scale: progress,
12
+ opacity: Math.min(1, progress * 1.5)
13
+ };
14
+ };
15
+ /**
16
+ * Linear position trajectory: pure position interpolation without altering scale or opacity.
17
+ * Used for displaced sibling nodes to ensure their visibility remains unaltered.
18
+ */
19
+ export const linearPositionTrajectory = (origin, target, progress) => {
20
+ return {
21
+ position: {
22
+ x: origin.x + (target.x - origin.x) * progress,
23
+ y: origin.y + (target.y - origin.y) * progress
24
+ }
25
+ };
26
+ };
27
+ /**
28
+ * Creates a fan-out trajectory where nodes arc outward from origin to target.
29
+ * Matches the curved distribution shown in multi-node branching diagrams.
30
+ */
31
+ export function createFanOutTrajectory(options = {}) {
32
+ const { curvature = 0.4, startScale = 0, endScale = 1, startOpacity = 0, endOpacity = 1 } = options;
33
+ return (origin, target, progress, index, total) => {
34
+ const dx = target.x - origin.x;
35
+ const dy = target.y - origin.y;
36
+ // Normalized index from -1 (top) to +1 (bottom)
37
+ const normIndex = total > 1 ? (index - (total - 1) / 2) / ((total - 1) / 2) : 0;
38
+ // Perpendicular control point offset to create smooth fan arc
39
+ const midX = origin.x + dx * 0.4;
40
+ const midY = origin.y + dy * 0.1 - normIndex * Math.abs(dx) * 0.15 * curvature;
41
+ // Quadratic Bezier interpolation: B(t) = (1-t)^2 * P0 + 2(1-t)t * P1 + t^2 * P2
42
+ const t = progress;
43
+ const oneMinusT = 1 - t;
44
+ const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;
45
+ const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;
46
+ const scale = startScale + (endScale - startScale) * progress;
47
+ const opacity = startOpacity + (endOpacity - startOpacity) * progress;
48
+ return {
49
+ position: { x, y },
50
+ scale,
51
+ opacity
52
+ };
53
+ };
54
+ }
55
+ /**
56
+ * Creates a custom quadratic Bezier trajectory with a specified or dynamically calculated control point.
57
+ */
58
+ export function createBezierTrajectory(getControlPoint) {
59
+ return (origin, target, progress) => {
60
+ const cp = getControlPoint(origin, target);
61
+ const t = progress;
62
+ const oneMinusT = 1 - t;
63
+ const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * cp.x + t * t * target.x;
64
+ const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * cp.y + t * t * target.y;
65
+ return {
66
+ position: { x, y },
67
+ scale: progress,
68
+ opacity: progress
69
+ };
70
+ };
71
+ }
72
+ /**
73
+ * Coordinates and animates multiple node transitions simultaneously with zero per-frame array allocations.
74
+ * Directly mutates node positions and data (scale, opacity) in-place during the animation loop.
75
+ */
76
+ export function runMultiNodeTransition(transitions, options = {}) {
77
+ if (transitions.length === 0) {
78
+ options.onComplete?.();
79
+ return () => { };
80
+ }
81
+ const { defaultDuration = 400, defaultEasing = cubicOut, onUpdate, onComplete } = options;
82
+ let isCancelled = false;
83
+ const startTime = Date.now();
84
+ const items = transitions.map((tr, i) => ({
85
+ ...tr,
86
+ index: tr.index ?? i,
87
+ total: tr.total ?? transitions.length,
88
+ duration: tr.duration ?? defaultDuration,
89
+ easing: tr.easing ?? defaultEasing,
90
+ delay: tr.delay ?? 0,
91
+ trajectory: tr.trajectory ?? linearTrajectory
92
+ }));
93
+ function frame() {
94
+ if (isCancelled)
95
+ return;
96
+ const now = Date.now();
97
+ let allCompleted = true;
98
+ for (let i = 0; i < items.length; i++) {
99
+ const item = items[i];
100
+ const elapsed = now - (startTime + item.delay);
101
+ if (elapsed < 0) {
102
+ allCompleted = false;
103
+ continue;
104
+ }
105
+ const rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);
106
+ const progress = item.duration <= 0 ? 1 : item.easing(rawProgress);
107
+ const point = item.trajectory(item.from, item.to, progress, item.index, item.total);
108
+ // Direct in-place mutation avoids array reconstruction during RAF
109
+ item.node.position = { ...point.position };
110
+ if (point.scale !== undefined || point.opacity !== undefined) {
111
+ if (!item.node.data) {
112
+ item.node.data = {};
113
+ }
114
+ if (point.scale !== undefined) {
115
+ item.node.data.scale = point.scale;
116
+ }
117
+ if (point.opacity !== undefined) {
118
+ item.node.data.opacity = point.opacity;
119
+ const currentStyle = (item.node.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim();
120
+ item.node.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: ${point.opacity};`;
121
+ }
122
+ }
123
+ if (rawProgress < 1) {
124
+ allCompleted = false;
125
+ }
126
+ }
127
+ onUpdate?.();
128
+ if (!allCompleted) {
129
+ if (typeof requestAnimationFrame !== 'undefined') {
130
+ requestAnimationFrame(frame);
131
+ }
132
+ }
133
+ else {
134
+ onComplete?.();
135
+ }
136
+ }
137
+ frame();
138
+ return () => {
139
+ isCancelled = true;
140
+ };
141
+ }
@@ -0,0 +1,19 @@
1
+ import { type CanvasEdge, type CanvasNode, type IncrementalLayoutOptions, type XYPosition } from '@pixerate/editor/canvas';
2
+ export interface CreateStreamingCanvasOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
3
+ throttleMs?: number;
4
+ glideDurationMs?: number;
5
+ connectedOnly?: boolean;
6
+ clock?: any;
7
+ layoutOptions?: IncrementalLayoutOptions;
8
+ onPositionsChange?: (positions: Map<string, XYPosition>) => void;
9
+ }
10
+ /**
11
+ * Svelte 5 rune managing throttled graph streaming and fluid node glide animations.
12
+ */
13
+ export declare function createStreamingCanvas<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(options?: CreateStreamingCanvasOptions<TNode, TEdge>): {
14
+ readonly positions: Map<string, XYPosition>;
15
+ pushStreamUpdate(nodes: TNode[], edges: TEdge[], currentPositions: Map<string, XYPosition>): void;
16
+ flush(nodes: TNode[], edges: TEdge[], currentPositions: Map<string, XYPosition>): void;
17
+ destroy(): void;
18
+ };
19
+ //# sourceMappingURL=createStreamingCanvas.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStreamingCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createStreamingCanvas.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EACf,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,4BAA4B,CAC5C,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU;IAErC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;CACjE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU,EACpC,OAAO,GAAE,4BAA4B,CAAC,KAAK,EAAE,KAAK,CAAM;;4BAmBhC,KAAK,EAAE,SAAS,KAAK,EAAE,oBAAoB,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;iBAG7E,KAAK,EAAE,SAAS,KAAK,EAAE,oBAAoB,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;;EAOhF"}
@@ -0,0 +1,32 @@
1
+ import { StreamingLayoutManager } from '@pixerate/editor/canvas';
2
+ /**
3
+ * Svelte 5 rune managing throttled graph streaming and fluid node glide animations.
4
+ */
5
+ export function createStreamingCanvas(options = {}) {
6
+ let positions = $state(new Map());
7
+ const manager = new StreamingLayoutManager({
8
+ throttleMs: options.throttleMs,
9
+ glideDurationMs: options.glideDurationMs,
10
+ connectedOnly: options.connectedOnly,
11
+ clock: options.clock,
12
+ layoutOptions: options.layoutOptions,
13
+ onLayoutUpdated: (updated) => {
14
+ positions = updated;
15
+ options.onPositionsChange?.(updated);
16
+ }
17
+ });
18
+ return {
19
+ get positions() {
20
+ return positions;
21
+ },
22
+ pushStreamUpdate(nodes, edges, currentPositions) {
23
+ manager.pushStreamUpdate(nodes, edges, currentPositions);
24
+ },
25
+ flush(nodes, edges, currentPositions) {
26
+ manager.flush(nodes, edges, currentPositions);
27
+ },
28
+ destroy() {
29
+ manager.destroy();
30
+ }
31
+ };
32
+ }