@dxos/plugin-markdown 0.7.4 → 0.7.5-main.9cb18ac

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 (65) hide show
  1. package/dist/lib/browser/{MarkdownContainer-6OPC5MKP.mjs → MarkdownContainer-XY6NEUOA.mjs} +86 -86
  2. package/dist/lib/browser/MarkdownContainer-XY6NEUOA.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-CMSUKMPM.mjs → chunk-6FIHBJRV.mjs} +27 -7
  4. package/dist/lib/browser/chunk-6FIHBJRV.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-TZN5FGB2.mjs → chunk-R4MG2DP2.mjs} +6 -6
  6. package/dist/lib/browser/chunk-R4MG2DP2.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +88 -174
  8. package/dist/lib/browser/index.mjs.map +3 -3
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/types/index.mjs +1 -1
  11. package/dist/lib/node/{MarkdownContainer-6OKJOHTZ.cjs → MarkdownContainer-EX6YDF6J.cjs} +78 -78
  12. package/dist/lib/node/MarkdownContainer-EX6YDF6J.cjs.map +7 -0
  13. package/dist/lib/node/{chunk-YGMWZIIJ.cjs → chunk-CQMXZ54Z.cjs} +28 -8
  14. package/dist/lib/node/chunk-CQMXZ54Z.cjs.map +7 -0
  15. package/dist/lib/node/{chunk-KEPAM4JP.cjs → chunk-SXQAPZZU.cjs} +9 -9
  16. package/dist/lib/node/chunk-SXQAPZZU.cjs.map +7 -0
  17. package/dist/lib/node/index.cjs +123 -209
  18. package/dist/lib/node/index.cjs.map +3 -3
  19. package/dist/lib/node/meta.json +1 -1
  20. package/dist/lib/node/types/index.cjs +5 -5
  21. package/dist/lib/node/types/index.cjs.map +1 -1
  22. package/dist/lib/node-esm/{MarkdownContainer-GBNSGROQ.mjs → MarkdownContainer-E7W623A7.mjs} +86 -86
  23. package/dist/lib/node-esm/MarkdownContainer-E7W623A7.mjs.map +7 -0
  24. package/dist/lib/node-esm/{chunk-NUMUUCYF.mjs → chunk-Y76MM22C.mjs} +6 -6
  25. package/dist/lib/node-esm/chunk-Y76MM22C.mjs.map +7 -0
  26. package/dist/lib/node-esm/{chunk-ERJ52KN2.mjs → chunk-ZVFBKBSA.mjs} +27 -7
  27. package/dist/lib/node-esm/chunk-ZVFBKBSA.mjs.map +7 -0
  28. package/dist/lib/node-esm/index.mjs +88 -174
  29. package/dist/lib/node-esm/index.mjs.map +3 -3
  30. package/dist/lib/node-esm/meta.json +1 -1
  31. package/dist/lib/node-esm/types/index.mjs +1 -1
  32. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  33. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
  34. package/dist/types/src/components/MarkdownEditor.d.ts.map +1 -1
  35. package/dist/types/src/extensions.d.ts +2 -2
  36. package/dist/types/src/extensions.d.ts.map +1 -1
  37. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -1
  38. package/dist/types/src/types/index.d.ts +1 -1
  39. package/dist/types/src/types/index.d.ts.map +1 -1
  40. package/dist/types/src/types/schema.d.ts +82 -0
  41. package/dist/types/src/types/schema.d.ts.map +1 -0
  42. package/dist/types/src/types/types.d.ts +31 -12
  43. package/dist/types/src/types/types.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -0
  45. package/package.json +30 -29
  46. package/src/MarkdownPlugin.tsx +84 -149
  47. package/src/components/MarkdownContainer.tsx +8 -3
  48. package/src/components/MarkdownEditor.tsx +5 -13
  49. package/src/extensions.tsx +9 -10
  50. package/src/hooks/useSelectCurrentThread.tsx +17 -14
  51. package/src/types/index.ts +1 -1
  52. package/src/types/{document.ts → schema.ts} +4 -3
  53. package/src/types/types.ts +21 -15
  54. package/src/util.tsx +3 -3
  55. package/dist/lib/browser/MarkdownContainer-6OPC5MKP.mjs.map +0 -7
  56. package/dist/lib/browser/chunk-CMSUKMPM.mjs.map +0 -7
  57. package/dist/lib/browser/chunk-TZN5FGB2.mjs.map +0 -7
  58. package/dist/lib/node/MarkdownContainer-6OKJOHTZ.cjs.map +0 -7
  59. package/dist/lib/node/chunk-KEPAM4JP.cjs.map +0 -7
  60. package/dist/lib/node/chunk-YGMWZIIJ.cjs.map +0 -7
  61. package/dist/lib/node-esm/MarkdownContainer-GBNSGROQ.mjs.map +0 -7
  62. package/dist/lib/node-esm/chunk-ERJ52KN2.mjs.map +0 -7
  63. package/dist/lib/node-esm/chunk-NUMUUCYF.mjs.map +0 -7
  64. package/dist/types/src/types/document.d.ts +0 -106
  65. package/dist/types/src/types/document.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-markdown",
