@dxos/plugin-markdown 0.6.12-main.15a606f → 0.6.12-main.2d19bf1
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.
- package/dist/lib/browser/MarkdownContainer-52FJDCTV.mjs +467 -0
- package/dist/lib/browser/MarkdownContainer-52FJDCTV.mjs.map +7 -0
- package/dist/lib/browser/chunk-4MPY6KRJ.mjs +50 -0
- package/dist/lib/browser/chunk-4MPY6KRJ.mjs.map +7 -0
- package/dist/lib/browser/{chunk-2SJN46PA.mjs → chunk-DRJ3FPYF.mjs} +6 -7
- package/dist/lib/browser/chunk-DRJ3FPYF.mjs.map +7 -0
- package/dist/lib/browser/{chunk-R6CSLNWW.mjs → chunk-US5O2P3R.mjs} +4 -2
- package/dist/lib/browser/chunk-US5O2P3R.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +56 -103
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types/index.mjs +6 -4
- package/dist/lib/node/MarkdownContainer-5XPB5VP5.cjs +482 -0
- package/dist/lib/node/MarkdownContainer-5XPB5VP5.cjs.map +7 -0
- package/dist/lib/node/chunk-MOF6UCLA.cjs +72 -0
- package/dist/lib/node/chunk-MOF6UCLA.cjs.map +7 -0
- package/dist/lib/node/{chunk-LPD4NOTH.cjs → chunk-P7YU53RP.cjs} +8 -9
- package/dist/lib/node/chunk-P7YU53RP.cjs.map +7 -0
- package/dist/lib/node/{chunk-MCA5BBJR.cjs → chunk-UJMOZCIA.cjs} +11 -8
- package/dist/lib/node/chunk-UJMOZCIA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +92 -135
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.cjs +3 -3
- package/dist/lib/node/meta.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +8 -6
- package/dist/lib/node/types/index.cjs.map +2 -2
- package/dist/lib/node-esm/MarkdownContainer-ILCO3PDV.mjs +468 -0
- package/dist/lib/node-esm/MarkdownContainer-ILCO3PDV.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-CD634NG3.mjs +51 -0
- package/dist/lib/node-esm/chunk-CD634NG3.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-W525OVFX.mjs → chunk-MIDCCMIX.mjs} +4 -2
- package/dist/lib/node-esm/chunk-MIDCCMIX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-2BGTVWHN.mjs → chunk-NEVN5WR6.mjs} +6 -7
- package/dist/lib/node-esm/chunk-NEVN5WR6.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +56 -103
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +1 -1
- package/dist/lib/node-esm/types/index.mjs +6 -4
- package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownContainer.d.ts +15 -0
- package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownEditor.d.ts +7 -2
- package/dist/types/src/components/MarkdownEditor.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor.stories.d.ts +3 -3
- package/dist/types/src/components/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -11
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions.d.ts +11 -15
- package/dist/types/src/extensions.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +4 -6
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/types/document.d.ts +8 -1
- package/dist/types/src/types/document.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +4 -4
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/package.json +32 -31
- package/src/MarkdownPlugin.tsx +32 -87
- package/src/components/MarkdownContainer.tsx +108 -0
- package/src/components/MarkdownEditor.stories.tsx +11 -5
- package/src/components/MarkdownEditor.tsx +29 -36
- package/src/components/index.ts +2 -14
- package/src/extensions.tsx +124 -67
- package/src/{meta.tsx → meta.ts} +5 -5
- package/src/types/document.ts +12 -0
- package/src/types/types.ts +5 -3
- package/dist/lib/browser/DocumentCard-RKENHCNE.mjs +0 -11
- package/dist/lib/browser/DocumentCard-RKENHCNE.mjs.map +0 -7
- package/dist/lib/browser/DocumentEditor-FAXQRX37.mjs +0 -11
- package/dist/lib/browser/DocumentEditor-FAXQRX37.mjs.map +0 -7
- package/dist/lib/browser/MarkdownEditor-5EUT7P66.mjs +0 -10
- package/dist/lib/browser/MarkdownEditor-5EUT7P66.mjs.map +0 -7
- package/dist/lib/browser/chunk-2SJN46PA.mjs.map +0 -7
- package/dist/lib/browser/chunk-354DCID5.mjs +0 -117
- package/dist/lib/browser/chunk-354DCID5.mjs.map +0 -7
- package/dist/lib/browser/chunk-AFWT6Z7B.mjs +0 -86
- package/dist/lib/browser/chunk-AFWT6Z7B.mjs.map +0 -7
- package/dist/lib/browser/chunk-AVGUYNPR.mjs +0 -220
- package/dist/lib/browser/chunk-AVGUYNPR.mjs.map +0 -7
- package/dist/lib/browser/chunk-JDTH4A4I.mjs +0 -166
- package/dist/lib/browser/chunk-JDTH4A4I.mjs.map +0 -7
- package/dist/lib/browser/chunk-R6CSLNWW.mjs.map +0 -7
- package/dist/lib/node/DocumentCard-ECPKHJT7.cjs +0 -32
- package/dist/lib/node/DocumentCard-ECPKHJT7.cjs.map +0 -7
- package/dist/lib/node/DocumentEditor-YVZTTY5L.cjs +0 -29
- package/dist/lib/node/DocumentEditor-YVZTTY5L.cjs.map +0 -7
- package/dist/lib/node/MarkdownEditor-ZD4W4UJ6.cjs +0 -31
- package/dist/lib/node/MarkdownEditor-ZD4W4UJ6.cjs.map +0 -7
- package/dist/lib/node/chunk-2T7LIVPT.cjs +0 -246
- package/dist/lib/node/chunk-2T7LIVPT.cjs.map +0 -7
- package/dist/lib/node/chunk-5ZWOR7JF.cjs +0 -114
- package/dist/lib/node/chunk-5ZWOR7JF.cjs.map +0 -7
- package/dist/lib/node/chunk-KTYIOXL5.cjs +0 -149
- package/dist/lib/node/chunk-KTYIOXL5.cjs.map +0 -7
- package/dist/lib/node/chunk-LPD4NOTH.cjs.map +0 -7
- package/dist/lib/node/chunk-MCA5BBJR.cjs.map +0 -7
- package/dist/lib/node/chunk-OEWBZFBF.cjs +0 -191
- package/dist/lib/node/chunk-OEWBZFBF.cjs.map +0 -7
- package/dist/lib/node-esm/DocumentCard-RHVY4Z6L.mjs +0 -12
- package/dist/lib/node-esm/DocumentCard-RHVY4Z6L.mjs.map +0 -7
- package/dist/lib/node-esm/DocumentEditor-JBVVPEYE.mjs +0 -12
- package/dist/lib/node-esm/DocumentEditor-JBVVPEYE.mjs.map +0 -7
- package/dist/lib/node-esm/MarkdownEditor-OS7YG6MA.mjs +0 -11
- package/dist/lib/node-esm/MarkdownEditor-OS7YG6MA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2BGTVWHN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-OE3CMI5X.mjs +0 -87
- package/dist/lib/node-esm/chunk-OE3CMI5X.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-QARGBUBS.mjs +0 -221
- package/dist/lib/node-esm/chunk-QARGBUBS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RO5FEVW6.mjs +0 -119
- package/dist/lib/node-esm/chunk-RO5FEVW6.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UG4MIBCA.mjs +0 -167
- package/dist/lib/node-esm/chunk-UG4MIBCA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-W525OVFX.mjs.map +0 -7
- package/dist/types/src/components/DocumentCard.d.ts +0 -16
- package/dist/types/src/components/DocumentCard.d.ts.map +0 -1
- package/dist/types/src/components/DocumentEditor.d.ts +0 -14
- package/dist/types/src/components/DocumentEditor.d.ts.map +0 -1
- package/dist/types/src/components/HeadingMenu.d.ts +0 -13
- package/dist/types/src/components/HeadingMenu.d.ts.map +0 -1
- package/dist/types/src/components/Layout.d.ts +0 -6
- package/dist/types/src/components/Layout.d.ts.map +0 -1
- package/src/components/DocumentCard.tsx +0 -107
- package/src/components/DocumentEditor.tsx +0 -139
- package/src/components/HeadingMenu.tsx +0 -46
- package/src/components/Layout.tsx +0 -27
package/src/MarkdownPlugin.tsx
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { TextAa } from '@phosphor-icons/react';
|
|
6
|
-
import React
|
|
6
|
+
import React from 'react';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
isObject,
|
|
10
9
|
parseIntentPlugin,
|
|
11
10
|
resolvePlugin,
|
|
12
11
|
LayoutAction,
|
|
@@ -33,12 +32,11 @@ import {
|
|
|
33
32
|
EditorViewModes,
|
|
34
33
|
translations as editorTranslations,
|
|
35
34
|
} from '@dxos/react-ui-editor';
|
|
36
|
-
import { isTileComponentProps } from '@dxos/react-ui-mosaic';
|
|
37
35
|
|
|
38
|
-
import {
|
|
36
|
+
import { MarkdownContainer, MarkdownSettings } from './components';
|
|
39
37
|
import meta, { MARKDOWN_PLUGIN } from './meta';
|
|
40
38
|
import translations from './translations';
|
|
41
|
-
import { DocumentType, TextType } from './types';
|
|
39
|
+
import { DocumentType, isEditorModel, TextType } from './types';
|
|
42
40
|
import {
|
|
43
41
|
type MarkdownPluginProvides,
|
|
44
42
|
type MarkdownSettingsProps,
|
|
@@ -47,19 +45,8 @@ import {
|
|
|
47
45
|
} from './types';
|
|
48
46
|
import { markdownExtensionPlugins, serializer } from './util';
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
*/
|
|
53
|
-
const isEditorModel = (data: any): data is { id: string; text: string } => {
|
|
54
|
-
return (
|
|
55
|
-
data &&
|
|
56
|
-
typeof data === 'object' &&
|
|
57
|
-
'id' in data &&
|
|
58
|
-
typeof data.id === 'string' &&
|
|
59
|
-
'text' in data &&
|
|
60
|
-
typeof data.text === 'string'
|
|
61
|
-
);
|
|
62
|
-
};
|
|
48
|
+
// TODO(burdon): Normalize active/object.
|
|
49
|
+
const getDoc = (object: any) => (object instanceof DocumentType ? object : undefined);
|
|
63
50
|
|
|
64
51
|
export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
|
|
65
52
|
const settings = new LocalStorageStore<MarkdownSettingsProps>(MARKDOWN_PLUGIN, {
|
|
@@ -71,13 +58,8 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
|
|
|
71
58
|
|
|
72
59
|
const state = new LocalStorageStore<MarkdownPluginState>(MARKDOWN_PLUGIN, { extensionProviders: [], viewMode: {} });
|
|
73
60
|
|
|
74
|
-
const getViewMode = (id
|
|
75
|
-
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const setViewMode = (id: string, nextViewMode: EditorViewMode) => {
|
|
79
|
-
state.values.viewMode[id] = nextViewMode;
|
|
80
|
-
};
|
|
61
|
+
const getViewMode = (id: string) => (id && state.values.viewMode[id]) || settings.values.defaultViewMode;
|
|
62
|
+
const setViewMode = (id: string, viewMode: EditorViewMode) => (state.values.viewMode[id] = viewMode);
|
|
81
63
|
|
|
82
64
|
return {
|
|
83
65
|
meta,
|
|
@@ -108,7 +90,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
|
|
|
108
90
|
|
|
109
91
|
markdownExtensionPlugins(plugins).forEach((plugin) => {
|
|
110
92
|
const { extensions } = plugin.provides.markdown;
|
|
111
|
-
state.values.extensionProviders
|
|
93
|
+
state.values.extensionProviders?.push(extensions);
|
|
112
94
|
});
|
|
113
95
|
},
|
|
114
96
|
provides: {
|
|
@@ -116,7 +98,7 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
|
|
|
116
98
|
metadata: {
|
|
117
99
|
records: {
|
|
118
100
|
[DocumentType.typename]: {
|
|
119
|
-
label: (object: any) => (object instanceof DocumentType ? object.name
|
|
101
|
+
label: (object: any) => (object instanceof DocumentType ? object.name || object.fallbackName : undefined),
|
|
120
102
|
placeholder: ['document title placeholder', { ns: MARKDOWN_PLUGIN }],
|
|
121
103
|
icon: 'ph--text-aa--regular',
|
|
122
104
|
graphProps: {
|
|
@@ -267,71 +249,34 @@ export const MarkdownPlugin = (): PluginDefinition<MarkdownPluginProvides> => {
|
|
|
267
249
|
},
|
|
268
250
|
},
|
|
269
251
|
surface: {
|
|
270
|
-
component: ({ data, role
|
|
271
|
-
const doc =
|
|
272
|
-
data.active instanceof DocumentType
|
|
273
|
-
? data.active
|
|
274
|
-
: data.object instanceof DocumentType
|
|
275
|
-
? data.object
|
|
276
|
-
: undefined;
|
|
277
|
-
|
|
252
|
+
component: ({ data, role }) => {
|
|
278
253
|
switch (role) {
|
|
279
254
|
case 'section':
|
|
280
255
|
case 'article': {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
settings={settings.values}
|
|
289
|
-
scrollPastEnd
|
|
290
|
-
viewMode={getViewMode(fullyQualifiedId(doc))}
|
|
291
|
-
onViewModeChange={setViewMode}
|
|
292
|
-
/>
|
|
293
|
-
);
|
|
294
|
-
} else if (isEditorModel(data.object)) {
|
|
295
|
-
return (
|
|
296
|
-
<MarkdownEditor
|
|
297
|
-
id={data.object.id}
|
|
298
|
-
role={role}
|
|
299
|
-
coordinate={data.coordinate as LayoutCoordinate}
|
|
300
|
-
initialValue={data.object.text}
|
|
301
|
-
extensionProviders={state.values.extensionProviders}
|
|
302
|
-
inputMode={settings.values.editorInputMode}
|
|
303
|
-
toolbar={settings.values.toolbar}
|
|
304
|
-
scrollPastEnd
|
|
305
|
-
viewMode={getViewMode(data.object.id)}
|
|
306
|
-
onViewModeChange={setViewMode}
|
|
307
|
-
/>
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
case 'card': {
|
|
314
|
-
if (
|
|
315
|
-
isObject(data.content) &&
|
|
316
|
-
typeof data.content.id === 'string' &&
|
|
317
|
-
data.content.object instanceof DocumentType
|
|
318
|
-
) {
|
|
319
|
-
// isTileComponentProps is a type guard for these props.
|
|
320
|
-
// `props` will not pass this guard without transforming `data` into `item`.
|
|
321
|
-
const cardProps = {
|
|
322
|
-
...props,
|
|
323
|
-
item: {
|
|
324
|
-
id: data.content.id,
|
|
325
|
-
object: data.content.object,
|
|
326
|
-
color: typeof data.content.color === 'string' ? data.content.color : undefined,
|
|
327
|
-
} as DocumentItemProps,
|
|
328
|
-
};
|
|
256
|
+
// TODO(burdon): Normalize types (from FilesPlugin).
|
|
257
|
+
const doc = getDoc(data.active) ?? getDoc(data.object);
|
|
258
|
+
const { id, object } = isEditorModel(data.object)
|
|
259
|
+
? { id: data.object.id, object: data.object }
|
|
260
|
+
: doc
|
|
261
|
+
? { id: fullyQualifiedId(doc), object: doc }
|
|
262
|
+
: {};
|
|
329
263
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
) : null;
|
|
264
|
+
if (!id || !object) {
|
|
265
|
+
return null;
|
|
333
266
|
}
|
|
334
|
-
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<MarkdownContainer
|
|
270
|
+
id={id}
|
|
271
|
+
object={object}
|
|
272
|
+
role={role}
|
|
273
|
+
coordinate={data.coordinate as LayoutCoordinate}
|
|
274
|
+
settings={settings.values}
|
|
275
|
+
extensionProviders={state.values.extensionProviders}
|
|
276
|
+
viewMode={getViewMode(id)}
|
|
277
|
+
onViewModeChange={setViewMode}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
335
280
|
}
|
|
336
281
|
|
|
337
282
|
case 'settings': {
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
import { localStorageStateStoreAdapter, type EditorSelectionState } from '@dxos/react-ui-editor';
|
|
10
|
+
|
|
11
|
+
import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
|
|
12
|
+
import { useExtensions } from '../extensions';
|
|
13
|
+
import { DocumentType, type MarkdownSettingsProps } from '../types';
|
|
14
|
+
import { getFallbackName } from '../util';
|
|
15
|
+
|
|
16
|
+
export type MarkdownContainerProps = Pick<
|
|
17
|
+
MarkdownEditorProps,
|
|
18
|
+
'role' | 'coordinate' | 'extensionProviders' | 'viewMode' | 'onViewModeChange'
|
|
19
|
+
> & {
|
|
20
|
+
id: string;
|
|
21
|
+
object: DocumentType | any;
|
|
22
|
+
settings: MarkdownSettingsProps;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// TODO(burdon): Factor out difference for ECHO and non-ECHO objects; i.e., single component.
|
|
26
|
+
const MarkdownContainer = ({ role, id, object, settings, ...props }: MarkdownContainerProps) => {
|
|
27
|
+
const scrollPastEnd = role === 'article';
|
|
28
|
+
if (object instanceof DocumentType) {
|
|
29
|
+
return (
|
|
30
|
+
<DocumentEditor
|
|
31
|
+
id={fullyQualifiedId(object)}
|
|
32
|
+
document={object}
|
|
33
|
+
settings={settings}
|
|
34
|
+
scrollPastEnd={scrollPastEnd}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
} else {
|
|
39
|
+
return (
|
|
40
|
+
<MarkdownEditor
|
|
41
|
+
id={id}
|
|
42
|
+
initialValue={object.text}
|
|
43
|
+
toolbar={settings.toolbar}
|
|
44
|
+
scrollPastEnd={scrollPastEnd}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type DocumentEditorProps = Omit<MarkdownContainerProps, 'object'> & { document: DocumentType } & Pick<
|
|
52
|
+
MarkdownEditorProps,
|
|
53
|
+
'id' | 'scrollPastEnd'
|
|
54
|
+
>;
|
|
55
|
+
|
|
56
|
+
export const DocumentEditor = ({
|
|
57
|
+
id,
|
|
58
|
+
document: doc,
|
|
59
|
+
extensionProviders,
|
|
60
|
+
settings,
|
|
61
|
+
viewMode,
|
|
62
|
+
...props
|
|
63
|
+
}: DocumentEditorProps) => {
|
|
64
|
+
const space = getSpace(doc);
|
|
65
|
+
const initialValue = useMemo(() => doc.content?.content, [doc.content]);
|
|
66
|
+
const extensions = useExtensions({ extensionProviders, document: doc, settings, viewMode });
|
|
67
|
+
|
|
68
|
+
// Migrate gradually to `fallbackName`.
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!doc.fallbackName && doc.content?.content) {
|
|
71
|
+
doc.fallbackName = getFallbackName(doc.content.content);
|
|
72
|
+
}
|
|
73
|
+
}, [doc, doc.content]);
|
|
74
|
+
|
|
75
|
+
// Restore last selection and scroll point.
|
|
76
|
+
const { scrollTo, selection } = useMemo<EditorSelectionState>(
|
|
77
|
+
() => localStorageStateStoreAdapter.getState(id) ?? {},
|
|
78
|
+
[id, doc],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// File dragging.
|
|
82
|
+
const fileManagerPlugin = useResolvePlugin(parseFileManagerPlugin);
|
|
83
|
+
const handleFileUpload = useMemo(() => {
|
|
84
|
+
if (space === undefined || fileManagerPlugin?.provides.file.upload === undefined) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// TODO(burdon): Re-order props: space, file.
|
|
89
|
+
return async (file: File) => fileManagerPlugin?.provides?.file?.upload?.(file, space);
|
|
90
|
+
}, [space, fileManagerPlugin]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<MarkdownEditor
|
|
94
|
+
id={id}
|
|
95
|
+
initialValue={initialValue}
|
|
96
|
+
extensions={extensions}
|
|
97
|
+
scrollTo={scrollTo}
|
|
98
|
+
selection={selection}
|
|
99
|
+
toolbar={settings.toolbar}
|
|
100
|
+
inputMode={settings.editorInputMode}
|
|
101
|
+
viewMode={viewMode}
|
|
102
|
+
onFileUpload={handleFileUpload}
|
|
103
|
+
{...props}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default MarkdownContainer;
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
|
+
|
|
6
7
|
import React, { useMemo, type FC } from 'react';
|
|
7
8
|
|
|
8
9
|
import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
|
|
9
|
-
import {
|
|
10
|
+
import { Main } from '@dxos/react-ui';
|
|
11
|
+
import { editorWithToolbarLayout, automerge } from '@dxos/react-ui-editor';
|
|
12
|
+
import { topbarBlockPaddingStart } from '@dxos/react-ui-theme';
|
|
10
13
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
11
14
|
|
|
12
|
-
import { MainLayout } from './Layout';
|
|
13
15
|
import { MarkdownEditor } from './MarkdownEditor';
|
|
14
16
|
|
|
15
17
|
const Story: FC<{
|
|
@@ -20,9 +22,13 @@ const Story: FC<{
|
|
|
20
22
|
const extensions = useMemo(() => [automerge(createDocAccessor(doc, ['content']))], [doc]);
|
|
21
23
|
|
|
22
24
|
return (
|
|
23
|
-
<
|
|
25
|
+
<Main.Content
|
|
26
|
+
bounce
|
|
27
|
+
data-toolbar={toolbar ? 'enabled' : 'disabled'}
|
|
28
|
+
classNames={[topbarBlockPaddingStart, editorWithToolbarLayout]}
|
|
29
|
+
>
|
|
24
30
|
<MarkdownEditor id='test' initialValue={doc.content} extensions={extensions} toolbar={toolbar} />
|
|
25
|
-
</
|
|
31
|
+
</Main.Content>
|
|
26
32
|
);
|
|
27
33
|
};
|
|
28
34
|
|
|
@@ -30,8 +36,8 @@ export default {
|
|
|
30
36
|
title: 'plugin-markdown/EditorMain',
|
|
31
37
|
component: MarkdownEditor,
|
|
32
38
|
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
33
|
-
render: Story,
|
|
34
39
|
parameters: { layout: 'fullscreen' },
|
|
40
|
+
render: Story,
|
|
35
41
|
};
|
|
36
42
|
|
|
37
43
|
const content = Array.from({ length: 100 })
|
|
@@ -6,35 +6,28 @@ import { openSearchPanel } from '@codemirror/search';
|
|
|
6
6
|
import { type EditorView } from '@codemirror/view';
|
|
7
7
|
import React, { useMemo, useEffect, useCallback } from 'react';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
type FileInfo,
|
|
11
|
-
LayoutAction,
|
|
12
|
-
type LayoutCoordinate,
|
|
13
|
-
useResolvePlugin,
|
|
14
|
-
parseLayoutPlugin,
|
|
15
|
-
useIntentDispatcher,
|
|
16
|
-
} from '@dxos/app-framework';
|
|
9
|
+
import { type FileInfo, LayoutAction, type LayoutCoordinate, useIntentDispatcher } from '@dxos/app-framework';
|
|
17
10
|
import { useThemeContext, useTranslation } from '@dxos/react-ui';
|
|
18
|
-
import {
|
|
11
|
+
import { useAttendableAttributes, useAttention } from '@dxos/react-ui-attention';
|
|
19
12
|
import {
|
|
20
13
|
type Action,
|
|
21
14
|
type DNDOptions,
|
|
22
15
|
type EditorViewMode,
|
|
23
16
|
type EditorInputMode,
|
|
24
|
-
type UseTextEditorProps,
|
|
25
17
|
Toolbar,
|
|
18
|
+
type UseTextEditorProps,
|
|
26
19
|
createBasicExtensions,
|
|
27
20
|
createMarkdownExtensions,
|
|
28
21
|
createThemeExtensions,
|
|
29
22
|
dropFile,
|
|
23
|
+
editorContent,
|
|
24
|
+
editorGutter,
|
|
30
25
|
processAction,
|
|
31
26
|
useActionHandler,
|
|
32
27
|
useCommentState,
|
|
33
28
|
useCommentClickListener,
|
|
34
29
|
useFormattingState,
|
|
35
30
|
useTextEditor,
|
|
36
|
-
editorContent,
|
|
37
|
-
editorGutter,
|
|
38
31
|
} from '@dxos/react-ui-editor';
|
|
39
32
|
import { sectionToolbarLayout } from '@dxos/react-ui-stack';
|
|
40
33
|
import { textBlockWidth, focusRing, mx } from '@dxos/react-ui-theme';
|
|
@@ -44,19 +37,13 @@ import { useSelectCurrentThread } from '../hooks';
|
|
|
44
37
|
import { MARKDOWN_PLUGIN } from '../meta';
|
|
45
38
|
import { type MarkdownPluginState } from '../types';
|
|
46
39
|
|
|
47
|
-
// TODO(Zan): Factor into a shared location.
|
|
48
|
-
const attentionFragment = mx(
|
|
49
|
-
'group-focus-within/editor:attention-surface group-[[aria-current]]/editor:attention-surface',
|
|
50
|
-
'group-focus-within/editor:border-separator',
|
|
51
|
-
);
|
|
52
|
-
|
|
53
40
|
const DEFAULT_VIEW_MODE: EditorViewMode = 'preview';
|
|
54
41
|
|
|
55
42
|
export type MarkdownEditorProps = {
|
|
56
43
|
id: string;
|
|
44
|
+
role?: string;
|
|
57
45
|
coordinate?: LayoutCoordinate;
|
|
58
46
|
inputMode?: EditorInputMode;
|
|
59
|
-
role?: string;
|
|
60
47
|
scrollPastEnd?: boolean;
|
|
61
48
|
toolbar?: boolean;
|
|
62
49
|
viewMode?: EditorViewMode;
|
|
@@ -65,6 +52,12 @@ export type MarkdownEditorProps = {
|
|
|
65
52
|
} & Pick<UseTextEditorProps, 'initialValue' | 'scrollTo' | 'selection' | 'extensions'> &
|
|
66
53
|
Partial<Pick<MarkdownPluginState, 'extensionProviders'>>;
|
|
67
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Base markdown editor component.
|
|
57
|
+
*
|
|
58
|
+
* This component provides all the features of the markdown editor that do no depend on ECHO.
|
|
59
|
+
* This allows it to be used as a common editor for markdown content on arbitrary backends (e.g. files).
|
|
60
|
+
*/
|
|
68
61
|
export const MarkdownEditor = ({
|
|
69
62
|
id,
|
|
70
63
|
role = 'article',
|
|
@@ -82,13 +75,13 @@ export const MarkdownEditor = ({
|
|
|
82
75
|
const { t } = useTranslation(MARKDOWN_PLUGIN);
|
|
83
76
|
const { themeMode } = useThemeContext();
|
|
84
77
|
const dispatch = useIntentDispatcher();
|
|
85
|
-
const layoutPlugin = useResolvePlugin(parseLayoutPlugin);
|
|
86
78
|
const [formattingState, formattingObserver] = useFormattingState();
|
|
87
|
-
const
|
|
79
|
+
const attendableAttributes = useAttendableAttributes(id);
|
|
80
|
+
const { hasAttention } = useAttention(id);
|
|
88
81
|
|
|
89
82
|
// Extensions from other plugins.
|
|
83
|
+
// TODO(burdon): Reconcile with DocumentEditor.useExtensions.
|
|
90
84
|
const providerExtensions = useMemo(
|
|
91
|
-
// TODO(burdon): Must pass object to provider.
|
|
92
85
|
() => extensionProviders?.flatMap((provider) => provider({})).filter(nonNullable),
|
|
93
86
|
[extensionProviders],
|
|
94
87
|
);
|
|
@@ -96,7 +89,10 @@ export const MarkdownEditor = ({
|
|
|
96
89
|
// TODO(Zan): Move these into thread plugin as well?
|
|
97
90
|
const [commentsState, commentObserver] = useCommentState();
|
|
98
91
|
const onCommentClick = useCallback(() => {
|
|
99
|
-
void dispatch({
|
|
92
|
+
void dispatch({
|
|
93
|
+
action: LayoutAction.SET_LAYOUT,
|
|
94
|
+
data: { element: 'complementary', state: true },
|
|
95
|
+
});
|
|
100
96
|
}, [dispatch]);
|
|
101
97
|
const commentClickObserver = useCommentClickListener(onCommentClick);
|
|
102
98
|
|
|
@@ -141,7 +137,7 @@ export const MarkdownEditor = ({
|
|
|
141
137
|
scrollTo,
|
|
142
138
|
selection,
|
|
143
139
|
// TODO(wittjosiah): Autofocus based on layout is racy.
|
|
144
|
-
autoFocus: layoutPlugin?.provides.layout ? layoutPlugin?.provides.layout.scrollIntoView === id : true,
|
|
140
|
+
// autoFocus: layoutPlugin?.provides.layout ? layoutPlugin?.provides.layout.scrollIntoView === id : true,
|
|
145
141
|
moveToEndOfLine: true,
|
|
146
142
|
}),
|
|
147
143
|
}),
|
|
@@ -177,25 +173,24 @@ export const MarkdownEditor = ({
|
|
|
177
173
|
{...(role === 'section'
|
|
178
174
|
? { className: 'flex flex-col' }
|
|
179
175
|
: {
|
|
180
|
-
className: 'contents
|
|
181
|
-
|
|
176
|
+
className: 'contents',
|
|
177
|
+
// TODO(wittjosiah): Factor out to `useAttendableAttributes`?
|
|
178
|
+
...(hasAttention && { 'aria-current': 'location' }),
|
|
179
|
+
...attendableAttributes,
|
|
182
180
|
})}
|
|
183
181
|
>
|
|
184
182
|
{toolbar && (
|
|
185
|
-
<div role='none' className=
|
|
183
|
+
<div role='none' className='flex shrink-0 justify-center overflow-x-auto attention-surface'>
|
|
186
184
|
<Toolbar.Root
|
|
187
185
|
classNames={
|
|
188
186
|
role === 'section'
|
|
189
187
|
? [
|
|
190
188
|
textBlockWidth,
|
|
191
189
|
'z-[2] group-focus-within/section:visible',
|
|
192
|
-
!
|
|
190
|
+
!hasAttention && 'invisible',
|
|
193
191
|
sectionToolbarLayout,
|
|
194
192
|
]
|
|
195
|
-
: [
|
|
196
|
-
textBlockWidth,
|
|
197
|
-
'group-focus-within/editor:border-separator group-[[aria-current]]/editor:border-separator',
|
|
198
|
-
]
|
|
193
|
+
: [textBlockWidth]
|
|
199
194
|
}
|
|
200
195
|
state={formattingState && { ...formattingState, ...commentsState }}
|
|
201
196
|
onAction={handleAction}
|
|
@@ -219,8 +214,8 @@ export const MarkdownEditor = ({
|
|
|
219
214
|
: mx(
|
|
220
215
|
'flex is-full bs-full overflow-hidden',
|
|
221
216
|
focusRing,
|
|
222
|
-
|
|
223
|
-
'
|
|
217
|
+
'focus-visible:ring-inset attention-surface',
|
|
218
|
+
'p-0.5', // TODO(burdon): Handle padding for focusRing consistently.
|
|
224
219
|
'data-[toolbar=disabled]:pbs-2 data-[toolbar=disabled]:row-span-2',
|
|
225
220
|
)
|
|
226
221
|
}
|
|
@@ -240,5 +235,3 @@ const useTest = (view?: EditorView) => {
|
|
|
240
235
|
}
|
|
241
236
|
}, [view]);
|
|
242
237
|
};
|
|
243
|
-
|
|
244
|
-
export default MarkdownEditor;
|
package/src/components/index.ts
CHANGED
|
@@ -2,20 +2,8 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React
|
|
5
|
+
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { type DocumentEditor as DocumentEditorType } from './DocumentEditor';
|
|
8
|
-
|
|
9
|
-
export { type DocumentCardProps, type DocumentItemProps } from './DocumentCard';
|
|
10
|
-
|
|
11
|
-
export * from './DocumentCard';
|
|
12
|
-
export * from './DocumentEditor';
|
|
13
|
-
export * from './MarkdownEditor';
|
|
14
|
-
export * from './HeadingMenu';
|
|
15
|
-
export * from './Layout';
|
|
16
7
|
export * from './MarkdownSettings';
|
|
17
8
|
|
|
18
|
-
|
|
19
|
-
export const DocumentCard = React.lazy(() => import('./DocumentCard'));
|
|
20
|
-
export const DocumentEditor: LazyExoticComponent<DocumentEditorType> = React.lazy(() => import('./DocumentEditor'));
|
|
21
|
-
export const MarkdownEditor = React.lazy(() => import('./MarkdownEditor'));
|
|
9
|
+
export const MarkdownContainer = React.lazy(() => import('./MarkdownContainer'));
|