@dxos/plugin-illustrator 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 (184) hide show
  1. package/dist/lib/IllustratorPlugin.mjs +7 -3
  2. package/dist/lib/IllustratorPlugin.mjs.map +1 -1
  3. package/dist/lib/IllustratorPlugin.node.mjs +3 -3
  4. package/dist/lib/IllustratorPlugin.node.mjs.map +1 -1
  5. package/dist/lib/IllustratorPlugin.workerd.mjs +2 -2
  6. package/dist/lib/IllustratorPlugin.workerd.mjs.map +1 -1
  7. package/dist/lib/capabilities.mjs +2 -1
  8. package/dist/lib/capabilities.mjs.map +1 -1
  9. package/dist/lib/chunk-Drawing.mjs +64 -0
  10. package/dist/lib/chunk-Drawing.mjs.map +1 -0
  11. package/dist/lib/chunk-IllustratorCapabilities.mjs +2 -2
  12. package/dist/lib/chunk-IllustratorCapabilities.mjs.map +1 -1
  13. package/dist/lib/chunk-comment-config.mjs +3 -3
  14. package/dist/lib/chunk-comment-config.mjs.map +1 -1
  15. package/dist/lib/chunk-create-object.mjs +13 -12
  16. package/dist/lib/chunk-create-object.mjs.map +1 -1
  17. package/dist/lib/chunk-create.mjs +5 -4
  18. package/dist/lib/chunk-create.mjs.map +1 -1
  19. package/dist/lib/chunk-edit.mjs +4 -4
  20. package/dist/lib/chunk-edit.mjs.map +1 -1
  21. package/dist/lib/chunk-generate.mjs +20 -0
  22. package/dist/lib/chunk-generate.mjs.map +1 -0
  23. package/dist/lib/chunk-load-drawing.mjs +35 -0
  24. package/dist/lib/chunk-load-drawing.mjs.map +1 -0
  25. package/dist/lib/chunk-meta.mjs +2 -1
  26. package/dist/lib/chunk-meta.mjs.map +1 -1
  27. package/dist/lib/chunk-migrations.mjs +23 -0
  28. package/dist/lib/chunk-migrations.mjs.map +1 -0
  29. package/dist/lib/chunk-model.mjs +387 -4
  30. package/dist/lib/chunk-model.mjs.map +1 -1
  31. package/dist/lib/chunk-react-surface.mjs +14 -13
  32. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  33. package/dist/lib/chunk-read.mjs +4 -4
  34. package/dist/lib/chunk-read.mjs.map +1 -1
  35. package/dist/lib/chunk-skill-definition.mjs +2 -2
  36. package/dist/lib/chunk-skill-definition.mjs.map +1 -1
  37. package/dist/lib/chunk-skills.mjs +10 -10
  38. package/dist/lib/chunk-skills.mjs.map +1 -1
  39. package/dist/lib/chunk-types.mjs +41 -49
  40. package/dist/lib/chunk-types.mjs.map +1 -1
  41. package/dist/lib/components.mjs +6 -6
  42. package/dist/lib/components.mjs.map +1 -1
  43. package/dist/lib/containers.mjs +17 -19
  44. package/dist/lib/containers.mjs.map +1 -1
  45. package/dist/lib/index.mjs +4 -3
  46. package/dist/lib/model.mjs +2 -2
  47. package/dist/lib/operations.mjs +1 -1
  48. package/dist/lib/operations.mjs.map +1 -1
  49. package/dist/lib/skills.mjs +1 -1
  50. package/dist/lib/translations.mjs +13 -13
  51. package/dist/lib/translations.mjs.map +1 -1
  52. package/dist/lib/types.mjs +3 -2
  53. package/dist/lib/util.mjs +2 -2
  54. package/dist/types/src/IllustratorPlugin.d.ts.map +1 -1
  55. package/dist/types/src/IllustratorPlugin.node.d.ts +1 -1
  56. package/dist/types/src/IllustratorPlugin.test.d.ts +2 -0
  57. package/dist/types/src/IllustratorPlugin.test.d.ts.map +1 -0
  58. package/dist/types/src/capabilities/index.d.ts +1 -0
  59. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  60. package/dist/types/src/capabilities/migrations.d.ts +7 -0
  61. package/dist/types/src/capabilities/migrations.d.ts.map +1 -0
  62. package/dist/types/src/capabilities/migrations.test.d.ts +2 -0
  63. package/dist/types/src/capabilities/migrations.test.d.ts.map +1 -0
  64. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  65. package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
  66. package/dist/types/src/components/CreateDrawingPanel.d.ts +15 -0
  67. package/dist/types/src/components/CreateDrawingPanel.d.ts.map +1 -0
  68. package/dist/types/src/components/index.d.ts +1 -1
  69. package/dist/types/src/components/index.d.ts.map +1 -1
  70. package/dist/types/src/containers/DrawingArticle/DrawingArticle.d.ts +11 -0
  71. package/dist/types/src/containers/DrawingArticle/DrawingArticle.d.ts.map +1 -0
  72. package/dist/types/src/containers/DrawingArticle/index.d.ts +2 -0
  73. package/dist/types/src/containers/DrawingArticle/index.d.ts.map +1 -0
  74. package/dist/types/src/containers/DrawingCard/DrawingCard.d.ts +10 -0
  75. package/dist/types/src/containers/DrawingCard/DrawingCard.d.ts.map +1 -0
  76. package/dist/types/src/containers/DrawingCard/index.d.ts +2 -0
  77. package/dist/types/src/containers/DrawingCard/index.d.ts.map +1 -0
  78. package/dist/types/src/containers/index.d.ts +2 -2
  79. package/dist/types/src/containers/index.d.ts.map +1 -1
  80. package/dist/types/src/model/builder.d.ts +18 -26
  81. package/dist/types/src/model/builder.d.ts.map +1 -1
  82. package/dist/types/src/model/content.d.ts +60 -0
  83. package/dist/types/src/model/content.d.ts.map +1 -0
  84. package/dist/types/src/model/index.d.ts +2 -0
  85. package/dist/types/src/model/index.d.ts.map +1 -1
  86. package/dist/types/src/model/mermaid.d.ts +38 -0
  87. package/dist/types/src/model/mermaid.d.ts.map +1 -0
  88. package/dist/types/src/model/mermaid.test.d.ts +3 -0
  89. package/dist/types/src/model/mermaid.test.d.ts.map +1 -0
  90. package/dist/types/src/operations/create.d.ts +2 -2
  91. package/dist/types/src/operations/create.d.ts.map +1 -1
  92. package/dist/types/src/operations/edit.d.ts +2 -2
  93. package/dist/types/src/operations/edit.d.ts.map +1 -1
  94. package/dist/types/src/operations/generate.d.ts +5 -0
  95. package/dist/types/src/operations/generate.d.ts.map +1 -0
  96. package/dist/types/src/operations/index.d.ts.map +1 -1
  97. package/dist/types/src/operations/read.d.ts +2 -2
  98. package/dist/types/src/operations/read.d.ts.map +1 -1
  99. package/dist/types/src/skills/{sketch-skill.d.ts → drawing-skill.d.ts} +1 -1
  100. package/dist/types/src/skills/drawing-skill.d.ts.map +1 -0
  101. package/dist/types/src/skills/index.d.ts +1 -1
  102. package/dist/types/src/skills/index.d.ts.map +1 -1
  103. package/dist/types/src/translations.d.ts +10 -10
  104. package/dist/types/src/translations.d.ts.map +1 -1
  105. package/dist/types/src/types/Drawing.d.ts +50 -0
  106. package/dist/types/src/types/Drawing.d.ts.map +1 -0
  107. package/dist/types/src/types/{SketchOperation.d.ts → DrawingOperation.d.ts} +111 -5
  108. package/dist/types/src/types/DrawingOperation.d.ts.map +1 -0
  109. package/dist/types/src/types/IllustratorCapabilities.d.ts +4 -4
  110. package/dist/types/src/types/IllustratorCapabilities.d.ts.map +1 -1
  111. package/dist/types/src/types/LegacySketch.d.ts +17 -0
  112. package/dist/types/src/types/LegacySketch.d.ts.map +1 -0
  113. package/dist/types/src/types/index.d.ts +3 -2
  114. package/dist/types/src/types/index.d.ts.map +1 -1
  115. package/dist/types/src/types/types.d.ts +18 -18
  116. package/dist/types/src/types/types.d.ts.map +1 -1
  117. package/dist/types/src/util/index.d.ts +1 -1
  118. package/dist/types/src/util/index.d.ts.map +1 -1
  119. package/dist/types/src/util/load-drawing.d.ts +22 -0
  120. package/dist/types/src/util/load-drawing.d.ts.map +1 -0
  121. package/dist/types/tsconfig.tsbuildinfo +1 -1
  122. package/dx.config.ts +1 -0
  123. package/package.json +21 -19
  124. package/src/IllustratorPlugin.node.tsx +3 -3
  125. package/src/IllustratorPlugin.test.ts +32 -0
  126. package/src/IllustratorPlugin.tsx +15 -3
  127. package/src/IllustratorPlugin.workerd.tsx +2 -2
  128. package/src/capabilities/comment-config.ts +2 -2
  129. package/src/capabilities/create-object.ts +16 -14
  130. package/src/capabilities/index.ts +1 -0
  131. package/src/capabilities/migrations.test.ts +142 -0
  132. package/src/capabilities/migrations.ts +28 -0
  133. package/src/capabilities/react-surface.ts +36 -0
  134. package/src/capabilities/skill-definition.ts +2 -2
  135. package/src/components/{CreateSketchPanel.tsx → CreateDrawingPanel.tsx} +7 -7
  136. package/src/components/index.ts +1 -1
  137. package/src/containers/{SketchArticle/SketchArticle.tsx → DrawingArticle/DrawingArticle.tsx} +10 -11
  138. package/src/containers/{SketchArticle → DrawingArticle}/index.ts +1 -1
  139. package/src/containers/DrawingCard/DrawingCard.tsx +38 -0
  140. package/src/containers/{SketchCard → DrawingCard}/index.ts +1 -1
  141. package/src/containers/index.ts +2 -2
  142. package/src/model/builder.ts +34 -26
  143. package/src/model/content.ts +180 -0
  144. package/src/model/index.ts +2 -0
  145. package/src/model/mermaid.test.ts +116 -0
  146. package/src/model/mermaid.ts +299 -0
  147. package/src/operations/create.ts +6 -6
  148. package/src/operations/edit.ts +5 -5
  149. package/src/operations/generate.ts +25 -0
  150. package/src/operations/index.ts +1 -0
  151. package/src/operations/read.ts +5 -5
  152. package/src/skills/{sketch-skill.ts → drawing-skill.ts} +7 -7
  153. package/src/skills/index.ts +1 -1
  154. package/src/translations.ts +12 -12
  155. package/src/types/Drawing.ts +69 -0
  156. package/src/types/{SketchOperation.ts → DrawingOperation.ts} +28 -9
  157. package/src/types/IllustratorCapabilities.ts +4 -4
  158. package/src/types/LegacySketch.ts +25 -0
  159. package/src/types/index.ts +3 -2
  160. package/src/types/types.ts +18 -18
  161. package/src/util/index.ts +1 -1
  162. package/src/util/load-drawing.ts +48 -0
  163. package/dist/lib/chunk-load-sketch.mjs +0 -64
  164. package/dist/lib/chunk-load-sketch.mjs.map +0 -1
  165. package/dist/types/src/components/CreateSketchPanel.d.ts +0 -15
  166. package/dist/types/src/components/CreateSketchPanel.d.ts.map +0 -1
  167. package/dist/types/src/containers/SketchArticle/SketchArticle.d.ts +0 -11
  168. package/dist/types/src/containers/SketchArticle/SketchArticle.d.ts.map +0 -1
  169. package/dist/types/src/containers/SketchArticle/index.d.ts +0 -2
  170. package/dist/types/src/containers/SketchArticle/index.d.ts.map +0 -1
  171. package/dist/types/src/containers/SketchCard/SketchCard.d.ts +0 -10
  172. package/dist/types/src/containers/SketchCard/SketchCard.d.ts.map +0 -1
  173. package/dist/types/src/containers/SketchCard/index.d.ts +0 -2
  174. package/dist/types/src/containers/SketchCard/index.d.ts.map +0 -1
  175. package/dist/types/src/skills/sketch-skill.d.ts.map +0 -1
  176. package/dist/types/src/types/Sketch.d.ts +0 -50
  177. package/dist/types/src/types/Sketch.d.ts.map +0 -1
  178. package/dist/types/src/types/SketchOperation.d.ts.map +0 -1
  179. package/dist/types/src/util/load-sketch.d.ts +0 -37
  180. package/dist/types/src/util/load-sketch.d.ts.map +0 -1
  181. package/src/capabilities/react-surface.tsx +0 -37
  182. package/src/containers/SketchCard/SketchCard.tsx +0 -41
  183. package/src/types/Sketch.ts +0 -69
  184. package/src/util/load-sketch.ts +0 -74
