@dxos/plugin-markdown 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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 (241) hide show
  1. package/dist/lib/browser/MarkdownCard-JYMDPKV5.mjs +12 -0
  2. package/dist/lib/browser/MarkdownContainer-Y75XSVBX.mjs +15 -0
  3. package/dist/lib/browser/{anchor-sort-E33BSTYF.mjs → anchor-sort-3HGPGCOO.mjs} +6 -7
  4. package/dist/lib/browser/anchor-sort-3HGPGCOO.mjs.map +7 -0
  5. package/dist/lib/browser/{app-graph-serializer-OX62DNPT.mjs → app-graph-serializer-POZN234F.mjs} +10 -10
  6. package/dist/lib/browser/app-graph-serializer-POZN234F.mjs.map +7 -0
  7. package/dist/lib/browser/blueprint-definition-GIPKFDY5.mjs +13 -0
  8. package/dist/lib/browser/blueprint-definition-GIPKFDY5.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-Z7P6JGGW.mjs → chunk-22XSSNBS.mjs} +7 -4
  10. package/dist/lib/browser/{chunk-Z7P6JGGW.mjs.map → chunk-22XSSNBS.mjs.map} +2 -2
  11. package/dist/lib/browser/chunk-2MLGSYRN.mjs +20 -0
  12. package/dist/lib/browser/chunk-2MLGSYRN.mjs.map +7 -0
  13. package/dist/lib/browser/{chunk-ODB2PTBP.mjs → chunk-BQTYJOFB.mjs} +4 -4
  14. package/dist/lib/browser/chunk-BQTYJOFB.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-LAVZ2W6X.mjs → chunk-GH6GQSBL.mjs} +9 -8
  16. package/dist/lib/browser/chunk-GH6GQSBL.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-OY6CGPOO.mjs → chunk-IBCHVMZW.mjs} +2 -2
  18. package/dist/lib/browser/{chunk-OY6CGPOO.mjs.map → chunk-IBCHVMZW.mjs.map} +2 -2
  19. package/dist/lib/browser/chunk-K3LXOU3E.mjs +827 -0
  20. package/dist/lib/browser/chunk-K3LXOU3E.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-PBJLFIOX.mjs +96 -0
  22. package/dist/lib/browser/chunk-PBJLFIOX.mjs.map +7 -0
  23. package/dist/lib/browser/{chunk-BEE7VQPU.mjs → chunk-QYSEJ5GP.mjs} +13 -12
  24. package/dist/lib/browser/chunk-QYSEJ5GP.mjs.map +7 -0
  25. package/dist/lib/browser/chunk-Y53FQREH.mjs +150 -0
  26. package/dist/lib/browser/chunk-Y53FQREH.mjs.map +7 -0
  27. package/dist/lib/browser/index.mjs +25 -24
  28. package/dist/lib/browser/index.mjs.map +3 -3
  29. package/dist/lib/browser/{intent-resolver-WDDH56JC.mjs → intent-resolver-Z5L7TXUK.mjs} +8 -8
  30. package/dist/lib/browser/intent-resolver-Z5L7TXUK.mjs.map +7 -0
  31. package/dist/lib/browser/meta.json +1 -1
  32. package/dist/lib/browser/{react-surface-L3NTMD4D.mjs → react-surface-GO5ZOKNN.mjs} +59 -63
  33. package/dist/lib/browser/react-surface-GO5ZOKNN.mjs.map +7 -0
  34. package/dist/lib/browser/{settings-AABBTB4Q.mjs → settings-TZUDB5EW.mjs} +5 -5
  35. package/dist/lib/browser/{settings-AABBTB4Q.mjs.map → settings-TZUDB5EW.mjs.map} +1 -1
  36. package/dist/lib/browser/{state-FTHQQX7V.mjs → state-BTUKVZHY.mjs} +5 -5
  37. package/dist/lib/browser/{state-FTHQQX7V.mjs.map → state-BTUKVZHY.mjs.map} +1 -1
  38. package/dist/lib/browser/toolkit.mjs +13 -0
  39. package/dist/lib/browser/toolkit.mjs.map +7 -0
  40. package/dist/lib/browser/types/index.mjs +2 -2
  41. package/dist/lib/node-esm/MarkdownCard-ZXPJLUYO.mjs +13 -0
  42. package/dist/lib/node-esm/MarkdownCard-ZXPJLUYO.mjs.map +7 -0
  43. package/dist/lib/node-esm/MarkdownContainer-YRDSRDCS.mjs +16 -0
  44. package/dist/lib/node-esm/MarkdownContainer-YRDSRDCS.mjs.map +7 -0
  45. package/dist/lib/node-esm/{anchor-sort-ALP2NH24.mjs → anchor-sort-PCDXEBJ2.mjs} +6 -7
  46. package/dist/lib/node-esm/anchor-sort-PCDXEBJ2.mjs.map +7 -0
  47. package/dist/lib/node-esm/{app-graph-serializer-56TD3BMX.mjs → app-graph-serializer-NF65JYAS.mjs} +10 -10
  48. package/dist/lib/node-esm/app-graph-serializer-NF65JYAS.mjs.map +7 -0
  49. package/dist/lib/node-esm/blueprint-definition-ENKJZYQS.mjs +14 -0
  50. package/dist/lib/node-esm/blueprint-definition-ENKJZYQS.mjs.map +7 -0
  51. package/dist/lib/node-esm/{chunk-J7A6TUB2.mjs → chunk-AMHACOXW.mjs} +7 -4
  52. package/dist/lib/node-esm/{chunk-J7A6TUB2.mjs.map → chunk-AMHACOXW.mjs.map} +2 -2
  53. package/dist/lib/node-esm/chunk-CT7CFX5G.mjs +828 -0
  54. package/dist/lib/node-esm/chunk-CT7CFX5G.mjs.map +7 -0
  55. package/dist/lib/node-esm/{chunk-CB2R4YIY.mjs → chunk-GMMVSXQ6.mjs} +2 -2
  56. package/dist/lib/node-esm/{chunk-CB2R4YIY.mjs.map → chunk-GMMVSXQ6.mjs.map} +2 -2
  57. package/dist/lib/node-esm/chunk-HAIEWPU7.mjs +151 -0
  58. package/dist/lib/node-esm/chunk-HAIEWPU7.mjs.map +7 -0
  59. package/dist/lib/node-esm/chunk-KCHUTL3Q.mjs +22 -0
  60. package/dist/lib/node-esm/chunk-KCHUTL3Q.mjs.map +7 -0
  61. package/dist/lib/node-esm/{chunk-FXILAQ5F.mjs → chunk-NGYJNQ6A.mjs} +13 -12
  62. package/dist/lib/node-esm/chunk-NGYJNQ6A.mjs.map +7 -0
  63. package/dist/lib/node-esm/chunk-PIOOG7A5.mjs +97 -0
  64. package/dist/lib/node-esm/chunk-PIOOG7A5.mjs.map +7 -0
  65. package/dist/lib/node-esm/{chunk-O6EXWGGS.mjs → chunk-PLZ7EVCT.mjs} +9 -8
  66. package/dist/lib/node-esm/chunk-PLZ7EVCT.mjs.map +7 -0
  67. package/dist/lib/node-esm/{chunk-VCG2U522.mjs → chunk-SHAMSMKQ.mjs} +4 -4
  68. package/dist/lib/node-esm/chunk-SHAMSMKQ.mjs.map +7 -0
  69. package/dist/lib/node-esm/index.mjs +25 -24
  70. package/dist/lib/node-esm/index.mjs.map +3 -3
  71. package/dist/lib/node-esm/{intent-resolver-2I5HKCUU.mjs → intent-resolver-6B3PFQ5F.mjs} +8 -8
  72. package/dist/lib/node-esm/intent-resolver-6B3PFQ5F.mjs.map +7 -0
  73. package/dist/lib/node-esm/meta.json +1 -1
  74. package/dist/lib/node-esm/{react-surface-YZSZFR5D.mjs → react-surface-I46BPCWT.mjs} +59 -63
  75. package/dist/lib/node-esm/react-surface-I46BPCWT.mjs.map +7 -0
  76. package/dist/lib/node-esm/{settings-CXGR6DH4.mjs → settings-CJ3T5EX4.mjs} +5 -5
  77. package/dist/lib/node-esm/{settings-CXGR6DH4.mjs.map → settings-CJ3T5EX4.mjs.map} +1 -1
  78. package/dist/lib/node-esm/{state-NWMQ3XAI.mjs → state-K6EH7SRZ.mjs} +5 -5
  79. package/dist/lib/node-esm/{state-NWMQ3XAI.mjs.map → state-K6EH7SRZ.mjs.map} +1 -1
  80. package/dist/lib/node-esm/toolkit.mjs +14 -0
  81. package/dist/lib/node-esm/toolkit.mjs.map +7 -0
  82. package/dist/lib/node-esm/types/index.mjs +2 -2
  83. package/dist/types/src/MarkdownPlugin.d.ts +1 -1
  84. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/anchor-sort.d.ts +2 -4
  86. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  88. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -3
  89. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
  90. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/index.d.ts +1 -5
  92. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  94. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  95. package/dist/types/src/components/MarkdownCard/MarkdownCard.d.ts +3 -3
  96. package/dist/types/src/components/MarkdownCard/MarkdownCard.d.ts.map +1 -1
  97. package/dist/types/src/components/MarkdownCard/MarkdownCard.stories.d.ts +0 -1
  98. package/dist/types/src/components/MarkdownCard/MarkdownCard.stories.d.ts.map +1 -1
  99. package/dist/types/src/components/MarkdownContainer.d.ts +8 -12
  100. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
  101. package/dist/types/src/components/MarkdownContainer.stories.d.ts +7 -4
  102. package/dist/types/src/components/MarkdownContainer.stories.d.ts.map +1 -1
  103. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts +11 -0
  104. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts.map +1 -0
  105. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +42 -23
  106. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  107. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts +5 -110
  108. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts.map +1 -1
  109. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts +26 -0
  110. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts.map +1 -0
  111. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts +12 -0
  112. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts.map +1 -0
  113. package/dist/types/src/components/Suggestions.stories.d.ts +1 -2
  114. package/dist/types/src/components/Suggestions.stories.d.ts.map +1 -1
  115. package/dist/types/src/components/index.d.ts +3 -1
  116. package/dist/types/src/components/index.d.ts.map +1 -1
  117. package/dist/types/src/functions/create.d.ts +8 -0
  118. package/dist/types/src/functions/create.d.ts.map +1 -0
  119. package/dist/types/src/functions/create.test.d.ts +2 -0
  120. package/dist/types/src/functions/create.test.d.ts.map +1 -0
  121. package/dist/types/src/functions/index.d.ts +17 -2
  122. package/dist/types/src/functions/index.d.ts.map +1 -1
  123. package/dist/types/src/functions/open.d.ts +1 -1
  124. package/dist/types/src/functions/open.d.ts.map +1 -1
  125. package/dist/types/src/functions/{diff.d.ts → update.d.ts} +2 -2
  126. package/dist/types/src/functions/update.d.ts.map +1 -0
  127. package/dist/types/src/functions/update.test.d.ts +2 -0
  128. package/dist/types/src/functions/update.test.d.ts.map +1 -0
  129. package/dist/types/src/hooks/index.d.ts +3 -0
  130. package/dist/types/src/hooks/index.d.ts.map +1 -1
  131. package/dist/types/src/hooks/useEditorMenuOptions.d.ts +9 -0
  132. package/dist/types/src/hooks/useEditorMenuOptions.d.ts.map +1 -0
  133. package/dist/types/src/hooks/useExtensions.d.ts +21 -0
  134. package/dist/types/src/hooks/useExtensions.d.ts.map +1 -0
  135. package/dist/types/src/hooks/useLinkQuery.d.ts +4 -0
  136. package/dist/types/src/hooks/useLinkQuery.d.ts.map +1 -0
  137. package/dist/types/src/hooks/useSelectCurrentThread.d.ts +1 -1
  138. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -1
  139. package/dist/types/src/testing.d.ts +6 -0
  140. package/dist/types/src/testing.d.ts.map +1 -0
  141. package/dist/types/src/toolkit.d.ts +3 -0
  142. package/dist/types/src/toolkit.d.ts.map +1 -0
  143. package/dist/types/src/translations.d.ts +3 -0
  144. package/dist/types/src/translations.d.ts.map +1 -1
  145. package/dist/types/src/types/Markdown.d.ts +6 -4
  146. package/dist/types/src/types/Markdown.d.ts.map +1 -1
  147. package/dist/types/src/types/MarkdownAction.d.ts +2 -1
  148. package/dist/types/src/types/MarkdownAction.d.ts.map +1 -1
  149. package/dist/types/src/types/index.d.ts.map +1 -1
  150. package/dist/types/src/util.d.ts +3 -3
  151. package/dist/types/src/util.d.ts.map +1 -1
  152. package/dist/types/tsconfig.tsbuildinfo +1 -1
  153. package/package.json +71 -55
  154. package/src/MarkdownPlugin.tsx +99 -101
  155. package/src/capabilities/anchor-sort.ts +3 -3
  156. package/src/capabilities/app-graph-serializer.ts +5 -5
  157. package/src/capabilities/artifact-definition.ts +6 -5
  158. package/src/capabilities/blueprint-definition.ts +30 -26
  159. package/src/capabilities/capabilities.ts +1 -0
  160. package/src/capabilities/index.ts +1 -2
  161. package/src/capabilities/intent-resolver.ts +3 -2
  162. package/src/capabilities/react-surface.tsx +44 -66
  163. package/src/components/MarkdownCard/MarkdownCard.stories.tsx +6 -9
  164. package/src/components/MarkdownCard/MarkdownCard.tsx +52 -38
  165. package/src/components/MarkdownContainer.stories.tsx +74 -38
  166. package/src/components/MarkdownContainer.tsx +78 -220
  167. package/src/components/MarkdownEditor/FileUpload.tsx +63 -0
  168. package/src/components/MarkdownEditor/MarkdownEditor.stories.tsx +55 -35
  169. package/src/components/MarkdownEditor/MarkdownEditor.tsx +221 -272
  170. package/src/components/MarkdownEditor/MarkdownEditorContent.tsx +136 -0
  171. package/src/components/MarkdownEditor/MarkdownEditorToolbar.tsx +63 -0
  172. package/src/components/Suggestions.stories.tsx +41 -34
  173. package/src/components/index.ts +3 -1
  174. package/src/functions/create.conversations.json +1 -0
  175. package/src/functions/create.test.ts +128 -0
  176. package/src/functions/create.ts +34 -0
  177. package/src/functions/index.ts +9 -2
  178. package/src/functions/open.ts +4 -2
  179. package/src/functions/update.conversations.json +1 -0
  180. package/src/functions/update.test.ts +151 -0
  181. package/src/functions/{diff.ts → update.ts} +4 -2
  182. package/src/hooks/index.ts +3 -0
  183. package/src/hooks/useEditorMenuOptions.ts +71 -0
  184. package/src/{extensions.tsx → hooks/useExtensions.tsx} +60 -81
  185. package/src/hooks/useLinkQuery.ts +83 -0
  186. package/src/hooks/useSelectCurrentThread.tsx +15 -5
  187. package/src/meta.ts +3 -3
  188. package/src/testing.ts +27 -0
  189. package/src/toolkit.ts +6 -0
  190. package/src/translations.ts +3 -0
  191. package/src/types/Markdown.ts +9 -7
  192. package/src/types/MarkdownAction.ts +1 -1
  193. package/src/types/index.ts +1 -0
  194. package/src/util.tsx +10 -5
  195. package/dist/lib/browser/MarkdownCard-JLUQITYK.mjs +0 -80
  196. package/dist/lib/browser/MarkdownCard-JLUQITYK.mjs.map +0 -7
  197. package/dist/lib/browser/MarkdownContainer-JW7TRDSA.mjs +0 -755
  198. package/dist/lib/browser/MarkdownContainer-JW7TRDSA.mjs.map +0 -7
  199. package/dist/lib/browser/anchor-sort-E33BSTYF.mjs.map +0 -7
  200. package/dist/lib/browser/app-graph-serializer-OX62DNPT.mjs.map +0 -7
  201. package/dist/lib/browser/blueprint-definition-5YKFUHRU.mjs +0 -11
  202. package/dist/lib/browser/chunk-BEE7VQPU.mjs.map +0 -7
  203. package/dist/lib/browser/chunk-F6JJLKLN.mjs +0 -102
  204. package/dist/lib/browser/chunk-F6JJLKLN.mjs.map +0 -7
  205. package/dist/lib/browser/chunk-LAVZ2W6X.mjs.map +0 -7
  206. package/dist/lib/browser/chunk-ODB2PTBP.mjs.map +0 -7
  207. package/dist/lib/browser/chunk-SUOK6YMI.mjs +0 -22
  208. package/dist/lib/browser/chunk-SUOK6YMI.mjs.map +0 -7
  209. package/dist/lib/browser/intent-resolver-WDDH56JC.mjs.map +0 -7
  210. package/dist/lib/browser/react-surface-L3NTMD4D.mjs.map +0 -7
  211. package/dist/lib/browser/toolkit-2AJTHG74.mjs +0 -74
  212. package/dist/lib/browser/toolkit-2AJTHG74.mjs.map +0 -7
  213. package/dist/lib/node-esm/MarkdownCard-XL5EVSJ7.mjs +0 -81
  214. package/dist/lib/node-esm/MarkdownCard-XL5EVSJ7.mjs.map +0 -7
  215. package/dist/lib/node-esm/MarkdownContainer-HRGQXIXP.mjs +0 -756
  216. package/dist/lib/node-esm/MarkdownContainer-HRGQXIXP.mjs.map +0 -7
  217. package/dist/lib/node-esm/anchor-sort-ALP2NH24.mjs.map +0 -7
  218. package/dist/lib/node-esm/app-graph-serializer-56TD3BMX.mjs.map +0 -7
  219. package/dist/lib/node-esm/blueprint-definition-GVW67KGV.mjs +0 -12
  220. package/dist/lib/node-esm/chunk-DVK63TD3.mjs +0 -103
  221. package/dist/lib/node-esm/chunk-DVK63TD3.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-FXILAQ5F.mjs.map +0 -7
  223. package/dist/lib/node-esm/chunk-JC2YWB5D.mjs +0 -24
  224. package/dist/lib/node-esm/chunk-JC2YWB5D.mjs.map +0 -7
  225. package/dist/lib/node-esm/chunk-O6EXWGGS.mjs.map +0 -7
  226. package/dist/lib/node-esm/chunk-VCG2U522.mjs.map +0 -7
  227. package/dist/lib/node-esm/intent-resolver-2I5HKCUU.mjs.map +0 -7
  228. package/dist/lib/node-esm/react-surface-YZSZFR5D.mjs.map +0 -7
  229. package/dist/lib/node-esm/toolkit-RC44I2MI.mjs +0 -75
  230. package/dist/lib/node-esm/toolkit-RC44I2MI.mjs.map +0 -7
  231. package/dist/types/src/capabilities/toolkit.d.ts +0 -4
  232. package/dist/types/src/capabilities/toolkit.d.ts.map +0 -1
  233. package/dist/types/src/components/Toolbar.stories.d.ts +0 -48
  234. package/dist/types/src/components/Toolbar.stories.d.ts.map +0 -1
  235. package/dist/types/src/extensions.d.ts +0 -22
  236. package/dist/types/src/extensions.d.ts.map +0 -1
  237. package/dist/types/src/functions/diff.d.ts.map +0 -1
  238. package/src/capabilities/toolkit.ts +0 -47
  239. package/src/components/Toolbar.stories.tsx +0 -118
  240. /package/dist/lib/browser/{blueprint-definition-5YKFUHRU.mjs.map → MarkdownCard-JYMDPKV5.mjs.map} +0 -0
  241. /package/dist/lib/{node-esm/blueprint-definition-GVW67KGV.mjs.map → browser/MarkdownContainer-Y75XSVBX.mjs.map} +0 -0
