@dxos/plugin-markdown 0.8.4-main.67995b8 → 0.8.4-main.ae835ea

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 (244) hide show
  1. package/dist/lib/browser/MarkdownCard-SLM6QZYC.mjs +12 -0
  2. package/dist/lib/browser/MarkdownCard-SLM6QZYC.mjs.map +7 -0
  3. package/dist/lib/browser/MarkdownContainer-UZFQC6XY.mjs +15 -0
  4. package/dist/lib/browser/MarkdownContainer-UZFQC6XY.mjs.map +7 -0
  5. package/dist/lib/browser/{anchor-sort-Z7JQA7RL.mjs → anchor-sort-4XPPLMZS.mjs} +5 -5
  6. package/dist/lib/browser/{anchor-sort-Z7JQA7RL.mjs.map → anchor-sort-4XPPLMZS.mjs.map} +1 -1
  7. package/dist/lib/browser/{app-graph-serializer-ZT5OVF5G.mjs → app-graph-serializer-QQFV4K6P.mjs} +9 -10
  8. package/dist/lib/browser/app-graph-serializer-QQFV4K6P.mjs.map +7 -0
  9. package/dist/lib/browser/blueprint-definition-BC5R3T72.mjs +11 -0
  10. package/dist/lib/browser/blueprint-definition-BC5R3T72.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-VMX5SDGW.mjs → chunk-2LLVTQCK.mjs} +6 -5
  12. package/dist/lib/browser/chunk-2LLVTQCK.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-3VILQLA4.mjs +95 -0
  14. package/dist/lib/browser/chunk-3VILQLA4.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-5AYTOIUF.mjs +822 -0
  16. package/dist/lib/browser/chunk-5AYTOIUF.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-K7ZFMSC4.mjs → chunk-A3CQYGCN.mjs} +8 -4
  18. package/dist/lib/browser/chunk-A3CQYGCN.mjs.map +7 -0
  19. package/dist/lib/browser/{chunk-ZGY3DYC2.mjs → chunk-BQTYJOFB.mjs} +5 -7
  20. package/dist/lib/browser/chunk-BQTYJOFB.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-GLEYXJX3.mjs +22 -0
  22. package/dist/lib/browser/chunk-GLEYXJX3.mjs.map +7 -0
  23. package/dist/lib/browser/{chunk-CD4E4K7J.mjs → chunk-IBCHVMZW.mjs} +2 -2
  24. package/dist/lib/browser/{chunk-CD4E4K7J.mjs.map → chunk-IBCHVMZW.mjs.map} +2 -2
  25. package/dist/lib/browser/chunk-JAETS5LE.mjs +106 -0
  26. package/dist/lib/browser/chunk-JAETS5LE.mjs.map +7 -0
  27. package/dist/lib/browser/{chunk-YHMGUSO7.mjs → chunk-UKTCPHLI.mjs} +13 -14
  28. package/dist/lib/browser/chunk-UKTCPHLI.mjs.map +7 -0
  29. package/dist/lib/browser/index.mjs +32 -20
  30. package/dist/lib/browser/index.mjs.map +3 -3
  31. package/dist/lib/browser/{intent-resolver-EBEF7WEI.mjs → intent-resolver-VQGMBNXZ.mjs} +20 -18
  32. package/dist/lib/browser/intent-resolver-VQGMBNXZ.mjs.map +7 -0
  33. package/dist/lib/browser/meta.json +1 -1
  34. package/dist/lib/browser/{react-surface-ZPMZT4VU.mjs → react-surface-WOMJOPJE.mjs} +83 -74
  35. package/dist/lib/browser/react-surface-WOMJOPJE.mjs.map +7 -0
  36. package/dist/lib/browser/{settings-MBDK4TWE.mjs → settings-LBXJHVBU.mjs} +5 -5
  37. package/dist/lib/browser/{settings-MBDK4TWE.mjs.map → settings-LBXJHVBU.mjs.map} +1 -1
  38. package/dist/lib/browser/{state-ZA6PZPUI.mjs → state-BTUKVZHY.mjs} +5 -5
  39. package/dist/lib/browser/state-BTUKVZHY.mjs.map +7 -0
  40. package/dist/lib/browser/toolkit-YPIVDB4A.mjs +66 -0
  41. package/dist/lib/browser/toolkit-YPIVDB4A.mjs.map +7 -0
  42. package/dist/lib/browser/types/index.mjs +2 -2
  43. package/dist/lib/node-esm/MarkdownCard-MCWEFW4F.mjs +13 -0
  44. package/dist/lib/node-esm/MarkdownCard-MCWEFW4F.mjs.map +7 -0
  45. package/dist/lib/node-esm/MarkdownContainer-KAQOK7K5.mjs +16 -0
  46. package/dist/lib/node-esm/MarkdownContainer-KAQOK7K5.mjs.map +7 -0
  47. package/dist/lib/node-esm/{anchor-sort-R6AAKYNG.mjs → anchor-sort-4SXYVYXT.mjs} +5 -5
  48. package/dist/lib/node-esm/{anchor-sort-R6AAKYNG.mjs.map → anchor-sort-4SXYVYXT.mjs.map} +1 -1
  49. package/dist/lib/node-esm/{app-graph-serializer-X4M5QEI6.mjs → app-graph-serializer-KBVRLQN2.mjs} +9 -10
  50. package/dist/lib/node-esm/app-graph-serializer-KBVRLQN2.mjs.map +7 -0
  51. package/dist/lib/node-esm/blueprint-definition-FPNOTEYC.mjs +12 -0
  52. package/dist/lib/node-esm/blueprint-definition-FPNOTEYC.mjs.map +7 -0
  53. package/dist/lib/node-esm/chunk-2Q4WCKWT.mjs +823 -0
  54. package/dist/lib/node-esm/chunk-2Q4WCKWT.mjs.map +7 -0
  55. package/dist/lib/node-esm/chunk-DOB2MJAX.mjs +107 -0
  56. package/dist/lib/node-esm/chunk-DOB2MJAX.mjs.map +7 -0
  57. package/dist/lib/node-esm/chunk-GGKPPGWA.mjs +24 -0
  58. package/dist/lib/node-esm/chunk-GGKPPGWA.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-B3J2M4YL.mjs → chunk-GMMVSXQ6.mjs} +2 -2
  60. package/dist/lib/node-esm/{chunk-B3J2M4YL.mjs.map → chunk-GMMVSXQ6.mjs.map} +2 -2
  61. package/dist/lib/node-esm/{chunk-6GCOJS4Y.mjs → chunk-JELROKGD.mjs} +13 -14
  62. package/dist/lib/node-esm/chunk-JELROKGD.mjs.map +7 -0
  63. package/dist/lib/node-esm/{chunk-LZK3TLKM.mjs → chunk-QH4MC5BE.mjs} +6 -5
  64. package/dist/lib/node-esm/chunk-QH4MC5BE.mjs.map +7 -0
  65. package/dist/lib/node-esm/{chunk-RCIXKCVG.mjs → chunk-SHAMSMKQ.mjs} +5 -7
  66. package/dist/lib/node-esm/chunk-SHAMSMKQ.mjs.map +7 -0
  67. package/dist/lib/node-esm/{chunk-YGNVDYMB.mjs → chunk-SJ2QRGPM.mjs} +8 -4
  68. package/dist/lib/node-esm/chunk-SJ2QRGPM.mjs.map +7 -0
  69. package/dist/lib/node-esm/chunk-YYSASY7X.mjs +96 -0
  70. package/dist/lib/node-esm/chunk-YYSASY7X.mjs.map +7 -0
  71. package/dist/lib/node-esm/index.mjs +32 -20
  72. package/dist/lib/node-esm/index.mjs.map +3 -3
  73. package/dist/lib/node-esm/{intent-resolver-L2UGZ72W.mjs → intent-resolver-Q4XVI5EX.mjs} +20 -18
  74. package/dist/lib/node-esm/intent-resolver-Q4XVI5EX.mjs.map +7 -0
  75. package/dist/lib/node-esm/meta.json +1 -1
  76. package/dist/lib/node-esm/{react-surface-3JJSTTQP.mjs → react-surface-FAMZTAXK.mjs} +83 -74
  77. package/dist/lib/node-esm/react-surface-FAMZTAXK.mjs.map +7 -0
  78. package/dist/lib/node-esm/{settings-LBDWWPZJ.mjs → settings-2YRA67H6.mjs} +5 -5
  79. package/dist/lib/node-esm/{settings-LBDWWPZJ.mjs.map → settings-2YRA67H6.mjs.map} +1 -1
  80. package/dist/lib/node-esm/{state-UIHO2SFZ.mjs → state-K6EH7SRZ.mjs} +5 -5
  81. package/dist/lib/node-esm/state-K6EH7SRZ.mjs.map +7 -0
  82. package/dist/lib/node-esm/toolkit-36BFLIR3.mjs +67 -0
  83. package/dist/lib/node-esm/toolkit-36BFLIR3.mjs.map +7 -0
  84. package/dist/lib/node-esm/types/index.mjs +2 -2
  85. package/dist/types/src/MarkdownPlugin.d.ts +1 -1
  86. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/anchor-sort.d.ts +2 -2
  88. package/dist/types/src/capabilities/app-graph-serializer.d.ts +1 -1
  89. package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +1 -1
  90. package/dist/types/src/capabilities/artifact-definition.d.ts +1 -9
  91. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  92. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
  93. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  94. package/dist/types/src/capabilities/capabilities.d.ts +1 -1
  95. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  96. package/dist/types/src/capabilities/index.d.ts +12 -10
  97. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  98. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  99. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  100. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  101. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  102. package/dist/types/src/capabilities/settings.d.ts +1 -1
  103. package/dist/types/src/capabilities/state.d.ts +2 -2
  104. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  105. package/dist/types/src/capabilities/toolkit.d.ts +20 -0
  106. package/dist/types/src/capabilities/toolkit.d.ts.map +1 -0
  107. package/dist/types/src/components/MarkdownCard/MarkdownCard.d.ts +7 -0
  108. package/dist/types/src/components/MarkdownCard/MarkdownCard.d.ts.map +1 -0
  109. package/dist/types/src/components/MarkdownCard/MarkdownCard.stories.d.ts +9 -0
  110. package/dist/types/src/components/MarkdownCard/MarkdownCard.stories.d.ts.map +1 -0
  111. package/dist/types/src/components/MarkdownCard/index.d.ts +4 -0
  112. package/dist/types/src/components/MarkdownCard/index.d.ts.map +1 -0
  113. package/dist/types/src/components/MarkdownContainer.d.ts +8 -12
  114. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
  115. package/dist/types/src/components/MarkdownContainer.stories.d.ts +54 -5
  116. package/dist/types/src/components/MarkdownContainer.stories.d.ts.map +1 -1
  117. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts +11 -0
  118. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts.map +1 -0
  119. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +42 -23
  120. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  121. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts +8 -15
  122. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts.map +1 -1
  123. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts +26 -0
  124. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts.map +1 -0
  125. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts +12 -0
  126. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts.map +1 -0
  127. package/dist/types/src/components/MarkdownSettings/MarkdownSettings.d.ts.map +1 -1
  128. package/dist/types/src/components/Suggestions.stories.d.ts +1 -2
  129. package/dist/types/src/components/Suggestions.stories.d.ts.map +1 -1
  130. package/dist/types/src/components/index.d.ts +4 -2
  131. package/dist/types/src/components/index.d.ts.map +1 -1
  132. package/dist/types/src/functions/diff.d.ts +6 -0
  133. package/dist/types/src/functions/diff.d.ts.map +1 -0
  134. package/dist/types/src/functions/index.d.ts +3 -0
  135. package/dist/types/src/functions/index.d.ts.map +1 -0
  136. package/dist/types/src/functions/open.d.ts +7 -0
  137. package/dist/types/src/functions/open.d.ts.map +1 -0
  138. package/dist/types/src/hooks/index.d.ts +3 -0
  139. package/dist/types/src/hooks/index.d.ts.map +1 -1
  140. package/dist/types/src/hooks/useExtensions.d.ts +21 -0
  141. package/dist/types/src/hooks/useExtensions.d.ts.map +1 -0
  142. package/dist/types/src/hooks/useLinkQuery.d.ts +4 -0
  143. package/dist/types/src/hooks/useLinkQuery.d.ts.map +1 -0
  144. package/dist/types/src/hooks/usePopoverMenuOptions.d.ts +9 -0
  145. package/dist/types/src/hooks/usePopoverMenuOptions.d.ts.map +1 -0
  146. package/dist/types/src/hooks/useSelectCurrentThread.d.ts +1 -1
  147. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -1
  148. package/dist/types/src/index.d.ts +2 -1
  149. package/dist/types/src/index.d.ts.map +1 -1
  150. package/dist/types/src/meta.d.ts +0 -1
  151. package/dist/types/src/meta.d.ts.map +1 -1
  152. package/dist/types/src/translations.d.ts +4 -0
  153. package/dist/types/src/translations.d.ts.map +1 -1
  154. package/dist/types/src/types/Markdown.d.ts +7 -5
  155. package/dist/types/src/types/Markdown.d.ts.map +1 -1
  156. package/dist/types/src/types/MarkdownAction.d.ts +6 -14
  157. package/dist/types/src/types/MarkdownAction.d.ts.map +1 -1
  158. package/dist/types/src/types/types.d.ts.map +1 -1
  159. package/dist/types/src/util.d.ts +1 -1
  160. package/dist/types/src/util.d.ts.map +1 -1
  161. package/dist/types/tsconfig.tsbuildinfo +1 -1
  162. package/package.json +62 -56
  163. package/src/MarkdownPlugin.tsx +103 -94
  164. package/src/capabilities/app-graph-serializer.ts +4 -4
  165. package/src/capabilities/artifact-definition.ts +15 -19
  166. package/src/capabilities/blueprint-definition.ts +39 -0
  167. package/src/capabilities/capabilities.ts +2 -1
  168. package/src/capabilities/index.ts +3 -1
  169. package/src/capabilities/intent-resolver.ts +14 -13
  170. package/src/capabilities/react-surface.tsx +39 -60
  171. package/src/capabilities/state.ts +3 -2
  172. package/src/capabilities/toolkit.ts +53 -0
  173. package/src/components/{MarkdownPreview/MarkdownPreview.stories.tsx → MarkdownCard/MarkdownCard.stories.tsx} +14 -15
  174. package/src/components/{MarkdownPreview/MarkdownPreview.tsx → MarkdownCard/MarkdownCard.tsx} +45 -33
  175. package/src/components/MarkdownCard/index.ts +9 -0
  176. package/src/components/MarkdownContainer.stories.tsx +80 -43
  177. package/src/components/MarkdownContainer.tsx +86 -219
  178. package/src/components/MarkdownEditor/FileUpload.tsx +63 -0
  179. package/src/components/MarkdownEditor/MarkdownEditor.stories.tsx +58 -34
  180. package/src/components/MarkdownEditor/MarkdownEditor.tsx +220 -271
  181. package/src/components/MarkdownEditor/MarkdownEditorContent.tsx +134 -0
  182. package/src/components/MarkdownEditor/MarkdownEditorToolbar.tsx +63 -0
  183. package/src/components/MarkdownSettings/MarkdownSettings.tsx +77 -74
  184. package/src/components/Suggestions.stories.tsx +40 -41
  185. package/src/components/index.ts +3 -1
  186. package/src/functions/diff.ts +37 -0
  187. package/src/functions/index.ts +6 -0
  188. package/src/functions/open.ts +32 -0
  189. package/src/hooks/index.ts +3 -0
  190. package/src/{extensions.tsx → hooks/useExtensions.tsx} +61 -119
  191. package/src/hooks/useLinkQuery.ts +82 -0
  192. package/src/hooks/usePopoverMenuOptions.ts +71 -0
  193. package/src/hooks/useSelectCurrentThread.tsx +3 -3
  194. package/src/index.ts +3 -1
  195. package/src/meta.ts +3 -6
  196. package/src/translations.ts +4 -0
  197. package/src/types/Markdown.ts +8 -5
  198. package/src/types/MarkdownAction.ts +5 -6
  199. package/src/types/types.ts +1 -0
  200. package/src/util.tsx +9 -2
  201. package/dist/lib/browser/MarkdownContainer-NNBPE6A5.mjs +0 -779
  202. package/dist/lib/browser/MarkdownContainer-NNBPE6A5.mjs.map +0 -7
  203. package/dist/lib/browser/MarkdownPreview-7VG3K24R.mjs +0 -80
  204. package/dist/lib/browser/MarkdownPreview-7VG3K24R.mjs.map +0 -7
  205. package/dist/lib/browser/app-graph-serializer-ZT5OVF5G.mjs.map +0 -7
  206. package/dist/lib/browser/artifact-definition-7VNP5PCP.mjs +0 -145
  207. package/dist/lib/browser/artifact-definition-7VNP5PCP.mjs.map +0 -7
  208. package/dist/lib/browser/chunk-K7ZFMSC4.mjs.map +0 -7
  209. package/dist/lib/browser/chunk-VCUKIILA.mjs +0 -20
  210. package/dist/lib/browser/chunk-VCUKIILA.mjs.map +0 -7
  211. package/dist/lib/browser/chunk-VMX5SDGW.mjs.map +0 -7
  212. package/dist/lib/browser/chunk-YHMGUSO7.mjs.map +0 -7
  213. package/dist/lib/browser/chunk-ZGY3DYC2.mjs.map +0 -7
  214. package/dist/lib/browser/intent-resolver-EBEF7WEI.mjs.map +0 -7
  215. package/dist/lib/browser/react-surface-ZPMZT4VU.mjs.map +0 -7
  216. package/dist/lib/browser/state-ZA6PZPUI.mjs.map +0 -7
  217. package/dist/lib/node-esm/MarkdownContainer-Q6UO7DKT.mjs +0 -780
  218. package/dist/lib/node-esm/MarkdownContainer-Q6UO7DKT.mjs.map +0 -7
  219. package/dist/lib/node-esm/MarkdownPreview-UVWR2YK3.mjs +0 -81
  220. package/dist/lib/node-esm/MarkdownPreview-UVWR2YK3.mjs.map +0 -7
  221. package/dist/lib/node-esm/app-graph-serializer-X4M5QEI6.mjs.map +0 -7
  222. package/dist/lib/node-esm/artifact-definition-IRIILD7S.mjs +0 -146
  223. package/dist/lib/node-esm/artifact-definition-IRIILD7S.mjs.map +0 -7
  224. package/dist/lib/node-esm/chunk-6GCOJS4Y.mjs.map +0 -7
  225. package/dist/lib/node-esm/chunk-A7LLVI34.mjs +0 -22
  226. package/dist/lib/node-esm/chunk-A7LLVI34.mjs.map +0 -7
  227. package/dist/lib/node-esm/chunk-LZK3TLKM.mjs.map +0 -7
  228. package/dist/lib/node-esm/chunk-RCIXKCVG.mjs.map +0 -7
  229. package/dist/lib/node-esm/chunk-YGNVDYMB.mjs.map +0 -7
  230. package/dist/lib/node-esm/intent-resolver-L2UGZ72W.mjs.map +0 -7
  231. package/dist/lib/node-esm/react-surface-3JJSTTQP.mjs.map +0 -7
  232. package/dist/lib/node-esm/state-UIHO2SFZ.mjs.map +0 -7
  233. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts +0 -6
  234. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.d.ts.map +0 -1
  235. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts +0 -10
  236. package/dist/types/src/components/MarkdownPreview/MarkdownPreview.stories.d.ts.map +0 -1
  237. package/dist/types/src/components/MarkdownPreview/index.d.ts +0 -4
  238. package/dist/types/src/components/MarkdownPreview/index.d.ts.map +0 -1
  239. package/dist/types/src/components/Toolbar.stories.d.ts +0 -11
  240. package/dist/types/src/components/Toolbar.stories.d.ts.map +0 -1
  241. package/dist/types/src/extensions.d.ts +0 -24
  242. package/dist/types/src/extensions.d.ts.map +0 -1
  243. package/src/components/MarkdownPreview/index.ts +0 -9
  244. package/src/components/Toolbar.stories.tsx +0 -112
