@dxos/plugin-markdown 0.6.13 → 0.6.14-main.69511f5

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 (127) hide show
  1. package/dist/lib/browser/MarkdownContainer-HRGXWEA4.mjs +465 -0
  2. package/dist/lib/browser/MarkdownContainer-HRGXWEA4.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-DRJ3FPYF.mjs +15 -0
  4. package/dist/lib/browser/chunk-DRJ3FPYF.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-CQJL4G4X.mjs → chunk-US5O2P3R.mjs} +4 -2
  6. package/dist/lib/browser/chunk-US5O2P3R.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-VGIHBUXB.mjs +52 -0
  8. package/dist/lib/browser/chunk-VGIHBUXB.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +85 -125
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/meta.mjs +1 -1
  13. package/dist/lib/browser/types/index.mjs +6 -4
  14. package/dist/lib/node/MarkdownContainer-QZ4YLO7M.cjs +480 -0
  15. package/dist/lib/node/MarkdownContainer-QZ4YLO7M.cjs.map +7 -0
  16. package/dist/lib/node/chunk-6HPTH2F5.cjs +74 -0
  17. package/dist/lib/node/chunk-6HPTH2F5.cjs.map +7 -0
  18. package/dist/lib/node/{DocumentCard-EHJDDSRY.cjs → chunk-P7YU53RP.cjs} +16 -10
  19. package/dist/lib/node/chunk-P7YU53RP.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-VWQH4WC2.cjs → chunk-UJMOZCIA.cjs} +11 -8
  21. package/dist/lib/node/chunk-UJMOZCIA.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +117 -153
  23. package/dist/lib/node/index.cjs.map +4 -4
  24. package/dist/lib/node/meta.cjs +3 -3
  25. package/dist/lib/node/meta.cjs.map +1 -1
  26. package/dist/lib/node/meta.json +1 -1
  27. package/dist/lib/node/types/index.cjs +8 -6
  28. package/dist/lib/node/types/index.cjs.map +2 -2
  29. package/dist/lib/node-esm/MarkdownContainer-FSWQL76V.mjs +466 -0
  30. package/dist/lib/node-esm/MarkdownContainer-FSWQL76V.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-HPOTHJC4.mjs +53 -0
  32. package/dist/lib/node-esm/chunk-HPOTHJC4.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-MIDCCMIX.mjs +42 -0
  34. package/dist/lib/node-esm/chunk-MIDCCMIX.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-NEVN5WR6.mjs +17 -0
  36. package/dist/lib/node-esm/chunk-NEVN5WR6.mjs.map +7 -0
  37. package/dist/lib/node-esm/index.mjs +493 -0
  38. package/dist/lib/node-esm/index.mjs.map +7 -0
  39. package/dist/lib/node-esm/meta.json +1 -0
  40. package/dist/lib/node-esm/meta.mjs +10 -0
  41. package/dist/lib/node-esm/types/index.mjs +15 -0
  42. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  43. package/dist/types/src/components/MarkdownContainer.d.ts +15 -0
  44. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -0
  45. package/dist/types/src/components/MarkdownEditor.d.ts +12 -6
  46. package/dist/types/src/components/MarkdownEditor.d.ts.map +1 -1
  47. package/dist/types/src/components/MarkdownEditor.stories.d.ts +4 -14
  48. package/dist/types/src/components/MarkdownEditor.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/Toolbar.stories.d.ts +4 -2
  50. package/dist/types/src/components/Toolbar.stories.d.ts.map +1 -1
  51. package/dist/types/src/components/index.d.ts +1 -11
  52. package/dist/types/src/components/index.d.ts.map +1 -1
  53. package/dist/types/src/extensions.d.ts +12 -15
  54. package/dist/types/src/extensions.d.ts.map +1 -1
  55. package/dist/types/src/hooks/index.d.ts +2 -0
  56. package/dist/types/src/hooks/index.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useSelectCurrentThread.d.ts +6 -0
  58. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -0
  59. package/dist/types/src/meta.d.ts +4 -9
  60. package/dist/types/src/meta.d.ts.map +1 -1
  61. package/dist/types/src/types/document.d.ts +10 -1
  62. package/dist/types/src/types/document.d.ts.map +1 -1
  63. package/dist/types/src/types/types.d.ts +8 -9
  64. package/dist/types/src/types/types.d.ts.map +1 -1
  65. package/dist/types/src/util.d.ts.map +1 -1
  66. package/package.json +42 -45
  67. package/src/MarkdownPlugin.tsx +58 -113
  68. package/src/components/MarkdownContainer.tsx +103 -0
  69. package/src/components/MarkdownEditor.stories.tsx +34 -23
  70. package/src/components/MarkdownEditor.tsx +48 -79
  71. package/src/components/MarkdownSettings.tsx +15 -15
  72. package/src/components/Toolbar.stories.tsx +14 -11
  73. package/src/components/index.ts +2 -14
  74. package/src/extensions.tsx +128 -67
  75. package/src/hooks/index.ts +5 -0
  76. package/src/hooks/useSelectCurrentThread.tsx +46 -0
  77. package/src/meta.ts +15 -0
  78. package/src/translations.ts +1 -1
  79. package/src/types/document.ts +12 -0
  80. package/src/types/types.ts +10 -7
  81. package/src/util.tsx +6 -4
  82. package/dist/lib/browser/DocumentCard-2P4EICBA.mjs +0 -11
  83. package/dist/lib/browser/DocumentEditor-GPWV3VN3.mjs +0 -11
  84. package/dist/lib/browser/MarkdownEditor-EKJJQEFL.mjs +0 -10
  85. package/dist/lib/browser/MarkdownEditor-EKJJQEFL.mjs.map +0 -7
  86. package/dist/lib/browser/chunk-354DCID5.mjs +0 -117
  87. package/dist/lib/browser/chunk-354DCID5.mjs.map +0 -7
  88. package/dist/lib/browser/chunk-4GGD6YJO.mjs +0 -19
  89. package/dist/lib/browser/chunk-4GGD6YJO.mjs.map +0 -7
  90. package/dist/lib/browser/chunk-7AF2JLK4.mjs +0 -164
  91. package/dist/lib/browser/chunk-7AF2JLK4.mjs.map +0 -7
  92. package/dist/lib/browser/chunk-CQJL4G4X.mjs.map +0 -7
  93. package/dist/lib/browser/chunk-RL7QY322.mjs +0 -86
  94. package/dist/lib/browser/chunk-RL7QY322.mjs.map +0 -7
  95. package/dist/lib/browser/chunk-VUN4QKTT.mjs +0 -208
  96. package/dist/lib/browser/chunk-VUN4QKTT.mjs.map +0 -7
  97. package/dist/lib/node/DocumentCard-EHJDDSRY.cjs.map +0 -7
  98. package/dist/lib/node/DocumentEditor-I5GCRBKU.cjs +0 -29
  99. package/dist/lib/node/DocumentEditor-I5GCRBKU.cjs.map +0 -7
  100. package/dist/lib/node/MarkdownEditor-UE23H75V.cjs +0 -31
  101. package/dist/lib/node/MarkdownEditor-UE23H75V.cjs.map +0 -7
  102. package/dist/lib/node/chunk-7XIBNEI7.cjs +0 -238
  103. package/dist/lib/node/chunk-7XIBNEI7.cjs.map +0 -7
  104. package/dist/lib/node/chunk-KTYIOXL5.cjs +0 -149
  105. package/dist/lib/node/chunk-KTYIOXL5.cjs.map +0 -7
  106. package/dist/lib/node/chunk-Q4ZSCBQE.cjs +0 -114
  107. package/dist/lib/node/chunk-Q4ZSCBQE.cjs.map +0 -7
  108. package/dist/lib/node/chunk-RVGN72IX.cjs +0 -189
  109. package/dist/lib/node/chunk-RVGN72IX.cjs.map +0 -7
  110. package/dist/lib/node/chunk-TGMR2CKU.cjs +0 -52
  111. package/dist/lib/node/chunk-TGMR2CKU.cjs.map +0 -7
  112. package/dist/lib/node/chunk-VWQH4WC2.cjs.map +0 -7
  113. package/dist/types/src/components/DocumentCard.d.ts +0 -16
  114. package/dist/types/src/components/DocumentCard.d.ts.map +0 -1
  115. package/dist/types/src/components/DocumentEditor.d.ts +0 -14
  116. package/dist/types/src/components/DocumentEditor.d.ts.map +0 -1
  117. package/dist/types/src/components/HeadingMenu.d.ts +0 -13
  118. package/dist/types/src/components/HeadingMenu.d.ts.map +0 -1
  119. package/dist/types/src/components/Layout.d.ts +0 -6
  120. package/dist/types/src/components/Layout.d.ts.map +0 -1
  121. package/src/components/DocumentCard.tsx +0 -107
  122. package/src/components/DocumentEditor.tsx +0 -137
  123. package/src/components/HeadingMenu.tsx +0 -46
  124. package/src/components/Layout.tsx +0 -27
  125. package/src/meta.tsx +0 -19
  126. /package/dist/lib/{browser/DocumentCard-2P4EICBA.mjs.map → node-esm/meta.mjs.map} +0 -0
  127. /package/dist/lib/{browser/DocumentEditor-GPWV3VN3.mjs.map → node-esm/types/index.mjs.map} +0 -0