@@ -2,253 +2,111 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
6
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
7
- import { createPortal } from 'react-dom';
8
-
9
- import { Capabilities, Surface, useAppGraph, useCapabilities, usePluginManager } from '@dxos/app-framework';
10
- import { DXN, Filter, Obj, Query, Type } from '@dxos/echo';
11
- import { ClientCapabilities } from '@dxos/plugin-client';
12
- import { SpaceCapabilities } from '@dxos/plugin-space';
13
- import { fullyQualifiedId, getSpace, useQuery, useSpace } from '@dxos/react-client/echo';
14
- import { toLocalizedString, useTranslation } from '@dxos/react-ui';
5
+ import { type Extension } from '@codemirror/state';
6
+ import { Atom } from '@effect-atom/atom-react';
7
+ import React, { useMemo } from 'react';
8
+
9
+ import { Capabilities } from '@dxos/app-framework';
10
+ import { useAppGraph, useCapabilities } from '@dxos/app-framework/react';
11
+ import { Obj } from '@dxos/echo';
12
+ import { getSpace } from '@dxos/react-client/echo';
15
13
  import { type SelectionManager } from '@dxos/react-ui-attention';
16
- import {
17
- type CommandMenuGroup,
18
- type CommandMenuItem,
19
- type PreviewLinkRef,
20
- type PreviewOptions,
21
- insertAtCursor,
22
- insertAtLineStart,
23
- } from '@dxos/react-ui-editor';
24
- import { DataType } from '@dxos/schema';
14
+ import { StackItem } from '@dxos/react-ui-stack';
15
+ import { Text } from '@dxos/schema';
25
16
 
