@dxos/plugin-markdown 0.6.13 → 0.6.14-main.1366248

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-J5BZUIVL.mjs +472 -0
  2. package/dist/lib/browser/MarkdownContainer-J5BZUIVL.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-4X6YX3KU.mjs +15 -0
  4. package/dist/lib/browser/chunk-4X6YX3KU.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-PV4AWYWK.mjs +52 -0
  6. package/dist/lib/browser/chunk-PV4AWYWK.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-CQJL4G4X.mjs → chunk-VZAGHNHU.mjs} +4 -2
  8. package/dist/lib/browser/chunk-VZAGHNHU.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +84 -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-UYBYWCRU.cjs +487 -0
  15. package/dist/lib/node/MarkdownContainer-UYBYWCRU.cjs.map +7 -0
  16. package/dist/lib/node/chunk-2A5P424C.cjs +74 -0
  17. package/dist/lib/node/chunk-2A5P424C.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-VWQH4WC2.cjs → chunk-BHPFK7YI.cjs} +11 -8
  19. package/dist/lib/node/chunk-BHPFK7YI.cjs.map +7 -0
  20. package/dist/lib/node/{DocumentCard-EHJDDSRY.cjs → chunk-PHHIPRJC.cjs} +16 -10
  21. package/dist/lib/node/chunk-PHHIPRJC.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +116 -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-P3EAZ3OR.mjs +473 -0
  30. package/dist/lib/node-esm/MarkdownContainer-P3EAZ3OR.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-BABK7FMW.mjs +17 -0
  32. package/dist/lib/node-esm/chunk-BABK7FMW.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-EREAR7QS.mjs +53 -0
  34. package/dist/lib/node-esm/chunk-EREAR7QS.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-OEMU3XY7.mjs +42 -0
  36. package/dist/lib/node-esm/chunk-OEMU3XY7.mjs.map +7 -0
  37. package/dist/lib/node-esm/index.mjs +492 -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 +13 -8
  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 +11 -14
  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 +56 -114
  68. package/src/components/MarkdownContainer.tsx +109 -0
  69. package/src/components/MarkdownEditor.stories.tsx +34 -23
  70. package/src/components/MarkdownEditor.tsx +48 -80
  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 +139 -66
  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,21 +2,18 @@
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,
13
- type LayoutCoordinate,
14
12
  NavigationAction,
15
13
  type PluginDefinition,
16
14
  } from '@dxos/app-framework';
17
15
  import { create } from '@dxos/echo-schema';
18
16
  import { LocalStorageStore } from '@dxos/local-storage';
19
- import { log } from '@dxos/log';
20
17
  import { parseClientPlugin } from '@dxos/plugin-client';
21
18
  import { type ActionGroup, createExtension, isActionGroup } from '@dxos/plugin-graph';
22
19
  import { SpaceAction } from '@dxos/plugin-space';
@@ -33,13 +30,13 @@ import {
33
30
  type EditorViewMode,
34
31
  EditorViewModes,
35
32
  translations as editorTranslations,
33
+ createEditorStateStore,
36
34
  } from '@dxos/react-ui-editor';
37
- import { isTileComponentProps } from '@dxos/react-ui-mosaic';
38
35
 
39
- import { type DocumentItemProps, DocumentCard, DocumentEditor, MarkdownEditor, MarkdownSettings } from './components';
36
+ import { MarkdownContainer, MarkdownSettings } from './components';
40
37
  import meta, { MARKDOWN_PLUGIN } from './meta';
41
38
  import translations from './translations';
42
- import { DocumentType, TextType } from './types';
39
+ import { DocumentType, isEditorModel, TextType } from './types';
43
40
  import {
44
41
  type MarkdownPluginProvides,
45
42
  type MarkdownSettingsProps,
@@ -48,52 +45,31 @@ import {
48
45
  } from './types';
49
46
  import { markdownExtensionPlugins, serializer } from './util';
50
47
 
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
- };
48
+ // TODO(burdon): Normalize active/object.
49
+ const getDoc = (object: any) => (object instanceof DocumentType ? object : undefined);
64
50
 
65
51
  export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
66
52
  const settings = new LocalStorageStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN, {
67
53
  defaultViewMode: 'preview',
68
54
  toolbar: true,
69
- folding: false,
55
+ numberedHeadings: true,
56
+ folding: true,
70
57
  experimental: false,
71
58
  });
72
59
 
73
- const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
60
+ const editorStateStore = createEditorStateStore(`${MARKDOWN_PLUGIN}/editor`);
74
61
 
