@canvas-harness/core 0.1.9 → 0.1.10
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/index.cjs +34 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -7
- package/dist/index.d.ts +37 -7
- package/dist/index.js +34 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2529,15 +2529,36 @@ type SerializedClipboard = {
|
|
|
2529
2529
|
*/
|
|
2530
2530
|
declare const serializeSelection: (store: CanvasStore) => SerializedClipboard;
|
|
2531
2531
|
type DeserializeOptions = {
|
|
2532
|
-
/**
|
|
2532
|
+
/**
|
|
2533
|
+
* Relative world-space offset added to every pasted node's `x/y`
|
|
2534
|
+
* (and to free-floating edge endpoints). Takes precedence over
|
|
2535
|
+
* `at` when both are passed. Default `(20, 20)` when neither is
|
|
2536
|
+
* given.
|
|
2537
|
+
*/
|
|
2533
2538
|
offset?: Vec2;
|
|
2539
|
+
/**
|
|
2540
|
+
* Absolute world-space target — the *center* of the pasted bbox
|
|
2541
|
+
* lands here. Used by `paste()` to place the paste at the cursor;
|
|
2542
|
+
* pass directly for programmatic absolute placement. Ignored if
|
|
2543
|
+
* `offset` is also set.
|
|
2544
|
+
*/
|
|
2545
|
+
at?: Vec2;
|
|
2534
2546
|
/** Override the selection on the store after applying. Default true. */
|
|
2535
2547
|
select?: boolean;
|
|
2536
2548
|
};
|
|
2537
2549
|
/**
|
|
2538
2550
|
* Applies a clipboard payload to the store. New ids are minted; edge
|
|
2539
|
-
* endpoints are rewired;
|
|
2540
|
-
*
|
|
2551
|
+
* endpoints are rewired; the resulting nodes + edges become the new
|
|
2552
|
+
* selection by default. Positioning precedence:
|
|
2553
|
+
*
|
|
2554
|
+
* 1. `opts.offset` (relative) — used as-is.
|
|
2555
|
+
* 2. `opts.at` (absolute) — offset computed so the clip's bbox
|
|
2556
|
+
* center lands on this point.
|
|
2557
|
+
* 3. Default — relative `(20, 20)` offset.
|
|
2558
|
+
*
|
|
2559
|
+
* Free-floating edge endpoints (`{ worldPoint }`) also receive the
|
|
2560
|
+
* offset so an edge with an unattached end stays connected to the
|
|
2561
|
+
* surrounding nodes after the paste.
|
|
2541
2562
|
*
|
|
2542
2563
|
* One `store.batch` — one undo step.
|
|
2543
2564
|
*
|
|
@@ -2577,8 +2598,17 @@ declare const cut: (store: CanvasStore) => Promise<SerializedClipboard>;
|
|
|
2577
2598
|
/**
|
|
2578
2599
|
* Paste from the system clipboard (or a supplied payload). Every node
|
|
2579
2600
|
* + edge gets a fresh id; edge endpoints rewire to the new ids; the
|
|
2580
|
-
*
|
|
2581
|
-
*
|
|
2601
|
+
* resulting nodes + edges become the new selection. Wrapped in one
|
|
2602
|
+
* undoable batch.
|
|
2603
|
+
*
|
|
2604
|
+
* Positioning, in precedence order:
|
|
2605
|
+
* 1. `opts.offset` — relative offset, used as-is.
|
|
2606
|
+
* 2. `opts.at` — absolute target; the paste's bbox center lands here.
|
|
2607
|
+
* 3. The store's current cursor (`interactionState.pointer`) — the
|
|
2608
|
+
* paste lands centered under the cursor. This is the default
|
|
2609
|
+
* `paste(store)` behavior on a Cmd+V keybind.
|
|
2610
|
+
* 4. Fallback `(20, 20)` relative offset when nothing else is known
|
|
2611
|
+
* (e.g. fresh session with no pointermove yet).
|
|
2582
2612
|
*
|
|
2583
2613
|
* Returns the new node ids on success, or `null` if the clipboard
|
|
2584
2614
|
* didn't contain a canvas-harness payload.
|
|
@@ -2587,8 +2617,8 @@ declare const cut: (store: CanvasStore) => Promise<SerializedClipboard>;
|
|
|
2587
2617
|
* <button onClick={() => paste(store)}>Paste</button>
|
|
2588
2618
|
*
|
|
2589
2619
|
* @example
|
|
2590
|
-
* // Programmatic paste
|
|
2591
|
-
* paste(store, savedClip, {
|
|
2620
|
+
* // Programmatic paste at a specific world point:
|
|
2621
|
+
* paste(store, savedClip, { at: { x: 300, y: 200 }, select: false })
|
|
2592
2622
|
*/
|
|
2593
2623
|
declare const paste: (store: CanvasStore, payload?: SerializedClipboard, opts?: DeserializeOptions) => Promise<(NodeId | EdgeId)[] | null>;
|
|
2594
2624
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2529,15 +2529,36 @@ type SerializedClipboard = {
|
|
|
2529
2529
|
*/
|
|
2530
2530
|
declare const serializeSelection: (store: CanvasStore) => SerializedClipboard;
|
|
2531
2531
|
type DeserializeOptions = {
|
|
2532
|
-
/**
|
|
2532
|
+
/**
|
|
2533
|
+
* Relative world-space offset added to every pasted node's `x/y`
|
|
2534
|
+
* (and to free-floating edge endpoints). Takes precedence over
|
|
2535
|
+
* `at` when both are passed. Default `(20, 20)` when neither is
|
|
2536
|
+
* given.
|
|
2537
|
+
*/
|
|
2533
2538
|
offset?: Vec2;
|
|
2539
|
+
/**
|
|
2540
|
+
* Absolute world-space target — the *center* of the pasted bbox
|
|
2541
|
+
* lands here. Used by `paste()` to place the paste at the cursor;
|
|
2542
|
+
* pass directly for programmatic absolute placement. Ignored if
|
|
2543
|
+
* `offset` is also set.
|
|
2544
|
+
*/
|
|
2545
|
+
at?: Vec2;
|
|
2534
2546
|
/** Override the selection on the store after applying. Default true. */
|
|
2535
2547
|
select?: boolean;
|
|
2536
2548
|
};
|
|
2537
2549
|
/**
|
|
2538
2550
|
* Applies a clipboard payload to the store. New ids are minted; edge
|
|
2539
|
-
* endpoints are rewired;
|
|
2540
|
-
*
|
|
2551
|
+
* endpoints are rewired; the resulting nodes + edges become the new
|
|
2552
|
+
* selection by default. Positioning precedence:
|
|
2553
|
+
*
|
|
2554
|
+
* 1. `opts.offset` (relative) — used as-is.
|
|
2555
|
+
* 2. `opts.at` (absolute) — offset computed so the clip's bbox
|
|
2556
|
+
* center lands on this point.
|
|
2557
|
+
* 3. Default — relative `(20, 20)` offset.
|
|
2558
|
+
*
|
|
2559
|
+
* Free-floating edge endpoints (`{ worldPoint }`) also receive the
|
|
2560
|
+
* offset so an edge with an unattached end stays connected to the
|
|
2561
|
+
* surrounding nodes after the paste.
|
|
2541
2562
|
*
|
|
2542
2563
|
* One `store.batch` — one undo step.
|
|
2543
2564
|
*
|
|
@@ -2577,8 +2598,17 @@ declare const cut: (store: CanvasStore) => Promise<SerializedClipboard>;
|
|
|
2577
2598
|
/**
|
|
2578
2599
|
* Paste from the system clipboard (or a supplied payload). Every node
|
|
2579
2600
|
* + edge gets a fresh id; edge endpoints rewire to the new ids; the
|
|
2580
|
-
*
|
|
2581
|
-
*
|
|
2601
|
+
* resulting nodes + edges become the new selection. Wrapped in one
|
|
2602
|
+
* undoable batch.
|
|
2603
|
+
*
|
|
2604
|
+
* Positioning, in precedence order:
|
|
2605
|
+
* 1. `opts.offset` — relative offset, used as-is.
|
|
2606
|
+
* 2. `opts.at` — absolute target; the paste's bbox center lands here.
|
|
2607
|
+
* 3. The store's current cursor (`interactionState.pointer`) — the
|
|
2608
|
+
* paste lands centered under the cursor. This is the default
|
|
2609
|
+
* `paste(store)` behavior on a Cmd+V keybind.
|
|
2610
|
+
* 4. Fallback `(20, 20)` relative offset when nothing else is known
|
|
2611
|
+
* (e.g. fresh session with no pointermove yet).
|
|
2582
2612
|
*
|
|
2583
2613
|
* Returns the new node ids on success, or `null` if the clipboard
|
|
2584
2614
|
* didn't contain a canvas-harness payload.
|
|
@@ -2587,8 +2617,8 @@ declare const cut: (store: CanvasStore) => Promise<SerializedClipboard>;
|
|
|
2587
2617
|
* <button onClick={() => paste(store)}>Paste</button>
|
|
2588
2618
|
*
|
|
2589
2619
|
* @example
|
|
2590
|
-
* // Programmatic paste
|
|
2591
|
-
* paste(store, savedClip, {
|
|
2620
|
+
* // Programmatic paste at a specific world point:
|
|
2621
|
+
* paste(store, savedClip, { at: { x: 300, y: 200 }, select: false })
|
|
2592
2622
|
*/
|
|
2593
2623
|
declare const paste: (store: CanvasStore, payload?: SerializedClipboard, opts?: DeserializeOptions) => Promise<(NodeId | EdgeId)[] | null>;
|
|
2594
2624
|
|
package/dist/index.js
CHANGED
|
@@ -5957,8 +5957,30 @@ var endInside = (end, ids) => {
|
|
|
5957
5957
|
if (!isAttached(end)) return true;
|
|
5958
5958
|
return ids.has(end.nodeId);
|
|
5959
5959
|
};
|
|
5960
|
+
var clipBboxCenter = (nodes) => {
|
|
5961
|
+
if (nodes.length === 0) return { x: 0, y: 0 };
|
|
5962
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
5963
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
5964
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
5965
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
5966
|
+
for (const n of nodes) {
|
|
5967
|
+
if (n.x < minX) minX = n.x;
|
|
5968
|
+
if (n.y < minY) minY = n.y;
|
|
5969
|
+
if (n.x + n.w > maxX) maxX = n.x + n.w;
|
|
5970
|
+
if (n.y + n.h > maxY) maxY = n.y + n.h;
|
|
5971
|
+
}
|
|
5972
|
+
return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
|
|
5973
|
+
};
|
|
5960
5974
|
var deserializeClipboard = (store, clip, opts = {}) => {
|
|
5961
|
-
|
|
5975
|
+
let offset;
|
|
5976
|
+
if (opts.offset) {
|
|
5977
|
+
offset = opts.offset;
|
|
5978
|
+
} else if (opts.at && clip.nodes.length > 0) {
|
|
5979
|
+
const center = clipBboxCenter(clip.nodes);
|
|
5980
|
+
offset = { x: opts.at.x - center.x, y: opts.at.y - center.y };
|
|
5981
|
+
} else {
|
|
5982
|
+
offset = { x: 20, y: 20 };
|
|
5983
|
+
}
|
|
5962
5984
|
const select = opts.select ?? true;
|
|
5963
5985
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
5964
5986
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
@@ -5971,7 +5993,9 @@ var deserializeClipboard = (store, clip, opts = {}) => {
|
|
|
5971
5993
|
y: n.y + offset.y
|
|
5972
5994
|
}));
|
|
5973
5995
|
const remapEnd = (end) => {
|
|
5974
|
-
if (!isAttached(end))
|
|
5996
|
+
if (!isAttached(end)) {
|
|
5997
|
+
return { worldPoint: { x: end.worldPoint.x + offset.x, y: end.worldPoint.y + offset.y } };
|
|
5998
|
+
}
|
|
5975
5999
|
const newId = nodeMap.get(end.nodeId);
|
|
5976
6000
|
return newId ? { nodeId: newId, localOffset: end.localOffset } : end;
|
|
5977
6001
|
};
|
|
@@ -6014,7 +6038,14 @@ var cut = async (store) => {
|
|
|
6014
6038
|
var paste = async (store, payload, opts) => {
|
|
6015
6039
|
const clip = payload ?? await readClipboard();
|
|
6016
6040
|
if (!clip) return null;
|
|
6017
|
-
|
|
6041
|
+
let effective = opts;
|
|
6042
|
+
if (!opts?.offset && !opts?.at) {
|
|
6043
|
+
const pointer = store.getInteractionState().pointer;
|
|
6044
|
+
if (pointer) {
|
|
6045
|
+
effective = { ...opts, at: { x: pointer.worldX, y: pointer.worldY } };
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
const ids = deserializeClipboard(store, clip, effective);
|
|
6018
6049
|
return ids;
|
|
6019
6050
|
};
|
|
6020
6051
|
var writeClipboard = async (clip) => {
|