@dxos/plugin-markdown 0.8.2-main.f11618f → 0.8.2-staging.42af850

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 (210) hide show
  1. package/dist/lib/browser/MarkdownContainer-5IEINNQB.mjs +588 -0
  2. package/dist/lib/browser/MarkdownContainer-5IEINNQB.mjs.map +7 -0
  3. package/dist/lib/browser/MarkdownPreview-YW5CS3ID.mjs +87 -0
  4. package/dist/lib/browser/MarkdownPreview-YW5CS3ID.mjs.map +7 -0
  5. package/dist/lib/browser/anchor-sort-VS4OZVPP.mjs +32 -0
  6. package/dist/lib/browser/anchor-sort-VS4OZVPP.mjs.map +7 -0
  7. package/dist/lib/browser/{app-graph-serializer-OCXP7PCK.mjs → app-graph-serializer-V6RLEHVY.mjs} +5 -6
  8. package/dist/lib/browser/app-graph-serializer-V6RLEHVY.mjs.map +7 -0
  9. package/dist/lib/browser/{artifact-definition-XTVOUMMI.mjs → artifact-definition-5NAODQLG.mjs} +65 -17
  10. package/dist/lib/browser/artifact-definition-5NAODQLG.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-QV6ZIXAD.mjs → chunk-77NGW7EO.mjs} +6 -7
  12. package/dist/lib/browser/chunk-77NGW7EO.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-ACAID3XF.mjs +20 -0
  14. package/dist/lib/browser/chunk-ACAID3XF.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-LJ2UFBJ2.mjs → chunk-C5RABVIX.mjs} +3 -4
  16. package/dist/lib/browser/chunk-C5RABVIX.mjs.map +7 -0
  17. package/dist/lib/browser/chunk-ECSM56YC.mjs +80 -0
  18. package/dist/lib/browser/chunk-ECSM56YC.mjs.map +7 -0
  19. package/dist/lib/browser/{chunk-NAGMSX77.mjs → chunk-QVJETNGS.mjs} +2 -2
  20. package/dist/lib/{node-esm/chunk-ETXPC5VP.mjs.map → browser/chunk-QVJETNGS.mjs.map} +1 -1
  21. package/dist/lib/browser/index.mjs +31 -19
  22. package/dist/lib/browser/index.mjs.map +3 -3
  23. package/dist/lib/browser/intent-resolver-4GDYST4Y.mjs +65 -0
  24. package/dist/lib/browser/intent-resolver-4GDYST4Y.mjs.map +7 -0
  25. package/dist/lib/browser/meta.json +1 -1
  26. package/dist/lib/browser/{react-surface-LBCMSLJ5.mjs → react-surface-QE4SKXBT.mjs} +80 -66
  27. package/dist/lib/browser/react-surface-QE4SKXBT.mjs.map +7 -0
  28. package/dist/lib/browser/{settings-EQSDBX6O.mjs → settings-W5CK4PXP.mjs} +2 -2
  29. package/dist/lib/browser/{state-AIN4J7N5.mjs → state-KI6PJ6DT.mjs} +3 -3
  30. package/dist/lib/browser/state-KI6PJ6DT.mjs.map +7 -0
  31. package/dist/lib/browser/types/index.mjs +1 -1
  32. package/dist/lib/node/MarkdownContainer-LSNNPNRB.cjs +601 -0
  33. package/dist/lib/node/MarkdownContainer-LSNNPNRB.cjs.map +7 -0
  34. package/dist/lib/node/MarkdownPreview-G34HSQEB.cjs +110 -0
  35. package/dist/lib/node/MarkdownPreview-G34HSQEB.cjs.map +7 -0
  36. package/dist/lib/node/{thread-MXEGV6HS.cjs → anchor-sort-NHVF23EU.cjs} +15 -20
  37. package/dist/lib/node/anchor-sort-NHVF23EU.cjs.map +7 -0
  38. package/dist/lib/node/{app-graph-serializer-KBDLASRP.cjs → app-graph-serializer-CLALIYN3.cjs} +10 -11
  39. package/dist/lib/node/app-graph-serializer-CLALIYN3.cjs.map +7 -0
  40. package/dist/lib/node/{artifact-definition-ADEN2KD6.cjs → artifact-definition-VEAHK7BX.cjs} +68 -21
  41. package/dist/lib/node/artifact-definition-VEAHK7BX.cjs.map +7 -0
  42. package/dist/lib/node/{chunk-QRE5L6ZC.cjs → chunk-C4HR7UXE.cjs} +15 -15
  43. package/dist/lib/node/chunk-C4HR7UXE.cjs.map +7 -0
  44. package/dist/lib/node/{chunk-WGMVEPB3.cjs → chunk-G7RBJX22.cjs} +8 -9
  45. package/dist/lib/node/chunk-G7RBJX22.cjs.map +7 -0
  46. package/dist/lib/node/{chunk-DZXTXSXX.cjs → chunk-IFYSBQE5.cjs} +5 -5
  47. package/dist/lib/node/{chunk-DZXTXSXX.cjs.map → chunk-IFYSBQE5.cjs.map} +1 -1
  48. package/dist/lib/node/{chunk-YHL4JSA6.cjs → chunk-RQS4KBMG.cjs} +38 -42
  49. package/dist/lib/node/chunk-RQS4KBMG.cjs.map +7 -0
  50. package/dist/lib/node/{chunk-JO4SBK36.cjs → chunk-ZDTL47I7.cjs} +6 -7
  51. package/dist/lib/node/chunk-ZDTL47I7.cjs.map +7 -0
  52. package/dist/lib/node/index.cjs +42 -30
  53. package/dist/lib/node/index.cjs.map +3 -3
  54. package/dist/lib/node/intent-resolver-AUZVK3NZ.cjs +78 -0
  55. package/dist/lib/node/intent-resolver-AUZVK3NZ.cjs.map +7 -0
  56. package/dist/lib/node/meta.json +1 -1
  57. package/dist/lib/node/react-surface-WJZTEBYO.cjs +213 -0
  58. package/dist/lib/node/react-surface-WJZTEBYO.cjs.map +7 -0
  59. package/dist/lib/node/{settings-2JXASSLU.cjs → settings-IRKU3WPM.cjs} +6 -6
  60. package/dist/lib/node/{state-PC7IVXFP.cjs → state-KKDRAG7X.cjs} +7 -7
  61. package/dist/lib/node/state-KKDRAG7X.cjs.map +7 -0
  62. package/dist/lib/node/types/index.cjs +7 -7
  63. package/dist/lib/node/types/index.cjs.map +1 -1
  64. package/dist/lib/node-esm/MarkdownContainer-UZSLXMWO.mjs +589 -0
  65. package/dist/lib/node-esm/MarkdownContainer-UZSLXMWO.mjs.map +7 -0
  66. package/dist/lib/node-esm/MarkdownPreview-TCV7BI32.mjs +88 -0
  67. package/dist/lib/node-esm/MarkdownPreview-TCV7BI32.mjs.map +7 -0
  68. package/dist/lib/node-esm/anchor-sort-G2HLCYFK.mjs +33 -0
  69. package/dist/lib/node-esm/anchor-sort-G2HLCYFK.mjs.map +7 -0
  70. package/dist/lib/node-esm/{app-graph-serializer-67CO7ST3.mjs → app-graph-serializer-C3RNTQGM.mjs} +5 -6
  71. package/dist/lib/node-esm/app-graph-serializer-C3RNTQGM.mjs.map +7 -0
  72. package/dist/lib/node-esm/{artifact-definition-KTS5M2FW.mjs → artifact-definition-7TIJW2CO.mjs} +65 -17
  73. package/dist/lib/node-esm/artifact-definition-7TIJW2CO.mjs.map +7 -0
  74. package/dist/lib/node-esm/{chunk-4U2F4EB7.mjs → chunk-6RPARLIK.mjs} +6 -7
  75. package/dist/lib/node-esm/chunk-6RPARLIK.mjs.map +7 -0
  76. package/dist/lib/node-esm/{chunk-PALFXZBY.mjs → chunk-EIUTPXGL.mjs} +10 -10
  77. package/dist/lib/node-esm/chunk-EIUTPXGL.mjs.map +7 -0
  78. package/dist/lib/node-esm/{chunk-ETXPC5VP.mjs → chunk-JXXDCSMW.mjs} +2 -2
  79. package/dist/lib/{browser/chunk-NAGMSX77.mjs.map → node-esm/chunk-JXXDCSMW.mjs.map} +1 -1
  80. package/dist/lib/node-esm/chunk-NCMPVEXO.mjs +81 -0
  81. package/dist/lib/node-esm/chunk-NCMPVEXO.mjs.map +7 -0
  82. package/dist/lib/node-esm/{chunk-VQA6BQGT.mjs → chunk-TCFJNUAE.mjs} +3 -4
  83. package/dist/lib/node-esm/chunk-TCFJNUAE.mjs.map +7 -0
  84. package/dist/lib/node-esm/index.mjs +31 -19
  85. package/dist/lib/node-esm/index.mjs.map +3 -3
  86. package/dist/lib/node-esm/intent-resolver-FTNXUNI2.mjs +66 -0
  87. package/dist/lib/node-esm/intent-resolver-FTNXUNI2.mjs.map +7 -0
  88. package/dist/lib/node-esm/meta.json +1 -1
  89. package/dist/lib/node-esm/{react-surface-737EXAWT.mjs → react-surface-XNM3YDFB.mjs} +80 -66
  90. package/dist/lib/node-esm/react-surface-XNM3YDFB.mjs.map +7 -0
  91. package/dist/lib/node-esm/{settings-67RVIH3N.mjs → settings-MK7D7LHQ.mjs} +2 -2
  92. package/dist/lib/node-esm/{state-PNOPM4TS.mjs → state-LLGVRYKL.mjs} +3 -3
  93. package/dist/lib/node-esm/state-LLGVRYKL.mjs.map +7 -0
  94. package/dist/lib/node-esm/types/index.mjs +1 -1
  95. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  96. package/dist/types/src/capabilities/anchor-sort.d.ts +6 -0
  97. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -0
  98. package/dist/types/src/capabilities/app-graph-serializer.d.ts +2 -2
  99. package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +1 -1
  100. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  101. package/dist/types/src/capabilities/index.d.ts +7 -7
  102. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  103. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  104. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  105. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  106. package/dist/types/src/capabilities/state.d.ts +2 -2
  107. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  108. package/dist/types/src/components/MarkdownContainer.d.ts +5 -3
  109. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
  110. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +3 -18
  111. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  112. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts +2 -2
  113. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts.map +1 -1
  114. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts +4 -172
  115. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts.map +1 -1
  116. package/dist/types/src/components/MarkdownSettings/MarkdownSettings.d.ts.map +1 -1
  117. package/dist/types/src/components/Suggestions.stories.d.ts.map +1 -1
  118. package/dist/types/src/components/Toolbar.stories.d.ts.map +1 -1
  119. package/dist/types/src/components/index.d.ts +2 -2
  120. package/dist/types/src/components/index.d.ts.map +1 -1
  121. package/dist/types/src/extensions.d.ts +8 -5
  122. package/dist/types/src/extensions.d.ts.map +1 -1
  123. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -1
  124. package/dist/types/src/translations.d.ts +2 -46
  125. package/dist/types/src/translations.d.ts.map +1 -1
  126. package/dist/types/src/types/schema.d.ts +21 -525
  127. package/dist/types/src/types/schema.d.ts.map +1 -1
  128. package/dist/types/src/types/types.d.ts +40 -200
  129. package/dist/types/src/types/types.d.ts.map +1 -1
  130. package/dist/types/src/util.d.ts.map +1 -1
  131. package/dist/types/tsconfig.tsbuildinfo +1 -1
  132. package/package.json +48 -39
  133. package/src/MarkdownPlugin.tsx +19 -9
  134. package/src/capabilities/anchor-sort.ts +30 -0
  135. package/src/capabilities/app-graph-serializer.ts +4 -5
  136. package/src/capabilities/artifact-definition.ts +48 -10
  137. package/src/capabilities/index.ts +1 -1
  138. package/src/capabilities/intent-resolver.ts +29 -34
  139. package/src/capabilities/react-surface.tsx +14 -6
  140. package/src/capabilities/state.ts +3 -3
  141. package/src/components/MarkdownContainer.tsx +19 -7
  142. package/src/components/MarkdownEditor/MarkdownEditor.stories.tsx +1 -1
  143. package/src/components/MarkdownEditor/MarkdownEditor.tsx +29 -71
  144. package/src/components/MarkdownPreview/MarkdownPreview.stories.tsx +9 -4
  145. package/src/components/MarkdownPreview/MarkdownPreview.tsx +8 -8
  146. package/src/components/Suggestions.stories.tsx +53 -21
  147. package/src/components/Toolbar.stories.tsx +16 -16
  148. package/src/extensions.tsx +45 -16
  149. package/src/hooks/useSelectCurrentThread.tsx +2 -2
  150. package/src/translations.ts +1 -3
  151. package/src/types/schema.ts +19 -17
  152. package/src/types/types.ts +23 -21
  153. package/src/util.tsx +4 -4
  154. package/dist/lib/browser/MarkdownContainer-5XV7K2NX.mjs +0 -567
  155. package/dist/lib/browser/MarkdownContainer-5XV7K2NX.mjs.map +0 -7
  156. package/dist/lib/browser/MarkdownPreview-DX5U5LCX.mjs +0 -81
  157. package/dist/lib/browser/MarkdownPreview-DX5U5LCX.mjs.map +0 -7
  158. package/dist/lib/browser/app-graph-serializer-OCXP7PCK.mjs.map +0 -7
  159. package/dist/lib/browser/artifact-definition-XTVOUMMI.mjs.map +0 -7
  160. package/dist/lib/browser/chunk-5QXYEKSX.mjs +0 -20
  161. package/dist/lib/browser/chunk-5QXYEKSX.mjs.map +0 -7
  162. package/dist/lib/browser/chunk-GVOEHF7E.mjs +0 -84
  163. package/dist/lib/browser/chunk-GVOEHF7E.mjs.map +0 -7
  164. package/dist/lib/browser/chunk-LJ2UFBJ2.mjs.map +0 -7
  165. package/dist/lib/browser/chunk-QV6ZIXAD.mjs.map +0 -7
  166. package/dist/lib/browser/intent-resolver-H37L3DBD.mjs +0 -86
  167. package/dist/lib/browser/intent-resolver-H37L3DBD.mjs.map +0 -7
  168. package/dist/lib/browser/react-surface-LBCMSLJ5.mjs.map +0 -7
  169. package/dist/lib/browser/state-AIN4J7N5.mjs.map +0 -7
  170. package/dist/lib/browser/thread-MFKBUVCB.mjs +0 -37
  171. package/dist/lib/browser/thread-MFKBUVCB.mjs.map +0 -7
  172. package/dist/lib/node/MarkdownContainer-5EQTBXV3.cjs +0 -580
  173. package/dist/lib/node/MarkdownContainer-5EQTBXV3.cjs.map +0 -7
  174. package/dist/lib/node/MarkdownPreview-W7QIN2KJ.cjs +0 -104
  175. package/dist/lib/node/MarkdownPreview-W7QIN2KJ.cjs.map +0 -7
  176. package/dist/lib/node/app-graph-serializer-KBDLASRP.cjs.map +0 -7
  177. package/dist/lib/node/artifact-definition-ADEN2KD6.cjs.map +0 -7
  178. package/dist/lib/node/chunk-JO4SBK36.cjs.map +0 -7
  179. package/dist/lib/node/chunk-QRE5L6ZC.cjs.map +0 -7
  180. package/dist/lib/node/chunk-WGMVEPB3.cjs.map +0 -7
  181. package/dist/lib/node/chunk-YHL4JSA6.cjs.map +0 -7
  182. package/dist/lib/node/intent-resolver-NX5QNRYF.cjs +0 -99
  183. package/dist/lib/node/intent-resolver-NX5QNRYF.cjs.map +0 -7
  184. package/dist/lib/node/react-surface-DJIZSVMN.cjs +0 -199
  185. package/dist/lib/node/react-surface-DJIZSVMN.cjs.map +0 -7
  186. package/dist/lib/node/state-PC7IVXFP.cjs.map +0 -7
  187. package/dist/lib/node/thread-MXEGV6HS.cjs.map +0 -7
  188. package/dist/lib/node-esm/MarkdownContainer-LONZOJJX.mjs +0 -568
  189. package/dist/lib/node-esm/MarkdownContainer-LONZOJJX.mjs.map +0 -7
  190. package/dist/lib/node-esm/MarkdownPreview-T3OW2EN4.mjs +0 -82
  191. package/dist/lib/node-esm/MarkdownPreview-T3OW2EN4.mjs.map +0 -7
  192. package/dist/lib/node-esm/app-graph-serializer-67CO7ST3.mjs.map +0 -7
  193. package/dist/lib/node-esm/artifact-definition-KTS5M2FW.mjs.map +0 -7
  194. package/dist/lib/node-esm/chunk-4U2F4EB7.mjs.map +0 -7
  195. package/dist/lib/node-esm/chunk-NUZHKZSZ.mjs +0 -85
  196. package/dist/lib/node-esm/chunk-NUZHKZSZ.mjs.map +0 -7
  197. package/dist/lib/node-esm/chunk-PALFXZBY.mjs.map +0 -7
  198. package/dist/lib/node-esm/chunk-VQA6BQGT.mjs.map +0 -7
  199. package/dist/lib/node-esm/intent-resolver-XES4ZCA6.mjs +0 -87
  200. package/dist/lib/node-esm/intent-resolver-XES4ZCA6.mjs.map +0 -7
  201. package/dist/lib/node-esm/react-surface-737EXAWT.mjs.map +0 -7
  202. package/dist/lib/node-esm/state-PNOPM4TS.mjs.map +0 -7
  203. package/dist/lib/node-esm/thread-5U4KSBED.mjs +0 -38
  204. package/dist/lib/node-esm/thread-5U4KSBED.mjs.map +0 -7
  205. package/dist/types/src/capabilities/thread.d.ts +0 -6
  206. package/dist/types/src/capabilities/thread.d.ts.map +0 -1
  207. package/src/capabilities/thread.ts +0 -35
  208. /package/dist/lib/browser/{settings-EQSDBX6O.mjs.map → settings-W5CK4PXP.mjs.map} +0 -0
  209. /package/dist/lib/node/{settings-2JXASSLU.cjs.map → settings-IRKU3WPM.cjs.map} +0 -0
  210. /package/dist/lib/node-esm/{settings-67RVIH3N.mjs.map → settings-MK7D7LHQ.mjs.map} +0 -0
