@dxos/plugin-debug 0.7.2 → 0.7.3-staging.971cd8d

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 (39) hide show
  1. package/dist/lib/browser/{DebugSpace-ZLGGNDAR.mjs → DebugSpace-DHKEAMIC.mjs} +3 -3
  2. package/dist/lib/browser/{DebugSpace-ZLGGNDAR.mjs.map → DebugSpace-DHKEAMIC.mjs.map} +2 -2
  3. package/dist/lib/browser/SpaceGenerator-2Z5WFX4T.mjs +469 -0
  4. package/dist/lib/browser/SpaceGenerator-2Z5WFX4T.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +35 -34
  6. package/dist/lib/browser/index.mjs.map +3 -3
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/types/src/DebugPlugin.d.ts.map +1 -1
  9. package/dist/types/src/components/DebugObjectPanel.d.ts.map +1 -1
  10. package/dist/types/src/components/DebugSpace/DebugSpace.d.ts +1 -1
  11. package/dist/types/src/components/{SurfaceDebug.d.ts → DebugSurface.d.ts} +2 -2
  12. package/dist/types/src/components/{SurfaceDebug.d.ts.map → DebugSurface.d.ts.map} +1 -1
  13. package/dist/types/src/components/SpaceGenerator/ObjectGenerator.d.ts +7 -0
  14. package/dist/types/src/components/SpaceGenerator/ObjectGenerator.d.ts.map +1 -0
  15. package/dist/types/src/components/SpaceGenerator/SchemaTable.d.ts +9 -0
  16. package/dist/types/src/components/SpaceGenerator/SchemaTable.d.ts.map +1 -0
  17. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.d.ts +9 -0
  18. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.d.ts.map +1 -0
  19. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.stories.d.ts +6 -0
  20. package/dist/types/src/components/SpaceGenerator/SpaceGenerator.stories.d.ts.map +1 -0
  21. package/dist/types/src/components/SpaceGenerator/draw-util.d.ts +8 -0
  22. package/dist/types/src/components/SpaceGenerator/draw-util.d.ts.map +1 -0
  23. package/dist/types/src/components/SpaceGenerator/index.d.ts +3 -0
  24. package/dist/types/src/components/SpaceGenerator/index.d.ts.map +1 -0
  25. package/dist/types/src/components/index.d.ts +2 -1
  26. package/dist/types/src/components/index.d.ts.map +1 -1
  27. package/package.json +45 -38
  28. package/src/DebugPlugin.tsx +58 -39
  29. package/src/components/DebugObjectPanel.tsx +2 -1
  30. package/src/components/DebugSpace/DebugSpace.tsx +2 -2
  31. package/src/components/DebugSpace/ObjectCreator.tsx +1 -1
  32. package/src/components/{SurfaceDebug.tsx → DebugSurface.tsx} +1 -1
  33. package/src/components/SpaceGenerator/ObjectGenerator.tsx +178 -0
  34. package/src/components/SpaceGenerator/SchemaTable.tsx +38 -0
  35. package/src/components/SpaceGenerator/SpaceGenerator.stories.tsx +37 -0
  36. package/src/components/SpaceGenerator/SpaceGenerator.tsx +113 -0
  37. package/src/components/SpaceGenerator/draw-util.ts +199 -0
  38. package/src/components/SpaceGenerator/index.ts +7 -0
  39. package/src/components/index.ts +1 -0
@@ -16,7 +16,7 @@ export type SurfaceDebugProps = ThemedClassName<{}>;
16
16
  * Show surface info.
17
17
  * NOTE: Remove from @dxos/app-framework if removing this.
18
18
  */
