@dxos/react-ui-editor 0.8.4-main.937b3ca → 0.8.4-main.9be5663bfe
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 +310 -388
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +310 -388
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts +9 -15
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
- package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +1 -1
- 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/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.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +3 -8
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +0 -1
- 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 -8
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/stories/Automerge.stories.d.ts +25 -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 +26 -26
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +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/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +3 -3
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +3 -3
- 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 -4
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +45 -45
- package/src/components/Editor/Editor.stories.tsx +6 -7
- package/src/components/Editor/Editor.tsx +21 -27
- package/src/components/EditorContent/EditorContent.tsx +1 -2
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +21 -28
- package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
- package/src/components/EditorMenuProvider/useEditorMenu.ts +8 -1
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +5 -7
- package/src/components/EditorToolbar/EditorToolbar.tsx +24 -61
- package/src/components/EditorToolbar/blocks.ts +53 -46
- package/src/components/EditorToolbar/formatting.ts +44 -46
- package/src/components/EditorToolbar/headings.ts +42 -49
- package/src/components/EditorToolbar/image.ts +16 -21
- package/src/components/EditorToolbar/index.ts +0 -1
- package/src/components/EditorToolbar/lists.ts +57 -0
- package/src/components/EditorToolbar/search.ts +16 -21
- package/src/components/EditorToolbar/view-mode.ts +34 -41
- package/src/stories/Automerge.stories.tsx +10 -12
- package/src/stories/Comments.stories.tsx +4 -5
- package/src/stories/EditorToolbar.stories.tsx +32 -17
- package/src/stories/Experimental.stories.tsx +6 -6
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +4 -5
- package/src/stories/Popover.stories.tsx +9 -10
- package/src/stories/Preview.stories.tsx +60 -51
- package/src/stories/Tags.stories.tsx +5 -5
- package/src/stories/TextEditor.stories.tsx +2 -2
- package/src/stories/Theme.stories.tsx +2 -2
- package/src/stories/components/EditorStory.tsx +17 -12
- package/src/stories/components/util.tsx +49 -50
- package/src/translations.ts +29 -24
- package/src/util/react.tsx +2 -11
- package/dist/types/src/components/EditorToolbar/actions.d.ts +0 -24
- package/dist/types/src/components/EditorToolbar/actions.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/EditorToolbar/actions.ts +0 -87
- package/src/stories/CommandDialog.stories.tsx +0 -81
|
@@ -4,56 +4,63 @@
|
|
|
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 {
|
|
10
|
+
import { translationKey } from '../../translations';
|
|
12
11
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
13
12
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} as ToolbarMenuActionGroupProperties);
|
|
20
|
-
|
|
21
|
-
const createBlockActions = (value: string, getView: () => EditorView, blankLine?: boolean) =>
|
|
22
|
-
Object.entries({
|
|
23
|
-
blockquote: 'ph--quotes--regular',
|
|
24
|
-
codeblock: 'ph--code-block--regular',
|
|
25
|
-
table: 'ph--table--regular',
|
|
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
|
-
}
|
|
13
|
+
const blockTypes = {
|
|
14
|
+
blockquote: 'ph--quotes--regular',
|
|
15
|
+
codeblock: 'ph--code-block--regular',
|
|
16
|
+
table: 'ph--table--regular',
|
|
17
|
+
};
|
|
33
18
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
19
|
+
/** Add block actions to the builder. */
|
|
20
|
+
export const addBlocks =
|
|
21
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
22
|
+
(builder) => {
|
|
23
|
+
const value = state?.blockQuote ? 'blockquote' : (state.blockType ?? '');
|
|
24
|
+
builder.group(
|
|
25
|
+
'block',
|
|
26
|
+
{
|
|
27
|
+
label: ['block.label', { ns: translationKey }],
|
|
28
|
+
iconOnly: true,
|
|
29
|
+
variant: 'toggleGroup',
|
|
30
|
+
selectCardinality: 'single',
|
|
31
|
+
value,
|
|
32
|
+
} as ToolbarMenuActionGroupProperties,
|
|
33
|
+
(group) => {
|
|
34
|
+
for (const [type, icon] of Object.entries(blockTypes)) {
|
|
35
|
+
const checked = type === value;
|
|
36
|
+
group.action(
|
|
37
|
+
type,
|
|
38
|
+
{
|
|
39
|
+
label: [`block.${type}.label`, { ns: translationKey }],
|
|
40
|
+
checked,
|
|
41
|
+
...(type === 'table' && { disabled: !!state.blankLine }),
|
|
42
|
+
icon,
|
|
43
|
+
},
|
|
44
|
+
() => {
|
|
45
|
+
const view = getView();
|
|
46
|
+
if (!view) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
switch (type) {
|
|
51
|
+
case 'blockquote':
|
|
52
|
+
checked ? removeBlockquote(view) : addBlockquote(view);
|
|
53
|
+
break;
|
|
54
|
+
case 'codeblock':
|
|
55
|
+
checked ? removeCodeblock(view) : addCodeblock(view);
|
|
56
|
+
break;
|
|
57
|
+
case 'table':
|
|
58
|
+
insertTable(view);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
);
|
|
58
66
|
};
|
|
59
|
-
};
|
|
@@ -4,11 +4,10 @@
|
|
|
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 {
|
|
10
|
+
import { translationKey } from '../../translations';
|
|
12
11
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
13
12
|
|
|
14
13
|
const formats = {
|
|
@@ -19,47 +18,46 @@ const formats = {
|
|
|
19
18
|
link: 'ph--link--regular',
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
/** Add formatting actions to the builder. */
|
|
22
|
+
export const addFormatting =
|
|
23
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
24
|
+
(builder) => {
|
|
25
|
+
const formatting: Formatting = state;
|
|
26
|
+
builder.group(
|
|
27
|
+
'formatting',
|
|
28
|
+
{
|
|
29
|
+
label: ['formatting.label', { ns: translationKey }],
|
|
30
|
+
iconOnly: true,
|
|
31
|
+
variant: 'toggleGroup',
|
|
32
|
+
selectCardinality: 'multiple',
|
|
33
|
+
value: Object.keys(formats).filter((key) => !!formatting[key as keyof Formatting]),
|
|
34
|
+
} as ToolbarMenuActionGroupProperties,
|
|
35
|
+
(group) => {
|
|
36
|
+
for (const [type, icon] of Object.entries(formats)) {
|
|
37
|
+
const checked = !!formatting[type as keyof Formatting];
|
|
38
|
+
group.action(type, { label: [`formatting.${type}.label`, { ns: translationKey }], checked, icon }, () => {
|
|
39
|
+
const view = getView();
|
|
40
|
+
if (!view) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (type === 'link') {
|
|
45
|
+
checked ? removeLink(view) : addLink()(view);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setStyle(
|
|
50
|
+
type === 'strong'
|
|
51
|
+
? Inline.Strong
|
|
52
|
+
: type === 'emphasis'
|
|
53
|
+
? Inline.Emphasis
|
|
54
|
+
: type === 'strikethrough'
|
|
55
|
+
? Inline.Strikethrough
|
|
56
|
+
: Inline.Code,
|
|
57
|
+
!checked,
|
|
58
|
+
)(view);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
);
|
|
64
63
|
};
|
|
65
|
-
};
|
|
@@ -4,49 +4,21 @@
|
|
|
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
10
|
import { translationKey } from '../../translations';
|
|
12
|
-
|
|
13
|
-
import { createEditorAction, createEditorActionGroup } from './actions';
|
|
14
11
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
15
12
|
|
|
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
|
-
});
|
|
13
|
+
const headingIcons: Record<string, string> = {
|
|
14
|
+
0: 'ph--paragraph--regular',
|
|
15
|
+
1: 'ph--text-h-one--regular',
|
|
16
|
+
2: 'ph--text-h-two--regular',
|
|
17
|
+
3: 'ph--text-h-three--regular',
|
|
18
|
+
4: 'ph--text-h-four--regular',
|
|
19
|
+
5: 'ph--text-h-five--regular',
|
|
20
|
+
6: 'ph--text-h-six--regular',
|
|
21
|
+
};
|
|
50
22
|
|
|
51
23
|
const computeHeadingValue = (state: EditorToolbarState) => {
|
|
52
24
|
const blockType = state ? state.blockType : 'paragraph';
|
|
@@ -54,15 +26,36 @@ const computeHeadingValue = (state: EditorToolbarState) => {
|
|
|
54
26
|
return heading ? heading[1] : blockType === 'paragraph' || !blockType ? '0' : '';
|
|
55
27
|
};
|
|
56
28
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
29
|
+
/** Add heading actions to the builder. */
|
|
30
|
+
export const addHeadings =
|
|
31
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
32
|
+
(builder) => {
|
|
33
|
+
const headingValue = computeHeadingValue(state);
|
|
34
|
+
builder.group(
|
|
35
|
+
'heading',
|
|
36
|
+
{
|
|
37
|
+
label: ['heading.label', { ns: translationKey }],
|
|
38
|
+
icon: 'ph--text-h--regular',
|
|
39
|
+
iconOnly: true,
|
|
40
|
+
variant: 'dropdownMenu',
|
|
41
|
+
applyActive: true,
|
|
42
|
+
selectCardinality: 'single',
|
|
43
|
+
// TODO(wittjosiah): Remove? Not sure this does anything.
|
|
44
|
+
value: headingValue,
|
|
45
|
+
} as ToolbarMenuActionGroupProperties,
|
|
46
|
+
(group) => {
|
|
47
|
+
for (const [levelStr, icon] of Object.entries(headingIcons)) {
|
|
48
|
+
const level = parseInt(levelStr);
|
|
49
|
+
group.action(
|
|
50
|
+
`heading--${levelStr}`,
|
|
51
|
+
{
|
|
52
|
+
label: ['heading-level.label', { count: level, ns: translationKey }],
|
|
53
|
+
icon,
|
|
54
|
+
checked: levelStr === headingValue,
|
|
55
|
+
},
|
|
56
|
+
() => setHeading(level)(getView()),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
);
|
|
67
61
|
};
|
|
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 }>;
|
|
24
|
-
} => ({
|
|
25
|
-
nodes: [createImageUploadAction(onImageUpload)],
|
|
26
|
-
edges: [{ source: 'root', target: 'image' }],
|
|
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
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
import { type EditorToolbarState } from './useEditorToolbar';
|
|
12
|
+
|
|
13
|
+
const listStyles = {
|
|
14
|
+
bullet: 'ph--list-bullets--regular',
|
|
15
|
+
ordered: 'ph--list-numbers--regular',
|
|
16
|
+
task: 'ph--list-checks--regular',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Add list actions to the builder. */
|
|
20
|
+
export const addLists =
|
|
21
|
+
(state: EditorToolbarState, getView: () => EditorView): ActionGroupBuilderFn =>
|
|
22
|
+
(builder) => {
|
|
23
|
+
const value = state.listStyle ?? '';
|
|
24
|
+
builder.group(
|
|
25
|
+
'list',
|
|
26
|
+
{
|
|
27
|
+
label: ['list.label', { ns: translationKey }],
|
|
28
|
+
iconOnly: true,
|
|
29
|
+
variant: 'toggleGroup',
|
|
30
|
+
selectCardinality: 'single',
|
|
31
|
+
value,
|
|
32
|
+
} as ToolbarMenuActionGroupProperties,
|
|
33
|
+
(group) => {
|
|
34
|
+
for (const [listStyle, icon] of Object.entries(listStyles)) {
|
|
35
|
+
const checked = value === listStyle;
|
|
36
|
+
group.action(
|
|
37
|
+
`list-${listStyle}`,
|
|
38
|
+
{ label: [`list.${listStyle}.label`, { ns: translationKey }], checked, icon },
|
|
39
|
+
() => {
|
|
40
|
+
const view = getView();
|
|
41
|
+
if (!view) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const listType =
|
|
46
|
+
listStyle === 'ordered' ? List.Ordered : listStyle === 'bullet' ? List.Bullet : List.Task;
|
|
47
|
+
if (checked) {
|
|
48
|
+
removeList(listType)(view);
|
|
49
|
+
} else {
|
|
50
|
+
addList(listType)(view);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
};
|
|
@@ -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 }>;
|
|
27
|
-
} => ({
|
|
28
|
-
nodes: [createSearchAction(getView)],
|
|
29
|
-
edges: [{ source: 'root', target: 'search' }],
|
|
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
|
+
};
|
|
@@ -2,54 +2,47 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
6
|
-
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
5
|
+
import { type ActionGroupBuilderFn, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
|
7
6
|
import { type EditorViewMode } from '@dxos/ui-editor';
|
|
8
7
|
|
|
9
8
|
import { translationKey } from '../../translations';
|
|
10
|
-
|
|
11
|
-
import { createEditorAction, createEditorActionGroup } from './actions';
|
|
12
9
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
13
10
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
applyActive: true,
|
|
20
|
-
selectCardinality: 'single',
|
|
21
|
-
value,
|
|
22
|
-
} as ToolbarMenuActionGroupProperties,
|
|
23
|
-
'ph--eye--regular',
|
|
24
|
-
);
|
|
11
|
+
const viewModes = {
|
|
12
|
+
preview: 'ph--eye--regular',
|
|
13
|
+
source: 'ph--pencil-simple--regular',
|
|
14
|
+
readonly: 'ph--pencil-slash--regular',
|
|
15
|
+
};
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return createEditorAction(
|
|
34
|
-
`view-mode--${viewMode}`,
|
|
17
|
+
/** Add view mode actions to the builder. */
|
|
18
|
+
export const addViewMode =
|
|
19
|
+
(state: EditorToolbarState, onViewModeChange: (mode: EditorViewMode) => void): ActionGroupBuilderFn =>
|
|
20
|
+
(builder) => {
|
|
21
|
+
const value = state.viewMode ?? 'source';
|
|
22
|
+
builder.group(
|
|
23
|
+
'viewMode',
|
|
35
24
|
{
|
|
36
|
-
label: [
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
label: ['view-mode.label', { ns: translationKey }],
|
|
26
|
+
icon: 'ph--eye--regular',
|
|
27
|
+
iconOnly: true,
|
|
28
|
+
variant: 'dropdownMenu',
|
|
29
|
+
applyActive: true,
|
|
30
|
+
selectCardinality: 'single',
|
|
31
|
+
value,
|
|
32
|
+
} as ToolbarMenuActionGroupProperties,
|
|
33
|
+
(group) => {
|
|
34
|
+
for (const [viewMode, icon] of Object.entries(viewModes)) {
|
|
35
|
+
const checked = viewMode === value;
|
|
36
|
+
group.action(
|
|
37
|
+
`view-mode--${viewMode}`,
|
|
38
|
+
{
|
|
39
|
+
label: [`view-mode.${viewMode}.label`, { ns: translationKey }],
|
|
40
|
+
checked,
|
|
41
|
+
icon,
|
|
42
|
+
},
|
|
43
|
+
() => onViewModeChange(viewMode as EditorViewMode),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
39
46
|
},
|
|
40
|
-
() => onViewModeChange(viewMode as EditorViewMode),
|
|
41
47
|
);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export const createViewMode = (state: EditorToolbarState, onViewModeChange: (mode: EditorViewMode) => void) => {
|
|
45
|
-
const value = state.viewMode ?? 'source';
|
|
46
|
-
const viewModeGroupAction = createViewModeGroupAction(value);
|
|
47
|
-
const viewModeActions = createViewModeActions(value, onViewModeChange);
|
|
48
|
-
return {
|
|
49
|
-
nodes: [viewModeGroupAction as Node.NodeArg<any>, ...viewModeActions],
|
|
50
|
-
edges: [
|
|
51
|
-
{ source: 'root', target: 'viewMode' },
|
|
52
|
-
...viewModeActions.map(({ id }) => ({ source: viewModeGroupAction.id, target: id })),
|
|
53
|
-
],
|
|
54
48
|
};
|
|
55
|
-
};
|
|
@@ -8,16 +8,15 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
8
8
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
10
|
import { Obj, Ref } from '@dxos/echo';
|
|
11
|
-
import { TestSchema } from '@dxos/echo/testing';
|
|
12
11
|
import { DocAccessor, createDocAccessor } from '@dxos/echo-db';
|
|
12
|
+
import { TestSchema } from '@dxos/echo/testing';
|
|
13
13
|
import { log } from '@dxos/log';
|
|
14
14
|
import { type Messenger } from '@dxos/protocols';
|
|
15
15
|
import { Query, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
16
16
|
import { type Identity, useIdentity } from '@dxos/react-client/halo';
|
|
17
17
|
import { useClientStory, withMultiClientProvider } from '@dxos/react-client/testing';
|
|
18
18
|
import { Button, useThemeContext } from '@dxos/react-ui';
|
|
19
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
20
|
-
import { render } from '@dxos/storybook-utils';
|
|
19
|
+
import { withLayout, withTheme, Loading } from '@dxos/react-ui/testing';
|
|
21
20
|
import { createBasicExtensions, createDataExtensions, createThemeExtensions } from '@dxos/ui-editor';
|
|
22
21
|
|
|
23
22
|
import { useTextEditor } from '../hooks';
|
|
@@ -44,14 +43,14 @@ const Editor = ({ source, messenger, identity, autoFocus }: EditorProps) => {
|
|
|
44
43
|
initialValue: DocAccessor.getValue(source),
|
|
45
44
|
extensions: [
|
|
46
45
|
createBasicExtensions({ placeholder: 'Type here...', search: true }),
|
|
47
|
-
createThemeExtensions({ themeMode, slots: {
|
|
46
|
+
createThemeExtensions({ themeMode, slots: { scroller: { className: 'p-2' } } }),
|
|
48
47
|
createDataExtensions({ id: 'test', text: source, messenger, identity }),
|
|
49
48
|
],
|
|
50
49
|
}),
|
|
51
50
|
[source, themeMode],
|
|
52
51
|
);
|
|
53
52
|
|
|
54
|
-
return <div ref={parentRef} className='flex
|
|
53
|
+
return <div ref={parentRef} className='flex w-full' />;
|
|
55
54
|
};
|
|
56
55
|
|
|
57
56
|
const DefaultStory = () => {
|
|
@@ -77,11 +76,11 @@ const DefaultStory = () => {
|
|
|
77
76
|
}, []);
|
|
78
77
|
|
|
79
78
|
if (!object1 || !object2) {
|
|
80
|
-
return
|
|
79
|
+
return <Loading data={{ object1: !!object1, object2: !!object2 }} />;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
return (
|
|
84
|
-
<div className='
|
|
83
|
+
<div className='h-full w-full grid grid-cols-2 gap-4'>
|
|
85
84
|
<Editor source={object1} autoFocus />
|
|
86
85
|
<Editor source={object2} />
|
|
87
86
|
</div>
|
|
@@ -117,7 +116,7 @@ const EchoStory = () => {
|
|
|
117
116
|
}, [objects, source]);
|
|
118
117
|
|
|
119
118
|
return (
|
|
120
|
-
<div className='
|
|
119
|
+
<div className='h-full w-full flex flex-col overflow-hidden'>
|
|
121
120
|
<pre className='p-2 text-xs text-subdued'>
|
|
122
121
|
{JSON.stringify({ index, identity: identity?.identityKey.truncate(), spaceId, objects }, null, 2)}
|
|
123
122
|
</pre>
|
|
@@ -137,6 +136,7 @@ const EchoStory = () => {
|
|
|
137
136
|
const meta = {
|
|
138
137
|
title: 'ui/react-ui-editor/Automerge',
|
|
139
138
|
component: Editor as any,
|
|
139
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
140
140
|
parameters: {
|
|
141
141
|
layout: 'fullscreen',
|
|
142
142
|
translations,
|
|
@@ -149,14 +149,12 @@ type Story = StoryObj<typeof meta>;
|
|
|
149
149
|
|
|
150
150
|
// TODO(burdon): ERROR: factories.ts:126 Error: Non-base58 character
|
|
151
151
|
export const Default: Story = {
|
|
152
|
-
|
|
153
|
-
render: render(DefaultStory),
|
|
152
|
+
render: DefaultStory,
|
|
154
153
|
};
|
|
155
154
|
|
|
156
155
|
// TODO(burdon): Failing (doesn't sync)
|
|
157
156
|
export const WithEcho: Story = {
|
|
158
157
|
decorators: [
|
|
159
|
-
withTheme,
|
|
160
158
|
withMultiClientProvider({
|
|
161
159
|
numClients: 2,
|
|
162
160
|
createIdentity: true,
|
|
@@ -171,5 +169,5 @@ export const WithEcho: Story = {
|
|
|
171
169
|
},
|
|
172
170
|
}),
|
|
173
171
|
],
|
|
174
|
-
render:
|
|
172
|
+
render: EchoStory,
|
|
175
173
|
};
|