@dxos/plugin-markdown 0.7.5-main.9cb18ac → 0.7.5-main.9d2a38b
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-XY6NEUOA.mjs → MarkdownContainer-ARRY4I6S.mjs} +95 -46
- package/dist/lib/browser/MarkdownContainer-ARRY4I6S.mjs.map +7 -0
- package/dist/lib/browser/app-graph-serializer-HHWSLYIW.mjs +51 -0
- package/dist/lib/browser/app-graph-serializer-HHWSLYIW.mjs.map +7 -0
- package/dist/lib/browser/{chunk-R4MG2DP2.mjs → chunk-ADAYSA5G.mjs} +20 -9
- package/dist/lib/browser/chunk-ADAYSA5G.mjs.map +7 -0
- package/dist/lib/browser/{chunk-6FIHBJRV.mjs → chunk-EMIIXXVX.mjs} +17 -12
- package/dist/lib/browser/chunk-EMIIXXVX.mjs.map +7 -0
- package/dist/lib/browser/chunk-FSAYVXSE.mjs +16 -0
- package/dist/lib/browser/chunk-FSAYVXSE.mjs.map +7 -0
- package/dist/lib/browser/{chunk-4X6YX3KU.mjs → chunk-YB2TJFNH.mjs} +3 -3
- package/dist/lib/browser/chunk-YB2TJFNH.mjs.map +7 -0
- package/dist/lib/browser/chunk-YPDWX3WI.mjs +47 -0
- package/dist/lib/browser/chunk-YPDWX3WI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +100 -367
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-resolver-4KWMUMND.mjs +37 -0
- package/dist/lib/browser/intent-resolver-4KWMUMND.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-surface-RL4CISJZ.mjs +152 -0
- package/dist/lib/browser/react-surface-RL4CISJZ.mjs.map +7 -0
- package/dist/lib/browser/settings-PTF73JDL.mjs +28 -0
- package/dist/lib/browser/settings-PTF73JDL.mjs.map +7 -0
- package/dist/lib/browser/state-DOVZP7XJ.mjs +37 -0
- package/dist/lib/browser/state-DOVZP7XJ.mjs.map +7 -0
- package/dist/lib/browser/thread-G4RS7NBZ.mjs +36 -0
- package/dist/lib/browser/thread-G4RS7NBZ.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +4 -4
- package/dist/lib/node/{MarkdownContainer-EX6YDF6J.cjs → MarkdownContainer-TV6W64EN.cjs} +100 -53
- package/dist/lib/node/MarkdownContainer-TV6W64EN.cjs.map +7 -0
- package/dist/lib/node/app-graph-serializer-PJRST43Q.cjs +62 -0
- package/dist/lib/node/app-graph-serializer-PJRST43Q.cjs.map +7 -0
- package/dist/lib/node/{chunk-CQMXZ54Z.cjs → chunk-34WFGSZU.cjs} +21 -16
- package/dist/lib/node/chunk-34WFGSZU.cjs.map +7 -0
- package/dist/lib/node/chunk-7WZANRNS.cjs +64 -0
- package/dist/lib/node/chunk-7WZANRNS.cjs.map +7 -0
- package/dist/lib/node/{meta.cjs → chunk-G7WKHUGU.cjs} +13 -8
- package/dist/lib/node/chunk-G7WKHUGU.cjs.map +7 -0
- package/dist/lib/node/{chunk-PHHIPRJC.cjs → chunk-HTWAAR54.cjs} +7 -7
- package/dist/lib/node/chunk-HTWAAR54.cjs.map +7 -0
- package/dist/lib/node/{chunk-SXQAPZZU.cjs → chunk-UFFFUC6W.cjs} +37 -12
- package/dist/lib/node/chunk-UFFFUC6W.cjs.map +7 -0
- package/dist/lib/node/index.cjs +92 -366
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/intent-resolver-QN25AFOP.cjs +50 -0
- package/dist/lib/node/intent-resolver-QN25AFOP.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/react-surface-RZ2XV56V.cjs +165 -0
- package/dist/lib/node/react-surface-RZ2XV56V.cjs.map +7 -0
- package/dist/lib/node/settings-BO5P5R4I.cjs +42 -0
- package/dist/lib/node/settings-BO5P5R4I.cjs.map +7 -0
- package/dist/lib/node/state-F26NQP7F.cjs +51 -0
- package/dist/lib/node/state-F26NQP7F.cjs.map +7 -0
- package/dist/lib/node/thread-THWQ67WS.cjs +52 -0
- package/dist/lib/node/thread-THWQ67WS.cjs.map +7 -0
- package/dist/lib/node/types/index.cjs +7 -7
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{MarkdownContainer-E7W623A7.mjs → MarkdownContainer-3ZHQTTMQ.mjs} +95 -46
- package/dist/lib/node-esm/MarkdownContainer-3ZHQTTMQ.mjs.map +7 -0
- package/dist/lib/node-esm/app-graph-serializer-JTHJUUS2.mjs +52 -0
- package/dist/lib/node-esm/app-graph-serializer-JTHJUUS2.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-2GHK262V.mjs +17 -0
- package/dist/lib/node-esm/chunk-2GHK262V.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-BABK7FMW.mjs → chunk-AOKWCL3O.mjs} +3 -3
- package/dist/lib/node-esm/chunk-AOKWCL3O.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ZVFBKBSA.mjs → chunk-CDFNMFGT.mjs} +17 -12
- package/dist/lib/node-esm/chunk-CDFNMFGT.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HLP536EW.mjs +48 -0
- package/dist/lib/node-esm/chunk-HLP536EW.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-Y76MM22C.mjs → chunk-Y5RSQVGH.mjs} +20 -9
- package/dist/lib/node-esm/chunk-Y5RSQVGH.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +100 -367
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/intent-resolver-F7MQOTG7.mjs +38 -0
- package/dist/lib/node-esm/intent-resolver-F7MQOTG7.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-surface-RRXHEW4R.mjs +153 -0
- package/dist/lib/node-esm/react-surface-RRXHEW4R.mjs.map +7 -0
- package/dist/lib/node-esm/settings-E7P5FQ3F.mjs +29 -0
- package/dist/lib/node-esm/settings-E7P5FQ3F.mjs.map +7 -0
- package/dist/lib/node-esm/state-HXSOQNOV.mjs +38 -0
- package/dist/lib/node-esm/state-HXSOQNOV.mjs.map +7 -0
- package/dist/lib/node-esm/thread-CYEXBXTW.mjs +37 -0
- package/dist/lib/node-esm/thread-CYEXBXTW.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +4 -4
- package/dist/types/src/MarkdownPlugin.d.ts +1 -3
- package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-serializer.d.ts +4 -0
- package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +1 -0
- package/dist/types/src/capabilities/capabilities.d.ts +12 -0
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +16 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +4 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +4 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +11 -0
- package/dist/types/src/capabilities/state.d.ts.map +1 -0
- package/dist/types/src/capabilities/thread.d.ts +6 -0
- package/dist/types/src/capabilities/thread.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownContainer.d.ts +1 -1
- package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor.d.ts +15 -0
- package/dist/types/src/components/MarkdownEditor.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar.stories.d.ts +2 -2
- package/dist/types/src/components/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions.d.ts +2 -2
- package/dist/types/src/extensions.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +0 -7
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +12 -26
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +1 -5
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -37
- package/src/MarkdownPlugin.tsx +79 -213
- package/src/capabilities/app-graph-serializer.ts +50 -0
- package/src/capabilities/capabilities.ts +20 -0
- package/src/capabilities/index.ts +14 -0
- package/src/capabilities/intent-resolver.ts +27 -0
- package/src/capabilities/react-surface.tsx +73 -0
- package/src/capabilities/settings.ts +25 -0
- package/src/capabilities/state.ts +31 -0
- package/src/capabilities/thread.ts +34 -0
- package/src/components/MarkdownContainer.tsx +6 -7
- package/src/components/MarkdownEditor.stories.tsx +16 -5
- package/src/components/MarkdownEditor.tsx +82 -48
- package/src/components/Toolbar.stories.tsx +16 -22
- package/src/extensions.tsx +13 -10
- package/src/index.ts +2 -5
- package/src/meta.ts +1 -1
- package/src/translations.ts +1 -0
- package/src/types/schema.ts +1 -5
- package/src/types/types.ts +16 -44
- package/src/util.tsx +2 -8
- package/dist/lib/browser/MarkdownContainer-XY6NEUOA.mjs.map +0 -7
- package/dist/lib/browser/chunk-4X6YX3KU.mjs.map +0 -7
- package/dist/lib/browser/chunk-6FIHBJRV.mjs.map +0 -7
- package/dist/lib/browser/chunk-R4MG2DP2.mjs.map +0 -7
- package/dist/lib/browser/meta.mjs +0 -9
- package/dist/lib/browser/meta.mjs.map +0 -7
- package/dist/lib/node/MarkdownContainer-EX6YDF6J.cjs.map +0 -7
- package/dist/lib/node/chunk-CQMXZ54Z.cjs.map +0 -7
- package/dist/lib/node/chunk-PHHIPRJC.cjs.map +0 -7
- package/dist/lib/node/chunk-SXQAPZZU.cjs.map +0 -7
- package/dist/lib/node/meta.cjs.map +0 -7
- package/dist/lib/node-esm/MarkdownContainer-E7W623A7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-BABK7FMW.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-Y76MM22C.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZVFBKBSA.mjs.map +0 -7
- package/dist/lib/node-esm/meta.mjs +0 -10
- package/dist/lib/node-esm/meta.mjs.map +0 -7
|
@@ -7,13 +7,18 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React, { useMemo } from 'react';
|
|
9
9
|
|
|
10
|
+
import { IntentPlugin } from '@dxos/app-framework';
|
|
11
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
12
|
import { createDocAccessor, createObject } from '@dxos/react-client/echo';
|
|
11
13
|
import { Main } from '@dxos/react-ui';
|
|
12
|
-
import {
|
|
14
|
+
import { AttendableContainer } from '@dxos/react-ui-attention';
|
|
15
|
+
import { withAttention } from '@dxos/react-ui-attention/testing';
|
|
16
|
+
import { editorWithToolbarLayout, automerge, translations as editorTranslations } from '@dxos/react-ui-editor';
|
|
13
17
|
import { topbarBlockPaddingStart } from '@dxos/react-ui-theme';
|
|
14
18
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
15
19
|
|
|
16
20
|
import { MarkdownEditor, type MarkdownEditorProps } from './MarkdownEditor';
|
|
21
|
+
import translations from '../translations';
|
|
17
22
|
|
|
18
23
|
const content = Array.from({ length: 100 })
|
|
19
24
|
.map((_, i) => `Line ${i + 1}`)
|
|
@@ -27,14 +32,15 @@ type StoryProps = MarkdownEditorProps & {
|
|
|
27
32
|
const DefaultStory = ({ content = '# Test', toolbar }: StoryProps) => {
|
|
28
33
|
const doc = useMemo(() => createObject({ content }), [content]);
|
|
29
34
|
const extensions = useMemo(() => [automerge(createDocAccessor(doc, ['content']))], [doc]);
|
|
30
|
-
|
|
31
35
|
return (
|
|
32
36
|
<Main.Content
|
|
33
37
|
bounce
|
|
34
38
|
data-toolbar={toolbar ? 'enabled' : 'disabled'}
|
|
35
39
|
classNames={[topbarBlockPaddingStart, editorWithToolbarLayout]}
|
|
36
40
|
>
|
|
37
|
-
<
|
|
41
|
+
<AttendableContainer id='test'>
|
|
42
|
+
<MarkdownEditor id='test' initialValue={doc.content} extensions={extensions} toolbar={toolbar} />
|
|
43
|
+
</AttendableContainer>
|
|
38
44
|
</Main.Content>
|
|
39
45
|
);
|
|
40
46
|
};
|
|
@@ -56,8 +62,13 @@ const meta: Meta<typeof MarkdownEditor> = {
|
|
|
56
62
|
title: 'plugins/plugin-markdown/EditorMain',
|
|
57
63
|
component: MarkdownEditor,
|
|
58
64
|
render: DefaultStory,
|
|
59
|
-
decorators: [
|
|
60
|
-
|
|
65
|
+
decorators: [
|
|
66
|
+
withTheme,
|
|
67
|
+
withLayout({ tooltips: true }),
|
|
68
|
+
withAttention,
|
|
69
|
+
withPluginManager({ plugins: [IntentPlugin()] }),
|
|
70
|
+
],
|
|
71
|
+
parameters: { layout: 'fullscreen', translations: [...translations, ...editorTranslations] },
|
|
61
72
|
};
|
|
62
73
|
|
|
63
74
|
export default meta;
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
import { openSearchPanel } from '@codemirror/search';
|
|
6
6
|
import { type EditorView } from '@codemirror/view';
|
|
7
7
|
import React, { useMemo, useEffect, useCallback } from 'react';
|
|
8
|
+
import { useDropzone } from 'react-dropzone';
|
|
8
9
|
|
|
9
10
|
import { createIntent, type FileInfo, LayoutAction, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
|
|
10
11
|
import { useThemeContext, useTranslation } from '@dxos/react-ui';
|
|
11
|
-
import { useAttention } from '@dxos/react-ui-attention';
|
|
12
12
|
import {
|
|
13
|
-
type
|
|
13
|
+
type EditorAction,
|
|
14
14
|
type DNDOptions,
|
|
15
15
|
type EditorViewMode,
|
|
16
16
|
type EditorInputMode,
|
|
17
17
|
type EditorSelectionState,
|
|
18
18
|
type EditorStateStore,
|
|
19
|
-
|
|
19
|
+
EditorToolbar,
|
|
20
20
|
type UseTextEditorProps,
|
|
21
21
|
createBasicExtensions,
|
|
22
22
|
createMarkdownExtensions,
|
|
@@ -24,23 +24,23 @@ import {
|
|
|
24
24
|
dropFile,
|
|
25
25
|
editorContent,
|
|
26
26
|
editorGutter,
|
|
27
|
-
|
|
27
|
+
processEditorPayload,
|
|
28
28
|
useActionHandler,
|
|
29
29
|
useCommentState,
|
|
30
30
|
useCommentClickListener,
|
|
31
31
|
useFormattingState,
|
|
32
32
|
useTextEditor,
|
|
33
|
+
stackItemContentEditorClassNames,
|
|
34
|
+
useEditorToolbarState,
|
|
35
|
+
createEditorAction,
|
|
33
36
|
} from '@dxos/react-ui-editor';
|
|
34
37
|
import { StackItem } from '@dxos/react-ui-stack';
|
|
35
|
-
import { mx, textBlockWidth } from '@dxos/react-ui-theme';
|
|
36
38
|
import { isNotFalsy, nonNullable } from '@dxos/util';
|
|
37
39
|
|
|
38
40
|
import { useSelectCurrentThread } from '../hooks';
|
|
39
41
|
import { MARKDOWN_PLUGIN } from '../meta';
|
|
40
42
|
import { type MarkdownPluginState } from '../types';
|
|
41
43
|
|
|
42
|
-
const DEFAULT_VIEW_MODE: EditorViewMode = 'preview';
|
|
43
|
-
|
|
44
44
|
export type MarkdownEditorProps = {
|
|
45
45
|
id: string;
|
|
46
46
|
role?: string;
|
|
@@ -76,8 +76,8 @@ export const MarkdownEditor = ({
|
|
|
76
76
|
const { t } = useTranslation(MARKDOWN_PLUGIN);
|
|
77
77
|
const { themeMode } = useThemeContext();
|
|
78
78
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
79
|
-
const
|
|
80
|
-
const
|
|
79
|
+
const toolbarState = useEditorToolbarState({ viewMode });
|
|
80
|
+
const formattingObserver = useFormattingState(toolbarState);
|
|
81
81
|
|
|
82
82
|
// Restore last selection and scroll point.
|
|
83
83
|
const { scrollTo, selection } = useMemo<EditorSelectionState>(() => editorStateStore?.getState(id) ?? {}, [id]);
|
|
@@ -89,20 +89,21 @@ export const MarkdownEditor = ({
|
|
|
89
89
|
[extensionProviders],
|
|
90
90
|
);
|
|
91
91
|
|
|
92
|
-
// TODO(Zan):
|
|
93
|
-
const
|
|
92
|
+
// TODO(Zan): Factor out to thread plugin.
|
|
93
|
+
const commentObserver = useCommentState(toolbarState);
|
|
94
94
|
const onCommentClick = useCallback(async () => {
|
|
95
95
|
await dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: 'comments' } }));
|
|
96
96
|
await dispatch(createIntent(LayoutAction.SetLayout, { element: 'complementary', state: true }));
|
|
97
97
|
}, [dispatch]);
|
|
98
98
|
const commentClickObserver = useCommentClickListener(onCommentClick);
|
|
99
99
|
|
|
100
|
+
// TODO(wittjosiah): Factor out to file uploader plugin.
|
|
100
101
|
// Drag files.
|
|
101
102
|
const handleDrop: DNDOptions['onDrop'] = async (view, { files }) => {
|
|
102
103
|
const file = files[0];
|
|
103
104
|
const info = file && onFileUpload ? await onFileUpload(file) : undefined;
|
|
104
105
|
if (info) {
|
|
105
|
-
|
|
106
|
+
processEditorPayload(view, { type: 'image', data: info.url });
|
|
106
107
|
}
|
|
107
108
|
};
|
|
108
109
|
|
|
@@ -148,57 +149,79 @@ export const MarkdownEditor = ({
|
|
|
148
149
|
useTest(editorView);
|
|
149
150
|
useSelectCurrentThread(editorView, id);
|
|
150
151
|
|
|
152
|
+
// https://react-dropzone.js.org/#src
|
|
153
|
+
const { acceptedFiles, getInputProps, open } = useDropzone({
|
|
154
|
+
multiple: false,
|
|
155
|
+
noDrag: true,
|
|
156
|
+
accept: {
|
|
157
|
+
'image/*': ['.jpg', '.jpeg', '.png', '.gif'],
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (editorView && onFileUpload && acceptedFiles.length) {
|
|
163
|
+
requestAnimationFrame(async () => {
|
|
164
|
+
// NOTE: Clone file since react-dropzone patches in a non-standard `path` property, which confuses IPFS.
|
|
165
|
+
const f = acceptedFiles[0];
|
|
166
|
+
const file = new File([f], f.name, {
|
|
167
|
+
type: f.type,
|
|
168
|
+
lastModified: f.lastModified,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const info = await onFileUpload(file);
|
|
172
|
+
if (info) {
|
|
173
|
+
processEditorPayload(editorView, { type: 'image', data: info.url });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}, [acceptedFiles, editorView]);
|
|
178
|
+
|
|
151
179
|
// Toolbar handler.
|
|
152
180
|
const handleToolbarAction = useActionHandler(editorView);
|
|
153
|
-
const handleAction = (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
const handleAction = useCallback(
|
|
182
|
+
(action: EditorAction) => {
|
|
183
|
+
switch (action.properties.type) {
|
|
184
|
+
case 'search': {
|
|
185
|
+
if (editorView) {
|
|
186
|
+
openSearchPanel(editorView);
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
case 'view-mode': {
|
|
191
|
+
onViewModeChange?.(id, action.properties.data);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
case 'image': {
|
|
195
|
+
open();
|
|
196
|
+
return;
|
|
158
197
|
}
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
case 'view-mode': {
|
|
162
|
-
onViewModeChange?.(id, action.data);
|
|
163
|
-
return;
|
|
164
198
|
}
|
|
165
|
-
}
|
|
166
199
|
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
handleToolbarAction?.(action);
|
|
201
|
+
},
|
|
202
|
+
[editorView, onViewModeChange, open],
|
|
203
|
+
);
|
|
169
204
|
|
|
170
205
|
return (
|
|
171
|
-
<StackItem.Content toolbar={toolbar}>
|
|
206
|
+
<StackItem.Content toolbar={!!toolbar}>
|
|
172
207
|
{toolbar && (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
>
|
|
180
|
-
<Toolbar.Root
|
|
181
|
-
classNames={[textBlockWidth, !hasAttention && 'opacity-20']}
|
|
182
|
-
state={formattingState && { ...formattingState, ...commentsState }}
|
|
208
|
+
<>
|
|
209
|
+
<EditorToolbar
|
|
210
|
+
attendableId={id}
|
|
211
|
+
role={role}
|
|
212
|
+
state={toolbarState}
|
|
213
|
+
customActions={onFileUpload ? createUploadAction : undefined}
|
|
183
214
|
onAction={handleAction}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
<Toolbar.Separator />
|
|
188
|
-
<Toolbar.View mode={viewMode ?? DEFAULT_VIEW_MODE} />
|
|
189
|
-
<Toolbar.Actions />
|
|
190
|
-
</Toolbar.Root>
|
|
191
|
-
</div>
|
|
215
|
+
/>
|
|
216
|
+
<input {...getInputProps()} />
|
|
217
|
+
</>
|
|
192
218
|
)}
|
|
193
219
|
<div
|
|
194
220
|
role='none'
|
|
195
221
|
ref={parentRef}
|
|
196
222
|
data-testid='composer.markdownRoot'
|
|
197
223
|
data-toolbar={toolbar ? 'enabled' : 'disabled'}
|
|
198
|
-
className={
|
|
199
|
-
'ch-focus-ring-inset data-[toolbar=disabled]:pbs-2 attention-surface',
|
|
200
|
-
role === 'article' ? 'min-bs-0' : '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24',
|
|
201
|
-
)}
|
|
224
|
+
className={stackItemContentEditorClassNames(role)}
|
|
202
225
|
{...focusAttributes}
|
|
203
226
|
/>
|
|
204
227
|
</StackItem.Content>
|
|
@@ -215,3 +238,14 @@ const useTest = (view?: EditorView) => {
|
|
|
215
238
|
}
|
|
216
239
|
}, [view]);
|
|
217
240
|
};
|
|
241
|
+
|
|
242
|
+
export const createUploadAction = () => ({
|
|
243
|
+
nodes: [
|
|
244
|
+
createEditorAction(
|
|
245
|
+
{ type: 'image', testId: 'editor.toolbar.image' },
|
|
246
|
+
'ph--image-square--regular',
|
|
247
|
+
'upload image label',
|
|
248
|
+
),
|
|
249
|
+
],
|
|
250
|
+
edges: [{ source: 'root', target: 'image' }],
|
|
251
|
+
});
|
|
@@ -13,9 +13,8 @@ import { faker } from '@dxos/random';
|
|
|
13
13
|
import { createDocAccessor, createObject } from '@dxos/react-client/echo';
|
|
14
14
|
import { useThemeContext } from '@dxos/react-ui';
|
|
15
15
|
import {
|
|
16
|
-
type
|
|
16
|
+
type EditorAction,
|
|
17
17
|
type Comment,
|
|
18
|
-
type EditorViewMode,
|
|
19
18
|
comments,
|
|
20
19
|
createBasicExtensions,
|
|
21
20
|
createDataExtensions,
|
|
@@ -24,32 +23,33 @@ import {
|
|
|
24
23
|
decorateMarkdown,
|
|
25
24
|
editorContent,
|
|
26
25
|
formattingKeymap,
|
|
27
|
-
|
|
26
|
+
EditorToolbar,
|
|
28
27
|
translations,
|
|
29
28
|
useActionHandler,
|
|
30
29
|
useComments,
|
|
31
30
|
useFormattingState,
|
|
32
31
|
useTextEditor,
|
|
32
|
+
useEditorToolbarState,
|
|
33
33
|
} from '@dxos/react-ui-editor';
|
|
34
|
-
import {
|
|
34
|
+
import { TextType } from '@dxos/schema';
|
|
35
35
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
36
36
|
|
|
37
|
-
import { TextType } from '../types';
|
|
38
|
-
|
|
39
37
|
faker.seed(101);
|
|
40
38
|
|
|
39
|
+
const _onUpload = async (file: File) => ({ url: file.name });
|
|
40
|
+
|
|
41
41
|
const DefaultStory: FC<{ content?: string }> = ({ content = '' }) => {
|
|
42
42
|
const { themeMode } = useThemeContext();
|
|
43
43
|
const [text] = useState(createObject(create(TextType, { content })));
|
|
44
|
-
const
|
|
45
|
-
const
|
|
44
|
+
const toolbarState = useEditorToolbarState({ viewMode: 'preview' });
|
|
45
|
+
const formattingObserver = useFormattingState(toolbarState);
|
|
46
46
|
const { parentRef, view } = useTextEditor(() => {
|
|
47
47
|
return {
|
|
48
48
|
id: text.id,
|
|
49
49
|
initialValue: text.content,
|
|
50
50
|
extensions: [
|
|
51
51
|
formattingObserver,
|
|
52
|
-
createBasicExtensions({ readonly: viewMode === 'readonly' }),
|
|
52
|
+
createBasicExtensions({ readonly: toolbarState.viewMode === 'readonly' }),
|
|
53
53
|
createMarkdownExtensions({ themeMode }),
|
|
54
54
|
createThemeExtensions({ themeMode, syntaxHighlighting: true, slots: { editor: { className: editorContent } } }),
|
|
55
55
|
createDataExtensions({ id: text.id, text: createDocAccessor(text, ['content']) }),
|
|
@@ -61,15 +61,15 @@ const DefaultStory: FC<{ content?: string }> = ({ content = '' }) => {
|
|
|
61
61
|
},
|
|
62
62
|
}),
|
|
63
63
|
formattingKeymap(),
|
|
64
|
-
...(viewMode !== 'source' ? [decorateMarkdown()] : []),
|
|
64
|
+
...(toolbarState.viewMode !== 'source' ? [decorateMarkdown()] : []),
|
|
65
65
|
],
|
|
66
66
|
};
|
|
67
|
-
}, [text, formattingObserver, viewMode, themeMode]);
|
|
67
|
+
}, [text, formattingObserver, toolbarState.viewMode, themeMode]);
|
|
68
68
|
|
|
69
69
|
const handleToolbarAction = useActionHandler(view);
|
|
70
|
-
const handleAction = (action:
|
|
70
|
+
const handleAction = (action: EditorAction) => {
|
|
71
71
|
if (action.type === 'view-mode') {
|
|
72
|
-
|
|
72
|
+
toolbarState.viewMode = action.properties.data;
|
|
73
73
|
} else {
|
|
74
74
|
handleToolbarAction?.(action);
|
|
75
75
|
}
|
|
@@ -80,13 +80,7 @@ const DefaultStory: FC<{ content?: string }> = ({ content = '' }) => {
|
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
82
|
<div role='none' className='fixed inset-0 flex flex-col'>
|
|
83
|
-
<
|
|
84
|
-
<Toolbar.View mode={viewMode} />
|
|
85
|
-
<Toolbar.Markdown />
|
|
86
|
-
<Toolbar.Custom onUpload={async (file) => ({ url: file.name })} />
|
|
87
|
-
<Toolbar.Separator />
|
|
88
|
-
<Toolbar.Actions />
|
|
89
|
-
</Toolbar.Root>
|
|
83
|
+
<EditorToolbar onAction={handleAction} state={toolbarState ?? {}} />
|
|
90
84
|
<div ref={parentRef} />
|
|
91
85
|
</div>
|
|
92
86
|
);
|
|
@@ -108,9 +102,9 @@ export const Default = {
|
|
|
108
102
|
},
|
|
109
103
|
};
|
|
110
104
|
|
|
111
|
-
const meta: Meta<typeof
|
|
105
|
+
const meta: Meta<typeof EditorToolbar> = {
|
|
112
106
|
title: 'plugins/plugin-markdown/Toolbar',
|
|
113
|
-
component:
|
|
107
|
+
component: EditorToolbar,
|
|
114
108
|
render: DefaultStory as any,
|
|
115
109
|
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
116
110
|
parameters: { translations, layout: 'fullscreen' },
|
package/src/extensions.tsx
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
import React, { type AnchorHTMLAttributes, type ReactNode, useMemo } from 'react';
|
|
6
6
|
import { createRoot } from 'react-dom/client';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
createIntent,
|
|
10
|
+
NavigationAction,
|
|
11
|
+
type PromiseIntentDispatcher,
|
|
12
|
+
useCapabilities,
|
|
13
|
+
useIntentDispatcher,
|
|
14
|
+
} from '@dxos/app-framework';
|
|
9
15
|
import { invariant } from '@dxos/invariant';
|
|
10
16
|
import { createDocAccessor, fullyQualifiedId, getSpace, type Query } from '@dxos/react-client/echo';
|
|
11
17
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
@@ -29,7 +35,8 @@ import {
|
|
|
29
35
|
import { defaultTx } from '@dxos/react-ui-theme';
|
|
30
36
|
import { isNotFalsy } from '@dxos/util';
|
|
31
37
|
|
|
32
|
-
import {
|
|
38
|
+
import { MarkdownCapabilities } from './capabilities';
|
|
39
|
+
import { type DocumentType, type MarkdownSettingsProps } from './types';
|
|
33
40
|
import { setFallbackName } from './util';
|
|
34
41
|
|
|
35
42
|
type ExtensionsOptions = {
|
|
@@ -42,13 +49,7 @@ type ExtensionsOptions = {
|
|
|
42
49
|
};
|
|
43
50
|
|
|
44
51
|
// TODO(burdon): Merge with createBaseExtensions below.
|
|
45
|
-
export const useExtensions = ({
|
|
46
|
-
document,
|
|
47
|
-
settings,
|
|
48
|
-
viewMode,
|
|
49
|
-
editorStateStore,
|
|
50
|
-
extensionProviders,
|
|
51
|
-
}: ExtensionsOptions & Pick<MarkdownPluginState, 'extensionProviders'>): Extension[] => {
|
|
52
|
+
export const useExtensions = ({ document, settings, viewMode, editorStateStore }: ExtensionsOptions): Extension[] => {
|
|
52
53
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
53
54
|
const identity = useIdentity();
|
|
54
55
|
const space = getSpace(document);
|
|
@@ -79,12 +80,14 @@ export const useExtensions = ({
|
|
|
79
80
|
],
|
|
80
81
|
);
|
|
81
82
|
|
|
83
|
+
const extensionProviders = useCapabilities(MarkdownCapabilities.Extensions);
|
|
84
|
+
|
|
82
85
|
//
|
|
83
86
|
// External extensions from other plugins.
|
|
84
87
|
//
|
|
85
88
|
const pluginExtensions = useMemo<Extension[] | undefined>(
|
|
86
89
|
() =>
|
|
87
|
-
extensionProviders
|
|
90
|
+
extensionProviders.flat().reduce((acc: Extension[], provider) => {
|
|
88
91
|
const extension = typeof provider === 'function' ? provider({ document }) : provider;
|
|
89
92
|
if (extension) {
|
|
90
93
|
acc.push(extension);
|
package/src/index.ts
CHANGED
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export default MarkdownPlugin;
|
|
8
|
-
|
|
5
|
+
export { MarkdownCapabilities } from './capabilities';
|
|
9
6
|
export * from './MarkdownPlugin';
|
|
10
|
-
export * from './
|
|
7
|
+
export * from './meta';
|
|
11
8
|
export * from './util';
|
package/src/meta.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type PluginMeta } from '@dxos/app-framework';
|
|
|
6
6
|
|
|
7
7
|
export const MARKDOWN_PLUGIN = 'dxos.org/plugin/markdown';
|
|
8
8
|
|
|
9
|
-
export
|
|
9
|
+
export const meta = {
|
|
10
10
|
id: MARKDOWN_PLUGIN,
|
|
11
11
|
name: 'Markdown',
|
|
12
12
|
description: 'Text editor supporting extended Markdown.',
|
package/src/translations.ts
CHANGED
package/src/types/schema.ts
CHANGED
|
@@ -4,11 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Ref, S, TypedObject } from '@dxos/echo-schema';
|
|
6
6
|
import { ThreadType } from '@dxos/plugin-space/types';
|
|
7
|
-
|
|
8
|
-
// TODO(burdon): Factor out.
|
|
9
|
-
export class TextType extends TypedObject({ typename: 'dxos.org/type/Text', version: '0.1.0' })({
|
|
10
|
-
content: S.String,
|
|
11
|
-
}) {}
|
|
7
|
+
import { TextType } from '@dxos/schema';
|
|
12
8
|
|
|
13
9
|
export class DocumentType extends TypedObject({ typename: 'dxos.org/type/Document', version: '0.1.0' })({
|
|
14
10
|
name: S.optional(S.String),
|
package/src/types/types.ts
CHANGED
|
@@ -2,17 +2,9 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import type {
|
|
6
|
-
GraphSerializerProvides,
|
|
7
|
-
IntentResolverProvides,
|
|
8
|
-
MetadataRecordsProvides,
|
|
9
|
-
SettingsProvides,
|
|
10
|
-
SurfaceProvides,
|
|
11
|
-
TranslationsProvides,
|
|
12
|
-
} from '@dxos/app-framework';
|
|
13
5
|
import { S } from '@dxos/echo-schema';
|
|
14
|
-
|
|
15
|
-
import { type Extension,
|
|
6
|
+
// TODO(wittjosiah): This pulls in UI code into the types entrypoint.
|
|
7
|
+
import { type Extension, EditorInputMode, EditorViewMode } from '@dxos/react-ui-editor';
|
|
16
8
|
|
|
17
9
|
import { DocumentType } from './schema';
|
|
18
10
|
import { MARKDOWN_PLUGIN } from '../meta';
|
|
@@ -46,13 +38,6 @@ export type MarkdownExtensionProvider = (props: { document?: DocumentType }) =>
|
|
|
46
38
|
|
|
47
39
|
export type OnChange = (text: string) => void;
|
|
48
40
|
|
|
49
|
-
export type MarkdownExtensionProvides = {
|
|
50
|
-
// TODO(burdon): Rename.
|
|
51
|
-
markdown: {
|
|
52
|
-
extensions: MarkdownExtensionProvider;
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
41
|
export type MarkdownPluginState = {
|
|
57
42
|
// Codemirror extensions provided by other plugins.
|
|
58
43
|
extensionProviders?: MarkdownExtensionProvider[];
|
|
@@ -62,31 +47,18 @@ export type MarkdownPluginState = {
|
|
|
62
47
|
viewMode: Record<string, EditorViewMode>;
|
|
63
48
|
};
|
|
64
49
|
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
type ThreadProvides<T> = {
|
|
79
|
-
thread: {
|
|
80
|
-
predicate: (obj: any) => obj is T;
|
|
81
|
-
createSort: (obj: T) => (anchorA: string | undefined, anchorB: string | undefined) => number;
|
|
82
|
-
};
|
|
83
|
-
};
|
|
50
|
+
export const MarkdownSettingsSchema = S.mutable(
|
|
51
|
+
S.Struct({
|
|
52
|
+
defaultViewMode: EditorViewMode,
|
|
53
|
+
editorInputMode: S.optional(EditorInputMode),
|
|
54
|
+
experimental: S.optional(S.Boolean),
|
|
55
|
+
debug: S.optional(S.Boolean),
|
|
56
|
+
toolbar: S.optional(S.Boolean),
|
|
57
|
+
typewriter: S.optional(S.String),
|
|
58
|
+
// TODO(burdon): Per document settings.
|
|
59
|
+
numberedHeadings: S.optional(S.Boolean),
|
|
60
|
+
folding: S.optional(S.Boolean),
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
84
63
|
|
|
85
|
-
export type
|
|
86
|
-
IntentResolverProvides &
|
|
87
|
-
GraphSerializerProvides &
|
|
88
|
-
MetadataRecordsProvides &
|
|
89
|
-
SettingsProvides<MarkdownSettingsProps> &
|
|
90
|
-
TranslationsProvides &
|
|
91
|
-
SchemaProvides &
|
|
92
|
-
ThreadProvides<DocumentType>;
|
|
64
|
+
export type MarkdownSettingsProps = S.Schema.Type<typeof MarkdownSettingsSchema>;
|
package/src/util.tsx
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Plugin } from '@dxos/app-framework';
|
|
6
5
|
import { debounce } from '@dxos/async';
|
|
7
6
|
import { type TypedObjectSerializer } from '@dxos/plugin-space/types';
|
|
8
7
|
import { create, createObject, isEchoObject, loadObjectReferences, makeRef } from '@dxos/react-client/echo';
|
|
8
|
+
import { TextType } from '@dxos/schema';
|
|
9
9
|
|
|
10
|
-
import { DocumentType, type MarkdownProperties
|
|
10
|
+
import { DocumentType, type MarkdownProperties } from './types';
|
|
11
11
|
|
|
12
12
|
export const isMarkdownProperties = (data: unknown): data is MarkdownProperties =>
|
|
13
13
|
isEchoObject(data)
|
|
@@ -16,12 +16,6 @@ export const isMarkdownProperties = (data: unknown): data is MarkdownProperties
|
|
|
16
16
|
? 'title' in data && typeof data.title === 'string'
|
|
17
17
|
: false;
|
|
18
18
|
|
|
19
|
-
type MarkdownExtensionPlugin = Plugin<MarkdownExtensionProvides>;
|
|
20
|
-
|
|
21
|
-
export const markdownExtensionPlugins = (plugins: Plugin[]): MarkdownExtensionPlugin[] => {
|
|
22
|
-
return (plugins as MarkdownExtensionPlugin[]).filter((plugin) => Boolean(plugin.provides?.markdown));
|
|
23
|
-
};
|
|
24
|
-
|
|
25
19
|
const nonTitleChars = /[^\w ]/g;
|
|
26
20
|
|
|
27
21
|
export const getFallbackName = (content: string) => {
|