19
- export const SurfaceDebug = ({ classNames }: SurfaceDebugProps) => {
19
+ export const DebugSurface = ({ classNames }: SurfaceDebugProps) => {
20
20
  const context = useSurfaceRoot();
21
21
  const [surfaces, setSurfaces] = useState<DebugInfo[]>([]);
22
22
  const renderMap = useMemo(() => new Map<string, { last: number; delta: number }>(), []);
@@ -0,0 +1,178 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import {
6
+ createTLStore,
7
+ defaultBindingUtils,
8
+ defaultShapeUtils,
9
+ defaultShapeTools,
10
+ defaultTools,
11
+ Editor,
12
+ type TLEditorOptions,
13
+ } from '@tldraw/tldraw';
14
+
15
+ import { type AbstractSchema, type BaseObject } from '@dxos/echo-schema';
16
+ import { create, type ReactiveObject } from '@dxos/live-object';
17
+ import { DocumentType, TextType } from '@dxos/plugin-markdown/types';
18
+ import { addressToA1Notation, createSheet } from '@dxos/plugin-sheet';
19
+ import { type CellValue } from '@dxos/plugin-sheet/types';
20
+ import { SheetType } from '@dxos/plugin-sheet/types';
21
+ import { TLDRAW_SCHEMA, CanvasType, DiagramType } from '@dxos/plugin-sketch/types';
22
+ import { faker } from '@dxos/random';
23
+ import { Filter, type Space } from '@dxos/react-client/echo';
24
+ import { TableType } from '@dxos/react-ui-table';
25
+ import { createView } from '@dxos/schema';
26
+ import { createAsyncGenerator, type ValueGenerator } from '@dxos/schema/testing';
27
+ import { range } from '@dxos/util';
28
+
29
+ import { drawGraph, generateGraph } from './draw-util';
30
+
31
+ const generator: ValueGenerator = faker as any;
32
+
33
+ // TODO(burdon): Add objects to collections.
34
+ // TODO(burdon): Create comments.
35
+ // TODO(burdon): Reuse in testbench-app.
36
+ // TODO(burdon): Mutator running in background (factor out): from echo-generator.
37
+
38
+ export type ObjectGenerator<T extends BaseObject> = (
39
+ space: Space,
40
+ n: number,
41
+ cb?: (objects: ReactiveObject<any>[]) => void,
42
+ ) => Promise<ReactiveObject<T>[]>;
43
+
44
+ // TODO(burdon): Factor out and create unit tests. See "fuzz" patterns.
45
+ export const staticGenerators = new Map<string, ObjectGenerator<any>>([
46
+ //
47
+ // DocumentType
48
+ //
49
+ [
50
+ DocumentType.typename,
51
+ async (space, n, cb) => {
52
+ const objects = range(n).map(() => {
53
+ const content = range(faker.number.int({ min: 3, max: 8 }))
54
+ .map(() => faker.lorem.sentences(faker.number.int({ min: 3, max: 16 })))
55
+ .join('\n\n');
56
+
57
+ const obj = space.db.add(
58
+ create(DocumentType, {
59
+ name: faker.commerce.productName(),
60
+ content: create(TextType, { content }),
61
+ threads: [],
62
+ }),
63
+ );
64
+
65
+ return obj;
66
+ });
67
+
68
+ cb?.(objects);
69
+ return objects;
70
+ },
71
+ ],
72
+ //
73
+ // DiagramType
74
+ //
75
+ [
76
+ DiagramType.typename,
77
+ async (space, n, cb) => {
78
+ const options: Pick<TLEditorOptions, 'bindingUtils' | 'shapeUtils' | 'tools' | 'getContainer'> = {
79
+ bindingUtils: defaultBindingUtils,
80
+ shapeUtils: defaultShapeUtils,
81
+ tools: [...defaultTools, ...defaultShapeTools],
82
+ getContainer: () => document.body, // TODO(burdon): Fake via JSDOM?
83
+ };
84
+
85
+ const objects = await Promise.all(
86
+ range(n).map(async () => {
87
+ const store = createTLStore();
88
+ const editor = new Editor({ ...options, store });
89
+ const graph = generateGraph();
90
+ const content = await drawGraph(editor, graph);
91
+ editor.dispose();
92
+ store.dispose();
93
+
94
+ const obj = space.db.add(
95
+ create(DiagramType, {
96
+ name: faker.commerce.productName(),
97
+ canvas: create(CanvasType, { schema: TLDRAW_SCHEMA, content }),
98
+ }),
99
+ );
100
+
101
+ return obj;
102
+ }),
103
+ );
104
+
105
+ cb?.(objects);
106
+ return objects;
107
+ },
108
+ ],
109
+ //
110
+ // SheetType
111
+ //
112
+ [
113
+ SheetType.typename,
114
+ async (space, n, cb) => {
115
+ const objects = range(n).map(() => {
116
+ // TODO(burdon): Reconcile with plugin-sheet/testing
117
+ const year = new Date().getFullYear();
118
+ const cols = 4;
119
+ const rows = 20;
120
+ const cells: Record<string, CellValue> = {};
121
+ for (let col = 1; col <= cols; col++) {
122
+ for (let row = 1; row <= 10; row++) {
123
+ const cell = addressToA1Notation({ col, row });
124
+ if (row === 1) {
125
+ cells[cell] = { value: `${year} Q${col}` };
126
+ } else if (row === rows) {
127
+ const from = addressToA1Notation({ col, row: 2 });
128
+ const to = addressToA1Notation({ col, row: rows - 1 });
129
+ cells[cell] = { value: `=SUM(${from}:${to})` };
130
+ } else if (row > 2 && row < rows - 1) {
131
+ cells[cell] = { value: Math.floor(Math.random() * 10_000) };
132
+ }
133
+ }
134
+ }
135
+
136
+ // TODO(burdon): Set width.
137
+ return space.db.add(
138
+ createSheet({
139
+ name: faker.commerce.productName(),
140
+ cells,
141
+ }),
142
+ );
143
+ });
144
+
145
+ cb?.(objects);
146
+ return objects;
147
+ },
148
+ ],
149
+ ]);
150
+
151
+ export const createGenerator = <T extends BaseObject>(type: AbstractSchema<T>): ObjectGenerator<T> => {
152
+ return async (
153
+ space: Space,
154
+ n: number,
155
+ cb?: (objects: ReactiveObject<any>[]) => void,
156
+ ): Promise<ReactiveObject<T>[]> => {
157
+ // Find or create mutable schema.
158
+ const mutableSchema = await space.db.schemaRegistry.query();
159
+ const schema =
160
+ mutableSchema.find((schema) => schema.typename === type.typename) ?? space.db.schemaRegistry.addSchema(type);
161
+
162
+ // Create objects.
163
+ const generate = createAsyncGenerator(generator, schema.schema, space.db);
164
+ const objects = await generate.createObjects(n);
165
+
166
+ // Find or create table and view.
167
+ const { objects: tables } = await space.db.query(Filter.schema(TableType)).run();
168
+ const table = tables.find((table) => table.view?.query?.typename === type.typename);
169
+ if (!table) {
170
+ const name = type.typename.split('/').pop() ?? type.typename;
171
+ const view = createView({ name, typename: type.typename, jsonSchema: schema.jsonSchema });
172
+ const table = space.db.add(create(TableType, { name, view }));
173
+ cb?.([table]);
174
+ }
175
+
176
+ return objects;
177
+ };
178
+ };
@@ -0,0 +1,38 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { IconButton } from '@dxos/react-ui';
8
+
9
+ export type SchemaTableProps = {
10
+ types: any[];
11
+ objects?: Record<string, number | undefined>;
12
+ label: string;
13
+ onClick: (typename: string) => void;
14
+ };
15
+
16
+ export const SchemaTable = ({ types, objects = {}, label, onClick }: SchemaTableProps) => {
17
+ return (
18
+ <div className='grid grid-cols-[1fr_80px_40px] gap-1 overflow-hidden'>
19
+ <div className='grid grid-cols-subgrid col-span-3'>
20
+ <div className='px-2 text-sm text-primary-500'>{label}</div>
21
+ <div className='px-2 text-xs text-subdued text-right'>count</div>
22
+ </div>
23
+ {types.map((type) => (
24
+ <div key={type.typename} className='grid grid-cols-subgrid col-span-3 items-center'>
25
+ <div className='px-2 text-sm font-mono text-green-500'>{type.typename}</div>
26
+ <div className='px-2 text-right font-mono'>{objects[type.typename] ?? 0}</div>
27
+ <IconButton
28
+ variant='ghost'
29
+ icon='ph--plus--regular'
30
+ iconOnly
31
+ label='Create data'
32
+ onClick={() => onClick(type.typename)}
33
+ />
34
+ </div>
35
+ ))}
36
+ </div>
37
+ );
38
+ };
@@ -0,0 +1,37 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta } from '@storybook/react';
8
+ import React from 'react';
9
+
10
+ import { useSpaces } from '@dxos/react-client/echo';
11
+ import { withClientProvider } from '@dxos/react-client/testing';
12
+ import { render, withLayout, withTheme } from '@dxos/storybook-utils';
13
+
14
+ import { SpaceGenerator } from './SpaceGenerator';
15
+
16
+ const DefaultStory = () => {
17
+ const [space] = useSpaces();
18
+ if (!space) {
19
+ return null;
20
+ }
21
+
22
+ return <SpaceGenerator space={space} />;
23
+ };
24
+
25
+ const meta: Meta = {
26
+ title: 'plugins/plugin-debug/SpaceGenerator',
27
+ component: SpaceGenerator,
28
+ render: render(DefaultStory),
29
+ decorators: [withClientProvider({ createSpace: true }), withLayout({ tooltips: true }), withTheme],
30
+ parameters: {
31
+ layout: 'fullscreen',
32
+ },
33
+ };
34
+
35
+ export default meta;
36
+
37
+ export const Default = {};
@@ -0,0 +1,113 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo, useState } from 'react';
6
+
7
+ import { type ReactiveObject } from '@dxos/live-object';
8
+ import { DocumentType } from '@dxos/plugin-markdown/types';
9
+ import { SheetType } from '@dxos/plugin-sheet/types';
10
+ import { DiagramType } from '@dxos/plugin-sketch/types';
11
+ import { useClient } from '@dxos/react-client';
12
+ import { getTypename, type Space } from '@dxos/react-client/echo';
13
+ import { IconButton, Input, Toolbar, useAsyncEffect } from '@dxos/react-ui';
14
+ import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
15
+ import { Testing } from '@dxos/schema/testing';
16
+ import { jsonKeyReplacer, sortKeys } from '@dxos/util';
17
+
18
+ import { type ObjectGenerator, createGenerator, staticGenerators } from './ObjectGenerator';
19
+ import { SchemaTable } from './SchemaTable';
20
+
21
+ export type SpaceGeneratorProps = {
22
+ space: Space;
23
+ onCreateObjects?: (objects: ReactiveObject<any>[]) => void;
24
+ };
25
+
26
+ export const SpaceGenerator = ({ space, onCreateObjects }: SpaceGeneratorProps) => {
27
+ const client = useClient();
28
+ const staticTypes = [DocumentType, DiagramType, SheetType]; // TODO(burdon): Make extensible.
29
+ const mutableTypes = [Testing.OrgType, Testing.ProjectType, Testing.ContactType];
30
+ const [count, setCount] = useState(1);
31
+ const [info, setInfo] = useState<any>({});
32
+
33
+ // Create type generators.
34
+ const typeMap = useMemo(() => {
35
+ client.addTypes(staticTypes);
36
+ const mutableGenerators = new Map<string, ObjectGenerator<any>>(
37
+ mutableTypes.map((type) => [type.typename, createGenerator(type)]),
38
+ );
39
+
40
+ return new Map([...staticGenerators, ...mutableGenerators]);
41
+ }, [client, mutableTypes]);
42
+
43
+ // Query space to get info.
44
+ const updateInfo = async () => {
45
+ // Create schema map.
46
+ const mutableSchema = await space.db.schemaRegistry.query();
47
+ const staticSchema = space.db.graph.schemaRegistry.schemas;
48
+
49
+ // Create object map.
50
+ const { objects } = await space.db.query().run();
51
+ const objectMap = sortKeys(
52
+ objects.reduce<Record<string, number>>((map, obj) => {
53
+ const type = getTypename(obj);
54
+ if (type) {
55
+ const count = map[type] ?? 0;
56
+ map[type] = count + 1;
57
+ }
58
+ return map;
59
+ }, {}),
60
+ );
61
+
62
+ setInfo({
63
+ schema: {
64
+ static: staticSchema.length,
65
+ mutable: mutableSchema.length,
66
+ },
67
+ objects: objectMap,
68
+ });
69
+ };
70
+
71
+ useAsyncEffect(updateInfo, [space]);
72
+
73
+ const handleCreateData = useCallback(
74
+ async (typename: string) => {
75
+ const constructor = typeMap.get(typename);
76
+ if (constructor) {
77
+ // TODO(burdon): Input to specify number of objects.
78
+ await constructor(space, count, onCreateObjects);
79
+ await updateInfo();
80
+ }
81
+ },
82
+ [typeMap, count],
83
+ );
84
+
85
+ return (
86
+ <div role='none' className='flex flex-col divide-y divide-separator'>
87
+ <Toolbar.Root classNames='p-1'>
88
+ <IconButton icon='ph--arrow-clockwise--regular' iconOnly label='Refresh' onClick={updateInfo} />
89
+ <Toolbar.Expander />
90
+ <div className='flex'>
91
+ <Input.Root>
92
+ <Input.TextInput
93
+ type='number'
94
+ min={1}
95
+ max={100}
96
+ placeholder={'Count'}
97
+ classNames='w-[80px]'
98
+ value={count}
99
+ onChange={(ev) => setCount(parseInt(ev.target.value))}
100
+ />
101
+ </Input.Root>
102
+ </div>
103
+ </Toolbar.Root>
104
+
105
+ <SchemaTable types={staticTypes} objects={info.objects} label='Static Types' onClick={handleCreateData} />
106
+ <SchemaTable types={mutableTypes} objects={info.objects} label='Mutable Types' onClick={handleCreateData} />
107
+
108
+ <SyntaxHighlighter classNames='flex text-xs' language='json'>
109
+ {JSON.stringify({ space, ...info }, jsonKeyReplacer({ truncate: true }), 2)}
110
+ </SyntaxHighlighter>
111
+ </div>
112
+ );
113
+ };
@@ -0,0 +1,199 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ // TODO(burdon): workerize-loader dep.
6
+ import { Graph, type Edge, type PlainObject } from '@antv/graphlib';
7
+ import {
8
+ D3ForceLayout,
9
+ type D3ForceLayoutOptions,
10
+ GridLayout,
11
+ type GridLayoutOptions,
12
+ RadialLayout,
13
+ type RadialLayoutOptions,
14
+ } from '@antv/layout';
15
+ import { type Layout } from '@antv/layout/lib/types';
16
+ import { createBindingId, createShapeId, type Editor, type SerializedStore, type TLRecord } from '@tldraw/tldraw';
17
+
18
+ import { faker } from '@dxos/random';
19
+ import { isNotFalsy, range } from '@dxos/util';
20
+
21
+ // TODO(burdon): Graph layout:
22
+ // - https://www.npmjs.com/package/@antv/layout (uses d3)
23
+ // - https://observablehq.com/d/2db6b0cc5e97d8d6
24
+ // - https://github.com/antvis/graphlib
25
+ // - https://www.npmjs.com/package/@dagrejs/dagre
26
+ // - https://github.com/dagrejs/dagre/wiki
27
+ // - https://www.npmjs.com/package/elkjs
28
+
29
+ // TLDraw structure:
30
+ // svg tl-svg-context
31
+ // div tl-html-layer tl-shapes
32
+ // div tl-shape
33
+ // svg tl-svg-container
34
+ // div class tl-html-container
35
+ // div tl-overlays
36
+ // svg
37
+
38
+ /**
39
+ * https://github.com/antvis/graphlib/blob/master/docs/classes/Graph.md
40
+ */
41
+ // TODO(burdon): Factor out.
42
+ // TODO(burdon): Map ECHO to Graph.
43
+ export const generateGraph = (): Graph<PlainObject, PlainObject> => {
44
+ const nodes = range(faker.number.int({ min: 8, max: 32 })).map(() => ({
45
+ id: faker.string.uuid(),
46
+ data: {
47
+ label: faker.lorem
48
+ .words(2)
49
+ .split(' ')
50
+ .map((word) => word.charAt(0).toUpperCase())
51
+ .join('-'),
52
+ },
53
+ }));
54
+
55
+ const unlinked = new Set(nodes.map((node) => node.id));
56
+ const pop = () => {
57
+ if (unlinked.size) {
58
+ const id = faker.helpers.arrayElement(Array.from(unlinked));
59
+ unlinked.delete(id);
60
+ return id;
61
+ }
62
+ };
63
+
64
+ const edges: Edge<PlainObject>[] = [];
65
+ const link = (source: string, target: string) => {
66
+ edges.push({ id: faker.string.uuid(), source, target, data: {} });
67
+ };
68
+
69
+ const branching = 3;
70
+ const traverse = (source: string) => {
71
+ const targets = range(faker.number.int({ min: 1, max: branching }))
72
+ .map(() => {
73
+ const target = pop();
74
+ if (target) {
75
+ link(source, target);
76
+ }
77
+ return target;
78
+ })
79
+ .filter(isNotFalsy);
80
+
81
+ for (const target of targets) {
82
+ traverse(target);
83
+ }
84
+ };
85
+
86
+ const source = pop();
87
+ if (source) {
88
+ traverse(source);
89
+ }
90
+
91
+ return new Graph<PlainObject, PlainObject>({ nodes, edges });
92
+ };
93
+
94
+ export const drawGraph = async (
95
+ editor: Editor,
96
+ graph: Graph<PlainObject, PlainObject>,
97
+ ): Promise<SerializedStore<TLRecord>> => {
98
+ const grid = 40;
99
+ const nodeSize = 80;
100
+
101
+ const snap = (n: number) => Math.round(n / grid) * grid;
102
+
103
+ type Intersection<Types extends readonly unknown[]> = Types extends [infer First, ...infer Rest]
104
+ ? First & Intersection<Rest>
105
+ : unknown;
106
+
107
+ const defaultOptions: Intersection<[D3ForceLayoutOptions, GridLayoutOptions, RadialLayoutOptions]> = {
108
+ center: [0, 0],
109
+ width: grid * 20,
110
+ height: grid * 20,
111
+ linkDistance: grid * 2,
112
+ nodeSize,
113
+ nodeSpacing: nodeSize,
114
+ preventOverlap: true,
115
+ };
116
+
117
+ const layoutType = faker.helpers.arrayElement(['d3force', 'grid', 'radial']);
118
+ let layout: Layout<any>;
119
+ switch (layoutType) {
120
+ case 'd3force': {
121
+ layout = new D3ForceLayout({
122
+ ...defaultOptions,
123
+ nodeStrength: 0.3,
124
+ collideStrength: 0.8,
125
+ });
126
+ break;
127
+ }
128
+
129
+ case 'grid': {
130
+ layout = new GridLayout({
131
+ ...defaultOptions,
132
+ });
133
+ break;
134
+ }
135
+
136
+ case 'radial':
137
+ default: {
138
+ layout = new RadialLayout({
139
+ ...defaultOptions,
140
+ focusNode: graph.getAllNodes()[0],
141
+ unitRadius: grid * 2,
142
+ });
143
+ }
144
+ }
145
+
146
+ const { nodes, edges } = await layout.execute(graph);
147
+
148
+ for (const node of nodes) {
149
+ const id = createShapeId(node.id as string);
150
+ editor.createShape({
151
+ id,
152
+ type: 'geo',
153
+ x: snap(node.data.x),
154
+ y: snap(node.data.y),
155
+ props: {
156
+ w: nodeSize,
157
+ h: nodeSize,
158
+ text: node.data.label,
159
+ },
160
+ });
161
+ }
162
+
163
+ for (const edge of edges) {
164
+ const arrowId = createShapeId(edge.id as string);
165
+ editor.createShape({ id: arrowId, type: 'arrow' });
166
+
167
+ editor.createBinding({
168
+ id: createBindingId(),
169
+ type: 'arrow',
170
+ fromId: arrowId,
171
+ toId: createShapeId(edge.source as string),
172
+ props: {
173
+ terminal: 'start',
174
+ isExact: false,
175
+ isPrecise: false,
176
+ normalizedAnchor: { x: 0.5, y: 0.5 },
177
+ },
178
+ });
179
+
180
+ editor.createBinding({
181
+ id: createBindingId(),
182
+ type: 'arrow',
183
+ fromId: arrowId,
184
+ toId: createShapeId(edge.target as string),
185
+ props: {
186
+ terminal: 'end',
187
+ isExact: false,
188
+ isPrecise: false,
189
+ normalizedAnchor: { x: 0.5, y: 0.5 },
190
+ },
191
+ });
192
+ }
193
+
194
+ const data = editor.store.getStoreSnapshot();
195
+ // TODO(burdon): Strip readonly properties (e.g., `meta`). Factor out.
196
+ const content: SerializedStore<TLRecord> = JSON.parse(JSON.stringify(data.store));
197
+
198
+ return content;
199
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { SpaceGenerator } from './SpaceGenerator';
6
+
7
+ export default SpaceGenerator;
@@ -6,6 +6,7 @@ import { lazy } from 'react';
6
6
 
7
7
  export const DebugApp = lazy(() => import('./DebugApp'));
8
8
  export const DebugSpace = lazy(() => import('./DebugSpace'));
9
+ export const SpaceGenerator = lazy(() => import('./SpaceGenerator'));
9
10
 
10
11
  export * from './DebugObjectPanel';
11
12
  export * from './DebugSettings';