@dxos/plugin-markdown 0.9.0 → 0.9.1-main.c7dcc2e112

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 (137) hide show
  1. package/dist/lib/neutral/{MarkdownArticle-LWT5RFFJ.mjs → MarkdownArticle-I4UMD7AA.mjs} +3 -3
  2. package/dist/lib/neutral/MarkdownArticle-I4UMD7AA.mjs.map +7 -0
  3. package/dist/lib/neutral/{MarkdownCard-TBLIRDBO.mjs → MarkdownCard-OYO2HYZF.mjs} +2 -2
  4. package/dist/lib/neutral/MarkdownCard-OYO2HYZF.mjs.map +7 -0
  5. package/dist/lib/neutral/MarkdownPlugin.mjs +6 -9
  6. package/dist/lib/neutral/MarkdownPlugin.mjs.map +3 -3
  7. package/dist/lib/neutral/{MarkdownSettings-YCTZJL5V.mjs → MarkdownSettings-F5AWRDT3.mjs} +2 -2
  8. package/dist/lib/neutral/{MarkdownSettings-YCTZJL5V.mjs.map → MarkdownSettings-F5AWRDT3.mjs.map} +3 -3
  9. package/dist/lib/neutral/{app-graph-builder-BWBA23FF.mjs → app-graph-builder-6Y5NHTNR.mjs} +3 -4
  10. package/dist/lib/neutral/app-graph-builder-6Y5NHTNR.mjs.map +7 -0
  11. package/dist/lib/neutral/capabilities/index.mjs +6 -8
  12. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  13. package/dist/lib/neutral/capabilities/node.mjs +1 -1
  14. package/dist/lib/neutral/{chunk-67DKWOKF.mjs → chunk-4ULSRZRL.mjs} +3 -3
  15. package/dist/lib/neutral/chunk-4ULSRZRL.mjs.map +7 -0
  16. package/dist/lib/neutral/chunk-BL46CERY.mjs +8 -0
  17. package/dist/lib/neutral/{chunk-Y2LQRUU7.mjs → chunk-CRKAIDRD.mjs} +11 -11
  18. package/dist/lib/neutral/chunk-CRKAIDRD.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-GUXWFDD4.mjs +43 -0
  20. package/dist/lib/neutral/chunk-GUXWFDD4.mjs.map +7 -0
  21. package/dist/lib/neutral/components/index.mjs +9 -8
  22. package/dist/lib/neutral/components/index.mjs.map +3 -3
  23. package/dist/lib/neutral/containers/index.mjs +2 -2
  24. package/dist/lib/neutral/{create-JK35XC4R.mjs → create-XW2FQNLK.mjs} +2 -2
  25. package/dist/lib/neutral/{create-markdown-7MLE625M.mjs → create-markdown-KLSVQCT7.mjs} +2 -2
  26. package/dist/lib/neutral/{create-object-MU2LGXG6.mjs → create-object-3WMEQJ2C.mjs} +2 -2
  27. package/dist/lib/neutral/hooks/index.mjs +16 -12
  28. package/dist/lib/neutral/hooks/index.mjs.map +3 -3
  29. package/dist/lib/neutral/index.mjs +4 -4
  30. package/dist/lib/neutral/meta.json +1 -1
  31. package/dist/lib/neutral/meta.mjs +1 -1
  32. package/dist/lib/neutral/{navigation-resolver-3KBOMN4U.mjs → navigation-resolver-3WEM7SSC.mjs} +3 -3
  33. package/dist/lib/neutral/navigation-resolver-3WEM7SSC.mjs.map +7 -0
  34. package/dist/lib/neutral/{open-5YC77C4O.mjs → open-F7KLNKVN.mjs} +2 -2
  35. package/dist/lib/neutral/operations/index.mjs +1 -1
  36. package/dist/lib/neutral/plugin.mjs +2 -2
  37. package/dist/lib/neutral/{react-surface-XYZJBKHZ.mjs → react-surface-6LX4ZQ2H.mjs} +7 -12
  38. package/dist/lib/neutral/react-surface-6LX4ZQ2H.mjs.map +7 -0
  39. package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs → scroll-to-anchor-ACND3WJU.mjs} +2 -2
  40. package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs → set-view-mode-WDC7CAEC.mjs} +2 -2
  41. package/dist/lib/neutral/{settings-TDGDLCUR.mjs → settings-O6O6HT3I.mjs} +3 -3
  42. package/dist/lib/neutral/settings-O6O6HT3I.mjs.map +7 -0
  43. package/dist/lib/neutral/state-ZYT3JRWT.mjs +69 -0
  44. package/dist/lib/neutral/state-ZYT3JRWT.mjs.map +7 -0
  45. package/dist/lib/neutral/testing.mjs +2 -2
  46. package/dist/lib/neutral/testing.mjs.map +3 -3
  47. package/dist/lib/neutral/translations.mjs +1 -1
  48. package/dist/lib/neutral/translations.mjs.map +3 -3
  49. package/dist/lib/neutral/types/index.mjs +1 -1
  50. package/dist/lib/neutral/{update-markdown-NNINDDV5.mjs → update-markdown-FGVN3LD4.mjs} +2 -2
  51. package/dist/types/dx.config.d.ts +28 -0
  52. package/dist/types/dx.config.d.ts.map +1 -0
  53. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  54. package/dist/types/src/capabilities/editor-view-state.d.ts +7 -0
  55. package/dist/types/src/capabilities/editor-view-state.d.ts.map +1 -0
  56. package/dist/types/src/capabilities/index.d.ts +9 -16
  57. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  58. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +1 -1
  59. package/dist/types/src/capabilities/node.d.ts +1 -6
  60. package/dist/types/src/capabilities/node.d.ts.map +1 -1
  61. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  62. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  63. package/dist/types/src/capabilities/state.d.ts +1 -1
  64. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts +2 -2
  65. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts.map +1 -1
  66. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +2 -2
  67. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  68. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts.map +1 -1
  69. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts +2 -2
  70. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts.map +1 -1
  71. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts +4 -4
  72. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts.map +1 -1
  73. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.stories.d.ts.map +1 -1
  74. package/dist/types/src/hooks/useExtensions.d.ts +3 -3
  75. package/dist/types/src/hooks/useExtensions.d.ts.map +1 -1
  76. package/dist/types/src/meta.d.ts +28 -2
  77. package/dist/types/src/meta.d.ts.map +1 -1
  78. package/dist/types/src/paths.d.ts.map +1 -1
  79. package/dist/types/src/types/MarkdownCapabilities.d.ts.map +1 -1
  80. package/dist/types/tsconfig.tsbuildinfo +1 -1
  81. package/dx.config.ts +31 -0
  82. package/package.json +41 -40
  83. package/src/MarkdownPlugin.test.ts +1 -1
  84. package/src/MarkdownPlugin.tsx +5 -10
  85. package/src/capabilities/app-graph-builder.ts +1 -3
  86. package/src/capabilities/editor-view-state.ts +28 -0
  87. package/src/capabilities/index.ts +2 -14
  88. package/src/capabilities/navigation-resolver.ts +2 -2
  89. package/src/capabilities/react-surface.tsx +20 -10
  90. package/src/capabilities/settings.ts +2 -2
  91. package/src/capabilities/state.ts +8 -4
  92. package/src/components/MarkdownEditor/FileUpload.tsx +2 -2
  93. package/src/components/MarkdownEditor/MarkdownEditor.tsx +4 -4
  94. package/src/components/MarkdownEditor/MarkdownEditorContent.tsx +4 -3
  95. package/src/components/MarkdownEditor/MarkdownEditorToolbar.tsx +2 -2
  96. package/src/components/MarkdownSettings/MarkdownSettings.tsx +1 -1
  97. package/src/containers/MarkdownArticle/MarkdownArticle.stories.tsx +3 -4
  98. package/src/containers/MarkdownArticle/MarkdownArticle.tsx +3 -3
  99. package/src/containers/MarkdownCard/MarkdownCard.tsx +1 -1
  100. package/src/hooks/useEditorMenuOptions.ts +1 -1
  101. package/src/hooks/useExtensions.tsx +11 -11
  102. package/src/meta.ts +2 -22
  103. package/src/operations/create.conversations.json +1 -1
  104. package/src/operations/update.conversations.json +1 -1
  105. package/src/paths.ts +4 -2
  106. package/src/testing.ts +2 -2
  107. package/src/translations.ts +1 -1
  108. package/src/types/Markdown.ts +3 -3
  109. package/src/types/MarkdownCapabilities.ts +7 -5
  110. package/src/types/MarkdownEvents.ts +1 -1
  111. package/src/types/MarkdownOperation.ts +1 -1
  112. package/dist/lib/neutral/MarkdownArticle-LWT5RFFJ.mjs.map +0 -7
  113. package/dist/lib/neutral/MarkdownCard-TBLIRDBO.mjs.map +0 -7
  114. package/dist/lib/neutral/app-graph-builder-BWBA23FF.mjs.map +0 -7
  115. package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs +0 -56
  116. package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs.map +0 -7
  117. package/dist/lib/neutral/chunk-36QFEVOZ.mjs +0 -30
  118. package/dist/lib/neutral/chunk-36QFEVOZ.mjs.map +0 -7
  119. package/dist/lib/neutral/chunk-67DKWOKF.mjs.map +0 -7
  120. package/dist/lib/neutral/chunk-CIJD7P6X.mjs +0 -8
  121. package/dist/lib/neutral/chunk-Y2LQRUU7.mjs.map +0 -7
  122. package/dist/lib/neutral/navigation-resolver-3KBOMN4U.mjs.map +0 -7
  123. package/dist/lib/neutral/react-surface-XYZJBKHZ.mjs.map +0 -7
  124. package/dist/lib/neutral/settings-TDGDLCUR.mjs.map +0 -7
  125. package/dist/lib/neutral/state-5COCF5PN.mjs +0 -44
  126. package/dist/lib/neutral/state-5COCF5PN.mjs.map +0 -7
  127. package/dist/types/src/capabilities/app-graph-serializer.d.ts +0 -5
  128. package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +0 -1
  129. package/src/capabilities/app-graph-serializer.ts +0 -64
  130. /package/dist/lib/neutral/{chunk-CIJD7P6X.mjs.map → chunk-BL46CERY.mjs.map} +0 -0
  131. /package/dist/lib/neutral/{create-JK35XC4R.mjs.map → create-XW2FQNLK.mjs.map} +0 -0
  132. /package/dist/lib/neutral/{create-markdown-7MLE625M.mjs.map → create-markdown-KLSVQCT7.mjs.map} +0 -0
  133. /package/dist/lib/neutral/{create-object-MU2LGXG6.mjs.map → create-object-3WMEQJ2C.mjs.map} +0 -0
  134. /package/dist/lib/neutral/{open-5YC77C4O.mjs.map → open-F7KLNKVN.mjs.map} +0 -0
  135. /package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs.map → scroll-to-anchor-ACND3WJU.mjs.map} +0 -0
  136. /package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs.map → set-view-mode-WDC7CAEC.mjs.map} +0 -0
  137. /package/dist/lib/neutral/{update-markdown-NNINDDV5.mjs.map → update-markdown-FGVN3LD4.mjs.map} +0 -0
