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