3
- "version": "0.7.4",
3
+ "version": "0.7.5-main.9cb18ac",
4
4
  "description": "DXOS Surface plugin for interacting with Markdown",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -44,28 +44,29 @@
44
44
  "@codemirror/view": "^6.34.1",
45
45
  "@effect/schema": "^0.75.5",
46
46
  "@preact/signals-core": "^1.6.0",
47
- "@dxos/app-framework": "0.7.4",
48
- "@dxos/echo-schema": "0.7.4",
49
- "@dxos/async": "0.7.4",
50
- "@dxos/live-object": "0.7.4",
51
- "@dxos/invariant": "0.7.4",
52
- "@dxos/local-storage": "0.7.4",
53
- "@dxos/log": "0.7.4",
54
- "@dxos/plugin-client": "0.7.4",
55
- "@dxos/plugin-attention": "0.7.4",
56
- "@dxos/keys": "0.7.4",
57
- "@dxos/plugin-graph": "0.7.4",
58
- "@dxos/plugin-space": "0.7.4",
59
- "@dxos/react-hooks": "0.7.4",
60
- "@dxos/plugin-theme": "0.7.4",
61
- "@dxos/react-client": "0.7.4",
62
- "@dxos/react-ui-card": "0.7.4",
63
- "@dxos/react-ui-attention": "0.7.4",
64
- "@dxos/react-ui-editor": "0.7.4",
65
- "@dxos/react-ui-form": "0.7.4",
66
- "@dxos/react-ui-stack": "0.7.4",
67
- "@dxos/util": "0.7.4",
68
- "@dxos/react-ui-mosaic": "0.7.4"
47
+ "effect": "^3.12.1",
48
+ "@dxos/app-framework": "0.7.5-main.9cb18ac",
49
+ "@dxos/echo-schema": "0.7.5-main.9cb18ac",
50
+ "@dxos/async": "0.7.5-main.9cb18ac",
51
+ "@dxos/invariant": "0.7.5-main.9cb18ac",
52
+ "@dxos/keys": "0.7.5-main.9cb18ac",
53
+ "@dxos/live-object": "0.7.5-main.9cb18ac",
54
+ "@dxos/local-storage": "0.7.5-main.9cb18ac",
55
+ "@dxos/log": "0.7.5-main.9cb18ac",
56
+ "@dxos/plugin-client": "0.7.5-main.9cb18ac",
57
+ "@dxos/plugin-attention": "0.7.5-main.9cb18ac",
58
+ "@dxos/plugin-space": "0.7.5-main.9cb18ac",
59
+ "@dxos/plugin-graph": "0.7.5-main.9cb18ac",
60
+ "@dxos/plugin-theme": "0.7.5-main.9cb18ac",
61
+ "@dxos/react-client": "0.7.5-main.9cb18ac",
62
+ "@dxos/react-ui-card": "0.7.5-main.9cb18ac",
63
+ "@dxos/react-hooks": "0.7.5-main.9cb18ac",
64
+ "@dxos/react-ui-editor": "0.7.5-main.9cb18ac",
65
+ "@dxos/react-ui-form": "0.7.5-main.9cb18ac",
66
+ "@dxos/react-ui-stack": "0.7.5-main.9cb18ac",
67
+ "@dxos/react-ui-mosaic": "0.7.5-main.9cb18ac",
68
+ "@dxos/util": "0.7.5-main.9cb18ac",
69
+ "@dxos/react-ui-attention": "0.7.5-main.9cb18ac"
69
70
  },
