@dxos/plugin-markdown 0.8.2-staging.7ac8446 → 0.8.2

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 (227) 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-NOXI4IQ5.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-CE6J6NY4.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-3ULJ4FIJ.mjs → chunk-77NGW7EO.mjs} +12 -26
  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-QXDKFACU.mjs → chunk-C5RABVIX.mjs} +6 -5
  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 +34 -18
  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-QE4SKXBT.mjs +200 -0
  27. package/dist/lib/browser/react-surface-QE4SKXBT.mjs.map +7 -0
  28. package/dist/lib/browser/{settings-GCSS3Y4Z.mjs → settings-W5CK4PXP.mjs} +4 -4
  29. package/dist/lib/browser/settings-W5CK4PXP.mjs.map +7 -0
  30. package/dist/lib/browser/{state-O7P5JDIH.mjs → state-KI6PJ6DT.mjs} +3 -3
  31. package/dist/lib/browser/state-KI6PJ6DT.mjs.map +7 -0
  32. package/dist/lib/browser/types/index.mjs +3 -1
  33. package/dist/lib/node/MarkdownContainer-LSNNPNRB.cjs +601 -0
  34. package/dist/lib/node/MarkdownContainer-LSNNPNRB.cjs.map +7 -0
  35. package/dist/lib/node/MarkdownPreview-G34HSQEB.cjs +110 -0
  36. package/dist/lib/node/MarkdownPreview-G34HSQEB.cjs.map +7 -0
  37. package/dist/lib/node/{thread-42R57L4K.cjs → anchor-sort-NHVF23EU.cjs} +15 -20
  38. package/dist/lib/node/anchor-sort-NHVF23EU.cjs.map +7 -0
  39. package/dist/lib/node/{app-graph-serializer-HKK3SEDN.cjs → app-graph-serializer-CLALIYN3.cjs} +10 -11
  40. package/dist/lib/node/app-graph-serializer-CLALIYN3.cjs.map +7 -0
  41. package/dist/lib/node/{artifact-definition-XGADFWCQ.cjs → artifact-definition-VEAHK7BX.cjs} +68 -21
  42. package/dist/lib/node/artifact-definition-VEAHK7BX.cjs.map +7 -0
  43. package/dist/lib/node/chunk-C4HR7UXE.cjs +58 -0
  44. package/dist/lib/node/chunk-C4HR7UXE.cjs.map +7 -0
  45. package/dist/lib/node/{chunk-7QVONRSI.cjs → chunk-G7RBJX22.cjs} +13 -41
  46. package/dist/lib/node/chunk-G7RBJX22.cjs.map +7 -0
  47. package/dist/lib/node/{chunk-DZXTXSXX.cjs → chunk-IFYSBQE5.cjs} +5 -5
  48. package/dist/lib/node/{chunk-DZXTXSXX.cjs.map → chunk-IFYSBQE5.cjs.map} +1 -1
  49. package/dist/lib/node/{chunk-UEXGNGSS.cjs → chunk-RQS4KBMG.cjs} +45 -39
  50. package/dist/lib/node/chunk-RQS4KBMG.cjs.map +7 -0
  51. package/dist/lib/node/{chunk-H5MYVP6F.cjs → chunk-ZDTL47I7.cjs} +9 -8
  52. package/dist/lib/node/chunk-ZDTL47I7.cjs.map +7 -0
  53. package/dist/lib/node/index.cjs +43 -28
  54. package/dist/lib/node/index.cjs.map +3 -3
  55. package/dist/lib/node/intent-resolver-AUZVK3NZ.cjs +78 -0
  56. package/dist/lib/node/intent-resolver-AUZVK3NZ.cjs.map +7 -0
  57. package/dist/lib/node/meta.json +1 -1
  58. package/dist/lib/node/react-surface-WJZTEBYO.cjs +213 -0
  59. package/dist/lib/node/react-surface-WJZTEBYO.cjs.map +7 -0
  60. package/dist/lib/node/{settings-S2ISUVIH.cjs → settings-IRKU3WPM.cjs} +7 -7
  61. package/dist/lib/node/settings-IRKU3WPM.cjs.map +7 -0
  62. package/dist/lib/node/{state-L44SG3ZM.cjs → state-KKDRAG7X.cjs} +7 -7
  63. package/dist/lib/node/state-KKDRAG7X.cjs.map +7 -0
  64. package/dist/lib/node/types/index.cjs +8 -6
  65. package/dist/lib/node/types/index.cjs.map +2 -2
  66. package/dist/lib/node-esm/MarkdownContainer-UZSLXMWO.mjs +589 -0
  67. package/dist/lib/node-esm/MarkdownContainer-UZSLXMWO.mjs.map +7 -0
  68. package/dist/lib/node-esm/MarkdownPreview-TCV7BI32.mjs +88 -0
  69. package/dist/lib/node-esm/MarkdownPreview-TCV7BI32.mjs.map +7 -0
  70. package/dist/lib/node-esm/anchor-sort-G2HLCYFK.mjs +33 -0
  71. package/dist/lib/node-esm/anchor-sort-G2HLCYFK.mjs.map +7 -0
  72. package/dist/lib/node-esm/{app-graph-serializer-QQ2CTHOQ.mjs → app-graph-serializer-C3RNTQGM.mjs} +5 -6
  73. package/dist/lib/node-esm/app-graph-serializer-C3RNTQGM.mjs.map +7 -0
  74. package/dist/lib/node-esm/{artifact-definition-WRG5ZRN5.mjs → artifact-definition-7TIJW2CO.mjs} +65 -17
  75. package/dist/lib/node-esm/artifact-definition-7TIJW2CO.mjs.map +7 -0
  76. package/dist/lib/node-esm/{chunk-F6UHVLH7.mjs → chunk-6RPARLIK.mjs} +12 -26
  77. package/dist/lib/node-esm/chunk-6RPARLIK.mjs.map +7 -0
  78. package/dist/lib/node-esm/chunk-EIUTPXGL.mjs +22 -0
  79. package/dist/lib/node-esm/chunk-EIUTPXGL.mjs.map +7 -0
  80. package/dist/lib/node-esm/{chunk-ETXPC5VP.mjs → chunk-JXXDCSMW.mjs} +2 -2
  81. package/dist/lib/{browser/chunk-NAGMSX77.mjs.map → node-esm/chunk-JXXDCSMW.mjs.map} +1 -1
  82. package/dist/lib/node-esm/chunk-NCMPVEXO.mjs +81 -0
  83. package/dist/lib/node-esm/chunk-NCMPVEXO.mjs.map +7 -0
  84. package/dist/lib/node-esm/{chunk-JAVD67QP.mjs → chunk-TCFJNUAE.mjs} +6 -5
  85. package/dist/lib/node-esm/chunk-TCFJNUAE.mjs.map +7 -0
  86. package/dist/lib/node-esm/index.mjs +34 -18
  87. package/dist/lib/node-esm/index.mjs.map +3 -3
  88. package/dist/lib/node-esm/intent-resolver-FTNXUNI2.mjs +66 -0
  89. package/dist/lib/node-esm/intent-resolver-FTNXUNI2.mjs.map +7 -0
  90. package/dist/lib/node-esm/meta.json +1 -1
  91. package/dist/lib/node-esm/react-surface-XNM3YDFB.mjs +201 -0
  92. package/dist/lib/node-esm/react-surface-XNM3YDFB.mjs.map +7 -0
  93. package/dist/lib/node-esm/{settings-ZDIFTK4N.mjs → settings-MK7D7LHQ.mjs} +4 -4
  94. package/dist/lib/node-esm/settings-MK7D7LHQ.mjs.map +7 -0
  95. package/dist/lib/node-esm/{state-DWPOKLEY.mjs → state-LLGVRYKL.mjs} +3 -3
  96. package/dist/lib/node-esm/state-LLGVRYKL.mjs.map +7 -0
  97. package/dist/lib/node-esm/types/index.mjs +3 -1
  98. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  99. package/dist/types/src/capabilities/anchor-sort.d.ts +6 -0
  100. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/app-graph-serializer.d.ts +2 -2
  102. package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +1 -1
  103. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  104. package/dist/types/src/capabilities/index.d.ts +7 -7
  105. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  106. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  107. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  108. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  109. package/dist/types/src/capabilities/state.d.ts +2 -2
  110. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  111. package/dist/types/src/components/MarkdownContainer.d.ts +5 -3
  112. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
  113. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +24 -0
  114. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -0
  115. package/dist/types/src/components/{MarkdownEditor.stories.d.ts → MarkdownEditor/MarkdownEditor.stories.d.ts} +3 -3
  116. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts.map +1 -0
  117. package/dist/types/src/components/MarkdownEditor/index.d.ts +2 -0
  118. package/dist/types/src/components/MarkdownEditor/index.d.ts.map +1 -0
  119. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts +6 -0
  120. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts.map +1 -0
  121. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts +23 -0
  122. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts.map +1 -0
  123. package/dist/types/src/components/MarkdownPreview/index.d.ts +4 -0
  124. package/dist/types/src/components/MarkdownPreview/index.d.ts.map +1 -0
  125. package/dist/types/src/components/{MarkdownSettings.d.ts → MarkdownSettings/MarkdownSettings.d.ts} +1 -1
  126. package/dist/types/src/components/MarkdownSettings/MarkdownSettings.d.ts.map +1 -0
  127. package/dist/types/src/components/MarkdownSettings/index.d.ts +2 -0
  128. package/dist/types/src/components/MarkdownSettings/index.d.ts.map +1 -0
  129. package/dist/types/src/components/Suggestions.stories.d.ts +12 -0
  130. package/dist/types/src/components/Suggestions.stories.d.ts.map +1 -0
  131. package/dist/types/src/components/Toolbar.stories.d.ts +2 -2
  132. package/dist/types/src/components/Toolbar.stories.d.ts.map +1 -1
  133. package/dist/types/src/components/index.d.ts +2 -1
  134. package/dist/types/src/components/index.d.ts.map +1 -1
  135. package/dist/types/src/extensions.d.ts +8 -5
  136. package/dist/types/src/extensions.d.ts.map +1 -1
  137. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -1
  138. package/dist/types/src/translations.d.ts +4 -42
  139. package/dist/types/src/translations.d.ts.map +1 -1
  140. package/dist/types/src/types/schema.d.ts +29 -129
  141. package/dist/types/src/types/schema.d.ts.map +1 -1
  142. package/dist/types/src/types/types.d.ts +40 -88
  143. package/dist/types/src/types/types.d.ts.map +1 -1
  144. package/dist/types/src/util.d.ts +1 -0
  145. package/dist/types/src/util.d.ts.map +1 -1
  146. package/dist/types/tsconfig.tsbuildinfo +1 -1
  147. package/package.json +48 -34
  148. package/src/MarkdownPlugin.tsx +22 -12
  149. package/src/capabilities/anchor-sort.ts +30 -0
  150. package/src/capabilities/app-graph-serializer.ts +4 -5
  151. package/src/capabilities/artifact-definition.ts +48 -10
  152. package/src/capabilities/index.ts +1 -1
  153. package/src/capabilities/intent-resolver.ts +40 -12
  154. package/src/capabilities/react-surface.tsx +20 -5
  155. package/src/capabilities/settings.ts +2 -2
  156. package/src/capabilities/state.ts +4 -4
  157. package/src/components/MarkdownContainer.tsx +20 -7
  158. package/src/components/{MarkdownEditor.stories.tsx → MarkdownEditor/MarkdownEditor.stories.tsx} +22 -35
  159. package/src/components/{MarkdownEditor.tsx → MarkdownEditor/MarkdownEditor.tsx} +32 -73
  160. package/src/components/MarkdownEditor/index.ts +5 -0
  161. package/src/components/MarkdownPreview/MarkdownPreview.stories.tsx +73 -0
  162. package/src/components/MarkdownPreview/MarkdownPreview.tsx +85 -0
  163. package/src/components/MarkdownPreview/index.ts +9 -0
  164. package/src/components/{MarkdownSettings.tsx → MarkdownSettings/MarkdownSettings.tsx} +2 -2
  165. package/src/components/MarkdownSettings/index.ts +5 -0
  166. package/src/components/Suggestions.stories.tsx +216 -0
  167. package/src/components/Toolbar.stories.tsx +29 -29
  168. package/src/components/index.ts +1 -0
  169. package/src/extensions.tsx +82 -48
  170. package/src/hooks/useSelectCurrentThread.tsx +2 -2
  171. package/src/translations.ts +3 -3
  172. package/src/types/schema.ts +22 -15
  173. package/src/types/types.ts +23 -21
  174. package/src/util.tsx +8 -4
  175. package/dist/lib/browser/MarkdownContainer-T3HU27RE.mjs +0 -563
  176. package/dist/lib/browser/MarkdownContainer-T3HU27RE.mjs.map +0 -7
  177. package/dist/lib/browser/app-graph-serializer-NOXI4IQ5.mjs.map +0 -7
  178. package/dist/lib/browser/artifact-definition-CE6J6NY4.mjs.map +0 -7
  179. package/dist/lib/browser/chunk-3ULJ4FIJ.mjs.map +0 -7
  180. package/dist/lib/browser/chunk-QXDKFACU.mjs.map +0 -7
  181. package/dist/lib/browser/chunk-YCJNW2RU.mjs +0 -75
  182. package/dist/lib/browser/chunk-YCJNW2RU.mjs.map +0 -7
  183. package/dist/lib/browser/intent-resolver-42GQ6HNZ.mjs +0 -50
  184. package/dist/lib/browser/intent-resolver-42GQ6HNZ.mjs.map +0 -7
  185. package/dist/lib/browser/react-surface-RQX3CPFV.mjs +0 -176
  186. package/dist/lib/browser/react-surface-RQX3CPFV.mjs.map +0 -7
  187. package/dist/lib/browser/settings-GCSS3Y4Z.mjs.map +0 -7
  188. package/dist/lib/browser/state-O7P5JDIH.mjs.map +0 -7
  189. package/dist/lib/browser/thread-3QGCFNVZ.mjs +0 -37
  190. package/dist/lib/browser/thread-3QGCFNVZ.mjs.map +0 -7
  191. package/dist/lib/node/MarkdownContainer-6ZJIFAP6.cjs +0 -576
  192. package/dist/lib/node/MarkdownContainer-6ZJIFAP6.cjs.map +0 -7
  193. package/dist/lib/node/app-graph-serializer-HKK3SEDN.cjs.map +0 -7
  194. package/dist/lib/node/artifact-definition-XGADFWCQ.cjs.map +0 -7
  195. package/dist/lib/node/chunk-7QVONRSI.cjs.map +0 -7
  196. package/dist/lib/node/chunk-H5MYVP6F.cjs.map +0 -7
  197. package/dist/lib/node/chunk-UEXGNGSS.cjs.map +0 -7
  198. package/dist/lib/node/intent-resolver-NW27BF3W.cjs +0 -63
  199. package/dist/lib/node/intent-resolver-NW27BF3W.cjs.map +0 -7
  200. package/dist/lib/node/react-surface-5X3SMHGI.cjs +0 -189
  201. package/dist/lib/node/react-surface-5X3SMHGI.cjs.map +0 -7
  202. package/dist/lib/node/settings-S2ISUVIH.cjs.map +0 -7
  203. package/dist/lib/node/state-L44SG3ZM.cjs.map +0 -7
  204. package/dist/lib/node/thread-42R57L4K.cjs.map +0 -7
  205. package/dist/lib/node-esm/MarkdownContainer-URAPTO37.mjs +0 -564
  206. package/dist/lib/node-esm/MarkdownContainer-URAPTO37.mjs.map +0 -7
  207. package/dist/lib/node-esm/app-graph-serializer-QQ2CTHOQ.mjs.map +0 -7
  208. package/dist/lib/node-esm/artifact-definition-WRG5ZRN5.mjs.map +0 -7
  209. package/dist/lib/node-esm/chunk-4AM4VU3Y.mjs +0 -76
  210. package/dist/lib/node-esm/chunk-4AM4VU3Y.mjs.map +0 -7
  211. package/dist/lib/node-esm/chunk-F6UHVLH7.mjs.map +0 -7
  212. package/dist/lib/node-esm/chunk-JAVD67QP.mjs.map +0 -7
  213. package/dist/lib/node-esm/intent-resolver-7HOMUVHR.mjs +0 -51
  214. package/dist/lib/node-esm/intent-resolver-7HOMUVHR.mjs.map +0 -7
  215. package/dist/lib/node-esm/react-surface-6IKC3G46.mjs +0 -177
  216. package/dist/lib/node-esm/react-surface-6IKC3G46.mjs.map +0 -7
  217. package/dist/lib/node-esm/settings-ZDIFTK4N.mjs.map +0 -7
  218. package/dist/lib/node-esm/state-DWPOKLEY.mjs.map +0 -7
  219. package/dist/lib/node-esm/thread-R2KHZD6V.mjs +0 -38
  220. package/dist/lib/node-esm/thread-R2KHZD6V.mjs.map +0 -7
  221. package/dist/types/src/capabilities/thread.d.ts +0 -6
  222. package/dist/types/src/capabilities/thread.d.ts.map +0 -1
  223. package/dist/types/src/components/MarkdownEditor.d.ts +0 -39
  224. package/dist/types/src/components/MarkdownEditor.d.ts.map +0 -1
  225. package/dist/types/src/components/MarkdownEditor.stories.d.ts.map +0 -1
  226. package/dist/types/src/components/MarkdownSettings.d.ts.map +0 -1
  227. package/src/capabilities/thread.ts +0 -35
