@dxos/plugin-tldraw 0.10.0 → 0.11.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.
- package/dist/lib/TldrawPlugin.mjs +4 -5
- package/dist/lib/TldrawPlugin.mjs.map +1 -1
- package/dist/lib/capabilities.mjs +2 -2
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/chunk-TldrawArticle.mjs +10 -9
- package/dist/lib/chunk-TldrawArticle.mjs.map +1 -1
- package/dist/lib/chunk-TldrawCard.mjs +5 -5
- package/dist/lib/chunk-TldrawCard.mjs.map +1 -1
- package/dist/lib/chunk-drawing-variant.mjs +20 -0
- package/dist/lib/chunk-drawing-variant.mjs.map +1 -0
- package/dist/lib/chunk-meta.mjs +1 -0
- package/dist/lib/chunk-meta.mjs.map +1 -1
- package/dist/lib/chunk-types.mjs +5 -31
- package/dist/lib/chunk-types.mjs.map +1 -1
- package/dist/lib/components.mjs +1 -1
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/hooks.mjs +5 -5
- package/dist/lib/hooks.mjs.map +1 -1
- package/dist/lib/index.mjs +1 -1
- package/dist/lib/model.mjs +58 -163
- package/dist/lib/model.mjs.map +1 -1
- package/dist/lib/types.mjs +1 -1
- package/dist/types/src/TldrawPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/{sketch-variant.d.ts → drawing-variant.d.ts} +1 -1
- package/dist/types/src/capabilities/drawing-variant.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/components/Canvas/Canvas.d.ts +4 -3
- package/dist/types/src/components/Canvas/Canvas.d.ts.map +1 -1
- package/dist/types/src/components/Canvas/Canvas.stories.d.ts.map +1 -1
- package/dist/types/src/components/Canvas/Mermaid.stories.d.ts +14 -0
- package/dist/types/src/components/Canvas/Mermaid.stories.d.ts.map +1 -0
- package/dist/types/src/components/actions.d.ts +2 -2
- package/dist/types/src/components/actions.d.ts.map +1 -1
- package/dist/types/src/containers/TldrawArticle/TldrawArticle.d.ts +3 -3
- package/dist/types/src/containers/TldrawArticle/TldrawArticle.d.ts.map +1 -1
- package/dist/types/src/containers/TldrawCard/TldrawCard.d.ts +2 -2
- package/dist/types/src/containers/TldrawCard/TldrawCard.d.ts.map +1 -1
- package/dist/types/src/containers/TldrawCard/TldrawCard.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useStoreAdapter.d.ts +2 -2
- package/dist/types/src/hooks/useStoreAdapter.d.ts.map +1 -1
- package/dist/types/src/model/{TldrawBuilder.d.ts → RecordBuilder.d.ts} +3 -3
- package/dist/types/src/model/{TldrawBuilder.d.ts.map → RecordBuilder.d.ts.map} +1 -1
- package/dist/types/src/model/RecordBuilder.test.d.ts +2 -0
- package/dist/types/src/model/RecordBuilder.test.d.ts.map +1 -0
- package/dist/types/src/model/builder.d.ts +7 -2
- package/dist/types/src/model/builder.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -2
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/read.d.ts +1 -1
- package/dist/types/src/model/read.d.ts.map +1 -1
- package/dist/types/src/model/render.d.ts +1 -1
- package/dist/types/src/types/Tldraw.d.ts +3 -22
- package/dist/types/src/types/Tldraw.d.ts.map +1 -1
- package/dist/types/src/types/TldrawCapabilities.d.ts +1 -1
- package/dist/types/src/types/TldrawCapabilities.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -0
- package/package.json +33 -32
- package/src/TldrawPlugin.tsx +3 -5
- package/src/capabilities/{sketch-variant.ts → drawing-variant.ts} +7 -8
- package/src/capabilities/index.ts +1 -1
- package/src/components/Canvas/Canvas.stories.tsx +11 -7
- package/src/components/Canvas/Canvas.tsx +3 -2
- package/src/components/Canvas/Mermaid.stories.tsx +68 -0
- package/src/components/actions.ts +2 -3
- package/src/containers/TldrawArticle/TldrawArticle.tsx +8 -7
- package/src/containers/TldrawCard/TldrawCard.stories.tsx +8 -7
- package/src/containers/TldrawCard/TldrawCard.tsx +4 -4
- package/src/hooks/useStoreAdapter.ts +2 -1
- package/src/model/{TldrawBuilder.test.ts → RecordBuilder.test.ts} +8 -8
- package/src/model/{TldrawBuilder.ts → RecordBuilder.ts} +2 -2
- package/src/model/builder.ts +55 -18
- package/src/model/index.ts +1 -2
- package/src/model/read.ts +1 -1
- package/src/model/render.ts +3 -3
- package/src/model/scene.test.ts +1 -1
- package/src/types/Tldraw.ts +3 -30
- package/src/types/TldrawCapabilities.ts +1 -1
- package/src/variant.test.ts +19 -21
- package/dist/lib/chunk-sketch-variant.mjs +0 -23
- package/dist/lib/chunk-sketch-variant.mjs.map +0 -1
- package/dist/types/src/capabilities/sketch-variant.d.ts.map +0 -1
- package/dist/types/src/model/TldrawBuilder.test.d.ts +0 -2
- package/dist/types/src/model/TldrawBuilder.test.d.ts.map +0 -1
- package/dist/types/src/model/apply.d.ts +0 -5
- package/dist/types/src/model/apply.d.ts.map +0 -1
- package/src/model/apply.ts +0 -132
package/src/model/scene.test.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { describe, test } from 'vitest';
|
|
|
7
7
|
|
|
8
8
|
import { type Scene } from '@dxos/plugin-illustrator/model';
|
|
9
9
|
|
|
10
|
-
import { applyCommands } from './
|
|
10
|
+
import { applyCommands } from './builder';
|
|
11
11
|
import { readScene } from './read';
|
|
12
12
|
|
|
13
13
|
/** A face made of every element category: boxes, circles, arc sugar, polyline, text. */
|
package/src/types/Tldraw.ts
CHANGED
|
@@ -4,35 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
// @import-as-namespace
|
|
6
6
|
|
|
7
|
-
import * as Schema from 'effect/Schema';
|
|
8
|
-
|
|
9
|
-
import { DXN, Obj, Type } from '@dxos/echo';
|
|
10
|
-
import { HiddenAnnotation } from '@dxos/echo/Annotation';
|
|
11
|
-
|
|
12
|
-
export const TLDRAW_SCHEMA = 'tldraw.com/2';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Persisted tldraw canvas: an opaque map of RecordId → TLRecord managed by the store adapter.
|
|
16
|
-
* Referenced by the base `Sketch` (plugin-illustrator) as its renderer-specific canvas.
|
|
17
|
-
* Keeps the pre-variant typename (`org.dxos.type.canvas`) so existing stored sketches load
|
|
18
|
-
* without a data migration.
|
|
19
|
-
*/
|
|
20
|
-
export class Canvas extends Type.makeObject<Canvas>(DXN.make('org.dxos.type.canvas', '0.1.0'))(
|
|
21
|
-
Schema.Struct({
|
|
22
|
-
/** Fully qualified external schema reference. */
|
|
23
|
-
// TODO(wittjosiah): Remove once the schema is fully internalized.
|
|
24
|
-
schema: Schema.String.pipe(Schema.optional),
|
|
25
|
-
content: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
26
|
-
}).pipe(HiddenAnnotation.set(true)),
|
|
27
|
-
) {}
|
|
28
|
-
|
|
29
|
-
export type MakeOptions = Partial<Obj.MakeProps<typeof Canvas>>;
|
|
30
|
-
|
|
31
7
|
/**
|
|
32
|
-
*
|
|
8
|
+
* Renderer dialect stored on `Drawing.Canvas.schema`; how a canvas is matched to this variant.
|
|
9
|
+
* The canvas type itself is the base `Drawing.Canvas` — tldraw adds no fields of its own.
|
|
33
10
|
*/
|
|
34
|
-
export const
|
|
35
|
-
Obj.make(Canvas, { schema, content });
|
|
36
|
-
|
|
37
|
-
/** Type guard for {@link Canvas} objects. */
|
|
38
|
-
export const isCanvas = (object: unknown): object is Canvas => Obj.instanceOf(Canvas, object);
|
|
11
|
+
export const TLDRAW_SCHEMA = 'tldraw.com/2';
|
package/src/variant.test.ts
CHANGED
|
@@ -11,17 +11,17 @@ import { describe } from 'vitest';
|
|
|
11
11
|
import { AssistantTestLayer } from '@dxos/agent-runtime/testing';
|
|
12
12
|
import { Capability, CapabilityManager } from '@dxos/app-framework';
|
|
13
13
|
import { Operation } from '@dxos/compute';
|
|
14
|
-
import { Database, Ref
|
|
14
|
+
import { Database, Ref } from '@dxos/echo';
|
|
15
15
|
import { TestHelpers } from '@dxos/effect/testing';
|
|
16
16
|
import { EntityId } from '@dxos/keys';
|
|
17
17
|
import {
|
|
18
|
+
Drawing,
|
|
19
|
+
DrawingOperation,
|
|
18
20
|
IllustratorCapabilities,
|
|
19
21
|
IllustratorOperationHandlerSet,
|
|
20
|
-
Sketch,
|
|
21
|
-
SketchOperation,
|
|
22
22
|
} from '@dxos/plugin-illustrator';
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import { TldrawBuilder } from '#model';
|
|
25
25
|
|
|
26
26
|
import { Tldraw } from './types';
|
|
27
27
|
|
|
@@ -30,21 +30,19 @@ EntityId.dangerouslyDisableRandomness();
|
|
|
30
30
|
const TestLayer = AssistantTestLayer({
|
|
31
31
|
operationHandlers: IllustratorOperationHandlerSet,
|
|
32
32
|
extraServices: Layer.sync(Capability.Service, () => capabilityService()),
|
|
33
|
-
types: [
|
|
33
|
+
types: [Drawing.Drawing, Drawing.Canvas],
|
|
34
34
|
disableLlmMemoization: true,
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
/** Capability manager pre-loaded with the tldraw
|
|
37
|
+
/** Capability manager pre-loaded with the tldraw drawing variant, as the plugin would contribute it. */
|
|
38
38
|
const capabilityService = () => {
|
|
39
39
|
const manager = CapabilityManager.make({ registry: Registry.make() });
|
|
40
40
|
manager.contribute({
|
|
41
41
|
interface: IllustratorCapabilities.VariantProvider,
|
|
42
42
|
implementation: {
|
|
43
|
-
id:
|
|
43
|
+
id: Tldraw.TLDRAW_SCHEMA,
|
|
44
44
|
label: 'tldraw',
|
|
45
|
-
|
|
46
|
-
createCanvas: () => Effect.sync(() => Tldraw.makeCanvas()),
|
|
47
|
-
builder: tldrawBuilder,
|
|
45
|
+
builder: TldrawBuilder,
|
|
48
46
|
},
|
|
49
47
|
module: 'test',
|
|
50
48
|
});
|
|
@@ -56,19 +54,19 @@ const capabilityService = () => {
|
|
|
56
54
|
* add a hat and edit the smile by id, and confirm the untouched face elements survive.
|
|
57
55
|
* Exercises the illustrator operations end-to-end through the tldraw builder.
|
|
58
56
|
*/
|
|
59
|
-
describe('tldraw
|
|
57
|
+
describe('tldraw drawing variant', () => {
|
|
60
58
|
it.effect(
|
|
61
59
|
'create → edit → read round-trip preserves untouched objects',
|
|
62
60
|
Effect.fnUntraced(
|
|
63
61
|
function* ({ expect }) {
|
|
64
|
-
const { object:
|
|
65
|
-
yield* Database.add(
|
|
62
|
+
const { object: drawing } = yield* Operation.invoke(DrawingOperation.Create, { name: 'Portrait' });
|
|
63
|
+
yield* Database.add(drawing);
|
|
66
64
|
yield* Database.flush();
|
|
67
|
-
const ref = Ref.make(
|
|
65
|
+
const ref = Ref.make(drawing);
|
|
68
66
|
|
|
69
67
|
// Draw a face.
|
|
70
|
-
const face = yield* Operation.invoke(
|
|
71
|
-
|
|
68
|
+
const face = yield* Operation.invoke(DrawingOperation.Edit, {
|
|
69
|
+
drawing: ref,
|
|
72
70
|
commands: [
|
|
73
71
|
{
|
|
74
72
|
op: 'upsert-object',
|
|
@@ -90,14 +88,14 @@ describe('tldraw sketch variant', () => {
|
|
|
90
88
|
expect(face.scene.objects).toHaveLength(1);
|
|
91
89
|
|
|
92
90
|
// Read the scene (what the agent would do before a follow-up edit).
|
|
93
|
-
const read = yield* Operation.invoke(
|
|
91
|
+
const read = yield* Operation.invoke(DrawingOperation.Read, { drawing: ref });
|
|
94
92
|
const readFace = read.scene.objects.find((object) => object.id === 'face');
|
|
95
93
|
expect(readFace?.origin).toEqual({ x: 100, y: 100 });
|
|
96
94
|
expect(readFace?.elements.map((element) => element.id)).toEqual(['head', 'left-eye', 'right-eye', 'smile']);
|
|
97
95
|
|
|
98
96
|
// Add a hat above the face and turn the smile into a frown — by id, without resending the face.
|
|
99
|
-
const edit = yield* Operation.invoke(
|
|
100
|
-
|
|
97
|
+
const edit = yield* Operation.invoke(DrawingOperation.Edit, {
|
|
98
|
+
drawing: ref,
|
|
101
99
|
commands: [
|
|
102
100
|
{
|
|
103
101
|
op: 'upsert-object',
|
|
@@ -128,8 +126,8 @@ describe('tldraw sketch variant', () => {
|
|
|
128
126
|
);
|
|
129
127
|
|
|
130
128
|
// Remove the hat again.
|
|
131
|
-
const removed = yield* Operation.invoke(
|
|
132
|
-
|
|
129
|
+
const removed = yield* Operation.invoke(DrawingOperation.Edit, {
|
|
130
|
+
drawing: ref,
|
|
133
131
|
commands: [{ op: 'remove-object', objectId: 'hat' }],
|
|
134
132
|
});
|
|
135
133
|
expect(removed.scene.objects.map((object) => object.id)).toEqual(['face']);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { i as makeCanvas, n as Canvas } from "./chunk-types.mjs";
|
|
2
|
-
import { Capability } from "@dxos/app-framework";
|
|
3
|
-
import { Type } from "@dxos/echo";
|
|
4
|
-
import * as Effect from "effect/Effect";
|
|
5
|
-
import { IllustratorCapabilities } from "@dxos/plugin-illustrator/types";
|
|
6
|
-
import { TldrawArticle, TldrawCard } from "#containers";
|
|
7
|
-
import { tldrawBuilder } from "#model";
|
|
8
|
-
//#region src/capabilities/sketch-variant.ts
|
|
9
|
-
var variant = {
|
|
10
|
-
id: Type.getTypename(Canvas),
|
|
11
|
-
label: "tldraw",
|
|
12
|
-
icon: "ph--compass-tool--regular",
|
|
13
|
-
canvasType: Canvas,
|
|
14
|
-
createCanvas: () => Effect.sync(() => makeCanvas()),
|
|
15
|
-
builder: tldrawBuilder,
|
|
16
|
-
card: TldrawCard,
|
|
17
|
-
article: TldrawArticle
|
|
18
|
-
};
|
|
19
|
-
var sketch_variant_default = Capability.makeModule(() => Effect.succeed(Capability.contributes(IllustratorCapabilities.VariantProvider, variant)));
|
|
20
|
-
//#endregion
|
|
21
|
-
export { sketch_variant_default as default };
|
|
22
|
-
|
|
23
|
-
//# sourceMappingURL=chunk-sketch-variant.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-sketch-variant.mjs","names":[],"sources":["../../src/capabilities/sketch-variant.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport { Type } from '@dxos/echo';\nimport { IllustratorCapabilities, type SketchVariant } from '@dxos/plugin-illustrator/types';\n\nimport { TldrawArticle, TldrawCard } from '#containers';\nimport { tldrawBuilder } from '#model';\n\nimport { Tldraw } from '../types';\n\nconst variant: SketchVariant = {\n id: Type.getTypename(Tldraw.Canvas),\n label: 'tldraw',\n icon: 'ph--compass-tool--regular',\n canvasType: Tldraw.Canvas,\n createCanvas: () => Effect.sync(() => Tldraw.makeCanvas()),\n builder: tldrawBuilder,\n card: TldrawCard,\n article: TldrawArticle,\n};\n\nexport default Capability.makeModule(() =>\n Effect.succeed(Capability.contributes(IllustratorCapabilities.VariantProvider, variant)),\n);\n"],"mappings":";;;;;;;;AAeA,IAAM,UAAyB;CAC7B,IAAI,KAAK,YAAY,MAAa;CAClC,OAAO;CACP,MAAM;CACN,YAAY;CACZ,oBAAoB,OAAO,WAAW,WAAkB,CAAC;CACzD,SAAS;CACT,MAAM;CACN,SAAS;AACX;AAEA,IAAA,yBAAe,WAAW,iBACxB,OAAO,QAAQ,WAAW,YAAY,wBAAwB,iBAAiB,OAAO,CAAC,CACzF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sketch-variant.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/sketch-variant.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TldrawBuilder.test.d.ts","sourceRoot":"","sources":["../../../../src/model/TldrawBuilder.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type ApplyResult, type Scene } from '@dxos/plugin-illustrator/model';
|
|
2
|
-
import { type CanvasContent } from './TldrawBuilder';
|
|
3
|
-
/** Apply a batch of edit commands to the canvas content (mutates `content`). */
|
|
4
|
-
export declare const applyCommands: (content: CanvasContent, commands: readonly Scene.Command[]) => ApplyResult;
|
|
5
|
-
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/model/apply.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAI9E,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAE3E,gFAAgF;AAChF,eAAO,MAAM,aAAa,YAAa,aAAa,YAAY,SAAS,KAAK,CAAC,OAAO,EAAE,KAAG,WA8D1F,CAAC"}
|
package/src/model/apply.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
// Applies scene DSL edit commands to canvas content by mutating the record map in place
|
|
7
|
-
// (callers wrap the call in `Obj.update` so a batch commits atomically).
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
import { invariant } from '@dxos/invariant';
|
|
11
|
-
import { type ApplyResult, type Scene } from '@dxos/plugin-illustrator/model';
|
|
12
|
-
|
|
13
|
-
import { elementBoxes, readScene } from './read';
|
|
14
|
-
import { renderObject } from './render';
|
|
15
|
-
import { type CanvasContent, DOCUMENT_ID, PAGE_ID } from './TldrawBuilder';
|
|
16
|
-
|
|
17
|
-
/** Apply a batch of edit commands to the canvas content (mutates `content`). */
|
|
18
|
-
export const applyCommands = (content: CanvasContent, commands: readonly Scene.Command[]): ApplyResult => {
|
|
19
|
-
ensurePage(content);
|
|
20
|
-
const upserted = new Set<string>();
|
|
21
|
-
let removed = 0;
|
|
22
|
-
|
|
23
|
-
for (const command of commands) {
|
|
24
|
-
switch (command.op) {
|
|
25
|
-
case 'upsert-object': {
|
|
26
|
-
const previous = readScene(content).scene.objects.find((object) => object.id === command.object.id);
|
|
27
|
-
removed += remove(content, (record) => record.meta?.object === command.object.id);
|
|
28
|
-
merge(content, command.object, {
|
|
29
|
-
origin: command.object.origin ?? previous?.origin ?? { x: 0, y: 0 },
|
|
30
|
-
scale: command.object.scale ?? previous?.scale ?? 1,
|
|
31
|
-
});
|
|
32
|
-
upserted.add(command.object.id);
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
case 'upsert-elements': {
|
|
36
|
-
const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);
|
|
37
|
-
invariant(previous, `unknown object: ${command.objectId} (use upsert-object to create it)`);
|
|
38
|
-
const ids = new Set(command.elements.map((element) => element.id));
|
|
39
|
-
removed += remove(
|
|
40
|
-
content,
|
|
41
|
-
(record) => record.meta?.object === command.objectId && ids.has(record.meta?.element),
|
|
42
|
-
);
|
|
43
|
-
merge(
|
|
44
|
-
content,
|
|
45
|
-
{ id: command.objectId, elements: command.elements },
|
|
46
|
-
{ origin: previous.origin, scale: previous.scale },
|
|
47
|
-
);
|
|
48
|
-
upserted.add(command.objectId);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
case 'remove-elements': {
|
|
52
|
-
const ids = new Set(command.elementIds);
|
|
53
|
-
removed += remove(
|
|
54
|
-
content,
|
|
55
|
-
(record) => record.meta?.object === command.objectId && ids.has(record.meta?.element),
|
|
56
|
-
);
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
case 'remove-object': {
|
|
60
|
-
removed += remove(content, (record) => record.meta?.object === command.objectId);
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
case 'move-object': {
|
|
64
|
-
const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);
|
|
65
|
-
invariant(previous, `unknown object: ${command.objectId}`);
|
|
66
|
-
const delta = { x: command.origin.x - previous.origin.x, y: command.origin.y - previous.origin.y };
|
|
67
|
-
for (const record of Object.values(content)) {
|
|
68
|
-
if (record?.typeName === 'shape' && record.meta?.object === command.objectId) {
|
|
69
|
-
record.x += delta.x;
|
|
70
|
-
record.y += delta.y;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
upserted.add(command.objectId);
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return { upserted: [...upserted], removed };
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const merge = (
|
|
83
|
-
content: CanvasContent,
|
|
84
|
-
object: Scene.WorldObject | { id: string; elements: readonly Scene.Element[] },
|
|
85
|
-
placement: { origin: Scene.Point; scale: number },
|
|
86
|
-
): void => {
|
|
87
|
-
const records = renderObject(object, {
|
|
88
|
-
...placement,
|
|
89
|
-
indexStart: nextIndex(content),
|
|
90
|
-
external: elementBoxes(content),
|
|
91
|
-
});
|
|
92
|
-
Object.assign(content, records);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/** Delete matching shape records, then any bindings left dangling. */
|
|
96
|
-
const remove = (content: CanvasContent, predicate: (record: any) => boolean): number => {
|
|
97
|
-
let removed = 0;
|
|
98
|
-
for (const [key, record] of Object.entries(content)) {
|
|
99
|
-
if (record?.typeName === 'shape' && predicate(record)) {
|
|
100
|
-
delete content[key];
|
|
101
|
-
removed++;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const [key, record] of Object.entries(content)) {
|
|
105
|
-
if (record?.typeName === 'binding' && (!content[record.fromId] || !content[record.toId])) {
|
|
106
|
-
delete content[key];
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return removed;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
/** Seed the fractional-index counter past any existing `a<n>` indexes. */
|
|
113
|
-
const nextIndex = (content: CanvasContent): number => {
|
|
114
|
-
let max = 0;
|
|
115
|
-
let shapes = 0;
|
|
116
|
-
for (const record of Object.values(content)) {
|
|
117
|
-
if (record?.typeName !== 'shape') {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
shapes++;
|
|
121
|
-
const match = /^a(\d+)$/.exec(record.index ?? '');
|
|
122
|
-
if (match) {
|
|
123
|
-
max = Math.max(max, Number(match[1]));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return Math.max(max, shapes);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const ensurePage = (content: CanvasContent): void => {
|
|
130
|
-
content[DOCUMENT_ID] ??= { gridSize: 10, name: '', meta: {}, id: DOCUMENT_ID, typeName: 'document' };
|
|
131
|
-
content[PAGE_ID] ??= { meta: {}, id: PAGE_ID, name: 'Page 1', index: 'a1', typeName: 'page' };
|
|
132
|
-
};
|