26
- import { useExtensions } from '../extensions';
27
- import { Markdown } from '../types';
28
- import { getFallbackName } from '../util';
17
+ import { MarkdownCapabilities } from '../capabilities';
18
+ import { type DocumentType, useLinkQuery } from '../hooks';
19
+ import { Markdown, type MarkdownPluginState } from '../types';
29
20
 
30
- import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
21
+ import { MarkdownEditor, type MarkdownEditorContentProps, type MarkdownEditorRootProps } from './MarkdownEditor';
31
22
 
32
- export type MarkdownContainerProps = Pick<
33
- MarkdownEditorProps,
34
- 'role' | 'extensionProviders' | 'viewMode' | 'editorStateStore' | 'onViewModeChange'
35
- > & {
36
- id: string;
37
- object: Markdown.Document | DataType.Text | any;
23
+ export type MarkdownContainerProps = {
24
+ role?: string;
25
+ object: DocumentType;
38
26
  settings: Markdown.Settings;
39
27
  selectionManager?: SelectionManager;
40
- };
28
+ } & (Pick<MarkdownEditorRootProps, 'id' | 'viewMode' | 'onViewModeChange'> &
29
+ Pick<MarkdownEditorContentProps, 'editorStateStore'> &
30
+ Pick<MarkdownPluginState, 'extensionProviders'>);
41
31
 