@@ -2,252 +2,119 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { type Extension } from '@codemirror/state';
5
6
  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';
7
+ import React, { useMemo } from 'react';
8
+
9
+ import { Capabilities, useAppGraph, useCapabilities } from '@dxos/app-framework';
10
+ import { Obj } from '@dxos/echo';
11
+ import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
15
12
  import { type SelectionManager } from '@dxos/react-ui-attention';
16
- import {
17
- type CommandMenuGroup,
18
- type CommandMenuItem,
19
- insertAtCursor,
20
- insertAtLineStart,
21
- type PreviewLinkRef,
22
- type PreviewOptions,
23
- } from '@dxos/react-ui-editor';
13
+ import { StackItem } from '@dxos/react-ui-stack';
24
14
  import { DataType } from '@dxos/schema';
25
15
 
26
- import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
27
- import { useExtensions } from '../extensions';
28
- import { Markdown } from '../types';
29
- import { getFallbackName } from '../util';
30
-
31
- export type MarkdownContainerProps = Pick<
32
- MarkdownEditorProps,
33
- 'role' | 'extensionProviders' | 'viewMode' | 'editorStateStore' | 'onViewModeChange'
34
- > & {
35
- id: string;
36
- object: Markdown.Document | DataType.Text | any;
16
+ import { MarkdownCapabilities } from '../capabilities';
17
+ import { type DocumentType, useLinkQuery } from '../hooks';
18
+ import { Markdown, type MarkdownPluginState } from '../types';
19
+
20
+ import { MarkdownEditor, type MarkdownEditorContentProps, type MarkdownEditorRootProps } from './MarkdownEditor';
21
+
22
+ export type MarkdownContainerProps = {
23
+ role?: string;
24
+ object: DocumentType;
37
25
  settings: Markdown.Settings;
38
26
  selectionManager?: SelectionManager;
39
- };
27
+ } & (Pick<MarkdownEditorRootProps, 'id' | 'viewMode' | 'onViewModeChange'> &
28
+ Pick<MarkdownEditorContentProps, 'editorStateStore'> &
29
+ Pick<MarkdownPluginState, 'extensionProviders'>);
30
+
31
+ // TODO(burdon): Attention doesn't update in storybook.
32
+ // TODO(burdon): Toolbar state (currently not working in labs: e.g., heading, list, table).
33
+ // Heading state is correct (see react-ui-editor headings.ts, but the toolbar isn't updated).
34
+ // TODO(burdon): View mode (currently not working in labs).
35
+ // TODO(burdon): Test update document name.
36
+ // TODO(burdon): Test comment threads.
37
+ // TODO(burdon): Test preview blocks.
38
+ // TODO(burdon): Test file upload.
40
39
 
