@dxos/react-ui-editor 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6
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 +298 -377
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +298 -377
- 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.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/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 +2 -2
- package/src/components/Editor/Editor.tsx +12 -6
- package/src/components/EditorContent/EditorContent.tsx +1 -1
- 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 +54 -46
- package/src/components/EditorToolbar/formatting.ts +43 -44
- package/src/components/EditorToolbar/headings.ts +42 -48
- 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 -40
- package/src/stories/Automerge.stories.tsx +8 -10
- package/src/stories/Comments.stories.tsx +4 -4
- package/src/stories/EditorToolbar.stories.tsx +32 -17
- package/src/stories/Experimental.stories.tsx +3 -3
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +4 -4
- package/src/stories/Popover.stories.tsx +6 -6
- package/src/stories/Preview.stories.tsx +58 -48
- 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 +19 -22
- 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,11 +4,11 @@
|
|
|
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';
|
|
11
|
+
|
|
12
12
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
13
13
|
|
|
14
14
|
const formats = {
|
|
@@ -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' },
|
|
62
|
-
...formattingActions.map(({ id }) => ({ source: formattingGroupAction.id, target: id })),
|
|
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
10
|
import { translationKey } from '../../translations';
|
|
12
11
|
|
|
13
|
-
import { createEditorAction, createEditorActionGroup } from './actions';
|
|
14
12
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
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 }>;
|
|
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,48 @@
|
|
|
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
9
|
|
|
11
|
-
import { createEditorAction, createEditorActionGroup } from './actions';
|
|
12
10
|
import { type EditorToolbarState } from './useEditorToolbar';
|
|
13
11
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
applyActive: true,
|
|
20
|
-
selectCardinality: 'single',
|
|
21
|
-
value,
|
|
22
|
-
} as ToolbarMenuActionGroupProperties,
|
|
23
|
-
'ph--eye--regular',
|
|
24
|
-
);
|
|
12
|
+
const viewModes = {
|
|
13
|
+
preview: 'ph--eye--regular',
|
|
14
|
+
source: 'ph--pencil-simple--regular',
|
|
15
|
+
readonly: 'ph--pencil-slash--regular',
|
|
16
|
+
};
|
|
25
17
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return createEditorAction(
|
|
34
|
-
`view-mode--${viewMode}`,
|
|
18
|
+
/** Add view mode actions to the builder. */
|
|
19
|
+
export const addViewMode =
|
|
20
|
+
(state: EditorToolbarState, onViewModeChange: (mode: EditorViewMode) => void): ActionGroupBuilderFn =>
|
|
21
|
+
(builder) => {
|
|
22
|
+
const value = state.viewMode ?? 'source';
|
|
23
|
+
builder.group(
|
|
24
|
+
'viewMode',
|
|
35
25
|
{
|
|
36
|
-
label: [
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
label: ['view-mode.label', { ns: translationKey }],
|
|
27
|
+
icon: 'ph--eye--regular',
|
|
28
|
+
iconOnly: true,
|
|
29
|
+
variant: 'dropdownMenu',
|
|
30
|
+
applyActive: true,
|
|
31
|
+
selectCardinality: 'single',
|
|
32
|
+
value,
|
|
33
|
+
} as ToolbarMenuActionGroupProperties,
|
|
34
|
+
(group) => {
|
|
35
|
+
for (const [viewMode, icon] of Object.entries(viewModes)) {
|
|
36
|
+
const checked = viewMode === value;
|
|
37
|
+
group.action(
|
|
38
|
+
`view-mode--${viewMode}`,
|
|
39
|
+
{
|
|
40
|
+
label: [`view-mode.${viewMode}.label`, { ns: translationKey }],
|
|
41
|
+
checked,
|
|
42
|
+
icon,
|
|
43
|
+
},
|
|
44
|
+
() => onViewModeChange(viewMode as EditorViewMode),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
39
47
|
},
|
|
40
|
-
() => onViewModeChange(viewMode as EditorViewMode),
|
|
41
48
|
);
|
|
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
49
|
};
|
|
55
|
-
};
|
|
@@ -16,8 +16,7 @@ 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';
|
|
@@ -51,7 +50,7 @@ const Editor = ({ source, messenger, identity, autoFocus }: EditorProps) => {
|
|
|
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
|
};
|
|
@@ -9,7 +9,7 @@ import React, { type FC, useContext, useMemo } from 'react';
|
|
|
9
9
|
import { keySymbols, parseShortcut } from '@dxos/keyboard';
|
|
10
10
|
import { PublicKey } from '@dxos/keys';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
12
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
13
13
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
14
14
|
import { type Comment, annotations, comments, createExternalCommentSync } from '@dxos/ui-editor';
|
|
15
15
|
|
|
@@ -20,7 +20,7 @@ import { EditorStory, content, longText } from './components';
|
|
|
20
20
|
const meta = {
|
|
21
21
|
title: 'ui/react-ui-editor/Comments',
|
|
22
22
|
component: EditorStory,
|
|
23
|
-
decorators: [withRegistry, withTheme],
|
|
23
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
24
24
|
parameters: {
|
|
25
25
|
layout: 'fullscreen',
|
|
26
26
|
},
|
|
@@ -77,14 +77,14 @@ export const Comments: Story = {
|
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
const Key: FC<{ char: string }> = ({ char }) => (
|
|
80
|
-
<span className='flex justify-center items-center
|
|
80
|
+
<span className='flex justify-center items-center w-[24px] h-[24px] rounded-sm text-xs bg-neutral-200 text-black'>
|
|
81
81
|
{char}
|
|
82
82
|
</span>
|
|
83
83
|
);
|
|
84
84
|
|
|
85
85
|
const CommentTooltip: FC<{ shortcut: string }> = ({ shortcut }) => {
|
|
86
86
|
return (
|
|
87
|
-
<div className='flex items-center gap-2
|
|
87
|
+
<div className='flex items-center gap-2 px-2 py-2 bg-neutral-700 text-white text-xs rounded-sm'>
|
|
88
88
|
<div>Create comment</div>
|
|
89
89
|
<div className='flex gap-1'>
|
|
90
90
|
{keySymbols(parseShortcut(shortcut)).map((char) => (
|
|
@@ -7,8 +7,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
7
7
|
import React, { useCallback, useContext, useState } from 'react';
|
|
8
8
|
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
|
-
import { useThemeContext } from '@dxos/react-ui';
|
|
11
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
import { Panel, useThemeContext } from '@dxos/react-ui';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
12
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
13
13
|
import {
|
|
14
14
|
type EditorInputMode,
|
|
@@ -18,19 +18,18 @@ import {
|
|
|
18
18
|
createMarkdownExtensions,
|
|
19
19
|
createThemeExtensions,
|
|
20
20
|
decorateMarkdown,
|
|
21
|
-
|
|
21
|
+
documentSlots,
|
|
22
22
|
formattingKeymap,
|
|
23
23
|
formattingListener,
|
|
24
24
|
} from '@dxos/ui-editor';
|
|
25
|
-
import { attentionSurface, mx } from '@dxos/ui-theme';
|
|
26
25
|
|
|
27
26
|
import { EditorToolbar, type EditorToolbarState, useEditorToolbar } from '../components';
|
|
28
27
|
import { type UseTextEditorProps, useTextEditor } from '../hooks';
|
|
29
28
|
import { translations } from '../translations';
|
|
30
29
|
|
|
31
|
-
type
|
|
30
|
+
type DefaultStoryProps = { placeholder?: string } & UseTextEditorProps;
|
|
32
31
|
|
|
33
|
-
const DefaultStory = ({ autoFocus, initialValue, placeholder }:
|
|
32
|
+
const DefaultStory = ({ autoFocus, initialValue, placeholder }: DefaultStoryProps) => {
|
|
34
33
|
const { themeMode } = useThemeContext();
|
|
35
34
|
const registry = useContext(RegistryContext);
|
|
36
35
|
|
|
@@ -53,9 +52,18 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
53
52
|
selectionEnd: true,
|
|
54
53
|
extensions: [
|
|
55
54
|
editorInputMode ? InputModeExtensions[editorInputMode] : [],
|
|
56
|
-
createBasicExtensions({
|
|
55
|
+
createBasicExtensions({
|
|
56
|
+
placeholder,
|
|
57
|
+
lineWrapping: true,
|
|
58
|
+
readOnly: viewMode === 'readonly',
|
|
59
|
+
search: true,
|
|
60
|
+
}),
|
|
61
|
+
createThemeExtensions({
|
|
62
|
+
themeMode,
|
|
63
|
+
syntaxHighlighting: true,
|
|
64
|
+
slots: documentSlots,
|
|
65
|
+
}),
|
|
57
66
|
createMarkdownExtensions(),
|
|
58
|
-
createThemeExtensions({ themeMode, syntaxHighlighting: true }),
|
|
59
67
|
viewMode === 'source' ? [] : decorateMarkdown(),
|
|
60
68
|
formattingKeymap(),
|
|
61
69
|
formattingListener(updateToolbarState),
|
|
@@ -76,22 +84,29 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
76
84
|
[registry, toolbarState],
|
|
77
85
|
);
|
|
78
86
|
|
|
79
|
-
// TODO(marijn): This doesn't update the state on view changes.
|
|
80
|
-
// Also not sure if view is even guaranteed to exist at this point.
|
|
81
87
|
return (
|
|
82
|
-
<
|
|
83
|
-
{toolbarState &&
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
<Panel.Root>
|
|
89
|
+
{toolbarState && (
|
|
90
|
+
<Panel.Toolbar>
|
|
91
|
+
<EditorToolbar
|
|
92
|
+
classNames='dx-document'
|
|
93
|
+
state={toolbarState}
|
|
94
|
+
getView={getView}
|
|
95
|
+
onViewModeChange={handleViewModeChange}
|
|
96
|
+
/>
|
|
97
|
+
</Panel.Toolbar>
|
|
98
|
+
)}
|
|
99
|
+
<Panel.Content>
|
|
100
|
+
<div role='none' className='dx-container dx-document bg-base-surface' ref={parentRef} />
|
|
101
|
+
</Panel.Content>
|
|
102
|
+
</Panel.Root>
|
|
88
103
|
);
|
|
89
104
|
};
|
|
90
105
|
|
|
91
106
|
const meta = {
|
|
92
107
|
title: 'ui/react-ui-editor/EditorToolbar',
|
|
93
108
|
render: DefaultStory,
|
|
94
|
-
decorators: [withRegistry, withTheme],
|
|
109
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen', classNames: 'bg-sidebar-surface' })],
|
|
95
110
|
parameters: {
|
|
96
111
|
layout: 'fullscreen',
|
|
97
112
|
translations,
|