@dxos/react-ui-editor 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
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 +100 -79
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +100 -79
- package/dist/lib/node-esm/index.mjs.map +3 -3
- 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.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/actions.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/actions.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/search.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/stories/Automerge.stories.d.ts +1 -0
- 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/Experimental.stories.d.ts +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +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 +2 -2
- 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/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 +1 -1
- package/src/components/Editor/Editor.tsx +12 -6
- package/src/components/EditorContent/EditorContent.tsx +1 -1
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +19 -24
- package/src/components/EditorMenuProvider/useEditorMenu.ts +6 -0
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +5 -7
- package/src/components/EditorToolbar/EditorToolbar.tsx +17 -33
- package/src/components/EditorToolbar/actions.ts +2 -2
- package/src/components/EditorToolbar/blocks.ts +2 -2
- package/src/components/EditorToolbar/formatting.ts +2 -2
- package/src/components/EditorToolbar/headings.ts +9 -9
- package/src/components/EditorToolbar/image.ts +2 -2
- package/src/components/EditorToolbar/search.ts +2 -2
- package/src/components/EditorToolbar/view-mode.ts +2 -2
- package/src/stories/Automerge.stories.tsx +8 -10
- package/src/stories/CommandDialog.stories.tsx +5 -5
- package/src/stories/Comments.stories.tsx +4 -4
- package/src/stories/EditorToolbar.stories.tsx +4 -4
- package/src/stories/Experimental.stories.tsx +3 -3
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +2 -2
- package/src/stories/Popover.stories.tsx +3 -3
- package/src/stories/Preview.stories.tsx +57 -47
- 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 +3 -5
- package/src/stories/components/util.tsx +19 -22
- package/src/util/react.tsx +2 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-editor",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.6fa680abb7",
|
|
4
4
|
"description": "Text editor components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@replit/codemirror-vim": "^6.2.1",
|
|
56
56
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
57
57
|
"@uiw/codemirror-theme-vscode": "^4.25.2",
|
|
58
|
-
"ajv": "^8.
|
|
58
|
+
"ajv": "^8.18.0",
|
|
59
59
|
"bind-event-listener": "^3.0.0",
|
|
60
60
|
"codemirror": "^6.0.1",
|
|
61
61
|
"lib0": "^0.2.65",
|
|
@@ -63,32 +63,32 @@
|
|
|
63
63
|
"lodash.merge": "^4.6.2",
|
|
64
64
|
"lodash.sortby": "^4.7.0",
|
|
65
65
|
"style-mod": "^4.1.0",
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/async": "0.8.4-main.
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/invariant": "0.8.4-main.
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/lit-ui": "0.8.4-main.
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/react-hooks": "0.8.4-main.
|
|
79
|
-
"@dxos/react-ui-
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/ui": "0.8.4-main.
|
|
82
|
-
"@dxos/ui-
|
|
83
|
-
"@dxos/
|
|
84
|
-
"@dxos/
|
|
66
|
+
"@dxos/client": "0.8.4-main.6fa680abb7",
|
|
67
|
+
"@dxos/async": "0.8.4-main.6fa680abb7",
|
|
68
|
+
"@dxos/context": "0.8.4-main.6fa680abb7",
|
|
69
|
+
"@dxos/debug": "0.8.4-main.6fa680abb7",
|
|
70
|
+
"@dxos/echo": "0.8.4-main.6fa680abb7",
|
|
71
|
+
"@dxos/echo-db": "0.8.4-main.6fa680abb7",
|
|
72
|
+
"@dxos/display-name": "0.8.4-main.6fa680abb7",
|
|
73
|
+
"@dxos/invariant": "0.8.4-main.6fa680abb7",
|
|
74
|
+
"@dxos/app-graph": "0.8.4-main.6fa680abb7",
|
|
75
|
+
"@dxos/lit-ui": "0.8.4-main.6fa680abb7",
|
|
76
|
+
"@dxos/log": "0.8.4-main.6fa680abb7",
|
|
77
|
+
"@dxos/protocols": "0.8.4-main.6fa680abb7",
|
|
78
|
+
"@dxos/react-hooks": "0.8.4-main.6fa680abb7",
|
|
79
|
+
"@dxos/react-ui-mosaic": "0.8.4-main.6fa680abb7",
|
|
80
|
+
"@dxos/ui": "0.8.4-main.6fa680abb7",
|
|
81
|
+
"@dxos/ui-editor": "0.8.4-main.6fa680abb7",
|
|
82
|
+
"@dxos/ui-theme": "0.8.4-main.6fa680abb7",
|
|
83
|
+
"@dxos/react-ui-menu": "0.8.4-main.6fa680abb7",
|
|
84
|
+
"@dxos/util": "0.8.4-main.6fa680abb7"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@automerge/automerge": "3.2.3",
|
|
88
88
|
"@automerge/automerge-repo": "2.5.1",
|
|
89
89
|
"@automerge/automerge-repo-network-broadcastchannel": "2.5.1",
|
|
90
|
-
"@effect-atom/atom-react": "^0.
|
|
91
|
-
"@effect/platform": "0.
|
|
90
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
91
|
+
"@effect/platform": "0.94.4",
|
|
92
92
|
"@types/chai": "^4.2.15",
|
|
93
93
|
"@types/chai-dom": "^1.11.0",
|
|
94
94
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
@@ -99,39 +99,39 @@
|
|
|
99
99
|
"@types/react-test-renderer": "^17.0.2",
|
|
100
100
|
"chai": "^4.4.1",
|
|
101
101
|
"chai-dom": "^1.11.0",
|
|
102
|
-
"effect": "3.19.
|
|
103
|
-
"happy-dom": "^
|
|
102
|
+
"effect": "3.19.16",
|
|
103
|
+
"happy-dom": "^20.0.0",
|
|
104
104
|
"jsdom": "^27.0.0",
|
|
105
105
|
"mocha": "^10.6.0",
|
|
106
106
|
"react": "~19.2.3",
|
|
107
107
|
"react-dom": "~19.2.3",
|
|
108
108
|
"react-test-renderer": "~19.2.0",
|
|
109
|
-
"vite": "7.1.
|
|
109
|
+
"vite": "^7.1.11",
|
|
110
110
|
"vite-plugin-top-level-await": "^1.6.0",
|
|
111
111
|
"vite-plugin-wasm": "^3.5.0",
|
|
112
|
-
"@dxos/
|
|
113
|
-
"@dxos/echo": "0.8.4-main.
|
|
114
|
-
"@dxos/
|
|
115
|
-
"@dxos/
|
|
116
|
-
"@dxos/random": "0.8.4-main.
|
|
117
|
-
"@dxos/react-client": "0.8.4-main.
|
|
118
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
119
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
120
|
-
"@dxos/
|
|
121
|
-
"@dxos/schema": "0.8.4-main.
|
|
122
|
-
"@dxos/
|
|
123
|
-
"@dxos/ui-
|
|
124
|
-
"@dxos/ui-types": "0.8.4-main.
|
|
112
|
+
"@dxos/config": "0.8.4-main.6fa680abb7",
|
|
113
|
+
"@dxos/echo-atom": "0.8.4-main.6fa680abb7",
|
|
114
|
+
"@dxos/echo": "0.8.4-main.6fa680abb7",
|
|
115
|
+
"@dxos/keyboard": "0.8.4-main.6fa680abb7",
|
|
116
|
+
"@dxos/random": "0.8.4-main.6fa680abb7",
|
|
117
|
+
"@dxos/react-client": "0.8.4-main.6fa680abb7",
|
|
118
|
+
"@dxos/react-ui": "0.8.4-main.6fa680abb7",
|
|
119
|
+
"@dxos/react-ui-attention": "0.8.4-main.6fa680abb7",
|
|
120
|
+
"@dxos/storybook-utils": "0.8.4-main.6fa680abb7",
|
|
121
|
+
"@dxos/schema": "0.8.4-main.6fa680abb7",
|
|
122
|
+
"@dxos/ui-theme": "0.8.4-main.6fa680abb7",
|
|
123
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.6fa680abb7",
|
|
124
|
+
"@dxos/ui-types": "0.8.4-main.6fa680abb7"
|
|
125
125
|
},
|
|
126
126
|
"peerDependencies": {
|
|
127
|
-
"@effect-atom/atom-react": "^0.
|
|
128
|
-
"@effect/platform": "0.
|
|
129
|
-
"effect": "3.19.
|
|
127
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
128
|
+
"@effect/platform": "0.94.4",
|
|
129
|
+
"effect": "3.19.16",
|
|
130
130
|
"react": "~19.2.3",
|
|
131
131
|
"react-dom": "~19.2.3",
|
|
132
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
133
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
134
|
-
"@dxos/react-client": "0.8.4-main.
|
|
132
|
+
"@dxos/react-ui": "0.8.4-main.6fa680abb7",
|
|
133
|
+
"@dxos/ui-theme": "0.8.4-main.6fa680abb7",
|
|
134
|
+
"@dxos/react-client": "0.8.4-main.6fa680abb7"
|
|
135
135
|
},
|
|
136
136
|
"publishConfig": {
|
|
137
137
|
"access": "public"
|
|
@@ -53,7 +53,7 @@ const withExtensions: Decorator<EditorContentProps> = (Story, { args }) => {
|
|
|
53
53
|
const meta = {
|
|
54
54
|
title: 'ui/react-ui-editor/Editor',
|
|
55
55
|
component: Editor.Content,
|
|
56
|
-
decorators: [withExtensions, withTheme, withLayout({ layout: 'column' }), withAttention],
|
|
56
|
+
decorators: [withExtensions, withTheme(), withLayout({ layout: 'column' }), withAttention()],
|
|
57
57
|
parameters: {
|
|
58
58
|
layout: 'fullscreen',
|
|
59
59
|
},
|
|
@@ -84,6 +84,8 @@ EditorRoot.displayName = 'Editor.Root';
|
|
|
84
84
|
// Viewport
|
|
85
85
|
//
|
|
86
86
|
|
|
87
|
+
const EDITOR_VIEWPORT_NAME = 'Editor.Viewport';
|
|
88
|
+
|
|
87
89
|
type EditorViewportProps = ThemedClassName<PropsWithChildren<{}>>;
|
|
88
90
|
|
|
89
91
|
/**
|
|
@@ -91,18 +93,20 @@ type EditorViewportProps = ThemedClassName<PropsWithChildren<{}>>;
|
|
|
91
93
|
*/
|
|
92
94
|
const EditorViewport = ({ classNames, children }: EditorViewportProps) => {
|
|
93
95
|
return (
|
|
94
|
-
<div role='none' className={mx('grid grid-rows-[min-content_1fr]
|
|
96
|
+
<div role='none' className={mx('grid grid-rows-[min-content_1fr] h-full overflow-hidden', classNames)}>
|
|
95
97
|
{children}
|
|
96
98
|
</div>
|
|
97
99
|
);
|
|
98
100
|
};
|
|
99
101
|
|
|
100
|
-
EditorViewport.displayName =
|
|
102
|
+
EditorViewport.displayName = EDITOR_VIEWPORT_NAME;
|
|
101
103
|
|
|
102
104
|
//
|
|
103
105
|
// Content
|
|
104
106
|
//
|
|
105
107
|
|
|
108
|
+
const EDITOR_CONTENT_NAME = 'Editor.Content';
|
|
109
|
+
|
|
106
110
|
type EditorContentProps = Omit<NaturalEditorContentProps, 'ref'>;
|
|
107
111
|
|
|
108
112
|
/**
|
|
@@ -110,7 +114,7 @@ type EditorContentProps = Omit<NaturalEditorContentProps, 'ref'>;
|
|
|
110
114
|
* Automatically registers the editor controller with the context.
|
|
111
115
|
*/
|
|
112
116
|
const EditorContent = ({ extensions: providedExtensions, ...props }: EditorContentProps) => {
|
|
113
|
-
const { extensions: additionalExtensions = [], setController } = useEditorContext(
|
|
117
|
+
const { extensions: additionalExtensions = [], setController } = useEditorContext(EDITOR_CONTENT_NAME);
|
|
114
118
|
|
|
115
119
|
const extensions = useMemo(
|
|
116
120
|
() => [additionalExtensions, providedExtensions].filter(isNonNullable).flat(),
|
|
@@ -120,12 +124,14 @@ const EditorContent = ({ extensions: providedExtensions, ...props }: EditorConte
|
|
|
120
124
|
return <NaturalEditorContent {...props} extensions={extensions} ref={setController} />;
|
|
121
125
|
};
|
|
122
126
|
|
|
123
|
-
EditorContent.displayName =
|
|
127
|
+
EditorContent.displayName = EDITOR_CONTENT_NAME;
|
|
124
128
|
|
|
125
129
|
//
|
|
126
130
|
// Toolbar
|
|
127
131
|
//
|
|
128
132
|
|
|
133
|
+
const EDITOR_TOOLBAR_NAME = 'Editor.Toolbar';
|
|
134
|
+
|
|
129
135
|
type EditorToolbarProps = Omit<NaturalEditorToolbarProps, 'getView' | 'state'>;
|
|
130
136
|
|
|
131
137
|
/**
|
|
@@ -133,7 +139,7 @@ type EditorToolbarProps = Omit<NaturalEditorToolbarProps, 'getView' | 'state'>;
|
|
|
133
139
|
* Automatically connects to the editor view through context.
|
|
134
140
|
*/
|
|
135
141
|
const EditorToolbar = (props: EditorToolbarProps) => {
|
|
136
|
-
const { controller, state } = useEditorContext(
|
|
142
|
+
const { controller, state } = useEditorContext(EDITOR_TOOLBAR_NAME);
|
|
137
143
|
|
|
138
144
|
// TODO(burdon): Fix invariant.
|
|
139
145
|
const getView = useCallback(() => {
|
|
@@ -144,7 +150,7 @@ const EditorToolbar = (props: EditorToolbarProps) => {
|
|
|
144
150
|
return <NaturalEditorToolbar {...props} getView={getView} state={state} />;
|
|
145
151
|
};
|
|
146
152
|
|
|
147
|
-
EditorToolbar.displayName =
|
|
153
|
+
EditorToolbar.displayName = EDITOR_TOOLBAR_NAME;
|
|
148
154
|
|
|
149
155
|
//
|
|
150
156
|
// Editor
|
|
@@ -72,7 +72,7 @@ export const EditorContent = forwardRef<EditorController, EditorContentProps>(
|
|
|
72
72
|
<div
|
|
73
73
|
role='none'
|
|
74
74
|
className={mx(
|
|
75
|
-
'
|
|
75
|
+
'w-full outline-hidden focus:border-accent-surface focus-within:border-neutral-focus-indicator',
|
|
76
76
|
classNames,
|
|
77
77
|
)}
|
|
78
78
|
ref={parentRef}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type DxAnchorActivate,
|
|
14
14
|
Icon,
|
|
15
15
|
Popover,
|
|
16
|
+
ScrollArea,
|
|
16
17
|
toLocalizedString,
|
|
17
18
|
useDynamicRef,
|
|
18
19
|
useThemeContext,
|
|
@@ -78,10 +79,8 @@ export const EditorMenuProvider = ({
|
|
|
78
79
|
root,
|
|
79
80
|
DX_ANCHOR_ACTIVATE as any,
|
|
80
81
|
(event: DxAnchorActivate) => {
|
|
81
|
-
const { trigger,
|
|
82
|
-
|
|
83
|
-
// If this has a `refId`, then it’s probably a URL or DXN and out of scope for this component.
|
|
84
|
-
if (!refId) {
|
|
82
|
+
const { trigger, dxn } = event;
|
|
83
|
+
if (!dxn) {
|
|
85
84
|
triggerRef.current = trigger as HTMLButtonElement;
|
|
86
85
|
if (onActivate) {
|
|
87
86
|
onActivate({ view: viewRef.current!, trigger: trigger.getAttribute('data-trigger') ?? undefined });
|
|
@@ -115,32 +114,32 @@ export const EditorMenuProvider = ({
|
|
|
115
114
|
<Popover.Portal>
|
|
116
115
|
<Popover.Content
|
|
117
116
|
align='start'
|
|
118
|
-
classNames={
|
|
119
|
-
'overflow-y-auto',
|
|
120
|
-
!menuGroups.length && 'hidden',
|
|
121
|
-
])}
|
|
117
|
+
classNames={['flex flex-col', !menuGroups.length && 'hidden']}
|
|
122
118
|
style={{
|
|
123
119
|
maxBlockSize: 36 * numItems + 10,
|
|
124
120
|
}}
|
|
125
|
-
|
|
126
|
-
* NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
127
|
-
*/
|
|
121
|
+
// NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
128
122
|
onEscapeKeyDown={() => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
const currentView = viewRef.current;
|
|
124
|
+
if (currentView) {
|
|
125
|
+
onCancel?.({ view: currentView });
|
|
126
|
+
}
|
|
132
127
|
}}
|
|
133
128
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
134
129
|
>
|
|
135
|
-
<Popover.Viewport classNames=
|
|
136
|
-
<
|
|
130
|
+
<Popover.Viewport asChild classNames='dx-container'>
|
|
131
|
+
<ScrollArea.Root thin>
|
|
132
|
+
<ScrollArea.Viewport>
|
|
133
|
+
<Menu groups={menuGroups} currentItem={currentItem} onSelect={handleSelect} />
|
|
134
|
+
</ScrollArea.Viewport>
|
|
135
|
+
</ScrollArea.Root>
|
|
137
136
|
</Popover.Viewport>
|
|
138
137
|
<Popover.Arrow />
|
|
139
138
|
</Popover.Content>
|
|
140
139
|
</Popover.Portal>
|
|
141
140
|
|
|
142
141
|
{/* Content */}
|
|
143
|
-
<div
|
|
142
|
+
<div role='none' className='contents' ref={setRoot}>
|
|
144
143
|
{children}
|
|
145
144
|
</div>
|
|
146
145
|
</Popover.Root>
|
|
@@ -162,7 +161,7 @@ const Menu = ({ groups, currentItem, onSelect }: MenuProps) => {
|
|
|
162
161
|
{groups.map((group, index) => (
|
|
163
162
|
<Fragment key={group.id}>
|
|
164
163
|
<MenuGroup group={group} currentItem={currentItem} onSelect={onSelect} />
|
|
165
|
-
{index < groups.length - 1 && <div className={tx('menu.separator',
|
|
164
|
+
{index < groups.length - 1 && <div className={tx('menu.separator', {})} />}
|
|
166
165
|
</Fragment>
|
|
167
166
|
))}
|
|
168
167
|
</ul>
|
|
@@ -185,7 +184,7 @@ const MenuGroup = ({ group, currentItem, onSelect }: MenuGroupProps) => {
|
|
|
185
184
|
return (
|
|
186
185
|
<>
|
|
187
186
|
{group.label && (
|
|
188
|
-
<div className={tx('menu.groupLabel',
|
|
187
|
+
<div className={tx('menu.groupLabel', {})}>
|
|
189
188
|
<span>{toLocalizedString(group.label, t)}</span>
|
|
190
189
|
</div>
|
|
191
190
|
)}
|
|
@@ -221,11 +220,7 @@ const MenuItem = ({ item, current, onSelect }: MenuItemProps) => {
|
|
|
221
220
|
const handleSelect = useCallback(() => onSelect?.(item), [item, onSelect]);
|
|
222
221
|
|
|
223
222
|
return (
|
|
224
|
-
<li
|
|
225
|
-
ref={listRef}
|
|
226
|
-
className={tx('menu.item', 'menu__item--exotic-unfocusable', {}, [current && 'bg-hoverSurface'])}
|
|
227
|
-
onClick={handleSelect}
|
|
228
|
-
>
|
|
223
|
+
<li ref={listRef} className={tx('menu.item', {}, [current && 'bg-hover-surface'])} onClick={handleSelect}>
|
|
229
224
|
{item.icon && <Icon icon={item.icon} size={5} />}
|
|
230
225
|
<span className='grow truncate'>{toLocalizedString(item.label, t)}</span>
|
|
231
226
|
</li>
|
|
@@ -108,7 +108,13 @@ export const useEditorMenu = ({
|
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
const handleSelect = useCallback<NonNullable<UseEditorMenu['onSelect']>>(({ view, item }) => {
|
|
111
|
+
// Delete trigger range (e.g., "/" and any typed filter text).
|
|
112
|
+
const { range } = view.state.field(popoverStateField) ?? {};
|
|
113
|
+
if (range) {
|
|
114
|
+
view.dispatch({ changes: { from: range.from, to: range.to, insert: '' } });
|
|
115
|
+
}
|
|
111
116
|
void item.onSelect?.({ view, head: view.state.selection.main.head });
|
|
117
|
+
view.focus();
|
|
112
118
|
}, []);
|
|
113
119
|
|
|
114
120
|
const handleCancel = useCallback<NonNullable<UseEditorMenu['onCancel']>>(({ view }) => {
|
|
@@ -32,16 +32,16 @@ export const EditorPreviewProvider = ({ children, onLookup }: EditorPreviewProvi
|
|
|
32
32
|
|
|
33
33
|
const handleActivate = useCallback(
|
|
34
34
|
(event: DxAnchorActivate) => {
|
|
35
|
-
const {
|
|
35
|
+
const { dxn, label, trigger } = event;
|
|
36
36
|
setValue((value) => ({
|
|
37
37
|
...value,
|
|
38
|
-
link: { label,
|
|
38
|
+
link: { label, dxn },
|
|
39
39
|
pending: true,
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
|
-
triggerRef.current =
|
|
42
|
+
triggerRef.current = trigger;
|
|
43
43
|
queueMicrotask(() => setOpen(true));
|
|
44
|
-
void onLookup?.({ label,
|
|
44
|
+
void onLookup?.({ label, dxn }).then((target) =>
|
|
45
45
|
setValue((value) => ({
|
|
46
46
|
...value,
|
|
47
47
|
target: target ?? undefined,
|
|
@@ -68,9 +68,7 @@ export const EditorPreviewProvider = ({ children, onLookup }: EditorPreviewProvi
|
|
|
68
68
|
<EditorPreviewContextProvider pending={value.pending} link={value.link} target={value.target}>
|
|
69
69
|
<Popover.Root open={open} onOpenChange={setOpen}>
|
|
70
70
|
<Popover.VirtualTrigger virtualRef={triggerRef as unknown as RefObject<HTMLButtonElement>} />
|
|
71
|
-
|
|
72
|
-
{/* Content */}
|
|
73
|
-
<div ref={setRoot} role='none' className='contents'>
|
|
71
|
+
<div role='none' className='contents' ref={setRoot}>
|
|
74
72
|
{children}
|
|
75
73
|
</div>
|
|
76
74
|
</Popover.Root>
|
|
@@ -8,14 +8,7 @@ import React, { memo, useMemo } from 'react';
|
|
|
8
8
|
|
|
9
9
|
import { type Node } from '@dxos/app-graph';
|
|
10
10
|
import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
|
|
11
|
-
import {
|
|
12
|
-
type ActionGraphProps,
|
|
13
|
-
type MenuAction,
|
|
14
|
-
MenuProvider,
|
|
15
|
-
ToolbarMenu,
|
|
16
|
-
createGapSeparator,
|
|
17
|
-
useMenuActions,
|
|
18
|
-
} from '@dxos/react-ui-menu';
|
|
11
|
+
import { type ActionGraphProps, Menu, type MenuAction, MenuBuilder, useMenuActions } from '@dxos/react-ui-menu';
|
|
19
12
|
import { type EditorViewMode } from '@dxos/ui-editor';
|
|
20
13
|
|
|
21
14
|
import { createLists } from './actions';
|
|
@@ -55,15 +48,14 @@ export type EditorToolbarProps = ThemedClassName<
|
|
|
55
48
|
} & (EditorToolbarActionGraphProps & EditorToolbarFeatureFlags)
|
|
56
49
|
>;
|
|
57
50
|
|
|
58
|
-
// TODO(burdon): Remove role dependency.
|
|
59
51
|
export const EditorToolbar = memo(({ classNames, role, attendableId, onAction, ...props }: EditorToolbarProps) => {
|
|
60
52
|
const menuProps = useEditorToolbarActionGraph(props);
|
|
61
53
|
|
|
62
54
|
return (
|
|
63
55
|
<ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
</
|
|
56
|
+
<Menu.Root {...menuProps} attendableId={attendableId} onAction={onAction}>
|
|
57
|
+
<Menu.Toolbar classNames={classNames} textBlockWidth />
|
|
58
|
+
</Menu.Root>
|
|
67
59
|
</ElevationProvider>
|
|
68
60
|
);
|
|
69
61
|
});
|
|
@@ -74,6 +66,7 @@ type ToolbarActionsProps = Pick<EditorToolbarActionGraphProps, 'state' | 'getVie
|
|
|
74
66
|
// TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
|
|
75
67
|
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
|
76
68
|
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
|
69
|
+
// TODO(burdon): Some actions should toggle the state (e.g., toggle bullets on/off depending on the current state).
|
|
77
70
|
const useEditorToolbarActionGraph = ({ state, getView, customActions, ...features }: ToolbarActionsProps) => {
|
|
78
71
|
const menuCreator = useMemo(
|
|
79
72
|
() => createToolbarActions({ state, getView, customActions, ...features }),
|
|
@@ -101,48 +94,39 @@ const createToolbarActions = ({
|
|
|
101
94
|
...features
|
|
102
95
|
}: ToolbarActionsProps): Atom.Atom<ActionGraphProps> => {
|
|
103
96
|
return Atom.make((get) => {
|
|
104
|
-
const graph: ActionGraphProps = {
|
|
105
|
-
nodes: [],
|
|
106
|
-
edges: [],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// TODO(burdon): Builder pattern?
|
|
110
|
-
const addSubGraph = (graph: ActionGraphProps, subGraph: ActionGraphProps) => {
|
|
111
|
-
graph.nodes.push(...subGraph.nodes);
|
|
112
|
-
graph.edges.push(...subGraph.edges);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
97
|
// Subscribe to state changes.
|
|
116
98
|
const stateSnapshot = get(state);
|
|
117
99
|
|
|
100
|
+
const builder = MenuBuilder.make();
|
|
101
|
+
|
|
118
102
|
if (features?.showHeadings ?? true) {
|
|
119
|
-
|
|
103
|
+
builder.subgraph(createHeadings(stateSnapshot, getView));
|
|
120
104
|
}
|
|
121
105
|
if (features?.showFormatting ?? true) {
|
|
122
|
-
|
|
106
|
+
builder.subgraph(createFormatting(stateSnapshot, getView));
|
|
123
107
|
}
|
|
124
108
|
if (features?.showLists ?? true) {
|
|
125
|
-
|
|
109
|
+
builder.subgraph(createLists(stateSnapshot, getView));
|
|
126
110
|
}
|
|
127
111
|
if (features?.showBlocks ?? true) {
|
|
128
|
-
|
|
112
|
+
builder.subgraph(createBlocks(stateSnapshot, getView));
|
|
129
113
|
}
|
|
130
114
|
if (features?.onImageUpload) {
|
|
131
|
-
|
|
115
|
+
builder.subgraph(createImageUpload(features.onImageUpload!));
|
|
132
116
|
}
|
|
133
117
|
|
|
134
|
-
|
|
118
|
+
builder.separator('gap');
|
|
135
119
|
|
|
136
120
|
if (customActions) {
|
|
137
|
-
|
|
121
|
+
builder.subgraph(get(customActions));
|
|
138
122
|
}
|
|
139
123
|
if (features?.showSearch ?? true) {
|
|
140
|
-
|
|
124
|
+
builder.subgraph(createSearch(getView));
|
|
141
125
|
}
|
|
142
126
|
if (features?.onViewModeChange) {
|
|
143
|
-
|
|
127
|
+
builder.subgraph(createViewMode(stateSnapshot, features.onViewModeChange!));
|
|
144
128
|
}
|
|
145
129
|
|
|
146
|
-
return
|
|
130
|
+
return builder.build();
|
|
147
131
|
});
|
|
148
132
|
};
|
|
@@ -31,8 +31,8 @@ export const createLists = (state: EditorToolbarState, getView: () => EditorView
|
|
|
31
31
|
return {
|
|
32
32
|
nodes: [listGroupAction as Node.NodeArg<any>, ...listActionsMap],
|
|
33
33
|
edges: [
|
|
34
|
-
{ source: 'root', target: 'list' },
|
|
35
|
-
...listActionsMap.map(({ id }) => ({ source: listGroupAction.id, target: id })),
|
|
34
|
+
{ source: 'root', target: 'list', relation: 'child' },
|
|
35
|
+
...listActionsMap.map(({ id }) => ({ source: listGroupAction.id, target: id, relation: 'child' })),
|
|
36
36
|
],
|
|
37
37
|
};
|
|
38
38
|
};
|
|
@@ -52,8 +52,8 @@ export const createBlocks = (state: EditorToolbarState, getView: () => EditorVie
|
|
|
52
52
|
return {
|
|
53
53
|
nodes: [blockGroupAction as Node.NodeArg<any>, ...blockActions],
|
|
54
54
|
edges: [
|
|
55
|
-
{ source: 'root', target: 'block' },
|
|
56
|
-
...blockActions.map(({ id }) => ({ source: blockGroupAction.id, target: id })),
|
|
55
|
+
{ source: 'root', target: 'block', relation: 'child' },
|
|
56
|
+
...blockActions.map(({ id }) => ({ source: blockGroupAction.id, target: id, relation: 'child' })),
|
|
57
57
|
],
|
|
58
58
|
};
|
|
59
59
|
};
|
|
@@ -58,8 +58,8 @@ export const createFormatting = (state: EditorToolbarState, getView: () => Edito
|
|
|
58
58
|
return {
|
|
59
59
|
nodes: [formattingGroupAction as Node.NodeArg<any>, ...formattingActions],
|
|
60
60
|
edges: [
|
|
61
|
-
{ source: 'root', target: 'formatting' },
|
|
62
|
-
...formattingActions.map(({ id }) => ({ source: formattingGroupAction.id, target: id })),
|
|
61
|
+
{ source: 'root', target: 'formatting', relation: 'child' },
|
|
62
|
+
...formattingActions.map(({ id }) => ({ source: formattingGroupAction.id, target: id, relation: 'child' })),
|
|
63
63
|
],
|
|
64
64
|
};
|
|
65
65
|
};
|
|
@@ -28,13 +28,13 @@ const createHeadingGroupAction = (value: string) =>
|
|
|
28
28
|
|
|
29
29
|
const createHeadingActions = (currentLevel: string, getView: () => EditorView) =>
|
|
30
30
|
Object.entries({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
38
|
}).map(([levelStr, icon]) => {
|
|
39
39
|
const level = parseInt(levelStr);
|
|
40
40
|
return createEditorAction(
|
|
@@ -61,8 +61,8 @@ export const createHeadings = (state: EditorToolbarState, getView: () => EditorV
|
|
|
61
61
|
return {
|
|
62
62
|
nodes: [headingGroupAction as Node.NodeArg<any>, ...headingActions],
|
|
63
63
|
edges: [
|
|
64
|
-
{ source: 'root', target: 'heading' },
|
|
65
|
-
...headingActions.map(({ id }) => ({ source: headingGroupAction.id, target: id })),
|
|
64
|
+
{ source: 'root', target: 'heading', relation: 'child' },
|
|
65
|
+
...headingActions.map(({ id }) => ({ source: headingGroupAction.id, target: id, relation: 'child' })),
|
|
66
66
|
],
|
|
67
67
|
};
|
|
68
68
|
};
|
|
@@ -20,8 +20,8 @@ export const createImageUpload = (
|
|
|
20
20
|
onImageUpload: () => void,
|
|
21
21
|
): {
|
|
22
22
|
nodes: Node.NodeArg<any>[];
|
|
23
|
-
edges: Array<{ source: string; target: string }>;
|
|
23
|
+
edges: Array<{ source: string; target: string; relation: 'child' }>;
|
|
24
24
|
} => ({
|
|
25
25
|
nodes: [createImageUploadAction(onImageUpload)],
|
|
26
|
-
edges: [{ source: 'root', target: 'image' }],
|
|
26
|
+
edges: [{ source: 'root', target: 'image', relation: 'child' }],
|
|
27
27
|
});
|
|
@@ -23,8 +23,8 @@ export const createSearch = (
|
|
|
23
23
|
getView: () => EditorView,
|
|
24
24
|
): {
|
|
25
25
|
nodes: Node.NodeArg<any>[];
|
|
26
|
-
edges: Array<{ source: string; target: string }>;
|
|
26
|
+
edges: Array<{ source: string; target: string; relation: 'child' }>;
|
|
27
27
|
} => ({
|
|
28
28
|
nodes: [createSearchAction(getView)],
|
|
29
|
-
edges: [{ source: 'root', target: 'search' }],
|
|
29
|
+
edges: [{ source: 'root', target: 'search', relation: 'child' }],
|
|
30
30
|
});
|
|
@@ -48,8 +48,8 @@ export const createViewMode = (state: EditorToolbarState, onViewModeChange: (mod
|
|
|
48
48
|
return {
|
|
49
49
|
nodes: [viewModeGroupAction as Node.NodeArg<any>, ...viewModeActions],
|
|
50
50
|
edges: [
|
|
51
|
-
{ source: 'root', target: 'viewMode' },
|
|
52
|
-
...viewModeActions.map(({ id }) => ({ source: viewModeGroupAction.id, target: id })),
|
|
51
|
+
{ source: 'root', target: 'viewMode', relation: 'child' },
|
|
52
|
+
...viewModeActions.map(({ id }) => ({ source: viewModeGroupAction.id, target: id, relation: 'child' })),
|
|
53
53
|
],
|
|
54
54
|
};
|
|
55
55
|
};
|