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