@dxos/react-ui-editor 0.8.2-main.fbd8ed0 → 0.8.2-staging.7ac8446
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/index.mjs +5088 -5521
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +4915 -5354
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +5088 -5521
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/{components/EditorToolbar/EditorToolbar.stories.d.ts → InputMode.stories.d.ts} +7 -3
- package/dist/types/src/InputMode.stories.d.ts.map +1 -0
- package/dist/types/src/{stories/TextEditorBasic.stories.d.ts → TextEditor.stories.d.ts} +35 -5
- package/dist/types/src/TextEditor.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +3 -4
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/comment.d.ts +3 -4
- package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +3 -4
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +3 -4
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts +3 -4
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/util.d.ts +20 -14
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/{view-mode.d.ts → viewMode.d.ts} +4 -5
- package/dist/types/src/components/EditorToolbar/viewMode.d.ts.map +1 -0
- package/dist/types/src/defaults.d.ts +0 -1
- package/dist/types/src/defaults.d.ts.map +1 -1
- package/dist/types/src/extensions/annotations.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/blast.d.ts.map +1 -1
- package/dist/types/src/extensions/command/command.d.ts +10 -5
- package/dist/types/src/extensions/command/command.d.ts.map +1 -1
- package/dist/types/src/extensions/command/hint.d.ts +2 -4
- package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
- package/dist/types/src/extensions/command/index.d.ts +0 -1
- package/dist/types/src/extensions/command/index.d.ts.map +1 -1
- package/dist/types/src/extensions/command/menu.d.ts +2 -7
- package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
- package/dist/types/src/extensions/command/preview.d.ts +12 -0
- package/dist/types/src/extensions/command/preview.d.ts.map +1 -0
- package/dist/types/src/extensions/command/state.d.ts +11 -9
- package/dist/types/src/extensions/command/state.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +7 -9
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/debug.d.ts.map +1 -1
- package/dist/types/src/extensions/dnd.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/folding.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +0 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/listener.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/decorate.d.ts +1 -5
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +3 -3
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/index.d.ts +0 -1
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts +1 -4
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/modes.d.ts +5 -5
- package/dist/types/src/extensions/modes.d.ts.map +1 -1
- package/dist/types/src/extensions/selection.d.ts.map +1 -1
- package/dist/types/src/extensions/typewriter.d.ts.map +1 -1
- package/dist/types/src/fragments.d.ts +3 -0
- package/dist/types/src/fragments.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +1 -2
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +0 -5
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/cursor.d.ts.map +1 -1
- package/dist/types/src/util/debug.d.ts.map +1 -1
- package/dist/types/src/util/dom.d.ts.map +1 -1
- package/dist/types/src/util/facet.d.ts.map +1 -1
- package/dist/types/src/util/react.d.ts +1 -6
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -37
- package/src/InputMode.stories.tsx +124 -0
- package/src/TextEditor.stories.tsx +856 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +34 -33
- package/src/components/EditorToolbar/blocks.ts +6 -27
- package/src/components/EditorToolbar/comment.ts +4 -11
- package/src/components/EditorToolbar/formatting.ts +7 -34
- package/src/components/EditorToolbar/headings.ts +8 -9
- package/src/components/EditorToolbar/lists.ts +7 -26
- package/src/components/EditorToolbar/util.ts +17 -17
- package/src/components/EditorToolbar/{view-mode.ts → viewMode.ts} +8 -9
- package/src/defaults.ts +3 -5
- package/src/extensions/automerge/automerge.stories.tsx +17 -11
- package/src/extensions/automerge/automerge.test.tsx +4 -4
- package/src/extensions/automerge/automerge.ts +2 -2
- package/src/extensions/automerge/defs.ts +2 -1
- package/src/extensions/automerge/sync.ts +4 -4
- package/src/extensions/automerge/update-automerge.ts +1 -1
- package/src/extensions/automerge/update-codemirror.ts +4 -3
- package/src/extensions/command/command.ts +27 -9
- package/src/extensions/command/hint.ts +30 -33
- package/src/extensions/command/index.ts +0 -1
- package/src/extensions/command/menu.ts +8 -11
- package/src/extensions/command/preview.ts +79 -0
- package/src/extensions/command/state.ts +61 -41
- package/src/extensions/comments.ts +9 -9
- package/src/extensions/folding.tsx +1 -1
- package/src/extensions/index.ts +0 -1
- package/src/extensions/markdown/changes.ts +2 -3
- package/src/extensions/markdown/decorate.ts +10 -12
- package/src/extensions/markdown/formatting.ts +6 -6
- package/src/extensions/markdown/image.ts +11 -12
- package/src/extensions/markdown/index.ts +0 -1
- package/src/extensions/markdown/link.ts +24 -33
- package/src/extensions/markdown/styles.ts +2 -2
- package/src/extensions/modes.ts +6 -5
- package/src/fragments.ts +19 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useActionHandler.ts +12 -0
- package/src/hooks/useTextEditor.ts +3 -4
- package/src/styles/theme.ts +0 -3
- package/src/types.ts +0 -7
- package/src/util/react.tsx +2 -20
- package/dist/lib/browser/testing/index.mjs +0 -67
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node/testing/index.cjs +0 -101
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -69
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +0 -16
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/search.d.ts +0 -17
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +0 -1
- package/dist/types/src/extensions/command/action.d.ts +0 -17
- package/dist/types/src/extensions/command/action.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/outliner.d.ts +0 -12
- package/dist/types/src/extensions/markdown/outliner.d.ts.map +0 -1
- package/dist/types/src/extensions/preview/index.d.ts +0 -2
- package/dist/types/src/extensions/preview/index.d.ts.map +0 -1
- package/dist/types/src/extensions/preview/preview.d.ts +0 -39
- package/dist/types/src/extensions/preview/preview.d.ts.map +0 -1
- package/dist/types/src/stories/TextEditorBasic.stories.d.ts.map +0 -1
- package/dist/types/src/stories/TextEditorComments.stories.d.ts +0 -13
- package/dist/types/src/stories/TextEditorComments.stories.d.ts.map +0 -1
- package/dist/types/src/stories/TextEditorPreview.stories.d.ts +0 -13
- package/dist/types/src/stories/TextEditorPreview.stories.d.ts.map +0 -1
- package/dist/types/src/stories/TextEditorSpecial.stories.d.ts +0 -19
- package/dist/types/src/stories/TextEditorSpecial.stories.d.ts.map +0 -1
- package/dist/types/src/stories/story-utils.d.ts +0 -53
- package/dist/types/src/stories/story-utils.d.ts.map +0 -1
- package/dist/types/src/testing/RefPopover.d.ts +0 -21
- package/dist/types/src/testing/RefPopover.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/src/components/EditorToolbar/EditorToolbar.stories.tsx +0 -90
- package/src/components/EditorToolbar/image.ts +0 -16
- package/src/components/EditorToolbar/search.ts +0 -19
- package/src/extensions/command/action.ts +0 -49
- package/src/extensions/markdown/outliner.ts +0 -235
- package/src/extensions/preview/index.ts +0 -5
- package/src/extensions/preview/preview.ts +0 -271
- package/src/stories/TextEditorBasic.stories.tsx +0 -333
- package/src/stories/TextEditorComments.stories.tsx +0 -99
- package/src/stories/TextEditorPreview.stories.tsx +0 -239
- package/src/stories/TextEditorSpecial.stories.tsx +0 -107
- package/src/stories/story-utils.tsx +0 -327
- package/src/testing/RefPopover.tsx +0 -74
- package/src/testing/index.ts +0 -5
@@ -2,60 +2,63 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import React, {
|
5
|
+
import React, { useCallback } from 'react';
|
6
6
|
|
7
7
|
import { type NodeArg } from '@dxos/app-graph';
|
8
8
|
import { ElevationProvider } from '@dxos/react-ui';
|
9
|
-
import {
|
9
|
+
import {
|
10
|
+
type MenuActionHandler,
|
11
|
+
MenuProvider,
|
12
|
+
ToolbarMenu,
|
13
|
+
createGapSeparator,
|
14
|
+
useMenuActions,
|
15
|
+
} from '@dxos/react-ui-menu';
|
10
16
|
import { textBlockWidth } from '@dxos/react-ui-theme';
|
11
17
|
|
12
18
|
import { createBlocks } from './blocks';
|
13
19
|
import { createComment } from './comment';
|
14
20
|
import { createFormatting } from './formatting';
|
15
21
|
import { createHeadings } from './headings';
|
16
|
-
import { createImageUpload } from './image';
|
17
22
|
import { createLists } from './lists';
|
18
|
-
import {
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
import {
|
24
|
+
type EditorToolbarActionGraphProps,
|
25
|
+
type EditorToolbarFeatureFlags,
|
26
|
+
type EditorToolbarProps,
|
27
|
+
editorToolbarSearch,
|
28
|
+
} from './util';
|
29
|
+
import { createViewMode } from './viewMode';
|
30
|
+
import { stackItemContentToolbarClassNames } from '../../fragments';
|
22
31
|
|
23
32
|
const createToolbar = ({
|
24
|
-
getView,
|
25
33
|
state,
|
26
34
|
customActions,
|
27
35
|
...features
|
28
|
-
}: EditorToolbarFeatureFlags & Pick<EditorToolbarActionGraphProps, '
|
36
|
+
}: EditorToolbarFeatureFlags & Pick<EditorToolbarActionGraphProps, 'state' | 'customActions'>): {
|
29
37
|
nodes: NodeArg<any>[];
|
30
38
|
edges: { source: string; target: string }[];
|
31
39
|
} => {
|
32
40
|
const nodes = [];
|
33
41
|
const edges = [];
|
34
42
|
if (features.headings ?? true) {
|
35
|
-
const headings = createHeadings(state
|
43
|
+
const headings = createHeadings(state);
|
36
44
|
nodes.push(...headings.nodes);
|
37
45
|
edges.push(...headings.edges);
|
38
46
|
}
|
39
47
|
if (features.formatting ?? true) {
|
40
|
-
const formatting = createFormatting(state
|
48
|
+
const formatting = createFormatting(state);
|
41
49
|
nodes.push(...formatting.nodes);
|
42
50
|
edges.push(...formatting.edges);
|
43
51
|
}
|
44
52
|
if (features.lists ?? true) {
|
45
|
-
const lists = createLists(state
|
53
|
+
const lists = createLists(state);
|
46
54
|
nodes.push(...lists.nodes);
|
47
55
|
edges.push(...lists.edges);
|
48
56
|
}
|
49
57
|
if (features.blocks ?? true) {
|
50
|
-
const blocks = createBlocks(state
|
58
|
+
const blocks = createBlocks(state);
|
51
59
|
nodes.push(...blocks.nodes);
|
52
60
|
edges.push(...blocks.edges);
|
53
61
|
}
|
54
|
-
if (features.image) {
|
55
|
-
const image = createImageUpload(features.image);
|
56
|
-
nodes.push(...image.nodes);
|
57
|
-
edges.push(...image.edges);
|
58
|
-
}
|
59
62
|
if (customActions) {
|
60
63
|
const custom = customActions();
|
61
64
|
nodes.push(...custom.nodes);
|
@@ -64,41 +67,39 @@ const createToolbar = ({
|
|
64
67
|
const editorToolbarGap = createGapSeparator();
|
65
68
|
nodes.push(...editorToolbarGap.nodes);
|
66
69
|
edges.push(...editorToolbarGap.edges);
|
67
|
-
if (features.comment) {
|
68
|
-
const comment = createComment(state
|
70
|
+
if (features.comment ?? true) {
|
71
|
+
const comment = createComment(state);
|
69
72
|
nodes.push(...comment.nodes);
|
70
73
|
edges.push(...comment.edges);
|
71
74
|
}
|
72
75
|
if (features.search ?? true) {
|
73
|
-
|
74
|
-
|
75
|
-
edges.push(...search.edges);
|
76
|
+
nodes.push(editorToolbarSearch);
|
77
|
+
edges.push({ source: 'root', target: editorToolbarSearch.id });
|
76
78
|
}
|
77
|
-
if (features.viewMode) {
|
78
|
-
const viewMode = createViewMode(state
|
79
|
+
if (features.viewMode ?? true) {
|
80
|
+
const viewMode = createViewMode(state);
|
79
81
|
nodes.push(...viewMode.nodes);
|
80
82
|
edges.push(...viewMode.edges);
|
81
83
|
}
|
82
84
|
return { nodes, edges };
|
83
85
|
};
|
84
86
|
|
85
|
-
|
86
|
-
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
87
|
-
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
88
|
-
const useEditorToolbarActionGraph = (props: EditorToolbarProps) => {
|
87
|
+
const useEditorToolbarActionGraph = ({ onAction, ...props }: EditorToolbarProps) => {
|
89
88
|
const menuCreator = useCallback(() => createToolbar(props), [props]);
|
90
|
-
|
89
|
+
const { resolveGroupItems } = useMenuActions(menuCreator);
|
90
|
+
|
91
|
+
return { resolveGroupItems, onAction: onAction as MenuActionHandler };
|
91
92
|
};
|
92
93
|
|
93
|
-
export const EditorToolbar =
|
94
|
+
export const EditorToolbar = ({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
|
94
95
|
const menuProps = useEditorToolbarActionGraph(props);
|
95
96
|
return (
|
96
97
|
<div role='none' className={stackItemContentToolbarClassNames(role)}>
|
97
98
|
<ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
|
98
99
|
<MenuProvider {...menuProps} attendableId={attendableId}>
|
99
|
-
<ToolbarMenu classNames={[textBlockWidth, classNames]} />
|
100
|
+
<ToolbarMenu classNames={[textBlockWidth, '!bg-transparent', classNames]} />
|
100
101
|
</MenuProvider>
|
101
102
|
</ElevationProvider>
|
102
103
|
</div>
|
103
104
|
);
|
104
|
-
}
|
105
|
+
};
|
@@ -2,13 +2,11 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
|
-
|
7
5
|
import { type NodeArg } from '@dxos/app-graph';
|
8
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
9
7
|
|
10
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
11
|
-
import {
|
9
|
+
import { type PayloadType } from '../../extensions';
|
12
10
|
|
13
11
|
const createBlockGroupAction = (value: string) =>
|
14
12
|
createEditorActionGroup('block', {
|
@@ -17,41 +15,22 @@ const createBlockGroupAction = (value: string) =>
|
|
17
15
|
value,
|
18
16
|
} as ToolbarMenuActionGroupProperties);
|
19
17
|
|
20
|
-
const createBlockActions = (value: string,
|
18
|
+
const createBlockActions = (value: string, blankLine?: boolean) =>
|
21
19
|
Object.entries({
|
22
20
|
blockquote: 'ph--quotes--regular',
|
23
21
|
codeblock: 'ph--code-block--regular',
|
24
22
|
table: 'ph--table--regular',
|
25
23
|
}).map(([type, icon]) => {
|
26
|
-
const checked = type === value;
|
27
24
|
return createEditorAction(
|
28
|
-
type,
|
29
|
-
|
30
|
-
const view = getView();
|
31
|
-
if (!view) {
|
32
|
-
return;
|
33
|
-
}
|
34
|
-
|
35
|
-
switch (type) {
|
36
|
-
case 'blockquote':
|
37
|
-
checked ? removeBlockquote(view) : addBlockquote(view);
|
38
|
-
break;
|
39
|
-
case 'codeblock':
|
40
|
-
checked ? removeCodeblock(view) : addCodeblock(view);
|
41
|
-
break;
|
42
|
-
case 'table':
|
43
|
-
insertTable(view);
|
44
|
-
break;
|
45
|
-
}
|
46
|
-
},
|
47
|
-
{ checked, ...(type === 'table' && { disabled: !!blankLine }), icon },
|
25
|
+
{ type: type as PayloadType, checked: type === value, ...(type === 'table' && { disabled: !!blankLine }) },
|
26
|
+
icon,
|
48
27
|
);
|
49
28
|
});
|
50
29
|
|
51
|
-
export const createBlocks = (state: EditorToolbarState
|
30
|
+
export const createBlocks = (state: EditorToolbarState) => {
|
52
31
|
const value = state?.blockQuote ? 'blockquote' : state.blockType ?? '';
|
53
32
|
const blockGroupAction = createBlockGroupAction(value);
|
54
|
-
const blockActions = createBlockActions(value,
|
33
|
+
const blockActions = createBlockActions(value, state.blankLine);
|
55
34
|
return {
|
56
35
|
nodes: [blockGroupAction as NodeArg<any>, ...blockActions],
|
57
36
|
edges: [
|
@@ -2,12 +2,9 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
|
-
|
7
5
|
import { type Label } from '@dxos/react-ui';
|
8
6
|
|
9
7
|
import { createEditorAction, type EditorToolbarState } from './util';
|
10
|
-
import { createComment as nativeCreateComment } from '../../extensions';
|
11
8
|
import { translationKey } from '../../translations';
|
12
9
|
|
13
10
|
const commentLabel = (comment?: boolean, selection?: boolean) =>
|
@@ -17,14 +14,10 @@ const commentLabel = (comment?: boolean, selection?: boolean) =>
|
|
17
14
|
? 'select text to comment label'
|
18
15
|
: 'comment label';
|
19
16
|
|
20
|
-
const createCommentAction = (label: Label
|
21
|
-
createEditorAction('comment',
|
22
|
-
testId: 'editor.toolbar.comment',
|
23
|
-
icon: 'ph--chat-text--regular',
|
24
|
-
label,
|
25
|
-
});
|
17
|
+
const createCommentAction = (label: Label) =>
|
18
|
+
createEditorAction({ type: 'comment', testId: 'editor.toolbar.comment' }, 'ph--chat-text--regular', label);
|
26
19
|
|
27
|
-
export const createComment = (state: EditorToolbarState
|
28
|
-
nodes: [createCommentAction([commentLabel(state.comment, state.selection), { ns: translationKey }]
|
20
|
+
export const createComment = (state: EditorToolbarState) => ({
|
21
|
+
nodes: [createCommentAction([commentLabel(state.comment, state.selection), { ns: translationKey }])],
|
29
22
|
edges: [{ source: 'root', target: 'comment' }],
|
30
23
|
});
|
@@ -2,13 +2,11 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
|
-
|
7
5
|
import { type NodeArg } from '@dxos/app-graph';
|
8
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
9
7
|
|
10
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
11
|
-
import {
|
9
|
+
import { type Formatting, type PayloadType } from '../../extensions';
|
12
10
|
|
13
11
|
const formats = {
|
14
12
|
strong: 'ph--text-b--regular',
|
@@ -25,39 +23,14 @@ const createFormattingGroup = (formatting: Formatting) =>
|
|
25
23
|
value: Object.keys(formats).filter((key) => !!formatting[key as keyof Formatting]),
|
26
24
|
} as ToolbarMenuActionGroupProperties);
|
27
25
|
|
28
|
-
const createFormattingActions = (formatting: Formatting
|
29
|
-
Object.entries(formats).map(([type, icon]) =>
|
30
|
-
|
31
|
-
|
32
|
-
type,
|
33
|
-
() => {
|
34
|
-
const view = getView();
|
35
|
-
if (!view) {
|
36
|
-
return;
|
37
|
-
}
|
38
|
-
|
39
|
-
if (type === 'link') {
|
40
|
-
checked ? removeLink(view) : addLink()(view);
|
41
|
-
return;
|
42
|
-
}
|
43
|
-
|
44
|
-
const inlineType =
|
45
|
-
type === 'strong'
|
46
|
-
? Inline.Strong
|
47
|
-
: type === 'emphasis'
|
48
|
-
? Inline.Emphasis
|
49
|
-
: type === 'strikethrough'
|
50
|
-
? Inline.Strikethrough
|
51
|
-
: Inline.Code;
|
52
|
-
setStyle(inlineType, !checked)(view);
|
53
|
-
},
|
54
|
-
{ checked, icon },
|
55
|
-
);
|
56
|
-
});
|
26
|
+
const createFormattingActions = (formatting: Formatting) =>
|
27
|
+
Object.entries(formats).map(([type, icon]) =>
|
28
|
+
createEditorAction({ type: type as PayloadType, checked: !!formatting[type as keyof Formatting] }, icon),
|
29
|
+
);
|
57
30
|
|
58
|
-
export const createFormatting = (state: EditorToolbarState
|
31
|
+
export const createFormatting = (state: EditorToolbarState) => {
|
59
32
|
const formattingGroupAction = createFormattingGroup(state);
|
60
|
-
const formattingActions = createFormattingActions(state
|
33
|
+
const formattingActions = createFormattingActions(state);
|
61
34
|
return {
|
62
35
|
nodes: [formattingGroupAction as NodeArg<any>, ...formattingActions],
|
63
36
|
edges: [
|
@@ -2,13 +2,10 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
|
-
|
7
5
|
import { type NodeArg } from '@dxos/app-graph';
|
8
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
9
7
|
|
10
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
11
|
-
import { setHeading } from '../../extensions';
|
12
9
|
import { translationKey } from '../../translations';
|
13
10
|
|
14
11
|
const createHeadingGroupAction = (value: string) =>
|
@@ -23,7 +20,7 @@ const createHeadingGroupAction = (value: string) =>
|
|
23
20
|
'ph--text-h--regular',
|
24
21
|
);
|
25
22
|
|
26
|
-
const createHeadingActions = (
|
23
|
+
const createHeadingActions = (value: string) =>
|
27
24
|
Object.entries({
|
28
25
|
'0': 'ph--paragraph--regular',
|
29
26
|
'1': 'ph--text-h-one--regular',
|
@@ -34,10 +31,12 @@ const createHeadingActions = (getView: () => EditorView) =>
|
|
34
31
|
'6': 'ph--text-h-six--regular',
|
35
32
|
}).map(([levelStr, icon]) => {
|
36
33
|
const level = parseInt(levelStr);
|
37
|
-
return createEditorAction(
|
38
|
-
|
34
|
+
return createEditorAction(
|
35
|
+
{ type: 'heading', data: level, checked: value === levelStr },
|
39
36
|
icon,
|
40
|
-
|
37
|
+
['heading level label', { count: level, ns: translationKey }],
|
38
|
+
`heading--${levelStr}`,
|
39
|
+
);
|
41
40
|
});
|
42
41
|
|
43
42
|
const computeHeadingValue = (state: EditorToolbarState) => {
|
@@ -46,10 +45,10 @@ const computeHeadingValue = (state: EditorToolbarState) => {
|
|
46
45
|
return header ? header[1] : blockType === 'paragraph' || !blockType ? '0' : '';
|
47
46
|
};
|
48
47
|
|
49
|
-
export const createHeadings = (state: EditorToolbarState
|
48
|
+
export const createHeadings = (state: EditorToolbarState) => {
|
50
49
|
const headingValue = computeHeadingValue(state);
|
51
50
|
const headingGroupAction = createHeadingGroupAction(headingValue);
|
52
|
-
const headingActions = createHeadingActions(
|
51
|
+
const headingActions = createHeadingActions(headingValue);
|
53
52
|
return {
|
54
53
|
nodes: [headingGroupAction as NodeArg<any>, ...headingActions],
|
55
54
|
edges: [
|
@@ -2,13 +2,11 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
|
-
|
7
5
|
import { type NodeArg } from '@dxos/app-graph';
|
8
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
9
7
|
|
10
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
11
|
-
import {
|
9
|
+
import { type PayloadType } from '../../extensions';
|
12
10
|
|
13
11
|
const listStyles = {
|
14
12
|
bullet: 'ph--list-bullets--regular',
|
@@ -23,32 +21,15 @@ const createListGroupAction = (value: string) =>
|
|
23
21
|
value,
|
24
22
|
} as ToolbarMenuActionGroupProperties);
|
25
23
|
|
26
|
-
const createListActions = (value: string
|
27
|
-
Object.entries(listStyles).map(([listStyle, icon]) =>
|
28
|
-
|
29
|
-
|
30
|
-
`list-${listStyle}`,
|
31
|
-
() => {
|
32
|
-
const view = getView();
|
33
|
-
if (!view) {
|
34
|
-
return;
|
35
|
-
}
|
36
|
-
|
37
|
-
const listType = listStyle === 'ordered' ? List.Ordered : listStyle === 'bullet' ? List.Bullet : List.Task;
|
38
|
-
if (checked) {
|
39
|
-
removeList(listType)(view);
|
40
|
-
} else {
|
41
|
-
addList(listType)(view);
|
42
|
-
}
|
43
|
-
},
|
44
|
-
{ checked, icon },
|
45
|
-
);
|
46
|
-
});
|
24
|
+
const createListActions = (value: string) =>
|
25
|
+
Object.entries(listStyles).map(([listStyle, icon]) =>
|
26
|
+
createEditorAction({ type: `list-${listStyle}` as PayloadType, checked: value === listStyle }, icon),
|
27
|
+
);
|
47
28
|
|
48
|
-
export const createLists = (state: EditorToolbarState
|
29
|
+
export const createLists = (state: EditorToolbarState) => {
|
49
30
|
const value = state.listStyle ?? '';
|
50
31
|
const listGroupAction = createListGroupAction(value);
|
51
|
-
const listActionsMap = createListActions(value
|
32
|
+
const listActionsMap = createListActions(value);
|
52
33
|
return {
|
53
34
|
nodes: [listGroupAction as NodeArg<any>, ...listActionsMap],
|
54
35
|
edges: [
|
@@ -2,30 +2,28 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type EditorView } from '@codemirror/view';
|
6
5
|
import { useMemo } from 'react';
|
7
6
|
|
8
|
-
import { type
|
9
|
-
import {
|
10
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
7
|
+
import { create, type ReactiveObject } from '@dxos/live-object';
|
8
|
+
import { type Label, type ThemedClassName } from '@dxos/react-ui';
|
11
9
|
import {
|
12
10
|
type MenuSeparator,
|
13
11
|
type MenuItemGroup,
|
14
12
|
type ToolbarMenuActionGroupProperties,
|
13
|
+
type MenuActionProperties,
|
15
14
|
createMenuAction,
|
16
15
|
createMenuItemGroup,
|
17
16
|
type ActionGraphProps,
|
18
|
-
type MenuActionProperties,
|
19
17
|
} from '@dxos/react-ui-menu';
|
20
18
|
|
21
|
-
import type { EditorAction, EditorViewMode, Formatting } from '../../extensions';
|
19
|
+
import type { EditorAction, EditorActionPayload, EditorViewMode, Formatting } from '../../extensions';
|
22
20
|
import { translationKey } from '../../translations';
|
23
21
|
|
24
22
|
export type EditorToolbarState = Formatting &
|
25
23
|
Partial<{ comment: boolean; viewMode: EditorViewMode; selection: boolean }>;
|
26
24
|
|
27
25
|
export const useEditorToolbarState = (initialState: Partial<EditorToolbarState> = {}) => {
|
28
|
-
return useMemo(() =>
|
26
|
+
return useMemo(() => create<EditorToolbarState>(initialState), []);
|
29
27
|
};
|
30
28
|
|
31
29
|
export type EditorToolbarFeatureFlags = Partial<{
|
@@ -33,18 +31,16 @@ export type EditorToolbarFeatureFlags = Partial<{
|
|
33
31
|
formatting: boolean;
|
34
32
|
lists: boolean;
|
35
33
|
blocks: boolean;
|
36
|
-
search: boolean;
|
37
|
-
// TODO(wittjosiah): Factor out. Depend on plugin-level capabilities.
|
38
34
|
comment: boolean;
|
39
|
-
|
40
|
-
viewMode:
|
35
|
+
search: boolean;
|
36
|
+
viewMode: boolean;
|
41
37
|
}>;
|
42
38
|
|
43
39
|
export type EditorToolbarActionGraphProps = {
|
44
|
-
state:
|
45
|
-
getView: () => EditorView;
|
40
|
+
state: ReactiveObject<EditorToolbarState>;
|
46
41
|
// TODO(wittjosiah): Control positioning.
|
47
42
|
customActions?: () => ActionGraphProps;
|
43
|
+
onAction: (action: EditorAction) => void;
|
48
44
|
};
|
49
45
|
|
50
46
|
export type EditorToolbarProps = ThemedClassName<
|
@@ -53,13 +49,17 @@ export type EditorToolbarProps = ThemedClassName<
|
|
53
49
|
|
54
50
|
export type EditorToolbarItem = EditorAction | MenuItemGroup | MenuSeparator;
|
55
51
|
|
56
|
-
export const createEditorAction = (
|
57
|
-
|
58
|
-
|
59
|
-
}
|
52
|
+
export const createEditorAction = (
|
53
|
+
payload: EditorActionPayload & Partial<MenuActionProperties>,
|
54
|
+
icon: string,
|
55
|
+
label: Label = [`${payload.type} label`, { ns: translationKey }],
|
56
|
+
id: string = payload.type,
|
57
|
+
) => createMenuAction(id, { icon, label, ...payload }) as EditorAction;
|
60
58
|
|
61
59
|
export const createEditorActionGroup = (
|
62
60
|
id: string,
|
63
61
|
props: Omit<ToolbarMenuActionGroupProperties, 'icon'>,
|
64
62
|
icon?: string,
|
65
63
|
) => createMenuItemGroup(id, { icon, iconOnly: true, ...props });
|
64
|
+
|
65
|
+
export const editorToolbarSearch = createEditorAction({ type: 'search' }, 'ph--magnifying-glass--regular');
|
@@ -6,7 +6,6 @@ import { type NodeArg } from '@dxos/app-graph';
|
|
6
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
7
7
|
|
8
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
9
|
-
import { type EditorViewMode } from '../../extensions';
|
10
9
|
import { translationKey } from '../../translations';
|
11
10
|
|
12
11
|
const createViewModeGroupAction = (value: string) =>
|
@@ -21,24 +20,24 @@ const createViewModeGroupAction = (value: string) =>
|
|
21
20
|
'ph--eye--regular',
|
22
21
|
);
|
23
22
|
|
24
|
-
const createViewModeActions = (value: string
|
23
|
+
const createViewModeActions = (value: string) =>
|
25
24
|
Object.entries({
|
26
25
|
preview: 'ph--eye--regular',
|
27
26
|
source: 'ph--pencil-simple--regular',
|
28
27
|
readonly: 'ph--pencil-slash--regular',
|
29
28
|
}).map(([viewMode, icon]) => {
|
30
|
-
|
31
|
-
|
32
|
-
label: [`${viewMode} mode label`, { ns: translationKey }],
|
33
|
-
checked,
|
29
|
+
return createEditorAction(
|
30
|
+
{ type: 'view-mode', data: viewMode, checked: viewMode === value },
|
34
31
|
icon,
|
35
|
-
|
32
|
+
[`${viewMode} mode label`, { ns: translationKey }],
|
33
|
+
`view-mode--${viewMode}`,
|
34
|
+
);
|
36
35
|
});
|
37
36
|
|
38
|
-
export const createViewMode = (state: EditorToolbarState
|
37
|
+
export const createViewMode = (state: EditorToolbarState) => {
|
39
38
|
const value = state.viewMode ?? 'source';
|
40
39
|
const viewModeGroupAction = createViewModeGroupAction(value);
|
41
|
-
const viewModeActions = createViewModeActions(value
|
40
|
+
const viewModeActions = createViewModeActions(value);
|
42
41
|
return {
|
43
42
|
nodes: [viewModeGroupAction as NodeArg<any>, ...viewModeActions],
|
44
43
|
edges: [
|
package/src/defaults.ts
CHANGED
@@ -17,9 +17,7 @@ const margin = '!mt-[1rem]';
|
|
17
17
|
* NOTE: Max width - 4rem = 2rem left/right margin (or 2rem gutter plus 1rem left/right margin).
|
18
18
|
*/
|
19
19
|
// TOOD(burdon): Adjust depending on
|
20
|
-
export const
|
21
|
-
|
22
|
-
export const editorContent = mx(margin, editorWidth);
|
20
|
+
export const editorContent = mx(margin, '!mli-auto w-full max-w-[min(50rem,100%-4rem)]');
|
23
21
|
|
24
22
|
/**
|
25
23
|
* Margin for numbers.
|
@@ -52,6 +50,6 @@ export const stackItemContentEditorClassNames = (role?: string) =>
|
|
52
50
|
|
53
51
|
export const stackItemContentToolbarClassNames = (role?: string) =>
|
54
52
|
mx(
|
55
|
-
'
|
56
|
-
role === 'section' && 'sticky block-start-0 -mbe-px min-is-0',
|
53
|
+
'attention-surface is-full border-be !border-separator',
|
54
|
+
role === 'section' && 'sticky block-start-0 z-[1] -mbe-px min-is-0',
|
57
55
|
);
|
@@ -5,13 +5,20 @@
|
|
5
5
|
import '@dxos-theme';
|
6
6
|
|
7
7
|
import '@preact/signals-react';
|
8
|
-
|
9
|
-
import { Repo } from '@automerge/automerge-repo';
|
10
|
-
import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-network-broadcastchannel';
|
11
8
|
import React, { useEffect, useState } from 'react';
|
12
9
|
|
10
|
+
import { Repo } from '@dxos/automerge/automerge-repo';
|
11
|
+
import { BroadcastChannelNetworkAdapter } from '@dxos/automerge/automerge-repo-network-broadcastchannel';
|
13
12
|
import { Expando } from '@dxos/echo-schema';
|
14
|
-
import {
|
13
|
+
import {
|
14
|
+
DocAccessor,
|
15
|
+
Filter,
|
16
|
+
create,
|
17
|
+
createDocAccessor,
|
18
|
+
useQuery,
|
19
|
+
useSpace,
|
20
|
+
type Space,
|
21
|
+
} from '@dxos/react-client/echo';
|
15
22
|
import { useIdentity, type Identity } from '@dxos/react-client/halo';
|
16
23
|
import { ClientRepeater, type ClientRepeatedComponentProps } from '@dxos/react-client/testing';
|
17
24
|
import { useThemeContext } from '@dxos/react-ui';
|
@@ -72,12 +79,11 @@ const Story = () => {
|
|
72
79
|
doc.text = initialContent;
|
73
80
|
});
|
74
81
|
|
75
|
-
const object2 =
|
82
|
+
const object2 = repo2.find<TestObject>(object1.url);
|
76
83
|
await object2.whenReady();
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
setObject2({ handle: object2 as any, path: ['text'] });
|
85
|
+
setObject1({ handle: object1, path: ['text'] });
|
86
|
+
setObject2({ handle: object2, path: ['text'] });
|
81
87
|
});
|
82
88
|
}, []);
|
83
89
|
|
@@ -105,7 +111,7 @@ const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
|
|
105
111
|
const identity = useIdentity();
|
106
112
|
const space = useSpace(spaceKey);
|
107
113
|
const [source, setSource] = useState<DocAccessor>();
|
108
|
-
const objects = useQuery(space,
|
114
|
+
const objects = useQuery<Expando>(space, Filter.from({ type: 'test' }));
|
109
115
|
|
110
116
|
useEffect(() => {
|
111
117
|
if (!source && objects.length) {
|
@@ -133,9 +139,9 @@ export const WithEcho = {
|
|
133
139
|
createSpace
|
134
140
|
onSpaceCreated={async ({ space }) => {
|
135
141
|
space.db.add(
|
136
|
-
|
142
|
+
create({
|
137
143
|
type: 'test',
|
138
|
-
content:
|
144
|
+
content: create(Expando, { content: initialContent }),
|
139
145
|
}),
|
140
146
|
);
|
141
147
|
}}
|
@@ -2,7 +2,6 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import { type DocHandle, Repo } from '@automerge/automerge-repo';
|
6
5
|
import { EditorState } from '@codemirror/state';
|
7
6
|
import { EditorView } from '@codemirror/view';
|
8
7
|
import { render, screen } from '@testing-library/react';
|
@@ -13,6 +12,8 @@ import get from 'lodash.get';
|
|
13
12
|
import React, { type FC, useEffect, useRef, useState } from 'react';
|
14
13
|
import { describe, test } from 'vitest';
|
15
14
|
|
15
|
+
import { type DocHandle, Repo } from '@dxos/automerge/automerge-repo';
|
16
|
+
|
16
17
|
import { automerge } from './automerge';
|
17
18
|
|
18
19
|
type TestObject = {
|
@@ -35,8 +36,7 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
35
36
|
const [view, setView] = useState<EditorView>();
|
36
37
|
useEffect(() => {
|
37
38
|
const extensions = [
|
38
|
-
|
39
|
-
automerge({ handle: handle as any, path }),
|
39
|
+
automerge({ handle, path }),
|
40
40
|
EditorView.updateListener.of((update) => {
|
41
41
|
if (view.state.doc.toString() === 'hello!') {
|
42
42
|
// Update editor.
|
@@ -46,7 +46,7 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
46
46
|
];
|
47
47
|
|
48
48
|
const view = new EditorView({
|
49
|
-
state: EditorState.create({ doc: get(handle.
|
49
|
+
state: EditorState.create({ doc: get(handle.docSync()!, path), extensions }),
|
50
50
|
parent: ref.current!,
|
51
51
|
});
|
52
52
|
|
@@ -4,10 +4,10 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
-
import { next as A } from '@automerge/automerge';
|
8
7
|
import { StateField, type Extension } from '@codemirror/state';
|
9
8
|
import { EditorView, ViewPlugin } from '@codemirror/view';
|
10
9
|
|
10
|
+
import { next as A } from '@dxos/automerge/automerge';
|
11
11
|
import { type DocAccessor } from '@dxos/react-client/echo';
|
12
12
|
|
13
13
|
import { cursorConverter } from './cursor';
|
@@ -19,7 +19,7 @@ export const automerge = (accessor: DocAccessor): Extension => {
|
|
19
19
|
const syncState = StateField.define<State>({
|
20
20
|
create: () => ({
|
21
21
|
path: accessor.path.slice(),
|
22
|
-
lastHeads: A.getHeads(accessor.handle.
|
22
|
+
lastHeads: A.getHeads(accessor.handle.docSync()!),
|
23
23
|
unreconciledTransactions: [],
|
24
24
|
}),
|
25
25
|
|