@dxos/plugin-markdown 0.9.0 → 0.9.1-staging.ee54ba693a

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 (255) hide show
  1. package/dist/lib/neutral/{MarkdownArticle-LWT5RFFJ.mjs → MarkdownArticle-ZHBXH7YF.mjs} +5 -7
  2. package/dist/lib/neutral/MarkdownArticle-ZHBXH7YF.mjs.map +7 -0
  3. package/dist/lib/neutral/{MarkdownCard-TBLIRDBO.mjs → MarkdownCard-2HUXCGZP.mjs} +3 -3
  4. package/dist/lib/neutral/MarkdownCard-2HUXCGZP.mjs.map +7 -0
  5. package/dist/lib/neutral/MarkdownPlugin.mjs +8 -15
  6. package/dist/lib/neutral/MarkdownPlugin.mjs.map +3 -3
  7. package/dist/lib/neutral/MarkdownPlugin.node.mjs +4 -2
  8. package/dist/lib/neutral/MarkdownPlugin.node.mjs.map +3 -3
  9. package/dist/lib/neutral/MarkdownPlugin.workerd.mjs +6 -17
  10. package/dist/lib/neutral/MarkdownPlugin.workerd.mjs.map +4 -4
  11. package/dist/lib/neutral/MarkdownSettings-5VMOYMND.mjs +43 -0
  12. package/dist/lib/neutral/MarkdownSettings-5VMOYMND.mjs.map +7 -0
  13. package/dist/lib/neutral/{anchor-sort-UXN4RHFX.mjs → anchor-sort-QF7UDG2A.mjs} +4 -3
  14. package/dist/lib/neutral/anchor-sort-QF7UDG2A.mjs.map +7 -0
  15. package/dist/lib/neutral/capabilities/index.mjs +10 -16
  16. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  17. package/dist/lib/neutral/capabilities/node.mjs +5 -3
  18. package/dist/lib/neutral/capabilities/node.mjs.map +3 -3
  19. package/dist/lib/neutral/chunk-2V6A5NDQ.mjs +8 -0
  20. package/dist/lib/neutral/{operation-handler-2ARMPBGZ.mjs → chunk-ANHHOTCD.mjs} +3 -4
  21. package/dist/lib/neutral/{operation-handler-2ARMPBGZ.mjs.map → chunk-ANHHOTCD.mjs.map} +1 -1
  22. package/dist/lib/neutral/chunk-CNYFGIDS.mjs +32 -0
  23. package/dist/lib/neutral/chunk-CNYFGIDS.mjs.map +7 -0
  24. package/dist/lib/neutral/{chunk-LXNSKCPD.mjs → chunk-EV4ZOL4P.mjs} +12 -11
  25. package/dist/lib/neutral/chunk-EV4ZOL4P.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-OC3JD73N.mjs +43 -0
  27. package/dist/lib/neutral/chunk-OC3JD73N.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-YJF6XOXX.mjs +175 -0
  29. package/dist/lib/neutral/chunk-YJF6XOXX.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-YMBC62S7.mjs +14 -0
  31. package/dist/lib/neutral/chunk-YMBC62S7.mjs.map +7 -0
  32. package/dist/lib/neutral/{chunk-Y2LQRUU7.mjs → chunk-ZJ3GWRUJ.mjs} +24 -23
  33. package/dist/lib/neutral/chunk-ZJ3GWRUJ.mjs.map +7 -0
  34. package/dist/lib/neutral/{comment-config-EGY7RPPW.mjs → comment-config-M5OGFULS.mjs} +6 -4
  35. package/dist/lib/neutral/comment-config-M5OGFULS.mjs.map +7 -0
  36. package/dist/lib/neutral/components/index.mjs +19 -57
  37. package/dist/lib/neutral/components/index.mjs.map +4 -4
  38. package/dist/lib/neutral/containers/index.mjs +5 -3
  39. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  40. package/dist/lib/neutral/{create-JK35XC4R.mjs → create-OQUMKL5I.mjs} +2 -2
  41. package/dist/lib/neutral/{create-markdown-7MLE625M.mjs → create-markdown-4O5FDA77.mjs} +2 -2
  42. package/dist/lib/neutral/{create-object-MU2LGXG6.mjs → create-object-RSEWTCMM.mjs} +2 -6
  43. package/dist/lib/neutral/create-object-RSEWTCMM.mjs.map +7 -0
  44. package/dist/lib/neutral/hooks/index.mjs +53 -23
  45. package/dist/lib/neutral/hooks/index.mjs.map +3 -3
  46. package/dist/lib/neutral/index.mjs +10 -16
  47. package/dist/lib/neutral/meta.json +1 -1
  48. package/dist/lib/neutral/meta.mjs +1 -1
  49. package/dist/lib/neutral/{open-5YC77C4O.mjs → open-BAZIRXII.mjs} +2 -2
  50. package/dist/lib/neutral/operation-handler-SDCXGMGK.mjs +8 -0
  51. package/dist/lib/neutral/operations/index.mjs +1 -1
  52. package/dist/lib/neutral/plugin.mjs +2 -2
  53. package/dist/lib/neutral/plugin.workerd.mjs +12 -0
  54. package/dist/lib/neutral/plugin.workerd.mjs.map +7 -0
  55. package/dist/lib/neutral/{react-surface-XYZJBKHZ.mjs → react-surface-37GL3UVG.mjs} +10 -15
  56. package/dist/lib/neutral/react-surface-37GL3UVG.mjs.map +7 -0
  57. package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs → scroll-to-anchor-I6HFE5AH.mjs} +2 -2
  58. package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs → set-view-mode-NY5OYYIM.mjs} +2 -2
  59. package/dist/lib/neutral/{settings-TDGDLCUR.mjs → settings-O6O6HT3I.mjs} +3 -3
  60. package/dist/lib/neutral/settings-O6O6HT3I.mjs.map +7 -0
  61. package/dist/lib/neutral/skill-definition-ET7BYY47.mjs +8 -0
  62. package/dist/lib/neutral/skill-definition-ET7BYY47.mjs.map +7 -0
  63. package/dist/lib/neutral/skills/index.mjs +8 -0
  64. package/dist/lib/neutral/skills/index.mjs.map +7 -0
  65. package/dist/lib/neutral/state-3BR7L6CW.mjs +69 -0
  66. package/dist/lib/neutral/state-3BR7L6CW.mjs.map +7 -0
  67. package/dist/lib/neutral/testing.mjs +2 -2
  68. package/dist/lib/neutral/testing.mjs.map +3 -3
  69. package/dist/lib/neutral/translations.mjs +1 -1
  70. package/dist/lib/neutral/translations.mjs.map +3 -3
  71. package/dist/lib/neutral/types/index.mjs +1 -1
  72. package/dist/lib/neutral/update-markdown-M4PTA6VS.mjs +24 -0
  73. package/dist/lib/neutral/update-markdown-M4PTA6VS.mjs.map +7 -0
  74. package/dist/types/dx.config.d.ts +28 -0
  75. package/dist/types/dx.config.d.ts.map +1 -0
  76. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  77. package/dist/types/src/MarkdownPlugin.node.d.ts.map +1 -1
  78. package/dist/types/src/MarkdownPlugin.workerd.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/anchor-sort.d.ts +1 -2
  80. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/comment-config.d.ts +1 -2
  82. package/dist/types/src/capabilities/comment-config.d.ts.map +1 -1
  83. package/dist/types/src/capabilities/create-object.d.ts +1 -7
  84. package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/editor-view-state.d.ts +7 -0
  86. package/dist/types/src/capabilities/editor-view-state.d.ts.map +1 -0
  87. package/dist/types/src/capabilities/index.d.ts +7 -16
  88. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  89. package/dist/types/src/capabilities/node.d.ts +2 -6
  90. package/dist/types/src/capabilities/node.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  92. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/settings.d.ts +1 -2
  94. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  95. package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
  96. package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
  97. package/dist/types/src/capabilities/state.d.ts +1 -2
  98. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  99. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts +2 -2
  100. package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts.map +1 -1
  101. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +5 -6
  102. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  103. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts +3 -2
  104. package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts.map +1 -1
  105. package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts.map +1 -1
  106. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts +2 -2
  107. package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts.map +1 -1
  108. package/dist/types/src/components/PreviewComponent/PreviewComponent.d.ts +17 -0
  109. package/dist/types/src/components/PreviewComponent/PreviewComponent.d.ts.map +1 -0
  110. package/dist/types/src/components/PreviewComponent/index.d.ts +2 -0
  111. package/dist/types/src/components/PreviewComponent/index.d.ts.map +1 -0
  112. package/dist/types/src/components/index.d.ts +1 -2
  113. package/dist/types/src/components/index.d.ts.map +1 -1
  114. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts +6 -17
  115. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts.map +1 -1
  116. package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.stories.d.ts.map +1 -1
  117. package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.d.ts +1 -1
  118. package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.d.ts.map +1 -1
  119. package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.d.ts.map +1 -1
  120. package/dist/types/src/{components → containers}/MarkdownSettings/index.d.ts.map +1 -1
  121. package/dist/types/src/containers/index.d.ts +1 -0
  122. package/dist/types/src/containers/index.d.ts.map +1 -1
  123. package/dist/types/src/hooks/useExtensions.d.ts +5 -5
  124. package/dist/types/src/hooks/useExtensions.d.ts.map +1 -1
  125. package/dist/types/src/hooks/useLinkQuery.d.ts +2 -2
  126. package/dist/types/src/hooks/useLinkQuery.d.ts.map +1 -1
  127. package/dist/types/src/index.d.ts +1 -2
  128. package/dist/types/src/index.d.ts.map +1 -1
  129. package/dist/types/src/meta.d.ts +32 -2
  130. package/dist/types/src/meta.d.ts.map +1 -1
  131. package/dist/types/src/operations/update-markdown.d.ts.map +1 -1
  132. package/dist/types/src/plugin.workerd.d.ts +2 -0
  133. package/dist/types/src/plugin.workerd.d.ts.map +1 -0
  134. package/dist/types/src/skills/index.d.ts +2 -0
  135. package/dist/types/src/skills/index.d.ts.map +1 -0
  136. package/dist/types/src/skills/markdown-skill.d.ts +4 -0
  137. package/dist/types/src/skills/markdown-skill.d.ts.map +1 -0
  138. package/dist/types/src/types/Markdown.d.ts +12 -20
  139. package/dist/types/src/types/Markdown.d.ts.map +1 -1
  140. package/dist/types/src/types/MarkdownCapabilities.d.ts.map +1 -1
  141. package/dist/types/src/types/MarkdownOperation.d.ts +5 -28
  142. package/dist/types/src/types/MarkdownOperation.d.ts.map +1 -1
  143. package/dist/types/src/types/types.d.ts +2 -0
  144. package/dist/types/src/types/types.d.ts.map +1 -1
  145. package/dist/types/tsconfig.tsbuildinfo +1 -1
  146. package/dx.config.ts +31 -0
  147. package/package.json +67 -59
  148. package/src/MarkdownPlugin.node.ts +2 -1
  149. package/src/MarkdownPlugin.test.ts +1 -1
  150. package/src/MarkdownPlugin.tsx +7 -16
  151. package/src/MarkdownPlugin.workerd.ts +5 -2
  152. package/src/capabilities/anchor-sort.ts +3 -2
  153. package/src/capabilities/comment-config.ts +6 -9
  154. package/src/capabilities/create-object.ts +1 -4
  155. package/src/capabilities/editor-view-state.ts +28 -0
  156. package/src/capabilities/index.ts +2 -16
  157. package/src/capabilities/node.ts +1 -0
  158. package/src/capabilities/react-surface.tsx +29 -13
  159. package/src/capabilities/settings.ts +2 -2
  160. package/src/capabilities/skill-definition.ts +14 -0
  161. package/src/capabilities/state.ts +8 -4
  162. package/src/components/MarkdownEditor/FileUpload.tsx +2 -2
  163. package/src/components/MarkdownEditor/MarkdownEditor.stories.tsx +72 -30
  164. package/src/components/MarkdownEditor/MarkdownEditor.tsx +14 -40
  165. package/src/components/MarkdownEditor/MarkdownEditorContent.tsx +7 -6
  166. package/src/components/MarkdownEditor/MarkdownEditorToolbar.tsx +2 -2
  167. package/src/components/PreviewComponent/PreviewComponent.tsx +195 -0
  168. package/src/components/PreviewComponent/index.ts +5 -0
  169. package/src/components/index.ts +1 -4
  170. package/src/containers/MarkdownArticle/MarkdownArticle.stories.tsx +3 -4
  171. package/src/containers/MarkdownArticle/MarkdownArticle.tsx +6 -6
  172. package/src/containers/MarkdownCard/MarkdownCard.tsx +2 -2
  173. package/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.tsx +1 -1
  174. package/src/containers/MarkdownSettings/MarkdownSettings.tsx +54 -0
  175. package/src/containers/index.ts +1 -0
  176. package/src/hooks/useEditorMenuOptions.ts +2 -2
  177. package/src/hooks/useExtensions.tsx +42 -22
  178. package/src/hooks/useLinkQuery.ts +5 -3
  179. package/src/index.ts +1 -2
  180. package/src/meta.ts +2 -22
  181. package/src/operations/create.conversations.json +1 -1
  182. package/src/operations/create.test.ts +5 -12
  183. package/src/operations/update-markdown.ts +7 -27
  184. package/src/operations/update.conversations.json +1 -1
  185. package/src/operations/update.test.ts +86 -16
  186. package/src/plugin.workerd.ts +5 -0
  187. package/src/skills/index.ts +5 -0
  188. package/src/{blueprints/markdown-blueprint.ts → skills/markdown-skill.ts} +8 -7
  189. package/src/testing.ts +2 -2
  190. package/src/translations.ts +1 -1
  191. package/src/types/Markdown.ts +20 -19
  192. package/src/types/MarkdownCapabilities.ts +7 -5
  193. package/src/types/MarkdownEvents.ts +1 -1
  194. package/src/types/MarkdownOperation.ts +12 -6
  195. package/src/types/types.ts +2 -7
  196. package/dist/lib/neutral/MarkdownArticle-LWT5RFFJ.mjs.map +0 -7
  197. package/dist/lib/neutral/MarkdownCard-TBLIRDBO.mjs.map +0 -7
  198. package/dist/lib/neutral/MarkdownSettings-YCTZJL5V.mjs +0 -32
  199. package/dist/lib/neutral/MarkdownSettings-YCTZJL5V.mjs.map +0 -7
  200. package/dist/lib/neutral/anchor-sort-UXN4RHFX.mjs.map +0 -7
  201. package/dist/lib/neutral/app-graph-builder-BWBA23FF.mjs +0 -67
  202. package/dist/lib/neutral/app-graph-builder-BWBA23FF.mjs.map +0 -7
  203. package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs +0 -56
  204. package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs.map +0 -7
  205. package/dist/lib/neutral/blueprint-definition-DSPXK77L.mjs +0 -15
  206. package/dist/lib/neutral/blueprint-definition-DSPXK77L.mjs.map +0 -7
  207. package/dist/lib/neutral/blueprints/index.mjs +0 -8
  208. package/dist/lib/neutral/chunk-36QFEVOZ.mjs +0 -30
  209. package/dist/lib/neutral/chunk-36QFEVOZ.mjs.map +0 -7
  210. package/dist/lib/neutral/chunk-67DKWOKF.mjs +0 -10
  211. package/dist/lib/neutral/chunk-67DKWOKF.mjs.map +0 -7
  212. package/dist/lib/neutral/chunk-CIJD7P6X.mjs +0 -8
  213. package/dist/lib/neutral/chunk-LXNSKCPD.mjs.map +0 -7
  214. package/dist/lib/neutral/chunk-Y2LQRUU7.mjs.map +0 -7
  215. package/dist/lib/neutral/comment-config-EGY7RPPW.mjs.map +0 -7
  216. package/dist/lib/neutral/create-object-MU2LGXG6.mjs.map +0 -7
  217. package/dist/lib/neutral/navigation-resolver-3KBOMN4U.mjs +0 -14
  218. package/dist/lib/neutral/navigation-resolver-3KBOMN4U.mjs.map +0 -7
  219. package/dist/lib/neutral/react-surface-XYZJBKHZ.mjs.map +0 -7
  220. package/dist/lib/neutral/settings-TDGDLCUR.mjs.map +0 -7
  221. package/dist/lib/neutral/state-5COCF5PN.mjs +0 -44
  222. package/dist/lib/neutral/state-5COCF5PN.mjs.map +0 -7
  223. package/dist/lib/neutral/update-markdown-NNINDDV5.mjs +0 -44
  224. package/dist/lib/neutral/update-markdown-NNINDDV5.mjs.map +0 -7
  225. package/dist/types/src/blueprints/index.d.ts +0 -2
  226. package/dist/types/src/blueprints/index.d.ts.map +0 -1
  227. package/dist/types/src/blueprints/markdown-blueprint.d.ts +0 -4
  228. package/dist/types/src/blueprints/markdown-blueprint.d.ts.map +0 -1
  229. package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -6
  230. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
  231. package/dist/types/src/capabilities/app-graph-serializer.d.ts +0 -5
  232. package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +0 -1
  233. package/dist/types/src/capabilities/blueprint-definition.d.ts +0 -6
  234. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +0 -1
  235. package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -6
  236. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
  237. package/dist/types/src/paths.d.ts +0 -3
  238. package/dist/types/src/paths.d.ts.map +0 -1
  239. package/src/blueprints/index.ts +0 -5
  240. package/src/capabilities/app-graph-builder.ts +0 -63
  241. package/src/capabilities/app-graph-serializer.ts +0 -64
  242. package/src/capabilities/blueprint-definition.ts +0 -19
  243. package/src/capabilities/navigation-resolver.ts +0 -19
  244. package/src/components/MarkdownSettings/MarkdownSettings.tsx +0 -35
  245. package/src/paths.ts +0 -11
  246. /package/dist/lib/neutral/{chunk-CIJD7P6X.mjs.map → chunk-2V6A5NDQ.mjs.map} +0 -0
  247. /package/dist/lib/neutral/{create-JK35XC4R.mjs.map → create-OQUMKL5I.mjs.map} +0 -0
  248. /package/dist/lib/neutral/{create-markdown-7MLE625M.mjs.map → create-markdown-4O5FDA77.mjs.map} +0 -0
  249. /package/dist/lib/neutral/{open-5YC77C4O.mjs.map → open-BAZIRXII.mjs.map} +0 -0
  250. /package/dist/lib/neutral/{blueprints/index.mjs.map → operation-handler-SDCXGMGK.mjs.map} +0 -0
  251. /package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs.map → scroll-to-anchor-I6HFE5AH.mjs.map} +0 -0
  252. /package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs.map → set-view-mode-NY5OYYIM.mjs.map} +0 -0
  253. /package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.d.ts +0 -0
  254. /package/dist/types/src/{components → containers}/MarkdownSettings/index.d.ts +0 -0
  255. /package/src/{components → containers}/MarkdownSettings/index.ts +0 -0