41
40
  export const MarkdownContainer = ({
42
41
  id,
43
42
  role,
44
43
  object,
45
44
  settings,
46
- selectionManager,
47
- viewMode,
48
- editorStateStore,
49
- onViewModeChange,
45
+ extensionProviders,
46
+ ...props
50
47
  }: MarkdownContainerProps) => {
51
- const { t } = useTranslation();
52
- const scrollPastEnd = role === 'article';
53
- const doc = Obj.instanceOf(Markdown.Document, object) ? object : undefined;
54
- const text = Obj.instanceOf(DataType.Text, object) ? object : undefined;
55
- const [previewBlocks, setPreviewBlocks] = useState<{ link: PreviewLinkRef; el: HTMLElement }[]>([]);
56
- const previewOptions = useMemo(
57
- (): PreviewOptions => ({
58
- addBlockContainer: (link, el) => {
59
- setPreviewBlocks((prev) => [...prev, { link, el }]);
60
- },
61
- removeBlockContainer: (link) => {
62
- setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.ref !== link.ref));
63
- },
64
- }),
65
- [],
66
- );
67
- const extensions = useExtensions({
68
- document: doc,
69
- text,
70
- id,
71
- settings,
72
- selectionManager,
73
- viewMode,
74
- editorStateStore,
75
- previewOptions,
76
- });
77
-
78
- // TODO(wittjosiah): Factor out.
79
- const manager = usePluginManager();
80
- const resolve = useCallback(
81
- (typename: string) =>
82
- manager.context.getCapabilities(Capabilities.Metadata).find(({ id }) => id === typename)?.metadata ?? {},
83
- [manager],
84
- );
85
48
  const space = getSpace(object);
