@dxos/react-ui-editor 0.8.4-main.ef1bc66f44 → 0.8.4-main.effb148878
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/index.mjs +796 -755
- 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 +796 -755
- 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 -18
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -18
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -18
- 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 +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 -8
- 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 -19
- 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 +25 -24
- package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts +2 -2
- 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 +3 -3
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +4 -4
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +3 -2
- 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 +2 -5
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +77 -68
- 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 +19 -24
- package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
- package/src/components/EditorMenuProvider/popover.ts +3 -1
- package/src/components/EditorMenuProvider/useEditorMenu.ts +8 -1
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -1
- package/src/components/EditorToolbar/EditorToolbar.tsx +31 -65
- 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 +18 -16
- package/src/stories/Comments.stories.tsx +6 -6
- package/src/stories/EditorToolbar.stories.tsx +37 -65
- package/src/stories/Experimental.stories.tsx +12 -12
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +4 -5
- package/src/stories/Popover.stories.tsx +10 -11
- package/src/stories/Preview.stories.tsx +51 -43
- package/src/stories/Tags.stories.tsx +5 -5
- package/src/stories/TextEditor.stories.tsx +2 -2
- package/src/stories/Theme.stories.tsx +4 -4
- package/src/stories/components/EditorStory.tsx +19 -12
- package/src/stories/components/util.tsx +49 -50
- package/src/translations.ts +29 -24
- package/src/util/react.tsx +4 -13
- 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 -24
- 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
|
@@ -1,309 +1,13 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
|
|
3
|
-
// src/translations.ts
|
|
4
|
-
var translationKey = "@dxos/react-ui-editor";
|
|
5
|
-
var translations = [
|
|
6
|
-
{
|
|
7
|
-
"en-US": {
|
|
8
|
-
[translationKey]: {
|
|
9
|
-
"strong label": "Bold",
|
|
10
|
-
"emphasis label": "Italics",
|
|
11
|
-
"strikethrough label": "Strikethrough",
|
|
12
|
-
"code label": "Code",
|
|
13
|
-
"link label": "Link",
|
|
14
|
-
"list-bullet label": "Bullet list",
|
|
15
|
-
"list-ordered label": "Numbered list",
|
|
16
|
-
"list-task label": "Task list",
|
|
17
|
-
"blockquote label": "Block quote",
|
|
18
|
-
"codeblock label": "Code block",
|
|
19
|
-
"comment label": "Create comment",
|
|
20
|
-
"selection overlaps existing comment label": "Selection overlaps existing comment",
|
|
21
|
-
"select text to comment label": "Select text to comment",
|
|
22
|
-
"image label": "Insert image",
|
|
23
|
-
"table label": "Create table",
|
|
24
|
-
"heading label": "Heading level",
|
|
25
|
-
"heading level label_zero": "Paragraph",
|
|
26
|
-
"heading level label_one": "Heading level {{count}}",
|
|
27
|
-
"heading level label_other": "Heading level {{count}}",
|
|
28
|
-
"search label": "Search",
|
|
29
|
-
"view mode label": "Editor view",
|
|
30
|
-
"preview mode label": "Markdown",
|
|
31
|
-
"readonly mode label": "Read only",
|
|
32
|
-
"source mode label": "Plain text"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
];
|
|
37
|
-
|
|
38
3
|
// src/components/Editor/Editor.tsx
|
|
4
|
+
import { Atom as Atom2 } from "@effect-atom/atom-react";
|
|
39
5
|
import { createContext } from "@radix-ui/react-context";
|
|
40
6
|
import React4, { forwardRef as forwardRef2, useCallback as useCallback4, useImperativeHandle as useImperativeHandle2, useMemo as useMemo5, useState as useState4 } from "react";
|
|
41
7
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
42
8
|
import { mx as mx2 } from "@dxos/ui-theme";
|
|
43
9
|
import { isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
44
10
|
|
|
45
|
-
// src/components/EditorContent/controller.ts
|
|
46
|
-
var noopController = {
|
|
47
|
-
get view() {
|
|
48
|
-
return null;
|
|
49
|
-
},
|
|
50
|
-
getText: () => "",
|
|
51
|
-
setText: () => {
|
|
52
|
-
},
|
|
53
|
-
focus: () => {
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
var createEditorController = (view) => {
|
|
57
|
-
return {
|
|
58
|
-
get view() {
|
|
59
|
-
return view;
|
|
60
|
-
},
|
|
61
|
-
getText: () => {
|
|
62
|
-
return view?.state.doc.toString() ?? "";
|
|
63
|
-
},
|
|
64
|
-
setText: (text, focus) => {
|
|
65
|
-
view?.dispatch({
|
|
66
|
-
changes: {
|
|
67
|
-
from: 0,
|
|
68
|
-
to: view?.state.doc.length ?? 0,
|
|
69
|
-
insert: text
|
|
70
|
-
},
|
|
71
|
-
selection: {
|
|
72
|
-
anchor: text.length,
|
|
73
|
-
head: text.length
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
if (focus) {
|
|
77
|
-
view?.focus();
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
focus: () => view?.focus()
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// src/components/EditorContent/EditorContent.tsx
|
|
85
|
-
import { Transaction } from "@codemirror/state";
|
|
86
|
-
import { EditorView as EditorView2 } from "@codemirror/view";
|
|
87
|
-
import React, { forwardRef, useEffect as useEffect2, useImperativeHandle } from "react";
|
|
88
|
-
import { initialSync } from "@dxos/ui-editor";
|
|
89
|
-
import { mx } from "@dxos/ui-theme";
|
|
90
|
-
|
|
91
|
-
// src/hooks/useTextEditor.ts
|
|
92
|
-
import { EditorState } from "@codemirror/state";
|
|
93
|
-
import { EditorView } from "@codemirror/view";
|
|
94
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
95
|
-
import { log } from "@dxos/log";
|
|
96
|
-
import { createEditorStateTransaction, debugDispatcher, documentId, modalStateField } from "@dxos/ui-editor";
|
|
97
|
-
import { getProviderValue, isTruthy } from "@dxos/util";
|
|
98
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
99
|
-
var instanceCount = 0;
|
|
100
|
-
var useTextEditor = (props = {}, deps = []) => {
|
|
101
|
-
const { id, doc, initialValue, extensions, autoFocus, scrollTo, selection, selectionEnd, debug } = useMemo(() => getProviderValue(props), deps ?? []);
|
|
102
|
-
const [instanceId] = useState(() => `text-editor-${++instanceCount}`);
|
|
103
|
-
const [view, setView] = useState(null);
|
|
104
|
-
const parentRef = useRef(null);
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
let view2 = null;
|
|
107
|
-
if (parentRef.current) {
|
|
108
|
-
log("create", {
|
|
109
|
-
id,
|
|
110
|
-
instanceId,
|
|
111
|
-
doc: initialValue?.length ?? 0
|
|
112
|
-
}, {
|
|
113
|
-
F: __dxlog_file,
|
|
114
|
-
L: 75,
|
|
115
|
-
S: void 0,
|
|
116
|
-
C: (f, a) => f(...a)
|
|
117
|
-
});
|
|
118
|
-
let initialSelection;
|
|
119
|
-
if (selection?.anchor && initialValue?.length) {
|
|
120
|
-
if (selection.anchor <= initialValue.length && (selection?.head ?? 0) <= initialValue.length) {
|
|
121
|
-
initialSelection = selection;
|
|
122
|
-
}
|
|
123
|
-
} else if (selectionEnd && selection === void 0) {
|
|
124
|
-
const index = initialValue?.indexOf("\n");
|
|
125
|
-
const anchor = !index || index === -1 ? 0 : index;
|
|
126
|
-
initialSelection = {
|
|
127
|
-
anchor
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
const state = EditorState.create({
|
|
131
|
-
doc: doc ?? initialValue,
|
|
132
|
-
// selection: initialSelection,
|
|
133
|
-
extensions: [
|
|
134
|
-
id && documentId.of(id),
|
|
135
|
-
extensions,
|
|
136
|
-
// NOTE: This doesn't catch errors in keymap functions.
|
|
137
|
-
EditorView.exceptionSink.of((err) => {
|
|
138
|
-
log.catch(err, void 0, {
|
|
139
|
-
F: __dxlog_file,
|
|
140
|
-
L: 97,
|
|
141
|
-
S: void 0,
|
|
142
|
-
C: (f, a) => f(...a)
|
|
143
|
-
});
|
|
144
|
-
})
|
|
145
|
-
].filter(isTruthy)
|
|
146
|
-
});
|
|
147
|
-
view2 = new EditorView({
|
|
148
|
-
parent: parentRef.current,
|
|
149
|
-
state,
|
|
150
|
-
scrollTo: scrollTo ? EditorView.scrollIntoView(scrollTo, {
|
|
151
|
-
yMargin: 96
|
|
152
|
-
}) : void 0,
|
|
153
|
-
dispatchTransactions: debug ? debugDispatcher : void 0
|
|
154
|
-
});
|
|
155
|
-
if (selectionEnd && !initialSelection) {
|
|
156
|
-
const { to } = view2.state.doc.lineAt(0);
|
|
157
|
-
if (to) {
|
|
158
|
-
view2.dispatch({
|
|
159
|
-
selection: {
|
|
160
|
-
anchor: to
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
setView(view2);
|
|
166
|
-
}
|
|
167
|
-
return () => {
|
|
168
|
-
log("destroy", {
|
|
169
|
-
id
|
|
170
|
-
}, {
|
|
171
|
-
F: __dxlog_file,
|
|
172
|
-
L: 122,
|
|
173
|
-
S: void 0,
|
|
174
|
-
C: (f, a) => f(...a)
|
|
175
|
-
});
|
|
176
|
-
view2?.destroy();
|
|
177
|
-
};
|
|
178
|
-
}, deps);
|
|
179
|
-
useEffect(() => {
|
|
180
|
-
if (view) {
|
|
181
|
-
if (scrollTo || selection) {
|
|
182
|
-
if (selection && selection.anchor > view.state.doc.length) {
|
|
183
|
-
log.warn("invalid selection", {
|
|
184
|
-
length: view.state.doc.length,
|
|
185
|
-
scrollTo,
|
|
186
|
-
selection
|
|
187
|
-
}, {
|
|
188
|
-
F: __dxlog_file,
|
|
189
|
-
L: 131,
|
|
190
|
-
S: void 0,
|
|
191
|
-
C: (f, a) => f(...a)
|
|
192
|
-
});
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
view.dispatch(createEditorStateTransaction({
|
|
196
|
-
scrollTo,
|
|
197
|
-
selection
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}, [
|
|
202
|
-
view,
|
|
203
|
-
scrollTo,
|
|
204
|
-
selection
|
|
205
|
-
]);
|
|
206
|
-
useEffect(() => {
|
|
207
|
-
if (view && autoFocus) {
|
|
208
|
-
view.focus();
|
|
209
|
-
}
|
|
210
|
-
}, [
|
|
211
|
-
autoFocus,
|
|
212
|
-
view
|
|
213
|
-
]);
|
|
214
|
-
const handleKeyDown = useCallback((event) => {
|
|
215
|
-
const { key, target, currentTarget } = event;
|
|
216
|
-
switch (key) {
|
|
217
|
-
case "Escape": {
|
|
218
|
-
const modal = view?.state.field(modalStateField, false);
|
|
219
|
-
if (modal) {
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const element = view?.contentDOM.closest('[tabindex="0"]');
|
|
223
|
-
element?.focus();
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "Enter": {
|
|
227
|
-
event.preventDefault();
|
|
228
|
-
if (target === currentTarget) {
|
|
229
|
-
view?.focus();
|
|
230
|
-
}
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}, [
|
|
235
|
-
view
|
|
236
|
-
]);
|
|
237
|
-
return {
|
|
238
|
-
parentRef,
|
|
239
|
-
view,
|
|
240
|
-
focusAttributes: {
|
|
241
|
-
tabIndex: 0,
|
|
242
|
-
onKeyDown: handleKeyDown
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// src/components/EditorContent/EditorContent.tsx
|
|
248
|
-
var EditorContent = /* @__PURE__ */ forwardRef(({ classNames, id, extensions, selectionEnd, focusable = true, value, onChange, ...props }, forwardedRef) => {
|
|
249
|
-
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
250
|
-
id,
|
|
251
|
-
initialValue: value,
|
|
252
|
-
selectionEnd,
|
|
253
|
-
extensions: [
|
|
254
|
-
extensions ?? [],
|
|
255
|
-
EditorView2.updateListener.of(({ view: view2, docChanged, transactions }) => {
|
|
256
|
-
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
|
|
257
|
-
if (!isInitialSync && docChanged) {
|
|
258
|
-
onChange?.(view2.state.doc.toString());
|
|
259
|
-
}
|
|
260
|
-
})
|
|
261
|
-
],
|
|
262
|
-
...props
|
|
263
|
-
}), [
|
|
264
|
-
id,
|
|
265
|
-
extensions,
|
|
266
|
-
selectionEnd,
|
|
267
|
-
onChange
|
|
268
|
-
]);
|
|
269
|
-
useImperativeHandle(forwardedRef, () => {
|
|
270
|
-
return createEditorController(view);
|
|
271
|
-
}, [
|
|
272
|
-
id,
|
|
273
|
-
view
|
|
274
|
-
]);
|
|
275
|
-
useEffect2(() => {
|
|
276
|
-
requestAnimationFrame(() => {
|
|
277
|
-
view?.dispatch({
|
|
278
|
-
annotations: initialSync,
|
|
279
|
-
changes: value ? [
|
|
280
|
-
{
|
|
281
|
-
from: 0,
|
|
282
|
-
to: view?.state.doc.length ?? 0,
|
|
283
|
-
insert: value ?? ""
|
|
284
|
-
}
|
|
285
|
-
] : [],
|
|
286
|
-
selection: selectionEnd ? {
|
|
287
|
-
anchor: view?.state.doc.length ?? 0
|
|
288
|
-
} : void 0
|
|
289
|
-
});
|
|
290
|
-
if (selectionEnd) {
|
|
291
|
-
view?.focus();
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
}, [
|
|
295
|
-
view,
|
|
296
|
-
value,
|
|
297
|
-
selectionEnd
|
|
298
|
-
]);
|
|
299
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
300
|
-
role: "none",
|
|
301
|
-
className: mx("is-full outline-none focus:border-accentSurface focus-within:border-neutralFocusIndicator", classNames),
|
|
302
|
-
ref: parentRef,
|
|
303
|
-
...focusable ? focusAttributes : {}
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
|
|
307
11
|
// src/components/EditorMenuProvider/menu.ts
|
|
308
12
|
import { insertAtCursor } from "@dxos/ui-editor";
|
|
309
13
|
var getMenuItem = (groups, id) => {
|
|
@@ -340,9 +44,9 @@ import { insertAtLineStart } from "@dxos/ui-editor";
|
|
|
340
44
|
|
|
341
45
|
// src/components/EditorMenuProvider/popover.ts
|
|
342
46
|
import { Prec, RangeSetBuilder, StateEffect, StateField } from "@codemirror/state";
|
|
343
|
-
import { Decoration, EditorView
|
|
344
|
-
import { modalStateField
|
|
345
|
-
import { isNonNullable, isTruthy
|
|
47
|
+
import { Decoration, EditorView, ViewPlugin, keymap } from "@codemirror/view";
|
|
48
|
+
import { modalStateField, placeholder } from "@dxos/ui-editor";
|
|
49
|
+
import { isNonNullable, isTruthy } from "@dxos/util";
|
|
346
50
|
var DELIMITERS = [
|
|
347
51
|
" ",
|
|
348
52
|
":"
|
|
@@ -353,15 +57,16 @@ var popover = (options = {}) => {
|
|
|
353
57
|
popoverStateField,
|
|
354
58
|
popoverTriggerListener(options),
|
|
355
59
|
popoverAnchorDecoration(options),
|
|
356
|
-
|
|
60
|
+
modalStateField,
|
|
357
61
|
options.trigger && placeholder({
|
|
358
62
|
// TODO(burdon): Translations.
|
|
359
63
|
content: `Press '${Array.isArray(options.trigger) ? options.trigger[0] : options.trigger}' for commands`,
|
|
64
|
+
focusOnly: true,
|
|
360
65
|
...options.placeholder
|
|
361
66
|
})
|
|
362
|
-
].filter(
|
|
67
|
+
].filter(isTruthy);
|
|
363
68
|
};
|
|
364
|
-
var popoverTriggerListener = (options) =>
|
|
69
|
+
var popoverTriggerListener = (options) => EditorView.updateListener.of(({ view, docChanged }) => {
|
|
365
70
|
const { range: activeRange, trigger } = view.state.field(popoverStateField) ?? {};
|
|
366
71
|
if (!activeRange) {
|
|
367
72
|
return;
|
|
@@ -506,7 +211,7 @@ var popoverKeymap = (options) => {
|
|
|
506
211
|
return false;
|
|
507
212
|
}
|
|
508
213
|
}
|
|
509
|
-
].filter(
|
|
214
|
+
].filter(isTruthy));
|
|
510
215
|
};
|
|
511
216
|
var popoverAnchorDecoration = (options) => {
|
|
512
217
|
return ViewPlugin.fromClass(class {
|
|
@@ -701,36 +406,28 @@ var linkSlashCommands = {
|
|
|
701
406
|
|
|
702
407
|
// src/components/EditorMenuProvider/EditorMenuProvider.tsx
|
|
703
408
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
704
|
-
import
|
|
409
|
+
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
|
705
410
|
import { addEventListener } from "@dxos/async";
|
|
706
411
|
import { invariant } from "@dxos/invariant";
|
|
707
|
-
import { DX_ANCHOR_ACTIVATE, Icon, Popover, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
708
|
-
var
|
|
412
|
+
import { DX_ANCHOR_ACTIVATE, Icon, Popover, ScrollArea, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
413
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/EditorMenuProvider/EditorMenuProvider.tsx";
|
|
709
414
|
var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp, defaultOpen, numItems = 8, onOpenChange, onActivate, onSelect, onCancel }) => {
|
|
710
415
|
const { tx } = useThemeContext();
|
|
711
|
-
const triggerRef =
|
|
416
|
+
const triggerRef = useRef(null);
|
|
712
417
|
const viewRef = useDynamicRef(view);
|
|
713
418
|
const [open, setOpen] = useControllableState({
|
|
714
419
|
prop: openProp,
|
|
715
420
|
defaultProp: defaultOpen,
|
|
716
421
|
onChange: (open2) => {
|
|
717
|
-
invariant(viewRef.current, void 0, {
|
|
718
|
-
F: __dxlog_file2,
|
|
719
|
-
L: 65,
|
|
720
|
-
S: void 0,
|
|
721
|
-
A: [
|
|
722
|
-
"viewRef.current",
|
|
723
|
-
""
|
|
724
|
-
]
|
|
725
|
-
});
|
|
422
|
+
invariant(viewRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 21, S: void 0, A: ["viewRef.current", ""] });
|
|
726
423
|
onOpenChange?.({
|
|
727
424
|
view: viewRef.current,
|
|
728
425
|
open: open2
|
|
729
426
|
});
|
|
730
427
|
}
|
|
731
428
|
});
|
|
732
|
-
const [root, setRoot] =
|
|
733
|
-
|
|
429
|
+
const [root, setRoot] = useState(null);
|
|
430
|
+
useEffect(() => {
|
|
734
431
|
if (!root) {
|
|
735
432
|
return;
|
|
736
433
|
}
|
|
@@ -755,16 +452,8 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
|
|
|
755
452
|
root,
|
|
756
453
|
onActivate
|
|
757
454
|
]);
|
|
758
|
-
const handleSelect =
|
|
759
|
-
invariant(viewRef.current, void 0, {
|
|
760
|
-
F: __dxlog_file2,
|
|
761
|
-
L: 100,
|
|
762
|
-
S: void 0,
|
|
763
|
-
A: [
|
|
764
|
-
"viewRef.current",
|
|
765
|
-
""
|
|
766
|
-
]
|
|
767
|
-
});
|
|
455
|
+
const handleSelect = useCallback((item) => {
|
|
456
|
+
invariant(viewRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0, A: ["viewRef.current", ""] });
|
|
768
457
|
onSelect?.({
|
|
769
458
|
view: viewRef.current,
|
|
770
459
|
item
|
|
@@ -774,62 +463,63 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
|
|
|
774
463
|
onSelect
|
|
775
464
|
]);
|
|
776
465
|
const menuGroups = groups?.filter((group) => group.items.length > 0) ?? [];
|
|
777
|
-
return /* @__PURE__ */
|
|
466
|
+
return /* @__PURE__ */ React.createElement(Popover.Root, {
|
|
778
467
|
modal: false,
|
|
779
468
|
open,
|
|
780
469
|
onOpenChange: setOpen
|
|
781
|
-
}, /* @__PURE__ */
|
|
470
|
+
}, /* @__PURE__ */ React.createElement(Popover.VirtualTrigger, {
|
|
782
471
|
virtualRef: triggerRef
|
|
783
|
-
}), /* @__PURE__ */
|
|
472
|
+
}), /* @__PURE__ */ React.createElement(Popover.Portal, null, /* @__PURE__ */ React.createElement(Popover.Content, {
|
|
784
473
|
align: "start",
|
|
785
|
-
classNames:
|
|
786
|
-
|
|
787
|
-
}, [
|
|
788
|
-
"overflow-y-auto",
|
|
474
|
+
classNames: [
|
|
475
|
+
"flex flex-col",
|
|
789
476
|
!menuGroups.length && "hidden"
|
|
790
|
-
]
|
|
477
|
+
],
|
|
791
478
|
style: {
|
|
792
479
|
maxBlockSize: 36 * numItems + 10
|
|
793
480
|
},
|
|
794
|
-
|
|
795
|
-
* NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
796
|
-
*/
|
|
481
|
+
// NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
797
482
|
onEscapeKeyDown: () => {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
483
|
+
const currentView = viewRef.current;
|
|
484
|
+
if (currentView) {
|
|
485
|
+
onCancel?.({
|
|
486
|
+
view: currentView
|
|
487
|
+
});
|
|
488
|
+
}
|
|
801
489
|
},
|
|
802
490
|
onOpenAutoFocus: (event) => event.preventDefault()
|
|
803
|
-
}, /* @__PURE__ */
|
|
804
|
-
|
|
805
|
-
|
|
491
|
+
}, /* @__PURE__ */ React.createElement(Popover.Viewport, {
|
|
492
|
+
asChild: true,
|
|
493
|
+
classNames: "dx-container"
|
|
494
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Root, {
|
|
495
|
+
thin: true
|
|
496
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React.createElement(Menu, {
|
|
806
497
|
groups: menuGroups,
|
|
807
498
|
currentItem,
|
|
808
499
|
onSelect: handleSelect
|
|
809
|
-
})), /* @__PURE__ */
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
className: "contents"
|
|
500
|
+
})))), /* @__PURE__ */ React.createElement(Popover.Arrow, null))), /* @__PURE__ */ React.createElement("div", {
|
|
501
|
+
className: "contents",
|
|
502
|
+
ref: setRoot
|
|
813
503
|
}, children));
|
|
814
504
|
};
|
|
815
505
|
var Menu = ({ groups, currentItem, onSelect }) => {
|
|
816
506
|
const { tx } = useThemeContext();
|
|
817
|
-
return /* @__PURE__ */
|
|
507
|
+
return /* @__PURE__ */ React.createElement("ul", null, groups.map((group, index) => /* @__PURE__ */ React.createElement(Fragment, {
|
|
818
508
|
key: group.id
|
|
819
|
-
}, /* @__PURE__ */
|
|
509
|
+
}, /* @__PURE__ */ React.createElement(MenuGroup, {
|
|
820
510
|
group,
|
|
821
511
|
currentItem,
|
|
822
512
|
onSelect
|
|
823
|
-
}), index < groups.length - 1 && /* @__PURE__ */
|
|
824
|
-
className: tx("menu.separator",
|
|
513
|
+
}), index < groups.length - 1 && /* @__PURE__ */ React.createElement("div", {
|
|
514
|
+
className: tx("menu.separator", {})
|
|
825
515
|
}))));
|
|
826
516
|
};
|
|
827
517
|
var MenuGroup = ({ group, currentItem, onSelect }) => {
|
|
828
518
|
const { tx } = useThemeContext();
|
|
829
519
|
const { t } = useTranslation();
|
|
830
|
-
return /* @__PURE__ */
|
|
831
|
-
className: tx("menu.groupLabel",
|
|
832
|
-
}, /* @__PURE__ */
|
|
520
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, group.label && /* @__PURE__ */ React.createElement("div", {
|
|
521
|
+
className: tx("menu.groupLabel", {})
|
|
522
|
+
}, /* @__PURE__ */ React.createElement("span", null, toLocalizedString(group.label, t))), group.items.map((item) => /* @__PURE__ */ React.createElement(MenuItem, {
|
|
833
523
|
key: item.id,
|
|
834
524
|
item,
|
|
835
525
|
current: currentItem === item.id,
|
|
@@ -839,8 +529,8 @@ var MenuGroup = ({ group, currentItem, onSelect }) => {
|
|
|
839
529
|
var MenuItem = ({ item, current, onSelect }) => {
|
|
840
530
|
const { tx } = useThemeContext();
|
|
841
531
|
const { t } = useTranslation();
|
|
842
|
-
const listRef =
|
|
843
|
-
|
|
532
|
+
const listRef = useRef(null);
|
|
533
|
+
useEffect(() => {
|
|
844
534
|
if (current && listRef.current) {
|
|
845
535
|
listRef.current.scrollIntoView({
|
|
846
536
|
behavior: "smooth",
|
|
@@ -850,56 +540,47 @@ var MenuItem = ({ item, current, onSelect }) => {
|
|
|
850
540
|
}, [
|
|
851
541
|
current
|
|
852
542
|
]);
|
|
853
|
-
const handleSelect =
|
|
543
|
+
const handleSelect = useCallback(() => onSelect?.(item), [
|
|
854
544
|
item,
|
|
855
545
|
onSelect
|
|
856
546
|
]);
|
|
857
|
-
return /* @__PURE__ */
|
|
547
|
+
return /* @__PURE__ */ React.createElement("li", {
|
|
858
548
|
ref: listRef,
|
|
859
|
-
className: tx("menu.item",
|
|
860
|
-
current && "bg-
|
|
549
|
+
className: tx("menu.item", {}, [
|
|
550
|
+
current && "bg-hover-surface"
|
|
861
551
|
]),
|
|
862
552
|
onClick: handleSelect
|
|
863
|
-
}, item.icon && /* @__PURE__ */
|
|
864
|
-
icon: item.icon
|
|
865
|
-
|
|
866
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
553
|
+
}, item.icon && /* @__PURE__ */ React.createElement(Icon, {
|
|
554
|
+
icon: item.icon
|
|
555
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
867
556
|
className: "grow truncate"
|
|
868
557
|
}, toLocalizedString(item.label, t)));
|
|
869
558
|
};
|
|
870
559
|
|
|
871
560
|
// src/components/EditorMenuProvider/useEditorMenu.ts
|
|
872
|
-
import { useCallback as
|
|
561
|
+
import { useCallback as useCallback2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
873
562
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
874
563
|
import { modalStateEffect } from "@dxos/ui-editor";
|
|
875
|
-
var
|
|
564
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/EditorMenuProvider/useEditorMenu.ts";
|
|
876
565
|
var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter = true, getMenu }) => {
|
|
877
|
-
const groupsRef =
|
|
878
|
-
const currentRef =
|
|
879
|
-
const [currentItem, setCurrentItem] =
|
|
880
|
-
const [open, setOpen] =
|
|
881
|
-
const [_, refresh] =
|
|
882
|
-
const getMenuOptions =
|
|
566
|
+
const groupsRef = useRef2([]);
|
|
567
|
+
const currentRef = useRef2(null);
|
|
568
|
+
const [currentItem, setCurrentItem] = useState2();
|
|
569
|
+
const [open, setOpen] = useState2(false);
|
|
570
|
+
const [_, refresh] = useState2({});
|
|
571
|
+
const getMenuOptions = useCallback2(async ({ text, trigger: trigger2, ...props }) => {
|
|
883
572
|
const groups = await getMenu?.({
|
|
884
573
|
text,
|
|
885
574
|
trigger: trigger2,
|
|
886
575
|
...props
|
|
887
576
|
}) ?? [];
|
|
888
|
-
return filter ? filterMenuGroups(groups, (item) => text ? item.label.toLowerCase().startsWith(text.toLowerCase()) : true) : groups;
|
|
577
|
+
return filter && trigger2 !== "@" ? filterMenuGroups(groups, (item) => text ? item.label.toLowerCase().startsWith(text.toLowerCase()) : true) : groups;
|
|
889
578
|
}, [
|
|
890
579
|
getMenu,
|
|
891
580
|
filter
|
|
892
581
|
]);
|
|
893
|
-
const handleOpenChange =
|
|
894
|
-
invariant2(view, void 0, {
|
|
895
|
-
F: __dxlog_file3,
|
|
896
|
-
L: 76,
|
|
897
|
-
S: void 0,
|
|
898
|
-
A: [
|
|
899
|
-
"view",
|
|
900
|
-
""
|
|
901
|
-
]
|
|
902
|
-
});
|
|
582
|
+
const handleOpenChange = useCallback2(async ({ view, open: open2 }) => {
|
|
583
|
+
invariant2(view, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 40, S: void 0, A: ["view", ""] });
|
|
903
584
|
setOpen(open2);
|
|
904
585
|
if (!open2) {
|
|
905
586
|
setCurrentItem(void 0);
|
|
@@ -919,7 +600,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
919
600
|
}, [
|
|
920
601
|
getMenuOptions
|
|
921
602
|
]);
|
|
922
|
-
const handleActivate =
|
|
603
|
+
const handleActivate = useCallback2(async ({ view, trigger: trigger2 }) => {
|
|
923
604
|
const item = getMenuItem(groupsRef.current, currentItem);
|
|
924
605
|
if (item) {
|
|
925
606
|
currentRef.current = item;
|
|
@@ -935,13 +616,24 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
935
616
|
open,
|
|
936
617
|
handleOpenChange
|
|
937
618
|
]);
|
|
938
|
-
const handleSelect =
|
|
619
|
+
const handleSelect = useCallback2(({ view, item }) => {
|
|
620
|
+
const { range } = view.state.field(popoverStateField) ?? {};
|
|
621
|
+
if (range) {
|
|
622
|
+
view.dispatch({
|
|
623
|
+
changes: {
|
|
624
|
+
from: range.from,
|
|
625
|
+
to: range.to,
|
|
626
|
+
insert: ""
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
}
|
|
939
630
|
void item.onSelect?.({
|
|
940
631
|
view,
|
|
941
632
|
head: view.state.selection.main.head
|
|
942
633
|
});
|
|
634
|
+
view.focus();
|
|
943
635
|
}, []);
|
|
944
|
-
const handleCancel =
|
|
636
|
+
const handleCancel = useCallback2(({ view }) => {
|
|
945
637
|
const { range, trigger: trigger2 } = view.state.field(popoverStateField) ?? {};
|
|
946
638
|
if (range && trigger2) {
|
|
947
639
|
view.dispatch({
|
|
@@ -953,7 +645,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
953
645
|
}
|
|
954
646
|
}, []);
|
|
955
647
|
const serializedTrigger = Array.isArray(trigger) ? trigger.join(",") : trigger;
|
|
956
|
-
const extension =
|
|
648
|
+
const extension = useMemo(() => {
|
|
957
649
|
return popover({
|
|
958
650
|
trigger,
|
|
959
651
|
triggerKey,
|
|
@@ -1019,150 +711,70 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
1019
711
|
|
|
1020
712
|
// src/components/EditorToolbar/EditorToolbar.tsx
|
|
1021
713
|
import { Atom } from "@effect-atom/atom-react";
|
|
1022
|
-
import
|
|
714
|
+
import React2, { memo, useMemo as useMemo2 } from "react";
|
|
1023
715
|
import { ElevationProvider } from "@dxos/react-ui";
|
|
1024
|
-
import {
|
|
716
|
+
import { Menu as Menu2, MenuBuilder, useMenuActions } from "@dxos/react-ui-menu";
|
|
1025
717
|
|
|
1026
|
-
// src/components/EditorToolbar/
|
|
1027
|
-
import {
|
|
1028
|
-
import {
|
|
1029
|
-
var
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
718
|
+
// src/components/EditorToolbar/blocks.ts
|
|
719
|
+
import { addBlockquote, addCodeblock, insertTable, removeBlockquote, removeCodeblock } from "@dxos/ui-editor";
|
|
720
|
+
import { translationKey } from "#translations";
|
|
721
|
+
var blockTypes = {
|
|
722
|
+
blockquote: "ph--quotes--regular",
|
|
723
|
+
codeblock: "ph--code-block--regular",
|
|
724
|
+
table: "ph--table--regular"
|
|
1033
725
|
};
|
|
1034
|
-
var
|
|
1035
|
-
const value = state.
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
nodes: [
|
|
1040
|
-
listGroupAction,
|
|
1041
|
-
...listActionsMap
|
|
1042
|
-
],
|
|
1043
|
-
edges: [
|
|
726
|
+
var addBlocks = (state, getView) => (builder) => {
|
|
727
|
+
const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
|
|
728
|
+
builder.group("block", {
|
|
729
|
+
label: [
|
|
730
|
+
"block.label",
|
|
1044
731
|
{
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
...listActionsMap.map(({ id }) => ({
|
|
1049
|
-
source: listGroupAction.id,
|
|
1050
|
-
target: id
|
|
1051
|
-
}))
|
|
1052
|
-
]
|
|
1053
|
-
};
|
|
1054
|
-
};
|
|
1055
|
-
var createEditorAction = (id, props, invoke) => {
|
|
1056
|
-
const { label = [
|
|
1057
|
-
`${id} label`,
|
|
1058
|
-
{
|
|
1059
|
-
ns: translationKey
|
|
1060
|
-
}
|
|
1061
|
-
], ...rest } = props;
|
|
1062
|
-
return createMenuAction(id, invoke, {
|
|
1063
|
-
label,
|
|
1064
|
-
...rest
|
|
1065
|
-
});
|
|
1066
|
-
};
|
|
1067
|
-
var createEditorActionGroup = (id, props, icon) => {
|
|
1068
|
-
const { label = [
|
|
1069
|
-
`${id} label`,
|
|
1070
|
-
{
|
|
1071
|
-
ns: translationKey
|
|
1072
|
-
}
|
|
1073
|
-
], ...rest } = props;
|
|
1074
|
-
return createMenuItemGroup(id, {
|
|
1075
|
-
label,
|
|
1076
|
-
icon,
|
|
732
|
+
ns: translationKey
|
|
733
|
+
}
|
|
734
|
+
],
|
|
1077
735
|
iconOnly: true,
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
blockquote: "ph--quotes--regular",
|
|
1114
|
-
codeblock: "ph--code-block--regular",
|
|
1115
|
-
table: "ph--table--regular"
|
|
1116
|
-
}).map(([type, icon]) => {
|
|
1117
|
-
const checked = type === value;
|
|
1118
|
-
return createEditorAction(type, {
|
|
1119
|
-
checked,
|
|
1120
|
-
...type === "table" && {
|
|
1121
|
-
disabled: !!blankLine
|
|
1122
|
-
},
|
|
1123
|
-
icon
|
|
1124
|
-
}, () => {
|
|
1125
|
-
const view = getView();
|
|
1126
|
-
if (!view) {
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
switch (type) {
|
|
1130
|
-
case "blockquote":
|
|
1131
|
-
checked ? removeBlockquote(view) : addBlockquote(view);
|
|
1132
|
-
break;
|
|
1133
|
-
case "codeblock":
|
|
1134
|
-
checked ? removeCodeblock(view) : addCodeblock(view);
|
|
1135
|
-
break;
|
|
1136
|
-
case "table":
|
|
1137
|
-
insertTable(view);
|
|
1138
|
-
break;
|
|
736
|
+
variant: "toggleGroup",
|
|
737
|
+
selectCardinality: "single",
|
|
738
|
+
value
|
|
739
|
+
}, (group) => {
|
|
740
|
+
for (const [type, icon] of Object.entries(blockTypes)) {
|
|
741
|
+
const checked = type === value;
|
|
742
|
+
group.action(type, {
|
|
743
|
+
label: [
|
|
744
|
+
`block.${type}.label`,
|
|
745
|
+
{
|
|
746
|
+
ns: translationKey
|
|
747
|
+
}
|
|
748
|
+
],
|
|
749
|
+
checked,
|
|
750
|
+
...type === "table" && {
|
|
751
|
+
disabled: !!state.blankLine
|
|
752
|
+
},
|
|
753
|
+
icon
|
|
754
|
+
}, () => {
|
|
755
|
+
const view = getView();
|
|
756
|
+
if (!view) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
switch (type) {
|
|
760
|
+
case "blockquote":
|
|
761
|
+
checked ? removeBlockquote(view) : addBlockquote(view);
|
|
762
|
+
break;
|
|
763
|
+
case "codeblock":
|
|
764
|
+
checked ? removeCodeblock(view) : addCodeblock(view);
|
|
765
|
+
break;
|
|
766
|
+
case "table":
|
|
767
|
+
insertTable(view);
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
});
|
|
1139
771
|
}
|
|
1140
772
|
});
|
|
1141
|
-
});
|
|
1142
|
-
var createBlocks = (state, getView) => {
|
|
1143
|
-
const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
|
|
1144
|
-
const blockGroupAction = createBlockGroupAction(value);
|
|
1145
|
-
const blockActions = createBlockActions(value, getView, state.blankLine);
|
|
1146
|
-
return {
|
|
1147
|
-
nodes: [
|
|
1148
|
-
blockGroupAction,
|
|
1149
|
-
...blockActions
|
|
1150
|
-
],
|
|
1151
|
-
edges: [
|
|
1152
|
-
{
|
|
1153
|
-
source: "root",
|
|
1154
|
-
target: "block"
|
|
1155
|
-
},
|
|
1156
|
-
...blockActions.map(({ id }) => ({
|
|
1157
|
-
source: blockGroupAction.id,
|
|
1158
|
-
target: id
|
|
1159
|
-
}))
|
|
1160
|
-
]
|
|
1161
|
-
};
|
|
1162
773
|
};
|
|
1163
774
|
|
|
1164
775
|
// src/components/EditorToolbar/formatting.ts
|
|
1165
776
|
import { Inline, addLink, removeLink, setStyle } from "@dxos/ui-editor";
|
|
777
|
+
import { translationKey as translationKey2 } from "#translations";
|
|
1166
778
|
var formats = {
|
|
1167
779
|
strong: "ph--text-b--regular",
|
|
1168
780
|
emphasis: "ph--text-italic--regular",
|
|
@@ -1170,205 +782,231 @@ var formats = {
|
|
|
1170
782
|
code: "ph--code--regular",
|
|
1171
783
|
link: "ph--link--regular"
|
|
1172
784
|
};
|
|
1173
|
-
var
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
785
|
+
var addFormatting = (state, getView) => (builder) => {
|
|
786
|
+
const formatting = state;
|
|
787
|
+
builder.group("formatting", {
|
|
788
|
+
label: [
|
|
789
|
+
"formatting.label",
|
|
790
|
+
{
|
|
791
|
+
ns: translationKey2
|
|
792
|
+
}
|
|
793
|
+
],
|
|
794
|
+
iconOnly: true,
|
|
795
|
+
variant: "toggleGroup",
|
|
796
|
+
selectCardinality: "multiple",
|
|
797
|
+
value: Object.keys(formats).filter((key) => !!formatting[key])
|
|
798
|
+
}, (group) => {
|
|
799
|
+
for (const [type, icon] of Object.entries(formats)) {
|
|
800
|
+
const checked = !!formatting[type];
|
|
801
|
+
group.action(type, {
|
|
802
|
+
label: [
|
|
803
|
+
`formatting.${type}.label`,
|
|
804
|
+
{
|
|
805
|
+
ns: translationKey2
|
|
806
|
+
}
|
|
807
|
+
],
|
|
808
|
+
checked,
|
|
809
|
+
icon
|
|
810
|
+
}, () => {
|
|
811
|
+
const view = getView();
|
|
812
|
+
if (!view) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (type === "link") {
|
|
816
|
+
checked ? removeLink(view) : addLink()(view);
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
setStyle(type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code, !checked)(view);
|
|
820
|
+
});
|
|
1191
821
|
}
|
|
1192
|
-
const inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
1193
|
-
setStyle(inlineType, !checked)(view);
|
|
1194
822
|
});
|
|
1195
|
-
});
|
|
1196
|
-
var createFormatting = (state, getView) => {
|
|
1197
|
-
const formattingGroupAction = createFormattingGroup(state);
|
|
1198
|
-
const formattingActions = createFormattingActions(state, getView);
|
|
1199
|
-
return {
|
|
1200
|
-
nodes: [
|
|
1201
|
-
formattingGroupAction,
|
|
1202
|
-
...formattingActions
|
|
1203
|
-
],
|
|
1204
|
-
edges: [
|
|
1205
|
-
{
|
|
1206
|
-
source: "root",
|
|
1207
|
-
target: "formatting"
|
|
1208
|
-
},
|
|
1209
|
-
...formattingActions.map(({ id }) => ({
|
|
1210
|
-
source: formattingGroupAction.id,
|
|
1211
|
-
target: id
|
|
1212
|
-
}))
|
|
1213
|
-
]
|
|
1214
|
-
};
|
|
1215
823
|
};
|
|
1216
824
|
|
|
1217
825
|
// src/components/EditorToolbar/headings.ts
|
|
1218
826
|
import { setHeading } from "@dxos/ui-editor";
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
"2": "ph--text-h-two--regular",
|
|
1230
|
-
"3": "ph--text-h-three--regular",
|
|
1231
|
-
"4": "ph--text-h-four--regular",
|
|
1232
|
-
"5": "ph--text-h-five--regular",
|
|
1233
|
-
"6": "ph--text-h-six--regular"
|
|
1234
|
-
}).map(([levelStr, icon]) => {
|
|
1235
|
-
const level = parseInt(levelStr);
|
|
1236
|
-
return createEditorAction(`heading--${levelStr}`, {
|
|
1237
|
-
label: [
|
|
1238
|
-
"heading level label",
|
|
1239
|
-
{
|
|
1240
|
-
count: level,
|
|
1241
|
-
ns: translationKey
|
|
1242
|
-
}
|
|
1243
|
-
],
|
|
1244
|
-
icon,
|
|
1245
|
-
checked: levelStr === currentLevel
|
|
1246
|
-
}, () => setHeading(level)(getView()));
|
|
1247
|
-
});
|
|
827
|
+
import { translationKey as translationKey3 } from "#translations";
|
|
828
|
+
var headingIcons = {
|
|
829
|
+
0: "ph--paragraph--regular",
|
|
830
|
+
1: "ph--text-h-one--regular",
|
|
831
|
+
2: "ph--text-h-two--regular",
|
|
832
|
+
3: "ph--text-h-three--regular",
|
|
833
|
+
4: "ph--text-h-four--regular",
|
|
834
|
+
5: "ph--text-h-five--regular",
|
|
835
|
+
6: "ph--text-h-six--regular"
|
|
836
|
+
};
|
|
1248
837
|
var computeHeadingValue = (state) => {
|
|
1249
838
|
const blockType = state ? state.blockType : "paragraph";
|
|
1250
839
|
const heading = blockType && /heading(\d)/.exec(blockType);
|
|
1251
840
|
return heading ? heading[1] : blockType === "paragraph" || !blockType ? "0" : "";
|
|
1252
841
|
};
|
|
1253
|
-
var
|
|
842
|
+
var addHeadings = (state, getView) => (builder) => {
|
|
1254
843
|
const headingValue = computeHeadingValue(state);
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
nodes: [
|
|
1259
|
-
headingGroupAction,
|
|
1260
|
-
...headingActions
|
|
1261
|
-
],
|
|
1262
|
-
edges: [
|
|
844
|
+
builder.group("heading", {
|
|
845
|
+
label: [
|
|
846
|
+
"heading.label",
|
|
1263
847
|
{
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
848
|
+
ns: translationKey3
|
|
849
|
+
}
|
|
850
|
+
],
|
|
851
|
+
icon: "ph--text-h--regular",
|
|
852
|
+
iconOnly: true,
|
|
853
|
+
variant: "dropdownMenu",
|
|
854
|
+
applyActive: true,
|
|
855
|
+
selectCardinality: "single",
|
|
856
|
+
// TODO(wittjosiah): Remove? Not sure this does anything.
|
|
857
|
+
value: headingValue
|
|
858
|
+
}, (group) => {
|
|
859
|
+
for (const [levelStr, icon] of Object.entries(headingIcons)) {
|
|
860
|
+
const level = parseInt(levelStr);
|
|
861
|
+
group.action(`heading--${levelStr}`, {
|
|
862
|
+
label: [
|
|
863
|
+
"heading-level.label",
|
|
864
|
+
{
|
|
865
|
+
count: level,
|
|
866
|
+
ns: translationKey3
|
|
867
|
+
}
|
|
868
|
+
],
|
|
869
|
+
icon,
|
|
870
|
+
checked: levelStr === headingValue
|
|
871
|
+
}, () => setHeading(level)(getView()));
|
|
872
|
+
}
|
|
873
|
+
});
|
|
1273
874
|
};
|
|
1274
875
|
|
|
1275
876
|
// src/components/EditorToolbar/image.ts
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
877
|
+
import { translationKey as translationKey4 } from "#translations";
|
|
878
|
+
var addImageUpload = (onImageUpload) => (builder) => {
|
|
879
|
+
builder.action("image", {
|
|
880
|
+
label: [
|
|
881
|
+
"image.label",
|
|
882
|
+
{
|
|
883
|
+
ns: translationKey4
|
|
884
|
+
}
|
|
885
|
+
],
|
|
886
|
+
testId: "editor.toolbar.image",
|
|
887
|
+
icon: "ph--image-square--regular"
|
|
888
|
+
}, onImageUpload);
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/components/EditorToolbar/lists.ts
|
|
892
|
+
import { List, addList, removeList } from "@dxos/ui-editor";
|
|
893
|
+
import { translationKey as translationKey5 } from "#translations";
|
|
894
|
+
var listStyles = {
|
|
895
|
+
bullet: "ph--list-bullets--regular",
|
|
896
|
+
ordered: "ph--list-numbers--regular",
|
|
897
|
+
task: "ph--list-checks--regular"
|
|
898
|
+
};
|
|
899
|
+
var addLists = (state, getView) => (builder) => {
|
|
900
|
+
const value = state.listStyle ?? "";
|
|
901
|
+
builder.group("list", {
|
|
902
|
+
label: [
|
|
903
|
+
"list.label",
|
|
904
|
+
{
|
|
905
|
+
ns: translationKey5
|
|
906
|
+
}
|
|
907
|
+
],
|
|
908
|
+
iconOnly: true,
|
|
909
|
+
variant: "toggleGroup",
|
|
910
|
+
selectCardinality: "single",
|
|
911
|
+
value
|
|
912
|
+
}, (group) => {
|
|
913
|
+
for (const [listStyle, icon] of Object.entries(listStyles)) {
|
|
914
|
+
const checked = value === listStyle;
|
|
915
|
+
group.action(`list-${listStyle}`, {
|
|
916
|
+
label: [
|
|
917
|
+
`list.${listStyle}.label`,
|
|
918
|
+
{
|
|
919
|
+
ns: translationKey5
|
|
920
|
+
}
|
|
921
|
+
],
|
|
922
|
+
checked,
|
|
923
|
+
icon
|
|
924
|
+
}, () => {
|
|
925
|
+
const view = getView();
|
|
926
|
+
if (!view) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const listType = listStyle === "ordered" ? List.Ordered : listStyle === "bullet" ? List.Bullet : List.Task;
|
|
930
|
+
if (checked) {
|
|
931
|
+
removeList(listType)(view);
|
|
932
|
+
} else {
|
|
933
|
+
addList(listType)(view);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
1288
936
|
}
|
|
1289
|
-
|
|
1290
|
-
}
|
|
937
|
+
});
|
|
938
|
+
};
|
|
1291
939
|
|
|
1292
940
|
// src/components/EditorToolbar/search.ts
|
|
1293
941
|
import { openSearchPanel } from "@codemirror/search";
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
]
|
|
1308
|
-
});
|
|
942
|
+
import { translationKey as translationKey6 } from "#translations";
|
|
943
|
+
var addSearch = (getView) => (builder) => {
|
|
944
|
+
builder.action("search", {
|
|
945
|
+
label: [
|
|
946
|
+
"search.label",
|
|
947
|
+
{
|
|
948
|
+
ns: translationKey6
|
|
949
|
+
}
|
|
950
|
+
],
|
|
951
|
+
testId: "editor.toolbar.search",
|
|
952
|
+
icon: "ph--magnifying-glass--regular"
|
|
953
|
+
}, () => openSearchPanel(getView()));
|
|
954
|
+
};
|
|
1309
955
|
|
|
1310
956
|
// src/components/EditorToolbar/view-mode.ts
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
applyActive: true,
|
|
1314
|
-
selectCardinality: "single",
|
|
1315
|
-
value
|
|
1316
|
-
}, "ph--eye--regular");
|
|
1317
|
-
var createViewModeActions = (value, onViewModeChange) => Object.entries({
|
|
957
|
+
import { translationKey as translationKey7 } from "#translations";
|
|
958
|
+
var viewModes = {
|
|
1318
959
|
preview: "ph--eye--regular",
|
|
1319
960
|
source: "ph--pencil-simple--regular",
|
|
1320
961
|
readonly: "ph--pencil-slash--regular"
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
|
|
962
|
+
};
|
|
963
|
+
var addViewMode = (state, onViewModeChange) => (builder) => {
|
|
964
|
+
const value = state.viewMode ?? "source";
|
|
965
|
+
builder.group("viewMode", {
|
|
1324
966
|
label: [
|
|
1325
|
-
|
|
967
|
+
"view-mode.label",
|
|
1326
968
|
{
|
|
1327
|
-
ns:
|
|
969
|
+
ns: translationKey7
|
|
1328
970
|
}
|
|
1329
971
|
],
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
}))
|
|
1352
|
-
]
|
|
1353
|
-
};
|
|
972
|
+
icon: "ph--eye--regular",
|
|
973
|
+
iconOnly: true,
|
|
974
|
+
variant: "dropdownMenu",
|
|
975
|
+
applyActive: true,
|
|
976
|
+
selectCardinality: "single",
|
|
977
|
+
value
|
|
978
|
+
}, (group) => {
|
|
979
|
+
for (const [viewMode, icon] of Object.entries(viewModes)) {
|
|
980
|
+
const checked = viewMode === value;
|
|
981
|
+
group.action(`view-mode--${viewMode}`, {
|
|
982
|
+
label: [
|
|
983
|
+
`view-mode.${viewMode}.label`,
|
|
984
|
+
{
|
|
985
|
+
ns: translationKey7
|
|
986
|
+
}
|
|
987
|
+
],
|
|
988
|
+
checked,
|
|
989
|
+
icon
|
|
990
|
+
}, () => onViewModeChange(viewMode));
|
|
991
|
+
}
|
|
992
|
+
});
|
|
1354
993
|
};
|
|
1355
994
|
|
|
1356
995
|
// src/components/EditorToolbar/EditorToolbar.tsx
|
|
1357
996
|
var EditorToolbar = /* @__PURE__ */ memo(({ classNames, role, attendableId, onAction, ...props }) => {
|
|
1358
|
-
const
|
|
1359
|
-
return /* @__PURE__ */
|
|
997
|
+
const menuActions = useMarkdownMenuActions(props);
|
|
998
|
+
return /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
1360
999
|
elevation: role === "section" ? "positioned" : "base"
|
|
1361
|
-
}, /* @__PURE__ */
|
|
1362
|
-
...
|
|
1000
|
+
}, /* @__PURE__ */ React2.createElement(Menu2.Root, {
|
|
1001
|
+
...menuActions,
|
|
1363
1002
|
attendableId,
|
|
1364
1003
|
onAction
|
|
1365
|
-
}, /* @__PURE__ */
|
|
1366
|
-
classNames
|
|
1367
|
-
textBlockWidth: true
|
|
1004
|
+
}, /* @__PURE__ */ React2.createElement(Menu2.Toolbar, {
|
|
1005
|
+
classNames
|
|
1368
1006
|
})));
|
|
1369
1007
|
});
|
|
1370
|
-
var
|
|
1371
|
-
const menuCreator =
|
|
1008
|
+
var useMarkdownMenuActions = ({ state, getView, customActions, ...features }) => {
|
|
1009
|
+
const menuCreator = useMemo2(() => createMarkdownActions({
|
|
1372
1010
|
state,
|
|
1373
1011
|
getView,
|
|
1374
1012
|
customActions,
|
|
@@ -1387,63 +1025,300 @@ var useEditorToolbarActionGraph = ({ state, getView, customActions, ...features
|
|
|
1387
1025
|
]);
|
|
1388
1026
|
return useMenuActions(menuCreator);
|
|
1389
1027
|
};
|
|
1390
|
-
var
|
|
1028
|
+
var createMarkdownActions = ({ state, getView, customActions, ...features }) => {
|
|
1391
1029
|
return Atom.make((get) => {
|
|
1392
|
-
const graph = {
|
|
1393
|
-
nodes: [],
|
|
1394
|
-
edges: []
|
|
1395
|
-
};
|
|
1396
|
-
const addSubGraph = (graph2, subGraph) => {
|
|
1397
|
-
graph2.nodes.push(...subGraph.nodes);
|
|
1398
|
-
graph2.edges.push(...subGraph.edges);
|
|
1399
|
-
};
|
|
1400
1030
|
const stateSnapshot = get(state);
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1031
|
+
return MenuBuilder.make().subgraph(features?.showHeadings !== false && addHeadings(stateSnapshot, getView)).subgraph(features?.showFormatting !== false && addFormatting(stateSnapshot, getView)).subgraph(features?.showLists !== false && addLists(stateSnapshot, getView)).subgraph(features?.showBlocks !== false && addBlocks(stateSnapshot, getView)).subgraph(features?.onImageUpload && addImageUpload(features.onImageUpload)).separator("gap").subgraph(customActions && get(customActions)).subgraph(features?.showSearch !== false && addSearch(getView)).subgraph(features?.onViewModeChange && addViewMode(stateSnapshot, features.onViewModeChange)).build();
|
|
1032
|
+
});
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
// src/components/Editor/EditorView.tsx
|
|
1036
|
+
import { Transaction } from "@codemirror/state";
|
|
1037
|
+
import { EditorView as NaturalEditorView } from "@codemirror/view";
|
|
1038
|
+
import React3, { forwardRef, useEffect as useEffect3, useImperativeHandle, useRef as useRef4 } from "react";
|
|
1039
|
+
import { initialSync } from "@dxos/ui-editor";
|
|
1040
|
+
import { mx } from "@dxos/ui-theme";
|
|
1041
|
+
|
|
1042
|
+
// src/hooks/useBasicMarkdownExtensions.ts
|
|
1043
|
+
import { useMemo as useMemo3 } from "react";
|
|
1044
|
+
import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
|
|
1045
|
+
import { createBasicExtensions, createMarkdownExtensions, createThemeExtensions, decorateMarkdown } from "@dxos/ui-editor";
|
|
1046
|
+
var useBasicMarkdownExtensions = ({ placeholder: placeholder2, decorate = true, extensions } = {}) => {
|
|
1047
|
+
const { themeMode } = useThemeContext2();
|
|
1048
|
+
return useMemo3(() => [
|
|
1049
|
+
createBasicExtensions({
|
|
1050
|
+
placeholder: placeholder2
|
|
1051
|
+
}),
|
|
1052
|
+
createThemeExtensions({
|
|
1053
|
+
syntaxHighlighting: true,
|
|
1054
|
+
themeMode
|
|
1055
|
+
}),
|
|
1056
|
+
createMarkdownExtensions(),
|
|
1057
|
+
...decorate ? [
|
|
1058
|
+
decorateMarkdown()
|
|
1059
|
+
] : [],
|
|
1060
|
+
...extensions ?? []
|
|
1061
|
+
], [
|
|
1062
|
+
placeholder2,
|
|
1063
|
+
themeMode,
|
|
1064
|
+
decorate,
|
|
1065
|
+
extensions
|
|
1066
|
+
]);
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
// src/hooks/useTextEditor.ts
|
|
1070
|
+
import { EditorState } from "@codemirror/state";
|
|
1071
|
+
import { EditorView as EditorView2 } from "@codemirror/view";
|
|
1072
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
|
|
1073
|
+
import { log } from "@dxos/log";
|
|
1074
|
+
import { createEditorStateTransaction, debugDispatcher, documentId, modalStateField as modalStateField2 } from "@dxos/ui-editor";
|
|
1075
|
+
import { getProviderValue, isTruthy as isTruthy2 } from "@dxos/util";
|
|
1076
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
1077
|
+
var instanceCount = 0;
|
|
1078
|
+
var useTextEditor = (props = {}, deps = []) => {
|
|
1079
|
+
const { id, doc, initialValue, extensions, autoFocus, scrollTo, selection, selectionEnd, debug } = useMemo4(() => getProviderValue(props), deps ?? []);
|
|
1080
|
+
const [instanceId] = useState3(() => `text-editor-${++instanceCount}`);
|
|
1081
|
+
const [view, setView] = useState3(null);
|
|
1082
|
+
const parentRef = useRef3(null);
|
|
1083
|
+
useEffect2(() => {
|
|
1084
|
+
let view2 = null;
|
|
1085
|
+
if (parentRef.current) {
|
|
1086
|
+
log("create", {
|
|
1087
|
+
id,
|
|
1088
|
+
instanceId,
|
|
1089
|
+
doc: initialValue?.length ?? 0
|
|
1090
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 22, S: void 0 });
|
|
1091
|
+
let initialSelection;
|
|
1092
|
+
if (selection?.anchor && initialValue?.length) {
|
|
1093
|
+
if (selection.anchor <= initialValue.length && (selection?.head ?? 0) <= initialValue.length) {
|
|
1094
|
+
initialSelection = selection;
|
|
1095
|
+
}
|
|
1096
|
+
} else if (selectionEnd && selection === void 0) {
|
|
1097
|
+
const index = initialValue?.indexOf("\n");
|
|
1098
|
+
const anchor = !index || index === -1 ? 0 : index;
|
|
1099
|
+
initialSelection = {
|
|
1100
|
+
anchor
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
const state = EditorState.create({
|
|
1104
|
+
doc: doc ?? initialValue,
|
|
1105
|
+
// selection: initialSelection,
|
|
1106
|
+
extensions: [
|
|
1107
|
+
id && documentId.of(id),
|
|
1108
|
+
extensions,
|
|
1109
|
+
// NOTE: This doesn't catch errors in keymap functions.
|
|
1110
|
+
EditorView2.exceptionSink.of((err) => {
|
|
1111
|
+
log.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 48, S: void 0 });
|
|
1112
|
+
})
|
|
1113
|
+
].filter(isTruthy2)
|
|
1114
|
+
});
|
|
1115
|
+
view2 = new EditorView2({
|
|
1116
|
+
parent: parentRef.current,
|
|
1117
|
+
state,
|
|
1118
|
+
scrollTo: scrollTo ? EditorView2.scrollIntoView(scrollTo, {
|
|
1119
|
+
yMargin: 96
|
|
1120
|
+
}) : void 0,
|
|
1121
|
+
dispatchTransactions: debug ? debugDispatcher : void 0
|
|
1122
|
+
});
|
|
1123
|
+
if (selectionEnd && !initialSelection) {
|
|
1124
|
+
const { to } = view2.state.doc.lineAt(0);
|
|
1125
|
+
if (to) {
|
|
1126
|
+
view2.dispatch({
|
|
1127
|
+
selection: {
|
|
1128
|
+
anchor: to
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
setView(view2);
|
|
1412
1134
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1135
|
+
return () => {
|
|
1136
|
+
log("destroy", {
|
|
1137
|
+
id
|
|
1138
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 75, S: void 0 });
|
|
1139
|
+
view2?.destroy();
|
|
1140
|
+
};
|
|
1141
|
+
}, deps);
|
|
1142
|
+
useEffect2(() => {
|
|
1143
|
+
if (view) {
|
|
1144
|
+
if (scrollTo || selection) {
|
|
1145
|
+
if (selection && selection.anchor > view.state.doc.length) {
|
|
1146
|
+
log.warn("invalid selection", {
|
|
1147
|
+
length: view.state.doc.length,
|
|
1148
|
+
scrollTo,
|
|
1149
|
+
selection
|
|
1150
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 85, S: void 0 });
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
view.dispatch(createEditorStateTransaction({
|
|
1154
|
+
scrollTo,
|
|
1155
|
+
selection
|
|
1156
|
+
}));
|
|
1157
|
+
}
|
|
1415
1158
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1159
|
+
}, [
|
|
1160
|
+
view,
|
|
1161
|
+
scrollTo,
|
|
1162
|
+
selection
|
|
1163
|
+
]);
|
|
1164
|
+
useEffect2(() => {
|
|
1165
|
+
if (view && autoFocus) {
|
|
1166
|
+
view.focus();
|
|
1419
1167
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1168
|
+
}, [
|
|
1169
|
+
autoFocus,
|
|
1170
|
+
view
|
|
1171
|
+
]);
|
|
1172
|
+
const handleKeyDown = useCallback3((event) => {
|
|
1173
|
+
const { key, target, currentTarget } = event;
|
|
1174
|
+
switch (key) {
|
|
1175
|
+
case "Escape": {
|
|
1176
|
+
const modal = view?.state.field(modalStateField2, false);
|
|
1177
|
+
if (modal) {
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
const element = view?.contentDOM.closest('[tabindex="0"]');
|
|
1181
|
+
element?.focus();
|
|
1182
|
+
break;
|
|
1183
|
+
}
|
|
1184
|
+
case "Enter": {
|
|
1185
|
+
event.preventDefault();
|
|
1186
|
+
if (target === currentTarget) {
|
|
1187
|
+
view?.focus();
|
|
1188
|
+
}
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1422
1191
|
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1192
|
+
}, [
|
|
1193
|
+
view
|
|
1194
|
+
]);
|
|
1195
|
+
return {
|
|
1196
|
+
parentRef,
|
|
1197
|
+
view,
|
|
1198
|
+
focusAttributes: {
|
|
1199
|
+
tabIndex: 0,
|
|
1200
|
+
onKeyDown: handleKeyDown
|
|
1425
1201
|
}
|
|
1426
|
-
|
|
1427
|
-
});
|
|
1202
|
+
};
|
|
1428
1203
|
};
|
|
1429
1204
|
|
|
1430
|
-
// src/components/
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1205
|
+
// src/components/Editor/controller.ts
|
|
1206
|
+
var noopController = {
|
|
1207
|
+
get view() {
|
|
1208
|
+
return null;
|
|
1209
|
+
},
|
|
1210
|
+
getText: () => "",
|
|
1211
|
+
setText: () => {
|
|
1212
|
+
},
|
|
1213
|
+
focus: () => {
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
var createEditorController = (view) => {
|
|
1217
|
+
return {
|
|
1218
|
+
get view() {
|
|
1219
|
+
return view;
|
|
1220
|
+
},
|
|
1221
|
+
getText: () => {
|
|
1222
|
+
return view?.state.doc.toString() ?? "";
|
|
1223
|
+
},
|
|
1224
|
+
setText: (text, focus) => {
|
|
1225
|
+
view?.dispatch({
|
|
1226
|
+
changes: {
|
|
1227
|
+
from: 0,
|
|
1228
|
+
to: view?.state.doc.length ?? 0,
|
|
1229
|
+
insert: text
|
|
1230
|
+
},
|
|
1231
|
+
selection: {
|
|
1232
|
+
anchor: text.length,
|
|
1233
|
+
head: text.length
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
if (focus) {
|
|
1237
|
+
view?.focus();
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
focus: () => view?.focus()
|
|
1241
|
+
};
|
|
1435
1242
|
};
|
|
1436
1243
|
|
|
1244
|
+
// src/components/Editor/EditorView.tsx
|
|
1245
|
+
var EditorView3 = /* @__PURE__ */ forwardRef(({ classNames, id, extensions, selectionEnd, focusable = true, value, onChange, ...props }, forwardedRef) => {
|
|
1246
|
+
const onChangeRef = useRef4(onChange);
|
|
1247
|
+
onChangeRef.current = onChange;
|
|
1248
|
+
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
1249
|
+
id,
|
|
1250
|
+
initialValue: value,
|
|
1251
|
+
selectionEnd,
|
|
1252
|
+
extensions: [
|
|
1253
|
+
extensions ?? [],
|
|
1254
|
+
NaturalEditorView.updateListener.of(({ view: view2, docChanged, transactions }) => {
|
|
1255
|
+
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
|
|
1256
|
+
if (!isInitialSync && docChanged) {
|
|
1257
|
+
onChangeRef.current?.(view2.state.doc.toString());
|
|
1258
|
+
}
|
|
1259
|
+
})
|
|
1260
|
+
],
|
|
1261
|
+
...props
|
|
1262
|
+
}), [
|
|
1263
|
+
id,
|
|
1264
|
+
extensions,
|
|
1265
|
+
selectionEnd
|
|
1266
|
+
]);
|
|
1267
|
+
useImperativeHandle(forwardedRef, () => {
|
|
1268
|
+
return createEditorController(view);
|
|
1269
|
+
}, [
|
|
1270
|
+
id,
|
|
1271
|
+
view
|
|
1272
|
+
]);
|
|
1273
|
+
useEffect3(() => {
|
|
1274
|
+
if (!view) {
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const next = value ?? "";
|
|
1278
|
+
if (view.state.doc.toString() === next) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
requestAnimationFrame(() => {
|
|
1282
|
+
if (view.state.doc.toString() === next) {
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
view.dispatch({
|
|
1286
|
+
annotations: initialSync,
|
|
1287
|
+
changes: [
|
|
1288
|
+
{
|
|
1289
|
+
from: 0,
|
|
1290
|
+
to: view.state.doc.length,
|
|
1291
|
+
insert: next
|
|
1292
|
+
}
|
|
1293
|
+
],
|
|
1294
|
+
selection: selectionEnd ? {
|
|
1295
|
+
anchor: next.length
|
|
1296
|
+
} : void 0
|
|
1297
|
+
});
|
|
1298
|
+
if (selectionEnd) {
|
|
1299
|
+
view.focus();
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
}, [
|
|
1303
|
+
view,
|
|
1304
|
+
value,
|
|
1305
|
+
selectionEnd
|
|
1306
|
+
]);
|
|
1307
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
1308
|
+
className: mx("w-full outline-hidden focus:border-accent-surface focus-within:border-focus-ring-subtle", classNames),
|
|
1309
|
+
...focusable ? focusAttributes : {},
|
|
1310
|
+
ref: parentRef
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1437
1314
|
// src/components/Editor/Editor.tsx
|
|
1438
1315
|
var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/Editor/Editor.tsx";
|
|
1439
1316
|
var [EditorContextProvider, useEditorContext] = createContext("Editor");
|
|
1440
|
-
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, ...props }, forwardedRef) => {
|
|
1441
|
-
const state =
|
|
1317
|
+
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, numItems, ...props }, forwardedRef) => {
|
|
1318
|
+
const state = useMemo5(() => Atom2.make({
|
|
1319
|
+
viewMode
|
|
1320
|
+
}), [
|
|
1442
1321
|
viewMode
|
|
1443
|
-
});
|
|
1444
|
-
const [controller, setController] = useState4();
|
|
1445
|
-
useImperativeHandle2(forwardedRef, () => controller ?? noopController, [
|
|
1446
|
-
controller
|
|
1447
1322
|
]);
|
|
1448
1323
|
const { groupsRef, extension, ...menuProps } = useEditorMenu(props);
|
|
1449
1324
|
const extensions = useMemo5(() => [
|
|
@@ -1453,6 +1328,10 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1453
1328
|
extension,
|
|
1454
1329
|
extensionsProp
|
|
1455
1330
|
]);
|
|
1331
|
+
const [controller, setController] = useState4(noopController);
|
|
1332
|
+
useImperativeHandle2(forwardedRef, () => controller, [
|
|
1333
|
+
controller
|
|
1334
|
+
]);
|
|
1456
1335
|
return /* @__PURE__ */ React4.createElement(EditorContextProvider, {
|
|
1457
1336
|
controller,
|
|
1458
1337
|
setController,
|
|
@@ -1461,21 +1340,21 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1461
1340
|
}, /* @__PURE__ */ React4.createElement(EditorMenuProvider, {
|
|
1462
1341
|
view: controller?.view,
|
|
1463
1342
|
groups: groupsRef.current,
|
|
1343
|
+
numItems,
|
|
1464
1344
|
...menuProps
|
|
1465
1345
|
}, children));
|
|
1466
1346
|
});
|
|
1467
1347
|
EditorRoot.displayName = "Editor.Root";
|
|
1468
|
-
var
|
|
1469
|
-
var
|
|
1348
|
+
var EDITOR_CONTENT_NAME = "Editor.Content";
|
|
1349
|
+
var EditorContent = ({ classNames, children }) => {
|
|
1470
1350
|
return /* @__PURE__ */ React4.createElement("div", {
|
|
1471
|
-
|
|
1472
|
-
className: mx2("grid grid-rows-[min-content_1fr] bs-full overflow-hidden", classNames)
|
|
1351
|
+
className: mx2("grid grid-rows-[min-content_1fr] h-full overflow-hidden", classNames)
|
|
1473
1352
|
}, children);
|
|
1474
1353
|
};
|
|
1475
|
-
|
|
1476
|
-
var
|
|
1477
|
-
var
|
|
1478
|
-
const { extensions: additionalExtensions = [], setController } = useEditorContext(
|
|
1354
|
+
EditorContent.displayName = EDITOR_CONTENT_NAME;
|
|
1355
|
+
var EDITOR_VIEW_NAME = "Editor.View";
|
|
1356
|
+
var EditorView4 = ({ extensions: providedExtensions, ...props }) => {
|
|
1357
|
+
const { extensions: additionalExtensions = [], setController } = useEditorContext(EDITOR_VIEW_NAME);
|
|
1479
1358
|
const extensions = useMemo5(() => [
|
|
1480
1359
|
additionalExtensions,
|
|
1481
1360
|
providedExtensions
|
|
@@ -1483,26 +1362,18 @@ var EditorContent2 = ({ extensions: providedExtensions, ...props }) => {
|
|
|
1483
1362
|
providedExtensions,
|
|
1484
1363
|
additionalExtensions
|
|
1485
1364
|
]);
|
|
1486
|
-
return /* @__PURE__ */ React4.createElement(
|
|
1365
|
+
return /* @__PURE__ */ React4.createElement(EditorView3, {
|
|
1487
1366
|
...props,
|
|
1488
1367
|
extensions,
|
|
1489
1368
|
ref: setController
|
|
1490
1369
|
});
|
|
1491
1370
|
};
|
|
1492
|
-
|
|
1371
|
+
EditorView4.displayName = EDITOR_VIEW_NAME;
|
|
1493
1372
|
var EDITOR_TOOLBAR_NAME = "Editor.Toolbar";
|
|
1494
1373
|
var EditorToolbar2 = (props) => {
|
|
1495
1374
|
const { controller, state } = useEditorContext(EDITOR_TOOLBAR_NAME);
|
|
1496
1375
|
const getView = useCallback4(() => {
|
|
1497
|
-
invariant3(controller?.view, void 0, {
|
|
1498
|
-
F: __dxlog_file4,
|
|
1499
|
-
L: 146,
|
|
1500
|
-
S: void 0,
|
|
1501
|
-
A: [
|
|
1502
|
-
"controller?.view",
|
|
1503
|
-
""
|
|
1504
|
-
]
|
|
1505
|
-
});
|
|
1376
|
+
invariant3(controller?.view, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 99, S: void 0, A: ["controller?.view", ""] });
|
|
1506
1377
|
return controller?.view;
|
|
1507
1378
|
}, [
|
|
1508
1379
|
controller
|
|
@@ -1516,19 +1387,19 @@ var EditorToolbar2 = (props) => {
|
|
|
1516
1387
|
EditorToolbar2.displayName = EDITOR_TOOLBAR_NAME;
|
|
1517
1388
|
var Editor = {
|
|
1518
1389
|
Root: EditorRoot,
|
|
1519
|
-
|
|
1520
|
-
Content:
|
|
1521
|
-
|
|
1390
|
+
Toolbar: EditorToolbar2,
|
|
1391
|
+
Content: EditorContent,
|
|
1392
|
+
View: EditorView4
|
|
1522
1393
|
};
|
|
1523
1394
|
|
|
1524
1395
|
// src/components/EditorPreviewProvider/EditorPreviewProvider.tsx
|
|
1525
1396
|
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
1526
|
-
import React5, { useCallback as useCallback5, useEffect as useEffect4, useRef as
|
|
1397
|
+
import React5, { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
|
|
1527
1398
|
import { addEventListener as addEventListener2 } from "@dxos/async";
|
|
1528
1399
|
import { DX_ANCHOR_ACTIVATE as DX_ANCHOR_ACTIVATE2, Popover as Popover2 } from "@dxos/react-ui";
|
|
1529
1400
|
var [EditorPreviewContextProvider, useEditorPreview] = createContext2("PreviewPopover", {});
|
|
1530
1401
|
var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
1531
|
-
const triggerRef =
|
|
1402
|
+
const triggerRef = useRef5(null);
|
|
1532
1403
|
const [value, setValue] = useState5({});
|
|
1533
1404
|
const [open, setOpen] = useState5(false);
|
|
1534
1405
|
const handleActivate = useCallback5((event) => {
|
|
@@ -1577,17 +1448,187 @@ var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
|
1577
1448
|
}, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
|
|
1578
1449
|
virtualRef: triggerRef
|
|
1579
1450
|
}), /* @__PURE__ */ React5.createElement("div", {
|
|
1580
|
-
role: "none",
|
|
1581
1451
|
className: "contents",
|
|
1582
1452
|
ref: setRoot
|
|
1583
1453
|
}, children)));
|
|
1584
1454
|
};
|
|
1455
|
+
|
|
1456
|
+
// src/extensions/assistant-extension.tsx
|
|
1457
|
+
import { forEachDiagnostic, linter, setDiagnostics } from "@codemirror/lint";
|
|
1458
|
+
import { ChangeSet } from "@codemirror/state";
|
|
1459
|
+
import { EditorView as EditorView5 } from "@codemirror/view";
|
|
1460
|
+
import { log as log2 } from "@dxos/log";
|
|
1461
|
+
import { safeParseJson, trim } from "@dxos/util";
|
|
1462
|
+
var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/extensions/assistant-extension.tsx";
|
|
1463
|
+
var DEFAULT_INSTRUCTIONS = trim`
|
|
1464
|
+
Proofread the input text below.
|
|
1465
|
+
Identify typos and grammatical errors.
|
|
1466
|
+
Return ONLY a valid JSON array of objects with fields: "original" (string), "replacement" (string), "context" (string, 3-5 words around match).
|
|
1467
|
+
--
|
|
1468
|
+
`;
|
|
1469
|
+
var underline = (color) => {
|
|
1470
|
+
const svg = trim`
|
|
1471
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="3">
|
|
1472
|
+
<path d="m0 3 l2 -2 l1 0 l2 2 l1 0" stroke="${color}" fill="none" stroke-width="1"/>
|
|
1473
|
+
</svg>
|
|
1474
|
+
`;
|
|
1475
|
+
return `url('data:image/svg+xml;base64,${btoa(svg)}') !important`;
|
|
1476
|
+
};
|
|
1477
|
+
var assistant = (options) => {
|
|
1478
|
+
const styles = getComputedStyle(document.documentElement);
|
|
1479
|
+
const style = {
|
|
1480
|
+
info: styles.getPropertyValue("--color-green-500").trim(),
|
|
1481
|
+
warning: styles.getPropertyValue("--color-orange-500").trim(),
|
|
1482
|
+
error: styles.getPropertyValue("--color-rose-500").trim()
|
|
1483
|
+
};
|
|
1484
|
+
return [
|
|
1485
|
+
assistantLinter(options),
|
|
1486
|
+
EditorView5.baseTheme({
|
|
1487
|
+
".cm-lintRange-info": {
|
|
1488
|
+
backgroundImage: underline(style.info)
|
|
1489
|
+
},
|
|
1490
|
+
".cm-lintRange-warning": {
|
|
1491
|
+
backgroundImage: underline(style.warning)
|
|
1492
|
+
},
|
|
1493
|
+
".cm-lintRange-error": {
|
|
1494
|
+
backgroundImage: underline(style.error)
|
|
1495
|
+
},
|
|
1496
|
+
".cm-panels-bottom": {
|
|
1497
|
+
borderTop: "1px solid var(--color-separator) !important"
|
|
1498
|
+
},
|
|
1499
|
+
".cm-panel-lint .cm-panel": {
|
|
1500
|
+
outline: "none !important"
|
|
1501
|
+
},
|
|
1502
|
+
/** @apply dx-button */
|
|
1503
|
+
".cm-panel button": {
|
|
1504
|
+
color: "var(--color-base-foreground) !important"
|
|
1505
|
+
},
|
|
1506
|
+
".cm-panel.cm-panel-lint ul": {
|
|
1507
|
+
color: "var(--color-base-foreground) !important",
|
|
1508
|
+
backgroundColor: "var(--color-base-surface) !important",
|
|
1509
|
+
marginRight: "2rem !important"
|
|
1510
|
+
},
|
|
1511
|
+
".cm-panel.cm-panel-lint ul [aria-selected]": {
|
|
1512
|
+
color: "var(--color-base-foreground) !important",
|
|
1513
|
+
backgroundColor: "var(--color-base-surface) !important"
|
|
1514
|
+
},
|
|
1515
|
+
".cm-panel.cm-panel-lint ul li": {
|
|
1516
|
+
display: "grid",
|
|
1517
|
+
gridTemplateColumns: "1fr auto",
|
|
1518
|
+
alignItems: "center"
|
|
1519
|
+
},
|
|
1520
|
+
".cm-panel.cm-panel-lint ul li .cm-diagnosticText": {
|
|
1521
|
+
paddingRight: "8px !important"
|
|
1522
|
+
},
|
|
1523
|
+
".cm-panel.cm-panel-lint ul li button.cm-diagnosticAction": {
|
|
1524
|
+
margin: "none !important"
|
|
1525
|
+
},
|
|
1526
|
+
".cm-diagnostic": {
|
|
1527
|
+
padding: "0px 8px !important",
|
|
1528
|
+
whiteSpace: "pre-wrap !important"
|
|
1529
|
+
},
|
|
1530
|
+
".cm-diagnostic-info": {
|
|
1531
|
+
border: "none !important"
|
|
1532
|
+
}
|
|
1533
|
+
})
|
|
1534
|
+
];
|
|
1535
|
+
};
|
|
1536
|
+
var isSuggestion = (value) => typeof value === "object" && value !== null && typeof value.original === "string" && typeof value.replacement === "string" && typeof value.context === "string";
|
|
1537
|
+
var findSuggestionIndex = (content, suggestion) => {
|
|
1538
|
+
const firstIdx = content.indexOf(suggestion.original);
|
|
1539
|
+
if (firstIdx === -1) {
|
|
1540
|
+
return -1;
|
|
1541
|
+
}
|
|
1542
|
+
const secondIdx = content.indexOf(suggestion.original, firstIdx + 1);
|
|
1543
|
+
if (secondIdx === -1) {
|
|
1544
|
+
return firstIdx;
|
|
1545
|
+
}
|
|
1546
|
+
const contextIdx = content.indexOf(suggestion.context);
|
|
1547
|
+
if (contextIdx !== -1) {
|
|
1548
|
+
const contextEnd = contextIdx + suggestion.context.length;
|
|
1549
|
+
if (secondIdx >= contextIdx && secondIdx <= contextEnd) {
|
|
1550
|
+
return secondIdx;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
return firstIdx;
|
|
1554
|
+
};
|
|
1555
|
+
var replaceTextAndDropLintAtRange = (view, from, to, insert) => {
|
|
1556
|
+
const kept = [];
|
|
1557
|
+
forEachDiagnostic(view.state, (diagnostic, diagnosticFrom, diagnosticTo) => {
|
|
1558
|
+
if (diagnosticFrom < to && diagnosticTo > from) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
kept.push({
|
|
1562
|
+
...diagnostic,
|
|
1563
|
+
from: diagnosticFrom,
|
|
1564
|
+
to: diagnosticTo
|
|
1565
|
+
});
|
|
1566
|
+
});
|
|
1567
|
+
const changeSet = ChangeSet.of({
|
|
1568
|
+
from,
|
|
1569
|
+
to,
|
|
1570
|
+
insert
|
|
1571
|
+
}, view.state.doc.length);
|
|
1572
|
+
const next = kept.map((d) => ({
|
|
1573
|
+
...d,
|
|
1574
|
+
from: changeSet.mapPos(d.from, 1),
|
|
1575
|
+
to: changeSet.mapPos(d.to, -1)
|
|
1576
|
+
}));
|
|
1577
|
+
view.dispatch({
|
|
1578
|
+
changes: {
|
|
1579
|
+
from,
|
|
1580
|
+
to,
|
|
1581
|
+
insert
|
|
1582
|
+
},
|
|
1583
|
+
...setDiagnostics(view.state, next)
|
|
1584
|
+
});
|
|
1585
|
+
};
|
|
1586
|
+
var assistantLinter = ({ generate, instructions = DEFAULT_INSTRUCTIONS, autoPanel = true, delay = 2e3 }) => linter(async (view) => {
|
|
1587
|
+
try {
|
|
1588
|
+
const content = view.state.doc.toString();
|
|
1589
|
+
const result = await generate({
|
|
1590
|
+
instructions,
|
|
1591
|
+
content
|
|
1592
|
+
});
|
|
1593
|
+
const [match] = result.match(/\[.*\]/s) ?? [];
|
|
1594
|
+
const parsed = match ? safeParseJson(match, []) : [];
|
|
1595
|
+
const suggestions = Array.isArray(parsed) ? parsed.filter(isSuggestion) : [];
|
|
1596
|
+
if (suggestions && suggestions.length > 0) {
|
|
1597
|
+
const diagnostics = [];
|
|
1598
|
+
for (const suggestion of suggestions) {
|
|
1599
|
+
const idx = findSuggestionIndex(content, suggestion);
|
|
1600
|
+
if (idx !== -1) {
|
|
1601
|
+
diagnostics.push({
|
|
1602
|
+
from: idx,
|
|
1603
|
+
to: idx + suggestion.original.length,
|
|
1604
|
+
severity: "info",
|
|
1605
|
+
message: `Suggestion: ${suggestion.replacement}`,
|
|
1606
|
+
actions: [
|
|
1607
|
+
{
|
|
1608
|
+
name: "Apply",
|
|
1609
|
+
apply: (view2, from, to) => {
|
|
1610
|
+
replaceTextAndDropLintAtRange(view2, from, to, suggestion.replacement);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
]
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
return diagnostics;
|
|
1618
|
+
}
|
|
1619
|
+
} catch (err) {
|
|
1620
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 169, S: void 0 });
|
|
1621
|
+
}
|
|
1622
|
+
return [];
|
|
1623
|
+
}, {
|
|
1624
|
+
delay,
|
|
1625
|
+
autoPanel
|
|
1626
|
+
});
|
|
1585
1627
|
export {
|
|
1586
1628
|
Editor,
|
|
1587
|
-
EditorContent,
|
|
1588
1629
|
EditorMenuProvider,
|
|
1589
1630
|
EditorPreviewProvider,
|
|
1590
|
-
|
|
1631
|
+
assistant,
|
|
1591
1632
|
createEditorController,
|
|
1592
1633
|
createMenuGroup,
|
|
1593
1634
|
filterMenuGroups,
|
|
@@ -1599,10 +1640,10 @@ export {
|
|
|
1599
1640
|
popover,
|
|
1600
1641
|
popoverRangeEffect,
|
|
1601
1642
|
popoverStateField,
|
|
1602
|
-
|
|
1643
|
+
useBasicMarkdownExtensions,
|
|
1644
|
+
useEditorContext,
|
|
1603
1645
|
useEditorMenu,
|
|
1604
1646
|
useEditorPreview,
|
|
1605
|
-
useEditorToolbar,
|
|
1606
1647
|
useTextEditor
|
|
1607
1648
|
};
|
|
1608
1649
|
//# sourceMappingURL=index.mjs.map
|