package/dx.config.ts CHANGED
@@ -31,5 +31,6 @@ export default Config2.make({
31
31
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-illustrator',
32
32
  icon: { key: 'ph--compass-tool--regular', hue: 'indigo' },
33
33
  spec: 'PLUGIN.mdl',
34
+ tags: ['alpha'],
34
35
  },
35
36
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-illustrator",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Headless diagramming plugin for DXOS Composer (unifies canvas renderers like tldraw and excalidraw).",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -108,20 +108,21 @@
108
108
  ],
109
109
  "dependencies": {
110
110
  "effect": "3.21.4",
111
- "@dxos/app-framework": "0.10.0",
112
- "@dxos/app-toolkit": "0.10.0",
113
- "@dxos/compute": "0.10.0",
114
- "@dxos/echo": "0.10.0",
115
- "@dxos/echo-react": "0.10.0",
116
- "@dxos/invariant": "0.10.0",
117
- "@dxos/log": "0.10.0",
118
- "@dxos/keys": "0.10.0",
119
- "@dxos/plugin-space": "0.10.0",
120
- "@dxos/react-ui": "0.10.0",
121
- "@dxos/react-ui-search": "0.10.0",
122
- "@dxos/util": "0.10.0",
123
- "@dxos/schema": "0.10.0",
124
- "@dxos/react-ui-form": "0.10.0"
111
+ "@dxos/app-framework": "0.11.1",
112
+ "@dxos/app-toolkit": "0.11.1",
113
+ "@dxos/compute": "0.11.1",
114
+ "@dxos/echo": "0.11.1",
115
+ "@dxos/invariant": "0.11.1",
116
+ "@dxos/echo-react": "0.11.1",
117
+ "@dxos/keys": "0.11.1",
118
+ "@dxos/log": "0.11.1",
119
+ "@dxos/plugin-client": "0.11.1",
120
+ "@dxos/react-ui": "0.11.1",
121
+ "@dxos/plugin-space": "0.11.1",
122
+ "@dxos/react-ui-form": "0.11.1",
123
+ "@dxos/react-ui-search": "0.11.1",
124
+ "@dxos/util": "0.11.1",
125
+ "@dxos/schema": "0.11.1"
125
126
  },
