@dxos/react-ui-editor 0.3.11-main.008b7c6 → 0.3.11-main.0252f93
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 +1510 -1369
- 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/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +9 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +14 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- 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/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 +37 -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 -8
- 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 +11 -0
- package/dist/types/src/extensions/markdown/formatting.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 +3 -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/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -32
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -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/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.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 +47 -37
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +84 -91
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +131 -95
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +86 -0
- package/src/components/Toolbar/Toolbar.tsx +115 -0
- package/src/extensions/autocomplete.ts +23 -19
- 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/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 +43 -49
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/comments.ts +323 -268
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -8
- package/src/extensions/markdown/bundle.ts +20 -30
- package/src/extensions/markdown/code.ts +142 -0
- package/src/extensions/markdown/formatting.ts +159 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +11 -26
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/image.ts +87 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +87 -86
- package/src/extensions/{table.ts → markdown/table.ts} +10 -4
- 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 +4 -2
- package/src/hooks/useActionHandler.ts +45 -0
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +50 -59
- package/src/index.ts +3 -0
- package/src/styles/markdown.ts +9 -12
- package/src/styles/tokens.ts +3 -0
- package/src/themes/default.ts +50 -79
- 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/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.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 -99
- package/src/extensions/hr.ts +0 -74
- package/src/extensions/image.ts +0 -69
- package/src/extensions/mermaid.ts +0 -11
- package/src/extensions/tasklist.ts +0 -121
- 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
|
@@ -8,55 +8,59 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
9
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
10
|
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
11
|
import { vim } from "@replit/codemirror-vim";
|
|
13
12
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
15
|
-
import {
|
|
13
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
14
|
+
import { log as log2 } from "@dxos/log";
|
|
16
15
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
16
|
+
import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
17
|
+
import { isNotFalsy } from "@dxos/util";
|
|
18
18
|
|
|
19
19
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
21
22
|
import { keymap } from "@codemirror/view";
|
|
22
23
|
var autocomplete = ({ onSearch }) => {
|
|
23
24
|
return [
|
|
24
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
25
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
26
28
|
keymap.of(completionKeymap),
|
|
27
29
|
// https://codemirror.net/examples/autocompletion
|
|
28
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
29
31
|
autocompletion({
|
|
30
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
31
34
|
// defaultKeymap: false,
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
from: match.from,
|
|
44
|
-
options: onSearch(match.text.toLowerCase())
|
|
45
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
46
45
|
}
|
|
47
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
48
51
|
})
|
|
49
52
|
];
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
+
import { invertedEffects } from "@codemirror/commands";
|
|
57
|
+
import { StateField } from "@codemirror/state";
|
|
58
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
59
|
+
import { next as A4 } from "@dxos/automerge/automerge";
|
|
56
60
|
|
|
57
61
|
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
58
62
|
import get from "lodash.get";
|
|
59
|
-
import { next as
|
|
63
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
60
64
|
var cursorConverter = (handle, path) => ({
|
|
61
65
|
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
62
66
|
toCursor: (pos) => {
|
|
@@ -68,7 +72,7 @@ var cursorConverter = (handle, path) => ({
|
|
|
68
72
|
if (typeof value === "string" && value.length <= pos) {
|
|
69
73
|
return "end";
|
|
70
74
|
}
|
|
71
|
-
return
|
|
75
|
+
return A.getCursor(doc, path.slice(), pos);
|
|
72
76
|
},
|
|
73
77
|
fromCursor: (cursor) => {
|
|
74
78
|
if (cursor === "") {
|
|
@@ -86,26 +90,28 @@ var cursorConverter = (handle, path) => ({
|
|
|
86
90
|
return 0;
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
|
-
return
|
|
93
|
+
return A.getCursorPosition(doc, path.slice(), cursor);
|
|
90
94
|
}
|
|
91
95
|
});
|
|
92
96
|
|
|
93
97
|
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
94
98
|
import { Annotation, StateEffect } from "@codemirror/state";
|
|
95
|
-
var
|
|
96
|
-
var
|
|
99
|
+
var getPath = (state, field) => state.field(field).path;
|
|
100
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
101
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
102
|
+
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
97
103
|
newHeads
|
|
98
104
|
});
|
|
99
|
-
var
|
|
100
|
-
var
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
var reconcileAnnotation = Annotation.define();
|
|
106
|
+
var isReconcile = (tr) => {
|
|
107
|
+
return !!tr.annotation(reconcileAnnotation);
|
|
108
|
+
};
|
|
103
109
|
|
|
104
110
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
105
|
-
import { next as
|
|
111
|
+
import { next as A3 } from "@dxos/automerge/automerge";
|
|
106
112
|
|
|
107
113
|
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
108
|
-
import { next as
|
|
114
|
+
import { next as A2 } from "@dxos/automerge/automerge";
|
|
109
115
|
var updateAutomerge = (field, handle, transactions, state) => {
|
|
110
116
|
const { lastHeads, path } = state.field(field);
|
|
111
117
|
let hasChanges = false;
|
|
@@ -118,11 +124,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
|
|
|
118
124
|
return void 0;
|
|
119
125
|
}
|
|
120
126
|
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
127
|
+
const invertedTransactions = [];
|
|
121
128
|
for (const tr of transactions) {
|
|
122
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB,
|
|
123
|
-
|
|
129
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
130
|
+
invertedTransactions.push({
|
|
131
|
+
from: fromA,
|
|
132
|
+
del: toA - fromA,
|
|
133
|
+
insert
|
|
134
|
+
});
|
|
124
135
|
});
|
|
125
136
|
}
|
|
137
|
+
invertedTransactions.reverse().forEach(({ from, del, insert }) => {
|
|
138
|
+
A2.splice(doc, path.slice(), from, del, insert.toString());
|
|
139
|
+
});
|
|
126
140
|
});
|
|
127
141
|
return newHeads ?? void 0;
|
|
128
142
|
};
|
|
@@ -137,13 +151,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
|
|
|
137
151
|
selection = selection.map(changeSet, 1);
|
|
138
152
|
view.dispatch({
|
|
139
153
|
changes: changeSet,
|
|
140
|
-
annotations:
|
|
154
|
+
annotations: reconcileAnnotation.of(false)
|
|
141
155
|
});
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
view.dispatch({
|
|
145
159
|
selection,
|
|
146
|
-
annotations:
|
|
160
|
+
annotations: reconcileAnnotation.of(false)
|
|
147
161
|
});
|
|
148
162
|
};
|
|
149
163
|
var handlePatch = (patch, target, state) => {
|
|
@@ -164,7 +178,7 @@ var handleInsert = (target, patch) => {
|
|
|
164
178
|
if (index == null) {
|
|
165
179
|
return [];
|
|
166
180
|
}
|
|
167
|
-
const text = patch.values.map((
|
|
181
|
+
const text = patch.values.map((value) => value ? value.toString() : "").join("");
|
|
168
182
|
return [
|
|
169
183
|
{
|
|
170
184
|
from: index,
|
|
@@ -236,89 +250,100 @@ var charPath = (textPath, candidatePath) => {
|
|
|
236
250
|
|
|
237
251
|
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
238
252
|
var PatchSemaphore = class {
|
|
239
|
-
|
|
240
|
-
|
|
253
|
+
// prettier-ignore
|
|
254
|
+
constructor(_handle, _state) {
|
|
255
|
+
this._handle = _handle;
|
|
256
|
+
this._state = _state;
|
|
241
257
|
this._inReconcile = false;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
258
|
+
}
|
|
259
|
+
reconcile(view) {
|
|
260
|
+
if (!this._inReconcile) {
|
|
247
261
|
this._inReconcile = true;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
262
|
-
if (newHeads === null || newHeads === void 0) {
|
|
263
|
-
newHeads = automerge2.getHeads(handle.docSync());
|
|
264
|
-
}
|
|
265
|
-
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
|
|
266
|
-
updateCodeMirror(view, selection, path, diff);
|
|
262
|
+
this.doReconcile(view);
|
|
263
|
+
this._inReconcile = false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
doReconcile(view) {
|
|
267
|
+
const path = getPath(view.state, this._state);
|
|
268
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
269
|
+
let selection = view.state.selection;
|
|
270
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
271
|
+
const toInvert = transactions.slice().reverse();
|
|
272
|
+
for (const tr of toInvert) {
|
|
273
|
+
const inverted = tr.changes.invert(tr.startState.doc);
|
|
274
|
+
selection = selection.map(inverted);
|
|
267
275
|
view.dispatch({
|
|
268
|
-
|
|
269
|
-
annotations:
|
|
276
|
+
changes: inverted,
|
|
277
|
+
annotations: reconcileAnnotation.of(true)
|
|
270
278
|
});
|
|
271
|
-
|
|
272
|
-
|
|
279
|
+
}
|
|
280
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
281
|
+
if (newHeads === null || newHeads === void 0) {
|
|
282
|
+
newHeads = A3.getHeads(this._handle.docSync());
|
|
283
|
+
}
|
|
284
|
+
const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
285
|
+
updateCodeMirror(view, selection, path, diff);
|
|
286
|
+
view.dispatch({
|
|
287
|
+
effects: updateHeads(newHeads),
|
|
288
|
+
annotations: reconcileAnnotation.of(false)
|
|
289
|
+
});
|
|
273
290
|
}
|
|
274
291
|
};
|
|
275
292
|
|
|
276
|
-
// packages/ui/react-ui-editor/src/
|
|
293
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
277
294
|
import { Facet } from "@codemirror/state";
|
|
278
|
-
var
|
|
295
|
+
var defaultCursorConverter = {
|
|
279
296
|
toCursor: (position) => position.toString(),
|
|
280
297
|
fromCursor: (cursor) => parseInt(cursor)
|
|
281
298
|
};
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
// packages/ui/react-ui-editor/src/util/util.ts
|
|
287
|
-
import { log } from "@dxos/log";
|
|
288
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
289
|
-
var callbackWrapper = (fn) => (...args) => {
|
|
290
|
-
try {
|
|
291
|
-
return fn(...args);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
log.catch(error, void 0, {
|
|
294
|
-
F: __dxlog_file,
|
|
295
|
-
L: 16,
|
|
296
|
-
S: void 0,
|
|
297
|
-
C: (f, a) => f(...a)
|
|
299
|
+
var Cursor = class _Cursor {
|
|
300
|
+
static {
|
|
301
|
+
this.converter = Facet.define({
|
|
302
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
298
303
|
});
|
|
299
304
|
}
|
|
305
|
+
static {
|
|
306
|
+
this.getCursorFromRange = (state, range) => {
|
|
307
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
308
|
+
const from = cursorConverter2.toCursor(range.from);
|
|
309
|
+
const to = cursorConverter2.toCursor(range.to, -1);
|
|
310
|
+
return [
|
|
311
|
+
from,
|
|
312
|
+
to
|
|
313
|
+
].join(":");
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
static {
|
|
317
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
318
|
+
const cursorConverter2 = state.facet(_Cursor.converter);
|
|
319
|
+
const parts = cursor.split(":");
|
|
320
|
+
const from = cursorConverter2.fromCursor(parts[0]);
|
|
321
|
+
const to = cursorConverter2.fromCursor(parts[1]);
|
|
322
|
+
return from !== void 0 && to !== void 0 ? {
|
|
323
|
+
from,
|
|
324
|
+
to
|
|
325
|
+
} : void 0;
|
|
326
|
+
};
|
|
327
|
+
}
|
|
300
328
|
};
|
|
301
329
|
|
|
302
330
|
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
303
|
-
var
|
|
304
|
-
|
|
305
|
-
});
|
|
306
|
-
var automerge3 = ({ handle, path }) => {
|
|
307
|
-
const stateField = StateField.define({
|
|
331
|
+
var automerge = ({ handle, path }) => {
|
|
332
|
+
const syncState = StateField.define({
|
|
308
333
|
create: () => ({
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
334
|
+
path: path.slice(),
|
|
335
|
+
lastHeads: A4.getHeads(handle.docSync()),
|
|
336
|
+
unreconciledTransactions: []
|
|
312
337
|
}),
|
|
313
338
|
update: (value, tr) => {
|
|
314
339
|
const result = {
|
|
340
|
+
path: path.slice(),
|
|
315
341
|
lastHeads: value.lastHeads,
|
|
316
|
-
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
317
|
-
path: path.slice()
|
|
342
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
318
343
|
};
|
|
319
344
|
let clearUnreconciled = false;
|
|
320
345
|
for (const effect of tr.effects) {
|
|
321
|
-
if (effect.is(
|
|
346
|
+
if (effect.is(updateHeadsEffect)) {
|
|
322
347
|
result.lastHeads = effect.value.newHeads;
|
|
323
348
|
clearUnreconciled = true;
|
|
324
349
|
}
|
|
@@ -326,46 +351,53 @@ var automerge3 = ({ handle, path }) => {
|
|
|
326
351
|
if (clearUnreconciled) {
|
|
327
352
|
result.unreconciledTransactions = [];
|
|
328
353
|
} else {
|
|
329
|
-
if (!
|
|
354
|
+
if (!isReconcile(tr)) {
|
|
330
355
|
result.unreconciledTransactions.push(tr);
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
return result;
|
|
334
359
|
}
|
|
335
360
|
});
|
|
336
|
-
const semaphore = new PatchSemaphore(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
361
|
+
const semaphore = new PatchSemaphore(handle, syncState);
|
|
362
|
+
return [
|
|
363
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
364
|
+
syncState,
|
|
365
|
+
// Reconcile external updates.
|
|
366
|
+
ViewPlugin.fromClass(class {
|
|
367
|
+
constructor(_view) {
|
|
368
|
+
this._view = _view;
|
|
369
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
370
|
+
}
|
|
371
|
+
destroy() {
|
|
372
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
373
|
+
}
|
|
374
|
+
_handleChange() {
|
|
375
|
+
semaphore.reconcile(this._view);
|
|
376
|
+
}
|
|
377
|
+
}),
|
|
378
|
+
// Reconcile local updates.
|
|
379
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
380
|
+
if (!changes.empty) {
|
|
381
|
+
semaphore.reconcile(view);
|
|
382
|
+
}
|
|
383
|
+
}),
|
|
384
|
+
// TODO(burdon): Record undo transactions.
|
|
385
|
+
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
386
|
+
// https://codemirror.net/examples/inverted-effect
|
|
387
|
+
invertedEffects.of((tr) => {
|
|
388
|
+
const effects = [];
|
|
389
|
+
if (!tr.changes.empty) {
|
|
390
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
349
391
|
});
|
|
350
392
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
return {
|
|
357
|
-
extension: [
|
|
358
|
-
CursorConverter.of(cursorConverter(handle, path)),
|
|
359
|
-
semaphoreFacet.of(semaphore),
|
|
360
|
-
stateField,
|
|
361
|
-
viewPlugin
|
|
362
|
-
]
|
|
363
|
-
};
|
|
393
|
+
return effects;
|
|
394
|
+
})
|
|
395
|
+
];
|
|
364
396
|
};
|
|
365
397
|
|
|
366
398
|
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
367
|
-
import { Annotation as Annotation2, Facet as
|
|
368
|
-
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
399
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
400
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
369
401
|
import { Event } from "@dxos/async";
|
|
370
402
|
import { Context } from "@dxos/context";
|
|
371
403
|
var dummyProvider = {
|
|
@@ -374,17 +406,17 @@ var dummyProvider = {
|
|
|
374
406
|
},
|
|
375
407
|
close: () => {
|
|
376
408
|
},
|
|
409
|
+
getRemoteStates: () => [],
|
|
377
410
|
update: () => {
|
|
378
|
-
}
|
|
379
|
-
getRemoteStates: () => []
|
|
411
|
+
}
|
|
380
412
|
};
|
|
381
|
-
var
|
|
413
|
+
var awarenessProvider = Facet2.define({
|
|
382
414
|
combine: (providers) => providers[0] ?? dummyProvider
|
|
383
415
|
});
|
|
384
416
|
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
385
417
|
var awareness = (provider = dummyProvider) => {
|
|
386
418
|
return [
|
|
387
|
-
|
|
419
|
+
awarenessProvider.of(provider),
|
|
388
420
|
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
389
421
|
decorations: (value) => value.decorations
|
|
390
422
|
}),
|
|
@@ -397,8 +429,8 @@ var RemoteSelectionsDecorator = class {
|
|
|
397
429
|
this._ctx = new Context();
|
|
398
430
|
this._lastAnchor = void 0;
|
|
399
431
|
this._lastHead = void 0;
|
|
400
|
-
this._cursorConverter = view.state.facet(
|
|
401
|
-
this._provider = view.state.facet(
|
|
432
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
433
|
+
this._provider = view.state.facet(awarenessProvider);
|
|
402
434
|
this._provider.open();
|
|
403
435
|
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
404
436
|
view.dispatch({
|
|
@@ -412,13 +444,13 @@ var RemoteSelectionsDecorator = class {
|
|
|
412
444
|
void this._ctx.dispose();
|
|
413
445
|
this._provider.close();
|
|
414
446
|
}
|
|
415
|
-
update(
|
|
416
|
-
this._updateLocalSelection(
|
|
417
|
-
this._updateRemoteSelections(
|
|
447
|
+
update(update2) {
|
|
448
|
+
this._updateLocalSelection(update2);
|
|
449
|
+
this._updateRemoteSelections(update2);
|
|
418
450
|
}
|
|
419
|
-
_updateLocalSelection(
|
|
420
|
-
const hasFocus =
|
|
421
|
-
const { anchor = void 0, head = void 0 } = hasFocus ?
|
|
451
|
+
_updateLocalSelection(update2) {
|
|
452
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
453
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
422
454
|
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
423
455
|
return;
|
|
424
456
|
}
|
|
@@ -429,7 +461,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
429
461
|
head: this._cursorConverter.toCursor(head)
|
|
430
462
|
} : void 0);
|
|
431
463
|
}
|
|
432
|
-
_updateRemoteSelections(
|
|
464
|
+
_updateRemoteSelections(update2) {
|
|
433
465
|
const decorations = [];
|
|
434
466
|
const awarenessStates = this._provider.getRemoteStates();
|
|
435
467
|
for (const state of awarenessStates) {
|
|
@@ -438,10 +470,10 @@ var RemoteSelectionsDecorator = class {
|
|
|
438
470
|
if (anchor == null || head == null) {
|
|
439
471
|
continue;
|
|
440
472
|
}
|
|
441
|
-
const start = Math.min(Math.min(anchor, head),
|
|
442
|
-
const end = Math.min(Math.max(anchor, head),
|
|
443
|
-
const startLine =
|
|
444
|
-
const endLine =
|
|
473
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
474
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
475
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
476
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
445
477
|
const color = state.info.color ?? "#30bced";
|
|
446
478
|
const lightColor = state.info.lightColor ?? color + "33";
|
|
447
479
|
if (startLine.number === endLine.number) {
|
|
@@ -452,7 +484,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
452
484
|
attributes: {
|
|
453
485
|
style: `background-color: ${lightColor}`
|
|
454
486
|
},
|
|
455
|
-
class: "cm-
|
|
487
|
+
class: "cm-collab-selection"
|
|
456
488
|
})
|
|
457
489
|
});
|
|
458
490
|
} else {
|
|
@@ -463,7 +495,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
463
495
|
attributes: {
|
|
464
496
|
style: `background-color: ${color}`
|
|
465
497
|
},
|
|
466
|
-
class: "cm-
|
|
498
|
+
class: "cm-collab-selection"
|
|
467
499
|
})
|
|
468
500
|
});
|
|
469
501
|
decorations.push({
|
|
@@ -473,18 +505,18 @@ var RemoteSelectionsDecorator = class {
|
|
|
473
505
|
attributes: {
|
|
474
506
|
style: `background-color: ${color}`
|
|
475
507
|
},
|
|
476
|
-
class: "cm-
|
|
508
|
+
class: "cm-collab-selection"
|
|
477
509
|
})
|
|
478
510
|
});
|
|
479
511
|
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
480
|
-
const linePos =
|
|
512
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
481
513
|
decorations.push({
|
|
482
514
|
from: linePos,
|
|
483
515
|
to: linePos,
|
|
484
516
|
value: Decoration.line({
|
|
485
517
|
attributes: {
|
|
486
518
|
style: `background-color: ${color}`,
|
|
487
|
-
class: "cm-
|
|
519
|
+
class: "cm-collab-selectionLine"
|
|
488
520
|
}
|
|
489
521
|
})
|
|
490
522
|
});
|
|
@@ -504,23 +536,21 @@ var RemoteSelectionsDecorator = class {
|
|
|
504
536
|
}
|
|
505
537
|
};
|
|
506
538
|
var RemoteCaretWidget = class extends WidgetType {
|
|
507
|
-
constructor(
|
|
539
|
+
constructor(_name, _color) {
|
|
508
540
|
super();
|
|
509
|
-
this.
|
|
510
|
-
this.
|
|
511
|
-
this.name = name;
|
|
512
|
-
this.color = color;
|
|
541
|
+
this._name = _name;
|
|
542
|
+
this._color = _color;
|
|
513
543
|
}
|
|
514
544
|
toDOM() {
|
|
515
545
|
const span = document.createElement("span");
|
|
516
|
-
span.className = "cm-
|
|
517
|
-
span.style.backgroundColor = this.
|
|
518
|
-
span.style.borderColor = this.
|
|
546
|
+
span.className = "cm-collab-selectionCaret";
|
|
547
|
+
span.style.backgroundColor = this._color;
|
|
548
|
+
span.style.borderColor = this._color;
|
|
519
549
|
const dot = document.createElement("div");
|
|
520
|
-
dot.className = "cm-
|
|
550
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
521
551
|
const info = document.createElement("div");
|
|
522
|
-
info.className = "cm-
|
|
523
|
-
info.innerText = this.
|
|
552
|
+
info.className = "cm-collab-selectionInfo";
|
|
553
|
+
info.innerText = this._name;
|
|
524
554
|
span.appendChild(document.createTextNode("\u2060"));
|
|
525
555
|
span.appendChild(dot);
|
|
526
556
|
span.appendChild(document.createTextNode("\u2060"));
|
|
@@ -528,15 +558,12 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
528
558
|
span.appendChild(document.createTextNode("\u2060"));
|
|
529
559
|
return span;
|
|
530
560
|
}
|
|
531
|
-
eq(widget) {
|
|
532
|
-
return widget.color === this.color;
|
|
533
|
-
}
|
|
534
|
-
compare(widget) {
|
|
535
|
-
return widget.color === this.color;
|
|
536
|
-
}
|
|
537
561
|
updateDOM() {
|
|
538
562
|
return false;
|
|
539
563
|
}
|
|
564
|
+
eq(widget) {
|
|
565
|
+
return widget._color === this._color;
|
|
566
|
+
}
|
|
540
567
|
get estimatedHeight() {
|
|
541
568
|
return -1;
|
|
542
569
|
}
|
|
@@ -544,58 +571,60 @@ var RemoteCaretWidget = class extends WidgetType {
|
|
|
544
571
|
return true;
|
|
545
572
|
}
|
|
546
573
|
};
|
|
547
|
-
var styles =
|
|
548
|
-
".cm-
|
|
549
|
-
".cm-
|
|
574
|
+
var styles = EditorView2.baseTheme({
|
|
575
|
+
".cm-collab-selection": {},
|
|
576
|
+
".cm-collab-selectionLine": {
|
|
550
577
|
padding: 0,
|
|
551
578
|
margin: "0px 2px 0px 4px"
|
|
552
579
|
},
|
|
553
|
-
".cm-
|
|
580
|
+
".cm-collab-selectionCaret": {
|
|
554
581
|
position: "relative",
|
|
555
582
|
borderLeft: "1px solid black",
|
|
556
583
|
borderRight: "1px solid black",
|
|
557
584
|
marginLeft: "-1px",
|
|
558
585
|
marginRight: "-1px",
|
|
559
586
|
boxSizing: "border-box",
|
|
560
|
-
display: "inline"
|
|
587
|
+
display: "inline",
|
|
588
|
+
cursor: "pointer"
|
|
561
589
|
},
|
|
562
|
-
".cm-
|
|
590
|
+
".cm-collab-selectionCaretDot": {
|
|
563
591
|
borderRadius: "50%",
|
|
564
592
|
position: "absolute",
|
|
565
|
-
width: ".
|
|
566
|
-
height: ".
|
|
567
|
-
top: "-.
|
|
568
|
-
left: "-.
|
|
593
|
+
width: ".5em",
|
|
594
|
+
height: ".5em",
|
|
595
|
+
top: "-.25em",
|
|
596
|
+
left: "-.25em",
|
|
569
597
|
backgroundColor: "inherit",
|
|
570
598
|
transition: "transform .3s ease-in-out",
|
|
571
599
|
boxSizing: "border-box"
|
|
572
600
|
},
|
|
573
|
-
".cm-
|
|
574
|
-
|
|
575
|
-
|
|
601
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
602
|
+
transform: "scale(0)",
|
|
603
|
+
transformOrigin: "center"
|
|
576
604
|
},
|
|
577
|
-
".cm-
|
|
605
|
+
".cm-collab-selectionInfo": {
|
|
578
606
|
position: "absolute",
|
|
579
|
-
|
|
580
|
-
|
|
607
|
+
transform: "translate(-50%, 0)",
|
|
608
|
+
top: "-20px",
|
|
609
|
+
left: 0,
|
|
581
610
|
fontSize: ".75em",
|
|
582
|
-
fontFamily: "serif",
|
|
611
|
+
fontFamily: "sans-serif",
|
|
583
612
|
fontStyle: "normal",
|
|
584
613
|
fontWeight: "normal",
|
|
585
614
|
lineHeight: "normal",
|
|
586
615
|
userSelect: "none",
|
|
587
616
|
color: "white",
|
|
588
|
-
|
|
589
|
-
paddingRight: "2px",
|
|
617
|
+
padding: "2px",
|
|
590
618
|
zIndex: 101,
|
|
591
619
|
transition: "opacity .3s ease-in-out",
|
|
592
620
|
backgroundColor: "inherit",
|
|
593
|
-
|
|
621
|
+
borderRadius: "2px",
|
|
622
|
+
// These should be separate.
|
|
594
623
|
opacity: 0,
|
|
595
624
|
transitionDelay: "0s",
|
|
596
625
|
whiteSpace: "nowrap"
|
|
597
626
|
},
|
|
598
|
-
".cm-
|
|
627
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
599
628
|
opacity: 1,
|
|
600
629
|
transitionDelay: "0s"
|
|
601
630
|
}
|
|
@@ -603,26 +632,28 @@ var styles = EditorView.baseTheme({
|
|
|
603
632
|
|
|
604
633
|
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
605
634
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
635
|
+
import { history } from "@codemirror/commands";
|
|
606
636
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
607
637
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
608
|
-
import { drawSelection, EditorView as
|
|
609
|
-
var basicBundle = ({
|
|
610
|
-
|
|
611
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
638
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
639
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
640
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
612
641
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
613
642
|
bracketMatching(),
|
|
614
643
|
closeBrackets(),
|
|
615
644
|
drawSelection(),
|
|
616
|
-
|
|
617
|
-
|
|
645
|
+
highlightActiveLine(),
|
|
646
|
+
history(),
|
|
647
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
648
|
+
// https://github.com/codemirror/theme-one-dark
|
|
618
649
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
619
|
-
]
|
|
650
|
+
];
|
|
620
651
|
|
|
621
652
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
622
|
-
import { EditorView as
|
|
653
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
623
654
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
624
655
|
import { invariant } from "@dxos/invariant";
|
|
625
|
-
var
|
|
656
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
626
657
|
var defaultOptions = {
|
|
627
658
|
effect: 2,
|
|
628
659
|
maxParticles: 200,
|
|
@@ -655,10 +686,10 @@ var blast = (options = defaultOptions) => {
|
|
|
655
686
|
const getPoint = (view, pos) => {
|
|
656
687
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
657
688
|
const element = document.elementFromPoint(x, y);
|
|
658
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
689
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
659
690
|
const point = {
|
|
660
691
|
x: x - left,
|
|
661
|
-
y: y -
|
|
692
|
+
y: y - top2
|
|
662
693
|
};
|
|
663
694
|
return {
|
|
664
695
|
element,
|
|
@@ -667,12 +698,12 @@ var blast = (options = defaultOptions) => {
|
|
|
667
698
|
};
|
|
668
699
|
return [
|
|
669
700
|
// Cursor moved.
|
|
670
|
-
|
|
671
|
-
if (blaster?.node !==
|
|
701
|
+
EditorView4.updateListener.of((update2) => {
|
|
702
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
703
|
if (blaster) {
|
|
673
704
|
blaster.destroy();
|
|
674
705
|
}
|
|
675
|
-
blaster = new Blaster(
|
|
706
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
676
707
|
particleGravity: 0.2,
|
|
677
708
|
particleShrinkRate: 0.995,
|
|
678
709
|
color: () => [
|
|
@@ -686,10 +717,10 @@ var blast = (options = defaultOptions) => {
|
|
|
686
717
|
} else {
|
|
687
718
|
blaster.resize();
|
|
688
719
|
}
|
|
689
|
-
const current =
|
|
720
|
+
const current = update2.state.selection.main.head;
|
|
690
721
|
if (current !== last) {
|
|
691
722
|
last = current;
|
|
692
|
-
const { element, point } = getPoint(
|
|
723
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
693
724
|
if (element && point) {
|
|
694
725
|
blaster.spawn({
|
|
695
726
|
element,
|
|
@@ -749,7 +780,7 @@ var Blaster = class {
|
|
|
749
780
|
}
|
|
750
781
|
initialize() {
|
|
751
782
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
752
|
-
F:
|
|
783
|
+
F: __dxlog_file,
|
|
753
784
|
L: 138,
|
|
754
785
|
S: this,
|
|
755
786
|
A: [
|
|
@@ -786,7 +817,7 @@ var Blaster = class {
|
|
|
786
817
|
}
|
|
787
818
|
start() {
|
|
788
819
|
invariant(this._canvas && this._ctx, void 0, {
|
|
789
|
-
F:
|
|
820
|
+
F: __dxlog_file,
|
|
790
821
|
L: 177,
|
|
791
822
|
S: this,
|
|
792
823
|
A: [
|
|
@@ -928,10 +959,14 @@ var random = (min, max) => {
|
|
|
928
959
|
return min + ~~(Math.random() * (max - min + 1));
|
|
929
960
|
};
|
|
930
961
|
|
|
931
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
932
|
-
import {
|
|
933
|
-
import
|
|
934
|
-
import {
|
|
962
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
963
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
964
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
965
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
966
|
+
import sortBy from "lodash.sortby";
|
|
967
|
+
import { useEffect } from "react";
|
|
968
|
+
import { debounce } from "@dxos/async";
|
|
969
|
+
import { nonNullable } from "@dxos/util";
|
|
935
970
|
|
|
936
971
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
972
|
import * as random2 from "lib0/random";
|
|
@@ -974,34 +1009,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
974
1009
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
1010
|
import { mx } from "@dxos/react-ui-theme";
|
|
976
1011
|
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);
|
|
1012
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1013
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1014
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1015
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1016
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1017
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1018
|
+
};
|
|
1019
|
+
var heading = (level) => {
|
|
1020
|
+
return headings[level];
|
|
1005
1021
|
};
|
|
1006
1022
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
1023
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1014,158 +1030,114 @@ var inlineUrl = mx(code, "px-1");
|
|
|
1014
1030
|
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1015
1031
|
|
|
1016
1032
|
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1033
|
+
import get2 from "lodash.get";
|
|
1017
1034
|
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1018
1035
|
var tokens = tailwindConfig({}).theme;
|
|
1036
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1019
1037
|
|
|
1020
|
-
// packages/ui/react-ui-editor/src/
|
|
1021
|
-
|
|
1022
|
-
var
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
display: "block",
|
|
1034
|
-
paddingInline: "4px !important"
|
|
1035
|
-
},
|
|
1036
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1037
|
-
paddingTop: "4px !important",
|
|
1038
|
-
borderTopLeftRadius: "4px",
|
|
1039
|
-
borderTopRightRadius: "4px"
|
|
1040
|
-
},
|
|
1041
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1042
|
-
paddingBottom: "4px !important",
|
|
1043
|
-
borderBottomLeftRadius: "4px",
|
|
1044
|
-
borderBottomRightRadius: "4px"
|
|
1038
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1039
|
+
import { log } from "@dxos/log";
|
|
1040
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1041
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1042
|
+
try {
|
|
1043
|
+
return fn(...args);
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
log.catch(err, void 0, {
|
|
1046
|
+
F: __dxlog_file2,
|
|
1047
|
+
L: 18,
|
|
1048
|
+
S: void 0,
|
|
1049
|
+
C: (f, a) => f(...a)
|
|
1050
|
+
});
|
|
1045
1051
|
}
|
|
1046
|
-
});
|
|
1047
|
-
var getLineRange = (lines, from, to) => {
|
|
1048
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1049
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1050
|
-
return [
|
|
1051
|
-
start,
|
|
1052
|
-
end
|
|
1053
|
-
];
|
|
1054
1052
|
};
|
|
1055
|
-
var
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
const text = view.state.doc.sliceString(0);
|
|
1060
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1061
|
-
const blocks = view.viewportLineBlocks;
|
|
1062
|
-
for (const match of matches) {
|
|
1063
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1064
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1065
|
-
const block = blocks[i];
|
|
1066
|
-
decorations.push(Decoration2.line({
|
|
1067
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1068
|
-
}).range(block.from));
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1053
|
+
var logChanges = (trs) => {
|
|
1054
|
+
const changes = trs.flatMap((tr) => {
|
|
1055
|
+
if (tr.changes.empty) {
|
|
1056
|
+
return void 0;
|
|
1071
1057
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
decorations: (value) => value.decorations
|
|
1086
|
-
}),
|
|
1087
|
-
styles2
|
|
1088
|
-
];
|
|
1058
|
+
const changes2 = [];
|
|
1059
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1060
|
+
fromA,
|
|
1061
|
+
toA,
|
|
1062
|
+
fromB,
|
|
1063
|
+
toB,
|
|
1064
|
+
inserted: inserted.toString()
|
|
1065
|
+
})));
|
|
1066
|
+
return changes2;
|
|
1067
|
+
}).filter(Boolean);
|
|
1068
|
+
if (changes.length) {
|
|
1069
|
+
console.log("changes", changes);
|
|
1070
|
+
}
|
|
1089
1071
|
};
|
|
1090
1072
|
|
|
1091
1073
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1092
|
-
|
|
1093
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1094
|
-
import get3 from "lodash.get";
|
|
1095
|
-
import sortBy from "lodash.sortby";
|
|
1096
|
-
import { debounce } from "@dxos/async";
|
|
1097
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1098
|
-
import { log as log2 } from "@dxos/log";
|
|
1099
|
-
import { nonNullable } from "@dxos/util";
|
|
1100
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1101
|
-
var styles3 = EditorView5.baseTheme({
|
|
1102
|
-
"& .cm-bookmark": {
|
|
1103
|
-
cursor: "pointer",
|
|
1104
|
-
margin: "4px",
|
|
1105
|
-
padding: "4px",
|
|
1106
|
-
backgroundColor: "yellow"
|
|
1107
|
-
},
|
|
1108
|
-
"& .cm-bookmark-selected": {
|
|
1109
|
-
backgroundColor: "orange"
|
|
1110
|
-
},
|
|
1074
|
+
var styles2 = EditorView5.baseTheme({
|
|
1111
1075
|
"& .cm-comment": {
|
|
1112
|
-
backgroundColor:
|
|
1076
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1077
|
},
|
|
1114
|
-
"& .cm-comment-
|
|
1115
|
-
backgroundColor:
|
|
1078
|
+
"& .cm-comment-current": {
|
|
1079
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1116
1080
|
}
|
|
1117
1081
|
});
|
|
1118
|
-
var
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1128
|
-
if (!range) {
|
|
1082
|
+
var commentMark = Decoration2.mark({
|
|
1083
|
+
class: "cm-comment"
|
|
1084
|
+
});
|
|
1085
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1086
|
+
class: "cm-comment-current"
|
|
1087
|
+
});
|
|
1088
|
+
var setFocus = (view, id, center = true) => {
|
|
1089
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1090
|
+
if (!comment?.comment.cursor) {
|
|
1129
1091
|
return;
|
|
1130
1092
|
}
|
|
1131
|
-
view.
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1093
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1094
|
+
if (range) {
|
|
1095
|
+
view.dispatch({
|
|
1096
|
+
selection: {
|
|
1097
|
+
anchor: range.from
|
|
1098
|
+
},
|
|
1099
|
+
effects: [
|
|
1100
|
+
//
|
|
1101
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1102
|
+
y: "center"
|
|
1103
|
+
} : void 0),
|
|
1104
|
+
setSelection.of({
|
|
1105
|
+
current: id
|
|
1106
|
+
})
|
|
1107
|
+
]
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1140
1110
|
};
|
|
1141
|
-
var
|
|
1111
|
+
var setComments = StateEffect2.define();
|
|
1142
1112
|
var setSelection = StateEffect2.define();
|
|
1143
1113
|
var setCommentState = StateEffect2.define();
|
|
1144
|
-
var
|
|
1114
|
+
var commentsState = StateField2.define({
|
|
1145
1115
|
create: () => ({
|
|
1146
|
-
|
|
1116
|
+
comments: [],
|
|
1117
|
+
selection: {}
|
|
1147
1118
|
}),
|
|
1148
1119
|
update: (value, tr) => {
|
|
1149
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1150
1120
|
for (const effect of tr.effects) {
|
|
1151
1121
|
if (effect.is(setSelection)) {
|
|
1152
1122
|
return {
|
|
1153
1123
|
...value,
|
|
1154
|
-
|
|
1124
|
+
selection: effect.value
|
|
1155
1125
|
};
|
|
1156
1126
|
}
|
|
1157
|
-
if (effect.is(
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1127
|
+
if (effect.is(setComments)) {
|
|
1128
|
+
const comments2 = effect.value.map((comment) => {
|
|
1129
|
+
if (!comment.cursor) {
|
|
1130
|
+
return void 0;
|
|
1131
|
+
}
|
|
1132
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1161
1133
|
return range && {
|
|
1162
|
-
|
|
1163
|
-
|
|
1134
|
+
comment,
|
|
1135
|
+
range
|
|
1164
1136
|
};
|
|
1165
1137
|
}).filter(nonNullable);
|
|
1166
1138
|
return {
|
|
1167
1139
|
...value,
|
|
1168
|
-
|
|
1140
|
+
comments: comments2
|
|
1169
1141
|
};
|
|
1170
1142
|
}
|
|
1171
1143
|
if (effect.is(setCommentState)) {
|
|
@@ -1175,143 +1147,174 @@ var commentsStateField = StateField2.define({
|
|
|
1175
1147
|
return value;
|
|
1176
1148
|
}
|
|
1177
1149
|
});
|
|
1178
|
-
var
|
|
1179
|
-
|
|
1150
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1151
|
+
commentsState
|
|
1180
1152
|
], (state) => {
|
|
1181
|
-
const {
|
|
1182
|
-
const decorations = sortBy(
|
|
1183
|
-
|
|
1153
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1154
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1155
|
+
const range = comment.range;
|
|
1156
|
+
if (!range || range.from === range.to) {
|
|
1157
|
+
console.warn("Invalid range:", range);
|
|
1184
1158
|
return void 0;
|
|
1185
1159
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
to: selection.to
|
|
1189
|
-
};
|
|
1190
|
-
if (selection.id === active) {
|
|
1191
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1160
|
+
if (comment.comment.id === current) {
|
|
1161
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1192
1162
|
} else {
|
|
1193
|
-
return
|
|
1163
|
+
return commentMark.range(range.from, range.to);
|
|
1194
1164
|
}
|
|
1195
|
-
}).filter(nonNullable)
|
|
1196
|
-
return
|
|
1165
|
+
}).filter(nonNullable);
|
|
1166
|
+
return Decoration2.set(decorations);
|
|
1197
1167
|
});
|
|
1198
|
-
var
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1216
|
-
}
|
|
1217
|
-
toDOM() {
|
|
1218
|
-
const span = document.createElement("span");
|
|
1219
|
-
span.className = "cm-bookmark";
|
|
1220
|
-
span.textContent = "\u203B";
|
|
1221
|
-
if (this._handleClick) {
|
|
1222
|
-
span.onclick = () => this._handleClick();
|
|
1223
|
-
}
|
|
1224
|
-
return span;
|
|
1225
|
-
}
|
|
1226
|
-
};
|
|
1227
|
-
var comments = (options = {}) => {
|
|
1228
|
-
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1229
|
-
const createCommentThread = (view) => {
|
|
1230
|
-
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1231
|
-
invariant2(options.onCreate, void 0, {
|
|
1232
|
-
F: __dxlog_file3,
|
|
1233
|
-
L: 225,
|
|
1234
|
-
S: void 0,
|
|
1235
|
-
A: [
|
|
1236
|
-
"options.onCreate",
|
|
1237
|
-
""
|
|
1238
|
-
]
|
|
1239
|
-
});
|
|
1240
|
-
const { head, from, to } = view.state.selection.main;
|
|
1241
|
-
if (from === to) {
|
|
1242
|
-
return false;
|
|
1168
|
+
var trackPastedComments = (onUpdate) => {
|
|
1169
|
+
let tracked = null;
|
|
1170
|
+
const handleTrack = (event, view) => {
|
|
1171
|
+
const comments2 = view.state.field(commentsState);
|
|
1172
|
+
const { main } = view.state.selection;
|
|
1173
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1174
|
+
if (!selectedRanges.length) {
|
|
1175
|
+
tracked = null;
|
|
1176
|
+
} else {
|
|
1177
|
+
tracked = {
|
|
1178
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1179
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1180
|
+
id: comment.id,
|
|
1181
|
+
from: range.from - main.from,
|
|
1182
|
+
to: range.to - main.from
|
|
1183
|
+
}))
|
|
1184
|
+
};
|
|
1243
1185
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1186
|
+
};
|
|
1187
|
+
return [
|
|
1188
|
+
EditorView5.domEventHandlers({
|
|
1189
|
+
cut: handleTrack,
|
|
1190
|
+
copy: handleTrack
|
|
1191
|
+
}),
|
|
1192
|
+
// Track deleted comments.
|
|
1193
|
+
invertedEffects2.of((tr) => {
|
|
1194
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1195
|
+
const effects = [];
|
|
1196
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1197
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1198
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1199
|
+
effects.push(restoreCommentEffect.of({
|
|
1200
|
+
id,
|
|
1201
|
+
from,
|
|
1202
|
+
to
|
|
1203
|
+
}));
|
|
1257
1204
|
}
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
return effects;
|
|
1208
|
+
}),
|
|
1209
|
+
// Handle paste or the undo of comment deletion.
|
|
1210
|
+
EditorView5.updateListener.of((update2) => {
|
|
1211
|
+
const restore = [];
|
|
1212
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1213
|
+
const tr = update2.transactions[i];
|
|
1214
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1215
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1216
|
+
}
|
|
1217
|
+
for (const effect of tr.effects) {
|
|
1218
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1219
|
+
restore.push(effect.value);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
if (tracked) {
|
|
1224
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1225
|
+
if (paste) {
|
|
1226
|
+
let found = -1;
|
|
1227
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1228
|
+
if (text.eq(tracked.text)) {
|
|
1229
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1230
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1231
|
+
}
|
|
1232
|
+
found = fromB;
|
|
1268
1233
|
}
|
|
1269
1234
|
});
|
|
1235
|
+
if (found > -1) {
|
|
1236
|
+
for (const moved of tracked.comments) {
|
|
1237
|
+
restore.push({
|
|
1238
|
+
id: moved.id,
|
|
1239
|
+
from: found + moved.from,
|
|
1240
|
+
to: found + moved.to
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
tracked = null;
|
|
1270
1245
|
}
|
|
1271
|
-
return true;
|
|
1272
1246
|
}
|
|
1273
|
-
|
|
1247
|
+
for (const comment of restore) {
|
|
1248
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1249
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1250
|
+
if (!exists) {
|
|
1251
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1252
|
+
onUpdate(comment.id, cursor);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
})
|
|
1256
|
+
];
|
|
1257
|
+
};
|
|
1258
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1259
|
+
id: comment.id,
|
|
1260
|
+
from: changes.mapPos(comment.from, 1),
|
|
1261
|
+
to: changes.mapPos(comment.to, 1)
|
|
1262
|
+
});
|
|
1263
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1264
|
+
map: mapTrackedComment
|
|
1265
|
+
});
|
|
1266
|
+
var optionsFacet = Facet3.define({
|
|
1267
|
+
combine: (providers) => providers[0]
|
|
1268
|
+
});
|
|
1269
|
+
var createComment = (view) => {
|
|
1270
|
+
const options = view.state.facet(optionsFacet);
|
|
1271
|
+
const { from, to } = view.state.selection.main;
|
|
1272
|
+
if (from === to) {
|
|
1274
1273
|
return false;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1274
|
+
}
|
|
1275
|
+
if (to === view.state.doc.length) {
|
|
1276
|
+
view.dispatch({
|
|
1277
|
+
changes: {
|
|
1278
|
+
from: to,
|
|
1279
|
+
insert: "\n"
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1284
|
+
from,
|
|
1285
|
+
to
|
|
1286
|
+
});
|
|
1287
|
+
if (cursor) {
|
|
1288
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1289
|
+
if (id) {
|
|
1290
|
+
view.dispatch({
|
|
1291
|
+
effects: setSelection.of({
|
|
1292
|
+
current: id
|
|
1293
|
+
}),
|
|
1294
|
+
selection: {
|
|
1295
|
+
anchor: to
|
|
1288
1296
|
}
|
|
1289
1297
|
});
|
|
1298
|
+
return true;
|
|
1290
1299
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
}, {
|
|
1298
|
-
decorations: (instance) => instance.bookmarks,
|
|
1299
|
-
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1300
|
-
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1301
|
-
})
|
|
1302
|
-
});
|
|
1300
|
+
}
|
|
1301
|
+
return false;
|
|
1302
|
+
};
|
|
1303
|
+
var comments = (options = {}) => {
|
|
1304
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1305
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1303
1306
|
return [
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1307
|
+
optionsFacet.of(options),
|
|
1308
|
+
commentsState,
|
|
1309
|
+
commentsDecorations,
|
|
1310
|
+
styles2,
|
|
1308
1311
|
//
|
|
1309
1312
|
// Keymap.
|
|
1310
1313
|
//
|
|
1311
1314
|
options.onCreate ? keymap3.of([
|
|
1312
1315
|
{
|
|
1313
|
-
key:
|
|
1314
|
-
run: callbackWrapper(
|
|
1316
|
+
key: shortcut,
|
|
1317
|
+
run: callbackWrapper(createComment)
|
|
1315
1318
|
}
|
|
1316
1319
|
]) : [],
|
|
1317
1320
|
//
|
|
@@ -1327,7 +1330,7 @@ var comments = (options = {}) => {
|
|
|
1327
1330
|
above: true,
|
|
1328
1331
|
create: () => {
|
|
1329
1332
|
const el = document.createElement("div");
|
|
1330
|
-
options.onHover
|
|
1333
|
+
options.onHover(el, shortcut);
|
|
1331
1334
|
return {
|
|
1332
1335
|
dom: el,
|
|
1333
1336
|
offset: {
|
|
@@ -1340,372 +1343,127 @@ var comments = (options = {}) => {
|
|
|
1340
1343
|
}
|
|
1341
1344
|
return null;
|
|
1342
1345
|
}, {
|
|
1343
|
-
|
|
1346
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1347
|
+
// hideOnChange: true,
|
|
1344
1348
|
hoverTime: 1e3
|
|
1345
1349
|
}) : [],
|
|
1346
1350
|
//
|
|
1347
|
-
//
|
|
1348
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1351
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1349
1352
|
//
|
|
1350
1353
|
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1351
|
-
|
|
1352
|
-
{
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1360
|
-
log2.info("deleted comment", {
|
|
1361
|
-
thread: range.id
|
|
1362
|
-
}, {
|
|
1363
|
-
F: __dxlog_file3,
|
|
1364
|
-
L: 359,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
if (from <= range.to) {
|
|
1371
|
-
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1372
|
-
Object.assign(range, newRange);
|
|
1373
|
-
mod = true;
|
|
1354
|
+
let mod = false;
|
|
1355
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1356
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1357
|
+
comments2.forEach(({ comment, range }) => {
|
|
1358
|
+
if (from2 === to2) {
|
|
1359
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1360
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1361
|
+
options.onDelete?.(comment.id);
|
|
1374
1362
|
}
|
|
1375
|
-
}
|
|
1363
|
+
}
|
|
1364
|
+
if (from <= range.to) {
|
|
1365
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1366
|
+
Object.assign(range, newRange);
|
|
1367
|
+
mod = true;
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
});
|
|
1371
|
+
if (mod) {
|
|
1372
|
+
view.dispatch({
|
|
1373
|
+
effects: setCommentState.of({
|
|
1374
|
+
comments: comments2,
|
|
1375
|
+
...value
|
|
1376
|
+
})
|
|
1376
1377
|
});
|
|
1377
|
-
if (mod) {
|
|
1378
|
-
view.dispatch({
|
|
1379
|
-
effects: setCommentState.of({
|
|
1380
|
-
active,
|
|
1381
|
-
ranges
|
|
1382
|
-
})
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
1378
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1379
|
+
}),
|
|
1380
|
+
//
|
|
1381
|
+
// Track selection/proximity.
|
|
1382
|
+
//
|
|
1383
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1384
|
+
let min = Infinity;
|
|
1385
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1386
|
+
const { head } = state.selection.main;
|
|
1387
|
+
const selection = {};
|
|
1388
|
+
comments2.forEach(({ comment, range }) => {
|
|
1389
|
+
if (head >= range.from && head <= range.to) {
|
|
1390
|
+
selection.current = comment.id;
|
|
1391
|
+
selection.closest = void 0;
|
|
1392
|
+
}
|
|
1393
|
+
if (!selection.current) {
|
|
1394
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1399
1395
|
if (d < min) {
|
|
1400
|
-
|
|
1396
|
+
selection.closest = comment.id;
|
|
1401
1397
|
min = d;
|
|
1402
1398
|
}
|
|
1403
|
-
});
|
|
1404
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1405
|
-
view.dispatch({
|
|
1406
|
-
effects: setSelection.of(selected)
|
|
1407
|
-
});
|
|
1408
|
-
handleSelect({
|
|
1409
|
-
...selected,
|
|
1410
|
-
ranges: ranges.map((range) => ({
|
|
1411
|
-
...range,
|
|
1412
|
-
location: view.coordsAtPos(range.from)
|
|
1413
|
-
}))
|
|
1414
|
-
});
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
})
|
|
1418
|
-
];
|
|
1419
|
-
};
|
|
1420
|
-
var getCursorFromRange = (cursorConverter3, range) => {
|
|
1421
|
-
const from = cursorConverter3.toCursor(range.from);
|
|
1422
|
-
const to = cursorConverter3.toCursor(range.to, -1);
|
|
1423
|
-
return [
|
|
1424
|
-
from,
|
|
1425
|
-
to
|
|
1426
|
-
].join(":");
|
|
1427
|
-
};
|
|
1428
|
-
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1429
|
-
const parts = cursor.split(":");
|
|
1430
|
-
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1431
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1432
|
-
return from && to ? {
|
|
1433
|
-
from,
|
|
1434
|
-
to
|
|
1435
|
-
} : void 0;
|
|
1436
|
-
};
|
|
1437
|
-
|
|
1438
|
-
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1439
|
-
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1440
|
-
import get4 from "lodash.get";
|
|
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 ${get4(tokens, "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(update4) {
|
|
1475
|
-
this.rules = placeholderMatcher.updateDeco(update4, 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 { RangeSetBuilder, 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) => update(state, options),
|
|
1493
|
-
update: (_, tr) => update(tr.state, options),
|
|
1494
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1495
|
-
});
|
|
1496
|
-
};
|
|
1497
|
-
var update = (state, options) => {
|
|
1498
|
-
const builder = new RangeSetBuilder();
|
|
1499
|
-
const cursor = state.selection.main.head;
|
|
1500
|
-
syntaxTree(state).iterate({
|
|
1501
|
-
enter: (node) => {
|
|
1502
|
-
if (node.name === "Image") {
|
|
1503
|
-
const urlNode = node.node.getChild("URL");
|
|
1504
|
-
if (urlNode) {
|
|
1505
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1506
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1507
|
-
builder.add(hide ? node.from : node.to, node.to, Decoration5.replace({
|
|
1508
|
-
block: true,
|
|
1509
|
-
widget: new ImageWidget(url)
|
|
1510
|
-
}));
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
});
|
|
1515
|
-
return builder.finish();
|
|
1516
|
-
};
|
|
1517
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1518
|
-
constructor(_url) {
|
|
1519
|
-
super();
|
|
1520
|
-
this._url = _url;
|
|
1521
|
-
}
|
|
1522
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1523
|
-
eq(other) {
|
|
1524
|
-
return this._url === other._url;
|
|
1525
|
-
}
|
|
1526
|
-
toDOM(view) {
|
|
1527
|
-
const img = document.createElement("img");
|
|
1528
|
-
img.setAttribute("src", this._url);
|
|
1529
|
-
img.setAttribute("class", "cm-image");
|
|
1530
|
-
return img;
|
|
1531
|
-
}
|
|
1532
|
-
};
|
|
1533
|
-
|
|
1534
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1535
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1536
|
-
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
|
|
1537
|
-
import { Decoration as Decoration6, EditorView as EditorView8, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2 } from "@codemirror/view";
|
|
1538
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1539
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1540
|
-
var link = (options = {}) => {
|
|
1541
|
-
const extensions = [
|
|
1542
|
-
StateField4.define({
|
|
1543
|
-
create: (state) => update2(state, options),
|
|
1544
|
-
update: (_, tr) => update2(tr.state, options),
|
|
1545
|
-
provide: (field) => EditorView8.decorations.from(field)
|
|
1546
|
-
})
|
|
1547
|
-
];
|
|
1548
|
-
if (options.onHover) {
|
|
1549
|
-
extensions.push(
|
|
1550
|
-
// https://codemirror.net/examples/tooltip
|
|
1551
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1552
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1553
|
-
hoverTooltip2((view, pos) => {
|
|
1554
|
-
const { from, text } = view.state.doc.lineAt(pos);
|
|
1555
|
-
const p = pos - from;
|
|
1556
|
-
let idx = 0;
|
|
1557
|
-
let match;
|
|
1558
|
-
do {
|
|
1559
|
-
match = text.substring(idx).match(markdownLinkRegexp);
|
|
1560
|
-
if (!match) {
|
|
1561
|
-
match = void 0;
|
|
1562
|
-
break;
|
|
1563
|
-
}
|
|
1564
|
-
idx = text.indexOf(match[0]);
|
|
1565
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1566
|
-
break;
|
|
1567
|
-
}
|
|
1568
|
-
idx += match[0].length;
|
|
1569
|
-
} while (true);
|
|
1570
|
-
if (!match) {
|
|
1571
|
-
return null;
|
|
1572
1399
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
pos: idx + from,
|
|
1576
|
-
end: idx + from + match[0].length,
|
|
1577
|
-
above: true,
|
|
1578
|
-
create: () => {
|
|
1579
|
-
const el = document.createElement("div");
|
|
1580
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1581
|
-
options.onHover(el, url);
|
|
1582
|
-
return {
|
|
1583
|
-
dom: el,
|
|
1584
|
-
offset: {
|
|
1585
|
-
x: 0,
|
|
1586
|
-
y: 4
|
|
1587
|
-
}
|
|
1588
|
-
};
|
|
1589
|
-
}
|
|
1590
|
-
};
|
|
1591
|
-
})
|
|
1592
|
-
);
|
|
1593
|
-
}
|
|
1594
|
-
return extensions;
|
|
1595
|
-
};
|
|
1596
|
-
var LinkButton = class extends WidgetType5 {
|
|
1597
|
-
constructor(_pos, _url, _onAttach) {
|
|
1598
|
-
super();
|
|
1599
|
-
this._pos = _pos;
|
|
1600
|
-
this._url = _url;
|
|
1601
|
-
this._onAttach = _onAttach;
|
|
1602
|
-
}
|
|
1603
|
-
eq(other) {
|
|
1604
|
-
return this._pos === other._pos && this._url === other._url;
|
|
1605
|
-
}
|
|
1606
|
-
toDOM(view) {
|
|
1607
|
-
const el = document.createElement("span");
|
|
1608
|
-
this._onAttach(el, this._url);
|
|
1609
|
-
return el;
|
|
1610
|
-
}
|
|
1611
|
-
};
|
|
1612
|
-
var LinkText = class extends WidgetType5 {
|
|
1613
|
-
constructor(_text, _url) {
|
|
1614
|
-
super();
|
|
1615
|
-
this._text = _text;
|
|
1616
|
-
this._url = _url;
|
|
1617
|
-
}
|
|
1618
|
-
eq(other) {
|
|
1619
|
-
return this._url === other._url;
|
|
1620
|
-
}
|
|
1621
|
-
toDOM(view) {
|
|
1622
|
-
const link2 = document.createElement("a");
|
|
1623
|
-
link2.setAttribute("class", "cm-link");
|
|
1624
|
-
link2.textContent = this._text;
|
|
1625
|
-
if (this._url) {
|
|
1626
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1627
|
-
link2.setAttribute("target", "_blank");
|
|
1628
|
-
link2.href = this._url;
|
|
1629
|
-
} else {
|
|
1630
|
-
link2.onclick = () => {
|
|
1400
|
+
});
|
|
1401
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1631
1402
|
view.dispatch({
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1403
|
+
effects: setSelection.of(selection)
|
|
1404
|
+
});
|
|
1405
|
+
handleSelect({
|
|
1406
|
+
selection,
|
|
1407
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1408
|
+
comment,
|
|
1409
|
+
range,
|
|
1410
|
+
location: view.coordsAtPos(range.from)
|
|
1411
|
+
}))
|
|
1635
1412
|
});
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
return link2;
|
|
1639
|
-
}
|
|
1640
|
-
};
|
|
1641
|
-
var update2 = (state, options) => {
|
|
1642
|
-
const builder = new RangeSetBuilder2();
|
|
1643
|
-
const cursor = state.selection.main.head;
|
|
1644
|
-
syntaxTree2(state).iterate({
|
|
1645
|
-
enter: (node) => {
|
|
1646
|
-
if (node.name === "Link") {
|
|
1647
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1648
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1649
|
-
const urlNode = node.node.getChild("URL");
|
|
1650
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1651
|
-
if (!url) {
|
|
1652
|
-
return false;
|
|
1653
|
-
}
|
|
1654
|
-
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1655
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1656
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1657
|
-
}));
|
|
1658
|
-
}
|
|
1659
|
-
if (options.onRender) {
|
|
1660
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1661
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1662
|
-
}));
|
|
1663
|
-
}
|
|
1664
|
-
return false;
|
|
1665
1413
|
}
|
|
1414
|
+
}),
|
|
1415
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1416
|
+
];
|
|
1417
|
+
};
|
|
1418
|
+
var useComments = (view, comments2 = []) => {
|
|
1419
|
+
useEffect(() => {
|
|
1420
|
+
if (view) {
|
|
1421
|
+
view.dispatch({
|
|
1422
|
+
effects: setComments.of(comments2)
|
|
1423
|
+
});
|
|
1666
1424
|
}
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1425
|
+
}, [
|
|
1426
|
+
view,
|
|
1427
|
+
comments2
|
|
1428
|
+
]);
|
|
1669
1429
|
};
|
|
1670
1430
|
|
|
1671
1431
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1672
|
-
import { EditorView as
|
|
1432
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1673
1433
|
var listener = ({ onFocus, onChange }) => {
|
|
1674
1434
|
const extensions = [];
|
|
1675
|
-
onFocus && extensions.push(
|
|
1435
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1676
1436
|
onFocus(focused);
|
|
1677
1437
|
return null;
|
|
1678
1438
|
}));
|
|
1679
|
-
onChange && extensions.push(
|
|
1680
|
-
onChange(
|
|
1439
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1440
|
+
onChange(update2.state.doc.toString());
|
|
1681
1441
|
}));
|
|
1682
1442
|
return extensions;
|
|
1683
1443
|
};
|
|
1684
1444
|
|
|
1685
1445
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1686
1446
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1687
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1688
|
-
import { markdownLanguage as
|
|
1447
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1448
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1689
1449
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1690
1450
|
import { languages } from "@codemirror/language-data";
|
|
1691
1451
|
import { searchKeymap } from "@codemirror/search";
|
|
1692
1452
|
import { EditorState } from "@codemirror/state";
|
|
1693
1453
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1694
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1454
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1695
1455
|
|
|
1696
1456
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1697
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1457
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1698
1458
|
import { HighlightStyle } from "@codemirror/language";
|
|
1699
1459
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1700
1460
|
import { Table } from "@lezer/markdown";
|
|
1701
|
-
import get5 from "lodash.get";
|
|
1702
1461
|
var markdownTags = {
|
|
1703
1462
|
Blockquote: Tag.define(),
|
|
1704
1463
|
CodeMark: Tag.define(),
|
|
1705
1464
|
CodeText: Tag.define(),
|
|
1706
1465
|
EmphasisMark: Tag.define(),
|
|
1707
1466
|
HeaderMark: Tag.define(),
|
|
1708
|
-
// HorizontalRule: Tag.define(),
|
|
1709
1467
|
InlineCode: Tag.define(),
|
|
1710
1468
|
LinkLabel: Tag.define(),
|
|
1711
1469
|
LinkReference: Tag.define(),
|
|
@@ -1790,7 +1548,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1790
1548
|
markdownTags.QuoteMark,
|
|
1791
1549
|
markdownTags.EmphasisMark
|
|
1792
1550
|
],
|
|
1793
|
-
class:
|
|
1551
|
+
class: mark
|
|
1794
1552
|
},
|
|
1795
1553
|
// E.g., code block language (after ```).
|
|
1796
1554
|
{
|
|
@@ -1798,7 +1556,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1798
1556
|
tags.function(tags.variableName),
|
|
1799
1557
|
tags.labelName
|
|
1800
1558
|
],
|
|
1801
|
-
class:
|
|
1559
|
+
class: codeMark
|
|
1802
1560
|
},
|
|
1803
1561
|
{
|
|
1804
1562
|
tag: [
|
|
@@ -1809,27 +1567,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1809
1567
|
// Headings.
|
|
1810
1568
|
{
|
|
1811
1569
|
tag: tags.heading1,
|
|
1812
|
-
class: heading(1
|
|
1570
|
+
class: heading(1)
|
|
1813
1571
|
},
|
|
1814
1572
|
{
|
|
1815
1573
|
tag: tags.heading2,
|
|
1816
|
-
class: heading(2
|
|
1574
|
+
class: heading(2)
|
|
1817
1575
|
},
|
|
1818
1576
|
{
|
|
1819
1577
|
tag: tags.heading3,
|
|
1820
|
-
class: heading(3
|
|
1578
|
+
class: heading(3)
|
|
1821
1579
|
},
|
|
1822
1580
|
{
|
|
1823
1581
|
tag: tags.heading4,
|
|
1824
|
-
class: heading(4
|
|
1582
|
+
class: heading(4)
|
|
1825
1583
|
},
|
|
1826
1584
|
{
|
|
1827
1585
|
tag: tags.heading5,
|
|
1828
|
-
class: heading(5
|
|
1586
|
+
class: heading(5)
|
|
1829
1587
|
},
|
|
1830
1588
|
{
|
|
1831
1589
|
tag: tags.heading6,
|
|
1832
|
-
class: heading(6
|
|
1590
|
+
class: heading(6)
|
|
1833
1591
|
},
|
|
1834
1592
|
// Emphasis.
|
|
1835
1593
|
{
|
|
@@ -1855,7 +1613,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1855
1613
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1856
1614
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1857
1615
|
// the code, but all other CSS properties will be inherited.
|
|
1858
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1616
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1859
1617
|
{
|
|
1860
1618
|
tag: [
|
|
1861
1619
|
markdownTags.CodeText,
|
|
@@ -1869,12 +1627,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1869
1627
|
],
|
|
1870
1628
|
class: blockquote
|
|
1871
1629
|
},
|
|
1872
|
-
// TODO(burdon): Replace with extension.
|
|
1873
|
-
// {
|
|
1874
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1875
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1876
|
-
// },
|
|
1877
|
-
// TODO(burdon): Only if being edited.
|
|
1878
1630
|
{
|
|
1879
1631
|
tag: [
|
|
1880
1632
|
markdownTags.TableCell
|
|
@@ -1882,29 +1634,29 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1882
1634
|
class: "font-mono"
|
|
1883
1635
|
}
|
|
1884
1636
|
], {
|
|
1885
|
-
scope:
|
|
1637
|
+
scope: markdownLanguage2,
|
|
1886
1638
|
all: {
|
|
1887
|
-
fontFamily:
|
|
1639
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1888
1640
|
}
|
|
1889
1641
|
});
|
|
1890
1642
|
};
|
|
1891
1643
|
|
|
1892
1644
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1893
|
-
var markdownBundle = ({
|
|
1645
|
+
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1894
1646
|
return [
|
|
1895
1647
|
EditorState.allowMultipleSelections.of(true),
|
|
1896
1648
|
EditorState.tabSize.of(2),
|
|
1897
|
-
|
|
1898
|
-
|
|
1649
|
+
EditorView7.lineWrapping,
|
|
1650
|
+
// https://github.com/codemirror/basic-setup
|
|
1899
1651
|
bracketMatching2(),
|
|
1900
1652
|
closeBrackets2(),
|
|
1901
1653
|
crosshairCursor(),
|
|
1902
1654
|
dropCursor(),
|
|
1903
1655
|
drawSelection2(),
|
|
1904
|
-
|
|
1905
|
-
|
|
1656
|
+
highlightActiveLine2(),
|
|
1657
|
+
history2(),
|
|
1906
1658
|
indentOnInput(),
|
|
1907
|
-
_placeholder
|
|
1659
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1908
1660
|
// Main extension.
|
|
1909
1661
|
// https://github.com/codemirror/lang-markdown
|
|
1910
1662
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1914,7 +1666,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1914
1666
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1915
1667
|
// https://github.github.com/gfm
|
|
1916
1668
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1917
|
-
base:
|
|
1669
|
+
base: markdownLanguage3,
|
|
1918
1670
|
// Languages for syntax highlighting fenced code blocks.
|
|
1919
1671
|
codeLanguages: languages,
|
|
1920
1672
|
// Parser extensions.
|
|
@@ -1926,63 +1678,575 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1926
1678
|
// https://github.com/codemirror/theme-one-dark
|
|
1927
1679
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1928
1680
|
// Custom styles.
|
|
1929
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1681
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1682
|
+
keymap4.of([
|
|
1683
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1684
|
+
indentWithTab,
|
|
1685
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1686
|
+
...closeBracketsKeymap,
|
|
1687
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1688
|
+
...historyKeymap,
|
|
1689
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1690
|
+
...searchKeymap,
|
|
1691
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1692
|
+
...standardKeymap
|
|
1693
|
+
])
|
|
1694
|
+
];
|
|
1695
|
+
};
|
|
1944
1696
|
|
|
1945
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1946
|
-
import {
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1697
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1698
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1699
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1700
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1701
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1702
|
+
var styles3 = EditorView8.baseTheme({
|
|
1703
|
+
"& .cm-code": {
|
|
1704
|
+
paddingInline: "1rem !important",
|
|
1705
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1706
|
+
},
|
|
1707
|
+
"& .cm-codeblock": {
|
|
1708
|
+
display: "inline-block",
|
|
1709
|
+
width: "100%",
|
|
1710
|
+
position: "relative",
|
|
1711
|
+
"&::after": {
|
|
1712
|
+
content: '""',
|
|
1713
|
+
position: "absolute",
|
|
1714
|
+
inset: 0
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
"&light .cm-codeblock": {
|
|
1718
|
+
"&::after": {
|
|
1719
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1720
|
+
mixBlendMode: "darken"
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
"&dark .cm-codeblock": {
|
|
1724
|
+
"&::after": {
|
|
1725
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1726
|
+
mixBlendMode: "lighten"
|
|
1727
|
+
}
|
|
1728
|
+
},
|
|
1729
|
+
"& .cm-codeblock-first": {
|
|
1730
|
+
"&::after": {
|
|
1731
|
+
borderTopLeftRadius: ".5rem",
|
|
1732
|
+
borderTopRightRadius: ".5rem"
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
"& .cm-codeblock-last": {
|
|
1736
|
+
"&::after": {
|
|
1737
|
+
borderBottomLeftRadius: ".5rem",
|
|
1738
|
+
borderBottomRightRadius: ".5rem"
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
var getLineRange = (lines, from, to) => {
|
|
1743
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1744
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1745
|
+
return [
|
|
1746
|
+
start,
|
|
1747
|
+
end
|
|
1748
|
+
];
|
|
1749
|
+
};
|
|
1750
|
+
var LineWidget = class extends WidgetType2 {
|
|
1751
|
+
constructor(_className) {
|
|
1752
|
+
super();
|
|
1753
|
+
this._className = _className;
|
|
1754
|
+
}
|
|
1755
|
+
toDOM() {
|
|
1756
|
+
const el = document.createElement("span");
|
|
1757
|
+
el.innerHTML = " ";
|
|
1758
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1759
|
+
return el;
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1763
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1764
|
+
var buildDecorations = (view) => {
|
|
1765
|
+
const builder = new RangeSetBuilder();
|
|
1766
|
+
const { state } = view;
|
|
1767
|
+
const blocks = view.viewportLineBlocks;
|
|
1768
|
+
const cursor = state.selection.main.head;
|
|
1769
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1770
|
+
syntaxTree(state).iterate({
|
|
1771
|
+
enter: (node) => {
|
|
1772
|
+
if (node.name === "FencedCode") {
|
|
1773
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1774
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1775
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1776
|
+
const block = blocks[i];
|
|
1777
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1778
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1779
|
+
widget: i === range[0] ? top : bottom
|
|
1780
|
+
}));
|
|
1781
|
+
} else {
|
|
1782
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1783
|
+
class: mx2("cm-code cm-codeblock")
|
|
1784
|
+
}));
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1789
|
+
from,
|
|
1790
|
+
to
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
return builder.finish();
|
|
1794
|
+
};
|
|
1795
|
+
var code2 = () => {
|
|
1796
|
+
return [
|
|
1797
|
+
ViewPlugin3.fromClass(class {
|
|
1798
|
+
constructor(view) {
|
|
1799
|
+
this.decorations = buildDecorations(view);
|
|
1800
|
+
}
|
|
1801
|
+
update(update2) {
|
|
1802
|
+
this.decorations = buildDecorations(update2.view);
|
|
1803
|
+
}
|
|
1804
|
+
}, {
|
|
1805
|
+
decorations: (value) => value.decorations
|
|
1806
|
+
}),
|
|
1807
|
+
styles3
|
|
1808
|
+
];
|
|
1809
|
+
};
|
|
1810
|
+
|
|
1811
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1812
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1813
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1814
|
+
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1815
|
+
var setHeading = (level) => (view) => {
|
|
1816
|
+
const { selection: { ranges }, doc } = view.state;
|
|
1817
|
+
const changes = [];
|
|
1818
|
+
for (const range of ranges) {
|
|
1819
|
+
const { number } = doc.lineAt(range.anchor);
|
|
1820
|
+
const { from } = doc.line(number);
|
|
1821
|
+
const line = doc.sliceString(from, from + 7);
|
|
1822
|
+
const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
|
|
1823
|
+
const current = marks?.length ?? 0;
|
|
1824
|
+
if (level !== current) {
|
|
1825
|
+
changes.push({
|
|
1826
|
+
from,
|
|
1827
|
+
to: from + current + (spaces?.length ?? 0),
|
|
1828
|
+
insert: "#".repeat(level) + (level > 0 ? " " : "")
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
if (changes.length) {
|
|
1833
|
+
view.dispatch({
|
|
1834
|
+
changes
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
return true;
|
|
1838
|
+
};
|
|
1839
|
+
var toggleStyle = (mark2) => (view) => {
|
|
1840
|
+
const { ranges } = view.state.selection;
|
|
1841
|
+
for (const range of ranges) {
|
|
1842
|
+
if (range.from === range.to) {
|
|
1843
|
+
return false;
|
|
1844
|
+
}
|
|
1845
|
+
view.dispatch({
|
|
1846
|
+
changes: [
|
|
1847
|
+
{
|
|
1848
|
+
from: range.from,
|
|
1849
|
+
insert: mark2
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
from: range.to,
|
|
1853
|
+
insert: mark2
|
|
1854
|
+
}
|
|
1855
|
+
]
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
return true;
|
|
1859
|
+
};
|
|
1860
|
+
var toggleBold = toggleStyle("**");
|
|
1861
|
+
var toggleItalic = toggleStyle("_");
|
|
1862
|
+
var toggleStrikethrough = toggleStyle("~~");
|
|
1863
|
+
var toggleList = (view) => {
|
|
1864
|
+
};
|
|
1865
|
+
var formatting = (options = {}) => {
|
|
1866
|
+
return [
|
|
1867
|
+
keymap5.of([
|
|
1868
|
+
{
|
|
1869
|
+
key: "meta-b",
|
|
1870
|
+
run: toggleBold
|
|
1871
|
+
}
|
|
1872
|
+
]),
|
|
1873
|
+
styling()
|
|
1874
|
+
];
|
|
1875
|
+
};
|
|
1876
|
+
var styling = () => {
|
|
1877
|
+
const buildDecorations7 = (view) => {
|
|
1878
|
+
const builder = new RangeSetBuilder2();
|
|
1879
|
+
const { state } = view;
|
|
1880
|
+
const cursor = state.selection.main.head;
|
|
1881
|
+
const replace = (node, marks) => {
|
|
1882
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1883
|
+
for (const mark2 of marks) {
|
|
1884
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1889
|
+
syntaxTree2(state).iterate({
|
|
1890
|
+
enter: (node) => {
|
|
1891
|
+
switch (node.name) {
|
|
1892
|
+
case "Emphasis":
|
|
1893
|
+
case "StrongEmphasis": {
|
|
1894
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
1895
|
+
replace(node, marks);
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
case "Strikethrough": {
|
|
1899
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
1900
|
+
replace(node, marks);
|
|
1901
|
+
break;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
},
|
|
1905
|
+
from,
|
|
1906
|
+
to
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
return builder.finish();
|
|
1910
|
+
};
|
|
1911
|
+
return [
|
|
1912
|
+
ViewPlugin4.fromClass(class {
|
|
1913
|
+
constructor(view) {
|
|
1914
|
+
this.decorations = buildDecorations7(view);
|
|
1915
|
+
}
|
|
1916
|
+
update(update2) {
|
|
1917
|
+
this.decorations = buildDecorations7(update2.view);
|
|
1918
|
+
}
|
|
1919
|
+
}, {
|
|
1920
|
+
decorations: (value) => value.decorations
|
|
1921
|
+
})
|
|
1922
|
+
];
|
|
1923
|
+
};
|
|
1924
|
+
|
|
1925
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1926
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1927
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1928
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1929
|
+
var buildDecorations2 = (view) => {
|
|
1930
|
+
const builder = new RangeSetBuilder3();
|
|
1931
|
+
const { state } = view;
|
|
1932
|
+
const cursor = state.selection.main.head;
|
|
1933
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1934
|
+
syntaxTree3(state).iterate({
|
|
1935
|
+
enter: (node) => {
|
|
1936
|
+
switch (node.name) {
|
|
1937
|
+
case "ATXHeading1":
|
|
1938
|
+
case "ATXHeading2":
|
|
1939
|
+
case "ATXHeading3":
|
|
1940
|
+
case "ATXHeading4":
|
|
1941
|
+
case "ATXHeading5":
|
|
1942
|
+
case "ATXHeading6": {
|
|
1943
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1944
|
+
if (mark2) {
|
|
1945
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1946
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1952
|
+
from,
|
|
1953
|
+
to
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
return builder.finish();
|
|
1957
|
+
};
|
|
1958
|
+
var heading2 = () => {
|
|
1959
|
+
return [
|
|
1960
|
+
ViewPlugin5.fromClass(class {
|
|
1961
|
+
constructor(view) {
|
|
1962
|
+
this.decorations = buildDecorations2(view);
|
|
1963
|
+
}
|
|
1964
|
+
update(update2) {
|
|
1965
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1966
|
+
}
|
|
1967
|
+
}, {
|
|
1968
|
+
decorations: (value) => value.decorations
|
|
1969
|
+
})
|
|
1970
|
+
];
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
1974
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
1975
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
1976
|
+
import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1977
|
+
var styles4 = EditorView9.baseTheme({
|
|
1978
|
+
"& .cm-hr": {
|
|
1979
|
+
// Note that block-level decorations should not have vertical margins,
|
|
1980
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1984
|
+
toDOM() {
|
|
1985
|
+
const el = document.createElement("div");
|
|
1986
|
+
el.className = "cm-hr";
|
|
1987
|
+
return el;
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1990
|
+
var decoration = Decoration6.replace({
|
|
1991
|
+
widget: new HorizontalRuleWidget()
|
|
1992
|
+
});
|
|
1993
|
+
var buildDecorations3 = (view) => {
|
|
1994
|
+
const builder = new RangeSetBuilder4();
|
|
1995
|
+
const { state } = view;
|
|
1996
|
+
const cursor = state.selection.main.head;
|
|
1997
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1998
|
+
syntaxTree4(state).iterate({
|
|
1999
|
+
enter: (node) => {
|
|
2000
|
+
if (node.name === "HorizontalRule") {
|
|
2001
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2002
|
+
builder.add(node.from, node.to, decoration);
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
from,
|
|
2007
|
+
to
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
return builder.finish();
|
|
2011
|
+
};
|
|
2012
|
+
var hr = () => {
|
|
2013
|
+
return [
|
|
2014
|
+
ViewPlugin6.fromClass(class {
|
|
2015
|
+
constructor(view) {
|
|
2016
|
+
this.decorations = buildDecorations3(view);
|
|
2017
|
+
}
|
|
2018
|
+
update(update2) {
|
|
2019
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2020
|
+
}
|
|
2021
|
+
}, {
|
|
2022
|
+
decorations: (value) => value.decorations
|
|
2023
|
+
}),
|
|
2024
|
+
styles4
|
|
2025
|
+
];
|
|
2026
|
+
};
|
|
2027
|
+
|
|
2028
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2029
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2030
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
2031
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2032
|
+
var image = (options = {}) => {
|
|
2033
|
+
return StateField3.define({
|
|
2034
|
+
create: (state) => {
|
|
2035
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
2036
|
+
},
|
|
2037
|
+
update: (value, tr) => {
|
|
2038
|
+
if (!tr.docChanged && !tr.selection) {
|
|
2039
|
+
return value;
|
|
2040
|
+
}
|
|
2041
|
+
const cursor = tr.state.selection.main.head;
|
|
2042
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
2043
|
+
let from = Math.min(cursor, oldCursor);
|
|
2044
|
+
let to = Math.max(cursor, oldCursor);
|
|
2045
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
2046
|
+
from = Math.min(from, fromB);
|
|
2047
|
+
to = Math.max(to, toB);
|
|
2048
|
+
});
|
|
2049
|
+
from = tr.state.doc.lineAt(from).from;
|
|
2050
|
+
to = tr.state.doc.lineAt(to).to;
|
|
2051
|
+
return value.map(tr.changes).update({
|
|
2052
|
+
filterFrom: from,
|
|
2053
|
+
filterTo: to,
|
|
2054
|
+
filter: () => false,
|
|
2055
|
+
add: buildDecorations4(from, to, tr.state)
|
|
2056
|
+
});
|
|
2057
|
+
},
|
|
2058
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
2059
|
+
});
|
|
2060
|
+
};
|
|
2061
|
+
var buildDecorations4 = (from, to, state) => {
|
|
2062
|
+
const decorations = [];
|
|
2063
|
+
const cursor = state.selection.main.head;
|
|
2064
|
+
syntaxTree5(state).iterate({
|
|
2065
|
+
enter: (node) => {
|
|
2066
|
+
if (node.name === "Image") {
|
|
2067
|
+
const urlNode = node.node.getChild("URL");
|
|
2068
|
+
if (urlNode) {
|
|
2069
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
2070
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2071
|
+
decorations.push(Decoration7.replace({
|
|
2072
|
+
block: true,
|
|
2073
|
+
widget: new ImageWidget(url)
|
|
2074
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
},
|
|
2078
|
+
from,
|
|
2079
|
+
to
|
|
2080
|
+
});
|
|
2081
|
+
return decorations;
|
|
2082
|
+
};
|
|
2083
|
+
var ImageWidget = class extends WidgetType4 {
|
|
2084
|
+
constructor(_url) {
|
|
2085
|
+
super();
|
|
2086
|
+
this._url = _url;
|
|
2087
|
+
}
|
|
2088
|
+
eq(other) {
|
|
2089
|
+
return this._url === other._url;
|
|
2090
|
+
}
|
|
2091
|
+
toDOM(view) {
|
|
2092
|
+
const img = document.createElement("img");
|
|
2093
|
+
img.setAttribute("src", this._url);
|
|
2094
|
+
img.setAttribute("class", "cm-image");
|
|
2095
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
2096
|
+
return img;
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
|
|
2100
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
2101
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2102
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
2103
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
2104
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
2105
|
+
var link = (options = {}) => {
|
|
2106
|
+
const extensions = [
|
|
2107
|
+
ViewPlugin7.fromClass(class {
|
|
2108
|
+
constructor(view) {
|
|
2109
|
+
this.decorations = buildDecorations5(view, options);
|
|
2110
|
+
}
|
|
2111
|
+
update(update2) {
|
|
2112
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2113
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}, {
|
|
2117
|
+
decorations: (value) => value.decorations
|
|
2118
|
+
})
|
|
2119
|
+
];
|
|
2120
|
+
if (options.onHover) {
|
|
2121
|
+
extensions.push(
|
|
2122
|
+
// https://codemirror.net/examples/tooltip
|
|
2123
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
2124
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
2125
|
+
hoverTooltip2((view, pos, side) => {
|
|
2126
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
2127
|
+
let link2 = null;
|
|
2128
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
2129
|
+
link2 = node.name === "Link" ? node : null;
|
|
2130
|
+
}
|
|
2131
|
+
const url = link2 && link2.getChild("URL");
|
|
2132
|
+
if (!url || !link2) {
|
|
1954
2133
|
return null;
|
|
1955
2134
|
}
|
|
1956
|
-
|
|
2135
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1957
2136
|
return {
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2137
|
+
pos: link2.from,
|
|
2138
|
+
end: link2.to,
|
|
2139
|
+
above: true,
|
|
2140
|
+
create: () => {
|
|
2141
|
+
const el = document.createElement("div");
|
|
2142
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2143
|
+
options.onHover(el, urlText);
|
|
2144
|
+
return {
|
|
2145
|
+
dom: el,
|
|
2146
|
+
offset: {
|
|
2147
|
+
x: 0,
|
|
2148
|
+
y: 4
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
1962
2152
|
};
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
}
|
|
2153
|
+
})
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
return extensions;
|
|
2157
|
+
};
|
|
2158
|
+
var LinkButton = class extends WidgetType5 {
|
|
2159
|
+
constructor(_url, _onAttach) {
|
|
2160
|
+
super();
|
|
2161
|
+
this._url = _url;
|
|
2162
|
+
this._onAttach = _onAttach;
|
|
2163
|
+
}
|
|
2164
|
+
eq(other) {
|
|
2165
|
+
return this._url === other._url;
|
|
2166
|
+
}
|
|
2167
|
+
toDOM(view) {
|
|
2168
|
+
const el = document.createElement("span");
|
|
2169
|
+
this._onAttach(el, this._url);
|
|
2170
|
+
return el;
|
|
2171
|
+
}
|
|
2172
|
+
};
|
|
2173
|
+
var LinkText = class extends WidgetType5 {
|
|
2174
|
+
constructor(_text, _url) {
|
|
2175
|
+
super();
|
|
2176
|
+
this._text = _text;
|
|
2177
|
+
this._url = _url;
|
|
2178
|
+
}
|
|
2179
|
+
eq(other) {
|
|
2180
|
+
return this._url === other._url;
|
|
2181
|
+
}
|
|
2182
|
+
toDOM(view) {
|
|
2183
|
+
const link2 = document.createElement("a");
|
|
2184
|
+
link2.setAttribute("class", "cm-link");
|
|
2185
|
+
link2.textContent = this._text;
|
|
2186
|
+
if (this._url) {
|
|
2187
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2188
|
+
link2.setAttribute("target", "_blank");
|
|
2189
|
+
link2.href = this._url;
|
|
2190
|
+
} else {
|
|
2191
|
+
link2.onclick = () => {
|
|
2192
|
+
view.dispatch({
|
|
2193
|
+
selection: {
|
|
2194
|
+
anchor: view.posAtDOM(link2)
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
return link2;
|
|
2200
|
+
}
|
|
1966
2201
|
};
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2202
|
+
var buildDecorations5 = (view, options) => {
|
|
2203
|
+
const builder = new RangeSetBuilder5();
|
|
2204
|
+
const { state } = view;
|
|
2205
|
+
const cursor = state.selection.main.head;
|
|
2206
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2207
|
+
syntaxTree6(state).iterate({
|
|
2208
|
+
enter: (node) => {
|
|
2209
|
+
if (node.name === "Link") {
|
|
2210
|
+
const marks = node.node.getChildren("LinkMark");
|
|
2211
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2212
|
+
const urlNode = node.node.getChild("URL");
|
|
2213
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2214
|
+
if (!url) {
|
|
2215
|
+
return false;
|
|
2216
|
+
}
|
|
2217
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2218
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2219
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2220
|
+
}));
|
|
2221
|
+
}
|
|
2222
|
+
if (options.onRender) {
|
|
2223
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2224
|
+
widget: new LinkButton(url, options.onRender)
|
|
2225
|
+
}));
|
|
2226
|
+
}
|
|
2227
|
+
return false;
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
from,
|
|
2231
|
+
to
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
return builder.finish();
|
|
1971
2235
|
};
|
|
1972
2236
|
|
|
1973
|
-
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1974
|
-
import { syntaxTree as
|
|
1975
|
-
import { RangeSetBuilder as
|
|
1976
|
-
import { Decoration as
|
|
2237
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2238
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2239
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2240
|
+
import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1977
2241
|
var table = (options = {}) => {
|
|
1978
|
-
return
|
|
1979
|
-
create: (state) =>
|
|
1980
|
-
update: (_, tr) =>
|
|
2242
|
+
return StateField4.define({
|
|
2243
|
+
create: (state) => update(state, options),
|
|
2244
|
+
update: (_, tr) => update(tr.state, options),
|
|
1981
2245
|
provide: (field) => EditorView11.decorations.from(field)
|
|
1982
2246
|
});
|
|
1983
2247
|
};
|
|
1984
|
-
var
|
|
1985
|
-
const builder = new
|
|
2248
|
+
var update = (state, options) => {
|
|
2249
|
+
const builder = new RangeSetBuilder6();
|
|
1986
2250
|
const cursor = state.selection.main.head;
|
|
1987
2251
|
const tables = [];
|
|
1988
2252
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1990,7 +2254,7 @@ var update3 = (state, options) => {
|
|
|
1990
2254
|
const table2 = getTable();
|
|
1991
2255
|
return table2.rows?.[table2.rows.length - 1];
|
|
1992
2256
|
};
|
|
1993
|
-
|
|
2257
|
+
syntaxTree7(state).iterate({
|
|
1994
2258
|
enter: (node) => {
|
|
1995
2259
|
switch (node.name) {
|
|
1996
2260
|
case "Table": {
|
|
@@ -2022,11 +2286,10 @@ var update3 = (state, options) => {
|
|
|
2022
2286
|
});
|
|
2023
2287
|
tables.forEach((table2) => {
|
|
2024
2288
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2025
|
-
hide && builder.add(table2.from, table2.to,
|
|
2026
|
-
block: true,
|
|
2289
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2027
2290
|
widget: new TableWidget(table2)
|
|
2028
2291
|
}));
|
|
2029
|
-
builder.add(table2.from, table2.to,
|
|
2292
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2030
2293
|
class: "cm-table"
|
|
2031
2294
|
}));
|
|
2032
2295
|
});
|
|
@@ -2038,7 +2301,7 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2038
2301
|
this._table = _table;
|
|
2039
2302
|
}
|
|
2040
2303
|
eq(other) {
|
|
2041
|
-
return this._table.
|
|
2304
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
2042
2305
|
}
|
|
2043
2306
|
toDOM(view) {
|
|
2044
2307
|
const table2 = document.createElement("table");
|
|
@@ -2064,95 +2327,144 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2064
2327
|
}
|
|
2065
2328
|
return table2;
|
|
2066
2329
|
}
|
|
2330
|
+
ignoreEvent(e) {
|
|
2331
|
+
return !/^mouse/.test(e.type);
|
|
2332
|
+
}
|
|
2067
2333
|
};
|
|
2068
2334
|
|
|
2069
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2070
|
-
import {
|
|
2335
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2336
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2337
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2338
|
+
import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
2071
2339
|
var styles5 = EditorView12.baseTheme({
|
|
2072
|
-
"& .cm-task
|
|
2073
|
-
|
|
2074
|
-
|
|
2340
|
+
"& .cm-task": {
|
|
2341
|
+
color: getToken("extend.colors.blue.500")
|
|
2342
|
+
},
|
|
2343
|
+
"& .cm-task-checkbox": {
|
|
2344
|
+
marginLeft: "4px",
|
|
2345
|
+
marginRight: "4px"
|
|
2075
2346
|
}
|
|
2076
2347
|
});
|
|
2077
2348
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2078
|
-
constructor(
|
|
2349
|
+
constructor(_checked) {
|
|
2079
2350
|
super();
|
|
2080
|
-
this._pos = _pos;
|
|
2081
2351
|
this._checked = _checked;
|
|
2082
|
-
this._indent = _indent;
|
|
2083
|
-
this._onCheck = _onCheck;
|
|
2084
2352
|
}
|
|
2085
2353
|
eq(other) {
|
|
2086
|
-
return this.
|
|
2354
|
+
return this._checked === other._checked;
|
|
2087
2355
|
}
|
|
2088
2356
|
toDOM(view) {
|
|
2089
|
-
const
|
|
2090
|
-
|
|
2091
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2092
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2093
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2357
|
+
const input = document.createElement("input");
|
|
2358
|
+
input.className = "cm-task-checkbox";
|
|
2094
2359
|
input.type = "checkbox";
|
|
2095
2360
|
input.checked = this._checked;
|
|
2096
|
-
if (
|
|
2361
|
+
if (view.state.readOnly) {
|
|
2097
2362
|
input.setAttribute("disabled", "true");
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2363
|
+
} else {
|
|
2364
|
+
input.onmousedown = (event) => {
|
|
2365
|
+
const pos = view.posAtDOM(input);
|
|
2366
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2367
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2368
|
+
view.dispatch({
|
|
2369
|
+
changes: {
|
|
2370
|
+
from: pos + 1,
|
|
2371
|
+
to: pos + 2,
|
|
2372
|
+
insert: this._checked ? " " : "x"
|
|
2373
|
+
}
|
|
2374
|
+
});
|
|
2375
|
+
event.preventDefault();
|
|
2376
|
+
}
|
|
2103
2377
|
};
|
|
2104
2378
|
}
|
|
2105
|
-
return
|
|
2379
|
+
return input;
|
|
2106
2380
|
}
|
|
2107
2381
|
ignoreEvent() {
|
|
2108
2382
|
return false;
|
|
2109
2383
|
}
|
|
2110
2384
|
};
|
|
2385
|
+
var checkedDecoration = Decoration10.replace({
|
|
2386
|
+
widget: new CheckboxWidget(true)
|
|
2387
|
+
});
|
|
2388
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2389
|
+
widget: new CheckboxWidget(false)
|
|
2390
|
+
});
|
|
2391
|
+
var buildDecorations6 = (view) => {
|
|
2392
|
+
const builder = new RangeSetBuilder7();
|
|
2393
|
+
const { state } = view;
|
|
2394
|
+
const cursor = state.selection.main.head;
|
|
2395
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2396
|
+
syntaxTree8(state).iterate({
|
|
2397
|
+
enter: (node) => {
|
|
2398
|
+
if (node.name === "TaskMarker") {
|
|
2399
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2400
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2401
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2402
|
+
class: "cm-task"
|
|
2403
|
+
}));
|
|
2404
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
from,
|
|
2409
|
+
to
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
return builder.finish();
|
|
2413
|
+
};
|
|
2111
2414
|
var tasklist = (options = {}) => {
|
|
2112
|
-
const taskMatcher = new MatchDecorator3({
|
|
2113
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2114
|
-
decoration: (match, view, pos) => {
|
|
2115
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2116
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2117
|
-
return Decoration8.replace({
|
|
2118
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2119
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2120
|
-
view.dispatch({
|
|
2121
|
-
changes: {
|
|
2122
|
-
from: idx,
|
|
2123
|
-
to: idx + 1,
|
|
2124
|
-
insert: checked2 ? "x" : " "
|
|
2125
|
-
},
|
|
2126
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2127
|
-
selection: {
|
|
2128
|
-
anchor: idx + 3
|
|
2129
|
-
}
|
|
2130
|
-
});
|
|
2131
|
-
})
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
});
|
|
2135
|
-
const tasks = ViewPlugin6.fromClass(class {
|
|
2136
|
-
constructor(view) {
|
|
2137
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2138
|
-
}
|
|
2139
|
-
update(update4) {
|
|
2140
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
2141
|
-
}
|
|
2142
|
-
}, {
|
|
2143
|
-
decorations: (value) => value.tasks,
|
|
2144
|
-
provide: (plugin) => EditorView12.atomicRanges.of((view) => {
|
|
2145
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2146
|
-
})
|
|
2147
|
-
});
|
|
2148
2415
|
return [
|
|
2149
|
-
|
|
2416
|
+
ViewPlugin8.fromClass(class {
|
|
2417
|
+
constructor(view) {
|
|
2418
|
+
this.decorations = buildDecorations6(view);
|
|
2419
|
+
}
|
|
2420
|
+
update(update2) {
|
|
2421
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2422
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}, {
|
|
2426
|
+
decorations: (value) => value.decorations
|
|
2427
|
+
}),
|
|
2150
2428
|
styles5
|
|
2151
2429
|
];
|
|
2152
2430
|
};
|
|
2153
2431
|
|
|
2432
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2433
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2434
|
+
var mention = ({ onSearch }) => {
|
|
2435
|
+
return autocompletion2({
|
|
2436
|
+
// TODO(burdon): Not working.
|
|
2437
|
+
activateOnTyping: true,
|
|
2438
|
+
// activateOnTypingDelay: 100,
|
|
2439
|
+
// selectOnOpen: true,
|
|
2440
|
+
closeOnBlur: false,
|
|
2441
|
+
// defaultKeymap: false,
|
|
2442
|
+
icons: false,
|
|
2443
|
+
override: [
|
|
2444
|
+
(context) => {
|
|
2445
|
+
console.log(context);
|
|
2446
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2447
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2448
|
+
return null;
|
|
2449
|
+
}
|
|
2450
|
+
return {
|
|
2451
|
+
from: match.from,
|
|
2452
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2453
|
+
label: `@${value}`
|
|
2454
|
+
}))
|
|
2455
|
+
};
|
|
2456
|
+
}
|
|
2457
|
+
]
|
|
2458
|
+
});
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2461
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2462
|
+
var outliner = (options = {}) => {
|
|
2463
|
+
return [];
|
|
2464
|
+
};
|
|
2465
|
+
|
|
2154
2466
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2155
|
-
import { keymap as
|
|
2467
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2156
2468
|
var defaultItems = [
|
|
2157
2469
|
"hello world!",
|
|
2158
2470
|
"this is a test.",
|
|
@@ -2162,7 +2474,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2162
2474
|
let t;
|
|
2163
2475
|
let idx = 0;
|
|
2164
2476
|
return [
|
|
2165
|
-
|
|
2477
|
+
keymap6.of([
|
|
2166
2478
|
{
|
|
2167
2479
|
// Reset.
|
|
2168
2480
|
key: "alt-meta-'",
|
|
@@ -2208,29 +2520,8 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2208
2520
|
];
|
|
2209
2521
|
};
|
|
2210
2522
|
|
|
2211
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2212
|
-
import { yCollab } from "y-codemirror.next";
|
|
2213
|
-
|
|
2214
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2215
|
-
import * as Y from "yjs";
|
|
2216
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2217
|
-
var cursorConverter2 = (text) => ({
|
|
2218
|
-
toCursor: (index, assoc) => {
|
|
2219
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2220
|
-
},
|
|
2221
|
-
fromCursor: (cursor) => {
|
|
2222
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2223
|
-
}
|
|
2224
|
-
});
|
|
2225
|
-
|
|
2226
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2227
|
-
var yjs = (content, awareness2) => [
|
|
2228
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2229
|
-
yCollab(content, awareness2)
|
|
2230
|
-
];
|
|
2231
|
-
|
|
2232
2523
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2233
|
-
import
|
|
2524
|
+
import get3 from "lodash.get";
|
|
2234
2525
|
var defaultTheme = {
|
|
2235
2526
|
//
|
|
2236
2527
|
// Main layout:
|
|
@@ -2259,21 +2550,21 @@ var defaultTheme = {
|
|
|
2259
2550
|
"&.cm-focused": {
|
|
2260
2551
|
outline: "none"
|
|
2261
2552
|
},
|
|
2262
|
-
"
|
|
2553
|
+
".cm-scroller": {
|
|
2263
2554
|
overflow: "visible",
|
|
2264
|
-
fontFamily:
|
|
2555
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2265
2556
|
},
|
|
2266
|
-
"
|
|
2557
|
+
".cm-content": {
|
|
2267
2558
|
padding: 0,
|
|
2268
2559
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2269
2560
|
fontSize: "16px"
|
|
2270
2561
|
},
|
|
2271
2562
|
"&light .cm-content": {
|
|
2272
|
-
color:
|
|
2563
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2273
2564
|
caretColor: "black"
|
|
2274
2565
|
},
|
|
2275
2566
|
"&dark .cm-content": {
|
|
2276
|
-
color:
|
|
2567
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2277
2568
|
caretColor: "white"
|
|
2278
2569
|
},
|
|
2279
2570
|
//
|
|
@@ -2285,158 +2576,120 @@ var defaultTheme = {
|
|
|
2285
2576
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2286
2577
|
borderLeft: "2px solid white"
|
|
2287
2578
|
},
|
|
2288
|
-
"
|
|
2579
|
+
".cm-placeholder": {
|
|
2289
2580
|
fontWeight: 100
|
|
2290
2581
|
},
|
|
2291
2582
|
//
|
|
2292
2583
|
// line
|
|
2293
2584
|
//
|
|
2294
|
-
"
|
|
2585
|
+
".cm-line": {
|
|
2295
2586
|
paddingInline: 0
|
|
2296
2587
|
},
|
|
2297
|
-
"
|
|
2298
|
-
background: "
|
|
2588
|
+
".cm-activeLine": {
|
|
2589
|
+
background: "transparent"
|
|
2299
2590
|
},
|
|
2300
2591
|
//
|
|
2301
2592
|
// Selection
|
|
2302
2593
|
//
|
|
2303
2594
|
"&light .cm-selectionBackground": {
|
|
2304
|
-
background:
|
|
2595
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2305
2596
|
},
|
|
2306
2597
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2307
|
-
background:
|
|
2598
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2308
2599
|
},
|
|
2309
2600
|
"&dark .cm-selectionBackground": {
|
|
2310
|
-
background:
|
|
2601
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2311
2602
|
},
|
|
2312
2603
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2313
|
-
background:
|
|
2604
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2314
2605
|
},
|
|
2315
2606
|
//
|
|
2316
2607
|
// Search
|
|
2317
2608
|
//
|
|
2318
2609
|
"&light .cm-searchMatch": {
|
|
2319
|
-
backgroundColor:
|
|
2610
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2320
2611
|
},
|
|
2321
2612
|
"&dark .cm-searchMatch": {
|
|
2322
|
-
backgroundColor:
|
|
2323
|
-
},
|
|
2324
|
-
//
|
|
2325
|
-
// collaboration
|
|
2326
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2327
|
-
//
|
|
2328
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2329
|
-
mixBlendMode: "multiply"
|
|
2330
|
-
},
|
|
2331
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2332
|
-
mixBlendMode: "screen"
|
|
2333
|
-
},
|
|
2334
|
-
"& .cm-ySelectionInfo": {
|
|
2335
|
-
padding: "2px 4px",
|
|
2336
|
-
marginBlockStart: "-4px"
|
|
2337
|
-
},
|
|
2338
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2339
|
-
paddingBlockStart: ".15em",
|
|
2340
|
-
paddingBlockEnd: ".15em"
|
|
2341
|
-
},
|
|
2342
|
-
"& .cm-ySelectionCaret": {
|
|
2343
|
-
display: "inline-block",
|
|
2344
|
-
insetBlockStart: ".1em",
|
|
2345
|
-
blockSize: "1.4em",
|
|
2346
|
-
verticalAlign: "top"
|
|
2347
|
-
},
|
|
2348
|
-
"& .cm-yLineSelection": {
|
|
2349
|
-
margin: 0
|
|
2613
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2350
2614
|
},
|
|
2351
2615
|
//
|
|
2352
2616
|
// link
|
|
2353
2617
|
//
|
|
2354
|
-
"
|
|
2355
|
-
color:
|
|
2618
|
+
".cm-link": {
|
|
2619
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2356
2620
|
textDecorationLine: "underline",
|
|
2357
2621
|
textDecorationThickness: "1px",
|
|
2358
2622
|
textUnderlineOffset: "2px",
|
|
2359
2623
|
borderRadius: ".125rem",
|
|
2360
|
-
fontFamily:
|
|
2624
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2361
2625
|
},
|
|
2362
2626
|
//
|
|
2363
2627
|
// tooltip
|
|
2364
2628
|
//
|
|
2365
|
-
"
|
|
2629
|
+
".cm-tooltip": {
|
|
2366
2630
|
border: "none"
|
|
2367
2631
|
},
|
|
2368
|
-
"
|
|
2632
|
+
".cm-tooltip-below": {},
|
|
2369
2633
|
//
|
|
2370
2634
|
// autocomplete
|
|
2371
2635
|
//
|
|
2372
|
-
"
|
|
2636
|
+
".cm-tooltip-autocomplete": {
|
|
2373
2637
|
marginTop: "4px",
|
|
2374
2638
|
marginLeft: "-3px"
|
|
2375
2639
|
},
|
|
2376
|
-
"
|
|
2377
|
-
"
|
|
2378
|
-
"
|
|
2640
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2641
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2642
|
+
".cm-completionIcon": {
|
|
2379
2643
|
display: "none"
|
|
2380
2644
|
},
|
|
2381
|
-
"
|
|
2382
|
-
fontFamily:
|
|
2645
|
+
".cm-completionLabel": {
|
|
2646
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2383
2647
|
},
|
|
2384
|
-
"
|
|
2648
|
+
".cm-completionMatchedText": {
|
|
2385
2649
|
textDecoration: "none"
|
|
2386
2650
|
},
|
|
2387
2651
|
//
|
|
2388
|
-
// widgets
|
|
2389
|
-
//
|
|
2390
|
-
"& .cm-widgetBuffer": {
|
|
2391
|
-
display: "none",
|
|
2392
|
-
height: 0
|
|
2393
|
-
},
|
|
2394
|
-
//
|
|
2395
2652
|
// table
|
|
2396
2653
|
//
|
|
2397
|
-
"
|
|
2398
|
-
fontFamily: `${
|
|
2654
|
+
".cm-table *": {
|
|
2655
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2399
2656
|
textDecoration: "none !important"
|
|
2400
2657
|
},
|
|
2401
|
-
"
|
|
2658
|
+
".cm-table-head": {
|
|
2402
2659
|
padding: "2px 16px 2px 0px",
|
|
2403
|
-
borderBottom: `1px solid ${
|
|
2660
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2404
2661
|
fontWeight: 100,
|
|
2405
2662
|
textAlign: "left",
|
|
2406
|
-
color:
|
|
2663
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2407
2664
|
},
|
|
2408
|
-
"
|
|
2665
|
+
".cm-table-cell": {
|
|
2409
2666
|
padding: "2px 16px 2px 0px"
|
|
2410
2667
|
},
|
|
2411
2668
|
//
|
|
2412
2669
|
// image
|
|
2413
2670
|
//
|
|
2414
|
-
"
|
|
2415
|
-
|
|
2671
|
+
".cm-image": {
|
|
2672
|
+
display: "block",
|
|
2673
|
+
height: "0"
|
|
2674
|
+
},
|
|
2675
|
+
".cm-image.cm-loaded-image": {
|
|
2676
|
+
height: "auto",
|
|
2677
|
+
borderTop: "0.5rem solid transparent",
|
|
2678
|
+
borderBottom: "0.5rem solid transparent"
|
|
2416
2679
|
},
|
|
2417
2680
|
//
|
|
2418
2681
|
// font size
|
|
2419
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2682
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2683
|
+
// but it's far more verbose than it needs to be.
|
|
2420
2684
|
//
|
|
2421
|
-
...Object.keys(
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2430
|
-
height
|
|
2431
|
-
};
|
|
2432
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2433
|
-
height
|
|
2434
|
-
};
|
|
2435
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2436
|
-
height
|
|
2437
|
-
};
|
|
2438
|
-
return acc;
|
|
2439
|
-
}, {}),
|
|
2685
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2686
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2687
|
+
//
|
|
2688
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2689
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2690
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2691
|
+
// return acc;
|
|
2692
|
+
// }, {}),
|
|
2440
2693
|
/**
|
|
2441
2694
|
* Panels
|
|
2442
2695
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2453,144 +2706,138 @@ var defaultTheme = {
|
|
|
2453
2706
|
* </div>
|
|
2454
2707
|
* </div
|
|
2455
2708
|
*/
|
|
2456
|
-
"
|
|
2457
|
-
border: `1px solid ${
|
|
2709
|
+
".cm-panels": {
|
|
2710
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2458
2711
|
},
|
|
2459
|
-
"
|
|
2460
|
-
background:
|
|
2461
|
-
fontFamily:
|
|
2712
|
+
".cm-panel": {
|
|
2713
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2714
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2462
2715
|
},
|
|
2463
|
-
"
|
|
2716
|
+
".cm-button": {
|
|
2464
2717
|
margin: "4px",
|
|
2465
|
-
fontFamily:
|
|
2466
|
-
background:
|
|
2718
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2719
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2467
2720
|
backgroundImage: "none",
|
|
2468
2721
|
border: "none",
|
|
2469
2722
|
"&:hover": {
|
|
2470
|
-
background:
|
|
2723
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2471
2724
|
},
|
|
2472
2725
|
"&:active": {
|
|
2473
|
-
background:
|
|
2726
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2474
2727
|
backgroundImage: "none"
|
|
2475
2728
|
}
|
|
2476
2729
|
},
|
|
2477
|
-
"
|
|
2730
|
+
".cm-panel input[type=checkbox]": {
|
|
2478
2731
|
marginRight: "0.4rem !important"
|
|
2479
2732
|
}
|
|
2480
2733
|
};
|
|
2481
2734
|
var textTheme = {
|
|
2482
|
-
"
|
|
2483
|
-
fontFamily:
|
|
2735
|
+
".cm-scroller": {
|
|
2736
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2484
2737
|
},
|
|
2485
|
-
"
|
|
2486
|
-
fontFamily:
|
|
2738
|
+
".cm-placeholder": {
|
|
2739
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2487
2740
|
}
|
|
2488
2741
|
};
|
|
2489
2742
|
var markdownTheme = {
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2743
|
+
".cm-scroller": {
|
|
2744
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2745
|
+
},
|
|
2746
|
+
".cm-placeholder": {
|
|
2747
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2493
2748
|
}
|
|
2494
2749
|
};
|
|
2495
2750
|
var codeTheme = {
|
|
2496
|
-
"
|
|
2497
|
-
fontFamily:
|
|
2751
|
+
".cm-scroller": {
|
|
2752
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2498
2753
|
},
|
|
2499
|
-
"
|
|
2500
|
-
fontFamily:
|
|
2754
|
+
".cm-placeholder": {
|
|
2755
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2501
2756
|
}
|
|
2502
2757
|
};
|
|
2503
2758
|
|
|
2504
2759
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2760
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2505
2761
|
var EditorModes = [
|
|
2506
2762
|
"default",
|
|
2507
2763
|
"vim"
|
|
2508
2764
|
];
|
|
2509
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2765
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2510
2766
|
const { themeMode } = useThemeContext();
|
|
2511
|
-
const
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
const [root, setRoot] = useState(null);
|
|
2515
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2516
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2517
|
-
root,
|
|
2518
|
-
state,
|
|
2767
|
+
const rootRef = useRef(null);
|
|
2768
|
+
const [view, setView] = useState(null);
|
|
2769
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2519
2770
|
view
|
|
2520
|
-
}), [
|
|
2521
|
-
view,
|
|
2522
|
-
state,
|
|
2523
|
-
root
|
|
2524
|
-
]);
|
|
2525
|
-
const { awareness: awareness2, peer } = model;
|
|
2526
|
-
useEffect(() => {
|
|
2527
|
-
if (awareness2 && peer) {
|
|
2528
|
-
awareness2.setLocalStateField("user", {
|
|
2529
|
-
name: peer.name ?? generateName(peer.id),
|
|
2530
|
-
color: getColorForValue({
|
|
2531
|
-
value: peer.id,
|
|
2532
|
-
type: "color"
|
|
2533
|
-
}),
|
|
2534
|
-
colorLight: getColorForValue({
|
|
2535
|
-
value: peer.id,
|
|
2536
|
-
themeMode,
|
|
2537
|
-
type: "highlight"
|
|
2538
|
-
})
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
}, [
|
|
2542
|
-
awareness2,
|
|
2543
|
-
peer,
|
|
2544
|
-
themeMode
|
|
2545
2771
|
]);
|
|
2546
|
-
|
|
2547
|
-
if (
|
|
2548
|
-
view
|
|
2549
|
-
effects: setCommentRange.of({
|
|
2550
|
-
model,
|
|
2551
|
-
comments: comments2
|
|
2552
|
-
})
|
|
2553
|
-
});
|
|
2772
|
+
useEffect2(() => {
|
|
2773
|
+
if (autoFocus) {
|
|
2774
|
+
view?.focus();
|
|
2554
2775
|
}
|
|
2555
2776
|
}, [
|
|
2556
2777
|
view,
|
|
2557
|
-
|
|
2778
|
+
autoFocus
|
|
2558
2779
|
]);
|
|
2559
|
-
|
|
2560
|
-
if (!
|
|
2780
|
+
useEffect2(() => {
|
|
2781
|
+
if (!model || !rootRef.current) {
|
|
2561
2782
|
return;
|
|
2562
2783
|
}
|
|
2563
|
-
const
|
|
2784
|
+
const state = EditorState2.create({
|
|
2564
2785
|
doc: model.text(),
|
|
2786
|
+
selection,
|
|
2565
2787
|
extensions: [
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2788
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2789
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2790
|
+
log2.catch(err, void 0, {
|
|
2791
|
+
F: __dxlog_file3,
|
|
2792
|
+
L: 129,
|
|
2793
|
+
S: void 0,
|
|
2794
|
+
C: (f, a) => f(...a)
|
|
2795
|
+
});
|
|
2796
|
+
}),
|
|
2569
2797
|
// Theme.
|
|
2570
|
-
// TODO(burdon): Make
|
|
2798
|
+
// TODO(burdon): Make configurable.
|
|
2571
2799
|
EditorView13.baseTheme(defaultTheme),
|
|
2572
|
-
EditorView13.theme(
|
|
2800
|
+
EditorView13.theme(theme ?? {}),
|
|
2573
2801
|
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2802
|
+
EditorView13.editorAttributes.of({
|
|
2803
|
+
class: slots.editor?.className ?? ""
|
|
2804
|
+
}),
|
|
2805
|
+
EditorView13.contentAttributes.of({
|
|
2806
|
+
class: slots.content?.className ?? ""
|
|
2807
|
+
}),
|
|
2808
|
+
// State.
|
|
2809
|
+
EditorView13.editable.of(!readonly),
|
|
2810
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2574
2811
|
// Storage and replication.
|
|
2812
|
+
// NOTE: This must come before user extensions.
|
|
2575
2813
|
model.extension,
|
|
2814
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2815
|
+
editorMode === "vim" && vim(),
|
|
2576
2816
|
// Custom.
|
|
2577
2817
|
...extensions
|
|
2578
|
-
].filter(
|
|
2818
|
+
].filter(isNotFalsy)
|
|
2579
2819
|
});
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2820
|
+
const newView = new EditorView13({
|
|
2821
|
+
state,
|
|
2822
|
+
parent: rootRef.current,
|
|
2823
|
+
scrollTo,
|
|
2824
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2825
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2826
|
+
dispatchTransactions: (trs, view2) => {
|
|
2827
|
+
if (debug) {
|
|
2828
|
+
logChanges(trs);
|
|
2829
|
+
}
|
|
2830
|
+
view2.update(trs);
|
|
2831
|
+
}
|
|
2587
2832
|
});
|
|
2833
|
+
view?.destroy();
|
|
2834
|
+
setView(newView);
|
|
2588
2835
|
return () => {
|
|
2589
|
-
|
|
2590
|
-
|
|
2836
|
+
newView?.destroy();
|
|
2837
|
+
setView(null);
|
|
2591
2838
|
};
|
|
2592
2839
|
}, [
|
|
2593
|
-
|
|
2840
|
+
rootRef,
|
|
2594
2841
|
model,
|
|
2595
2842
|
readonly,
|
|
2596
2843
|
editorMode,
|
|
@@ -2600,11 +2847,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2600
2847
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2601
2848
|
switch (key) {
|
|
2602
2849
|
case "Enter": {
|
|
2603
|
-
view?.
|
|
2850
|
+
view?.focus();
|
|
2604
2851
|
break;
|
|
2605
2852
|
}
|
|
2606
2853
|
case "Escape": {
|
|
2607
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2854
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2855
|
+
view?.focus();
|
|
2856
|
+
}
|
|
2608
2857
|
break;
|
|
2609
2858
|
}
|
|
2610
2859
|
}
|
|
@@ -2614,83 +2863,78 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2614
2863
|
]);
|
|
2615
2864
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2616
2865
|
key: model.id,
|
|
2617
|
-
|
|
2866
|
+
role: "none",
|
|
2618
2867
|
tabIndex: 0,
|
|
2619
|
-
...slots
|
|
2620
|
-
...editorMode !==
|
|
2621
|
-
onKeyUp: handleKeyUp
|
|
2868
|
+
...slots.root,
|
|
2869
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2870
|
+
onKeyUp: handleKeyUp,
|
|
2871
|
+
ref: rootRef
|
|
2622
2872
|
});
|
|
2623
2873
|
});
|
|
2624
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2874
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2625
2875
|
const { themeMode } = useThemeContext();
|
|
2626
|
-
const
|
|
2876
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2627
2877
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2628
2878
|
ref: forwardedRef,
|
|
2629
2879
|
readonly,
|
|
2630
2880
|
extensions: [
|
|
2631
2881
|
basicBundle({
|
|
2632
|
-
readonly,
|
|
2633
2882
|
themeMode,
|
|
2634
|
-
placeholder:
|
|
2883
|
+
placeholder: placeholder3,
|
|
2884
|
+
lineWrapping
|
|
2635
2885
|
}),
|
|
2636
2886
|
...extensions
|
|
2637
2887
|
],
|
|
2638
|
-
|
|
2888
|
+
theme,
|
|
2889
|
+
slots: updatedSlots,
|
|
2639
2890
|
...props
|
|
2640
2891
|
});
|
|
2641
2892
|
});
|
|
2642
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2893
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2643
2894
|
const { themeMode } = useThemeContext();
|
|
2644
|
-
const
|
|
2895
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2645
2896
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2646
2897
|
ref: forwardedRef,
|
|
2647
2898
|
readonly,
|
|
2648
2899
|
extensions: [
|
|
2649
2900
|
markdownBundle({
|
|
2650
|
-
readonly,
|
|
2651
2901
|
themeMode,
|
|
2652
|
-
placeholder:
|
|
2902
|
+
placeholder: placeholder3
|
|
2653
2903
|
}),
|
|
2654
2904
|
...extensions
|
|
2655
2905
|
],
|
|
2656
|
-
|
|
2906
|
+
theme,
|
|
2907
|
+
slots: updatedSlots,
|
|
2657
2908
|
...props
|
|
2658
2909
|
});
|
|
2659
2910
|
});
|
|
2660
2911
|
var defaultSlots = {
|
|
2661
2912
|
root: {
|
|
2662
|
-
|
|
2913
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2914
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2915
|
+
},
|
|
2916
|
+
editor: {
|
|
2917
|
+
className: "h-full p-2"
|
|
2663
2918
|
}
|
|
2664
2919
|
};
|
|
2665
2920
|
var defaultTextSlots = {
|
|
2666
|
-
...defaultSlots
|
|
2667
|
-
editor: {
|
|
2668
|
-
theme: textTheme
|
|
2669
|
-
}
|
|
2921
|
+
...defaultSlots
|
|
2670
2922
|
};
|
|
2671
2923
|
var defaultMarkdownSlots = {
|
|
2672
|
-
...defaultSlots
|
|
2673
|
-
editor: {
|
|
2674
|
-
theme: markdownTheme
|
|
2675
|
-
}
|
|
2924
|
+
...defaultSlots
|
|
2676
2925
|
};
|
|
2677
2926
|
|
|
2678
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2679
|
-
import get7 from "lodash.get";
|
|
2680
|
-
import { getRawDoc } from "@dxos/echo-schema";
|
|
2681
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2682
|
-
|
|
2683
2927
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2684
2928
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2685
2929
|
import { Context as Context2 } from "@dxos/context";
|
|
2686
|
-
import { invariant as
|
|
2930
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2687
2931
|
import { log as log3 } from "@dxos/log";
|
|
2688
2932
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2689
2933
|
var DEBOUNCE_INTERVAL = 100;
|
|
2690
2934
|
var SpaceAwarenessProvider = class {
|
|
2691
2935
|
constructor(params) {
|
|
2692
|
-
this.remoteStateChange = new Event2();
|
|
2693
2936
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2937
|
+
this.remoteStateChange = new Event2();
|
|
2694
2938
|
this._space = params.space;
|
|
2695
2939
|
this._channel = params.channel;
|
|
2696
2940
|
this._peerId = params.peerId;
|
|
@@ -2707,7 +2951,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2707
2951
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2708
2952
|
}
|
|
2709
2953
|
});
|
|
2710
|
-
|
|
2954
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2711
2955
|
switch (message.payload.kind) {
|
|
2712
2956
|
case "query": {
|
|
2713
2957
|
this._handleQueryMessage();
|
|
@@ -2718,8 +2962,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2718
2962
|
break;
|
|
2719
2963
|
}
|
|
2720
2964
|
}
|
|
2721
|
-
});
|
|
2722
|
-
this._ctx.onDispose(unsubscribe);
|
|
2965
|
+
}));
|
|
2723
2966
|
void this._space.postMessage(this._channel, {
|
|
2724
2967
|
kind: "query"
|
|
2725
2968
|
}).catch((err) => {
|
|
@@ -2727,7 +2970,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2727
2970
|
err
|
|
2728
2971
|
}, {
|
|
2729
2972
|
F: __dxlog_file4,
|
|
2730
|
-
L:
|
|
2973
|
+
L: 89,
|
|
2731
2974
|
S: this,
|
|
2732
2975
|
C: (f, a) => f(...a)
|
|
2733
2976
|
});
|
|
@@ -2738,10 +2981,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2738
2981
|
this._ctx = void 0;
|
|
2739
2982
|
this._postTask = void 0;
|
|
2740
2983
|
}
|
|
2984
|
+
getRemoteStates() {
|
|
2985
|
+
return Array.from(this._remoteStates.values());
|
|
2986
|
+
}
|
|
2741
2987
|
update(position) {
|
|
2742
|
-
|
|
2988
|
+
invariant2(this._postTask, void 0, {
|
|
2743
2989
|
F: __dxlog_file4,
|
|
2744
|
-
L:
|
|
2990
|
+
L: 104,
|
|
2745
2991
|
S: this,
|
|
2746
2992
|
A: [
|
|
2747
2993
|
"this._postTask",
|
|
@@ -2755,13 +3001,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2755
3001
|
};
|
|
2756
3002
|
this._postTask.schedule();
|
|
2757
3003
|
}
|
|
2758
|
-
getRemoteStates() {
|
|
2759
|
-
return Array.from(this._remoteStates.values());
|
|
2760
|
-
}
|
|
2761
3004
|
_handleQueryMessage() {
|
|
2762
|
-
|
|
3005
|
+
invariant2(this._postTask, void 0, {
|
|
2763
3006
|
F: __dxlog_file4,
|
|
2764
|
-
L:
|
|
3007
|
+
L: 115,
|
|
2765
3008
|
S: this,
|
|
2766
3009
|
A: [
|
|
2767
3010
|
"this._postTask",
|
|
@@ -2771,9 +3014,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2771
3014
|
this._postTask.schedule();
|
|
2772
3015
|
}
|
|
2773
3016
|
_handlePostMessage(message) {
|
|
2774
|
-
|
|
3017
|
+
invariant2(message.kind === "post", void 0, {
|
|
2775
3018
|
F: __dxlog_file4,
|
|
2776
|
-
L:
|
|
3019
|
+
L: 120,
|
|
2777
3020
|
S: this,
|
|
2778
3021
|
A: [
|
|
2779
3022
|
"message.kind === 'post'",
|
|
@@ -2785,229 +3028,115 @@ var SpaceAwarenessProvider = class {
|
|
|
2785
3028
|
}
|
|
2786
3029
|
};
|
|
2787
3030
|
|
|
2788
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2789
|
-
import { StateField as
|
|
2790
|
-
|
|
2791
|
-
|
|
3031
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
3032
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
3033
|
+
var modelState = StateField5.define({
|
|
3034
|
+
create: () => void 0,
|
|
3035
|
+
update: (model) => model
|
|
3036
|
+
});
|
|
2792
3037
|
|
|
2793
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
import * as Y2 from "yjs";
|
|
2799
|
-
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2800
|
-
import { log as log4 } from "@dxos/log";
|
|
2801
|
-
import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
|
|
2802
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2803
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
2804
|
-
invariant4(text?.doc && text?.content, void 0, {
|
|
2805
|
-
F: __dxlog_file5,
|
|
2806
|
-
L: 23,
|
|
2807
|
-
S: void 0,
|
|
2808
|
-
A: [
|
|
2809
|
-
"text?.doc && text?.content",
|
|
2810
|
-
""
|
|
2811
|
-
]
|
|
2812
|
-
});
|
|
2813
|
-
const provider = space ? new YAwarenessProvider({
|
|
2814
|
-
space,
|
|
2815
|
-
doc: text.doc,
|
|
2816
|
-
channel: `yjs.awareness.${text.id}`
|
|
2817
|
-
}) : void 0;
|
|
2818
|
-
const model = {
|
|
2819
|
-
id: text.doc.guid,
|
|
2820
|
-
content: text.content,
|
|
2821
|
-
text: () => text.content.toString(),
|
|
2822
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2823
|
-
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2824
|
-
getCursorFromRange: (range) => {
|
|
2825
|
-
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2826
|
-
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2827
|
-
return [
|
|
2828
|
-
arrayToString2(from),
|
|
2829
|
-
arrayToString2(to)
|
|
2830
|
-
].join(":");
|
|
2831
|
-
},
|
|
2832
|
-
getRangeFromCursor: (cursor) => {
|
|
2833
|
-
invariant4(text.doc, void 0, {
|
|
2834
|
-
F: __dxlog_file5,
|
|
2835
|
-
L: 40,
|
|
2836
|
-
S: void 0,
|
|
2837
|
-
A: [
|
|
2838
|
-
"text.doc",
|
|
2839
|
-
""
|
|
2840
|
-
]
|
|
2841
|
-
});
|
|
2842
|
-
const parts = cursor.split(":");
|
|
2843
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2844
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2845
|
-
return from && to ? {
|
|
2846
|
-
from: from.index,
|
|
2847
|
-
to: to.index
|
|
2848
|
-
} : void 0;
|
|
2849
|
-
},
|
|
2850
|
-
extension: [
|
|
2851
|
-
modelState.init(() => model),
|
|
2852
|
-
yjs(text.content, provider?.awareness)
|
|
2853
|
-
],
|
|
2854
|
-
awareness: provider?.awareness,
|
|
2855
|
-
peer: identity ? {
|
|
2856
|
-
id: identity.identityKey.toHex(),
|
|
2857
|
-
name: identity.profile?.displayName
|
|
2858
|
-
} : void 0
|
|
2859
|
-
};
|
|
2860
|
-
return model;
|
|
2861
|
-
};
|
|
2862
|
-
var messageAwareness = 1;
|
|
2863
|
-
var messageQueryAwareness = 3;
|
|
2864
|
-
var YAwarenessProvider = class extends Observable {
|
|
2865
|
-
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2866
|
-
super();
|
|
2867
|
-
this._space = space;
|
|
2868
|
-
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2869
|
-
this._channel = channel;
|
|
2870
|
-
this._clientId = doc.clientID;
|
|
2871
|
-
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2872
|
-
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2873
|
-
if (typeof window !== "undefined") {
|
|
2874
|
-
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2875
|
-
} else if (typeof process !== "undefined") {
|
|
2876
|
-
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2877
|
-
}
|
|
2878
|
-
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2879
|
-
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2880
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2881
|
-
const encoderAwarenessState = encoding.createEncoder();
|
|
2882
|
-
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2883
|
-
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2884
|
-
this._clientId
|
|
2885
|
-
]));
|
|
2886
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2887
|
-
}
|
|
2888
|
-
get awareness() {
|
|
2889
|
-
return this._awareness;
|
|
2890
|
-
}
|
|
2891
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2892
|
-
log4("awareness update", {
|
|
2893
|
-
added,
|
|
2894
|
-
updated,
|
|
2895
|
-
removed,
|
|
2896
|
-
origin
|
|
2897
|
-
}, {
|
|
2898
|
-
F: __dxlog_file5,
|
|
2899
|
-
L: 122,
|
|
2900
|
-
S: this,
|
|
2901
|
-
C: (f, a) => f(...a)
|
|
2902
|
-
});
|
|
2903
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2904
|
-
const encoderAwareness = encoding.createEncoder();
|
|
2905
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2906
|
-
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2907
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2908
|
-
}
|
|
2909
|
-
_handleSpaceMessage({ payload }) {
|
|
2910
|
-
log4("space message", payload, {
|
|
2911
|
-
F: __dxlog_file5,
|
|
2912
|
-
L: 131,
|
|
2913
|
-
S: this,
|
|
2914
|
-
C: (f, a) => f(...a)
|
|
2915
|
-
});
|
|
2916
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2917
|
-
const encoder = this._readMessage(data);
|
|
2918
|
-
if (encoder) {
|
|
2919
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
3038
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3039
|
+
var useActionHandler = (view) => {
|
|
3040
|
+
return (action) => {
|
|
3041
|
+
if (!view) {
|
|
3042
|
+
return;
|
|
2920
3043
|
}
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
const encoder = encoding.createEncoder();
|
|
2925
|
-
const messageType = decoding.readVarUint(decoder);
|
|
2926
|
-
let sendReply = false;
|
|
2927
|
-
switch (messageType) {
|
|
2928
|
-
case messageAwareness: {
|
|
2929
|
-
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
3044
|
+
switch (action.type) {
|
|
3045
|
+
case "heading":
|
|
3046
|
+
setHeading(parseInt(action.data))(view);
|
|
2930
3047
|
break;
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
3048
|
+
case "bold":
|
|
3049
|
+
toggleBold(view);
|
|
3050
|
+
break;
|
|
3051
|
+
case "italic":
|
|
3052
|
+
toggleItalic(view);
|
|
3053
|
+
break;
|
|
3054
|
+
case "strikethrough":
|
|
3055
|
+
toggleStrikethrough(view);
|
|
3056
|
+
break;
|
|
3057
|
+
case "list":
|
|
3058
|
+
toggleList(view);
|
|
3059
|
+
break;
|
|
3060
|
+
case "comment":
|
|
3061
|
+
createComment(view);
|
|
2936
3062
|
break;
|
|
2937
|
-
}
|
|
2938
|
-
default: {
|
|
2939
|
-
console.error("Invalid message:", messageType);
|
|
2940
|
-
return encoder;
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
if (!sendReply) {
|
|
2944
|
-
return null;
|
|
2945
3063
|
}
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3064
|
+
setTimeout(() => {
|
|
3065
|
+
view.focus();
|
|
3066
|
+
});
|
|
3067
|
+
};
|
|
3068
|
+
};
|
|
3069
|
+
|
|
3070
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3071
|
+
import { useState as useState2 } from "react";
|
|
3072
|
+
var useTextEditor = () => {
|
|
3073
|
+
const [view, setView] = useState2(null);
|
|
3074
|
+
return [
|
|
3075
|
+
(ref) => {
|
|
3076
|
+
setView(ref);
|
|
3077
|
+
},
|
|
3078
|
+
view
|
|
3079
|
+
];
|
|
2953
3080
|
};
|
|
2954
3081
|
|
|
2955
3082
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
}
|
|
3083
|
+
import get4 from "lodash.get";
|
|
3084
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
3085
|
+
import { generateName } from "@dxos/display-name";
|
|
3086
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
3087
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
3088
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3089
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2960
3090
|
var useTextModel = (props) => {
|
|
2961
3091
|
const { identity, space, text } = props;
|
|
2962
|
-
const [model, setModel] =
|
|
2963
|
-
|
|
3092
|
+
const [model, setModel] = useState3();
|
|
3093
|
+
useEffect3(() => setModel(createModel(props)), [
|
|
2964
3094
|
identity,
|
|
2965
3095
|
space,
|
|
2966
3096
|
text
|
|
2967
3097
|
]);
|
|
2968
3098
|
return model;
|
|
2969
3099
|
};
|
|
2970
|
-
var createModel = (
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
};
|
|
2980
|
-
|
|
2981
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2982
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
3100
|
+
var createModel = ({ space, identity, text }) => {
|
|
3101
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
3102
|
+
F: __dxlog_file5,
|
|
3103
|
+
L: 34,
|
|
3104
|
+
S: void 0,
|
|
3105
|
+
A: [
|
|
3106
|
+
"isAutomergeObject(text)",
|
|
3107
|
+
""
|
|
3108
|
+
]
|
|
3109
|
+
});
|
|
2983
3110
|
const obj = text;
|
|
2984
3111
|
const doc = getRawDoc(obj, [
|
|
2985
3112
|
obj.field
|
|
2986
3113
|
]);
|
|
2987
|
-
const
|
|
3114
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2988
3115
|
space,
|
|
2989
3116
|
channel: `automerge.awareness.${obj.id}`,
|
|
2990
3117
|
info: {
|
|
2991
|
-
displayName: identity
|
|
3118
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2992
3119
|
color: cursorColor.color,
|
|
2993
3120
|
lightColor: cursorColor.light
|
|
2994
3121
|
},
|
|
2995
3122
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2996
3123
|
});
|
|
3124
|
+
const extensions = [
|
|
3125
|
+
//
|
|
3126
|
+
modelState.init(() => model),
|
|
3127
|
+
automerge({
|
|
3128
|
+
handle: doc.handle,
|
|
3129
|
+
path: doc.path
|
|
3130
|
+
})
|
|
3131
|
+
];
|
|
3132
|
+
if (awarenessProvider2) {
|
|
3133
|
+
extensions.push(awareness(awarenessProvider2));
|
|
3134
|
+
}
|
|
2997
3135
|
const model = {
|
|
2998
3136
|
id: obj.id,
|
|
2999
3137
|
content: doc,
|
|
3000
|
-
text: () =>
|
|
3001
|
-
|
|
3002
|
-
extension: [
|
|
3003
|
-
modelState.init(() => model),
|
|
3004
|
-
automerge3({
|
|
3005
|
-
handle: doc.handle,
|
|
3006
|
-
path: doc.path
|
|
3007
|
-
}),
|
|
3008
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3009
|
-
awareness()
|
|
3010
|
-
].filter(isNotNullOrUndefined),
|
|
3138
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3139
|
+
extension: extensions,
|
|
3011
3140
|
peer: identity ? {
|
|
3012
3141
|
id: identity.identityKey.toHex(),
|
|
3013
3142
|
name: identity.profile?.displayName
|
|
@@ -3016,8 +3145,8 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3016
3145
|
return model;
|
|
3017
3146
|
};
|
|
3018
3147
|
export {
|
|
3019
|
-
AwarenessProvider,
|
|
3020
3148
|
BaseTextEditor,
|
|
3149
|
+
Cursor,
|
|
3021
3150
|
Doc,
|
|
3022
3151
|
EditorModes,
|
|
3023
3152
|
MarkdownEditor,
|
|
@@ -3025,45 +3154,57 @@ export {
|
|
|
3025
3154
|
SpaceAwarenessProvider,
|
|
3026
3155
|
TextEditor,
|
|
3027
3156
|
TextKind,
|
|
3028
|
-
YAwarenessProvider,
|
|
3029
3157
|
YText,
|
|
3030
3158
|
YXmlFragment,
|
|
3031
3159
|
autocomplete,
|
|
3032
|
-
|
|
3160
|
+
automerge,
|
|
3033
3161
|
awareness,
|
|
3162
|
+
awarenessProvider,
|
|
3034
3163
|
basicBundle,
|
|
3035
3164
|
blast,
|
|
3165
|
+
callbackWrapper,
|
|
3036
3166
|
code2 as code,
|
|
3037
3167
|
codeTheme,
|
|
3038
3168
|
comments,
|
|
3039
|
-
|
|
3040
|
-
createYjsModel,
|
|
3169
|
+
createComment,
|
|
3041
3170
|
defaultMarkdownSlots,
|
|
3042
3171
|
defaultOptions,
|
|
3043
3172
|
defaultSlots,
|
|
3044
3173
|
defaultTextSlots,
|
|
3045
3174
|
defaultTheme,
|
|
3175
|
+
formatting,
|
|
3176
|
+
getToken,
|
|
3177
|
+
heading2 as heading,
|
|
3046
3178
|
hr,
|
|
3047
3179
|
image,
|
|
3048
3180
|
link,
|
|
3049
3181
|
listener,
|
|
3182
|
+
logChanges,
|
|
3050
3183
|
markdownBundle,
|
|
3051
3184
|
markdownHighlightStyle,
|
|
3052
3185
|
markdownTags,
|
|
3053
3186
|
markdownTagsExtensions,
|
|
3054
3187
|
markdownTheme,
|
|
3055
3188
|
mention,
|
|
3056
|
-
mermaid,
|
|
3057
3189
|
modelState,
|
|
3058
|
-
|
|
3190
|
+
outliner,
|
|
3191
|
+
setComments,
|
|
3059
3192
|
setFocus,
|
|
3193
|
+
setHeading,
|
|
3060
3194
|
setSelection,
|
|
3061
3195
|
table,
|
|
3062
3196
|
tags2 as tags,
|
|
3063
3197
|
tasklist,
|
|
3064
3198
|
textTheme,
|
|
3199
|
+
toggleBold,
|
|
3200
|
+
toggleItalic,
|
|
3201
|
+
toggleList,
|
|
3202
|
+
toggleStrikethrough,
|
|
3203
|
+
toggleStyle,
|
|
3065
3204
|
typewriter,
|
|
3066
|
-
|
|
3067
|
-
|
|
3205
|
+
useActionHandler,
|
|
3206
|
+
useComments,
|
|
3207
|
+
useTextEditor,
|
|
3208
|
+
useTextModel
|
|
3068
3209
|
};
|
|
3069
3210
|
//# sourceMappingURL=index.mjs.map
|