@dxos/react-ui-editor 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced
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 +753 -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 +753 -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 +58 -49
- 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 +3 -5
- package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
- package/src/components/EditorMenuProvider/popover.ts +3 -1
- package/src/components/EditorMenuProvider/useEditorMenu.ts +2 -1
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -1
- package/src/components/EditorToolbar/EditorToolbar.tsx +28 -47
- 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 +10 -6
- 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 +4 -5
- package/src/stories/Theme.stories.tsx +2 -2
- package/src/stories/components/EditorStory.tsx +17 -8
- package/src/stories/components/util.tsx +38 -36
- 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/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("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,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
410
|
import { DX_ANCHOR_ACTIVATE, Icon, Popover, ScrollArea, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
706
|
-
var
|
|
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: 66,
|
|
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: 101,
|
|
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,13 +461,13 @@ 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
472
|
classNames: [
|
|
784
473
|
"flex flex-col",
|
|
@@ -797,39 +486,38 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
|
|
|
797
486
|
}
|
|
798
487
|
},
|
|
799
488
|
onOpenAutoFocus: (event) => event.preventDefault()
|
|
800
|
-
}, /* @__PURE__ */
|
|
489
|
+
}, /* @__PURE__ */ React.createElement(Popover.Viewport, {
|
|
801
490
|
asChild: true,
|
|
802
491
|
classNames: "dx-container"
|
|
803
|
-
}, /* @__PURE__ */
|
|
492
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Root, {
|
|
804
493
|
thin: true
|
|
805
|
-
}, /* @__PURE__ */
|
|
494
|
+
}, /* @__PURE__ */ React.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React.createElement(Menu, {
|
|
806
495
|
groups: menuGroups,
|
|
807
496
|
currentItem,
|
|
808
497
|
onSelect: handleSelect
|
|
809
|
-
})))), /* @__PURE__ */
|
|
810
|
-
role: "none",
|
|
498
|
+
})))), /* @__PURE__ */ React.createElement(Popover.Arrow, null))), /* @__PURE__ */ React.createElement("div", {
|
|
811
499
|
className: "contents",
|
|
812
500
|
ref: setRoot
|
|
813
501
|
}, children));
|
|
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/actions.ts
|
|
1038
|
-
import { createMenuAction, createMenuItemGroup } from "@dxos/react-ui-menu";
|
|
1039
|
-
import { List, addList, removeList } from "@dxos/ui-editor";
|
|
1040
|
-
var listStyles = {
|
|
1041
|
-
bullet: "ph--list-bullets--regular",
|
|
1042
|
-
ordered: "ph--list-numbers--regular",
|
|
1043
|
-
task: "ph--list-checks--regular"
|
|
1044
|
-
};
|
|
1045
|
-
var createLists = (state, getView) => {
|
|
1046
|
-
const value = state.listStyle ?? "";
|
|
1047
|
-
const listGroupAction = createListGroupAction(value);
|
|
1048
|
-
const listActionsMap = createListActions(value, getView);
|
|
1049
|
-
return {
|
|
1050
|
-
nodes: [
|
|
1051
|
-
listGroupAction,
|
|
1052
|
-
...listActionsMap
|
|
1053
|
-
],
|
|
1054
|
-
edges: [
|
|
1055
|
-
{
|
|
1056
|
-
source: "root",
|
|
1057
|
-
target: "list",
|
|
1058
|
-
relation: "child"
|
|
1059
|
-
},
|
|
1060
|
-
...listActionsMap.map(({ id }) => ({
|
|
1061
|
-
source: listGroupAction.id,
|
|
1062
|
-
target: id,
|
|
1063
|
-
relation: "child"
|
|
1064
|
-
}))
|
|
1065
|
-
]
|
|
1066
|
-
};
|
|
1067
|
-
};
|
|
1068
|
-
var createEditorAction = (id, props, invoke) => {
|
|
1069
|
-
const { label = [
|
|
1070
|
-
`${id} label`,
|
|
1071
|
-
{
|
|
1072
|
-
ns: translationKey
|
|
1073
|
-
}
|
|
1074
|
-
], ...rest } = props;
|
|
1075
|
-
return createMenuAction(id, invoke, {
|
|
1076
|
-
label,
|
|
1077
|
-
...rest
|
|
1078
|
-
});
|
|
1079
|
-
};
|
|
1080
|
-
var createEditorActionGroup = (id, props, icon) => {
|
|
1081
|
-
const { label = [
|
|
1082
|
-
`${id} label`,
|
|
1083
|
-
{
|
|
1084
|
-
ns: translationKey
|
|
1085
|
-
}
|
|
1086
|
-
], ...rest } = props;
|
|
1087
|
-
return createMenuItemGroup(id, {
|
|
1088
|
-
label,
|
|
1089
|
-
icon,
|
|
1090
|
-
iconOnly: true,
|
|
1091
|
-
...rest
|
|
1092
|
-
});
|
|
1093
|
-
};
|
|
1094
|
-
var createListGroupAction = (value) => createEditorActionGroup("list", {
|
|
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
716
|
// src/components/EditorToolbar/blocks.ts
|
|
1119
717
|
import { addBlockquote, addCodeblock, insertTable, removeBlockquote, removeCodeblock } from "@dxos/ui-editor";
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
selectCardinality: "single",
|
|
1123
|
-
value
|
|
1124
|
-
});
|
|
1125
|
-
var createBlockActions = (value, getView, blankLine) => Object.entries({
|
|
718
|
+
import { translationKey } from "#translations";
|
|
719
|
+
var blockTypes = {
|
|
1126
720
|
blockquote: "ph--quotes--regular",
|
|
1127
721
|
codeblock: "ph--code-block--regular",
|
|
1128
722
|
table: "ph--table--regular"
|
|
1129
|
-
}
|
|
1130
|
-
|
|
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;
|
|
1152
|
-
}
|
|
1153
|
-
});
|
|
1154
|
-
});
|
|
1155
|
-
var createBlocks = (state, getView) => {
|
|
723
|
+
};
|
|
724
|
+
var addBlocks = (state, getView) => (builder) => {
|
|
1156
725
|
const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
nodes: [
|
|
1161
|
-
blockGroupAction,
|
|
1162
|
-
...blockActions
|
|
1163
|
-
],
|
|
1164
|
-
edges: [
|
|
726
|
+
builder.group("block", {
|
|
727
|
+
label: [
|
|
728
|
+
"block.label",
|
|
1165
729
|
{
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
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
|
+
});
|
|
769
|
+
}
|
|
770
|
+
});
|
|
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,149 +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__ */
|
|
1002
|
+
}, /* @__PURE__ */ React2.createElement(Menu2.Toolbar, {
|
|
1389
1003
|
classNames
|
|
1390
1004
|
})));
|
|
1391
1005
|
});
|
|
1392
|
-
var
|
|
1393
|
-
const menuCreator =
|
|
1006
|
+
var useMarkdownMenuActions = ({ state, getView, customActions, ...features }) => {
|
|
1007
|
+
const menuCreator = useMemo2(() => createMarkdownActions({
|
|
1394
1008
|
state,
|
|
1395
1009
|
getView,
|
|
1396
1010
|
customActions,
|
|
@@ -1409,56 +1023,300 @@ var useEditorToolbarActionGraph = ({ state, getView, customActions, ...features
|
|
|
1409
1023
|
]);
|
|
1410
1024
|
return useMenuActions(menuCreator);
|
|
1411
1025
|
};
|
|
1412
|
-
var
|
|
1026
|
+
var createMarkdownActions = ({ state, getView, customActions, ...features }) => {
|
|
1413
1027
|
return Atom.make((get) => {
|
|
1414
1028
|
const stateSnapshot = get(state);
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
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);
|
|
1427
1132
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
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
|
+
}
|
|
1430
1156
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1157
|
+
}, [
|
|
1158
|
+
view,
|
|
1159
|
+
scrollTo,
|
|
1160
|
+
selection
|
|
1161
|
+
]);
|
|
1162
|
+
useEffect2(() => {
|
|
1163
|
+
if (view && autoFocus) {
|
|
1164
|
+
view.focus();
|
|
1434
1165
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
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
|
+
}
|
|
1437
1189
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1190
|
+
}, [
|
|
1191
|
+
view
|
|
1192
|
+
]);
|
|
1193
|
+
return {
|
|
1194
|
+
parentRef,
|
|
1195
|
+
view,
|
|
1196
|
+
focusAttributes: {
|
|
1197
|
+
tabIndex: 0,
|
|
1198
|
+
onKeyDown: handleKeyDown
|
|
1440
1199
|
}
|
|
1441
|
-
|
|
1442
|
-
});
|
|
1200
|
+
};
|
|
1443
1201
|
};
|
|
1444
1202
|
|
|
1445
|
-
// src/components/
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
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
|
+
};
|
|
1450
1240
|
};
|
|
1451
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
|
+
|
|
1452
1312
|
// src/components/Editor/Editor.tsx
|
|
1453
1313
|
var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/Editor/Editor.tsx";
|
|
1454
1314
|
var [EditorContextProvider, useEditorContext] = createContext("Editor");
|
|
1455
|
-
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, ...props }, forwardedRef) => {
|
|
1456
|
-
const state =
|
|
1315
|
+
var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensionsProp, viewMode, numItems, ...props }, forwardedRef) => {
|
|
1316
|
+
const state = useMemo5(() => Atom2.make({
|
|
1317
|
+
viewMode
|
|
1318
|
+
}), [
|
|
1457
1319
|
viewMode
|
|
1458
|
-
});
|
|
1459
|
-
const [controller, setController] = useState4();
|
|
1460
|
-
useImperativeHandle2(forwardedRef, () => controller ?? noopController, [
|
|
1461
|
-
controller
|
|
1462
1320
|
]);
|
|
1463
1321
|
const { groupsRef, extension, ...menuProps } = useEditorMenu(props);
|
|
1464
1322
|
const extensions = useMemo5(() => [
|
|
@@ -1468,6 +1326,10 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1468
1326
|
extension,
|
|
1469
1327
|
extensionsProp
|
|
1470
1328
|
]);
|
|
1329
|
+
const [controller, setController] = useState4(noopController);
|
|
1330
|
+
useImperativeHandle2(forwardedRef, () => controller, [
|
|
1331
|
+
controller
|
|
1332
|
+
]);
|
|
1471
1333
|
return /* @__PURE__ */ React4.createElement(EditorContextProvider, {
|
|
1472
1334
|
controller,
|
|
1473
1335
|
setController,
|
|
@@ -1476,21 +1338,21 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
|
|
|
1476
1338
|
}, /* @__PURE__ */ React4.createElement(EditorMenuProvider, {
|
|
1477
1339
|
view: controller?.view,
|
|
1478
1340
|
groups: groupsRef.current,
|
|
1341
|
+
numItems,
|
|
1479
1342
|
...menuProps
|
|
1480
1343
|
}, children));
|
|
1481
1344
|
});
|
|
1482
1345
|
EditorRoot.displayName = "Editor.Root";
|
|
1483
|
-
var
|
|
1484
|
-
var
|
|
1346
|
+
var EDITOR_CONTENT_NAME = "Editor.Content";
|
|
1347
|
+
var EditorContent = ({ classNames, children }) => {
|
|
1485
1348
|
return /* @__PURE__ */ React4.createElement("div", {
|
|
1486
|
-
role: "none",
|
|
1487
1349
|
className: mx2("grid grid-rows-[min-content_1fr] h-full overflow-hidden", classNames)
|
|
1488
1350
|
}, children);
|
|
1489
1351
|
};
|
|
1490
|
-
|
|
1491
|
-
var
|
|
1492
|
-
var
|
|
1493
|
-
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);
|
|
1494
1356
|
const extensions = useMemo5(() => [
|
|
1495
1357
|
additionalExtensions,
|
|
1496
1358
|
providedExtensions
|
|
@@ -1498,26 +1360,18 @@ var EditorContent2 = ({ extensions: providedExtensions, ...props }) => {
|
|
|
1498
1360
|
providedExtensions,
|
|
1499
1361
|
additionalExtensions
|
|
1500
1362
|
]);
|
|
1501
|
-
return /* @__PURE__ */ React4.createElement(
|
|
1363
|
+
return /* @__PURE__ */ React4.createElement(EditorView3, {
|
|
1502
1364
|
...props,
|
|
1503
1365
|
extensions,
|
|
1504
1366
|
ref: setController
|
|
1505
1367
|
});
|
|
1506
1368
|
};
|
|
1507
|
-
|
|
1369
|
+
EditorView4.displayName = EDITOR_VIEW_NAME;
|
|
1508
1370
|
var EDITOR_TOOLBAR_NAME = "Editor.Toolbar";
|
|
1509
1371
|
var EditorToolbar2 = (props) => {
|
|
1510
1372
|
const { controller, state } = useEditorContext(EDITOR_TOOLBAR_NAME);
|
|
1511
1373
|
const getView = useCallback4(() => {
|
|
1512
|
-
invariant3(controller?.view, void 0, {
|
|
1513
|
-
F: __dxlog_file4,
|
|
1514
|
-
L: 146,
|
|
1515
|
-
S: void 0,
|
|
1516
|
-
A: [
|
|
1517
|
-
"controller?.view",
|
|
1518
|
-
""
|
|
1519
|
-
]
|
|
1520
|
-
});
|
|
1374
|
+
invariant3(controller?.view, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 99, S: void 0, A: ["controller?.view", ""] });
|
|
1521
1375
|
return controller?.view;
|
|
1522
1376
|
}, [
|
|
1523
1377
|
controller
|
|
@@ -1531,19 +1385,19 @@ var EditorToolbar2 = (props) => {
|
|
|
1531
1385
|
EditorToolbar2.displayName = EDITOR_TOOLBAR_NAME;
|
|
1532
1386
|
var Editor = {
|
|
1533
1387
|
Root: EditorRoot,
|
|
1534
|
-
|
|
1535
|
-
Content:
|
|
1536
|
-
|
|
1388
|
+
Toolbar: EditorToolbar2,
|
|
1389
|
+
Content: EditorContent,
|
|
1390
|
+
View: EditorView4
|
|
1537
1391
|
};
|
|
1538
1392
|
|
|
1539
1393
|
// src/components/EditorPreviewProvider/EditorPreviewProvider.tsx
|
|
1540
1394
|
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
1541
|
-
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";
|
|
1542
1396
|
import { addEventListener as addEventListener2 } from "@dxos/async";
|
|
1543
1397
|
import { DX_ANCHOR_ACTIVATE as DX_ANCHOR_ACTIVATE2, Popover as Popover2 } from "@dxos/react-ui";
|
|
1544
1398
|
var [EditorPreviewContextProvider, useEditorPreview] = createContext2("PreviewPopover", {});
|
|
1545
1399
|
var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
1546
|
-
const triggerRef =
|
|
1400
|
+
const triggerRef = useRef5(null);
|
|
1547
1401
|
const [value, setValue] = useState5({});
|
|
1548
1402
|
const [open, setOpen] = useState5(false);
|
|
1549
1403
|
const handleActivate = useCallback5((event) => {
|
|
@@ -1592,17 +1446,187 @@ var EditorPreviewProvider = ({ children, onLookup }) => {
|
|
|
1592
1446
|
}, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
|
|
1593
1447
|
virtualRef: triggerRef
|
|
1594
1448
|
}), /* @__PURE__ */ React5.createElement("div", {
|
|
1595
|
-
role: "none",
|
|
1596
1449
|
className: "contents",
|
|
1597
1450
|
ref: setRoot
|
|
1598
1451
|
}, children)));
|
|
1599
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
|
+
});
|
|
1600
1625
|
export {
|
|
1601
1626
|
Editor,
|
|
1602
|
-
EditorContent,
|
|
1603
1627
|
EditorMenuProvider,
|
|
1604
1628
|
EditorPreviewProvider,
|
|
1605
|
-
|
|
1629
|
+
assistant,
|
|
1606
1630
|
createEditorController,
|
|
1607
1631
|
createMenuGroup,
|
|
1608
1632
|
filterMenuGroups,
|
|
@@ -1614,10 +1638,10 @@ export {
|
|
|
1614
1638
|
popover,
|
|
1615
1639
|
popoverRangeEffect,
|
|
1616
1640
|
popoverStateField,
|
|
1617
|
-
|
|
1641
|
+
useBasicMarkdownExtensions,
|
|
1642
|
+
useEditorContext,
|
|
1618
1643
|
useEditorMenu,
|
|
1619
1644
|
useEditorPreview,
|
|
1620
|
-
useEditorToolbar,
|
|
1621
1645
|
useTextEditor
|
|
1622
1646
|
};
|
|
1623
1647
|
//# sourceMappingURL=index.mjs.map
|