126
127
  "devDependencies": {
127
128
  "@types/react": "~19.2.17",
@@ -129,14 +130,15 @@
129
130
  "react": "~19.2.7",
130
131
  "react-dom": "~19.2.7",
131
132
  "vite": "^8.1.4",
132
- "@dxos/ui-theme": "0.10.0",
133
- "@dxos/plugin-testing": "0.10.0"
133
+ "@dxos/echo-client": "0.11.1",
134
+ "@dxos/ui-theme": "0.11.1",
135
+ "@dxos/plugin-testing": "0.11.1"
134
136
  },
135
137
  "peerDependencies": {
136
138
  "react": "~19.2.7",
137
139
  "react-dom": "~19.2.7",
138
- "@dxos/react-ui": "^0.10.0",
139
- "@dxos/ui-theme": "^0.10.0"
140
+ "@dxos/react-ui": "^0.11.1",
141
+ "@dxos/ui-theme": "^0.11.1"
140
142
  },
141
143
  "publishConfig": {
142
144
  "access": "public"
@@ -8,17 +8,17 @@ import { AppPlugin } from '@dxos/app-toolkit';
8
8
  import { OperationHandler, SkillDefinition } from '#capabilities';
9
9
  import { meta } from '#meta';
10
10
  import { translations } from '#translations';
11
- import { Sketch } from '#types';
11
+ import { Drawing } from '#types';
12
12
 
13
13
  /**
14
14
  * Headless variant of IllustratorPlugin (no React surfaces / CreateObject panel).
15
15
  * Used in node contexts (CLI, agents, tests) where rendering is unavailable —
16
- * the full variant lazy-loads `CreateSketchPanel` from `react-ui-search` which
16
+ * the full variant lazy-loads `CreateDrawingPanel` from `react-ui-search` which
17
17
  * downstream bundlers don't resolve cleanly under nested pnpm symlinks.
18
18
  */
19
19
  export const IllustratorPlugin = Plugin.define(meta).pipe(
20
20
  AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
21
- AppPlugin.addSchemaModule({ schema: [Sketch.Sketch] }),
21
+ AppPlugin.addSchemaModule({ schema: [Drawing.Drawing, Drawing.Canvas] }),
22
22
  AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }),
