@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/dist/lib/model.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as __exportAll, n as TLDRAW_SCHEMA } from "./chunk-types.mjs";
|
|
2
|
+
import { applyCommands as applyCommands$1, makeBuilder, nextIndex } from "@dxos/plugin-illustrator/model";
|
|
2
3
|
import { invariant } from "@dxos/invariant";
|
|
3
|
-
import { Obj } from "@dxos/echo";
|
|
4
4
|
//#region src/model/read.ts
|
|
5
5
|
/** Read the derived scene from canvas content. */
|
|
6
6
|
var readScene = (content) => {
|
|
@@ -184,8 +184,8 @@ var boxFrom = (xs, ys) => {
|
|
|
184
184
|
};
|
|
185
185
|
var round = (value) => Math.round(value * 100) / 100;
|
|
186
186
|
//#endregion
|
|
187
|
-
//#region src/model/
|
|
188
|
-
var __dxlog_file
|
|
187
|
+
//#region src/model/RecordBuilder.ts
|
|
188
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-tldraw/src/model/RecordBuilder.ts";
|
|
189
189
|
var PAGE_ID = "page:page";
|
|
190
190
|
var DOCUMENT_ID = "document:document";
|
|
191
191
|
var DEFAULTS = {
|
|
@@ -203,14 +203,14 @@ var DEFAULTS = {
|
|
|
203
203
|
*
|
|
204
204
|
* @example
|
|
205
205
|
* ```ts
|
|
206
|
-
* const content = new
|
|
206
|
+
* const content = new RecordBuilder()
|
|
207
207
|
* .rectangle({ id: 'a', x: 0, y: 0, text: 'DXOS', color: 'blue' })
|
|
208
208
|
* .ellipse({ id: 'b', x: 320, y: 0, text: 'ECHO', color: 'green' })
|
|
209
209
|
* .arrow({ from: 'a', to: 'b' })
|
|
210
210
|
* .build();
|
|
211
211
|
* ```
|
|
212
212
|
*/
|
|
213
|
-
var
|
|
213
|
+
var RecordBuilder = class {
|
|
214
214
|
#records = {};
|
|
215
215
|
#boxes = /* @__PURE__ */ new Map();
|
|
216
216
|
#metaFor;
|
|
@@ -228,7 +228,7 @@ var TldrawBuilder = class {
|
|
|
228
228
|
external(handle, box, shapeId) {
|
|
229
229
|
invariant(!this.#boxes.has(handle), `duplicate shape id: ${handle}`, {
|
|
230
230
|
"~LogMeta": "~LogMeta",
|
|
231
|
-
F: __dxlog_file
|
|
231
|
+
F: __dxlog_file,
|
|
232
232
|
L: 162,
|
|
233
233
|
S: this,
|
|
234
234
|
A: ["!this.#boxes.has(handle)", "`duplicate shape id: ${handle}`"]
|
|
@@ -347,7 +347,7 @@ var TldrawBuilder = class {
|
|
|
347
347
|
const source = closed && props.points.length > 1 ? [...props.points, props.points[0]] : [...props.points];
|
|
348
348
|
invariant(source.length >= 2, "path requires at least two points", {
|
|
349
349
|
"~LogMeta": "~LogMeta",
|
|
350
|
-
F: __dxlog_file
|
|
350
|
+
F: __dxlog_file,
|
|
351
351
|
L: 266,
|
|
352
352
|
S: this,
|
|
353
353
|
A: ["source.length >= 2", "'path requires at least two points'"]
|
|
@@ -419,14 +419,14 @@ var TldrawBuilder = class {
|
|
|
419
419
|
const to = props.to ? this.#boxes.get(props.to) : void 0;
|
|
420
420
|
invariant(!props.from || from, `unknown source shape: ${props.from}`, {
|
|
421
421
|
"~LogMeta": "~LogMeta",
|
|
422
|
-
F: __dxlog_file
|
|
422
|
+
F: __dxlog_file,
|
|
423
423
|
L: 325,
|
|
424
424
|
S: this,
|
|
425
425
|
A: ["!props.from || from", "`unknown source shape: ${props.from}`"]
|
|
426
426
|
});
|
|
427
427
|
invariant(!props.to || to, `unknown target shape: ${props.to}`, {
|
|
428
428
|
"~LogMeta": "~LogMeta",
|
|
429
|
-
F: __dxlog_file
|
|
429
|
+
F: __dxlog_file,
|
|
430
430
|
L: 326,
|
|
431
431
|
S: this,
|
|
432
432
|
A: ["!props.to || to", "`unknown target shape: ${props.to}`"]
|
|
@@ -551,7 +551,7 @@ var TldrawBuilder = class {
|
|
|
551
551
|
const handle = box.id ?? shapeId;
|
|
552
552
|
invariant(!this.#records[shapeId] && !this.#boxes.has(handle), `duplicate shape id: ${handle}`, {
|
|
553
553
|
"~LogMeta": "~LogMeta",
|
|
554
|
-
F: __dxlog_file
|
|
554
|
+
F: __dxlog_file,
|
|
555
555
|
L: 433,
|
|
556
556
|
S: this,
|
|
557
557
|
A: ["!this.#records[shapeId] && !this.#boxes.has(handle)", "`duplicate shape id: ${handle}`"]
|
|
@@ -613,7 +613,7 @@ var renderObject = (object, options) => {
|
|
|
613
613
|
});
|
|
614
614
|
const length = (units) => units * scale;
|
|
615
615
|
const kinds = /* @__PURE__ */ new Map();
|
|
616
|
-
const builder = new
|
|
616
|
+
const builder = new RecordBuilder({
|
|
617
617
|
indexStart,
|
|
618
618
|
metaFor: (handle) => {
|
|
619
619
|
const [objectId, elementId] = splitHandle(handle);
|
|
@@ -731,175 +731,70 @@ var sampleArc = ({ cx, cy, r, startAngle, endAngle }) => {
|
|
|
731
731
|
});
|
|
732
732
|
};
|
|
733
733
|
//#endregion
|
|
734
|
-
//#region src/model/
|
|
735
|
-
var
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
merge(content, command.object, {
|
|
746
|
-
origin: command.object.origin ?? previous?.origin ?? {
|
|
747
|
-
x: 0,
|
|
748
|
-
y: 0
|
|
749
|
-
},
|
|
750
|
-
scale: command.object.scale ?? previous?.scale ?? 1
|
|
751
|
-
});
|
|
752
|
-
upserted.add(command.object.id);
|
|
753
|
-
break;
|
|
754
|
-
}
|
|
755
|
-
case "upsert-elements": {
|
|
756
|
-
const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);
|
|
757
|
-
invariant(previous, `unknown object: ${command.objectId} (use upsert-object to create it)`, {
|
|
758
|
-
"~LogMeta": "~LogMeta",
|
|
759
|
-
F: __dxlog_file$1,
|
|
760
|
-
L: 37,
|
|
761
|
-
S: void 0,
|
|
762
|
-
A: ["previous", "`unknown object: ${command.objectId} (use upsert-object to create it)`"]
|
|
763
|
-
});
|
|
764
|
-
const ids = new Set(command.elements.map((element) => element.id));
|
|
765
|
-
removed += remove(content, (record) => record.meta?.object === command.objectId && ids.has(record.meta?.element));
|
|
766
|
-
merge(content, {
|
|
767
|
-
id: command.objectId,
|
|
768
|
-
elements: command.elements
|
|
769
|
-
}, {
|
|
770
|
-
origin: previous.origin,
|
|
771
|
-
scale: previous.scale
|
|
772
|
-
});
|
|
773
|
-
upserted.add(command.objectId);
|
|
774
|
-
break;
|
|
775
|
-
}
|
|
776
|
-
case "remove-elements": {
|
|
777
|
-
const ids = new Set(command.elementIds);
|
|
778
|
-
removed += remove(content, (record) => record.meta?.object === command.objectId && ids.has(record.meta?.element));
|
|
779
|
-
break;
|
|
780
|
-
}
|
|
781
|
-
case "remove-object":
|
|
782
|
-
removed += remove(content, (record) => record.meta?.object === command.objectId);
|
|
783
|
-
break;
|
|
784
|
-
case "move-object": {
|
|
785
|
-
const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);
|
|
786
|
-
invariant(previous, `unknown object: ${command.objectId}`, {
|
|
787
|
-
"~LogMeta": "~LogMeta",
|
|
788
|
-
F: __dxlog_file$1,
|
|
789
|
-
L: 65,
|
|
790
|
-
S: void 0,
|
|
791
|
-
A: ["previous", "`unknown object: ${command.objectId}`"]
|
|
792
|
-
});
|
|
793
|
-
const delta = {
|
|
794
|
-
x: command.origin.x - previous.origin.x,
|
|
795
|
-
y: command.origin.y - previous.origin.y
|
|
796
|
-
};
|
|
797
|
-
for (const record of Object.values(content)) if (record?.typeName === "shape" && record.meta?.object === command.objectId) {
|
|
798
|
-
record.x += delta.x;
|
|
799
|
-
record.y += delta.y;
|
|
800
|
-
}
|
|
801
|
-
upserted.add(command.objectId);
|
|
802
|
-
break;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
return {
|
|
806
|
-
upserted: [...upserted],
|
|
807
|
-
removed
|
|
808
|
-
};
|
|
809
|
-
};
|
|
810
|
-
var merge = (content, object, placement) => {
|
|
811
|
-
const records = renderObject(object, {
|
|
734
|
+
//#region src/model/builder.ts
|
|
735
|
+
var isShape = (record) => record?.typeName === "shape";
|
|
736
|
+
var handler = {
|
|
737
|
+
identify: (record) => {
|
|
738
|
+
if (!isShape(record) || typeof record.meta?.object !== "string" || typeof record.meta?.element !== "string") return;
|
|
739
|
+
return {
|
|
740
|
+
object: record.meta.object,
|
|
741
|
+
element: record.meta.element
|
|
742
|
+
};
|
|
743
|
+
},
|
|
744
|
+
render: (object, placement, content) => renderObject(object, {
|
|
812
745
|
...placement,
|
|
813
|
-
indexStart: nextIndex(content),
|
|
746
|
+
indexStart: nextIndex(content, isShape),
|
|
814
747
|
external: elementBoxes(content)
|
|
815
|
-
})
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
let removed = 0;
|
|
821
|
-
for (const [key, record] of Object.entries(content)) if (record?.typeName === "shape" && predicate(record)) {
|
|
822
|
-
delete content[key];
|
|
823
|
-
removed++;
|
|
824
|
-
}
|
|
825
|
-
for (const [key, record] of Object.entries(content)) if (record?.typeName === "binding" && (!content[record.fromId] || !content[record.toId])) delete content[key];
|
|
826
|
-
return removed;
|
|
827
|
-
};
|
|
828
|
-
/** Seed the fractional-index counter past any existing `a<n>` indexes. */
|
|
829
|
-
var nextIndex = (content) => {
|
|
830
|
-
let max = 0;
|
|
831
|
-
let shapes = 0;
|
|
832
|
-
for (const record of Object.values(content)) {
|
|
833
|
-
if (record?.typeName !== "shape") continue;
|
|
834
|
-
shapes++;
|
|
835
|
-
const match = /^a(\d+)$/.exec(record.index ?? "");
|
|
836
|
-
if (match) max = Math.max(max, Number(match[1]));
|
|
837
|
-
}
|
|
838
|
-
return Math.max(max, shapes);
|
|
839
|
-
};
|
|
840
|
-
var ensurePage = (content) => {
|
|
841
|
-
content[DOCUMENT_ID] ??= {
|
|
842
|
-
gridSize: 10,
|
|
843
|
-
name: "",
|
|
844
|
-
meta: {},
|
|
845
|
-
id: DOCUMENT_ID,
|
|
846
|
-
typeName: "document"
|
|
847
|
-
};
|
|
848
|
-
content[PAGE_ID] ??= {
|
|
849
|
-
meta: {},
|
|
850
|
-
id: PAGE_ID,
|
|
851
|
-
name: "Page 1",
|
|
852
|
-
index: "a1",
|
|
853
|
-
typeName: "page"
|
|
854
|
-
};
|
|
855
|
-
};
|
|
856
|
-
//#endregion
|
|
857
|
-
//#region src/model/builder.ts
|
|
858
|
-
var __dxlog_file = "/Users/burdon/Code/dxos/dxos/.claude/worktrees/peaceful-allen-9b542f/packages/plugins/plugin-tldraw/src/model/builder.ts";
|
|
859
|
-
var tldrawBuilder = {
|
|
860
|
-
read: (canvas) => {
|
|
861
|
-
invariant(Obj.instanceOf(Canvas, canvas), void 0, {
|
|
862
|
-
"~LogMeta": "~LogMeta",
|
|
863
|
-
F: __dxlog_file,
|
|
864
|
-
L: 20,
|
|
865
|
-
S: void 0,
|
|
866
|
-
A: ["Obj.instanceOf(Tldraw.Canvas, canvas)", ""]
|
|
867
|
-
});
|
|
868
|
-
return readScene(canvas.content);
|
|
748
|
+
}),
|
|
749
|
+
read: (content) => readScene(content),
|
|
750
|
+
translate: (record, delta) => {
|
|
751
|
+
record.x += delta.x;
|
|
752
|
+
record.y += delta.y;
|
|
869
753
|
},
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
});
|
|
878
|
-
let result = {
|
|
879
|
-
upserted: [],
|
|
880
|
-
removed: 0
|
|
754
|
+
scaffold: (content) => {
|
|
755
|
+
content[DOCUMENT_ID] ??= {
|
|
756
|
+
gridSize: 10,
|
|
757
|
+
name: "",
|
|
758
|
+
meta: {},
|
|
759
|
+
id: DOCUMENT_ID,
|
|
760
|
+
typeName: "document"
|
|
881
761
|
};
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
762
|
+
content[PAGE_ID] ??= {
|
|
763
|
+
meta: {},
|
|
764
|
+
id: PAGE_ID,
|
|
765
|
+
name: "Page 1",
|
|
766
|
+
index: "a1",
|
|
767
|
+
typeName: "page"
|
|
768
|
+
};
|
|
769
|
+
},
|
|
770
|
+
prune: (content) => {
|
|
771
|
+
for (const [key, record] of Object.entries(content)) if (record?.typeName === "binding" && (!content[record.fromId] || !content[record.toId])) delete content[key];
|
|
886
772
|
}
|
|
887
773
|
};
|
|
774
|
+
var TldrawBuilder = makeBuilder({
|
|
775
|
+
schema: TLDRAW_SCHEMA,
|
|
776
|
+
handler
|
|
777
|
+
});
|
|
778
|
+
/**
|
|
779
|
+
* Apply commands straight to a content map, bypassing ECHO — for tests and tooling that hold
|
|
780
|
+
* raw tldraw records. The object-aware path is {@link TldrawBuilder}.
|
|
781
|
+
*/
|
|
782
|
+
var applyCommands = (content, commands) => applyCommands$1(content, commands, handler);
|
|
888
783
|
//#endregion
|
|
889
784
|
//#region src/model/index.ts
|
|
890
785
|
var model_exports = /* @__PURE__ */ __exportAll({
|
|
891
786
|
DEFAULT_SCALE: () => 1,
|
|
892
787
|
DOCUMENT_ID: () => DOCUMENT_ID,
|
|
893
788
|
PAGE_ID: () => PAGE_ID,
|
|
789
|
+
RecordBuilder: () => RecordBuilder,
|
|
894
790
|
TldrawBuilder: () => TldrawBuilder,
|
|
895
791
|
applyCommands: () => applyCommands,
|
|
896
792
|
elementBoxes: () => elementBoxes,
|
|
897
793
|
readScene: () => readScene,
|
|
898
794
|
renderObject: () => renderObject,
|
|
899
|
-
shapeId: () => shapeId
|
|
900
|
-
tldrawBuilder: () => tldrawBuilder
|
|
795
|
+
shapeId: () => shapeId
|
|
901
796
|
});
|
|
902
797
|
//#endregion
|
|
903
|
-
export { DEFAULT_SCALE, DOCUMENT_ID, PAGE_ID, TldrawBuilder, applyCommands, elementBoxes, readScene, renderObject, shapeId, model_exports as t
|
|
798
|
+
export { DEFAULT_SCALE, DOCUMENT_ID, PAGE_ID, RecordBuilder, TldrawBuilder, applyCommands, elementBoxes, readScene, renderObject, shapeId, model_exports as t };
|
|
904
799
|
|
|
905
800
|
//# sourceMappingURL=model.mjs.map
|
package/dist/lib/model.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.mjs","names":[],"sources":["../../src/model/read.ts","../../src/model/TldrawBuilder.ts","../../src/model/render.ts","../../src/model/apply.ts","../../src/model/builder.ts","../../src/model/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Derives the neutral scene from tldraw records. Geometry is read from the live records —\n// not from a stored copy — so the agent's mental model stays coherent after users drag or\n// resize shapes in the UI. An object's `origin` is the top-left of its bounding box.\n//\n\nimport { type ReadResult, type ReadWorldObject, type Scene } from '@dxos/plugin-illustrator/model';\n\nimport { type ExternalBox } from './render';\nimport { type CanvasContent } from './TldrawBuilder';\n\ntype ShapeRecord = Record<string, any>;\n\n/** Read the derived scene from canvas content. */\nexport const readScene = (content: CanvasContent): ReadResult => {\n const groups = new Map<string, ShapeRecord[]>();\n let unmanaged = 0;\n for (const record of Object.values(content ?? {})) {\n if (record?.typeName !== 'shape') {\n continue;\n }\n const objectId = record.meta?.object;\n if (typeof objectId !== 'string' || typeof record.meta?.element !== 'string') {\n unmanaged++;\n continue;\n }\n groups.set(objectId, [...(groups.get(objectId) ?? []), record]);\n }\n\n const objects = [...groups.entries()].map(([objectId, records]) => readObject(objectId, records, content));\n return { scene: { objects }, unmanaged };\n};\n\n/** Canvas-px bounding boxes of all managed elements, keyed by `objectId/elementId`. */\nexport const elementBoxes = (content: CanvasContent): Record<string, ExternalBox> => {\n const boxes: Record<string, ExternalBox> = {};\n for (const record of Object.values(content ?? {})) {\n if (record?.typeName === 'shape' && record.meta?.object && record.meta?.element) {\n boxes[`${record.meta.object}/${record.meta.element}`] = bounds(record);\n }\n }\n return boxes;\n};\n\nconst readObject = (objectId: string, records: ShapeRecord[], content: CanvasContent): ReadWorldObject => {\n const scale = records.find((record) => typeof record.meta?.scale === 'number')?.meta.scale ?? 1;\n const origin = {\n x: Math.min(...records.map((record) => bounds(record).x)),\n y: Math.min(...records.map((record) => bounds(record).y)),\n };\n const local = (abs: { x: number; y: number }): Scene.Point => ({\n x: round((abs.x - origin.x) / scale),\n y: round((abs.y - origin.y) / scale),\n });\n const length = (px: number) => round(px / scale);\n\n const elements = records\n .map((record) => readElement(record, { local, length, objectId, content }))\n .filter((element): element is Scene.Element => element !== undefined);\n\n return { id: objectId, origin, scale, elements };\n};\n\ntype ReadContext = {\n local: (abs: { x: number; y: number }) => Scene.Point;\n length: (px: number) => number;\n objectId: string;\n content: CanvasContent;\n};\n\nconst readElement = (record: ShapeRecord, ctx: ReadContext): Scene.Element | undefined => {\n const id = record.meta.element;\n const kind = record.meta.kind;\n switch (record.type) {\n case 'geo': {\n const boxKind = kind === 'rect' || kind === 'diamond' || kind === 'triangle' ? kind : 'ellipse';\n return {\n kind: boxKind,\n id,\n ...ctx.local({ x: record.x, y: record.y }),\n w: ctx.length(record.props.w),\n h: ctx.length(record.props.h),\n ...(record.rotation ? { rotation: round((record.rotation * 180) / Math.PI) } : {}),\n ...(record.props.text ? { text: record.props.text } : {}),\n ...readStyle(record),\n };\n }\n case 'text': {\n return {\n kind: 'text',\n id,\n ...ctx.local({ x: record.x, y: record.y }),\n ...(record.props.autoSize ? {} : { w: ctx.length(record.props.w) }),\n text: record.props.text ?? '',\n ...readStyle(record),\n };\n }\n case 'line': {\n const points = linePoints(record).map((point) => ctx.local({ x: record.x + point.x, y: record.y + point.y }));\n if (kind === 'curve') {\n return { kind: 'curve', id, points, ...readStyle(record) };\n }\n const closed =\n points.length > 2 && points[0].x === points[points.length - 1].x && points[0].y === points[points.length - 1].y;\n return {\n kind: 'line',\n id,\n points: closed ? points.slice(0, -1) : points,\n ...(closed ? { closed: true } : {}),\n ...readStyle(record),\n };\n }\n case 'arrow': {\n const { from, to } = arrowRefs(record, ctx);\n return {\n kind: 'arrow',\n id,\n ...(from\n ? { from }\n : { start: ctx.local({ x: record.x + record.props.start.x, y: record.y + record.props.start.y }) }),\n ...(to ? { to } : { end: ctx.local({ x: record.x + record.props.end.x, y: record.y + record.props.end.y }) }),\n ...(record.props.text ? { text: record.props.text } : {}),\n ...readStyle(record),\n };\n }\n default:\n return undefined;\n }\n};\n\n/** Resolve arrow terminal bindings back to element refs (same-object refs are shortened). */\nconst arrowRefs = (record: ShapeRecord, ctx: ReadContext): { from?: string; to?: string } => {\n const refs: { from?: string; to?: string } = {};\n for (const binding of Object.values(ctx.content ?? {})) {\n if (binding?.typeName !== 'binding' || binding.fromId !== record.id) {\n continue;\n }\n const target = ctx.content[binding.toId];\n if (!target?.meta?.object || !target?.meta?.element) {\n continue;\n }\n const ref =\n target.meta.object === ctx.objectId ? target.meta.element : `${target.meta.object}/${target.meta.element}`;\n if (binding.props?.terminal === 'start') {\n refs.from = ref;\n } else {\n refs.to = ref;\n }\n }\n return refs;\n};\n\n/** Report only non-default styles to keep the read output compact. */\nconst readStyle = (record: ShapeRecord): Partial<Pick<Scene.Box, 'color' | 'fill' | 'stroke' | 'weight'>> => {\n const { color, fill, dash, size } = record.props;\n return {\n ...(color && color !== 'black' ? { color } : {}),\n ...(fill && fill !== 'none' ? { fill: fill === 'pattern' ? ('pattern' as const) : ('solid' as const) } : {}),\n ...(dash && dash !== 'draw' ? { stroke: dash as Scene.Stroke } : {}),\n ...(size && size !== 'm' ? { weight: size as Scene.Weight } : {}),\n };\n};\n\nconst linePoints = (record: ShapeRecord): { x: number; y: number }[] =>\n Object.values(record.props.points ?? {})\n // Indexes are `a<n>` fractional keys; numeric compare so `a10` sorts after `a2`.\n .sort((a: any, b: any) => Number(String(a.index).slice(1)) - Number(String(b.index).slice(1)))\n .map((point: any) => ({ x: point.x, y: point.y }));\n\n/** Bounding box of a shape record in canvas px. */\nconst bounds = (record: ShapeRecord): ExternalBox => {\n switch (record.type) {\n case 'geo':\n return { x: record.x, y: record.y, w: record.props.w, h: record.props.h };\n case 'text':\n return { x: record.x, y: record.y, w: record.props.w ?? 0, h: 0 };\n case 'line': {\n const points = linePoints(record);\n const xs = points.map((point) => record.x + point.x);\n const ys = points.map((point) => record.y + point.y);\n return boxFrom(xs, ys);\n }\n case 'arrow': {\n const xs = [record.x + record.props.start.x, record.x + record.props.end.x];\n const ys = [record.y + record.props.start.y, record.y + record.props.end.y];\n return boxFrom(xs, ys);\n }\n default:\n return { x: record.x ?? 0, y: record.y ?? 0, w: record.props?.w ?? 0, h: record.props?.h ?? 0 };\n }\n};\n\nconst boxFrom = (xs: number[], ys: number[]): ExternalBox => {\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n return { x, y, w: Math.max(...xs) - x, h: Math.max(...ys) - y };\n};\n\nconst round = (value: number) => Math.round(value * 100) / 100;\n","//\n// Copyright 2024 DXOS.org\n//\n\n//\n// A minimal, chainable builder for tldraw (`tldraw.com/2`) canvas records.\n// Produces the record map stored in `Sketch.Canvas.content`. Used directly to seed\n// stories/tests (`build()`), and by the scene renderer (`render.ts`) to compile the\n// neutral scene DSL into records merged into an existing canvas (`records()`).\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type Color =\n | 'black'\n | 'grey'\n | 'light-violet'\n | 'violet'\n | 'blue'\n | 'light-blue'\n | 'yellow'\n | 'orange'\n | 'green'\n | 'light-green'\n | 'light-red'\n | 'red'\n | 'white';\n\nexport type Fill = 'none' | 'semi' | 'solid' | 'pattern' | 'fill';\nexport type Dash = 'draw' | 'solid' | 'dashed' | 'dotted';\nexport type Size = 's' | 'm' | 'l' | 'xl';\nexport type Font = 'draw' | 'sans' | 'serif' | 'mono';\nexport type Align = 'start' | 'middle' | 'end';\nexport type Geo =\n | 'rectangle'\n | 'ellipse'\n | 'triangle'\n | 'diamond'\n | 'pentagon'\n | 'hexagon'\n | 'octagon'\n | 'star'\n | 'rhombus'\n | 'oval'\n | 'cloud'\n | 'heart';\n\n/** Common style props shared by all shapes. */\nexport type StyleProps = {\n color?: Color;\n fill?: Fill;\n dash?: Dash;\n size?: Size;\n font?: Font;\n text?: string;\n align?: Align;\n};\n\n/** Geometric shape (rectangle, ellipse, etc.). */\nexport type ShapeProps = StyleProps & {\n /** Friendly handle used to link shapes (e.g. as an arrow target). */\n id?: string;\n x?: number;\n y?: number;\n w?: number;\n h?: number;\n rotation?: number;\n};\n\n/** Free-standing text label. */\nexport type TextProps = Omit<ShapeProps, 'h' | 'fill' | 'dash'>;\n\n/** Connector (arrow/line) between two shapes (or between explicit points). */\nexport type ConnectorProps = Omit<StyleProps, 'align'> & {\n id?: string;\n /** Handle of the source shape. */\n from?: string;\n /** Handle of the target shape. */\n to?: string;\n /** Explicit start point (used when `from` is omitted). */\n start?: Point;\n /** Explicit end point (used when `to` is omitted). */\n end?: Point;\n};\n\n/** Open or closed path through explicit points. */\nexport type PathProps = Omit<StyleProps, 'align'> & {\n id?: string;\n points: readonly Point[];\n /** Smooth (cubic spline) instead of straight segments. */\n smooth?: boolean;\n /** Close the path back to the first point. */\n closed?: boolean;\n};\n\nexport type Point = { x: number; y: number };\n\nexport type CanvasContent = Record<string, any>;\n\nexport const PAGE_ID = 'page:page';\nexport const DOCUMENT_ID = 'document:document';\n\nexport type BuilderOptions = {\n /** Fractional-index counter seed; pass a value past existing content when merging. */\n indexStart?: number;\n /** Per-shape meta, keyed by handle; merged into each generated record's `meta`. */\n metaFor?: (handle: string) => Record<string, any>;\n};\n\nconst DEFAULTS: {\n color: Color;\n fill: Fill;\n dash: Dash;\n size: Size;\n font: Font;\n align: Align;\n w: number;\n h: number;\n} = {\n color: 'black',\n fill: 'none',\n dash: 'draw',\n size: 'm',\n font: 'draw',\n align: 'middle',\n w: 160,\n h: 120,\n};\n\ntype Box = { id: string; x: number; y: number; w: number; h: number };\n\n/**\n * Chainable builder for sketch (tldraw) canvas content.\n *\n * @example\n * ```ts\n * const content = new TldrawBuilder()\n * .rectangle({ id: 'a', x: 0, y: 0, text: 'DXOS', color: 'blue' })\n * .ellipse({ id: 'b', x: 320, y: 0, text: 'ECHO', color: 'green' })\n * .arrow({ from: 'a', to: 'b' })\n * .build();\n * ```\n */\nexport class TldrawBuilder {\n readonly #records: CanvasContent = {};\n readonly #boxes = new Map<string, Box>();\n readonly #metaFor?: (handle: string) => Record<string, any>;\n #shapeCount = 0;\n #bindingCount = 0;\n #indexCount: number;\n\n constructor(options: BuilderOptions = {}) {\n this.#indexCount = options.indexStart ?? 0;\n this.#metaFor = options.metaFor;\n }\n\n /**\n * Register a shape that already exists on the canvas (its bounding box in canvas px)\n * so connectors added by this builder can bind to it.\n */\n external(handle: string, box: { x: number; y: number; w: number; h: number }, shapeId?: string): this {\n invariant(!this.#boxes.has(handle), `duplicate shape id: ${handle}`);\n this.#boxes.set(handle, { id: shapeId ?? `shape:${handle}`, ...box });\n return this;\n }\n\n /** Add a rectangle. */\n rectangle(props: ShapeProps = {}): this {\n return this.geo('rectangle', props);\n }\n\n /** Add an ellipse. */\n ellipse(props: ShapeProps = {}): this {\n return this.geo('ellipse', props);\n }\n\n /** Add a circle (an ellipse with equal width and height). */\n circle(props: ShapeProps = {}): this {\n const size = props.w ?? props.h ?? DEFAULTS.w;\n return this.geo('ellipse', { ...props, w: size, h: size });\n }\n\n /** Add an arbitrary geometric shape. */\n geo(geo: Geo, props: ShapeProps = {}): this {\n const { id, x = 0, y = 0, w = DEFAULTS.w, h = DEFAULTS.h, rotation = 0 } = props;\n const shapeId = this.#registerShape({ id, x, y, w, h });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'geo',\n x,\n y,\n rotation,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n geo,\n w,\n h,\n color: props.color ?? DEFAULTS.color,\n labelColor: DEFAULTS.color,\n fill: props.fill ?? DEFAULTS.fill,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n font: props.font ?? DEFAULTS.font,\n align: props.align ?? DEFAULTS.align,\n verticalAlign: 'middle',\n url: '',\n growY: 0,\n text: props.text ?? '',\n scale: 1,\n },\n };\n\n return this;\n }\n\n /** Add a free-standing text label. */\n text(props: TextProps = {}): this {\n const { id, x = 0, y = 0, w = DEFAULTS.w, rotation = 0 } = props;\n const shapeId = this.#registerShape({ id, x, y, w, h: 0 });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'text',\n x,\n y,\n rotation,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n color: props.color ?? DEFAULTS.color,\n size: props.size ?? DEFAULTS.size,\n font: props.font ?? DEFAULTS.font,\n textAlign: props.align ?? DEFAULTS.align,\n w,\n text: props.text ?? '',\n scale: 1,\n autoSize: true,\n },\n };\n\n return this;\n }\n\n /** Add an arrow, optionally bound to source/target shapes so it tracks them. */\n arrow(props: ConnectorProps = {}): this {\n return this.#connector('arrow', props);\n }\n\n /** Add a line between two shapes (or explicit points). */\n line(props: ConnectorProps = {}): this {\n return this.#connector('line', props);\n }\n\n /** Add a path (open or closed, straight or smooth) through explicit points. */\n path(props: PathProps): this {\n const { id, smooth, closed } = props;\n const source = closed && props.points.length > 1 ? [...props.points, props.points[0]] : [...props.points];\n invariant(source.length >= 2, 'path requires at least two points');\n const origin = source[0];\n const xs = source.map((point) => point.x);\n const ys = source.map((point) => point.y);\n const shapeId = this.#registerShape({\n id,\n x: Math.min(...xs),\n y: Math.min(...ys),\n w: Math.max(...xs) - Math.min(...xs),\n h: Math.max(...ys) - Math.min(...ys),\n });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'line',\n x: origin.x,\n y: origin.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n color: props.color ?? DEFAULTS.color,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n spline: smooth ? 'cubic' : 'line',\n points: Object.fromEntries(\n source.map((point, i) => [\n `a${i + 1}`,\n { id: `a${i + 1}`, index: `a${i + 1}`, x: point.x - origin.x, y: point.y - origin.y },\n ]),\n ),\n scale: 1,\n },\n };\n\n return this;\n }\n\n /** Build the full canvas snapshot (document + page + records). */\n build(): CanvasContent {\n return {\n [DOCUMENT_ID]: { gridSize: 10, name: '', meta: {}, id: DOCUMENT_ID, typeName: 'document' },\n [PAGE_ID]: { meta: {}, id: PAGE_ID, name: 'Page 1', index: 'a1', typeName: 'page' },\n ...this.#records,\n };\n }\n\n /** Return only the generated records (for merging into an existing canvas). */\n records(): CanvasContent {\n return { ...this.#records };\n }\n\n #connector(type: 'arrow' | 'line', props: ConnectorProps): this {\n const from = props.from ? this.#boxes.get(props.from) : undefined;\n const to = props.to ? this.#boxes.get(props.to) : undefined;\n // A referenced handle that resolves to nothing is a typo; fail rather than emit a misplaced connector.\n invariant(!props.from || from, `unknown source shape: ${props.from}`);\n invariant(!props.to || to, `unknown target shape: ${props.to}`);\n const start = from ? center(from) : (props.start ?? { x: 0, y: 0 });\n const end = to ? center(to) : (props.end ?? { x: DEFAULTS.w, y: 0 });\n\n const shapeId = this.#registerShape({ id: props.id, x: start.x, y: start.y, w: 0, h: 0 });\n const relativeEnd = { x: end.x - start.x, y: end.y - start.y };\n const style = {\n color: props.color ?? DEFAULTS.color,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n };\n\n if (type === 'arrow') {\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'arrow',\n x: start.x,\n y: start.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(props.id),\n props: {\n ...style,\n labelColor: DEFAULTS.color,\n fill: props.fill ?? DEFAULTS.fill,\n font: props.font ?? DEFAULTS.font,\n arrowheadStart: 'none',\n arrowheadEnd: 'arrow',\n start: { x: 0, y: 0 },\n end: relativeEnd,\n bend: 0,\n text: props.text ?? '',\n labelPosition: 0.5,\n scale: 1,\n },\n };\n\n // Bindings make the arrow track its bound shapes (tldraw recomputes terminals).\n if (from) {\n this.#binding(shapeId, from.id, 'start');\n }\n if (to) {\n this.#binding(shapeId, to.id, 'end');\n }\n } else {\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'line',\n x: start.x,\n y: start.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(props.id),\n props: {\n ...style,\n spline: 'line',\n points: {\n a1: { id: 'a1', index: 'a1', x: 0, y: 0 },\n a2: { id: 'a2', index: 'a2', x: relativeEnd.x, y: relativeEnd.y },\n },\n scale: 1,\n },\n };\n }\n\n return this;\n }\n\n #binding(arrowId: string, shapeId: string, terminal: 'start' | 'end'): void {\n // Deterministic per-terminal id so re-rendering an arrow overwrites its own bindings.\n const bindingId = `binding:${arrowId.slice('shape:'.length)}/${terminal}-${++this.#bindingCount}`;\n this.#records[bindingId] = {\n id: bindingId,\n typeName: 'binding',\n type: 'arrow',\n fromId: arrowId,\n toId: shapeId,\n meta: {},\n props: {\n terminal,\n normalizedAnchor: { x: 0.5, y: 0.5 },\n isExact: false,\n isPrecise: false,\n },\n };\n }\n\n #meta(handle: string | undefined): Record<string, any> {\n return handle && this.#metaFor ? this.#metaFor(handle) : {};\n }\n\n #registerShape(box: { id?: string; x: number; y: number; w: number; h: number }): string {\n // Skip autogenerated ids that collide with an explicit one (e.g. a user-supplied `s1`).\n let shapeId = box.id ? `shape:${box.id}` : `shape:s${++this.#shapeCount}`;\n while (!box.id && this.#records[shapeId]) {\n shapeId = `shape:s${++this.#shapeCount}`;\n }\n const handle = box.id ?? shapeId;\n // The id is the record-map key; reusing one would silently overwrite the earlier shape.\n invariant(!this.#records[shapeId] && !this.#boxes.has(handle), `duplicate shape id: ${handle}`);\n this.#boxes.set(handle, { id: shapeId, x: box.x, y: box.y, w: box.w, h: box.h });\n return shapeId;\n }\n\n #nextIndex(): string {\n return `a${++this.#indexCount}`;\n }\n}\n\nconst center = (box: Box): Point => ({ x: box.x + box.w / 2, y: box.y + box.h / 2 });\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// tldraw backend for the scene DSL: compiles a `WorldObject` into tldraw records.\n// Element identity is stamped into each record's `meta` (`{ object, element, kind, scale }`)\n// so `read.ts` can reconstruct the scene and edits can address records by id.\n//\n\nimport { Scene } from '@dxos/plugin-illustrator/model';\n\nimport {\n type CanvasContent,\n type ConnectorProps,\n type Dash,\n type Fill,\n type PathProps,\n type Point,\n type ShapeProps,\n TldrawBuilder,\n} from './TldrawBuilder';\n\nexport const DEFAULT_SCALE = 1;\n\n/** Canvas-px bounding box of an existing element another object's arrow may bind to. */\nexport type ExternalBox = { x: number; y: number; w: number; h: number };\n\nexport type RenderOptions = {\n origin: Scene.Point;\n scale: number;\n /** Fractional-index seed past the existing canvas content. */\n indexStart: number;\n /** Bounding boxes of existing elements, keyed by `objectId/elementId` (canvas px). */\n external?: Record<string, ExternalBox>;\n dialect?: string;\n};\n\n/** Stable record id for an element: `shape:<objectId>/<elementId>`. */\nexport const shapeId = (objectId: string, elementId: string) => `shape:${objectId}/${elementId}`;\n\nconst strokeToDash: Record<Scene.Stroke, Dash> = {\n sketchy: 'draw',\n solid: 'solid',\n dashed: 'dashed',\n dotted: 'dotted',\n};\n\nconst fillToFill: Record<Scene.Fill, Fill> = {\n none: 'none',\n solid: 'solid',\n pattern: 'pattern',\n};\n\nconst boxKindToGeo = {\n rect: 'rectangle',\n ellipse: 'ellipse',\n diamond: 'diamond',\n triangle: 'triangle',\n} as const;\n\nconst style = (element: Scene.Element): Pick<ShapeProps, 'color' | 'fill' | 'dash' | 'size'> => ({\n color: element.color,\n fill: 'fill' in element && element.fill ? fillToFill[element.fill] : undefined,\n dash: element.stroke ? strokeToDash[element.stroke] : undefined,\n size: element.weight,\n});\n\n/**\n * Compile one world object into tldraw records (canvas-px coordinates).\n * Local coordinates are mapped via `canvas = origin + local * scale`.\n */\nexport const renderObject = (object: Scene.WorldObject, options: RenderOptions): CanvasContent => {\n const { origin, scale, indexStart, external = {}, dialect = 'scene' } = options;\n const point = (local: Scene.Point | { x: number; y: number }): Point => ({\n x: origin.x + local.x * scale,\n y: origin.y + local.y * scale,\n });\n const length = (units: number) => units * scale;\n\n const kinds = new Map<string, string>();\n const builder = new TldrawBuilder({\n indexStart,\n metaFor: (handle) => {\n const [objectId, elementId] = splitHandle(handle);\n return { object: objectId, element: elementId, kind: kinds.get(handle), scale, dialect };\n },\n });\n\n // Register existing canvas elements so arrows can bind across objects.\n for (const [handle, box] of Object.entries(external)) {\n builder.external(handle, box);\n }\n\n // Refs are element ids within this object, or `objectId/elementId` across objects.\n const ref = (value: string) => (value.includes('/') ? value : `${object.id}/${value}`);\n\n for (const element of object.elements) {\n const handle = `${object.id}/${element.id}`;\n kinds.set(handle, element.kind);\n switch (element.kind) {\n case 'rect':\n case 'ellipse':\n case 'diamond':\n case 'triangle': {\n builder.geo(boxKindToGeo[element.kind], {\n id: handle,\n ...point(element),\n w: length(element.w),\n h: length(element.h),\n rotation: element.rotation !== undefined ? (element.rotation * Math.PI) / 180 : undefined,\n text: element.text,\n ...style(element),\n });\n break;\n }\n case 'circle': {\n kinds.set(handle, 'ellipse');\n builder.circle({\n id: handle,\n ...point({ x: element.cx - element.r, y: element.cy - element.r }),\n w: length(element.r * 2),\n text: element.text,\n ...style(element),\n });\n break;\n }\n case 'line': {\n const props: PathProps = {\n id: handle,\n points: element.points.map(point),\n closed: element.closed,\n ...style(element),\n };\n builder.path(props);\n break;\n }\n case 'curve': {\n builder.path({ id: handle, points: element.points.map(point), smooth: true, ...style(element) });\n break;\n }\n case 'arc': {\n kinds.set(handle, 'curve');\n builder.path({ id: handle, points: sampleArc(element).map(point), smooth: true, ...style(element) });\n break;\n }\n case 'text': {\n builder.text({\n id: handle,\n ...point(element),\n w: element.w !== undefined ? length(element.w) : undefined,\n text: element.text,\n color: element.color,\n size: element.weight,\n });\n break;\n }\n case 'arrow': {\n const props: ConnectorProps = {\n id: handle,\n from: element.from ? ref(element.from) : undefined,\n to: element.to ? ref(element.to) : undefined,\n start: element.start ? point(element.start) : undefined,\n end: element.end ? point(element.end) : undefined,\n text: element.text,\n ...style(element),\n };\n builder.arrow(props);\n break;\n }\n }\n }\n\n return builder.records();\n};\n\n/** `objectId/elementId` — element ids may themselves not contain `/`. */\nconst splitHandle = (handle: string): [string, string] => {\n const index = handle.indexOf('/');\n return [handle.slice(0, index), handle.slice(index + 1)];\n};\n\n/** Sample an arc (degrees, clockwise from +x, y-down screen coords) into spline points. */\nconst sampleArc = ({ cx, cy, r, startAngle, endAngle }: Scene.Arc): Scene.Point[] => {\n const sweep = endAngle - startAngle;\n const steps = Math.max(4, Math.ceil(Math.abs(sweep) / 22.5));\n return Array.from({ length: steps + 1 }, (_, i) => {\n const angle = ((startAngle + (sweep * i) / steps) * Math.PI) / 180;\n return { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) };\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Applies scene DSL edit commands to canvas content by mutating the record map in place\n// (callers wrap the call in `Obj.update` so a batch commits atomically).\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { type ApplyResult, type Scene } from '@dxos/plugin-illustrator/model';\n\nimport { elementBoxes, readScene } from './read';\nimport { renderObject } from './render';\nimport { type CanvasContent, DOCUMENT_ID, PAGE_ID } from './TldrawBuilder';\n\n/** Apply a batch of edit commands to the canvas content (mutates `content`). */\nexport const applyCommands = (content: CanvasContent, commands: readonly Scene.Command[]): ApplyResult => {\n ensurePage(content);\n const upserted = new Set<string>();\n let removed = 0;\n\n for (const command of commands) {\n switch (command.op) {\n case 'upsert-object': {\n const previous = readScene(content).scene.objects.find((object) => object.id === command.object.id);\n removed += remove(content, (record) => record.meta?.object === command.object.id);\n merge(content, command.object, {\n origin: command.object.origin ?? previous?.origin ?? { x: 0, y: 0 },\n scale: command.object.scale ?? previous?.scale ?? 1,\n });\n upserted.add(command.object.id);\n break;\n }\n case 'upsert-elements': {\n const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);\n invariant(previous, `unknown object: ${command.objectId} (use upsert-object to create it)`);\n const ids = new Set(command.elements.map((element) => element.id));\n removed += remove(\n content,\n (record) => record.meta?.object === command.objectId && ids.has(record.meta?.element),\n );\n merge(\n content,\n { id: command.objectId, elements: command.elements },\n { origin: previous.origin, scale: previous.scale },\n );\n upserted.add(command.objectId);\n break;\n }\n case 'remove-elements': {\n const ids = new Set(command.elementIds);\n removed += remove(\n content,\n (record) => record.meta?.object === command.objectId && ids.has(record.meta?.element),\n );\n break;\n }\n case 'remove-object': {\n removed += remove(content, (record) => record.meta?.object === command.objectId);\n break;\n }\n case 'move-object': {\n const previous = readScene(content).scene.objects.find((object) => object.id === command.objectId);\n invariant(previous, `unknown object: ${command.objectId}`);\n const delta = { x: command.origin.x - previous.origin.x, y: command.origin.y - previous.origin.y };\n for (const record of Object.values(content)) {\n if (record?.typeName === 'shape' && record.meta?.object === command.objectId) {\n record.x += delta.x;\n record.y += delta.y;\n }\n }\n upserted.add(command.objectId);\n break;\n }\n }\n }\n\n return { upserted: [...upserted], removed };\n};\n\nconst merge = (\n content: CanvasContent,\n object: Scene.WorldObject | { id: string; elements: readonly Scene.Element[] },\n placement: { origin: Scene.Point; scale: number },\n): void => {\n const records = renderObject(object, {\n ...placement,\n indexStart: nextIndex(content),\n external: elementBoxes(content),\n });\n Object.assign(content, records);\n};\n\n/** Delete matching shape records, then any bindings left dangling. */\nconst remove = (content: CanvasContent, predicate: (record: any) => boolean): number => {\n let removed = 0;\n for (const [key, record] of Object.entries(content)) {\n if (record?.typeName === 'shape' && predicate(record)) {\n delete content[key];\n removed++;\n }\n }\n for (const [key, record] of Object.entries(content)) {\n if (record?.typeName === 'binding' && (!content[record.fromId] || !content[record.toId])) {\n delete content[key];\n }\n }\n return removed;\n};\n\n/** Seed the fractional-index counter past any existing `a<n>` indexes. */\nconst nextIndex = (content: CanvasContent): number => {\n let max = 0;\n let shapes = 0;\n for (const record of Object.values(content)) {\n if (record?.typeName !== 'shape') {\n continue;\n }\n shapes++;\n const match = /^a(\\d+)$/.exec(record.index ?? '');\n if (match) {\n max = Math.max(max, Number(match[1]));\n }\n }\n return Math.max(max, shapes);\n};\n\nconst ensurePage = (content: CanvasContent): void => {\n content[DOCUMENT_ID] ??= { gridSize: 10, name: '', meta: {}, id: DOCUMENT_ID, typeName: 'document' };\n content[PAGE_ID] ??= { meta: {}, id: PAGE_ID, name: 'Page 1', index: 'a1', typeName: 'page' };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// tldraw implementation of the illustrator `SketchBuilder` contract: maps the scene DSL\n// onto the tldraw record map stored in `Tldraw.Canvas.content`.\n//\n\nimport { Obj } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\nimport { type ApplyResult, type SketchBuilder } from '@dxos/plugin-illustrator/model';\n\nimport { Tldraw } from '../types';\nimport { applyCommands } from './apply';\nimport { readScene } from './read';\n\nexport const tldrawBuilder: SketchBuilder = {\n read: (canvas) => {\n invariant(Obj.instanceOf(Tldraw.Canvas, canvas));\n return readScene(canvas.content);\n },\n apply: (canvas, commands) => {\n invariant(Obj.instanceOf(Tldraw.Canvas, canvas));\n let result: ApplyResult = { upserted: [], removed: 0 };\n Obj.update(canvas, (canvas) => {\n result = applyCommands(canvas.content as Obj.Mutable<typeof canvas.content>, commands);\n });\n return result;\n },\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './apply';\nexport * from './builder';\nexport * from './read';\nexport * from './render';\nexport * from './TldrawBuilder';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model.mjs","names":[],"sources":["../../src/model/read.ts","../../src/model/RecordBuilder.ts","../../src/model/render.ts","../../src/model/builder.ts","../../src/model/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Derives the neutral scene from tldraw records. Geometry is read from the live records —\n// not from a stored copy — so the agent's mental model stays coherent after users drag or\n// resize shapes in the UI. An object's `origin` is the top-left of its bounding box.\n//\n\nimport { type ReadResult, type ReadWorldObject, type Scene } from '@dxos/plugin-illustrator/model';\n\nimport { type CanvasContent } from './RecordBuilder';\nimport { type ExternalBox } from './render';\n\ntype ShapeRecord = Record<string, any>;\n\n/** Read the derived scene from canvas content. */\nexport const readScene = (content: CanvasContent): ReadResult => {\n const groups = new Map<string, ShapeRecord[]>();\n let unmanaged = 0;\n for (const record of Object.values(content ?? {})) {\n if (record?.typeName !== 'shape') {\n continue;\n }\n const objectId = record.meta?.object;\n if (typeof objectId !== 'string' || typeof record.meta?.element !== 'string') {\n unmanaged++;\n continue;\n }\n groups.set(objectId, [...(groups.get(objectId) ?? []), record]);\n }\n\n const objects = [...groups.entries()].map(([objectId, records]) => readObject(objectId, records, content));\n return { scene: { objects }, unmanaged };\n};\n\n/** Canvas-px bounding boxes of all managed elements, keyed by `objectId/elementId`. */\nexport const elementBoxes = (content: CanvasContent): Record<string, ExternalBox> => {\n const boxes: Record<string, ExternalBox> = {};\n for (const record of Object.values(content ?? {})) {\n if (record?.typeName === 'shape' && record.meta?.object && record.meta?.element) {\n boxes[`${record.meta.object}/${record.meta.element}`] = bounds(record);\n }\n }\n return boxes;\n};\n\nconst readObject = (objectId: string, records: ShapeRecord[], content: CanvasContent): ReadWorldObject => {\n const scale = records.find((record) => typeof record.meta?.scale === 'number')?.meta.scale ?? 1;\n const origin = {\n x: Math.min(...records.map((record) => bounds(record).x)),\n y: Math.min(...records.map((record) => bounds(record).y)),\n };\n const local = (abs: { x: number; y: number }): Scene.Point => ({\n x: round((abs.x - origin.x) / scale),\n y: round((abs.y - origin.y) / scale),\n });\n const length = (px: number) => round(px / scale);\n\n const elements = records\n .map((record) => readElement(record, { local, length, objectId, content }))\n .filter((element): element is Scene.Element => element !== undefined);\n\n return { id: objectId, origin, scale, elements };\n};\n\ntype ReadContext = {\n local: (abs: { x: number; y: number }) => Scene.Point;\n length: (px: number) => number;\n objectId: string;\n content: CanvasContent;\n};\n\nconst readElement = (record: ShapeRecord, ctx: ReadContext): Scene.Element | undefined => {\n const id = record.meta.element;\n const kind = record.meta.kind;\n switch (record.type) {\n case 'geo': {\n const boxKind = kind === 'rect' || kind === 'diamond' || kind === 'triangle' ? kind : 'ellipse';\n return {\n kind: boxKind,\n id,\n ...ctx.local({ x: record.x, y: record.y }),\n w: ctx.length(record.props.w),\n h: ctx.length(record.props.h),\n ...(record.rotation ? { rotation: round((record.rotation * 180) / Math.PI) } : {}),\n ...(record.props.text ? { text: record.props.text } : {}),\n ...readStyle(record),\n };\n }\n case 'text': {\n return {\n kind: 'text',\n id,\n ...ctx.local({ x: record.x, y: record.y }),\n ...(record.props.autoSize ? {} : { w: ctx.length(record.props.w) }),\n text: record.props.text ?? '',\n ...readStyle(record),\n };\n }\n case 'line': {\n const points = linePoints(record).map((point) => ctx.local({ x: record.x + point.x, y: record.y + point.y }));\n if (kind === 'curve') {\n return { kind: 'curve', id, points, ...readStyle(record) };\n }\n const closed =\n points.length > 2 && points[0].x === points[points.length - 1].x && points[0].y === points[points.length - 1].y;\n return {\n kind: 'line',\n id,\n points: closed ? points.slice(0, -1) : points,\n ...(closed ? { closed: true } : {}),\n ...readStyle(record),\n };\n }\n case 'arrow': {\n const { from, to } = arrowRefs(record, ctx);\n return {\n kind: 'arrow',\n id,\n ...(from\n ? { from }\n : { start: ctx.local({ x: record.x + record.props.start.x, y: record.y + record.props.start.y }) }),\n ...(to ? { to } : { end: ctx.local({ x: record.x + record.props.end.x, y: record.y + record.props.end.y }) }),\n ...(record.props.text ? { text: record.props.text } : {}),\n ...readStyle(record),\n };\n }\n default:\n return undefined;\n }\n};\n\n/** Resolve arrow terminal bindings back to element refs (same-object refs are shortened). */\nconst arrowRefs = (record: ShapeRecord, ctx: ReadContext): { from?: string; to?: string } => {\n const refs: { from?: string; to?: string } = {};\n for (const binding of Object.values(ctx.content ?? {})) {\n if (binding?.typeName !== 'binding' || binding.fromId !== record.id) {\n continue;\n }\n const target = ctx.content[binding.toId];\n if (!target?.meta?.object || !target?.meta?.element) {\n continue;\n }\n const ref =\n target.meta.object === ctx.objectId ? target.meta.element : `${target.meta.object}/${target.meta.element}`;\n if (binding.props?.terminal === 'start') {\n refs.from = ref;\n } else {\n refs.to = ref;\n }\n }\n return refs;\n};\n\n/** Report only non-default styles to keep the read output compact. */\nconst readStyle = (record: ShapeRecord): Partial<Pick<Scene.Box, 'color' | 'fill' | 'stroke' | 'weight'>> => {\n const { color, fill, dash, size } = record.props;\n return {\n ...(color && color !== 'black' ? { color } : {}),\n ...(fill && fill !== 'none' ? { fill: fill === 'pattern' ? ('pattern' as const) : ('solid' as const) } : {}),\n ...(dash && dash !== 'draw' ? { stroke: dash as Scene.Stroke } : {}),\n ...(size && size !== 'm' ? { weight: size as Scene.Weight } : {}),\n };\n};\n\nconst linePoints = (record: ShapeRecord): { x: number; y: number }[] =>\n Object.values(record.props.points ?? {})\n // Indexes are `a<n>` fractional keys; numeric compare so `a10` sorts after `a2`.\n .sort((a: any, b: any) => Number(String(a.index).slice(1)) - Number(String(b.index).slice(1)))\n .map((point: any) => ({ x: point.x, y: point.y }));\n\n/** Bounding box of a shape record in canvas px. */\nconst bounds = (record: ShapeRecord): ExternalBox => {\n switch (record.type) {\n case 'geo':\n return { x: record.x, y: record.y, w: record.props.w, h: record.props.h };\n case 'text':\n return { x: record.x, y: record.y, w: record.props.w ?? 0, h: 0 };\n case 'line': {\n const points = linePoints(record);\n const xs = points.map((point) => record.x + point.x);\n const ys = points.map((point) => record.y + point.y);\n return boxFrom(xs, ys);\n }\n case 'arrow': {\n const xs = [record.x + record.props.start.x, record.x + record.props.end.x];\n const ys = [record.y + record.props.start.y, record.y + record.props.end.y];\n return boxFrom(xs, ys);\n }\n default:\n return { x: record.x ?? 0, y: record.y ?? 0, w: record.props?.w ?? 0, h: record.props?.h ?? 0 };\n }\n};\n\nconst boxFrom = (xs: number[], ys: number[]): ExternalBox => {\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n return { x, y, w: Math.max(...xs) - x, h: Math.max(...ys) - y };\n};\n\nconst round = (value: number) => Math.round(value * 100) / 100;\n","//\n// Copyright 2024 DXOS.org\n//\n\n//\n// A minimal, chainable builder for tldraw (`tldraw.com/2`) canvas records.\n// Produces the record map stored in `Sketch.Canvas.content`. Used directly to seed\n// stories/tests (`build()`), and by the scene renderer (`render.ts`) to compile the\n// neutral scene DSL into records merged into an existing canvas (`records()`).\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type Color =\n | 'black'\n | 'grey'\n | 'light-violet'\n | 'violet'\n | 'blue'\n | 'light-blue'\n | 'yellow'\n | 'orange'\n | 'green'\n | 'light-green'\n | 'light-red'\n | 'red'\n | 'white';\n\nexport type Fill = 'none' | 'semi' | 'solid' | 'pattern' | 'fill';\nexport type Dash = 'draw' | 'solid' | 'dashed' | 'dotted';\nexport type Size = 's' | 'm' | 'l' | 'xl';\nexport type Font = 'draw' | 'sans' | 'serif' | 'mono';\nexport type Align = 'start' | 'middle' | 'end';\nexport type Geo =\n | 'rectangle'\n | 'ellipse'\n | 'triangle'\n | 'diamond'\n | 'pentagon'\n | 'hexagon'\n | 'octagon'\n | 'star'\n | 'rhombus'\n | 'oval'\n | 'cloud'\n | 'heart';\n\n/** Common style props shared by all shapes. */\nexport type StyleProps = {\n color?: Color;\n fill?: Fill;\n dash?: Dash;\n size?: Size;\n font?: Font;\n text?: string;\n align?: Align;\n};\n\n/** Geometric shape (rectangle, ellipse, etc.). */\nexport type ShapeProps = StyleProps & {\n /** Friendly handle used to link shapes (e.g. as an arrow target). */\n id?: string;\n x?: number;\n y?: number;\n w?: number;\n h?: number;\n rotation?: number;\n};\n\n/** Free-standing text label. */\nexport type TextProps = Omit<ShapeProps, 'h' | 'fill' | 'dash'>;\n\n/** Connector (arrow/line) between two shapes (or between explicit points). */\nexport type ConnectorProps = Omit<StyleProps, 'align'> & {\n id?: string;\n /** Handle of the source shape. */\n from?: string;\n /** Handle of the target shape. */\n to?: string;\n /** Explicit start point (used when `from` is omitted). */\n start?: Point;\n /** Explicit end point (used when `to` is omitted). */\n end?: Point;\n};\n\n/** Open or closed path through explicit points. */\nexport type PathProps = Omit<StyleProps, 'align'> & {\n id?: string;\n points: readonly Point[];\n /** Smooth (cubic spline) instead of straight segments. */\n smooth?: boolean;\n /** Close the path back to the first point. */\n closed?: boolean;\n};\n\nexport type Point = { x: number; y: number };\n\nexport type CanvasContent = Record<string, any>;\n\nexport const PAGE_ID = 'page:page';\nexport const DOCUMENT_ID = 'document:document';\n\nexport type BuilderOptions = {\n /** Fractional-index counter seed; pass a value past existing content when merging. */\n indexStart?: number;\n /** Per-shape meta, keyed by handle; merged into each generated record's `meta`. */\n metaFor?: (handle: string) => Record<string, any>;\n};\n\nconst DEFAULTS: {\n color: Color;\n fill: Fill;\n dash: Dash;\n size: Size;\n font: Font;\n align: Align;\n w: number;\n h: number;\n} = {\n color: 'black',\n fill: 'none',\n dash: 'draw',\n size: 'm',\n font: 'draw',\n align: 'middle',\n w: 160,\n h: 120,\n};\n\ntype Box = { id: string; x: number; y: number; w: number; h: number };\n\n/**\n * Chainable builder for sketch (tldraw) canvas content.\n *\n * @example\n * ```ts\n * const content = new RecordBuilder()\n * .rectangle({ id: 'a', x: 0, y: 0, text: 'DXOS', color: 'blue' })\n * .ellipse({ id: 'b', x: 320, y: 0, text: 'ECHO', color: 'green' })\n * .arrow({ from: 'a', to: 'b' })\n * .build();\n * ```\n */\nexport class RecordBuilder {\n readonly #records: CanvasContent = {};\n readonly #boxes = new Map<string, Box>();\n readonly #metaFor?: (handle: string) => Record<string, any>;\n #shapeCount = 0;\n #bindingCount = 0;\n #indexCount: number;\n\n constructor(options: BuilderOptions = {}) {\n this.#indexCount = options.indexStart ?? 0;\n this.#metaFor = options.metaFor;\n }\n\n /**\n * Register a shape that already exists on the canvas (its bounding box in canvas px)\n * so connectors added by this builder can bind to it.\n */\n external(handle: string, box: { x: number; y: number; w: number; h: number }, shapeId?: string): this {\n invariant(!this.#boxes.has(handle), `duplicate shape id: ${handle}`);\n this.#boxes.set(handle, { id: shapeId ?? `shape:${handle}`, ...box });\n return this;\n }\n\n /** Add a rectangle. */\n rectangle(props: ShapeProps = {}): this {\n return this.geo('rectangle', props);\n }\n\n /** Add an ellipse. */\n ellipse(props: ShapeProps = {}): this {\n return this.geo('ellipse', props);\n }\n\n /** Add a circle (an ellipse with equal width and height). */\n circle(props: ShapeProps = {}): this {\n const size = props.w ?? props.h ?? DEFAULTS.w;\n return this.geo('ellipse', { ...props, w: size, h: size });\n }\n\n /** Add an arbitrary geometric shape. */\n geo(geo: Geo, props: ShapeProps = {}): this {\n const { id, x = 0, y = 0, w = DEFAULTS.w, h = DEFAULTS.h, rotation = 0 } = props;\n const shapeId = this.#registerShape({ id, x, y, w, h });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'geo',\n x,\n y,\n rotation,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n geo,\n w,\n h,\n color: props.color ?? DEFAULTS.color,\n labelColor: DEFAULTS.color,\n fill: props.fill ?? DEFAULTS.fill,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n font: props.font ?? DEFAULTS.font,\n align: props.align ?? DEFAULTS.align,\n verticalAlign: 'middle',\n url: '',\n growY: 0,\n text: props.text ?? '',\n scale: 1,\n },\n };\n\n return this;\n }\n\n /** Add a free-standing text label. */\n text(props: TextProps = {}): this {\n const { id, x = 0, y = 0, w = DEFAULTS.w, rotation = 0 } = props;\n const shapeId = this.#registerShape({ id, x, y, w, h: 0 });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'text',\n x,\n y,\n rotation,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n color: props.color ?? DEFAULTS.color,\n size: props.size ?? DEFAULTS.size,\n font: props.font ?? DEFAULTS.font,\n textAlign: props.align ?? DEFAULTS.align,\n w,\n text: props.text ?? '',\n scale: 1,\n autoSize: true,\n },\n };\n\n return this;\n }\n\n /** Add an arrow, optionally bound to source/target shapes so it tracks them. */\n arrow(props: ConnectorProps = {}): this {\n return this.#connector('arrow', props);\n }\n\n /** Add a line between two shapes (or explicit points). */\n line(props: ConnectorProps = {}): this {\n return this.#connector('line', props);\n }\n\n /** Add a path (open or closed, straight or smooth) through explicit points. */\n path(props: PathProps): this {\n const { id, smooth, closed } = props;\n const source = closed && props.points.length > 1 ? [...props.points, props.points[0]] : [...props.points];\n invariant(source.length >= 2, 'path requires at least two points');\n const origin = source[0];\n const xs = source.map((point) => point.x);\n const ys = source.map((point) => point.y);\n const shapeId = this.#registerShape({\n id,\n x: Math.min(...xs),\n y: Math.min(...ys),\n w: Math.max(...xs) - Math.min(...xs),\n h: Math.max(...ys) - Math.min(...ys),\n });\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'line',\n x: origin.x,\n y: origin.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(id),\n props: {\n color: props.color ?? DEFAULTS.color,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n spline: smooth ? 'cubic' : 'line',\n points: Object.fromEntries(\n source.map((point, i) => [\n `a${i + 1}`,\n { id: `a${i + 1}`, index: `a${i + 1}`, x: point.x - origin.x, y: point.y - origin.y },\n ]),\n ),\n scale: 1,\n },\n };\n\n return this;\n }\n\n /** Build the full canvas snapshot (document + page + records). */\n build(): CanvasContent {\n return {\n [DOCUMENT_ID]: { gridSize: 10, name: '', meta: {}, id: DOCUMENT_ID, typeName: 'document' },\n [PAGE_ID]: { meta: {}, id: PAGE_ID, name: 'Page 1', index: 'a1', typeName: 'page' },\n ...this.#records,\n };\n }\n\n /** Return only the generated records (for merging into an existing canvas). */\n records(): CanvasContent {\n return { ...this.#records };\n }\n\n #connector(type: 'arrow' | 'line', props: ConnectorProps): this {\n const from = props.from ? this.#boxes.get(props.from) : undefined;\n const to = props.to ? this.#boxes.get(props.to) : undefined;\n // A referenced handle that resolves to nothing is a typo; fail rather than emit a misplaced connector.\n invariant(!props.from || from, `unknown source shape: ${props.from}`);\n invariant(!props.to || to, `unknown target shape: ${props.to}`);\n const start = from ? center(from) : (props.start ?? { x: 0, y: 0 });\n const end = to ? center(to) : (props.end ?? { x: DEFAULTS.w, y: 0 });\n\n const shapeId = this.#registerShape({ id: props.id, x: start.x, y: start.y, w: 0, h: 0 });\n const relativeEnd = { x: end.x - start.x, y: end.y - start.y };\n const style = {\n color: props.color ?? DEFAULTS.color,\n dash: props.dash ?? DEFAULTS.dash,\n size: props.size ?? DEFAULTS.size,\n };\n\n if (type === 'arrow') {\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'arrow',\n x: start.x,\n y: start.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(props.id),\n props: {\n ...style,\n labelColor: DEFAULTS.color,\n fill: props.fill ?? DEFAULTS.fill,\n font: props.font ?? DEFAULTS.font,\n arrowheadStart: 'none',\n arrowheadEnd: 'arrow',\n start: { x: 0, y: 0 },\n end: relativeEnd,\n bend: 0,\n text: props.text ?? '',\n labelPosition: 0.5,\n scale: 1,\n },\n };\n\n // Bindings make the arrow track its bound shapes (tldraw recomputes terminals).\n if (from) {\n this.#binding(shapeId, from.id, 'start');\n }\n if (to) {\n this.#binding(shapeId, to.id, 'end');\n }\n } else {\n this.#records[shapeId] = {\n id: shapeId,\n typeName: 'shape',\n type: 'line',\n x: start.x,\n y: start.y,\n rotation: 0,\n index: this.#nextIndex(),\n parentId: PAGE_ID,\n isLocked: false,\n opacity: 1,\n meta: this.#meta(props.id),\n props: {\n ...style,\n spline: 'line',\n points: {\n a1: { id: 'a1', index: 'a1', x: 0, y: 0 },\n a2: { id: 'a2', index: 'a2', x: relativeEnd.x, y: relativeEnd.y },\n },\n scale: 1,\n },\n };\n }\n\n return this;\n }\n\n #binding(arrowId: string, shapeId: string, terminal: 'start' | 'end'): void {\n // Deterministic per-terminal id so re-rendering an arrow overwrites its own bindings.\n const bindingId = `binding:${arrowId.slice('shape:'.length)}/${terminal}-${++this.#bindingCount}`;\n this.#records[bindingId] = {\n id: bindingId,\n typeName: 'binding',\n type: 'arrow',\n fromId: arrowId,\n toId: shapeId,\n meta: {},\n props: {\n terminal,\n normalizedAnchor: { x: 0.5, y: 0.5 },\n isExact: false,\n isPrecise: false,\n },\n };\n }\n\n #meta(handle: string | undefined): Record<string, any> {\n return handle && this.#metaFor ? this.#metaFor(handle) : {};\n }\n\n #registerShape(box: { id?: string; x: number; y: number; w: number; h: number }): string {\n // Skip autogenerated ids that collide with an explicit one (e.g. a user-supplied `s1`).\n let shapeId = box.id ? `shape:${box.id}` : `shape:s${++this.#shapeCount}`;\n while (!box.id && this.#records[shapeId]) {\n shapeId = `shape:s${++this.#shapeCount}`;\n }\n const handle = box.id ?? shapeId;\n // The id is the record-map key; reusing one would silently overwrite the earlier shape.\n invariant(!this.#records[shapeId] && !this.#boxes.has(handle), `duplicate shape id: ${handle}`);\n this.#boxes.set(handle, { id: shapeId, x: box.x, y: box.y, w: box.w, h: box.h });\n return shapeId;\n }\n\n #nextIndex(): string {\n return `a${++this.#indexCount}`;\n }\n}\n\nconst center = (box: Box): Point => ({ x: box.x + box.w / 2, y: box.y + box.h / 2 });\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// tldraw backend for the scene DSL: compiles a `WorldObject` into tldraw records.\n// Element identity is stamped into each record's `meta` (`{ object, element, kind, scale }`)\n// so `read.ts` can reconstruct the scene and edits can address records by id.\n//\n\nimport { Scene } from '@dxos/plugin-illustrator/model';\n\nimport {\n type CanvasContent,\n type ConnectorProps,\n type Dash,\n type Fill,\n type PathProps,\n type Point,\n RecordBuilder,\n type ShapeProps,\n} from './RecordBuilder';\n\nexport const DEFAULT_SCALE = 1;\n\n/** Canvas-px bounding box of an existing element another object's arrow may bind to. */\nexport type ExternalBox = { x: number; y: number; w: number; h: number };\n\nexport type RenderOptions = {\n origin: Scene.Point;\n scale: number;\n /** Fractional-index seed past the existing canvas content. */\n indexStart: number;\n /** Bounding boxes of existing elements, keyed by `objectId/elementId` (canvas px). */\n external?: Record<string, ExternalBox>;\n dialect?: string;\n};\n\n/** Stable record id for an element: `shape:<objectId>/<elementId>`. */\nexport const shapeId = (objectId: string, elementId: string) => `shape:${objectId}/${elementId}`;\n\nconst strokeToDash: Record<Scene.Stroke, Dash> = {\n sketchy: 'draw',\n solid: 'solid',\n dashed: 'dashed',\n dotted: 'dotted',\n};\n\nconst fillToFill: Record<Scene.Fill, Fill> = {\n none: 'none',\n solid: 'solid',\n pattern: 'pattern',\n};\n\nconst boxKindToGeo = {\n rect: 'rectangle',\n ellipse: 'ellipse',\n diamond: 'diamond',\n triangle: 'triangle',\n} as const;\n\nconst style = (element: Scene.Element): Pick<ShapeProps, 'color' | 'fill' | 'dash' | 'size'> => ({\n color: element.color,\n fill: 'fill' in element && element.fill ? fillToFill[element.fill] : undefined,\n dash: element.stroke ? strokeToDash[element.stroke] : undefined,\n size: element.weight,\n});\n\n/**\n * Compile one world object into tldraw records (canvas-px coordinates).\n * Local coordinates are mapped via `canvas = origin + local * scale`.\n */\nexport const renderObject = (object: Scene.WorldObject, options: RenderOptions): CanvasContent => {\n const { origin, scale, indexStart, external = {}, dialect = 'scene' } = options;\n const point = (local: Scene.Point | { x: number; y: number }): Point => ({\n x: origin.x + local.x * scale,\n y: origin.y + local.y * scale,\n });\n const length = (units: number) => units * scale;\n\n const kinds = new Map<string, string>();\n const builder = new RecordBuilder({\n indexStart,\n metaFor: (handle) => {\n const [objectId, elementId] = splitHandle(handle);\n return { object: objectId, element: elementId, kind: kinds.get(handle), scale, dialect };\n },\n });\n\n // Register existing canvas elements so arrows can bind across objects.\n for (const [handle, box] of Object.entries(external)) {\n builder.external(handle, box);\n }\n\n // Refs are element ids within this object, or `objectId/elementId` across objects.\n const ref = (value: string) => (value.includes('/') ? value : `${object.id}/${value}`);\n\n for (const element of object.elements) {\n const handle = `${object.id}/${element.id}`;\n kinds.set(handle, element.kind);\n switch (element.kind) {\n case 'rect':\n case 'ellipse':\n case 'diamond':\n case 'triangle': {\n builder.geo(boxKindToGeo[element.kind], {\n id: handle,\n ...point(element),\n w: length(element.w),\n h: length(element.h),\n rotation: element.rotation !== undefined ? (element.rotation * Math.PI) / 180 : undefined,\n text: element.text,\n ...style(element),\n });\n break;\n }\n case 'circle': {\n kinds.set(handle, 'ellipse');\n builder.circle({\n id: handle,\n ...point({ x: element.cx - element.r, y: element.cy - element.r }),\n w: length(element.r * 2),\n text: element.text,\n ...style(element),\n });\n break;\n }\n case 'line': {\n const props: PathProps = {\n id: handle,\n points: element.points.map(point),\n closed: element.closed,\n ...style(element),\n };\n builder.path(props);\n break;\n }\n case 'curve': {\n builder.path({ id: handle, points: element.points.map(point), smooth: true, ...style(element) });\n break;\n }\n case 'arc': {\n kinds.set(handle, 'curve');\n builder.path({ id: handle, points: sampleArc(element).map(point), smooth: true, ...style(element) });\n break;\n }\n case 'text': {\n builder.text({\n id: handle,\n ...point(element),\n w: element.w !== undefined ? length(element.w) : undefined,\n text: element.text,\n color: element.color,\n size: element.weight,\n });\n break;\n }\n case 'arrow': {\n const props: ConnectorProps = {\n id: handle,\n from: element.from ? ref(element.from) : undefined,\n to: element.to ? ref(element.to) : undefined,\n start: element.start ? point(element.start) : undefined,\n end: element.end ? point(element.end) : undefined,\n text: element.text,\n ...style(element),\n };\n builder.arrow(props);\n break;\n }\n }\n }\n\n return builder.records();\n};\n\n/** `objectId/elementId` — element ids may themselves not contain `/`. */\nconst splitHandle = (handle: string): [string, string] => {\n const index = handle.indexOf('/');\n return [handle.slice(0, index), handle.slice(index + 1)];\n};\n\n/** Sample an arc (degrees, clockwise from +x, y-down screen coords) into spline points. */\nconst sampleArc = ({ cx, cy, r, startAngle, endAngle }: Scene.Arc): Scene.Point[] => {\n const sweep = endAngle - startAngle;\n const steps = Math.max(4, Math.ceil(Math.abs(sweep) / 22.5));\n return Array.from({ length: steps + 1 }, (_, i) => {\n const angle = ((startAngle + (sweep * i) / steps) * Math.PI) / 180;\n return { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) };\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// tldraw implementation of the illustrator `DrawingBuilder` contract: supplies the record\n// encoding (identity in `meta`, page scaffold, binding cleanup) and inherits the command\n// semantics from the shared content handler.\n//\n\nimport {\n type ContentHandler,\n type ContentMap,\n type Identity,\n type Scene,\n applyCommands as applyContentCommands,\n makeBuilder,\n nextIndex,\n} from '@dxos/plugin-illustrator/model';\n\nimport { Tldraw } from '../types';\nimport { elementBoxes, readScene } from './read';\nimport { DOCUMENT_ID, PAGE_ID } from './RecordBuilder';\nimport { renderObject } from './render';\n\nconst isShape = (record: any) => record?.typeName === 'shape';\n\nconst handler: ContentHandler = {\n identify: (record) => {\n if (!isShape(record) || typeof record.meta?.object !== 'string' || typeof record.meta?.element !== 'string') {\n return undefined;\n }\n return { object: record.meta.object, element: record.meta.element } satisfies Identity;\n },\n\n render: (object, placement, content) =>\n renderObject(object, { ...placement, indexStart: nextIndex(content, isShape), external: elementBoxes(content) }),\n\n read: (content) => readScene(content),\n\n translate: (record, delta) => {\n record.x += delta.x;\n record.y += delta.y;\n },\n\n scaffold: (content: ContentMap) => {\n content[DOCUMENT_ID] ??= { gridSize: 10, name: '', meta: {}, id: DOCUMENT_ID, typeName: 'document' };\n content[PAGE_ID] ??= { meta: {}, id: PAGE_ID, name: 'Page 1', index: 'a1', typeName: 'page' };\n },\n\n // Bindings reference shapes by id; drop any left dangling by a deletion.\n prune: (content: ContentMap) => {\n for (const [key, record] of Object.entries(content)) {\n if (record?.typeName === 'binding' && (!content[record.fromId] || !content[record.toId])) {\n delete content[key];\n }\n }\n },\n};\n\nexport const TldrawBuilder = makeBuilder({ schema: Tldraw.TLDRAW_SCHEMA, handler });\n\n/**\n * Apply commands straight to a content map, bypassing ECHO — for tests and tooling that hold\n * raw tldraw records. The object-aware path is {@link TldrawBuilder}.\n */\nexport const applyCommands = (content: ContentMap, commands: readonly Scene.Command[]) =>\n applyContentCommands(content, commands, handler);\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './builder';\nexport * from './read';\nexport * from './render';\nexport * from './RecordBuilder';\n"],"mappings":"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"}
|
package/dist/lib/types.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as Settings_exports, r as Tldraw_exports, t as TldrawCapabilities_exports } from "./chunk-types.mjs";
|
|
2
2
|
export { Settings_exports as Settings, Tldraw_exports as Tldraw, TldrawCapabilities_exports as TldrawCapabilities };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TldrawPlugin.d.ts","sourceRoot":"","sources":["../../../src/TldrawPlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"TldrawPlugin.d.ts","sourceRoot":"","sources":["../../../src/TldrawPlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAU7C,eAAO,MAAM,YAAY,4BAYxB,CAAC;eAEa,YAAY"}
|
|
@@ -2,4 +2,4 @@ import * as Effect from 'effect/Effect';
|
|
|
2
2
|
import { Capability } from '@dxos/app-framework';
|
|
3
3
|
declare const _default: (props: void) => Effect.Effect<Capability.Any, never, import("effect/Scope").Scope>;
|
|
4
4
|
export default _default;
|
|
5
|
-
//# sourceMappingURL=
|
|
5
|
+
//# sourceMappingURL=drawing-variant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing-variant.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/drawing-variant.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Capability } from '@dxos/app-framework';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const DrawingVariant: Capability.LazyCapability<void, Capability.ModuleReturn, Error>;
|
|
3
3
|
export declare const TldrawSettings: Capability.LazyCapability<void, Capability.ModuleReturn, Error>;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,cAAc,iEAAuE,CAAC;AACnG,eAAO,MAAM,cAAc,iEAAgE,CAAC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import '@tldraw/tldraw/tldraw.css';
|
|
2
2
|
import './theme.css';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { Drawing } from '@dxos/plugin-illustrator/types';
|
|
5
|
+
import { type Settings } from '#types';
|
|
5
6
|
export type CanvasProps = {
|
|
6
|
-
canvas:
|
|
7
|
+
canvas: Drawing.Canvas;
|
|
7
8
|
readonly?: boolean;
|
|
8
9
|
autoCenter?: boolean;
|
|
9
10
|
hideUi?: boolean;
|
|
@@ -13,5 +14,5 @@ export type CanvasProps = {
|
|
|
13
14
|
};
|
|
14
15
|
export declare const CanvasComponent: React.ForwardRefExoticComponent<Omit<CanvasProps, "className"> & {
|
|
15
16
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
16
|
-
} & Pick<React.HTMLAttributes<Element>, "children" | "
|
|
17
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
17
18
|
//# sourceMappingURL=Canvas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Canvas.d.ts","sourceRoot":"","sources":["../../../../../src/components/Canvas/Canvas.tsx"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,CAAC;AACnC,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAgD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Canvas.d.ts","sourceRoot":"","sources":["../../../../../src/components/Canvas/Canvas.tsx"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,CAAC;AACnC,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAgD,MAAM,OAAO,CAAC;AAIrE,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAKzD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAYvC,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,eAAe;;6GA8N3B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Canvas.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Canvas/Canvas.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAmB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Canvas.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Canvas/Canvas.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAmB,MAAM,OAAO,CAAC;AAwDxC,QAAA,MAAM,IAAI;;;;;QAKN,MAAM;;CAE2B,CAAC;eAEvB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AA4BjC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
declare const meta: {
|
|
4
|
+
title: string;
|
|
5
|
+
render: () => React.JSX.Element;
|
|
6
|
+
decorators: import("@storybook/react").Decorator[];
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
export declare const Default: Story;
|
|
14
|
+
//# sourceMappingURL=Mermaid.stories.d.ts.map
|