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