@pixerate/editor-svelte 0.15.3 → 0.16.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/BubbleMenu.svelte.d.ts +14 -0
- package/dist/BubbleMenu.svelte.d.ts.map +1 -0
- package/{src → dist}/EditableTextNodeEditor.svelte +1 -1
- package/dist/EditableTextNodeEditor.svelte.d.ts +26 -0
- package/dist/EditableTextNodeEditor.svelte.d.ts.map +1 -0
- package/dist/TemplateRenderer.svelte.d.ts +14 -0
- package/dist/TemplateRenderer.svelte.d.ts.map +1 -0
- package/dist/canvas/AgentPresenceLayer.svelte.d.ts +9 -0
- package/dist/canvas/AgentPresenceLayer.svelte.d.ts.map +1 -0
- package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts +9 -0
- package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasClipboard.svelte.d.ts +32 -0
- package/dist/canvas/createCanvasClipboard.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasClipboard.svelte.js +171 -0
- package/dist/canvas/createCanvasDisplacement.d.ts +32 -0
- package/dist/canvas/createCanvasDisplacement.d.ts.map +1 -0
- package/dist/canvas/createCanvasDisplacement.js +170 -0
- package/dist/canvas/createCanvasDocking.svelte.d.ts +56 -0
- package/dist/canvas/createCanvasDocking.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasDocking.svelte.js +227 -0
- package/dist/canvas/createCanvasExplosion.svelte.d.ts +31 -0
- package/dist/canvas/createCanvasExplosion.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasExplosion.svelte.js +346 -0
- package/dist/canvas/createCanvasGraph.svelte.d.ts +62 -0
- package/dist/canvas/createCanvasGraph.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasGraph.svelte.js +223 -0
- package/dist/canvas/createCanvasInteractions.svelte.d.ts +28 -0
- package/dist/canvas/createCanvasInteractions.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasInteractions.svelte.js +95 -0
- package/dist/canvas/createCanvasLayout.d.ts +22 -0
- package/dist/canvas/createCanvasLayout.d.ts.map +1 -0
- package/dist/canvas/createCanvasLayout.js +76 -0
- package/dist/canvas/createCanvasMultiDrag.svelte.d.ts +61 -0
- package/dist/canvas/createCanvasMultiDrag.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasMultiDrag.svelte.js +105 -0
- package/dist/canvas/createCanvasNodeSync.svelte.d.ts +58 -0
- package/dist/canvas/createCanvasNodeSync.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasNodeSync.svelte.js +82 -0
- package/dist/canvas/createCanvasSelection.svelte.d.ts +26 -0
- package/dist/canvas/createCanvasSelection.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasSelection.svelte.js +26 -0
- package/dist/canvas/createCanvasShortcuts.d.ts +9 -0
- package/dist/canvas/createCanvasShortcuts.d.ts.map +1 -0
- package/dist/canvas/createCanvasShortcuts.js +97 -0
- package/dist/canvas/createCanvasTrajectory.d.ts +31 -0
- package/dist/canvas/createCanvasTrajectory.d.ts.map +1 -0
- package/dist/canvas/createCanvasTrajectory.js +141 -0
- package/dist/canvas/createStreamingCanvas.svelte.d.ts +19 -0
- package/dist/canvas/createStreamingCanvas.svelte.d.ts.map +1 -0
- package/dist/canvas/createStreamingCanvas.svelte.js +32 -0
- package/dist/canvas/index.d.ts +18 -688
- package/dist/canvas/index.d.ts.map +1 -0
- package/dist/canvas/index.js +34 -1839
- package/dist/canvas/types.d.ts +183 -0
- package/dist/canvas/types.d.ts.map +1 -0
- package/dist/canvas/types.js +1 -0
- package/dist/createNavigationGuard.svelte.d.ts +24 -0
- package/dist/createNavigationGuard.svelte.d.ts.map +1 -0
- package/dist/createNavigationGuard.svelte.js +65 -0
- package/dist/editor.svelte.d.ts +23 -0
- package/dist/editor.svelte.d.ts.map +1 -0
- package/dist/editor.svelte.js +41 -0
- package/dist/history/createHistoryShortcuts.d.ts +24 -0
- package/dist/history/createHistoryShortcuts.d.ts.map +1 -0
- package/dist/history/createHistoryShortcuts.js +57 -0
- package/dist/history/history.svelte.d.ts +18 -0
- package/dist/history/history.svelte.d.ts.map +1 -0
- package/dist/history/history.svelte.js +43 -0
- package/dist/history/index.d.ts +3 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +2 -0
- package/{src → dist}/image-editor/ImageEditor.svelte +1 -1
- package/dist/image-editor/ImageEditor.svelte.d.ts +17 -0
- package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -0
- package/dist/image-editor/imageEditorState.svelte.d.ts +50 -0
- package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -0
- package/dist/image-editor/imageEditorState.svelte.js +132 -0
- package/dist/image-editor/index.d.ts +6 -16
- package/dist/image-editor/index.d.ts.map +1 -0
- package/dist/image-editor/index.js +2 -9
- package/dist/index.d.ts +20 -249
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -1119
- package/dist/navigationGuard.d.ts +21 -0
- package/dist/navigationGuard.d.ts.map +1 -0
- package/dist/navigationGuard.js +59 -0
- package/{src → dist}/spreadsheet/FormulaBar.svelte +1 -1
- package/dist/spreadsheet/FormulaBar.svelte.d.ts +17 -0
- package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -0
- package/{src → dist}/spreadsheet/SpreadsheetEditor.svelte +1 -1
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +22 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/index.d.ts +9 -0
- package/dist/spreadsheet/index.d.ts.map +1 -0
- package/{src/spreadsheet/index.ts → dist/spreadsheet/index.js} +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.d.ts +33 -0
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/spreadsheet.svelte.js +160 -0
- package/package.json +13 -15
- package/dist/canvas/index.js.map +0 -1
- package/dist/chunk-HEOI4UNF.js +0 -1191
- package/dist/chunk-HEOI4UNF.js.map +0 -1
- package/dist/image-editor/index.js.map +0 -1
- package/dist/index.css +0 -50
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/canvas/__tests__/canvas-clipboard.test.ts +0 -154
- package/src/canvas/__tests__/canvas-docking.test.ts +0 -288
- package/src/canvas/__tests__/canvas-explosion.test.ts +0 -634
- package/src/canvas/__tests__/canvas-graph.test.ts +0 -159
- package/src/canvas/__tests__/canvas-interactions.test.ts +0 -86
- package/src/canvas/__tests__/canvas-layout.test.ts +0 -75
- package/src/canvas/__tests__/canvas-multi-drag.test.ts +0 -112
- package/src/canvas/__tests__/canvas-node-sync.svelte.test.ts +0 -104
- package/src/canvas/__tests__/canvas-shortcuts.test.ts +0 -59
- package/src/canvas/createCanvasClipboard.svelte.ts +0 -219
- package/src/canvas/createCanvasDisplacement.ts +0 -253
- package/src/canvas/createCanvasDocking.svelte.ts +0 -355
- package/src/canvas/createCanvasExplosion.svelte.ts +0 -457
- package/src/canvas/createCanvasGraph.svelte.ts +0 -330
- package/src/canvas/createCanvasInteractions.svelte.ts +0 -112
- package/src/canvas/createCanvasLayout.ts +0 -129
- package/src/canvas/createCanvasMultiDrag.svelte.ts +0 -175
- package/src/canvas/createCanvasNodeSync.svelte.ts +0 -150
- package/src/canvas/createCanvasSelection.svelte.ts +0 -51
- package/src/canvas/createCanvasShortcuts.ts +0 -99
- package/src/canvas/createCanvasTrajectory.ts +0 -207
- package/src/canvas/createStreamingCanvas.svelte.ts +0 -56
- package/src/canvas/index.d.ts +0 -688
- package/src/canvas/index.ts +0 -126
- package/src/canvas/types.ts +0 -223
- package/src/createNavigationGuard.svelte.ts +0 -97
- package/src/editor.svelte.ts +0 -65
- package/src/history/createHistoryShortcuts.ts +0 -95
- package/src/history/history.svelte.ts +0 -68
- package/src/history/index.ts +0 -2
- package/src/image-editor/imageEditorState.svelte.ts +0 -151
- package/src/image-editor/index.d.ts +0 -16
- package/src/image-editor/index.ts +0 -2
- package/src/index.d.ts +0 -249
- package/src/index.ts +0 -89
- package/src/navigationGuard.ts +0 -82
- package/src/spreadsheet/spreadsheet.svelte.ts +0 -176
- package/src/svelte.d.ts +0 -5
- /package/{src → dist}/BubbleMenu.svelte +0 -0
- /package/{src → dist}/TemplateRenderer.svelte +0 -0
- /package/{src → dist}/canvas/AgentPresenceLayer.svelte +0 -0
- /package/{src → dist}/canvas/FloatingHorizontalScrollbar.svelte +0 -0
- /package/{src → dist}/canvas/README.md +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
interface Props {
|
|
3
|
+
editor?: Editor;
|
|
4
|
+
class?: string;
|
|
5
|
+
pluginKey?: any;
|
|
6
|
+
shouldShow?: ((props: any) => boolean) | null;
|
|
7
|
+
updateDelay?: number;
|
|
8
|
+
tippyOptions?: Record<string, any>;
|
|
9
|
+
children?: import("svelte").Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const BubbleMenu: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type BubbleMenu = ReturnType<typeof BubbleMenu>;
|
|
13
|
+
export default BubbleMenu;
|
|
14
|
+
//# sourceMappingURL=BubbleMenu.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BubbleMenu.svelte.d.ts","sourceRoot":"","sources":["../src/BubbleMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAIzC,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CACrC;AAkDH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { Editor, Content, Extensions, FocusPosition } from "@tiptap/core";
|
|
3
3
|
import type { RichTextPresetOptions, MarkdownOptions, ImageOptions } from "@pixerate/editor";
|
|
4
4
|
import { onDestroy, onMount } from "svelte";
|
|
5
|
-
import { initiateEditor } from "./editor.svelte";
|
|
5
|
+
import { initiateEditor } from "./editor.svelte.js";
|
|
6
6
|
|
|
7
7
|
interface EditorProps {
|
|
8
8
|
class?: string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Editor, Content, Extensions, FocusPosition } from "@tiptap/core";
|
|
2
|
+
import type { RichTextPresetOptions, MarkdownOptions, ImageOptions } from "@pixerate/editor";
|
|
3
|
+
interface EditorProps {
|
|
4
|
+
class?: string;
|
|
5
|
+
editorClass?: string;
|
|
6
|
+
content?: Content;
|
|
7
|
+
showMenu?: boolean;
|
|
8
|
+
editable?: boolean;
|
|
9
|
+
editor?: Editor;
|
|
10
|
+
extensions?: Extensions;
|
|
11
|
+
onUpdate?: () => void;
|
|
12
|
+
onFocus?: () => void;
|
|
13
|
+
onBlur?: () => void;
|
|
14
|
+
onCreate?: () => void;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
markdown?: boolean | MarkdownOptions;
|
|
17
|
+
richTextOptions?: RichTextPresetOptions;
|
|
18
|
+
autofocus?: FocusPosition | boolean;
|
|
19
|
+
image?: ImageOptions | boolean;
|
|
20
|
+
uploadImage?: (file: File) => Promise<string> | string;
|
|
21
|
+
onUploadError?: (error: Error, file: File) => void;
|
|
22
|
+
}
|
|
23
|
+
declare const EditableTextNodeEditor: import("svelte").Component<EditorProps, {}, "editor">;
|
|
24
|
+
type EditableTextNodeEditor = ReturnType<typeof EditableTextNodeEditor>;
|
|
25
|
+
export default EditableTextNodeEditor;
|
|
26
|
+
//# sourceMappingURL=EditableTextNodeEditor.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableTextNodeEditor.svelte.d.ts","sourceRoot":"","sources":["../src/EditableTextNodeEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAK3F,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,GAAG,eAAe,CAAC;IACrC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,SAAS,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACvD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpD;AA8FH,QAAA,MAAM,sBAAsB,uDAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Template, type ColorGradient } from "@pixerate/editor";
|
|
2
|
+
interface Props {
|
|
3
|
+
content: string;
|
|
4
|
+
templates?: Template[];
|
|
5
|
+
templateColorMap?: Map<string, ColorGradient>;
|
|
6
|
+
resolve?: boolean;
|
|
7
|
+
class?: string;
|
|
8
|
+
onTemplateClick?: (templateName: string) => void;
|
|
9
|
+
onVariableClick?: (variableName: string) => void;
|
|
10
|
+
}
|
|
11
|
+
declare const TemplateRenderer: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type TemplateRenderer = ReturnType<typeof TemplateRenderer>;
|
|
13
|
+
export default TemplateRenderer;
|
|
14
|
+
//# sourceMappingURL=TemplateRenderer.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/TemplateRenderer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAGH,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAG1B,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAiDH,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentPresence } from '@pixerate/editor/agent';
|
|
2
|
+
interface Props {
|
|
3
|
+
presences: AgentPresence[];
|
|
4
|
+
class?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const AgentPresenceLayer: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type AgentPresenceLayer = ReturnType<typeof AgentPresenceLayer>;
|
|
8
|
+
export default AgentPresenceLayer;
|
|
9
|
+
//# sourceMappingURL=AgentPresenceLayer.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentPresenceLayer.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/AgentPresenceLayer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG3D,UAAU,KAAK;IACd,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAwCF,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
targetElement?: HTMLDivElement | null;
|
|
3
|
+
totalWidth?: number;
|
|
4
|
+
minHeightAboveFold?: number;
|
|
5
|
+
};
|
|
6
|
+
declare const FloatingHorizontalScrollbar: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type FloatingHorizontalScrollbar = ReturnType<typeof FloatingHorizontalScrollbar>;
|
|
8
|
+
export default FloatingHorizontalScrollbar;
|
|
9
|
+
//# sourceMappingURL=FloatingHorizontalScrollbar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingHorizontalScrollbar.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/FloatingHorizontalScrollbar.svelte.ts"],"names":[],"mappings":"AAKC,KAAK,gBAAgB,GAAI;IACxB,aAAa,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAmGH,QAAA,MAAM,2BAA2B,sDAAwC,CAAC;AAC1E,KAAK,2BAA2B,GAAG,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAClF,eAAe,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { XYPosition } from '@xyflow/svelte';
|
|
2
|
+
import type { CanvasNode, CanvasEdge } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Checks if an event originated from a text input, textarea, contenteditable element, or rich editor.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isEventFromTextInput(event: Event | {
|
|
7
|
+
target: EventTarget | null;
|
|
8
|
+
}): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Validates that an object conforms to minimal CanvasNode shape.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isValidCanvasNode(obj: unknown): obj is CanvasNode;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if a string is a valid HTTP/HTTPS URL.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isValidUrl(url: string): boolean;
|
|
17
|
+
export interface CreateCanvasClipboardOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
|
|
18
|
+
onPasteNodes?: (nodes: TNode[], edges?: TEdge[]) => void | Promise<void>;
|
|
19
|
+
onPasteUrl?: (url: string, position?: XYPosition) => void;
|
|
20
|
+
onPasteText?: (text: string, position?: XYPosition) => void;
|
|
21
|
+
onPasteImage?: (blob: File) => void | Promise<void>;
|
|
22
|
+
screenToFlowPosition?: (position: XYPosition) => XYPosition;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Headless Svelte 5 rune managing canvas copy, cut, and paste interactions.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createCanvasClipboard<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(options?: CreateCanvasClipboardOptions<TNode, TEdge>): {
|
|
28
|
+
copySelectedNodes: (selectedNodes: TNode[], connectedEdges?: TEdge[], event?: ClipboardEvent) => boolean;
|
|
29
|
+
cutSelectedNodes: (selectedNodes: TNode[], connectedEdges?: TEdge[], onRemove?: (nodes: TNode[]) => void, event?: ClipboardEvent) => boolean;
|
|
30
|
+
handlePasteEvent: (event: ClipboardEvent) => Promise<boolean>;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=createCanvasClipboard.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCanvasClipboard.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasClipboard.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAA0B,MAAM,YAAY,CAAC;AAEjF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,CAc3F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU,CAYjE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED,MAAM,WAAW,4BAA4B,CAC5C,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU;IAErC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,UAAU,CAAC;CAC5D;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;uCAEzC,KAAK,EAAE,mBACL,KAAK,EAAE,UAChB,cAAc,KACpB,OAAO;sCA2BM,KAAK,EAAE,mBACL,KAAK,EAAE,aACb,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,UAC3B,cAAc,KACpB,OAAO;8BAY6B,cAAc,KAAG,OAAO,CAAC,OAAO,CAAC;EAqGxE"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { tick } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if an event originated from a text input, textarea, contenteditable element, or rich editor.
|
|
4
|
+
*/
|
|
5
|
+
export function isEventFromTextInput(event) {
|
|
6
|
+
const target = event.target;
|
|
7
|
+
if (!target)
|
|
8
|
+
return false;
|
|
9
|
+
if (target.tagName === 'INPUT' ||
|
|
10
|
+
target.tagName === 'TEXTAREA' ||
|
|
11
|
+
target.tagName === 'SELECT' ||
|
|
12
|
+
target.isContentEditable ||
|
|
13
|
+
target.closest?.('[contenteditable="true"]') ||
|
|
14
|
+
target.closest?.('.ProseMirror')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates that an object conforms to minimal CanvasNode shape.
|
|
21
|
+
*/
|
|
22
|
+
export function isValidCanvasNode(obj) {
|
|
23
|
+
return (typeof obj === 'object' &&
|
|
24
|
+
obj !== null &&
|
|
25
|
+
'id' in obj &&
|
|
26
|
+
typeof obj.id === 'string' &&
|
|
27
|
+
'position' in obj &&
|
|
28
|
+
typeof obj.position === 'object' &&
|
|
29
|
+
obj.position !== null &&
|
|
30
|
+
'x' in obj.position &&
|
|
31
|
+
'y' in obj.position);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks if a string is a valid HTTP/HTTPS URL.
|
|
35
|
+
*/
|
|
36
|
+
export function isValidUrl(url) {
|
|
37
|
+
try {
|
|
38
|
+
const parsed = new URL(url);
|
|
39
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Headless Svelte 5 rune managing canvas copy, cut, and paste interactions.
|
|
47
|
+
*/
|
|
48
|
+
export function createCanvasClipboard(options = {}) {
|
|
49
|
+
function copySelectedNodes(selectedNodes, connectedEdges, event) {
|
|
50
|
+
if (event && isEventFromTextInput(event)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (selectedNodes.length === 0)
|
|
54
|
+
return false;
|
|
55
|
+
const payload = {
|
|
56
|
+
version: 1,
|
|
57
|
+
nodes: selectedNodes,
|
|
58
|
+
edges: connectedEdges
|
|
59
|
+
};
|
|
60
|
+
const serialized = JSON.stringify(payload);
|
|
61
|
+
if (event?.clipboardData) {
|
|
62
|
+
event.clipboardData.setData('application/json', serialized);
|
|
63
|
+
event.clipboardData.setData('text/plain', serialized);
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
}
|
|
66
|
+
else if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
67
|
+
navigator.clipboard.writeText(serialized).catch(() => { });
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
function cutSelectedNodes(selectedNodes, connectedEdges, onRemove, event) {
|
|
72
|
+
if (event && isEventFromTextInput(event)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const copied = copySelectedNodes(selectedNodes, connectedEdges, event);
|
|
76
|
+
if (copied && onRemove) {
|
|
77
|
+
onRemove(selectedNodes);
|
|
78
|
+
}
|
|
79
|
+
return copied;
|
|
80
|
+
}
|
|
81
|
+
async function handlePasteEvent(event) {
|
|
82
|
+
if (isEventFromTextInput(event)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const clipboardData = event.clipboardData;
|
|
86
|
+
if (!clipboardData)
|
|
87
|
+
return false;
|
|
88
|
+
// 1. Check for files (images)
|
|
89
|
+
const files = clipboardData.files;
|
|
90
|
+
if (files && files.length > 0) {
|
|
91
|
+
const imageFile = Array.from(files).find((f) => f.type.startsWith('image/'));
|
|
92
|
+
if (imageFile && options.onPasteImage) {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
await options.onPasteImage(imageFile);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 2. Check for serialized nodes (application/json or json in text/plain)
|
|
99
|
+
const rawJson = clipboardData.getData('application/json') || clipboardData.getData('text/plain');
|
|
100
|
+
if (rawJson) {
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(rawJson);
|
|
103
|
+
let rawNodes;
|
|
104
|
+
let rawEdges;
|
|
105
|
+
if (Array.isArray(parsed) && parsed.every(isValidCanvasNode)) {
|
|
106
|
+
rawNodes = parsed;
|
|
107
|
+
}
|
|
108
|
+
else if (typeof parsed === 'object' &&
|
|
109
|
+
parsed !== null &&
|
|
110
|
+
Array.isArray(parsed.nodes) &&
|
|
111
|
+
parsed.nodes.every(isValidCanvasNode)) {
|
|
112
|
+
rawNodes = parsed.nodes;
|
|
113
|
+
rawEdges = parsed.edges;
|
|
114
|
+
}
|
|
115
|
+
if (rawNodes && rawNodes.length > 0) {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
// Create ID mapping for cloned nodes
|
|
118
|
+
const idMap = new Map();
|
|
119
|
+
const newNodes = rawNodes.map((node) => {
|
|
120
|
+
const newId = crypto.randomUUID();
|
|
121
|
+
idMap.set(node.id, newId);
|
|
122
|
+
return {
|
|
123
|
+
...node,
|
|
124
|
+
id: newId,
|
|
125
|
+
selected: true,
|
|
126
|
+
position: {
|
|
127
|
+
x: node.position.x + 40,
|
|
128
|
+
y: node.position.y + 40
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
// Clone edges mapping them to the newly generated node IDs
|
|
133
|
+
const newEdges = rawEdges?.map((edge) => ({
|
|
134
|
+
...edge,
|
|
135
|
+
id: crypto.randomUUID(),
|
|
136
|
+
source: idMap.get(edge.source) ?? edge.source,
|
|
137
|
+
target: idMap.get(edge.target) ?? edge.target
|
|
138
|
+
}));
|
|
139
|
+
if (options.onPasteNodes) {
|
|
140
|
+
await options.onPasteNodes(newNodes, newEdges);
|
|
141
|
+
await tick();
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Not JSON, fall through to text/URL processing
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// 3. Check for URLs or plain text
|
|
151
|
+
const text = clipboardData.getData('text/plain')?.trim();
|
|
152
|
+
if (text) {
|
|
153
|
+
if (isValidUrl(text) && options.onPasteUrl) {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
options.onPasteUrl(text);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
else if (options.onPasteText) {
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
options.onPasteText(text);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
copySelectedNodes,
|
|
168
|
+
cutSelectedNodes,
|
|
169
|
+
handlePasteEvent
|
|
170
|
+
};
|
|
171
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Rect, XYPosition } from '@xyflow/svelte';
|
|
2
|
+
import type { CanvasEdge, CanvasLayoutOptions, CanvasNode, DirectionalDisplacementOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.
|
|
5
|
+
*/
|
|
6
|
+
export declare function computeNodesBoundingBox<TNode extends CanvasNode = CanvasNode>(nodes: TNode[], defaultWidth?: number, defaultHeight?: number): Rect;
|
|
7
|
+
/**
|
|
8
|
+
* Pure directional displacement calculation.
|
|
9
|
+
* Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.
|
|
10
|
+
*/
|
|
11
|
+
export declare function calculateDirectionalDisplacement<TNode extends CanvasNode = CanvasNode>(params: {
|
|
12
|
+
existingNodes: TNode[];
|
|
13
|
+
originNode: TNode;
|
|
14
|
+
childNodes: TNode[];
|
|
15
|
+
getNodesBounds?: (nodes: TNode[]) => Rect;
|
|
16
|
+
options?: DirectionalDisplacementOptions;
|
|
17
|
+
}): Map<string, XYPosition>;
|
|
18
|
+
/**
|
|
19
|
+
* Pure hierarchical Dagre reflow displacement calculation.
|
|
20
|
+
* Calculates new coordinates for surrounding nodes using Dagre hierarchical layout,
|
|
21
|
+
* anchoring the origin node at its current position to eliminate layout jumping.
|
|
22
|
+
*/
|
|
23
|
+
export declare function calculateReflowDisplacement<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(params: {
|
|
24
|
+
existingNodes: TNode[];
|
|
25
|
+
existingEdges: TEdge[];
|
|
26
|
+
originNode: TNode;
|
|
27
|
+
childNodes: TNode[];
|
|
28
|
+
childEdges?: TEdge[];
|
|
29
|
+
getNodesBounds?: (nodes: TNode[]) => Rect;
|
|
30
|
+
options?: CanvasLayoutOptions;
|
|
31
|
+
}): Map<string, XYPosition>;
|
|
32
|
+
//# sourceMappingURL=createCanvasDisplacement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCanvasDisplacement.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasDisplacement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,8BAA8B,EAC9B,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAC5E,KAAK,EAAE,KAAK,EAAE,EACd,YAAY,SAAM,EAClB,aAAa,SAAK,GAChB,IAAI,CA0BN;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAAE,MAAM,EAAE;IAC/F,aAAa,EAAE,KAAK,EAAE,CAAC;IACvB,UAAU,EAAE,KAAK,CAAC;IAClB,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,8BAA8B,CAAC;CACzC,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CA2G1B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,SAAS,UAAU,GAAG,UAAU,EACrC,KAAK,SAAS,UAAU,GAAG,UAAU,EACpC,MAAM,EAAE;IACT,aAAa,EAAE,KAAK,EAAE,CAAC;IACvB,aAAa,EAAE,KAAK,EAAE,CAAC;IACvB,UAAU,EAAE,KAAK,CAAC;IAClB,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC9B,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAyE1B"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import dagre from '@dagrejs/dagre';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.
|
|
4
|
+
*/
|
|
5
|
+
export function computeNodesBoundingBox(nodes, defaultWidth = 200, defaultHeight = 60) {
|
|
6
|
+
if (nodes.length === 0) {
|
|
7
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
8
|
+
}
|
|
9
|
+
let minX = Infinity;
|
|
10
|
+
let minY = Infinity;
|
|
11
|
+
let maxX = -Infinity;
|
|
12
|
+
let maxY = -Infinity;
|
|
13
|
+
for (const node of nodes) {
|
|
14
|
+
const width = node.measured?.width ?? node.width ?? defaultWidth;
|
|
15
|
+
const height = node.measured?.height ?? node.height ?? defaultHeight;
|
|
16
|
+
minX = Math.min(minX, node.position.x);
|
|
17
|
+
minY = Math.min(minY, node.position.y);
|
|
18
|
+
maxX = Math.max(maxX, node.position.x + width);
|
|
19
|
+
maxY = Math.max(maxY, node.position.y + height);
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
x: minX,
|
|
23
|
+
y: minY,
|
|
24
|
+
width: maxX - minX,
|
|
25
|
+
height: maxY - minY
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pure directional displacement calculation.
|
|
30
|
+
* Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.
|
|
31
|
+
*/
|
|
32
|
+
export function calculateDirectionalDisplacement(params) {
|
|
33
|
+
const { existingNodes, originNode, childNodes, getNodesBounds, options = {} } = params;
|
|
34
|
+
const { direction = 'right', gap = 40, spreadSiblingLanes = false, siblingTolerance = 50, minY } = options;
|
|
35
|
+
const displacedMap = new Map();
|
|
36
|
+
if (childNodes.length === 0 || existingNodes.length === 0) {
|
|
37
|
+
return displacedMap;
|
|
38
|
+
}
|
|
39
|
+
const childBounds = getNodesBounds
|
|
40
|
+
? getNodesBounds(childNodes)
|
|
41
|
+
: computeNodesBoundingBox(childNodes);
|
|
42
|
+
const originWidth = originNode.measured?.width ?? originNode.width ?? 200;
|
|
43
|
+
const originHeight = originNode.measured?.height ?? originNode.height ?? 60;
|
|
44
|
+
// The delta space required along primary axis
|
|
45
|
+
const deltaPrimary = (direction === 'right' || direction === 'left')
|
|
46
|
+
? childBounds.width + gap
|
|
47
|
+
: childBounds.height + gap;
|
|
48
|
+
// Vertical displacement parameters: upward and downward row clearance
|
|
49
|
+
const deltaUp = Math.max(0, originNode.position.y - childBounds.y + gap);
|
|
50
|
+
const deltaDown = Math.max(0, childBounds.y + childBounds.height - (originNode.position.y + originHeight) + gap);
|
|
51
|
+
// Both above and below displace equally so the row expands symmetrically
|
|
52
|
+
const equalDelta = Math.max(deltaUp, deltaDown);
|
|
53
|
+
for (const node of existingNodes) {
|
|
54
|
+
if (node.id === originNode.id)
|
|
55
|
+
continue;
|
|
56
|
+
let newX = node.position.x;
|
|
57
|
+
let newY = node.position.y;
|
|
58
|
+
let moved = false;
|
|
59
|
+
if (direction === 'right') {
|
|
60
|
+
// Downstream nodes strictly to the right of the origin
|
|
61
|
+
if (node.position.x >= originNode.position.x + originWidth * 0.5) {
|
|
62
|
+
newX += deltaPrimary;
|
|
63
|
+
moved = true;
|
|
64
|
+
}
|
|
65
|
+
else if (spreadSiblingLanes) {
|
|
66
|
+
// Sibling nodes occupying the same vertical space as the exploded cluster
|
|
67
|
+
const isVerticallyOverlapping = node.position.y + (node.height ?? 60) >= childBounds.y - gap &&
|
|
68
|
+
node.position.y <= childBounds.y + childBounds.height + gap;
|
|
69
|
+
if (isVerticallyOverlapping && Math.abs(node.position.x - originNode.position.x) <= siblingTolerance) {
|
|
70
|
+
const pushDirection = node.position.y >= originNode.position.y ? 1 : -1;
|
|
71
|
+
newY += pushDirection * (childBounds.height * 0.5 + gap);
|
|
72
|
+
moved = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (direction === 'left') {
|
|
77
|
+
if (node.position.x <= originNode.position.x) {
|
|
78
|
+
newX -= deltaPrimary;
|
|
79
|
+
moved = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (direction === 'down') {
|
|
83
|
+
if (node.position.y >= originNode.position.y + originHeight * 0.5) {
|
|
84
|
+
newY += deltaPrimary;
|
|
85
|
+
moved = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (direction === 'up') {
|
|
89
|
+
if (node.position.y <= originNode.position.y) {
|
|
90
|
+
newY -= deltaPrimary;
|
|
91
|
+
moved = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (direction === 'vertical') {
|
|
95
|
+
// Row grows vertically:
|
|
96
|
+
// Nodes strictly above the origin node move up by equalDelta
|
|
97
|
+
// Nodes strictly below the origin node move down by equalDelta
|
|
98
|
+
// Both above and below displace equally; horizontal position (x) is strictly preserved
|
|
99
|
+
if (node.position.y < originNode.position.y) {
|
|
100
|
+
if (equalDelta > 0) {
|
|
101
|
+
newY -= equalDelta;
|
|
102
|
+
moved = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (node.position.y >= originNode.position.y + originHeight * 0.5) {
|
|
106
|
+
if (equalDelta > 0) {
|
|
107
|
+
newY += equalDelta;
|
|
108
|
+
moved = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (moved) {
|
|
113
|
+
displacedMap.set(node.id, { x: newX, y: newY });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return displacedMap;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Pure hierarchical Dagre reflow displacement calculation.
|
|
120
|
+
* Calculates new coordinates for surrounding nodes using Dagre hierarchical layout,
|
|
121
|
+
* anchoring the origin node at its current position to eliminate layout jumping.
|
|
122
|
+
*/
|
|
123
|
+
export function calculateReflowDisplacement(params) {
|
|
124
|
+
const { existingNodes, existingEdges, originNode, childNodes, childEdges = [], options = {} } = params;
|
|
125
|
+
const { direction = 'LR', ranksep = 80, nodesep = 30, defaultNodeWidth = 200, defaultNodeHeight = 60 } = options;
|
|
126
|
+
const displacedMap = new Map();
|
|
127
|
+
if (existingNodes.length === 0)
|
|
128
|
+
return displacedMap;
|
|
129
|
+
const allNodes = [...existingNodes, ...childNodes];
|
|
130
|
+
const allEdges = [...existingEdges, ...childEdges];
|
|
131
|
+
const dagreGraph = new dagre.graphlib.Graph();
|
|
132
|
+
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
|
133
|
+
dagreGraph.setGraph({ rankdir: direction, ranksep, nodesep });
|
|
134
|
+
const allNodeIds = new Set(allNodes.map((n) => n.id));
|
|
135
|
+
allNodes.forEach((node) => {
|
|
136
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
137
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
138
|
+
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
|
|
139
|
+
});
|
|
140
|
+
allEdges.forEach((edge) => {
|
|
141
|
+
if (allNodeIds.has(edge.source) && allNodeIds.has(edge.target)) {
|
|
142
|
+
dagreGraph.setEdge(edge.source, edge.target);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
dagre.layout(dagreGraph);
|
|
146
|
+
const dagreOrigin = dagreGraph.node(originNode.id);
|
|
147
|
+
if (!dagreOrigin)
|
|
148
|
+
return displacedMap;
|
|
149
|
+
const originWidth = originNode.measured?.width ?? originNode.width ?? defaultNodeWidth;
|
|
150
|
+
const originHeight = originNode.measured?.height ?? originNode.height ?? defaultNodeHeight;
|
|
151
|
+
// Calculate offset so origin node remains anchored at its exact initial coordinates
|
|
152
|
+
const anchorOffsetX = originNode.position.x - (dagreOrigin.x - originWidth / 2);
|
|
153
|
+
const anchorOffsetY = originNode.position.y - (dagreOrigin.y - originHeight / 2);
|
|
154
|
+
existingNodes.forEach((node) => {
|
|
155
|
+
if (node.id === originNode.id)
|
|
156
|
+
return;
|
|
157
|
+
const dagreNode = dagreGraph.node(node.id);
|
|
158
|
+
if (!dagreNode)
|
|
159
|
+
return;
|
|
160
|
+
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
161
|
+
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
162
|
+
const targetX = dagreNode.x - nodeWidth / 2 + anchorOffsetX;
|
|
163
|
+
const targetY = dagreNode.y - nodeHeight / 2 + anchorOffsetY;
|
|
164
|
+
// Only include if position actually shifted
|
|
165
|
+
if (Math.abs(targetX - node.position.x) > 0.5 || Math.abs(targetY - node.position.y) > 0.5) {
|
|
166
|
+
displacedMap.set(node.id, { x: targetX, y: targetY });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return displacedMap;
|
|
170
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { XYPosition } from '@xyflow/svelte';
|
|
2
|
+
import type { CanvasNode, CanvasDockingCallbacks, DockStrategy } from './types.js';
|
|
3
|
+
export type { DockStrategy };
|
|
4
|
+
export interface CreateCanvasDockingOptions<TNode extends CanvasNode = CanvasNode> extends CanvasDockingCallbacks<TNode> {
|
|
5
|
+
isDockTarget?: (target: TNode) => boolean;
|
|
6
|
+
restorePositionOnDock?: boolean;
|
|
7
|
+
onSave?: () => void;
|
|
8
|
+
/**
|
|
9
|
+
* Disambiguation strategy when multiple candidate dock targets intersect the dragged node.
|
|
10
|
+
* - 'center-point': (Default) Resolves the target enclosing or closest to the dragged node's center.
|
|
11
|
+
* - 'max-overlap': Resolves the target with the greatest overlapping area.
|
|
12
|
+
* - 'pointer': Resolves the target enclosing or closest to the mouse/touch cursor.
|
|
13
|
+
* - 'first': Resolves the first intersecting target (legacy behavior).
|
|
14
|
+
*/
|
|
15
|
+
dockStrategy?: DockStrategy;
|
|
16
|
+
/**
|
|
17
|
+
* Custom primary dock target resolution callback. If provided and returns a node, takes precedence.
|
|
18
|
+
*/
|
|
19
|
+
resolvePrimaryDockTarget?: (targets: TNode[], draggedNode: TNode, event?: MouseEvent | TouchEvent) => TNode | null;
|
|
20
|
+
/**
|
|
21
|
+
* When true (default), ensures only a single primary dock target is considered hovered at any time.
|
|
22
|
+
* Transitioning across adjacent dock targets automatically fires onDockLeave on the previous target
|
|
23
|
+
* and onDockHover on the new target. Set to false to allow concurrent multi-target hover.
|
|
24
|
+
*/
|
|
25
|
+
exclusiveHover?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Headless Svelte 5 rune managing canvas node dragging, docking intersection, and connection tracking.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createCanvasDocking<TNode extends CanvasNode = CanvasNode>(options?: CreateCanvasDockingOptions<TNode>): {
|
|
31
|
+
readonly draggedNode: TNode | null;
|
|
32
|
+
readonly draggedInitialPosition: XYPosition | null;
|
|
33
|
+
readonly connectingHandle: string;
|
|
34
|
+
readonly connectingNode: TNode | null;
|
|
35
|
+
readonly isDragging: boolean;
|
|
36
|
+
handleNodeDragStart: (params: {
|
|
37
|
+
targetNode: TNode | null;
|
|
38
|
+
event?: MouseEvent | TouchEvent;
|
|
39
|
+
}) => void;
|
|
40
|
+
handleNodeDrag: (params: {
|
|
41
|
+
targetNode: TNode | null;
|
|
42
|
+
event?: MouseEvent | TouchEvent;
|
|
43
|
+
}, getIntersectingNodes: (node: TNode) => TNode[]) => void;
|
|
44
|
+
handleNodeDragStop: (params: {
|
|
45
|
+
targetNode: TNode | null;
|
|
46
|
+
event?: MouseEvent | TouchEvent;
|
|
47
|
+
}, getIntersectingNodes: (node: TNode) => TNode[], updateNodePosition?: (nodeId: string, position: XYPosition) => void) => void;
|
|
48
|
+
handleConnectStart: (params: {
|
|
49
|
+
nodeId: string | null;
|
|
50
|
+
handleId?: string | null;
|
|
51
|
+
handleType: "source" | "target" | null;
|
|
52
|
+
}, getNode: (id: string) => TNode | undefined) => void;
|
|
53
|
+
handleConnectEnd: () => void;
|
|
54
|
+
reset: () => void;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=createCanvasDocking.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCanvasDocking.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasDocking.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnF,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,0BAA0B,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,CAChF,SAAQ,sBAAsB,CAAC,KAAK,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,KAAK,OAAO,CAAC;IAC1C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,wBAAwB,CAAC,EAAE,CAC1B,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,KAAK,EAClB,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,KAC3B,KAAK,GAAG,IAAI,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAkJD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EACxE,OAAO,GAAE,0BAA0B,CAAC,KAAK,CAAM;;;;;;kCAYV;QACpC,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;KAChC,KAAG,IAAI;6BAOC;QACP,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;KAChC,wBACqB,CAAC,IAAI,EAAE,KAAK,KAAK,KAAK,EAAE,KAC5C,IAAI;iCAyDE;QACP,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;KAChC,wBACqB,CAAC,IAAI,EAAE,KAAK,KAAK,KAAK,EAAE,uBACzB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,KAAK,IAAI,KACjE,IAAI;iCAmCE;QACP,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;KACvC,WACQ,CAAC,EAAE,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,KACxC,IAAI;4BAKsB,IAAI;iBAKf,IAAI;EA+BtB"}
|