@@ -4,12 +4,12 @@
4
4
 
5
5
  import { lazy } from '@dxos/app-framework';
6
6
 
7
+ export const AnchorSort = lazy(() => import('./anchor-sort'));
7
8
  export const AppGraphSerializer = lazy(() => import('./app-graph-serializer'));
8
9
  export const ArtifactDefinition = lazy(() => import('./artifact-definition'));
9
10
  export const IntentResolver = lazy(() => import('./intent-resolver'));
10
11
  export const ReactSurface = lazy(() => import('./react-surface'));
11
12
  export const MarkdownSettings = lazy(() => import('./settings'));
12
13
  export const MarkdownState = lazy(() => import('./state'));
13
- export const Thread = lazy(() => import('./thread'));
14
14
 
15
15
  export * from './capabilities';
@@ -2,36 +2,32 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { next as A } from '@automerge/automerge';
6
+ import { Option, pipe, type Schema } from 'effect';
7
+
5
8
  import {
6
9
  Capabilities,
7
10
  CollaborationActions,
8
11
  contributes,
9
12
  createResolver,
10
- type PluginsContext,
13
+ type PluginContext,
11
14
  } from '@dxos/app-framework';
12
- import { next as A } from '@dxos/automerge/automerge';
13
- import { isInstanceOf, ObjectId } from '@dxos/echo-schema';
14
- import { DXN, QueueSubspaceTags } from '@dxos/keys';
15
- import { makeRef, live, refFromDXN } from '@dxos/live-object';
16
- import { log } from '@dxos/log';
17
- import { ClientCapabilities } from '@dxos/plugin-client';
18
- import { resolveRef } from '@dxos/react-client';
19
- import { createDocAccessor } from '@dxos/react-client/echo';
20
- import { TextType } from '@dxos/schema';
15
+ import { isInstanceOf } from '@dxos/echo-schema';
16
+ import { live } from '@dxos/live-object';
17
+ import { createDocAccessor, getRangeFromCursor, Ref } from '@dxos/react-client/echo';
18
+ import { DataType } from '@dxos/schema';
21
19
 