86
- const objectForms = useCapabilities(SpaceCapabilities.ObjectForm);
87
- const schemaWhiteList = useCapabilities(ClientCapabilities.SchemaWhiteList);
88
- const filter = useMemo(
89
- () =>
90
- Filter.or(
91
- ...objectForms.map((form) => Filter.type(form.objectSchema)),
92
- ...schemaWhiteList.flat().map((schema) => Filter.typename(Type.getTypename(schema))),
93
- ),
94
- [objectForms, schemaWhiteList],
95
- );
96
- const onLinkQuery = useCallback(
97
- async (query?: string): Promise<CommandMenuGroup[]> => {
98
- const name = query?.startsWith('@') ? query.slice(1).toLowerCase() : (query?.toLowerCase() ?? '');
99
- const results = await space?.db.query(Query.select(filter)).run();
100
- // TODO(wittjosiah): Use `Obj.Any` type.
101
- const getLabel = (object: any) => {
102
- const label = Obj.getLabel(object);
103
- if (label) {
104
- return label;
105
- }
106
-
107
- // TODO(wittjosiah): Remove metadata labels.
108
- const type = Obj.getTypename(object)!;
109
- const metadata = resolve(type);
110
- return metadata.label?.(object) || ['object name placeholder', { ns: type, default: 'New object' }];
111
- };
112
- const items =
113
- results?.objects
114
- .filter((object) => toLocalizedString(getLabel(object), t).toLowerCase().includes(name))
115
- // TODO(wittjosiah): Remove `any` type.
116
- .map((object: any): CommandMenuItem => {
117
- const metadata = resolve(Obj.getTypename(object)!);
118
- const label = toLocalizedString(getLabel(object), t);
119
- return {
120
- id: object.id,
121
- label,
122
- icon: metadata.icon,
123
- onSelect: (view, head) => {
124
- const link = `[${label}][${Obj.getDXN(object)}]`;
125
- if (query?.startsWith('@')) {
126
- insertAtLineStart(view, head, `!${link}\n`);
127
- } else {
128
- insertAtCursor(view, head, `${link} `);
129
- }
130
- },
131
- };
132
- }) ?? [];
133
- return [{ id: 'echo', items }];
134
- },
135
- [filter, resolve, space],
136
- );
137
-
138
- const editor = doc ? (
139
- <DocumentEditor
140
- id={fullyQualifiedId(object)}
141
- role={role}
142
- document={doc}
143
- extensions={extensions}
144
- viewMode={viewMode}
145
- settings={settings}
146
- scrollPastEnd={scrollPastEnd}
147
- onViewModeChange={onViewModeChange}
148
- onLinkQuery={space ? onLinkQuery : undefined}
149
- />
150
- ) : text ? (
151
- <MarkdownEditor
152
- id={id}
153
- role={role}
154
- initialValue={text.content}
155
- extensions={extensions}
156
- viewMode={viewMode}
157
- toolbar={settings.toolbar}
158
- inputMode={settings.editorInputMode}
159
- scrollPastEnd={scrollPastEnd}
160
- onViewModeChange={onViewModeChange}
161
- onLinkQuery={space ? onLinkQuery : undefined}
162
- />
163
- ) : (
164
- // TODO(burdon): Normalize with above.
165
- <MarkdownEditor
166
- id={id}
167
- role={role}
168
- initialValue={object.text}
169
- extensions={extensions}
170
- viewMode={viewMode}
171
- toolbar={settings.toolbar}
172
- inputMode={settings.editorInputMode}
173
- scrollPastEnd={scrollPastEnd}
174
- onViewModeChange={onViewModeChange}
175
- onLinkQuery={space ? onLinkQuery : undefined}
176
- />
177
- );
178
-
179
- return (
180
- <>
181
- {editor}
182
- {previewBlocks.map(({ link, el }) => (
183
- <PreviewBlock key={link.ref} link={link} el={el} />
184
- ))}
185
- </>
186
- );
187
- };
188
-
189
- // TODO(wittjosiah): This shouldn't be "card" but "block".
190
- // It's not a preview card but an interactive embedded object.
191
- const PreviewBlock = ({ link, el }: { link: PreviewLinkRef; el: HTMLElement }) => {
192
- const echoDXN = useMemo(() => DXN.parse(link.ref).asEchoDXN(), [link.ref]);
193
- const space = useSpace(echoDXN?.spaceId);
194
- const [subject] = useQuery(space, Query.select(Filter.ids(echoDXN?.echoId ?? '')));
195
- const data = useMemo(() => ({ subject }), [subject]);
196
-
197
- return createPortal(<Surface role='card--transclusion' data={data} limit={1} />, el);
198
- };
199
-
200
- type DocumentEditorProps = Omit<MarkdownContainerProps, 'object' | 'extensionProviders' | 'editorStateStore'> &
201
- Pick<MarkdownEditorProps, 'id' | 'scrollPastEnd' | 'extensions' | 'onLinkQuery'> & {
202
- document: Markdown.Document;
203
- };
204
-
205
- export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props }: DocumentEditorProps) => {
206
- const space = getSpace(doc);
207
-
208
- // Migrate gradually to `fallbackName`.
209
- useEffect(() => {
210
- if (typeof doc.fallbackName === 'string') {
211
- return;
49
+ const isDocument = Obj.instanceOf(Markdown.Document, object);
50
+ const isText = Obj.instanceOf(DataType.Text, object);
51
+ const attendableId = isDocument ? fullyQualifiedId(object) : undefined;
52
+
53
+ // Extensions from other plugins.
54
+ // TODO(burdon): Document MarkdownPluginState.extensionProviders
55
+ const otherExtensionProviders = useCapabilities(MarkdownCapabilities.Extensions);
56
+ const extensions = useMemo<Extension[]>(() => {
57
+ if (!Obj.instanceOf(Markdown.Document, object)) {
58
+ return [];
212
59
  }
213
60
 
214
- const fallbackName = doc.content?.target?.content ? getFallbackName(doc.content.target.content) : undefined;
215
- if (fallbackName) {
216
- doc.fallbackName = fallbackName;
217
- }
218
- }, [doc, doc.content]);
61
+ return [...(otherExtensionProviders ?? []), ...(extensionProviders ?? [])]
62
+ .flat()
63
+ .reduce((acc: Extension[], provider) => {
64
+ const extension =
65
+ typeof provider === 'function' ? provider({ document: object as Markdown.Document }) : provider;
66
+ if (extension) {
67
+ acc.push(extension);
68
+ }
219
69
 
220
- // File dragging.
221
- const [upload] = useCapabilities(Capabilities.FileUploader);
222
- const handleFileUpload = useMemo(() => {
223
- if (space === undefined || upload === undefined) {
224
- return undefined;
225
- }
226
-
227
- // TODO(burdon): Re-order props: space, file.
228
- return async (file: File) => upload!(file, space);
229
- }, [space, upload]);
70
+ return acc;
71
+ }, []);
72
+ }, [extensionProviders, otherExtensionProviders, object]);
230
73
 
74
+ // Toolbar actions from app graph.
231
75
  const { graph } = useAppGraph();
232
76
  const customActions = useMemo(() => {
233
77
  return Rx.make((get) => {
234
78
  const actions = get(graph.actions(id));
235
79
  const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
236
- return { nodes, edges: nodes.map((node) => ({ source: 'root', target: node.id })) };
80
+ const edges = nodes.map((node) => ({ source: 'root', target: node.id }));
81
+ return { nodes, edges };
237
82
  });
238
83
  }, [graph]);
239
84
 
85
+ // File upload.
86
+ const [upload] = useCapabilities(Capabilities.FileUploader);
87
+ const handleFileUpload = useMemo(() => {
88
+ if (!space || !upload) {
89
+ return undefined;
90
+ }
91
+
92
+ return async (file: File) => upload(space, file);
93
+ }, [space, upload]);
94
+
95
+ // Query for @ refs.
96
+ const handleLinkQuery = useLinkQuery(space);
97
+
240
98
  return (
241
- <MarkdownEditor
242
- id={id}
243
- initialValue={doc.content?.target?.content}
244
- viewMode={viewMode}
245
- toolbar={settings.toolbar}
246
- customActions={customActions}
247
- inputMode={settings.editorInputMode}
248
- onFileUpload={handleFileUpload}
249
- {...props}
250
- />
99
+ <StackItem.Content toolbar={settings.toolbar}>
100
+ <MarkdownEditor.Root
101
+ id={attendableId ?? id}
102
+ object={object}
103
+ extensions={extensions}
104
+ onFileUpload={handleFileUpload}
105
+ onLinkQuery={handleLinkQuery}
106
+ {...props}
107
+ >
108
+ {settings.toolbar && (
109
+ <MarkdownEditor.Toolbar id={attendableId ?? id} role={role} customActions={customActions} />
110
+ )}
111
+ <MarkdownEditor.Content
112
+ initialValue={isDocument ? object.content?.target?.content : isText ? object.content : object.text}
113
+ scrollPastEnd={role === 'article'}
114
+ />
115
+ <MarkdownEditor.Blocks />
116
+ </MarkdownEditor.Root>
117
+ </StackItem.Content>
251
118
  );
252
119
  };
253
120
 
@@ -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,43 +2,76 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type Meta } from '@storybook/react-vite';
8
- import React, { useMemo } from 'react';
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
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 } from '@dxos/echo';
11
+ import { AttentionPlugin } from '@dxos/plugin-attention';
12
+ import { ClientPlugin } from '@dxos/plugin-client';
13
+ import { fullyQualifiedId, 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
- import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
18
19
  import { translations } from '../../translations';
20
+ import { Markdown } from '../../types';
21
+
22
+ import { MarkdownEditor, type MarkdownEditorRootProps } from './MarkdownEditor';
19
23
 
20
24
  const content = Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n');
21
25
 
22
- type StoryProps = MarkdownEditorProps & {
23
- content?: string;
24
- toolbar?: boolean;
25
- };
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 && fullyQualifiedId(doc);
32
+ const attentionAttrs = useAttentionAttributes(id);
33
+
34
+ if (!id) {
35
+ return null;
36
+ }
26
37
 
27
- const DefaultStory = ({ content = '# Test', toolbar }: StoryProps) => {
28
- const doc = useMemo(() => createObject({ content }), [content]); // TODO(burdon): Remove dependency on createObject.
29
- const extensions = useMemo(() => [automerge(createDocAccessor(doc, ['content']))], [doc]);
30
- return <MarkdownEditor id='test' initialValue={doc.content} extensions={extensions} toolbar={toolbar} />;
38
+ // TODO(burdon): Toolbar attention isn't working in this story.
39
+ return (
40
+ <div className='contents' {...attentionAttrs}>
41
+ <StackItem.Content toolbar>
42
+ <MarkdownEditor.Root id={id} object={doc} {...props}>
43
+ <MarkdownEditor.Toolbar id={id} />
44
+ <MarkdownEditor.Content />
45
+ </MarkdownEditor.Root>
46
+ </StackItem.Content>
47
+ </div>
48
+ );
31
49
  };
32
50
 
33
- const meta: Meta<typeof MarkdownEditor> = {
51
+ const meta: Meta<typeof DefaultStory> = {
34
52
  title: 'plugins/plugin-markdown/MarkdownEditor',
35
- component: MarkdownEditor,
36
- render: DefaultStory,
53
+ component: DefaultStory,
54
+ render: DefaultStory as any,
37
55
  decorators: [
38
- withPluginManager({ plugins: [IntentPlugin()] }),
39
- withAttention,
40
56
  withTheme,
41
- withLayout({ fullscreen: true }),
57
+ withLayout({ container: 'column' }),
58
+ // TODO(burdon): Create story without client.
59
+ withPluginManager({
60
+ plugins: [
61
+ ClientPlugin({
62
+ types: [Markdown.Document],
63
+ onClientInitialized: async ({ client }) => {
64
+ await client.halo.createIdentity();
65
+ await client.spaces.waitUntilReady();
66
+ const space = client.spaces.default;
67
+ await space.waitUntilReady();
68
+ space.db.add(Markdown.makeDocument({ content }));
69
+ },
70
+ }),
71
+ IntentPlugin(),
72
+ AttentionPlugin(),
73
+ ],
74
+ }),
42
75
  ],
43
76
  parameters: {
44
77
  translations: [...translations, ...editorTranslations],
@@ -47,15 +80,6 @@ const meta: Meta<typeof MarkdownEditor> = {
47
80
 
48
81
  export default meta;
49
82
 
50
- export const Default = {
51
- args: {
52
- content,
53
- },
54
- };
83
+ type Story = StoryObj<typeof meta>;
55
84
 
56
- export const WithToolbar = {
57
- args: {
58
- toolbar: true,
59
- content,
60
- },
61
- };
85
+ export const Default: Story = {};