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