@@ -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,27 +18,25 @@ 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';
40
36
 
41
- import { useSelectCurrentThread } from '../hooks';
42
- import { MARKDOWN_PLUGIN } from '../meta';
43
- import { type MarkdownPluginState } from '../types';
37
+ import { useSelectCurrentThread } from '../../hooks';
38
+ import { MARKDOWN_PLUGIN } from '../../meta';
39
+ import { type MarkdownPluginState } from '../../types';
44
40
 
45
41
  export type MarkdownEditorProps = {
46
42
  id: string;
@@ -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,38 +155,28 @@ 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
181
  <StackItem.Content toolbar={!!toolbar}>
215
182
  {toolbar && (
@@ -218,9 +185,10 @@ export const MarkdownEditor = ({
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
  </>
@@ -231,6 +199,7 @@ export const MarkdownEditor = ({
231
199
  data-testid='composer.markdownRoot'
232
200
  data-toolbar={toolbar ? 'enabled' : 'disabled'}
233
201
  className={stackItemContentEditorClassNames(role)}
202
+ data-popover-collision-boundary={true}
234
203
  {...focusAttributes}
235
204
  />
236
205
  </StackItem.Content>
@@ -247,13 +216,3 @@ const useTest = (view?: EditorView) => {
247
216
  }
248
217
  }, [view]);
249
218
  };
250
-
251
- export const createUploadAction = () => ({
252
- nodes: [
253
- createEditorAction({ type: 'image', testId: 'editor.toolbar.image' }, 'ph--image-square--regular', [
254
- 'upload image label',
255
- { ns: MARKDOWN_PLUGIN },
256
- ]),
257
- ],
258
- edges: [{ source: 'root', target: 'image' }],
259
- });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './MarkdownEditor';
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta } from '@storybook/react';
8
+ import React from 'react';
9
+
10
+ import { IntentPlugin } from '@dxos/app-framework';
11
+ import { withPluginManager } from '@dxos/app-framework/testing';
12
+ import { create } from '@dxos/echo-schema';
13
+ import { DocumentType } from '@dxos/plugin-markdown/types';
14
+ import { faker } from '@dxos/random';
15
+ import { makeRef } from '@dxos/react-client/echo';
16
+ import { Icon, Popover } from '@dxos/react-ui';
17
+ import { DataType } from '@dxos/schema';
18
+ import { withTheme, withLayout } from '@dxos/storybook-utils';
19
+
20
+ import { MarkdownPreview } from './MarkdownPreview';
21
+ import translations from '../../translations';
22
+
23
+ faker.seed(1234);
24
+
25
+ const meta: Meta<typeof MarkdownPreview> = {
26
+ title: 'plugins/plugin-markdown/MarkdownPreview',
27
+ component: MarkdownPreview,
28
+ render: ({ subject }) => {
29
+ return (
30
+ <Popover.Root open>
31
+ <Popover.Content>
32
+ <MarkdownPreview subject={subject} role='popover' />
33
+ <Popover.Arrow />
34
+ </Popover.Content>
35
+ <Popover.Trigger>
36
+ <Icon icon='ph--text-aa--regular' size={5} />
37
+ </Popover.Trigger>
38
+ </Popover.Root>
39
+ );
40
+ },
41
+ decorators: [
42
+ withPluginManager({
43
+ plugins: [IntentPlugin()],
44
+ }),
45
+ withTheme,
46
+ withLayout(),
47
+ ],
48
+ parameters: {
49
+ layout: 'centered',
50
+ translations,
51
+ },
52
+ };
53
+
54
+ export default meta;
55
+
56
+ const data = (() => {
57
+ const document = create(DocumentType, {
58
+ name: faker.lorem.words(3),
59
+ content: makeRef(
60
+ create(DataType.Text, {
61
+ content: faker.lorem.paragraphs(3),
62
+ }),
63
+ ),
64
+ });
65
+
66
+ return { document };
67
+ })();
68
+
69
+ export const Default = {
70
+ args: {
71
+ subject: create(DocumentType, data.document),
72
+ },
73
+ };
@@ -0,0 +1,85 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { pipe } from 'effect';
6
+ import React, { useCallback } from 'react';
7
+
8
+ import { chain, createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { isInstanceOf } from '@dxos/echo-schema';
10
+ import {
11
+ type PreviewProps,
12
+ defaultCard,
13
+ kanbanCardWithoutPoster,
14
+ popoverCard,
15
+ previewTitle,
16
+ previewProse,
17
+ previewChrome,
18
+ } from '@dxos/plugin-preview';
19
+ import { fullyQualifiedId } from '@dxos/react-client/echo';
20
+ import { Button, Icon, useTranslation } from '@dxos/react-ui';
21
+ import { mx } from '@dxos/react-ui-theme';
22
+ import { DataType } from '@dxos/schema';
23
+
24
+ import { MARKDOWN_PLUGIN } from '../../meta';
25
+ import { DocumentType } from '../../types';
26
+ import { getAbstract, getFallbackName } from '../../util';
27
+
28
+ // TODO(burdon): Factor out.
29
+ const getTitle = (subject: DocumentType | DataType.Text, fallback: string) => {
30
+ if (isInstanceOf(DocumentType, subject)) {
31
+ return subject.name ?? subject.fallbackName ?? getFallbackName(subject.content?.target?.content ?? fallback);
32
+ } else if (isInstanceOf(DataType.Text, subject)) {
33
+ return getFallbackName(subject.content);
34
+ }
35
+ };
36
+
37
+ // TODO(burdon): Factor out.
38
+ const getSnippet = (subject: DocumentType | DataType.Text, fallback: string) => {
39
+ if (isInstanceOf(DocumentType, subject)) {
40
+ return getAbstract(subject.content?.target?.content ?? fallback);
41
+ } else if (isInstanceOf(DataType.Text, subject)) {
42
+ return getAbstract(subject.content);
43
+ }
44
+ };
45
+
46
+ export const MarkdownPreview = ({ classNames, subject, role }: PreviewProps<DocumentType | DataType.Text>) => {
47
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
48
+ const { t } = useTranslation(MARKDOWN_PLUGIN);
49
+ const snippet = getSnippet(subject, t('fallback abstract'));
50
+
51
+ // TODO(wittjosiah): Factor out so this component isn't dependent on the app framework.
52
+ const handleNavigate = useCallback(
53
+ () =>
54
+ dispatch(
55
+ pipe(
56
+ createIntent(LayoutAction.UpdatePopover, {
57
+ part: 'popover',
58
+ subject: null,
59
+ options: { state: false, anchorId: '' },
60
+ }),
61
+ chain(LayoutAction.Open, { part: 'main', subject: [fullyQualifiedId(subject)] }),
62
+ ),
63
+ ),
64
+ [dispatch, subject],
65
+ );
66
+
67
+ return (
68
+ <div
69
+ role='none'
70
+ className={mx(
71
+ role === 'popover' ? popoverCard : role === 'card--kanban' ? kanbanCardWithoutPoster : defaultCard,
72
+ classNames,
73
+ )}
74
+ >
75
+ <h2 className={mx(previewTitle, previewProse)}>{getTitle(subject, t('fallback title'))}</h2>
76
+ {snippet && <p className={mx(previewProse, 'line-clamp-3 break-words col-span-2')}>{snippet}</p>}
77
+ <div role='none' className={previewChrome}>
78
+ <Button onClick={handleNavigate}>
79
+ <span className='grow'>{t('navigate to document label')}</span>
80
+ <Icon icon='ph--arrow-right--regular' />
81
+ </Button>
82
+ </div>
83
+ </div>
84
+ );
85
+ };
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { MarkdownPreview } from './MarkdownPreview';
6
+
7
+ export * from './MarkdownPreview';
8
+
9
+ export default MarkdownPreview;
@@ -8,8 +8,8 @@ import { Input, Select, useTranslation } from '@dxos/react-ui';
8
8
  import { type EditorInputMode, EditorInputModes, type EditorViewMode, EditorViewModes } from '@dxos/react-ui-editor';
9
9
  import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
10
10
 
11
- import { MARKDOWN_PLUGIN } from '../meta';
12
- import { type MarkdownSettingsProps } from '../types';
11
+ import { MARKDOWN_PLUGIN } from '../../meta';
12
+ import { type MarkdownSettingsProps } from '../../types';
13
13
 
14
14
  export const MarkdownSettings = ({ settings }: { settings: MarkdownSettingsProps }) => {
15
15
  const { t } = useTranslation(MARKDOWN_PLUGIN);
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './MarkdownSettings';
@@ -0,0 +1,216 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta } from '@storybook/react';
8
+ import { Match, Option, pipe, Schema } from 'effect';
9
+ import React, { type FC, useEffect, useMemo, useState } from 'react';
10
+
11
+ import { Message } from '@dxos/ai';
12
+ import {
13
+ Capabilities,
14
+ CollaborationActions,
15
+ IntentPlugin,
16
+ SettingsPlugin,
17
+ contributes,
18
+ createIntent,
19
+ useCapability,
20
+ useIntentDispatcher,
21
+ } from '@dxos/app-framework';
22
+ import { withPluginManager } from '@dxos/app-framework/testing';
23
+ import { Type } from '@dxos/echo';
24
+ import { create, createQueueDxn, type Expando } from '@dxos/echo-schema';
25
+ import { invariant } from '@dxos/invariant';
26
+ import { DXN } from '@dxos/keys';
27
+ import { live, makeRef, refFromDXN } from '@dxos/live-object';
28
+ import { ClientPlugin } from '@dxos/plugin-client';
29
+ import { PreviewPlugin } from '@dxos/plugin-preview';
30
+ import { SpacePlugin } from '@dxos/plugin-space';
31
+ import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
32
+ import { ThemePlugin } from '@dxos/plugin-theme';
33
+ import { faker } from '@dxos/random';
34
+ import { createDocAccessor, fullyQualifiedId, toCursorRange, useQueue, useSpace } from '@dxos/react-client/echo';
35
+ import { IconButton, Toolbar } from '@dxos/react-ui';
36
+ import { command, type EditorSelection, type Range, useTextEditor } from '@dxos/react-ui-editor';
37
+ import { StackItem } from '@dxos/react-ui-stack';
38
+ import { defaultTx } from '@dxos/react-ui-theme';
39
+ import { withLayout } from '@dxos/storybook-utils';
40
+
41
+ import MarkdownContainer from './MarkdownContainer';
42
+ import { MarkdownPlugin } from '../MarkdownPlugin';
43
+ import { MarkdownCapabilities } from '../capabilities';
44
+ import { MARKDOWN_PLUGIN } from '../meta';
45
+ import translations from '../translations';
46
+ import { createDocument, DocumentType, type MarkdownSettingsProps } from '../types';
47
+
48
+ faker.seed(1);
49
+
50
+ const TestItem = Schema.Struct({
51
+ title: Schema.String.annotations({
52
+ title: 'Title',
53
+ description: 'Product title',
54
+ }),
55
+ description: Schema.String.annotations({
56
+ title: 'Description',
57
+ description: 'Product description',
58
+ }),
59
+ }).pipe(
60
+ Type.Obj({
61
+ typename: 'dxos.org/type/Test',
62
+ version: '0.1.0',
63
+ }),
64
+ );
65
+
66
+ const TestChat: FC<{ doc: DocumentType; content: string }> = ({ doc, content }) => {
67
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
68
+ const { parentRef } = useTextEditor({ initialValue: content });
69
+ const { editorState } = useCapability(MarkdownCapabilities.State);
70
+
71
+ const space = useSpace();
72
+ const queueDxn = useMemo(() => space && createQueueDxn(space.id), [space]);
73
+ const queue = useQueue<Message>(queueDxn);
74
+
75
+ const handleInsert = async () => {
76
+ invariant(space);
77
+ invariant(queue);
78
+ queue.append([create(Message, { role: 'assistant', content: [{ type: 'text', text: 'Hello' }] })]);
79
+ const message = queue.objects.at(-1);
80
+ invariant(message);
81
+
82
+ const text = await doc.content.load();
83
+ const accessor = createDocAccessor(text, ['content']);
84
+ const cursor = pipe(
85
+ editorState.getState(fullyQualifiedId(doc))?.selection,
86
+ Option.fromNullable,
87
+ Option.map(selectionToRange),
88
+ Option.map((range) => toCursorRange(accessor, range.from, range.to)),
89
+ Option.getOrUndefined,
90
+ );
91
+
92
+ // {
93
+ // const ref = refFromDXN(new DXN(DXN.kind.QUEUE, [...queue.dxn.parts, message.id]));
94
+ // const message = deref(ref);
95
+ // }
96
+
97
+ void dispatch(
98
+ createIntent(CollaborationActions.InsertContent, {
99
+ target: doc as any as Expando, // TODO(burdon): Common base type.
100
+ object: refFromDXN(new DXN(DXN.kind.QUEUE, [...queue.dxn.parts, message.id])),
101
+ at: cursor,
102
+ label: 'Proposal',
103
+ }),
104
+ );
105
+ };
106
+
107
+ return (
108
+ <StackItem.Content toolbar>
109
+ <Toolbar.Root>
110
+ <IconButton icon='ph--plus--regular' disabled={!queue} label='Insert' onClick={handleInsert} />
111
+ </Toolbar.Root>
112
+ <div ref={parentRef} className='p-4' />
113
+ </StackItem.Content>
114
+ );
115
+ };
116
+
117
+ const DefaultStory = ({ document, chat }: { document: string; chat: string }) => {
118
+ const space = useSpace();
119
+ const [doc, setDoc] = useState<DocumentType>();
120
+ const settings = useCapability(Capabilities.SettingsStore).getStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN)!.value;
121
+ const { editorState } = useCapability(MarkdownCapabilities.State);
122
+
123
+ useEffect(() => {
124
+ if (!space) {
125
+ return undefined;
126
+ }
127
+
128
+ const doc = space.db.add(
129
+ createDocument({
130
+ name: 'Test',
131
+
132
+ // Create links.
133
+ content: document.replaceAll(/\[(\w+)\]/g, (_, label) => {
134
+ const obj = space.db.add(live(TestItem, { title: label, description: faker.lorem.paragraph() }));
135
+ const dxn = makeRef(obj).dxn.toString();
136
+ return `[${label}][${dxn}]`;
137
+ }),
138
+ }),
139
+ );
140
+
141
+ setDoc(doc);
142
+ }, [space]);
143
+
144
+ if (!space || !doc) {
145
+ return <></>;
146
+ }
147
+
148
+ return (
149
+ <>
150
+ <MarkdownContainer id={doc.id} object={doc} settings={settings} editorStateStore={editorState} />
151
+ <TestChat doc={doc} content={chat} />
152
+ </>
153
+ );
154
+ };
155
+
156
+ const meta: Meta<typeof DefaultStory> = {
157
+ title: 'plugins/plugin-markdown/Suggestions',
158
+ render: DefaultStory,
159
+ decorators: [
160
+ withPluginManager({
161
+ plugins: [
162
+ ThemePlugin({ tx: defaultTx }),
163
+ StorybookLayoutPlugin(),
164
+ ClientPlugin({
165
+ types: [DocumentType, TestItem],
166
+ onClientInitialized: async (_, client) => {
167
+ await client.halo.createIdentity();
168
+ },
169
+ }),
170
+ SpacePlugin(),
171
+ SettingsPlugin(),
172
+ IntentPlugin(),
173
+ MarkdownPlugin(),
174
+ PreviewPlugin(),
175
+ ],
176
+ capabilities: [contributes(MarkdownCapabilities.Extensions, [() => command()])],
177
+ }),
178
+ withLayout({ fullscreen: true, classNames: 'grid grid-cols-2' }),
179
+ ],
180
+ parameters: {
181
+ translations,
182
+ },
183
+ };
184
+
185
+ export default meta;
186
+
187
+ type Story = Meta<typeof DefaultStory>;
188
+
189
+ export const Default: Story = {
190
+ args: {
191
+ chat: 'Hello\n',
192
+ document: [
193
+ '# Test',
194
+ '',
195
+ faker.lorem.paragraph(1),
196
+ '',
197
+ 'This is a [DXOS] story that tests [ECHO] references inside the Markdown plugin.',
198
+ '',
199
+ faker.lorem.paragraph(3),
200
+ '',
201
+ ].join('\n'),
202
+ },
203
+ };
204
+
205
+ // TODO(wittjosiah): Factor out.
206
+ const selectionToRange = Match.type<EditorSelection>().pipe(
207
+ Match.when(
208
+ ({ head, anchor }) => (head ? head > anchor : false),
209
+ ({ head, anchor }) => ({ from: anchor, to: head! }) as Range,
210
+ ),
211
+ Match.when(
212
+ ({ head, anchor }) => (head ? head < anchor : false),
213
+ ({ head, anchor }) => ({ from: head!, to: anchor }) as Range,
214
+ ),
215
+ Match.orElse(({ anchor }) => ({ from: anchor, to: anchor }) as Range),
216
+ );