@dxos/react-ui-editor 0.8.4-main.d05673bc65 → 0.8.4-main.dfabb4ec29
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 +754 -731
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +39 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +754 -731
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +41 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/Editor/Editor.d.ts +36 -25
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +4 -4
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
- package/dist/types/src/components/{EditorContent/EditorContent.d.ts → Editor/EditorView.d.ts} +5 -5
- package/dist/types/src/components/Editor/EditorView.d.ts.map +1 -0
- package/dist/types/src/components/Editor/controller.d.ts.map +1 -0
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +1 -3
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts +2 -1
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +2 -2
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -19
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -19
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -19
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +3 -9
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +1 -2
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts +6 -0
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts +3 -9
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/types.d.ts +6 -0
- package/dist/types/src/components/EditorToolbar/types.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +5 -20
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/Assistant.stories.d.ts +10 -0
- package/dist/types/src/extensions/Assistant.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/assistant-extension.d.ts +24 -0
- package/dist/types/src/extensions/assistant-extension.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +2 -0
- package/dist/types/src/extensions/index.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/useBasicMarkdownExtensions.d.ts +25 -0
- package/dist/types/src/hooks/useBasicMarkdownExtensions.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/stories/Automerge.stories.d.ts +24 -24
- package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/EditorToolbar.stories.d.ts +28 -26
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +2 -2
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Outliner.stories.d.ts +2 -2
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Popover.stories.d.ts +2 -2
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Preview.stories.d.ts +1 -1
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Theme.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +2 -2
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +2 -1
- package/dist/types/src/stories/components/util.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +24 -24
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/react.d.ts +1 -1
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +57 -48
- package/src/components/Editor/Editor.stories.tsx +15 -21
- package/src/components/Editor/Editor.tsx +54 -53
- package/src/components/Editor/EditorView.tsx +102 -0
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +3 -5
- package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
- package/src/components/EditorMenuProvider/popover.ts +3 -1
- package/src/components/EditorMenuProvider/useEditorMenu.ts +2 -1
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -1
- package/src/components/EditorToolbar/EditorToolbar.tsx +29 -48
- package/src/components/EditorToolbar/blocks.ts +54 -46
- package/src/components/EditorToolbar/formatting.ts +44 -45
- package/src/components/EditorToolbar/headings.ts +44 -50
- package/src/components/EditorToolbar/image.ts +16 -21
- package/src/components/EditorToolbar/index.ts +2 -3
- package/src/components/EditorToolbar/lists.ts +58 -0
- package/src/components/EditorToolbar/search.ts +16 -21
- package/src/components/EditorToolbar/types.ts +8 -0
- package/src/components/EditorToolbar/view-mode.ts +37 -43
- package/src/components/index.ts +0 -3
- package/src/extensions/Assistant.stories.tsx +112 -0
- package/src/extensions/assistant-extension.tsx +223 -0
- package/src/extensions/index.ts +5 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useBasicMarkdownExtensions.ts +55 -0
- package/src/index.ts +1 -4
- package/src/stories/Automerge.stories.tsx +4 -3
- package/src/stories/Comments.stories.tsx +2 -2
- package/src/stories/EditorToolbar.stories.tsx +36 -64
- package/src/stories/Experimental.stories.tsx +10 -10
- package/src/stories/Outliner.stories.tsx +3 -4
- package/src/stories/Popover.stories.tsx +6 -7
- package/src/stories/Preview.stories.tsx +6 -7
- package/src/stories/Theme.stories.tsx +2 -2
- package/src/stories/components/EditorStory.tsx +17 -8
- package/src/stories/components/util.tsx +37 -35
- package/src/translations.ts +29 -24
- package/src/util/react.tsx +1 -1
- package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +0 -1
- package/dist/types/src/components/EditorContent/controller.d.ts.map +0 -1
- package/dist/types/src/components/EditorContent/index.d.ts +0 -3
- package/dist/types/src/components/EditorContent/index.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/actions.d.ts +0 -25
- package/dist/types/src/components/EditorToolbar/actions.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts +0 -11
- package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts.map +0 -1
- package/dist/types/src/stories/CommandDialog.stories.d.ts +0 -14
- package/dist/types/src/stories/CommandDialog.stories.d.ts.map +0 -1
- package/src/components/EditorContent/EditorContent.tsx +0 -83
- package/src/components/EditorContent/index.ts +0 -6
- package/src/components/EditorToolbar/actions.ts +0 -87
- package/src/components/EditorToolbar/useEditorToolbar.ts +0 -20
- package/src/stories/CommandDialog.stories.tsx +0 -81
- /package/dist/types/src/components/{EditorContent → Editor}/controller.d.ts +0 -0
- /package/src/components/{EditorContent → Editor}/controller.ts +0 -0
|
@@ -9,16 +9,18 @@ import React, { memo, useMemo } from 'react';
|
|
|
9
9
|
import { type Node } from '@dxos/app-graph';
|
|
10
10
|
import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
|
|
11
11
|
import { type ActionGraphProps, Menu, type MenuAction, MenuBuilder, useMenuActions } from '@dxos/react-ui-menu';
|
|
12
|
-
import { type EditorViewMode } from '@dxos/ui-editor';
|
|
12
|
+
import { type EditorViewMode } from '@dxos/ui-editor/types';
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { type EditorToolbarState } from './
|
|
21
|
-
import {
|
|
14
|
+
import { addBlocks } from './blocks';
|
|
15
|
+
import { addFormatting } from './formatting';
|
|
16
|
+
import { addHeadings } from './headings';
|
|
17
|
+
import { addImageUpload } from './image';
|
|
18
|
+
import { addLists } from './lists';
|
|
19
|
+
import { addSearch } from './search';
|
|
20
|
+
import { type EditorToolbarState } from './types';
|
|
21
|
+
import { addViewMode } from './view-mode';
|
|
22
|
+
|
|
23
|
+
// TODO(burdon): Enable toolbar variants (e.g., markdown, code).
|
|
22
24
|
|
|
23
25
|
export type EditorToolbarFeatureFlags = Partial<{
|
|
24
26
|
showHeadings: boolean;
|
|
@@ -49,12 +51,12 @@ export type EditorToolbarProps = ThemedClassName<
|
|
|
49
51
|
>;
|
|
50
52
|
|
|
51
53
|
export const EditorToolbar = memo(({ classNames, role, attendableId, onAction, ...props }: EditorToolbarProps) => {
|
|
52
|
-
const
|
|
54
|
+
const menuActions = useMarkdownMenuActions(props);
|
|
53
55
|
|
|
54
56
|
return (
|
|
55
57
|
<ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
|
|
56
|
-
<Menu.Root {...
|
|
57
|
-
<Menu.Toolbar classNames={classNames}
|
|
58
|
+
<Menu.Root {...menuActions} attendableId={attendableId} onAction={onAction}>
|
|
59
|
+
<Menu.Toolbar classNames={classNames} />
|
|
58
60
|
</Menu.Root>
|
|
59
61
|
</ElevationProvider>
|
|
60
62
|
);
|
|
@@ -63,13 +65,13 @@ export const EditorToolbar = memo(({ classNames, role, attendableId, onAction, .
|
|
|
63
65
|
type ToolbarActionsProps = Pick<EditorToolbarActionGraphProps, 'state' | 'getView' | 'customActions'> &
|
|
64
66
|
EditorToolbarFeatureFlags;
|
|
65
67
|
|
|
68
|
+
// TODO(burdon): Some actions should toggle the state (e.g., toggle bullets on/off depending on the current state).
|
|
66
69
|
// TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
|
|
67
70
|
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
|
68
71
|
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
|
69
|
-
|
|
70
|
-
const useEditorToolbarActionGraph = ({ state, getView, customActions, ...features }: ToolbarActionsProps) => {
|
|
72
|
+
const useMarkdownMenuActions = ({ state, getView, customActions, ...features }: ToolbarActionsProps) => {
|
|
71
73
|
const menuCreator = useMemo(
|
|
72
|
-
() =>
|
|
74
|
+
() => createMarkdownActions({ state, getView, customActions, ...features }),
|
|
73
75
|
[
|
|
74
76
|
state,
|
|
75
77
|
getView,
|
|
@@ -87,7 +89,7 @@ const useEditorToolbarActionGraph = ({ state, getView, customActions, ...feature
|
|
|
87
89
|
return useMenuActions(menuCreator);
|
|
88
90
|
};
|
|
89
91
|
|
|
90
|
-
const
|
|
92
|
+
const createMarkdownActions = ({
|
|
91
93
|
state,
|
|
92
94
|
getView,
|
|
93
95
|
customActions,
|
|
@@ -96,37 +98,16 @@ const createToolbarActions = ({
|
|
|
96
98
|
return Atom.make((get) => {
|
|
97
99
|
// Subscribe to state changes.
|
|
98
100
|
const stateSnapshot = get(state);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
if (features?.showBlocks ?? true) {
|
|
112
|
-
builder.subgraph(createBlocks(stateSnapshot, getView));
|
|
113
|
-
}
|
|
114
|
-
if (features?.onImageUpload) {
|
|
115
|
-
builder.subgraph(createImageUpload(features.onImageUpload!));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
builder.separator('gap');
|
|
119
|
-
|
|
120
|
-
if (customActions) {
|
|
121
|
-
builder.subgraph(get(customActions));
|
|
122
|
-
}
|
|
123
|
-
if (features?.showSearch ?? true) {
|
|
124
|
-
builder.subgraph(createSearch(getView));
|
|
125
|
-
}
|
|
126
|
-
if (features?.onViewModeChange) {
|
|
127
|
-
builder.subgraph(createViewMode(stateSnapshot, features.onViewModeChange!));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return builder.build();
|
|
101
|
+
return MenuBuilder.make()
|
|
102
|
+
.subgraph(features?.showHeadings !== false && addHeadings(stateSnapshot, getView))
|
|
103
|
+
.subgraph(features?.showFormatting !== false && addFormatting(stateSnapshot, getView))
|
|
104
|
+
.subgraph(features?.showLists !== false && addLists(stateSnapshot, getView))
|
|
105
|
+
.subgraph(features?.showBlocks !== false && addBlocks(stateSnapshot, getView))
|
|
106
|
+
.subgraph(features?.onImageUpload && addImageUpload(features.onImageUpload))
|
|
107
|
+
.separator('gap')
|
|
108
|
+
.subgraph(customActions && get(customActions))
|
|
109
|
+
.subgraph(features?.showSearch !== false && addSearch(getView))
|
|
110
|
+
.subgraph(features?.onViewModeChange && addViewMode(stateSnapshot, features.onViewModeChange))
|
|
111
|
+
.build();
|
|
131
112
|
});
|
|
132
113
|
};
|
|
@@ -4,56 +4,64 @@
|
|
|
4
4
|
|
|
5
5
|
import { type EditorView } from '@codemirror/view';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
8
|
-
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
7
|
+
import { type ActionGroupBuilderFn, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
9
8
|
import { addBlockquote, addCodeblock, insertTable, removeBlockquote, removeCodeblock } from '@dxos/ui-editor';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
import { type EditorToolbarState } from './useEditorToolbar';
|
|
10
|
+
import { translationKey } from '#translations';
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
createEditorActionGroup('block', {
|
|
16
|
-
variant: 'toggleGroup',
|
|
17
|
-
selectCardinality: 'single',
|
|
18
|
-
value,
|
|
19
|
-
} as ToolbarMenuActionGroupProperties);
|
|
12
|
+
import { type EditorToolbarState } from './types';
|
|
20
13
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}).map(([type, icon]) => {
|
|
27
|
-
const checked = type === value;
|
|
28
|
-
return createEditorAction(type, { checked, ...(type === 'table' && { disabled: !!blankLine }), icon }, () => {
|
|
29
|
-
const view = getView();
|
|
30
|
-
if (!view) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
14
|
+
const blockTypes = {
|
|
15
|
+
blockquote: 'ph--quotes--regular',
|
|
16
|
+
codeblock: 'ph--code-block--regular',
|
|
17
|
+
table: 'ph--table--regular',
|
|
18
|
+
};
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
20
|
+
/** Add block actions to the builder. */
|
|
21
|
+
export const addBlocks =
|
|
22
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
23
|
+
(builder) => {
|
|
24
|
+
const value = state?.blockQuote ? 'blockquote' : (state.blockType ?? '');
|
|
25
|
+
builder.group(
|
|
26
|
+
'block',
|
|
27
|
+
{
|
|
28
|
+
label: ['block.label', { ns: translationKey }],
|
|
29
|
+
iconOnly: true,
|
|
30
|
+
variant: 'toggleGroup',
|
|
31
|
+
selectCardinality: 'single',
|
|
32
|
+
value,
|
|
33
|
+
} as ToolbarMenuActionGroupProperties,
|
|
34
|
+
(group) => {
|
|
35
|
+
for (const [type, icon] of Object.entries(blockTypes)) {
|
|
36
|
+
const checked = type === value;
|
|
37
|
+
group.action(
|
|
38
|
+
type,
|
|
39
|
+
{
|
|
40
|
+
label: [`block.${type}.label`, { ns: translationKey }],
|
|
41
|
+
checked,
|
|
42
|
+
...(type === 'table' && { disabled: !!state.blankLine }),
|
|
43
|
+
icon,
|
|
44
|
+
},
|
|
45
|
+
() => {
|
|
46
|
+
const view = getView();
|
|
47
|
+
if (!view) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
switch (type) {
|
|
52
|
+
case 'blockquote':
|
|
53
|
+
checked ? removeBlockquote(view) : addBlockquote(view);
|
|
54
|
+
break;
|
|
55
|
+
case 'codeblock':
|
|
56
|
+
checked ? removeCodeblock(view) : addCodeblock(view);
|
|
57
|
+
break;
|
|
58
|
+
case 'table':
|
|
59
|
+
insertTable(view);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
);
|
|
58
67
|
};
|
|
59
|
-
};
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { type EditorView } from '@codemirror/view';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
8
|
-
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
7
|
+
import { type ActionGroupBuilderFn, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
9
8
|
import { type Formatting, Inline, addLink, removeLink, setStyle } from '@dxos/ui-editor';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
10
|
+
import { translationKey } from '#translations';
|
|
11
|
+
|
|
12
|
+
import { type EditorToolbarState } from './types';
|
|
13
13
|
|
|
14
14
|
const formats = {
|
|
15
15
|
strong: 'ph--text-b--regular',
|
|
@@ -19,47 +19,46 @@ const formats = {
|
|
|
19
19
|
link: 'ph--link--regular',
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
/** Add formatting actions to the builder. */
|
|
23
|
+
export const addFormatting =
|
|
24
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
25
|
+
(builder) => {
|
|
26
|
+
const formatting: Formatting = state;
|
|
27
|
+
builder.group(
|
|
28
|
+
'formatting',
|
|
29
|
+
{
|
|
30
|
+
label: ['formatting.label', { ns: translationKey }],
|
|
31
|
+
iconOnly: true,
|
|
32
|
+
variant: 'toggleGroup',
|
|
33
|
+
selectCardinality: 'multiple',
|
|
34
|
+
value: Object.keys(formats).filter((key) => !!formatting[key as keyof Formatting]),
|
|
35
|
+
} as ToolbarMenuActionGroupProperties,
|
|
36
|
+
(group) => {
|
|
37
|
+
for (const [type, icon] of Object.entries(formats)) {
|
|
38
|
+
const checked = !!formatting[type as keyof Formatting];
|
|
39
|
+
group.action(type, { label: [`formatting.${type}.label`, { ns: translationKey }], checked, icon }, () => {
|
|
40
|
+
const view = getView();
|
|
41
|
+
if (!view) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
if (type === 'link') {
|
|
46
|
+
checked ? removeLink(view) : addLink()(view);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const formattingActions = createFormattingActions(state, getView);
|
|
58
|
-
return {
|
|
59
|
-
nodes: [formattingGroupAction as Node.NodeArg<any>, ...formattingActions],
|
|
60
|
-
edges: [
|
|
61
|
-
{ source: 'root', target: 'formatting', relation: 'child' },
|
|
62
|
-
...formattingActions.map(({ id }) => ({ source: formattingGroupAction.id, target: id, relation: 'child' })),
|
|
63
|
-
],
|
|
50
|
+
setStyle(
|
|
51
|
+
type === 'strong'
|
|
52
|
+
? Inline.Strong
|
|
53
|
+
: type === 'emphasis'
|
|
54
|
+
? Inline.Emphasis
|
|
55
|
+
: type === 'strikethrough'
|
|
56
|
+
? Inline.Strikethrough
|
|
57
|
+
: Inline.Code,
|
|
58
|
+
!checked,
|
|
59
|
+
)(view);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
64
|
};
|
|
65
|
-
};
|
|
@@ -4,49 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
import { type EditorView } from '@codemirror/view';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
8
|
-
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
7
|
+
import { type ActionGroupBuilderFn, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
9
8
|
import { setHeading } from '@dxos/ui-editor';
|
|
10
9
|
|
|
11
|
-
import { translationKey } from '
|
|
10
|
+
import { translationKey } from '#translations';
|
|
12
11
|
|
|
13
|
-
import {
|
|
14
|
-
import { type EditorToolbarState } from './useEditorToolbar';
|
|
12
|
+
import { type EditorToolbarState } from './types';
|
|
15
13
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} as ToolbarMenuActionGroupProperties,
|
|
26
|
-
'ph--text-h--regular',
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const createHeadingActions = (currentLevel: string, getView: () => EditorView) =>
|
|
30
|
-
Object.entries({
|
|
31
|
-
0: 'ph--paragraph--regular',
|
|
32
|
-
1: 'ph--text-h-one--regular',
|
|
33
|
-
2: 'ph--text-h-two--regular',
|
|
34
|
-
3: 'ph--text-h-three--regular',
|
|
35
|
-
4: 'ph--text-h-four--regular',
|
|
36
|
-
5: 'ph--text-h-five--regular',
|
|
37
|
-
6: 'ph--text-h-six--regular',
|
|
38
|
-
}).map(([levelStr, icon]) => {
|
|
39
|
-
const level = parseInt(levelStr);
|
|
40
|
-
return createEditorAction(
|
|
41
|
-
`heading--${levelStr}`,
|
|
42
|
-
{
|
|
43
|
-
label: ['heading level label', { count: level, ns: translationKey }],
|
|
44
|
-
icon,
|
|
45
|
-
checked: levelStr === currentLevel,
|
|
46
|
-
},
|
|
47
|
-
() => setHeading(level)(getView()),
|
|
48
|
-
);
|
|
49
|
-
});
|
|
14
|
+
const headingIcons: Record<string, string> = {
|
|
15
|
+
0: 'ph--paragraph--regular',
|
|
16
|
+
1: 'ph--text-h-one--regular',
|
|
17
|
+
2: 'ph--text-h-two--regular',
|
|
18
|
+
3: 'ph--text-h-three--regular',
|
|
19
|
+
4: 'ph--text-h-four--regular',
|
|
20
|
+
5: 'ph--text-h-five--regular',
|
|
21
|
+
6: 'ph--text-h-six--regular',
|
|
22
|
+
};
|
|
50
23
|
|
|
51
24
|
const computeHeadingValue = (state: EditorToolbarState) => {
|
|
52
25
|
const blockType = state ? state.blockType : 'paragraph';
|
|
@@ -54,15 +27,36 @@ const computeHeadingValue = (state: EditorToolbarState) => {
|
|
|
54
27
|
return heading ? heading[1] : blockType === 'paragraph' || !blockType ? '0' : '';
|
|
55
28
|
};
|
|
56
29
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
30
|
+
/** Add heading actions to the builder. */
|
|
31
|
+
export const addHeadings =
|
|
32
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
33
|
+
(builder) => {
|
|
34
|
+
const headingValue = computeHeadingValue(state);
|
|
35
|
+
builder.group(
|
|
36
|
+
'heading',
|
|
37
|
+
{
|
|
38
|
+
label: ['heading.label', { ns: translationKey }],
|
|
39
|
+
icon: 'ph--text-h--regular',
|
|
40
|
+
iconOnly: true,
|
|
41
|
+
variant: 'dropdownMenu',
|
|
42
|
+
applyActive: true,
|
|
43
|
+
selectCardinality: 'single',
|
|
44
|
+
// TODO(wittjosiah): Remove? Not sure this does anything.
|
|
45
|
+
value: headingValue,
|
|
46
|
+
} as ToolbarMenuActionGroupProperties,
|
|
47
|
+
(group) => {
|
|
48
|
+
for (const [levelStr, icon] of Object.entries(headingIcons)) {
|
|
49
|
+
const level = parseInt(levelStr);
|
|
50
|
+
group.action(
|
|
51
|
+
`heading--${levelStr}`,
|
|
52
|
+
{
|
|
53
|
+
label: ['heading-level.label', { count: level, ns: translationKey }],
|
|
54
|
+
icon,
|
|
55
|
+
checked: levelStr === headingValue,
|
|
56
|
+
},
|
|
57
|
+
() => setHeading(level)(getView()),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
);
|
|
67
62
|
};
|
|
68
|
-
};
|
|
@@ -2,26 +2,21 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type ActionGroupBuilderFn } from '@dxos/react-ui-menu';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { translationKey } from '#translations';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
edges: Array<{ source: string; target: string; relation: 'child' }>;
|
|
24
|
-
} => ({
|
|
25
|
-
nodes: [createImageUploadAction(onImageUpload)],
|
|
26
|
-
edges: [{ source: 'root', target: 'image', relation: 'child' }],
|
|
27
|
-
});
|
|
9
|
+
/** Add image upload action to the builder. */
|
|
10
|
+
export const addImageUpload =
|
|
11
|
+
(onImageUpload: () => void): ActionGroupBuilderFn =>
|
|
12
|
+
(builder) => {
|
|
13
|
+
builder.action(
|
|
14
|
+
'image',
|
|
15
|
+
{
|
|
16
|
+
label: ['image.label', { ns: translationKey }],
|
|
17
|
+
testId: 'editor.toolbar.image',
|
|
18
|
+
icon: 'ph--image-square--regular',
|
|
19
|
+
},
|
|
20
|
+
onImageUpload,
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './types';
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
export { type EditorToolbarState, useEditorToolbar } from './useEditorToolbar';
|
|
7
|
+
export * from './EditorToolbar';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
|
6
|
+
|
|
7
|
+
import { type ActionGroupBuilderFn, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
8
|
+
import { List, addList, removeList } from '@dxos/ui-editor';
|
|
9
|
+
|
|
10
|
+
import { translationKey } from '#translations';
|
|
11
|
+
|
|
12
|
+
import { type EditorToolbarState } from './types';
|
|
13
|
+
|
|
14
|
+
const listStyles = {
|
|
15
|
+
bullet: 'ph--list-bullets--regular',
|
|
16
|
+
ordered: 'ph--list-numbers--regular',
|
|
17
|
+
task: 'ph--list-checks--regular',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Add list actions to the builder. */
|
|
21
|
+
export const addLists =
|
|
22
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
23
|
+
(builder) => {
|
|
24
|
+
const value = state.listStyle ?? '';
|
|
25
|
+
builder.group(
|
|
26
|
+
'list',
|
|
27
|
+
{
|
|
28
|
+
label: ['list.label', { ns: translationKey }],
|
|
29
|
+
iconOnly: true,
|
|
30
|
+
variant: 'toggleGroup',
|
|
31
|
+
selectCardinality: 'single',
|
|
32
|
+
value,
|
|
33
|
+
} as ToolbarMenuActionGroupProperties,
|
|
34
|
+
(group) => {
|
|
35
|
+
for (const [listStyle, icon] of Object.entries(listStyles)) {
|
|
36
|
+
const checked = value === listStyle;
|
|
37
|
+
group.action(
|
|
38
|
+
`list-${listStyle}`,
|
|
39
|
+
{ label: [`list.${listStyle}.label`, { ns: translationKey }], checked, icon },
|
|
40
|
+
() => {
|
|
41
|
+
const view = getView();
|
|
42
|
+
if (!view) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const listType =
|
|
47
|
+
listStyle === 'ordered' ? List.Ordered : listStyle === 'bullet' ? List.Bullet : List.Task;
|
|
48
|
+
if (checked) {
|
|
49
|
+
removeList(listType)(view);
|
|
50
|
+
} else {
|
|
51
|
+
addList(listType)(view);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -5,26 +5,21 @@
|
|
|
5
5
|
import { openSearchPanel } from '@codemirror/search';
|
|
6
6
|
import { type EditorView } from '@codemirror/view';
|
|
7
7
|
|
|
8
|
-
import { type
|
|
8
|
+
import { type ActionGroupBuilderFn } from '@dxos/react-ui-menu';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { translationKey } from '#translations';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
edges: Array<{ source: string; target: string; relation: 'child' }>;
|
|
27
|
-
} => ({
|
|
28
|
-
nodes: [createSearchAction(getView)],
|
|
29
|
-
edges: [{ source: 'root', target: 'search', relation: 'child' }],
|
|
30
|
-
});
|
|
12
|
+
/** Add search action to the builder. */
|
|
13
|
+
export const addSearch =
|
|
14
|
+
(getView: () => EditorView): ActionGroupBuilderFn =>
|
|
15
|
+
(builder) => {
|
|
16
|
+
builder.action(
|
|
17
|
+
'search',
|
|
18
|
+
{
|
|
19
|
+
label: ['search.label', { ns: translationKey }],
|
|
20
|
+
testId: 'editor.toolbar.search',
|
|
21
|
+
icon: 'ph--magnifying-glass--regular',
|
|
22
|
+
},
|
|
23
|
+
() => openSearchPanel(getView()),
|
|
24
|
+
);
|
|
25
|
+
};
|