@@ -2,11 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type IconProps, TextAa } from '@phosphor-icons/react';
6
- import React, { type Ref } from 'react';
5
+ import { TextAa } from '@phosphor-icons/react';
6
+ import React from 'react';
7
7
 
8
8
  import {
9
- isObject,
10
9
  parseIntentPlugin,
11
10
  resolvePlugin,
12
11
  LayoutAction,
@@ -16,7 +15,6 @@ import {
16
15
  } from '@dxos/app-framework';
17
16
  import { create } from '@dxos/echo-schema';
18
17
  import { LocalStorageStore } from '@dxos/local-storage';
19
- import { log } from '@dxos/log';
20
18
  import { parseClientPlugin } from '@dxos/plugin-client';
21
19
  import { type ActionGroup, createExtension, isActionGroup } from '@dxos/plugin-graph';
22
20
  import { SpaceAction } from '@dxos/plugin-space';
@@ -33,13 +31,13 @@ import {
33
31
  type EditorViewMode,
34
32
  EditorViewModes,
35
33
  translations as editorTranslations,
34
+ createEditorStateStore,
36
35
  } from '@dxos/react-ui-editor';
37
- import { isTileComponentProps } from '@dxos/react-ui-mosaic';
38
36
 
39
- import { type DocumentItemProps, DocumentCard, DocumentEditor, MarkdownEditor, MarkdownSettings } from './components';
37
+ import { MarkdownContainer, MarkdownSettings } from './components';
40
38
  import meta, { MARKDOWN_PLUGIN } from './meta';
41
39
  import translations from './translations';
42
- import { DocumentType, TextType } from './types';
40
+ import { DocumentType, isEditorModel, TextType } from './types';
43
41
  import {
44
42
  type MarkdownPluginProvides,
45
43
  type MarkdownSettingsProps,
@@ -48,52 +46,31 @@ import {
48
46
  } from './types';
49
47
  import { markdownExtensionPlugins, serializer } from './util';
50
48
 
51
- /**
52
- * Checks if an object conforms to the interface needed to render an editor.
53
- */
54
- const isEditorModel = (data: any): data is { id: string; text: string } => {
55
- return (
56
- data &&
57
- typeof data === 'object' &&
58
- 'id' in data &&
59
- typeof data.id === 'string' &&
60
- 'text' in data &&
61
- typeof data.text === 'string'
62
- );
63
- };
49
+ // TODO(burdon): Normalize active/object.
50
+ const getDoc = (object: any) => (object instanceof DocumentType ? object : undefined);
64
51
 
65
52
  export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
66
53
  const settings = new LocalStorageStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN, {
67
54
  defaultViewMode: 'preview',
68
55
  toolbar: true,
69
- folding: false,
56
+ numberedHeadings: true,
57
+ folding: true,
70
58
  experimental: false,
71
59
  });
72
60
 
73
- const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
61
+ const editorStateStore = createEditorStateStore(`${MARKDOWN_PLUGIN}/editor`);
74
62
 
75
- const getViewMode = (id?: string) => {
76
- return (id && state.values.viewMode[id]) || settings.values.defaultViewMode;
77
- };
63
+ const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
78
64
 
79
- const setViewMode = (id: string, nextViewMode: EditorViewMode) => {
80
- state.values.viewMode[id] = nextViewMode;
81
- };
65
+ const getViewMode = (id: string) => (id && state.values.viewMode[id]) || settings.values.defaultViewMode;
66
+ const setViewMode = (id: string, viewMode: EditorViewMode) => (state.values.viewMode[id] = viewMode);
82
67
 
83
68
  return {
84
69
  meta,
85
70
  ready: async (plugins) => {
86
71
  settings
87
- .prop({
88
- key: 'defaultViewMode',
89
- storageKey: 'default-view-mode',
90
- type: LocalStorageStore.enum<EditorViewMode>(),
91
- })
92
- .prop({
93
- key: 'editorInputMode',
94
- storageKey: 'editor-mode',
95
- type: LocalStorageStore.enum<EditorInputMode>({ allowUndefined: true }),
96
- })
72
+ .prop({ key: 'defaultViewMode', type: LocalStorageStore.enum<EditorViewMode>() })
73
+ .prop({ key: 'editorInputMode', type: LocalStorageStore.enum<EditorInputMode>({ allowUndefined: true }) })
97
74
  .prop({ key: 'toolbar', type: LocalStorageStore.bool({ allowUndefined: true }) })
98
75
  .prop({ key: 'experimental', type: LocalStorageStore.bool({ allowUndefined: true }) })
99
76
  .prop({ key: 'debug', type: LocalStorageStore.bool({ allowUndefined: true }) })
@@ -101,15 +78,11 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
101
78
  .prop({ key: 'numberedHeadings', type: LocalStorageStore.bool({ allowUndefined: true }) })
102
79
  .prop({ key: 'folding', type: LocalStorageStore.bool({ allowUndefined: true }) });
103
80
 
104
- state.prop({
105
- key: 'viewMode',
106
- storageKey: 'view-mode',
107
- type: LocalStorageStore.json<{ [key: string]: EditorViewMode }>(),
108
- });
81
+ state.prop({ key: 'viewMode', type: LocalStorageStore.json<{ [key: string]: EditorViewMode }>() });
109
82
 
110
83
  markdownExtensionPlugins(plugins).forEach((plugin) => {
111
84
  const { extensions } = plugin.provides.markdown;
112
- state.values.extensionProviders.push(extensions);
85
+ state.values.extensionProviders?.push(extensions);
113
86
  });
114
87
  },
115
88
  provides: {
@@ -117,10 +90,9 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
117
90
  metadata: {
118
91
  records: {
119
92
  [DocumentType.typename]: {
120
- label: (object: any) => (object instanceof DocumentType ? object.name ?? object.fallbackName : undefined),
93
+ label: (object: any) => (object instanceof DocumentType ? object.name || object.fallbackName : undefined),
121
94
  placeholder: ['document title placeholder', { ns: MARKDOWN_PLUGIN }],
122
- icon: (props: IconProps) => <TextAa {...props} />,
123
- iconSymbol: 'ph--text-aa--regular',
95
+ icon: 'ph--text-aa--regular',
124
96
  graphProps: {
125
97
  managesAutofocus: true,
126
98
  },
@@ -134,6 +106,12 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
134
106
  echo: {
135
107
  schema: [DocumentType, TextType],
136
108
  },
109
+ space: {
110
+ onSpaceCreate: {
111
+ label: ['create document label', { ns: MARKDOWN_PLUGIN }],
112
+ action: MarkdownAction.CREATE,
113
+ },
114
+ },
137
115
  graph: {
138
116
  builder: (plugins) => {
139
117
  const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
@@ -167,8 +145,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
167
145
  },
168
146
  properties: {
169
147
  label: ['create document label', { ns: MARKDOWN_PLUGIN }],
170
- icon: (props: IconProps) => <TextAa {...props} />,
171
- iconSymbol: 'ph--text-aa--regular',
148
+ icon: 'ph--text-aa--regular',
172
149
  testId: 'markdownPlugin.createObject',
173
150
  },
174
151
  },
@@ -241,13 +218,10 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
241
218
  ],
242
219
  },
243
220
  thread: {
244
- // TODO(Zan): How to better handle the type predicate?
245
221
  predicate: (obj) => obj instanceof DocumentType,
246
222
  createSort: (doc: DocumentType) => {
247
223
  const accessor = doc.content ? createDocAccessor(doc.content, ['content']) : undefined;
248
-
249
224
  if (!accessor) {
250
- log.warn('No accessor found for document content.');
251
225
  return (_) => 0;
252
226
  }
253
227
 
@@ -256,75 +230,46 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
256
230
  return range?.start ?? Number.MAX_SAFE_INTEGER;
257
231
  };
258
232
 
259
- return (anchorA: string, anchorB: string) => getStartPosition(anchorA) - getStartPosition(anchorB);
233
+ return (anchorA: string | undefined, anchorB: string | undefined): number => {
234
+ if (anchorA === undefined || anchorB === undefined) {
235
+ return 0;
236
+ }
237
+ const posA = getStartPosition(anchorA);
238
+ const posB = getStartPosition(anchorB);
239
+ return posA - posB;
240
+ };
260
241
  },
261
242
  },
262
243
  surface: {
263
- component: ({ data, role, ...props }, forwardedRef) => {
264
- const doc =
265
- data.active instanceof DocumentType
266
- ? data.active
267
- : data.object instanceof DocumentType
268
- ? data.object
269
- : undefined;
270
-
244
+ component: ({ data, role }) => {
271
245
  switch (role) {
272
246
  case 'section':
273
247
  case 'article': {
274
- if (doc && doc.content) {
275
- return (
276
- <DocumentEditor
277
- role={role}
278
- coordinate={data.coordinate as LayoutCoordinate}
279
- document={doc}
280
- extensionProviders={state.values.extensionProviders}
281
- settings={settings.values}
282
- scrollPastEnd
283
- viewMode={getViewMode(fullyQualifiedId(doc))}
284
- onViewModeChange={setViewMode}
285
- />
286
- );
287
- } else if (isEditorModel(data.object)) {
288
- return (
289
- <MarkdownEditor
290
- id={data.object.id}
291
- role={role}
292
- coordinate={data.coordinate as LayoutCoordinate}
293
- initialValue={data.object.text}
294
- extensionProviders={state.values.extensionProviders}
295
- inputMode={settings.values.editorInputMode}
296
- toolbar={settings.values.toolbar}
297
- scrollPastEnd
298
- viewMode={getViewMode(data.object.id)}
299
- onViewModeChange={setViewMode}
300
- />
301
- );
302
- }
303
- break;
304
- }
248
+ // TODO(burdon): Normalize types (from FilesPlugin).
249
+ const doc = getDoc(data.active) ?? getDoc(data.object);
250
+ const { id, object } = isEditorModel(data.object)
251
+ ? { id: data.object.id, object: data.object }
252
+ : doc
253
+ ? { id: fullyQualifiedId(doc), object: doc }
254
+ : {};
305
255
 
306
- case 'card': {
307
- if (
308
- isObject(data.content) &&
309
- typeof data.content.id === 'string' &&
310
- data.content.object instanceof DocumentType
311
- ) {
312
- // isTileComponentProps is a type guard for these props.
313
- // `props` will not pass this guard without transforming `data` into `item`.
314
- const cardProps = {
315
- ...props,
316
- item: {
317
- id: data.content.id,
318
- object: data.content.object,
319
- color: typeof data.content.color === 'string' ? data.content.color : undefined,
320
- } as DocumentItemProps,
321
- };
322
-
323
- return isTileComponentProps(cardProps) ? (
324
- <DocumentCard {...cardProps} settings={settings.values} ref={forwardedRef as Ref<HTMLDivElement>} />
325
- ) : null;
256
+ if (!id || !object) {
257
+ return null;
326
258
  }
327
- break;
259
+
260
+ return (
261
+ <MarkdownContainer
262
+ id={id}
263
+ object={object}
264
+ role={role}
265
+ coordinate={data.coordinate as LayoutCoordinate}
266
+ settings={settings.values}
267
+ extensionProviders={state.values.extensionProviders}
268
+ viewMode={getViewMode(id)}
269
+ editorStateStore={editorStateStore}
270
+ onViewModeChange={setViewMode}
271
+ />
272
+ );
328
273
  }
329
274
 
330
275
  case 'settings': {
@@ -0,0 +1,103 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useEffect, useMemo } from 'react';
6
+
7
+ import { useResolvePlugin, parseFileManagerPlugin } from '@dxos/app-framework';
8
+ import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
9
+
10
+ import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
11
+ import { useExtensions } from '../extensions';
12
+ import { DocumentType, type MarkdownSettingsProps } from '../types';
13
+ import { getFallbackName } from '../util';
14
+
15
+ export type MarkdownContainerProps = Pick<
16
+ MarkdownEditorProps,
17
+ 'role' | 'coordinate' | 'extensionProviders' | 'viewMode' | 'editorStateStore' | 'onViewModeChange'
18
+ > & {
19
+ id: string;
20
+ object: DocumentType | any;
21
+ settings: MarkdownSettingsProps;
22
+ };
23
+
24
+ // TODO(burdon): Move toolbar here.
25
+ // TODO(burdon): Factor out difference for ECHO and non-ECHO objects; i.e., single component.
26
+ const MarkdownContainer = ({ id, role, object, settings, ...props }: MarkdownContainerProps) => {
27
+ const scrollPastEnd = role === 'article';
28
+ if (object instanceof DocumentType) {
29
+ return (
30
+ <DocumentEditor
31
+ id={fullyQualifiedId(object)}
32
+ role={role}
33
+ document={object}
34
+ settings={settings}
35
+ scrollPastEnd={scrollPastEnd}
36
+ {...props}
37
+ />
38
+ );
39
+ } else {
40
+ return (
41
+ <MarkdownEditor
42
+ id={id}
43
+ role={role}
44
+ initialValue={object.text}
45
+ toolbar={settings.toolbar}
46
+ scrollPastEnd={scrollPastEnd}
47
+ {...props}
48
+ />
49
+ );
50
+ }
51
+ };
52
+
53
+ type DocumentEditorProps = Omit<MarkdownContainerProps, 'object'> & { document: DocumentType } & Pick<
54
+ MarkdownEditorProps,
55
+ 'id' | 'scrollPastEnd'
56
+ >;
57
+
58
+ export const DocumentEditor = ({
59
+ id,
60
+ document: doc,
61
+ extensionProviders,
62
+ settings,
63
+ viewMode,
64
+ editorStateStore,
65
+ ...props
66
+ }: DocumentEditorProps) => {
67
+ const space = getSpace(doc);
68
+ const initialValue = useMemo(() => doc.content?.content, [doc.content]);
69
+ const extensions = useExtensions({ extensionProviders, document: doc, settings, viewMode, editorStateStore });
70
+
71
+ // Migrate gradually to `fallbackName`.
72
+ useEffect(() => {
73
+ if (!doc.fallbackName && doc.content?.content) {
74
+ doc.fallbackName = getFallbackName(doc.content.content);
75
+ }
76
+ }, [doc, doc.content]);
77
+
78
+ // File dragging.
79
+ const fileManagerPlugin = useResolvePlugin(parseFileManagerPlugin);
80
+ const handleFileUpload = useMemo(() => {
81
+ if (space === undefined || fileManagerPlugin?.provides.file.upload === undefined) {
82
+ return undefined;
83
+ }
84
+
85
+ // TODO(burdon): Re-order props: space, file.
86
+ return async (file: File) => fileManagerPlugin?.provides?.file?.upload?.(file, space);
87
+ }, [space, fileManagerPlugin]);
88
+
89
+ return (
90
+ <MarkdownEditor
91
+ id={id}
92
+ initialValue={initialValue}
93
+ extensions={extensions}
94
+ toolbar={settings.toolbar}
95
+ inputMode={settings.editorInputMode}
96
+ viewMode={viewMode}
97
+ onFileUpload={handleFileUpload}
98
+ {...props}
99
+ />
100
+ );
101
+ };
102
+
103
+ export default MarkdownContainer;
@@ -3,41 +3,42 @@
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
6
- import React, { useMemo, type FC } from 'react';
7
6
 
8
- import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
9
- import { automerge } from '@dxos/react-ui-editor';
7
+ import { type Meta } from '@storybook/react';
8
+ import React, { useMemo } from 'react';
9
+
10
+ import { createDocAccessor, createObject } from '@dxos/react-client/echo';
11
+ import { Main } from '@dxos/react-ui';
12
+ import { editorWithToolbarLayout, automerge } from '@dxos/react-ui-editor';
13
+ import { topbarBlockPaddingStart } from '@dxos/react-ui-theme';
10
14
  import { withLayout, withTheme } from '@dxos/storybook-utils';
11
15
 
12
- import { MainLayout } from './Layout';
13
- import { MarkdownEditor } from './MarkdownEditor';
16
+ import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
17
+
18
+ const content = Array.from({ length: 100 })
19
+ .map((_, i) => `Line ${i + 1}`)
20
+ .join('\n');
14
21
 
15
- const Story: FC<{
16
- content: string;
22
+ type StoryProps = MarkdownEditorProps & {
23
+ content?: string;
17
24
  toolbar?: boolean;
18
- }> = ({ content = '# Test', toolbar }) => {
19
- const doc = useMemo(() => createEchoObject({ content }), [content]);
25
+ };
26
+
27
+ const DefaultStory = ({ content = '# Test', toolbar }: StoryProps) => {
28
+ const doc = useMemo(() => createObject({ content }), [content]);
20
29
  const extensions = useMemo(() => [automerge(createDocAccessor(doc, ['content']))], [doc]);
21
30
 
22
31
  return (
23
- <MainLayout toolbar={toolbar}>
32
+ <Main.Content
33
+ bounce
34
+ data-toolbar={toolbar ? 'enabled' : 'disabled'}
35
+ classNames={[topbarBlockPaddingStart, editorWithToolbarLayout]}
36
+ >
24
37
  <MarkdownEditor id='test' initialValue={doc.content} extensions={extensions} toolbar={toolbar} />
25
- </MainLayout>
38
+ </Main.Content>
26
39
  );
27
40
  };
28
41
 
29
- export default {
30
- title: 'plugin-markdown/EditorMain',
31
- component: MarkdownEditor,
32
- decorators: [withTheme, withLayout({ tooltips: true })],
33
- render: Story,
34
- parameters: { layout: 'fullscreen' },
35
- };
36
-
37
- const content = Array.from({ length: 100 })
38
- .map((_, i) => `Line ${i + 1}`)
39
- .join('\n');
40
-
41
42
  export const Default = {
42
43
  args: {
43
44
  content,
@@ -50,3 +51,13 @@ export const WithToolbar = {
50
51
  toolbar: true,
51
52
  },
52
53
  };
54
+
55
+ const meta: Meta<typeof MarkdownEditor> = {
56
+ title: 'plugins/plugin-markdown/EditorMain',
57
+ component: MarkdownEditor,
58
+ render: DefaultStory,
59
+ decorators: [withTheme, withLayout({ tooltips: true })],
60
+ parameters: { layout: 'fullscreen' },
61
+ };
62
+
63
+ export default meta;