75
- const getViewMode = (id?: string) => {
76
- return (id && state.values.viewMode[id]) || settings.values.defaultViewMode;
77
- };
62
+ const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
78
63
 
79
- const setViewMode = (id: string, nextViewMode: EditorViewMode) => {
80
- state.values.viewMode[id] = nextViewMode;
81
- };
64
+ const getViewMode = (id: string) => (id && state.values.viewMode[id]) || settings.values.defaultViewMode;
65
+ const setViewMode = (id: string, viewMode: EditorViewMode) => (state.values.viewMode[id] = viewMode);
82
66
 
83
67
  return {
84
68
  meta,
85
69
  ready: async (plugins) => {
86
70
  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
- })
71
+ .prop({ key: 'defaultViewMode', type: LocalStorageStore.enum<EditorViewMode>() })
72
+ .prop({ key: 'editorInputMode', type: LocalStorageStore.enum<EditorInputMode>({ allowUndefined: true }) })
97
73
  .prop({ key: 'toolbar', type: LocalStorageStore.bool({ allowUndefined: true }) })
98
74
  .prop({ key: 'experimental', type: LocalStorageStore.bool({ allowUndefined: true }) })
99
75
  .prop({ key: 'debug', type: LocalStorageStore.bool({ allowUndefined: true }) })
@@ -101,15 +77,11 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
101
77
  .prop({ key: 'numberedHeadings', type: LocalStorageStore.bool({ allowUndefined: true }) })
102
78
  .prop({ key: 'folding', type: LocalStorageStore.bool({ allowUndefined: true }) });
103
79
 
104
- state.prop({
105
- key: 'viewMode',
106
- storageKey: 'view-mode',
107
- type: LocalStorageStore.json<{ [key: string]: EditorViewMode }>(),
108
- });
80
+ state.prop({ key: 'viewMode', type: LocalStorageStore.json<{ [key: string]: EditorViewMode }>() });
109
81
 
110
82
  markdownExtensionPlugins(plugins).forEach((plugin) => {
111
83
  const { extensions } = plugin.provides.markdown;
112
- state.values.extensionProviders.push(extensions);
84
+ state.values.extensionProviders?.push(extensions);
113
85
  });
114
86
  },