@@ -2,15 +2,19 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type Meta, type StoryObj } from '@storybook/react-vite';
5
+ import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import React from 'react';
8
8
 
9
9
  import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { AppActivationEvents } from '@dxos/app-toolkit';
10
11
  import { Filter, Obj } from '@dxos/echo';
11
- import { ClientPlugin } from '@dxos/plugin-client/testing';
12
- import { initializeIdentity } from '@dxos/plugin-client/testing';
12
+ import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
13
+ import { Sketch } from '@dxos/plugin-sketch';
14
+ import { SketchPlugin } from '@dxos/plugin-sketch/plugin';
15
+ import { SketchBuilder } from '@dxos/plugin-sketch/testing';
13
16
  import { corePlugins } from '@dxos/plugin-testing';
17
+ import { type Client } from '@dxos/react-client';
14
18
  import { useQuery, useSpaces } from '@dxos/react-client/echo';
15
19
  import { Panel } from '@dxos/react-ui';
16
20
  import { AttendableContainer } from '@dxos/react-ui-attention';
@@ -19,16 +23,23 @@ import { translations as editorTranslations } from '@dxos/react-ui-editor/transl
19
23
  import { Loading, withLayout } from '@dxos/react-ui/testing';
20
24
  import { Text } from '@dxos/schema';
