@dxos/plugin-illustrator 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/IllustratorPlugin.mjs +7 -3
- package/dist/lib/IllustratorPlugin.mjs.map +1 -1
- package/dist/lib/IllustratorPlugin.node.mjs +3 -3
- package/dist/lib/IllustratorPlugin.node.mjs.map +1 -1
- package/dist/lib/IllustratorPlugin.workerd.mjs +2 -2
- package/dist/lib/IllustratorPlugin.workerd.mjs.map +1 -1
- package/dist/lib/capabilities.mjs +2 -1
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/chunk-Drawing.mjs +64 -0
- package/dist/lib/chunk-Drawing.mjs.map +1 -0
- package/dist/lib/chunk-IllustratorCapabilities.mjs +2 -2
- package/dist/lib/chunk-IllustratorCapabilities.mjs.map +1 -1
- package/dist/lib/chunk-comment-config.mjs +3 -3
- package/dist/lib/chunk-comment-config.mjs.map +1 -1
- package/dist/lib/chunk-create-object.mjs +13 -12
- package/dist/lib/chunk-create-object.mjs.map +1 -1
- package/dist/lib/chunk-create.mjs +5 -4
- package/dist/lib/chunk-create.mjs.map +1 -1
- package/dist/lib/chunk-edit.mjs +4 -4
- package/dist/lib/chunk-edit.mjs.map +1 -1
- package/dist/lib/chunk-generate.mjs +20 -0
- package/dist/lib/chunk-generate.mjs.map +1 -0
- package/dist/lib/chunk-load-drawing.mjs +35 -0
- package/dist/lib/chunk-load-drawing.mjs.map +1 -0
- package/dist/lib/chunk-meta.mjs +2 -1
- package/dist/lib/chunk-meta.mjs.map +1 -1
- package/dist/lib/chunk-migrations.mjs +23 -0
- package/dist/lib/chunk-migrations.mjs.map +1 -0
- package/dist/lib/chunk-model.mjs +387 -4
- package/dist/lib/chunk-model.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +14 -13
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/chunk-read.mjs +4 -4
- package/dist/lib/chunk-read.mjs.map +1 -1
- package/dist/lib/chunk-skill-definition.mjs +2 -2
- package/dist/lib/chunk-skill-definition.mjs.map +1 -1
- package/dist/lib/chunk-skills.mjs +10 -10
- package/dist/lib/chunk-skills.mjs.map +1 -1
- package/dist/lib/chunk-types.mjs +41 -49
- package/dist/lib/chunk-types.mjs.map +1 -1
- package/dist/lib/components.mjs +6 -6
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/containers.mjs +17 -19
- package/dist/lib/containers.mjs.map +1 -1
- package/dist/lib/index.mjs +4 -3
- package/dist/lib/model.mjs +2 -2
- package/dist/lib/operations.mjs +1 -1
- package/dist/lib/operations.mjs.map +1 -1
- package/dist/lib/skills.mjs +1 -1
- package/dist/lib/translations.mjs +13 -13
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/lib/types.mjs +3 -2
- package/dist/lib/util.mjs +2 -2
- package/dist/types/src/IllustratorPlugin.d.ts.map +1 -1
- package/dist/types/src/IllustratorPlugin.node.d.ts +1 -1
- package/dist/types/src/IllustratorPlugin.test.d.ts +2 -0
- package/dist/types/src/IllustratorPlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +1 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/migrations.d.ts +7 -0
- package/dist/types/src/capabilities/migrations.d.ts.map +1 -0
- package/dist/types/src/capabilities/migrations.test.d.ts +2 -0
- package/dist/types/src/capabilities/migrations.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
- package/dist/types/src/components/CreateDrawingPanel.d.ts +15 -0
- package/dist/types/src/components/CreateDrawingPanel.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/DrawingArticle/DrawingArticle.d.ts +11 -0
- package/dist/types/src/containers/DrawingArticle/DrawingArticle.d.ts.map +1 -0
- package/dist/types/src/containers/DrawingArticle/index.d.ts +2 -0
- package/dist/types/src/containers/DrawingArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/DrawingCard/DrawingCard.d.ts +10 -0
- package/dist/types/src/containers/DrawingCard/DrawingCard.d.ts.map +1 -0
- package/dist/types/src/containers/DrawingCard/index.d.ts +2 -0
- package/dist/types/src/containers/DrawingCard/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +2 -2
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/model/builder.d.ts +18 -26
- package/dist/types/src/model/builder.d.ts.map +1 -1
- package/dist/types/src/model/content.d.ts +60 -0
- package/dist/types/src/model/content.d.ts.map +1 -0
- package/dist/types/src/model/index.d.ts +2 -0
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/mermaid.d.ts +38 -0
- package/dist/types/src/model/mermaid.d.ts.map +1 -0
- package/dist/types/src/model/mermaid.test.d.ts +3 -0
- package/dist/types/src/model/mermaid.test.d.ts.map +1 -0
- package/dist/types/src/operations/create.d.ts +2 -2
- package/dist/types/src/operations/create.d.ts.map +1 -1
- package/dist/types/src/operations/edit.d.ts +2 -2
- package/dist/types/src/operations/edit.d.ts.map +1 -1
- package/dist/types/src/operations/generate.d.ts +5 -0
- package/dist/types/src/operations/generate.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/read.d.ts +2 -2
- package/dist/types/src/operations/read.d.ts.map +1 -1
- package/dist/types/src/skills/{sketch-skill.d.ts → drawing-skill.d.ts} +1 -1
- package/dist/types/src/skills/drawing-skill.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +1 -1
- package/dist/types/src/skills/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +10 -10
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Drawing.d.ts +50 -0
- package/dist/types/src/types/Drawing.d.ts.map +1 -0
- package/dist/types/src/types/{SketchOperation.d.ts → DrawingOperation.d.ts} +111 -5
- package/dist/types/src/types/DrawingOperation.d.ts.map +1 -0
- package/dist/types/src/types/IllustratorCapabilities.d.ts +4 -4
- package/dist/types/src/types/IllustratorCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/LegacySketch.d.ts +17 -0
- package/dist/types/src/types/LegacySketch.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +3 -2
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +18 -18
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/load-drawing.d.ts +22 -0
- package/dist/types/src/util/load-drawing.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -0
- package/package.json +21 -19
- package/src/IllustratorPlugin.node.tsx +3 -3
- package/src/IllustratorPlugin.test.ts +32 -0
- package/src/IllustratorPlugin.tsx +15 -3
- package/src/IllustratorPlugin.workerd.tsx +2 -2
- package/src/capabilities/comment-config.ts +2 -2
- package/src/capabilities/create-object.ts +16 -14
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/migrations.test.ts +142 -0
- package/src/capabilities/migrations.ts +28 -0
- package/src/capabilities/react-surface.ts +36 -0
- package/src/capabilities/skill-definition.ts +2 -2
- package/src/components/{CreateSketchPanel.tsx → CreateDrawingPanel.tsx} +7 -7
- package/src/components/index.ts +1 -1
- package/src/containers/{SketchArticle/SketchArticle.tsx → DrawingArticle/DrawingArticle.tsx} +10 -11
- package/src/containers/{SketchArticle → DrawingArticle}/index.ts +1 -1
- package/src/containers/DrawingCard/DrawingCard.tsx +38 -0
- package/src/containers/{SketchCard → DrawingCard}/index.ts +1 -1
- package/src/containers/index.ts +2 -2
- package/src/model/builder.ts +34 -26
- package/src/model/content.ts +180 -0
- package/src/model/index.ts +2 -0
- package/src/model/mermaid.test.ts +116 -0
- package/src/model/mermaid.ts +299 -0
- package/src/operations/create.ts +6 -6
- package/src/operations/edit.ts +5 -5
- package/src/operations/generate.ts +25 -0
- package/src/operations/index.ts +1 -0
- package/src/operations/read.ts +5 -5
- package/src/skills/{sketch-skill.ts → drawing-skill.ts} +7 -7
- package/src/skills/index.ts +1 -1
- package/src/translations.ts +12 -12
- package/src/types/Drawing.ts +69 -0
- package/src/types/{SketchOperation.ts → DrawingOperation.ts} +28 -9
- package/src/types/IllustratorCapabilities.ts +4 -4
- package/src/types/LegacySketch.ts +25 -0
- package/src/types/index.ts +3 -2
- package/src/types/types.ts +18 -18
- package/src/util/index.ts +1 -1
- package/src/util/load-drawing.ts +48 -0
- package/dist/lib/chunk-load-sketch.mjs +0 -64
- package/dist/lib/chunk-load-sketch.mjs.map +0 -1
- package/dist/types/src/components/CreateSketchPanel.d.ts +0 -15
- package/dist/types/src/components/CreateSketchPanel.d.ts.map +0 -1
- package/dist/types/src/containers/SketchArticle/SketchArticle.d.ts +0 -11
- package/dist/types/src/containers/SketchArticle/SketchArticle.d.ts.map +0 -1
- package/dist/types/src/containers/SketchArticle/index.d.ts +0 -2
- package/dist/types/src/containers/SketchArticle/index.d.ts.map +0 -1
- package/dist/types/src/containers/SketchCard/SketchCard.d.ts +0 -10
- package/dist/types/src/containers/SketchCard/SketchCard.d.ts.map +0 -1
- package/dist/types/src/containers/SketchCard/index.d.ts +0 -2
- package/dist/types/src/containers/SketchCard/index.d.ts.map +0 -1
- package/dist/types/src/skills/sketch-skill.d.ts.map +0 -1
- package/dist/types/src/types/Sketch.d.ts +0 -50
- package/dist/types/src/types/Sketch.d.ts.map +0 -1
- package/dist/types/src/types/SketchOperation.d.ts.map +0 -1
- package/dist/types/src/util/load-sketch.d.ts +0 -37
- package/dist/types/src/util/load-sketch.d.ts.map +0 -1
- package/src/capabilities/react-surface.tsx +0 -37
- package/src/containers/SketchCard/SketchCard.tsx +0 -41
- package/src/types/Sketch.ts +0 -69
- package/src/util/load-sketch.ts +0 -74
package/dx.config.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-illustrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
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.
|
|
112
|
-
"@dxos/app-toolkit": "0.
|
|
113
|
-
"@dxos/compute": "0.
|
|
114
|
-
"@dxos/echo": "0.
|
|
115
|
-
"@dxos/echo-react": "0.
|
|
116
|
-
"@dxos/invariant": "0.
|
|
117
|
-
"@dxos/log": "0.
|
|
118
|
-
"@dxos/
|
|
119
|
-
"@dxos/plugin-space": "0.
|
|
120
|
-
"@dxos/react-ui": "0.
|
|
121
|
-
"@dxos/react-ui-
|
|
122
|
-
"@dxos/
|
|
123
|
-
"@dxos/schema": "0.
|
|
124
|
-
"@dxos/
|
|
111
|
+
"@dxos/app-framework": "0.11.0",
|
|
112
|
+
"@dxos/app-toolkit": "0.11.0",
|
|
113
|
+
"@dxos/compute": "0.11.0",
|
|
114
|
+
"@dxos/echo": "0.11.0",
|
|
115
|
+
"@dxos/echo-react": "0.11.0",
|
|
116
|
+
"@dxos/invariant": "0.11.0",
|
|
117
|
+
"@dxos/log": "0.11.0",
|
|
118
|
+
"@dxos/plugin-client": "0.11.0",
|
|
119
|
+
"@dxos/plugin-space": "0.11.0",
|
|
120
|
+
"@dxos/react-ui": "0.11.0",
|
|
121
|
+
"@dxos/react-ui-form": "0.11.0",
|
|
122
|
+
"@dxos/react-ui-search": "0.11.0",
|
|
123
|
+
"@dxos/schema": "0.11.0",
|
|
124
|
+
"@dxos/util": "0.11.0",
|
|
125
|
+
"@dxos/keys": "0.11.0"
|
|
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/
|
|
133
|
-
"@dxos/
|
|
133
|
+
"@dxos/plugin-testing": "0.11.0",
|
|
134
|
+
"@dxos/ui-theme": "0.11.0",
|
|
135
|
+
"@dxos/echo-client": "0.11.0"
|
|
134
136
|
},
|
|
135
137
|
"peerDependencies": {
|
|
136
138
|
"react": "~19.2.7",
|
|
137
139
|
"react-dom": "~19.2.7",
|
|
138
|
-
"@dxos/
|
|
139
|
-
"@dxos/ui
|
|
140
|
+
"@dxos/ui-theme": "^0.11.0",
|
|
141
|
+
"@dxos/react-ui": "^0.11.0"
|
|
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 {
|
|
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 `
|
|
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: [
|
|
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 {
|
|
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 {
|
|
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: [
|
|
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 {
|
|
9
|
+
import { Drawing } from '#types';
|
|
10
10
|
|
|
11
11
|
export const IllustratorPlugin = Plugin.define(meta).pipe(
|
|
12
|
-
AppPlugin.addSchemaModule({ schema: [
|
|
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 {
|
|
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(
|
|
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 {
|
|
13
|
+
import { CreateDrawingPanel } from '#components';
|
|
14
14
|
|
|
15
|
-
import {
|
|
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(
|
|
23
|
-
customPanel:
|
|
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
|
|
31
|
+
invariant(variant, `Unknown drawing variant: ${variantId}`);
|
|
32
32
|
|
|
33
|
-
// Build the canvas
|
|
34
|
-
const canvas =
|
|
35
|
-
|
|
36
|
-
|
|
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.
|
|
39
|
-
//
|
|
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
|
|
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
|
|
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:
|
|
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 {
|
|
10
|
+
import { DrawingSkill } from '#skills';
|
|
11
11
|
|
|
12
|
-
const skillDefinition = () => Effect.succeed([Capability.contributes(AppCapabilities.SkillDefinition,
|
|
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 {
|
|
13
|
+
import { type DrawingVariant, IllustratorCapabilities } from '#types';
|
|
14
14
|
|
|
15
|
-
export type
|
|
15
|
+
export type CreateDrawingPanelProps = SpaceCapabilities.CreateObjectCustomPanelProps & {
|
|
16
16
|
/** Optional override (primarily for stories/tests). Defaults to IllustratorCapabilities.VariantProvider. */
|
|
17
|
-
variants?:
|
|
17
|
+
variants?: DrawingVariant[];
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Variant picker for
|
|
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
|
|
24
|
+
* variant.createCanvas, then wraps it in a Drawing.
|
|
25
25
|
*/
|
|
26
|
-
export const
|
|
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-
|
|
52
|
+
data-testid='create-drawing-panel.variant-input'
|
|
53
53
|
placeholder={t('create-panel.variant.placeholder')}
|
|
54
54
|
/>
|
|
55
55
|
<SearchList.Viewport>
|
package/src/components/index.ts
CHANGED
package/src/containers/{SketchArticle/SketchArticle.tsx → DrawingArticle/DrawingArticle.tsx}
RENAMED
|
@@ -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 {
|
|
13
|
+
import { type Drawing, IllustratorCapabilities } from '#types';
|
|
14
|
+
import { findVariant } from '#util';
|
|
15
15
|
|
|
16
|
-
export type
|
|
16
|
+
export type DrawingArticleProps = AppSurface.ObjectArticleProps<Drawing.Drawing> & {
|
|
17
17
|
extrinsic?: boolean;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
/** Resolves the
|
|
21
|
-
export const
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
44
|
+
return <Component drawing={drawing} canvas={canvas} role={role} attendableId={attendableId} extrinsic={extrinsic} />;
|
|
46
45
|
};
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
DrawingArticle.displayName = '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;
|
package/src/containers/index.ts
CHANGED