42
32
  export const MarkdownContainer = ({
43
33
  id,
44
34
  role,
45
35
  object,
46
36
  settings,
47
- selectionManager,
48
- viewMode,
49
- editorStateStore,
50
- onViewModeChange,
37
+ extensionProviders,
38
+ ...props
51
39
  }: MarkdownContainerProps) => {
52
- const { t } = useTranslation();
53
- const scrollPastEnd = role === 'article';
54
- const doc = Obj.instanceOf(Markdown.Document, object) ? object : undefined;
55
- const text = Obj.instanceOf(DataType.Text, object) ? object : undefined;
56
- const [previewBlocks, setPreviewBlocks] = useState<{ link: PreviewLinkRef; el: HTMLElement }[]>([]);
57
- const previewOptions = useMemo(
58
- (): PreviewOptions => ({
59
- addBlockContainer: (link, el) => {
60
- setPreviewBlocks((prev) => [...prev, { link, el }]);
61
- },
62
- removeBlockContainer: (link) => {
63
- setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.ref !== link.ref));
64
- },
65
- }),
66
- [],
67
- );
68
- const extensions = useExtensions({
69
- document: doc,
70
- text,
71
- id,
72
- settings,
73
- selectionManager,
74
- viewMode,
75
- editorStateStore,
76
- previewOptions,
77
- });
78
-
79
- // TODO(wittjosiah): Factor out.
80
- const manager = usePluginManager();
81
- const resolve = useCallback(
82
- (typename: string) =>
83
- manager.context.getCapabilities(Capabilities.Metadata).find(({ id }) => id === typename)?.metadata ?? {},
84
- [manager],
85
- );
86
40
  const space = getSpace(object);