115
87
  provides: {
@@ -117,10 +89,9 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
117
89
  metadata: {
118
90
  records: {
119
91
  [DocumentType.typename]: {
120
- label: (object: any) => (object instanceof DocumentType ? object.name ?? object.fallbackName : undefined),
92
+ label: (object: any) => (object instanceof DocumentType ? object.name || object.fallbackName : undefined),
121
93
  placeholder: ['document title placeholder', { ns: MARKDOWN_PLUGIN }],
122
- icon: (props: IconProps) => <TextAa {...props} />,
123
- iconSymbol: 'ph--text-aa--regular',
94
+ icon: 'ph--text-aa--regular',
124
95
  graphProps: {
125
96
  managesAutofocus: true,
126
97
  },
@@ -134,6 +105,12 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
134
105
  echo: {
135
106
  schema: [DocumentType, TextType],
136
107
  },
108
+ space: {
109
+ onSpaceCreate: {
110
+ label: ['create document label', { ns: MARKDOWN_PLUGIN }],
111
+ action: MarkdownAction.CREATE,
112
+ },
113
+ },
137
114
  graph: {
138
115
  builder: (plugins) => {
139
116
  const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
@@ -167,8 +144,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
167
144
  },
168
145
  properties: {
169
146
  label: ['create document label', { ns: MARKDOWN_PLUGIN }],
170
- icon: (props: IconProps) => <TextAa {...props} />,
171
- iconSymbol: 'ph--text-aa--regular',
147
+ icon: 'ph--text-aa--regular',
172
148
  testId: 'markdownPlugin.createObject',
173
149
  },
174
150
  },
@@ -241,13 +217,10 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
241
217
  ],
242
218
  },
243
219
  thread: {
244
- // TODO(Zan): How to better handle the type predicate?
245
220
  predicate: (obj) => obj instanceof DocumentType,
246
221
  createSort: (doc: DocumentType) => {
247
222
  const accessor = doc.content ? createDocAccessor(doc.content, ['content']) : undefined;
248
-
249
223
  if (!accessor) {
250
- log.warn('No accessor found for document content.');
251
224
  return (_) => 0;
252
225
  }
253
226
 
@@ -256,75 +229,44 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
256
229
  return range?.start ?? Number.MAX_SAFE_INTEGER;
257
230
  };
258
231
 
259
- return (anchorA: string, anchorB: string) => getStartPosition(anchorA) - getStartPosition(anchorB);
232
+ return (anchorA: string | undefined, anchorB: string | undefined): number => {
233
+ if (anchorA === undefined || anchorB === undefined) {
234
+ return 0;
235
+ }
236
+ const posA = getStartPosition(anchorA);
237
+ const posB = getStartPosition(anchorB);
238
+ return posA - posB;
239
+ };
260
240
  },
261
241
  },
262
242
  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
-
243
+ component: ({ data, role }) => {
271
244
  switch (role) {
272
245
  case 'section':
273
246
  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
- }
247
+ const doc = getDoc(data.object);
248
+ const { id, object } = isEditorModel(data.object)
249
+ ? { id: data.object.id, object: data.object }
250
+ : doc
251
+ ? { id: fullyQualifiedId(doc), object: doc }
252
+ : {};
305
253
 
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;
254
+ if (!id || !object) {
255
+ return null;
326
256
  }
327
- break;
257
+
258
+ return (
259
+ <MarkdownContainer
260
+ id={id}
261
+ object={object}
262
+ role={role}
263
+ settings={settings.values}
264
+ extensionProviders={state.values.extensionProviders}
265
+ viewMode={getViewMode(id)}
266
+ editorStateStore={editorStateStore}
267
+ onViewModeChange={setViewMode}
268
+ />
269
+ );
328
270
  }
329
271
 
330
272
  case 'settings': {
@@ -0,0 +1,109 @@
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' | '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 = ({
27
+ id,
28
+ role,
29
+ object,
30
+ extensionProviders,
31
+ settings,
32
+ viewMode,
33
+ editorStateStore,
34
+ onViewModeChange,
35
+ }: MarkdownContainerProps) => {
36
+ const scrollPastEnd = role === 'article';
37
+ const doc = object instanceof DocumentType ? object : undefined;
38
+ const extensions = useExtensions({ extensionProviders, document: doc, settings, viewMode, editorStateStore });
39
+
40
+ if (doc) {
41
+ return (
42
+ <DocumentEditor
43
+ id={fullyQualifiedId(object)}
44
+ role={role}
45
+ document={doc}
46
+ extensions={extensions}
47
+ settings={settings}
48
+ scrollPastEnd={scrollPastEnd}
49
+ onViewModeChange={onViewModeChange}
50
+ />
51
+ );
52
+ } else {
53
+ return (
54
+ <MarkdownEditor
55
+ id={id}
56
+ role={role}
57
+ initialValue={object.text}
58
+ extensions={extensions}
59
+ viewMode={viewMode}
60
+ toolbar={settings.toolbar}
61
+ inputMode={settings.editorInputMode}
62
+ scrollPastEnd={scrollPastEnd}
63
+ onViewModeChange={onViewModeChange}
64
+ />
65
+ );
66
+ }
67
+ };
68
+
69
+ type DocumentEditorProps = Omit<MarkdownContainerProps, 'object' | 'extensionProviders' | 'editorStateStore'> &
70
+ Pick<MarkdownEditorProps, 'id' | 'scrollPastEnd' | 'extensions'> & {
71
+ document: DocumentType;
72
+ };
73
+
74
+ export const DocumentEditor = ({ id, document: doc, settings, viewMode, ...props }: DocumentEditorProps) => {
75
+ const space = getSpace(doc);
76
+ const initialValue = useMemo(() => doc.content?.content, [doc.content]);
77
+
78
+ // Migrate gradually to `fallbackName`.
79
+ useEffect(() => {
80
+ if (!doc.fallbackName && doc.content?.content) {
81
+ doc.fallbackName = getFallbackName(doc.content.content);
82
+ }
83
+ }, [doc, doc.content]);
84
+
85
+ // File dragging.
86
+ const fileManagerPlugin = useResolvePlugin(parseFileManagerPlugin);
87
+ const handleFileUpload = useMemo(() => {
88
+ if (space === undefined || fileManagerPlugin?.provides.file.upload === undefined) {
89
+ return undefined;
90
+ }
91
+
92
+ // TODO(burdon): Re-order props: space, file.
93
+ return async (file: File) => fileManagerPlugin?.provides?.file?.upload?.(file, space);
94
+ }, [space, fileManagerPlugin]);
95
+
96
+ return (
97
+ <MarkdownEditor
98
+ id={id}
99
+ initialValue={initialValue}
100
+ viewMode={viewMode}
101
+ toolbar={settings.toolbar}
102
+ inputMode={settings.editorInputMode}
103
+ onFileUpload={handleFileUpload}
104
+ {...props}
105
+ />
106
+ );
107
+ };
108
+
109
+ 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;