70
71
  "devDependencies": {
71
72
  "@phosphor-icons/react": "^2.1.5",
@@ -74,17 +75,17 @@
74
75
  "react": "~18.2.0",
75
76
  "react-dom": "~18.2.0",
76
77
  "vite": "5.4.7",
77
- "@dxos/random": "0.7.4",
78
- "@dxos/react-ui-theme": "0.7.4",
79
- "@dxos/storybook-utils": "0.7.4",
80
- "@dxos/react-ui": "0.7.4"
78
+ "@dxos/random": "0.7.5-main.9cb18ac",
79
+ "@dxos/storybook-utils": "0.7.5-main.9cb18ac",
80
+ "@dxos/react-ui-theme": "0.7.5-main.9cb18ac",
81
+ "@dxos/react-ui": "0.7.5-main.9cb18ac"
81
82
  },
82
83
  "peerDependencies": {
83
84
  "@phosphor-icons/react": "^2.1.5",
84
85
  "react": "~18.2.0",
85
86
  "react-dom": "~18.2.0",
86
- "@dxos/react-ui": "0.7.4",
87
- "@dxos/react-ui-theme": "0.7.4"
87
+ "@dxos/react-ui": "0.7.5-main.9cb18ac",
88
+ "@dxos/react-ui-theme": "0.7.5-main.9cb18ac"
88
89
  },
