@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,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("is-full outline-none focus:border-accentSurface focus-within:border-neutralFocusIndicator", 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,16 @@ 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`,
|
|
62
|
+
focusOnly: true,
|
|
358
63
|
...options.placeholder
|
|
359
64
|
})
|
|
360
|
-
].filter(
|
|
65
|
+
].filter(isTruthy);
|
|
361
66
|
};
|
|
362
|
-
var popoverTriggerListener = (options) =>
|
|
67
|
+
var popoverTriggerListener = (options) => EditorView.updateListener.of(({ view, docChanged }) => {
|
|
363
68
|
const { range: activeRange, trigger } = view.state.field(popoverStateField) ?? {};
|
|
364
69
|
if (!activeRange) {
|
|
365
70
|
return;
|
|
@@ -504,7 +209,7 @@ var popoverKeymap = (options) => {
|
|
|
504
209
|
return false;
|
|
505
210
|
}
|
|
506
211
|
}
|
|
507
|
-
].filter(
|
|
212
|
+
].filter(isTruthy));
|
|
508
213
|
};
|
|
509
214
|
var popoverAnchorDecoration = (options) => {
|
|
510
215
|
return ViewPlugin.fromClass(class {
|
|
@@ -699,36 +404,28 @@ var linkSlashCommands = {
|
|
|
699
404
|
|
|
700
405
|
// src/components/EditorMenuProvider/EditorMenuProvider.tsx
|
|
701
406
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
702
|
-
import
|
|
407
|
+
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
|
703
408
|
import { addEventListener } from "@dxos/async";
|
|
704
409
|
import { invariant } from "@dxos/invariant";
|
|
705
|
-
import { DX_ANCHOR_ACTIVATE, Icon, Popover, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
706
|
-
var
|
|
410
|
+
import { DX_ANCHOR_ACTIVATE, Icon, Popover, ScrollArea, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
411
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/EditorMenuProvider/EditorMenuProvider.tsx";
|
|
707
412
|
var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp, defaultOpen, numItems = 8, onOpenChange, onActivate, onSelect, onCancel }) => {
|
|
708
413
|
const { tx } = useThemeContext();
|
|
709
|
-
const triggerRef =
|
|
414
|
+
const triggerRef = useRef(null);
|
|
710
415
|
const viewRef = useDynamicRef(view);
|
|
711
416
|
const [open, setOpen] = useControllableState({
|
|
712
417
|
prop: openProp,
|
|
713
418
|
defaultProp: defaultOpen,
|
|
714
419
|
onChange: (open2) => {
|
|
715
|
-
invariant(viewRef.current, void 0, {
|
|
716
|
-
F: __dxlog_file2,
|
|
717
|
-
L: 65,
|
|
718
|
-
S: void 0,
|
|
719
|
-
A: [
|
|
720
|
-
"viewRef.current",
|
|
721
|
-
""
|
|
722
|
-
]
|
|
723
|
-
});
|
|
420
|
+
invariant(viewRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 21, S: void 0, A: ["viewRef.current", ""] });
|
|
724
421
|
onOpenChange?.({
|
|
725
422
|
view: viewRef.current,
|
|
726
423
|
open: open2
|
|
727
424
|
});
|
|
728
425
|
}
|
|
729
426
|
});
|
|
730
|
-
const [root, setRoot] =
|
|
731
|
-
|
|
427
|
+
const [root, setRoot] = useState(null);
|
|
428
|
+
useEffect(() => {
|
|
732
429
|
if (!root) {
|
|
733
430
|
return;
|
|
734
431
|
}
|
|
@@ -753,16 +450,8 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
|
|
|
753
450
|
root,
|
|
754
451
|
onActivate
|
|
755
452
|
]);
|
|
756
|
-
const handleSelect =
|
|
757
|
-
invariant(viewRef.current, void 0, {
|
|
758
|
-
F: __dxlog_file2,
|
|
759
|
-
L: 100,
|
|
760
|
-
S: void 0,
|
|
761
|
-
A: [
|
|
762
|
-
"viewRef.current",
|
|
763
|
-
""
|
|
764
|
-
]
|
|
765
|
-
});
|
|
453
|
+
const handleSelect = useCallback((item) => {
|
|
454
|
+
invariant(viewRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0, A: ["viewRef.current", ""] });
|
|
766
455
|
onSelect?.({
|
|
767
456
|
view: viewRef.current,
|
|
768
457
|
item
|
|
@@ -772,62 +461,63 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
|
|
|
772
461
|
onSelect
|
|
773
462
|
]);
|
|
774
463
|
const menuGroups = groups?.filter((group) => group.items.length > 0) ?? [];
|
|
775
|
-
return /* @__PURE__ */
|
|
464
|
+
return /* @__PURE__ */ React.createElement(Popover.Root, {
|
|
776
465
|
modal: false,
|
|
777
466
|
open,
|
|
778
467
|
onOpenChange: setOpen
|
|
779
|
-
}, /* @__PURE__ */
|
|
468
|
+
}, /* @__PURE__ */ React.createElement(Popover.VirtualTrigger, {
|
|
780
469
|
virtualRef: triggerRef
|
|
781
|
-
}), /* @__PURE__ */
|
|
470
|
+
}), /* @__PURE__ */ React.createElement(Popover.Portal, null, /* @__PURE__ */ React.createElement(Popover.Content, {
|
|
782
471
|
align: "start",
|
|
783
|
-
classNames:
|
|
784
|
-
|
|
785
|
-
}, [
|
|
786
|
-
"overflow-y-auto",
|
|
472
|
+
classNames: [
|
|
473
|
+
"flex flex-col",
|
|
787
474
|
!menuGroups.length && "hidden"
|
|
788
|
-
]
|
|
475
|
+
],
|
|
789
476
|
style: {
|
|
790
477
|
maxBlockSize: 36 * numItems + 10
|
|
791
478
|
},
|
|
792
|
-
|
|
793
|
-
* NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
794
|
-
*/
|
|
479
|
+
// NOTE: We keep the focus in the editor, but Radix routes escape key.
|
|
795
480
|
onEscapeKeyDown: () => {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
481
|
+
const currentView = viewRef.current;
|
|
482
|
+
if (currentView) {
|
|
483
|
+
onCancel?.({
|
|
484
|
+
view: currentView
|
|
485
|
+
});
|
|
486
|
+
}
|
|
799
487
|
},
|
|
800
488
|
onOpenAutoFocus: (event) => event.preventDefault()
|
|
801
|
-
}, /* @__PURE__ */
|
|
802
|
-
|
|
803
|
-
|
|
489
|
+
}, /* @__PURE__ */ React.createElement(Popover.Viewport, {
|
|
490
|
+
asChild: true,
|
|
491
|
+
classNames: "dx-container"
|
|
492
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Root, {
|
|
493
|
+
thin: true
|
|
494
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React.createElement(Menu, {
|
|
804
495
|
groups: menuGroups,
|
|
805
496
|
currentItem,
|
|
806
497
|
onSelect: handleSelect
|
|
807
|
-
})), /* @__PURE__ */
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
className: "contents"
|
|
498
|
+
})))), /* @__PURE__ */ React.createElement(Popover.Arrow, null))), /* @__PURE__ */ React.createElement("div", {
|
|
499
|
+
className: "contents",
|
|
500
|
+
ref: setRoot
|
|
811
501
|
}, children));
|
|
812
502
|
};
|
|
813
503
|
var Menu = ({ groups, currentItem, onSelect }) => {
|
|
814
504
|
const { tx } = useThemeContext();
|
|
815
|
-
return /* @__PURE__ */
|
|
505
|
+
return /* @__PURE__ */ React.createElement("ul", null, groups.map((group, index) => /* @__PURE__ */ React.createElement(Fragment, {
|
|
816
506
|
key: group.id
|
|
817
|
-
}, /* @__PURE__ */
|
|
507
|
+
}, /* @__PURE__ */ React.createElement(MenuGroup, {
|
|
818
508
|
group,
|
|
819
509
|
currentItem,
|
|
820
510
|
onSelect
|
|
821
|
-
}), index < groups.length - 1 && /* @__PURE__ */
|
|
822
|
-
className: tx("menu.separator",
|
|
511
|
+
}), index < groups.length - 1 && /* @__PURE__ */ React.createElement("div", {
|
|
512
|
+
className: tx("menu.separator", {})
|
|
823
513
|
}))));
|
|
824
514
|
};
|
|
825
515
|
var MenuGroup = ({ group, currentItem, onSelect }) => {
|
|
826
516
|
const { tx } = useThemeContext();
|
|
827
517
|
const { t } = useTranslation();
|
|
828
|
-
return /* @__PURE__ */
|
|
829
|
-
className: tx("menu.groupLabel",
|
|
830
|
-
}, /* @__PURE__ */
|
|
518
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, group.label && /* @__PURE__ */ React.createElement("div", {
|
|
519
|
+
className: tx("menu.groupLabel", {})
|
|
520
|
+
}, /* @__PURE__ */ React.createElement("span", null, toLocalizedString(group.label, t))), group.items.map((item) => /* @__PURE__ */ React.createElement(MenuItem, {
|
|
831
521
|
key: item.id,
|
|
832
522
|
item,
|
|
833
523
|
current: currentItem === item.id,
|
|
@@ -837,8 +527,8 @@ var MenuGroup = ({ group, currentItem, onSelect }) => {
|
|
|
837
527
|
var MenuItem = ({ item, current, onSelect }) => {
|
|
838
528
|
const { tx } = useThemeContext();
|
|
839
529
|
const { t } = useTranslation();
|
|
840
|
-
const listRef =
|
|
841
|
-
|
|
530
|
+
const listRef = useRef(null);
|
|
531
|
+
useEffect(() => {
|
|
842
532
|
if (current && listRef.current) {
|
|
843
533
|
listRef.current.scrollIntoView({
|
|
844
534
|
behavior: "smooth",
|
|
@@ -848,56 +538,47 @@ var MenuItem = ({ item, current, onSelect }) => {
|
|
|
848
538
|
}, [
|
|
849
539
|
current
|
|
850
540
|
]);
|
|
851
|
-
const handleSelect =
|
|
541
|
+
const handleSelect = useCallback(() => onSelect?.(item), [
|
|
852
542
|
item,
|
|
853
543
|
onSelect
|
|
854
544
|
]);
|
|
855
|
-
return /* @__PURE__ */
|
|
545
|
+
return /* @__PURE__ */ React.createElement("li", {
|
|
856
546
|
ref: listRef,
|
|
857
|
-
className: tx("menu.item",
|
|
858
|
-
current && "bg-
|
|
547
|
+
className: tx("menu.item", {}, [
|
|
548
|
+
current && "bg-hover-surface"
|
|
859
549
|
]),
|
|
860
550
|
onClick: handleSelect
|
|
861
|
-
}, item.icon && /* @__PURE__ */
|
|
862
|
-
icon: item.icon
|
|
863
|
-
|
|
864
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
551
|
+
}, item.icon && /* @__PURE__ */ React.createElement(Icon, {
|
|
552
|
+
icon: item.icon
|
|
553
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
865
554
|
className: "grow truncate"
|
|
866
555
|
}, toLocalizedString(item.label, t)));
|
|
867
556
|
};
|
|
868
557
|
|
|
869
558
|
// src/components/EditorMenuProvider/useEditorMenu.ts
|
|
870
|
-
import { useCallback as
|
|
559
|
+
import { useCallback as useCallback2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
871
560
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
872
561
|
import { modalStateEffect } from "@dxos/ui-editor";
|
|
873
|
-
var
|
|
562
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/EditorMenuProvider/useEditorMenu.ts";
|
|
874
563
|
var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter = true, getMenu }) => {
|
|
875
|
-
const groupsRef =
|
|
876
|
-
const currentRef =
|
|
877
|
-
const [currentItem, setCurrentItem] =
|
|
878
|
-
const [open, setOpen] =
|
|
879
|
-
const [_, refresh] =
|
|
880
|
-
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 }) => {
|
|
881
570
|
const groups = await getMenu?.({
|
|
882
571
|
text,
|
|
883
572
|
trigger: trigger2,
|
|
884
573
|
...props
|
|
885
574
|
}) ?? [];
|
|
886
|
-
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;
|
|
887
576
|
}, [
|
|
888
577
|
getMenu,
|
|
889
578
|
filter
|
|
890
579
|
]);
|
|
891
|
-
const handleOpenChange =
|
|
892
|
-
invariant2(view, void 0, {
|
|
893
|
-
F: __dxlog_file3,
|
|
894
|
-
L: 76,
|
|
895
|
-
S: void 0,
|
|
896
|
-
A: [
|
|
897
|
-
"view",
|
|
898
|
-
""
|
|
899
|
-
]
|
|
900
|
-
});
|
|
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", ""] });
|
|
901
582
|
setOpen(open2);
|
|
902
583
|
if (!open2) {
|
|
903
584
|
setCurrentItem(void 0);
|
|
@@ -917,7 +598,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
917
598
|
}, [
|
|
918
599
|
getMenuOptions
|
|
919
600
|
]);
|
|
920
|
-
const handleActivate =
|
|
601
|
+
const handleActivate = useCallback2(async ({ view, trigger: trigger2 }) => {
|
|
921
602
|
const item = getMenuItem(groupsRef.current, currentItem);
|
|
922
603
|
if (item) {
|
|
923
604
|
currentRef.current = item;
|
|
@@ -933,13 +614,24 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
933
614
|
open,
|
|
934
615
|
handleOpenChange
|
|
935
616
|
]);
|
|
936
|
-
const handleSelect =
|
|
617
|
+
const handleSelect = useCallback2(({ view, item }) => {
|
|
618
|
+
const { range } = view.state.field(popoverStateField) ?? {};
|
|
619
|
+
if (range) {
|
|
620
|
+
view.dispatch({
|
|
621
|
+
changes: {
|
|
622
|
+
from: range.from,
|
|
623
|
+
to: range.to,
|
|
624
|
+
insert: ""
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
937
628
|
void item.onSelect?.({
|
|
938
629
|
view,
|
|
939
630
|
head: view.state.selection.main.head
|
|
940
631
|
});
|
|
632
|
+
view.focus();
|
|
941
633
|
}, []);
|
|
942
|
-
const handleCancel =
|
|
634
|
+
const handleCancel = useCallback2(({ view }) => {
|
|
943
635
|
const { range, trigger: trigger2 } = view.state.field(popoverStateField) ?? {};
|
|
944
636
|
if (range && trigger2) {
|
|
945
637
|
view.dispatch({
|
|
@@ -951,7 +643,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
951
643
|
}
|
|
952
644
|
}, []);
|
|
953
645
|
const serializedTrigger = Array.isArray(trigger) ? trigger.join(",") : trigger;
|
|
954
|
-
const extension =
|
|
646
|
+
const extension = useMemo(() => {
|
|
955
647
|
return popover({
|
|
956
648
|
trigger,
|
|
957
649
|
triggerKey,
|
|
@@ -1017,150 +709,70 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
|
|
|
1017
709
|
|
|
1018
710
|
// src/components/EditorToolbar/EditorToolbar.tsx
|
|
1019
711
|
import { Atom } from "@effect-atom/atom-react";
|
|
1020
|
-
import
|
|
712
|
+
import React2, { memo, useMemo as useMemo2 } from "react";
|
|
1021
713
|
import { ElevationProvider } from "@dxos/react-ui";
|
|
1022
|
-
import {
|
|
714
|
+
import { Menu as Menu2, MenuBuilder, useMenuActions } from "@dxos/react-ui-menu";
|
|
1023
715
|
|
|
1024
|
-
// src/components/EditorToolbar/
|
|
1025
|
-
import {
|
|
1026
|
-
import {
|
|
1027
|
-
var
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
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"
|
|
1031
723
|
};
|
|
1032
|
-
var
|
|
1033
|
-
const value = state.
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
nodes: [
|
|
1038
|
-
listGroupAction,
|
|
1039
|
-
...listActionsMap
|
|
1040
|
-
],
|
|
1041
|
-
edges: [
|
|
724
|
+
var addBlocks = (state, getView) => (builder) => {
|
|
725
|
+
const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
|
|
726
|
+
builder.group("block", {
|
|
727
|
+
label: [
|
|
728
|
+
"block.label",
|
|
1042
729
|
{
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
...listActionsMap.map(({ id }) => ({
|
|
1047
|
-
source: listGroupAction.id,
|
|
1048
|
-
target: id
|
|
1049
|
-
}))
|
|
1050
|
-
]
|
|
1051
|
-
};
|
|
1052
|
-
};
|
|
1053
|
-
var createEditorAction = (id, props, invoke) => {
|
|
1054
|
-
const { label = [
|
|
1055
|
-
`${id} label`,
|
|
1056
|
-
{
|
|
1057
|
-
ns: translationKey
|
|
1058
|
-
}
|
|
1059
|
-
], ...rest } = props;
|
|
1060
|
-
return createMenuAction(id, invoke, {
|
|
1061
|
-
label,
|
|
1062
|
-
...rest
|
|
1063
|
-
});
|
|
1064
|
-
};
|
|
1065
|
-
var createEditorActionGroup = (id, props, icon) => {
|
|
1066
|
-
const { label = [
|
|
1067
|
-
`${id} label`,
|
|
1068
|
-
{
|
|
1069
|
-
ns: translationKey
|
|
1070
|
-
}
|
|
1071
|
-
], ...rest } = props;
|
|
1072
|
-
return createMenuItemGroup(id, {
|
|
1073
|
-
label,
|
|
1074
|
-
icon,
|
|
730
|
+
ns: translationKey
|
|
731
|
+
}
|
|
732
|
+
],
|
|
1075
733
|
iconOnly: true,
|
|
1076
|
-
|
|
1077
|
-
|
|
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
|
-
blockquote: "ph--quotes--regular",
|
|
1112
|
-
codeblock: "ph--code-block--regular",
|
|
1113
|
-
table: "ph--table--regular"
|
|
1114
|
-
}).map(([type, icon]) => {
|
|
1115
|
-
const checked = type === value;
|
|
1116
|
-
return createEditorAction(type, {
|
|
1117
|
-
checked,
|
|
1118
|
-
...type === "table" && {
|
|
1119
|
-
disabled: !!blankLine
|
|
1120
|
-
},
|
|
1121
|
-
icon
|
|
1122
|
-
}, () => {
|
|
1123
|
-
const view = getView();
|
|
1124
|
-
if (!view) {
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
switch (type) {
|
|
1128
|
-
case "blockquote":
|
|
1129
|
-
checked ? removeBlockquote(view) : addBlockquote(view);
|
|
1130
|
-
break;
|
|
1131
|
-
case "codeblock":
|
|
1132
|
-
checked ? removeCodeblock(view) : addCodeblock(view);
|
|
1133
|
-
break;
|
|
1134
|
-
case "table":
|
|
1135
|
-
insertTable(view);
|
|
1136
|
-
break;
|
|
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
|
+
});
|
|
1137
769
|
}
|
|
1138
770
|
});
|
|
1139
|
-
});
|
|
1140
|
-
var createBlocks = (state, getView) => {
|
|
1141
|
-
const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
|
|
1142
|
-
const blockGroupAction = createBlockGroupAction(value);
|
|
1143
|
-
const blockActions = createBlockActions(value, getView, state.blankLine);
|
|
1144
|
-
return {
|
|
1145
|
-
nodes: [
|
|
1146
|
-
blockGroupAction,
|
|
1147
|
-
...blockActions
|
|
1148
|
-
],
|
|
1149
|
-
edges: [
|
|
1150
|
-
{
|
|
1151
|
-
source: "root",
|
|
1152
|
-
target: "block"
|
|
1153
|
-
},
|
|
1154
|
-
...blockActions.map(({ id }) => ({
|
|
1155
|
-
source: blockGroupAction.id,
|
|
1156
|
-
target: id
|
|
1157
|
-
}))
|
|
1158
|
-
]
|
|
1159
|
-
};
|
|
1160
771
|
};
|
|
1161
772
|
|
|
1162
773
|
// src/components/EditorToolbar/formatting.ts
|
|
1163
774
|
import { Inline, addLink, removeLink, setStyle } from "@dxos/ui-editor";
|
|
775
|
+
import { translationKey as translationKey2 } from "#translations";
|
|
1164
776
|
var formats = {
|
|
1165
777
|
strong: "ph--text-b--regular",
|
|
1166
778
|
emphasis: "ph--text-italic--regular",
|
|
@@ -1168,205 +780,231 @@ var formats = {
|
|
|
1168
780
|
code: "ph--code--regular",
|
|
1169
781
|
link: "ph--link--regular"
|
|
1170
782
|
};
|
|
1171
|
-
var
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
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
|
+
});
|
|
1189
819
|
}
|
|
1190
|
-
const inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
1191
|
-
setStyle(inlineType, !checked)(view);
|
|
1192
820
|
});
|
|
1193
|
-
});
|
|
1194
|
-
var createFormatting = (state, getView) => {
|
|
1195
|
-
const formattingGroupAction = createFormattingGroup(state);
|
|
1196
|
-
const formattingActions = createFormattingActions(state, getView);
|
|
1197
|
-
return {
|
|
1198
|
-
nodes: [
|
|
1199
|
-
formattingGroupAction,
|
|
1200
|
-
...formattingActions
|
|
1201
|
-
],
|
|
1202
|
-
edges: [
|
|
1203
|
-
{
|
|
1204
|
-
source: "root",
|
|
1205
|
-
target: "formatting"
|
|
1206
|
-
},
|
|
1207
|
-
...formattingActions.map(({ id }) => ({
|
|
1208
|
-
source: formattingGroupAction.id,
|
|
1209
|
-
target: id
|
|
1210
|
-
}))
|
|
1211
|
-
]
|
|
1212
|
-
};
|
|
1213
821
|
};
|
|
1214
822
|
|
|
1215
823
|
// src/components/EditorToolbar/headings.ts
|
|
1216
824
|
import { setHeading } from "@dxos/ui-editor";
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
"2": "ph--text-h-two--regular",
|
|
1228
|
-
"3": "ph--text-h-three--regular",
|
|
1229
|
-
"4": "ph--text-h-four--regular",
|
|
1230
|
-
"5": "ph--text-h-five--regular",
|
|
1231
|
-
"6": "ph--text-h-six--regular"
|
|
1232
|
-
}).map(([levelStr, icon]) => {
|
|
1233
|
-
const level = parseInt(levelStr);
|
|
1234
|
-
return createEditorAction(`heading--${levelStr}`, {
|
|
1235
|
-
label: [
|
|
1236
|
-
"heading level label",
|
|
1237
|
-
{
|
|
1238
|
-
count: level,
|
|
1239
|
-
ns: translationKey
|
|
1240
|
-
}
|
|
1241
|
-
],
|
|
1242
|
-
icon,
|
|
1243
|
-
checked: levelStr === currentLevel
|
|
1244
|
-
}, () => setHeading(level)(getView()));
|
|
1245
|
-
});
|
|
825
|
+
import { translationKey as translationKey3 } from "#translations";
|
|
826
|
+
var headingIcons = {
|
|
827
|
+
0: "ph--paragraph--regular",
|
|
828
|
+
1: "ph--text-h-one--regular",
|
|
829
|
+
2: "ph--text-h-two--regular",
|
|
830
|
+
3: "ph--text-h-three--regular",
|
|
831
|
+
4: "ph--text-h-four--regular",
|
|
832
|
+
5: "ph--text-h-five--regular",
|
|
833
|
+
6: "ph--text-h-six--regular"
|
|
834
|
+
};
|
|
1246
835
|
var computeHeadingValue = (state) => {
|
|
1247
836
|
const blockType = state ? state.blockType : "paragraph";
|
|
1248
837
|
const heading = blockType && /heading(\d)/.exec(blockType);
|
|
1249
838
|
return heading ? heading[1] : blockType === "paragraph" || !blockType ? "0" : "";
|
|
1250
839
|
};
|
|
1251
|
-
var
|
|
840
|
+
var addHeadings = (state, getView) => (builder) => {
|
|
1252
841
|
const headingValue = computeHeadingValue(state);
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
nodes: [
|
|
1257
|
-
headingGroupAction,
|
|
1258
|
-
...headingActions
|
|
1259
|
-
],
|
|
1260
|
-
edges: [
|
|
842
|
+
builder.group("heading", {
|
|
843
|
+
label: [
|
|
844
|
+
"heading.label",
|
|
1261
845
|
{
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
+
});
|
|
1271
872
|
};
|
|
1272
873
|
|
|
1273
874
|
// src/components/EditorToolbar/image.ts
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
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
|
+
});
|
|
1286
934
|
}
|
|
1287
|
-
|
|
1288
|
-
}
|
|
935
|
+
});
|
|
936
|
+
};
|
|
1289
937
|
|
|
1290
938
|
// src/components/EditorToolbar/search.ts
|
|
1291
939
|
import { openSearchPanel } from "@codemirror/search";
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
]
|
|
1306
|
-
});
|
|
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
|
+
};
|
|
1307
953
|
|
|
1308
954
|
// src/components/EditorToolbar/view-mode.ts
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
applyActive: true,
|
|
1312
|
-
selectCardinality: "single",
|
|
1313
|
-
value
|
|
1314
|
-
}, "ph--eye--regular");
|
|
1315
|
-
var createViewModeActions = (value, onViewModeChange) => Object.entries({
|
|
955
|
+
import { translationKey as translationKey7 } from "#translations";
|
|
956
|
+
var viewModes = {
|
|
1316
957
|
preview: "ph--eye--regular",
|
|
1317
958
|
source: "ph--pencil-simple--regular",
|
|
1318
959
|
readonly: "ph--pencil-slash--regular"
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
|
|
960
|
+
};
|
|
961
|
+
var addViewMode = (state, onViewModeChange) => (builder) => {
|
|
962
|
+
const value = state.viewMode ?? "source";
|
|
963
|
+
builder.group("viewMode", {
|
|
1322
964
|
label: [
|
|
1323
|
-
|
|
965
|
+
"view-mode.label",
|
|
1324
966
|
{
|
|
1325
|
-
ns:
|
|
967
|
+
ns: translationKey7
|
|
1326
968
|
}
|
|
1327
969
|
],
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}))
|
|
1350
|
-
]
|
|
1351
|
-
};
|
|
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
|
+
});
|
|
1352
991
|
};
|
|
1353
992
|
|
|
1354
993
|
// src/components/EditorToolbar/EditorToolbar.tsx
|
|
1355
994
|
var EditorToolbar = /* @__PURE__ */ memo(({ classNames, role, attendableId, onAction, ...props }) => {
|
|
1356
|
-
const
|
|
1357
|
-
return /* @__PURE__ */
|
|
995
|
+
const menuActions = useMarkdownMenuActions(props);
|
|
996
|
+
return /* @__PURE__ */ React2.createElement(ElevationProvider, {
|
|
1358
997
|
elevation: role === "section" ? "positioned" : "base"
|
|
1359
|
-
}, /* @__PURE__ */
|
|
1360
|
-
...
|
|
998
|
+
}, /* @__PURE__ */ React2.createElement(Menu2.Root, {
|
|
999
|
+
...menuActions,
|
|
1361
1000
|
attendableId,
|
|
1362
1001
|
onAction
|
|
1363
|
-
}, /* @__PURE__ */
|
|
1364
|
-
classNames
|
|
1365
|
-
textBlockWidth: true
|
|
1002
|
+
}, /* @__PURE__ */ React2.createElement(Menu2.Toolbar, {
|
|
1003
|
+
classNames
|
|
1366
1004
|
})));
|
|
1367
1005
|
});
|
|
1368
|
-
var
|
|
1369
|
-
const menuCreator =
|
|
1006
|
+
var useMarkdownMenuActions = ({ state, getView, customActions, ...features }) => {
|
|
1007
|
+
const menuCreator = useMemo2(() => createMarkdownActions({
|
|
1370
1008
|
state,
|
|
1371
1009
|
getView,
|
|
1372
1010
|
customActions,
|
|
@@ -1385,63 +1023,300 @@ var useEditorToolbarActionGraph = ({ state, getView, customActions, ...features
|
|
|
1385
1023
|
]);
|
|
1386
1024
|
return useMenuActions(menuCreator);
|
|
1387
1025
|
};
|
|
1388
|
-
var
|
|
1026
|
+
var createMarkdownActions = ({ state, getView, customActions, ...features }) => {
|
|
1389
1027
|
return Atom.make((get) => {
|
|
1390
|
-
const graph = {
|
|
1391
|
-
nodes: [],
|
|
1392
|
-
edges: []
|
|
1393
|
-
};
|
|
1394
|
-
const addSubGraph = (graph2, subGraph) => {
|
|
1395
|
-
graph2.nodes.push(...subGraph.nodes);
|
|
1396
|
-
graph2.edges.push(...subGraph.edges);
|
|
1397
|
-
};
|
|
1398
1028
|
const stateSnapshot = get(state);
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
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, useRef as useRef4 } 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);
|
|
1410
1132
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
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
|
+
}
|
|
1413
1156
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1157
|
+
}, [
|
|
1158
|
+
view,
|
|
1159
|
+
scrollTo,
|
|
1160
|
+
selection
|
|
1161
|
+
]);
|
|
1162
|
+
useEffect2(() => {
|
|
1163
|
+
if (view && autoFocus) {
|
|
1164
|
+
view.focus();
|
|
1417
1165
|
}
|
|
1418
|
-
|
|
1419
|
-
|
|
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
|
+
}
|
|
1420
1189
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1190
|
+
}, [
|
|
1191
|
+
view
|
|
1192
|
+
]);
|
|
1193
|
+
return {
|
|
1194
|
+
parentRef,
|
|
1195
|
+
view,
|
|
1196
|
+
focusAttributes: {
|
|
1197
|
+
tabIndex: 0,
|
|
1198
|
+
onKeyDown: handleKeyDown
|
|
1423
1199
|
}
|
|
1424
|
-
|
|
1425
|
-
});
|
|
1200
|
+
};
|
|
1426
1201
|
};
|
|
1427
1202
|
|
|
1428
|
-
// src/components/
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
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
|
+
};
|
|
1433
1240
|
};
|
|
1434
1241
|
|
|
1242
|
+
// src/components/Editor/EditorView.tsx
|
|
1243
|
+
var EditorView3 = /* @__PURE__ */ forwardRef(({ classNames, id, extensions, selectionEnd, focusable = true, value, onChange, ...props }, forwardedRef) => {
|
|
1244
|
+
const onChangeRef = useRef4(onChange);
|
|
1245
|
+
onChangeRef.current = onChange;
|
|
1246
|
+
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
1247
|
+
id,
|
|
1248
|
+
initialValue: value,
|
|
1249
|
+
selectionEnd,
|
|
1250
|
+
extensions: [
|
|
1251
|
+
extensions ?? [],
|
|
1252
|
+
NaturalEditorView.updateListener.of(({ view: view2, docChanged, transactions }) => {
|
|
1253
|
+
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
|
|
1254
|
+
if (!isInitialSync && docChanged) {
|
|
1255
|
+
onChangeRef.current?.(view2.state.doc.toString());
|
|
1256
|
+
}
|
|
1257
|
+
})
|
|
1258
|
+
],
|
|
1259
|
+
...props
|
|
1260
|
+
}), [
|
|
1261
|
+
id,
|
|
1262
|
+
extensions,
|
|
1263
|
+
selectionEnd
|
|
1264
|
+
]);
|
|
1265
|
+
useImperativeHandle(forwardedRef, () => {
|
|
1266
|
+
return createEditorController(view);
|
|
1267
|
+
}, [
|
|
1268
|
+
id,
|
|
1269
|
+
view
|
|
1270
|
+
]);
|
|
1271
|
+
useEffect3(() => {
|
|
1272
|
+
if (!view) {
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const next = value ?? "";
|
|
1276
|
+
if (view.state.doc.toString() === next) {
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
requestAnimationFrame(() => {
|
|
1280
|
+
if (view.state.doc.toString() === next) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
view.dispatch({
|
|
1284
|
+
annotations: initialSync,
|
|
1285
|
+
changes: [
|
|
1286
|
+
{
|
|
1287
|
+
from: 0,
|
|
1288
|
+
to: view.state.doc.length,
|
|
1289
|
+
insert: next
|
|
1290
|
+
}
|
|
1291
|
+
],
|
|
1292
|
+
selection: selectionEnd ? {
|
|
1293
|
+
anchor: next.length
|
|
1294
|
+
} : void 0
|
|
1295
|
+
});
|
|
1296
|
+
if (selectionEnd) {
|
|
1297
|
+
view.focus();
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
}, [
|
|
1301
|
+
view,
|
|
1302
|
+
value,
|
|
1303
|
+
selectionEnd
|
|
1304
|
+
]);
|
|
1305
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
1306
|
+
className: mx("w-full outline-hidden focus:border-accent-surface focus-within:border-focus-ring-subtle", classNames),
|
|
1307
|
+
...focusable ? focusAttributes : {},
|
|
1308
|
+
ref: parentRef
|
|
1309
|
+
});
|
|
1310
|
+
});
|
|
1311
|
+
|
|
1435
1312
|
// src/components/Editor/Editor.tsx
|
|
1436
1313
|
var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/Editor/Editor.tsx";
|
|
1437
1314
|
var [EditorContextProvider, useEditorContext] = createContext("Editor");
|
|
1438
|
-
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, ...props }, forwardedRef) => {
|
|
1439
|
-
const state =
|
|
1315
|
+
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, numItems, ...props }, forwardedRef) => {
|
|
1316
|
+
const state = useMemo5(() => Atom2.make({
|
|
1317
|
+
viewMode
|
|
1318
|
+
}), [
|
|
1440
1319
|
viewMode
|
|
1441
|
-
});
|
|
1442
|
-
const [controller, setController] = useState4();
|
|
1443
|
-
useImperativeHandle2(forwardedRef, () => controller ?? noopController, [
|
|
1444
|
-
controller
|
|
1445
1320
|
]);
|
|
1446
1321
|
const { groupsRef, extension, ...menuProps } = useEditorMenu(props);
|
|
1447
1322
|
const extensions = useMemo5(() => [
|
|
@@ -1451,6 +1326,10 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1451
1326
|
extension,
|
|
1452
1327
|
extensionsProp
|
|
1453
1328
|
]);
|
|
1329
|
+
const [controller, setController] = useState4(noopController);
|
|
1330
|
+
useImperativeHandle2(forwardedRef, () => controller, [
|
|
1331
|
+
controller
|
|
1332
|
+
]);
|
|
1454
1333
|
return /* @__PURE__ */ React4.createElement(EditorContextProvider, {
|
|
1455
1334
|
controller,
|
|
1456
1335
|
setController,
|
|
@@ -1459,21 +1338,21 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1459
1338
|
}, /* @__PURE__ */ React4.createElement(EditorMenuProvider, {
|
|
1460
1339
|
view: controller?.view,
|
|
1461
1340
|
groups: groupsRef.current,
|
|
1341
|
+
numItems,
|
|
1462
1342
|
...menuProps
|
|
1463
1343
|
}, children));
|
|
1464
1344
|
});
|
|
1465
1345
|
EditorRoot.displayName = "Editor.Root";
|
|
1466
|
-
var
|
|
1467
|
-
var
|
|
1346
|
+
var EDITOR_CONTENT_NAME = "Editor.Content";
|
|
1347
|
+
var EditorContent = ({ classNames, children }) => {
|
|
1468
1348
|
return /* @__PURE__ */ React4.createElement("div", {
|
|
1469
|
-
|
|
1470
|
-
className: mx2("grid grid-rows-[min-content_1fr] bs-full overflow-hidden", classNames)
|
|
1349
|
+
className: mx2("grid grid-rows-[min-content_1fr] h-full overflow-hidden", classNames)
|
|
1471
1350
|
}, children);
|
|
1472
1351
|
};
|
|
1473
|
-
|
|
1474
|
-
var
|
|
1475
|
-
var
|
|
1476
|
-
const { extensions: additionalExtensions = [], setController } = useEditorContext(
|
|
1352
|
+
EditorContent.displayName = EDITOR_CONTENT_NAME;
|
|
1353
|
+
var EDITOR_VIEW_NAME = "Editor.View";
|
|
1354
|
+
var EditorView4 = ({ extensions: providedExtensions, ...props }) => {
|
|
1355
|
+
const { extensions: additionalExtensions = [], setController } = useEditorContext(EDITOR_VIEW_NAME);
|
|
1477
1356
|
const extensions = useMemo5(() => [
|
|
1478
1357
|
additionalExtensions,
|
|
1479
1358
|
providedExtensions
|
|
@@ -1481,26 +1360,18 @@ var EditorContent2 = ({ extensions: providedExtensions, ...props }) => {
|
|
|
1481
1360
|
providedExtensions,
|
|
1482
1361
|
additionalExtensions
|
|
1483
1362
|
]);
|
|
1484
|
-
return /* @__PURE__ */ React4.createElement(
|
|
1363
|
+
return /* @__PURE__ */ React4.createElement(EditorView3, {
|
|
1485
1364
|
...props,
|
|
1486
1365
|
extensions,
|
|
1487
1366
|
ref: setController
|
|
1488
1367
|
});
|
|
1489
1368
|
};
|
|
1490
|
-
|
|
1369
|
+
EditorView4.displayName = EDITOR_VIEW_NAME;
|
|
1491
1370
|
var EDITOR_TOOLBAR_NAME = "Editor.Toolbar";
|
|
1492
1371
|
var EditorToolbar2 = (props) => {
|
|
1493
1372
|
const { controller, state } = useEditorContext(EDITOR_TOOLBAR_NAME);
|
|
1494
1373
|
const getView = useCallback4(() => {
|
|
1495
|
-
invariant3(controller?.view, void 0, {
|
|
1496
|
-
F: __dxlog_file4,
|
|
1497
|
-
L: 146,
|
|
1498
|
-
S: void 0,
|
|
1499
|
-
A: [
|
|
1500
|
-
"controller?.view",
|
|
1501
|
-
""
|
|
1502
|
-
]
|
|
1503
|
-
});
|
|
1374
|
+
invariant3(controller?.view, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 99, S: void 0, A: ["controller?.view", ""] });
|
|
1504
1375
|
return controller?.view;
|
|
1505
1376
|
}, [
|
|
1506
1377
|
controller
|
|
@@ -1514,19 +1385,19 @@ var EditorToolbar2 = (props) => {
|
|
|
1514
1385
|
EditorToolbar2.displayName = EDITOR_TOOLBAR_NAME;
|
|
1515
1386
|
var Editor = {
|
|
1516
1387
|
Root: EditorRoot,
|
|
1517
|
-
|
|
1518
|
-
Content:
|
|
1519
|
-
|
|
1388
|
+
Toolbar: EditorToolbar2,
|
|
1389
|
+
Content: EditorContent,
|
|
1390
|
+
View: EditorView4
|
|
1520
1391
|
};
|
|
1521
1392
|
|
|
1522
1393
|
// src/components/EditorPreviewProvider/EditorPreviewProvider.tsx
|
|
1523
1394
|
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
1524
|
-
import React5, { useCallback as useCallback5, useEffect as useEffect4, useRef as
|
|
1395
|
+
import React5, { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
|
|
1525
1396
|
import { addEventListener as addEventListener2 } from "@dxos/async";
|
|
1526
1397
|
import { DX_ANCHOR_ACTIVATE as DX_ANCHOR_ACTIVATE2, Popover as Popover2 } from "@dxos/react-ui";
|
|
1527
1398
|
var [EditorPreviewContextProvider, useEditorPreview] = createContext2("PreviewPopover", {});
|
|
1528
1399
|
var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
1529
|
-
const triggerRef =
|
|
1400
|
+
const triggerRef = useRef5(null);
|
|
1530
1401
|
const [value, setValue] = useState5({});
|
|
1531
1402
|
const [open, setOpen] = useState5(false);
|
|
1532
1403
|
const handleActivate = useCallback5((event) => {
|
|
@@ -1575,17 +1446,187 @@ var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
|
1575
1446
|
}, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
|
|
1576
1447
|
virtualRef: triggerRef
|
|
1577
1448
|
}), /* @__PURE__ */ React5.createElement("div", {
|
|
1578
|
-
role: "none",
|
|
1579
1449
|
className: "contents",
|
|
1580
1450
|
ref: setRoot
|
|
1581
1451
|
}, children)));
|
|
1582
1452
|
};
|
|
1453
|
+
|
|
1454
|
+
// src/extensions/assistant-extension.tsx
|
|
1455
|
+
import { forEachDiagnostic, linter, setDiagnostics } from "@codemirror/lint";
|
|
1456
|
+
import { ChangeSet } from "@codemirror/state";
|
|
1457
|
+
import { EditorView as EditorView5 } from "@codemirror/view";
|
|
1458
|
+
import { log as log2 } from "@dxos/log";
|
|
1459
|
+
import { safeParseJson, trim } from "@dxos/util";
|
|
1460
|
+
var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/extensions/assistant-extension.tsx";
|
|
1461
|
+
var DEFAULT_INSTRUCTIONS = trim`
|
|
1462
|
+
Proofread the input text below.
|
|
1463
|
+
Identify typos and grammatical errors.
|
|
1464
|
+
Return ONLY a valid JSON array of objects with fields: "original" (string), "replacement" (string), "context" (string, 3-5 words around match).
|
|
1465
|
+
--
|
|
1466
|
+
`;
|
|
1467
|
+
var underline = (color) => {
|
|
1468
|
+
const svg = trim`
|
|
1469
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="3">
|
|
1470
|
+
<path d="m0 3 l2 -2 l1 0 l2 2 l1 0" stroke="${color}" fill="none" stroke-width="1"/>
|
|
1471
|
+
</svg>
|
|
1472
|
+
`;
|
|
1473
|
+
return `url('data:image/svg+xml;base64,${btoa(svg)}') !important`;
|
|
1474
|
+
};
|
|
1475
|
+
var assistant = (options) => {
|
|
1476
|
+
const styles = getComputedStyle(document.documentElement);
|
|
1477
|
+
const style = {
|
|
1478
|
+
info: styles.getPropertyValue("--color-green-500").trim(),
|
|
1479
|
+
warning: styles.getPropertyValue("--color-orange-500").trim(),
|
|
1480
|
+
error: styles.getPropertyValue("--color-rose-500").trim()
|
|
1481
|
+
};
|
|
1482
|
+
return [
|
|
1483
|
+
assistantLinter(options),
|
|
1484
|
+
EditorView5.baseTheme({
|
|
1485
|
+
".cm-lintRange-info": {
|
|
1486
|
+
backgroundImage: underline(style.info)
|
|
1487
|
+
},
|
|
1488
|
+
".cm-lintRange-warning": {
|
|
1489
|
+
backgroundImage: underline(style.warning)
|
|
1490
|
+
},
|
|
1491
|
+
".cm-lintRange-error": {
|
|
1492
|
+
backgroundImage: underline(style.error)
|
|
1493
|
+
},
|
|
1494
|
+
".cm-panels-bottom": {
|
|
1495
|
+
borderTop: "1px solid var(--color-separator) !important"
|
|
1496
|
+
},
|
|
1497
|
+
".cm-panel-lint .cm-panel": {
|
|
1498
|
+
outline: "none !important"
|
|
1499
|
+
},
|
|
1500
|
+
/** @apply dx-button */
|
|
1501
|
+
".cm-panel button": {
|
|
1502
|
+
color: "var(--color-base-foreground) !important"
|
|
1503
|
+
},
|
|
1504
|
+
".cm-panel.cm-panel-lint ul": {
|
|
1505
|
+
color: "var(--color-base-foreground) !important",
|
|
1506
|
+
backgroundColor: "var(--color-base-surface) !important",
|
|
1507
|
+
marginRight: "2rem !important"
|
|
1508
|
+
},
|
|
1509
|
+
".cm-panel.cm-panel-lint ul [aria-selected]": {
|
|
1510
|
+
color: "var(--color-base-foreground) !important",
|
|
1511
|
+
backgroundColor: "var(--color-base-surface) !important"
|
|
1512
|
+
},
|
|
1513
|
+
".cm-panel.cm-panel-lint ul li": {
|
|
1514
|
+
display: "grid",
|
|
1515
|
+
gridTemplateColumns: "1fr auto",
|
|
1516
|
+
alignItems: "center"
|
|
1517
|
+
},
|
|
1518
|
+
".cm-panel.cm-panel-lint ul li .cm-diagnosticText": {
|
|
1519
|
+
paddingRight: "8px !important"
|
|
1520
|
+
},
|
|
1521
|
+
".cm-panel.cm-panel-lint ul li button.cm-diagnosticAction": {
|
|
1522
|
+
margin: "none !important"
|
|
1523
|
+
},
|
|
1524
|
+
".cm-diagnostic": {
|
|
1525
|
+
padding: "0px 8px !important",
|
|
1526
|
+
whiteSpace: "pre-wrap !important"
|
|
1527
|
+
},
|
|
1528
|
+
".cm-diagnostic-info": {
|
|
1529
|
+
border: "none !important"
|
|
1530
|
+
}
|
|
1531
|
+
})
|
|
1532
|
+
];
|
|
1533
|
+
};
|
|
1534
|
+
var isSuggestion = (value) => typeof value === "object" && value !== null && typeof value.original === "string" && typeof value.replacement === "string" && typeof value.context === "string";
|
|
1535
|
+
var findSuggestionIndex = (content, suggestion) => {
|
|
1536
|
+
const firstIdx = content.indexOf(suggestion.original);
|
|
1537
|
+
if (firstIdx === -1) {
|
|
1538
|
+
return -1;
|
|
1539
|
+
}
|
|
1540
|
+
const secondIdx = content.indexOf(suggestion.original, firstIdx + 1);
|
|
1541
|
+
if (secondIdx === -1) {
|
|
1542
|
+
return firstIdx;
|
|
1543
|
+
}
|
|
1544
|
+
const contextIdx = content.indexOf(suggestion.context);
|
|
1545
|
+
if (contextIdx !== -1) {
|
|
1546
|
+
const contextEnd = contextIdx + suggestion.context.length;
|
|
1547
|
+
if (secondIdx >= contextIdx && secondIdx <= contextEnd) {
|
|
1548
|
+
return secondIdx;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
return firstIdx;
|
|
1552
|
+
};
|
|
1553
|
+
var replaceTextAndDropLintAtRange = (view, from, to, insert) => {
|
|
1554
|
+
const kept = [];
|
|
1555
|
+
forEachDiagnostic(view.state, (diagnostic, diagnosticFrom, diagnosticTo) => {
|
|
1556
|
+
if (diagnosticFrom < to && diagnosticTo > from) {
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
kept.push({
|
|
1560
|
+
...diagnostic,
|
|
1561
|
+
from: diagnosticFrom,
|
|
1562
|
+
to: diagnosticTo
|
|
1563
|
+
});
|
|
1564
|
+
});
|
|
1565
|
+
const changeSet = ChangeSet.of({
|
|
1566
|
+
from,
|
|
1567
|
+
to,
|
|
1568
|
+
insert
|
|
1569
|
+
}, view.state.doc.length);
|
|
1570
|
+
const next = kept.map((d) => ({
|
|
1571
|
+
...d,
|
|
1572
|
+
from: changeSet.mapPos(d.from, 1),
|
|
1573
|
+
to: changeSet.mapPos(d.to, -1)
|
|
1574
|
+
}));
|
|
1575
|
+
view.dispatch({
|
|
1576
|
+
changes: {
|
|
1577
|
+
from,
|
|
1578
|
+
to,
|
|
1579
|
+
insert
|
|
1580
|
+
},
|
|
1581
|
+
...setDiagnostics(view.state, next)
|
|
1582
|
+
});
|
|
1583
|
+
};
|
|
1584
|
+
var assistantLinter = ({ generate, instructions = DEFAULT_INSTRUCTIONS, autoPanel = true, delay = 2e3 }) => linter(async (view) => {
|
|
1585
|
+
try {
|
|
1586
|
+
const content = view.state.doc.toString();
|
|
1587
|
+
const result = await generate({
|
|
1588
|
+
instructions,
|
|
1589
|
+
content
|
|
1590
|
+
});
|
|
1591
|
+
const [match] = result.match(/\[.*\]/s) ?? [];
|
|
1592
|
+
const parsed = match ? safeParseJson(match, []) : [];
|
|
1593
|
+
const suggestions = Array.isArray(parsed) ? parsed.filter(isSuggestion) : [];
|
|
1594
|
+
if (suggestions && suggestions.length > 0) {
|
|
1595
|
+
const diagnostics = [];
|
|
1596
|
+
for (const suggestion of suggestions) {
|
|
1597
|
+
const idx = findSuggestionIndex(content, suggestion);
|
|
1598
|
+
if (idx !== -1) {
|
|
1599
|
+
diagnostics.push({
|
|
1600
|
+
from: idx,
|
|
1601
|
+
to: idx + suggestion.original.length,
|
|
1602
|
+
severity: "info",
|
|
1603
|
+
message: `Suggestion: ${suggestion.replacement}`,
|
|
1604
|
+
actions: [
|
|
1605
|
+
{
|
|
1606
|
+
name: "Apply",
|
|
1607
|
+
apply: (view2, from, to) => {
|
|
1608
|
+
replaceTextAndDropLintAtRange(view2, from, to, suggestion.replacement);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
]
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
return diagnostics;
|
|
1616
|
+
}
|
|
1617
|
+
} catch (err) {
|
|
1618
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 169, S: void 0 });
|
|
1619
|
+
}
|
|
1620
|
+
return [];
|
|
1621
|
+
}, {
|
|
1622
|
+
delay,
|
|
1623
|
+
autoPanel
|
|
1624
|
+
});
|
|
1583
1625
|
export {
|
|
1584
1626
|
Editor,
|
|
1585
|
-
EditorContent,
|
|
1586
1627
|
EditorMenuProvider,
|
|
1587
1628
|
EditorPreviewProvider,
|
|
1588
|
-
|
|
1629
|
+
assistant,
|
|
1589
1630
|
createEditorController,
|
|
1590
1631
|
createMenuGroup,
|
|
1591
1632
|
filterMenuGroups,
|
|
@@ -1597,10 +1638,10 @@ export {
|
|
|
1597
1638
|
popover,
|
|
1598
1639
|
popoverRangeEffect,
|
|
1599
1640
|
popoverStateField,
|
|
1600
|
-
|
|
1641
|
+
useBasicMarkdownExtensions,
|
|
1642
|
+
useEditorContext,
|
|
1601
1643
|
useEditorMenu,
|
|
1602
1644
|
useEditorPreview,
|
|
1603
|
-
useEditorToolbar,
|
|
1604
1645
|
useTextEditor
|
|
1605
1646
|
};
|
|
1606
1647
|
//# sourceMappingURL=index.mjs.map
|