21
25
 
26
+ import { useLinkQuery } from '#hooks';
22
27
  import { translations } from '#translations';
23
28
  import { Markdown } from '#types';
24
29
 
25
30
  import { MarkdownEditor, MarkdownEditorProvider, type MarkdownEditorProviderProps } from './MarkdownEditor';
26
31
 
27
- type DefaultStoryProps = Omit<MarkdownEditorProviderProps, 'id' | 'extensions' | 'children'>;
32
+ // A minimal sketch (tldraw `tldraw.com/2`) snapshot, used as a test sketch.
33
+ const SKETCH_CONTENT = new SketchBuilder()
34
+ .rectangle({ id: 'rect', x: 0, y: 0, text: 'DXOS', color: 'blue', fill: 'solid', size: 'l' })
35
+ .build();
28
36
 
29
- const DefaultStory = (props: DefaultStoryProps) => {
37
+ type StoryArgs = Omit<MarkdownEditorProviderProps, 'id' | 'extensions' | 'children'>;
38
+
39
+ const DefaultStory = (props: StoryArgs) => {
30
40
  const [space] = useSpaces();
31
41
  const [doc] = useQuery(space?.db, Filter.type(Markdown.Document));
42
+ const handleLinkQuery = useLinkQuery(space?.db, doc);
32
43
  const id = doc && Obj.getURI(doc);
33
44
  if (!id) {
34
45
  return <Loading data={{ id }} />;
@@ -36,15 +47,19 @@ const DefaultStory = (props: DefaultStoryProps) => {
36
47
 
37
48
  return (
38
49
  <AttendableContainer id={id} tabIndex={0} classNames='dx-container'>
39
- <MarkdownEditorProvider id={id} object={doc} {...props}>
50
+ <MarkdownEditorProvider id={id} attendableId={id} object={doc} onLinkQuery={handleLinkQuery} {...props}>
40
51
  {(editorRootProps) => (
41
52
  <Editor.Root {...editorRootProps}>
42
- <Panel.Root>
43
- <Panel.Toolbar asChild>
44
- <MarkdownEditor.Toolbar />
53
+ {/* Mirror MarkdownArticle: Panel.Toolbar/Content are NOT `asChild` (MarkdownEditor.Toolbar is not
54
+ composable, so asChild wraps it in a dx-slot-warning div that breaks the grid-area layout). */}
55
+ <Panel.Root role='article'>
56
+ <Panel.Toolbar>
57
+ <MarkdownEditor.Toolbar classNames='dx-document' />
45
58
  </Panel.Toolbar>
46
- <Panel.Content asChild>
59
+ <Panel.Content>
47
60
  <MarkdownEditor.Content />
61
+ {/* Embedded objects (transclusions) portal into block-container elements created by the editor. */}
62
+ <MarkdownEditor.Blocks />
48
63
  </Panel.Content>
49
64
  </Panel.Root>
50
65
  </Editor.Root>
@@ -54,28 +69,49 @@ const DefaultStory = (props: DefaultStoryProps) => {
54
69
  );
55
70
  };
56
71
 
72
+ const withClient = (seed: (client: Client) => Effect.Effect<void>): Decorator =>
73
+ withPluginManager({
74
+ // SketchPlugin's section surface reads its Settings atom, contributed on SetupSettings.
75
+ setupEvents: [AppActivationEvents.SetupSettings],
76
+ plugins: [
77
+ ...corePlugins(),
78
+ SketchPlugin(),
79
+ ClientPlugin({
80
+ types: [Markdown.Document, Text.Text, Sketch.Sketch, Sketch.Canvas],
81
+ onClientInitialized: ({ client }) => seed(client),
82
+ }),
83
+ ],
84
+ });
85
+
86
+ const seedPlainDocument = (client: Client) =>
87
+ Effect.gen(function* () {
88
+ const { personalSpace } = yield* initializeIdentity(client);
89
+ personalSpace.db.add(Markdown.make({ content: Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n') }));
90
+ });
91
+
92
+ const seedEmbeddedSketch = (client: Client) =>
93
+ Effect.gen(function* () {
94
+ const { personalSpace } = yield* initializeIdentity(client);
95
+ const sketch = personalSpace.db.add(Sketch.make({ name: 'Test Sketch', canvas: { content: SKETCH_CONTENT } }));
96
+ const uri = Obj.getURI(sketch);
97
+ personalSpace.db.add(
98
+ Markdown.make({
99
+ content: [
100
+ '# Test Document',
101
+ '',
102
+ 'The sketch below renders inline as a block surface:',
103
+ '',
104
+ `![${sketch.name}](${uri})`,
105
+ '',
106
+ ].join('\n'),
107
+ }),
108
+ );
109
+ });
110
+
57
111
  const meta: Meta<typeof DefaultStory> = {
58
112
  title: 'plugins/plugin-markdown/components/MarkdownEditor',
59
113
  render: DefaultStory,
60
- decorators: [
61
- withLayout({ layout: 'column' }),
62
- withPluginManager({
63
- plugins: [
64
- ...corePlugins(),
65
- // TODO(burdon): Try to write story without ClientPlugin.
66
- ClientPlugin({
67
- types: [Markdown.Document, Text.Text],
68
- onClientInitialized: ({ client }) =>
69
- Effect.gen(function* () {
70
- const { personalSpace } = yield* initializeIdentity(client);
71
- personalSpace.db.add(
72
- Markdown.make({ content: Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n') }),
73
- );
74
- }),
75
- }),
76
- ],
77
- }),
78
- ],
114
+ decorators: [withLayout({ layout: 'column' })],
79
115
  parameters: {
80
116
  translations: [...translations, ...editorTranslations],
81
117
  },
@@ -85,4 +121,10 @@ export default meta;
85
121
 
86
122
  type Story = StoryObj<typeof meta>;
87
123
 
88
- export const Default: Story = {};
124
+ export const Default: Story = {
125
+ decorators: [withClient(seedPlainDocument)],
126
+ };
127
+
128
+ export const WithEmbeddedSketch: Story = {
129
+ decorators: [withClient(seedEmbeddedSketch)],
130
+ };
@@ -9,11 +9,6 @@ import { createContext } from '@radix-ui/react-context';
9
9
  import React, { type ReactNode, useCallback, useMemo, useState } from 'react';
10
10
  import { createPortal } from 'react-dom';
11
11
 
12
- import { Surface } from '@dxos/app-framework/ui';
13
- import { AppSurface } from '@dxos/app-toolkit/ui';
14
- import { Obj } from '@dxos/echo';
15
- import { URI } from '@dxos/keys';
16
- import { useClient } from '@dxos/react-client';
17
12
  import { type ThemedClassName } from '@dxos/react-ui';
18
13
  import { composable, composableProps } from '@dxos/react-ui';
19
14
  import {
@@ -22,7 +17,7 @@ import {
22
17
  createEditorController,
23
18
  useEditorContext,
24
19
  } from '@dxos/react-ui-editor';
25
- import { type PreviewBlock, type PreviewOptions } from '@dxos/ui-editor';
20
+ import { type XmlWidgetState } from '@dxos/ui-editor';
26
21
  import { isNonNullable } from '@dxos/util';
27
22
 
28
23
  import {
@@ -49,7 +44,7 @@ import {
49
44
  type MarkdownEditorContextValue = {
50
45
  id: string;
51
46
  attendableId?: string;
52
- previewBlocks: PreviewBlock[];
47
+ widgets: XmlWidgetState[];
53
48
  } & Pick<ExtensionsOptions, 'compact' | 'viewMode'> &
54
49
  Pick<NaturalMarkdownToolbarProps, 'onAction' | 'onFileUpload' | 'onViewModeChange'>;
55
50
 
@@ -74,7 +69,7 @@ export type MarkdownEditorProviderProps = {
74
69
  'id' | 'attendableId' | 'viewMode' | 'compact' | 'onAction' | 'onFileUpload' | 'onViewModeChange'
75
70
  > &
76
71
  Pick<UseEditorMenuOptionsProps, 'slashCommandGroups' | 'onLinkQuery'> &
77
- Pick<ExtensionsOptions, 'editorStateStore' | 'selectionManager' | 'settings' | 'onSelectObject'>;
72
+ Pick<ExtensionsOptions, 'editorStateStore' | 'viewState' | 'settings' | 'onSelectObject'>;
78
73
 
79
74
  export const MarkdownEditorProvider = ({
80
75
  children,
@@ -84,7 +79,7 @@ export const MarkdownEditorProvider = ({
84
79
  settings,
85
80
  compact,
86
81
  viewMode,
87
- selectionManager,
82
+ viewState,
88
83
  editorStateStore,
89
84
  extensions: extensionsProp,
90
85
  slashCommandGroups,
@@ -94,20 +89,8 @@ export const MarkdownEditorProvider = ({
94
89
  onFileUpload,
95
90
  onViewModeChange,
96
91
  }: MarkdownEditorProviderProps) => {
97
- // Preview blocks.
98
- const [previewBlocks, setPreviewBlocks] = useState<PreviewBlock[]>([]);
99
- const previewOptions = useMemo<PreviewOptions>(
100
- () => ({
101
- db: Obj.isObject(object) ? Obj.getDatabase(object) : undefined,
102
- addBlockContainer: (block) => {
103
- setPreviewBlocks((prev) => [...prev, block]);
104
- },
105
- removeBlockContainer: ({ link }) => {
106
- setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.dxn !== link.dxn));
107
- },
108
- }),
109
- [object],
110
- );
92
+ // Widget portals driven by xmlTags.
93
+ const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);
111
94
 
112
95
  // Context menu options (Editor.Root calls useEditorMenu with these props).
113
96
  const menuOptions = useEditorMenuOptions({ slashCommandGroups, onLinkQuery });
@@ -118,9 +101,9 @@ export const MarkdownEditorProvider = ({
118
101
  object,
119
102
  compact,
120
103
  viewMode,
121
- selectionManager,
104
+ viewState,
122
105
  editorStateStore,
123
- previewOptions,
106
+ setWidgets,
124
107
  settings,
125
108
  onSelectObject,
126
109
  });
@@ -149,12 +132,12 @@ export const MarkdownEditorProvider = ({
149
132
  attendableId,
150
133
  compact,
151
134
  viewMode,
152
- previewBlocks,
135
+ widgets,
153
136
  onAction,
154
137
  onFileUpload,
155
138
  onViewModeChange,
156
139
  }),
157
- [id, attendableId, compact, viewMode, previewBlocks, onAction, onFileUpload, onViewModeChange],
140
+ [id, attendableId, compact, viewMode, widgets, onAction, onFileUpload, onViewModeChange],
158
141
  );
159
142
 
160
143
  return (
@@ -251,12 +234,12 @@ const MARKDOWN_EDITOR_BLOCKS_NAME = 'MarkdownEditor.Blocks';
251
234
  type MarkdownEditorBlocksProps = {};
252
235
 
253
236
  const MarkdownEditorBlocks = (_props: MarkdownEditorBlocksProps) => {
254
- const { previewBlocks } = useMarkdownEditorContext(MARKDOWN_EDITOR_BLOCKS_NAME);
237
+ const { widgets } = useMarkdownEditorContext(MARKDOWN_EDITOR_BLOCKS_NAME);
255
238
 
256
239
  return (
257
240
  <>
258
- {previewBlocks.map(({ link, el }) => (
259
- <PreviewBlock key={link.dxn} link={link} el={el} />
241
+ {widgets.map(({ id, root, Component, props }) => (
242
+ <div key={id}>{createPortal(<Component {...props} />, root)}</div>
260
243
  ))}
261
244
  </>
262
245
  );
@@ -264,15 +247,6 @@ const MarkdownEditorBlocks = (_props: MarkdownEditorBlocksProps) => {
264
247
 
265
248
  MarkdownEditorBlocks.displayName = MARKDOWN_EDITOR_BLOCKS_NAME;
266
249
 
267
- const PreviewBlock = ({ el, link }: PreviewBlock) => {
268
- const client = useClient();
269
- const dxn = URI.make(link.dxn);
270
- const subject = client.graph.makeRef(dxn).target;
271
- const data = useMemo(() => ({ subject }), [subject]);
272
-
273
- return createPortal(<Surface.Surface type={AppSurface.Card} data={data} limit={1} />, el);
274
- };
275
-
276
250
  //
277
251
  // MarkdownEditor
278
252
  //
@@ -284,7 +258,7 @@ export const MarkdownEditor = {
284
258
  Blocks: MarkdownEditorBlocks,
285
259
  };
286
260
 
287
- export type { MarkdownEditorContentProps, MarkdownEditorToolbarProps, MarkdownEditorBlocksProps };
261
+ export type { MarkdownEditorBlocksProps, MarkdownEditorContentProps, MarkdownEditorToolbarProps };
288
262
 
289
263
  /** @deprecated Use `MarkdownEditorProviderProps`. */
290
264
  export type MarkdownEditorRootProps = MarkdownEditorProviderProps;
@@ -7,6 +7,7 @@ import { type Atom, RegistryContext } from '@effect-atom/atom-react';
7
7
  import React, { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo } from 'react';
8
8
 
9
9
  import { useCapabilities } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
10
11
  import { type ThemedClassName, useThemeContext, useTranslation } from '@dxos/react-ui';
11
12
  import {
12
13
  type EditorMenuGroup,
@@ -18,15 +19,15 @@ import {
18
19
  type EditorSelectionState,
19
20
  type EditorStateStore,
20
21
  type ThemeExtensionsOptions,
21
- mobileSlots,
22
22
  createBasicExtensions,
23
23
  createMarkdownExtensions,
24
24
  createThemeExtensions,
25
- dropFile,
26
25
  documentSlots,
26
+ dropFile,
27
+ editorClassNames,
27
28
  formattingListener,
29
+ mobileSlots,
28
30
  processEditorPayload,
29
- editorClassNames,
30
31
  scrollbarAutohide,
31
32
  } from '@dxos/ui-editor';
32
33
  import { type EditorViewMode } from '@dxos/ui-editor/types';
@@ -72,7 +73,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
72
73
  },
73
74
  forwardedRef,
74
75
  ) => {
75
- const { t } = useTranslation(meta.id);
76
+ const { t } = useTranslation(meta.profile.key);
76
77
  const { themeMode } = useThemeContext();
77
78
  const registry = useContext(RegistryContext);
78
79
 
@@ -95,7 +96,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
95
96
  focusAttributes,
96
97
  } = useTextEditor(
97
98
  () => ({
98
- ...(role !== 'section' && {
99
+ ...(role !== AppSurface.Section.role && {
99
100
  id,
100
101
  scrollTo,
101
102
  selection,
@@ -117,7 +118,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
117
118
  createMarkdownExtensions(),
118
119
  scrollbarAutohide(),
119
120
  toolbarState && formattingListener(updateToolbarState),
120
- role !== 'section' &&
121
+ role !== AppSurface.Section.role &&
121
122
  onFileUpload &&
122
123
  dropFile({
123
124
  // TODO(wittjosiah): Factor out to file uploader plugin.
@@ -5,7 +5,7 @@
5
5
  import { type EditorView } from '@codemirror/view';
6
6
  import React, { useCallback, useState } from 'react';
7
7
 
8
- import { type FileInfo } from '@dxos/app-toolkit';
8
+ import { AppCapabilities } from '@dxos/app-toolkit';
9
9
  import { composable, composableProps } from '@dxos/react-ui';
10
10
  import { Editor, type EditorToolbarProps } from '@dxos/react-ui-editor';
11
11
 
@@ -17,7 +17,7 @@ export type MarkdownEditorToolbarProps = {
17
17
  // that React 19.2's dev render-logger would walk into a cross-origin frame. See
18
18
  // `react-ui-editor/.../controller.ts` for the full rationale.
19
19
  getView?: () => EditorView | null;
20
- onFileUpload?: (file: File) => Promise<FileInfo | undefined>;
20
+ onFileUpload?: (file: File) => Promise<AppCapabilities.FileInfo | undefined>;
21
21
  } & Pick<EditorToolbarProps, 'role' | 'customActions' | 'onAction' | 'onViewModeChange'>;
22
22
 
23
23
  export const MarkdownEditorToolbar = composable<HTMLDivElement, MarkdownEditorToolbarProps>(
@@ -0,0 +1,195 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
6
+
7
+ import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
8
+ import { LayoutOperation, Paths } from '@dxos/app-toolkit';
9
+ import { AppSurface } from '@dxos/app-toolkit/ui';
10
+ import { Obj } from '@dxos/echo';
11
+ import { URI } from '@dxos/keys';
12
+ import { useClient } from '@dxos/react-client';
13
+ import { Icon, IconButton } from '@dxos/react-ui';
14
+ import { ResizeHandle, type Size, resizeAttributes, sizeStyle } from '@dxos/react-ui-dnd';
15
+ import { type XmlWidgetProps } from '@dxos/ui-editor';
16
+
17
+ export type PreviewComponentProps = XmlWidgetProps<{
18
+ label: string;
19
+ dxn: string;
20
+ block?: boolean;
21
+ suggest?: boolean;
22
+ onOpen?: (dxn: URI.URI) => void;
23
+ }>;
24
+
25
+ // Persisted height (px) lives in the image alt text after the label, Obsidian-style: `![label|320](dxn)`.
26
+ const HEIGHT_PATTERN = /^(.*)\|(\d+)$/;
27
+
28
+ const parseEmbedLabel = (alt: string): { baseLabel: string; height?: number } => {
29
+ const match = HEIGHT_PATTERN.exec(alt ?? '');
30
+ if (match) {
31
+ const height = Number.parseInt(match[2], 10);
32
+ if (Number.isFinite(height) && height > 0) {
33
+ return { baseLabel: match[1], height };
34
+ }
35
+ }
36
+ return { baseLabel: alt ?? '' };
37
+ };
38
+
39
+ const formatEmbedLabel = (baseLabel: string, height?: number): string =>
40
+ height != null ? `${baseLabel}|${height}` : baseLabel;
41
+
42
+ const MIN_SIZE = 6;
43
+ const FALLBACK_SIZE = 320;
44
+
45
+ /** Scroll the element's top into view (honoring its `scroll-margin`) only if that top is not already visible. */
46
+ const scrollTopIntoViewIfNeeded = (element: HTMLElement): void => {
47
+ let parent = element.parentElement;
48
+ while (parent) {
49
+ const { overflowY } = getComputedStyle(parent);
50
+ if (
51
+ (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') &&
52
+ parent.scrollHeight > parent.clientHeight
53
+ ) {
54
+ break;
55
+ }
56
+ parent = parent.parentElement;
57
+ }
58
+ const elementTop = element.getBoundingClientRect().top;
59
+ const viewTop = parent ? parent.getBoundingClientRect().top : 0;
60
+ const viewBottom = parent ? parent.getBoundingClientRect().bottom : window.innerHeight;
61
+ if (elementTop < viewTop || elementTop > viewBottom) {
62
+ element.scrollIntoView({ block: 'start', inline: 'nearest' });
63
+ }
64
+ };
65
+
66
+ /**
67
+ * Registry-backed block widget for URL-scheme preview slots.
68
+ * Replaces the addBlockContainer callback pattern.
69
+ * Used as the Component entry in a urlSchemes XmlWidgetDef.
70
+ */
71
+ export const PreviewComponent = ({ dxn, label: alt, onOpen, view, range }: PreviewComponentProps) => {
72
+ const client = useClient();
73
+ const { invokePromise } = useOperationInvoker();
74
+ const containerRef = useRef<HTMLDivElement>(null);
75
+ const uri = dxn ? URI.make(dxn) : undefined;
76
+ const subject = uri ? client.graph.makeRef<Obj.Unknown>(uri).target : undefined;
77
+
78
+ // px per rem; ResizeHandle works in rem while the persisted height is in px.
79
+ const remSize = useMemo(() => parseFloat(getComputedStyle(document.documentElement).fontSize) || 16, []);
80
+ const { height } = parseEmbedLabel(alt);
81
+
82
+ // `min-content` keeps the embed at its intrinsic height until the user resizes it; the handle then
83
+ // measures the rendered box and switches to an explicit height.
84
+ const [size, setSize] = useState<Size>(height != null ? height / remSize : 'min-content');
85
+
86
+ // Tell the surface it is sized by its container (vs. intrinsic) so content (e.g. an image) can fit.
87
+ const extrinsic = size !== 'min-content';
88
+ const data = useMemo(
89
+ () => (subject ? { subject, attendableId: dxn, extrinsic } : undefined),
90
+ [subject, dxn, extrinsic],
91
+ );
92
+ useEffect(() => {
93
+ setSize(height != null ? height / remSize : 'min-content');
94
+ }, [height, remSize]);
95
+
96
+ // Persist the height (px) into the alt text on drop by rewriting the image node in the source. The
97
+ // node bounds and base label are re-derived from the live document (the captured `range`/`label`
98
+ // can lag a prior edit before React re-renders the widget). When the same object is transcluded
99
+ // more than once, the node whose start is NEAREST the widget's range is chosen so a duplicate
100
+ // embed isn't rewritten by mistake.
101
+ const handleResize = useCallback(
102
+ (next: Size, commit?: boolean) => {
103
+ setSize(next);
104
+ if (!commit || typeof next !== 'number' || !view) {
105
+ return;
106
+ }
107
+ const doc = view.state.doc.toString();
108
+ const marker = `](${dxn})`;
109
+ let open = -1;
110
+ let close = -1;
111
+ for (let at = doc.indexOf(marker); at >= 0; at = doc.indexOf(marker, at + marker.length)) {
112
+ const start = doc.lastIndexOf('![', at);
113
+ if (start >= 0 && (open < 0 || Math.abs(start - range.from) < Math.abs(open - range.from))) {
114
+ open = start;
115
+ close = at;
116
+ }
117
+ }
118
+ if (open < 0) {
119
+ return;
120
+ }
121
+ const { baseLabel: currentBaseLabel } = parseEmbedLabel(doc.slice(open + 2, close));
122
+ const insert = `![${formatEmbedLabel(currentBaseLabel, Math.round(next * remSize))}](${dxn})`;
123
+ view.dispatch({ changes: { from: open, to: close + marker.length, insert } });
124
+ // After the resized box has laid out, bring its top into frame — but only if that top scrolled
125
+ // out of view. Scroll the element itself (not the CM view) so it works whichever ancestor
126
+ // actually scrolls (cm-scroller or an outer panel); defer a frame so the new height applies first.
127
+ requestAnimationFrame(() => {
128
+ if (containerRef.current) {
129
+ scrollTopIntoViewIfNeeded(containerRef.current);
130
+ }
131
+ });
132
+ },
133
+ [view, range, dxn, remSize],
134
+ );
135
+
136
+ // Open the referenced object: defer to the caller's handler when provided, else navigate to it.
137
+ const handleOpen = useCallback(() => {
138
+ if (!uri || !subject) {
139
+ return;
140
+ }
141
+ if (onOpen) {
142
+ onOpen(uri);
143
+ } else {
144
+ void invokePromise?.(LayoutOperation.Open, {
145
+ subject: [Paths.getObjectPathFromObject(subject)],
146
+ navigation: 'immediate',
147
+ });
148
+ }
149
+ }, [uri, subject, onOpen, invokePromise]);
150
+
151
+ if (!uri || !subject || !data) {
152
+ return null;
153
+ }
154
+
155
+ const objectLabel = Obj.getLabel(subject);
156
+ const objectIcon = Obj.getIcon(subject);
157
+
158
+ // Frame transcluded block embeds so they read as a self-contained card within the document flow.
159
+ // The clip/border live on an inner element so they don't clip the resize handle (which straddles the
160
+ // bottom edge); the inner grid stretches the surface to fill the resizable box, overriding any
161
+ // intrinsic aspect.
162
+ return (
163
+ <div
164
+ className='relative grid scroll-mt-16'
165
+ style={sizeStyle(size, 'vertical')}
166
+ {...resizeAttributes}
167
+ ref={containerRef}
168
+ >
169
+ <div className='grid overflow-hidden border border-subdued-separator rounded-md'>
170
+ <Surface.Surface type={AppSurface.Section} data={data} limit={1} />
171
+ </div>
172
+ <div className='absolute top-1 right-1 flex items-center justify-end gap-1'>
173
+ <span className='dx-tag dx-tag--neutral flex items-center gap-1'>
174
+ {objectIcon && <Icon icon={objectIcon.icon} size={4} />}
175
+ {objectLabel}
176
+ </span>
177
+ <IconButton
178
+ density='sm'
179
+ icon='ph--arrow-square-out--regular'
180
+ iconOnly
181
+ label='Open'
182
+ variant='ghost'
183
+ onClick={handleOpen}
184
+ />
185
+ </div>
186
+ <ResizeHandle
187
+ side='block-end'
188
+ fallbackSize={FALLBACK_SIZE}
189
+ minSize={MIN_SIZE}
190
+ size={size}
191
+ onSizeChange={handleResize}
192
+ />
193
+ </div>
194
+ );
195
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './PreviewComponent';
@@ -2,8 +2,5 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type ComponentType, lazy } from 'react';
6
-
7
5
  export * from './MarkdownEditor';
8
-
9
- export const MarkdownSettings: ComponentType<any> = lazy(() => import('./MarkdownSettings'));
6
+ export * from './PreviewComponent';
@@ -91,10 +91,9 @@ const meta = {
91
91
  const createObjects = createObjectFactory(personalSpace.db, generator);
92
92
  yield* Effect.promise(() => createObjects([{ type: Organization.Organization, count: 10 }]));
93
93
 
94
- const queue = personalSpace.queues.create();
95
- const kai = Obj.make(Person.Person, { fullName: 'Kai' });
96
- const dxos = Obj.make(Organization.Organization, { name: 'DXOS' });
97
- yield* Effect.promise(() => queue.append([kai, dxos]));
94
+ const kai = personalSpace.db.add(Obj.make(Person.Person, { fullName: 'Kai' }));
95
+ const dxos = personalSpace.db.add(Obj.make(Organization.Organization, { name: 'DXOS' }));
96
+ yield* Effect.promise(() => personalSpace.db.flush());
98
97
 
99
98
  personalSpace.db.add(
100
99
  Markdown.make({
@@ -13,14 +13,14 @@ import { Obj } from '@dxos/echo';
13
13
  import { useActionRunner } from '@dxos/plugin-graph';
14
14
  import { useObject } from '@dxos/react-client/echo';
15
15
  import { Panel } from '@dxos/react-ui';
16
- import { type SelectionManager } from '@dxos/react-ui-attention';
16
+ import { type ViewStateManager } from '@dxos/react-ui-attention';
17
17
  import { Editor } from '@dxos/react-ui-editor';
18
18
  import { Text } from '@dxos/schema';
19
19
 
20
20
  import {
21
21
  MarkdownEditor,
22
- MarkdownEditorProvider,
23
22
  type MarkdownEditorContentProps,
23
+ MarkdownEditorProvider,
24
24
  type MarkdownEditorProviderProps,
25
25
  } from '#components';
26
26
  import { useLinkQuery } from '#hooks';
@@ -31,7 +31,7 @@ export type MarkdownArticleProps = AppSurface.ObjectArticleProps<
31
31
  {
32
32
  id: string;
33
33
  settings: Markdown.Settings;
34
- selectionManager?: SelectionManager;
34
+ viewState?: ViewStateManager;
35
35
  } & Pick<MarkdownPluginState, 'extensionProviders'> &
36
36
  Pick<MarkdownEditorProviderProps, 'viewMode' | 'onSelectObject' | 'onViewModeChange'> &
37
37
  Pick<MarkdownEditorContentProps, 'editorStateStore'>
@@ -90,7 +90,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
90
90
  }, [db, upload]);
91
91
 
92
92
  // Query for @ refs.
93
- const handleLinkQuery = useLinkQuery(db);
93
+ const handleLinkQuery = useLinkQuery(db, Obj.isObject(object) ? object : undefined);
94
94
 
95
95
  // Open linked objects.
96
96
  const { invokePromise } = useOperationInvoker();
@@ -115,7 +115,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
115
115
  id={id}
116
116
  attendableId={attendableId}
117
117
  object={object}
118
- compact={role !== 'article'}
118
+ compact={role !== AppSurface.Article.role}
119
119
  extensions={extensions}
120
120
  settings={settings}
121
121
  viewMode={viewMode}
@@ -129,7 +129,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
129
129
  <Editor.Root {...editorRootProps}>
130
130
  <Panel.Root role={role} ref={forwardedRef}>
131
131
  {settings.toolbar && (
132
- <Panel.Toolbar classNames='bg-toolbar-surface'>
132
+ <Panel.Toolbar>
133
133
  <MarkdownEditor.Toolbar classNames='dx-document' customActions={customActions} />
134
134
  </Panel.Toolbar>
135
135
  )}
@@ -20,7 +20,7 @@ import { snippet as snippetExtension } from './snippet';
20
20
  export type MarkdownCardProps = { subject: Markdown.Document | Text.Text };
21
21
 
22
22
  export const MarkdownCard = ({ subject }: MarkdownCardProps) => {
23
- const { t } = useTranslation(meta.id);
23
+ const { t } = useTranslation(meta.profile.key);
24
24
  // NOTE: Newline is added so that Fade does not obscure the last line.
25
25
  const snippet = useMemo(() => getSnippet(subject) + '\n', [subject]);
26
26
  const extensions = useMemo(() => [snippetExtension({ height: 300, scale: 0.8 })], []);
@@ -29,7 +29,7 @@ export const MarkdownCard = ({ subject }: MarkdownCardProps) => {
29
29
  return (
30
30
  <Card.Body>
31
31
  {snippet && (
32
- <Card.Section className='relative'>
32
+ <Card.Section className='aspect-square relative'>
33
33
  <Card.Row fullWidth>
34
34
  <MarkdownEditorProvider id={subject.id} viewMode='readonly' extensions={extensions}>
35
35
  {(editorRootProps) => (
@@ -11,7 +11,7 @@ import { translations } from '#translations';
11
11
  import { MarkdownSettings } from './MarkdownSettings';
12
12
 
13
13
  const meta = {
14
- title: 'plugins/plugin-markdown/components/MarkdownSettings',
14
+ title: 'plugins/plugin-markdown/containers/MarkdownSettings',
15
15
  tags: ['settings'],
16
16
  component: MarkdownSettings,
17
17
  decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],