89
90
  "publishConfig": {
90
91
  "access": "public"
@@ -2,27 +2,27 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { TextAa } from '@phosphor-icons/react';
5
+ import { pipe } from 'effect';
6
6
  import React from 'react';
7
7
 
8
- import { parseIntentPlugin, resolvePlugin, NavigationAction, type PluginDefinition } from '@dxos/app-framework';
9
- import { create } from '@dxos/live-object';
8
+ import {
9
+ parseIntentPlugin,
10
+ resolvePlugin,
11
+ type PluginDefinition,
12
+ createSurface,
13
+ createResolver,
14
+ createIntent,
15
+ chain,
16
+ } from '@dxos/app-framework';
17
+ import type { BaseObject } from '@dxos/echo-schema';
18
+ import { create, makeRef, RefArray } from '@dxos/live-object';
10
19
  import { LocalStorageStore } from '@dxos/local-storage';
11
- import { parseClientPlugin } from '@dxos/plugin-client';
12
- import { type ActionGroup, createExtension, isActionGroup } from '@dxos/plugin-graph';
13
20
  import { SpaceAction } from '@dxos/plugin-space';
14
21
  import { CollectionType } from '@dxos/plugin-space/types';
15
- import {
16
- createDocAccessor,
17
- fullyQualifiedId,
18
- getRangeFromCursor,
19
- isSpace,
20
- loadObjectReferences,
21
- } from '@dxos/react-client/echo';
22
+ import { createDocAccessor, fullyQualifiedId, getRangeFromCursor, isSpace } from '@dxos/react-client/echo';
22
23
  import {
23
24
  type EditorInputMode,
24
25
  type EditorViewMode,
25
- EditorViewModes,
26
26
  translations as editorTranslations,
27
27
  createEditorStateStore,
28
28
  } from '@dxos/react-ui-editor';
@@ -39,9 +39,6 @@ import {
39
39
  } from './types';
40
40
  import { markdownExtensionPlugins, serializer } from './util';
41
41
 
42
- // TODO(burdon): Normalize active/object.
43
- const getDoc = (object: any) => (object instanceof DocumentType ? object : undefined);
44
-
45
42
  export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
46
43
  const settings = new LocalStorageStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN, {
47
44
  defaultViewMode: 'preview',
@@ -60,7 +57,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
60
57
 
61
58
  return {
62
59
  meta,
63
- ready: async (plugins) => {
60
+ ready: async ({ plugins }) => {
64
61
  settings
65
62
  .prop({ key: 'defaultViewMode', type: LocalStorageStore.enum<EditorViewMode>() })
66
63
  .prop({ key: 'editorInputMode', type: LocalStorageStore.enum<EditorInputMode>({ allowUndefined: true }) })
@@ -83,7 +80,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
83
80
  metadata: {
84
81
  records: {
85
82
  [DocumentType.typename]: {
86
- createObject: MarkdownAction.CREATE,
83
+ createObject: (props: { name?: string }) => createIntent(MarkdownAction.Create, props),
87
84
  label: (object: any) => (object instanceof DocumentType ? object.name || object.fallbackName : undefined),
88
85
  placeholder: ['document title placeholder', { ns: MARKDOWN_PLUGIN }],
89
86
  icon: 'ph--text-aa--regular',
@@ -91,7 +88,8 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
91
88
  managesAutofocus: true,
92
89
  },
93
90
  // TODO(wittjosiah): Move out of metadata.
94
- loadReferences: (doc: DocumentType) => loadObjectReferences(doc, (doc) => [doc.content, ...doc.threads]),
91
+ loadReferences: async (doc: DocumentType) =>
92
+ await RefArray.loadAll<BaseObject>([doc.content, ...doc.threads]),
95
93
  serializer,
96
94
  },
97
95
  },
@@ -102,48 +100,8 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
102
100
  system: [TextType],
103
101
  },
104
102
  graph: {
105
- builder: (plugins) => {
106
- const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
107
- const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
108
- if (!client || !dispatch) {
109
- return [];
110
- }
111
-
112
- return createExtension({
113
- id: MarkdownAction.CREATE,
114
- filter: (node): node is ActionGroup => isActionGroup(node) && node.id.startsWith(SpaceAction.ADD_OBJECT),
115
- actions: ({ node }) => {
116
- const id = node.id.split('/').at(-1);
117
- const [spaceId, objectId] = id?.split(':') ?? [];
118
- const space = client.spaces.get().find((space) => space.id === spaceId);
119
- const object = objectId && space?.db.getObjectById(objectId);
120
- const target = objectId ? object : space;
121
- if (!target) {
122
- return;
123
- }
124
-
125
- return [
126
- {
127
- id: `${MARKDOWN_PLUGIN}/create/${node.id}`,
128
- data: async () => {
129
- await dispatch([
130
- { plugin: MARKDOWN_PLUGIN, action: MarkdownAction.CREATE },
131
- { action: SpaceAction.ADD_OBJECT, data: { target } },
132
- { action: NavigationAction.OPEN },
133
- ]);
134
- },
135
- properties: {
136
- label: ['create document label', { ns: MARKDOWN_PLUGIN }],
137
- icon: 'ph--text-aa--regular',
138
- testId: 'markdownPlugin.createObject',
139
- },
140
- },
141
- ];
142
- },
143
- });
144
- },
145
103
  serializer: (plugins) => {
146
- const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
104
+ const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatchPromise;
147
105
  if (!dispatch) {
148
106
  return [];
149
107
  }
@@ -155,7 +113,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
155
113
  // Reconcile with metadata serializers.
156
114
  serialize: async (node) => {
157
115
  const doc = node.data;
158
- const content = await loadObjectReferences(doc, (doc) => doc.content);
116
+ const content = await doc.content.load();
159
117
  return {
160
118
  name:
161
119
  doc.name ||
@@ -169,48 +127,28 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
169
127
  const space = ancestors.find(isSpace);
170
128
  const target =
171
129
  ancestors.findLast((ancestor) => ancestor instanceof CollectionType) ??
172
- space?.properties[CollectionType.typename];
130
+ space?.properties[CollectionType.typename]?.target;
173
131
  if (!space || !target) {
174
132
  return;
175
133
  }
176
134
 
177
- const result = await dispatch([
178
- {
179
- plugin: MARKDOWN_PLUGIN,
180
- action: MarkdownAction.CREATE,
181
- data: { name: data.name, content: data.data },
182
- },
183
- {
184
- action: SpaceAction.ADD_OBJECT,
185
- data: { target },
186
- },
187
- ]);
135
+ const result = await dispatch(
136
+ pipe(
137
+ createIntent(MarkdownAction.Create, { name: data.name, content: data.data }),
138
+ chain(SpaceAction.AddObject, { target }),
139
+ ),
140
+ );
188
141
 
189
- return result?.data.object;
142
+ return result.data?.object;
190
143
  },
191
144
  },
192
145
  ];
193
146
  },
194
147
  },
195
- stack: {
196
- creators: [
197
- {
198
- id: 'create-stack-section-doc',
199
- testId: 'markdownPlugin.createSection',
200
- type: ['plugin name', { ns: MARKDOWN_PLUGIN }],
201
- label: ['create stack section label', { ns: MARKDOWN_PLUGIN }],
202
- icon: (props: any) => <TextAa {...props} />,
203
- intent: {
204
- plugin: MARKDOWN_PLUGIN,
205
- action: MarkdownAction.CREATE,
206
- },
207
- },
208
- ],
209
- },
210
148
  thread: {
211
149
  predicate: (obj) => obj instanceof DocumentType,
212
150
  createSort: (doc: DocumentType) => {
213
- const accessor = doc.content ? createDocAccessor(doc.content, ['content']) : undefined;
151
+ const accessor = doc.content.target ? createDocAccessor(doc.content.target, ['content']) : undefined;
214
152
  if (!accessor) {
215
153
  return (_) => 0;
216
154
  }
@@ -231,67 +169,64 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
231
169
  },
232
170
  },
233
171
  surface: {
234
- component: ({ data, role }) => {
235
- switch (role) {
236
- case 'section':
237
- case 'article': {
238
- const doc = getDoc(data.object);
239
- const { id, object } = isEditorModel(data.object)
240
- ? { id: data.object.id, object: data.object }
241
- : doc
242
- ? { id: fullyQualifiedId(doc), object: doc }
243
- : {};
244
-
245
- if (!id || !object) {
246
- return null;
247
- }
248
-
249
- return (
250
- <MarkdownContainer
251
- id={id}
252
- object={object}
253
- role={role}
254
- settings={settings.values}
255
- extensionProviders={state.values.extensionProviders}
256
- viewMode={getViewMode(id)}
257
- editorStateStore={editorStateStore}
258
- onViewModeChange={setViewMode}
259
- />
260
- );
261
- }
262
-
263
- case 'settings': {
264
- return data.plugin === meta.id ? <MarkdownSettings settings={settings.values} /> : null;
265
- }
266
- }
267
-
268
- return null;
269
- },
172
+ definitions: () => [
173
+ createSurface({
174
+ id: `${MARKDOWN_PLUGIN}/document`,
175
+ role: ['article', 'section'],
176
+ filter: (data): data is { subject: DocumentType } => data.subject instanceof DocumentType,
177
+ component: ({ data, role }) => (
178
+ <MarkdownContainer
179
+ id={fullyQualifiedId(data.subject)}
180
+ object={data.subject}
181
+ role={role}
182
+ settings={settings.values}
183
+ extensionProviders={state.values.extensionProviders}
184
+ viewMode={getViewMode(fullyQualifiedId(data.subject))}
185
+ editorStateStore={editorStateStore}
186
+ onViewModeChange={setViewMode}
187
+ />
188
+ ),
189
+ }),
190
+ createSurface({
191
+ id: `${MARKDOWN_PLUGIN}/editor`,
192
+ role: ['article', 'section'],
193
+ filter: (data): data is { subject: { id: string; text: string } } => isEditorModel(data.subject),
194
+ component: ({ data, role }) => (
195
+ <MarkdownContainer
196
+ id={data.subject.id}
197
+ object={data.subject}
198
+ role={role}
199
+ settings={settings.values}
200
+ extensionProviders={state.values.extensionProviders}
201
+ viewMode={getViewMode(data.subject.id)}
202
+ editorStateStore={editorStateStore}
203
+ onViewModeChange={setViewMode}
204
+ />
205
+ ),
206
+ }),
207
+ createSurface({
208
+ id: `${MARKDOWN_PLUGIN}/settings`,
209
+ role: 'settings',
210
+ filter: (data): data is any => data.subject === MARKDOWN_PLUGIN,
211
+ component: () => <MarkdownSettings settings={settings.values} />,
212
+ }),
213
+ ],
270
214
  },
271
215
  intent: {
272
- resolver: ({ action, data }) => {
273
- switch (action) {
274
- case MarkdownAction.CREATE: {
275
- const doc = create(DocumentType, {
276
- name: data?.name,
277
- content: create(TextType, { content: data?.content ?? '' }),
278
- threads: [],
279
- });
280
-
281
- return { data: doc };
282
- }
283
-
284
- case MarkdownAction.SET_VIEW_MODE: {
285
- const { id, viewMode } = data ?? {};
286
- if (typeof id === 'string' && EditorViewModes.includes(viewMode)) {
287
- state.values.viewMode[id] = viewMode;
288
- return { data: true };
289
- }
290
-
291
- break;
292
- }
293
- }
294
- },
216
+ resolvers: () => [
217
+ createResolver(MarkdownAction.Create, ({ name, content }) => {
218
+ const doc = create(DocumentType, {
219
+ name,
220
+ content: makeRef(create(TextType, { content: content ?? '' })),
221
+ threads: [],
222
+ });
223
+
224
+ return { data: { object: doc } };
225
+ }),
226
+ createResolver(MarkdownAction.SetViewMode, ({ id, viewMode }) => {
227
+ state.values.viewMode[id] = viewMode;
228
+ }),
229
+ ],
295
230
  },
296
231
  },
297
232
  };
@@ -77,8 +77,13 @@ export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props
77
77
 
78
78
  // Migrate gradually to `fallbackName`.
79
79
  useEffect(() => {
80
- if (!doc.fallbackName && doc.content?.content) {
81
- doc.fallbackName = getFallbackName(doc.content.content);
80
+ if (typeof doc.fallbackName === 'string') {
81
+ return;
82
+ }
83
+
84
+ const fallbackName = doc.content?.target?.content ? getFallbackName(doc.content.target.content) : undefined;
85
+ if (fallbackName) {
86
+ doc.fallbackName = fallbackName;
82
87
  }
83
88
  }, [doc, doc.content]);
84
89
 
@@ -96,7 +101,7 @@ export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props
96
101
  return (
97
102
  <MarkdownEditor
98
103
  id={id}
99
- initialValue={doc.content?.content}
104
+ initialValue={doc.content?.target?.content}
100
105
  viewMode={viewMode}
101
106
  toolbar={settings.toolbar}
102
107
  inputMode={settings.editorInputMode}
@@ -6,7 +6,7 @@ import { openSearchPanel } from '@codemirror/search';
6
6
  import { type EditorView } from '@codemirror/view';
7
7
  import React, { useMemo, useEffect, useCallback } from 'react';
8
8
 
9
- import { type FileInfo, LayoutAction, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { createIntent, type FileInfo, LayoutAction, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
10
10
  import { useThemeContext, useTranslation } from '@dxos/react-ui';
11
11
  import { useAttention } from '@dxos/react-ui-attention';
12
12
  import {
@@ -75,7 +75,7 @@ export const MarkdownEditor = ({
75
75
  }: MarkdownEditorProps) => {
76
76
  const { t } = useTranslation(MARKDOWN_PLUGIN);
77
77
  const { themeMode } = useThemeContext();
78
- const dispatch = useIntentDispatcher();
78
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
79
79
  const [formattingState, formattingObserver] = useFormattingState();
80
80
  const { hasAttention } = useAttention(id);
81
81
 
@@ -91,17 +91,9 @@ export const MarkdownEditor = ({
91
91
 
92
92
  // TODO(Zan): Move these into thread plugin as well?
93
93
  const [commentsState, commentObserver] = useCommentState();
94
- const onCommentClick = useCallback(() => {
95
- void dispatch([
96
- {
97
- action: NavigationAction.OPEN,
98
- data: { activeParts: { complementary: 'comments' } },
99
- },
100
- {
101
- action: LayoutAction.SET_LAYOUT,
102
- data: { element: 'complementary', state: true },
103
- },
104
- ]);
94
+ const onCommentClick = useCallback(async () => {
95
+ await dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: 'comments' } }));
96
+ await dispatch(createIntent(LayoutAction.SetLayout, { element: 'complementary', state: true }));
105
97
  }, [dispatch]);
106
98
  const commentClickObserver = useCommentClickListener(onCommentClick);
107
99
 
@@ -5,7 +5,7 @@
5
5
  import React, { type AnchorHTMLAttributes, type ReactNode, useMemo } from 'react';
6
6
  import { createRoot } from 'react-dom/client';
7
7
 
8
- import { type IntentDispatcher, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
8
+ import { createIntent, NavigationAction, type PromiseIntentDispatcher, useIntentDispatcher } from '@dxos/app-framework';
9
9
  import { invariant } from '@dxos/invariant';
10
10
  import { createDocAccessor, fullyQualifiedId, getSpace, type Query } from '@dxos/react-client/echo';
11
11
  import { useIdentity } from '@dxos/react-client/halo';
@@ -34,7 +34,7 @@ import { setFallbackName } from './util';
34
34
 
35
35
  type ExtensionsOptions = {
36
36
  document?: DocumentType;
37
- dispatch?: IntentDispatcher;
37
+ dispatch?: PromiseIntentDispatcher;
38
38
  query?: Query<DocumentType>;
39
39
  settings: MarkdownSettingsProps;
40
40
  viewMode?: EditorViewMode;
@@ -49,7 +49,7 @@ export const useExtensions = ({
49
49
  editorStateStore,
50
50
  extensionProviders,
51
51
  }: ExtensionsOptions & Pick<MarkdownPluginState, 'extensionProviders'>): Extension[] => {
52
- const dispatch = useIntentDispatcher();
52
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
53
53
  const identity = useIdentity();
54
54
  const space = getSpace(document);
55
55
 
@@ -105,7 +105,7 @@ export const useExtensions = ({
105
105
  document &&
106
106
  createDataExtensions({
107
107
  id: document.id,
108
- text: document.content && createDocAccessor(document.content, ['content']),
108
+ text: document.content.target && createDocAccessor(document.content.target, ['content']),
109
109
  space,
110
110
  identity,
111
111
  }),
@@ -117,7 +117,7 @@ export const useExtensions = ({
117
117
  baseExtensions,
118
118
  pluginExtensions,
119
119
  ].filter(isNotFalsy),
120
- [baseExtensions, pluginExtensions, document, document?.content, space, identity],
120
+ [baseExtensions, pluginExtensions, document, document?.content?.target, space, identity],
121
121
  );
122
122
  };
123
123
 
@@ -144,15 +144,14 @@ const createBaseExtensions = ({ document, dispatch, settings, query, viewMode }:
144
144
  renderLinkButton:
145
145
  dispatch && document
146
146
  ? onRenderLink((id: string) => {
147
- void dispatch({
148
- action: NavigationAction.ADD_TO_ACTIVE,
149
- data: {
147
+ void dispatch(
148
+ createIntent(NavigationAction.AddToActive, {
150
149
  id,
151
150
  part: 'main',
152
151
  pivotId: fullyQualifiedId(document),
153
152
  scrollIntoView: true,
154
- },
155
- });
153
+ }),
154
+ );
156
155
  })
157
156
  : undefined,
158
157
  }),
@@ -3,9 +3,10 @@
3
3
  //
4
4
 
5
5
  import { EditorView } from '@codemirror/view';
6
- import { useCallback } from 'react';
6
+ import { useMemo } from 'react';
7
7
 
8
- import { LayoutAction, useIntentResolver } from '@dxos/app-framework';
8
+ import { createResolver, LayoutAction, useIntentResolver } from '@dxos/app-framework';
9
+ import { invariant } from '@dxos/invariant';
9
10
  import { Cursor, setSelection } from '@dxos/react-ui-editor';
10
11
 
11
12
  import { MARKDOWN_PLUGIN } from '../meta';
@@ -14,12 +15,13 @@ import { MARKDOWN_PLUGIN } from '../meta';
14
15
  * Handle scrolling and selection of the current thread in a markdown editor.
15
16
  */
16
17
  export const useSelectCurrentThread = (editorView: EditorView | undefined, documentId: string) => {
17
- const handleScrollIntoView = useCallback(
18
- ({ action, data }: { action: string; data?: any }) => {
19
- if (action === LayoutAction.SCROLL_INTO_VIEW) {
20
- if (editorView && data?.id === documentId && data?.cursor) {
21
- // TODO(burdon): We need typed intents.
22
- const range = Cursor.getRangeFromCursor(editorView.state, data.cursor);
18
+ const scrollIntoViewResolver = useMemo(
19
+ () =>
20
+ createResolver(
21
+ LayoutAction.ScrollIntoView,
22
+ ({ cursor }) => {
23
+ invariant(editorView, 'Editor view is not defined.');
24
+ const range = Cursor.getRangeFromCursor(editorView.state, cursor!);
23
25
  if (range) {
24
26
  const selection = editorView.state.selection.main.from !== range.from ? { anchor: range.from } : undefined;
25
27
  const effects = [
@@ -35,14 +37,15 @@ export const useSelectCurrentThread = (editorView: EditorView | undefined, docum
35
37
  effects,
36
38
  selection: selection ? { anchor: range.from } : undefined,
37
39
  });
38
-
39
- return { data: true };
40
40
  }
41
- }
42
- }
43
- },
41
+ },
42
+ {
43
+ disposition: 'hoist',
44
+ filter: (data) => !!editorView && data.id === documentId && !!data.cursor,
45
+ },
46
+ ),
44
47
  [documentId, editorView],
45
48
  );
46
49
 
47
- useIntentResolver(MARKDOWN_PLUGIN, handleScrollIntoView);
50
+ useIntentResolver(MARKDOWN_PLUGIN, scrollIntoViewResolver);
48
51
  };
@@ -2,5 +2,5 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './document';
5
+ export * from './schema';
6
6
  export * from './types';
@@ -2,9 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { ref, S, TypedObject } from '@dxos/echo-schema';
5
+ import { Ref, S, TypedObject } from '@dxos/echo-schema';
6
6
  import { ThreadType } from '@dxos/plugin-space/types';
7
7
 
8
+ // TODO(burdon): Factor out.
8
9
  export class TextType extends TypedObject({ typename: 'dxos.org/type/Text', version: '0.1.0' })({
9
10
  content: S.String,
10
11
  }) {}
@@ -12,8 +13,8 @@ export class TextType extends TypedObject({ typename: 'dxos.org/type/Text', vers
12
13
  export class DocumentType extends TypedObject({ typename: 'dxos.org/type/Document', version: '0.1.0' })({
13
14
  name: S.optional(S.String),
14
15
  fallbackName: S.optional(S.String),
15
- content: ref(TextType),
16
- threads: S.mutable(S.Array(ref(ThreadType))),
16
+ content: Ref(TextType),
17
+ threads: S.mutable(S.Array(Ref(ThreadType))),
17
18
  }) {}
18
19
 
19
20
  /**