@dxos/react-ui-editor 0.3.11-main.674a7f9 → 0.3.11-main.6901f09
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 +1994 -433
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +1 -2
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/{comments.stories.d.ts → hooks.stories.d.ts} +9 -12
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +29 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +25 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +5 -5
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +2 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +1 -1
- package/dist/types/src/extensions/basic.d.ts +1 -1
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +11 -3
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -2
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +57 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/index.d.ts +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +36 -14
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +12 -0
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/package.json +40 -27
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +15 -21
- package/src/components/TextEditor/TextEditor.tsx +27 -16
- package/src/components/TextEditor/automerge.stories.tsx +1 -2
- package/src/components/TextEditor/hooks.stories.tsx +111 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +102 -0
- package/src/components/Toolbar/Toolbar.tsx +245 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +26 -11
- package/src/extensions/automerge/cursor.ts +3 -3
- package/src/extensions/automerge/defs.ts +9 -9
- package/src/extensions/automerge/semaphore.ts +17 -19
- package/src/extensions/automerge/update-automerge.ts +12 -6
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +7 -4
- package/src/extensions/basic.ts +15 -13
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +126 -68
- package/src/extensions/markdown/bundle.ts +9 -8
- package/src/extensions/markdown/code.ts +95 -49
- package/src/extensions/markdown/formatting.test.ts +481 -0
- package/src/extensions/markdown/formatting.ts +1198 -0
- package/src/extensions/markdown/heading.ts +5 -6
- package/src/extensions/markdown/highlight.ts +9 -15
- package/src/extensions/markdown/hr.ts +2 -3
- package/src/extensions/markdown/index.ts +1 -0
- package/src/extensions/markdown/link.ts +13 -4
- package/src/extensions/markdown/tasklist.ts +1 -2
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useActionHandler.ts +93 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +143 -19
- package/src/hooks/useTextModel.ts +28 -9
- package/src/index.ts +1 -1
- package/src/styles/markdown.ts +9 -10
- package/src/themes/default.ts +11 -8
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +0 -1
- package/src/components/TextEditor/comments.stories.tsx +0 -357
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
3
|
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
|
+
import { keymap as keymap7 } from "@codemirror/view";
|
|
4
5
|
|
|
5
6
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
7
|
import { tags as tags2 } from "@lezer/highlight";
|
|
7
8
|
|
|
8
9
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
10
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
11
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
15
15
|
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
17
|
+
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
|
+
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
18
19
|
|
|
19
20
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
21
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
@@ -53,14 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
56
58
|
import { StateField } from "@codemirror/state";
|
|
57
59
|
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
58
|
-
import { next as
|
|
59
|
-
import { invariant } from "@dxos/invariant";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
60
61
|
|
|
61
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
62
63
|
import get from "lodash.get";
|
|
63
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
64
65
|
var cursorConverter = (handle, path) => ({
|
|
65
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
66
67
|
toCursor: (pos) => {
|
|
@@ -72,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
72
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
73
74
|
return "end";
|
|
74
75
|
}
|
|
75
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
76
77
|
},
|
|
77
78
|
fromCursor: (cursor) => {
|
|
78
79
|
if (cursor === "") {
|
|
@@ -90,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
90
91
|
return 0;
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
94
95
|
}
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
98
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
99
|
-
var effectType = StateEffect.define({});
|
|
100
|
-
var reconcileAnnotationType = Annotation.define();
|
|
101
100
|
var getPath = (state, field) => state.field(field).path;
|
|
102
101
|
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
103
|
-
var
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
104
104
|
newHeads
|
|
105
105
|
});
|
|
106
|
-
var
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
107
110
|
|
|
108
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
110
113
|
|
|
111
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
113
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
117
|
const { lastHeads, path } = state.field(field);
|
|
115
118
|
let hasChanges = false;
|
|
@@ -122,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
122
125
|
return void 0;
|
|
123
126
|
}
|
|
124
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
125
129
|
for (const tr of transactions) {
|
|
126
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
127
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
128
136
|
});
|
|
129
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
130
141
|
});
|
|
131
142
|
return newHeads ?? void 0;
|
|
132
143
|
};
|
|
@@ -141,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
141
152
|
selection = selection.map(changeSet, 1);
|
|
142
153
|
view.dispatch({
|
|
143
154
|
changes: changeSet,
|
|
144
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
145
156
|
});
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
view.dispatch({
|
|
149
160
|
selection,
|
|
150
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
151
162
|
});
|
|
152
163
|
};
|
|
153
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -168,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
168
179
|
if (index == null) {
|
|
169
180
|
return [];
|
|
170
181
|
}
|
|
171
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
172
183
|
return [
|
|
173
184
|
{
|
|
174
185
|
from: index,
|
|
@@ -246,36 +257,37 @@ var PatchSemaphore = class {
|
|
|
246
257
|
this._state = _state;
|
|
247
258
|
this._inReconcile = false;
|
|
248
259
|
}
|
|
249
|
-
// NOTE: Cannot destruct view.state.
|
|
250
260
|
reconcile(view) {
|
|
251
|
-
if (this._inReconcile) {
|
|
252
|
-
|
|
261
|
+
if (!this._inReconcile) {
|
|
262
|
+
this._inReconcile = true;
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
253
265
|
}
|
|
254
|
-
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
255
268
|
const path = getPath(view.state, this._state);
|
|
256
269
|
const oldHeads = getLastHeads(view.state, this._state);
|
|
257
270
|
let selection = view.state.selection;
|
|
258
|
-
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
259
272
|
const toInvert = transactions.slice().reverse();
|
|
260
|
-
for (const
|
|
261
|
-
const inverted =
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
262
275
|
selection = selection.map(inverted);
|
|
263
276
|
view.dispatch({
|
|
264
277
|
changes: inverted,
|
|
265
|
-
annotations:
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
266
279
|
});
|
|
267
280
|
}
|
|
268
281
|
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
269
282
|
if (newHeads === null || newHeads === void 0) {
|
|
270
|
-
newHeads =
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
271
284
|
}
|
|
272
|
-
const diff =
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
273
286
|
updateCodeMirror(view, selection, path, diff);
|
|
274
287
|
view.dispatch({
|
|
275
288
|
effects: updateHeads(newHeads),
|
|
276
|
-
annotations:
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
277
290
|
});
|
|
278
|
-
this._inReconcile = false;
|
|
279
291
|
}
|
|
280
292
|
};
|
|
281
293
|
|
|
@@ -317,12 +329,11 @@ var Cursor = class _Cursor {
|
|
|
317
329
|
};
|
|
318
330
|
|
|
319
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
320
|
-
var
|
|
321
|
-
|
|
322
|
-
const state = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
323
334
|
create: () => ({
|
|
324
335
|
path: path.slice(),
|
|
325
|
-
lastHeads:
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
326
337
|
unreconciledTransactions: []
|
|
327
338
|
}),
|
|
328
339
|
update: (value, tr) => {
|
|
@@ -333,7 +344,7 @@ var automerge3 = ({ handle, path }) => {
|
|
|
333
344
|
};
|
|
334
345
|
let clearUnreconciled = false;
|
|
335
346
|
for (const effect of tr.effects) {
|
|
336
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
337
348
|
result.lastHeads = effect.value.newHeads;
|
|
338
349
|
clearUnreconciled = true;
|
|
339
350
|
}
|
|
@@ -341,29 +352,21 @@ var automerge3 = ({ handle, path }) => {
|
|
|
341
352
|
if (clearUnreconciled) {
|
|
342
353
|
result.unreconciledTransactions = [];
|
|
343
354
|
} else {
|
|
344
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
345
356
|
result.unreconciledTransactions.push(tr);
|
|
346
357
|
}
|
|
347
358
|
}
|
|
348
359
|
return result;
|
|
349
360
|
}
|
|
350
361
|
});
|
|
351
|
-
const semaphore = new PatchSemaphore(handle,
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
352
363
|
return [
|
|
353
364
|
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
354
366
|
// Reconcile external updates.
|
|
355
367
|
ViewPlugin.fromClass(class {
|
|
356
368
|
constructor(_view) {
|
|
357
369
|
this._view = _view;
|
|
358
|
-
invariant(this._view, void 0, {
|
|
359
|
-
F: __dxlog_file,
|
|
360
|
-
L: 66,
|
|
361
|
-
S: this,
|
|
362
|
-
A: [
|
|
363
|
-
"this._view",
|
|
364
|
-
""
|
|
365
|
-
]
|
|
366
|
-
});
|
|
367
370
|
handle.addListener("change", this._handleChange.bind(this));
|
|
368
371
|
}
|
|
369
372
|
destroy() {
|
|
@@ -379,7 +382,17 @@ var automerge3 = ({ handle, path }) => {
|
|
|
379
382
|
semaphore.reconcile(view);
|
|
380
383
|
}
|
|
381
384
|
}),
|
|
382
|
-
|
|
385
|
+
// TODO(burdon): Record undo transactions.
|
|
386
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
387
|
+
// https://codemirror.net/examples/inverted-effect
|
|
388
|
+
invertedEffects.of((tr) => {
|
|
389
|
+
const effects = [];
|
|
390
|
+
if (!tr.changes.empty) {
|
|
391
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
383
396
|
];
|
|
384
397
|
};
|
|
385
398
|
|
|
@@ -398,13 +411,13 @@ var dummyProvider = {
|
|
|
398
411
|
update: () => {
|
|
399
412
|
}
|
|
400
413
|
};
|
|
401
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
402
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
403
416
|
});
|
|
404
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
405
418
|
var awareness = (provider = dummyProvider) => {
|
|
406
419
|
return [
|
|
407
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
408
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
409
422
|
decorations: (value) => value.decorations
|
|
410
423
|
}),
|
|
@@ -418,7 +431,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
418
431
|
this._lastAnchor = void 0;
|
|
419
432
|
this._lastHead = void 0;
|
|
420
433
|
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
421
|
-
this._provider = view.state.facet(
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
422
435
|
this._provider.open();
|
|
423
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
424
437
|
view.dispatch({
|
|
@@ -624,24 +637,25 @@ import { history } from "@codemirror/commands";
|
|
|
624
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
625
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
626
639
|
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
627
|
-
|
|
628
|
-
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
629
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
630
644
|
bracketMatching(),
|
|
631
645
|
closeBrackets(),
|
|
632
646
|
drawSelection(),
|
|
633
647
|
highlightActiveLine(),
|
|
634
648
|
history(),
|
|
635
|
-
_placeholder
|
|
649
|
+
_placeholder && placeholder(_placeholder),
|
|
636
650
|
// https://github.com/codemirror/theme-one-dark
|
|
637
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
638
|
-
];
|
|
652
|
+
].filter(isNotFalsy);
|
|
639
653
|
|
|
640
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
641
655
|
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
642
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
643
|
-
import { invariant
|
|
644
|
-
var
|
|
657
|
+
import { invariant } from "@dxos/invariant";
|
|
658
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
645
659
|
var defaultOptions = {
|
|
646
660
|
effect: 2,
|
|
647
661
|
maxParticles: 200,
|
|
@@ -674,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
674
688
|
const getPoint = (view, pos) => {
|
|
675
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
676
690
|
const element = document.elementFromPoint(x, y);
|
|
677
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
678
692
|
const point = {
|
|
679
693
|
x: x - left,
|
|
680
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
681
695
|
};
|
|
682
696
|
return {
|
|
683
697
|
element,
|
|
@@ -767,9 +781,9 @@ var Blaster = class {
|
|
|
767
781
|
return this._node;
|
|
768
782
|
}
|
|
769
783
|
initialize() {
|
|
770
|
-
|
|
771
|
-
F:
|
|
772
|
-
L:
|
|
784
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
785
|
+
F: __dxlog_file,
|
|
786
|
+
L: 141,
|
|
773
787
|
S: this,
|
|
774
788
|
A: [
|
|
775
789
|
"!this._canvas && !this._ctx",
|
|
@@ -804,9 +818,9 @@ var Blaster = class {
|
|
|
804
818
|
}
|
|
805
819
|
}
|
|
806
820
|
start() {
|
|
807
|
-
|
|
808
|
-
F:
|
|
809
|
-
L:
|
|
821
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
822
|
+
F: __dxlog_file,
|
|
823
|
+
L: 180,
|
|
810
824
|
S: this,
|
|
811
825
|
A: [
|
|
812
826
|
"this._canvas && this._ctx",
|
|
@@ -948,12 +962,12 @@ var random = (min, max) => {
|
|
|
948
962
|
};
|
|
949
963
|
|
|
950
964
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
951
|
-
import {
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
952
967
|
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
953
968
|
import sortBy from "lodash.sortby";
|
|
954
969
|
import { useEffect } from "react";
|
|
955
970
|
import { debounce } from "@dxos/async";
|
|
956
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
957
971
|
import { nonNullable } from "@dxos/util";
|
|
958
972
|
|
|
959
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
@@ -997,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
997
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
998
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
999
1013
|
var headings = {
|
|
1000
|
-
1:
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1010
|
-
"-ml-[7px]"
|
|
1011
|
-
],
|
|
1012
|
-
4: [
|
|
1013
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1014
|
-
"-ml-[6px]"
|
|
1015
|
-
],
|
|
1016
|
-
5: [
|
|
1017
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1018
|
-
"-ml-[5px]"
|
|
1019
|
-
],
|
|
1020
|
-
6: [
|
|
1021
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1022
|
-
"-ml-[4px]"
|
|
1023
|
-
]
|
|
1024
|
-
};
|
|
1025
|
-
var heading = (level, readonly) => {
|
|
1026
|
-
const [style, offset] = headings[level];
|
|
1027
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1028
1023
|
};
|
|
1029
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1030
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1044,13 +1039,13 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
|
|
|
1044
1039
|
|
|
1045
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1046
1041
|
import { log } from "@dxos/log";
|
|
1047
|
-
var
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1048
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1049
1044
|
try {
|
|
1050
1045
|
return fn(...args);
|
|
1051
1046
|
} catch (err) {
|
|
1052
1047
|
log.catch(err, void 0, {
|
|
1053
|
-
F:
|
|
1048
|
+
F: __dxlog_file2,
|
|
1054
1049
|
L: 18,
|
|
1055
1050
|
S: void 0,
|
|
1056
1051
|
C: (f, a) => f(...a)
|
|
@@ -1078,24 +1073,35 @@ var logChanges = (trs) => {
|
|
|
1078
1073
|
};
|
|
1079
1074
|
|
|
1080
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1081
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1082
1076
|
var styles2 = EditorView5.baseTheme({
|
|
1083
|
-
"& .cm-comment": {
|
|
1077
|
+
"&light .cm-comment, &light .cm-comment-current": {
|
|
1078
|
+
mixBlendMode: "darken"
|
|
1079
|
+
},
|
|
1080
|
+
"&dark .cm-comment, &dark .cm-comment-current": {
|
|
1081
|
+
mixBlendMode: "plus-lighter"
|
|
1082
|
+
},
|
|
1083
|
+
"&light .cm-comment": {
|
|
1084
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1085
1085
|
},
|
|
1086
|
-
"& .cm-comment-current": {
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1087
1087
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1088
|
+
},
|
|
1089
|
+
"&dark .cm-comment": {
|
|
1090
|
+
color: getToken("extend.colors.yellow.50"),
|
|
1091
|
+
backgroundColor: getToken("extend.colors.yellow.900")
|
|
1092
|
+
},
|
|
1093
|
+
"&dark .cm-comment-current": {
|
|
1094
|
+
color: getToken("extend.colors.yellow.100"),
|
|
1095
|
+
backgroundColor: getToken("extend.colors.yellow.950")
|
|
1088
1096
|
}
|
|
1089
1097
|
});
|
|
1090
|
-
var
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
};
|
|
1098
|
-
var setFocus = (view, id, center = true) => {
|
|
1098
|
+
var commentMark = Decoration2.mark({
|
|
1099
|
+
class: "cm-comment"
|
|
1100
|
+
});
|
|
1101
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1102
|
+
class: "cm-comment-current"
|
|
1103
|
+
});
|
|
1104
|
+
var focusComment = (view, id, center = true) => {
|
|
1099
1105
|
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1100
1106
|
if (!comment?.comment.cursor) {
|
|
1101
1107
|
return;
|
|
@@ -1157,7 +1163,7 @@ var commentsState = StateField2.define({
|
|
|
1157
1163
|
return value;
|
|
1158
1164
|
}
|
|
1159
1165
|
});
|
|
1160
|
-
var
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1161
1167
|
commentsState
|
|
1162
1168
|
], (state) => {
|
|
1163
1169
|
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
@@ -1168,9 +1174,9 @@ var highlightDecorations = EditorView5.decorations.compute([
|
|
|
1168
1174
|
return void 0;
|
|
1169
1175
|
}
|
|
1170
1176
|
if (comment.comment.id === current) {
|
|
1171
|
-
return
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1172
1178
|
} else {
|
|
1173
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1174
1180
|
}
|
|
1175
1181
|
}).filter(nonNullable);
|
|
1176
1182
|
return Decoration2.set(decorations);
|
|
@@ -1199,84 +1205,128 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1199
1205
|
cut: handleTrack,
|
|
1200
1206
|
copy: handleTrack
|
|
1201
1207
|
}),
|
|
1202
|
-
//
|
|
1203
|
-
|
|
1208
|
+
// Track deleted comments.
|
|
1209
|
+
invertedEffects2.of((tr) => {
|
|
1210
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1211
|
+
const effects = [];
|
|
1212
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1213
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1214
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1215
|
+
effects.push(restoreCommentEffect.of({
|
|
1216
|
+
id,
|
|
1217
|
+
from,
|
|
1218
|
+
to
|
|
1219
|
+
}));
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
return effects;
|
|
1224
|
+
}),
|
|
1225
|
+
// Handle paste or the undo of comment deletion.
|
|
1226
|
+
EditorView5.updateListener.of((update2) => {
|
|
1227
|
+
const restore = [];
|
|
1228
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1229
|
+
const tr = update2.transactions[i];
|
|
1230
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1231
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1232
|
+
}
|
|
1233
|
+
for (const effect of tr.effects) {
|
|
1234
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1235
|
+
restore.push(effect.value);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1204
1239
|
if (tracked) {
|
|
1205
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1240
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1206
1241
|
if (paste) {
|
|
1207
1242
|
let found = -1;
|
|
1208
1243
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1209
1244
|
if (text.eq(tracked.text)) {
|
|
1210
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1211
|
-
fromB = transactions[i].changes.mapPos(fromB);
|
|
1245
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1246
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1212
1247
|
}
|
|
1213
1248
|
found = fromB;
|
|
1214
1249
|
}
|
|
1215
1250
|
});
|
|
1216
1251
|
if (found > -1) {
|
|
1217
1252
|
for (const moved of tracked.comments) {
|
|
1218
|
-
|
|
1253
|
+
restore.push({
|
|
1254
|
+
id: moved.id,
|
|
1219
1255
|
from: found + moved.from,
|
|
1220
1256
|
to: found + moved.to
|
|
1221
|
-
};
|
|
1222
|
-
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1223
|
-
onUpdate(moved.id, cursor);
|
|
1257
|
+
});
|
|
1224
1258
|
}
|
|
1225
1259
|
}
|
|
1226
1260
|
tracked = null;
|
|
1227
1261
|
}
|
|
1228
1262
|
}
|
|
1263
|
+
for (const comment of restore) {
|
|
1264
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1265
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1266
|
+
if (!exists) {
|
|
1267
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1268
|
+
onUpdate(comment.id, cursor);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1229
1271
|
})
|
|
1230
1272
|
];
|
|
1231
1273
|
};
|
|
1232
|
-
var
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1274
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1275
|
+
id: comment.id,
|
|
1276
|
+
from: changes.mapPos(comment.from, 1),
|
|
1277
|
+
to: changes.mapPos(comment.to, 1)
|
|
1278
|
+
});
|
|
1279
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1280
|
+
map: mapTrackedComment
|
|
1281
|
+
});
|
|
1282
|
+
var optionsFacet = Facet3.define({
|
|
1283
|
+
combine: (providers) => providers[0]
|
|
1284
|
+
});
|
|
1285
|
+
var createComment = (view) => {
|
|
1286
|
+
const options = view.state.facet(optionsFacet);
|
|
1287
|
+
const { from, to } = view.state.selection.main;
|
|
1288
|
+
if (from === to) {
|
|
1289
|
+
return false;
|
|
1290
|
+
}
|
|
1291
|
+
if (to === view.state.doc.length) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
changes: {
|
|
1294
|
+
from: to,
|
|
1295
|
+
insert: "\n"
|
|
1296
|
+
}
|
|
1244
1297
|
});
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1298
|
+
}
|
|
1299
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1300
|
+
from,
|
|
1301
|
+
to
|
|
1302
|
+
});
|
|
1303
|
+
if (cursor) {
|
|
1304
|
+
const id = options.onCreate?.({
|
|
1305
|
+
cursor,
|
|
1306
|
+
from,
|
|
1307
|
+
location: view.coordsAtPos(from)
|
|
1308
|
+
});
|
|
1309
|
+
if (id) {
|
|
1250
1310
|
view.dispatch({
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1254
1316
|
}
|
|
1255
1317
|
});
|
|
1318
|
+
return true;
|
|
1256
1319
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
if (id) {
|
|
1264
|
-
view.dispatch({
|
|
1265
|
-
effects: setSelection.of({
|
|
1266
|
-
current: id
|
|
1267
|
-
}),
|
|
1268
|
-
selection: {
|
|
1269
|
-
anchor: from
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
return true;
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
return false;
|
|
1276
|
-
};
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1277
1326
|
return [
|
|
1327
|
+
optionsFacet.of(options),
|
|
1278
1328
|
commentsState,
|
|
1279
|
-
|
|
1329
|
+
commentsDecorations,
|
|
1280
1330
|
styles2,
|
|
1281
1331
|
//
|
|
1282
1332
|
// Keymap.
|
|
@@ -1284,7 +1334,7 @@ var comments = (options = {}) => {
|
|
|
1284
1334
|
options.onCreate ? keymap3.of([
|
|
1285
1335
|
{
|
|
1286
1336
|
key: shortcut,
|
|
1287
|
-
run: callbackWrapper(
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1288
1338
|
}
|
|
1289
1339
|
]) : [],
|
|
1290
1340
|
//
|
|
@@ -1422,6 +1472,7 @@ import { searchKeymap } from "@codemirror/search";
|
|
|
1422
1472
|
import { EditorState } from "@codemirror/state";
|
|
1423
1473
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1424
1474
|
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1475
|
+
import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1425
1476
|
|
|
1426
1477
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1427
1478
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1518,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1518
1569
|
markdownTags.QuoteMark,
|
|
1519
1570
|
markdownTags.EmphasisMark
|
|
1520
1571
|
],
|
|
1521
|
-
class:
|
|
1572
|
+
class: mark
|
|
1522
1573
|
},
|
|
1523
1574
|
// E.g., code block language (after ```).
|
|
1524
1575
|
{
|
|
@@ -1526,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1526
1577
|
tags.function(tags.variableName),
|
|
1527
1578
|
tags.labelName
|
|
1528
1579
|
],
|
|
1529
|
-
class:
|
|
1580
|
+
class: codeMark
|
|
1530
1581
|
},
|
|
1531
1582
|
{
|
|
1532
1583
|
tag: [
|
|
@@ -1537,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1537
1588
|
// Headings.
|
|
1538
1589
|
{
|
|
1539
1590
|
tag: tags.heading1,
|
|
1540
|
-
class: heading(1
|
|
1591
|
+
class: heading(1)
|
|
1541
1592
|
},
|
|
1542
1593
|
{
|
|
1543
1594
|
tag: tags.heading2,
|
|
1544
|
-
class: heading(2
|
|
1595
|
+
class: heading(2)
|
|
1545
1596
|
},
|
|
1546
1597
|
{
|
|
1547
1598
|
tag: tags.heading3,
|
|
1548
|
-
class: heading(3
|
|
1599
|
+
class: heading(3)
|
|
1549
1600
|
},
|
|
1550
1601
|
{
|
|
1551
1602
|
tag: tags.heading4,
|
|
1552
|
-
class: heading(4
|
|
1603
|
+
class: heading(4)
|
|
1553
1604
|
},
|
|
1554
1605
|
{
|
|
1555
1606
|
tag: tags.heading5,
|
|
1556
|
-
class: heading(5
|
|
1607
|
+
class: heading(5)
|
|
1557
1608
|
},
|
|
1558
1609
|
{
|
|
1559
1610
|
tag: tags.heading6,
|
|
1560
|
-
class: heading(6
|
|
1611
|
+
class: heading(6)
|
|
1561
1612
|
},
|
|
1562
1613
|
// Emphasis.
|
|
1563
1614
|
{
|
|
@@ -1583,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1583
1634
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1584
1635
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1585
1636
|
// the code, but all other CSS properties will be inherited.
|
|
1586
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1637
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1587
1638
|
{
|
|
1588
1639
|
tag: [
|
|
1589
1640
|
markdownTags.CodeText,
|
|
@@ -1612,11 +1663,11 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1612
1663
|
};
|
|
1613
1664
|
|
|
1614
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1615
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1616
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1617
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1618
1670
|
EditorState.tabSize.of(2),
|
|
1619
|
-
EditorView7.lineWrapping,
|
|
1620
1671
|
// https://github.com/codemirror/basic-setup
|
|
1621
1672
|
bracketMatching2(),
|
|
1622
1673
|
closeBrackets2(),
|
|
@@ -1626,7 +1677,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1626
1677
|
highlightActiveLine2(),
|
|
1627
1678
|
history2(),
|
|
1628
1679
|
indentOnInput(),
|
|
1629
|
-
_placeholder
|
|
1680
|
+
_placeholder && placeholder2(_placeholder),
|
|
1630
1681
|
// Main extension.
|
|
1631
1682
|
// https://github.com/codemirror/lang-markdown
|
|
1632
1683
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1648,7 +1699,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1648
1699
|
// https://github.com/codemirror/theme-one-dark
|
|
1649
1700
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1650
1701
|
// Custom styles.
|
|
1651
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1702
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1652
1703
|
keymap4.of([
|
|
1653
1704
|
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1654
1705
|
indentWithTab,
|
|
@@ -1661,36 +1712,53 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1661
1712
|
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1662
1713
|
...standardKeymap
|
|
1663
1714
|
])
|
|
1664
|
-
];
|
|
1715
|
+
].filter(isNotFalsy2);
|
|
1665
1716
|
};
|
|
1666
1717
|
|
|
1667
1718
|
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1668
|
-
import {
|
|
1719
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1720
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1721
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1669
1722
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1670
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1671
1723
|
var styles3 = EditorView8.baseTheme({
|
|
1672
|
-
"& .cm-
|
|
1724
|
+
"& .cm-code": {
|
|
1673
1725
|
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1674
1726
|
},
|
|
1675
|
-
|
|
1676
|
-
|
|
1727
|
+
"& .cm-codeblock": {
|
|
1728
|
+
width: "100%",
|
|
1729
|
+
paddingInline: "1rem !important",
|
|
1730
|
+
position: "relative",
|
|
1731
|
+
"&::after": {
|
|
1732
|
+
content: '""',
|
|
1733
|
+
position: "absolute",
|
|
1734
|
+
inset: 0
|
|
1735
|
+
}
|
|
1677
1736
|
},
|
|
1678
|
-
|
|
1679
|
-
|
|
1737
|
+
"&light .cm-codeblock": {
|
|
1738
|
+
"&::after": {
|
|
1739
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1740
|
+
mixBlendMode: "darken"
|
|
1741
|
+
}
|
|
1680
1742
|
},
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1743
|
+
"&dark .cm-codeblock": {
|
|
1744
|
+
"&::after": {
|
|
1745
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1746
|
+
mixBlendMode: "lighten"
|
|
1747
|
+
}
|
|
1684
1748
|
},
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1749
|
+
"& .cm-codeblock-first": {
|
|
1750
|
+
display: "inline-block",
|
|
1751
|
+
"&::after": {
|
|
1752
|
+
borderTopLeftRadius: ".5rem",
|
|
1753
|
+
borderTopRightRadius: ".5rem"
|
|
1754
|
+
}
|
|
1689
1755
|
},
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1756
|
+
"& .cm-codeblock-last": {
|
|
1757
|
+
display: "inline-block",
|
|
1758
|
+
"&::after": {
|
|
1759
|
+
borderBottomLeftRadius: ".5rem",
|
|
1760
|
+
borderBottomRightRadius: ".5rem"
|
|
1761
|
+
}
|
|
1694
1762
|
}
|
|
1695
1763
|
});
|
|
1696
1764
|
var getLineRange = (lines, from, to) => {
|
|
@@ -1701,66 +1769,41 @@ var getLineRange = (lines, from, to) => {
|
|
|
1701
1769
|
end
|
|
1702
1770
|
];
|
|
1703
1771
|
};
|
|
1704
|
-
var
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1716
|
-
}).range(block.from));
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
return Decoration3.set(decorations);
|
|
1720
|
-
};
|
|
1721
|
-
return [
|
|
1722
|
-
ViewPlugin3.fromClass(class {
|
|
1723
|
-
constructor(view) {
|
|
1724
|
-
this.hasFocus = false;
|
|
1725
|
-
this.decorations = buildDecorations6(view);
|
|
1726
|
-
}
|
|
1727
|
-
update(update2) {
|
|
1728
|
-
if (
|
|
1729
|
-
// TODO(burdon): Generalize for other extensions.
|
|
1730
|
-
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1731
|
-
) {
|
|
1732
|
-
this.hasFocus = update2.view.hasFocus;
|
|
1733
|
-
this.decorations = buildDecorations6(update2.view);
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
}, {
|
|
1737
|
-
decorations: (value) => value.decorations
|
|
1738
|
-
}),
|
|
1739
|
-
styles3
|
|
1740
|
-
];
|
|
1772
|
+
var LineWidget = class extends WidgetType2 {
|
|
1773
|
+
constructor(_className) {
|
|
1774
|
+
super();
|
|
1775
|
+
this._className = _className;
|
|
1776
|
+
}
|
|
1777
|
+
toDOM() {
|
|
1778
|
+
const el = document.createElement("span");
|
|
1779
|
+
el.innerHTML = " ";
|
|
1780
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1781
|
+
return el;
|
|
1782
|
+
}
|
|
1741
1783
|
};
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1745
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1746
|
-
import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1784
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1785
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1747
1786
|
var buildDecorations = (view) => {
|
|
1748
1787
|
const builder = new RangeSetBuilder();
|
|
1749
1788
|
const { state } = view;
|
|
1789
|
+
const blocks = view.viewportLineBlocks;
|
|
1750
1790
|
const cursor = state.selection.main.head;
|
|
1751
1791
|
for (const { from, to } of view.visibleRanges) {
|
|
1752
1792
|
syntaxTree(state).iterate({
|
|
1753
1793
|
enter: (node) => {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1794
|
+
if (node.name === "FencedCode") {
|
|
1795
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1796
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1797
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1798
|
+
const block = blocks[i];
|
|
1799
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1800
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1801
|
+
widget: i === range[0] ? top : bottom
|
|
1802
|
+
}));
|
|
1803
|
+
} else {
|
|
1804
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1805
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1806
|
+
}));
|
|
1764
1807
|
}
|
|
1765
1808
|
}
|
|
1766
1809
|
}
|
|
@@ -1771,9 +1814,9 @@ var buildDecorations = (view) => {
|
|
|
1771
1814
|
}
|
|
1772
1815
|
return builder.finish();
|
|
1773
1816
|
};
|
|
1774
|
-
var
|
|
1817
|
+
var code2 = () => {
|
|
1775
1818
|
return [
|
|
1776
|
-
|
|
1819
|
+
ViewPlugin3.fromClass(class {
|
|
1777
1820
|
constructor(view) {
|
|
1778
1821
|
this.decorations = buildDecorations(view);
|
|
1779
1822
|
}
|
|
@@ -1781,86 +1824,1205 @@ var heading2 = () => {
|
|
|
1781
1824
|
this.decorations = buildDecorations(update2.view);
|
|
1782
1825
|
}
|
|
1783
1826
|
}, {
|
|
1784
|
-
decorations: (
|
|
1785
|
-
})
|
|
1827
|
+
decorations: (value) => value.decorations
|
|
1828
|
+
}),
|
|
1829
|
+
styles3
|
|
1786
1830
|
];
|
|
1787
1831
|
};
|
|
1788
1832
|
|
|
1789
|
-
// packages/ui/react-ui-editor/src/extensions/markdown/
|
|
1833
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1834
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1790
1835
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1791
|
-
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1792
|
-
import { Decoration as
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1836
|
+
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1837
|
+
import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
+
import { useState, useMemo } from "react";
|
|
1839
|
+
var compareFormatting = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockquote === b.blockquote;
|
|
1840
|
+
var Inline;
|
|
1841
|
+
(function(Inline2) {
|
|
1842
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
1843
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
1844
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
1845
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
1846
|
+
})(Inline || (Inline = {}));
|
|
1847
|
+
var List;
|
|
1848
|
+
(function(List2) {
|
|
1849
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
1850
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
1851
|
+
List2[List2["Task"] = 2] = "Task";
|
|
1852
|
+
})(List || (List = {}));
|
|
1853
|
+
var setHeading = (level) => ({ state, dispatch }) => {
|
|
1854
|
+
const { selection: { ranges }, doc } = state;
|
|
1855
|
+
const changes = [];
|
|
1856
|
+
let prevBlock = -1;
|
|
1857
|
+
for (const range of ranges) {
|
|
1858
|
+
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1861
|
+
enter: (node) => {
|
|
1862
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
prevBlock = node.from;
|
|
1866
|
+
const blockType = Textblocks[node.name];
|
|
1867
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
1868
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
1869
|
+
if (curLevel < 0 || curLevel === level) {
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (curLevel === 0) {
|
|
1873
|
+
changes.push({
|
|
1874
|
+
from: node.from,
|
|
1875
|
+
insert: "#".repeat(level) + " "
|
|
1876
|
+
});
|
|
1877
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
1878
|
+
const nextLine = doc.lineAt(node.to);
|
|
1879
|
+
if (level) {
|
|
1880
|
+
changes.push({
|
|
1881
|
+
from: node.from,
|
|
1882
|
+
insert: "#".repeat(level) + " "
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
changes.push({
|
|
1886
|
+
from: nextLine.from - 1,
|
|
1887
|
+
to: nextLine.to
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
if (level === 0) {
|
|
1891
|
+
changes.push({
|
|
1892
|
+
from: node.from,
|
|
1893
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
1894
|
+
});
|
|
1895
|
+
} else if (level < curLevel) {
|
|
1896
|
+
changes.push({
|
|
1897
|
+
from: node.from,
|
|
1898
|
+
to: node.from + (curLevel - level)
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
changes.push({
|
|
1902
|
+
from: node.from,
|
|
1903
|
+
insert: "#".repeat(level - curLevel)
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1797
1909
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
toDOM() {
|
|
1801
|
-
const el = document.createElement("div");
|
|
1802
|
-
el.className = "cm-hr";
|
|
1803
|
-
return el;
|
|
1910
|
+
if (!changes.length) {
|
|
1911
|
+
return false;
|
|
1804
1912
|
}
|
|
1913
|
+
dispatch(state.update({
|
|
1914
|
+
changes,
|
|
1915
|
+
userEvent: "format.setHeading",
|
|
1916
|
+
scrollIntoView: true
|
|
1917
|
+
}));
|
|
1918
|
+
return true;
|
|
1805
1919
|
};
|
|
1806
|
-
var
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1920
|
+
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
1921
|
+
const marker = inlineMarkerText(type);
|
|
1922
|
+
const changes = state.changeByRange((range) => {
|
|
1923
|
+
if (!enable && range.empty) {
|
|
1924
|
+
const after = state.doc.sliceString(range.head, range.head + 6);
|
|
1925
|
+
const found = after.indexOf(marker);
|
|
1926
|
+
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
1927
|
+
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
1928
|
+
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
1929
|
+
...before.slice(before.length - found)
|
|
1930
|
+
].reverse().join("") === after.slice(0, found)) {
|
|
1931
|
+
return {
|
|
1932
|
+
changes: [
|
|
1933
|
+
{
|
|
1934
|
+
from: range.head - marker.length - found,
|
|
1935
|
+
to: range.head - found
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
from: range.head + found,
|
|
1939
|
+
to: range.head + found + marker.length
|
|
1940
|
+
}
|
|
1941
|
+
],
|
|
1942
|
+
range: EditorSelection.cursor(range.from - marker.length)
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
const changes2 = [];
|
|
1948
|
+
const changesAtEnd = [];
|
|
1949
|
+
let blockStart = -1;
|
|
1950
|
+
let blockEnd = -1;
|
|
1951
|
+
let startCovered = false;
|
|
1952
|
+
let endCovered = false;
|
|
1953
|
+
let { from, to } = range;
|
|
1814
1954
|
syntaxTree2(state).iterate({
|
|
1955
|
+
from,
|
|
1956
|
+
to,
|
|
1815
1957
|
enter: (node) => {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1958
|
+
const { name } = node;
|
|
1959
|
+
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
1960
|
+
blockStart = blockContentStart(node);
|
|
1961
|
+
blockEnd = blockContentEnd(node, state.doc);
|
|
1962
|
+
startCovered = endCovered = false;
|
|
1963
|
+
} else if (name === "Link" || name === "Image" && enable) {
|
|
1964
|
+
if (from < node.from && to > node.from && to <= node.to) {
|
|
1965
|
+
to = node.to;
|
|
1966
|
+
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
1967
|
+
from = node.from;
|
|
1968
|
+
}
|
|
1969
|
+
} else if (IgnoreInline.has(name) && enable) {
|
|
1970
|
+
if (node.from < from && node.to > from) {
|
|
1971
|
+
if (to === from) {
|
|
1972
|
+
to = node.to;
|
|
1973
|
+
}
|
|
1974
|
+
from = node.to;
|
|
1975
|
+
}
|
|
1976
|
+
if (node.from < to && node.to > to) {
|
|
1977
|
+
to = node.from;
|
|
1978
|
+
}
|
|
1979
|
+
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
1980
|
+
const markType = InlineMarker[name];
|
|
1981
|
+
const size = inlineMarkerText(markType).length;
|
|
1982
|
+
const openEnd = node.from + size;
|
|
1983
|
+
const closeStart = node.to - size;
|
|
1984
|
+
if (markType === type) {
|
|
1985
|
+
if (openEnd <= from && closeStart >= from) {
|
|
1986
|
+
startCovered = openEnd === from ? "adjacent" : true;
|
|
1987
|
+
}
|
|
1988
|
+
if (openEnd <= to && closeStart >= to) {
|
|
1989
|
+
endCovered = closeStart === to ? "adjacent" : true;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (markType === type || type === 3 && enable) {
|
|
1993
|
+
if (node.from >= from && openEnd <= to) {
|
|
1994
|
+
changes2.push({
|
|
1995
|
+
from: node.from,
|
|
1996
|
+
to: openEnd
|
|
1997
|
+
});
|
|
1998
|
+
if (markType !== type && closeStart >= to) {
|
|
1999
|
+
changesAtEnd.push({
|
|
2000
|
+
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2001
|
+
insert: inlineMarkerText(markType)
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
if (closeStart >= from && node.to <= to) {
|
|
2006
|
+
changes2.push({
|
|
2007
|
+
from: closeStart,
|
|
2008
|
+
to: node.to
|
|
2009
|
+
});
|
|
2010
|
+
if (markType !== type && openEnd <= from) {
|
|
2011
|
+
changes2.push({
|
|
2012
|
+
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2013
|
+
insert: inlineMarkerText(markType)
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
1819
2017
|
}
|
|
1820
2018
|
}
|
|
1821
2019
|
},
|
|
1822
|
-
|
|
1823
|
-
|
|
2020
|
+
leave: (node) => {
|
|
2021
|
+
if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
|
|
2022
|
+
const rangeStart = Math.max(from, blockStart);
|
|
2023
|
+
const rangeEnd = Math.min(to, blockEnd);
|
|
2024
|
+
if (enable) {
|
|
2025
|
+
if (!startCovered) {
|
|
2026
|
+
changes2.push({
|
|
2027
|
+
from: rangeStart,
|
|
2028
|
+
insert: marker
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (!endCovered) {
|
|
2032
|
+
changes2.push({
|
|
2033
|
+
from: rangeEnd,
|
|
2034
|
+
insert: marker
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
} else {
|
|
2038
|
+
if (startCovered === "adjacent") {
|
|
2039
|
+
changes2.push({
|
|
2040
|
+
from: from - marker.length,
|
|
2041
|
+
to: from
|
|
2042
|
+
});
|
|
2043
|
+
} else if (startCovered) {
|
|
2044
|
+
changes2.push({
|
|
2045
|
+
from: skipSpaces(rangeStart, state.doc, -1, blockStart),
|
|
2046
|
+
insert: marker
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (endCovered === "adjacent") {
|
|
2050
|
+
changes2.push({
|
|
2051
|
+
from: to,
|
|
2052
|
+
to: to + marker.length
|
|
2053
|
+
});
|
|
2054
|
+
} else if (endCovered) {
|
|
2055
|
+
changes2.push({
|
|
2056
|
+
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
2057
|
+
insert: marker
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
1824
2063
|
});
|
|
2064
|
+
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
2065
|
+
return {
|
|
2066
|
+
changes: changeSet,
|
|
2067
|
+
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
2068
|
+
};
|
|
2069
|
+
});
|
|
2070
|
+
dispatch(state.update(changes, {
|
|
2071
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2072
|
+
scrollIntoView: true
|
|
2073
|
+
}));
|
|
2074
|
+
return true;
|
|
2075
|
+
};
|
|
2076
|
+
var addStyle = (style) => setStyle(style, true);
|
|
2077
|
+
var removeStyle = (style) => setStyle(style, false);
|
|
2078
|
+
var toggleStyle = (style) => (arg) => {
|
|
2079
|
+
const form = getFormatting(arg.state);
|
|
2080
|
+
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
2081
|
+
};
|
|
2082
|
+
var toggleStrong = toggleStyle(0);
|
|
2083
|
+
var toggleEmphasis = toggleStyle(1);
|
|
2084
|
+
var toggleStrikethrough = toggleStyle(2);
|
|
2085
|
+
var toggleInlineCode = toggleStyle(3);
|
|
2086
|
+
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
2087
|
+
var blockContentStart = (node) => {
|
|
2088
|
+
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
2089
|
+
if (atx) {
|
|
2090
|
+
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
1825
2091
|
}
|
|
1826
|
-
return
|
|
2092
|
+
return node.from;
|
|
1827
2093
|
};
|
|
1828
|
-
var
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
update(update2) {
|
|
1836
|
-
this.decorations = buildDecorations2(update2.view);
|
|
1837
|
-
}
|
|
1838
|
-
}, {
|
|
1839
|
-
decorations: (v) => v.decorations
|
|
1840
|
-
})
|
|
1841
|
-
];
|
|
2094
|
+
var blockContentEnd = (node, doc) => {
|
|
2095
|
+
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
2096
|
+
const lastLine = doc.lineAt(node.to);
|
|
2097
|
+
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
2098
|
+
return lastLine.from - 1;
|
|
2099
|
+
}
|
|
2100
|
+
return node.to;
|
|
1842
2101
|
};
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
},
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
2102
|
+
var skipSpaces = (pos, doc, dir, limit) => {
|
|
2103
|
+
const line = doc.lineAt(pos);
|
|
2104
|
+
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
2105
|
+
pos += dir;
|
|
2106
|
+
}
|
|
2107
|
+
return pos;
|
|
2108
|
+
};
|
|
2109
|
+
var snippets = {
|
|
2110
|
+
codeblock: snippet([
|
|
2111
|
+
"```#{lang}",
|
|
2112
|
+
"#{}",
|
|
2113
|
+
"```"
|
|
2114
|
+
].join("\n")),
|
|
2115
|
+
table: snippet([
|
|
2116
|
+
"| #{col1} | #{col2} |",
|
|
2117
|
+
"| ---- | ---- |",
|
|
2118
|
+
"| #{val1} | #{val2} |",
|
|
2119
|
+
"| #{val3} | #{val4} |"
|
|
2120
|
+
].join("\n"))
|
|
2121
|
+
};
|
|
2122
|
+
var insertTable = (view) => {
|
|
2123
|
+
const { selection: { main }, doc } = view.state;
|
|
2124
|
+
const { number } = doc.lineAt(main.anchor);
|
|
2125
|
+
const { from } = doc.line(number);
|
|
2126
|
+
snippets.table(view, null, from, from);
|
|
2127
|
+
};
|
|
2128
|
+
var removeLinkInner = (from, to, changes, state) => {
|
|
2129
|
+
syntaxTree2(state).iterate({
|
|
2130
|
+
from,
|
|
2131
|
+
to,
|
|
2132
|
+
enter: (node) => {
|
|
2133
|
+
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
2134
|
+
node.node.cursor().iterate((node2) => {
|
|
2135
|
+
const { name } = node2;
|
|
2136
|
+
if (name === "LinkMark" || name === "LinkLabel") {
|
|
2137
|
+
changes.push({
|
|
2138
|
+
from: node2.from,
|
|
2139
|
+
to: node2.to
|
|
2140
|
+
});
|
|
2141
|
+
} else if (name === "LinkTitle" || name === "URL") {
|
|
2142
|
+
changes.push({
|
|
2143
|
+
from: skipSpaces(node2.from, state.doc, -1),
|
|
2144
|
+
to: skipSpaces(node2.to, state.doc, 1)
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
return false;
|
|
1856
2149
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2150
|
+
}
|
|
2151
|
+
});
|
|
2152
|
+
};
|
|
2153
|
+
var removeLink = ({ state, dispatch }) => {
|
|
2154
|
+
const changes = [];
|
|
2155
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2156
|
+
removeLinkInner(from, to, changes, state);
|
|
2157
|
+
}
|
|
2158
|
+
if (!changes) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
dispatch(state.update({
|
|
2162
|
+
changes,
|
|
2163
|
+
userEvent: "format.link.remove",
|
|
2164
|
+
scrollIntoView: true
|
|
2165
|
+
}));
|
|
2166
|
+
return true;
|
|
2167
|
+
};
|
|
2168
|
+
var addLink = ({ state, dispatch }) => {
|
|
2169
|
+
const changes = state.changeByRange((range) => {
|
|
2170
|
+
let { from, to } = range;
|
|
2171
|
+
const cutStyles = [];
|
|
2172
|
+
let okay = null;
|
|
2173
|
+
syntaxTree2(state).iterate({
|
|
2174
|
+
from,
|
|
2175
|
+
to,
|
|
2176
|
+
enter: (node) => {
|
|
2177
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2178
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
|
|
2179
|
+
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
2180
|
+
const sNode = node.node;
|
|
2181
|
+
if (node.from < from && node.to <= to) {
|
|
2182
|
+
if (sNode.firstChild.to === from) {
|
|
2183
|
+
from = node.from;
|
|
2184
|
+
} else {
|
|
2185
|
+
cutStyles.push(sNode);
|
|
2186
|
+
}
|
|
2187
|
+
} else if (node.from >= from && node.to > to) {
|
|
2188
|
+
if (sNode.lastChild.from === to) {
|
|
2189
|
+
to = node.to;
|
|
2190
|
+
} else {
|
|
2191
|
+
cutStyles.push(sNode);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
if (okay === null) {
|
|
2198
|
+
const line = state.doc.lineAt(from);
|
|
2199
|
+
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
2200
|
+
}
|
|
2201
|
+
if (!okay) {
|
|
2202
|
+
return {
|
|
2203
|
+
range
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
const changes2 = [];
|
|
2207
|
+
const changesAfter = [];
|
|
2208
|
+
removeLinkInner(from, to, changesAfter, state);
|
|
2209
|
+
let cursorOffset = 1;
|
|
2210
|
+
for (const style of cutStyles) {
|
|
2211
|
+
const type = InlineMarker[style.name];
|
|
2212
|
+
const mark2 = inlineMarkerText(type);
|
|
2213
|
+
if (style.from < from) {
|
|
2214
|
+
changes2.push({
|
|
2215
|
+
from: skipSpaces(from, state.doc, -1),
|
|
2216
|
+
insert: mark2
|
|
2217
|
+
});
|
|
2218
|
+
changesAfter.push({
|
|
2219
|
+
from: skipSpaces(from, state.doc, 1, to),
|
|
2220
|
+
insert: mark2
|
|
2221
|
+
});
|
|
2222
|
+
} else {
|
|
2223
|
+
changes2.push({
|
|
2224
|
+
from: skipSpaces(to, state.doc, -1, from),
|
|
2225
|
+
insert: mark2
|
|
2226
|
+
});
|
|
2227
|
+
const after = skipSpaces(to, state.doc, 1);
|
|
2228
|
+
if (after === to) {
|
|
2229
|
+
cursorOffset += mark2.length;
|
|
2230
|
+
}
|
|
2231
|
+
changesAfter.push({
|
|
2232
|
+
from: after,
|
|
2233
|
+
insert: mark2
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
changes2.push({
|
|
2238
|
+
from,
|
|
2239
|
+
insert: "["
|
|
2240
|
+
}, {
|
|
2241
|
+
from: to,
|
|
2242
|
+
insert: "]()"
|
|
2243
|
+
});
|
|
2244
|
+
const changeSet = state.changes(changes2.concat(changesAfter));
|
|
2245
|
+
return {
|
|
2246
|
+
changes: changeSet,
|
|
2247
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
2248
|
+
};
|
|
2249
|
+
});
|
|
2250
|
+
if (changes.changes.empty) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
dispatch(state.update(changes, {
|
|
2254
|
+
userEvent: "format.link.add",
|
|
2255
|
+
scrollIntoView: true
|
|
2256
|
+
}));
|
|
2257
|
+
return true;
|
|
2258
|
+
};
|
|
2259
|
+
var addList = (type) => ({ state, dispatch }) => {
|
|
2260
|
+
let lastBlock = -1;
|
|
2261
|
+
let counter = 1;
|
|
2262
|
+
let first = true;
|
|
2263
|
+
let parentColumn = null;
|
|
2264
|
+
const blocks = [];
|
|
2265
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2266
|
+
syntaxTree2(state).iterate({
|
|
2267
|
+
from,
|
|
2268
|
+
to,
|
|
2269
|
+
enter: (node) => {
|
|
2270
|
+
if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
|
|
2271
|
+
if (first) {
|
|
2272
|
+
let before = node.node.prevSibling;
|
|
2273
|
+
while (before && /Mark$/.test(before.name)) {
|
|
2274
|
+
before = before.prevSibling;
|
|
2275
|
+
}
|
|
2276
|
+
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
2277
|
+
const item = before.lastChild;
|
|
2278
|
+
const itemLine = state.doc.lineAt(item.from);
|
|
2279
|
+
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
2280
|
+
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
2281
|
+
if (type === 0) {
|
|
2282
|
+
const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
|
|
2283
|
+
if (mark2) {
|
|
2284
|
+
parentColumn += mark2[1].length;
|
|
2285
|
+
counter = +mark2[1] + 1;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
first = false;
|
|
2290
|
+
}
|
|
2291
|
+
if (node.from === lastBlock) {
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
lastBlock = node.from;
|
|
2295
|
+
blocks.push({
|
|
2296
|
+
node: node.node,
|
|
2297
|
+
counter,
|
|
2298
|
+
parentColumn
|
|
2299
|
+
});
|
|
2300
|
+
counter++;
|
|
2301
|
+
return false;
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
leave: (node) => {
|
|
2305
|
+
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
2306
|
+
counter = 1;
|
|
2307
|
+
parentColumn = null;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
if (!blocks.length) {
|
|
2313
|
+
return false;
|
|
2314
|
+
}
|
|
2315
|
+
const changes = [];
|
|
2316
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
2317
|
+
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
2318
|
+
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
2319
|
+
let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
2320
|
+
if (type === 0) {
|
|
2321
|
+
padding += String(counter2).length;
|
|
2322
|
+
}
|
|
2323
|
+
let line = state.doc.lineAt(nodeFrom);
|
|
2324
|
+
const column = nodeFrom - line.from;
|
|
2325
|
+
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
2326
|
+
padding = Math.max(padding, parentColumn2 - column);
|
|
2327
|
+
}
|
|
2328
|
+
let mark2;
|
|
2329
|
+
if (type === 0) {
|
|
2330
|
+
let max = counter2;
|
|
2331
|
+
for (let j = i + 1; j < blocks.length; j++) {
|
|
2332
|
+
if (blocks[j].counter !== max + 1) {
|
|
2333
|
+
break;
|
|
2334
|
+
}
|
|
2335
|
+
max++;
|
|
2336
|
+
}
|
|
2337
|
+
const num = String(counter2);
|
|
2338
|
+
padding = Math.max(String(max).length, padding);
|
|
2339
|
+
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
2340
|
+
} else {
|
|
2341
|
+
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
2342
|
+
}
|
|
2343
|
+
changes.push({
|
|
2344
|
+
from: nodeFrom,
|
|
2345
|
+
insert: mark2
|
|
2346
|
+
});
|
|
2347
|
+
while (line.to < node.to) {
|
|
2348
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2349
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2350
|
+
changes.push({
|
|
2351
|
+
from: line.from + Math.min(open, column),
|
|
2352
|
+
insert: " ".repeat(mark2.length)
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
if (type === 0) {
|
|
2357
|
+
const last = blocks[blocks.length - 1];
|
|
2358
|
+
let next = last.node.nextSibling;
|
|
2359
|
+
while (next && /Mark$/.test(next.name)) {
|
|
2360
|
+
next = next.nextSibling;
|
|
2361
|
+
}
|
|
2362
|
+
if (next?.name === "OrderedList") {
|
|
2363
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
dispatch(state.update({
|
|
2367
|
+
changes,
|
|
2368
|
+
userEvent: "format.list.add",
|
|
2369
|
+
scrollIntoView: true
|
|
2370
|
+
}));
|
|
2371
|
+
return true;
|
|
2372
|
+
};
|
|
2373
|
+
var removeList = (type) => ({ state, dispatch }) => {
|
|
2374
|
+
let lastBlock = -1;
|
|
2375
|
+
const changes = [];
|
|
2376
|
+
const stack = [];
|
|
2377
|
+
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
2378
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2379
|
+
syntaxTree2(state).iterate({
|
|
2380
|
+
from,
|
|
2381
|
+
to,
|
|
2382
|
+
enter: (node) => {
|
|
2383
|
+
const { name } = node;
|
|
2384
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2385
|
+
stack.push(name);
|
|
2386
|
+
} else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2387
|
+
stack[stack.length - 1] = "TaskList";
|
|
2388
|
+
}
|
|
2389
|
+
},
|
|
2390
|
+
leave: (node) => {
|
|
2391
|
+
const { name } = node;
|
|
2392
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2393
|
+
stack.pop();
|
|
2394
|
+
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
2395
|
+
lastBlock = node.from;
|
|
2396
|
+
let line = state.doc.lineAt(node.from);
|
|
2397
|
+
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
2398
|
+
if (!mark2) {
|
|
2399
|
+
return false;
|
|
2400
|
+
}
|
|
2401
|
+
const column = node.from - line.from;
|
|
2402
|
+
changes.push({
|
|
2403
|
+
from: node.from,
|
|
2404
|
+
to: node.from + mark2[0].length
|
|
2405
|
+
});
|
|
2406
|
+
while (line.to < node.to) {
|
|
2407
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2408
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2409
|
+
if (open > column) {
|
|
2410
|
+
changes.push({
|
|
2411
|
+
from: line.from + column,
|
|
2412
|
+
to: line.from + Math.min(column + mark2[0].length, open)
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
if (node.to >= to) {
|
|
2417
|
+
renumberListItems(node.node.nextSibling, 1, changes, state.doc);
|
|
2418
|
+
}
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
if (!changes.length) {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
dispatch(state.update({
|
|
2428
|
+
changes,
|
|
2429
|
+
userEvent: "format.list.remove",
|
|
2430
|
+
scrollIntoView: true
|
|
2431
|
+
}));
|
|
2432
|
+
return true;
|
|
2433
|
+
};
|
|
2434
|
+
var toggleList = (type) => (target) => {
|
|
2435
|
+
const formatting2 = getFormatting(target.state);
|
|
2436
|
+
const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
|
|
2437
|
+
return (active ? removeList(type) : addList(type))(target);
|
|
2438
|
+
};
|
|
2439
|
+
var renumberListItems = (item, counter, changes, doc) => {
|
|
2440
|
+
for (; item; item = item.nextSibling) {
|
|
2441
|
+
if (item.name === "ListItem") {
|
|
2442
|
+
const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
|
|
2443
|
+
if (!number || +number[2] === counter) {
|
|
2444
|
+
break;
|
|
2445
|
+
}
|
|
2446
|
+
const size = number[1].length + number[2].length;
|
|
2447
|
+
const newNum = String(counter);
|
|
2448
|
+
changes.push({
|
|
2449
|
+
from: item.from + Math.max(0, size - newNum.length),
|
|
2450
|
+
to: item.from + size,
|
|
2451
|
+
insert: newNum
|
|
2452
|
+
});
|
|
2453
|
+
counter++;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
2458
|
+
const lines = [];
|
|
2459
|
+
let lastBlock = -1;
|
|
2460
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2461
|
+
syntaxTree2(state).iterate({
|
|
2462
|
+
from,
|
|
2463
|
+
to,
|
|
2464
|
+
enter: (node) => {
|
|
2465
|
+
if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
|
|
2466
|
+
if (node.from === lastBlock) {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
lastBlock = node.from;
|
|
2470
|
+
let line = state.doc.lineAt(node.from);
|
|
2471
|
+
if (line.number > 1) {
|
|
2472
|
+
const prevLine = state.doc.line(line.number - 1);
|
|
2473
|
+
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2474
|
+
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2475
|
+
lines.push(prevLine);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
for (; ; ) {
|
|
2480
|
+
lines.push(line);
|
|
2481
|
+
if (line.to >= node.to) {
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
line = state.doc.line(line.number + 1);
|
|
2485
|
+
}
|
|
2486
|
+
if (!enable && line.number < state.doc.lines) {
|
|
2487
|
+
const nextLine = state.doc.line(line.number + 1);
|
|
2488
|
+
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2489
|
+
lines.push(nextLine);
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return false;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
const changes = [];
|
|
2498
|
+
for (const line of lines) {
|
|
2499
|
+
if (enable) {
|
|
2500
|
+
changes.push({
|
|
2501
|
+
from: line.from,
|
|
2502
|
+
insert: /\S/.test(line.text) ? "> " : ">"
|
|
2503
|
+
});
|
|
2504
|
+
} else {
|
|
2505
|
+
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
2506
|
+
if (quote) {
|
|
2507
|
+
changes.push({
|
|
2508
|
+
from: line.from + quote[1].length,
|
|
2509
|
+
to: line.from + quote[0].length
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (!changes.length) {
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
dispatch(state.update({
|
|
2518
|
+
changes,
|
|
2519
|
+
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
2520
|
+
scrollIntoView: true
|
|
2521
|
+
}));
|
|
2522
|
+
return true;
|
|
2523
|
+
};
|
|
2524
|
+
var addBlockquote = setBlockquote(true);
|
|
2525
|
+
var removeBlockquote = setBlockquote(false);
|
|
2526
|
+
var toggleBlockquote = (target) => {
|
|
2527
|
+
return (getFormatting(target.state).blockquote ? removeBlockquote : addBlockquote)(target);
|
|
2528
|
+
};
|
|
2529
|
+
var addCodeblock = (target) => {
|
|
2530
|
+
const { state, dispatch } = target;
|
|
2531
|
+
const { selection } = state;
|
|
2532
|
+
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
2533
|
+
const { head } = selection.main;
|
|
2534
|
+
const line = state.doc.lineAt(head);
|
|
2535
|
+
if (!/\S/.test(line.text) && head === line.from) {
|
|
2536
|
+
snippets.codeblock(target, null, line.from, line.to);
|
|
2537
|
+
return true;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const ranges = [];
|
|
2541
|
+
for (const { from, to } of selection.ranges) {
|
|
2542
|
+
let blockFrom = from;
|
|
2543
|
+
let blockTo = to;
|
|
2544
|
+
syntaxTree2(state).iterate({
|
|
2545
|
+
from,
|
|
2546
|
+
to,
|
|
2547
|
+
enter: (node) => {
|
|
2548
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2549
|
+
if (from >= node.from && to <= node.to) {
|
|
2550
|
+
blockFrom = node.from;
|
|
2551
|
+
blockTo = node.to;
|
|
2552
|
+
} else {
|
|
2553
|
+
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
2554
|
+
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
});
|
|
2559
|
+
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
2560
|
+
ranges[ranges.length - 1].to = blockTo;
|
|
2561
|
+
} else {
|
|
2562
|
+
ranges.push({
|
|
2563
|
+
from: blockFrom,
|
|
2564
|
+
to: blockTo
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if (!ranges.length) {
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
const changes = ranges.map(({ from, to }) => {
|
|
2572
|
+
const column = from - state.doc.lineAt(from).from;
|
|
2573
|
+
return [
|
|
2574
|
+
{
|
|
2575
|
+
from,
|
|
2576
|
+
insert: "```\n" + " ".repeat(column)
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
from: to,
|
|
2580
|
+
insert: "\n" + " ".repeat(column) + "```"
|
|
2581
|
+
}
|
|
2582
|
+
];
|
|
2583
|
+
});
|
|
2584
|
+
dispatch(state.update({
|
|
2585
|
+
changes,
|
|
2586
|
+
userEvent: "format.codeblock.add",
|
|
2587
|
+
scrollIntoView: true
|
|
2588
|
+
}));
|
|
2589
|
+
return true;
|
|
2590
|
+
};
|
|
2591
|
+
var removeCodeblock = ({ state, dispatch }) => {
|
|
2592
|
+
const changes = [];
|
|
2593
|
+
let lastBlock = -1;
|
|
2594
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2595
|
+
syntaxTree2(state).iterate({
|
|
2596
|
+
from,
|
|
2597
|
+
to,
|
|
2598
|
+
enter: (node) => {
|
|
2599
|
+
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
2600
|
+
lastBlock = node.from;
|
|
2601
|
+
const firstLine = state.doc.lineAt(node.from);
|
|
2602
|
+
if (node.name === "FencedCode") {
|
|
2603
|
+
changes.push({
|
|
2604
|
+
from: node.from,
|
|
2605
|
+
to: firstLine.to + 1 + node.from - firstLine.from
|
|
2606
|
+
});
|
|
2607
|
+
const lastLine = state.doc.lineAt(node.to);
|
|
2608
|
+
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
2609
|
+
changes.push({
|
|
2610
|
+
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
2611
|
+
to: lastLine.to
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2614
|
+
} else {
|
|
2615
|
+
const column = node.from - firstLine.from;
|
|
2616
|
+
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
2617
|
+
changes.push({
|
|
2618
|
+
from: line.from + column - 4,
|
|
2619
|
+
to: line.from + column
|
|
2620
|
+
});
|
|
2621
|
+
if (line.to >= node.to) {
|
|
2622
|
+
break;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
if (!changes.length) {
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
dispatch(state.update({
|
|
2634
|
+
changes,
|
|
2635
|
+
userEvent: "format.codeblock.remove",
|
|
2636
|
+
scrollIntoView: true
|
|
2637
|
+
}));
|
|
2638
|
+
return true;
|
|
2639
|
+
};
|
|
2640
|
+
var toggleCodeblock = (target) => {
|
|
2641
|
+
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
2642
|
+
};
|
|
2643
|
+
var formatting = (options = {}) => {
|
|
2644
|
+
return [
|
|
2645
|
+
keymap5.of([
|
|
2646
|
+
{
|
|
2647
|
+
key: "meta-b",
|
|
2648
|
+
run: toggleStrong
|
|
2649
|
+
}
|
|
2650
|
+
]),
|
|
2651
|
+
styling()
|
|
2652
|
+
];
|
|
2653
|
+
};
|
|
2654
|
+
var styling = () => {
|
|
2655
|
+
const buildDecorations7 = (view) => {
|
|
2656
|
+
const builder = new RangeSetBuilder2();
|
|
2657
|
+
const { state } = view;
|
|
2658
|
+
const cursor = state.selection.main.head;
|
|
2659
|
+
const replace = (node, marks) => {
|
|
2660
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2661
|
+
for (const mark2 of marks) {
|
|
2662
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2667
|
+
syntaxTree2(state).iterate({
|
|
2668
|
+
enter: (node) => {
|
|
2669
|
+
switch (node.name) {
|
|
2670
|
+
case "Emphasis":
|
|
2671
|
+
case "StrongEmphasis": {
|
|
2672
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
2673
|
+
replace(node, marks);
|
|
2674
|
+
break;
|
|
2675
|
+
}
|
|
2676
|
+
case "Strikethrough": {
|
|
2677
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
2678
|
+
replace(node, marks);
|
|
2679
|
+
break;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
},
|
|
2683
|
+
from,
|
|
2684
|
+
to
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
return builder.finish();
|
|
2688
|
+
};
|
|
2689
|
+
return [
|
|
2690
|
+
ViewPlugin4.fromClass(class {
|
|
2691
|
+
constructor(view) {
|
|
2692
|
+
this.decorations = buildDecorations7(view);
|
|
2693
|
+
}
|
|
2694
|
+
update(update2) {
|
|
2695
|
+
this.decorations = buildDecorations7(update2.view);
|
|
2696
|
+
}
|
|
2697
|
+
}, {
|
|
2698
|
+
decorations: (value) => value.decorations
|
|
2699
|
+
})
|
|
2700
|
+
];
|
|
2701
|
+
};
|
|
2702
|
+
var InlineMarker = {
|
|
2703
|
+
Emphasis: 1,
|
|
2704
|
+
StrongEmphasis: 0,
|
|
2705
|
+
InlineCode: 3,
|
|
2706
|
+
Strikethrough: 2
|
|
2707
|
+
};
|
|
2708
|
+
var IgnoreInline = /* @__PURE__ */ new Set([
|
|
2709
|
+
"Hardbreak",
|
|
2710
|
+
"HTMLTag",
|
|
2711
|
+
"Comment",
|
|
2712
|
+
"ProcessingInstruction",
|
|
2713
|
+
"Autolink",
|
|
2714
|
+
"HeaderMark",
|
|
2715
|
+
"QuoteMark",
|
|
2716
|
+
"ListMark",
|
|
2717
|
+
"LinkMark",
|
|
2718
|
+
"EmphasisMark",
|
|
2719
|
+
"CodeMark",
|
|
2720
|
+
"CodeText",
|
|
2721
|
+
"StrikethroughMark",
|
|
2722
|
+
"TaskMarker",
|
|
2723
|
+
"SuperscriptMark",
|
|
2724
|
+
"SubscriptMark"
|
|
2725
|
+
]);
|
|
2726
|
+
var Textblocks = {
|
|
2727
|
+
Paragraph: "paragraph",
|
|
2728
|
+
Task: "paragraph",
|
|
2729
|
+
CodeBlock: "codeblock",
|
|
2730
|
+
FencedCode: "codeblock",
|
|
2731
|
+
ATXHeading1: "heading1",
|
|
2732
|
+
ATXHeading2: "heading2",
|
|
2733
|
+
ATXHeading3: "heading3",
|
|
2734
|
+
ATXHeading4: "heading4",
|
|
2735
|
+
ATXHeading5: "heading5",
|
|
2736
|
+
ATXHeading6: "heading6",
|
|
2737
|
+
SetextHeading1: "heading1",
|
|
2738
|
+
SetextHeading2: "heading2",
|
|
2739
|
+
TableCell: "tablecell"
|
|
2740
|
+
};
|
|
2741
|
+
var getFormatting = (state) => {
|
|
2742
|
+
let blockType = null;
|
|
2743
|
+
const inline = [
|
|
2744
|
+
null,
|
|
2745
|
+
null,
|
|
2746
|
+
null,
|
|
2747
|
+
null
|
|
2748
|
+
];
|
|
2749
|
+
let link2 = false;
|
|
2750
|
+
let blockquote2 = null;
|
|
2751
|
+
let listStyle = null;
|
|
2752
|
+
const stack = [];
|
|
2753
|
+
let currentBlock = null;
|
|
2754
|
+
const advanceInline = (upto) => {
|
|
2755
|
+
if (!currentBlock) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
upto = Math.min(upto, currentBlock.end);
|
|
2759
|
+
if (upto <= currentBlock.pos) {
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
2763
|
+
if (inline[i] === false) {
|
|
2764
|
+
continue;
|
|
2765
|
+
} else if (currentBlock.active[i]) {
|
|
2766
|
+
inline[i] = true;
|
|
2767
|
+
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
2768
|
+
inline[i] = false;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
currentBlock.pos = upto;
|
|
2772
|
+
};
|
|
2773
|
+
const skipInline = (upto) => {
|
|
2774
|
+
if (currentBlock && upto > currentBlock.pos) {
|
|
2775
|
+
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
2776
|
+
}
|
|
2777
|
+
};
|
|
2778
|
+
const { selection } = state;
|
|
2779
|
+
for (const range of selection.ranges) {
|
|
2780
|
+
if (range.empty && inline.some((v) => v === null)) {
|
|
2781
|
+
const contextSize = Math.min(range.head, 6);
|
|
2782
|
+
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
2783
|
+
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
2784
|
+
for (let i = 0; i < contextSize; i++) {
|
|
2785
|
+
const ch = contextAfter[i];
|
|
2786
|
+
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
2787
|
+
contextAfter = contextAfter.slice(0, i);
|
|
2788
|
+
break;
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
for (let i = 0; i < inline.length; i++) {
|
|
2792
|
+
const mark2 = inlineMarkerText(i);
|
|
2793
|
+
const found = contextAfter.indexOf(mark2);
|
|
2794
|
+
if (found > -1) {
|
|
2795
|
+
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
2796
|
+
if (inline[i] === null) {
|
|
2797
|
+
inline[i] = true;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
syntaxTree2(state).iterate({
|
|
2803
|
+
from: range.from,
|
|
2804
|
+
to: range.to,
|
|
2805
|
+
enter: (node) => {
|
|
2806
|
+
advanceInline(node.from);
|
|
2807
|
+
const { name } = node;
|
|
2808
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2809
|
+
stack.push(name);
|
|
2810
|
+
} else if (name === "Link") {
|
|
2811
|
+
link2 = true;
|
|
2812
|
+
} else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
|
|
2813
|
+
if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2814
|
+
stack[stack.length - 1] = "TaskList";
|
|
2815
|
+
}
|
|
2816
|
+
const blockCode = Textblocks[name];
|
|
2817
|
+
if (blockType === null) {
|
|
2818
|
+
blockType = blockCode;
|
|
2819
|
+
} else if (blockType !== blockCode) {
|
|
2820
|
+
blockType = false;
|
|
2821
|
+
}
|
|
2822
|
+
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
2823
|
+
currentBlock = {
|
|
2824
|
+
pos: Math.max(range.from, node.from),
|
|
2825
|
+
end: Math.min(range.to, node.to),
|
|
2826
|
+
active: [
|
|
2827
|
+
false,
|
|
2828
|
+
false,
|
|
2829
|
+
false,
|
|
2830
|
+
false
|
|
2831
|
+
]
|
|
2832
|
+
};
|
|
2833
|
+
}
|
|
2834
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2835
|
+
const index = InlineMarker[name];
|
|
2836
|
+
if (range.empty && inline[index] === null) {
|
|
2837
|
+
inline[index] = true;
|
|
2838
|
+
}
|
|
2839
|
+
currentBlock.active[index] = true;
|
|
2840
|
+
} else if (IgnoreInline.has(name)) {
|
|
2841
|
+
skipInline(node.to);
|
|
2842
|
+
}
|
|
2843
|
+
},
|
|
2844
|
+
leave: (node) => {
|
|
2845
|
+
advanceInline(node.to);
|
|
2846
|
+
const { name } = node;
|
|
2847
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2848
|
+
stack.pop();
|
|
2849
|
+
} else if (Object.hasOwn(Textblocks, name)) {
|
|
2850
|
+
let hasList = false;
|
|
2851
|
+
let hasQuote = false;
|
|
2852
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2853
|
+
if (stack[i] === "Blockquote") {
|
|
2854
|
+
hasQuote = true;
|
|
2855
|
+
} else if (!hasList) {
|
|
2856
|
+
hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
if (blockquote2 === null) {
|
|
2860
|
+
blockquote2 = hasQuote;
|
|
2861
|
+
} else if (!hasQuote && blockquote2) {
|
|
2862
|
+
blockquote2 = false;
|
|
2863
|
+
}
|
|
2864
|
+
if (listStyle === null) {
|
|
2865
|
+
listStyle = hasList;
|
|
2866
|
+
} else if (listStyle !== hasList) {
|
|
2867
|
+
listStyle = false;
|
|
2868
|
+
}
|
|
2869
|
+
currentBlock = null;
|
|
2870
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2871
|
+
currentBlock.active[InlineMarker[name]] = false;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
return {
|
|
2877
|
+
blockType: blockType || null,
|
|
2878
|
+
strong: inline[0] ?? false,
|
|
2879
|
+
emphasis: inline[1] ?? false,
|
|
2880
|
+
code: inline[3] ?? false,
|
|
2881
|
+
strikethrough: inline[2] ?? false,
|
|
2882
|
+
link: link2,
|
|
2883
|
+
blockquote: blockquote2 ?? false,
|
|
2884
|
+
listStyle: listStyle || null
|
|
2885
|
+
};
|
|
2886
|
+
};
|
|
2887
|
+
var useFormattingState = () => {
|
|
2888
|
+
const [state, setState] = useState(null);
|
|
2889
|
+
const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
|
|
2890
|
+
if (update2.docChanged || update2.selectionSet) {
|
|
2891
|
+
const newState = getFormatting(update2.state);
|
|
2892
|
+
if (!state || !compareFormatting(state, newState)) {
|
|
2893
|
+
setState(newState);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}), []);
|
|
2897
|
+
return [
|
|
2898
|
+
state,
|
|
2899
|
+
observer
|
|
2900
|
+
];
|
|
2901
|
+
};
|
|
2902
|
+
|
|
2903
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
2904
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
2905
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
2906
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
2907
|
+
var buildDecorations2 = (view) => {
|
|
2908
|
+
const builder = new RangeSetBuilder3();
|
|
2909
|
+
const { state } = view;
|
|
2910
|
+
const cursor = state.selection.main.head;
|
|
2911
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2912
|
+
syntaxTree3(state).iterate({
|
|
2913
|
+
enter: (node) => {
|
|
2914
|
+
switch (node.name) {
|
|
2915
|
+
case "ATXHeading1":
|
|
2916
|
+
case "ATXHeading2":
|
|
2917
|
+
case "ATXHeading3":
|
|
2918
|
+
case "ATXHeading4":
|
|
2919
|
+
case "ATXHeading5":
|
|
2920
|
+
case "ATXHeading6": {
|
|
2921
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
2922
|
+
if (mark2) {
|
|
2923
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2924
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
from,
|
|
2931
|
+
to
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
return builder.finish();
|
|
2935
|
+
};
|
|
2936
|
+
var heading2 = () => {
|
|
2937
|
+
return [
|
|
2938
|
+
ViewPlugin5.fromClass(class {
|
|
2939
|
+
constructor(view) {
|
|
2940
|
+
this.decorations = buildDecorations2(view);
|
|
2941
|
+
}
|
|
2942
|
+
update(update2) {
|
|
2943
|
+
this.decorations = buildDecorations2(update2.view);
|
|
2944
|
+
}
|
|
2945
|
+
}, {
|
|
2946
|
+
decorations: (value) => value.decorations
|
|
2947
|
+
})
|
|
2948
|
+
];
|
|
2949
|
+
};
|
|
2950
|
+
|
|
2951
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2952
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2953
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2954
|
+
import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2955
|
+
var styles4 = EditorView10.baseTheme({
|
|
2956
|
+
"& .cm-hr": {
|
|
2957
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2958
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2962
|
+
toDOM() {
|
|
2963
|
+
const el = document.createElement("div");
|
|
2964
|
+
el.className = "cm-hr";
|
|
2965
|
+
return el;
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
var decoration = Decoration6.replace({
|
|
2969
|
+
widget: new HorizontalRuleWidget()
|
|
2970
|
+
});
|
|
2971
|
+
var buildDecorations3 = (view) => {
|
|
2972
|
+
const builder = new RangeSetBuilder4();
|
|
2973
|
+
const { state } = view;
|
|
2974
|
+
const cursor = state.selection.main.head;
|
|
2975
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2976
|
+
syntaxTree4(state).iterate({
|
|
2977
|
+
enter: (node) => {
|
|
2978
|
+
if (node.name === "HorizontalRule") {
|
|
2979
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2980
|
+
builder.add(node.from, node.to, decoration);
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
},
|
|
2984
|
+
from,
|
|
2985
|
+
to
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
return builder.finish();
|
|
2989
|
+
};
|
|
2990
|
+
var hr = () => {
|
|
2991
|
+
return [
|
|
2992
|
+
ViewPlugin6.fromClass(class {
|
|
2993
|
+
constructor(view) {
|
|
2994
|
+
this.decorations = buildDecorations3(view);
|
|
2995
|
+
}
|
|
2996
|
+
update(update2) {
|
|
2997
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2998
|
+
}
|
|
2999
|
+
}, {
|
|
3000
|
+
decorations: (value) => value.decorations
|
|
3001
|
+
}),
|
|
3002
|
+
styles4
|
|
3003
|
+
];
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3007
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
3008
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
3009
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3010
|
+
var image = (options = {}) => {
|
|
3011
|
+
return StateField3.define({
|
|
3012
|
+
create: (state) => {
|
|
3013
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
3014
|
+
},
|
|
3015
|
+
update: (value, tr) => {
|
|
3016
|
+
if (!tr.docChanged && !tr.selection) {
|
|
3017
|
+
return value;
|
|
3018
|
+
}
|
|
3019
|
+
const cursor = tr.state.selection.main.head;
|
|
3020
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
3021
|
+
let from = Math.min(cursor, oldCursor);
|
|
3022
|
+
let to = Math.max(cursor, oldCursor);
|
|
3023
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
3024
|
+
from = Math.min(from, fromB);
|
|
3025
|
+
to = Math.max(to, toB);
|
|
1864
3026
|
});
|
|
1865
3027
|
from = tr.state.doc.lineAt(from).from;
|
|
1866
3028
|
to = tr.state.doc.lineAt(to).to;
|
|
@@ -1868,23 +3030,23 @@ var image = (options = {}) => {
|
|
|
1868
3030
|
filterFrom: from,
|
|
1869
3031
|
filterTo: to,
|
|
1870
3032
|
filter: () => false,
|
|
1871
|
-
add:
|
|
3033
|
+
add: buildDecorations4(from, to, tr.state)
|
|
1872
3034
|
});
|
|
1873
3035
|
},
|
|
1874
|
-
provide: (field) =>
|
|
3036
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1875
3037
|
});
|
|
1876
3038
|
};
|
|
1877
|
-
var
|
|
3039
|
+
var buildDecorations4 = (from, to, state) => {
|
|
1878
3040
|
const decorations = [];
|
|
1879
3041
|
const cursor = state.selection.main.head;
|
|
1880
|
-
|
|
3042
|
+
syntaxTree5(state).iterate({
|
|
1881
3043
|
enter: (node) => {
|
|
1882
3044
|
if (node.name === "Image") {
|
|
1883
3045
|
const urlNode = node.node.getChild("URL");
|
|
1884
3046
|
if (urlNode) {
|
|
1885
3047
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1886
3048
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1887
|
-
decorations.push(
|
|
3049
|
+
decorations.push(Decoration7.replace({
|
|
1888
3050
|
block: true,
|
|
1889
3051
|
widget: new ImageWidget(url)
|
|
1890
3052
|
}).range(hide ? node.from : node.to, node.to));
|
|
@@ -1896,7 +3058,7 @@ var buildDecorations3 = (from, to, state) => {
|
|
|
1896
3058
|
});
|
|
1897
3059
|
return decorations;
|
|
1898
3060
|
};
|
|
1899
|
-
var ImageWidget = class extends
|
|
3061
|
+
var ImageWidget = class extends WidgetType4 {
|
|
1900
3062
|
constructor(_url) {
|
|
1901
3063
|
super();
|
|
1902
3064
|
this._url = _url;
|
|
@@ -1914,23 +3076,23 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1914
3076
|
};
|
|
1915
3077
|
|
|
1916
3078
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
1917
|
-
import { syntaxTree as
|
|
1918
|
-
import { RangeSetBuilder as
|
|
1919
|
-
import { hoverTooltip as hoverTooltip2, Decoration as
|
|
3079
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
3080
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
3081
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1920
3082
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1921
3083
|
var link = (options = {}) => {
|
|
1922
3084
|
const extensions = [
|
|
1923
|
-
|
|
3085
|
+
ViewPlugin7.fromClass(class {
|
|
1924
3086
|
constructor(view) {
|
|
1925
|
-
this.decorations =
|
|
3087
|
+
this.decorations = buildDecorations5(view, options);
|
|
1926
3088
|
}
|
|
1927
3089
|
update(update2) {
|
|
1928
3090
|
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1929
|
-
this.decorations =
|
|
3091
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
1930
3092
|
}
|
|
1931
3093
|
}
|
|
1932
3094
|
}, {
|
|
1933
|
-
decorations: (
|
|
3095
|
+
decorations: (value) => value.decorations
|
|
1934
3096
|
})
|
|
1935
3097
|
];
|
|
1936
3098
|
if (options.onHover) {
|
|
@@ -1939,7 +3101,7 @@ var link = (options = {}) => {
|
|
|
1939
3101
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1940
3102
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1941
3103
|
hoverTooltip2((view, pos, side) => {
|
|
1942
|
-
const syntax =
|
|
3104
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
1943
3105
|
let link2 = null;
|
|
1944
3106
|
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1945
3107
|
link2 = node.name === "Link" ? node : null;
|
|
@@ -1971,7 +3133,7 @@ var link = (options = {}) => {
|
|
|
1971
3133
|
}
|
|
1972
3134
|
return extensions;
|
|
1973
3135
|
};
|
|
1974
|
-
var LinkButton = class extends
|
|
3136
|
+
var LinkButton = class extends WidgetType5 {
|
|
1975
3137
|
constructor(_url, _onAttach) {
|
|
1976
3138
|
super();
|
|
1977
3139
|
this._url = _url;
|
|
@@ -1986,7 +3148,7 @@ var LinkButton = class extends WidgetType4 {
|
|
|
1986
3148
|
return el;
|
|
1987
3149
|
}
|
|
1988
3150
|
};
|
|
1989
|
-
var LinkText = class extends
|
|
3151
|
+
var LinkText = class extends WidgetType5 {
|
|
1990
3152
|
constructor(_text, _url) {
|
|
1991
3153
|
super();
|
|
1992
3154
|
this._text = _text;
|
|
@@ -2015,28 +3177,28 @@ var LinkText = class extends WidgetType4 {
|
|
|
2015
3177
|
return link2;
|
|
2016
3178
|
}
|
|
2017
3179
|
};
|
|
2018
|
-
var
|
|
2019
|
-
const builder = new
|
|
3180
|
+
var buildDecorations5 = (view, options) => {
|
|
3181
|
+
const builder = new RangeSetBuilder5();
|
|
2020
3182
|
const { state } = view;
|
|
2021
3183
|
const cursor = state.selection.main.head;
|
|
2022
3184
|
for (const { from, to } of view.visibleRanges) {
|
|
2023
|
-
|
|
3185
|
+
syntaxTree6(state).iterate({
|
|
2024
3186
|
enter: (node) => {
|
|
2025
3187
|
if (node.name === "Link") {
|
|
2026
|
-
const
|
|
2027
|
-
const text =
|
|
3188
|
+
const marks = node.node.getChildren("LinkMark");
|
|
3189
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2028
3190
|
const urlNode = node.node.getChild("URL");
|
|
2029
3191
|
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2030
3192
|
if (!url) {
|
|
2031
3193
|
return false;
|
|
2032
3194
|
}
|
|
2033
3195
|
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2034
|
-
builder.add(node.from, node.to,
|
|
3196
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2035
3197
|
widget: new LinkText(text, options.link ? url : void 0)
|
|
2036
3198
|
}));
|
|
2037
3199
|
}
|
|
2038
3200
|
if (options.onRender) {
|
|
2039
|
-
builder.add(node.to, node.to,
|
|
3201
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2040
3202
|
widget: new LinkButton(url, options.onRender)
|
|
2041
3203
|
}));
|
|
2042
3204
|
}
|
|
@@ -2051,18 +3213,18 @@ var buildDecorations4 = (view, options) => {
|
|
|
2051
3213
|
};
|
|
2052
3214
|
|
|
2053
3215
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2054
|
-
import { syntaxTree as
|
|
2055
|
-
import { RangeSetBuilder as
|
|
2056
|
-
import { Decoration as
|
|
3216
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
3217
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
3218
|
+
import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
2057
3219
|
var table = (options = {}) => {
|
|
2058
3220
|
return StateField4.define({
|
|
2059
3221
|
create: (state) => update(state, options),
|
|
2060
3222
|
update: (_, tr) => update(tr.state, options),
|
|
2061
|
-
provide: (field) =>
|
|
3223
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
2062
3224
|
});
|
|
2063
3225
|
};
|
|
2064
3226
|
var update = (state, options) => {
|
|
2065
|
-
const builder = new
|
|
3227
|
+
const builder = new RangeSetBuilder6();
|
|
2066
3228
|
const cursor = state.selection.main.head;
|
|
2067
3229
|
const tables = [];
|
|
2068
3230
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2070,7 +3232,7 @@ var update = (state, options) => {
|
|
|
2070
3232
|
const table2 = getTable();
|
|
2071
3233
|
return table2.rows?.[table2.rows.length - 1];
|
|
2072
3234
|
};
|
|
2073
|
-
|
|
3235
|
+
syntaxTree7(state).iterate({
|
|
2074
3236
|
enter: (node) => {
|
|
2075
3237
|
switch (node.name) {
|
|
2076
3238
|
case "Table": {
|
|
@@ -2102,16 +3264,16 @@ var update = (state, options) => {
|
|
|
2102
3264
|
});
|
|
2103
3265
|
tables.forEach((table2) => {
|
|
2104
3266
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2105
|
-
hide && builder.add(table2.from, table2.to,
|
|
3267
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2106
3268
|
widget: new TableWidget(table2)
|
|
2107
3269
|
}));
|
|
2108
|
-
builder.add(table2.from, table2.to,
|
|
3270
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2109
3271
|
class: "cm-table"
|
|
2110
3272
|
}));
|
|
2111
3273
|
});
|
|
2112
3274
|
return builder.finish();
|
|
2113
3275
|
};
|
|
2114
|
-
var TableWidget = class extends
|
|
3276
|
+
var TableWidget = class extends WidgetType6 {
|
|
2115
3277
|
constructor(_table) {
|
|
2116
3278
|
super();
|
|
2117
3279
|
this._table = _table;
|
|
@@ -2149,10 +3311,10 @@ var TableWidget = class extends WidgetType5 {
|
|
|
2149
3311
|
};
|
|
2150
3312
|
|
|
2151
3313
|
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2152
|
-
import { syntaxTree as
|
|
2153
|
-
import { RangeSetBuilder as
|
|
2154
|
-
import { EditorView as
|
|
2155
|
-
var styles5 =
|
|
3314
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
3315
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
3316
|
+
import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
3317
|
+
var styles5 = EditorView13.baseTheme({
|
|
2156
3318
|
"& .cm-task": {
|
|
2157
3319
|
color: getToken("extend.colors.blue.500")
|
|
2158
3320
|
},
|
|
@@ -2161,7 +3323,7 @@ var styles5 = EditorView12.baseTheme({
|
|
|
2161
3323
|
marginRight: "4px"
|
|
2162
3324
|
}
|
|
2163
3325
|
});
|
|
2164
|
-
var CheckboxWidget = class extends
|
|
3326
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2165
3327
|
constructor(_checked) {
|
|
2166
3328
|
super();
|
|
2167
3329
|
this._checked = _checked;
|
|
@@ -2198,23 +3360,23 @@ var CheckboxWidget = class extends WidgetType6 {
|
|
|
2198
3360
|
return false;
|
|
2199
3361
|
}
|
|
2200
3362
|
};
|
|
2201
|
-
var checkedDecoration =
|
|
3363
|
+
var checkedDecoration = Decoration10.replace({
|
|
2202
3364
|
widget: new CheckboxWidget(true)
|
|
2203
3365
|
});
|
|
2204
|
-
var uncheckedDecoration =
|
|
3366
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2205
3367
|
widget: new CheckboxWidget(false)
|
|
2206
3368
|
});
|
|
2207
|
-
var
|
|
2208
|
-
const builder = new
|
|
3369
|
+
var buildDecorations6 = (view) => {
|
|
3370
|
+
const builder = new RangeSetBuilder7();
|
|
2209
3371
|
const { state } = view;
|
|
2210
3372
|
const cursor = state.selection.main.head;
|
|
2211
3373
|
for (const { from, to } of view.visibleRanges) {
|
|
2212
|
-
|
|
3374
|
+
syntaxTree8(state).iterate({
|
|
2213
3375
|
enter: (node) => {
|
|
2214
3376
|
if (node.name === "TaskMarker") {
|
|
2215
3377
|
if (cursor < node.from || cursor > node.to) {
|
|
2216
3378
|
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2217
|
-
builder.add(node.from - 2, node.from - 1,
|
|
3379
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2218
3380
|
class: "cm-task"
|
|
2219
3381
|
}));
|
|
2220
3382
|
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
@@ -2229,17 +3391,17 @@ var buildDecorations5 = (view) => {
|
|
|
2229
3391
|
};
|
|
2230
3392
|
var tasklist = (options = {}) => {
|
|
2231
3393
|
return [
|
|
2232
|
-
|
|
3394
|
+
ViewPlugin8.fromClass(class {
|
|
2233
3395
|
constructor(view) {
|
|
2234
|
-
this.decorations =
|
|
3396
|
+
this.decorations = buildDecorations6(view);
|
|
2235
3397
|
}
|
|
2236
3398
|
update(update2) {
|
|
2237
3399
|
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2238
|
-
this.decorations =
|
|
3400
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2239
3401
|
}
|
|
2240
3402
|
}
|
|
2241
3403
|
}, {
|
|
2242
|
-
decorations: (
|
|
3404
|
+
decorations: (value) => value.decorations
|
|
2243
3405
|
}),
|
|
2244
3406
|
styles5
|
|
2245
3407
|
];
|
|
@@ -2280,7 +3442,7 @@ var outliner = (options = {}) => {
|
|
|
2280
3442
|
};
|
|
2281
3443
|
|
|
2282
3444
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2283
|
-
import { keymap as
|
|
3445
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2284
3446
|
var defaultItems = [
|
|
2285
3447
|
"hello world!",
|
|
2286
3448
|
"this is a test.",
|
|
@@ -2290,7 +3452,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2290
3452
|
let t;
|
|
2291
3453
|
let idx = 0;
|
|
2292
3454
|
return [
|
|
2293
|
-
|
|
3455
|
+
keymap6.of([
|
|
2294
3456
|
{
|
|
2295
3457
|
// Reset.
|
|
2296
3458
|
key: "alt-meta-'",
|
|
@@ -2367,8 +3529,9 @@ var defaultTheme = {
|
|
|
2367
3529
|
outline: "none"
|
|
2368
3530
|
},
|
|
2369
3531
|
".cm-scroller": {
|
|
2370
|
-
overflow:
|
|
2371
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3532
|
+
// overflow: 'visible',
|
|
3533
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3534
|
+
lineHeight: 1.4
|
|
2372
3535
|
},
|
|
2373
3536
|
".cm-content": {
|
|
2374
3537
|
padding: 0,
|
|
@@ -2376,11 +3539,11 @@ var defaultTheme = {
|
|
|
2376
3539
|
fontSize: "16px"
|
|
2377
3540
|
},
|
|
2378
3541
|
"&light .cm-content": {
|
|
2379
|
-
color: get3(tokens, "extend.
|
|
3542
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2380
3543
|
caretColor: "black"
|
|
2381
3544
|
},
|
|
2382
3545
|
"&dark .cm-content": {
|
|
2383
|
-
color: get3(tokens, "extend.
|
|
3546
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2384
3547
|
caretColor: "white"
|
|
2385
3548
|
},
|
|
2386
3549
|
//
|
|
@@ -2392,8 +3555,11 @@ var defaultTheme = {
|
|
|
2392
3555
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2393
3556
|
borderLeft: "2px solid white"
|
|
2394
3557
|
},
|
|
2395
|
-
".cm-placeholder": {
|
|
2396
|
-
|
|
3558
|
+
"&light .cm-placeholder": {
|
|
3559
|
+
color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
|
|
3560
|
+
},
|
|
3561
|
+
"&dark .cm-placeholder": {
|
|
3562
|
+
color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
|
|
2397
3563
|
},
|
|
2398
3564
|
//
|
|
2399
3565
|
// line
|
|
@@ -2402,7 +3568,7 @@ var defaultTheme = {
|
|
|
2402
3568
|
paddingInline: 0
|
|
2403
3569
|
},
|
|
2404
3570
|
".cm-activeLine": {
|
|
2405
|
-
background: "
|
|
3571
|
+
background: "transparent"
|
|
2406
3572
|
},
|
|
2407
3573
|
//
|
|
2408
3574
|
// Selection
|
|
@@ -2573,23 +3739,28 @@ var codeTheme = {
|
|
|
2573
3739
|
};
|
|
2574
3740
|
|
|
2575
3741
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2576
|
-
var
|
|
3742
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2577
3743
|
var EditorModes = [
|
|
2578
3744
|
"default",
|
|
2579
3745
|
"vim"
|
|
2580
3746
|
];
|
|
2581
3747
|
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2582
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2583
|
-
tabBehavior: "limited"
|
|
2584
|
-
});
|
|
2585
3748
|
const { themeMode } = useThemeContext();
|
|
2586
3749
|
const rootRef = useRef(null);
|
|
2587
|
-
const [view, setView] =
|
|
3750
|
+
const [view, setView] = useState2(null);
|
|
2588
3751
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2589
3752
|
view
|
|
2590
3753
|
]);
|
|
2591
3754
|
useEffect2(() => {
|
|
2592
|
-
if (autoFocus) {
|
|
3755
|
+
if (autoFocus && !view?.hasFocus) {
|
|
3756
|
+
if (view?.state.selection.main?.from === 0) {
|
|
3757
|
+
const { to } = view.state.doc.lineAt(0);
|
|
3758
|
+
view?.dispatch({
|
|
3759
|
+
selection: {
|
|
3760
|
+
anchor: to
|
|
3761
|
+
}
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
2593
3764
|
view?.focus();
|
|
2594
3765
|
}
|
|
2595
3766
|
}, [
|
|
@@ -2605,37 +3776,38 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2605
3776
|
selection,
|
|
2606
3777
|
extensions: [
|
|
2607
3778
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2608
|
-
|
|
3779
|
+
EditorView14.exceptionSink.of((err) => {
|
|
2609
3780
|
log2.catch(err, void 0, {
|
|
2610
|
-
F:
|
|
2611
|
-
L:
|
|
3781
|
+
F: __dxlog_file3,
|
|
3782
|
+
L: 134,
|
|
2612
3783
|
S: void 0,
|
|
2613
3784
|
C: (f, a) => f(...a)
|
|
2614
3785
|
});
|
|
2615
3786
|
}),
|
|
2616
3787
|
// Theme.
|
|
2617
3788
|
// TODO(burdon): Make configurable.
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
3789
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3790
|
+
EditorView14.theme(theme ?? {}),
|
|
3791
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3792
|
+
EditorView14.editorAttributes.of({
|
|
2622
3793
|
class: slots.editor?.className ?? ""
|
|
2623
3794
|
}),
|
|
2624
|
-
|
|
3795
|
+
EditorView14.contentAttributes.of({
|
|
2625
3796
|
class: slots.content?.className ?? ""
|
|
2626
3797
|
}),
|
|
2627
3798
|
// State.
|
|
3799
|
+
EditorView14.editable.of(!readonly),
|
|
2628
3800
|
EditorState2.readOnly.of(!!readonly),
|
|
2629
3801
|
// Storage and replication.
|
|
2630
3802
|
// NOTE: This must come before user extensions.
|
|
2631
3803
|
model.extension,
|
|
2632
|
-
// TODO(burdon): Factor out (
|
|
3804
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2633
3805
|
editorMode === "vim" && vim(),
|
|
2634
3806
|
// Custom.
|
|
2635
3807
|
...extensions
|
|
2636
|
-
].filter(
|
|
3808
|
+
].filter(isNotFalsy3)
|
|
2637
3809
|
});
|
|
2638
|
-
const newView = new
|
|
3810
|
+
const newView = new EditorView14({
|
|
2639
3811
|
state,
|
|
2640
3812
|
parent: rootRef.current,
|
|
2641
3813
|
scrollTo,
|
|
@@ -2670,7 +3842,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2670
3842
|
}
|
|
2671
3843
|
case "Escape": {
|
|
2672
3844
|
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2673
|
-
|
|
3845
|
+
view?.focus();
|
|
2674
3846
|
}
|
|
2675
3847
|
break;
|
|
2676
3848
|
}
|
|
@@ -2683,9 +3855,9 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2683
3855
|
key: model.id,
|
|
2684
3856
|
role: "none",
|
|
2685
3857
|
tabIndex: 0,
|
|
2686
|
-
onKeyUp: handleKeyUp,
|
|
2687
3858
|
...slots.root,
|
|
2688
|
-
...editorMode !==
|
|
3859
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3860
|
+
onKeyUp: handleKeyUp,
|
|
2689
3861
|
ref: rootRef
|
|
2690
3862
|
});
|
|
2691
3863
|
});
|
|
@@ -2696,7 +3868,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2696
3868
|
ref: forwardedRef,
|
|
2697
3869
|
readonly,
|
|
2698
3870
|
extensions: [
|
|
2699
|
-
|
|
3871
|
+
createBasicBundle({
|
|
2700
3872
|
themeMode,
|
|
2701
3873
|
placeholder: placeholder3,
|
|
2702
3874
|
lineWrapping
|
|
@@ -2715,9 +3887,8 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2715
3887
|
ref: forwardedRef,
|
|
2716
3888
|
readonly,
|
|
2717
3889
|
extensions: [
|
|
2718
|
-
|
|
3890
|
+
createMarkdownExtensions({
|
|
2719
3891
|
themeMode,
|
|
2720
|
-
readonly,
|
|
2721
3892
|
placeholder: placeholder3
|
|
2722
3893
|
}),
|
|
2723
3894
|
...extensions
|
|
@@ -2729,11 +3900,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2729
3900
|
});
|
|
2730
3901
|
var defaultSlots = {
|
|
2731
3902
|
root: {
|
|
2732
|
-
|
|
2733
|
-
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
3903
|
+
className: mx3("grow", focusRing)
|
|
2734
3904
|
},
|
|
2735
3905
|
editor: {
|
|
2736
|
-
className: "
|
|
3906
|
+
className: "bs-full"
|
|
2737
3907
|
}
|
|
2738
3908
|
};
|
|
2739
3909
|
var defaultTextSlots = {
|
|
@@ -2743,12 +3913,200 @@ var defaultMarkdownSlots = {
|
|
|
2743
3913
|
...defaultSlots
|
|
2744
3914
|
};
|
|
2745
3915
|
|
|
3916
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
3917
|
+
import { CaretRight, ChatText, Code, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
|
|
3918
|
+
import { createContext } from "@radix-ui/react-context";
|
|
3919
|
+
import React2 from "react";
|
|
3920
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
3921
|
+
import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
|
|
3922
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
3923
|
+
var ToolbarRoot = ({ children, onAction, state }) => {
|
|
3924
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
3925
|
+
onAction,
|
|
3926
|
+
state
|
|
3927
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
3928
|
+
density: "fine"
|
|
3929
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
3930
|
+
role: "toolbar",
|
|
3931
|
+
className: "flex w-full shrink-0 p-1 gap-2 items-center whitespace-nowrap overflow-hidden"
|
|
3932
|
+
}, children)));
|
|
3933
|
+
};
|
|
3934
|
+
var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
|
|
3935
|
+
const { onAction, state } = useToolbarContext("ToolbarButton");
|
|
3936
|
+
const active = getState && state ? getState(state) : false;
|
|
3937
|
+
const disabled = disable && state ? disable(state) : false;
|
|
3938
|
+
const handleClick = (event) => {
|
|
3939
|
+
const action = onClick(state);
|
|
3940
|
+
if (action) {
|
|
3941
|
+
onAction?.(action);
|
|
3942
|
+
event.preventDefault();
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
3946
|
+
variant: "ghost",
|
|
3947
|
+
classNames: mx4("p-2", active && "ring-[1px]"),
|
|
3948
|
+
onMouseDown: handleClick,
|
|
3949
|
+
title,
|
|
3950
|
+
disabled
|
|
3951
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
3952
|
+
className: getSize(5)
|
|
3953
|
+
}));
|
|
3954
|
+
};
|
|
3955
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3956
|
+
className: "grow"
|
|
3957
|
+
});
|
|
3958
|
+
var MarkdownHeading = () => {
|
|
3959
|
+
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
3960
|
+
const blockType = state ? state.blockType : "paragraph";
|
|
3961
|
+
const header = blockType && /heading(\d)/.exec(blockType);
|
|
3962
|
+
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : null;
|
|
3963
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3964
|
+
disabled: value === null,
|
|
3965
|
+
value: value ?? "0",
|
|
3966
|
+
onValueChange: (value2) => onAction?.({
|
|
3967
|
+
type: "heading",
|
|
3968
|
+
data: parseInt(value2)
|
|
3969
|
+
})
|
|
3970
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, null, /* @__PURE__ */ React2.createElement(Paragraph, {
|
|
3971
|
+
className: getSize(5)
|
|
3972
|
+
})), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3973
|
+
value: "0"
|
|
3974
|
+
}, "Paragraph"), [
|
|
3975
|
+
1,
|
|
3976
|
+
2,
|
|
3977
|
+
3,
|
|
3978
|
+
4,
|
|
3979
|
+
5,
|
|
3980
|
+
6
|
|
3981
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3982
|
+
key: level,
|
|
3983
|
+
value: String(level)
|
|
3984
|
+
}, "Heading ", level))))));
|
|
3985
|
+
};
|
|
3986
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3987
|
+
role: "none"
|
|
3988
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3989
|
+
Icon: TextB,
|
|
3990
|
+
title: "String",
|
|
3991
|
+
disable: (s) => s.blockType === "codeblock",
|
|
3992
|
+
getState: (s) => s.strong,
|
|
3993
|
+
onClick: (s) => ({
|
|
3994
|
+
type: "strong",
|
|
3995
|
+
data: s ? !s.strong : null
|
|
3996
|
+
})
|
|
3997
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3998
|
+
Icon: TextItalic,
|
|
3999
|
+
title: "Emphasis",
|
|
4000
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4001
|
+
getState: (s) => s.emphasis,
|
|
4002
|
+
onClick: (s) => ({
|
|
4003
|
+
type: "emphasis",
|
|
4004
|
+
data: s ? !s.emphasis : null
|
|
4005
|
+
})
|
|
4006
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4007
|
+
Icon: TextStrikethrough,
|
|
4008
|
+
title: "Strike-through",
|
|
4009
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4010
|
+
getState: (s) => s.strikethrough,
|
|
4011
|
+
onClick: (s) => ({
|
|
4012
|
+
type: "strikethrough",
|
|
4013
|
+
data: s ? !s.strikethrough : null
|
|
4014
|
+
})
|
|
4015
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4016
|
+
Icon: Code,
|
|
4017
|
+
title: "Inline code",
|
|
4018
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4019
|
+
getState: (s) => s.code,
|
|
4020
|
+
onClick: (s) => ({
|
|
4021
|
+
type: "code",
|
|
4022
|
+
data: s ? !s.code : null
|
|
4023
|
+
})
|
|
4024
|
+
}));
|
|
4025
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4026
|
+
role: "none"
|
|
4027
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4028
|
+
Icon: ListBullets,
|
|
4029
|
+
title: "Bullet list",
|
|
4030
|
+
getState: (s) => s.listStyle === "bullet",
|
|
4031
|
+
onClick: (s) => ({
|
|
4032
|
+
type: "list-bullet",
|
|
4033
|
+
data: s ? s.listStyle !== "bullet" : null
|
|
4034
|
+
})
|
|
4035
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4036
|
+
Icon: ListNumbers,
|
|
4037
|
+
title: "Numbered list",
|
|
4038
|
+
getState: (s) => s.listStyle === "ordered",
|
|
4039
|
+
onClick: (s) => ({
|
|
4040
|
+
type: "list-ordered",
|
|
4041
|
+
data: s ? s.listStyle !== "ordered" : null
|
|
4042
|
+
})
|
|
4043
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4044
|
+
Icon: ListChecks,
|
|
4045
|
+
title: "Task list",
|
|
4046
|
+
getState: (s) => s.listStyle === "task",
|
|
4047
|
+
onClick: (s) => ({
|
|
4048
|
+
type: "list-tasks",
|
|
4049
|
+
data: s ? s.listStyle !== "task" : null
|
|
4050
|
+
})
|
|
4051
|
+
}));
|
|
4052
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4053
|
+
role: "none"
|
|
4054
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4055
|
+
Icon: CaretRight,
|
|
4056
|
+
title: "Block quote",
|
|
4057
|
+
getState: (s) => s.blockquote,
|
|
4058
|
+
onClick: (s) => ({
|
|
4059
|
+
type: "blockquote",
|
|
4060
|
+
data: s ? !s.blockquote : null
|
|
4061
|
+
})
|
|
4062
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4063
|
+
Icon: Code,
|
|
4064
|
+
title: "Code block",
|
|
4065
|
+
getState: (s) => s.blockType === "codeblock",
|
|
4066
|
+
onClick: (s) => ({
|
|
4067
|
+
type: "codeblock",
|
|
4068
|
+
data: s ? s.blockType !== "codeblock" : null
|
|
4069
|
+
})
|
|
4070
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4071
|
+
Icon: Table2,
|
|
4072
|
+
title: "Table",
|
|
4073
|
+
onClick: () => ({
|
|
4074
|
+
type: "table"
|
|
4075
|
+
})
|
|
4076
|
+
}));
|
|
4077
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4078
|
+
role: "none"
|
|
4079
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4080
|
+
Icon: Link,
|
|
4081
|
+
title: "Link",
|
|
4082
|
+
getState: (s) => s.link,
|
|
4083
|
+
onClick: (s) => ({
|
|
4084
|
+
type: "link",
|
|
4085
|
+
data: s ? !s.link : null
|
|
4086
|
+
})
|
|
4087
|
+
}));
|
|
4088
|
+
var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
|
|
4089
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
4090
|
+
Icon: ChatText,
|
|
4091
|
+
title: "Create comment",
|
|
4092
|
+
onClick: () => ({
|
|
4093
|
+
type: "comment"
|
|
4094
|
+
})
|
|
4095
|
+
});
|
|
4096
|
+
var Toolbar = {
|
|
4097
|
+
Root: ToolbarRoot,
|
|
4098
|
+
Button: ToolbarButton,
|
|
4099
|
+
Separator: ToolbarSeparator,
|
|
4100
|
+
Markdown: MarkdownStandard,
|
|
4101
|
+
Extended: MarkdownExtended
|
|
4102
|
+
};
|
|
4103
|
+
|
|
2746
4104
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2747
4105
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2748
4106
|
import { Context as Context2 } from "@dxos/context";
|
|
2749
|
-
import { invariant as
|
|
4107
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2750
4108
|
import { log as log3 } from "@dxos/log";
|
|
2751
|
-
var
|
|
4109
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2752
4110
|
var DEBOUNCE_INTERVAL = 100;
|
|
2753
4111
|
var SpaceAwarenessProvider = class {
|
|
2754
4112
|
constructor(params) {
|
|
@@ -2788,7 +4146,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2788
4146
|
log3.debug("failed to query awareness", {
|
|
2789
4147
|
err
|
|
2790
4148
|
}, {
|
|
2791
|
-
F:
|
|
4149
|
+
F: __dxlog_file4,
|
|
2792
4150
|
L: 89,
|
|
2793
4151
|
S: this,
|
|
2794
4152
|
C: (f, a) => f(...a)
|
|
@@ -2804,8 +4162,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2804
4162
|
return Array.from(this._remoteStates.values());
|
|
2805
4163
|
}
|
|
2806
4164
|
update(position) {
|
|
2807
|
-
|
|
2808
|
-
F:
|
|
4165
|
+
invariant2(this._postTask, void 0, {
|
|
4166
|
+
F: __dxlog_file4,
|
|
2809
4167
|
L: 104,
|
|
2810
4168
|
S: this,
|
|
2811
4169
|
A: [
|
|
@@ -2821,8 +4179,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2821
4179
|
this._postTask.schedule();
|
|
2822
4180
|
}
|
|
2823
4181
|
_handleQueryMessage() {
|
|
2824
|
-
|
|
2825
|
-
F:
|
|
4182
|
+
invariant2(this._postTask, void 0, {
|
|
4183
|
+
F: __dxlog_file4,
|
|
2826
4184
|
L: 115,
|
|
2827
4185
|
S: this,
|
|
2828
4186
|
A: [
|
|
@@ -2833,8 +4191,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2833
4191
|
this._postTask.schedule();
|
|
2834
4192
|
}
|
|
2835
4193
|
_handlePostMessage(message) {
|
|
2836
|
-
|
|
2837
|
-
F:
|
|
4194
|
+
invariant2(message.kind === "post", void 0, {
|
|
4195
|
+
F: __dxlog_file4,
|
|
2838
4196
|
L: 120,
|
|
2839
4197
|
S: this,
|
|
2840
4198
|
A: [
|
|
@@ -2854,10 +4212,58 @@ var modelState = StateField5.define({
|
|
|
2854
4212
|
update: (model) => model
|
|
2855
4213
|
});
|
|
2856
4214
|
|
|
2857
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
4215
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
4216
|
+
var useActionHandler = (view) => {
|
|
4217
|
+
return (action) => {
|
|
4218
|
+
if (!view) {
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
let inlineType, listType;
|
|
4222
|
+
switch (action.type) {
|
|
4223
|
+
case "heading":
|
|
4224
|
+
setHeading(parseInt(action.data))(view);
|
|
4225
|
+
break;
|
|
4226
|
+
case "strong":
|
|
4227
|
+
case "emphasis":
|
|
4228
|
+
case "strikethrough":
|
|
4229
|
+
case "code":
|
|
4230
|
+
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4231
|
+
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
4232
|
+
break;
|
|
4233
|
+
case "list-ordered":
|
|
4234
|
+
case "list-bullet":
|
|
4235
|
+
case "list-tasks":
|
|
4236
|
+
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4237
|
+
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
4238
|
+
break;
|
|
4239
|
+
case "blockquote":
|
|
4240
|
+
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
4241
|
+
break;
|
|
4242
|
+
case "codeblock":
|
|
4243
|
+
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
4244
|
+
break;
|
|
4245
|
+
case "table":
|
|
4246
|
+
insertTable(view);
|
|
4247
|
+
break;
|
|
4248
|
+
case "link":
|
|
4249
|
+
(action.data === false ? removeLink : addLink)(view);
|
|
4250
|
+
break;
|
|
4251
|
+
case "comment":
|
|
4252
|
+
createComment(view);
|
|
4253
|
+
break;
|
|
4254
|
+
}
|
|
4255
|
+
setTimeout(() => {
|
|
4256
|
+
if (!view.hasFocus) {
|
|
4257
|
+
view.focus();
|
|
4258
|
+
}
|
|
4259
|
+
});
|
|
4260
|
+
};
|
|
4261
|
+
};
|
|
4262
|
+
|
|
4263
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
4264
|
+
import { useState as useState3 } from "react";
|
|
4265
|
+
var useEditorView = () => {
|
|
4266
|
+
const [view, setView] = useState3(null);
|
|
2861
4267
|
return [
|
|
2862
4268
|
(ref) => {
|
|
2863
4269
|
setView(ref);
|
|
@@ -2866,29 +4272,144 @@ var useTextEditor = () => {
|
|
|
2866
4272
|
];
|
|
2867
4273
|
};
|
|
2868
4274
|
|
|
4275
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4276
|
+
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4277
|
+
import { EditorView as EditorView15 } from "@codemirror/view";
|
|
4278
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
4279
|
+
import { log as log4 } from "@dxos/log";
|
|
4280
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
4281
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4282
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
4283
|
+
const onUpdate = useRef2();
|
|
4284
|
+
const [view, setView] = useState4();
|
|
4285
|
+
const parentRef = useRef2(null);
|
|
4286
|
+
useEffect3(() => {
|
|
4287
|
+
if (parentRef.current) {
|
|
4288
|
+
const state = EditorState3.create({
|
|
4289
|
+
doc,
|
|
4290
|
+
selection,
|
|
4291
|
+
extensions: [
|
|
4292
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4293
|
+
EditorView15.exceptionSink.of((err) => {
|
|
4294
|
+
log4.catch(err, void 0, {
|
|
4295
|
+
F: __dxlog_file5,
|
|
4296
|
+
L: 57,
|
|
4297
|
+
S: void 0,
|
|
4298
|
+
C: (f, a) => f(...a)
|
|
4299
|
+
});
|
|
4300
|
+
}),
|
|
4301
|
+
extensions,
|
|
4302
|
+
EditorView15.updateListener.of(() => {
|
|
4303
|
+
onUpdate.current?.();
|
|
4304
|
+
})
|
|
4305
|
+
].filter(isNotFalsy4)
|
|
4306
|
+
});
|
|
4307
|
+
const view2 = new EditorView15({
|
|
4308
|
+
parent: parentRef.current,
|
|
4309
|
+
scrollTo,
|
|
4310
|
+
state,
|
|
4311
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4312
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4313
|
+
dispatchTransactions: (trs, view3) => {
|
|
4314
|
+
if (debug) {
|
|
4315
|
+
logChanges(trs);
|
|
4316
|
+
}
|
|
4317
|
+
view3.update(trs);
|
|
4318
|
+
}
|
|
4319
|
+
});
|
|
4320
|
+
setView(view2);
|
|
4321
|
+
}
|
|
4322
|
+
return () => {
|
|
4323
|
+
view?.destroy();
|
|
4324
|
+
};
|
|
4325
|
+
}, [
|
|
4326
|
+
parentRef
|
|
4327
|
+
]);
|
|
4328
|
+
useEffect3(() => {
|
|
4329
|
+
if (view) {
|
|
4330
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
4331
|
+
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
4332
|
+
}
|
|
4333
|
+
if (selection || scrollTo) {
|
|
4334
|
+
onUpdate.current = () => {
|
|
4335
|
+
onUpdate.current = void 0;
|
|
4336
|
+
view.dispatch({
|
|
4337
|
+
selection,
|
|
4338
|
+
effects: scrollTo && [
|
|
4339
|
+
scrollTo
|
|
4340
|
+
],
|
|
4341
|
+
scrollIntoView: !scrollTo
|
|
4342
|
+
});
|
|
4343
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
if (autoFocus) {
|
|
4346
|
+
view.focus();
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
}, [
|
|
4350
|
+
view,
|
|
4351
|
+
autoFocus,
|
|
4352
|
+
selection,
|
|
4353
|
+
scrollTo
|
|
4354
|
+
]);
|
|
4355
|
+
return {
|
|
4356
|
+
parentRef,
|
|
4357
|
+
view
|
|
4358
|
+
};
|
|
4359
|
+
};
|
|
4360
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
4361
|
+
return [
|
|
4362
|
+
//
|
|
4363
|
+
EditorState3.readOnly.of(readonly),
|
|
4364
|
+
EditorView15.editable.of(!readonly)
|
|
4365
|
+
];
|
|
4366
|
+
};
|
|
4367
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
4368
|
+
return [
|
|
4369
|
+
//
|
|
4370
|
+
EditorView15.baseTheme(defaultTheme),
|
|
4371
|
+
theme && EditorView15.theme(theme),
|
|
4372
|
+
EditorView15.darkTheme.of(themeMode === "dark"),
|
|
4373
|
+
EditorView15.editorAttributes.of({
|
|
4374
|
+
class: slots?.editor?.className ?? ""
|
|
4375
|
+
}),
|
|
4376
|
+
EditorView15.contentAttributes.of({
|
|
4377
|
+
class: slots?.content?.className ?? ""
|
|
4378
|
+
})
|
|
4379
|
+
].filter(isNotFalsy4);
|
|
4380
|
+
};
|
|
4381
|
+
|
|
2869
4382
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2870
4383
|
import get4 from "lodash.get";
|
|
2871
|
-
import { useEffect as
|
|
4384
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
2872
4385
|
import { generateName } from "@dxos/display-name";
|
|
2873
4386
|
import { getRawDoc } from "@dxos/echo-schema";
|
|
2874
|
-
import { invariant as
|
|
4387
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2875
4388
|
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2876
|
-
|
|
2877
|
-
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
4389
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2878
4390
|
var useTextModel = (props) => {
|
|
2879
4391
|
const { identity, space, text } = props;
|
|
2880
|
-
const [model, setModel] =
|
|
2881
|
-
|
|
4392
|
+
const [model, setModel] = useState5();
|
|
4393
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2882
4394
|
identity,
|
|
2883
4395
|
space,
|
|
2884
4396
|
text
|
|
2885
4397
|
]);
|
|
2886
4398
|
return model;
|
|
2887
4399
|
};
|
|
4400
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4401
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4402
|
+
return {
|
|
4403
|
+
id,
|
|
4404
|
+
content,
|
|
4405
|
+
setContent,
|
|
4406
|
+
text: () => content
|
|
4407
|
+
};
|
|
4408
|
+
};
|
|
2888
4409
|
var createModel = ({ space, identity, text }) => {
|
|
2889
|
-
|
|
2890
|
-
F:
|
|
2891
|
-
L:
|
|
4410
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
4411
|
+
F: __dxlog_file6,
|
|
4412
|
+
L: 50,
|
|
2892
4413
|
S: void 0,
|
|
2893
4414
|
A: [
|
|
2894
4415
|
"isAutomergeObject(text)",
|
|
@@ -2899,7 +4420,7 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2899
4420
|
const doc = getRawDoc(obj, [
|
|
2900
4421
|
obj.field
|
|
2901
4422
|
]);
|
|
2902
|
-
const
|
|
4423
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2903
4424
|
space,
|
|
2904
4425
|
channel: `automerge.awareness.${obj.id}`,
|
|
2905
4426
|
info: {
|
|
@@ -2909,19 +4430,22 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2909
4430
|
},
|
|
2910
4431
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2911
4432
|
});
|
|
4433
|
+
const extensions = [
|
|
4434
|
+
//
|
|
4435
|
+
modelState.init(() => model),
|
|
4436
|
+
automerge({
|
|
4437
|
+
handle: doc.handle,
|
|
4438
|
+
path: doc.path
|
|
4439
|
+
})
|
|
4440
|
+
];
|
|
4441
|
+
if (awarenessProvider2) {
|
|
4442
|
+
extensions.push(awareness(awarenessProvider2));
|
|
4443
|
+
}
|
|
2912
4444
|
const model = {
|
|
2913
4445
|
id: obj.id,
|
|
2914
4446
|
content: doc,
|
|
2915
4447
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2916
|
-
extension:
|
|
2917
|
-
modelState.init(() => model),
|
|
2918
|
-
automerge3({
|
|
2919
|
-
handle: doc.handle,
|
|
2920
|
-
path: doc.path
|
|
2921
|
-
}),
|
|
2922
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2923
|
-
awareness()
|
|
2924
|
-
].filter(isNotNullOrUndefined),
|
|
4448
|
+
extension: extensions,
|
|
2925
4449
|
peer: identity ? {
|
|
2926
4450
|
id: identity.identityKey.toHex(),
|
|
2927
4451
|
name: identity.profile?.displayName
|
|
@@ -2930,40 +4454,57 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2930
4454
|
return model;
|
|
2931
4455
|
};
|
|
2932
4456
|
export {
|
|
2933
|
-
AwarenessProvider,
|
|
2934
4457
|
BaseTextEditor,
|
|
2935
4458
|
Cursor,
|
|
2936
4459
|
Doc,
|
|
2937
4460
|
EditorModes,
|
|
4461
|
+
Inline,
|
|
4462
|
+
List,
|
|
2938
4463
|
MarkdownEditor,
|
|
2939
4464
|
RemoteSelectionsDecorator,
|
|
2940
4465
|
SpaceAwarenessProvider,
|
|
2941
4466
|
TextEditor,
|
|
2942
4467
|
TextKind,
|
|
4468
|
+
Toolbar,
|
|
2943
4469
|
YText,
|
|
2944
4470
|
YXmlFragment,
|
|
4471
|
+
addBlockquote,
|
|
4472
|
+
addCodeblock,
|
|
4473
|
+
addLink,
|
|
4474
|
+
addList,
|
|
4475
|
+
addStyle,
|
|
2945
4476
|
autocomplete,
|
|
2946
|
-
|
|
4477
|
+
automerge,
|
|
2947
4478
|
awareness,
|
|
2948
|
-
|
|
4479
|
+
awarenessProvider,
|
|
2949
4480
|
blast,
|
|
2950
4481
|
callbackWrapper,
|
|
2951
4482
|
code2 as code,
|
|
2952
4483
|
codeTheme,
|
|
2953
4484
|
comments,
|
|
4485
|
+
compareFormatting,
|
|
4486
|
+
createBasicBundle,
|
|
4487
|
+
createComment,
|
|
4488
|
+
createDataExtensions,
|
|
4489
|
+
createMarkdownExtensions,
|
|
4490
|
+
createThemeExtensions,
|
|
2954
4491
|
defaultMarkdownSlots,
|
|
2955
4492
|
defaultOptions,
|
|
2956
4493
|
defaultSlots,
|
|
2957
4494
|
defaultTextSlots,
|
|
2958
4495
|
defaultTheme,
|
|
4496
|
+
focusComment,
|
|
4497
|
+
formatting,
|
|
4498
|
+
getFormatting,
|
|
2959
4499
|
getToken,
|
|
2960
4500
|
heading2 as heading,
|
|
2961
4501
|
hr,
|
|
2962
4502
|
image,
|
|
4503
|
+
insertTable,
|
|
4504
|
+
keymap7 as keymap,
|
|
2963
4505
|
link,
|
|
2964
4506
|
listener,
|
|
2965
4507
|
logChanges,
|
|
2966
|
-
markdownBundle,
|
|
2967
4508
|
markdownHighlightStyle,
|
|
2968
4509
|
markdownTags,
|
|
2969
4510
|
markdownTagsExtensions,
|
|
@@ -2971,16 +4512,36 @@ export {
|
|
|
2971
4512
|
mention,
|
|
2972
4513
|
modelState,
|
|
2973
4514
|
outliner,
|
|
4515
|
+
removeBlockquote,
|
|
4516
|
+
removeCodeblock,
|
|
4517
|
+
removeLink,
|
|
4518
|
+
removeList,
|
|
4519
|
+
removeStyle,
|
|
4520
|
+
setBlockquote,
|
|
2974
4521
|
setComments,
|
|
2975
|
-
|
|
4522
|
+
setHeading,
|
|
2976
4523
|
setSelection,
|
|
4524
|
+
setStyle,
|
|
2977
4525
|
table,
|
|
2978
4526
|
tags2 as tags,
|
|
2979
4527
|
tasklist,
|
|
2980
4528
|
textTheme,
|
|
4529
|
+
toggleBlockquote,
|
|
4530
|
+
toggleCodeblock,
|
|
4531
|
+
toggleEmphasis,
|
|
4532
|
+
toggleInlineCode,
|
|
4533
|
+
toggleList,
|
|
4534
|
+
toggleStrikethrough,
|
|
4535
|
+
toggleStrong,
|
|
4536
|
+
toggleStyle,
|
|
2981
4537
|
typewriter,
|
|
4538
|
+
useActionHandler,
|
|
2982
4539
|
useComments,
|
|
4540
|
+
useEditorView,
|
|
4541
|
+
useFormattingState,
|
|
4542
|
+
useInMemoryTextModel,
|
|
2983
4543
|
useTextEditor,
|
|
2984
|
-
useTextModel
|
|
4544
|
+
useTextModel,
|
|
4545
|
+
useToolbarContext
|
|
2985
4546
|
};
|
|
2986
4547
|
//# sourceMappingURL=index.mjs.map
|