@dxos/react-ui-editor 0.3.11-main.a757f8c → 0.3.11-main.a8c932f
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 +1915 -326
- 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 +58 -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/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/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/themes/default.d.ts.map +1 -1
- package/package.json +40 -27
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +12 -18
- 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 +264 -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 +10 -5
- package/src/extensions/markdown/code.ts +36 -13
- package/src/extensions/markdown/formatting.test.ts +482 -0
- package/src/extensions/markdown/formatting.ts +1237 -0
- package/src/extensions/markdown/heading.ts +1 -1
- package/src/extensions/markdown/index.ts +1 -0
- package/src/extensions/markdown/link.ts +12 -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/themes/default.ts +11 -6
- 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,
|
|
@@ -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
|
|
@@ -1025,13 +1039,13 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
|
|
|
1025
1039
|
|
|
1026
1040
|
// packages/ui/react-ui-editor/src/util.ts
|
|
1027
1041
|
import { log } from "@dxos/log";
|
|
1028
|
-
var
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1029
1043
|
var callbackWrapper = (fn) => (...args) => {
|
|
1030
1044
|
try {
|
|
1031
1045
|
return fn(...args);
|
|
1032
1046
|
} catch (err) {
|
|
1033
1047
|
log.catch(err, void 0, {
|
|
1034
|
-
F:
|
|
1048
|
+
F: __dxlog_file2,
|
|
1035
1049
|
L: 18,
|
|
1036
1050
|
S: void 0,
|
|
1037
1051
|
C: (f, a) => f(...a)
|
|
@@ -1059,24 +1073,35 @@ var logChanges = (trs) => {
|
|
|
1059
1073
|
};
|
|
1060
1074
|
|
|
1061
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1062
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1063
1076
|
var styles2 = EditorView5.baseTheme({
|
|
1064
|
-
"& .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": {
|
|
1065
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1066
1085
|
},
|
|
1067
|
-
"& .cm-comment-current": {
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1068
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")
|
|
1069
1096
|
}
|
|
1070
1097
|
});
|
|
1071
|
-
var
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
};
|
|
1079
|
-
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) => {
|
|
1080
1105
|
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1081
1106
|
if (!comment?.comment.cursor) {
|
|
1082
1107
|
return;
|
|
@@ -1138,7 +1163,7 @@ var commentsState = StateField2.define({
|
|
|
1138
1163
|
return value;
|
|
1139
1164
|
}
|
|
1140
1165
|
});
|
|
1141
|
-
var
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1142
1167
|
commentsState
|
|
1143
1168
|
], (state) => {
|
|
1144
1169
|
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
@@ -1149,9 +1174,9 @@ var highlightDecorations = EditorView5.decorations.compute([
|
|
|
1149
1174
|
return void 0;
|
|
1150
1175
|
}
|
|
1151
1176
|
if (comment.comment.id === current) {
|
|
1152
|
-
return
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1153
1178
|
} else {
|
|
1154
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1155
1180
|
}
|
|
1156
1181
|
}).filter(nonNullable);
|
|
1157
1182
|
return Decoration2.set(decorations);
|
|
@@ -1180,84 +1205,128 @@ var trackPastedComments = (onUpdate) => {
|
|
|
1180
1205
|
cut: handleTrack,
|
|
1181
1206
|
copy: handleTrack
|
|
1182
1207
|
}),
|
|
1183
|
-
//
|
|
1184
|
-
|
|
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
|
+
}
|
|
1185
1239
|
if (tracked) {
|
|
1186
|
-
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1240
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1187
1241
|
if (paste) {
|
|
1188
1242
|
let found = -1;
|
|
1189
1243
|
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1190
1244
|
if (text.eq(tracked.text)) {
|
|
1191
|
-
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1192
|
-
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);
|
|
1193
1247
|
}
|
|
1194
1248
|
found = fromB;
|
|
1195
1249
|
}
|
|
1196
1250
|
});
|
|
1197
1251
|
if (found > -1) {
|
|
1198
1252
|
for (const moved of tracked.comments) {
|
|
1199
|
-
|
|
1253
|
+
restore.push({
|
|
1254
|
+
id: moved.id,
|
|
1200
1255
|
from: found + moved.from,
|
|
1201
1256
|
to: found + moved.to
|
|
1202
|
-
};
|
|
1203
|
-
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1204
|
-
onUpdate(moved.id, cursor);
|
|
1257
|
+
});
|
|
1205
1258
|
}
|
|
1206
1259
|
}
|
|
1207
1260
|
tracked = null;
|
|
1208
1261
|
}
|
|
1209
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
|
+
}
|
|
1210
1271
|
})
|
|
1211
1272
|
];
|
|
1212
1273
|
};
|
|
1213
|
-
var
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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
|
+
}
|
|
1225
1297
|
});
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
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) {
|
|
1231
1310
|
view.dispatch({
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1235
1316
|
}
|
|
1236
1317
|
});
|
|
1318
|
+
return true;
|
|
1237
1319
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
if (id) {
|
|
1245
|
-
view.dispatch({
|
|
1246
|
-
effects: setSelection.of({
|
|
1247
|
-
current: id
|
|
1248
|
-
}),
|
|
1249
|
-
selection: {
|
|
1250
|
-
anchor: from
|
|
1251
|
-
}
|
|
1252
|
-
});
|
|
1253
|
-
return true;
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
return false;
|
|
1257
|
-
};
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1258
1326
|
return [
|
|
1327
|
+
optionsFacet.of(options),
|
|
1259
1328
|
commentsState,
|
|
1260
|
-
|
|
1329
|
+
commentsDecorations,
|
|
1261
1330
|
styles2,
|
|
1262
1331
|
//
|
|
1263
1332
|
// Keymap.
|
|
@@ -1265,7 +1334,7 @@ var comments = (options = {}) => {
|
|
|
1265
1334
|
options.onCreate ? keymap3.of([
|
|
1266
1335
|
{
|
|
1267
1336
|
key: shortcut,
|
|
1268
|
-
run: callbackWrapper(
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1269
1338
|
}
|
|
1270
1339
|
]) : [],
|
|
1271
1340
|
//
|
|
@@ -1403,6 +1472,7 @@ import { searchKeymap } from "@codemirror/search";
|
|
|
1403
1472
|
import { EditorState } from "@codemirror/state";
|
|
1404
1473
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1405
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";
|
|
1406
1476
|
|
|
1407
1477
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1408
1478
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1593,11 +1663,11 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1593
1663
|
};
|
|
1594
1664
|
|
|
1595
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1596
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1597
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1598
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1599
1670
|
EditorState.tabSize.of(2),
|
|
1600
|
-
EditorView7.lineWrapping,
|
|
1601
1671
|
// https://github.com/codemirror/basic-setup
|
|
1602
1672
|
bracketMatching2(),
|
|
1603
1673
|
closeBrackets2(),
|
|
@@ -1607,7 +1677,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
1607
1677
|
highlightActiveLine2(),
|
|
1608
1678
|
history2(),
|
|
1609
1679
|
indentOnInput(),
|
|
1610
|
-
_placeholder
|
|
1680
|
+
_placeholder && placeholder2(_placeholder),
|
|
1611
1681
|
// Main extension.
|
|
1612
1682
|
// https://github.com/codemirror/lang-markdown
|
|
1613
1683
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1642,7 +1712,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
1642
1712
|
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1643
1713
|
...standardKeymap
|
|
1644
1714
|
])
|
|
1645
|
-
];
|
|
1715
|
+
].filter(isNotFalsy2);
|
|
1646
1716
|
};
|
|
1647
1717
|
|
|
1648
1718
|
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
@@ -1652,26 +1722,43 @@ import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Dec
|
|
|
1652
1722
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1653
1723
|
var styles3 = EditorView8.baseTheme({
|
|
1654
1724
|
"& .cm-code": {
|
|
1655
|
-
paddingInline: "1rem !important",
|
|
1656
1725
|
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1657
1726
|
},
|
|
1658
1727
|
"& .cm-codeblock": {
|
|
1659
|
-
|
|
1660
|
-
|
|
1728
|
+
width: "100%",
|
|
1729
|
+
paddingInline: "1rem !important",
|
|
1730
|
+
position: "relative",
|
|
1731
|
+
"&::after": {
|
|
1732
|
+
content: '""',
|
|
1733
|
+
position: "absolute",
|
|
1734
|
+
inset: 0
|
|
1735
|
+
}
|
|
1661
1736
|
},
|
|
1662
|
-
"&light .cm-codeblock
|
|
1663
|
-
|
|
1737
|
+
"&light .cm-codeblock": {
|
|
1738
|
+
"&::after": {
|
|
1739
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1740
|
+
mixBlendMode: "darken"
|
|
1741
|
+
}
|
|
1664
1742
|
},
|
|
1665
|
-
"&dark .cm-codeblock
|
|
1666
|
-
|
|
1743
|
+
"&dark .cm-codeblock": {
|
|
1744
|
+
"&::after": {
|
|
1745
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1746
|
+
mixBlendMode: "lighten"
|
|
1747
|
+
}
|
|
1667
1748
|
},
|
|
1668
1749
|
"& .cm-codeblock-first": {
|
|
1669
|
-
|
|
1670
|
-
|
|
1750
|
+
display: "inline-block",
|
|
1751
|
+
"&::after": {
|
|
1752
|
+
borderTopLeftRadius: ".5rem",
|
|
1753
|
+
borderTopRightRadius: ".5rem"
|
|
1754
|
+
}
|
|
1671
1755
|
},
|
|
1672
1756
|
"& .cm-codeblock-last": {
|
|
1673
|
-
|
|
1674
|
-
|
|
1757
|
+
display: "inline-block",
|
|
1758
|
+
"&::after": {
|
|
1759
|
+
borderBottomLeftRadius: ".5rem",
|
|
1760
|
+
borderBottomRightRadius: ".5rem"
|
|
1761
|
+
}
|
|
1675
1762
|
}
|
|
1676
1763
|
});
|
|
1677
1764
|
var getLineRange = (lines, from, to) => {
|
|
@@ -1715,7 +1802,7 @@ var buildDecorations = (view) => {
|
|
|
1715
1802
|
}));
|
|
1716
1803
|
} else {
|
|
1717
1804
|
builder.add(block.from, block.from, Decoration3.line({
|
|
1718
|
-
class: mx2("cm-code cm-codeblock")
|
|
1805
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1719
1806
|
}));
|
|
1720
1807
|
}
|
|
1721
1808
|
}
|
|
@@ -1743,98 +1830,1188 @@ var code2 = () => {
|
|
|
1743
1830
|
];
|
|
1744
1831
|
};
|
|
1745
1832
|
|
|
1746
|
-
// 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";
|
|
1747
1835
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1748
|
-
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1749
|
-
import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
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) {
|
|
1755
1858
|
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1756
1861
|
enter: (node) => {
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
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
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
if (!changes.length) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
dispatch(state.update({
|
|
1914
|
+
changes,
|
|
1915
|
+
userEvent: "format.setHeading",
|
|
1916
|
+
scrollIntoView: true
|
|
1917
|
+
}));
|
|
1918
|
+
return true;
|
|
1919
|
+
};
|
|
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;
|
|
1954
|
+
syntaxTree2(state).iterate({
|
|
1955
|
+
from,
|
|
1956
|
+
to,
|
|
1957
|
+
enter: (node) => {
|
|
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
|
+
});
|
|
1768
2015
|
}
|
|
1769
2016
|
}
|
|
1770
2017
|
}
|
|
1771
2018
|
}
|
|
1772
2019
|
},
|
|
1773
|
-
|
|
1774
|
-
|
|
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
|
+
}
|
|
1775
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);
|
|
1776
2091
|
}
|
|
1777
|
-
return
|
|
2092
|
+
return node.from;
|
|
1778
2093
|
};
|
|
1779
|
-
var
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
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;
|
|
2101
|
+
};
|
|
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
|
+
//
|
|
2112
|
+
"```#{}",
|
|
2113
|
+
"#{}",
|
|
2114
|
+
"```"
|
|
2115
|
+
].join("\n")),
|
|
2116
|
+
table: snippet([
|
|
2117
|
+
//
|
|
2118
|
+
"| #{col1} | #{col2} |",
|
|
2119
|
+
"| ---- | ---- |",
|
|
2120
|
+
"| #{val1} | #{val2} |",
|
|
2121
|
+
"| #{val3} | #{val4} |",
|
|
2122
|
+
""
|
|
2123
|
+
].join("\n"))
|
|
2124
|
+
};
|
|
2125
|
+
var insertTable = (view) => {
|
|
2126
|
+
const { selection: { main }, doc } = view.state;
|
|
2127
|
+
const { number } = doc.lineAt(main.anchor);
|
|
2128
|
+
const { from } = doc.line(number);
|
|
2129
|
+
snippets.table(view, null, from, from);
|
|
2130
|
+
};
|
|
2131
|
+
var removeLinkInner = (from, to, changes, state) => {
|
|
2132
|
+
syntaxTree2(state).iterate({
|
|
2133
|
+
from,
|
|
2134
|
+
to,
|
|
2135
|
+
enter: (node) => {
|
|
2136
|
+
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
2137
|
+
node.node.cursor().iterate((node2) => {
|
|
2138
|
+
const { name } = node2;
|
|
2139
|
+
if (name === "LinkMark" || name === "LinkLabel") {
|
|
2140
|
+
changes.push({
|
|
2141
|
+
from: node2.from,
|
|
2142
|
+
to: node2.to
|
|
2143
|
+
});
|
|
2144
|
+
} else if (name === "LinkTitle" || name === "URL") {
|
|
2145
|
+
changes.push({
|
|
2146
|
+
from: skipSpaces(node2.from, state.doc, -1),
|
|
2147
|
+
to: skipSpaces(node2.to, state.doc, 1)
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
});
|
|
2151
|
+
return false;
|
|
1787
2152
|
}
|
|
1788
|
-
}
|
|
1789
|
-
|
|
1790
|
-
})
|
|
1791
|
-
];
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
1792
2155
|
};
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
import { Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1798
|
-
var styles4 = EditorView9.baseTheme({
|
|
1799
|
-
"& .cm-hr": {
|
|
1800
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1801
|
-
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2156
|
+
var removeLink = ({ state, dispatch }) => {
|
|
2157
|
+
const changes = [];
|
|
2158
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2159
|
+
removeLinkInner(from, to, changes, state);
|
|
1802
2160
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
toDOM() {
|
|
1806
|
-
const el = document.createElement("div");
|
|
1807
|
-
el.className = "cm-hr";
|
|
1808
|
-
return el;
|
|
2161
|
+
if (!changes) {
|
|
2162
|
+
return false;
|
|
1809
2163
|
}
|
|
2164
|
+
dispatch(state.update({
|
|
2165
|
+
changes,
|
|
2166
|
+
userEvent: "format.link.remove",
|
|
2167
|
+
scrollIntoView: true
|
|
2168
|
+
}));
|
|
2169
|
+
return true;
|
|
1810
2170
|
};
|
|
1811
|
-
var
|
|
1812
|
-
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
syntaxTree3(state).iterate({
|
|
2171
|
+
var addLink = ({ state, dispatch }) => {
|
|
2172
|
+
const changes = state.changeByRange((range) => {
|
|
2173
|
+
let { from, to } = range;
|
|
2174
|
+
const cutStyles = [];
|
|
2175
|
+
let okay = null;
|
|
2176
|
+
syntaxTree2(state).iterate({
|
|
2177
|
+
from,
|
|
2178
|
+
to,
|
|
1820
2179
|
enter: (node) => {
|
|
1821
|
-
if (node.name
|
|
1822
|
-
|
|
1823
|
-
|
|
2180
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2181
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
|
|
2182
|
+
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
2183
|
+
const sNode = node.node;
|
|
2184
|
+
if (node.from < from && node.to <= to) {
|
|
2185
|
+
if (sNode.firstChild.to === from) {
|
|
2186
|
+
from = node.from;
|
|
2187
|
+
} else {
|
|
2188
|
+
cutStyles.push(sNode);
|
|
2189
|
+
}
|
|
2190
|
+
} else if (node.from >= from && node.to > to) {
|
|
2191
|
+
if (sNode.lastChild.from === to) {
|
|
2192
|
+
to = node.to;
|
|
2193
|
+
} else {
|
|
2194
|
+
cutStyles.push(sNode);
|
|
2195
|
+
}
|
|
1824
2196
|
}
|
|
1825
2197
|
}
|
|
1826
|
-
}
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
if (okay === null) {
|
|
2201
|
+
const line = state.doc.lineAt(from);
|
|
2202
|
+
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
2203
|
+
}
|
|
2204
|
+
if (!okay) {
|
|
2205
|
+
return {
|
|
2206
|
+
range
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
const changes2 = [];
|
|
2210
|
+
const changesAfter = [];
|
|
2211
|
+
removeLinkInner(from, to, changesAfter, state);
|
|
2212
|
+
let cursorOffset = 1;
|
|
2213
|
+
for (const style of cutStyles) {
|
|
2214
|
+
const type = InlineMarker[style.name];
|
|
2215
|
+
const mark2 = inlineMarkerText(type);
|
|
2216
|
+
if (style.from < from) {
|
|
2217
|
+
changes2.push({
|
|
2218
|
+
from: skipSpaces(from, state.doc, -1),
|
|
2219
|
+
insert: mark2
|
|
2220
|
+
});
|
|
2221
|
+
changesAfter.push({
|
|
2222
|
+
from: skipSpaces(from, state.doc, 1, to),
|
|
2223
|
+
insert: mark2
|
|
2224
|
+
});
|
|
2225
|
+
} else {
|
|
2226
|
+
changes2.push({
|
|
2227
|
+
from: skipSpaces(to, state.doc, -1, from),
|
|
2228
|
+
insert: mark2
|
|
2229
|
+
});
|
|
2230
|
+
const after = skipSpaces(to, state.doc, 1);
|
|
2231
|
+
if (after === to) {
|
|
2232
|
+
cursorOffset += mark2.length;
|
|
2233
|
+
}
|
|
2234
|
+
changesAfter.push({
|
|
2235
|
+
from: after,
|
|
2236
|
+
insert: mark2
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
changes2.push({
|
|
1827
2241
|
from,
|
|
1828
|
-
|
|
2242
|
+
insert: "["
|
|
2243
|
+
}, {
|
|
2244
|
+
from: to,
|
|
2245
|
+
insert: "]()"
|
|
1829
2246
|
});
|
|
2247
|
+
const changeSet = state.changes(changes2.concat(changesAfter));
|
|
2248
|
+
return {
|
|
2249
|
+
changes: changeSet,
|
|
2250
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
2251
|
+
};
|
|
2252
|
+
});
|
|
2253
|
+
if (changes.changes.empty) {
|
|
2254
|
+
return false;
|
|
1830
2255
|
}
|
|
1831
|
-
|
|
2256
|
+
dispatch(state.update(changes, {
|
|
2257
|
+
userEvent: "format.link.add",
|
|
2258
|
+
scrollIntoView: true
|
|
2259
|
+
}));
|
|
2260
|
+
return true;
|
|
1832
2261
|
};
|
|
1833
|
-
var
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
2262
|
+
var addList = (type) => ({ state, dispatch }) => {
|
|
2263
|
+
let lastBlock = -1;
|
|
2264
|
+
let counter = 1;
|
|
2265
|
+
let first = true;
|
|
2266
|
+
let parentColumn = null;
|
|
2267
|
+
const blocks = [];
|
|
2268
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2269
|
+
syntaxTree2(state).iterate({
|
|
2270
|
+
from,
|
|
2271
|
+
to,
|
|
2272
|
+
enter: (node) => {
|
|
2273
|
+
if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
|
|
2274
|
+
if (first) {
|
|
2275
|
+
let before = node.node.prevSibling;
|
|
2276
|
+
while (before && /Mark$/.test(before.name)) {
|
|
2277
|
+
before = before.prevSibling;
|
|
2278
|
+
}
|
|
2279
|
+
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
2280
|
+
const item = before.lastChild;
|
|
2281
|
+
const itemLine = state.doc.lineAt(item.from);
|
|
2282
|
+
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
2283
|
+
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
2284
|
+
if (type === 0) {
|
|
2285
|
+
const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
|
|
2286
|
+
if (mark2) {
|
|
2287
|
+
parentColumn += mark2[1].length;
|
|
2288
|
+
counter = +mark2[1] + 1;
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
first = false;
|
|
2293
|
+
}
|
|
2294
|
+
if (node.from === lastBlock) {
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
lastBlock = node.from;
|
|
2298
|
+
blocks.push({
|
|
2299
|
+
node: node.node,
|
|
2300
|
+
counter,
|
|
2301
|
+
parentColumn
|
|
2302
|
+
});
|
|
2303
|
+
counter++;
|
|
2304
|
+
return false;
|
|
2305
|
+
}
|
|
2306
|
+
},
|
|
2307
|
+
leave: (node) => {
|
|
2308
|
+
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
2309
|
+
counter = 1;
|
|
2310
|
+
parentColumn = null;
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
if (!blocks.length) {
|
|
2316
|
+
const { from, to } = state.doc.lineAt(state.selection.main.anchor);
|
|
2317
|
+
if (from === to) {
|
|
2318
|
+
dispatch(state.update({
|
|
2319
|
+
changes: [
|
|
2320
|
+
{
|
|
2321
|
+
from,
|
|
2322
|
+
insert: type === 1 ? "- " : type === 0 ? "1. " : "- [ ] "
|
|
2323
|
+
}
|
|
2324
|
+
],
|
|
2325
|
+
userEvent: "format.list.add",
|
|
2326
|
+
scrollIntoView: true
|
|
2327
|
+
}));
|
|
2328
|
+
return true;
|
|
2329
|
+
}
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
const changes = [];
|
|
2333
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
2334
|
+
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
2335
|
+
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
2336
|
+
let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
2337
|
+
if (type === 0) {
|
|
2338
|
+
padding += String(counter2).length;
|
|
2339
|
+
}
|
|
2340
|
+
let line = state.doc.lineAt(nodeFrom);
|
|
2341
|
+
const column = nodeFrom - line.from;
|
|
2342
|
+
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
2343
|
+
padding = Math.max(padding, parentColumn2 - column);
|
|
2344
|
+
}
|
|
2345
|
+
let mark2;
|
|
2346
|
+
if (type === 0) {
|
|
2347
|
+
let max = counter2;
|
|
2348
|
+
for (let j = i + 1; j < blocks.length; j++) {
|
|
2349
|
+
if (blocks[j].counter !== max + 1) {
|
|
2350
|
+
break;
|
|
2351
|
+
}
|
|
2352
|
+
max++;
|
|
2353
|
+
}
|
|
2354
|
+
const num = String(counter2);
|
|
2355
|
+
padding = Math.max(String(max).length, padding);
|
|
2356
|
+
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
2357
|
+
} else {
|
|
2358
|
+
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
2359
|
+
}
|
|
2360
|
+
changes.push({
|
|
2361
|
+
from: nodeFrom,
|
|
2362
|
+
insert: mark2
|
|
2363
|
+
});
|
|
2364
|
+
while (line.to < node.to) {
|
|
2365
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2366
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2367
|
+
changes.push({
|
|
2368
|
+
from: line.from + Math.min(open, column),
|
|
2369
|
+
insert: " ".repeat(mark2.length)
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
if (type === 0) {
|
|
2374
|
+
const last = blocks[blocks.length - 1];
|
|
2375
|
+
let next = last.node.nextSibling;
|
|
2376
|
+
while (next && /Mark$/.test(next.name)) {
|
|
2377
|
+
next = next.nextSibling;
|
|
2378
|
+
}
|
|
2379
|
+
if (next?.name === "OrderedList") {
|
|
2380
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
dispatch(state.update({
|
|
2384
|
+
changes,
|
|
2385
|
+
userEvent: "format.list.add",
|
|
2386
|
+
scrollIntoView: true
|
|
2387
|
+
}));
|
|
2388
|
+
return true;
|
|
2389
|
+
};
|
|
2390
|
+
var removeList = (type) => ({ state, dispatch }) => {
|
|
2391
|
+
let lastBlock = -1;
|
|
2392
|
+
const changes = [];
|
|
2393
|
+
const stack = [];
|
|
2394
|
+
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
2395
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2396
|
+
syntaxTree2(state).iterate({
|
|
2397
|
+
from,
|
|
2398
|
+
to,
|
|
2399
|
+
enter: (node) => {
|
|
2400
|
+
const { name } = node;
|
|
2401
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2402
|
+
stack.push(name);
|
|
2403
|
+
} else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2404
|
+
stack[stack.length - 1] = "TaskList";
|
|
2405
|
+
}
|
|
2406
|
+
},
|
|
2407
|
+
leave: (node) => {
|
|
2408
|
+
const { name } = node;
|
|
2409
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2410
|
+
stack.pop();
|
|
2411
|
+
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
2412
|
+
lastBlock = node.from;
|
|
2413
|
+
let line = state.doc.lineAt(node.from);
|
|
2414
|
+
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
2415
|
+
if (!mark2) {
|
|
2416
|
+
return false;
|
|
2417
|
+
}
|
|
2418
|
+
const column = node.from - line.from;
|
|
2419
|
+
changes.push({
|
|
2420
|
+
from: node.from,
|
|
2421
|
+
to: node.from + mark2[0].length
|
|
2422
|
+
});
|
|
2423
|
+
while (line.to < node.to) {
|
|
2424
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2425
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2426
|
+
if (open > column) {
|
|
2427
|
+
changes.push({
|
|
2428
|
+
from: line.from + column,
|
|
2429
|
+
to: line.from + Math.min(column + mark2[0].length, open)
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
if (node.to >= to) {
|
|
2434
|
+
renumberListItems(node.node.nextSibling, 1, changes, state.doc);
|
|
2435
|
+
}
|
|
2436
|
+
return false;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
if (!changes.length) {
|
|
2442
|
+
return false;
|
|
2443
|
+
}
|
|
2444
|
+
dispatch(state.update({
|
|
2445
|
+
changes,
|
|
2446
|
+
userEvent: "format.list.remove",
|
|
2447
|
+
scrollIntoView: true
|
|
2448
|
+
}));
|
|
2449
|
+
return true;
|
|
2450
|
+
};
|
|
2451
|
+
var toggleList = (type) => (target) => {
|
|
2452
|
+
const formatting2 = getFormatting(target.state);
|
|
2453
|
+
const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
|
|
2454
|
+
return (active ? removeList(type) : addList(type))(target);
|
|
2455
|
+
};
|
|
2456
|
+
var renumberListItems = (item, counter, changes, doc) => {
|
|
2457
|
+
for (; item; item = item.nextSibling) {
|
|
2458
|
+
if (item.name === "ListItem") {
|
|
2459
|
+
const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
|
|
2460
|
+
if (!number || +number[2] === counter) {
|
|
2461
|
+
break;
|
|
2462
|
+
}
|
|
2463
|
+
const size = number[1].length + number[2].length;
|
|
2464
|
+
const newNum = String(counter);
|
|
2465
|
+
changes.push({
|
|
2466
|
+
from: item.from + Math.max(0, size - newNum.length),
|
|
2467
|
+
to: item.from + size,
|
|
2468
|
+
insert: newNum
|
|
2469
|
+
});
|
|
2470
|
+
counter++;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
};
|
|
2474
|
+
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
2475
|
+
const lines = [];
|
|
2476
|
+
let lastBlock = -1;
|
|
2477
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2478
|
+
syntaxTree2(state).iterate({
|
|
2479
|
+
from,
|
|
2480
|
+
to,
|
|
2481
|
+
enter: (node) => {
|
|
2482
|
+
if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
|
|
2483
|
+
if (node.from === lastBlock) {
|
|
2484
|
+
return false;
|
|
2485
|
+
}
|
|
2486
|
+
lastBlock = node.from;
|
|
2487
|
+
let line = state.doc.lineAt(node.from);
|
|
2488
|
+
if (line.number > 1) {
|
|
2489
|
+
const prevLine = state.doc.line(line.number - 1);
|
|
2490
|
+
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2491
|
+
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2492
|
+
lines.push(prevLine);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
for (; ; ) {
|
|
2497
|
+
lines.push(line);
|
|
2498
|
+
if (line.to >= node.to) {
|
|
2499
|
+
break;
|
|
2500
|
+
}
|
|
2501
|
+
line = state.doc.line(line.number + 1);
|
|
2502
|
+
}
|
|
2503
|
+
if (!enable && line.number < state.doc.lines) {
|
|
2504
|
+
const nextLine = state.doc.line(line.number + 1);
|
|
2505
|
+
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2506
|
+
lines.push(nextLine);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return false;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
const changes = [];
|
|
2515
|
+
for (const line of lines) {
|
|
2516
|
+
if (enable) {
|
|
2517
|
+
changes.push({
|
|
2518
|
+
from: line.from,
|
|
2519
|
+
insert: /\S/.test(line.text) ? "> " : ">"
|
|
2520
|
+
});
|
|
2521
|
+
} else {
|
|
2522
|
+
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
2523
|
+
if (quote) {
|
|
2524
|
+
changes.push({
|
|
2525
|
+
from: line.from + quote[1].length,
|
|
2526
|
+
to: line.from + quote[0].length
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (!changes.length) {
|
|
2532
|
+
return false;
|
|
2533
|
+
}
|
|
2534
|
+
dispatch(state.update({
|
|
2535
|
+
changes,
|
|
2536
|
+
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
2537
|
+
scrollIntoView: true
|
|
2538
|
+
}));
|
|
2539
|
+
return true;
|
|
2540
|
+
};
|
|
2541
|
+
var addBlockquote = setBlockquote(true);
|
|
2542
|
+
var removeBlockquote = setBlockquote(false);
|
|
2543
|
+
var toggleBlockquote = (target) => {
|
|
2544
|
+
return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
|
|
2545
|
+
};
|
|
2546
|
+
var addCodeblock = (target) => {
|
|
2547
|
+
const { state, dispatch } = target;
|
|
2548
|
+
const { selection } = state;
|
|
2549
|
+
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
2550
|
+
const { head } = selection.main;
|
|
2551
|
+
const line = state.doc.lineAt(head);
|
|
2552
|
+
if (!/\S/.test(line.text) && head === line.from) {
|
|
2553
|
+
snippets.codeblock(target, null, line.from, line.to);
|
|
2554
|
+
return true;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
const ranges = [];
|
|
2558
|
+
for (const { from, to } of selection.ranges) {
|
|
2559
|
+
let blockFrom = from;
|
|
2560
|
+
let blockTo = to;
|
|
2561
|
+
syntaxTree2(state).iterate({
|
|
2562
|
+
from,
|
|
2563
|
+
to,
|
|
2564
|
+
enter: (node) => {
|
|
2565
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2566
|
+
if (from >= node.from && to <= node.to) {
|
|
2567
|
+
blockFrom = node.from;
|
|
2568
|
+
blockTo = node.to;
|
|
2569
|
+
} else {
|
|
2570
|
+
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
2571
|
+
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
});
|
|
2576
|
+
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
2577
|
+
ranges[ranges.length - 1].to = blockTo;
|
|
2578
|
+
} else {
|
|
2579
|
+
ranges.push({
|
|
2580
|
+
from: blockFrom,
|
|
2581
|
+
to: blockTo
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
if (!ranges.length) {
|
|
2586
|
+
return false;
|
|
2587
|
+
}
|
|
2588
|
+
const changes = ranges.map(({ from, to }) => {
|
|
2589
|
+
const column = from - state.doc.lineAt(from).from;
|
|
2590
|
+
return [
|
|
2591
|
+
{
|
|
2592
|
+
from,
|
|
2593
|
+
insert: "```\n" + " ".repeat(column)
|
|
2594
|
+
},
|
|
2595
|
+
{
|
|
2596
|
+
from: to,
|
|
2597
|
+
insert: "\n" + " ".repeat(column) + "```"
|
|
2598
|
+
}
|
|
2599
|
+
];
|
|
2600
|
+
});
|
|
2601
|
+
dispatch(state.update({
|
|
2602
|
+
changes,
|
|
2603
|
+
userEvent: "format.codeblock.add",
|
|
2604
|
+
scrollIntoView: true
|
|
2605
|
+
}));
|
|
2606
|
+
return true;
|
|
2607
|
+
};
|
|
2608
|
+
var removeCodeblock = ({ state, dispatch }) => {
|
|
2609
|
+
const changes = [];
|
|
2610
|
+
let lastBlock = -1;
|
|
2611
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2612
|
+
syntaxTree2(state).iterate({
|
|
2613
|
+
from,
|
|
2614
|
+
to,
|
|
2615
|
+
enter: (node) => {
|
|
2616
|
+
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
2617
|
+
lastBlock = node.from;
|
|
2618
|
+
const firstLine = state.doc.lineAt(node.from);
|
|
2619
|
+
if (node.name === "FencedCode") {
|
|
2620
|
+
changes.push({
|
|
2621
|
+
from: node.from,
|
|
2622
|
+
to: firstLine.to + 1 + node.from - firstLine.from
|
|
2623
|
+
});
|
|
2624
|
+
const lastLine = state.doc.lineAt(node.to);
|
|
2625
|
+
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
2626
|
+
changes.push({
|
|
2627
|
+
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
2628
|
+
to: lastLine.to
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
} else {
|
|
2632
|
+
const column = node.from - firstLine.from;
|
|
2633
|
+
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
2634
|
+
changes.push({
|
|
2635
|
+
from: line.from + column - 4,
|
|
2636
|
+
to: line.from + column
|
|
2637
|
+
});
|
|
2638
|
+
if (line.to >= node.to) {
|
|
2639
|
+
break;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
});
|
|
2646
|
+
}
|
|
2647
|
+
if (!changes.length) {
|
|
2648
|
+
return false;
|
|
2649
|
+
}
|
|
2650
|
+
dispatch(state.update({
|
|
2651
|
+
changes,
|
|
2652
|
+
userEvent: "format.codeblock.remove",
|
|
2653
|
+
scrollIntoView: true
|
|
2654
|
+
}));
|
|
2655
|
+
return true;
|
|
2656
|
+
};
|
|
2657
|
+
var toggleCodeblock = (target) => {
|
|
2658
|
+
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
2659
|
+
};
|
|
2660
|
+
var formatting = (options = {}) => {
|
|
2661
|
+
return [
|
|
2662
|
+
keymap5.of([
|
|
2663
|
+
{
|
|
2664
|
+
key: "meta-b",
|
|
2665
|
+
run: toggleStrong
|
|
2666
|
+
}
|
|
2667
|
+
]),
|
|
2668
|
+
styling()
|
|
2669
|
+
];
|
|
2670
|
+
};
|
|
2671
|
+
var styling = () => {
|
|
2672
|
+
const buildDecorations7 = (view) => {
|
|
2673
|
+
const builder = new RangeSetBuilder2();
|
|
2674
|
+
const { state } = view;
|
|
2675
|
+
const cursor = state.selection.main.head;
|
|
2676
|
+
const replace = (node, marks) => {
|
|
2677
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2678
|
+
for (const mark2 of marks) {
|
|
2679
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
};
|
|
2683
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2684
|
+
syntaxTree2(state).iterate({
|
|
2685
|
+
enter: (node) => {
|
|
2686
|
+
switch (node.name) {
|
|
2687
|
+
case "Emphasis":
|
|
2688
|
+
case "StrongEmphasis": {
|
|
2689
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
2690
|
+
replace(node, marks);
|
|
2691
|
+
break;
|
|
2692
|
+
}
|
|
2693
|
+
case "Strikethrough": {
|
|
2694
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
2695
|
+
replace(node, marks);
|
|
2696
|
+
break;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
},
|
|
2700
|
+
from,
|
|
2701
|
+
to
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
return builder.finish();
|
|
2705
|
+
};
|
|
2706
|
+
return [
|
|
2707
|
+
ViewPlugin4.fromClass(class {
|
|
2708
|
+
constructor(view) {
|
|
2709
|
+
this.decorations = buildDecorations7(view);
|
|
2710
|
+
}
|
|
2711
|
+
update(update2) {
|
|
2712
|
+
this.decorations = buildDecorations7(update2.view);
|
|
2713
|
+
}
|
|
2714
|
+
}, {
|
|
2715
|
+
decorations: (value) => value.decorations
|
|
2716
|
+
})
|
|
2717
|
+
];
|
|
2718
|
+
};
|
|
2719
|
+
var InlineMarker = {
|
|
2720
|
+
Emphasis: 1,
|
|
2721
|
+
StrongEmphasis: 0,
|
|
2722
|
+
InlineCode: 3,
|
|
2723
|
+
Strikethrough: 2
|
|
2724
|
+
};
|
|
2725
|
+
var IgnoreInline = /* @__PURE__ */ new Set([
|
|
2726
|
+
"Autolink",
|
|
2727
|
+
"CodeMark",
|
|
2728
|
+
"CodeText",
|
|
2729
|
+
"Comment",
|
|
2730
|
+
"EmphasisMark",
|
|
2731
|
+
"Hardbreak",
|
|
2732
|
+
"HeaderMark",
|
|
2733
|
+
"HTMLTag",
|
|
2734
|
+
"LinkMark",
|
|
2735
|
+
"ListMark",
|
|
2736
|
+
"ProcessingInstruction",
|
|
2737
|
+
"QuoteMark",
|
|
2738
|
+
"StrikethroughMark",
|
|
2739
|
+
"SubscriptMark",
|
|
2740
|
+
"SuperscriptMark",
|
|
2741
|
+
"TaskMarker"
|
|
2742
|
+
]);
|
|
2743
|
+
var Textblocks = {
|
|
2744
|
+
ATXHeading1: "heading1",
|
|
2745
|
+
ATXHeading2: "heading2",
|
|
2746
|
+
ATXHeading3: "heading3",
|
|
2747
|
+
ATXHeading4: "heading4",
|
|
2748
|
+
ATXHeading5: "heading5",
|
|
2749
|
+
ATXHeading6: "heading6",
|
|
2750
|
+
CodeBlock: "codeblock",
|
|
2751
|
+
FencedCode: "codeblock",
|
|
2752
|
+
Paragraph: "paragraph",
|
|
2753
|
+
SetextHeading1: "heading1",
|
|
2754
|
+
SetextHeading2: "heading2",
|
|
2755
|
+
TableCell: "tablecell",
|
|
2756
|
+
Task: "paragraph"
|
|
2757
|
+
};
|
|
2758
|
+
var getFormatting = (state) => {
|
|
2759
|
+
let blockType = null;
|
|
2760
|
+
const inline = [
|
|
2761
|
+
null,
|
|
2762
|
+
null,
|
|
2763
|
+
null,
|
|
2764
|
+
null
|
|
2765
|
+
];
|
|
2766
|
+
let link2 = false;
|
|
2767
|
+
let blockQuote = null;
|
|
2768
|
+
let listStyle = null;
|
|
2769
|
+
const stack = [];
|
|
2770
|
+
let currentBlock = null;
|
|
2771
|
+
const advanceInline = (upto) => {
|
|
2772
|
+
if (!currentBlock) {
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
upto = Math.min(upto, currentBlock.end);
|
|
2776
|
+
if (upto <= currentBlock.pos) {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
2780
|
+
if (inline[i] === false) {
|
|
2781
|
+
continue;
|
|
2782
|
+
} else if (currentBlock.active[i]) {
|
|
2783
|
+
inline[i] = true;
|
|
2784
|
+
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
2785
|
+
inline[i] = false;
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
currentBlock.pos = upto;
|
|
2789
|
+
};
|
|
2790
|
+
const skipInline = (upto) => {
|
|
2791
|
+
if (currentBlock && upto > currentBlock.pos) {
|
|
2792
|
+
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
const { selection } = state;
|
|
2796
|
+
for (const range of selection.ranges) {
|
|
2797
|
+
if (range.empty && inline.some((v) => v === null)) {
|
|
2798
|
+
const contextSize = Math.min(range.head, 6);
|
|
2799
|
+
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
2800
|
+
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
2801
|
+
for (let i = 0; i < contextSize; i++) {
|
|
2802
|
+
const ch = contextAfter[i];
|
|
2803
|
+
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
2804
|
+
contextAfter = contextAfter.slice(0, i);
|
|
2805
|
+
break;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
for (let i = 0; i < inline.length; i++) {
|
|
2809
|
+
const mark2 = inlineMarkerText(i);
|
|
2810
|
+
const found = contextAfter.indexOf(mark2);
|
|
2811
|
+
if (found > -1) {
|
|
2812
|
+
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
2813
|
+
if (inline[i] === null) {
|
|
2814
|
+
inline[i] = true;
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
syntaxTree2(state).iterate({
|
|
2820
|
+
from: range.from,
|
|
2821
|
+
to: range.to,
|
|
2822
|
+
enter: (node) => {
|
|
2823
|
+
advanceInline(node.from);
|
|
2824
|
+
const { name } = node;
|
|
2825
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2826
|
+
stack.push(name);
|
|
2827
|
+
} else if (name === "Link") {
|
|
2828
|
+
link2 = true;
|
|
2829
|
+
} else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
|
|
2830
|
+
if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2831
|
+
stack[stack.length - 1] = "TaskList";
|
|
2832
|
+
}
|
|
2833
|
+
const blockCode = Textblocks[name];
|
|
2834
|
+
if (blockType === null) {
|
|
2835
|
+
blockType = blockCode;
|
|
2836
|
+
} else if (blockType !== blockCode) {
|
|
2837
|
+
blockType = false;
|
|
2838
|
+
}
|
|
2839
|
+
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
2840
|
+
currentBlock = {
|
|
2841
|
+
pos: Math.max(range.from, node.from),
|
|
2842
|
+
end: Math.min(range.to, node.to),
|
|
2843
|
+
active: [
|
|
2844
|
+
false,
|
|
2845
|
+
false,
|
|
2846
|
+
false,
|
|
2847
|
+
false
|
|
2848
|
+
]
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2851
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2852
|
+
const index = InlineMarker[name];
|
|
2853
|
+
if (range.empty && inline[index] === null) {
|
|
2854
|
+
inline[index] = true;
|
|
2855
|
+
}
|
|
2856
|
+
currentBlock.active[index] = true;
|
|
2857
|
+
} else if (IgnoreInline.has(name)) {
|
|
2858
|
+
skipInline(node.to);
|
|
2859
|
+
}
|
|
2860
|
+
},
|
|
2861
|
+
leave: (node) => {
|
|
2862
|
+
advanceInline(node.to);
|
|
2863
|
+
const { name } = node;
|
|
2864
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2865
|
+
stack.pop();
|
|
2866
|
+
} else if (Object.hasOwn(Textblocks, name)) {
|
|
2867
|
+
let hasList = false;
|
|
2868
|
+
let hasQuote = false;
|
|
2869
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2870
|
+
if (stack[i] === "Blockquote") {
|
|
2871
|
+
hasQuote = true;
|
|
2872
|
+
} else if (!hasList) {
|
|
2873
|
+
hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
if (blockQuote === null) {
|
|
2877
|
+
blockQuote = hasQuote;
|
|
2878
|
+
} else if (!hasQuote && blockQuote) {
|
|
2879
|
+
blockQuote = false;
|
|
2880
|
+
}
|
|
2881
|
+
if (listStyle === null) {
|
|
2882
|
+
listStyle = hasList;
|
|
2883
|
+
} else if (listStyle !== hasList) {
|
|
2884
|
+
listStyle = false;
|
|
2885
|
+
}
|
|
2886
|
+
currentBlock = null;
|
|
2887
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2888
|
+
currentBlock.active[InlineMarker[name]] = false;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
const { from, to } = state.doc.lineAt(selection.main.anchor);
|
|
2894
|
+
const blankLine = from === to;
|
|
2895
|
+
return {
|
|
2896
|
+
blankLine,
|
|
2897
|
+
blockType: blockType || null,
|
|
2898
|
+
blockQuote: blockQuote ?? false,
|
|
2899
|
+
code: inline[3] ?? false,
|
|
2900
|
+
emphasis: inline[1] ?? false,
|
|
2901
|
+
strong: inline[0] ?? false,
|
|
2902
|
+
strikethrough: inline[2] ?? false,
|
|
2903
|
+
link: link2,
|
|
2904
|
+
listStyle: listStyle || null
|
|
2905
|
+
};
|
|
2906
|
+
};
|
|
2907
|
+
var useFormattingState = () => {
|
|
2908
|
+
const [state, setState] = useState(null);
|
|
2909
|
+
const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
|
|
2910
|
+
if (update2.docChanged || update2.selectionSet) {
|
|
2911
|
+
const newState = getFormatting(update2.state);
|
|
2912
|
+
if (!state || !compareFormatting(state, newState)) {
|
|
2913
|
+
setState(newState);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}), []);
|
|
2917
|
+
return [
|
|
2918
|
+
state,
|
|
2919
|
+
observer
|
|
2920
|
+
];
|
|
2921
|
+
};
|
|
2922
|
+
|
|
2923
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
2924
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
2925
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
2926
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
2927
|
+
var buildDecorations2 = (view) => {
|
|
2928
|
+
const builder = new RangeSetBuilder3();
|
|
2929
|
+
const { state } = view;
|
|
2930
|
+
const cursor = state.selection.main.head;
|
|
2931
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2932
|
+
syntaxTree3(state).iterate({
|
|
2933
|
+
enter: (node) => {
|
|
2934
|
+
switch (node.name) {
|
|
2935
|
+
case "ATXHeading1":
|
|
2936
|
+
case "ATXHeading2":
|
|
2937
|
+
case "ATXHeading3":
|
|
2938
|
+
case "ATXHeading4":
|
|
2939
|
+
case "ATXHeading5":
|
|
2940
|
+
case "ATXHeading6": {
|
|
2941
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
2942
|
+
if (mark2) {
|
|
2943
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2944
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
},
|
|
2950
|
+
from,
|
|
2951
|
+
to
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
return builder.finish();
|
|
2955
|
+
};
|
|
2956
|
+
var heading2 = () => {
|
|
2957
|
+
return [
|
|
2958
|
+
ViewPlugin5.fromClass(class {
|
|
2959
|
+
constructor(view) {
|
|
2960
|
+
this.decorations = buildDecorations2(view);
|
|
2961
|
+
}
|
|
2962
|
+
update(update2) {
|
|
2963
|
+
this.decorations = buildDecorations2(update2.view);
|
|
2964
|
+
}
|
|
2965
|
+
}, {
|
|
2966
|
+
decorations: (value) => value.decorations
|
|
2967
|
+
})
|
|
2968
|
+
];
|
|
2969
|
+
};
|
|
2970
|
+
|
|
2971
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2972
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2973
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2974
|
+
import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2975
|
+
var styles4 = EditorView10.baseTheme({
|
|
2976
|
+
"& .cm-hr": {
|
|
2977
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2978
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2979
|
+
}
|
|
2980
|
+
});
|
|
2981
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2982
|
+
toDOM() {
|
|
2983
|
+
const el = document.createElement("div");
|
|
2984
|
+
el.className = "cm-hr";
|
|
2985
|
+
return el;
|
|
2986
|
+
}
|
|
2987
|
+
};
|
|
2988
|
+
var decoration = Decoration6.replace({
|
|
2989
|
+
widget: new HorizontalRuleWidget()
|
|
2990
|
+
});
|
|
2991
|
+
var buildDecorations3 = (view) => {
|
|
2992
|
+
const builder = new RangeSetBuilder4();
|
|
2993
|
+
const { state } = view;
|
|
2994
|
+
const cursor = state.selection.main.head;
|
|
2995
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2996
|
+
syntaxTree4(state).iterate({
|
|
2997
|
+
enter: (node) => {
|
|
2998
|
+
if (node.name === "HorizontalRule") {
|
|
2999
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
3000
|
+
builder.add(node.from, node.to, decoration);
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
},
|
|
3004
|
+
from,
|
|
3005
|
+
to
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
return builder.finish();
|
|
3009
|
+
};
|
|
3010
|
+
var hr = () => {
|
|
3011
|
+
return [
|
|
3012
|
+
ViewPlugin6.fromClass(class {
|
|
3013
|
+
constructor(view) {
|
|
3014
|
+
this.decorations = buildDecorations3(view);
|
|
1838
3015
|
}
|
|
1839
3016
|
update(update2) {
|
|
1840
3017
|
this.decorations = buildDecorations3(update2.view);
|
|
@@ -1847,13 +3024,13 @@ var hr = () => {
|
|
|
1847
3024
|
};
|
|
1848
3025
|
|
|
1849
3026
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
1850
|
-
import { syntaxTree as
|
|
3027
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
1851
3028
|
import { StateField as StateField3 } from "@codemirror/state";
|
|
1852
|
-
import { Decoration as
|
|
3029
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1853
3030
|
var image = (options = {}) => {
|
|
1854
3031
|
return StateField3.define({
|
|
1855
3032
|
create: (state) => {
|
|
1856
|
-
return
|
|
3033
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
1857
3034
|
},
|
|
1858
3035
|
update: (value, tr) => {
|
|
1859
3036
|
if (!tr.docChanged && !tr.selection) {
|
|
@@ -1876,20 +3053,20 @@ var image = (options = {}) => {
|
|
|
1876
3053
|
add: buildDecorations4(from, to, tr.state)
|
|
1877
3054
|
});
|
|
1878
3055
|
},
|
|
1879
|
-
provide: (field) =>
|
|
3056
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1880
3057
|
});
|
|
1881
3058
|
};
|
|
1882
3059
|
var buildDecorations4 = (from, to, state) => {
|
|
1883
3060
|
const decorations = [];
|
|
1884
3061
|
const cursor = state.selection.main.head;
|
|
1885
|
-
|
|
3062
|
+
syntaxTree5(state).iterate({
|
|
1886
3063
|
enter: (node) => {
|
|
1887
3064
|
if (node.name === "Image") {
|
|
1888
3065
|
const urlNode = node.node.getChild("URL");
|
|
1889
3066
|
if (urlNode) {
|
|
1890
3067
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1891
3068
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1892
|
-
decorations.push(
|
|
3069
|
+
decorations.push(Decoration7.replace({
|
|
1893
3070
|
block: true,
|
|
1894
3071
|
widget: new ImageWidget(url)
|
|
1895
3072
|
}).range(hide ? node.from : node.to, node.to));
|
|
@@ -1919,13 +3096,13 @@ var ImageWidget = class extends WidgetType4 {
|
|
|
1919
3096
|
};
|
|
1920
3097
|
|
|
1921
3098
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
1922
|
-
import { syntaxTree as
|
|
1923
|
-
import { RangeSetBuilder as
|
|
1924
|
-
import { hoverTooltip as hoverTooltip2, Decoration as
|
|
3099
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
3100
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
3101
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1925
3102
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1926
3103
|
var link = (options = {}) => {
|
|
1927
3104
|
const extensions = [
|
|
1928
|
-
|
|
3105
|
+
ViewPlugin7.fromClass(class {
|
|
1929
3106
|
constructor(view) {
|
|
1930
3107
|
this.decorations = buildDecorations5(view, options);
|
|
1931
3108
|
}
|
|
@@ -1944,7 +3121,7 @@ var link = (options = {}) => {
|
|
|
1944
3121
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1945
3122
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1946
3123
|
hoverTooltip2((view, pos, side) => {
|
|
1947
|
-
const syntax =
|
|
3124
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
1948
3125
|
let link2 = null;
|
|
1949
3126
|
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1950
3127
|
link2 = node.name === "Link" ? node : null;
|
|
@@ -2021,27 +3198,27 @@ var LinkText = class extends WidgetType5 {
|
|
|
2021
3198
|
}
|
|
2022
3199
|
};
|
|
2023
3200
|
var buildDecorations5 = (view, options) => {
|
|
2024
|
-
const builder = new
|
|
3201
|
+
const builder = new RangeSetBuilder5();
|
|
2025
3202
|
const { state } = view;
|
|
2026
3203
|
const cursor = state.selection.main.head;
|
|
2027
3204
|
for (const { from, to } of view.visibleRanges) {
|
|
2028
|
-
|
|
3205
|
+
syntaxTree6(state).iterate({
|
|
2029
3206
|
enter: (node) => {
|
|
2030
3207
|
if (node.name === "Link") {
|
|
2031
|
-
const
|
|
2032
|
-
const text =
|
|
3208
|
+
const marks = node.node.getChildren("LinkMark");
|
|
3209
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2033
3210
|
const urlNode = node.node.getChild("URL");
|
|
2034
3211
|
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2035
3212
|
if (!url) {
|
|
2036
3213
|
return false;
|
|
2037
3214
|
}
|
|
2038
3215
|
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2039
|
-
builder.add(node.from, node.to,
|
|
3216
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2040
3217
|
widget: new LinkText(text, options.link ? url : void 0)
|
|
2041
3218
|
}));
|
|
2042
3219
|
}
|
|
2043
3220
|
if (options.onRender) {
|
|
2044
|
-
builder.add(node.to, node.to,
|
|
3221
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2045
3222
|
widget: new LinkButton(url, options.onRender)
|
|
2046
3223
|
}));
|
|
2047
3224
|
}
|
|
@@ -2056,18 +3233,18 @@ var buildDecorations5 = (view, options) => {
|
|
|
2056
3233
|
};
|
|
2057
3234
|
|
|
2058
3235
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2059
|
-
import { syntaxTree as
|
|
2060
|
-
import { RangeSetBuilder as
|
|
2061
|
-
import { Decoration as
|
|
3236
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
3237
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
3238
|
+
import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
2062
3239
|
var table = (options = {}) => {
|
|
2063
3240
|
return StateField4.define({
|
|
2064
3241
|
create: (state) => update(state, options),
|
|
2065
3242
|
update: (_, tr) => update(tr.state, options),
|
|
2066
|
-
provide: (field) =>
|
|
3243
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
2067
3244
|
});
|
|
2068
3245
|
};
|
|
2069
3246
|
var update = (state, options) => {
|
|
2070
|
-
const builder = new
|
|
3247
|
+
const builder = new RangeSetBuilder6();
|
|
2071
3248
|
const cursor = state.selection.main.head;
|
|
2072
3249
|
const tables = [];
|
|
2073
3250
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2075,7 +3252,7 @@ var update = (state, options) => {
|
|
|
2075
3252
|
const table2 = getTable();
|
|
2076
3253
|
return table2.rows?.[table2.rows.length - 1];
|
|
2077
3254
|
};
|
|
2078
|
-
|
|
3255
|
+
syntaxTree7(state).iterate({
|
|
2079
3256
|
enter: (node) => {
|
|
2080
3257
|
switch (node.name) {
|
|
2081
3258
|
case "Table": {
|
|
@@ -2107,10 +3284,10 @@ var update = (state, options) => {
|
|
|
2107
3284
|
});
|
|
2108
3285
|
tables.forEach((table2) => {
|
|
2109
3286
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2110
|
-
hide && builder.add(table2.from, table2.to,
|
|
3287
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2111
3288
|
widget: new TableWidget(table2)
|
|
2112
3289
|
}));
|
|
2113
|
-
builder.add(table2.from, table2.to,
|
|
3290
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2114
3291
|
class: "cm-table"
|
|
2115
3292
|
}));
|
|
2116
3293
|
});
|
|
@@ -2154,10 +3331,10 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2154
3331
|
};
|
|
2155
3332
|
|
|
2156
3333
|
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2157
|
-
import { syntaxTree as
|
|
2158
|
-
import { RangeSetBuilder as
|
|
2159
|
-
import { EditorView as
|
|
2160
|
-
var styles5 =
|
|
3334
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
3335
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
3336
|
+
import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
3337
|
+
var styles5 = EditorView13.baseTheme({
|
|
2161
3338
|
"& .cm-task": {
|
|
2162
3339
|
color: getToken("extend.colors.blue.500")
|
|
2163
3340
|
},
|
|
@@ -2203,23 +3380,23 @@ var CheckboxWidget = class extends WidgetType7 {
|
|
|
2203
3380
|
return false;
|
|
2204
3381
|
}
|
|
2205
3382
|
};
|
|
2206
|
-
var checkedDecoration =
|
|
3383
|
+
var checkedDecoration = Decoration10.replace({
|
|
2207
3384
|
widget: new CheckboxWidget(true)
|
|
2208
3385
|
});
|
|
2209
|
-
var uncheckedDecoration =
|
|
3386
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2210
3387
|
widget: new CheckboxWidget(false)
|
|
2211
3388
|
});
|
|
2212
3389
|
var buildDecorations6 = (view) => {
|
|
2213
|
-
const builder = new
|
|
3390
|
+
const builder = new RangeSetBuilder7();
|
|
2214
3391
|
const { state } = view;
|
|
2215
3392
|
const cursor = state.selection.main.head;
|
|
2216
3393
|
for (const { from, to } of view.visibleRanges) {
|
|
2217
|
-
|
|
3394
|
+
syntaxTree8(state).iterate({
|
|
2218
3395
|
enter: (node) => {
|
|
2219
3396
|
if (node.name === "TaskMarker") {
|
|
2220
3397
|
if (cursor < node.from || cursor > node.to) {
|
|
2221
3398
|
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2222
|
-
builder.add(node.from - 2, node.from - 1,
|
|
3399
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2223
3400
|
class: "cm-task"
|
|
2224
3401
|
}));
|
|
2225
3402
|
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
@@ -2234,7 +3411,7 @@ var buildDecorations6 = (view) => {
|
|
|
2234
3411
|
};
|
|
2235
3412
|
var tasklist = (options = {}) => {
|
|
2236
3413
|
return [
|
|
2237
|
-
|
|
3414
|
+
ViewPlugin8.fromClass(class {
|
|
2238
3415
|
constructor(view) {
|
|
2239
3416
|
this.decorations = buildDecorations6(view);
|
|
2240
3417
|
}
|
|
@@ -2285,7 +3462,7 @@ var outliner = (options = {}) => {
|
|
|
2285
3462
|
};
|
|
2286
3463
|
|
|
2287
3464
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2288
|
-
import { keymap as
|
|
3465
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2289
3466
|
var defaultItems = [
|
|
2290
3467
|
"hello world!",
|
|
2291
3468
|
"this is a test.",
|
|
@@ -2295,7 +3472,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2295
3472
|
let t;
|
|
2296
3473
|
let idx = 0;
|
|
2297
3474
|
return [
|
|
2298
|
-
|
|
3475
|
+
keymap6.of([
|
|
2299
3476
|
{
|
|
2300
3477
|
// Reset.
|
|
2301
3478
|
key: "alt-meta-'",
|
|
@@ -2372,8 +3549,9 @@ var defaultTheme = {
|
|
|
2372
3549
|
outline: "none"
|
|
2373
3550
|
},
|
|
2374
3551
|
".cm-scroller": {
|
|
2375
|
-
overflow:
|
|
2376
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3552
|
+
// overflow: 'visible',
|
|
3553
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3554
|
+
lineHeight: 1.4
|
|
2377
3555
|
},
|
|
2378
3556
|
".cm-content": {
|
|
2379
3557
|
padding: 0,
|
|
@@ -2381,11 +3559,11 @@ var defaultTheme = {
|
|
|
2381
3559
|
fontSize: "16px"
|
|
2382
3560
|
},
|
|
2383
3561
|
"&light .cm-content": {
|
|
2384
|
-
color: get3(tokens, "extend.
|
|
3562
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2385
3563
|
caretColor: "black"
|
|
2386
3564
|
},
|
|
2387
3565
|
"&dark .cm-content": {
|
|
2388
|
-
color: get3(tokens, "extend.
|
|
3566
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2389
3567
|
caretColor: "white"
|
|
2390
3568
|
},
|
|
2391
3569
|
//
|
|
@@ -2397,8 +3575,11 @@ var defaultTheme = {
|
|
|
2397
3575
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2398
3576
|
borderLeft: "2px solid white"
|
|
2399
3577
|
},
|
|
2400
|
-
".cm-placeholder": {
|
|
2401
|
-
|
|
3578
|
+
"&light .cm-placeholder": {
|
|
3579
|
+
color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
|
|
3580
|
+
},
|
|
3581
|
+
"&dark .cm-placeholder": {
|
|
3582
|
+
color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
|
|
2402
3583
|
},
|
|
2403
3584
|
//
|
|
2404
3585
|
// line
|
|
@@ -2407,7 +3588,7 @@ var defaultTheme = {
|
|
|
2407
3588
|
paddingInline: 0
|
|
2408
3589
|
},
|
|
2409
3590
|
".cm-activeLine": {
|
|
2410
|
-
background: "
|
|
3591
|
+
background: "transparent"
|
|
2411
3592
|
},
|
|
2412
3593
|
//
|
|
2413
3594
|
// Selection
|
|
@@ -2578,23 +3759,28 @@ var codeTheme = {
|
|
|
2578
3759
|
};
|
|
2579
3760
|
|
|
2580
3761
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2581
|
-
var
|
|
3762
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2582
3763
|
var EditorModes = [
|
|
2583
3764
|
"default",
|
|
2584
3765
|
"vim"
|
|
2585
3766
|
];
|
|
2586
3767
|
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2587
|
-
const tabsterDOMAttribute = useFocusableGroup({
|
|
2588
|
-
tabBehavior: "limited"
|
|
2589
|
-
});
|
|
2590
3768
|
const { themeMode } = useThemeContext();
|
|
2591
3769
|
const rootRef = useRef(null);
|
|
2592
|
-
const [view, setView] =
|
|
3770
|
+
const [view, setView] = useState2(null);
|
|
2593
3771
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2594
3772
|
view
|
|
2595
3773
|
]);
|
|
2596
3774
|
useEffect2(() => {
|
|
2597
|
-
if (autoFocus) {
|
|
3775
|
+
if (autoFocus && !view?.hasFocus) {
|
|
3776
|
+
if (view?.state.selection.main?.from === 0) {
|
|
3777
|
+
const { to } = view.state.doc.lineAt(0);
|
|
3778
|
+
view?.dispatch({
|
|
3779
|
+
selection: {
|
|
3780
|
+
anchor: to
|
|
3781
|
+
}
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
2598
3784
|
view?.focus();
|
|
2599
3785
|
}
|
|
2600
3786
|
}, [
|
|
@@ -2610,37 +3796,38 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2610
3796
|
selection,
|
|
2611
3797
|
extensions: [
|
|
2612
3798
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2613
|
-
|
|
3799
|
+
EditorView14.exceptionSink.of((err) => {
|
|
2614
3800
|
log2.catch(err, void 0, {
|
|
2615
|
-
F:
|
|
2616
|
-
L:
|
|
3801
|
+
F: __dxlog_file3,
|
|
3802
|
+
L: 134,
|
|
2617
3803
|
S: void 0,
|
|
2618
3804
|
C: (f, a) => f(...a)
|
|
2619
3805
|
});
|
|
2620
3806
|
}),
|
|
2621
3807
|
// Theme.
|
|
2622
3808
|
// TODO(burdon): Make configurable.
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
3809
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3810
|
+
EditorView14.theme(theme ?? {}),
|
|
3811
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3812
|
+
EditorView14.editorAttributes.of({
|
|
2627
3813
|
class: slots.editor?.className ?? ""
|
|
2628
3814
|
}),
|
|
2629
|
-
|
|
3815
|
+
EditorView14.contentAttributes.of({
|
|
2630
3816
|
class: slots.content?.className ?? ""
|
|
2631
3817
|
}),
|
|
2632
3818
|
// State.
|
|
3819
|
+
EditorView14.editable.of(!readonly),
|
|
2633
3820
|
EditorState2.readOnly.of(!!readonly),
|
|
2634
3821
|
// Storage and replication.
|
|
2635
3822
|
// NOTE: This must come before user extensions.
|
|
2636
3823
|
model.extension,
|
|
2637
|
-
// TODO(burdon): Factor out (
|
|
3824
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2638
3825
|
editorMode === "vim" && vim(),
|
|
2639
3826
|
// Custom.
|
|
2640
3827
|
...extensions
|
|
2641
|
-
].filter(
|
|
3828
|
+
].filter(isNotFalsy3)
|
|
2642
3829
|
});
|
|
2643
|
-
const newView = new
|
|
3830
|
+
const newView = new EditorView14({
|
|
2644
3831
|
state,
|
|
2645
3832
|
parent: rootRef.current,
|
|
2646
3833
|
scrollTo,
|
|
@@ -2675,7 +3862,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2675
3862
|
}
|
|
2676
3863
|
case "Escape": {
|
|
2677
3864
|
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2678
|
-
|
|
3865
|
+
view?.focus();
|
|
2679
3866
|
}
|
|
2680
3867
|
break;
|
|
2681
3868
|
}
|
|
@@ -2688,9 +3875,9 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2688
3875
|
key: model.id,
|
|
2689
3876
|
role: "none",
|
|
2690
3877
|
tabIndex: 0,
|
|
2691
|
-
onKeyUp: handleKeyUp,
|
|
2692
3878
|
...slots.root,
|
|
2693
|
-
...editorMode !==
|
|
3879
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3880
|
+
onKeyUp: handleKeyUp,
|
|
2694
3881
|
ref: rootRef
|
|
2695
3882
|
});
|
|
2696
3883
|
});
|
|
@@ -2701,7 +3888,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
|
|
|
2701
3888
|
ref: forwardedRef,
|
|
2702
3889
|
readonly,
|
|
2703
3890
|
extensions: [
|
|
2704
|
-
|
|
3891
|
+
createBasicBundle({
|
|
2705
3892
|
themeMode,
|
|
2706
3893
|
placeholder: placeholder3,
|
|
2707
3894
|
lineWrapping
|
|
@@ -2720,7 +3907,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2720
3907
|
ref: forwardedRef,
|
|
2721
3908
|
readonly,
|
|
2722
3909
|
extensions: [
|
|
2723
|
-
|
|
3910
|
+
createMarkdownExtensions({
|
|
2724
3911
|
themeMode,
|
|
2725
3912
|
placeholder: placeholder3
|
|
2726
3913
|
}),
|
|
@@ -2733,11 +3920,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
|
|
|
2733
3920
|
});
|
|
2734
3921
|
var defaultSlots = {
|
|
2735
3922
|
root: {
|
|
2736
|
-
|
|
2737
|
-
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
3923
|
+
className: mx3("grow", focusRing)
|
|
2738
3924
|
},
|
|
2739
3925
|
editor: {
|
|
2740
|
-
className: "
|
|
3926
|
+
className: "bs-full"
|
|
2741
3927
|
}
|
|
2742
3928
|
};
|
|
2743
3929
|
var defaultTextSlots = {
|
|
@@ -2747,12 +3933,212 @@ var defaultMarkdownSlots = {
|
|
|
2747
3933
|
...defaultSlots
|
|
2748
3934
|
};
|
|
2749
3935
|
|
|
3936
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
3937
|
+
import { CaretRight, ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic } from "@phosphor-icons/react";
|
|
3938
|
+
import { createContext } from "@radix-ui/react-context";
|
|
3939
|
+
import React2 from "react";
|
|
3940
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
3941
|
+
import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
|
|
3942
|
+
var HeadingIcons = {
|
|
3943
|
+
"0": Paragraph,
|
|
3944
|
+
"1": TextHOne,
|
|
3945
|
+
"2": TextHTwo,
|
|
3946
|
+
"3": TextHThree,
|
|
3947
|
+
"4": TextHFour,
|
|
3948
|
+
"5": TextHFive,
|
|
3949
|
+
"6": TextHSix
|
|
3950
|
+
};
|
|
3951
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
3952
|
+
var ToolbarRoot = ({ children, onAction, state }) => {
|
|
3953
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
3954
|
+
onAction,
|
|
3955
|
+
state
|
|
3956
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
3957
|
+
density: "fine"
|
|
3958
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
3959
|
+
role: "toolbar",
|
|
3960
|
+
className: "flex w-full shrink-0 p-1 gap-4 items-center whitespace-nowrap overflow-hidden"
|
|
3961
|
+
}, children)));
|
|
3962
|
+
};
|
|
3963
|
+
var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
|
|
3964
|
+
const { onAction, state } = useToolbarContext("ToolbarButton");
|
|
3965
|
+
const active = getState && state ? getState(state) : false;
|
|
3966
|
+
const disabled = disable && state ? disable(state) : false;
|
|
3967
|
+
const handleClick = (event) => {
|
|
3968
|
+
const action = onClick(state);
|
|
3969
|
+
if (action) {
|
|
3970
|
+
onAction?.(action);
|
|
3971
|
+
event.preventDefault();
|
|
3972
|
+
}
|
|
3973
|
+
};
|
|
3974
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
3975
|
+
variant: "ghost",
|
|
3976
|
+
classNames: mx4("p-2", active && "ring-[1px]"),
|
|
3977
|
+
onMouseDown: handleClick,
|
|
3978
|
+
title,
|
|
3979
|
+
disabled
|
|
3980
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
3981
|
+
className: getSize(5)
|
|
3982
|
+
}));
|
|
3983
|
+
};
|
|
3984
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3985
|
+
className: "grow"
|
|
3986
|
+
});
|
|
3987
|
+
var MarkdownHeading = () => {
|
|
3988
|
+
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
3989
|
+
const blockType = state ? state.blockType : "paragraph";
|
|
3990
|
+
const header = blockType && /heading(\d)/.exec(blockType);
|
|
3991
|
+
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
|
|
3992
|
+
const HeadingIcon = HeadingIcons[value ?? "0"];
|
|
3993
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3994
|
+
disabled: value === null,
|
|
3995
|
+
value: value ?? "0",
|
|
3996
|
+
onValueChange: (value2) => onAction?.({
|
|
3997
|
+
type: "heading",
|
|
3998
|
+
data: parseInt(value2)
|
|
3999
|
+
})
|
|
4000
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, null, /* @__PURE__ */ React2.createElement(HeadingIcon, {
|
|
4001
|
+
className: getSize(5)
|
|
4002
|
+
})), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
4003
|
+
value: "0"
|
|
4004
|
+
}, "Paragraph"), [
|
|
4005
|
+
1,
|
|
4006
|
+
2,
|
|
4007
|
+
3,
|
|
4008
|
+
4,
|
|
4009
|
+
5,
|
|
4010
|
+
6
|
|
4011
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
4012
|
+
key: level,
|
|
4013
|
+
value: String(level)
|
|
4014
|
+
}, "Heading ", level))))));
|
|
4015
|
+
};
|
|
4016
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4017
|
+
role: "none"
|
|
4018
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4019
|
+
Icon: TextB,
|
|
4020
|
+
title: "String",
|
|
4021
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4022
|
+
getState: (s) => s.strong,
|
|
4023
|
+
onClick: (s) => ({
|
|
4024
|
+
type: "strong",
|
|
4025
|
+
data: s ? !s.strong : null
|
|
4026
|
+
})
|
|
4027
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4028
|
+
Icon: TextItalic,
|
|
4029
|
+
title: "Emphasis",
|
|
4030
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4031
|
+
getState: (s) => s.emphasis,
|
|
4032
|
+
onClick: (s) => ({
|
|
4033
|
+
type: "emphasis",
|
|
4034
|
+
data: s ? !s.emphasis : null
|
|
4035
|
+
})
|
|
4036
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4037
|
+
Icon: TextStrikethrough,
|
|
4038
|
+
title: "Strike-through",
|
|
4039
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4040
|
+
getState: (s) => s.strikethrough,
|
|
4041
|
+
onClick: (s) => ({
|
|
4042
|
+
type: "strikethrough",
|
|
4043
|
+
data: s ? !s.strikethrough : null
|
|
4044
|
+
})
|
|
4045
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4046
|
+
Icon: Code,
|
|
4047
|
+
title: "Inline code",
|
|
4048
|
+
disable: (s) => s.blockType === "codeblock",
|
|
4049
|
+
getState: (s) => s.code,
|
|
4050
|
+
onClick: (s) => ({
|
|
4051
|
+
type: "code",
|
|
4052
|
+
data: s ? !s.code : null
|
|
4053
|
+
})
|
|
4054
|
+
}));
|
|
4055
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4056
|
+
role: "none"
|
|
4057
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4058
|
+
Icon: ListBullets,
|
|
4059
|
+
title: "Bullet list",
|
|
4060
|
+
getState: (s) => s.listStyle === "bullet",
|
|
4061
|
+
onClick: (s) => ({
|
|
4062
|
+
type: "list-bullet",
|
|
4063
|
+
data: s ? s.listStyle !== "bullet" : null
|
|
4064
|
+
})
|
|
4065
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4066
|
+
Icon: ListNumbers,
|
|
4067
|
+
title: "Numbered list",
|
|
4068
|
+
getState: (s) => s.listStyle === "ordered",
|
|
4069
|
+
onClick: (s) => ({
|
|
4070
|
+
type: "list-ordered",
|
|
4071
|
+
data: s ? s.listStyle !== "ordered" : null
|
|
4072
|
+
})
|
|
4073
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4074
|
+
Icon: ListChecks,
|
|
4075
|
+
title: "Task list",
|
|
4076
|
+
getState: (s) => s.listStyle === "task",
|
|
4077
|
+
onClick: (s) => ({
|
|
4078
|
+
type: "list-tasks",
|
|
4079
|
+
data: s ? s.listStyle !== "task" : null
|
|
4080
|
+
})
|
|
4081
|
+
}));
|
|
4082
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4083
|
+
role: "none"
|
|
4084
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4085
|
+
Icon: CaretRight,
|
|
4086
|
+
title: "Block quote",
|
|
4087
|
+
getState: (s) => s.blockQuote,
|
|
4088
|
+
onClick: (s) => ({
|
|
4089
|
+
type: "blockquote",
|
|
4090
|
+
data: s ? !s.blockQuote : null
|
|
4091
|
+
})
|
|
4092
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4093
|
+
Icon: CodeBlock,
|
|
4094
|
+
title: "Code block",
|
|
4095
|
+
disable: (s) => !s.blankLine,
|
|
4096
|
+
getState: (s) => s.blockType === "codeblock",
|
|
4097
|
+
onClick: (s) => ({
|
|
4098
|
+
type: "codeblock",
|
|
4099
|
+
data: s ? s.blockType !== "codeblock" : null
|
|
4100
|
+
})
|
|
4101
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4102
|
+
Icon: Table2,
|
|
4103
|
+
title: "Table",
|
|
4104
|
+
disable: (s) => !s.blankLine,
|
|
4105
|
+
onClick: () => ({
|
|
4106
|
+
type: "table"
|
|
4107
|
+
})
|
|
4108
|
+
}));
|
|
4109
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
4110
|
+
role: "none"
|
|
4111
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4112
|
+
Icon: Link,
|
|
4113
|
+
title: "Link",
|
|
4114
|
+
getState: (s) => s.link,
|
|
4115
|
+
onClick: (s) => ({
|
|
4116
|
+
type: "link",
|
|
4117
|
+
data: s ? !s.link : null
|
|
4118
|
+
})
|
|
4119
|
+
}));
|
|
4120
|
+
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));
|
|
4121
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
4122
|
+
Icon: ChatText,
|
|
4123
|
+
title: "Create comment",
|
|
4124
|
+
onClick: () => ({
|
|
4125
|
+
type: "comment"
|
|
4126
|
+
})
|
|
4127
|
+
});
|
|
4128
|
+
var Toolbar = {
|
|
4129
|
+
Root: ToolbarRoot,
|
|
4130
|
+
Button: ToolbarButton,
|
|
4131
|
+
Separator: ToolbarSeparator,
|
|
4132
|
+
Markdown: MarkdownStandard,
|
|
4133
|
+
Extended: MarkdownExtended
|
|
4134
|
+
};
|
|
4135
|
+
|
|
2750
4136
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2751
4137
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2752
4138
|
import { Context as Context2 } from "@dxos/context";
|
|
2753
|
-
import { invariant as
|
|
4139
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2754
4140
|
import { log as log3 } from "@dxos/log";
|
|
2755
|
-
var
|
|
4141
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2756
4142
|
var DEBOUNCE_INTERVAL = 100;
|
|
2757
4143
|
var SpaceAwarenessProvider = class {
|
|
2758
4144
|
constructor(params) {
|
|
@@ -2792,7 +4178,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2792
4178
|
log3.debug("failed to query awareness", {
|
|
2793
4179
|
err
|
|
2794
4180
|
}, {
|
|
2795
|
-
F:
|
|
4181
|
+
F: __dxlog_file4,
|
|
2796
4182
|
L: 89,
|
|
2797
4183
|
S: this,
|
|
2798
4184
|
C: (f, a) => f(...a)
|
|
@@ -2808,8 +4194,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2808
4194
|
return Array.from(this._remoteStates.values());
|
|
2809
4195
|
}
|
|
2810
4196
|
update(position) {
|
|
2811
|
-
|
|
2812
|
-
F:
|
|
4197
|
+
invariant2(this._postTask, void 0, {
|
|
4198
|
+
F: __dxlog_file4,
|
|
2813
4199
|
L: 104,
|
|
2814
4200
|
S: this,
|
|
2815
4201
|
A: [
|
|
@@ -2825,8 +4211,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2825
4211
|
this._postTask.schedule();
|
|
2826
4212
|
}
|
|
2827
4213
|
_handleQueryMessage() {
|
|
2828
|
-
|
|
2829
|
-
F:
|
|
4214
|
+
invariant2(this._postTask, void 0, {
|
|
4215
|
+
F: __dxlog_file4,
|
|
2830
4216
|
L: 115,
|
|
2831
4217
|
S: this,
|
|
2832
4218
|
A: [
|
|
@@ -2837,8 +4223,8 @@ var SpaceAwarenessProvider = class {
|
|
|
2837
4223
|
this._postTask.schedule();
|
|
2838
4224
|
}
|
|
2839
4225
|
_handlePostMessage(message) {
|
|
2840
|
-
|
|
2841
|
-
F:
|
|
4226
|
+
invariant2(message.kind === "post", void 0, {
|
|
4227
|
+
F: __dxlog_file4,
|
|
2842
4228
|
L: 120,
|
|
2843
4229
|
S: this,
|
|
2844
4230
|
A: [
|
|
@@ -2858,10 +4244,58 @@ var modelState = StateField5.define({
|
|
|
2858
4244
|
update: (model) => model
|
|
2859
4245
|
});
|
|
2860
4246
|
|
|
2861
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
4247
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
4248
|
+
var useActionHandler = (view) => {
|
|
4249
|
+
return (action) => {
|
|
4250
|
+
if (!view) {
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
let inlineType, listType;
|
|
4254
|
+
switch (action.type) {
|
|
4255
|
+
case "heading":
|
|
4256
|
+
setHeading(parseInt(action.data))(view);
|
|
4257
|
+
break;
|
|
4258
|
+
case "strong":
|
|
4259
|
+
case "emphasis":
|
|
4260
|
+
case "strikethrough":
|
|
4261
|
+
case "code":
|
|
4262
|
+
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4263
|
+
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
4264
|
+
break;
|
|
4265
|
+
case "list-ordered":
|
|
4266
|
+
case "list-bullet":
|
|
4267
|
+
case "list-tasks":
|
|
4268
|
+
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4269
|
+
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
4270
|
+
break;
|
|
4271
|
+
case "blockquote":
|
|
4272
|
+
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
4273
|
+
break;
|
|
4274
|
+
case "codeblock":
|
|
4275
|
+
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
4276
|
+
break;
|
|
4277
|
+
case "table":
|
|
4278
|
+
insertTable(view);
|
|
4279
|
+
break;
|
|
4280
|
+
case "link":
|
|
4281
|
+
(action.data === false ? removeLink : addLink)(view);
|
|
4282
|
+
break;
|
|
4283
|
+
case "comment":
|
|
4284
|
+
createComment(view);
|
|
4285
|
+
break;
|
|
4286
|
+
}
|
|
4287
|
+
setTimeout(() => {
|
|
4288
|
+
if (!view.hasFocus) {
|
|
4289
|
+
view.focus();
|
|
4290
|
+
}
|
|
4291
|
+
});
|
|
4292
|
+
};
|
|
4293
|
+
};
|
|
4294
|
+
|
|
4295
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
4296
|
+
import { useState as useState3 } from "react";
|
|
4297
|
+
var useEditorView = () => {
|
|
4298
|
+
const [view, setView] = useState3(null);
|
|
2865
4299
|
return [
|
|
2866
4300
|
(ref) => {
|
|
2867
4301
|
setView(ref);
|
|
@@ -2870,29 +4304,144 @@ var useTextEditor = () => {
|
|
|
2870
4304
|
];
|
|
2871
4305
|
};
|
|
2872
4306
|
|
|
4307
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4308
|
+
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4309
|
+
import { EditorView as EditorView15 } from "@codemirror/view";
|
|
4310
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
4311
|
+
import { log as log4 } from "@dxos/log";
|
|
4312
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
4313
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
4314
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
4315
|
+
const onUpdate = useRef2();
|
|
4316
|
+
const [view, setView] = useState4();
|
|
4317
|
+
const parentRef = useRef2(null);
|
|
4318
|
+
useEffect3(() => {
|
|
4319
|
+
if (parentRef.current) {
|
|
4320
|
+
const state = EditorState3.create({
|
|
4321
|
+
doc,
|
|
4322
|
+
selection,
|
|
4323
|
+
extensions: [
|
|
4324
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4325
|
+
EditorView15.exceptionSink.of((err) => {
|
|
4326
|
+
log4.catch(err, void 0, {
|
|
4327
|
+
F: __dxlog_file5,
|
|
4328
|
+
L: 57,
|
|
4329
|
+
S: void 0,
|
|
4330
|
+
C: (f, a) => f(...a)
|
|
4331
|
+
});
|
|
4332
|
+
}),
|
|
4333
|
+
extensions,
|
|
4334
|
+
EditorView15.updateListener.of(() => {
|
|
4335
|
+
onUpdate.current?.();
|
|
4336
|
+
})
|
|
4337
|
+
].filter(isNotFalsy4)
|
|
4338
|
+
});
|
|
4339
|
+
const view2 = new EditorView15({
|
|
4340
|
+
parent: parentRef.current,
|
|
4341
|
+
scrollTo,
|
|
4342
|
+
state,
|
|
4343
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
4344
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
4345
|
+
dispatchTransactions: (trs, view3) => {
|
|
4346
|
+
if (debug) {
|
|
4347
|
+
logChanges(trs);
|
|
4348
|
+
}
|
|
4349
|
+
view3.update(trs);
|
|
4350
|
+
}
|
|
4351
|
+
});
|
|
4352
|
+
setView(view2);
|
|
4353
|
+
}
|
|
4354
|
+
return () => {
|
|
4355
|
+
view?.destroy();
|
|
4356
|
+
};
|
|
4357
|
+
}, [
|
|
4358
|
+
parentRef
|
|
4359
|
+
]);
|
|
4360
|
+
useEffect3(() => {
|
|
4361
|
+
if (view) {
|
|
4362
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
4363
|
+
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
4364
|
+
}
|
|
4365
|
+
if (selection || scrollTo) {
|
|
4366
|
+
onUpdate.current = () => {
|
|
4367
|
+
onUpdate.current = void 0;
|
|
4368
|
+
view.dispatch({
|
|
4369
|
+
selection,
|
|
4370
|
+
effects: scrollTo && [
|
|
4371
|
+
scrollTo
|
|
4372
|
+
],
|
|
4373
|
+
scrollIntoView: !scrollTo
|
|
4374
|
+
});
|
|
4375
|
+
};
|
|
4376
|
+
}
|
|
4377
|
+
if (autoFocus) {
|
|
4378
|
+
view.focus();
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
}, [
|
|
4382
|
+
view,
|
|
4383
|
+
autoFocus,
|
|
4384
|
+
selection,
|
|
4385
|
+
scrollTo
|
|
4386
|
+
]);
|
|
4387
|
+
return {
|
|
4388
|
+
parentRef,
|
|
4389
|
+
view
|
|
4390
|
+
};
|
|
4391
|
+
};
|
|
4392
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
4393
|
+
return [
|
|
4394
|
+
//
|
|
4395
|
+
EditorState3.readOnly.of(readonly),
|
|
4396
|
+
EditorView15.editable.of(!readonly)
|
|
4397
|
+
];
|
|
4398
|
+
};
|
|
4399
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
4400
|
+
return [
|
|
4401
|
+
//
|
|
4402
|
+
EditorView15.baseTheme(defaultTheme),
|
|
4403
|
+
theme && EditorView15.theme(theme),
|
|
4404
|
+
EditorView15.darkTheme.of(themeMode === "dark"),
|
|
4405
|
+
EditorView15.editorAttributes.of({
|
|
4406
|
+
class: slots?.editor?.className ?? ""
|
|
4407
|
+
}),
|
|
4408
|
+
EditorView15.contentAttributes.of({
|
|
4409
|
+
class: slots?.content?.className ?? ""
|
|
4410
|
+
})
|
|
4411
|
+
].filter(isNotFalsy4);
|
|
4412
|
+
};
|
|
4413
|
+
|
|
2873
4414
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2874
4415
|
import get4 from "lodash.get";
|
|
2875
|
-
import { useEffect as
|
|
4416
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
2876
4417
|
import { generateName } from "@dxos/display-name";
|
|
2877
4418
|
import { getRawDoc } from "@dxos/echo-schema";
|
|
2878
|
-
import { invariant as
|
|
4419
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2879
4420
|
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2880
|
-
|
|
2881
|
-
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
4421
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2882
4422
|
var useTextModel = (props) => {
|
|
2883
4423
|
const { identity, space, text } = props;
|
|
2884
|
-
const [model, setModel] =
|
|
2885
|
-
|
|
4424
|
+
const [model, setModel] = useState5();
|
|
4425
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2886
4426
|
identity,
|
|
2887
4427
|
space,
|
|
2888
4428
|
text
|
|
2889
4429
|
]);
|
|
2890
4430
|
return model;
|
|
2891
4431
|
};
|
|
4432
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4433
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4434
|
+
return {
|
|
4435
|
+
id,
|
|
4436
|
+
content,
|
|
4437
|
+
setContent,
|
|
4438
|
+
text: () => content
|
|
4439
|
+
};
|
|
4440
|
+
};
|
|
2892
4441
|
var createModel = ({ space, identity, text }) => {
|
|
2893
|
-
|
|
2894
|
-
F:
|
|
2895
|
-
L:
|
|
4442
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
4443
|
+
F: __dxlog_file6,
|
|
4444
|
+
L: 50,
|
|
2896
4445
|
S: void 0,
|
|
2897
4446
|
A: [
|
|
2898
4447
|
"isAutomergeObject(text)",
|
|
@@ -2903,7 +4452,7 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2903
4452
|
const doc = getRawDoc(obj, [
|
|
2904
4453
|
obj.field
|
|
2905
4454
|
]);
|
|
2906
|
-
const
|
|
4455
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2907
4456
|
space,
|
|
2908
4457
|
channel: `automerge.awareness.${obj.id}`,
|
|
2909
4458
|
info: {
|
|
@@ -2913,19 +4462,22 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2913
4462
|
},
|
|
2914
4463
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2915
4464
|
});
|
|
4465
|
+
const extensions = [
|
|
4466
|
+
//
|
|
4467
|
+
modelState.init(() => model),
|
|
4468
|
+
automerge({
|
|
4469
|
+
handle: doc.handle,
|
|
4470
|
+
path: doc.path
|
|
4471
|
+
})
|
|
4472
|
+
];
|
|
4473
|
+
if (awarenessProvider2) {
|
|
4474
|
+
extensions.push(awareness(awarenessProvider2));
|
|
4475
|
+
}
|
|
2916
4476
|
const model = {
|
|
2917
4477
|
id: obj.id,
|
|
2918
4478
|
content: doc,
|
|
2919
4479
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2920
|
-
extension:
|
|
2921
|
-
modelState.init(() => model),
|
|
2922
|
-
automerge3({
|
|
2923
|
-
handle: doc.handle,
|
|
2924
|
-
path: doc.path
|
|
2925
|
-
}),
|
|
2926
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2927
|
-
awareness()
|
|
2928
|
-
].filter(isNotNullOrUndefined),
|
|
4480
|
+
extension: extensions,
|
|
2929
4481
|
peer: identity ? {
|
|
2930
4482
|
id: identity.identityKey.toHex(),
|
|
2931
4483
|
name: identity.profile?.displayName
|
|
@@ -2934,40 +4486,57 @@ var createModel = ({ space, identity, text }) => {
|
|
|
2934
4486
|
return model;
|
|
2935
4487
|
};
|
|
2936
4488
|
export {
|
|
2937
|
-
AwarenessProvider,
|
|
2938
4489
|
BaseTextEditor,
|
|
2939
4490
|
Cursor,
|
|
2940
4491
|
Doc,
|
|
2941
4492
|
EditorModes,
|
|
4493
|
+
Inline,
|
|
4494
|
+
List,
|
|
2942
4495
|
MarkdownEditor,
|
|
2943
4496
|
RemoteSelectionsDecorator,
|
|
2944
4497
|
SpaceAwarenessProvider,
|
|
2945
4498
|
TextEditor,
|
|
2946
4499
|
TextKind,
|
|
4500
|
+
Toolbar,
|
|
2947
4501
|
YText,
|
|
2948
4502
|
YXmlFragment,
|
|
4503
|
+
addBlockquote,
|
|
4504
|
+
addCodeblock,
|
|
4505
|
+
addLink,
|
|
4506
|
+
addList,
|
|
4507
|
+
addStyle,
|
|
2949
4508
|
autocomplete,
|
|
2950
|
-
|
|
4509
|
+
automerge,
|
|
2951
4510
|
awareness,
|
|
2952
|
-
|
|
4511
|
+
awarenessProvider,
|
|
2953
4512
|
blast,
|
|
2954
4513
|
callbackWrapper,
|
|
2955
4514
|
code2 as code,
|
|
2956
4515
|
codeTheme,
|
|
2957
4516
|
comments,
|
|
4517
|
+
compareFormatting,
|
|
4518
|
+
createBasicBundle,
|
|
4519
|
+
createComment,
|
|
4520
|
+
createDataExtensions,
|
|
4521
|
+
createMarkdownExtensions,
|
|
4522
|
+
createThemeExtensions,
|
|
2958
4523
|
defaultMarkdownSlots,
|
|
2959
4524
|
defaultOptions,
|
|
2960
4525
|
defaultSlots,
|
|
2961
4526
|
defaultTextSlots,
|
|
2962
4527
|
defaultTheme,
|
|
4528
|
+
focusComment,
|
|
4529
|
+
formatting,
|
|
4530
|
+
getFormatting,
|
|
2963
4531
|
getToken,
|
|
2964
4532
|
heading2 as heading,
|
|
2965
4533
|
hr,
|
|
2966
4534
|
image,
|
|
4535
|
+
insertTable,
|
|
4536
|
+
keymap7 as keymap,
|
|
2967
4537
|
link,
|
|
2968
4538
|
listener,
|
|
2969
4539
|
logChanges,
|
|
2970
|
-
markdownBundle,
|
|
2971
4540
|
markdownHighlightStyle,
|
|
2972
4541
|
markdownTags,
|
|
2973
4542
|
markdownTagsExtensions,
|
|
@@ -2975,16 +4544,36 @@ export {
|
|
|
2975
4544
|
mention,
|
|
2976
4545
|
modelState,
|
|
2977
4546
|
outliner,
|
|
4547
|
+
removeBlockquote,
|
|
4548
|
+
removeCodeblock,
|
|
4549
|
+
removeLink,
|
|
4550
|
+
removeList,
|
|
4551
|
+
removeStyle,
|
|
4552
|
+
setBlockquote,
|
|
2978
4553
|
setComments,
|
|
2979
|
-
|
|
4554
|
+
setHeading,
|
|
2980
4555
|
setSelection,
|
|
4556
|
+
setStyle,
|
|
2981
4557
|
table,
|
|
2982
4558
|
tags2 as tags,
|
|
2983
4559
|
tasklist,
|
|
2984
4560
|
textTheme,
|
|
4561
|
+
toggleBlockquote,
|
|
4562
|
+
toggleCodeblock,
|
|
4563
|
+
toggleEmphasis,
|
|
4564
|
+
toggleInlineCode,
|
|
4565
|
+
toggleList,
|
|
4566
|
+
toggleStrikethrough,
|
|
4567
|
+
toggleStrong,
|
|
4568
|
+
toggleStyle,
|
|
2985
4569
|
typewriter,
|
|
4570
|
+
useActionHandler,
|
|
2986
4571
|
useComments,
|
|
4572
|
+
useEditorView,
|
|
4573
|
+
useFormattingState,
|
|
4574
|
+
useInMemoryTextModel,
|
|
2987
4575
|
useTextEditor,
|
|
2988
|
-
useTextModel
|
|
4576
|
+
useTextModel,
|
|
4577
|
+
useToolbarContext
|
|
2989
4578
|
};
|
|
2990
4579
|
//# sourceMappingURL=index.mjs.map
|