23
23
  AppPlugin.addTranslationsModule({ translations }),
24
24
  Plugin.make,
@@ -0,0 +1,32 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { AppCapabilities } from '@dxos/app-toolkit';
8
+ import { Type } from '@dxos/echo';
9
+ import { ClientPlugin } from '@dxos/plugin-client/plugin';
10
+ import { createComposerTestApp } from '@dxos/plugin-testing/harness';
11
+
12
+ import { IllustratorPlugin } from '#plugin';
13
+
14
+ import { Drawing } from './types';
15
+
16
+ describe('IllustratorPlugin', () => {
17
+ // Canvas is written to the database by every variant's create flow, so the plugin that owns the
18
+ // type must register it — registering it from a renderer plugin breaks the others when disabled.
19
+ test('registers both the Drawing and Canvas schemas', async ({ expect }) => {
20
+ await using harness = await createComposerTestApp({
21
+ plugins: [ClientPlugin({}), IllustratorPlugin()],
22
+ });
23
+
24
+ const typenames = harness
25
+ .getAll(AppCapabilities.Schema)
26
+ .flat()
27
+ .map((schema) => Type.getTypename(schema));
28
+ expect(typenames).toEqual(
29
+ expect.arrayContaining([Type.getTypename(Drawing.Drawing), Type.getTypename(Drawing.Canvas)]),
30
+ );
31
+ });
32
+ });
@@ -4,20 +4,32 @@
4
4
 
5
5
  import { Plugin } from '@dxos/app-framework';
6
6
  import { AppPlugin } from '@dxos/app-toolkit';
7
+ import { ClientEvents } from '@dxos/plugin-client';
7
8
 
8
- import { CommentConfig, CreateObject, OperationHandler, ReactSurface, SkillDefinition } from '#capabilities';
9
+ import {
10
+ CommentConfig,
11
+ CreateObject,
12
+ Migrations,
13
+ OperationHandler,
14
+ ReactSurface,
15
+ SkillDefinition,
16
+ } from '#capabilities';
9
17
  import { meta } from '#meta';
10
18
  import { translations } from '#translations';
11
- import { Sketch } from '#types';
19
+ import { Drawing } from '#types';
12
20
 
13
21
  // eslint-disable-next-line import/no-relative-packages
14
22
  import pluginSpec from '../PLUGIN.mdl?raw';
15
23
 
16
24
  export const IllustratorPlugin = Plugin.define(meta).pipe(
25
+ Plugin.addModule({
26
+ activatesOn: ClientEvents.SetupMigration,
27
+ activate: Migrations,
28
+ }),
17
29
  AppPlugin.addCommentConfigModule({ activate: CommentConfig }),
18
30
  AppPlugin.addCreateObjectModule({ activate: CreateObject }),
19
31
  AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
20
- AppPlugin.addSchemaModule({ schema: [Sketch.Sketch] }),
32
+ AppPlugin.addSchemaModule({ schema: [Drawing.Drawing, Drawing.Canvas] }),
21
33
  AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }),
22
34
  AppPlugin.addSurfaceModule({ activate: ReactSurface }),
23
35
  AppPlugin.addTranslationsModule({ translations }),
@@ -6,10 +6,10 @@ import { Plugin } from '@dxos/app-framework';
6
6
  import { AppPlugin } from '@dxos/app-toolkit';
7
7
 
8
8
  import { meta } from '#meta';
9
- import { Sketch } from '#types';
9
+ import { Drawing } from '#types';
10
10
 
11
11
  export const IllustratorPlugin = Plugin.define(meta).pipe(
12
- AppPlugin.addSchemaModule({ schema: [Sketch.Sketch] }),
12
+ AppPlugin.addSchemaModule({ schema: [Drawing.Drawing, Drawing.Canvas] }),
13
13
  Plugin.make,
14
14
  );
15
15
 
@@ -8,11 +8,11 @@ import { Capability } from '@dxos/app-framework';
8
8
  import { AppCapabilities } from '@dxos/app-toolkit';
