@dxos/react-ui-editor 0.3.11-main.7e75884 → 0.3.11-main.800163e
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 +1747 -1307
- 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/TextEditor/hooks.stories.d.ts +23 -0
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +24 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +24 -0
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/index.d.ts +2 -0
- package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +9 -11
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/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 -7
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts +13 -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 +4 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useEditorView.d.ts +17 -0
- package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -32
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +48 -37
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +84 -90
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +136 -95
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/components/TextEditor/hooks.stories.tsx +106 -0
- package/src/components/Toolbar/Toolbar.stories.tsx +90 -0
- package/src/components/Toolbar/Toolbar.tsx +163 -0
- package/src/components/Toolbar/index.ts +5 -0
- package/src/components/index.ts +1 -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 +17 -10
- package/src/extensions/comments.ts +320 -264
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -7
- package/src/extensions/markdown/bundle.ts +23 -28
- package/src/extensions/markdown/code.ts +142 -0
- package/src/extensions/markdown/formatting.ts +188 -0
- package/src/extensions/markdown/heading.ts +59 -0
- package/src/extensions/markdown/highlight.ts +9 -23
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/{image.ts → markdown/image.ts} +2 -2
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +12 -9
- package/src/extensions/{table.ts → markdown/table.ts} +6 -3
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +5 -2
- package/src/hooks/useActionHandler.ts +62 -0
- package/src/hooks/useEditorView.ts +29 -0
- package/src/hooks/useTextEditor.ts +153 -0
- package/src/hooks/useTextModel.ts +50 -59
- package/src/index.ts +2 -0
- package/src/styles/markdown.ts +9 -12
- package/src/themes/default.ts +19 -52
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/dist/types/src/util/cursor.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -3
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/util.d.ts +0 -5
- package/dist/types/src/util/util.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -98
- package/src/extensions/hr.ts +0 -73
- package/src/extensions/tasklist.ts +0 -119
- package/src/extensions/yjs/cursor.ts +0 -21
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -178
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- package/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
|
@@ -7,56 +7,60 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
7
7
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
9
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
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 as isNotFalsy3 } 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({
|
|
@@ -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,7 +505,7 @@ 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++) {
|
|
@@ -484,7 +516,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
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,29 @@ 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
|
-
|
|
610
|
-
|
|
611
|
-
|
|
638
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
639
|
+
import { isNotFalsy } from "@dxos/util";
|
|
640
|
+
var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
|
|
641
|
+
lineWrapping && EditorView3.lineWrapping,
|
|
612
642
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
613
643
|
bracketMatching(),
|
|
614
644
|
closeBrackets(),
|
|
615
645
|
drawSelection(),
|
|
646
|
+
highlightActiveLine(),
|
|
647
|
+
history(),
|
|
616
648
|
_placeholder && placeholder(_placeholder),
|
|
617
|
-
//
|
|
649
|
+
// https://github.com/codemirror/theme-one-dark
|
|
618
650
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
619
|
-
].filter(
|
|
651
|
+
].filter(isNotFalsy);
|
|
620
652
|
|
|
621
653
|
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
622
|
-
import { EditorView as
|
|
654
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
623
655
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
624
656
|
import { invariant } from "@dxos/invariant";
|
|
625
|
-
var
|
|
657
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
626
658
|
var defaultOptions = {
|
|
627
659
|
effect: 2,
|
|
628
660
|
maxParticles: 200,
|
|
@@ -655,10 +687,10 @@ var blast = (options = defaultOptions) => {
|
|
|
655
687
|
const getPoint = (view, pos) => {
|
|
656
688
|
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
657
689
|
const element = document.elementFromPoint(x, y);
|
|
658
|
-
const { offsetLeft: left = 0, offsetTop:
|
|
690
|
+
const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
|
|
659
691
|
const point = {
|
|
660
692
|
x: x - left,
|
|
661
|
-
y: y -
|
|
693
|
+
y: y - top2
|
|
662
694
|
};
|
|
663
695
|
return {
|
|
664
696
|
element,
|
|
@@ -667,7 +699,7 @@ var blast = (options = defaultOptions) => {
|
|
|
667
699
|
};
|
|
668
700
|
return [
|
|
669
701
|
// Cursor moved.
|
|
670
|
-
|
|
702
|
+
EditorView4.updateListener.of((update2) => {
|
|
671
703
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
704
|
if (blaster) {
|
|
673
705
|
blaster.destroy();
|
|
@@ -749,7 +781,7 @@ var Blaster = class {
|
|
|
749
781
|
}
|
|
750
782
|
initialize() {
|
|
751
783
|
invariant(!this._canvas && !this._ctx, void 0, {
|
|
752
|
-
F:
|
|
784
|
+
F: __dxlog_file,
|
|
753
785
|
L: 138,
|
|
754
786
|
S: this,
|
|
755
787
|
A: [
|
|
@@ -786,7 +818,7 @@ var Blaster = class {
|
|
|
786
818
|
}
|
|
787
819
|
start() {
|
|
788
820
|
invariant(this._canvas && this._ctx, void 0, {
|
|
789
|
-
F:
|
|
821
|
+
F: __dxlog_file,
|
|
790
822
|
L: 177,
|
|
791
823
|
S: this,
|
|
792
824
|
A: [
|
|
@@ -928,9 +960,14 @@ var random = (min, max) => {
|
|
|
928
960
|
return min + ~~(Math.random() * (max - min + 1));
|
|
929
961
|
};
|
|
930
962
|
|
|
931
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
932
|
-
import {
|
|
933
|
-
import {
|
|
963
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
964
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
965
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
966
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
967
|
+
import sortBy from "lodash.sortby";
|
|
968
|
+
import { useEffect } from "react";
|
|
969
|
+
import { debounce } from "@dxos/async";
|
|
970
|
+
import { nonNullable } from "@dxos/util";
|
|
934
971
|
|
|
935
972
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
936
973
|
import * as random2 from "lib0/random";
|
|
@@ -973,34 +1010,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
973
1010
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
974
1011
|
import { mx } from "@dxos/react-ui-theme";
|
|
975
1012
|
var headings = {
|
|
976
|
-
1:
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
986
|
-
"-ml-[7px]"
|
|
987
|
-
],
|
|
988
|
-
4: [
|
|
989
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
990
|
-
"-ml-[6px]"
|
|
991
|
-
],
|
|
992
|
-
5: [
|
|
993
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
994
|
-
"-ml-[5px]"
|
|
995
|
-
],
|
|
996
|
-
6: [
|
|
997
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
998
|
-
"-ml-[4px]"
|
|
999
|
-
]
|
|
1000
|
-
};
|
|
1001
|
-
var heading = (level, readonly) => {
|
|
1002
|
-
const [style, offset] = headings[level];
|
|
1003
|
-
return mx(style, readonly && offset);
|
|
1013
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1014
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1015
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1016
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1017
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1018
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1019
|
+
};
|
|
1020
|
+
var heading = (level) => {
|
|
1021
|
+
return headings[level];
|
|
1004
1022
|
};
|
|
1005
1023
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1006
1024
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1018,154 +1036,109 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
|
1018
1036
|
var tokens = tailwindConfig({}).theme;
|
|
1019
1037
|
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1020
1038
|
|
|
1021
|
-
// packages/ui/react-ui-editor/src/
|
|
1022
|
-
|
|
1023
|
-
var
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
display: "block",
|
|
1035
|
-
paddingInline: "4px !important"
|
|
1036
|
-
},
|
|
1037
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1038
|
-
paddingTop: "4px !important",
|
|
1039
|
-
borderTopLeftRadius: "4px",
|
|
1040
|
-
borderTopRightRadius: "4px"
|
|
1041
|
-
},
|
|
1042
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1043
|
-
paddingBottom: "4px !important",
|
|
1044
|
-
borderBottomLeftRadius: "4px",
|
|
1045
|
-
borderBottomRightRadius: "4px"
|
|
1039
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1040
|
+
import { log } from "@dxos/log";
|
|
1041
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1042
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1043
|
+
try {
|
|
1044
|
+
return fn(...args);
|
|
1045
|
+
} catch (err) {
|
|
1046
|
+
log.catch(err, void 0, {
|
|
1047
|
+
F: __dxlog_file2,
|
|
1048
|
+
L: 18,
|
|
1049
|
+
S: void 0,
|
|
1050
|
+
C: (f, a) => f(...a)
|
|
1051
|
+
});
|
|
1046
1052
|
}
|
|
1047
|
-
});
|
|
1048
|
-
var getLineRange = (lines, from, to) => {
|
|
1049
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1050
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1051
|
-
return [
|
|
1052
|
-
start,
|
|
1053
|
-
end
|
|
1054
|
-
];
|
|
1055
1053
|
};
|
|
1056
|
-
var
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
const text = view.state.doc.sliceString(0);
|
|
1061
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1062
|
-
const blocks = view.viewportLineBlocks;
|
|
1063
|
-
for (const match of matches) {
|
|
1064
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1065
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1066
|
-
const block = blocks[i];
|
|
1067
|
-
decorations.push(Decoration2.line({
|
|
1068
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1069
|
-
}).range(block.from));
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1054
|
+
var logChanges = (trs) => {
|
|
1055
|
+
const changes = trs.flatMap((tr) => {
|
|
1056
|
+
if (tr.changes.empty) {
|
|
1057
|
+
return void 0;
|
|
1072
1058
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
decorations: (value) => value.decorations
|
|
1087
|
-
}),
|
|
1088
|
-
styles2
|
|
1089
|
-
];
|
|
1059
|
+
const changes2 = [];
|
|
1060
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1061
|
+
fromA,
|
|
1062
|
+
toA,
|
|
1063
|
+
fromB,
|
|
1064
|
+
toB,
|
|
1065
|
+
inserted: inserted.toString()
|
|
1066
|
+
})));
|
|
1067
|
+
return changes2;
|
|
1068
|
+
}).filter(Boolean);
|
|
1069
|
+
if (changes.length) {
|
|
1070
|
+
console.log("changes", changes);
|
|
1071
|
+
}
|
|
1090
1072
|
};
|
|
1091
1073
|
|
|
1092
1074
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1093
|
-
|
|
1094
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
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
|
-
},
|
|
1075
|
+
var styles2 = EditorView5.baseTheme({
|
|
1111
1076
|
"& .cm-comment": {
|
|
1112
1077
|
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1078
|
},
|
|
1114
|
-
"& .cm-comment-
|
|
1079
|
+
"& .cm-comment-current": {
|
|
1115
1080
|
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1116
1081
|
}
|
|
1117
1082
|
});
|
|
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) {
|
|
1083
|
+
var commentMark = Decoration2.mark({
|
|
1084
|
+
class: "cm-comment"
|
|
1085
|
+
});
|
|
1086
|
+
var commentCurrentMark = Decoration2.mark({
|
|
1087
|
+
class: "cm-comment-current"
|
|
1088
|
+
});
|
|
1089
|
+
var focusComment = (view, id, center = true) => {
|
|
1090
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1091
|
+
if (!comment?.comment.cursor) {
|
|
1129
1092
|
return;
|
|
1130
1093
|
}
|
|
1131
|
-
view.
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1094
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1095
|
+
if (range) {
|
|
1096
|
+
view.dispatch({
|
|
1097
|
+
selection: {
|
|
1098
|
+
anchor: range.from
|
|
1099
|
+
},
|
|
1100
|
+
effects: [
|
|
1101
|
+
//
|
|
1102
|
+
EditorView5.scrollIntoView(range.from, center ? {
|
|
1103
|
+
y: "center"
|
|
1104
|
+
} : void 0),
|
|
1105
|
+
setSelection.of({
|
|
1106
|
+
current: id
|
|
1107
|
+
})
|
|
1108
|
+
]
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1140
1111
|
};
|
|
1141
|
-
var
|
|
1112
|
+
var setComments = StateEffect2.define();
|
|
1142
1113
|
var setSelection = StateEffect2.define();
|
|
1143
1114
|
var setCommentState = StateEffect2.define();
|
|
1144
|
-
var
|
|
1115
|
+
var commentsState = StateField2.define({
|
|
1145
1116
|
create: () => ({
|
|
1146
|
-
|
|
1117
|
+
comments: [],
|
|
1118
|
+
selection: {}
|
|
1147
1119
|
}),
|
|
1148
1120
|
update: (value, tr) => {
|
|
1149
|
-
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1150
1121
|
for (const effect of tr.effects) {
|
|
1151
1122
|
if (effect.is(setSelection)) {
|
|
1152
1123
|
return {
|
|
1153
1124
|
...value,
|
|
1154
|
-
|
|
1125
|
+
selection: effect.value
|
|
1155
1126
|
};
|
|
1156
1127
|
}
|
|
1157
|
-
if (effect.is(
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1128
|
+
if (effect.is(setComments)) {
|
|
1129
|
+
const comments2 = effect.value.map((comment) => {
|
|
1130
|
+
if (!comment.cursor) {
|
|
1131
|
+
return void 0;
|
|
1132
|
+
}
|
|
1133
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1161
1134
|
return range && {
|
|
1162
|
-
|
|
1163
|
-
|
|
1135
|
+
comment,
|
|
1136
|
+
range
|
|
1164
1137
|
};
|
|
1165
1138
|
}).filter(nonNullable);
|
|
1166
1139
|
return {
|
|
1167
1140
|
...value,
|
|
1168
|
-
|
|
1141
|
+
comments: comments2
|
|
1169
1142
|
};
|
|
1170
1143
|
}
|
|
1171
1144
|
if (effect.is(setCommentState)) {
|
|
@@ -1175,143 +1148,174 @@ var commentsStateField = StateField2.define({
|
|
|
1175
1148
|
return value;
|
|
1176
1149
|
}
|
|
1177
1150
|
});
|
|
1178
|
-
var
|
|
1179
|
-
|
|
1151
|
+
var commentsDecorations = EditorView5.decorations.compute([
|
|
1152
|
+
commentsState
|
|
1180
1153
|
], (state) => {
|
|
1181
|
-
const {
|
|
1182
|
-
const decorations = sortBy(
|
|
1183
|
-
|
|
1154
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1155
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1156
|
+
const range = comment.range;
|
|
1157
|
+
if (!range || range.from === range.to) {
|
|
1158
|
+
console.warn("Invalid range:", range);
|
|
1184
1159
|
return void 0;
|
|
1185
1160
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
to: selection.to
|
|
1189
|
-
};
|
|
1190
|
-
if (selection.id === active) {
|
|
1191
|
-
return marks.highlightActive.range(range.from, range.to);
|
|
1161
|
+
if (comment.comment.id === current) {
|
|
1162
|
+
return commentCurrentMark.range(range.from, range.to);
|
|
1192
1163
|
} else {
|
|
1193
|
-
return
|
|
1164
|
+
return commentMark.range(range.from, range.to);
|
|
1194
1165
|
}
|
|
1195
|
-
}).filter(nonNullable)
|
|
1196
|
-
return
|
|
1166
|
+
}).filter(nonNullable);
|
|
1167
|
+
return Decoration2.set(decorations);
|
|
1197
1168
|
});
|
|
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: 224,
|
|
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;
|
|
1169
|
+
var trackPastedComments = (onUpdate) => {
|
|
1170
|
+
let tracked = null;
|
|
1171
|
+
const handleTrack = (event, view) => {
|
|
1172
|
+
const comments2 = view.state.field(commentsState);
|
|
1173
|
+
const { main } = view.state.selection;
|
|
1174
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1175
|
+
if (!selectedRanges.length) {
|
|
1176
|
+
tracked = null;
|
|
1177
|
+
} else {
|
|
1178
|
+
tracked = {
|
|
1179
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1180
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1181
|
+
id: comment.id,
|
|
1182
|
+
from: range.from - main.from,
|
|
1183
|
+
to: range.to - main.from
|
|
1184
|
+
}))
|
|
1185
|
+
};
|
|
1243
1186
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1187
|
+
};
|
|
1188
|
+
return [
|
|
1189
|
+
EditorView5.domEventHandlers({
|
|
1190
|
+
cut: handleTrack,
|
|
1191
|
+
copy: handleTrack
|
|
1192
|
+
}),
|
|
1193
|
+
// Track deleted comments.
|
|
1194
|
+
invertedEffects2.of((tr) => {
|
|
1195
|
+
const { comments: comments2 } = tr.startState.field(commentsState);
|
|
1196
|
+
const effects = [];
|
|
1197
|
+
tr.changes.iterChangedRanges((fromA, toA) => {
|
|
1198
|
+
for (const { comment: { id }, range: { from, to } } of comments2) {
|
|
1199
|
+
if (from < to && from >= fromA && to <= toA) {
|
|
1200
|
+
effects.push(restoreCommentEffect.of({
|
|
1201
|
+
id,
|
|
1202
|
+
from,
|
|
1203
|
+
to
|
|
1204
|
+
}));
|
|
1257
1205
|
}
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
return effects;
|
|
1209
|
+
}),
|
|
1210
|
+
// Handle paste or the undo of comment deletion.
|
|
1211
|
+
EditorView5.updateListener.of((update2) => {
|
|
1212
|
+
const restore = [];
|
|
1213
|
+
for (let i = 0; i < update2.transactions.length; i++) {
|
|
1214
|
+
const tr = update2.transactions[i];
|
|
1215
|
+
for (let j = 0; j < restore.length; j++) {
|
|
1216
|
+
restore[j] = mapTrackedComment(restore[j], tr.changes);
|
|
1217
|
+
}
|
|
1218
|
+
for (const effect of tr.effects) {
|
|
1219
|
+
if (effect.is(restoreCommentEffect)) {
|
|
1220
|
+
restore.push(effect.value);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (tracked) {
|
|
1225
|
+
const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1226
|
+
if (paste) {
|
|
1227
|
+
let found = -1;
|
|
1228
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1229
|
+
if (text.eq(tracked.text)) {
|
|
1230
|
+
for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
|
|
1231
|
+
fromB = update2.transactions[i].changes.mapPos(fromB);
|
|
1232
|
+
}
|
|
1233
|
+
found = fromB;
|
|
1268
1234
|
}
|
|
1269
1235
|
});
|
|
1236
|
+
if (found > -1) {
|
|
1237
|
+
for (const moved of tracked.comments) {
|
|
1238
|
+
restore.push({
|
|
1239
|
+
id: moved.id,
|
|
1240
|
+
from: found + moved.from,
|
|
1241
|
+
to: found + moved.to
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
tracked = null;
|
|
1270
1246
|
}
|
|
1271
|
-
return true;
|
|
1272
1247
|
}
|
|
1273
|
-
|
|
1248
|
+
for (const comment of restore) {
|
|
1249
|
+
const { comments: comments2 } = update2.startState.field(commentsState);
|
|
1250
|
+
const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
|
|
1251
|
+
if (!exists) {
|
|
1252
|
+
const cursor = Cursor.getCursorFromRange(update2.state, comment);
|
|
1253
|
+
onUpdate(comment.id, cursor);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
})
|
|
1257
|
+
];
|
|
1258
|
+
};
|
|
1259
|
+
var mapTrackedComment = (comment, changes) => ({
|
|
1260
|
+
id: comment.id,
|
|
1261
|
+
from: changes.mapPos(comment.from, 1),
|
|
1262
|
+
to: changes.mapPos(comment.to, 1)
|
|
1263
|
+
});
|
|
1264
|
+
var restoreCommentEffect = StateEffect2.define({
|
|
1265
|
+
map: mapTrackedComment
|
|
1266
|
+
});
|
|
1267
|
+
var optionsFacet = Facet3.define({
|
|
1268
|
+
combine: (providers) => providers[0]
|
|
1269
|
+
});
|
|
1270
|
+
var createComment = (view) => {
|
|
1271
|
+
const options = view.state.facet(optionsFacet);
|
|
1272
|
+
const { from, to } = view.state.selection.main;
|
|
1273
|
+
if (from === to) {
|
|
1274
1274
|
return false;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1275
|
+
}
|
|
1276
|
+
if (to === view.state.doc.length) {
|
|
1277
|
+
view.dispatch({
|
|
1278
|
+
changes: {
|
|
1279
|
+
from: to,
|
|
1280
|
+
insert: "\n"
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1285
|
+
from,
|
|
1286
|
+
to
|
|
1287
|
+
});
|
|
1288
|
+
if (cursor) {
|
|
1289
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1290
|
+
if (id) {
|
|
1291
|
+
view.dispatch({
|
|
1292
|
+
effects: setSelection.of({
|
|
1293
|
+
current: id
|
|
1294
|
+
}),
|
|
1295
|
+
selection: {
|
|
1296
|
+
anchor: to
|
|
1288
1297
|
}
|
|
1289
1298
|
});
|
|
1299
|
+
return true;
|
|
1290
1300
|
}
|
|
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
|
-
});
|
|
1301
|
+
}
|
|
1302
|
+
return false;
|
|
1303
|
+
};
|
|
1304
|
+
var comments = (options = {}) => {
|
|
1305
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1306
|
+
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1303
1307
|
return [
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
+
optionsFacet.of(options),
|
|
1309
|
+
commentsState,
|
|
1310
|
+
commentsDecorations,
|
|
1311
|
+
styles2,
|
|
1308
1312
|
//
|
|
1309
1313
|
// Keymap.
|
|
1310
1314
|
//
|
|
1311
1315
|
options.onCreate ? keymap3.of([
|
|
1312
1316
|
{
|
|
1313
|
-
key:
|
|
1314
|
-
run: callbackWrapper(
|
|
1317
|
+
key: shortcut,
|
|
1318
|
+
run: callbackWrapper(createComment)
|
|
1315
1319
|
}
|
|
1316
1320
|
]) : [],
|
|
1317
1321
|
//
|
|
@@ -1327,7 +1331,7 @@ var comments = (options = {}) => {
|
|
|
1327
1331
|
above: true,
|
|
1328
1332
|
create: () => {
|
|
1329
1333
|
const el = document.createElement("div");
|
|
1330
|
-
options.onHover
|
|
1334
|
+
options.onHover(el, shortcut);
|
|
1331
1335
|
return {
|
|
1332
1336
|
dom: el,
|
|
1333
1337
|
offset: {
|
|
@@ -1340,366 +1344,100 @@ var comments = (options = {}) => {
|
|
|
1340
1344
|
}
|
|
1341
1345
|
return null;
|
|
1342
1346
|
}, {
|
|
1343
|
-
|
|
1347
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1348
|
+
// hideOnChange: true,
|
|
1344
1349
|
hoverTime: 1e3
|
|
1345
1350
|
}) : [],
|
|
1346
1351
|
//
|
|
1347
|
-
//
|
|
1348
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1352
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1349
1353
|
//
|
|
1350
1354
|
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: 358,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1355
|
+
let mod = false;
|
|
1356
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1357
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1358
|
+
comments2.forEach(({ comment, range }) => {
|
|
1359
|
+
if (from2 === to2) {
|
|
1360
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1361
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1362
|
+
options.onDelete?.(comment.id);
|
|
1369
1363
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1364
|
+
}
|
|
1365
|
+
if (from <= range.to) {
|
|
1366
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1367
|
+
Object.assign(range, newRange);
|
|
1368
|
+
mod = true;
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
});
|
|
1372
|
+
if (mod) {
|
|
1373
|
+
view.dispatch({
|
|
1374
|
+
effects: setCommentState.of({
|
|
1375
|
+
comments: comments2,
|
|
1376
|
+
...value
|
|
1377
|
+
})
|
|
1376
1378
|
});
|
|
1377
|
-
if (mod) {
|
|
1378
|
-
view.dispatch({
|
|
1379
|
-
effects: setCommentState.of({
|
|
1380
|
-
active,
|
|
1381
|
-
ranges
|
|
1382
|
-
})
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
1379
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1380
|
+
}),
|
|
1381
|
+
//
|
|
1382
|
+
// Track selection/proximity.
|
|
1383
|
+
//
|
|
1384
|
+
EditorView5.updateListener.of(({ view, state }) => {
|
|
1385
|
+
let min = Infinity;
|
|
1386
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1387
|
+
const { head } = state.selection.main;
|
|
1388
|
+
const selection = {};
|
|
1389
|
+
comments2.forEach(({ comment, range }) => {
|
|
1390
|
+
if (head >= range.from && head <= range.to) {
|
|
1391
|
+
selection.current = comment.id;
|
|
1392
|
+
selection.closest = void 0;
|
|
1393
|
+
}
|
|
1394
|
+
if (!selection.current) {
|
|
1395
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1399
1396
|
if (d < min) {
|
|
1400
|
-
|
|
1397
|
+
selection.closest = comment.id;
|
|
1401
1398
|
min = d;
|
|
1402
1399
|
}
|
|
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
1400
|
}
|
|
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 !== void 0 && to !== void 0 ? {
|
|
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
|
-
var styles4 = EditorView6.baseTheme({
|
|
1441
|
-
"& .cm-hr": {
|
|
1442
|
-
// TODO(burdon): ???
|
|
1443
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1444
|
-
borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1445
|
-
}
|
|
1446
|
-
});
|
|
1447
|
-
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1448
|
-
constructor(_pos) {
|
|
1449
|
-
super();
|
|
1450
|
-
this._pos = _pos;
|
|
1451
|
-
}
|
|
1452
|
-
eq(other) {
|
|
1453
|
-
return this._pos === other._pos;
|
|
1454
|
-
}
|
|
1455
|
-
toDOM(view) {
|
|
1456
|
-
const el = document.createElement("div");
|
|
1457
|
-
el.className = "cm-hr";
|
|
1458
|
-
return el;
|
|
1459
|
-
}
|
|
1460
|
-
};
|
|
1461
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1462
|
-
regexp: /^---$/g,
|
|
1463
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1464
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1465
|
-
})
|
|
1466
|
-
});
|
|
1467
|
-
var hr = () => [
|
|
1468
|
-
styles4,
|
|
1469
|
-
ViewPlugin5.fromClass(class {
|
|
1470
|
-
constructor(view) {
|
|
1471
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1472
|
-
}
|
|
1473
|
-
update(update2) {
|
|
1474
|
-
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1475
|
-
}
|
|
1476
|
-
}, {
|
|
1477
|
-
decorations: (instance) => instance.rules,
|
|
1478
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1479
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1480
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1481
|
-
})
|
|
1482
|
-
})
|
|
1483
|
-
];
|
|
1484
|
-
|
|
1485
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1486
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1487
|
-
import { StateField as StateField3 } from "@codemirror/state";
|
|
1488
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1489
|
-
var image = (options = {}) => {
|
|
1490
|
-
return StateField3.define({
|
|
1491
|
-
create: (state) => {
|
|
1492
|
-
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1493
|
-
},
|
|
1494
|
-
update: (value, tr) => {
|
|
1495
|
-
if (!tr.docChanged && !tr.selection) {
|
|
1496
|
-
return value;
|
|
1497
|
-
}
|
|
1498
|
-
const cursor = tr.state.selection.main.head;
|
|
1499
|
-
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1500
|
-
let from = Math.min(cursor, oldCursor);
|
|
1501
|
-
let to = Math.max(cursor, oldCursor);
|
|
1502
|
-
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1503
|
-
from = Math.min(from, fromB);
|
|
1504
|
-
to = Math.max(to, toB);
|
|
1505
|
-
});
|
|
1506
|
-
from = tr.state.doc.lineAt(from).from;
|
|
1507
|
-
to = tr.state.doc.lineAt(to).to;
|
|
1508
|
-
return value.map(tr.changes).update({
|
|
1509
|
-
filterFrom: from,
|
|
1510
|
-
filterTo: to,
|
|
1511
|
-
filter: () => false,
|
|
1512
|
-
add: buildDecorations(from, to, tr.state)
|
|
1513
1401
|
});
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
};
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1527
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1528
|
-
decorations.push(Decoration5.replace({
|
|
1529
|
-
block: true,
|
|
1530
|
-
widget: new ImageWidget(url)
|
|
1531
|
-
}).range(hide ? node.from : node.to, node.to));
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
},
|
|
1535
|
-
from,
|
|
1536
|
-
to
|
|
1537
|
-
});
|
|
1538
|
-
return decorations;
|
|
1539
|
-
};
|
|
1540
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1541
|
-
constructor(_url) {
|
|
1542
|
-
super();
|
|
1543
|
-
this._url = _url;
|
|
1544
|
-
}
|
|
1545
|
-
eq(other) {
|
|
1546
|
-
return this._url === other._url;
|
|
1547
|
-
}
|
|
1548
|
-
toDOM(view) {
|
|
1549
|
-
const img = document.createElement("img");
|
|
1550
|
-
img.setAttribute("src", this._url);
|
|
1551
|
-
img.setAttribute("class", "cm-image");
|
|
1552
|
-
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1553
|
-
return img;
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
|
|
1557
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1558
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1559
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
1560
|
-
import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
1561
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1562
|
-
var link = (options = {}) => {
|
|
1563
|
-
const extensions = [
|
|
1564
|
-
ViewPlugin6.fromClass(class {
|
|
1565
|
-
constructor(view) {
|
|
1566
|
-
this.decorations = buildDecorations2(view, options);
|
|
1567
|
-
}
|
|
1568
|
-
update(update2) {
|
|
1569
|
-
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1570
|
-
this.decorations = buildDecorations2(update2.view, options);
|
|
1571
|
-
}
|
|
1402
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1403
|
+
view.dispatch({
|
|
1404
|
+
effects: setSelection.of(selection)
|
|
1405
|
+
});
|
|
1406
|
+
handleSelect({
|
|
1407
|
+
selection,
|
|
1408
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1409
|
+
comment,
|
|
1410
|
+
range,
|
|
1411
|
+
location: view.coordsAtPos(range.from)
|
|
1412
|
+
}))
|
|
1413
|
+
});
|
|
1572
1414
|
}
|
|
1573
|
-
},
|
|
1574
|
-
|
|
1575
|
-
})
|
|
1415
|
+
}),
|
|
1416
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1576
1417
|
];
|
|
1577
|
-
if (options.onHover) {
|
|
1578
|
-
extensions.push(
|
|
1579
|
-
// https://codemirror.net/examples/tooltip
|
|
1580
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1581
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1582
|
-
hoverTooltip2((view, pos, side) => {
|
|
1583
|
-
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1584
|
-
let link2 = null;
|
|
1585
|
-
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1586
|
-
link2 = node.name === "Link" ? node : null;
|
|
1587
|
-
}
|
|
1588
|
-
const url = link2 && link2.getChild("URL");
|
|
1589
|
-
if (!url || !link2) {
|
|
1590
|
-
return null;
|
|
1591
|
-
}
|
|
1592
|
-
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1593
|
-
return {
|
|
1594
|
-
pos: link2.from,
|
|
1595
|
-
end: link2.to,
|
|
1596
|
-
above: true,
|
|
1597
|
-
create: () => {
|
|
1598
|
-
const el = document.createElement("div");
|
|
1599
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1600
|
-
options.onHover(el, urlText);
|
|
1601
|
-
return {
|
|
1602
|
-
dom: el,
|
|
1603
|
-
offset: {
|
|
1604
|
-
x: 0,
|
|
1605
|
-
y: 4
|
|
1606
|
-
}
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
};
|
|
1610
|
-
})
|
|
1611
|
-
);
|
|
1612
|
-
}
|
|
1613
|
-
return extensions;
|
|
1614
|
-
};
|
|
1615
|
-
var LinkButton = class extends WidgetType5 {
|
|
1616
|
-
constructor(_url, _onAttach) {
|
|
1617
|
-
super();
|
|
1618
|
-
this._url = _url;
|
|
1619
|
-
this._onAttach = _onAttach;
|
|
1620
|
-
}
|
|
1621
|
-
eq(other) {
|
|
1622
|
-
return this._url === other._url;
|
|
1623
|
-
}
|
|
1624
|
-
toDOM(view) {
|
|
1625
|
-
const el = document.createElement("span");
|
|
1626
|
-
this._onAttach(el, this._url);
|
|
1627
|
-
return el;
|
|
1628
|
-
}
|
|
1629
1418
|
};
|
|
1630
|
-
var
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
eq(other) {
|
|
1637
|
-
return this._url === other._url;
|
|
1638
|
-
}
|
|
1639
|
-
toDOM(view) {
|
|
1640
|
-
const link2 = document.createElement("a");
|
|
1641
|
-
link2.setAttribute("class", "cm-link");
|
|
1642
|
-
link2.textContent = this._text;
|
|
1643
|
-
if (this._url) {
|
|
1644
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1645
|
-
link2.setAttribute("target", "_blank");
|
|
1646
|
-
link2.href = this._url;
|
|
1647
|
-
} else {
|
|
1648
|
-
link2.onclick = () => {
|
|
1649
|
-
view.dispatch({
|
|
1650
|
-
selection: {
|
|
1651
|
-
anchor: view.posAtDOM(link2)
|
|
1652
|
-
}
|
|
1653
|
-
});
|
|
1654
|
-
};
|
|
1419
|
+
var useComments = (view, comments2 = []) => {
|
|
1420
|
+
useEffect(() => {
|
|
1421
|
+
if (view) {
|
|
1422
|
+
view.dispatch({
|
|
1423
|
+
effects: setComments.of(comments2)
|
|
1424
|
+
});
|
|
1655
1425
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
const builder = new RangeSetBuilder();
|
|
1661
|
-
const { state } = view;
|
|
1662
|
-
const cursor = state.selection.main.head;
|
|
1663
|
-
for (const { from, to } of view.visibleRanges) {
|
|
1664
|
-
syntaxTree2(state).iterate({
|
|
1665
|
-
enter: (node) => {
|
|
1666
|
-
if (node.name === "Link") {
|
|
1667
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1668
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1669
|
-
const urlNode = node.node.getChild("URL");
|
|
1670
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1671
|
-
if (!url) {
|
|
1672
|
-
return false;
|
|
1673
|
-
}
|
|
1674
|
-
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1675
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1676
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1677
|
-
}));
|
|
1678
|
-
}
|
|
1679
|
-
if (options.onRender) {
|
|
1680
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1681
|
-
widget: new LinkButton(url, options.onRender)
|
|
1682
|
-
}));
|
|
1683
|
-
}
|
|
1684
|
-
return false;
|
|
1685
|
-
}
|
|
1686
|
-
},
|
|
1687
|
-
from,
|
|
1688
|
-
to
|
|
1689
|
-
});
|
|
1690
|
-
}
|
|
1691
|
-
return builder.finish();
|
|
1426
|
+
}, [
|
|
1427
|
+
view,
|
|
1428
|
+
comments2
|
|
1429
|
+
]);
|
|
1692
1430
|
};
|
|
1693
1431
|
|
|
1694
1432
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1695
|
-
import { EditorView as
|
|
1433
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1696
1434
|
var listener = ({ onFocus, onChange }) => {
|
|
1697
1435
|
const extensions = [];
|
|
1698
|
-
onFocus && extensions.push(
|
|
1436
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1699
1437
|
onFocus(focused);
|
|
1700
1438
|
return null;
|
|
1701
1439
|
}));
|
|
1702
|
-
onChange && extensions.push(
|
|
1440
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1703
1441
|
onChange(update2.state.doc.toString());
|
|
1704
1442
|
}));
|
|
1705
1443
|
return extensions;
|
|
@@ -1707,17 +1445,18 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1707
1445
|
|
|
1708
1446
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1709
1447
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1710
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1711
|
-
import { markdownLanguage as
|
|
1448
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1449
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1712
1450
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1713
1451
|
import { languages } from "@codemirror/language-data";
|
|
1714
1452
|
import { searchKeymap } from "@codemirror/search";
|
|
1715
1453
|
import { EditorState } from "@codemirror/state";
|
|
1716
1454
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1717
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1455
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1456
|
+
import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
|
|
1718
1457
|
|
|
1719
1458
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1720
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1459
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1721
1460
|
import { HighlightStyle } from "@codemirror/language";
|
|
1722
1461
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1723
1462
|
import { Table } from "@lezer/markdown";
|
|
@@ -1727,7 +1466,6 @@ var markdownTags = {
|
|
|
1727
1466
|
CodeText: Tag.define(),
|
|
1728
1467
|
EmphasisMark: Tag.define(),
|
|
1729
1468
|
HeaderMark: Tag.define(),
|
|
1730
|
-
// HorizontalRule: Tag.define(),
|
|
1731
1469
|
InlineCode: Tag.define(),
|
|
1732
1470
|
LinkLabel: Tag.define(),
|
|
1733
1471
|
LinkReference: Tag.define(),
|
|
@@ -1812,7 +1550,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1812
1550
|
markdownTags.QuoteMark,
|
|
1813
1551
|
markdownTags.EmphasisMark
|
|
1814
1552
|
],
|
|
1815
|
-
class:
|
|
1553
|
+
class: mark
|
|
1816
1554
|
},
|
|
1817
1555
|
// E.g., code block language (after ```).
|
|
1818
1556
|
{
|
|
@@ -1820,7 +1558,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1820
1558
|
tags.function(tags.variableName),
|
|
1821
1559
|
tags.labelName
|
|
1822
1560
|
],
|
|
1823
|
-
class:
|
|
1561
|
+
class: codeMark
|
|
1824
1562
|
},
|
|
1825
1563
|
{
|
|
1826
1564
|
tag: [
|
|
@@ -1831,27 +1569,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1831
1569
|
// Headings.
|
|
1832
1570
|
{
|
|
1833
1571
|
tag: tags.heading1,
|
|
1834
|
-
class: heading(1
|
|
1572
|
+
class: heading(1)
|
|
1835
1573
|
},
|
|
1836
1574
|
{
|
|
1837
1575
|
tag: tags.heading2,
|
|
1838
|
-
class: heading(2
|
|
1576
|
+
class: heading(2)
|
|
1839
1577
|
},
|
|
1840
1578
|
{
|
|
1841
1579
|
tag: tags.heading3,
|
|
1842
|
-
class: heading(3
|
|
1580
|
+
class: heading(3)
|
|
1843
1581
|
},
|
|
1844
1582
|
{
|
|
1845
1583
|
tag: tags.heading4,
|
|
1846
|
-
class: heading(4
|
|
1584
|
+
class: heading(4)
|
|
1847
1585
|
},
|
|
1848
1586
|
{
|
|
1849
1587
|
tag: tags.heading5,
|
|
1850
|
-
class: heading(5
|
|
1588
|
+
class: heading(5)
|
|
1851
1589
|
},
|
|
1852
1590
|
{
|
|
1853
1591
|
tag: tags.heading6,
|
|
1854
|
-
class: heading(6
|
|
1592
|
+
class: heading(6)
|
|
1855
1593
|
},
|
|
1856
1594
|
// Emphasis.
|
|
1857
1595
|
{
|
|
@@ -1877,7 +1615,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1877
1615
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1878
1616
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1879
1617
|
// the code, but all other CSS properties will be inherited.
|
|
1880
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1618
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
|
|
1881
1619
|
{
|
|
1882
1620
|
tag: [
|
|
1883
1621
|
markdownTags.CodeText,
|
|
@@ -1891,12 +1629,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1891
1629
|
],
|
|
1892
1630
|
class: blockquote
|
|
1893
1631
|
},
|
|
1894
|
-
// TODO(burdon): Replace with extension.
|
|
1895
|
-
// {
|
|
1896
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1897
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1898
|
-
// },
|
|
1899
|
-
// TODO(burdon): Only if being edited.
|
|
1900
1632
|
{
|
|
1901
1633
|
tag: [
|
|
1902
1634
|
markdownTags.TableCell
|
|
@@ -1904,7 +1636,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1904
1636
|
class: "font-mono"
|
|
1905
1637
|
}
|
|
1906
1638
|
], {
|
|
1907
|
-
scope:
|
|
1639
|
+
scope: markdownLanguage2,
|
|
1908
1640
|
all: {
|
|
1909
1641
|
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1910
1642
|
}
|
|
@@ -1912,19 +1644,19 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1912
1644
|
};
|
|
1913
1645
|
|
|
1914
1646
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1915
|
-
var
|
|
1647
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1916
1648
|
return [
|
|
1649
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1917
1650
|
EditorState.allowMultipleSelections.of(true),
|
|
1918
1651
|
EditorState.tabSize.of(2),
|
|
1919
|
-
|
|
1920
|
-
customKeymap(),
|
|
1652
|
+
// https://github.com/codemirror/basic-setup
|
|
1921
1653
|
bracketMatching2(),
|
|
1922
1654
|
closeBrackets2(),
|
|
1923
1655
|
crosshairCursor(),
|
|
1924
1656
|
dropCursor(),
|
|
1925
1657
|
drawSelection2(),
|
|
1926
|
-
|
|
1927
|
-
|
|
1658
|
+
highlightActiveLine2(),
|
|
1659
|
+
history2(),
|
|
1928
1660
|
indentOnInput(),
|
|
1929
1661
|
_placeholder && placeholder2(_placeholder),
|
|
1930
1662
|
// Main extension.
|
|
@@ -1936,7 +1668,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1936
1668
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1937
1669
|
// https://github.github.com/gfm
|
|
1938
1670
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1939
|
-
base:
|
|
1671
|
+
base: markdownLanguage3,
|
|
1940
1672
|
// Languages for syntax highlighting fenced code blocks.
|
|
1941
1673
|
codeLanguages: languages,
|
|
1942
1674
|
// Parser extensions.
|
|
@@ -1948,58 +1680,601 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1948
1680
|
// https://github.com/codemirror/theme-one-dark
|
|
1949
1681
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1950
1682
|
// Custom styles.
|
|
1951
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
]);
|
|
1966
|
-
|
|
1967
|
-
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1968
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1969
|
-
var mention = ({ onSearch }) => {
|
|
1970
|
-
return autocompletion2({
|
|
1971
|
-
closeOnBlur: false,
|
|
1972
|
-
override: [
|
|
1973
|
-
(context) => {
|
|
1974
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1975
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
1976
|
-
return null;
|
|
1977
|
-
}
|
|
1978
|
-
console.log(match);
|
|
1979
|
-
return {
|
|
1980
|
-
from: match.from,
|
|
1981
|
-
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1982
|
-
label: `@${value}`
|
|
1983
|
-
}))
|
|
1984
|
-
};
|
|
1985
|
-
}
|
|
1986
|
-
]
|
|
1987
|
-
});
|
|
1683
|
+
syntaxHighlighting2(markdownHighlightStyle()),
|
|
1684
|
+
keymap4.of([
|
|
1685
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1686
|
+
indentWithTab,
|
|
1687
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1688
|
+
...closeBracketsKeymap,
|
|
1689
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1690
|
+
...historyKeymap,
|
|
1691
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1692
|
+
...searchKeymap,
|
|
1693
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1694
|
+
...standardKeymap
|
|
1695
|
+
])
|
|
1696
|
+
].filter(isNotFalsy2);
|
|
1988
1697
|
};
|
|
1989
1698
|
|
|
1990
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1699
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1700
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1701
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1702
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1703
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1704
|
+
var styles3 = EditorView8.baseTheme({
|
|
1705
|
+
"& .cm-code": {
|
|
1706
|
+
paddingInline: "1rem !important",
|
|
1707
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1708
|
+
},
|
|
1709
|
+
"& .cm-codeblock": {
|
|
1710
|
+
display: "inline-block",
|
|
1711
|
+
width: "100%",
|
|
1712
|
+
position: "relative",
|
|
1713
|
+
"&::after": {
|
|
1714
|
+
content: '""',
|
|
1715
|
+
position: "absolute",
|
|
1716
|
+
inset: 0
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
"&light .cm-codeblock": {
|
|
1720
|
+
"&::after": {
|
|
1721
|
+
background: getToken("extend.semanticColors.input.light"),
|
|
1722
|
+
mixBlendMode: "darken"
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
"&dark .cm-codeblock": {
|
|
1726
|
+
"&::after": {
|
|
1727
|
+
background: getToken("extend.semanticColors.input.dark"),
|
|
1728
|
+
mixBlendMode: "lighten"
|
|
1729
|
+
}
|
|
1730
|
+
},
|
|
1731
|
+
"& .cm-codeblock-first": {
|
|
1732
|
+
"&::after": {
|
|
1733
|
+
borderTopLeftRadius: ".5rem",
|
|
1734
|
+
borderTopRightRadius: ".5rem"
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
"& .cm-codeblock-last": {
|
|
1738
|
+
"&::after": {
|
|
1739
|
+
borderBottomLeftRadius: ".5rem",
|
|
1740
|
+
borderBottomRightRadius: ".5rem"
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1744
|
+
var getLineRange = (lines, from, to) => {
|
|
1745
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1746
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1747
|
+
return [
|
|
1748
|
+
start,
|
|
1749
|
+
end
|
|
1750
|
+
];
|
|
1751
|
+
};
|
|
1752
|
+
var LineWidget = class extends WidgetType2 {
|
|
1753
|
+
constructor(_className) {
|
|
1754
|
+
super();
|
|
1755
|
+
this._className = _className;
|
|
1756
|
+
}
|
|
1757
|
+
toDOM() {
|
|
1758
|
+
const el = document.createElement("span");
|
|
1759
|
+
el.innerHTML = " ";
|
|
1760
|
+
el.className = mx2("cm-code cm-codeblock", this._className);
|
|
1761
|
+
return el;
|
|
1762
|
+
}
|
|
1763
|
+
};
|
|
1764
|
+
var top = new LineWidget("cm-codeblock-first");
|
|
1765
|
+
var bottom = new LineWidget("cm-codeblock-last");
|
|
1766
|
+
var buildDecorations = (view) => {
|
|
1767
|
+
const builder = new RangeSetBuilder();
|
|
1768
|
+
const { state } = view;
|
|
1769
|
+
const blocks = view.viewportLineBlocks;
|
|
1770
|
+
const cursor = state.selection.main.head;
|
|
1771
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1772
|
+
syntaxTree(state).iterate({
|
|
1773
|
+
enter: (node) => {
|
|
1774
|
+
if (node.name === "FencedCode") {
|
|
1775
|
+
const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
|
|
1776
|
+
const range = getLineRange(blocks, node.from, node.to);
|
|
1777
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1778
|
+
const block = blocks[i];
|
|
1779
|
+
if (!edit && (i === range[0] || i === range[1])) {
|
|
1780
|
+
builder.add(block.from, block.to, Decoration3.replace({
|
|
1781
|
+
widget: i === range[0] ? top : bottom
|
|
1782
|
+
}));
|
|
1783
|
+
} else {
|
|
1784
|
+
builder.add(block.from, block.from, Decoration3.line({
|
|
1785
|
+
class: mx2("cm-code cm-codeblock")
|
|
1786
|
+
}));
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
},
|
|
1791
|
+
from,
|
|
1792
|
+
to
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
return builder.finish();
|
|
1796
|
+
};
|
|
1797
|
+
var code2 = () => {
|
|
1798
|
+
return [
|
|
1799
|
+
ViewPlugin3.fromClass(class {
|
|
1800
|
+
constructor(view) {
|
|
1801
|
+
this.decorations = buildDecorations(view);
|
|
1802
|
+
}
|
|
1803
|
+
update(update2) {
|
|
1804
|
+
this.decorations = buildDecorations(update2.view);
|
|
1805
|
+
}
|
|
1806
|
+
}, {
|
|
1807
|
+
decorations: (value) => value.decorations
|
|
1808
|
+
}),
|
|
1809
|
+
styles3
|
|
1810
|
+
];
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1814
|
+
import { snippet } from "@codemirror/autocomplete";
|
|
1815
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1816
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1817
|
+
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1818
|
+
var setHeading = (level) => (view) => {
|
|
1819
|
+
const { selection: { ranges }, doc } = view.state;
|
|
1820
|
+
const changes = [];
|
|
1821
|
+
for (const range of ranges) {
|
|
1822
|
+
const { number } = doc.lineAt(range.anchor);
|
|
1823
|
+
const { from, to } = doc.line(number);
|
|
1824
|
+
const line = doc.sliceString(from, to);
|
|
1825
|
+
const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
|
|
1826
|
+
const current = marks?.length ?? 0;
|
|
1827
|
+
if (level !== current) {
|
|
1828
|
+
changes.push({
|
|
1829
|
+
from,
|
|
1830
|
+
to: from + current + (spaces?.length ?? 0),
|
|
1831
|
+
insert: "#".repeat(level) + (level > 0 ? " " : "")
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
if (changes.length) {
|
|
1836
|
+
view.dispatch({
|
|
1837
|
+
changes
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
return true;
|
|
1841
|
+
};
|
|
1842
|
+
var toggleStyle = (mark2) => (view) => {
|
|
1843
|
+
const { ranges } = view.state.selection;
|
|
1844
|
+
for (const range of ranges) {
|
|
1845
|
+
if (range.from === range.to) {
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
view.dispatch({
|
|
1849
|
+
changes: [
|
|
1850
|
+
{
|
|
1851
|
+
from: range.from,
|
|
1852
|
+
insert: mark2
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
from: range.to,
|
|
1856
|
+
insert: mark2
|
|
1857
|
+
}
|
|
1858
|
+
]
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
return true;
|
|
1862
|
+
};
|
|
1863
|
+
var snippets = {
|
|
1864
|
+
codeblock: snippet([
|
|
1865
|
+
"```#{lang}",
|
|
1866
|
+
" #{}",
|
|
1867
|
+
"```"
|
|
1868
|
+
].join("\n")),
|
|
1869
|
+
table: snippet([
|
|
1870
|
+
"| #{col1} | #{col2} |",
|
|
1871
|
+
"| ---- | ---- |",
|
|
1872
|
+
"| #{val1} | #{val2} |",
|
|
1873
|
+
"| #{val3} | #{val4} |"
|
|
1874
|
+
].join("\n"))
|
|
1875
|
+
};
|
|
1876
|
+
var insertCodeblock = (view) => {
|
|
1877
|
+
const { selection: { main }, doc } = view.state;
|
|
1878
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1879
|
+
const { from } = doc.line(number);
|
|
1880
|
+
snippets.codeblock(view, null, from, from);
|
|
1881
|
+
};
|
|
1882
|
+
var insertTable = (view) => {
|
|
1883
|
+
const { selection: { main }, doc } = view.state;
|
|
1884
|
+
const { number } = doc.lineAt(main.anchor);
|
|
1885
|
+
const { from } = doc.line(number);
|
|
1886
|
+
snippets.table(view, null, from, from);
|
|
1887
|
+
};
|
|
1888
|
+
var toggleBold = toggleStyle("**");
|
|
1889
|
+
var toggleItalic = toggleStyle("_");
|
|
1890
|
+
var toggleStrikethrough = toggleStyle("~~");
|
|
1891
|
+
var toggleList = (view) => {
|
|
1892
|
+
};
|
|
1893
|
+
var formatting = (options = {}) => {
|
|
1894
|
+
return [
|
|
1895
|
+
keymap5.of([
|
|
1896
|
+
{
|
|
1897
|
+
key: "meta-b",
|
|
1898
|
+
run: toggleBold
|
|
1899
|
+
}
|
|
1900
|
+
]),
|
|
1901
|
+
styling()
|
|
1902
|
+
];
|
|
1903
|
+
};
|
|
1904
|
+
var styling = () => {
|
|
1905
|
+
const buildDecorations7 = (view) => {
|
|
1906
|
+
const builder = new RangeSetBuilder2();
|
|
1907
|
+
const { state } = view;
|
|
1908
|
+
const cursor = state.selection.main.head;
|
|
1909
|
+
const replace = (node, marks) => {
|
|
1910
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1911
|
+
for (const mark2 of marks) {
|
|
1912
|
+
builder.add(mark2.from, mark2.to, Decoration4.replace({}));
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1917
|
+
syntaxTree2(state).iterate({
|
|
1918
|
+
enter: (node) => {
|
|
1919
|
+
switch (node.name) {
|
|
1920
|
+
case "Emphasis":
|
|
1921
|
+
case "StrongEmphasis": {
|
|
1922
|
+
const marks = node.node.getChildren("EmphasisMark");
|
|
1923
|
+
replace(node, marks);
|
|
1924
|
+
break;
|
|
1925
|
+
}
|
|
1926
|
+
case "Strikethrough": {
|
|
1927
|
+
const marks = node.node.getChildren("StrikethroughMark");
|
|
1928
|
+
replace(node, marks);
|
|
1929
|
+
break;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
},
|
|
1933
|
+
from,
|
|
1934
|
+
to
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
return builder.finish();
|
|
1938
|
+
};
|
|
1939
|
+
return [
|
|
1940
|
+
ViewPlugin4.fromClass(class {
|
|
1941
|
+
constructor(view) {
|
|
1942
|
+
this.decorations = buildDecorations7(view);
|
|
1943
|
+
}
|
|
1944
|
+
update(update2) {
|
|
1945
|
+
this.decorations = buildDecorations7(update2.view);
|
|
1946
|
+
}
|
|
1947
|
+
}, {
|
|
1948
|
+
decorations: (value) => value.decorations
|
|
1949
|
+
})
|
|
1950
|
+
];
|
|
1951
|
+
};
|
|
1952
|
+
|
|
1953
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1991
1954
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1992
|
-
import { RangeSetBuilder as
|
|
1993
|
-
import { Decoration as
|
|
1955
|
+
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1956
|
+
import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
1957
|
+
var buildDecorations2 = (view) => {
|
|
1958
|
+
const builder = new RangeSetBuilder3();
|
|
1959
|
+
const { state } = view;
|
|
1960
|
+
const cursor = state.selection.main.head;
|
|
1961
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1962
|
+
syntaxTree3(state).iterate({
|
|
1963
|
+
enter: (node) => {
|
|
1964
|
+
switch (node.name) {
|
|
1965
|
+
case "ATXHeading1":
|
|
1966
|
+
case "ATXHeading2":
|
|
1967
|
+
case "ATXHeading3":
|
|
1968
|
+
case "ATXHeading4":
|
|
1969
|
+
case "ATXHeading5":
|
|
1970
|
+
case "ATXHeading6": {
|
|
1971
|
+
const mark2 = node.node.getChild("HeaderMark");
|
|
1972
|
+
if (mark2) {
|
|
1973
|
+
if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1974
|
+
builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
},
|
|
1980
|
+
from,
|
|
1981
|
+
to
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1984
|
+
return builder.finish();
|
|
1985
|
+
};
|
|
1986
|
+
var heading2 = () => {
|
|
1987
|
+
return [
|
|
1988
|
+
ViewPlugin5.fromClass(class {
|
|
1989
|
+
constructor(view) {
|
|
1990
|
+
this.decorations = buildDecorations2(view);
|
|
1991
|
+
}
|
|
1992
|
+
update(update2) {
|
|
1993
|
+
this.decorations = buildDecorations2(update2.view);
|
|
1994
|
+
}
|
|
1995
|
+
}, {
|
|
1996
|
+
decorations: (value) => value.decorations
|
|
1997
|
+
})
|
|
1998
|
+
];
|
|
1999
|
+
};
|
|
2000
|
+
|
|
2001
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2002
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2003
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2004
|
+
import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2005
|
+
var styles4 = EditorView9.baseTheme({
|
|
2006
|
+
"& .cm-hr": {
|
|
2007
|
+
// Note that block-level decorations should not have vertical margins,
|
|
2008
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
2012
|
+
toDOM() {
|
|
2013
|
+
const el = document.createElement("div");
|
|
2014
|
+
el.className = "cm-hr";
|
|
2015
|
+
return el;
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
var decoration = Decoration6.replace({
|
|
2019
|
+
widget: new HorizontalRuleWidget()
|
|
2020
|
+
});
|
|
2021
|
+
var buildDecorations3 = (view) => {
|
|
2022
|
+
const builder = new RangeSetBuilder4();
|
|
2023
|
+
const { state } = view;
|
|
2024
|
+
const cursor = state.selection.main.head;
|
|
2025
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2026
|
+
syntaxTree4(state).iterate({
|
|
2027
|
+
enter: (node) => {
|
|
2028
|
+
if (node.name === "HorizontalRule") {
|
|
2029
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
2030
|
+
builder.add(node.from, node.to, decoration);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
},
|
|
2034
|
+
from,
|
|
2035
|
+
to
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
return builder.finish();
|
|
2039
|
+
};
|
|
2040
|
+
var hr = () => {
|
|
2041
|
+
return [
|
|
2042
|
+
ViewPlugin6.fromClass(class {
|
|
2043
|
+
constructor(view) {
|
|
2044
|
+
this.decorations = buildDecorations3(view);
|
|
2045
|
+
}
|
|
2046
|
+
update(update2) {
|
|
2047
|
+
this.decorations = buildDecorations3(update2.view);
|
|
2048
|
+
}
|
|
2049
|
+
}, {
|
|
2050
|
+
decorations: (value) => value.decorations
|
|
2051
|
+
}),
|
|
2052
|
+
styles4
|
|
2053
|
+
];
|
|
2054
|
+
};
|
|
2055
|
+
|
|
2056
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2057
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2058
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
2059
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2060
|
+
var image = (options = {}) => {
|
|
2061
|
+
return StateField3.define({
|
|
2062
|
+
create: (state) => {
|
|
2063
|
+
return Decoration7.set(buildDecorations4(0, state.doc.length, state));
|
|
2064
|
+
},
|
|
2065
|
+
update: (value, tr) => {
|
|
2066
|
+
if (!tr.docChanged && !tr.selection) {
|
|
2067
|
+
return value;
|
|
2068
|
+
}
|
|
2069
|
+
const cursor = tr.state.selection.main.head;
|
|
2070
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
2071
|
+
let from = Math.min(cursor, oldCursor);
|
|
2072
|
+
let to = Math.max(cursor, oldCursor);
|
|
2073
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
2074
|
+
from = Math.min(from, fromB);
|
|
2075
|
+
to = Math.max(to, toB);
|
|
2076
|
+
});
|
|
2077
|
+
from = tr.state.doc.lineAt(from).from;
|
|
2078
|
+
to = tr.state.doc.lineAt(to).to;
|
|
2079
|
+
return value.map(tr.changes).update({
|
|
2080
|
+
filterFrom: from,
|
|
2081
|
+
filterTo: to,
|
|
2082
|
+
filter: () => false,
|
|
2083
|
+
add: buildDecorations4(from, to, tr.state)
|
|
2084
|
+
});
|
|
2085
|
+
},
|
|
2086
|
+
provide: (field) => EditorView10.decorations.from(field)
|
|
2087
|
+
});
|
|
2088
|
+
};
|
|
2089
|
+
var buildDecorations4 = (from, to, state) => {
|
|
2090
|
+
const decorations = [];
|
|
2091
|
+
const cursor = state.selection.main.head;
|
|
2092
|
+
syntaxTree5(state).iterate({
|
|
2093
|
+
enter: (node) => {
|
|
2094
|
+
if (node.name === "Image") {
|
|
2095
|
+
const urlNode = node.node.getChild("URL");
|
|
2096
|
+
if (urlNode) {
|
|
2097
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
2098
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
2099
|
+
decorations.push(Decoration7.replace({
|
|
2100
|
+
block: true,
|
|
2101
|
+
widget: new ImageWidget(url)
|
|
2102
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
},
|
|
2106
|
+
from,
|
|
2107
|
+
to
|
|
2108
|
+
});
|
|
2109
|
+
return decorations;
|
|
2110
|
+
};
|
|
2111
|
+
var ImageWidget = class extends WidgetType4 {
|
|
2112
|
+
constructor(_url) {
|
|
2113
|
+
super();
|
|
2114
|
+
this._url = _url;
|
|
2115
|
+
}
|
|
2116
|
+
eq(other) {
|
|
2117
|
+
return this._url === other._url;
|
|
2118
|
+
}
|
|
2119
|
+
toDOM(view) {
|
|
2120
|
+
const img = document.createElement("img");
|
|
2121
|
+
img.setAttribute("src", this._url);
|
|
2122
|
+
img.setAttribute("class", "cm-image");
|
|
2123
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
2124
|
+
return img;
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
|
|
2128
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
2129
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
2130
|
+
import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
|
|
2131
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
2132
|
+
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
2133
|
+
var link = (options = {}) => {
|
|
2134
|
+
const extensions = [
|
|
2135
|
+
ViewPlugin7.fromClass(class {
|
|
2136
|
+
constructor(view) {
|
|
2137
|
+
this.decorations = buildDecorations5(view, options);
|
|
2138
|
+
}
|
|
2139
|
+
update(update2) {
|
|
2140
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2141
|
+
this.decorations = buildDecorations5(update2.view, options);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
}, {
|
|
2145
|
+
decorations: (value) => value.decorations
|
|
2146
|
+
})
|
|
2147
|
+
];
|
|
2148
|
+
if (options.onHover) {
|
|
2149
|
+
extensions.push(
|
|
2150
|
+
// https://codemirror.net/examples/tooltip
|
|
2151
|
+
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
2152
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
2153
|
+
hoverTooltip2((view, pos, side) => {
|
|
2154
|
+
const syntax = syntaxTree6(view.state).resolveInner(pos, side);
|
|
2155
|
+
let link2 = null;
|
|
2156
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
2157
|
+
link2 = node.name === "Link" ? node : null;
|
|
2158
|
+
}
|
|
2159
|
+
const url = link2 && link2.getChild("URL");
|
|
2160
|
+
if (!url || !link2) {
|
|
2161
|
+
return null;
|
|
2162
|
+
}
|
|
2163
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
2164
|
+
return {
|
|
2165
|
+
pos: link2.from,
|
|
2166
|
+
end: link2.to,
|
|
2167
|
+
above: true,
|
|
2168
|
+
create: () => {
|
|
2169
|
+
const el = document.createElement("div");
|
|
2170
|
+
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
2171
|
+
options.onHover(el, urlText);
|
|
2172
|
+
return {
|
|
2173
|
+
dom: el,
|
|
2174
|
+
offset: {
|
|
2175
|
+
x: 0,
|
|
2176
|
+
y: 4
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
})
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
2184
|
+
return extensions;
|
|
2185
|
+
};
|
|
2186
|
+
var LinkButton = class extends WidgetType5 {
|
|
2187
|
+
constructor(_url, _onAttach) {
|
|
2188
|
+
super();
|
|
2189
|
+
this._url = _url;
|
|
2190
|
+
this._onAttach = _onAttach;
|
|
2191
|
+
}
|
|
2192
|
+
eq(other) {
|
|
2193
|
+
return this._url === other._url;
|
|
2194
|
+
}
|
|
2195
|
+
toDOM(view) {
|
|
2196
|
+
const el = document.createElement("span");
|
|
2197
|
+
this._onAttach(el, this._url);
|
|
2198
|
+
return el;
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
var LinkText = class extends WidgetType5 {
|
|
2202
|
+
constructor(_text, _url) {
|
|
2203
|
+
super();
|
|
2204
|
+
this._text = _text;
|
|
2205
|
+
this._url = _url;
|
|
2206
|
+
}
|
|
2207
|
+
eq(other) {
|
|
2208
|
+
return this._url === other._url;
|
|
2209
|
+
}
|
|
2210
|
+
toDOM(view) {
|
|
2211
|
+
const link2 = document.createElement("a");
|
|
2212
|
+
link2.setAttribute("class", "cm-link");
|
|
2213
|
+
link2.textContent = this._text;
|
|
2214
|
+
if (this._url) {
|
|
2215
|
+
link2.setAttribute("rel", "noreferrer");
|
|
2216
|
+
link2.setAttribute("target", "_blank");
|
|
2217
|
+
link2.href = this._url;
|
|
2218
|
+
} else {
|
|
2219
|
+
link2.onclick = () => {
|
|
2220
|
+
view.dispatch({
|
|
2221
|
+
selection: {
|
|
2222
|
+
anchor: view.posAtDOM(link2)
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
return link2;
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
var buildDecorations5 = (view, options) => {
|
|
2231
|
+
const builder = new RangeSetBuilder5();
|
|
2232
|
+
const { state } = view;
|
|
2233
|
+
const cursor = state.selection.main.head;
|
|
2234
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2235
|
+
syntaxTree6(state).iterate({
|
|
2236
|
+
enter: (node) => {
|
|
2237
|
+
if (node.name === "Link") {
|
|
2238
|
+
const marks = node.node.getChildren("LinkMark");
|
|
2239
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
2240
|
+
const urlNode = node.node.getChild("URL");
|
|
2241
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
2242
|
+
if (!url) {
|
|
2243
|
+
return false;
|
|
2244
|
+
}
|
|
2245
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
2246
|
+
builder.add(node.from, node.to, Decoration8.replace({
|
|
2247
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
2248
|
+
}));
|
|
2249
|
+
}
|
|
2250
|
+
if (options.onRender) {
|
|
2251
|
+
builder.add(node.to, node.to, Decoration8.replace({
|
|
2252
|
+
widget: new LinkButton(url, options.onRender)
|
|
2253
|
+
}));
|
|
2254
|
+
}
|
|
2255
|
+
return false;
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
from,
|
|
2259
|
+
to
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
return builder.finish();
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2266
|
+
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2267
|
+
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2268
|
+
import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1994
2269
|
var table = (options = {}) => {
|
|
1995
2270
|
return StateField4.define({
|
|
1996
2271
|
create: (state) => update(state, options),
|
|
1997
2272
|
update: (_, tr) => update(tr.state, options),
|
|
1998
|
-
provide: (field) =>
|
|
2273
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1999
2274
|
});
|
|
2000
2275
|
};
|
|
2001
2276
|
var update = (state, options) => {
|
|
2002
|
-
const builder = new
|
|
2277
|
+
const builder = new RangeSetBuilder6();
|
|
2003
2278
|
const cursor = state.selection.main.head;
|
|
2004
2279
|
const tables = [];
|
|
2005
2280
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -2007,7 +2282,7 @@ var update = (state, options) => {
|
|
|
2007
2282
|
const table2 = getTable();
|
|
2008
2283
|
return table2.rows?.[table2.rows.length - 1];
|
|
2009
2284
|
};
|
|
2010
|
-
|
|
2285
|
+
syntaxTree7(state).iterate({
|
|
2011
2286
|
enter: (node) => {
|
|
2012
2287
|
switch (node.name) {
|
|
2013
2288
|
case "Table": {
|
|
@@ -2039,11 +2314,10 @@ var update = (state, options) => {
|
|
|
2039
2314
|
});
|
|
2040
2315
|
tables.forEach((table2) => {
|
|
2041
2316
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2042
|
-
hide && builder.add(table2.from, table2.to,
|
|
2043
|
-
block: true,
|
|
2317
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2044
2318
|
widget: new TableWidget(table2)
|
|
2045
2319
|
}));
|
|
2046
|
-
builder.add(table2.from, table2.to,
|
|
2320
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2047
2321
|
class: "cm-table"
|
|
2048
2322
|
}));
|
|
2049
2323
|
});
|
|
@@ -2081,94 +2355,144 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2081
2355
|
}
|
|
2082
2356
|
return table2;
|
|
2083
2357
|
}
|
|
2358
|
+
ignoreEvent(e) {
|
|
2359
|
+
return !/^mouse/.test(e.type);
|
|
2360
|
+
}
|
|
2084
2361
|
};
|
|
2085
2362
|
|
|
2086
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2087
|
-
import {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2363
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2364
|
+
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2365
|
+
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2366
|
+
import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
2367
|
+
var styles5 = EditorView12.baseTheme({
|
|
2368
|
+
"& .cm-task": {
|
|
2369
|
+
color: getToken("extend.colors.blue.500")
|
|
2370
|
+
},
|
|
2371
|
+
"& .cm-task-checkbox": {
|
|
2372
|
+
marginLeft: "4px",
|
|
2373
|
+
marginRight: "4px"
|
|
2092
2374
|
}
|
|
2093
2375
|
});
|
|
2094
2376
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2095
|
-
constructor(_checked
|
|
2377
|
+
constructor(_checked) {
|
|
2096
2378
|
super();
|
|
2097
2379
|
this._checked = _checked;
|
|
2098
|
-
this._indent = _indent;
|
|
2099
|
-
this._onCheck = _onCheck;
|
|
2100
2380
|
}
|
|
2101
2381
|
eq(other) {
|
|
2102
|
-
return this._checked === other._checked
|
|
2382
|
+
return this._checked === other._checked;
|
|
2103
2383
|
}
|
|
2104
2384
|
toDOM(view) {
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2108
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2109
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2385
|
+
const input = document.createElement("input");
|
|
2386
|
+
input.className = "cm-task-checkbox";
|
|
2110
2387
|
input.type = "checkbox";
|
|
2111
2388
|
input.checked = this._checked;
|
|
2112
|
-
if (
|
|
2389
|
+
if (view.state.readOnly) {
|
|
2113
2390
|
input.setAttribute("disabled", "true");
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2391
|
+
} else {
|
|
2392
|
+
input.onmousedown = (event) => {
|
|
2393
|
+
const pos = view.posAtDOM(input);
|
|
2394
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2395
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2396
|
+
view.dispatch({
|
|
2397
|
+
changes: {
|
|
2398
|
+
from: pos + 1,
|
|
2399
|
+
to: pos + 2,
|
|
2400
|
+
insert: this._checked ? " " : "x"
|
|
2401
|
+
}
|
|
2402
|
+
});
|
|
2403
|
+
event.preventDefault();
|
|
2404
|
+
}
|
|
2119
2405
|
};
|
|
2120
2406
|
}
|
|
2121
|
-
return
|
|
2407
|
+
return input;
|
|
2122
2408
|
}
|
|
2123
2409
|
ignoreEvent() {
|
|
2124
2410
|
return false;
|
|
2125
2411
|
}
|
|
2126
2412
|
};
|
|
2413
|
+
var checkedDecoration = Decoration10.replace({
|
|
2414
|
+
widget: new CheckboxWidget(true)
|
|
2415
|
+
});
|
|
2416
|
+
var uncheckedDecoration = Decoration10.replace({
|
|
2417
|
+
widget: new CheckboxWidget(false)
|
|
2418
|
+
});
|
|
2419
|
+
var buildDecorations6 = (view) => {
|
|
2420
|
+
const builder = new RangeSetBuilder7();
|
|
2421
|
+
const { state } = view;
|
|
2422
|
+
const cursor = state.selection.main.head;
|
|
2423
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2424
|
+
syntaxTree8(state).iterate({
|
|
2425
|
+
enter: (node) => {
|
|
2426
|
+
if (node.name === "TaskMarker") {
|
|
2427
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2428
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2429
|
+
builder.add(node.from - 2, node.from - 1, Decoration10.mark({
|
|
2430
|
+
class: "cm-task"
|
|
2431
|
+
}));
|
|
2432
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
},
|
|
2436
|
+
from,
|
|
2437
|
+
to
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
return builder.finish();
|
|
2441
|
+
};
|
|
2127
2442
|
var tasklist = (options = {}) => {
|
|
2128
|
-
const taskMatcher = new MatchDecorator3({
|
|
2129
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2130
|
-
decoration: (match, view, pos) => {
|
|
2131
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2132
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2133
|
-
return Decoration8.replace({
|
|
2134
|
-
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2135
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2136
|
-
view.dispatch({
|
|
2137
|
-
changes: {
|
|
2138
|
-
from: idx,
|
|
2139
|
-
to: idx + 1,
|
|
2140
|
-
insert: checked2 ? "x" : " "
|
|
2141
|
-
},
|
|
2142
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2143
|
-
selection: {
|
|
2144
|
-
anchor: idx + 3
|
|
2145
|
-
}
|
|
2146
|
-
});
|
|
2147
|
-
})
|
|
2148
|
-
});
|
|
2149
|
-
}
|
|
2150
|
-
});
|
|
2151
|
-
const tasks = ViewPlugin7.fromClass(class {
|
|
2152
|
-
constructor(view) {
|
|
2153
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2154
|
-
}
|
|
2155
|
-
update(update2) {
|
|
2156
|
-
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2157
|
-
}
|
|
2158
|
-
}, {
|
|
2159
|
-
decorations: (value) => value.tasks,
|
|
2160
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2161
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2162
|
-
})
|
|
2163
|
-
});
|
|
2164
2443
|
return [
|
|
2165
|
-
|
|
2444
|
+
ViewPlugin8.fromClass(class {
|
|
2445
|
+
constructor(view) {
|
|
2446
|
+
this.decorations = buildDecorations6(view);
|
|
2447
|
+
}
|
|
2448
|
+
update(update2) {
|
|
2449
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2450
|
+
this.decorations = buildDecorations6(update2.view);
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
}, {
|
|
2454
|
+
decorations: (value) => value.decorations
|
|
2455
|
+
}),
|
|
2166
2456
|
styles5
|
|
2167
2457
|
];
|
|
2168
2458
|
};
|
|
2169
2459
|
|
|
2460
|
+
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
2461
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
2462
|
+
var mention = ({ onSearch }) => {
|
|
2463
|
+
return autocompletion2({
|
|
2464
|
+
// TODO(burdon): Not working.
|
|
2465
|
+
activateOnTyping: true,
|
|
2466
|
+
// activateOnTypingDelay: 100,
|
|
2467
|
+
// selectOnOpen: true,
|
|
2468
|
+
closeOnBlur: false,
|
|
2469
|
+
// defaultKeymap: false,
|
|
2470
|
+
icons: false,
|
|
2471
|
+
override: [
|
|
2472
|
+
(context) => {
|
|
2473
|
+
console.log(context);
|
|
2474
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
2475
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
2476
|
+
return null;
|
|
2477
|
+
}
|
|
2478
|
+
return {
|
|
2479
|
+
from: match.from,
|
|
2480
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
2481
|
+
label: `@${value}`
|
|
2482
|
+
}))
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
]
|
|
2486
|
+
});
|
|
2487
|
+
};
|
|
2488
|
+
|
|
2489
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2490
|
+
var outliner = (options = {}) => {
|
|
2491
|
+
return [];
|
|
2492
|
+
};
|
|
2493
|
+
|
|
2170
2494
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2171
|
-
import { keymap as
|
|
2495
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2172
2496
|
var defaultItems = [
|
|
2173
2497
|
"hello world!",
|
|
2174
2498
|
"this is a test.",
|
|
@@ -2178,7 +2502,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2178
2502
|
let t;
|
|
2179
2503
|
let idx = 0;
|
|
2180
2504
|
return [
|
|
2181
|
-
|
|
2505
|
+
keymap6.of([
|
|
2182
2506
|
{
|
|
2183
2507
|
// Reset.
|
|
2184
2508
|
key: "alt-meta-'",
|
|
@@ -2224,27 +2548,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2224
2548
|
];
|
|
2225
2549
|
};
|
|
2226
2550
|
|
|
2227
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2228
|
-
import { yCollab } from "y-codemirror.next";
|
|
2229
|
-
|
|
2230
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2231
|
-
import * as Y from "yjs";
|
|
2232
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2233
|
-
var cursorConverter2 = (text) => ({
|
|
2234
|
-
toCursor: (index, assoc) => {
|
|
2235
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2236
|
-
},
|
|
2237
|
-
fromCursor: (cursor) => {
|
|
2238
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2239
|
-
}
|
|
2240
|
-
});
|
|
2241
|
-
|
|
2242
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2243
|
-
var yjs = (content, awareness2) => [
|
|
2244
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2245
|
-
yCollab(content, awareness2)
|
|
2246
|
-
];
|
|
2247
|
-
|
|
2248
2551
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2249
2552
|
import get3 from "lodash.get";
|
|
2250
2553
|
var defaultTheme = {
|
|
@@ -2276,8 +2579,9 @@ var defaultTheme = {
|
|
|
2276
2579
|
outline: "none"
|
|
2277
2580
|
},
|
|
2278
2581
|
".cm-scroller": {
|
|
2279
|
-
overflow:
|
|
2280
|
-
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2582
|
+
// overflow: 'visible',
|
|
2583
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
2584
|
+
lineHeight: 1.4
|
|
2281
2585
|
},
|
|
2282
2586
|
".cm-content": {
|
|
2283
2587
|
padding: 0,
|
|
@@ -2311,7 +2615,7 @@ var defaultTheme = {
|
|
|
2311
2615
|
paddingInline: 0
|
|
2312
2616
|
},
|
|
2313
2617
|
".cm-activeLine": {
|
|
2314
|
-
background: "
|
|
2618
|
+
background: "transparent"
|
|
2315
2619
|
},
|
|
2316
2620
|
//
|
|
2317
2621
|
// Selection
|
|
@@ -2338,33 +2642,6 @@ var defaultTheme = {
|
|
|
2338
2642
|
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2339
2643
|
},
|
|
2340
2644
|
//
|
|
2341
|
-
// collaboration
|
|
2342
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2343
|
-
//
|
|
2344
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2345
|
-
mixBlendMode: "multiply"
|
|
2346
|
-
},
|
|
2347
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2348
|
-
mixBlendMode: "screen"
|
|
2349
|
-
},
|
|
2350
|
-
".cm-ySelectionInfo": {
|
|
2351
|
-
padding: "2px 4px",
|
|
2352
|
-
marginBlockStart: "-4px"
|
|
2353
|
-
},
|
|
2354
|
-
".cm-ySelection, & .cm-selectionMatch": {
|
|
2355
|
-
paddingBlockStart: ".15em",
|
|
2356
|
-
paddingBlockEnd: ".15em"
|
|
2357
|
-
},
|
|
2358
|
-
".cm-ySelectionCaret": {
|
|
2359
|
-
display: "inline-block",
|
|
2360
|
-
insetBlockStart: ".1em",
|
|
2361
|
-
blockSize: "1.4em",
|
|
2362
|
-
verticalAlign: "top"
|
|
2363
|
-
},
|
|
2364
|
-
".cm-yLineSelection": {
|
|
2365
|
-
margin: 0
|
|
2366
|
-
},
|
|
2367
|
-
//
|
|
2368
2645
|
// link
|
|
2369
2646
|
//
|
|
2370
2647
|
".cm-link": {
|
|
@@ -2401,13 +2678,6 @@ var defaultTheme = {
|
|
|
2401
2678
|
textDecoration: "none"
|
|
2402
2679
|
},
|
|
2403
2680
|
//
|
|
2404
|
-
// widgets
|
|
2405
|
-
//
|
|
2406
|
-
".cm-widgetBuffer": {
|
|
2407
|
-
display: "none",
|
|
2408
|
-
height: 0
|
|
2409
|
-
},
|
|
2410
|
-
//
|
|
2411
2681
|
// table
|
|
2412
2682
|
//
|
|
2413
2683
|
".cm-table *": {
|
|
@@ -2438,27 +2708,17 @@ var defaultTheme = {
|
|
|
2438
2708
|
},
|
|
2439
2709
|
//
|
|
2440
2710
|
// font size
|
|
2441
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2711
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2712
|
+
// but it's far more verbose than it needs to be.
|
|
2442
2713
|
//
|
|
2443
|
-
...Object.keys(
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2452
|
-
height
|
|
2453
|
-
};
|
|
2454
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2455
|
-
height
|
|
2456
|
-
};
|
|
2457
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2458
|
-
height
|
|
2459
|
-
};
|
|
2460
|
-
return acc;
|
|
2461
|
-
}, {}),
|
|
2714
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2715
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2716
|
+
//
|
|
2717
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2718
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2719
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2720
|
+
// return acc;
|
|
2721
|
+
// }, {}),
|
|
2462
2722
|
/**
|
|
2463
2723
|
* Panels
|
|
2464
2724
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2509,7 +2769,9 @@ var textTheme = {
|
|
|
2509
2769
|
}
|
|
2510
2770
|
};
|
|
2511
2771
|
var markdownTheme = {
|
|
2512
|
-
|
|
2772
|
+
".cm-scroller": {
|
|
2773
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2774
|
+
},
|
|
2513
2775
|
".cm-placeholder": {
|
|
2514
2776
|
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2515
2777
|
}
|
|
@@ -2524,95 +2786,95 @@ var codeTheme = {
|
|
|
2524
2786
|
};
|
|
2525
2787
|
|
|
2526
2788
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2789
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2527
2790
|
var EditorModes = [
|
|
2528
2791
|
"default",
|
|
2529
2792
|
"vim"
|
|
2530
2793
|
];
|
|
2531
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2794
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2532
2795
|
const { themeMode } = useThemeContext();
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
const [root, setRoot] = useState(null);
|
|
2537
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2538
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2539
|
-
root,
|
|
2540
|
-
state,
|
|
2796
|
+
const rootRef = useRef(null);
|
|
2797
|
+
const [view, setView] = useState(null);
|
|
2798
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2541
2799
|
view
|
|
2542
|
-
}), [
|
|
2543
|
-
view,
|
|
2544
|
-
state,
|
|
2545
|
-
root
|
|
2546
2800
|
]);
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
})
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
themeMode,
|
|
2559
|
-
type: "highlight"
|
|
2560
|
-
})
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
}, [
|
|
2564
|
-
awareness2,
|
|
2565
|
-
peer,
|
|
2566
|
-
themeMode
|
|
2567
|
-
]);
|
|
2568
|
-
useEffect(() => {
|
|
2569
|
-
if (view && comments2?.length) {
|
|
2570
|
-
view.dispatch({
|
|
2571
|
-
effects: setCommentRange.of({
|
|
2572
|
-
model,
|
|
2573
|
-
comments: comments2
|
|
2574
|
-
})
|
|
2575
|
-
});
|
|
2801
|
+
useEffect2(() => {
|
|
2802
|
+
if (autoFocus && !view?.hasFocus) {
|
|
2803
|
+
if (view?.state.selection.main?.from === 0) {
|
|
2804
|
+
const { to } = view.state.doc.lineAt(0);
|
|
2805
|
+
view?.dispatch({
|
|
2806
|
+
selection: {
|
|
2807
|
+
anchor: to
|
|
2808
|
+
}
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2811
|
+
view?.focus();
|
|
2576
2812
|
}
|
|
2577
2813
|
}, [
|
|
2578
2814
|
view,
|
|
2579
|
-
|
|
2815
|
+
autoFocus
|
|
2580
2816
|
]);
|
|
2581
|
-
|
|
2582
|
-
if (!
|
|
2817
|
+
useEffect2(() => {
|
|
2818
|
+
if (!model || !rootRef.current) {
|
|
2583
2819
|
return;
|
|
2584
2820
|
}
|
|
2585
|
-
const
|
|
2821
|
+
const state = EditorState2.create({
|
|
2586
2822
|
doc: model.text(),
|
|
2823
|
+
selection,
|
|
2587
2824
|
extensions: [
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2825
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2826
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2827
|
+
log2.catch(err, void 0, {
|
|
2828
|
+
F: __dxlog_file3,
|
|
2829
|
+
L: 134,
|
|
2830
|
+
S: void 0,
|
|
2831
|
+
C: (f, a) => f(...a)
|
|
2832
|
+
});
|
|
2833
|
+
}),
|
|
2591
2834
|
// Theme.
|
|
2592
|
-
// TODO(burdon): Make
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2835
|
+
// TODO(burdon): Make configurable.
|
|
2836
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2837
|
+
EditorView13.theme(theme ?? {}),
|
|
2838
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2839
|
+
EditorView13.editorAttributes.of({
|
|
2840
|
+
class: slots.editor?.className ?? ""
|
|
2841
|
+
}),
|
|
2842
|
+
EditorView13.contentAttributes.of({
|
|
2843
|
+
class: slots.content?.className ?? ""
|
|
2844
|
+
}),
|
|
2845
|
+
// State.
|
|
2846
|
+
EditorView13.editable.of(!readonly),
|
|
2847
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2596
2848
|
// Storage and replication.
|
|
2849
|
+
// NOTE: This must come before user extensions.
|
|
2597
2850
|
model.extension,
|
|
2851
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2852
|
+
editorMode === "vim" && vim(),
|
|
2598
2853
|
// Custom.
|
|
2599
2854
|
...extensions
|
|
2600
|
-
].filter(
|
|
2855
|
+
].filter(isNotFalsy3)
|
|
2601
2856
|
});
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2857
|
+
const newView = new EditorView13({
|
|
2858
|
+
state,
|
|
2859
|
+
parent: rootRef.current,
|
|
2860
|
+
scrollTo,
|
|
2861
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2862
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2863
|
+
dispatchTransactions: (trs, view2) => {
|
|
2864
|
+
if (debug) {
|
|
2865
|
+
logChanges(trs);
|
|
2866
|
+
}
|
|
2867
|
+
view2.update(trs);
|
|
2868
|
+
}
|
|
2609
2869
|
});
|
|
2870
|
+
view?.destroy();
|
|
2871
|
+
setView(newView);
|
|
2610
2872
|
return () => {
|
|
2611
|
-
|
|
2612
|
-
|
|
2873
|
+
newView?.destroy();
|
|
2874
|
+
setView(null);
|
|
2613
2875
|
};
|
|
2614
2876
|
}, [
|
|
2615
|
-
|
|
2877
|
+
rootRef,
|
|
2616
2878
|
model,
|
|
2617
2879
|
readonly,
|
|
2618
2880
|
editorMode,
|
|
@@ -2622,11 +2884,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2622
2884
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2623
2885
|
switch (key) {
|
|
2624
2886
|
case "Enter": {
|
|
2625
|
-
view?.
|
|
2887
|
+
view?.focus();
|
|
2626
2888
|
break;
|
|
2627
2889
|
}
|
|
2628
2890
|
case "Escape": {
|
|
2629
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2891
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2892
|
+
view?.focus();
|
|
2893
|
+
}
|
|
2630
2894
|
break;
|
|
2631
2895
|
}
|
|
2632
2896
|
}
|
|
@@ -2636,83 +2900,239 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2636
2900
|
]);
|
|
2637
2901
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2638
2902
|
key: model.id,
|
|
2639
|
-
|
|
2903
|
+
role: "none",
|
|
2640
2904
|
tabIndex: 0,
|
|
2641
|
-
...slots
|
|
2642
|
-
...editorMode !==
|
|
2643
|
-
onKeyUp: handleKeyUp
|
|
2905
|
+
...slots.root,
|
|
2906
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2907
|
+
onKeyUp: handleKeyUp,
|
|
2908
|
+
ref: rootRef
|
|
2644
2909
|
});
|
|
2645
2910
|
});
|
|
2646
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2911
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2647
2912
|
const { themeMode } = useThemeContext();
|
|
2648
|
-
const
|
|
2913
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2649
2914
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2650
2915
|
ref: forwardedRef,
|
|
2651
2916
|
readonly,
|
|
2652
2917
|
extensions: [
|
|
2653
|
-
|
|
2654
|
-
readonly,
|
|
2918
|
+
createBasicBundle({
|
|
2655
2919
|
themeMode,
|
|
2656
|
-
placeholder:
|
|
2920
|
+
placeholder: placeholder3,
|
|
2921
|
+
lineWrapping
|
|
2657
2922
|
}),
|
|
2658
2923
|
...extensions
|
|
2659
2924
|
],
|
|
2660
|
-
|
|
2925
|
+
theme,
|
|
2926
|
+
slots: updatedSlots,
|
|
2661
2927
|
...props
|
|
2662
2928
|
});
|
|
2663
2929
|
});
|
|
2664
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2930
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2665
2931
|
const { themeMode } = useThemeContext();
|
|
2666
|
-
const
|
|
2932
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2667
2933
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2668
2934
|
ref: forwardedRef,
|
|
2669
2935
|
readonly,
|
|
2670
2936
|
extensions: [
|
|
2671
|
-
|
|
2672
|
-
readonly,
|
|
2937
|
+
createMarkdownExtensions({
|
|
2673
2938
|
themeMode,
|
|
2674
|
-
placeholder:
|
|
2939
|
+
placeholder: placeholder3
|
|
2675
2940
|
}),
|
|
2676
2941
|
...extensions
|
|
2677
2942
|
],
|
|
2678
|
-
|
|
2943
|
+
theme,
|
|
2944
|
+
slots: updatedSlots,
|
|
2679
2945
|
...props
|
|
2680
2946
|
});
|
|
2681
2947
|
});
|
|
2682
2948
|
var defaultSlots = {
|
|
2683
2949
|
root: {
|
|
2684
|
-
|
|
2950
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2951
|
+
className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
|
|
2952
|
+
},
|
|
2953
|
+
editor: {
|
|
2954
|
+
className: "h-full p-2"
|
|
2685
2955
|
}
|
|
2686
2956
|
};
|
|
2687
2957
|
var defaultTextSlots = {
|
|
2688
|
-
...defaultSlots
|
|
2689
|
-
editor: {
|
|
2690
|
-
theme: textTheme
|
|
2691
|
-
}
|
|
2958
|
+
...defaultSlots
|
|
2692
2959
|
};
|
|
2693
2960
|
var defaultMarkdownSlots = {
|
|
2694
|
-
...defaultSlots
|
|
2695
|
-
editor: {
|
|
2696
|
-
theme: markdownTheme
|
|
2697
|
-
}
|
|
2961
|
+
...defaultSlots
|
|
2698
2962
|
};
|
|
2699
2963
|
|
|
2700
|
-
// packages/ui/react-ui-editor/src/
|
|
2701
|
-
import
|
|
2702
|
-
import {
|
|
2703
|
-
import
|
|
2964
|
+
// packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
|
|
2965
|
+
import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, ListNumbers, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
|
|
2966
|
+
import { createContext } from "@radix-ui/react-context";
|
|
2967
|
+
import React2 from "react";
|
|
2968
|
+
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
2969
|
+
import { getSize } from "@dxos/react-ui-theme";
|
|
2970
|
+
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
2971
|
+
var ToolbarButton = ({ Icon, onClick, title }) => {
|
|
2972
|
+
const { onAction } = useToolbarContext("ToolbarButton");
|
|
2973
|
+
const handleClick = () => {
|
|
2974
|
+
const action = onClick();
|
|
2975
|
+
if (action) {
|
|
2976
|
+
onAction?.(action);
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
2980
|
+
variant: "ghost",
|
|
2981
|
+
classNames: "p-2",
|
|
2982
|
+
onClick: handleClick,
|
|
2983
|
+
title
|
|
2984
|
+
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
2985
|
+
className: getSize(5)
|
|
2986
|
+
}));
|
|
2987
|
+
};
|
|
2988
|
+
var ToolbarRoot = ({ children, onAction }) => {
|
|
2989
|
+
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
2990
|
+
onAction
|
|
2991
|
+
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
2992
|
+
density: "fine"
|
|
2993
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
2994
|
+
role: "toolbar",
|
|
2995
|
+
className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
|
|
2996
|
+
}, children)));
|
|
2997
|
+
};
|
|
2998
|
+
var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
2999
|
+
className: "grow"
|
|
3000
|
+
});
|
|
3001
|
+
var MarkdownHeading = () => {
|
|
3002
|
+
const { onAction } = useToolbarContext("MarkdownFormatting");
|
|
3003
|
+
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3004
|
+
defaultValue: "0",
|
|
3005
|
+
onValueChange: (value) => onAction?.({
|
|
3006
|
+
type: "heading",
|
|
3007
|
+
data: parseInt(value)
|
|
3008
|
+
})
|
|
3009
|
+
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
|
|
3010
|
+
classNames: "w-[8rem]"
|
|
3011
|
+
}), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3012
|
+
value: "0"
|
|
3013
|
+
}, "Paragraph"), [
|
|
3014
|
+
1,
|
|
3015
|
+
2,
|
|
3016
|
+
3,
|
|
3017
|
+
4,
|
|
3018
|
+
5,
|
|
3019
|
+
6
|
|
3020
|
+
].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
|
|
3021
|
+
key: level,
|
|
3022
|
+
value: String(level)
|
|
3023
|
+
}, "Heading ", level))))));
|
|
3024
|
+
};
|
|
3025
|
+
var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3026
|
+
role: "none"
|
|
3027
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3028
|
+
Icon: TextB,
|
|
3029
|
+
title: "Bold",
|
|
3030
|
+
onClick: () => ({
|
|
3031
|
+
type: "bold"
|
|
3032
|
+
})
|
|
3033
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3034
|
+
Icon: TextItalic,
|
|
3035
|
+
title: "Italic",
|
|
3036
|
+
onClick: () => ({
|
|
3037
|
+
type: "italic"
|
|
3038
|
+
})
|
|
3039
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3040
|
+
Icon: TextStrikethrough,
|
|
3041
|
+
title: "Strike-through",
|
|
3042
|
+
onClick: () => ({
|
|
3043
|
+
type: "strikethrough"
|
|
3044
|
+
})
|
|
3045
|
+
}));
|
|
3046
|
+
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3047
|
+
role: "none"
|
|
3048
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3049
|
+
Icon: ListBullets,
|
|
3050
|
+
title: "Bullet list",
|
|
3051
|
+
onClick: () => ({
|
|
3052
|
+
type: "list"
|
|
3053
|
+
})
|
|
3054
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3055
|
+
Icon: ListNumbers,
|
|
3056
|
+
title: "Numbered list",
|
|
3057
|
+
onClick: () => ({
|
|
3058
|
+
type: "list-ordered"
|
|
3059
|
+
})
|
|
3060
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3061
|
+
Icon: ListChecks,
|
|
3062
|
+
title: "Task list",
|
|
3063
|
+
onClick: () => ({
|
|
3064
|
+
type: "list-tasks"
|
|
3065
|
+
})
|
|
3066
|
+
}));
|
|
3067
|
+
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3068
|
+
role: "none"
|
|
3069
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3070
|
+
Icon: CaretRight,
|
|
3071
|
+
title: "Block quite",
|
|
3072
|
+
onClick: () => ({
|
|
3073
|
+
type: "blockquote"
|
|
3074
|
+
})
|
|
3075
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3076
|
+
Icon: Code,
|
|
3077
|
+
title: "Code block",
|
|
3078
|
+
onClick: () => ({
|
|
3079
|
+
type: "codeblock"
|
|
3080
|
+
})
|
|
3081
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3082
|
+
Icon: Table2,
|
|
3083
|
+
title: "Table",
|
|
3084
|
+
onClick: () => ({
|
|
3085
|
+
type: "table"
|
|
3086
|
+
})
|
|
3087
|
+
}));
|
|
3088
|
+
var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3089
|
+
role: "none"
|
|
3090
|
+
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3091
|
+
Icon: Link,
|
|
3092
|
+
title: "Link",
|
|
3093
|
+
onClick: () => ({
|
|
3094
|
+
type: "link"
|
|
3095
|
+
})
|
|
3096
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3097
|
+
Icon: At,
|
|
3098
|
+
title: "Mention",
|
|
3099
|
+
onClick: () => ({
|
|
3100
|
+
type: "mention"
|
|
3101
|
+
})
|
|
3102
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3103
|
+
Icon: Image,
|
|
3104
|
+
title: "Image",
|
|
3105
|
+
onClick: () => ({
|
|
3106
|
+
type: "image"
|
|
3107
|
+
})
|
|
3108
|
+
}));
|
|
3109
|
+
var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
|
|
3110
|
+
var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
|
|
3111
|
+
Icon: ChatText,
|
|
3112
|
+
title: "Create comment",
|
|
3113
|
+
onClick: () => ({
|
|
3114
|
+
type: "comment"
|
|
3115
|
+
})
|
|
3116
|
+
});
|
|
3117
|
+
var Toolbar = {
|
|
3118
|
+
Root: ToolbarRoot,
|
|
3119
|
+
Button: ToolbarButton,
|
|
3120
|
+
Separator: ToolbarSeparator,
|
|
3121
|
+
Markdown: MarkdownStandard,
|
|
3122
|
+
Extended: MarkdownExtended
|
|
3123
|
+
};
|
|
2704
3124
|
|
|
2705
3125
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2706
3126
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2707
3127
|
import { Context as Context2 } from "@dxos/context";
|
|
2708
|
-
import { invariant as
|
|
3128
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2709
3129
|
import { log as log3 } from "@dxos/log";
|
|
2710
3130
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2711
3131
|
var DEBOUNCE_INTERVAL = 100;
|
|
2712
3132
|
var SpaceAwarenessProvider = class {
|
|
2713
3133
|
constructor(params) {
|
|
2714
|
-
this.remoteStateChange = new Event2();
|
|
2715
3134
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
3135
|
+
this.remoteStateChange = new Event2();
|
|
2716
3136
|
this._space = params.space;
|
|
2717
3137
|
this._channel = params.channel;
|
|
2718
3138
|
this._peerId = params.peerId;
|
|
@@ -2729,7 +3149,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2729
3149
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2730
3150
|
}
|
|
2731
3151
|
});
|
|
2732
|
-
|
|
3152
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2733
3153
|
switch (message.payload.kind) {
|
|
2734
3154
|
case "query": {
|
|
2735
3155
|
this._handleQueryMessage();
|
|
@@ -2740,8 +3160,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2740
3160
|
break;
|
|
2741
3161
|
}
|
|
2742
3162
|
}
|
|
2743
|
-
});
|
|
2744
|
-
this._ctx.onDispose(unsubscribe);
|
|
3163
|
+
}));
|
|
2745
3164
|
void this._space.postMessage(this._channel, {
|
|
2746
3165
|
kind: "query"
|
|
2747
3166
|
}).catch((err) => {
|
|
@@ -2749,7 +3168,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2749
3168
|
err
|
|
2750
3169
|
}, {
|
|
2751
3170
|
F: __dxlog_file4,
|
|
2752
|
-
L:
|
|
3171
|
+
L: 89,
|
|
2753
3172
|
S: this,
|
|
2754
3173
|
C: (f, a) => f(...a)
|
|
2755
3174
|
});
|
|
@@ -2760,10 +3179,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2760
3179
|
this._ctx = void 0;
|
|
2761
3180
|
this._postTask = void 0;
|
|
2762
3181
|
}
|
|
3182
|
+
getRemoteStates() {
|
|
3183
|
+
return Array.from(this._remoteStates.values());
|
|
3184
|
+
}
|
|
2763
3185
|
update(position) {
|
|
2764
|
-
|
|
3186
|
+
invariant2(this._postTask, void 0, {
|
|
2765
3187
|
F: __dxlog_file4,
|
|
2766
|
-
L:
|
|
3188
|
+
L: 104,
|
|
2767
3189
|
S: this,
|
|
2768
3190
|
A: [
|
|
2769
3191
|
"this._postTask",
|
|
@@ -2777,13 +3199,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2777
3199
|
};
|
|
2778
3200
|
this._postTask.schedule();
|
|
2779
3201
|
}
|
|
2780
|
-
getRemoteStates() {
|
|
2781
|
-
return Array.from(this._remoteStates.values());
|
|
2782
|
-
}
|
|
2783
3202
|
_handleQueryMessage() {
|
|
2784
|
-
|
|
3203
|
+
invariant2(this._postTask, void 0, {
|
|
2785
3204
|
F: __dxlog_file4,
|
|
2786
|
-
L:
|
|
3205
|
+
L: 115,
|
|
2787
3206
|
S: this,
|
|
2788
3207
|
A: [
|
|
2789
3208
|
"this._postTask",
|
|
@@ -2793,9 +3212,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2793
3212
|
this._postTask.schedule();
|
|
2794
3213
|
}
|
|
2795
3214
|
_handlePostMessage(message) {
|
|
2796
|
-
|
|
3215
|
+
invariant2(message.kind === "post", void 0, {
|
|
2797
3216
|
F: __dxlog_file4,
|
|
2798
|
-
L:
|
|
3217
|
+
L: 120,
|
|
2799
3218
|
S: this,
|
|
2800
3219
|
A: [
|
|
2801
3220
|
"message.kind === 'post'",
|
|
@@ -2807,229 +3226,231 @@ var SpaceAwarenessProvider = class {
|
|
|
2807
3226
|
}
|
|
2808
3227
|
};
|
|
2809
3228
|
|
|
2810
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
3229
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2811
3230
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
2812
|
-
|
|
2813
|
-
|
|
3231
|
+
var modelState = StateField5.define({
|
|
3232
|
+
create: () => void 0,
|
|
3233
|
+
update: (model) => model
|
|
3234
|
+
});
|
|
2814
3235
|
|
|
2815
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
arrayToString2(to)
|
|
2852
|
-
].join(":");
|
|
2853
|
-
},
|
|
2854
|
-
getRangeFromCursor: (cursor) => {
|
|
2855
|
-
invariant4(text.doc, void 0, {
|
|
2856
|
-
F: __dxlog_file5,
|
|
2857
|
-
L: 40,
|
|
2858
|
-
S: void 0,
|
|
2859
|
-
A: [
|
|
2860
|
-
"text.doc",
|
|
2861
|
-
""
|
|
2862
|
-
]
|
|
3236
|
+
// packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
|
|
3237
|
+
var useActionHandler = (view) => {
|
|
3238
|
+
return (action) => {
|
|
3239
|
+
if (!view) {
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
switch (action.type) {
|
|
3243
|
+
case "heading":
|
|
3244
|
+
setHeading(parseInt(action.data))(view);
|
|
3245
|
+
break;
|
|
3246
|
+
case "bold":
|
|
3247
|
+
toggleBold(view);
|
|
3248
|
+
break;
|
|
3249
|
+
case "italic":
|
|
3250
|
+
toggleItalic(view);
|
|
3251
|
+
break;
|
|
3252
|
+
case "strikethrough":
|
|
3253
|
+
toggleStrikethrough(view);
|
|
3254
|
+
break;
|
|
3255
|
+
case "list":
|
|
3256
|
+
toggleList(view);
|
|
3257
|
+
break;
|
|
3258
|
+
case "codeblock":
|
|
3259
|
+
insertCodeblock(view);
|
|
3260
|
+
break;
|
|
3261
|
+
case "table":
|
|
3262
|
+
insertTable(view);
|
|
3263
|
+
break;
|
|
3264
|
+
case "comment":
|
|
3265
|
+
createComment(view);
|
|
3266
|
+
break;
|
|
3267
|
+
}
|
|
3268
|
+
setTimeout(() => {
|
|
3269
|
+
view.focus();
|
|
3270
|
+
view.dispatch({
|
|
3271
|
+
selection: view.state.selection
|
|
2863
3272
|
});
|
|
2864
|
-
|
|
2865
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2866
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2867
|
-
return from && to ? {
|
|
2868
|
-
from: from.index,
|
|
2869
|
-
to: to.index
|
|
2870
|
-
} : void 0;
|
|
2871
|
-
},
|
|
2872
|
-
extension: [
|
|
2873
|
-
modelState.init(() => model),
|
|
2874
|
-
yjs(text.content, provider?.awareness)
|
|
2875
|
-
],
|
|
2876
|
-
awareness: provider?.awareness,
|
|
2877
|
-
peer: identity ? {
|
|
2878
|
-
id: identity.identityKey.toHex(),
|
|
2879
|
-
name: identity.profile?.displayName
|
|
2880
|
-
} : void 0
|
|
3273
|
+
});
|
|
2881
3274
|
};
|
|
2882
|
-
return model;
|
|
2883
3275
|
};
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3276
|
+
|
|
3277
|
+
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
3278
|
+
import { useState as useState2 } from "react";
|
|
3279
|
+
var useEditorView = () => {
|
|
3280
|
+
const [view, setView] = useState2(null);
|
|
3281
|
+
return [
|
|
3282
|
+
(ref) => {
|
|
3283
|
+
setView(ref);
|
|
3284
|
+
},
|
|
3285
|
+
view
|
|
3286
|
+
];
|
|
3287
|
+
};
|
|
3288
|
+
|
|
3289
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3290
|
+
import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
|
|
3291
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
3292
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
3293
|
+
import { log as log4 } from "@dxos/log";
|
|
3294
|
+
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
3295
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
3296
|
+
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
3297
|
+
const onUpdate = useRef2();
|
|
3298
|
+
const [view, setView] = useState3();
|
|
3299
|
+
const parentRef = useRef2(null);
|
|
3300
|
+
useEffect3(() => {
|
|
3301
|
+
if (parentRef.current) {
|
|
3302
|
+
const state = EditorState3.create({
|
|
3303
|
+
doc,
|
|
3304
|
+
selection,
|
|
3305
|
+
extensions: [
|
|
3306
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3307
|
+
EditorView14.exceptionSink.of((err) => {
|
|
3308
|
+
log4.catch(err, void 0, {
|
|
3309
|
+
F: __dxlog_file5,
|
|
3310
|
+
L: 57,
|
|
3311
|
+
S: void 0,
|
|
3312
|
+
C: (f, a) => f(...a)
|
|
3313
|
+
});
|
|
3314
|
+
}),
|
|
3315
|
+
extensions,
|
|
3316
|
+
EditorView14.updateListener.of(() => {
|
|
3317
|
+
onUpdate.current?.();
|
|
3318
|
+
})
|
|
3319
|
+
].filter(isNotFalsy4)
|
|
3320
|
+
});
|
|
3321
|
+
const view2 = new EditorView14({
|
|
3322
|
+
parent: parentRef.current,
|
|
3323
|
+
scrollTo,
|
|
3324
|
+
state,
|
|
3325
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
3326
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
3327
|
+
dispatchTransactions: (trs, view3) => {
|
|
3328
|
+
if (debug) {
|
|
3329
|
+
logChanges(trs);
|
|
3330
|
+
}
|
|
3331
|
+
view3.update(trs);
|
|
3332
|
+
}
|
|
3333
|
+
});
|
|
3334
|
+
setView(view2);
|
|
2942
3335
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3336
|
+
return () => {
|
|
3337
|
+
view?.destroy();
|
|
3338
|
+
};
|
|
3339
|
+
}, [
|
|
3340
|
+
parentRef
|
|
3341
|
+
]);
|
|
3342
|
+
useEffect3(() => {
|
|
3343
|
+
if (view) {
|
|
3344
|
+
if (!selection && !view.state.selection.main.anchor) {
|
|
3345
|
+
selection = EditorSelection.single(view.state.doc.line(1).to);
|
|
2953
3346
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
3347
|
+
if (selection || scrollTo) {
|
|
3348
|
+
onUpdate.current = () => {
|
|
3349
|
+
onUpdate.current = void 0;
|
|
3350
|
+
view.dispatch({
|
|
3351
|
+
selection,
|
|
3352
|
+
effects: scrollTo && [
|
|
3353
|
+
scrollTo
|
|
3354
|
+
],
|
|
3355
|
+
scrollIntoView: !scrollTo
|
|
3356
|
+
});
|
|
3357
|
+
};
|
|
2959
3358
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
return encoder;
|
|
3359
|
+
if (autoFocus) {
|
|
3360
|
+
view.focus();
|
|
2963
3361
|
}
|
|
2964
3362
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
}
|
|
3363
|
+
}, [
|
|
3364
|
+
view,
|
|
3365
|
+
autoFocus,
|
|
3366
|
+
selection,
|
|
3367
|
+
scrollTo
|
|
3368
|
+
]);
|
|
3369
|
+
return {
|
|
3370
|
+
parentRef,
|
|
3371
|
+
view
|
|
3372
|
+
};
|
|
3373
|
+
};
|
|
3374
|
+
var createDataExtensions = ({ readonly = false } = {}) => {
|
|
3375
|
+
return [
|
|
3376
|
+
//
|
|
3377
|
+
EditorState3.readOnly.of(readonly),
|
|
3378
|
+
EditorView14.editable.of(!readonly)
|
|
3379
|
+
];
|
|
3380
|
+
};
|
|
3381
|
+
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
3382
|
+
return [
|
|
3383
|
+
//
|
|
3384
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3385
|
+
theme && EditorView14.theme(theme),
|
|
3386
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3387
|
+
EditorView14.editorAttributes.of({
|
|
3388
|
+
class: slots?.editor?.className ?? ""
|
|
3389
|
+
}),
|
|
3390
|
+
EditorView14.contentAttributes.of({
|
|
3391
|
+
class: slots?.content?.className ?? ""
|
|
3392
|
+
})
|
|
3393
|
+
].filter(isNotFalsy4);
|
|
2975
3394
|
};
|
|
2976
3395
|
|
|
2977
3396
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
}
|
|
3397
|
+
import get4 from "lodash.get";
|
|
3398
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
3399
|
+
import { generateName } from "@dxos/display-name";
|
|
3400
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
3401
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
3402
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3403
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
2982
3404
|
var useTextModel = (props) => {
|
|
2983
3405
|
const { identity, space, text } = props;
|
|
2984
|
-
const [model, setModel] =
|
|
2985
|
-
|
|
3406
|
+
const [model, setModel] = useState4();
|
|
3407
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2986
3408
|
identity,
|
|
2987
3409
|
space,
|
|
2988
3410
|
text
|
|
2989
3411
|
]);
|
|
2990
3412
|
return model;
|
|
2991
3413
|
};
|
|
2992
|
-
var createModel = (
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
};
|
|
3002
|
-
|
|
3003
|
-
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
3004
|
-
var createAutomergeModel = ({ space, identity, text }) => {
|
|
3414
|
+
var createModel = ({ space, identity, text }) => {
|
|
3415
|
+
invariant3(isAutomergeObject(text), void 0, {
|
|
3416
|
+
F: __dxlog_file6,
|
|
3417
|
+
L: 34,
|
|
3418
|
+
S: void 0,
|
|
3419
|
+
A: [
|
|
3420
|
+
"isAutomergeObject(text)",
|
|
3421
|
+
""
|
|
3422
|
+
]
|
|
3423
|
+
});
|
|
3005
3424
|
const obj = text;
|
|
3006
3425
|
const doc = getRawDoc(obj, [
|
|
3007
3426
|
obj.field
|
|
3008
3427
|
]);
|
|
3009
|
-
const
|
|
3428
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
3010
3429
|
space,
|
|
3011
3430
|
channel: `automerge.awareness.${obj.id}`,
|
|
3012
3431
|
info: {
|
|
3013
|
-
displayName: identity
|
|
3432
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
3014
3433
|
color: cursorColor.color,
|
|
3015
3434
|
lightColor: cursorColor.light
|
|
3016
3435
|
},
|
|
3017
3436
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3018
3437
|
});
|
|
3438
|
+
const extensions = [
|
|
3439
|
+
//
|
|
3440
|
+
modelState.init(() => model),
|
|
3441
|
+
automerge({
|
|
3442
|
+
handle: doc.handle,
|
|
3443
|
+
path: doc.path
|
|
3444
|
+
})
|
|
3445
|
+
];
|
|
3446
|
+
if (awarenessProvider2) {
|
|
3447
|
+
extensions.push(awareness(awarenessProvider2));
|
|
3448
|
+
}
|
|
3019
3449
|
const model = {
|
|
3020
3450
|
id: obj.id,
|
|
3021
3451
|
content: doc,
|
|
3022
3452
|
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3023
|
-
|
|
3024
|
-
extension: [
|
|
3025
|
-
modelState.init(() => model),
|
|
3026
|
-
automerge3({
|
|
3027
|
-
handle: doc.handle,
|
|
3028
|
-
path: doc.path
|
|
3029
|
-
}),
|
|
3030
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3031
|
-
awareness()
|
|
3032
|
-
].filter(isNotNullOrUndefined),
|
|
3453
|
+
extension: extensions,
|
|
3033
3454
|
peer: identity ? {
|
|
3034
3455
|
id: identity.identityKey.toHex(),
|
|
3035
3456
|
name: identity.profile?.displayName
|
|
@@ -3038,8 +3459,8 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3038
3459
|
return model;
|
|
3039
3460
|
};
|
|
3040
3461
|
export {
|
|
3041
|
-
AwarenessProvider,
|
|
3042
3462
|
BaseTextEditor,
|
|
3463
|
+
Cursor,
|
|
3043
3464
|
Doc,
|
|
3044
3465
|
EditorModes,
|
|
3045
3466
|
MarkdownEditor,
|
|
@@ -3047,45 +3468,64 @@ export {
|
|
|
3047
3468
|
SpaceAwarenessProvider,
|
|
3048
3469
|
TextEditor,
|
|
3049
3470
|
TextKind,
|
|
3050
|
-
|
|
3471
|
+
Toolbar,
|
|
3051
3472
|
YText,
|
|
3052
3473
|
YXmlFragment,
|
|
3053
3474
|
autocomplete,
|
|
3054
|
-
|
|
3475
|
+
automerge,
|
|
3055
3476
|
awareness,
|
|
3056
|
-
|
|
3477
|
+
awarenessProvider,
|
|
3057
3478
|
blast,
|
|
3479
|
+
callbackWrapper,
|
|
3058
3480
|
code2 as code,
|
|
3059
3481
|
codeTheme,
|
|
3060
3482
|
comments,
|
|
3061
|
-
|
|
3062
|
-
|
|
3483
|
+
createBasicBundle,
|
|
3484
|
+
createComment,
|
|
3485
|
+
createDataExtensions,
|
|
3486
|
+
createMarkdownExtensions,
|
|
3487
|
+
createThemeExtensions,
|
|
3063
3488
|
defaultMarkdownSlots,
|
|
3064
3489
|
defaultOptions,
|
|
3065
3490
|
defaultSlots,
|
|
3066
3491
|
defaultTextSlots,
|
|
3067
3492
|
defaultTheme,
|
|
3493
|
+
focusComment,
|
|
3494
|
+
formatting,
|
|
3068
3495
|
getToken,
|
|
3496
|
+
heading2 as heading,
|
|
3069
3497
|
hr,
|
|
3070
3498
|
image,
|
|
3499
|
+
insertCodeblock,
|
|
3500
|
+
insertTable,
|
|
3071
3501
|
link,
|
|
3072
3502
|
listener,
|
|
3073
|
-
|
|
3503
|
+
logChanges,
|
|
3074
3504
|
markdownHighlightStyle,
|
|
3075
3505
|
markdownTags,
|
|
3076
3506
|
markdownTagsExtensions,
|
|
3077
3507
|
markdownTheme,
|
|
3078
3508
|
mention,
|
|
3079
3509
|
modelState,
|
|
3080
|
-
|
|
3081
|
-
|
|
3510
|
+
outliner,
|
|
3511
|
+
setComments,
|
|
3512
|
+
setHeading,
|
|
3082
3513
|
setSelection,
|
|
3083
3514
|
table,
|
|
3084
3515
|
tags2 as tags,
|
|
3085
3516
|
tasklist,
|
|
3086
3517
|
textTheme,
|
|
3518
|
+
toggleBold,
|
|
3519
|
+
toggleItalic,
|
|
3520
|
+
toggleList,
|
|
3521
|
+
toggleStrikethrough,
|
|
3522
|
+
toggleStyle,
|
|
3087
3523
|
typewriter,
|
|
3524
|
+
useActionHandler,
|
|
3525
|
+
useComments,
|
|
3526
|
+
useEditorView,
|
|
3527
|
+
useTextEditor,
|
|
3088
3528
|
useTextModel,
|
|
3089
|
-
|
|
3529
|
+
useToolbarContext
|
|
3090
3530
|
};
|
|
3091
3531
|
//# sourceMappingURL=index.mjs.map
|