@oh-just-another/state 0.57.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/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/actions/actionClipboard.d.ts +6 -0
- package/dist/actions/actionClipboard.d.ts.map +1 -0
- package/dist/actions/actionClipboard.js +26 -0
- package/dist/actions/actionClipboard.js.map +1 -0
- package/dist/actions/actionGrouping.d.ts +5 -0
- package/dist/actions/actionGrouping.d.ts.map +1 -0
- package/dist/actions/actionGrouping.js +26 -0
- package/dist/actions/actionGrouping.js.map +1 -0
- package/dist/actions/actionHistory.d.ts +5 -0
- package/dist/actions/actionHistory.d.ts.map +1 -0
- package/dist/actions/actionHistory.js +25 -0
- package/dist/actions/actionHistory.js.map +1 -0
- package/dist/actions/actionKeyboard.d.ts +3 -0
- package/dist/actions/actionKeyboard.d.ts.map +1 -0
- package/dist/actions/actionKeyboard.js +130 -0
- package/dist/actions/actionKeyboard.js.map +1 -0
- package/dist/actions/actionLayout.d.ts +3 -0
- package/dist/actions/actionLayout.d.ts.map +1 -0
- package/dist/actions/actionLayout.js +65 -0
- package/dist/actions/actionLayout.js.map +1 -0
- package/dist/actions/actionMode.d.ts +13 -0
- package/dist/actions/actionMode.d.ts.map +1 -0
- package/dist/actions/actionMode.js +116 -0
- package/dist/actions/actionMode.js.map +1 -0
- package/dist/actions/actionSelection.d.ts +9 -0
- package/dist/actions/actionSelection.d.ts.map +1 -0
- package/dist/actions/actionSelection.js +57 -0
- package/dist/actions/actionSelection.js.map +1 -0
- package/dist/actions/actionView.d.ts +7 -0
- package/dist/actions/actionView.d.ts.map +1 -0
- package/dist/actions/actionView.js +14 -0
- package/dist/actions/actionView.js.map +1 -0
- package/dist/actions/actionZOrder.d.ts +7 -0
- package/dist/actions/actionZOrder.d.ts.map +1 -0
- package/dist/actions/actionZOrder.js +42 -0
- package/dist/actions/actionZOrder.js.map +1 -0
- package/dist/actions/actionZoom.d.ts +8 -0
- package/dist/actions/actionZoom.d.ts.map +1 -0
- package/dist/actions/actionZoom.js +61 -0
- package/dist/actions/actionZoom.js.map +1 -0
- package/dist/actions/index.d.ts +12 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +11 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/registry.d.ts +68 -0
- package/dist/actions/registry.d.ts.map +1 -0
- package/dist/actions/registry.js +300 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/actions/types.d.ts +103 -0
- package/dist/actions/types.d.ts.map +1 -0
- package/dist/actions/types.js +10 -0
- package/dist/actions/types.js.map +1 -0
- package/dist/animation-tick.d.ts +28 -0
- package/dist/animation-tick.d.ts.map +1 -0
- package/dist/animation-tick.js +50 -0
- package/dist/animation-tick.js.map +1 -0
- package/dist/auto-compact.d.ts +27 -0
- package/dist/auto-compact.d.ts.map +1 -0
- package/dist/auto-compact.js +46 -0
- package/dist/auto-compact.js.map +1 -0
- package/dist/auto-layout-scheduler.d.ts +50 -0
- package/dist/auto-layout-scheduler.d.ts.map +1 -0
- package/dist/auto-layout-scheduler.js +94 -0
- package/dist/auto-layout-scheduler.js.map +1 -0
- package/dist/built-in-handlers.d.ts +24 -0
- package/dist/built-in-handlers.d.ts.map +1 -0
- package/dist/built-in-handlers.js +210 -0
- package/dist/built-in-handlers.js.map +1 -0
- package/dist/clipboard.d.ts +51 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +105 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/constants.d.ts +544 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +537 -0
- package/dist/constants.js.map +1 -0
- package/dist/dom-events.d.ts +13 -0
- package/dist/dom-events.d.ts.map +1 -0
- package/dist/dom-events.js +70 -0
- package/dist/dom-events.js.map +1 -0
- package/dist/editor/anchor-points.d.ts +22 -0
- package/dist/editor/anchor-points.d.ts.map +1 -0
- package/dist/editor/anchor-points.js +28 -0
- package/dist/editor/anchor-points.js.map +1 -0
- package/dist/editor/applies/create.d.ts +60 -0
- package/dist/editor/applies/create.d.ts.map +1 -0
- package/dist/editor/applies/create.js +107 -0
- package/dist/editor/applies/create.js.map +1 -0
- package/dist/editor/applies/edge.d.ts +32 -0
- package/dist/editor/applies/edge.d.ts.map +1 -0
- package/dist/editor/applies/edge.js +44 -0
- package/dist/editor/applies/edge.js.map +1 -0
- package/dist/editor/applies/link-move.d.ts +53 -0
- package/dist/editor/applies/link-move.d.ts.map +1 -0
- package/dist/editor/applies/link-move.js +160 -0
- package/dist/editor/applies/link-move.js.map +1 -0
- package/dist/editor/applies/move.d.ts +38 -0
- package/dist/editor/applies/move.d.ts.map +1 -0
- package/dist/editor/applies/move.js +83 -0
- package/dist/editor/applies/move.js.map +1 -0
- package/dist/editor/applies/resize.d.ts +68 -0
- package/dist/editor/applies/resize.d.ts.map +1 -0
- package/dist/editor/applies/resize.js +199 -0
- package/dist/editor/applies/resize.js.map +1 -0
- package/dist/editor/applies/selection.d.ts +34 -0
- package/dist/editor/applies/selection.d.ts.map +1 -0
- package/dist/editor/applies/selection.js +65 -0
- package/dist/editor/applies/selection.js.map +1 -0
- package/dist/editor/applies/snap-grid.d.ts +45 -0
- package/dist/editor/applies/snap-grid.d.ts.map +1 -0
- package/dist/editor/applies/snap-grid.js +90 -0
- package/dist/editor/applies/snap-grid.js.map +1 -0
- package/dist/editor/container-ops.d.ts +74 -0
- package/dist/editor/container-ops.d.ts.map +1 -0
- package/dist/editor/container-ops.js +262 -0
- package/dist/editor/container-ops.js.map +1 -0
- package/dist/editor/event-fanout.d.ts +48 -0
- package/dist/editor/event-fanout.d.ts.map +1 -0
- package/dist/editor/event-fanout.js +53 -0
- package/dist/editor/event-fanout.js.map +1 -0
- package/dist/editor/gesture-tx.d.ts +77 -0
- package/dist/editor/gesture-tx.d.ts.map +1 -0
- package/dist/editor/gesture-tx.js +93 -0
- package/dist/editor/gesture-tx.js.map +1 -0
- package/dist/editor/hit-test.d.ts +178 -0
- package/dist/editor/hit-test.d.ts.map +1 -0
- package/dist/editor/hit-test.js +460 -0
- package/dist/editor/hit-test.js.map +1 -0
- package/dist/editor/long-press.d.ts +34 -0
- package/dist/editor/long-press.d.ts.map +1 -0
- package/dist/editor/long-press.js +58 -0
- package/dist/editor/long-press.js.map +1 -0
- package/dist/editor/pinch.d.ts +37 -0
- package/dist/editor/pinch.d.ts.map +1 -0
- package/dist/editor/pinch.js +90 -0
- package/dist/editor/pinch.js.map +1 -0
- package/dist/editor/pointer-binding.d.ts +18 -0
- package/dist/editor/pointer-binding.d.ts.map +1 -0
- package/dist/editor/pointer-binding.js +1087 -0
- package/dist/editor/pointer-binding.js.map +1 -0
- package/dist/editor/public/annotations.d.ts +54 -0
- package/dist/editor/public/annotations.d.ts.map +1 -0
- package/dist/editor/public/annotations.js +106 -0
- package/dist/editor/public/annotations.js.map +1 -0
- package/dist/editor/public/arrange-group.d.ts +81 -0
- package/dist/editor/public/arrange-group.d.ts.map +1 -0
- package/dist/editor/public/arrange-group.js +193 -0
- package/dist/editor/public/arrange-group.js.map +1 -0
- package/dist/editor/public/brush.d.ts +33 -0
- package/dist/editor/public/brush.d.ts.map +1 -0
- package/dist/editor/public/brush.js +54 -0
- package/dist/editor/public/brush.js.map +1 -0
- package/dist/editor/public/clipboard.d.ts +31 -0
- package/dist/editor/public/clipboard.d.ts.map +1 -0
- package/dist/editor/public/clipboard.js +35 -0
- package/dist/editor/public/clipboard.js.map +1 -0
- package/dist/editor/public/image-insert.d.ts +30 -0
- package/dist/editor/public/image-insert.d.ts.map +1 -0
- package/dist/editor/public/image-insert.js +57 -0
- package/dist/editor/public/image-insert.js.map +1 -0
- package/dist/editor/public/layers.d.ts +56 -0
- package/dist/editor/public/layers.d.ts.map +1 -0
- package/dist/editor/public/layers.js +104 -0
- package/dist/editor/public/layers.js.map +1 -0
- package/dist/editor/public/link.d.ts +25 -0
- package/dist/editor/public/link.d.ts.map +1 -0
- package/dist/editor/public/link.js +74 -0
- package/dist/editor/public/link.js.map +1 -0
- package/dist/editor/public/placement.d.ts +60 -0
- package/dist/editor/public/placement.d.ts.map +1 -0
- package/dist/editor/public/placement.js +111 -0
- package/dist/editor/public/placement.js.map +1 -0
- package/dist/editor/public/selection-ops.d.ts +78 -0
- package/dist/editor/public/selection-ops.d.ts.map +1 -0
- package/dist/editor/public/selection-ops.js +226 -0
- package/dist/editor/public/selection-ops.js.map +1 -0
- package/dist/editor/public/text-edit.d.ts +17 -0
- package/dist/editor/public/text-edit.d.ts.map +1 -0
- package/dist/editor/public/text-edit.js +28 -0
- package/dist/editor/public/text-edit.js.map +1 -0
- package/dist/editor/public/z-order.d.ts +47 -0
- package/dist/editor/public/z-order.d.ts.map +1 -0
- package/dist/editor/public/z-order.js +151 -0
- package/dist/editor/public/z-order.js.map +1 -0
- package/dist/editor/public/zoom-pan.d.ts +44 -0
- package/dist/editor/public/zoom-pan.d.ts.map +1 -0
- package/dist/editor/public/zoom-pan.js +116 -0
- package/dist/editor/public/zoom-pan.js.map +1 -0
- package/dist/editor/render-orchestrator.d.ts +11 -0
- package/dist/editor/render-orchestrator.d.ts.map +1 -0
- package/dist/editor/render-orchestrator.js +473 -0
- package/dist/editor/render-orchestrator.js.map +1 -0
- package/dist/editor/resize-helpers.d.ts +30 -0
- package/dist/editor/resize-helpers.d.ts.map +1 -0
- package/dist/editor/resize-helpers.js +121 -0
- package/dist/editor/resize-helpers.js.map +1 -0
- package/dist/editor/shape-filters.d.ts +11 -0
- package/dist/editor/shape-filters.d.ts.map +1 -0
- package/dist/editor/shape-filters.js +19 -0
- package/dist/editor/shape-filters.js.map +1 -0
- package/dist/editor/shape-traits.d.ts +16 -0
- package/dist/editor/shape-traits.d.ts.map +1 -0
- package/dist/editor/shape-traits.js +29 -0
- package/dist/editor/shape-traits.js.map +1 -0
- package/dist/editor/viewport-helpers.d.ts +24 -0
- package/dist/editor/viewport-helpers.d.ts.map +1 -0
- package/dist/editor/viewport-helpers.js +63 -0
- package/dist/editor/viewport-helpers.js.map +1 -0
- package/dist/editor-events.d.ts +33 -0
- package/dist/editor-events.d.ts.map +1 -0
- package/dist/editor-events.js +2 -0
- package/dist/editor-events.js.map +1 -0
- package/dist/editor.d.ts +1841 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +4803 -0
- package/dist/editor.js.map +1 -0
- package/dist/file-drop.d.ts +99 -0
- package/dist/file-drop.d.ts.map +1 -0
- package/dist/file-drop.js +198 -0
- package/dist/file-drop.js.map +1 -0
- package/dist/frame-helpers.d.ts +30 -0
- package/dist/frame-helpers.d.ts.map +1 -0
- package/dist/frame-helpers.js +105 -0
- package/dist/frame-helpers.js.map +1 -0
- package/dist/group-helpers.d.ts +39 -0
- package/dist/group-helpers.d.ts.map +1 -0
- package/dist/group-helpers.js +116 -0
- package/dist/group-helpers.js.map +1 -0
- package/dist/handle.d.ts +73 -0
- package/dist/handle.d.ts.map +1 -0
- package/dist/handle.js +184 -0
- package/dist/handle.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.d.ts +21 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +11 -0
- package/dist/interactive.js.map +1 -0
- package/dist/link-selection.d.ts +21 -0
- package/dist/link-selection.d.ts.map +1 -0
- package/dist/link-selection.js +37 -0
- package/dist/link-selection.js.map +1 -0
- package/dist/machine.d.ts +322 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +568 -0
- package/dist/machine.js.map +1 -0
- package/dist/modes.d.ts +24 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +2 -0
- package/dist/modes.js.map +1 -0
- package/dist/overlay.d.ts +262 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +673 -0
- package/dist/overlay.js.map +1 -0
- package/dist/platform.d.ts +70 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +115 -0
- package/dist/platform.js.map +1 -0
- package/dist/selection.d.ts +18 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +31 -0
- package/dist/selection.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-layout-scheduler.d.ts","sourceRoot":"","sources":["../src/auto-layout-scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,KAAK,EAML,KAAK,KAAK,EACV,KAAK,KAAK,EACX,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,mBAAmB;IAIlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;gBAE9B,IAAI,EAAE,0BAA0B;IAE7D,8DAA8D;IAC9D,QAAQ,IAAI,IAAI;IAShB;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI;IAIzC,kEAAkE;IAClE,QAAQ,IAAI,IAAI;IAuBhB,OAAO,CAAC,YAAY;CA0BrB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC5C,iEAAiE;IACjE,QAAQ,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1E;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { apply, getAutoLayoutSpec, getDropZoneWorld, getElement, getElementWorldBounds, runAutoLayout, } from "@oh-just-another/scene";
|
|
2
|
+
/**
|
|
3
|
+
* Microtask-coalesced re-runner for shapes carrying
|
|
4
|
+
* `metadata.autoLayout`. The editor calls `schedule()` from `notify()`;
|
|
5
|
+
* the check walks every auto-layout parent, compares its children-set
|
|
6
|
+
* fingerprint against the previous run, and re-runs the layout when the
|
|
7
|
+
* set changed.
|
|
8
|
+
*
|
|
9
|
+
* Pure position edits inside an existing children set are ignored
|
|
10
|
+
* (fingerprint is sorted-ids only), so a manual nudge of a child
|
|
11
|
+
* isn't snapped back. Add / remove / reparent does trigger.
|
|
12
|
+
*/
|
|
13
|
+
export class AutoLayoutScheduler {
|
|
14
|
+
opts;
|
|
15
|
+
pending = false;
|
|
16
|
+
signatures = new Map();
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
}
|
|
20
|
+
/** Queue a check for the next microtask. Coalesces bursts. */
|
|
21
|
+
schedule() {
|
|
22
|
+
if (this.pending)
|
|
23
|
+
return;
|
|
24
|
+
this.pending = true;
|
|
25
|
+
queueMicrotask(() => {
|
|
26
|
+
this.pending = false;
|
|
27
|
+
this.runCheck();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Recompute and store the signature for a parent, used after the
|
|
32
|
+
* editor's public `runLayout(parentId)` to prevent the next
|
|
33
|
+
* scheduled check from firing a redundant second run.
|
|
34
|
+
*/
|
|
35
|
+
resetSignature(parentId) {
|
|
36
|
+
this.signatures.set(parentId, this.signatureFor(parentId));
|
|
37
|
+
}
|
|
38
|
+
/** Run the actual check + relayout immediately. Used by tests. */
|
|
39
|
+
runCheck() {
|
|
40
|
+
const scene = this.opts.getScene();
|
|
41
|
+
let mutated = false;
|
|
42
|
+
for (const parent of scene.elements.values()) {
|
|
43
|
+
if (!getAutoLayoutSpec(parent))
|
|
44
|
+
continue;
|
|
45
|
+
const sig = this.signatureFor(parent.id);
|
|
46
|
+
if (this.signatures.get(parent.id) === sig)
|
|
47
|
+
continue;
|
|
48
|
+
this.signatures.set(parent.id, sig);
|
|
49
|
+
const patch = runAutoLayout(this.opts.getScene(), parent.id);
|
|
50
|
+
if (!patch)
|
|
51
|
+
continue;
|
|
52
|
+
this.opts.applyPatch(patch);
|
|
53
|
+
// Grow container to fit children after they've been re-laid out.
|
|
54
|
+
// Per-child idempotent: `growContainer` is a no-op when the child
|
|
55
|
+
// already fits the drop-zone.
|
|
56
|
+
const post = this.opts.getScene();
|
|
57
|
+
for (const s of post.elements.values()) {
|
|
58
|
+
if (s.parentId === parent.id)
|
|
59
|
+
this.opts.growContainer(parent.id, s.id);
|
|
60
|
+
}
|
|
61
|
+
mutated = true;
|
|
62
|
+
}
|
|
63
|
+
if (mutated)
|
|
64
|
+
this.opts.onMutated();
|
|
65
|
+
}
|
|
66
|
+
signatureFor(parentId) {
|
|
67
|
+
const scene = this.opts.getScene();
|
|
68
|
+
const parent = getElement(scene, parentId);
|
|
69
|
+
const children = [...scene.elements.values()].filter((s) => s.parentId === parentId);
|
|
70
|
+
// Wrap containers reflow on drop-zone geometry (origin + width) AND
|
|
71
|
+
// child-size changes (not just child add/remove): fold the drop-zone
|
|
72
|
+
// top-left + width + each child's size into the signature so resizing the
|
|
73
|
+
// container, MOVING it, or resizing a child re-anchors children at the
|
|
74
|
+
// (top-left-pinned) drop-zone origin. Other kinds keep the ids-only
|
|
75
|
+
// fingerprint (a manual position nudge isn't snapped back).
|
|
76
|
+
if (parent && getAutoLayoutSpec(parent)?.kind === "wrap") {
|
|
77
|
+
const dz = getDropZoneWorld(parent);
|
|
78
|
+
const origin = dz ? `${Math.round(dz.x)},${Math.round(dz.y)}` : "0,0";
|
|
79
|
+
const innerW = dz ? Math.round(dz.width) : 0;
|
|
80
|
+
const parts = children
|
|
81
|
+
.map((s) => {
|
|
82
|
+
const b = getElementWorldBounds(s);
|
|
83
|
+
return `${s.id}:${Math.round(b.width)}x${Math.round(b.height)}`;
|
|
84
|
+
})
|
|
85
|
+
.sort();
|
|
86
|
+
return `o${origin}|w${innerW}|${parts.join(",")}`;
|
|
87
|
+
}
|
|
88
|
+
const ids = children.map((s) => s.id);
|
|
89
|
+
ids.sort();
|
|
90
|
+
return ids.join(",");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export { apply };
|
|
94
|
+
//# sourceMappingURL=auto-layout-scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-layout-scheduler.js","sourceRoot":"","sources":["../src/auto-layout-scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type FileDropHandler } from "./file-drop.js";
|
|
2
|
+
/**
|
|
3
|
+
* Built-in handler: any file matching IMAGE_MIME_TYPES becomes an
|
|
4
|
+
* ImageElement at the drop point. Measured size is downscaled to
|
|
5
|
+
* `DEFAULT_IMAGE_MAX_EDGE_PX` on the longer axis so huge phone
|
|
6
|
+
* snapshots arrive at a reasonable on-canvas size.
|
|
7
|
+
*
|
|
8
|
+
* Registered automatically by the Editor constructor; hosts that
|
|
9
|
+
* want different sizing can `unregisterFileDropHandler("image")`
|
|
10
|
+
* and supply their own.
|
|
11
|
+
*/
|
|
12
|
+
export declare const imageFileDropHandler: FileDropHandler;
|
|
13
|
+
/**
|
|
14
|
+
* Built-in video file-drop handler. Drops a `<video>` element into
|
|
15
|
+
* the hidden sink (autoplay + muted + loop so it advances frames
|
|
16
|
+
* without user-gesture limits), reads the natural dimensions, and
|
|
17
|
+
* inserts an image-shaped scene element pointing at the video
|
|
18
|
+
* element via `metadata.image`. The Canvas2D renderer accepts a
|
|
19
|
+
* video element through drawImage and reads its current frame.
|
|
20
|
+
* The editor's animation tick (`metadata.animated = true`) keeps
|
|
21
|
+
* the canvas in sync with the playing video.
|
|
22
|
+
*/
|
|
23
|
+
export declare const videoFileDropHandler: FileDropHandler;
|
|
24
|
+
//# sourceMappingURL=built-in-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in-handlers.d.ts","sourceRoot":"","sources":["../src/built-in-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAmBxB;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,eA+FlC,CAAC;AAiCF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,eAgDlC,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { DEFAULT_IMAGE_MAX_EDGE_PX } from "./constants.js";
|
|
2
|
+
import { isImageFile, isVideoFile, readFileAsDataURL, } from "./file-drop.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read an image data URL and return its natural pixel dimensions
|
|
5
|
+
* (loaded once via an off-screen `<img>` element).
|
|
6
|
+
*/
|
|
7
|
+
const measureImage = (dataUrl) => new Promise((resolve, reject) => {
|
|
8
|
+
if (typeof Image === "undefined") {
|
|
9
|
+
reject(new Error("Image() is not available in this environment"));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const img = new Image();
|
|
13
|
+
img.onload = () => { resolve({ width: img.naturalWidth, height: img.naturalHeight }); };
|
|
14
|
+
img.onerror = () => { reject(new Error("Failed to decode image data URL")); };
|
|
15
|
+
img.src = dataUrl;
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Built-in handler: any file matching IMAGE_MIME_TYPES becomes an
|
|
19
|
+
* ImageElement at the drop point. Measured size is downscaled to
|
|
20
|
+
* `DEFAULT_IMAGE_MAX_EDGE_PX` on the longer axis so huge phone
|
|
21
|
+
* snapshots arrive at a reasonable on-canvas size.
|
|
22
|
+
*
|
|
23
|
+
* Registered automatically by the Editor constructor; hosts that
|
|
24
|
+
* want different sizing can `unregisterFileDropHandler("image")`
|
|
25
|
+
* and supply their own.
|
|
26
|
+
*/
|
|
27
|
+
export const imageFileDropHandler = {
|
|
28
|
+
id: "image",
|
|
29
|
+
accept: (file) => isImageFile(file),
|
|
30
|
+
handle: async (file, { editor, worldPoint }) => {
|
|
31
|
+
// Register the blob in Scene.files first, then create an object-URL
|
|
32
|
+
// for renderer convenience. Scene.json ends up with just a small
|
|
33
|
+
// `fileId` reference instead of the full base64 dataURL, keeping the
|
|
34
|
+
// payload small even for large PNGs.
|
|
35
|
+
//
|
|
36
|
+
// The dataURL fallback path produces a usable `src` for the renderer
|
|
37
|
+
// where `URL.createObjectURL(blob)` is unavailable (headless / SSR):
|
|
38
|
+
// the file is read as a dataURL so the shape still has something to
|
|
39
|
+
// draw if a host renders it before the file blob lands.
|
|
40
|
+
const useObjectUrl = typeof URL !== "undefined" && typeof URL.createObjectURL === "function";
|
|
41
|
+
const fileId = await editor.addBinaryFile(file, file.name);
|
|
42
|
+
const src = useObjectUrl ? URL.createObjectURL(file) : await readFileAsDataURL(file);
|
|
43
|
+
const natural = await measureImage(src);
|
|
44
|
+
const max = DEFAULT_IMAGE_MAX_EDGE_PX;
|
|
45
|
+
const scale = Math.max(natural.width, natural.height) > max
|
|
46
|
+
? max / Math.max(natural.width, natural.height)
|
|
47
|
+
: 1;
|
|
48
|
+
const width = Math.round(natural.width * scale);
|
|
49
|
+
const height = Math.round(natural.height * scale);
|
|
50
|
+
// Land the image centered on the drop point.
|
|
51
|
+
const topLeft = {
|
|
52
|
+
x: worldPoint.x - width / 2,
|
|
53
|
+
y: worldPoint.y - height / 2,
|
|
54
|
+
};
|
|
55
|
+
// Pre-decoded `<img>` instance so the Canvas2D renderer can call
|
|
56
|
+
// drawImage() directly (canvas can't drawImage a raw string). GIFs
|
|
57
|
+
// animate natively in the element — the animation tick re-draws every
|
|
58
|
+
// frame.
|
|
59
|
+
//
|
|
60
|
+
// For animation the `<img>` must be attached to the DOM (Safari won't
|
|
61
|
+
// advance frames on a detached element, and Chrome/Firefox can also
|
|
62
|
+
// pause off-DOM elements). It is attached to a hidden container so the
|
|
63
|
+
// user never sees the raw image element.
|
|
64
|
+
const isGif = file.type === "image/gif" || /\.gif$/i.test(file.name);
|
|
65
|
+
let img = null;
|
|
66
|
+
if (typeof Image !== "undefined") {
|
|
67
|
+
img = new Image();
|
|
68
|
+
img.src = src;
|
|
69
|
+
if (typeof document !== "undefined") {
|
|
70
|
+
const sink = ensureAnimatedImageSink();
|
|
71
|
+
// Keep the element inside the viewport — browsers pause GIF frame
|
|
72
|
+
// advancement for images scrolled out of view as a power-saving
|
|
73
|
+
// measure, so an off-screen element would freeze on its first
|
|
74
|
+
// frame. It is pinned to the top-left corner and hidden via
|
|
75
|
+
// near-zero opacity + 1px size + z-index behind everything.
|
|
76
|
+
// Throttling keys off viewport-intersection, not opacity, so a
|
|
77
|
+
// 0.01-alpha 1px element keeps decoding frames while staying
|
|
78
|
+
// imperceptible to the user.
|
|
79
|
+
img.style.position = "fixed";
|
|
80
|
+
img.style.left = "0";
|
|
81
|
+
img.style.top = "0";
|
|
82
|
+
img.style.width = "1px";
|
|
83
|
+
img.style.height = "1px";
|
|
84
|
+
img.style.opacity = "0.01";
|
|
85
|
+
img.style.zIndex = "-1";
|
|
86
|
+
img.style.pointerEvents = "none";
|
|
87
|
+
sink.appendChild(img);
|
|
88
|
+
}
|
|
89
|
+
// Wait for the image to decode before handing it to the renderer; an
|
|
90
|
+
// undecoded element draws nothing and the user sees a flash of empty
|
|
91
|
+
// rectangle on first paint.
|
|
92
|
+
const el = img;
|
|
93
|
+
if (!el.complete) {
|
|
94
|
+
await new Promise((resolve) => {
|
|
95
|
+
el.onload = () => { resolve(); };
|
|
96
|
+
el.onerror = () => { resolve(); };
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// GIF animation goes through the adapter path: the raw bytes become
|
|
101
|
+
// `animationData`, and the renderer asks the registered "gif" adapter
|
|
102
|
+
// for the current frame (relying on the hidden `<img>` to advance
|
|
103
|
+
// frames is unreliable since browsers pause near-invisible elements).
|
|
104
|
+
// `animationData` is transient (an ArrayBuffer doesn't survive JSON) —
|
|
105
|
+
// on reload the editor rehydrates it from `Scene.files`.
|
|
106
|
+
const animationBytes = isGif ? await file.arrayBuffer() : undefined;
|
|
107
|
+
editor.insertImage({
|
|
108
|
+
src,
|
|
109
|
+
fileId,
|
|
110
|
+
width,
|
|
111
|
+
height,
|
|
112
|
+
position: topLeft,
|
|
113
|
+
...(img ? { image: img } : {}),
|
|
114
|
+
animated: isGif,
|
|
115
|
+
...(isGif ? { animationKind: "gif" } : {}),
|
|
116
|
+
...(animationBytes ? { animationData: animationBytes } : {}),
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Singleton hidden container that holds animated `<img>` elements so
|
|
122
|
+
* the browser keeps decoding their frames. One container per
|
|
123
|
+
* document; created lazily.
|
|
124
|
+
*
|
|
125
|
+
* Pinned to the viewport's top-left (`position:fixed; 0,0`) — not
|
|
126
|
+
* off-screen — because browsers pause GIF animation for elements
|
|
127
|
+
* outside the viewport. A 0×0 container with `overflow:visible`
|
|
128
|
+
* lets the 1px children sit at the corner; `pointer-events:none`
|
|
129
|
+
* and `z-index:-1` keep it from intercepting clicks or covering UI.
|
|
130
|
+
*/
|
|
131
|
+
const SINK_ID = "oh-just-another-animated-image-sink";
|
|
132
|
+
const ensureAnimatedImageSink = () => {
|
|
133
|
+
const existing = document.getElementById(SINK_ID);
|
|
134
|
+
if (existing)
|
|
135
|
+
return existing;
|
|
136
|
+
const div = document.createElement("div");
|
|
137
|
+
div.id = SINK_ID;
|
|
138
|
+
div.setAttribute("aria-hidden", "true");
|
|
139
|
+
div.style.position = "fixed";
|
|
140
|
+
div.style.left = "0";
|
|
141
|
+
div.style.top = "0";
|
|
142
|
+
div.style.width = "0";
|
|
143
|
+
div.style.height = "0";
|
|
144
|
+
div.style.overflow = "visible";
|
|
145
|
+
div.style.pointerEvents = "none";
|
|
146
|
+
div.style.zIndex = "-1";
|
|
147
|
+
document.body.appendChild(div);
|
|
148
|
+
return div;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Built-in video file-drop handler. Drops a `<video>` element into
|
|
152
|
+
* the hidden sink (autoplay + muted + loop so it advances frames
|
|
153
|
+
* without user-gesture limits), reads the natural dimensions, and
|
|
154
|
+
* inserts an image-shaped scene element pointing at the video
|
|
155
|
+
* element via `metadata.image`. The Canvas2D renderer accepts a
|
|
156
|
+
* video element through drawImage and reads its current frame.
|
|
157
|
+
* The editor's animation tick (`metadata.animated = true`) keeps
|
|
158
|
+
* the canvas in sync with the playing video.
|
|
159
|
+
*/
|
|
160
|
+
export const videoFileDropHandler = {
|
|
161
|
+
id: "video",
|
|
162
|
+
accept: (file) => isVideoFile(file),
|
|
163
|
+
handle: async (file, { editor, worldPoint }) => {
|
|
164
|
+
if (typeof document === "undefined")
|
|
165
|
+
return;
|
|
166
|
+
const url = URL.createObjectURL(file);
|
|
167
|
+
const video = document.createElement("video");
|
|
168
|
+
video.src = url;
|
|
169
|
+
video.muted = true;
|
|
170
|
+
video.loop = true;
|
|
171
|
+
video.playsInline = true;
|
|
172
|
+
video.autoplay = true;
|
|
173
|
+
const sink = ensureAnimatedImageSink();
|
|
174
|
+
video.style.position = "absolute";
|
|
175
|
+
video.style.left = "-99999px";
|
|
176
|
+
video.style.top = "-99999px";
|
|
177
|
+
video.style.width = "1px";
|
|
178
|
+
video.style.height = "1px";
|
|
179
|
+
sink.appendChild(video);
|
|
180
|
+
await new Promise((resolve) => {
|
|
181
|
+
const done = () => { resolve(); };
|
|
182
|
+
video.onloadedmetadata = done;
|
|
183
|
+
video.onerror = done;
|
|
184
|
+
});
|
|
185
|
+
const nW = video.videoWidth || 480;
|
|
186
|
+
const nH = video.videoHeight || 270;
|
|
187
|
+
const max = DEFAULT_IMAGE_MAX_EDGE_PX;
|
|
188
|
+
const scale = Math.max(nW, nH) > max ? max / Math.max(nW, nH) : 1;
|
|
189
|
+
const width = Math.round(nW * scale);
|
|
190
|
+
const height = Math.round(nH * scale);
|
|
191
|
+
const topLeft = {
|
|
192
|
+
x: worldPoint.x - width / 2,
|
|
193
|
+
y: worldPoint.y - height / 2,
|
|
194
|
+
};
|
|
195
|
+
// Best-effort play (some browsers require an interaction
|
|
196
|
+
// before allowing autoplay even when muted).
|
|
197
|
+
void video.play().catch(() => {
|
|
198
|
+
/* intentional no-op: autoplay rejection is expected before user interaction */
|
|
199
|
+
});
|
|
200
|
+
editor.insertImage({
|
|
201
|
+
src: url,
|
|
202
|
+
width,
|
|
203
|
+
height,
|
|
204
|
+
position: topLeft,
|
|
205
|
+
image: video,
|
|
206
|
+
animated: true,
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
//# sourceMappingURL=built-in-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in-handlers.js","sourceRoot":"","sources":["../src/built-in-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ElementId, Vec2 } from "@oh-just-another/types";
|
|
2
|
+
import { type Scene, type Element } from "@oh-just-another/scene";
|
|
3
|
+
import type { HistoryProvider } from "@oh-just-another/history";
|
|
4
|
+
/**
|
|
5
|
+
* Clipboard helpers.
|
|
6
|
+
*
|
|
7
|
+
* The Editor's internal clipboard buffer is an array of deep-cloned
|
|
8
|
+
* shapes — it survives across calls within one editor session;
|
|
9
|
+
* cross-tab paste is a host concern (`navigator.clipboard`).
|
|
10
|
+
*
|
|
11
|
+
* • `copyElements` — collect selection into a fresh buffer.
|
|
12
|
+
* • `pasteElements` — paste a buffer into the scene at a target
|
|
13
|
+
* centroid, returning the new selection.
|
|
14
|
+
*/
|
|
15
|
+
export interface PasteResult {
|
|
16
|
+
readonly scene: Scene;
|
|
17
|
+
readonly newIds: readonly ElementId[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Clone a shape for the clipboard buffer / paste output. Deep-clones the
|
|
21
|
+
* plain data (so later edits don't bleed into the buffer) but carries
|
|
22
|
+
* live runtime handles by reference instead of cloning them:
|
|
23
|
+
*
|
|
24
|
+
* - `metadata.image` — a decoded `HTMLImageElement`; `structuredClone`
|
|
25
|
+
* throws `DataCloneError` on DOM nodes.
|
|
26
|
+
* - `animationData` — the raw GIF/video buffer; large and re-derivable
|
|
27
|
+
* from `fileId`, so sharing the reference avoids copying megabytes.
|
|
28
|
+
*
|
|
29
|
+
* The live `<img>` / buffer is shared, so the pasted shape draws
|
|
30
|
+
* immediately (same as the original) and still references its `fileId`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const cloneElementForClipboard: (shape: Element) => Element;
|
|
33
|
+
/**
|
|
34
|
+
* Snapshot every selected shape into a fresh array. Uses
|
|
35
|
+
* {@link cloneElementForClipboard} so live runtime handles (decoded
|
|
36
|
+
* image element, animation buffer) survive — a plain `structuredClone`
|
|
37
|
+
* throws on the DOM `<img>` an image shape carries in `metadata.image`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const copyElements: (scene: Scene, selection: Iterable<ElementId>) => Element[];
|
|
40
|
+
/**
|
|
41
|
+
* Paste the clipboard into `scene` so that its centroid lands at
|
|
42
|
+
* `target` (when supplied) or `+10` from each shape's stored
|
|
43
|
+
* position (so duplicates stay visible). Relative offsets between
|
|
44
|
+
* clipboard items are preserved.
|
|
45
|
+
*
|
|
46
|
+
* Allocates new shape ids via the `genId` callback (so the Editor
|
|
47
|
+
* keeps owning the counter) and pushes patches into `history`.
|
|
48
|
+
* Returns the new scene + ids the caller should select.
|
|
49
|
+
*/
|
|
50
|
+
export declare const pasteElements: (scene: Scene, history: HistoryProvider, clipboard: readonly Element[], target: Vec2 | null, genId: () => ElementId) => PasteResult;
|
|
51
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAML,KAAK,KAAK,EACV,KAAK,OAAO,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;CACvC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,OAmBzD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GACvB,OAAO,KAAK,EACZ,WAAW,QAAQ,CAAC,SAAS,CAAC,KAC7B,OAAO,EAOT,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,KAAK,EACZ,SAAS,eAAe,EACxB,WAAW,SAAS,OAAO,EAAE,EAC7B,QAAQ,IAAI,GAAG,IAAI,EACnB,OAAO,MAAM,SAAS,KACrB,WA8CF,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { addElement, batch, getElement, orderForTop, } from "@oh-just-another/scene";
|
|
2
|
+
/**
|
|
3
|
+
* Clone a shape for the clipboard buffer / paste output. Deep-clones the
|
|
4
|
+
* plain data (so later edits don't bleed into the buffer) but carries
|
|
5
|
+
* live runtime handles by reference instead of cloning them:
|
|
6
|
+
*
|
|
7
|
+
* - `metadata.image` — a decoded `HTMLImageElement`; `structuredClone`
|
|
8
|
+
* throws `DataCloneError` on DOM nodes.
|
|
9
|
+
* - `animationData` — the raw GIF/video buffer; large and re-derivable
|
|
10
|
+
* from `fileId`, so sharing the reference avoids copying megabytes.
|
|
11
|
+
*
|
|
12
|
+
* The live `<img>` / buffer is shared, so the pasted shape draws
|
|
13
|
+
* immediately (same as the original) and still references its `fileId`.
|
|
14
|
+
*/
|
|
15
|
+
export const cloneElementForClipboard = (shape) => {
|
|
16
|
+
const meta = shape.metadata;
|
|
17
|
+
const liveImage = meta && "image" in meta ? meta.image : undefined;
|
|
18
|
+
const liveAnim = shape.animationData;
|
|
19
|
+
// Strip the live handles, deep-clone the rest, then re-attach by ref.
|
|
20
|
+
const stripped = { ...shape };
|
|
21
|
+
if (liveAnim !== undefined)
|
|
22
|
+
delete stripped.animationData;
|
|
23
|
+
if (meta) {
|
|
24
|
+
const m = { ...meta };
|
|
25
|
+
delete m.image;
|
|
26
|
+
stripped.metadata = m;
|
|
27
|
+
}
|
|
28
|
+
const cloned = structuredClone(stripped);
|
|
29
|
+
if (liveImage !== undefined) {
|
|
30
|
+
cloned.metadata = { ...cloned.metadata, image: liveImage };
|
|
31
|
+
}
|
|
32
|
+
if (liveAnim !== undefined)
|
|
33
|
+
cloned.animationData = liveAnim;
|
|
34
|
+
return cloned;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Snapshot every selected shape into a fresh array. Uses
|
|
38
|
+
* {@link cloneElementForClipboard} so live runtime handles (decoded
|
|
39
|
+
* image element, animation buffer) survive — a plain `structuredClone`
|
|
40
|
+
* throws on the DOM `<img>` an image shape carries in `metadata.image`.
|
|
41
|
+
*/
|
|
42
|
+
export const copyElements = (scene, selection) => {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const id of selection) {
|
|
45
|
+
const s = getElement(scene, id);
|
|
46
|
+
if (s)
|
|
47
|
+
out.push(cloneElementForClipboard(s));
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Paste the clipboard into `scene` so that its centroid lands at
|
|
53
|
+
* `target` (when supplied) or `+10` from each shape's stored
|
|
54
|
+
* position (so duplicates stay visible). Relative offsets between
|
|
55
|
+
* clipboard items are preserved.
|
|
56
|
+
*
|
|
57
|
+
* Allocates new shape ids via the `genId` callback (so the Editor
|
|
58
|
+
* keeps owning the counter) and pushes patches into `history`.
|
|
59
|
+
* Returns the new scene + ids the caller should select.
|
|
60
|
+
*/
|
|
61
|
+
export const pasteElements = (scene, history, clipboard, target, genId) => {
|
|
62
|
+
if (clipboard.length === 0)
|
|
63
|
+
return { scene, newIds: [] };
|
|
64
|
+
let cx = 0;
|
|
65
|
+
let cy = 0;
|
|
66
|
+
for (const s of clipboard) {
|
|
67
|
+
cx += s.position.x;
|
|
68
|
+
cy += s.position.y;
|
|
69
|
+
}
|
|
70
|
+
cx /= clipboard.length;
|
|
71
|
+
cy /= clipboard.length;
|
|
72
|
+
const delta = target
|
|
73
|
+
? { x: target.x - cx, y: target.y - cy }
|
|
74
|
+
: { x: 10, y: 10 };
|
|
75
|
+
// Build the patch list first, push as one batch. `history.transaction()`
|
|
76
|
+
// is intentionally avoided: an Editor with an open gesture-transaction
|
|
77
|
+
// (drag/resize in flight) would make `transaction()` throw "A transaction
|
|
78
|
+
// is already open". The batch-push path doesn't nest, so paste is always
|
|
79
|
+
// safe to call.
|
|
80
|
+
const patches = [];
|
|
81
|
+
const newIds = [];
|
|
82
|
+
let next = scene;
|
|
83
|
+
for (const tmpl of clipboard) {
|
|
84
|
+
const newId = genId();
|
|
85
|
+
const order = orderForTop([...next.elements.values()]
|
|
86
|
+
.filter((s) => s.layerId === tmpl.layerId)
|
|
87
|
+
.map((s) => s.order));
|
|
88
|
+
const clone = {
|
|
89
|
+
...cloneElementForClipboard(tmpl),
|
|
90
|
+
id: newId,
|
|
91
|
+
position: { x: tmpl.position.x + delta.x, y: tmpl.position.y + delta.y },
|
|
92
|
+
order,
|
|
93
|
+
};
|
|
94
|
+
const r = addElement(next, clone);
|
|
95
|
+
next = r.scene;
|
|
96
|
+
patches.push(r.patch);
|
|
97
|
+
newIds.push(newId);
|
|
98
|
+
}
|
|
99
|
+
const first = patches[0];
|
|
100
|
+
if (first !== undefined) {
|
|
101
|
+
history.push(patches.length === 1 ? first : batch(patches));
|
|
102
|
+
}
|
|
103
|
+
return { scene: next, newIds };
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"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"}
|