87
- const objectForms = useCapabilities(SpaceCapabilities.ObjectForm);
88
- const schemaWhiteList = useCapabilities(ClientCapabilities.SchemaWhiteList);
89
- const filter = useMemo(
90
- () =>
91
- Filter.or(
92
- ...objectForms.map((form) => Filter.type(form.objectSchema)),
93
- ...schemaWhiteList.flat().map((schema) => Filter.typename(Type.getTypename(schema))),
94
- ),
95
- [objectForms, schemaWhiteList],
96
- );
97
- const onLinkQuery = useCallback(
98
- async (query?: string): Promise<CommandMenuGroup[]> => {
99
- const name = query?.startsWith('@') ? query.slice(1).toLowerCase() : (query?.toLowerCase() ?? '');
100
- const results = await space?.db.query(Query.select(filter)).run();
101
- // TODO(wittjosiah): Use `Obj.Any` type.
102
- const getLabel = (object: any) => {
103
- const label = Obj.getLabel(object);
104
- if (label) {
105
- return label;
106
- }
107
-
108
- // TODO(wittjosiah): Remove metadata labels.
109
- const type = Obj.getTypename(object)!;
110
- const metadata = resolve(type);
111
- return metadata.label?.(object) || ['object name placeholder', { ns: type, default: 'New object' }];
112
- };
113
- const items =
114
- results?.objects
115
- .filter((object) => toLocalizedString(getLabel(object), t).toLowerCase().includes(name))
116
- // TODO(wittjosiah): Remove `any` type.
117
- .map((object: any): CommandMenuItem => {
118
- const metadata = resolve(Obj.getTypename(object)!);
119
- const label = toLocalizedString(getLabel(object), t);
120
- return {
121
- id: object.id,
122
- label,
123
- icon: metadata.icon,
124
- onSelect: (view, head) => {
125
- const link = `[${label}][${Obj.getDXN(object)}]`;
126
- if (query?.startsWith('@')) {
127
- insertAtLineStart(view, head, `!${link}\n`);
128
- } else {
129
- insertAtCursor(view, head, `${link} `);
130
- }
131
- },
132
- };
133
- }) ?? [];
134
- return [{ id: 'echo', items }];
135
- },
136
- [filter, resolve, space],
137
- );
138
-
139
- const editor = doc ? (
140
- <DocumentEditor
141
- id={fullyQualifiedId(object)}
142
- role={role}
143
- document={doc}
144
- extensions={extensions}
145
- viewMode={viewMode}
146
- settings={settings}
147
- scrollPastEnd={scrollPastEnd}
148
- onViewModeChange={onViewModeChange}
149
- onLinkQuery={space ? onLinkQuery : undefined}
150
- />
151
- ) : text ? (
152
- <MarkdownEditor
153
- id={id}
154
- role={role}
155
- initialValue={text.content}
156
- extensions={extensions}
157
- viewMode={viewMode}
158
- toolbar={settings.toolbar}
159
- inputMode={settings.editorInputMode}
160
- scrollPastEnd={scrollPastEnd}
161
- onViewModeChange={onViewModeChange}
162
- onLinkQuery={space ? onLinkQuery : undefined}
163
- />
164
- ) : (
165
- // TODO(burdon): Normalize with above.
166
- <MarkdownEditor
167
- id={id}
168
- role={role}
169
- initialValue={object.text}
170
- extensions={extensions}
171
- viewMode={viewMode}
172
- toolbar={settings.toolbar}
173
- inputMode={settings.editorInputMode}
174
- scrollPastEnd={scrollPastEnd}
175
- onViewModeChange={onViewModeChange}
176
- onLinkQuery={space ? onLinkQuery : undefined}
177
- />
178
- );
179
-
180
- return (
181
- <>
182
- {editor}
183
- {previewBlocks.map(({ link, el }) => (
184
- <PreviewBlock key={link.ref} link={link} el={el} />
185
- ))}
186
- </>
187
- );
188
- };
189
-
190
- // TODO(wittjosiah): This shouldn't be "card" but "block".
191
- // It's not a preview card but an interactive embedded object.
192
- const PreviewBlock = ({ link, el }: { link: PreviewLinkRef; el: HTMLElement }) => {
193
- const echoDXN = useMemo(() => DXN.parse(link.ref).asEchoDXN(), [link.ref]);
194
- const space = useSpace(echoDXN?.spaceId);
195
- const [subject] = useQuery(space, Query.select(Filter.ids(echoDXN?.echoId ?? '')));
196
- const data = useMemo(() => ({ subject }), [subject]);
197
-
198
- return createPortal(<Surface role='card--transclusion' data={data} limit={1} />, el);
199
- };
41
+ const isDocument = Obj.instanceOf(Markdown.Document, object);
42
+ const isText = Obj.instanceOf(Text.Text, object);
43
+ const attendableId = isDocument ? Obj.getDXN(object).toString() : undefined;
44
+
45
+ // Extensions from other plugins.
46
+ // TODO(burdon): Document MarkdownPluginState.extensionProviders
47
+ const otherExtensionProviders = useCapabilities(MarkdownCapabilities.Extensions);
48
+ const extensions = useMemo<Extension[]>(() => {
49
+ if (!Obj.instanceOf(Markdown.Document, object)) {
50
+ return [];
51
+ }
200
52
 
201
- type DocumentEditorProps = Omit<MarkdownContainerProps, 'object' | 'extensionProviders' | 'editorStateStore'> &
202
- Pick<MarkdownEditorProps, 'id' | 'scrollPastEnd' | 'extensions' | 'onLinkQuery'> & {
203
- document: Markdown.Document;
204
- };
53
+ return [...(otherExtensionProviders ?? []), ...(extensionProviders ?? [])]
54
+ .flat()
55
+ .reduce((acc: Extension[], provider) => {
56
+ const extension =
57
+ typeof provider === 'function' ? provider({ document: object as Markdown.Document }) : provider;
58
+ if (extension) {
59
+ acc.push(extension);
60
+ }
205
61
 
206
- export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props }: DocumentEditorProps) => {
207
- const space = getSpace(doc);
62
+ return acc;
63
+ }, []);
64
+ }, [extensionProviders, otherExtensionProviders, object]);
208
65
 
