@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.
Files changed (88) hide show
  1. package/dist/lib/TldrawPlugin.mjs +4 -5
  2. package/dist/lib/TldrawPlugin.mjs.map +1 -1
  3. package/dist/lib/capabilities.mjs +2 -2
  4. package/dist/lib/capabilities.mjs.map +1 -1
  5. package/dist/lib/chunk-TldrawArticle.mjs +10 -9
  6. package/dist/lib/chunk-TldrawArticle.mjs.map +1 -1
  7. package/dist/lib/chunk-TldrawCard.mjs +5 -5
  8. package/dist/lib/chunk-TldrawCard.mjs.map +1 -1
  9. package/dist/lib/chunk-drawing-variant.mjs +20 -0
  10. package/dist/lib/chunk-drawing-variant.mjs.map +1 -0
  11. package/dist/lib/chunk-meta.mjs +1 -0
  12. package/dist/lib/chunk-meta.mjs.map +1 -1
  13. package/dist/lib/chunk-types.mjs +5 -31
  14. package/dist/lib/chunk-types.mjs.map +1 -1
  15. package/dist/lib/components.mjs +1 -1
  16. package/dist/lib/components.mjs.map +1 -1
  17. package/dist/lib/hooks.mjs +5 -5
  18. package/dist/lib/hooks.mjs.map +1 -1
  19. package/dist/lib/index.mjs +1 -1
  20. package/dist/lib/model.mjs +58 -163
  21. package/dist/lib/model.mjs.map +1 -1
  22. package/dist/lib/types.mjs +1 -1
  23. package/dist/types/src/TldrawPlugin.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/{sketch-variant.d.ts → drawing-variant.d.ts} +1 -1
  25. package/dist/types/src/capabilities/drawing-variant.d.ts.map +1 -0
  26. package/dist/types/src/capabilities/index.d.ts +1 -1
  27. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  28. package/dist/types/src/components/Canvas/Canvas.d.ts +4 -3
  29. package/dist/types/src/components/Canvas/Canvas.d.ts.map +1 -1
  30. package/dist/types/src/components/Canvas/Canvas.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Canvas/Mermaid.stories.d.ts +14 -0
  32. package/dist/types/src/components/Canvas/Mermaid.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/actions.d.ts +2 -2
  34. package/dist/types/src/components/actions.d.ts.map +1 -1
  35. package/dist/types/src/containers/TldrawArticle/TldrawArticle.d.ts +3 -3
  36. package/dist/types/src/containers/TldrawArticle/TldrawArticle.d.ts.map +1 -1
  37. package/dist/types/src/containers/TldrawCard/TldrawCard.d.ts +2 -2
  38. package/dist/types/src/containers/TldrawCard/TldrawCard.d.ts.map +1 -1
  39. package/dist/types/src/containers/TldrawCard/TldrawCard.stories.d.ts.map +1 -1
  40. package/dist/types/src/hooks/useStoreAdapter.d.ts +2 -2
  41. package/dist/types/src/hooks/useStoreAdapter.d.ts.map +1 -1
  42. package/dist/types/src/model/{TldrawBuilder.d.ts → RecordBuilder.d.ts} +3 -3
  43. package/dist/types/src/model/{TldrawBuilder.d.ts.map → RecordBuilder.d.ts.map} +1 -1
  44. package/dist/types/src/model/RecordBuilder.test.d.ts +2 -0
  45. package/dist/types/src/model/RecordBuilder.test.d.ts.map +1 -0
  46. package/dist/types/src/model/builder.d.ts +7 -2
  47. package/dist/types/src/model/builder.d.ts.map +1 -1
  48. package/dist/types/src/model/index.d.ts +1 -2
  49. package/dist/types/src/model/index.d.ts.map +1 -1
  50. package/dist/types/src/model/read.d.ts +1 -1
  51. package/dist/types/src/model/read.d.ts.map +1 -1
  52. package/dist/types/src/model/render.d.ts +1 -1
  53. package/dist/types/src/types/Tldraw.d.ts +3 -22
  54. package/dist/types/src/types/Tldraw.d.ts.map +1 -1
  55. package/dist/types/src/types/TldrawCapabilities.d.ts +1 -1
  56. package/dist/types/src/types/TldrawCapabilities.d.ts.map +1 -1
  57. package/dist/types/tsconfig.tsbuildinfo +1 -1
  58. package/dx.config.ts +1 -0
  59. package/package.json +33 -32
  60. package/src/TldrawPlugin.tsx +3 -5
  61. package/src/capabilities/{sketch-variant.ts → drawing-variant.ts} +7 -8
  62. package/src/capabilities/index.ts +1 -1
  63. package/src/components/Canvas/Canvas.stories.tsx +11 -7
  64. package/src/components/Canvas/Canvas.tsx +3 -2
  65. package/src/components/Canvas/Mermaid.stories.tsx +68 -0
  66. package/src/components/actions.ts +2 -3
  67. package/src/containers/TldrawArticle/TldrawArticle.tsx +8 -7
  68. package/src/containers/TldrawCard/TldrawCard.stories.tsx +8 -7
  69. package/src/containers/TldrawCard/TldrawCard.tsx +4 -4
  70. package/src/hooks/useStoreAdapter.ts +2 -1
  71. package/src/model/{TldrawBuilder.test.ts → RecordBuilder.test.ts} +8 -8
  72. package/src/model/{TldrawBuilder.ts → RecordBuilder.ts} +2 -2
  73. package/src/model/builder.ts +55 -18
  74. package/src/model/index.ts +1 -2
  75. package/src/model/read.ts +1 -1
  76. package/src/model/render.ts +3 -3
  77. package/src/model/scene.test.ts +1 -1
  78. package/src/types/Tldraw.ts +3 -30
  79. package/src/types/TldrawCapabilities.ts +1 -1
  80. package/src/variant.test.ts +19 -21
  81. package/dist/lib/chunk-sketch-variant.mjs +0 -23
  82. package/dist/lib/chunk-sketch-variant.mjs.map +0 -1
  83. package/dist/types/src/capabilities/sketch-variant.d.ts.map +0 -1
  84. package/dist/types/src/model/TldrawBuilder.test.d.ts +0 -2
  85. package/dist/types/src/model/TldrawBuilder.test.d.ts.map +0 -1
  86. package/dist/types/src/model/apply.d.ts +0 -5
  87. package/dist/types/src/model/apply.d.ts.map +0 -1
  88. package/src/model/apply.ts +0 -132