22
20
  import { MarkdownCapabilities } from './capabilities';
23
21
  import { DocumentType, MarkdownAction } from '../types';
24
22
 
25
- export default (context: PluginsContext) =>
23
+ export default (context: PluginContext) =>
26
24
  contributes(Capabilities.IntentResolver, [
27
25
  createResolver({
28
26
  intent: MarkdownAction.Create,
29
- resolve: ({ name, spaceId, content }) => {
27
+ resolve: ({ name, content }) => {
30
28
  const doc = live(DocumentType, {
31
29
  name,
32
- content: makeRef(live(TextType, { content: content ?? '' })),
33
- assistantChatQueue: refFromDXN(new DXN(DXN.kind.QUEUE, [QueueSubspaceTags.DATA, spaceId, ObjectId.random()])),
34
- threads: [],
30
+ content: Ref.make(live(DataType.Text, { content: content ?? '' })),
35
31
  });
36
32
 
37
33
  return { data: { object: doc } };
@@ -40,30 +36,29 @@ export default (context: PluginsContext) =>
40
36
  createResolver({
41
37
  intent: MarkdownAction.SetViewMode,
42
38
  resolve: ({ id, viewMode }) => {
43
- const { state } = context.requestCapability(MarkdownCapabilities.State);
39
+ const { state } = context.getCapability(MarkdownCapabilities.State);
44
40
  state.viewMode[id] = viewMode;
45
41
  },
46
42
  }),
47
- // TODO(burdon): What is the error boundary for intents? Are errors reported back to caller?
48
43
  createResolver({
49
44
  intent: CollaborationActions.InsertContent,
50
- resolve: async ({ spaceId, target: targetRef, object: objectRef, label }) => {
51
- const client = context.requestCapability(ClientCapabilities.Client);
52
- const space = client.spaces.get(spaceId);
53
- const target = await resolveRef(client, targetRef.dxn, space);
54
- if (target && isInstanceOf(DocumentType, target)) {
55
- const accessor = createDocAccessor(target, ['content']);
56
- // TODO(burdon): Should be a cursor that references a selected position.
57
- const index = 0;
58
- accessor.handle.change((doc) => {
59
- // TODO(burdon): Throws error:
60
- // intent-dispatcher.ts:270 Cannot read properties of undefined (reading 'annotations') (FiberFailure) TypeError: Cannot read properties of undefined (reading 'annotations')
61
- const ref = `[${label ?? 'Generated content'}]](${objectRef.dxn.toString()})\n`;
62
- A.splice(doc, accessor.path.slice(), index, 0, ref);
63
- });
64
- } else {
65
- log.warn('target is not a document', { targetRef, objectRef });
66
- }
45
+ filter: (
46
+ data,
47
+ ): data is Omit<Schema.Schema.Type<typeof CollaborationActions.InsertContent.fields.input>, 'target'> & {
48
+ target: DocumentType;
49
+ } => isInstanceOf(DocumentType, data.target),
50
+ resolve: async ({ target, object: objectRef, at, label }) => {
51
+ const text = await target.content.load();
52
+ const accessor = createDocAccessor(text, ['content']);
53
+ const { start, end } = pipe(
54
+ Option.fromNullable(at),
55
+ Option.flatMap((at) => Option.fromNullable(getRangeFromCursor(accessor, at))),
56
+ Option.getOrElse(() => ({ start: text.content.length - 1, end: text.content.length - 1 })),
57
+ );
58
+ accessor.handle.change((doc) => {
59
+ const ref = `[${label ?? 'Generated content'}]](${objectRef.dxn.toString()})\n`;
60
+ A.splice(doc, accessor.path.slice(), start, end - start, ref);
61
+ });
67
62
  },
68
63
  }),
69
64
  ]);
@@ -7,8 +7,9 @@ import React from 'react';
7
7
  import { createSurface, contributes, Capabilities, useCapability } from '@dxos/app-framework';
8
8
  import { isInstanceOf } from '@dxos/echo-schema';
9
9
  import { SettingsStore } from '@dxos/local-storage';
10
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
10
11
  import { fullyQualifiedId } from '@dxos/react-client/echo';
11
- import { TextType } from '@dxos/schema';
12
+ import { DataType } from '@dxos/schema';
12
13
 
13
14
  import { MarkdownCapabilities } from './capabilities';
14
15
  import { MarkdownContainer, MarkdownSettings, MarkdownPreview } from '../components';
@@ -23,9 +24,11 @@ export default () =>
23
24
  filter: (data): data is { subject: DocumentType; variant: undefined } =>
24
25
  isInstanceOf(DocumentType, data.subject) && !data.variant,
25
26
  component: ({ data, role }) => {
27
+ const selectionManager = useCapability(AttentionCapabilities.Selection);
26
28
  const settingsStore = useCapability(Capabilities.SettingsStore);
27
29
  const settings = settingsStore.getStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN)!.value;
28
30
  const { state, editorState, getViewMode, setViewMode } = useCapability(MarkdownCapabilities.State);
31
+ const viewMode = getViewMode(fullyQualifiedId(data.subject));
29
32
 
30
33
  return (
31
34
  <MarkdownContainer
@@ -33,8 +36,9 @@ export default () =>
33
36
  object={data.subject}
34
37
  role={role}
35
38
  settings={settings}
39
+ selectionManager={selectionManager}
36
40
  extensionProviders={state.extensionProviders}
37
- viewMode={getViewMode(fullyQualifiedId(data.subject))}
41
+ viewMode={viewMode}
38
42
  editorStateStore={editorState}
39
43
  onViewModeChange={setViewMode}
40
44
  />
@@ -44,9 +48,10 @@ export default () =>
44
48
  createSurface({
45
49
  id: `${MARKDOWN_PLUGIN}/text`,
46
50
  role: ['article', 'section', 'tabpanel'],
47
- filter: (data): data is { id: string; subject: TextType } =>
48
- typeof data.id === 'string' && isInstanceOf(TextType, data.subject),
51
+ filter: (data): data is { id: string; subject: DataType.Text } =>
52
+ typeof data.id === 'string' && isInstanceOf(DataType.Text, data.subject),
49
53
  component: ({ data, role }) => {
54
+ const selectionManager = useCapability(AttentionCapabilities.Selection);
50
55
  const settingsStore = useCapability(Capabilities.SettingsStore);
51
56
  const settings = settingsStore.getStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN)!.value;
52
57
  const { state, editorState, getViewMode, setViewMode } = useCapability(MarkdownCapabilities.State);
@@ -57,6 +62,7 @@ export default () =>
57
62
  object={data.subject}
58
63
  role={role}
59
64
  settings={settings}
65
+ selectionManager={selectionManager}
60
66
  extensionProviders={state.extensionProviders}
61
67
  viewMode={getViewMode(data.id)}
62
68
  editorStateStore={editorState}
@@ -70,6 +76,7 @@ export default () =>
70
76
  role: ['article', 'section'],
71
77
  filter: (data): data is { subject: { id: string; text: string } } => isEditorModel(data.subject),
72
78
  component: ({ data, role }) => {
79
+ const selectionManager = useCapability(AttentionCapabilities.Selection);
73
80
  const settingsStore = useCapability(Capabilities.SettingsStore);
74
81
  const settings = settingsStore.getStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN)!.value;
75
82
  const { state, editorState, getViewMode, setViewMode } = useCapability(MarkdownCapabilities.State);
@@ -80,6 +87,7 @@ export default () =>
80
87
  object={data.subject}
81
88
  role={role}
82
89
  settings={settings}
90
+ selectionManager={selectionManager}
83
91
  extensionProviders={state.extensionProviders}
84
92
  viewMode={getViewMode(data.subject.id)}
85
93
  editorStateStore={editorState}
@@ -98,8 +106,8 @@ export default () =>
98
106
  createSurface({
99
107
  id: `${MARKDOWN_PLUGIN}/preview`,
100
108
  role: 'popover',
101
- filter: (data): data is { subject: DocumentType | TextType } =>
102
- isInstanceOf(DocumentType, data.subject) || isInstanceOf(TextType, data.subject),
109
+ filter: (data): data is { subject: DocumentType | DataType.Text } =>
110
+ isInstanceOf(DocumentType, data.subject) || isInstanceOf(DataType.Text, data.subject),
103
111
  component: ({ data, role }) => <MarkdownPreview {...data} role={role} />,
104
112
  }),
105
113
  ]);
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
5
+ import { Capabilities, contributes, type PluginContext } from '@dxos/app-framework';
6
6
  import { LocalStorageStore } from '@dxos/local-storage';
7
7
  import { type EditorViewMode, createEditorStateStore } from '@dxos/react-ui-editor';
8
8
 
@@ -10,7 +10,7 @@ import { MarkdownCapabilities } from './capabilities';
10
10
  import { MARKDOWN_PLUGIN } from '../meta';
11
11
  import { type MarkdownPluginState, type MarkdownSettingsProps } from '../types';
12
12
 
13
- export default (context: PluginsContext) => {
13
+ export default (context: PluginContext) => {
14
14
  const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
15
15
  state.prop({ key: 'viewMode', type: LocalStorageStore.json<{ [key: string]: EditorViewMode }>() });
16
16
 
@@ -19,7 +19,7 @@ export default (context: PluginsContext) => {
19
19
 
20
20
  const getViewMode = (id: string) => {
21
21
  const defaultViewMode = context
22
- .requestCapability(Capabilities.SettingsStore)
22
+ .getCapability(Capabilities.SettingsStore)
23
23
  .getStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN)!.value.defaultViewMode;
24
24
  return (id && state.values.viewMode[id]) || defaultViewMode;
25
25
  };
@@ -2,12 +2,14 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Rx } from '@effect-rx/rx-react';
5
6
  import React, { useEffect, useMemo } from 'react';
6
7
 
7
- import { Capabilities, useCapabilities } from '@dxos/app-framework';
8
+ import { Capabilities, useAppGraph, useCapabilities } from '@dxos/app-framework';
8
9
  import { isInstanceOf } from '@dxos/echo-schema';
9
10
  import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
10
- import { TextType } from '@dxos/schema';
11
+ import { type SelectionManager } from '@dxos/react-ui-attention';
12
+ import { DataType } from '@dxos/schema';
11
13
 
12
14
  import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
13
15
  import { useExtensions } from '../extensions';
@@ -19,25 +21,26 @@ export type MarkdownContainerProps = Pick<
19
21
  'role' | 'extensionProviders' | 'viewMode' | 'editorStateStore' | 'onViewModeChange'
20
22
  > & {
21
23
  id: string;
22
- object: DocumentType | TextType | any;
24
+ object: DocumentType | DataType.Text | any;
23
25
  settings: MarkdownSettingsProps;
26
+ selectionManager?: SelectionManager;
24
27
  };
25
28
 
26
- // TODO(burdon): Move toolbar here.
27
29
  // TODO(burdon): Factor out difference for ECHO and non-ECHO objects; i.e., single component.
28
30
  const MarkdownContainer = ({
29
31
  id,
30
32
  role,
31
33
  object,
32
34
  settings,
35
+ selectionManager,
33
36
  viewMode,
34
37
  editorStateStore,
35
38
  onViewModeChange,
36
39
  }: MarkdownContainerProps) => {
37
40
  const scrollPastEnd = role === 'article';
38
41
  const doc = isInstanceOf(DocumentType, object) ? object : undefined;
39
- const text = isInstanceOf(TextType, object) ? object : undefined;
40
- const extensions = useExtensions({ document: doc, text, id, settings, viewMode, editorStateStore });
42
+ const text = isInstanceOf(DataType.Text, object) ? object : undefined;
43
+ const extensions = useExtensions({ document: doc, text, id, settings, selectionManager, viewMode, editorStateStore });
41
44
 
42
45
  if (doc) {
43
46
  return (
@@ -61,7 +64,6 @@ const MarkdownContainer = ({
61
64
  extensions={extensions}
62
65
  viewMode={viewMode}
63
66
  toolbar={settings.toolbar}
64
- comment={false}
65
67
  inputMode={settings.editorInputMode}
66
68
  scrollPastEnd={scrollPastEnd}
67
69
  onViewModeChange={onViewModeChange}
@@ -116,12 +118,22 @@ export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props
116
118
  return async (file: File) => upload!(file, space);
117
119
  }, [space, upload]);
118
120
 
121
+ const { graph } = useAppGraph();
122
+ const customActions = useMemo(() => {
123
+ return Rx.make((get) => {
124
+ const actions = get(graph.actions(id));
125
+ const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
126
+ return { nodes, edges: nodes.map((node) => ({ source: 'root', target: node.id })) };
127
+ });
128
+ }, [graph]);
129
+
119
130
  return (
120
131
  <MarkdownEditor
121
132
  id={id}
122
133
  initialValue={doc.content?.target?.content}
123
134
  viewMode={viewMode}
124
135
  toolbar={settings.toolbar}
136
+ customActions={customActions}
125
137
  inputMode={settings.editorInputMode}
126
138
  onFileUpload={handleFileUpload}
127
139
  {...props}
@@ -36,7 +36,7 @@ const meta: Meta<typeof MarkdownEditor> = {
36
36
  render: DefaultStory,
37
37
  decorators: [
38
38
  withTheme,
39
- withLayout({ tooltips: true, fullscreen: true }),
39
+ withLayout({ fullscreen: true }),
40
40
  withAttention,
41
41
  withPluginManager({ plugins: [IntentPlugin()] }),
42
42
  ],
@@ -2,17 +2,15 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { openSearchPanel } from '@codemirror/search';
6
5
  import { type EditorView } from '@codemirror/view';
7
6
  import React, { useMemo, useEffect, useCallback } from 'react';
8
7
  import { useDropzone } from 'react-dropzone';
9
8
 
10
- import { createIntent, type FileInfo, useIntentDispatcher } from '@dxos/app-framework';
11
- import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
9
+ import { type FileInfo } from '@dxos/app-framework';
10
+ import { invariant } from '@dxos/invariant';
12
11
  import { useThemeContext, useTranslation } from '@dxos/react-ui';
13
12
  import {
14
13
  type DNDOptions,
15
- type EditorAction,
16
14
  type EditorViewMode,
17
15
  type EditorInputMode,
18
16
  type EditorSelectionState,
@@ -20,20 +18,18 @@ import {
20
18
  EditorToolbar,
21
19
  type UseTextEditorProps,
22
20
  createBasicExtensions,
23
- createEditorAction,
24
21
  createMarkdownExtensions,
25
22
  createThemeExtensions,
26
23
  dropFile,
27
- editorContent,
24
+ editorSlots,
28
25
  editorGutter,
29
26
  processEditorPayload,
30
27
  stackItemContentEditorClassNames,
31
- useActionHandler,
32
- useCommentState,
33
- useCommentClickListener,
34
28
  useFormattingState,
35
29
  useTextEditor,
36
30
  useEditorToolbarState,
31
+ addLink,
32
+ type EditorToolbarActionGraphProps,
37
33
  } from '@dxos/react-ui-editor';
38
34
  import { StackItem } from '@dxos/react-ui-stack';
39
35
  import { isNotFalsy, isNonNullable } from '@dxos/util';
@@ -48,8 +44,8 @@ export type MarkdownEditorProps = {
48
44
  inputMode?: EditorInputMode;
49
45
  scrollPastEnd?: boolean;
50
46
  toolbar?: boolean;
47
+ customActions?: EditorToolbarActionGraphProps['customActions'];
51
48
  // TODO(wittjosiah): Generalize custom toolbar actions (e.g. comment, upload, etc.)
52
- comment?: boolean;
53
49
  viewMode?: EditorViewMode;
54
50
  editorStateStore?: EditorStateStore;
55
51
  onViewModeChange?: (id: string, mode: EditorViewMode) => void;
@@ -71,7 +67,7 @@ export const MarkdownEditor = ({
71
67
  extensionProviders,
72
68
  scrollPastEnd,
73
69
  toolbar,
74
- comment = true,
70
+ customActions,
75
71
  viewMode,
76
72
  editorStateStore,
77
73
  onFileUpload,
@@ -79,7 +75,6 @@ export const MarkdownEditor = ({
79
75
  }: MarkdownEditorProps) => {
80
76
  const { t } = useTranslation(MARKDOWN_PLUGIN);
81
77
  const { themeMode } = useThemeContext();
82
- const { dispatchPromise: dispatch } = useIntentDispatcher();
83
78
  const toolbarState = useEditorToolbarState({ viewMode });
84
79
  const formattingObserver = useFormattingState(toolbarState);
85
80
 
@@ -93,18 +88,6 @@ export const MarkdownEditor = ({
93
88
  [extensionProviders],
94
89
  );
95
90
 
96
- // TODO(Zan): Factor out to thread plugin.
97
- const commentObserver = useCommentState(toolbarState);
98
- const onCommentClick = useCallback(async () => {
99
- await dispatch(
100
- createIntent(DeckAction.ChangeCompanion, {
101
- primary: id,
102
- companion: `${id}${ATTENDABLE_PATH_SEPARATOR}comments`,
103
- }),
104
- );
105
- }, [dispatch]);
106
- const commentClickObserver = useCommentClickListener(onCommentClick);
107
-
108
91
  // TODO(wittjosiah): Factor out to file uploader plugin.
109
92
  // Drag files.
110
93
  const handleDrop: DNDOptions['onDrop'] = async (view, { files }) => {
@@ -124,19 +107,13 @@ export const MarkdownEditor = ({
124
107
  initialValue,
125
108
  extensions: [
126
109
  formattingObserver,
127
- comment && commentObserver,
128
- comment && commentClickObserver,
129
110
  createBasicExtensions({
130
111
  readOnly: viewMode === 'readonly',
131
112
  placeholder: t('editor placeholder'),
132
113
  scrollPastEnd: role === 'section' ? false : scrollPastEnd,
133
114
  }),
134
115
  createMarkdownExtensions({ themeMode }),
135
- createThemeExtensions({
136
- themeMode,
137
- syntaxHighlighting: true,
138
- slots: { content: { className: editorContent } },
139
- }),
116
+ createThemeExtensions({ themeMode, syntaxHighlighting: true, slots: editorSlots }),
140
117
  editorGutter,
141
118
  role !== 'section' && onFileUpload && dropFile({ onDrop: handleDrop }),
142
119
  providerExtensions,
@@ -151,7 +128,7 @@ export const MarkdownEditor = ({
151
128
  moveToEndOfLine: true,
152
129
  }),
153
130
  }),
154
- [id, formattingObserver, comment, viewMode, themeMode, extensions, providerExtensions],
131
+ [id, formattingObserver, viewMode, themeMode, extensions, providerExtensions],
155
132
  );
156
133
 
157
134
  useTest(editorView);
@@ -178,49 +155,40 @@ export const MarkdownEditor = ({
178
155
 
179
156
  const info = await onFileUpload(file);
180
157
  if (info) {
181
- processEditorPayload(editorView, { type: 'image', data: info.url });
158
+ addLink({ url: info.url, image: true })(editorView);
182
159
  }
183
160
  });
184
161
  }
185
- }, [acceptedFiles, editorView]);
162
+ }, [acceptedFiles, editorView, onFileUpload]);
186
163
 
187
- // Toolbar handler.
188
- const handleToolbarAction = useActionHandler(editorView);
189
- const handleAction = useCallback(
190
- (action: EditorAction) => {
191
- switch (action.properties.type) {
192
- case 'search': {
193
- if (editorView) {
194
- openSearchPanel(editorView);
195
- }
196
- return;
197
- }
198
- case 'view-mode': {
199
- onViewModeChange?.(id, action.properties.data);
200
- return;
201
- }
202
- case 'image': {
203
- open();
204
- return;
205
- }
206
- }
164
+ const getView = useCallback(() => {
165
+ invariant(editorView);
166
+ return editorView;
167
+ }, [editorView]);
207
168
 
208
- handleToolbarAction?.(action);
209
- },
210
- [editorView, onViewModeChange, open],
169
+ const handleViewModeChange = useCallback(
170
+ (mode: EditorViewMode) => onViewModeChange?.(id, mode),
171
+ [id, onViewModeChange],
211
172
  );
212
173
 
174
+ const handleImageUpload = useCallback(() => {
175
+ if (onFileUpload) {
176
+ open();
177
+ }
178
+ }, [onFileUpload]);
179
+
213
180
  return (
214
- <StackItem.Content toolbar={!!toolbar} classNames='is-full min-bs-0'>
181
+ <StackItem.Content toolbar={!!toolbar}>
215
182
  {toolbar && (
216
183
  <>
217
184
  <EditorToolbar
218
185
  attendableId={id}
219
186
  role={role}
220
187
  state={toolbarState}
221
- comment={comment}
222
- customActions={onFileUpload ? createUploadAction : undefined}
223
- onAction={handleAction}
188
+ customActions={customActions}
189
+ getView={getView}
190
+ image={handleImageUpload}
191
+ viewMode={handleViewModeChange}
224
192
  />
225
193
  <input {...getInputProps()} />
226
194
  </>
@@ -248,13 +216,3 @@ const useTest = (view?: EditorView) => {
248
216
  }
249
217
  }, [view]);
250
218
  };
251
-
252
- export const createUploadAction = () => ({
253
- nodes: [
254
- createEditorAction({ type: 'image', testId: 'editor.toolbar.image' }, 'ph--image-square--regular', [
255
- 'upload image label',
256
- { ns: MARKDOWN_PLUGIN },
257
- ]),
258
- ],
259
- edges: [{ source: 'root', target: 'image' }],
260
- });
@@ -14,7 +14,7 @@ import { DocumentType } from '@dxos/plugin-markdown/types';
14
14
  import { faker } from '@dxos/random';
15
15
  import { makeRef } from '@dxos/react-client/echo';
16
16
  import { Icon, Popover } from '@dxos/react-ui';
17
- import { TextType } from '@dxos/schema';
17
+ import { DataType } from '@dxos/schema';
18
18
  import { withTheme, withLayout } from '@dxos/storybook-utils';
19
19
 
20
20
  import { MarkdownPreview } from './MarkdownPreview';
@@ -38,7 +38,13 @@ const meta: Meta<typeof MarkdownPreview> = {
38
38
  </Popover.Root>
39
39
  );
40
40
  },
41
- decorators: [withPluginManager({ plugins: [IntentPlugin()] }), withTheme, withLayout({ tooltips: true })],
41
+ decorators: [
42
+ withPluginManager({
43
+ plugins: [IntentPlugin()],
44
+ }),
45
+ withTheme,
46
+ withLayout(),
47
+ ],
42
48
  parameters: {
43
49
  layout: 'centered',
44
50
  translations,
@@ -51,11 +57,10 @@ const data = (() => {
51
57
  const document = create(DocumentType, {
52
58
  name: faker.lorem.words(3),
53
59
  content: makeRef(
54
- create(TextType, {
60
+ create(DataType.Text, {
55
61
  content: faker.lorem.paragraphs(3),
56
62
  }),
57
63
  ),
58
- threads: [],
59
64
  });
60
65
 
61
66
  return { document };
@@ -9,41 +9,41 @@ import { chain, createIntent, LayoutAction, useIntentDispatcher } from '@dxos/ap
9
9
  import { isInstanceOf } from '@dxos/echo-schema';
10
10
  import {
11
11
  type PreviewProps,
12
+ defaultCard,
13
+ kanbanCardWithoutPoster,
12
14
  popoverCard,
13
15
  previewTitle,
14
16
  previewProse,
15
17
  previewChrome,
16
- defaultCard,
17
- kanbanCardWithoutPoster,
18
18
  } from '@dxos/plugin-preview';
19
19
  import { fullyQualifiedId } from '@dxos/react-client/echo';
20
20
  import { Button, Icon, useTranslation } from '@dxos/react-ui';
21
21
  import { mx } from '@dxos/react-ui-theme';
22
- import { TextType } from '@dxos/schema';
22
+ import { DataType } from '@dxos/schema';
23
23
 
24
24
  import { MARKDOWN_PLUGIN } from '../../meta';
25
25
  import { DocumentType } from '../../types';
26
26
  import { getAbstract, getFallbackName } from '../../util';
27
27
 
28
28
  // TODO(burdon): Factor out.
29
- const getTitle = (subject: DocumentType | TextType, fallback: string) => {
29
+ const getTitle = (subject: DocumentType | DataType.Text, fallback: string) => {
30
30
  if (isInstanceOf(DocumentType, subject)) {
31
31
  return subject.name ?? subject.fallbackName ?? getFallbackName(subject.content?.target?.content ?? fallback);
32
- } else if (isInstanceOf(TextType, subject)) {
32
+ } else if (isInstanceOf(DataType.Text, subject)) {
33
33
  return getFallbackName(subject.content);
34
34
  }
35
35
  };
36
36
 
37
37
  // TODO(burdon): Factor out.
38
- const getSnippet = (subject: DocumentType | TextType, fallback: string) => {
38
+ const getSnippet = (subject: DocumentType | DataType.Text, fallback: string) => {
39
39
  if (isInstanceOf(DocumentType, subject)) {
40
40
  return getAbstract(subject.content?.target?.content ?? fallback);
41
- } else if (isInstanceOf(TextType, subject)) {
41
+ } else if (isInstanceOf(DataType.Text, subject)) {
42
42
  return getAbstract(subject.content);
43
43
  }
44
44
  };
45
45
 
46
- export const MarkdownPreview = ({ classNames, subject, role }: PreviewProps<DocumentType | TextType>) => {
46
+ export const MarkdownPreview = ({ classNames, subject, role }: PreviewProps<DocumentType | DataType.Text>) => {
47
47
  const { dispatchPromise: dispatch } = useIntentDispatcher();
48
48
  const { t } = useTranslation(MARKDOWN_PLUGIN);
49
49
  const snippet = getSnippet(subject, t('fallback abstract'));