209
- // Migrate gradually to `fallbackName`.
210
- useEffect(() => {
211
- if (typeof doc.fallbackName === 'string') {
212
- return;
213
- }
214
-
215
- const fallbackName = doc.content?.target?.content ? getFallbackName(doc.content.target.content) : undefined;
216
- if (fallbackName) {
217
- doc.fallbackName = fallbackName;
218
- }
219
- }, [doc, doc.content]);
66
+ // Toolbar actions from app graph.
67
+ const { graph } = useAppGraph();
68
+ const customActions = useMemo(() => {
69
+ return Atom.make((get) => {
70
+ const actions = get(graph.actions(id));
71
+ const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
72
+ const edges = nodes.map((node) => ({ source: 'root', target: node.id }));
73
+ return { nodes, edges };
74
+ });
75
+ }, [graph]);
220
76
 
221
- // File dragging.
77
+ // File upload.
222
78
  const [upload] = useCapabilities(Capabilities.FileUploader);
223
79
  const handleFileUpload = useMemo(() => {
224
- if (space === undefined || upload === undefined) {
80
+ if (!space || !upload) {
225
81
  return undefined;
226
82
  }
227
83
 
228
- // TODO(burdon): Re-order props: space, file.
229
- return async (file: File) => upload!(file, space);
84
+ return async (file: File) => upload(space, file);
230
85
  }, [space, upload]);
231
86
 
232
- const { graph } = useAppGraph();
233
- const customActions = useMemo(() => {
234
- return Rx.make((get) => {
235
- const actions = get(graph.actions(id));
236
- const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
237
- return { nodes, edges: nodes.map((node) => ({ source: 'root', target: node.id })) };
238
- });
239
- }, [graph]);
87
+ // Query for @ refs.
88
+ const handleLinkQuery = useLinkQuery(space);
240
89
 
241
90
  return (
242
- <MarkdownEditor
243
- id={id}
244
- initialValue={doc.content?.target?.content}
245
- viewMode={viewMode}
246
- toolbar={settings.toolbar}
247
- customActions={customActions}
248
- inputMode={settings.editorInputMode}
249
- onFileUpload={handleFileUpload}
250
- {...props}
251
- />
91
+ <StackItem.Content toolbar={settings.toolbar}>
92
+ <MarkdownEditor.Root
93
+ id={attendableId ?? id}
94
+ object={object}
95
+ extensions={extensions}
96
+ onFileUpload={handleFileUpload}
97
+ onLinkQuery={handleLinkQuery}
98
+ {...props}
99
+ >
100
+ {settings.toolbar && (
101
+ <MarkdownEditor.Toolbar id={attendableId ?? id} role={role} customActions={customActions} />
102
+ )}
103
+ <MarkdownEditor.Content
104
+ initialValue={isDocument ? object.content?.target?.content : isText ? object.content : object.text}
105
+ scrollPastEnd={role === 'article'}
106
+ />
107
+ <MarkdownEditor.Blocks />
108
+ </MarkdownEditor.Root>
109
+ </StackItem.Content>
252
110
  );
253
111
  };