@@ -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 './apply';
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. */
@@ -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
- * Creates an empty {@link Canvas}.
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 makeCanvas = ({ schema = TLDRAW_SCHEMA, content = {} }: MakeOptions = {}): Canvas =>
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';
@@ -4,7 +4,7 @@
4
4
 
5
5
  // @import-as-namespace
6
6
 
7
- import { type Atom } from '@effect-atom/atom-react';
7
+ import { type Atom } from '@effect-atom/atom';
8
8
 
9
9
  import { Capability } from '@dxos/app-framework';
10
10
 
@@ -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, Type } from '@dxos/echo';
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 { tldrawBuilder } from '#model';
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: [Sketch.Sketch, Tldraw.Canvas],
33
+ types: [Drawing.Drawing, Drawing.Canvas],
34
34
  disableLlmMemoization: true,
35
35
  });
36
36
 
37
- /** Capability manager pre-loaded with the tldraw sketch variant, as the plugin would contribute it. */
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: Type.getTypename(Tldraw.Canvas),
43
+ id: Tldraw.TLDRAW_SCHEMA,
44
44
  label: 'tldraw',
45
- canvasType: Tldraw.Canvas,
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 sketch variant', () => {
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: sketch } = yield* Operation.invoke(SketchOperation.Create, { name: 'Portrait' });
65
- yield* Database.add(sketch);
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(sketch);
65
+ const ref = Ref.make(drawing);
68
66
 
69
67
  // Draw a face.
70
- const face = yield* Operation.invoke(SketchOperation.Edit, {
71
- sketch: ref,
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(SketchOperation.Read, { sketch: ref });
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(SketchOperation.Edit, {
100
- sketch: ref,
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(SketchOperation.Edit, {
132
- sketch: ref,
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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=TldrawBuilder.test.d.ts.map
@@ -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"}
@@ -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
- };