package/dx.config.ts ADDED
@@ -0,0 +1,31 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Config2 } from '@dxos/app-framework/config';
6
+ import { trim } from '@dxos/util';
7
+
8
+ export default Config2.make({
9
+ plugin: {
10
+ key: 'org.dxos.plugin.markdown',
11
+ name: 'Markdown',
12
+ author: 'DXOS',
13
+ description: trim`
14
+ A full-featured markdown editor for authoring documents in your space. Edits flow through a collaborative CodeMirror surface backed by ECHO Text, so every keystroke replicates to other peers in real time without merge conflicts or lost work.
15
+
16
+ Documents can be opened in source, preview, or read-only mode and rendered as a full-surface article or as embeddable cards. An optional formatting toolbar exposes headings, lists, links, and other common markdown actions, and dispositional toolbar actions contributed by other plugins are surfaced inline alongside it.
17
+
18
+ The editor integrates with the rest of the workspace through @ references that link to any ECHO object, image and file uploads stored in the active space, and anchored comment threads on text ranges. Comments can optionally be routed to an AI agent on every message or only on @mention.
19
+
20
+ A built-in blueprint exposes create, open, and update operations as tools for AI agents. Updates are applied as compact find-and-replace diffs against the document, making it safe for agents to edit large documents incrementally while you continue collaborating.
21
+ `,
22
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-markdown',
23
+ icon: { key: 'ph--text-aa--regular', hue: 'indigo' },
24
+ screenshots: [
25
+ {
26
+ dark: 'https://customer-5rxcjpyab08avpmn.cloudflarestream.com/cdf2656365bb1fd327c1fc2105d75e5a/iframe?poster=https%3A%2F%2Fcustomer-5rxcjpyab08avpmn.cloudflarestream.com%2Fcdf2656365bb1fd327c1fc2105d75e5a%2Fthumbnails%2Fthumbnail.jpg%3Ftime%3D%26height%3D600',
27
+ },
28
+ { dark: 'https://dxos.network/plugin-details-markdown-dark.png' },
29
+ ],
30
+ },
31
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-markdown",
3
- "version": "0.9.0",
3
+ "version": "0.9.1-main.c7dcc2e112",
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",
@@ -114,6 +114,7 @@
114
114
  "types": "dist/types/src/index.d.ts",
115
115
  "files": [
116
116
  "dist",
117
+ "dx.config.ts",
117
118
  "src"
118
119
  ],
119
120
  "dependencies": {
@@ -125,36 +126,36 @@
125
126
  "@effect/experimental": "0.60.0",
126
127
  "@radix-ui/react-context": "1.1.1",
127
128
  "react-dropzone": "^14.2.3",
128
- "@dxos/ai": "0.9.0",
129
- "@dxos/app-framework": "0.9.0",
130
- "@dxos/assistant": "0.9.0",
131
- "@dxos/app-toolkit": "0.9.0",
132
- "@dxos/client": "0.9.0",
133
- "@dxos/async": "0.9.0",
134
- "@dxos/client-protocol": "0.9.0",
135
- "@dxos/compute": "0.9.0",
136
- "@dxos/echo": "0.9.0",
137
- "@dxos/echo-client": "0.9.0",
138
- "@dxos/invariant": "0.9.0",
139
- "@dxos/functions-runtime": "0.9.0",
140
- "@dxos/keys": "0.9.0",
141
- "@dxos/effect": "0.9.0",
142
- "@dxos/log": "0.9.0",
143
- "@dxos/plugin-client": "0.9.0",
144
- "@dxos/plugin-attention": "0.9.0",
145
- "@dxos/plugin-graph": "0.9.0",
146
- "@dxos/plugin-preview": "0.9.0",
147
- "@dxos/plugin-space": "0.9.0",
148
- "@dxos/react-ui-attention": "0.9.0",
149
- "@dxos/react-client": "0.9.0",
150
- "@dxos/react-ui-form": "0.9.0",
151
- "@dxos/react-ui-editor": "0.9.0",
152
- "@dxos/react-ui-mosaic": "0.9.0",
153
- "@dxos/types": "0.9.0",
154
- "@dxos/schema": "0.9.0",
155
- "@dxos/ui-editor": "0.9.0",
156
- "@dxos/ui": "0.9.0",
157
- "@dxos/util": "0.9.0"
129
+ "@dxos/ai": "0.9.1-main.c7dcc2e112",
130
+ "@dxos/app-toolkit": "0.9.1-main.c7dcc2e112",
131
+ "@dxos/app-framework": "0.9.1-main.c7dcc2e112",
132
+ "@dxos/async": "0.9.1-main.c7dcc2e112",
133
+ "@dxos/client-protocol": "0.9.1-main.c7dcc2e112",
134
+ "@dxos/client": "0.9.1-main.c7dcc2e112",
135
+ "@dxos/assistant": "0.9.1-main.c7dcc2e112",
136
+ "@dxos/compute": "0.9.1-main.c7dcc2e112",
137
+ "@dxos/echo-client": "0.9.1-main.c7dcc2e112",
138
+ "@dxos/echo": "0.9.1-main.c7dcc2e112",
139
+ "@dxos/functions-runtime": "0.9.1-main.c7dcc2e112",
140
+ "@dxos/invariant": "0.9.1-main.c7dcc2e112",
141
+ "@dxos/keys": "0.9.1-main.c7dcc2e112",
142
+ "@dxos/plugin-client": "0.9.1-main.c7dcc2e112",
143
+ "@dxos/effect": "0.9.1-main.c7dcc2e112",
144
+ "@dxos/plugin-attention": "0.9.1-main.c7dcc2e112",
145
+ "@dxos/plugin-preview": "0.9.1-main.c7dcc2e112",
146
+ "@dxos/plugin-space": "0.9.1-main.c7dcc2e112",
147
+ "@dxos/plugin-graph": "0.9.1-main.c7dcc2e112",
148
+ "@dxos/react-client": "0.9.1-main.c7dcc2e112",
149
+ "@dxos/react-ui-attention": "0.9.1-main.c7dcc2e112",
150
+ "@dxos/react-ui-editor": "0.9.1-main.c7dcc2e112",
151
+ "@dxos/react-ui-mosaic": "0.9.1-main.c7dcc2e112",
152
+ "@dxos/react-ui-form": "0.9.1-main.c7dcc2e112",
153
+ "@dxos/schema": "0.9.1-main.c7dcc2e112",
154
+ "@dxos/types": "0.9.1-main.c7dcc2e112",
155
+ "@dxos/ui-editor": "0.9.1-main.c7dcc2e112",
156
+ "@dxos/ui": "0.9.1-main.c7dcc2e112",
157
+ "@dxos/util": "0.9.1-main.c7dcc2e112",
158
+ "@dxos/log": "0.9.1-main.c7dcc2e112"
158
159
  },
159
160
  "devDependencies": {
160
161
  "@effect-atom/atom-react": "^0.5.0",
@@ -165,13 +166,13 @@
165
166
  "react": "~19.2.3",
166
167
  "react-dom": "~19.2.3",
167
168
  "vite": "^8.0.16",
168
- "@dxos/debug": "0.9.0",
169
- "@dxos/plugin-theme": "0.9.0",
170
- "@dxos/plugin-testing": "0.9.0",
171
- "@dxos/react-ui": "0.9.0",
172
- "@dxos/random": "0.9.0",
173
- "@dxos/ui-theme": "0.9.0",
174
- "@dxos/storybook-utils": "0.9.0"
169
+ "@dxos/debug": "0.9.1-main.c7dcc2e112",
170
+ "@dxos/plugin-testing": "0.9.1-main.c7dcc2e112",
171
+ "@dxos/plugin-theme": "0.9.1-main.c7dcc2e112",
172
+ "@dxos/react-ui": "0.9.1-main.c7dcc2e112",
173
+ "@dxos/ui-theme": "0.9.1-main.c7dcc2e112",
174
+ "@dxos/random": "0.9.1-main.c7dcc2e112",
175
+ "@dxos/storybook-utils": "0.9.1-main.c7dcc2e112"
175
176
  },
176
177
  "peerDependencies": {
177
178
  "@effect-atom/atom-react": "^0.5.0",
@@ -179,8 +180,8 @@
179
180
  "effect": "3.21.3",
180
181
  "react": "~19.2.3",
181
182
  "react-dom": "~19.2.3",
182
- "@dxos/react-ui": "0.9.0",
183
- "@dxos/ui-theme": "0.9.0"
183
+ "@dxos/ui-theme": "0.9.1-main.c7dcc2e112",
184
+ "@dxos/react-ui": "0.9.1-main.c7dcc2e112"
184
185
  },
185
186
  "publishConfig": {
186
187
  "access": "public"
@@ -11,7 +11,7 @@ import { MarkdownPlugin } from '#plugin';
11
11
 
12
12
  import { meta } from './meta';
13
13
 
14
- const moduleId = (name: string) => `${meta.id}.module.${name}`;
14
+ const moduleId = (name: string) => `${meta.profile.key}.module.${name}`;
15
15
 
16
16
  describe('MarkdownPlugin', () => {
17
17
  test('modules activate on the expected events', async ({ expect }) => {
@@ -2,8 +2,9 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Plugin } from '@dxos/app-framework';
5
+ import { ActivationEvent, Plugin } from '@dxos/app-framework';
6
6
  import { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';
7
+ import { AttentionEvents } from '@dxos/plugin-attention';
7
8
  import { translations as editorTranslations } from '@dxos/react-ui-editor/translations';
8
9
  import { Text } from '@dxos/schema';
9
10
 
@@ -11,7 +12,6 @@ import {
11
12
  AnchorSort,
12
13
  AppGraphBuilder,
13
14
  NavigationResolver,
14
- AppGraphSerializer,
15
15
  BlueprintDefinition,
16
16
  CommentConfig,
17
17
  CreateObject,
@@ -43,16 +43,11 @@ export const MarkdownPlugin = Plugin.define(meta).pipe(
43
43
  }),
44
44
  Plugin.addModule({
45
45
  id: 'state',
46
- // TODO(wittjosiah): Does not integrate with settings store.
47
- // Should this be a different event?
48
- // Should settings store be renamed to be more generic?
49
- activatesOn: AppActivationEvents.SetupSettings,
46
+ // Wait for AttentionEvents.AttentionReady so ViewStateManager is available when the module
47
+ // resolves AttentionCapabilities.ViewState to build the editor state store.
48
+ activatesOn: ActivationEvent.allOf(AppActivationEvents.SetupSettings, AttentionEvents.AttentionReady),
50
49
  activate: MarkdownState,
51
50
  }),
52
- Plugin.addModule({
53
- activatesOn: AppActivationEvents.AppGraphReady,
54
- activate: AppGraphSerializer,
55
- }),
56
51
  Plugin.addModule({
57
52
  // TODO(wittjosiah): More relevant event?
58
53
  activatesOn: AppActivationEvents.AppGraphReady,
@@ -6,7 +6,7 @@ import * as Effect from 'effect/Effect';
6
6
  import * as Option from 'effect/Option';
7
7
 
8
8
  import { Capability } from '@dxos/app-framework';
9
- import { AppCapabilities, LayoutOperation, createTypeSectionExtension } from '@dxos/app-toolkit';
9
+ import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
10
10
  import { isSpace } from '@dxos/client/echo';
11
11
  import { Operation } from '@dxos/compute';
12
12
  import { Type } from '@dxos/echo';
@@ -22,8 +22,6 @@ const documentTypename = Type.getTypename(Markdown.Document);
22
22
  export default Capability.makeModule(
23
23
  Effect.fnUntraced(function* () {
24
24
  const extensions = yield* Effect.all([
25
- createTypeSectionExtension(Markdown.Document),
26
-
27
25
  GraphBuilder.createExtension({
28
26
  id: 'documentsSectionActions',
29
27
  match: (node) => {
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { invariant } from '@dxos/invariant';
6
+ import { type ViewStateManager, defineViewState } from '@dxos/react-ui-attention';
7
+ import { type EditorStateStore, EditorSelectionStateSchema } from '@dxos/ui-editor';
8
+
9
+ /** Per-document editor scroll/caret state, persisted to localStorage on this device. */
10
+ export const editorViewStateAspect = defineViewState({
11
+ key: 'editor',
12
+ backend: 'local',
13
+ schema: EditorSelectionStateSchema,
14
+ defaultValue: () => ({}),
15
+ });
16
+
17
+ /** Adapts the imperative editor store seam onto the ViewState manager (local backend). */
18
+ export const createEditorViewStateStore = (manager: ViewStateManager): EditorStateStore => ({
19
+ getState: (id) => {
20
+ // Guard against an unset document id, which would key state under a literal "undefined".
21
+ invariant(id);
22
+ return manager.get(editorViewStateAspect, id);
23
+ },
24
+ setState: (id, state) => {
25
+ invariant(id);
26
+ manager.set(editorViewStateAspect, id, state);
27
+ },
28
+ });
@@ -3,26 +3,14 @@
3
3
  //
4
4
 
5
5
  import { Capability } from '@dxos/app-framework';
6
- import { type AppCapabilities } from '@dxos/app-toolkit';
7
6
  import type { OperationHandlerSet } from '@dxos/compute';
8
7
 
9
8
  export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
10
9
  export const NavigationResolver = Capability.lazy('NavigationResolver', () => import('./navigation-resolver'));
11
10
  export const AnchorSort = Capability.lazy('AnchorSort', () => import('./anchor-sort'));
12
- export const AppGraphSerializer = Capability.lazy('AppGraphSerializer', () => import('./app-graph-serializer'));
13
- // The contributed capability type references Operation types from @dxos/compute, so the lazy
14
- // wrapper needs an explicit annotation to keep the inferred type portable (TS2883).
15
- export const CommentConfig: Capability.LazyCapability<
16
- void,
17
- Capability.Capability<typeof AppCapabilities.CommentConfig>
18
- > = Capability.lazy('CommentConfig', () => import('./comment-config'));
11
+ export const CommentConfig = Capability.lazy('CommentConfig', () => import('./comment-config'));
19
12
  export const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));
20
- // The contributed capability type references Blueprint types from @dxos/compute, so the lazy
21
- // wrapper needs an explicit annotation to keep the inferred type portable (TS2883).
22
- export const BlueprintDefinition: Capability.LazyCapability<
23
- void,
24
- Capability.Capability<typeof AppCapabilities.BlueprintDefinition>[]
25
- > = Capability.lazy('BlueprintDefinition', () => import('./blueprint-definition'));
13
+ export const BlueprintDefinition = Capability.lazy('BlueprintDefinition', () => import('./blueprint-definition'));
26
14
  export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
27
15
  'OperationHandler',
28
16
  () => import('./operation-handler'),
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { Capability } from '@dxos/app-framework';
8
- import { AppCapabilities, createTypeSectionPathResolver } from '@dxos/app-toolkit';
8
+ import { AppCapabilities, TypeSection } from '@dxos/app-toolkit';
9
9
 
10
10
  import { Markdown } from '#types';
11
11
 
@@ -13,7 +13,7 @@ export default Capability.makeModule(
13
13
  Effect.fnUntraced(function* () {
14
14
  return Capability.contributes(
15
15
  AppCapabilities.NavigationPathResolver,
16
- createTypeSectionPathResolver(Markdown.Document),
16
+ TypeSection.createTypeSectionPathResolver(Markdown.Document),
17
17
  );
18
18
  }),
19
19
  );
@@ -31,9 +31,11 @@ export default Capability.makeModule(() =>
31
31
  Surface.create({
32
32
  id: 'surface.document',
33
33
  // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.
34
- role: ['article', 'section', 'tabpanel'],
35
- filter: (data): data is { subject: Markdown.Document; attendableId: string; variant: undefined } =>
36
- typeof data.attendableId === 'string' && Obj.instanceOf(Markdown.Document, data.subject) && !data.variant,
34
+ filter: AppSurface.oneOf(
35
+ AppSurface.object(AppSurface.Article, Markdown.Document, (data) => !data.variant),
36
+ AppSurface.object(AppSurface.Section, Markdown.Document),
37
+ AppSurface.object(AppSurface.Tabpanel, Markdown.Document, (data) => !data.variant),
38
+ ),
37
39
  component: ({ data, role, ref }) => {
38
40
  return (
39
41
  <Container
@@ -41,7 +43,7 @@ export default Capability.makeModule(() =>
41
43
  attendableId={data.attendableId}
42
44
  subject={data.subject}
43
45
  role={role}
44
- ref={ref}
46
+ ref={ref as React.Ref<HTMLDivElement>}
45
47
  />
46
48
  );
47
49
  },
@@ -62,14 +64,14 @@ export default Capability.makeModule(() =>
62
64
  attendableId={data.attendableId}
63
65
  subject={data.subject}
64
66
  role={role}
65
- ref={ref}
67
+ ref={ref as React.Ref<HTMLDivElement>}
66
68
  />
67
69
  );
68
70
  },
69
71
  }),
70
72
  Surface.create({
71
73
  id: 'surface.pluginSettings',
72
- filter: AppSurface.settings(AppSurface.Article, meta.id),
74
+ filter: AppSurface.settings(AppSurface.Article, meta.profile.key),
73
75
  component: ({ data: { subject } }) => {
74
76
  const { settings, updateSettings } = useSettingsState<Markdown.Settings>(subject.atom);
75
77
  return <MarkdownSettings settings={settings} onSettingsChange={updateSettings} />;
@@ -78,12 +80,20 @@ export default Capability.makeModule(() =>
78
80
  Surface.create({
79
81
  id: 'surface.editable',
80
82
  position: 'first',
81
- filter: AppSurface.object(AppSurface.Card, [Markdown.Document, Text.Text], (data) => data.editable === true),
83
+ filter: AppSurface.object(
84
+ AppSurface.CardContent,
85
+ [Markdown.Document, Text.Text],
86
+ (data) => data.editable === true,
87
+ ),
82
88
  component: ({ data }) => <EditableMarkdownCard subject={data.subject} />,
83
89
  }),
84
90
  Surface.create({
85
91
  id: 'surface.preview',
86
- filter: AppSurface.object(AppSurface.Card, [Markdown.Document, Text.Text], (data) => data.editable !== true),
92
+ filter: AppSurface.object(
93
+ AppSurface.CardContent,
94
+ [Markdown.Document, Text.Text],
95
+ (data) => data.editable !== true,
96
+ ),
87
97
  component: ({ data }) => <MarkdownCard {...data} />,
88
98
  }),
89
99
  ]),
@@ -97,7 +107,7 @@ const Container = forwardRef<
97
107
  HTMLDivElement,
98
108
  AppSurface.ObjectArticleProps<Markdown.Document | Text.Text, { id: string }>
99
109
  >(({ id, attendableId, subject, role }, forwardedRef) => {
100
- const selectionManager = useCapability(AttentionCapabilities.Selection);
110
+ const viewState = useCapability(AttentionCapabilities.ViewState);
101
111
  const settings = useAtomCapability(MarkdownCapabilities.Settings);
102
112
  const [state, setState] = useAtomCapabilityState(MarkdownCapabilities.State);
103
113
  const editorState = useCapability(MarkdownCapabilities.EditorState);
@@ -117,7 +127,7 @@ const Container = forwardRef<
117
127
  id={id}
118
128
  attendableId={attendableId}
119
129
  settings={settings}
120
- selectionManager={selectionManager}
130
+ viewState={viewState}
121
131
  extensionProviders={extensionProviders}
122
132
  editorStateStore={editorState}
123
133
  viewMode={viewMode}
@@ -14,7 +14,7 @@ import { Markdown, MarkdownCapabilities } from '#types';
14
14
  export default Capability.makeModule(() =>
15
15
  Effect.sync(() => {
16
16
  const settingsAtom = createKvsStore({
17
- key: meta.id,
17
+ key: meta.profile.key,
18
18
  schema: Markdown.Settings,
19
19
  defaultValue: () => ({
20
20
  defaultViewMode: 'preview' as const,
@@ -28,7 +28,7 @@ export default Capability.makeModule(() =>
28
28
  return [
29
29
  Capability.contributes(MarkdownCapabilities.Settings, settingsAtom),
30
30
  Capability.contributes(AppCapabilities.Settings, {
31
- prefix: meta.id,
31
+ prefix: meta.profile.key,
32
32
  schema: Markdown.Settings,
33
33
  atom: settingsAtom,
34
34
  }),
@@ -6,11 +6,13 @@ import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { Capability } from '@dxos/app-framework';
8
8
  import { createKvsStore } from '@dxos/effect';
9
- import { createEditorStateStore } from '@dxos/ui-editor';
9
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
10
10
 
11
11
  import { meta } from '#meta';
12
12
  import { MarkdownCapabilities } from '#types';
13
13
 
14
+ import { createEditorViewStateStore } from './editor-view-state';
15
+
14
16
  const createEditorViewRegistry = (): MarkdownCapabilities.EditorViewRegistry => {
15
17
  const views = new Map<string, MarkdownCapabilities.EditorViewEntry>();
16
18
  return {
@@ -28,13 +30,15 @@ export default Capability.makeModule(
28
30
  Effect.fnUntraced(function* () {
29
31
  // Persisted state using KVS store.
30
32
  const stateAtom = createKvsStore({
31
- key: `${meta.id}.state`,
33
+ key: `${meta.profile.key}.state`,
32
34
  schema: MarkdownCapabilities.StateSchema,
33
35
  defaultValue: () => ({ viewMode: {} }),
34
36
  });
35
37
 
36
- // TODO(wittjosiah): Fold into state.
37
- const editorState = createEditorStateStore(`${meta.id}.editor`);
38
+ // Resolve ViewStateManager contributed by plugin-attention (guaranteed available because this
39
+ // module activates only after AttentionEvents.AttentionReady fires — see MarkdownPlugin.tsx).
40
+ const viewState = yield* Capability.get(AttentionCapabilities.ViewState);
41
+ const editorState = createEditorViewStateStore(viewState);
38
42
 
39
43
  const editorViews = createEditorViewRegistry();
40
44
 
@@ -7,7 +7,7 @@ import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
7
7
  import { createPortal } from 'react-dom';
8
8
  import { useDropzone } from 'react-dropzone';
9
9
 
10
- import { type FileInfo } from '@dxos/app-toolkit';
10
+ import { AppCapabilities } from '@dxos/app-toolkit';
11
11
  import { addLink } from '@dxos/ui-editor';
12
12
 
13
13
  export const IMAGE_FILES = ['.jpg', '.jpeg', '.png', '.gif'];
@@ -19,7 +19,7 @@ export type FileUploadProps = {
19
19
  // that React 19.2's dev render-logger would walk into a cross-origin frame. See
20
20
  // `react-ui-editor/.../controller.ts` for the full rationale.
21
21
  getView?: () => EditorView | null;
22
- onFileUpload?: (file: File) => Promise<FileInfo | undefined>;
22
+ onFileUpload?: (file: File) => Promise<AppCapabilities.FileInfo | undefined>;
23
23
  };
24
24
 
25
25
  // TODO(burdon): Factor out.
@@ -74,7 +74,7 @@ export type MarkdownEditorProviderProps = {
74
74
  'id' | 'attendableId' | 'viewMode' | 'compact' | 'onAction' | 'onFileUpload' | 'onViewModeChange'
75
75
  > &
76
76
  Pick<UseEditorMenuOptionsProps, 'slashCommandGroups' | 'onLinkQuery'> &
77
- Pick<ExtensionsOptions, 'editorStateStore' | 'selectionManager' | 'settings' | 'onSelectObject'>;
77
+ Pick<ExtensionsOptions, 'editorStateStore' | 'viewState' | 'settings' | 'onSelectObject'>;
78
78
 
79
79
  export const MarkdownEditorProvider = ({
80
80
  children,
@@ -84,7 +84,7 @@ export const MarkdownEditorProvider = ({
84
84
  settings,
85
85
  compact,
86
86
  viewMode,
87
- selectionManager,
87
+ viewState,
88
88
  editorStateStore,
89
89
  extensions: extensionsProp,
90
90
  slashCommandGroups,
@@ -118,7 +118,7 @@ export const MarkdownEditorProvider = ({
118
118
  object,
119
119
  compact,
120
120
  viewMode,
121
- selectionManager,
121
+ viewState,
122
122
  editorStateStore,
123
123
  previewOptions,
124
124
  settings,
@@ -270,7 +270,7 @@ const PreviewBlock = ({ el, link }: PreviewBlock) => {
270
270
  const subject = client.graph.makeRef(dxn).target;
271
271
  const data = useMemo(() => ({ subject }), [subject]);
272
272
 
273
- return createPortal(<Surface.Surface type={AppSurface.Card} data={data} limit={1} />, el);
273
+ return createPortal(<Surface.Surface type={AppSurface.CardContent} data={data} limit={1} />, el);
274
274
  };
275
275
 
276
276
  //
@@ -7,6 +7,7 @@ import { type Atom, RegistryContext } from '@effect-atom/atom-react';
7
7
  import React, { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo } from 'react';
8
8
 
9
9
  import { useCapabilities } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
10
11
  import { type ThemedClassName, useThemeContext, useTranslation } from '@dxos/react-ui';
11
12
  import {
12
13
  type EditorMenuGroup,
@@ -72,7 +73,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
72
73
  },
73
74
  forwardedRef,
74
75
  ) => {
75
- const { t } = useTranslation(meta.id);
76
+ const { t } = useTranslation(meta.profile.key);
76
77
  const { themeMode } = useThemeContext();
77
78
  const registry = useContext(RegistryContext);
78
79
 
@@ -95,7 +96,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
95
96
  focusAttributes,
96
97
  } = useTextEditor(
97
98
  () => ({
98
- ...(role !== 'section' && {
99
+ ...(role !== AppSurface.Section.role && {
99
100
  id,
100
101
  scrollTo,
101
102
  selection,
@@ -117,7 +118,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
117
118
  createMarkdownExtensions(),
118
119
  scrollbarAutohide(),
119
120
  toolbarState && formattingListener(updateToolbarState),
120
- role !== 'section' &&
121
+ role !== AppSurface.Section.role &&
121
122
  onFileUpload &&
122
123
  dropFile({
123
124
  // TODO(wittjosiah): Factor out to file uploader plugin.
@@ -5,7 +5,7 @@
5
5
  import { type EditorView } from '@codemirror/view';
6
6
  import React, { useCallback, useState } from 'react';
7
7
 
8
- import { type FileInfo } from '@dxos/app-toolkit';
8
+ import { AppCapabilities } from '@dxos/app-toolkit';
9
9
  import { composable, composableProps } from '@dxos/react-ui';
10
10
  import { Editor, type EditorToolbarProps } from '@dxos/react-ui-editor';
11
11
 
@@ -17,7 +17,7 @@ export type MarkdownEditorToolbarProps = {
17
17
  // that React 19.2's dev render-logger would walk into a cross-origin frame. See
18
18
  // `react-ui-editor/.../controller.ts` for the full rationale.
19
19
  getView?: () => EditorView | null;
20
- onFileUpload?: (file: File) => Promise<FileInfo | undefined>;
20
+ onFileUpload?: (file: File) => Promise<AppCapabilities.FileInfo | undefined>;
21
21
  } & Pick<EditorToolbarProps, 'role' | 'customActions' | 'onAction' | 'onViewModeChange'>;
22
22
 
23
23
  export const MarkdownEditorToolbar = composable<HTMLDivElement, MarkdownEditorToolbarProps>(
@@ -20,7 +20,7 @@ const SnippetsField = ({ value, onChange, readonly }: SettingsFieldProps<string
20
20
  export const MarkdownSettings = ({ settings, onSettingsChange }: MarkdownSettingsProps) => {
21
21
  return (
22
22
  <SettingsForm.Viewport>
23
- <SettingsForm.Section title={meta.name ?? 'Editor'}>
23
+ <SettingsForm.Section title={meta.profile.name ?? 'Editor'}>
24
24
  <SettingsForm.FieldSet
25
25
  readonly={!onSettingsChange}
26
26
  schema={Markdown.Settings}
@@ -91,10 +91,9 @@ const meta = {
91
91
  const createObjects = createObjectFactory(personalSpace.db, generator);
92
92
  yield* Effect.promise(() => createObjects([{ type: Organization.Organization, count: 10 }]));
93
93
 
94
- const queue = personalSpace.queues.create();
95
- const kai = Obj.make(Person.Person, { fullName: 'Kai' });
96
- const dxos = Obj.make(Organization.Organization, { name: 'DXOS' });
97
- yield* Effect.promise(() => queue.append([kai, dxos]));
94
+ const kai = personalSpace.db.add(Obj.make(Person.Person, { fullName: 'Kai' }));
95
+ const dxos = personalSpace.db.add(Obj.make(Organization.Organization, { name: 'DXOS' }));
96
+ yield* Effect.promise(() => personalSpace.db.flush());
98
97
 
99
98
  personalSpace.db.add(
100
99
  Markdown.make({
@@ -13,7 +13,7 @@ import { Obj } from '@dxos/echo';
13
13
  import { useActionRunner } from '@dxos/plugin-graph';
14
14
  import { useObject } from '@dxos/react-client/echo';
15
15
  import { Panel } from '@dxos/react-ui';
16
- import { type SelectionManager } from '@dxos/react-ui-attention';
16
+ import { type ViewStateManager } from '@dxos/react-ui-attention';
17
17
  import { Editor } from '@dxos/react-ui-editor';
18
18
  import { Text } from '@dxos/schema';
19
19
 
@@ -31,7 +31,7 @@ export type MarkdownArticleProps = AppSurface.ObjectArticleProps<
31
31
  {
32
32
  id: string;
33
33
  settings: Markdown.Settings;
34
- selectionManager?: SelectionManager;
34
+ viewState?: ViewStateManager;
35
35
  } & Pick<MarkdownPluginState, 'extensionProviders'> &
36
36
  Pick<MarkdownEditorProviderProps, 'viewMode' | 'onSelectObject' | 'onViewModeChange'> &
37
37
  Pick<MarkdownEditorContentProps, 'editorStateStore'>
@@ -115,7 +115,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
115
115
  id={id}
116
116
  attendableId={attendableId}
117
117
  object={object}
118
- compact={role !== 'article'}
118
+ compact={role !== AppSurface.Article.role}
119
119
  extensions={extensions}
120
120
  settings={settings}
121
121
  viewMode={viewMode}
@@ -20,7 +20,7 @@ import { snippet as snippetExtension } from './snippet';
20
20
  export type MarkdownCardProps = { subject: Markdown.Document | Text.Text };
21
21
 
22
22
  export const MarkdownCard = ({ subject }: MarkdownCardProps) => {
23
- const { t } = useTranslation(meta.id);
23
+ const { t } = useTranslation(meta.profile.key);
24
24
  // NOTE: Newline is added so that Fade does not obscure the last line.
25
25
  const snippet = useMemo(() => getSnippet(subject) + '\n', [subject]);
26
26
  const extensions = useMemo(() => [snippetExtension({ height: 300, scale: 0.8 })], []);
@@ -28,7 +28,7 @@ export const useEditorMenuOptions = ({
28
28
  slashCommandGroups,
29
29
  onLinkQuery,
30
30
  }: UseEditorMenuOptionsProps): UseEditorMenuProps => {
31
- const { t } = useTranslation(meta.id);
31
+ const { t } = useTranslation(meta.profile.key);
32
32
 
33
33
  const getMenu = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(
34
34
  ({ text, trigger }) => {