254
112
 
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type EditorView } from '@codemirror/view';
6
+ import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
7
+ import { createPortal } from 'react-dom';
8
+ import { useDropzone } from 'react-dropzone';
9
+
10
+ import { type FileInfo } from '@dxos/app-framework';
11
+ import { addLink } from '@dxos/react-ui-editor';
12
+
13
+ export const IMAGE_FILES = ['.jpg', '.jpeg', '.png', '.gif'];
14
+
15
+ export type FileUploadAction = () => void;
16
+
17
+ export type FileUploadProps = {
18
+ editorView?: EditorView;
19
+ onFileUpload?: (file: File) => Promise<FileInfo | undefined>;
20
+ };
21
+
22
+ // TODO(burdon): Factor out.
23
+ // TODO(burdon): Move to root? (support drag into document via dropzone).
24
+ export const FileUpload = forwardRef<FileUploadAction, FileUploadProps>(
25
+ ({ editorView, onFileUpload }, forwardedRef) => {
26
+ // https://react-dropzone.js.org
27
+ const { acceptedFiles, open, inputRef } = useDropzone({
28
+ disabled: !onFileUpload,
29
+ multiple: false,
30
+ noDrag: true,
31
+ accept: {
32
+ 'image/*': IMAGE_FILES,
33
+ },
34
+ });
35
+
36
+ useImperativeHandle(forwardedRef, () => open, []);
37
+
38
+ useEffect(() => {
39
+ if (editorView && acceptedFiles.length && onFileUpload) {
40
+ requestAnimationFrame(async () => {
41
+ // NOTE: Clone file since react-dropzone patches in a non-standard `path` property, which confuses IPFS.
42
+ const f = acceptedFiles[0];
43
+ const file = new File([f], f.name, {
44
+ type: f.type,
45
+ lastModified: f.lastModified,
46
+ });
47
+
48
+ // TODO(burdon): Factor out.
49
+ const info = await onFileUpload(file);
50
+ if (info) {
51
+ addLink({ url: info.url, image: true })(editorView);
52
+ }
53
+ });
54
+ }
55
+ }, [editorView, acceptedFiles, onFileUpload]);
56
+
57
+ if (!onFileUpload) {
58
+ return null;
59
+ }
60
+
61
+ return <>{createPortal(<input ref={inputRef} />, document.body)} </>;
62
+ },
63
+ );
@@ -2,63 +2,83 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import React, { useMemo } from 'react';
6
+ import React from 'react';
9
7
 