9
9
  import { Type } from '@dxos/echo';
10
10
 
11
- import { Sketch } from '#types';
11
+ import { Drawing } from '#types';
12
12
 
13
13
  const activate = Effect.fnUntraced(function* () {
14
14
  return Capability.contributes(AppCapabilities.CommentConfig, {
15
- id: Type.getTypename(Sketch.Sketch),
15
+ id: Type.getTypename(Drawing.Drawing),
16
16
  comments: 'unanchored',
17
17
  });
18
18
  });
@@ -10,17 +10,17 @@ import { Database, Type } from '@dxos/echo';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { SpaceCapabilities, SpaceOperation } from '@dxos/plugin-space';
12
12
 
13
- import { CreateSketchPanel } from '#components';
13
+ import { CreateDrawingPanel } from '#components';
14
14
 
15
- import { IllustratorCapabilities, Sketch } from '../types';
15
+ import { Drawing, IllustratorCapabilities } from '../types';
16
16
 
17
17
  type CreateOptions = Parameters<SpaceCapabilities.CreateObjectEntry['createObject']>[1];
18
18
 
19
19
  export default Capability.makeModule(
20
20
  Effect.fnUntraced(function* () {
21
21
  return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
22
- id: Type.getTypename(Sketch.Sketch),
23
- customPanel: CreateSketchPanel,
22
+ id: Type.getTypename(Drawing.Drawing),
23
+ customPanel: CreateDrawingPanel,
24
24
  createObject: (
25
25
  { variantId, input }: { variantId: string; input?: Record<string, any> },
26
26
  options: CreateOptions,
@@ -28,31 +28,33 @@ export default Capability.makeModule(
28
28
  Effect.gen(function* () {
29
29
  const variants = yield* Capability.getAll(IllustratorCapabilities.VariantProvider);
30
30
  const variant = variants.find((entry) => entry.id === variantId);
31
- invariant(variant, `Unknown sketch variant: ${variantId}`);
31
+ invariant(variant, `Unknown drawing variant: ${variantId}`);
32
32
 
33
- // Build the canvas object via the variant's factory.
34
- const canvas = yield* variant
35
- .createCanvas(input ?? {})
36
- .pipe(Effect.provideService(Database.Service, Database.makeService(options.db)));
33
+ // Build the canvas: variants only supply a factory when they extend the base type.
34
+ const canvas = variant.createCanvas
35
+ ? yield* variant
36
+ .createCanvas(input ?? {})
37
+ .pipe(Effect.provideService(Database.Service, Database.makeService(options.db)))
38
+ : Drawing.makeCanvas({ schema: variant.id });
37
39
 
38
- // Add the canvas to the database. Stays hidden — it's referenced by the Sketch and
39
- // shouldn't appear as a top-level item in the user's space.
40
+ // Add the canvas to the database. It carries HiddenAnnotation, so `CollectionModel.add`
41
+ // persists it without filing it into the target collection.
40
42
  yield* Operation.invoke(SpaceOperation.AddObject, {
41
43
  object: canvas,
42
44
  target: options.target,
43
45
  targetNodeId: options.targetNodeId,
44
46
  });
45
47
 
46
- const sketch = Sketch.make({
48
+ const drawing = Drawing.make({
47
49
  name: typeof input?.name === 'string' ? input.name : undefined,
48
50
  canvas,
49
51
  });
50
52
 
51
- // Add the user-facing Sketch wrapper. Not hidden — this is the object the user sees
53
+ // Add the user-facing Drawing wrapper. Not hidden — this is the object the user sees
52
54
  // and navigates to. If this second write fails, roll back the canvas so we don't
53
55
  // leak an orphaned object into the space.
54
56
  return yield* Operation.invoke(SpaceOperation.AddObject, {
55
- object: sketch,
57
+ object: drawing,
56
58
  target: options.target,
57
59
  targetNodeId: options.targetNodeId,
58
60
  }).pipe(
@@ -7,6 +7,7 @@ import { OperationHandlerSet } from '@dxos/compute';
7
7
 
8
8
  export const CommentConfig = Capability.lazy('CommentConfig', () => import('./comment-config'));
9
9
  export const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));
10
+ export const Migrations = Capability.lazy('IllustratorMigrations', () => import('./migrations'));
10
11
  export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
11
12
  'OperationHandler',
12
13
  () => import('./operation-handler'),
@@ -0,0 +1,142 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { afterEach, beforeEach, describe, test } from 'vitest';
6
+
7
+ import { Filter, Obj, Ref } from '@dxos/echo';
8
+ import { EchoTestBuilder } from '@dxos/echo-client/testing';
9
+ import { invariant } from '@dxos/invariant';
10
+
11
+ import { Drawing, LegacySketch } from '../types';
12
+ import { sketchToDrawing } from './migrations';
13
+
14
+ let builder: EchoTestBuilder;
15
+
16
+ beforeEach(async () => {
17
+ builder = await new EchoTestBuilder().open();
18
+ });
19
+
20
+ afterEach(async () => {
21
+ await builder.close();
22
+ });
23
+
24
+ const setup = async () => {
25
+ const { db, graph } = await builder.createDatabase();
26
+ graph.registry.add([LegacySketch.Sketch, Drawing.Drawing, Drawing.Canvas]);
27
+ return db;
28
+ };
29
+
30
+ /** A sketch as it exists in spaces created before the rename. */
31
+ const addLegacySketch = (db: any, { name, schema = 'tldraw.com/2' }: { name?: string; schema?: string } = {}) => {
32
+ const canvas = db.add(Drawing.makeCanvas({ schema, content: { 'shape:1': { id: 'shape:1' } } }));
33
+ return db.add(Obj.make(LegacySketch.Sketch, { name, canvas: Ref.make(canvas) }));
34
+ };
35
+
36
+ describe('sketch → drawing migration', () => {
37
+ test('converts a legacy sketch in place, preserving id and canvas', async ({ expect }) => {
38
+ const db = await setup();
39
+ const sketch = addLegacySketch(db, { name: 'Diagram' });
40
+ const sketchId = sketch.id;
41
+ const canvasId = sketch.canvas.target?.id;
42
+ await db.flush();
43
+
44
+ await db.runMigrations([sketchToDrawing]);
45
+
46
+ expect(await db.query(Filter.type(LegacySketch.Sketch)).run()).toHaveLength(0);
47
+ const drawings = await db.query(Filter.type(Drawing.Drawing)).run();
48
+ expect(drawings).toHaveLength(1);
49
+
50
+ const [drawing] = drawings;
51
+ // The runtime swaps the type on the same object rather than creating a replacement, so
52
+ // anything already referencing the sketch keeps resolving.
53
+ expect(drawing.id).toBe(sketchId);
54
+ expect(Obj.getTypename(drawing)).toBe('org.dxos.type.drawing');
55
+ expect(drawing.name).toBe('Diagram');
56
+ expect(drawing.canvas.target?.id).toBe(canvasId);
57
+ });
58
+
59
+ test('leaves the canvas untouched so the renderer variant still resolves', async ({ expect }) => {
60
+ const db = await setup();
61
+ addLegacySketch(db, { name: 'Diagram' });
62
+ await db.flush();
63
+
64
+ await db.runMigrations([sketchToDrawing]);
65
+
66
+ const [drawing] = await db.query(Filter.type(Drawing.Drawing)).run();
67
+ const canvas = drawing.canvas.target;
68
+ invariant(canvas, 'canvas ref did not resolve after migration');
69
+ expect(Obj.getTypename(canvas)).toBe('org.dxos.type.canvas');
70
+ // `schema` is what matches a drawing to its variant; losing it would render "unsupported".
71
+ expect(canvas.schema).toBe('tldraw.com/2');
72
+ expect(canvas.content).toEqual({ 'shape:1': { id: 'shape:1' } });
73
+ });
74
+
75
+ test('carries a sketch with no name', async ({ expect }) => {
76
+ const db = await setup();
77
+ addLegacySketch(db);
78
+ await db.flush();
79
+
80
+ await db.runMigrations([sketchToDrawing]);
81
+
82
+ const [drawing] = await db.query(Filter.type(Drawing.Drawing)).run();
83
+ expect(drawing.name).toBeUndefined();
84
+ });
85
+
86
+ test('migrates every sketch in the space', async ({ expect }) => {
87
+ const db = await setup();
88
+ addLegacySketch(db, { name: 'One' });
89
+ addLegacySketch(db, { name: 'Two', schema: 'excalidraw.com/2' });
90
+ await db.flush();
91
+
92
+ await db.runMigrations([sketchToDrawing]);
93
+
94
+ const drawings = await db.query(Filter.type(Drawing.Drawing)).run();
95
+ expect(drawings.map((drawing) => drawing.name).sort()).toEqual(['One', 'Two']);
96
+ expect(drawings.map((drawing) => drawing.canvas.target?.schema).sort()).toEqual([
97
+ 'excalidraw.com/2',
98
+ 'tldraw.com/2',
99
+ ]);
100
+ });
101
+
102
+ test('runs against a space reopened without the legacy schema registered', async ({ expect }) => {
103
+ // The plugin registers only `Drawing`, never `LegacySketch.Sketch` — so the migration has to
104
+ // work on a client whose registry has no entry for the type it is reading.
105
+ const { db, peer, key } = await builder.createDatabase();
106
+ db.graph.registry.add([LegacySketch.Sketch, Drawing.Drawing, Drawing.Canvas]);
107
+ const sketchId = addLegacySketch(db, { name: 'Diagram' }).id;
108
+ await db.flush();
109
+
110
+ const client = await peer.createClient();
111
+ await client.graph.registry.add([Drawing.Drawing, Drawing.Canvas]);
112
+ const reopened = await peer.openDatabase(key, undefined, { client });
113
+
114
+ await reopened.runMigrations([sketchToDrawing]);
115
+
116
+ const drawings = await reopened.query(Filter.type(Drawing.Drawing)).run();
117
+ expect(drawings).toHaveLength(1);
118
+ expect(drawings[0].id).toBe(sketchId);
119
+ expect(drawings[0].name).toBe('Diagram');
120
+ });
121
+
122
+ test('is idempotent and picks up sketches that arrive later', async ({ expect }) => {
123
+ const db = await setup();
124
+ addLegacySketch(db, { name: 'One' });
125
+ await db.flush();
126
+ await db.runMigrations([sketchToDrawing]);
127
+
128
+ // Re-running finds nothing: a migrated object no longer matches the source type. This is what
129
+ // makes it safe to run on every startup and on every peer.
130
+ await db.runMigrations([sketchToDrawing]);
131
+ expect(await db.query(Filter.type(Drawing.Drawing)).run()).toHaveLength(1);
132
+
133
+ // A sketch replicated in from a peer that has not migrated yet is converted on the next sweep.
134
+ addLegacySketch(db, { name: 'Two' });
135
+ await db.flush();
136
+ await db.runMigrations([sketchToDrawing]);
137
+
138
+ const drawings = await db.query(Filter.type(Drawing.Drawing)).run();
139
+ expect(drawings.map((drawing) => drawing.name).sort()).toEqual(['One', 'Two']);
140
+ expect(await db.query(Filter.type(LegacySketch.Sketch)).run()).toHaveLength(0);
141
+ });
142
+ });
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capability } from '@dxos/app-framework';
8
+ import { Migration } from '@dxos/echo';
9
+ import { ClientCapabilities } from '@dxos/plugin-client';
10
+
11
+ import { Drawing, LegacySketch } from '../types';
12
+
13
+ // `org.dxos.type.sketch` -> `org.dxos.type.drawing`. The shape is unchanged (name + canvas ref)
14
+ // and the canvas keeps its typename, so the transform is a field copy; the runtime swaps the
15
+ // object's type and retires the old one.
16
+ export const sketchToDrawing = Migration.define({
17
+ from: LegacySketch.Sketch,
18
+ to: Drawing.Drawing,
19
+ transform: async ({ name, canvas }) => ({ name, canvas }),
20
+ });
21
+
22
+ const migrations = [sketchToDrawing];
23
+
24
+ export default Capability.makeModule(
25
+ Effect.fnUntraced(function* () {
26
+ return Capability.contributes(ClientCapabilities.Migration, migrations);
27
+ }),
28
+ );
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { Surface } from '@dxos/app-framework/ui';
9
+ import { AppSurface } from '@dxos/app-toolkit/ui';
10
+
11
+ import { DrawingArticle, DrawingCard } from '#containers';
12
+
13
+ import { Drawing } from '../types';
14
+
15
+ export default Capability.makeModule(() =>
16
+ Effect.succeed(
17
+ Capability.contributes(Capabilities.ReactSurface, [
18
+ Surface.create({
19
+ id: 'drawing',
20
+ filter: AppSurface.oneOf(
21
+ AppSurface.object(AppSurface.Article, Drawing.Drawing),
22
+ AppSurface.object(AppSurface.Section, Drawing.Drawing),
23
+ AppSurface.object(AppSurface.Slide, Drawing.Drawing),
24
+ ),
25
+ component: DrawingArticle,
26
+ props: ({ role, data: { subject, attendableId, extrinsic } }) => ({ role, subject, attendableId, extrinsic }),
27
+ }),
28
+ Surface.create({
29
+ id: 'drawingCard',
30
+ filter: AppSurface.object(AppSurface.CardContent, Drawing.Drawing),
31
+ component: DrawingCard,
32
+ props: ({ role, data: { subject, editable } }) => ({ role, subject, editable }),
33
+ }),
34
+ ]),
35
+ ),
36
+ );
@@ -7,8 +7,8 @@ import * as Effect from 'effect/Effect';
7
7
  import { Capability } from '@dxos/app-framework';
8
8
  import { AppCapabilities } from '@dxos/app-toolkit';
9
9
 
10
- import { SketchSkill } from '#skills';
10
+ import { DrawingSkill } from '#skills';
11
11
 
12
- const skillDefinition = () => Effect.succeed([Capability.contributes(AppCapabilities.SkillDefinition, SketchSkill)]);
12
+ const skillDefinition = () => Effect.succeed([Capability.contributes(AppCapabilities.SkillDefinition, DrawingSkill)]);
13
13
 
14
14
  export default skillDefinition;
@@ -10,20 +10,20 @@ import { useTranslation } from '@dxos/react-ui';
10
10
  import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
11
11
 
12
12
  import { meta } from '#meta';
13
- import { IllustratorCapabilities, type SketchVariant } from '#types';
13
+ import { type DrawingVariant, IllustratorCapabilities } from '#types';
14
14
 
15
- export type CreateSketchPanelProps = SpaceCapabilities.CreateObjectCustomPanelProps & {
15
+ export type CreateDrawingPanelProps = SpaceCapabilities.CreateObjectCustomPanelProps & {
16
16
  /** Optional override (primarily for stories/tests). Defaults to IllustratorCapabilities.VariantProvider. */
17
- variants?: SketchVariant[];
17
+ variants?: DrawingVariant[];
18
18
  };
19
19
 
20
20
  /**
21
- * Variant picker for sketches (SearchList over contributed `SketchVariant[]`).
21
+ * Variant picker for drawings (SearchList over contributed `DrawingVariant[]`).
22
22
  * On select, calls `onCreateObject({ variantId })`; plugin-illustrator's
23
23
  * CreateObjectEntry.createObject resolves the variantId, builds the canvas via
24
- * variant.createCanvas, then wraps it in a Sketch.
24
+ * variant.createCanvas, then wraps it in a Drawing.
25
25
  */
26
- export const CreateSketchPanel = ({ onCreateObject, variants: variantsProp }: CreateSketchPanelProps) => {
26
+ export const CreateDrawingPanel = ({ onCreateObject, variants: variantsProp }: CreateDrawingPanelProps) => {
27
27
  const { t } = useTranslation(meta.profile.key);
28
28
  const capabilityVariants = useCapabilities(IllustratorCapabilities.VariantProvider);
29
29
  const variants = variantsProp ?? capabilityVariants;
@@ -49,7 +49,7 @@ export const CreateSketchPanel = ({ onCreateObject, variants: variantsProp }: Cr
49
49
  <SearchList.Input
50
50
  classNames='mb-form-gap'
51
51
  autoFocus
52
- data-testid='create-sketch-panel.variant-input'
52
+ data-testid='create-drawing-panel.variant-input'
53
53
  placeholder={t('create-panel.variant.placeholder')}
54
54
  />
55
55
  <SearchList.Viewport>
@@ -2,4 +2,4 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- export * from './CreateSketchPanel';
5
+ export * from './CreateDrawingPanel';
@@ -6,22 +6,22 @@ import React from 'react';
6
6
 
7
7
  import { useCapabilities } from '@dxos/app-framework/ui';
8
8
  import { type AppSurface } from '@dxos/app-toolkit/ui';
9
- import { Obj, type Ref } from '@dxos/echo';
10
9
  import { useObject } from '@dxos/echo-react';
11
10
  import { useTranslation } from '@dxos/react-ui';
12
11
 
13
12
  import { meta } from '#meta';
14
- import { IllustratorCapabilities, type Sketch } from '#types';
13
+ import { type Drawing, IllustratorCapabilities } from '#types';
14
+ import { findVariant } from '#util';
15
15
 
16
- export type SketchArticleProps = AppSurface.ObjectArticleProps<Sketch.Sketch> & {
16
+ export type DrawingArticleProps = AppSurface.ObjectArticleProps<Drawing.Drawing> & {
17
17
  extrinsic?: boolean;
18
18
  };
19
19
 
20
- /** Resolves the sketch's canvas and delegates rendering to the matching variant's article. */
21
- export const SketchArticle = ({ role, attendableId, subject: sketch, extrinsic }: SketchArticleProps) => {
20
+ /** Resolves the drawing's canvas and delegates rendering to the variant claiming its schema. */
21
+ export const DrawingArticle = ({ role, attendableId, subject: drawing, extrinsic }: DrawingArticleProps) => {
22
22
  const { t } = useTranslation(meta.profile.key);
23
23
  const variants = useCapabilities(IllustratorCapabilities.VariantProvider);
24
- const ref = sketch.canvas as Ref.Ref<Obj.Unknown>;
24
+ const ref = drawing.canvas;
25
25
  // Subscribe via the snapshot for load/re-render, but hand variants the LIVE object —
26
26
  // their store adapters need `Doc.createAccessor`, which rejects snapshots.
27
27
  const [snapshot] = useObject(ref);
@@ -31,18 +31,17 @@ export const SketchArticle = ({ role, attendableId, subject: sketch, extrinsic }
31
31
  return null;
32
32
  }
33
33
 
34
- const typename = Obj.getTypename(canvas);
35
- const match = variants.find((variant) => variant.id === typename);
34
+ const match = findVariant(variants, canvas);
36
35
  if (!match?.article) {
37
36
  return (
38
37
  <div className='p-4 text-sm'>
39
- {t('unsupported-variant.label', { defaultValue: 'Unsupported sketch variant' })}
38
+ {t('unsupported-variant.label', { defaultValue: 'Unsupported drawing variant' })}
40
39
  </div>
41
40
  );
42
41
  }
43
42
 
44
43
  const Component = match.article;
45
- return <Component sketch={sketch} canvas={canvas} role={role} attendableId={attendableId} extrinsic={extrinsic} />;
44
+ return <Component drawing={drawing} canvas={canvas} role={role} attendableId={attendableId} extrinsic={extrinsic} />;
46
45
  };
47
46
 
48
- SketchArticle.displayName = 'SketchArticle';
47
+ DrawingArticle.displayName = 'DrawingArticle';
@@ -2,4 +2,4 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- export * from './SketchArticle';
5
+ export * from './DrawingArticle';
@@ -0,0 +1,38 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { useCapabilities } from '@dxos/app-framework/ui';
8
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
9
+ import { useObject } from '@dxos/echo-react';
10
+
11
+ import { type Drawing, IllustratorCapabilities } from '#types';
12
+ import { findVariant } from '#util';
13
+
14
+ export type DrawingCardProps = AppSurface.ObjectCardProps<Drawing.Drawing>;
15
+
16
+ /** Resolves the drawing's canvas and delegates rendering to the variant claiming its schema. */
17
+ export const DrawingCard = ({ role, subject: drawing, editable }: DrawingCardProps) => {
18
+ const variants = useCapabilities(IllustratorCapabilities.VariantProvider);
19
+ const ref = drawing.canvas;
20
+ const [snapshot] = useObject(ref);
21
+ const canvas = snapshot ? ref.target : undefined;
22
+
23
+ if (!canvas) {
24
+ return null;
25
+ }
26
+
27
+ const match = findVariant(variants, canvas);
28
+ if (!match?.card) {
29
+ return null;
30
+ }
31
+
32
+ const Component = match.card;
33
+ return <Component drawing={drawing} canvas={canvas} role={role} editable={editable} />;
34
+ };
35
+
36
+ DrawingCard.displayName = 'DrawingCard';
37
+
38
+ export default DrawingCard;
@@ -2,4 +2,4 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- export * from './SketchCard';
5
+ export * from './DrawingCard';
@@ -2,5 +2,5 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- export * from './SketchArticle';
6
- export * from './SketchCard';
5
+ export * from './DrawingArticle';
6
+ export * from './DrawingCard';