@dxos/react-ui-editor 0.3.11-main.f89c150 → 0.3.11-main.fc97a54
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 +2787 -1305
- 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 +16 -14
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts +23 -0
- 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/autocomplete.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/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/index.d.ts +0 -1
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/semaphore.d.ts +8 -12
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness.d.ts +2 -2
- package/dist/types/src/extensions/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +41 -20
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/{util → extensions}/cursor.d.ts +10 -2
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +2 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- 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/heading.d.ts +6 -0
- package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +8 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -2
- 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 +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +14 -32
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +48 -37
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +85 -91
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +135 -95
- 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/autocomplete.ts +6 -3
- package/src/extensions/automerge/automerge.spec.tsx +76 -0
- package/src/extensions/automerge/automerge.test.ts +13 -0
- package/src/extensions/automerge/automerge.ts +55 -46
- package/src/extensions/automerge/cursor.ts +5 -4
- package/src/extensions/automerge/defs.ts +13 -34
- package/src/extensions/automerge/index.ts +0 -1
- package/src/extensions/automerge/semaphore.ts +33 -32
- package/src/extensions/automerge/update-automerge.ts +14 -8
- package/src/extensions/automerge/update-codemirror.ts +5 -5
- package/src/extensions/awareness.ts +46 -49
- package/src/extensions/basic.ts +17 -10
- package/src/extensions/blast.ts +4 -1
- package/src/extensions/comments.ts +331 -265
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -7
- package/src/extensions/markdown/bundle.ts +23 -28
- package/src/extensions/markdown/code.ts +150 -0
- package/src/extensions/markdown/formatting.test.ts +482 -0
- package/src/extensions/markdown/formatting.ts +1237 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -23
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/{image.ts → markdown/image.ts} +2 -2
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +20 -11
- package/src/extensions/{table.ts → markdown/table.ts} +2 -2
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +93 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +67 -60
- package/src/index.ts +1 -0
- package/src/styles/markdown.ts +9 -12
- package/src/themes/default.ts +26 -56
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/dist/types/src/util/cursor.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -3
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/util.d.ts +0 -5
- package/dist/types/src/util/util.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -98
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/tasklist.ts +0 -119
- package/src/extensions/yjs/cursor.ts +0 -21
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -178
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- package/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
|
@@ -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, useImperativeHandle, useState } from "react";
|
|
15
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
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";
|
|
@@ -29,9 +30,11 @@ var autocomplete = ({ onSearch }) => {
|
|
|
29
30
|
// https://codemirror.net/examples/autocompletion
|
|
30
31
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
31
32
|
autocompletion({
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
33
|
+
activateOnTyping: true,
|
|
34
|
+
// closeOnBlur: false,
|
|
35
|
+
// defaultKeymap: false,
|
|
36
|
+
// TODO(burdon): Styles/fragments.
|
|
37
|
+
tooltipClass: () => "shadow rounded"
|
|
35
38
|
}),
|
|
36
39
|
// TODO(burdon): Option to create new page?
|
|
37
40
|
// TODO(burdon): Optional decoration via addToOptions
|
|
@@ -51,13 +54,14 @@ var autocomplete = ({ onSearch }) => {
|
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
59
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
60
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
57
61
|
|
|
58
62
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
59
63
|
import get from "lodash.get";
|
|
60
|
-
import { next as
|
|
64
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
61
65
|
var cursorConverter = (handle, path) => ({
|
|
62
66
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
63
67
|
toCursor: (pos) => {
|
|
@@ -69,7 +73,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
69
73
|
if (typeof value === "string" && value.length <= pos) {
|
|
70
74
|
return "end";
|
|
71
75
|
}
|
|
72
|
-
return
|
|
76
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
73
77
|
},
|
|
74
78
|
fromCursor: (cursor) => {
|
|
75
79
|
if (cursor === "") {
|
|
@@ -87,26 +91,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
87
91
|
return 0;
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
95
99
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
96
|
-
var
|
|
97
|
-
var
|
|
100
|
+
var getPath = (state, field) => state.field(field).path;
|
|
101
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
102
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
103
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
98
104
|
newHeads
|
|
99
105
|
});
|
|
100
|
-
var
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
var reconcileAnnotation = Annotation.define();
|
|
107
|
+
var isReconcile = (tr) => {
|
|
108
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
109
|
+
};
|
|
104
110
|
|
|
105
111
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
106
|
-
import { next as
|
|
112
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
107
113
|
|
|
108
114
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
109
|
-
import { next as
|
|
115
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
110
116
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
111
117
|
const { lastHeads, path } = state.field(field);
|
|
112
118
|
let hasChanges = false;
|
|
@@ -119,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
119
125
|
return void 0;
|
|
120
126
|
}
|
|
121
127
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
128
|
+
const invertedTransactions = [];
|
|
122
129
|
for (const tr of transactions) {
|
|
123
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
124
|
-
|
|
130
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
131
|
+
invertedTransactions.push({
|
|
132
|
+
from: fromA,
|
|
133
|
+
del: toA - fromA,
|
|
134
|
+
insert
|
|
135
|
+
});
|
|
125
136
|
});
|
|
126
137
|
}
|
|
138
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
139
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
140
|
+
});
|
|
127
141
|
});
|
|
128
142
|
return newHeads ?? void 0;
|
|
129
143
|
};
|
|
@@ -138,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
138
152
|
selection = selection.map(changeSet, 1);
|
|
139
153
|
view.dispatch({
|
|
140
154
|
changes: changeSet,
|
|
141
|
-
annotations:
|
|
155
|
+
annotations: reconcileAnnotation.of(false)
|
|
142
156
|
});
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
view.dispatch({
|
|
146
160
|
selection,
|
|
147
|
-
annotations:
|
|
161
|
+
annotations: reconcileAnnotation.of(false)
|
|
148
162
|
});
|
|
149
163
|
};
|
|
150
164
|
var handlePatch = (patch, target, state) => {
|
|
@@ -165,7 +179,7 @@ var handleInsert = (target, patch) => {
|
|
|
165
179
|
if (index == null) {
|
|
166
180
|
return [];
|
|
167
181
|
}
|
|
168
|
-
const text = patch.values.map((
|
|
182
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
169
183
|
return [
|
|
170
184
|
{
|
|
171
185
|
from: index,
|
|
@@ -237,89 +251,100 @@ var charPath = (textPath, candidatePath) => {
|
|
|
237
251
|
|
|
238
252
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
239
253
|
var PatchSemaphore = class {
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
// prettier-ignore
|
|
255
|
+
constructor(_handle, _state) {
|
|
256
|
+
this._handle = _handle;
|
|
257
|
+
this._state = _state;
|
|
242
258
|
this._inReconcile = false;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
259
|
+
}
|
|
260
|
+
reconcile(view) {
|
|
261
|
+
if (!this._inReconcile) {
|
|
248
262
|
this._inReconcile = true;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
263
|
-
if (newHeads === null || newHeads === void 0) {
|
|
264
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
265
|
-
}
|
|
266
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
267
|
-
updateCodeMirror(view, selection, path, diff);
|
|
263
|
+
this.doReconcile(view);
|
|
264
|
+
this._inReconcile = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
doReconcile(view) {
|
|
268
|
+
const path = getPath(view.state, this._state);
|
|
269
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
270
|
+
let selection = view.state.selection;
|
|
271
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
272
|
+
const toInvert = transactions.slice().reverse();
|
|
273
|
+
for (const tr of toInvert) {
|
|
274
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
275
|
+
selection = selection.map(inverted);
|
|
268
276
|
view.dispatch({
|
|
269
|
-
|
|
270
|
-
annotations:
|
|
277
|
+
changes: inverted,
|
|
278
|
+
annotations: reconcileAnnotation.of(true)
|
|
271
279
|
});
|
|
272
|
-
|
|
273
|
-
|
|
280
|
+
}
|
|
281
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
282
|
+
if (newHeads === null || newHeads === void 0) {
|
|
283
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
284
|
+
}
|
|
285
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
286
|
+
updateCodeMirror(view, selection, path, diff);
|
|
287
|
+
view.dispatch({
|
|
288
|
+
effects: updateHeads(newHeads),
|
|
289
|
+
annotations: reconcileAnnotation.of(false)
|
|
290
|
+
});
|
|
274
291
|
}
|
|
275
292
|
};
|
|
276
293
|
|
|
277
|
-
// packages/ui/react-ui-editor/src/
|
|
294
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
278
295
|
import { Facet } from "@codemirror/state";
|
|
279
|
-
var
|
|
296
|
+
var defaultCursorConverter = {
|
|
280
297
|
toCursor: (position) => position.toString(),
|
|
281
298
|
fromCursor: (cursor) => parseInt(cursor)
|
|
282
299
|
};
|
|
283
|
-
var
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// packages/ui/react-ui-editor/src/util/util.ts
|
|
288
|
-
import { log } from "@dxos/log";
|
|
289
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
290
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
291
|
-
try {
|
|
292
|
-
return fn(...args);
|
|
293
|
-
} catch (error) {
|
|
294
|
-
log.catch(error, void 0, {
|
|
295
|
-
F: __dxlog_file,
|
|
296
|
-
L: 16,
|
|
297
|
-
S: void 0,
|
|
298
|
-
C: (f, a) => f(...a)
|
|
300
|
+
var Cursor = class _Cursor {
|
|
301
|
+
static {
|
|
302
|
+
this.converter = Facet.define({
|
|
303
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
299
304
|
});
|
|
300
305
|
}
|
|
306
|
+
static {
|
|
307
|
+
this.getCursorFromRange = (state, range) => {
|
|
308
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
309
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
310
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
311
|
+
return [
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
].join(":");
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
static {
|
|
318
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
319
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
320
|
+
const parts = cursor.split(":");
|
|
321
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
322
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
323
|
+
return from !== void 0 && to !== void 0 ? {
|
|
324
|
+
from,
|
|
325
|
+
to
|
|
326
|
+
} : void 0;
|
|
327
|
+
};
|
|
328
|
+
}
|
|
301
329
|
};
|
|
302
330
|
|
|
303
331
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
304
|
-
var
|
|
305
|
-
|
|
306
|
-
});
|
|
307
|
-
var automerge3 = ({ handle, path }) => {
|
|
308
|
-
const stateField = StateField.define({
|
|
332
|
+
var automerge = ({ handle, path }) => {
|
|
333
|
+
const syncState = StateField.define({
|
|
309
334
|
create: () => ({
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
335
|
+
path: path.slice(),
|
|
336
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
337
|
+
unreconciledTransactions: []
|
|
313
338
|
}),
|
|
314
339
|
update: (value, tr) => {
|
|
315
340
|
const result = {
|
|
341
|
+
path: path.slice(),
|
|
316
342
|
lastHeads: value.lastHeads,
|
|
317
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
318
|
-
path: path.slice()
|
|
343
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
319
344
|
};
|
|
320
345
|
let clearUnreconciled = false;
|
|
321
346
|
for (const effect of tr.effects) {
|
|
322
|
-
if (effect.is(
|
|
347
|
+
if (effect.is(updateHeadsEffect)) {
|
|
323
348
|
result.lastHeads = effect.value.newHeads;
|
|
324
349
|
clearUnreconciled = true;
|
|
325
350
|
}
|
|
@@ -327,46 +352,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
327
352
|
if (clearUnreconciled) {
|
|
328
353
|
result.unreconciledTransactions = [];
|
|
329
354
|
} else {
|
|
330
|
-
if (!
|
|
355
|
+
if (!isReconcile(tr)) {
|
|
331
356
|
result.unreconciledTransactions.push(tr);
|
|
332
357
|
}
|
|
333
358
|
}
|
|
334
359
|
return result;
|
|
335
360
|
}
|
|
336
361
|
});
|
|
337
|
-
const semaphore = new PatchSemaphore(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
362
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
363
|
+
return [
|
|
364
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
365
|
+
syncState,
|
|
366
|
+
// Reconcile external updates.
|
|
367
|
+
ViewPlugin.fromClass(class {
|
|
368
|
+
constructor(_view) {
|
|
369
|
+
this._view = _view;
|
|
370
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
destroy() {
|
|
373
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
374
|
+
}
|
|
375
|
+
_handleChange() {
|
|
376
|
+
semaphore.reconcile(this._view);
|
|
377
|
+
}
|
|
378
|
+
}),
|
|
379
|
+
// Reconcile local updates.
|
|
380
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
381
|
+
if (!changes.empty) {
|
|
382
|
+
semaphore.reconcile(view);
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
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) => {
|
|
350
392
|
});
|
|
351
393
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
return {
|
|
358
|
-
extension: [
|
|
359
|
-
CursorConverter.of(cursorConverter(handle, path)),
|
|
360
|
-
semaphoreFacet.of(semaphore),
|
|
361
|
-
stateField,
|
|
362
|
-
viewPlugin
|
|
363
|
-
]
|
|
364
|
-
};
|
|
394
|
+
return effects;
|
|
395
|
+
})
|
|
396
|
+
];
|
|
365
397
|
};
|
|
366
398
|
|
|
367
399
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
368
|
-
import { Annotation as Annotation2, Facet as
|
|
369
|
-
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
400
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
401
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
370
402
|
import { Event } from "@dxos/async";
|
|
371
403
|
import { Context } from "@dxos/context";
|
|
372
404
|
var dummyProvider = {
|
|
@@ -375,17 +407,17 @@ var dummyProvider = {
|
|
|
375
407
|
},
|
|
376
408
|
close: () => {
|
|
377
409
|
},
|
|
410
|
+
getRemoteStates: () => [],
|
|
378
411
|
update: () => {
|
|
379
|
-
}
|
|
380
|
-
getRemoteStates: () => []
|
|
412
|
+
}
|
|
381
413
|
};
|
|
382
|
-
var
|
|
414
|
+
var awarenessProvider = Facet2.define({
|
|
383
415
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
384
416
|
});
|
|
385
417
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
386
418
|
var awareness = (provider = dummyProvider) => {
|
|
387
419
|
return [
|
|
388
|
-
|
|
420
|
+
awarenessProvider.of(provider),
|
|
389
421
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
390
422
|
decorations: (value) => value.decorations
|
|
391
423
|
}),
|
|
@@ -398,8 +430,8 @@ var RemoteSelectionsDecorator = class {
|
|
|
398
430
|
this._ctx = new Context();
|
|
399
431
|
this._lastAnchor = void 0;
|
|
400
432
|
this._lastHead = void 0;
|
|
401
|
-
this._cursorConverter = view.state.facet(
|
|
402
|
-
this._provider = view.state.facet(
|
|
433
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
434
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
403
435
|
this._provider.open();
|
|
404
436
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
405
437
|
view.dispatch({
|
|
@@ -453,7 +485,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
453
485
|
attributes: {
|
|
454
486
|
style: `background-color: ${lightColor}`
|
|
455
487
|
},
|
|
456
|
-
class: "cm-
|
|
488
|
+
class: "cm-collab-selection"
|
|
457
489
|
})
|
|
458
490
|
});
|
|
459
491
|
} else {
|
|
@@ -464,7 +496,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
464
496
|
attributes: {
|
|
465
497
|
style: `background-color: ${color}`
|
|
466
498
|
},
|
|
467
|
-
class: "cm-
|
|
499
|
+
class: "cm-collab-selection"
|
|
468
500
|
})
|
|
469
501
|
});
|
|
470
502
|
decorations.push({
|
|
@@ -474,7 +506,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
474
506
|
attributes: {
|
|
475
507
|
style: `background-color: ${color}`
|
|
476
508
|
},
|
|
477
|
-
class: "cm-
|
|
509
|
+
class: "cm-collab-selection"
|
|
478
510
|
})
|
|
479
511
|
});
|
|
480
512
|
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
@@ -485,7 +517,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
485
517
|
value: Decoration.line({
|
|
486
518
|
attributes: {
|
|
487
519
|
style: `background-color: ${color}`,
|
|
488
|
-
class: "cm-
|
|
520
|
+
class: "cm-collab-selectionLine"
|
|
489
521
|
}
|
|
490
522
|
})
|
|
491
523
|
});
|
|
@@ -505,23 +537,21 @@ var RemoteSelectionsDecorator = class {
|
|
|
505
537
|
}
|
|
506
538
|
};
|
|
507
539
|
var RemoteCaretWidget = class extends WidgetType {
|
|
508
|
-
constructor(
|
|
540
|
+
constructor(_name, _color) {
|
|
509
541
|
super();
|
|
510
|
-
this.
|
|
511
|
-
this.
|
|
512
|
-
this.name = name;
|
|
513
|
-
this.color = color;
|
|
542
|
+
this._name = _name;
|
|
543
|
+
this._color = _color;
|
|
514
544
|
}
|
|
515
545
|
toDOM() {
|
|
516
546
|
const span = document.createElement("span");
|
|
517
|
-
span.className = "cm-
|
|
518
|
-
span.style.backgroundColor = this.
|
|
519
|
-
span.style.borderColor = this.
|
|
547
|
+
span.className = "cm-collab-selectionCaret";
|
|
548
|
+
span.style.backgroundColor = this._color;
|
|
549
|
+
span.style.borderColor = this._color;
|
|
520
550
|
const dot = document.createElement("div");
|
|
521
|
-
dot.className = "cm-
|
|
551
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
522
552
|
const info = document.createElement("div");
|
|
523
|
-
info.className = "cm-
|
|
524
|
-
info.innerText = this.
|
|
553
|
+
info.className = "cm-collab-selectionInfo";
|
|
554
|
+
info.innerText = this._name;
|
|
525
555
|
span.appendChild(document.createTextNode("\u2060"));
|
|
526
556
|
span.appendChild(dot);
|
|
527
557
|
span.appendChild(document.createTextNode("\u2060"));
|
|
@@ -529,15 +559,12 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
529
559
|
span.appendChild(document.createTextNode("\u2060"));
|
|
530
560
|
return span;
|
|
531
561
|
}
|
|
532
|
-
eq(widget) {
|
|
533
|
-
return widget.color === this.color;
|
|
534
|
-
}
|
|
535
|
-
compare(widget) {
|
|
536
|
-
return widget.color === this.color;
|
|
537
|
-
}
|
|
538
562
|
updateDOM() {
|
|
539
563
|
return false;
|
|
540
564
|
}
|
|
565
|
+
eq(widget) {
|
|
566
|
+
return widget._color === this._color;
|
|
567
|
+
}
|
|
541
568
|
get estimatedHeight() {
|
|
542
569
|
return -1;
|
|
543
570
|
}
|
|
@@ -545,58 +572,60 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
545
572
|
return true;
|
|
546
573
|
}
|
|
547
574
|
};
|
|
548
|
-
var styles =
|
|
549
|
-
".cm-
|
|
550
|
-
".cm-
|
|
575
|
+
var styles = EditorView2.baseTheme({
|
|
576
|
+
".cm-collab-selection": {},
|
|
577
|
+
".cm-collab-selectionLine": {
|
|
551
578
|
padding: 0,
|
|
552
579
|
margin: "0px 2px 0px 4px"
|
|
553
580
|
},
|
|
554
|
-
".cm-
|
|
581
|
+
".cm-collab-selectionCaret": {
|
|
555
582
|
position: "relative",
|
|
556
583
|
borderLeft: "1px solid black",
|
|
557
584
|
borderRight: "1px solid black",
|
|
558
585
|
marginLeft: "-1px",
|
|
559
586
|
marginRight: "-1px",
|
|
560
587
|
boxSizing: "border-box",
|
|
561
|
-
display: "inline"
|
|
588
|
+
display: "inline",
|
|
589
|
+
cursor: "pointer"
|
|
562
590
|
},
|
|
563
|
-
".cm-
|
|
591
|
+
".cm-collab-selectionCaretDot": {
|
|
564
592
|
borderRadius: "50%",
|
|
565
593
|
position: "absolute",
|
|
566
|
-
width: ".
|
|
567
|
-
height: ".
|
|
568
|
-
top: "-.
|
|
569
|
-
left: "-.
|
|
594
|
+
width: ".5em",
|
|
595
|
+
height: ".5em",
|
|
596
|
+
top: "-.25em",
|
|
597
|
+
left: "-.25em",
|
|
570
598
|
backgroundColor: "inherit",
|
|
571
599
|
transition: "transform .3s ease-in-out",
|
|
572
600
|
boxSizing: "border-box"
|
|
573
601
|
},
|
|
574
|
-
".cm-
|
|
575
|
-
|
|
576
|
-
|
|
602
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
603
|
+
transform: "scale(0)",
|
|
604
|
+
transformOrigin: "center"
|
|
577
605
|
},
|
|
578
|
-
".cm-
|
|
606
|
+
".cm-collab-selectionInfo": {
|
|
579
607
|
position: "absolute",
|
|
580
|
-
|
|
581
|
-
|
|
608
|
+
transform: "translate(-50%, 0)",
|
|
609
|
+
top: "-20px",
|
|
610
|
+
left: 0,
|
|
582
611
|
fontSize: ".75em",
|
|
583
|
-
fontFamily: "serif",
|
|
612
|
+
fontFamily: "sans-serif",
|
|
584
613
|
fontStyle: "normal",
|
|
585
614
|
fontWeight: "normal",
|
|
586
615
|
lineHeight: "normal",
|
|
587
616
|
userSelect: "none",
|
|
588
617
|
color: "white",
|
|
589
|
-
|
|
590
|
-
paddingRight: "2px",
|
|
618
|
+
padding: "2px",
|
|
591
619
|
zIndex: 101,
|
|
592
620
|
transition: "opacity .3s ease-in-out",
|
|
593
621
|
backgroundColor: "inherit",
|
|
594
|
-
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
// These should be separate.
|
|
595
624
|
opacity: 0,
|
|
596
625
|
transitionDelay: "0s",
|
|
597
626
|
whiteSpace: "nowrap"
|
|
598
627
|
},
|
|
599
|
-
".cm-
|
|
628
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
600
629
|
opacity: 1,
|
|
601
630
|
transitionDelay: "0s"
|
|
602
631
|
}
|
|
@@ -604,26 +633,29 @@ var styles = EditorView.baseTheme({
|
|
|
604
633
|
|
|
605
634
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
606
635
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
636
|
+
import { history } from "@codemirror/commands";
|
|
607
637
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
608
638
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
609
|
-
import { drawSelection, EditorView as
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
639
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
640
|
+
import { isNotFalsy } from "@dxos/util";
|
|
641
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
642
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
613
643
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
614
644
|
bracketMatching(),
|
|
615
645
|
closeBrackets(),
|
|
616
646
|
drawSelection(),
|
|
647
|
+
highlightActiveLine(),
|
|
648
|
+
history(),
|
|
617
649
|
_placeholder && placeholder(_placeholder),
|
|
618
|
-
//
|
|
650
|
+
// https://github.com/codemirror/theme-one-dark
|
|
619
651
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
620
|
-
].filter(
|
|
652
|
+
].filter(isNotFalsy);
|
|
621
653
|
|
|
622
654
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
623
|
-
import { EditorView as
|
|
655
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
624
656
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
625
657
|
import { invariant } from "@dxos/invariant";
|
|
626
|
-
var
|
|
658
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
627
659
|
var defaultOptions = {
|
|
628
660
|
effect: 2,
|
|
629
661
|
maxParticles: 200,
|
|
@@ -656,10 +688,10 @@ var blast = (options = defaultOptions) => {
|
|
|
656
688
|
const getPoint = (view, pos) => {
|
|
657
689
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
658
690
|
const element = document.elementFromPoint(x, y);
|
|
659
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
691
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
660
692
|
const point = {
|
|
661
693
|
x: x - left,
|
|
662
|
-
y: y -
|
|
694
|
+
y: y - top2
|
|
663
695
|
};
|
|
664
696
|
return {
|
|
665
697
|
element,
|
|
@@ -668,7 +700,7 @@ var blast = (options = defaultOptions) => {
|
|
|
668
700
|
};
|
|
669
701
|
return [
|
|
670
702
|
// Cursor moved.
|
|
671
|
-
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
672
704
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
673
705
|
if (blaster) {
|
|
674
706
|
blaster.destroy();
|
|
@@ -750,8 +782,8 @@ var Blaster = class {
|
|
|
750
782
|
}
|
|
751
783
|
initialize() {
|
|
752
784
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
753
|
-
F:
|
|
754
|
-
L:
|
|
785
|
+
F: __dxlog_file,
|
|
786
|
+
L: 141,
|
|
755
787
|
S: this,
|
|
756
788
|
A: [
|
|
757
789
|
"!this._canvas && !this._ctx",
|
|
@@ -787,8 +819,8 @@ var Blaster = class {
|
|
|
787
819
|
}
|
|
788
820
|
start() {
|
|
789
821
|
invariant(this._canvas && this._ctx, void 0, {
|
|
790
|
-
F:
|
|
791
|
-
L:
|
|
822
|
+
F: __dxlog_file,
|
|
823
|
+
L: 180,
|
|
792
824
|
S: this,
|
|
793
825
|
A: [
|
|
794
826
|
"this._canvas && this._ctx",
|
|
@@ -929,9 +961,14 @@ var random = (min, max) => {
|
|
|
929
961
|
return min + ~~(Math.random() * (max - min + 1));
|
|
930
962
|
};
|
|
931
963
|
|
|
932
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
933
|
-
import {
|
|
934
|
-
import {
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
935
972
|
|
|
936
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
974
|
import * as random2 from "lib0/random";
|
|
@@ -974,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
974
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
976
1013
|
var headings = {
|
|
977
|
-
1:
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
987
|
-
"-ml-[7px]"
|
|
988
|
-
],
|
|
989
|
-
4: [
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
991
|
-
"-ml-[6px]"
|
|
992
|
-
],
|
|
993
|
-
5: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
995
|
-
"-ml-[5px]"
|
|
996
|
-
],
|
|
997
|
-
6: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
999
|
-
"-ml-[4px]"
|
|
1000
|
-
]
|
|
1001
|
-
};
|
|
1002
|
-
var heading = (level, readonly) => {
|
|
1003
|
-
const [style, offset] = headings[level];
|
|
1004
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1005
1023
|
};
|
|
1006
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1019,154 +1037,123 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1019
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1020
1038
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1021
1039
|
|
|
1022
|
-
// packages/ui/react-ui-editor/src/
|
|
1023
|
-
|
|
1024
|
-
var
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
display: "block",
|
|
1036
|
-
paddingInline: "4px !important"
|
|
1037
|
-
},
|
|
1038
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1039
|
-
paddingTop: "4px !important",
|
|
1040
|
-
borderTopLeftRadius: "4px",
|
|
1041
|
-
borderTopRightRadius: "4px"
|
|
1042
|
-
},
|
|
1043
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1044
|
-
paddingBottom: "4px !important",
|
|
1045
|
-
borderBottomLeftRadius: "4px",
|
|
1046
|
-
borderBottomRightRadius: "4px"
|
|
1040
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1041
|
+
import { log } from "@dxos/log";
|
|
1042
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1043
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1044
|
+
try {
|
|
1045
|
+
return fn(...args);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log.catch(err, void 0, {
|
|
1048
|
+
F: __dxlog_file2,
|
|
1049
|
+
L: 18,
|
|
1050
|
+
S: void 0,
|
|
1051
|
+
C: (f, a) => f(...a)
|
|
1052
|
+
});
|
|
1047
1053
|
}
|
|
1048
|
-
});
|
|
1049
|
-
var getLineRange = (lines, from, to) => {
|
|
1050
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1051
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1052
|
-
return [
|
|
1053
|
-
start,
|
|
1054
|
-
end
|
|
1055
|
-
];
|
|
1056
1054
|
};
|
|
1057
|
-
var
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
const text = view.state.doc.sliceString(0);
|
|
1062
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1063
|
-
const blocks = view.viewportLineBlocks;
|
|
1064
|
-
for (const match of matches) {
|
|
1065
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1066
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1067
|
-
const block = blocks[i];
|
|
1068
|
-
decorations.push(Decoration2.line({
|
|
1069
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1070
|
-
}).range(block.from));
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1073
1059
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
decorations: (value) => value.decorations
|
|
1088
|
-
}),
|
|
1089
|
-
styles2
|
|
1090
|
-
];
|
|
1060
|
+
const changes2 = [];
|
|
1061
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1062
|
+
fromA,
|
|
1063
|
+
toA,
|
|
1064
|
+
fromB,
|
|
1065
|
+
toB,
|
|
1066
|
+
inserted: inserted.toString()
|
|
1067
|
+
})));
|
|
1068
|
+
return changes2;
|
|
1069
|
+
}).filter(Boolean);
|
|
1070
|
+
if (changes.length) {
|
|
1071
|
+
console.log("changes", changes);
|
|
1072
|
+
}
|
|
1091
1073
|
};
|
|
1092
1074
|
|
|
1093
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
import { debounce } from "@dxos/async";
|
|
1098
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1099
|
-
import { log as log2 } from "@dxos/log";
|
|
1100
|
-
import { nonNullable } from "@dxos/util";
|
|
1101
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1102
|
-
var styles3 = EditorView5.baseTheme({
|
|
1103
|
-
"& .cm-bookmark": {
|
|
1104
|
-
cursor: "pointer",
|
|
1105
|
-
margin: "4px",
|
|
1106
|
-
padding: "4px",
|
|
1107
|
-
backgroundColor: "yellow"
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1077
|
+
"&light .cm-comment, &light .cm-comment-current": {
|
|
1078
|
+
mixBlendMode: "darken"
|
|
1108
1079
|
},
|
|
1109
|
-
"& .cm-
|
|
1110
|
-
|
|
1080
|
+
"&dark .cm-comment, &dark .cm-comment-current": {
|
|
1081
|
+
mixBlendMode: "plus-lighter"
|
|
1111
1082
|
},
|
|
1112
|
-
"& .cm-comment": {
|
|
1083
|
+
"&light .cm-comment": {
|
|
1113
1084
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1114
1085
|
},
|
|
1115
|
-
"& .cm-comment-
|
|
1086
|
+
"&light .cm-comment-current": {
|
|
1116
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")
|
|
1117
1096
|
}
|
|
1118
1097
|
});
|
|
1119
|
-
var
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1129
|
-
if (!range) {
|
|
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) => {
|
|
1105
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1106
|
+
if (!comment?.comment.cursor) {
|
|
1130
1107
|
return;
|
|
1131
1108
|
}
|
|
1132
|
-
view.
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1109
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1110
|
+
if (range) {
|
|
1111
|
+
view.dispatch({
|
|
1112
|
+
selection: {
|
|
1113
|
+
anchor: range.from
|
|
1114
|
+
},
|
|
1115
|
+
effects: [
|
|
1116
|
+
//
|
|
1117
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1118
|
+
y: "center"
|
|
1119
|
+
} : void 0),
|
|
1120
|
+
setSelection.of({
|
|
1121
|
+
current: id
|
|
1122
|
+
})
|
|
1123
|
+
]
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1141
1126
|
};
|
|
1142
|
-
var
|
|
1127
|
+
var setComments = StateEffect2.define();
|
|
1143
1128
|
var setSelection = StateEffect2.define();
|
|
1144
1129
|
var setCommentState = StateEffect2.define();
|
|
1145
|
-
var
|
|
1130
|
+
var commentsState = StateField2.define({
|
|
1146
1131
|
create: () => ({
|
|
1147
|
-
|
|
1132
|
+
comments: [],
|
|
1133
|
+
selection: {}
|
|
1148
1134
|
}),
|
|
1149
1135
|
update: (value, tr) => {
|
|
1150
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1151
1136
|
for (const effect of tr.effects) {
|
|
1152
1137
|
if (effect.is(setSelection)) {
|
|
1153
1138
|
return {
|
|
1154
1139
|
...value,
|
|
1155
|
-
|
|
1140
|
+
selection: effect.value
|
|
1156
1141
|
};
|
|
1157
1142
|
}
|
|
1158
|
-
if (effect.is(
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
1143
|
+
if (effect.is(setComments)) {
|
|
1144
|
+
const comments2 = effect.value.map((comment) => {
|
|
1145
|
+
if (!comment.cursor) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1162
1149
|
return range && {
|
|
1163
|
-
|
|
1164
|
-
|
|
1150
|
+
comment,
|
|
1151
|
+
range
|
|
1165
1152
|
};
|
|
1166
1153
|
}).filter(nonNullable);
|
|
1167
1154
|
return {
|
|
1168
1155
|
...value,
|
|
1169
|
-
|
|
1156
|
+
comments: comments2
|
|
1170
1157
|
};
|
|
1171
1158
|
}
|
|
1172
1159
|
if (effect.is(setCommentState)) {
|
|
@@ -1176,143 +1163,178 @@ var commentsStateField = StateField2.define({
|
|
|
1176
1163
|
return value;
|
|
1177
1164
|
}
|
|
1178
1165
|
});
|
|
1179
|
-
var
|
|
1180
|
-
|
|
1166
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1167
|
+
commentsState
|
|
1181
1168
|
], (state) => {
|
|
1182
|
-
const {
|
|
1183
|
-
const decorations = sortBy(
|
|
1184
|
-
|
|
1169
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1170
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1171
|
+
const range = comment.range;
|
|
1172
|
+
if (!range || range.from === range.to) {
|
|
1173
|
+
console.warn("Invalid range:", range);
|
|
1185
1174
|
return void 0;
|
|
1186
1175
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
to: selection.to
|
|
1190
|
-
};
|
|
1191
|
-
if (selection.id === active) {
|
|
1192
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1176
|
+
if (comment.comment.id === current) {
|
|
1177
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1193
1178
|
} else {
|
|
1194
|
-
return
|
|
1179
|
+
return commentMark.range(range.from, range.to);
|
|
1195
1180
|
}
|
|
1196
|
-
}).filter(nonNullable)
|
|
1197
|
-
return
|
|
1181
|
+
}).filter(nonNullable);
|
|
1182
|
+
return Decoration2.set(decorations);
|
|
1198
1183
|
});
|
|
1199
|
-
var
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1217
|
-
}
|
|
1218
|
-
toDOM() {
|
|
1219
|
-
const span = document.createElement("span");
|
|
1220
|
-
span.className = "cm-bookmark";
|
|
1221
|
-
span.textContent = "\u203B";
|
|
1222
|
-
if (this._handleClick) {
|
|
1223
|
-
span.onclick = () => this._handleClick();
|
|
1224
|
-
}
|
|
1225
|
-
return span;
|
|
1226
|
-
}
|
|
1227
|
-
};
|
|
1228
|
-
var comments = (options = {}) => {
|
|
1229
|
-
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1230
|
-
const createCommentThread = (view) => {
|
|
1231
|
-
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1232
|
-
invariant2(options.onCreate, void 0, {
|
|
1233
|
-
F: __dxlog_file3,
|
|
1234
|
-
L: 224,
|
|
1235
|
-
S: void 0,
|
|
1236
|
-
A: [
|
|
1237
|
-
"options.onCreate",
|
|
1238
|
-
""
|
|
1239
|
-
]
|
|
1240
|
-
});
|
|
1241
|
-
const { head, from, to } = view.state.selection.main;
|
|
1242
|
-
if (from === to) {
|
|
1243
|
-
return false;
|
|
1184
|
+
var trackPastedComments = (onUpdate) => {
|
|
1185
|
+
let tracked = null;
|
|
1186
|
+
const handleTrack = (event, view) => {
|
|
1187
|
+
const comments2 = view.state.field(commentsState);
|
|
1188
|
+
const { main } = view.state.selection;
|
|
1189
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1190
|
+
if (!selectedRanges.length) {
|
|
1191
|
+
tracked = null;
|
|
1192
|
+
} else {
|
|
1193
|
+
tracked = {
|
|
1194
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1195
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1196
|
+
id: comment.id,
|
|
1197
|
+
from: range.from - main.from,
|
|
1198
|
+
to: range.to - main.from
|
|
1199
|
+
}))
|
|
1200
|
+
};
|
|
1244
1201
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1202
|
+
};
|
|
1203
|
+
return [
|
|
1204
|
+
EditorView5.domEventHandlers({
|
|
1205
|
+
cut: handleTrack,
|
|
1206
|
+
copy: handleTrack
|
|
1207
|
+
}),
|
|
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
|
+
}));
|
|
1258
1220
|
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
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
|
+
}
|
|
1239
|
+
if (tracked) {
|
|
1240
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1241
|
+
if (paste) {
|
|
1242
|
+
let found = -1;
|
|
1243
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1244
|
+
if (text.eq(tracked.text)) {
|
|
1245
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1246
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1247
|
+
}
|
|
1248
|
+
found = fromB;
|
|
1269
1249
|
}
|
|
1270
1250
|
});
|
|
1251
|
+
if (found > -1) {
|
|
1252
|
+
for (const moved of tracked.comments) {
|
|
1253
|
+
restore.push({
|
|
1254
|
+
id: moved.id,
|
|
1255
|
+
from: found + moved.from,
|
|
1256
|
+
to: found + moved.to
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
tracked = null;
|
|
1271
1261
|
}
|
|
1272
|
-
return true;
|
|
1273
1262
|
}
|
|
1274
|
-
|
|
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
|
+
}
|
|
1271
|
+
})
|
|
1272
|
+
];
|
|
1273
|
+
};
|
|
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) {
|
|
1275
1289
|
return false;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1290
|
+
}
|
|
1291
|
+
if (to === view.state.doc.length) {
|
|
1292
|
+
view.dispatch({
|
|
1293
|
+
changes: {
|
|
1294
|
+
from: to,
|
|
1295
|
+
insert: "\n"
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
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) {
|
|
1310
|
+
view.dispatch({
|
|
1311
|
+
effects: setSelection.of({
|
|
1312
|
+
current: id
|
|
1313
|
+
}),
|
|
1314
|
+
selection: {
|
|
1315
|
+
anchor: to
|
|
1289
1316
|
}
|
|
1290
1317
|
});
|
|
1318
|
+
return true;
|
|
1291
1319
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}, {
|
|
1299
|
-
decorations: (instance) => instance.bookmarks,
|
|
1300
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1301
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1302
|
-
})
|
|
1303
|
-
});
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
var comments = (options = {}) => {
|
|
1324
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1325
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1304
1326
|
return [
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1327
|
+
optionsFacet.of(options),
|
|
1328
|
+
commentsState,
|
|
1329
|
+
commentsDecorations,
|
|
1330
|
+
styles2,
|
|
1309
1331
|
//
|
|
1310
1332
|
// Keymap.
|
|
1311
1333
|
//
|
|
1312
1334
|
options.onCreate ? keymap3.of([
|
|
1313
1335
|
{
|
|
1314
|
-
key:
|
|
1315
|
-
run: callbackWrapper(
|
|
1336
|
+
key: shortcut,
|
|
1337
|
+
run: callbackWrapper(createComment)
|
|
1316
1338
|
}
|
|
1317
1339
|
]) : [],
|
|
1318
1340
|
//
|
|
@@ -1328,7 +1350,7 @@ var comments = (options = {}) => {
|
|
|
1328
1350
|
above: true,
|
|
1329
1351
|
create: () => {
|
|
1330
1352
|
const el = document.createElement("div");
|
|
1331
|
-
options.onHover
|
|
1353
|
+
options.onHover(el, shortcut);
|
|
1332
1354
|
return {
|
|
1333
1355
|
dom: el,
|
|
1334
1356
|
offset: {
|
|
@@ -1341,366 +1363,100 @@ var comments = (options = {}) => {
|
|
|
1341
1363
|
}
|
|
1342
1364
|
return null;
|
|
1343
1365
|
}, {
|
|
1344
|
-
|
|
1366
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1367
|
+
// hideOnChange: true,
|
|
1345
1368
|
hoverTime: 1e3
|
|
1346
1369
|
}) : [],
|
|
1347
1370
|
//
|
|
1348
|
-
//
|
|
1349
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1371
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1350
1372
|
//
|
|
1351
1373
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1352
|
-
|
|
1353
|
-
{
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
if (
|
|
1359
|
-
|
|
1360
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1361
|
-
log2.info("deleted comment", {
|
|
1362
|
-
thread: range.id
|
|
1363
|
-
}, {
|
|
1364
|
-
F: __dxlog_file3,
|
|
1365
|
-
L: 358,
|
|
1366
|
-
S: void 0,
|
|
1367
|
-
C: (f, a) => f(...a)
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
if (from <= range.to) {
|
|
1372
|
-
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1373
|
-
Object.assign(range, newRange);
|
|
1374
|
-
mod = true;
|
|
1374
|
+
let mod = false;
|
|
1375
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1376
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1377
|
+
comments2.forEach(({ comment, range }) => {
|
|
1378
|
+
if (from2 === to2) {
|
|
1379
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1380
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1381
|
+
options.onDelete?.(comment.id);
|
|
1375
1382
|
}
|
|
1376
|
-
}
|
|
1383
|
+
}
|
|
1384
|
+
if (from <= range.to) {
|
|
1385
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1386
|
+
Object.assign(range, newRange);
|
|
1387
|
+
mod = true;
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
if (mod) {
|
|
1392
|
+
view.dispatch({
|
|
1393
|
+
effects: setCommentState.of({
|
|
1394
|
+
comments: comments2,
|
|
1395
|
+
...value
|
|
1396
|
+
})
|
|
1377
1397
|
});
|
|
1378
|
-
if (mod) {
|
|
1379
|
-
view.dispatch({
|
|
1380
|
-
effects: setCommentState.of({
|
|
1381
|
-
active,
|
|
1382
|
-
ranges
|
|
1383
|
-
})
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
1398
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1399
|
+
}),
|
|
1400
|
+
//
|
|
1401
|
+
// Track selection/proximity.
|
|
1402
|
+
//
|
|
1403
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1404
|
+
let min = Infinity;
|
|
1405
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1406
|
+
const { head } = state.selection.main;
|
|
1407
|
+
const selection = {};
|
|
1408
|
+
comments2.forEach(({ comment, range }) => {
|
|
1409
|
+
if (head >= range.from && head <= range.to) {
|
|
1410
|
+
selection.current = comment.id;
|
|
1411
|
+
selection.closest = void 0;
|
|
1412
|
+
}
|
|
1413
|
+
if (!selection.current) {
|
|
1414
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1400
1415
|
if (d < min) {
|
|
1401
|
-
|
|
1416
|
+
selection.closest = comment.id;
|
|
1402
1417
|
min = d;
|
|
1403
1418
|
}
|
|
1404
|
-
});
|
|
1405
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1406
|
-
view.dispatch({
|
|
1407
|
-
effects: setSelection.of(selected)
|
|
1408
|
-
});
|
|
1409
|
-
handleSelect({
|
|
1410
|
-
...selected,
|
|
1411
|
-
ranges: ranges.map((range) => ({
|
|
1412
|
-
...range,
|
|
1413
|
-
location: view.coordsAtPos(range.from)
|
|
1414
|
-
}))
|
|
1415
|
-
});
|
|
1416
1419
|
}
|
|
1417
|
-
}
|
|
1418
|
-
})
|
|
1419
|
-
];
|
|
1420
|
-
};
|
|
1421
|
-
var getCursorFromRange = (cursorConverter3, range) => {
|
|
1422
|
-
const from = cursorConverter3.toCursor(range.from);
|
|
1423
|
-
const to = cursorConverter3.toCursor(range.to, -1);
|
|
1424
|
-
return [
|
|
1425
|
-
from,
|
|
1426
|
-
to
|
|
1427
|
-
].join(":");
|
|
1428
|
-
};
|
|
1429
|
-
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1430
|
-
const parts = cursor.split(":");
|
|
1431
|
-
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1432
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1433
|
-
return from !== void 0 && to !== void 0 ? {
|
|
1434
|
-
from,
|
|
1435
|
-
to
|
|
1436
|
-
} : void 0;
|
|
1437
|
-
};
|
|
1438
|
-
|
|
1439
|
-
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1440
|
-
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1441
|
-
var styles4 = EditorView6.baseTheme({
|
|
1442
|
-
"& .cm-hr": {
|
|
1443
|
-
// TODO(burdon): ???
|
|
1444
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1445
|
-
borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1449
|
-
constructor(_pos) {
|
|
1450
|
-
super();
|
|
1451
|
-
this._pos = _pos;
|
|
1452
|
-
}
|
|
1453
|
-
eq(other) {
|
|
1454
|
-
return this._pos === other._pos;
|
|
1455
|
-
}
|
|
1456
|
-
toDOM(view) {
|
|
1457
|
-
const el = document.createElement("div");
|
|
1458
|
-
el.className = "cm-hr";
|
|
1459
|
-
return el;
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1463
|
-
regexp: /^---$/g,
|
|
1464
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1465
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1466
|
-
})
|
|
1467
|
-
});
|
|
1468
|
-
var hr = () => [
|
|
1469
|
-
styles4,
|
|
1470
|
-
ViewPlugin5.fromClass(class {
|
|
1471
|
-
constructor(view) {
|
|
1472
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1473
|
-
}
|
|
1474
|
-
update(update2) {
|
|
1475
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1476
|
-
}
|
|
1477
|
-
}, {
|
|
1478
|
-
decorations: (instance) => instance.rules,
|
|
1479
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1480
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1482
|
-
})
|
|
1483
|
-
})
|
|
1484
|
-
];
|
|
1485
|
-
|
|
1486
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1487
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1488
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1490
|
-
var image = (options = {}) => {
|
|
1491
|
-
return StateField3.define({
|
|
1492
|
-
create: (state) => {
|
|
1493
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1494
|
-
},
|
|
1495
|
-
update: (value, tr) => {
|
|
1496
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1497
|
-
return value;
|
|
1498
|
-
}
|
|
1499
|
-
const cursor = tr.state.selection.main.head;
|
|
1500
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1501
|
-
let from = Math.min(cursor, oldCursor);
|
|
1502
|
-
let to = Math.max(cursor, oldCursor);
|
|
1503
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1504
|
-
from = Math.min(from, fromB);
|
|
1505
|
-
to = Math.max(to, toB);
|
|
1506
|
-
});
|
|
1507
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1508
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1509
|
-
return value.map(tr.changes).update({
|
|
1510
|
-
filterFrom: from,
|
|
1511
|
-
filterTo: to,
|
|
1512
|
-
filter: () => false,
|
|
1513
|
-
add: buildDecorations(from, to, tr.state)
|
|
1514
1420
|
});
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
};
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1528
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1529
|
-
decorations.push(Decoration5.replace({
|
|
1530
|
-
block: true,
|
|
1531
|
-
widget: new ImageWidget(url)
|
|
1532
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
},
|
|
1536
|
-
from,
|
|
1537
|
-
to
|
|
1538
|
-
});
|
|
1539
|
-
return decorations;
|
|
1540
|
-
};
|
|
1541
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1542
|
-
constructor(_url) {
|
|
1543
|
-
super();
|
|
1544
|
-
this._url = _url;
|
|
1545
|
-
}
|
|
1546
|
-
eq(other) {
|
|
1547
|
-
return this._url === other._url;
|
|
1548
|
-
}
|
|
1549
|
-
toDOM(view) {
|
|
1550
|
-
const img = document.createElement("img");
|
|
1551
|
-
img.setAttribute("src", this._url);
|
|
1552
|
-
img.setAttribute("class", "cm-image");
|
|
1553
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1554
|
-
return img;
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
|
|
1558
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1559
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1560
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1561
|
-
import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
1562
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1563
|
-
var link = (options = {}) => {
|
|
1564
|
-
const extensions = [
|
|
1565
|
-
ViewPlugin6.fromClass(class {
|
|
1566
|
-
constructor(view) {
|
|
1567
|
-
this.decorations = buildDecorations2(view, options);
|
|
1568
|
-
}
|
|
1569
|
-
update(update2) {
|
|
1570
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1571
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1572
|
-
}
|
|
1421
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1422
|
+
view.dispatch({
|
|
1423
|
+
effects: setSelection.of(selection)
|
|
1424
|
+
});
|
|
1425
|
+
handleSelect({
|
|
1426
|
+
selection,
|
|
1427
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1428
|
+
comment,
|
|
1429
|
+
range,
|
|
1430
|
+
location: view.coordsAtPos(range.from)
|
|
1431
|
+
}))
|
|
1432
|
+
});
|
|
1573
1433
|
}
|
|
1574
|
-
},
|
|
1575
|
-
|
|
1576
|
-
})
|
|
1434
|
+
}),
|
|
1435
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1577
1436
|
];
|
|
1578
|
-
if (options.onHover) {
|
|
1579
|
-
extensions.push(
|
|
1580
|
-
// https://codemirror.net/examples/tooltip
|
|
1581
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1582
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1583
|
-
hoverTooltip2((view, pos, side) => {
|
|
1584
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1585
|
-
let link2 = null;
|
|
1586
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1587
|
-
link2 = node.name === "Link" ? node : null;
|
|
1588
|
-
}
|
|
1589
|
-
const url = link2 && link2.getChild("URL");
|
|
1590
|
-
if (!url || !link2) {
|
|
1591
|
-
return null;
|
|
1592
|
-
}
|
|
1593
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1594
|
-
return {
|
|
1595
|
-
pos: link2.from,
|
|
1596
|
-
end: link2.to,
|
|
1597
|
-
above: true,
|
|
1598
|
-
create: () => {
|
|
1599
|
-
const el = document.createElement("div");
|
|
1600
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1601
|
-
options.onHover(el, urlText);
|
|
1602
|
-
return {
|
|
1603
|
-
dom: el,
|
|
1604
|
-
offset: {
|
|
1605
|
-
x: 0,
|
|
1606
|
-
y: 4
|
|
1607
|
-
}
|
|
1608
|
-
};
|
|
1609
|
-
}
|
|
1610
|
-
};
|
|
1611
|
-
})
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
return extensions;
|
|
1615
|
-
};
|
|
1616
|
-
var LinkButton = class extends WidgetType5 {
|
|
1617
|
-
constructor(_url, _onAttach) {
|
|
1618
|
-
super();
|
|
1619
|
-
this._url = _url;
|
|
1620
|
-
this._onAttach = _onAttach;
|
|
1621
|
-
}
|
|
1622
|
-
eq(other) {
|
|
1623
|
-
return this._url === other._url;
|
|
1624
|
-
}
|
|
1625
|
-
toDOM(view) {
|
|
1626
|
-
const el = document.createElement("span");
|
|
1627
|
-
this._onAttach(el, this._url);
|
|
1628
|
-
return el;
|
|
1629
|
-
}
|
|
1630
1437
|
};
|
|
1631
|
-
var
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
eq(other) {
|
|
1638
|
-
return this._url === other._url;
|
|
1639
|
-
}
|
|
1640
|
-
toDOM(view) {
|
|
1641
|
-
const link2 = document.createElement("a");
|
|
1642
|
-
link2.setAttribute("class", "cm-link");
|
|
1643
|
-
link2.textContent = this._text;
|
|
1644
|
-
if (this._url) {
|
|
1645
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1646
|
-
link2.setAttribute("target", "_blank");
|
|
1647
|
-
link2.href = this._url;
|
|
1648
|
-
} else {
|
|
1649
|
-
link2.onclick = () => {
|
|
1650
|
-
view.dispatch({
|
|
1651
|
-
selection: {
|
|
1652
|
-
anchor: view.posAtDOM(link2)
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
};
|
|
1438
|
+
var useComments = (view, comments2 = []) => {
|
|
1439
|
+
useEffect(() => {
|
|
1440
|
+
if (view) {
|
|
1441
|
+
view.dispatch({
|
|
1442
|
+
effects: setComments.of(comments2)
|
|
1443
|
+
});
|
|
1656
1444
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
const builder = new RangeSetBuilder();
|
|
1662
|
-
const { state } = view;
|
|
1663
|
-
const cursor = state.selection.main.head;
|
|
1664
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1665
|
-
syntaxTree2(state).iterate({
|
|
1666
|
-
enter: (node) => {
|
|
1667
|
-
if (node.name === "Link") {
|
|
1668
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1669
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1670
|
-
const urlNode = node.node.getChild("URL");
|
|
1671
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1672
|
-
if (!url) {
|
|
1673
|
-
return false;
|
|
1674
|
-
}
|
|
1675
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1676
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1677
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1678
|
-
}));
|
|
1679
|
-
}
|
|
1680
|
-
if (options.onRender) {
|
|
1681
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1682
|
-
widget: new LinkButton(url, options.onRender)
|
|
1683
|
-
}));
|
|
1684
|
-
}
|
|
1685
|
-
return false;
|
|
1686
|
-
}
|
|
1687
|
-
},
|
|
1688
|
-
from,
|
|
1689
|
-
to
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
return builder.finish();
|
|
1445
|
+
}, [
|
|
1446
|
+
view,
|
|
1447
|
+
comments2
|
|
1448
|
+
]);
|
|
1693
1449
|
};
|
|
1694
1450
|
|
|
1695
1451
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1696
|
-
import { EditorView as
|
|
1452
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1697
1453
|
var listener = ({ onFocus, onChange }) => {
|
|
1698
1454
|
const extensions = [];
|
|
1699
|
-
onFocus && extensions.push(
|
|
1455
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1700
1456
|
onFocus(focused);
|
|
1701
1457
|
return null;
|
|
1702
1458
|
}));
|
|
1703
|
-
onChange && extensions.push(
|
|
1459
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1704
1460
|
onChange(update2.state.doc.toString());
|
|
1705
1461
|
}));
|
|
1706
1462
|
return extensions;
|
|
@@ -1708,14 +1464,15 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1708
1464
|
|
|
1709
1465
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1710
1466
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1711
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1467
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1712
1468
|
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1713
1469
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1714
1470
|
import { languages } from "@codemirror/language-data";
|
|
1715
1471
|
import { searchKeymap } from "@codemirror/search";
|
|
1716
1472
|
import { EditorState } from "@codemirror/state";
|
|
1717
1473
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1718
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
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";
|
|
1719
1476
|
|
|
1720
1477
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1721
1478
|
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
@@ -1728,7 +1485,6 @@ var markdownTags = {
|
|
|
1728
1485
|
CodeText: Tag.define(),
|
|
1729
1486
|
EmphasisMark: Tag.define(),
|
|
1730
1487
|
HeaderMark: Tag.define(),
|
|
1731
|
-
// HorizontalRule: Tag.define(),
|
|
1732
1488
|
InlineCode: Tag.define(),
|
|
1733
1489
|
LinkLabel: Tag.define(),
|
|
1734
1490
|
LinkReference: Tag.define(),
|
|
@@ -1813,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1813
1569
|
markdownTags.QuoteMark,
|
|
1814
1570
|
markdownTags.EmphasisMark
|
|
1815
1571
|
],
|
|
1816
|
-
class:
|
|
1572
|
+
class: mark
|
|
1817
1573
|
},
|
|
1818
1574
|
// E.g., code block language (after ```).
|
|
1819
1575
|
{
|
|
@@ -1821,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1821
1577
|
tags.function(tags.variableName),
|
|
1822
1578
|
tags.labelName
|
|
1823
1579
|
],
|
|
1824
|
-
class:
|
|
1580
|
+
class: codeMark
|
|
1825
1581
|
},
|
|
1826
1582
|
{
|
|
1827
1583
|
tag: [
|
|
@@ -1832,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1832
1588
|
// Headings.
|
|
1833
1589
|
{
|
|
1834
1590
|
tag: tags.heading1,
|
|
1835
|
-
class: heading(1
|
|
1591
|
+
class: heading(1)
|
|
1836
1592
|
},
|
|
1837
1593
|
{
|
|
1838
1594
|
tag: tags.heading2,
|
|
1839
|
-
class: heading(2
|
|
1595
|
+
class: heading(2)
|
|
1840
1596
|
},
|
|
1841
1597
|
{
|
|
1842
1598
|
tag: tags.heading3,
|
|
1843
|
-
class: heading(3
|
|
1599
|
+
class: heading(3)
|
|
1844
1600
|
},
|
|
1845
1601
|
{
|
|
1846
1602
|
tag: tags.heading4,
|
|
1847
|
-
class: heading(4
|
|
1603
|
+
class: heading(4)
|
|
1848
1604
|
},
|
|
1849
1605
|
{
|
|
1850
1606
|
tag: tags.heading5,
|
|
1851
|
-
class: heading(5
|
|
1607
|
+
class: heading(5)
|
|
1852
1608
|
},
|
|
1853
1609
|
{
|
|
1854
1610
|
tag: tags.heading6,
|
|
1855
|
-
class: heading(6
|
|
1611
|
+
class: heading(6)
|
|
1856
1612
|
},
|
|
1857
1613
|
// Emphasis.
|
|
1858
1614
|
{
|
|
@@ -1878,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1878
1634
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1879
1635
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1880
1636
|
// the code, but all other CSS properties will be inherited.
|
|
1881
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1637
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1882
1638
|
{
|
|
1883
1639
|
tag: [
|
|
1884
1640
|
markdownTags.CodeText,
|
|
@@ -1892,12 +1648,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1892
1648
|
],
|
|
1893
1649
|
class: blockquote
|
|
1894
1650
|
},
|
|
1895
|
-
// TODO(burdon): Replace with extension.
|
|
1896
|
-
// {
|
|
1897
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1898
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1899
|
-
// },
|
|
1900
|
-
// TODO(burdon): Only if being edited.
|
|
1901
1651
|
{
|
|
1902
1652
|
tag: [
|
|
1903
1653
|
markdownTags.TableCell
|
|
@@ -1913,19 +1663,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1913
1663
|
};
|
|
1914
1664
|
|
|
1915
1665
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1916
|
-
var
|
|
1666
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1917
1667
|
return [
|
|
1668
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1918
1669
|
EditorState.allowMultipleSelections.of(true),
|
|
1919
1670
|
EditorState.tabSize.of(2),
|
|
1920
|
-
|
|
1921
|
-
customKeymap(),
|
|
1671
|
+
// https://github.com/codemirror/basic-setup
|
|
1922
1672
|
bracketMatching2(),
|
|
1923
1673
|
closeBrackets2(),
|
|
1924
1674
|
crosshairCursor(),
|
|
1925
1675
|
dropCursor(),
|
|
1926
1676
|
drawSelection2(),
|
|
1927
|
-
|
|
1928
|
-
|
|
1677
|
+
highlightActiveLine2(),
|
|
1678
|
+
history2(),
|
|
1929
1679
|
indentOnInput(),
|
|
1930
1680
|
_placeholder && placeholder2(_placeholder),
|
|
1931
1681
|
// Main extension.
|
|
@@ -1949,58 +1699,1552 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1949
1699
|
// https://github.com/codemirror/theme-one-dark
|
|
1950
1700
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1951
1701
|
// Custom styles.
|
|
1952
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
]);
|
|
1967
|
-
|
|
1968
|
-
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1969
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1970
|
-
var mention = ({ onSearch }) => {
|
|
1971
|
-
return autocompletion2({
|
|
1972
|
-
closeOnBlur: false,
|
|
1973
|
-
override: [
|
|
1974
|
-
(context) => {
|
|
1975
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1976
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
1977
|
-
return null;
|
|
1978
|
-
}
|
|
1979
|
-
console.log(match);
|
|
1980
|
-
return {
|
|
1981
|
-
from: match.from,
|
|
1982
|
-
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1983
|
-
label: `@${value}`
|
|
1984
|
-
}))
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
]
|
|
1988
|
-
});
|
|
1702
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1703
|
+
keymap4.of([
|
|
1704
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1705
|
+
indentWithTab,
|
|
1706
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1707
|
+
...closeBracketsKeymap,
|
|
1708
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1709
|
+
...historyKeymap,
|
|
1710
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1711
|
+
...searchKeymap,
|
|
1712
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1713
|
+
...standardKeymap
|
|
1714
|
+
])
|
|
1715
|
+
].filter(isNotFalsy2);
|
|
1989
1716
|
};
|
|
1990
1717
|
|
|
1991
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1992
|
-
import { syntaxTree
|
|
1993
|
-
import { RangeSetBuilder
|
|
1994
|
-
import {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
1718
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1719
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1720
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1721
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1722
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1723
|
+
var styles3 = EditorView8.baseTheme({
|
|
1724
|
+
"& .cm-code": {
|
|
1725
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1726
|
+
},
|
|
1727
|
+
"& .cm-codeblock": {
|
|
1728
|
+
width: "100%",
|
|
1729
|
+
paddingInline: "1rem !important",
|
|
1730
|
+
position: "relative",
|
|
1731
|
+
"&::after": {
|
|
1732
|
+
content: '""',
|
|
1733
|
+
position: "absolute",
|
|
1734
|
+
inset: 0
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
"&light .cm-codeblock": {
|
|
1738
|
+
"&::after": {
|
|
1739
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1740
|
+
mixBlendMode: "darken"
|
|
1741
|
+
}
|
|
1742
|
+
},
|
|
1743
|
+
"&dark .cm-codeblock": {
|
|
1744
|
+
"&::after": {
|
|
1745
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1746
|
+
mixBlendMode: "lighten"
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
"& .cm-codeblock-first": {
|
|
1750
|
+
display: "inline-block",
|
|
1751
|
+
"&::after": {
|
|
1752
|
+
borderTopLeftRadius: ".5rem",
|
|
1753
|
+
borderTopRightRadius: ".5rem"
|
|
1754
|
+
}
|
|
1755
|
+
},
|
|
1756
|
+
"& .cm-codeblock-last": {
|
|
1757
|
+
display: "inline-block",
|
|
1758
|
+
"&::after": {
|
|
1759
|
+
borderBottomLeftRadius: ".5rem",
|
|
1760
|
+
borderBottomRightRadius: ".5rem"
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
var getLineRange = (lines, from, to) => {
|
|
1765
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1766
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1767
|
+
return [
|
|
1768
|
+
start,
|
|
1769
|
+
end
|
|
1770
|
+
];
|
|
1771
|
+
};
|
|
1772
|
+
var LineWidget = class extends WidgetType2 {
|
|
1773
|
+
constructor(_className) {
|
|
1774
|
+
super();
|
|
1775
|
+
this._className = _className;
|
|
1776
|
+
}
|
|
1777
|
+
toDOM() {
|
|
1778
|
+
const el = document.createElement("span");
|
|
1779
|
+
el.innerHTML = " ";
|
|
1780
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1781
|
+
return el;
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1785
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1786
|
+
var buildDecorations = (view) => {
|
|
1787
|
+
const builder = new RangeSetBuilder();
|
|
1788
|
+
const { state } = view;
|
|
1789
|
+
const blocks = view.viewportLineBlocks;
|
|
1790
|
+
const cursor = state.selection.main.head;
|
|
1791
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1792
|
+
syntaxTree(state).iterate({
|
|
1793
|
+
enter: (node) => {
|
|
1794
|
+
if (node.name === "FencedCode") {
|
|
1795
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1796
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1797
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1798
|
+
const block = blocks[i];
|
|
1799
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1800
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1801
|
+
widget: i === range[0] ? top : bottom
|
|
1802
|
+
}));
|
|
1803
|
+
} else {
|
|
1804
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1805
|
+
class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1806
|
+
}));
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
from,
|
|
1812
|
+
to
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return builder.finish();
|
|
1816
|
+
};
|
|
1817
|
+
var code2 = () => {
|
|
1818
|
+
return [
|
|
1819
|
+
ViewPlugin3.fromClass(class {
|
|
1820
|
+
constructor(view) {
|
|
1821
|
+
this.decorations = buildDecorations(view);
|
|
1822
|
+
}
|
|
1823
|
+
update(update2) {
|
|
1824
|
+
this.decorations = buildDecorations(update2.view);
|
|
1825
|
+
}
|
|
1826
|
+
}, {
|
|
1827
|
+
decorations: (value) => value.decorations
|
|
1828
|
+
}),
|
|
1829
|
+
styles3
|
|
1830
|
+
];
|
|
1831
|
+
};
|
|
1832
|
+
|
|
1833
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1834
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1835
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1836
|
+
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1837
|
+
import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
+
import { useState, useMemo } from "react";
|
|
1839
|
+
var compareFormatting = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
|
|
1840
|
+
var Inline;
|
|
1841
|
+
(function(Inline2) {
|
|
1842
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
1843
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
1844
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
1845
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
1846
|
+
})(Inline || (Inline = {}));
|
|
1847
|
+
var List;
|
|
1848
|
+
(function(List2) {
|
|
1849
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
1850
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
1851
|
+
List2[List2["Task"] = 2] = "Task";
|
|
1852
|
+
})(List || (List = {}));
|
|
1853
|
+
var setHeading = (level) => ({ state, dispatch }) => {
|
|
1854
|
+
const { selection: { ranges }, doc } = state;
|
|
1855
|
+
const changes = [];
|
|
1856
|
+
let prevBlock = -1;
|
|
1857
|
+
for (const range of ranges) {
|
|
1858
|
+
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1861
|
+
enter: (node) => {
|
|
1862
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
prevBlock = node.from;
|
|
1866
|
+
const blockType = Textblocks[node.name];
|
|
1867
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
1868
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
1869
|
+
if (curLevel < 0 || curLevel === level) {
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (curLevel === 0) {
|
|
1873
|
+
changes.push({
|
|
1874
|
+
from: node.from,
|
|
1875
|
+
insert: "#".repeat(level) + " "
|
|
1876
|
+
});
|
|
1877
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
1878
|
+
const nextLine = doc.lineAt(node.to);
|
|
1879
|
+
if (level) {
|
|
1880
|
+
changes.push({
|
|
1881
|
+
from: node.from,
|
|
1882
|
+
insert: "#".repeat(level) + " "
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
changes.push({
|
|
1886
|
+
from: nextLine.from - 1,
|
|
1887
|
+
to: nextLine.to
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
if (level === 0) {
|
|
1891
|
+
changes.push({
|
|
1892
|
+
from: node.from,
|
|
1893
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
1894
|
+
});
|
|
1895
|
+
} else if (level < curLevel) {
|
|
1896
|
+
changes.push({
|
|
1897
|
+
from: node.from,
|
|
1898
|
+
to: node.from + (curLevel - level)
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
changes.push({
|
|
1902
|
+
from: node.from,
|
|
1903
|
+
insert: "#".repeat(level - curLevel)
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
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
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
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
|
+
}
|
|
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);
|
|
2091
|
+
}
|
|
2092
|
+
return node.from;
|
|
2093
|
+
};
|
|
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;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
};
|
|
2156
|
+
var removeLink = ({ state, dispatch }) => {
|
|
2157
|
+
const changes = [];
|
|
2158
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2159
|
+
removeLinkInner(from, to, changes, state);
|
|
2160
|
+
}
|
|
2161
|
+
if (!changes) {
|
|
2162
|
+
return false;
|
|
2163
|
+
}
|
|
2164
|
+
dispatch(state.update({
|
|
2165
|
+
changes,
|
|
2166
|
+
userEvent: "format.link.remove",
|
|
2167
|
+
scrollIntoView: true
|
|
2168
|
+
}));
|
|
2169
|
+
return true;
|
|
2170
|
+
};
|
|
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,
|
|
2179
|
+
enter: (node) => {
|
|
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
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
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({
|
|
2241
|
+
from,
|
|
2242
|
+
insert: "["
|
|
2243
|
+
}, {
|
|
2244
|
+
from: to,
|
|
2245
|
+
insert: "]()"
|
|
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;
|
|
2255
|
+
}
|
|
2256
|
+
dispatch(state.update(changes, {
|
|
2257
|
+
userEvent: "format.link.add",
|
|
2258
|
+
scrollIntoView: true
|
|
2259
|
+
}));
|
|
2260
|
+
return true;
|
|
2261
|
+
};
|
|
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);
|
|
3015
|
+
}
|
|
3016
|
+
update(update2) {
|
|
3017
|
+
this.decorations = buildDecorations3(update2.view);
|
|
3018
|
+
}
|
|
3019
|
+
}, {
|
|
3020
|
+
decorations: (value) => value.decorations
|
|
3021
|
+
}),
|
|
3022
|
+
styles4
|
|
3023
|
+
];
|
|
3024
|
+
};
|
|
3025
|
+
|
|
3026
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3027
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
3028
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
3029
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3030
|
+
var image = (options = {}) => {
|
|
3031
|
+
return StateField3.define({
|
|
3032
|
+
create: (state) => {
|
|
3033
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
3034
|
+
},
|
|
3035
|
+
update: (value, tr) => {
|
|
3036
|
+
if (!tr.docChanged && !tr.selection) {
|
|
3037
|
+
return value;
|
|
3038
|
+
}
|
|
3039
|
+
const cursor = tr.state.selection.main.head;
|
|
3040
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
3041
|
+
let from = Math.min(cursor, oldCursor);
|
|
3042
|
+
let to = Math.max(cursor, oldCursor);
|
|
3043
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
3044
|
+
from = Math.min(from, fromB);
|
|
3045
|
+
to = Math.max(to, toB);
|
|
3046
|
+
});
|
|
3047
|
+
from = tr.state.doc.lineAt(from).from;
|
|
3048
|
+
to = tr.state.doc.lineAt(to).to;
|
|
3049
|
+
return value.map(tr.changes).update({
|
|
3050
|
+
filterFrom: from,
|
|
3051
|
+
filterTo: to,
|
|
3052
|
+
filter: () => false,
|
|
3053
|
+
add: buildDecorations4(from, to, tr.state)
|
|
3054
|
+
});
|
|
3055
|
+
},
|
|
3056
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
3057
|
+
});
|
|
3058
|
+
};
|
|
3059
|
+
var buildDecorations4 = (from, to, state) => {
|
|
3060
|
+
const decorations = [];
|
|
3061
|
+
const cursor = state.selection.main.head;
|
|
3062
|
+
syntaxTree5(state).iterate({
|
|
3063
|
+
enter: (node) => {
|
|
3064
|
+
if (node.name === "Image") {
|
|
3065
|
+
const urlNode = node.node.getChild("URL");
|
|
3066
|
+
if (urlNode) {
|
|
3067
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
3068
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
3069
|
+
decorations.push(Decoration7.replace({
|
|
3070
|
+
block: true,
|
|
3071
|
+
widget: new ImageWidget(url)
|
|
3072
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
},
|
|
3076
|
+
from,
|
|
3077
|
+
to
|
|
3078
|
+
});
|
|
3079
|
+
return decorations;
|
|
3080
|
+
};
|
|
3081
|
+
var ImageWidget = class extends WidgetType4 {
|
|
3082
|
+
constructor(_url) {
|
|
3083
|
+
super();
|
|
3084
|
+
this._url = _url;
|
|
3085
|
+
}
|
|
3086
|
+
eq(other) {
|
|
3087
|
+
return this._url === other._url;
|
|
3088
|
+
}
|
|
3089
|
+
toDOM(view) {
|
|
3090
|
+
const img = document.createElement("img");
|
|
3091
|
+
img.setAttribute("src", this._url);
|
|
3092
|
+
img.setAttribute("class", "cm-image");
|
|
3093
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
3094
|
+
return img;
|
|
3095
|
+
}
|
|
3096
|
+
};
|
|
3097
|
+
|
|
3098
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
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";
|
|
3102
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
3103
|
+
var link = (options = {}) => {
|
|
3104
|
+
const extensions = [
|
|
3105
|
+
ViewPlugin7.fromClass(class {
|
|
3106
|
+
constructor(view) {
|
|
3107
|
+
this.decorations = buildDecorations5(view, options);
|
|
3108
|
+
}
|
|
3109
|
+
update(update2) {
|
|
3110
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
3111
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
}, {
|
|
3115
|
+
decorations: (value) => value.decorations
|
|
3116
|
+
})
|
|
3117
|
+
];
|
|
3118
|
+
if (options.onHover) {
|
|
3119
|
+
extensions.push(
|
|
3120
|
+
// https://codemirror.net/examples/tooltip
|
|
3121
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
3122
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
3123
|
+
hoverTooltip2((view, pos, side) => {
|
|
3124
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
3125
|
+
let link2 = null;
|
|
3126
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
3127
|
+
link2 = node.name === "Link" ? node : null;
|
|
3128
|
+
}
|
|
3129
|
+
const url = link2 && link2.getChild("URL");
|
|
3130
|
+
if (!url || !link2) {
|
|
3131
|
+
return null;
|
|
3132
|
+
}
|
|
3133
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
3134
|
+
return {
|
|
3135
|
+
pos: link2.from,
|
|
3136
|
+
end: link2.to,
|
|
3137
|
+
above: true,
|
|
3138
|
+
create: () => {
|
|
3139
|
+
const el = document.createElement("div");
|
|
3140
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
3141
|
+
options.onHover(el, urlText);
|
|
3142
|
+
return {
|
|
3143
|
+
dom: el,
|
|
3144
|
+
offset: {
|
|
3145
|
+
x: 0,
|
|
3146
|
+
y: 4
|
|
3147
|
+
}
|
|
3148
|
+
};
|
|
3149
|
+
}
|
|
3150
|
+
};
|
|
3151
|
+
})
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
return extensions;
|
|
3155
|
+
};
|
|
3156
|
+
var LinkButton = class extends WidgetType5 {
|
|
3157
|
+
constructor(_url, _onAttach) {
|
|
3158
|
+
super();
|
|
3159
|
+
this._url = _url;
|
|
3160
|
+
this._onAttach = _onAttach;
|
|
3161
|
+
}
|
|
3162
|
+
eq(other) {
|
|
3163
|
+
return this._url === other._url;
|
|
3164
|
+
}
|
|
3165
|
+
toDOM(view) {
|
|
3166
|
+
const el = document.createElement("span");
|
|
3167
|
+
this._onAttach(el, this._url);
|
|
3168
|
+
return el;
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
var LinkText = class extends WidgetType5 {
|
|
3172
|
+
constructor(_text, _url) {
|
|
3173
|
+
super();
|
|
3174
|
+
this._text = _text;
|
|
3175
|
+
this._url = _url;
|
|
3176
|
+
}
|
|
3177
|
+
eq(other) {
|
|
3178
|
+
return this._url === other._url;
|
|
3179
|
+
}
|
|
3180
|
+
toDOM(view) {
|
|
3181
|
+
const link2 = document.createElement("a");
|
|
3182
|
+
link2.setAttribute("class", "cm-link");
|
|
3183
|
+
link2.textContent = this._text;
|
|
3184
|
+
if (this._url) {
|
|
3185
|
+
link2.setAttribute("rel", "noreferrer");
|
|
3186
|
+
link2.setAttribute("target", "_blank");
|
|
3187
|
+
link2.href = this._url;
|
|
3188
|
+
} else {
|
|
3189
|
+
link2.onclick = () => {
|
|
3190
|
+
view.dispatch({
|
|
3191
|
+
selection: {
|
|
3192
|
+
anchor: view.posAtDOM(link2)
|
|
3193
|
+
}
|
|
3194
|
+
});
|
|
3195
|
+
};
|
|
3196
|
+
}
|
|
3197
|
+
return link2;
|
|
3198
|
+
}
|
|
3199
|
+
};
|
|
3200
|
+
var buildDecorations5 = (view, options) => {
|
|
3201
|
+
const builder = new RangeSetBuilder5();
|
|
3202
|
+
const { state } = view;
|
|
3203
|
+
const cursor = state.selection.main.head;
|
|
3204
|
+
for (const { from, to } of view.visibleRanges) {
|
|
3205
|
+
syntaxTree6(state).iterate({
|
|
3206
|
+
enter: (node) => {
|
|
3207
|
+
if (node.name === "Link") {
|
|
3208
|
+
const marks = node.node.getChildren("LinkMark");
|
|
3209
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
3210
|
+
const urlNode = node.node.getChild("URL");
|
|
3211
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
3212
|
+
if (!url) {
|
|
3213
|
+
return false;
|
|
3214
|
+
}
|
|
3215
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
3216
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
3217
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
3218
|
+
}));
|
|
3219
|
+
}
|
|
3220
|
+
if (options.onRender) {
|
|
3221
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
3222
|
+
widget: new LinkButton(url, options.onRender)
|
|
3223
|
+
}));
|
|
3224
|
+
}
|
|
3225
|
+
return false;
|
|
3226
|
+
}
|
|
3227
|
+
},
|
|
3228
|
+
from,
|
|
3229
|
+
to
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
return builder.finish();
|
|
3233
|
+
};
|
|
3234
|
+
|
|
3235
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
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";
|
|
3239
|
+
var table = (options = {}) => {
|
|
3240
|
+
return StateField4.define({
|
|
3241
|
+
create: (state) => update(state, options),
|
|
3242
|
+
update: (_, tr) => update(tr.state, options),
|
|
3243
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
3244
|
+
});
|
|
3245
|
+
};
|
|
3246
|
+
var update = (state, options) => {
|
|
3247
|
+
const builder = new RangeSetBuilder6();
|
|
2004
3248
|
const cursor = state.selection.main.head;
|
|
2005
3249
|
const tables = [];
|
|
2006
3250
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2008,7 +3252,7 @@ var update = (state, options) => {
|
|
|
2008
3252
|
const table2 = getTable();
|
|
2009
3253
|
return table2.rows?.[table2.rows.length - 1];
|
|
2010
3254
|
};
|
|
2011
|
-
|
|
3255
|
+
syntaxTree7(state).iterate({
|
|
2012
3256
|
enter: (node) => {
|
|
2013
3257
|
switch (node.name) {
|
|
2014
3258
|
case "Table": {
|
|
@@ -2040,10 +3284,10 @@ var update = (state, options) => {
|
|
|
2040
3284
|
});
|
|
2041
3285
|
tables.forEach((table2) => {
|
|
2042
3286
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2043
|
-
hide && builder.add(table2.from, table2.to,
|
|
3287
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2044
3288
|
widget: new TableWidget(table2)
|
|
2045
3289
|
}));
|
|
2046
|
-
builder.add(table2.from, table2.to,
|
|
3290
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2047
3291
|
class: "cm-table"
|
|
2048
3292
|
}));
|
|
2049
3293
|
});
|
|
@@ -2086,92 +3330,139 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2086
3330
|
}
|
|
2087
3331
|
};
|
|
2088
3332
|
|
|
2089
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2090
|
-
import {
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
3333
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
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({
|
|
3338
|
+
"& .cm-task": {
|
|
3339
|
+
color: getToken("extend.colors.blue.500")
|
|
3340
|
+
},
|
|
3341
|
+
"& .cm-task-checkbox": {
|
|
3342
|
+
marginLeft: "4px",
|
|
3343
|
+
marginRight: "4px"
|
|
2095
3344
|
}
|
|
2096
3345
|
});
|
|
2097
3346
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2098
|
-
constructor(_checked
|
|
3347
|
+
constructor(_checked) {
|
|
2099
3348
|
super();
|
|
2100
3349
|
this._checked = _checked;
|
|
2101
|
-
this._indent = _indent;
|
|
2102
|
-
this._onCheck = _onCheck;
|
|
2103
3350
|
}
|
|
2104
3351
|
eq(other) {
|
|
2105
|
-
return this._checked === other._checked
|
|
3352
|
+
return this._checked === other._checked;
|
|
2106
3353
|
}
|
|
2107
3354
|
toDOM(view) {
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2111
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2112
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
3355
|
+
const input = document.createElement("input");
|
|
3356
|
+
input.className = "cm-task-checkbox";
|
|
2113
3357
|
input.type = "checkbox";
|
|
2114
3358
|
input.checked = this._checked;
|
|
2115
|
-
if (
|
|
3359
|
+
if (view.state.readOnly) {
|
|
2116
3360
|
input.setAttribute("disabled", "true");
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
3361
|
+
} else {
|
|
3362
|
+
input.onmousedown = (event) => {
|
|
3363
|
+
const pos = view.posAtDOM(input);
|
|
3364
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
3365
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
3366
|
+
view.dispatch({
|
|
3367
|
+
changes: {
|
|
3368
|
+
from: pos + 1,
|
|
3369
|
+
to: pos + 2,
|
|
3370
|
+
insert: this._checked ? " " : "x"
|
|
3371
|
+
}
|
|
3372
|
+
});
|
|
3373
|
+
event.preventDefault();
|
|
3374
|
+
}
|
|
2122
3375
|
};
|
|
2123
3376
|
}
|
|
2124
|
-
return
|
|
3377
|
+
return input;
|
|
2125
3378
|
}
|
|
2126
3379
|
ignoreEvent() {
|
|
2127
3380
|
return false;
|
|
2128
3381
|
}
|
|
2129
3382
|
};
|
|
3383
|
+
var checkedDecoration = Decoration10.replace({
|
|
3384
|
+
widget: new CheckboxWidget(true)
|
|
3385
|
+
});
|
|
3386
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
3387
|
+
widget: new CheckboxWidget(false)
|
|
3388
|
+
});
|
|
3389
|
+
var buildDecorations6 = (view) => {
|
|
3390
|
+
const builder = new RangeSetBuilder7();
|
|
3391
|
+
const { state } = view;
|
|
3392
|
+
const cursor = state.selection.main.head;
|
|
3393
|
+
for (const { from, to } of view.visibleRanges) {
|
|
3394
|
+
syntaxTree8(state).iterate({
|
|
3395
|
+
enter: (node) => {
|
|
3396
|
+
if (node.name === "TaskMarker") {
|
|
3397
|
+
if (cursor < node.from || cursor > node.to) {
|
|
3398
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
3399
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
3400
|
+
class: "cm-task"
|
|
3401
|
+
}));
|
|
3402
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
},
|
|
3406
|
+
from,
|
|
3407
|
+
to
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
return builder.finish();
|
|
3411
|
+
};
|
|
2130
3412
|
var tasklist = (options = {}) => {
|
|
2131
|
-
const taskMatcher = new MatchDecorator3({
|
|
2132
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2133
|
-
decoration: (match, view, pos) => {
|
|
2134
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2135
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2136
|
-
return Decoration8.replace({
|
|
2137
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2138
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2139
|
-
view.dispatch({
|
|
2140
|
-
changes: {
|
|
2141
|
-
from: idx,
|
|
2142
|
-
to: idx + 1,
|
|
2143
|
-
insert: checked2 ? "x" : " "
|
|
2144
|
-
},
|
|
2145
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2146
|
-
selection: {
|
|
2147
|
-
anchor: idx + 3
|
|
2148
|
-
}
|
|
2149
|
-
});
|
|
2150
|
-
})
|
|
2151
|
-
});
|
|
2152
|
-
}
|
|
2153
|
-
});
|
|
2154
|
-
const tasks = ViewPlugin7.fromClass(class {
|
|
2155
|
-
constructor(view) {
|
|
2156
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2157
|
-
}
|
|
2158
|
-
update(update2) {
|
|
2159
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2160
|
-
}
|
|
2161
|
-
}, {
|
|
2162
|
-
decorations: (value) => value.tasks,
|
|
2163
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2164
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2165
|
-
})
|
|
2166
|
-
});
|
|
2167
3413
|
return [
|
|
2168
|
-
|
|
3414
|
+
ViewPlugin8.fromClass(class {
|
|
3415
|
+
constructor(view) {
|
|
3416
|
+
this.decorations = buildDecorations6(view);
|
|
3417
|
+
}
|
|
3418
|
+
update(update2) {
|
|
3419
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
3420
|
+
this.decorations = buildDecorations6(update2.view);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
}, {
|
|
3424
|
+
decorations: (value) => value.decorations
|
|
3425
|
+
}),
|
|
2169
3426
|
styles5
|
|
2170
3427
|
];
|
|
2171
3428
|
};
|
|
2172
3429
|
|
|
3430
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
3431
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
3432
|
+
var mention = ({ onSearch }) => {
|
|
3433
|
+
return autocompletion2({
|
|
3434
|
+
// TODO(burdon): Not working.
|
|
3435
|
+
activateOnTyping: true,
|
|
3436
|
+
// activateOnTypingDelay: 100,
|
|
3437
|
+
// selectOnOpen: true,
|
|
3438
|
+
closeOnBlur: false,
|
|
3439
|
+
// defaultKeymap: false,
|
|
3440
|
+
icons: false,
|
|
3441
|
+
override: [
|
|
3442
|
+
(context) => {
|
|
3443
|
+
console.log(context);
|
|
3444
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
3445
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
3446
|
+
return null;
|
|
3447
|
+
}
|
|
3448
|
+
return {
|
|
3449
|
+
from: match.from,
|
|
3450
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
3451
|
+
label: `@${value}`
|
|
3452
|
+
}))
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
]
|
|
3456
|
+
});
|
|
3457
|
+
};
|
|
3458
|
+
|
|
3459
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
3460
|
+
var outliner = (options = {}) => {
|
|
3461
|
+
return [];
|
|
3462
|
+
};
|
|
3463
|
+
|
|
2173
3464
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2174
|
-
import { keymap as
|
|
3465
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2175
3466
|
var defaultItems = [
|
|
2176
3467
|
"hello world!",
|
|
2177
3468
|
"this is a test.",
|
|
@@ -2181,7 +3472,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2181
3472
|
let t;
|
|
2182
3473
|
let idx = 0;
|
|
2183
3474
|
return [
|
|
2184
|
-
|
|
3475
|
+
keymap6.of([
|
|
2185
3476
|
{
|
|
2186
3477
|
// Reset.
|
|
2187
3478
|
key: "alt-meta-'",
|
|
@@ -2227,27 +3518,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2227
3518
|
];
|
|
2228
3519
|
};
|
|
2229
3520
|
|
|
2230
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2231
|
-
import { yCollab } from "y-codemirror.next";
|
|
2232
|
-
|
|
2233
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2234
|
-
import * as Y from "yjs";
|
|
2235
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2236
|
-
var cursorConverter2 = (text) => ({
|
|
2237
|
-
toCursor: (index, assoc) => {
|
|
2238
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2239
|
-
},
|
|
2240
|
-
fromCursor: (cursor) => {
|
|
2241
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2242
|
-
}
|
|
2243
|
-
});
|
|
2244
|
-
|
|
2245
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2246
|
-
var yjs = (content, awareness2) => [
|
|
2247
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2248
|
-
yCollab(content, awareness2)
|
|
2249
|
-
];
|
|
2250
|
-
|
|
2251
3521
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2252
3522
|
import get3 from "lodash.get";
|
|
2253
3523
|
var defaultTheme = {
|
|
@@ -2279,8 +3549,9 @@ var defaultTheme = {
|
|
|
2279
3549
|
outline: "none"
|
|
2280
3550
|
},
|
|
2281
3551
|
".cm-scroller": {
|
|
2282
|
-
overflow:
|
|
2283
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
3552
|
+
// overflow: 'visible',
|
|
3553
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
3554
|
+
lineHeight: 1.4
|
|
2284
3555
|
},
|
|
2285
3556
|
".cm-content": {
|
|
2286
3557
|
padding: 0,
|
|
@@ -2288,11 +3559,11 @@ var defaultTheme = {
|
|
|
2288
3559
|
fontSize: "16px"
|
|
2289
3560
|
},
|
|
2290
3561
|
"&light .cm-content": {
|
|
2291
|
-
color: get3(tokens, "extend.
|
|
3562
|
+
color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
|
|
2292
3563
|
caretColor: "black"
|
|
2293
3564
|
},
|
|
2294
3565
|
"&dark .cm-content": {
|
|
2295
|
-
color: get3(tokens, "extend.
|
|
3566
|
+
color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
|
|
2296
3567
|
caretColor: "white"
|
|
2297
3568
|
},
|
|
2298
3569
|
//
|
|
@@ -2304,8 +3575,11 @@ var defaultTheme = {
|
|
|
2304
3575
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2305
3576
|
borderLeft: "2px solid white"
|
|
2306
3577
|
},
|
|
2307
|
-
".cm-placeholder": {
|
|
2308
|
-
|
|
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)")
|
|
2309
3583
|
},
|
|
2310
3584
|
//
|
|
2311
3585
|
// line
|
|
@@ -2314,7 +3588,7 @@ var defaultTheme = {
|
|
|
2314
3588
|
paddingInline: 0
|
|
2315
3589
|
},
|
|
2316
3590
|
".cm-activeLine": {
|
|
2317
|
-
background: "
|
|
3591
|
+
background: "transparent"
|
|
2318
3592
|
},
|
|
2319
3593
|
//
|
|
2320
3594
|
// Selection
|
|
@@ -2341,33 +3615,6 @@ var defaultTheme = {
|
|
|
2341
3615
|
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2342
3616
|
},
|
|
2343
3617
|
//
|
|
2344
|
-
// collaboration
|
|
2345
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2346
|
-
//
|
|
2347
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2348
|
-
mixBlendMode: "multiply"
|
|
2349
|
-
},
|
|
2350
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2351
|
-
mixBlendMode: "screen"
|
|
2352
|
-
},
|
|
2353
|
-
".cm-ySelectionInfo": {
|
|
2354
|
-
padding: "2px 4px",
|
|
2355
|
-
marginBlockStart: "-4px"
|
|
2356
|
-
},
|
|
2357
|
-
".cm-ySelection, & .cm-selectionMatch": {
|
|
2358
|
-
paddingBlockStart: ".15em",
|
|
2359
|
-
paddingBlockEnd: ".15em"
|
|
2360
|
-
},
|
|
2361
|
-
".cm-ySelectionCaret": {
|
|
2362
|
-
display: "inline-block",
|
|
2363
|
-
insetBlockStart: ".1em",
|
|
2364
|
-
blockSize: "1.4em",
|
|
2365
|
-
verticalAlign: "top"
|
|
2366
|
-
},
|
|
2367
|
-
".cm-yLineSelection": {
|
|
2368
|
-
margin: 0
|
|
2369
|
-
},
|
|
2370
|
-
//
|
|
2371
3618
|
// link
|
|
2372
3619
|
//
|
|
2373
3620
|
".cm-link": {
|
|
@@ -2404,13 +3651,6 @@ var defaultTheme = {
|
|
|
2404
3651
|
textDecoration: "none"
|
|
2405
3652
|
},
|
|
2406
3653
|
//
|
|
2407
|
-
// widgets
|
|
2408
|
-
//
|
|
2409
|
-
".cm-widgetBuffer": {
|
|
2410
|
-
display: "none",
|
|
2411
|
-
height: 0
|
|
2412
|
-
},
|
|
2413
|
-
//
|
|
2414
3654
|
// table
|
|
2415
3655
|
//
|
|
2416
3656
|
".cm-table *": {
|
|
@@ -2441,27 +3681,17 @@ var defaultTheme = {
|
|
|
2441
3681
|
},
|
|
2442
3682
|
//
|
|
2443
3683
|
// font size
|
|
2444
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
3684
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
3685
|
+
// but it's far more verbose than it needs to be.
|
|
2445
3686
|
//
|
|
2446
|
-
...Object.keys(
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2455
|
-
height
|
|
2456
|
-
};
|
|
2457
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2458
|
-
height
|
|
2459
|
-
};
|
|
2460
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2461
|
-
height
|
|
2462
|
-
};
|
|
2463
|
-
return acc;
|
|
2464
|
-
}, {}),
|
|
3687
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
3688
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
3689
|
+
//
|
|
3690
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
3691
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
3692
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
3693
|
+
// return acc;
|
|
3694
|
+
// }, {}),
|
|
2465
3695
|
/**
|
|
2466
3696
|
* Panels
|
|
2467
3697
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2512,7 +3742,9 @@ var textTheme = {
|
|
|
2512
3742
|
}
|
|
2513
3743
|
};
|
|
2514
3744
|
var markdownTheme = {
|
|
2515
|
-
|
|
3745
|
+
".cm-scroller": {
|
|
3746
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
3747
|
+
},
|
|
2516
3748
|
".cm-placeholder": {
|
|
2517
3749
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2518
3750
|
}
|
|
@@ -2527,95 +3759,95 @@ var codeTheme = {
|
|
|
2527
3759
|
};
|
|
2528
3760
|
|
|
2529
3761
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
3762
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2530
3763
|
var EditorModes = [
|
|
2531
3764
|
"default",
|
|
2532
3765
|
"vim"
|
|
2533
3766
|
];
|
|
2534
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
3767
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2535
3768
|
const { themeMode } = useThemeContext();
|
|
2536
|
-
const
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
const [root, setRoot] = useState(null);
|
|
2540
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2541
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2542
|
-
root,
|
|
2543
|
-
state,
|
|
3769
|
+
const rootRef = useRef(null);
|
|
3770
|
+
const [view, setView] = useState2(null);
|
|
3771
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2544
3772
|
view
|
|
2545
|
-
}), [
|
|
2546
|
-
view,
|
|
2547
|
-
state,
|
|
2548
|
-
root
|
|
2549
|
-
]);
|
|
2550
|
-
const { awareness: awareness2, peer } = model;
|
|
2551
|
-
useEffect(() => {
|
|
2552
|
-
if (awareness2 && peer) {
|
|
2553
|
-
awareness2.setLocalStateField("user", {
|
|
2554
|
-
name: peer.name ?? generateName(peer.id),
|
|
2555
|
-
color: getColorForValue({
|
|
2556
|
-
value: peer.id,
|
|
2557
|
-
type: "color"
|
|
2558
|
-
}),
|
|
2559
|
-
colorLight: getColorForValue({
|
|
2560
|
-
value: peer.id,
|
|
2561
|
-
themeMode,
|
|
2562
|
-
type: "highlight"
|
|
2563
|
-
})
|
|
2564
|
-
});
|
|
2565
|
-
}
|
|
2566
|
-
}, [
|
|
2567
|
-
awareness2,
|
|
2568
|
-
peer,
|
|
2569
|
-
themeMode
|
|
2570
3773
|
]);
|
|
2571
|
-
|
|
2572
|
-
if (
|
|
2573
|
-
view.
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
3774
|
+
useEffect2(() => {
|
|
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
|
+
}
|
|
3784
|
+
view?.focus();
|
|
2579
3785
|
}
|
|
2580
3786
|
}, [
|
|
2581
3787
|
view,
|
|
2582
|
-
|
|
3788
|
+
autoFocus
|
|
2583
3789
|
]);
|
|
2584
|
-
|
|
2585
|
-
if (!
|
|
3790
|
+
useEffect2(() => {
|
|
3791
|
+
if (!model || !rootRef.current) {
|
|
2586
3792
|
return;
|
|
2587
3793
|
}
|
|
2588
|
-
const
|
|
3794
|
+
const state = EditorState2.create({
|
|
2589
3795
|
doc: model.text(),
|
|
3796
|
+
selection,
|
|
2590
3797
|
extensions: [
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
3798
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3799
|
+
EditorView14.exceptionSink.of((err) => {
|
|
3800
|
+
log2.catch(err, void 0, {
|
|
3801
|
+
F: __dxlog_file3,
|
|
3802
|
+
L: 134,
|
|
3803
|
+
S: void 0,
|
|
3804
|
+
C: (f, a) => f(...a)
|
|
3805
|
+
});
|
|
3806
|
+
}),
|
|
2594
3807
|
// Theme.
|
|
2595
|
-
// TODO(burdon): Make
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
3808
|
+
// TODO(burdon): Make configurable.
|
|
3809
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3810
|
+
EditorView14.theme(theme ?? {}),
|
|
3811
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3812
|
+
EditorView14.editorAttributes.of({
|
|
3813
|
+
class: slots.editor?.className ?? ""
|
|
3814
|
+
}),
|
|
3815
|
+
EditorView14.contentAttributes.of({
|
|
3816
|
+
class: slots.content?.className ?? ""
|
|
3817
|
+
}),
|
|
3818
|
+
// State.
|
|
3819
|
+
EditorView14.editable.of(!readonly),
|
|
3820
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2599
3821
|
// Storage and replication.
|
|
3822
|
+
// NOTE: This must come before user extensions.
|
|
2600
3823
|
model.extension,
|
|
3824
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
3825
|
+
editorMode === "vim" && vim(),
|
|
2601
3826
|
// Custom.
|
|
2602
3827
|
...extensions
|
|
2603
|
-
].filter(
|
|
3828
|
+
].filter(isNotFalsy3)
|
|
2604
3829
|
});
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
3830
|
+
const newView = new EditorView14({
|
|
3831
|
+
state,
|
|
3832
|
+
parent: rootRef.current,
|
|
3833
|
+
scrollTo,
|
|
3834
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
3835
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
3836
|
+
dispatchTransactions: (trs, view2) => {
|
|
3837
|
+
if (debug) {
|
|
3838
|
+
logChanges(trs);
|
|
3839
|
+
}
|
|
3840
|
+
view2.update(trs);
|
|
3841
|
+
}
|
|
2612
3842
|
});
|
|
3843
|
+
view?.destroy();
|
|
3844
|
+
setView(newView);
|
|
2613
3845
|
return () => {
|
|
2614
|
-
|
|
2615
|
-
|
|
3846
|
+
newView?.destroy();
|
|
3847
|
+
setView(null);
|
|
2616
3848
|
};
|
|
2617
3849
|
}, [
|
|
2618
|
-
|
|
3850
|
+
rootRef,
|
|
2619
3851
|
model,
|
|
2620
3852
|
readonly,
|
|
2621
3853
|
editorMode,
|
|
@@ -2625,11 +3857,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2625
3857
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2626
3858
|
switch (key) {
|
|
2627
3859
|
case "Enter": {
|
|
2628
|
-
view?.
|
|
3860
|
+
view?.focus();
|
|
2629
3861
|
break;
|
|
2630
3862
|
}
|
|
2631
3863
|
case "Escape": {
|
|
2632
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
3864
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
3865
|
+
view?.focus();
|
|
3866
|
+
}
|
|
2633
3867
|
break;
|
|
2634
3868
|
}
|
|
2635
3869
|
}
|
|
@@ -2639,83 +3873,277 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2639
3873
|
]);
|
|
2640
3874
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2641
3875
|
key: model.id,
|
|
2642
|
-
|
|
3876
|
+
role: "none",
|
|
2643
3877
|
tabIndex: 0,
|
|
2644
|
-
...slots
|
|
2645
|
-
...editorMode !==
|
|
2646
|
-
onKeyUp: handleKeyUp
|
|
3878
|
+
...slots.root,
|
|
3879
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
3880
|
+
onKeyUp: handleKeyUp,
|
|
3881
|
+
ref: rootRef
|
|
2647
3882
|
});
|
|
2648
3883
|
});
|
|
2649
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
3884
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2650
3885
|
const { themeMode } = useThemeContext();
|
|
2651
|
-
const
|
|
3886
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2652
3887
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2653
3888
|
ref: forwardedRef,
|
|
2654
3889
|
readonly,
|
|
2655
3890
|
extensions: [
|
|
2656
|
-
|
|
2657
|
-
readonly,
|
|
3891
|
+
createBasicBundle({
|
|
2658
3892
|
themeMode,
|
|
2659
|
-
placeholder:
|
|
3893
|
+
placeholder: placeholder3,
|
|
3894
|
+
lineWrapping
|
|
2660
3895
|
}),
|
|
2661
3896
|
...extensions
|
|
2662
3897
|
],
|
|
2663
|
-
|
|
3898
|
+
theme,
|
|
3899
|
+
slots: updatedSlots,
|
|
2664
3900
|
...props
|
|
2665
3901
|
});
|
|
2666
3902
|
});
|
|
2667
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
3903
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2668
3904
|
const { themeMode } = useThemeContext();
|
|
2669
|
-
const
|
|
3905
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2670
3906
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2671
3907
|
ref: forwardedRef,
|
|
2672
3908
|
readonly,
|
|
2673
3909
|
extensions: [
|
|
2674
|
-
|
|
2675
|
-
readonly,
|
|
3910
|
+
createMarkdownExtensions({
|
|
2676
3911
|
themeMode,
|
|
2677
|
-
placeholder:
|
|
3912
|
+
placeholder: placeholder3
|
|
2678
3913
|
}),
|
|
2679
3914
|
...extensions
|
|
2680
3915
|
],
|
|
2681
|
-
|
|
3916
|
+
theme,
|
|
3917
|
+
slots: updatedSlots,
|
|
2682
3918
|
...props
|
|
2683
3919
|
});
|
|
2684
3920
|
});
|
|
2685
3921
|
var defaultSlots = {
|
|
2686
3922
|
root: {
|
|
2687
|
-
className: mx3("
|
|
3923
|
+
className: mx3("grow", focusRing)
|
|
3924
|
+
},
|
|
3925
|
+
editor: {
|
|
3926
|
+
className: "bs-full"
|
|
2688
3927
|
}
|
|
2689
3928
|
};
|
|
2690
3929
|
var defaultTextSlots = {
|
|
2691
|
-
...defaultSlots
|
|
2692
|
-
editor: {
|
|
2693
|
-
theme: textTheme
|
|
2694
|
-
}
|
|
3930
|
+
...defaultSlots
|
|
2695
3931
|
};
|
|
2696
3932
|
var defaultMarkdownSlots = {
|
|
2697
|
-
...defaultSlots
|
|
2698
|
-
editor: {
|
|
2699
|
-
theme: markdownTheme
|
|
2700
|
-
}
|
|
3933
|
+
...defaultSlots
|
|
2701
3934
|
};
|
|
2702
3935
|
|
|
2703
|
-
// packages/ui/react-ui-editor/src/
|
|
2704
|
-
import
|
|
2705
|
-
import {
|
|
2706
|
-
import
|
|
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
|
+
};
|
|
2707
4135
|
|
|
2708
4136
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2709
4137
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2710
4138
|
import { Context as Context2 } from "@dxos/context";
|
|
2711
|
-
import { invariant as
|
|
4139
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2712
4140
|
import { log as log3 } from "@dxos/log";
|
|
2713
4141
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2714
4142
|
var DEBOUNCE_INTERVAL = 100;
|
|
2715
4143
|
var SpaceAwarenessProvider = class {
|
|
2716
4144
|
constructor(params) {
|
|
2717
|
-
this.remoteStateChange = new Event2();
|
|
2718
4145
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
4146
|
+
this.remoteStateChange = new Event2();
|
|
2719
4147
|
this._space = params.space;
|
|
2720
4148
|
this._channel = params.channel;
|
|
2721
4149
|
this._peerId = params.peerId;
|
|
@@ -2732,7 +4160,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2732
4160
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2733
4161
|
}
|
|
2734
4162
|
});
|
|
2735
|
-
|
|
4163
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2736
4164
|
switch (message.payload.kind) {
|
|
2737
4165
|
case "query": {
|
|
2738
4166
|
this._handleQueryMessage();
|
|
@@ -2743,8 +4171,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2743
4171
|
break;
|
|
2744
4172
|
}
|
|
2745
4173
|
}
|
|
2746
|
-
});
|
|
2747
|
-
this._ctx.onDispose(unsubscribe);
|
|
4174
|
+
}));
|
|
2748
4175
|
void this._space.postMessage(this._channel, {
|
|
2749
4176
|
kind: "query"
|
|
2750
4177
|
}).catch((err) => {
|
|
@@ -2752,7 +4179,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2752
4179
|
err
|
|
2753
4180
|
}, {
|
|
2754
4181
|
F: __dxlog_file4,
|
|
2755
|
-
L:
|
|
4182
|
+
L: 89,
|
|
2756
4183
|
S: this,
|
|
2757
4184
|
C: (f, a) => f(...a)
|
|
2758
4185
|
});
|
|
@@ -2763,10 +4190,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2763
4190
|
this._ctx = void 0;
|
|
2764
4191
|
this._postTask = void 0;
|
|
2765
4192
|
}
|
|
4193
|
+
getRemoteStates() {
|
|
4194
|
+
return Array.from(this._remoteStates.values());
|
|
4195
|
+
}
|
|
2766
4196
|
update(position) {
|
|
2767
|
-
|
|
4197
|
+
invariant2(this._postTask, void 0, {
|
|
2768
4198
|
F: __dxlog_file4,
|
|
2769
|
-
L:
|
|
4199
|
+
L: 104,
|
|
2770
4200
|
S: this,
|
|
2771
4201
|
A: [
|
|
2772
4202
|
"this._postTask",
|
|
@@ -2780,13 +4210,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2780
4210
|
};
|
|
2781
4211
|
this._postTask.schedule();
|
|
2782
4212
|
}
|
|
2783
|
-
getRemoteStates() {
|
|
2784
|
-
return Array.from(this._remoteStates.values());
|
|
2785
|
-
}
|
|
2786
4213
|
_handleQueryMessage() {
|
|
2787
|
-
|
|
4214
|
+
invariant2(this._postTask, void 0, {
|
|
2788
4215
|
F: __dxlog_file4,
|
|
2789
|
-
L:
|
|
4216
|
+
L: 115,
|
|
2790
4217
|
S: this,
|
|
2791
4218
|
A: [
|
|
2792
4219
|
"this._postTask",
|
|
@@ -2796,9 +4223,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2796
4223
|
this._postTask.schedule();
|
|
2797
4224
|
}
|
|
2798
4225
|
_handlePostMessage(message) {
|
|
2799
|
-
|
|
4226
|
+
invariant2(message.kind === "post", void 0, {
|
|
2800
4227
|
F: __dxlog_file4,
|
|
2801
|
-
L:
|
|
4228
|
+
L: 120,
|
|
2802
4229
|
S: this,
|
|
2803
4230
|
A: [
|
|
2804
4231
|
"message.kind === 'post'",
|
|
@@ -2810,229 +4237,247 @@ var SpaceAwarenessProvider = class {
|
|
|
2810
4237
|
}
|
|
2811
4238
|
};
|
|
2812
4239
|
|
|
2813
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
4240
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2814
4241
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2815
|
-
|
|
2816
|
-
|
|
4242
|
+
var modelState = StateField5.define({
|
|
4243
|
+
create: () => void 0,
|
|
4244
|
+
update: (model) => model
|
|
4245
|
+
});
|
|
2817
4246
|
|
|
2818
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
"text.doc",
|
|
2864
|
-
""
|
|
2865
|
-
]
|
|
2866
|
-
});
|
|
2867
|
-
const parts = cursor.split(":");
|
|
2868
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2869
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2870
|
-
return from && to ? {
|
|
2871
|
-
from: from.index,
|
|
2872
|
-
to: to.index
|
|
2873
|
-
} : void 0;
|
|
2874
|
-
},
|
|
2875
|
-
extension: [
|
|
2876
|
-
modelState.init(() => model),
|
|
2877
|
-
yjs(text.content, provider?.awareness)
|
|
2878
|
-
],
|
|
2879
|
-
awareness: provider?.awareness,
|
|
2880
|
-
peer: identity ? {
|
|
2881
|
-
id: identity.identityKey.toHex(),
|
|
2882
|
-
name: identity.profile?.displayName
|
|
2883
|
-
} : void 0
|
|
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
|
+
});
|
|
2884
4292
|
};
|
|
2885
|
-
return model;
|
|
2886
4293
|
};
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
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);
|
|
4299
|
+
return [
|
|
4300
|
+
(ref) => {
|
|
4301
|
+
setView(ref);
|
|
4302
|
+
},
|
|
4303
|
+
view
|
|
4304
|
+
];
|
|
4305
|
+
};
|
|
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);
|
|
2956
4364
|
}
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
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
|
+
};
|
|
2962
4376
|
}
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
return encoder;
|
|
4377
|
+
if (autoFocus) {
|
|
4378
|
+
view.focus();
|
|
2966
4379
|
}
|
|
2967
4380
|
}
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
}
|
|
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);
|
|
2978
4412
|
};
|
|
2979
4413
|
|
|
2980
4414
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
}
|
|
4415
|
+
import get4 from "lodash.get";
|
|
4416
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
4417
|
+
import { generateName } from "@dxos/display-name";
|
|
4418
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
4419
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
4420
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
4421
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2985
4422
|
var useTextModel = (props) => {
|
|
2986
4423
|
const { identity, space, text } = props;
|
|
2987
|
-
const [model, setModel] =
|
|
2988
|
-
|
|
4424
|
+
const [model, setModel] = useState5();
|
|
4425
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2989
4426
|
identity,
|
|
2990
4427
|
space,
|
|
2991
4428
|
text
|
|
2992
4429
|
]);
|
|
2993
4430
|
return model;
|
|
2994
4431
|
};
|
|
2995
|
-
var
|
|
2996
|
-
const
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
}
|
|
4432
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4433
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4434
|
+
return {
|
|
4435
|
+
id,
|
|
4436
|
+
content,
|
|
4437
|
+
setContent,
|
|
4438
|
+
text: () => content
|
|
4439
|
+
};
|
|
3004
4440
|
};
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
4441
|
+
var createModel = ({ space, identity, text }) => {
|
|
4442
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
4443
|
+
F: __dxlog_file6,
|
|
4444
|
+
L: 50,
|
|
4445
|
+
S: void 0,
|
|
4446
|
+
A: [
|
|
4447
|
+
"isAutomergeObject(text)",
|
|
4448
|
+
""
|
|
4449
|
+
]
|
|
4450
|
+
});
|
|
3008
4451
|
const obj = text;
|
|
3009
4452
|
const doc = getRawDoc(obj, [
|
|
3010
4453
|
obj.field
|
|
3011
4454
|
]);
|
|
3012
|
-
const
|
|
4455
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
3013
4456
|
space,
|
|
3014
4457
|
channel: `automerge.awareness.${obj.id}`,
|
|
3015
4458
|
info: {
|
|
3016
|
-
displayName: identity
|
|
4459
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
3017
4460
|
color: cursorColor.color,
|
|
3018
4461
|
lightColor: cursorColor.light
|
|
3019
4462
|
},
|
|
3020
4463
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3021
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
|
+
}
|
|
3022
4476
|
const model = {
|
|
3023
4477
|
id: obj.id,
|
|
3024
4478
|
content: doc,
|
|
3025
4479
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3026
|
-
|
|
3027
|
-
extension: [
|
|
3028
|
-
modelState.init(() => model),
|
|
3029
|
-
automerge3({
|
|
3030
|
-
handle: doc.handle,
|
|
3031
|
-
path: doc.path
|
|
3032
|
-
}),
|
|
3033
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3034
|
-
awareness()
|
|
3035
|
-
].filter(isNotNullOrUndefined),
|
|
4480
|
+
extension: extensions,
|
|
3036
4481
|
peer: identity ? {
|
|
3037
4482
|
id: identity.identityKey.toHex(),
|
|
3038
4483
|
name: identity.profile?.displayName
|
|
@@ -3041,57 +4486,94 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3041
4486
|
return model;
|
|
3042
4487
|
};
|
|
3043
4488
|
export {
|
|
3044
|
-
AwarenessProvider,
|
|
3045
4489
|
BaseTextEditor,
|
|
3046
|
-
|
|
4490
|
+
Cursor,
|
|
3047
4491
|
Doc,
|
|
3048
4492
|
EditorModes,
|
|
4493
|
+
Inline,
|
|
4494
|
+
List,
|
|
3049
4495
|
MarkdownEditor,
|
|
3050
4496
|
RemoteSelectionsDecorator,
|
|
3051
4497
|
SpaceAwarenessProvider,
|
|
3052
4498
|
TextEditor,
|
|
3053
4499
|
TextKind,
|
|
3054
|
-
|
|
4500
|
+
Toolbar,
|
|
3055
4501
|
YText,
|
|
3056
4502
|
YXmlFragment,
|
|
4503
|
+
addBlockquote,
|
|
4504
|
+
addCodeblock,
|
|
4505
|
+
addLink,
|
|
4506
|
+
addList,
|
|
4507
|
+
addStyle,
|
|
3057
4508
|
autocomplete,
|
|
3058
|
-
|
|
4509
|
+
automerge,
|
|
3059
4510
|
awareness,
|
|
3060
|
-
|
|
4511
|
+
awarenessProvider,
|
|
3061
4512
|
blast,
|
|
3062
4513
|
callbackWrapper,
|
|
3063
4514
|
code2 as code,
|
|
3064
4515
|
codeTheme,
|
|
3065
4516
|
comments,
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
4517
|
+
compareFormatting,
|
|
4518
|
+
createBasicBundle,
|
|
4519
|
+
createComment,
|
|
4520
|
+
createDataExtensions,
|
|
4521
|
+
createMarkdownExtensions,
|
|
4522
|
+
createThemeExtensions,
|
|
3069
4523
|
defaultMarkdownSlots,
|
|
3070
4524
|
defaultOptions,
|
|
3071
4525
|
defaultSlots,
|
|
3072
4526
|
defaultTextSlots,
|
|
3073
4527
|
defaultTheme,
|
|
4528
|
+
focusComment,
|
|
4529
|
+
formatting,
|
|
4530
|
+
getFormatting,
|
|
3074
4531
|
getToken,
|
|
4532
|
+
heading2 as heading,
|
|
3075
4533
|
hr,
|
|
3076
4534
|
image,
|
|
4535
|
+
insertTable,
|
|
4536
|
+
keymap7 as keymap,
|
|
3077
4537
|
link,
|
|
3078
4538
|
listener,
|
|
3079
|
-
|
|
4539
|
+
logChanges,
|
|
3080
4540
|
markdownHighlightStyle,
|
|
3081
4541
|
markdownTags,
|
|
3082
4542
|
markdownTagsExtensions,
|
|
3083
4543
|
markdownTheme,
|
|
3084
4544
|
mention,
|
|
3085
4545
|
modelState,
|
|
3086
|
-
|
|
3087
|
-
|
|
4546
|
+
outliner,
|
|
4547
|
+
removeBlockquote,
|
|
4548
|
+
removeCodeblock,
|
|
4549
|
+
removeLink,
|
|
4550
|
+
removeList,
|
|
4551
|
+
removeStyle,
|
|
4552
|
+
setBlockquote,
|
|
4553
|
+
setComments,
|
|
4554
|
+
setHeading,
|
|
3088
4555
|
setSelection,
|
|
4556
|
+
setStyle,
|
|
3089
4557
|
table,
|
|
3090
4558
|
tags2 as tags,
|
|
3091
4559
|
tasklist,
|
|
3092
4560
|
textTheme,
|
|
4561
|
+
toggleBlockquote,
|
|
4562
|
+
toggleCodeblock,
|
|
4563
|
+
toggleEmphasis,
|
|
4564
|
+
toggleInlineCode,
|
|
4565
|
+
toggleList,
|
|
4566
|
+
toggleStrikethrough,
|
|
4567
|
+
toggleStrong,
|
|
4568
|
+
toggleStyle,
|
|
3093
4569
|
typewriter,
|
|
4570
|
+
useActionHandler,
|
|
4571
|
+
useComments,
|
|
4572
|
+
useEditorView,
|
|
4573
|
+
useFormattingState,
|
|
4574
|
+
useInMemoryTextModel,
|
|
4575
|
+
useTextEditor,
|
|
3094
4576
|
useTextModel,
|
|
3095
|
-
|
|
4577
|
+
useToolbarContext
|
|
3096
4578
|
};
|
|
3097
4579
|
//# sourceMappingURL=index.mjs.map
|