10
8
  import { IntentPlugin } from '@dxos/app-framework';
11
9
  import { withPluginManager } from '@dxos/app-framework/testing';
12
- import { createDocAccessor, createObject } from '@dxos/react-client/echo';
13
- import { withAttention } from '@dxos/react-ui-attention/testing';
14
- import { automerge, translations as editorTranslations } from '@dxos/react-ui-editor';
15
- import { withLayout, withTheme } from '@dxos/storybook-utils';
10
+ import { Filter, Obj } from '@dxos/echo';
11
+ import { AttentionPlugin } from '@dxos/plugin-attention';
12
+ import { ClientPlugin } from '@dxos/plugin-client';
13
+ import { useQuery, useSpace } from '@dxos/react-client/echo';
14
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
+ import { useAttentionAttributes } from '@dxos/react-ui-attention';
16
+ import { translations as editorTranslations } from '@dxos/react-ui-editor';
17
+ import { StackItem } from '@dxos/react-ui-stack';
16
18
 
17
19
  import { translations } from '../../translations';
20
+ import { Markdown } from '../../types';
18
21
 
19
- import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
22
+ import { MarkdownEditor, type MarkdownEditorRootProps } from './MarkdownEditor';
20
23
 
21
24
  const content = Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n');
22
25
 
23
- type StoryProps = MarkdownEditorProps & {
24
- content?: string;
25
- toolbar?: boolean;
26
- };
26
+ type StoryProps = Omit<MarkdownEditorRootProps, 'id' | 'extensions'>;
27
+
28
+ const DefaultStory = (props: StoryProps) => {
29
+ const space = useSpace();
30
+ const [doc] = useQuery(space?.db, Filter.type(Markdown.Document));
31
+ const id = doc && Obj.getDXN(doc).toString();
32
+ const attentionAttrs = useAttentionAttributes(id);
27
33
 
28
- const DefaultStory = ({ content = '# Test', toolbar }: StoryProps) => {
29
- const doc = useMemo(() => createObject({ content }), [content]); // TODO(burdon): Remove dependency on createObject.
30
- const extensions = useMemo(() => [automerge(createDocAccessor(doc, ['content']))], [doc]);
31
- return <MarkdownEditor id='test' initialValue={doc.content} extensions={extensions} toolbar={toolbar} />;
34
+ if (!id) {
35
+ return null;
36
+ }
37
+
38
+ return (
39
+ <div className='contents' {...attentionAttrs}>
40
+ <StackItem.Content toolbar>
41
+ <MarkdownEditor.Root id={id} object={doc} {...props}>
42
+ <MarkdownEditor.Toolbar id={id} />
43
+ <MarkdownEditor.Content />
44
+ </MarkdownEditor.Root>
45
+ </StackItem.Content>
46
+ </div>
47
+ );
32
48
  };
33
49
 
34
- const meta = {
50
+ const meta: Meta<typeof DefaultStory> = {
35
51
  title: 'plugins/plugin-markdown/MarkdownEditor',
36
- component: MarkdownEditor as any,
37
- render: DefaultStory,
52
+ component: DefaultStory,
53
+ render: DefaultStory as any,
38
54
  decorators: [
39
- withPluginManager({ plugins: [IntentPlugin()] }),
40
- withAttention,
41
55
  withTheme,
42
- withLayout({ fullscreen: true }),
56
+ withLayout({ container: 'column' }),
57
+ // TODO(burdon): Create story without client.
58
+ withPluginManager({
59
+ plugins: [
60
+ ClientPlugin({
61
+ types: [Markdown.Document],
62
+ onClientInitialized: async ({ client }) => {
63
+ await client.halo.createIdentity();
64
+ await client.spaces.waitUntilReady();
65
+ const space = client.spaces.default;
66
+ await space.waitUntilReady();
67
+ space.db.add(Markdown.make({ content }));
68
+ },
69
+ }),
70
+ IntentPlugin(),
71
+ AttentionPlugin(),
72
+ ],
73
+ }),
43
74
  ],
44
75
  parameters: {
45
76
  translations: [...translations, ...editorTranslations],
46
77
  },
47
- } satisfies Meta<typeof DefaultStory>;
78
+ };
48
79
 
49
80
  export default meta;
50
81
 
51
82
  type Story = StoryObj<typeof meta>;
52
83
 
53
- export const Default: Story = {
54
- args: {
55
- content,
56
- },
57
- };
58
-
59
- export const WithToolbar: Story = {
60
- args: {
61
- toolbar: true,
62
- content,
63
- },
64
- };
84
+ export const Default: Story = {};