@dxos/react-ui-editor 0.3.11-main.1b2c8cb → 0.3.11-main.1b488db
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 +1870 -1393
- 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 -8
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts +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 +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts +2 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +48 -37
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +84 -91
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
- package/src/components/TextEditor/TextEditor.tsx +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 +323 -268
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/index.ts +2 -8
- 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 +11 -26
- package/src/extensions/markdown/hr.ts +71 -0
- package/src/extensions/markdown/image.ts +87 -0
- package/src/extensions/markdown/index.ts +8 -0
- package/src/extensions/{link.ts → markdown/link.ts} +90 -83
- package/src/extensions/{table.ts → markdown/table.ts} +10 -4
- package/src/extensions/markdown/tasklist.ts +110 -0
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/hooks/awareness-provider.ts +24 -20
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +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 +3 -0
- package/src/styles/markdown.ts +9 -12
- package/src/styles/tokens.ts +3 -0
- package/src/themes/default.ts +57 -81
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/code.d.ts.map +0 -1
- package/dist/types/src/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/extensions/image.d.ts.map +0 -1
- package/dist/types/src/extensions/link.d.ts.map +0 -1
- package/dist/types/src/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/extensions/table.d.ts.map +0 -1
- package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/index.d.ts +0 -2
- package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
- package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge.d.ts +0 -3
- package/dist/types/src/hooks/automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs.d.ts +0 -27
- package/dist/types/src/hooks/yjs.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
- package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
- package/dist/types/src/testing/proto/index.d.ts +0 -2
- package/dist/types/src/testing/proto/index.d.ts.map +0 -1
- package/dist/types/src/testing/replicator.d.ts +0 -45
- package/dist/types/src/testing/replicator.d.ts.map +0 -1
- package/dist/types/src/util/cursor.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -3
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/util.d.ts +0 -5
- package/dist/types/src/util/util.d.ts.map +0 -1
- package/src/components/TextEditor/codemirror.stories.ts +0 -115
- package/src/components/TextEditor/yjs.stories.tsx +0 -56
- package/src/extensions/code.ts +0 -99
- package/src/extensions/hr.ts +0 -74
- package/src/extensions/image.ts +0 -69
- package/src/extensions/mermaid.ts +0 -11
- package/src/extensions/tasklist.ts +0 -121
- package/src/extensions/yjs/cursor.ts +0 -21
- package/src/extensions/yjs/index.ts +0 -5
- package/src/extensions/yjs/yjs.test.ts +0 -35
- package/src/extensions/yjs/yjs.ts +0 -16
- package/src/hooks/automerge.ts +0 -52
- package/src/hooks/yjs.ts +0 -178
- package/src/testing/index.ts +0 -6
- package/src/testing/proto/gen/schema.ts +0 -49
- package/src/testing/proto/index.ts +0 -5
- package/src/testing/proto/schema.proto +0 -15
- package/src/testing/replicator.ts +0 -184
- package/src/util/cursor.ts +0 -29
- package/src/util/index.ts +0 -6
- package/src/util/util.ts +0 -18
- /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
- /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
- /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
- /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
- /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
- /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
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";
|
|
@@ -8,55 +9,59 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
8
9
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
10
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
11
|
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
|
-
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
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({
|
|
@@ -412,13 +445,13 @@ var RemoteSelectionsDecorator = class {
|
|
|
412
445
|
void this._ctx.dispose();
|
|
413
446
|
this._provider.close();
|
|
414
447
|
}
|
|
415
|
-
update(
|
|
416
|
-
this._updateLocalSelection(
|
|
417
|
-
this._updateRemoteSelections(
|
|
448
|
+
update(update2) {
|
|
449
|
+
this._updateLocalSelection(update2);
|
|
450
|
+
this._updateRemoteSelections(update2);
|
|
418
451
|
}
|
|
419
|
-
_updateLocalSelection(
|
|
420
|
-
const hasFocus =
|
|
421
|
-
const { anchor = void 0, head = void 0 } = hasFocus ?
|
|
452
|
+
_updateLocalSelection(update2) {
|
|
453
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
454
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
422
455
|
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
423
456
|
return;
|
|
424
457
|
}
|
|
@@ -429,7 +462,7 @@ var RemoteSelectionsDecorator = class {
|
|
|
429
462
|
head: this._cursorConverter.toCursor(head)
|
|
430
463
|
} : void 0);
|
|
431
464
|
}
|
|
432
|
-
_updateRemoteSelections(
|
|
465
|
+
_updateRemoteSelections(update2) {
|
|
433
466
|
const decorations = [];
|
|
434
467
|
const awarenessStates = this._provider.getRemoteStates();
|
|
435
468
|
for (const state of awarenessStates) {
|
|
@@ -438,10 +471,10 @@ var RemoteSelectionsDecorator = class {
|
|
|
438
471
|
if (anchor == null || head == null) {
|
|
439
472
|
continue;
|
|
440
473
|
}
|
|
441
|
-
const start = Math.min(Math.min(anchor, head),
|
|
442
|
-
const end = Math.min(Math.max(anchor, head),
|
|
443
|
-
const startLine =
|
|
444
|
-
const endLine =
|
|
474
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
475
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
476
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
477
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
445
478
|
const color = state.info.color ?? "#30bced";
|
|
446
479
|
const lightColor = state.info.lightColor ?? color + "33";
|
|
447
480
|
if (startLine.number === endLine.number) {
|
|
@@ -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,18 +506,18 @@ 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++) {
|
|
480
|
-
const linePos =
|
|
513
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
481
514
|
decorations.push({
|
|
482
515
|
from: linePos,
|
|
483
516
|
to: linePos,
|
|
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,12 +700,12 @@ var blast = (options = defaultOptions) => {
|
|
|
667
700
|
};
|
|
668
701
|
return [
|
|
669
702
|
// Cursor moved.
|
|
670
|
-
|
|
671
|
-
if (blaster?.node !==
|
|
703
|
+
EditorView4.updateListener.of((update2) => {
|
|
704
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
672
705
|
if (blaster) {
|
|
673
706
|
blaster.destroy();
|
|
674
707
|
}
|
|
675
|
-
blaster = new Blaster(
|
|
708
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
676
709
|
particleGravity: 0.2,
|
|
677
710
|
particleShrinkRate: 0.995,
|
|
678
711
|
color: () => [
|
|
@@ -686,10 +719,10 @@ var blast = (options = defaultOptions) => {
|
|
|
686
719
|
} else {
|
|
687
720
|
blaster.resize();
|
|
688
721
|
}
|
|
689
|
-
const current =
|
|
722
|
+
const current = update2.state.selection.main.head;
|
|
690
723
|
if (current !== last) {
|
|
691
724
|
last = current;
|
|
692
|
-
const { element, point } = getPoint(
|
|
725
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
693
726
|
if (element && point) {
|
|
694
727
|
blaster.spawn({
|
|
695
728
|
element,
|
|
@@ -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,10 +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
|
|
934
|
-
import {
|
|
964
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
965
|
+
import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
|
|
966
|
+
import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
967
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
|
|
968
|
+
import sortBy from "lodash.sortby";
|
|
969
|
+
import { useEffect } from "react";
|
|
970
|
+
import { debounce } from "@dxos/async";
|
|
971
|
+
import { nonNullable } from "@dxos/util";
|
|
935
972
|
|
|
936
973
|
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
974
|
import * as random2 from "lib0/random";
|
|
@@ -974,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
|
974
1011
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
1012
|
import { mx } from "@dxos/react-ui-theme";
|
|
976
1013
|
var headings = {
|
|
977
|
-
1:
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
987
|
-
"-ml-[7px]"
|
|
988
|
-
],
|
|
989
|
-
4: [
|
|
990
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
991
|
-
"-ml-[6px]"
|
|
992
|
-
],
|
|
993
|
-
5: [
|
|
994
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
995
|
-
"-ml-[5px]"
|
|
996
|
-
],
|
|
997
|
-
6: [
|
|
998
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
999
|
-
"-ml-[4px]"
|
|
1000
|
-
]
|
|
1001
|
-
};
|
|
1002
|
-
var heading = (level, readonly) => {
|
|
1003
|
-
const [style, offset] = headings[level];
|
|
1004
|
-
return mx(style, readonly && offset);
|
|
1014
|
+
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1015
|
+
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1016
|
+
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1017
|
+
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1018
|
+
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1019
|
+
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
1020
|
+
};
|
|
1021
|
+
var heading = (level) => {
|
|
1022
|
+
return headings[level];
|
|
1005
1023
|
};
|
|
1006
1024
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
1025
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -1014,158 +1032,114 @@ var inlineUrl = mx(code, "px-1");
|
|
|
1014
1032
|
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
1015
1033
|
|
|
1016
1034
|
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1035
|
+
import get2 from "lodash.get";
|
|
1017
1036
|
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1018
1037
|
var tokens = tailwindConfig({}).theme;
|
|
1038
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1019
1039
|
|
|
1020
|
-
// packages/ui/react-ui-editor/src/
|
|
1021
|
-
|
|
1022
|
-
var
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
display: "block",
|
|
1034
|
-
paddingInline: "4px !important"
|
|
1035
|
-
},
|
|
1036
|
-
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1037
|
-
paddingTop: "4px !important",
|
|
1038
|
-
borderTopLeftRadius: "4px",
|
|
1039
|
-
borderTopRightRadius: "4px"
|
|
1040
|
-
},
|
|
1041
|
-
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1042
|
-
paddingBottom: "4px !important",
|
|
1043
|
-
borderBottomLeftRadius: "4px",
|
|
1044
|
-
borderBottomRightRadius: "4px"
|
|
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
|
+
});
|
|
1045
1053
|
}
|
|
1046
|
-
});
|
|
1047
|
-
var getLineRange = (lines, from, to) => {
|
|
1048
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
1049
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
1050
|
-
return [
|
|
1051
|
-
start,
|
|
1052
|
-
end
|
|
1053
|
-
];
|
|
1054
1054
|
};
|
|
1055
|
-
var
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
const text = view.state.doc.sliceString(0);
|
|
1060
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
1061
|
-
const blocks = view.viewportLineBlocks;
|
|
1062
|
-
for (const match of matches) {
|
|
1063
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1064
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
1065
|
-
const block = blocks[i];
|
|
1066
|
-
decorations.push(Decoration2.line({
|
|
1067
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1068
|
-
}).range(block.from));
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1055
|
+
var logChanges = (trs) => {
|
|
1056
|
+
const changes = trs.flatMap((tr) => {
|
|
1057
|
+
if (tr.changes.empty) {
|
|
1058
|
+
return void 0;
|
|
1071
1059
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
decorations: (value) => value.decorations
|
|
1086
|
-
}),
|
|
1087
|
-
styles2
|
|
1088
|
-
];
|
|
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
|
+
}
|
|
1089
1073
|
};
|
|
1090
1074
|
|
|
1091
1075
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1092
|
-
|
|
1093
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1094
|
-
import get3 from "lodash.get";
|
|
1095
|
-
import sortBy from "lodash.sortby";
|
|
1096
|
-
import { debounce } from "@dxos/async";
|
|
1097
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1098
|
-
import { log as log2 } from "@dxos/log";
|
|
1099
|
-
import { nonNullable } from "@dxos/util";
|
|
1100
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1101
|
-
var styles3 = EditorView5.baseTheme({
|
|
1102
|
-
"& .cm-bookmark": {
|
|
1103
|
-
cursor: "pointer",
|
|
1104
|
-
margin: "4px",
|
|
1105
|
-
padding: "4px",
|
|
1106
|
-
backgroundColor: "yellow"
|
|
1107
|
-
},
|
|
1108
|
-
"& .cm-bookmark-selected": {
|
|
1109
|
-
backgroundColor: "orange"
|
|
1110
|
-
},
|
|
1076
|
+
var styles2 = EditorView5.baseTheme({
|
|
1111
1077
|
"& .cm-comment": {
|
|
1112
|
-
backgroundColor:
|
|
1078
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1113
1079
|
},
|
|
1114
|
-
"& .cm-comment-
|
|
1115
|
-
backgroundColor:
|
|
1080
|
+
"& .cm-comment-current": {
|
|
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: 225,
|
|
1234
|
-
S: void 0,
|
|
1235
|
-
A: [
|
|
1236
|
-
"options.onCreate",
|
|
1237
|
-
""
|
|
1238
|
-
]
|
|
1239
|
-
});
|
|
1240
|
-
const { head, from, to } = view.state.selection.main;
|
|
1241
|
-
if (from === to) {
|
|
1242
|
-
return false;
|
|
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,372 +1345,128 @@ 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: 359,
|
|
1365
|
-
S: void 0,
|
|
1366
|
-
C: (f, a) => f(...a)
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
if (from <= range.to) {
|
|
1371
|
-
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1372
|
-
Object.assign(range, newRange);
|
|
1373
|
-
mod = true;
|
|
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);
|
|
1374
1364
|
}
|
|
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
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
})
|
|
1418
|
-
];
|
|
1419
|
-
};
|
|
1420
|
-
var getCursorFromRange = (cursorConverter3, range) => {
|
|
1421
|
-
const from = cursorConverter3.toCursor(range.from);
|
|
1422
|
-
const to = cursorConverter3.toCursor(range.to, -1);
|
|
1423
|
-
return [
|
|
1424
|
-
from,
|
|
1425
|
-
to
|
|
1426
|
-
].join(":");
|
|
1427
|
-
};
|
|
1428
|
-
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1429
|
-
const parts = cursor.split(":");
|
|
1430
|
-
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1431
|
-
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1432
|
-
return from && to ? {
|
|
1433
|
-
from,
|
|
1434
|
-
to
|
|
1435
|
-
} : void 0;
|
|
1436
|
-
};
|
|
1437
|
-
|
|
1438
|
-
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1439
|
-
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1440
|
-
import get4 from "lodash.get";
|
|
1441
|
-
var styles4 = EditorView6.baseTheme({
|
|
1442
|
-
"& .cm-hr": {
|
|
1443
|
-
// TODO(burdon): ???
|
|
1444
|
-
// Note that block-level decorations should not have vertical margins,
|
|
1445
|
-
borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1449
|
-
constructor(_pos) {
|
|
1450
|
-
super();
|
|
1451
|
-
this._pos = _pos;
|
|
1452
|
-
}
|
|
1453
|
-
eq(other) {
|
|
1454
|
-
return this._pos === other._pos;
|
|
1455
|
-
}
|
|
1456
|
-
toDOM(view) {
|
|
1457
|
-
const el = document.createElement("div");
|
|
1458
|
-
el.className = "cm-hr";
|
|
1459
|
-
return el;
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
var placeholderMatcher = new MatchDecorator2({
|
|
1463
|
-
regexp: /^---$/g,
|
|
1464
|
-
decoration: (match, view, pos) => Decoration4.replace({
|
|
1465
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1466
|
-
})
|
|
1467
|
-
});
|
|
1468
|
-
var hr = () => [
|
|
1469
|
-
styles4,
|
|
1470
|
-
ViewPlugin5.fromClass(class {
|
|
1471
|
-
constructor(view) {
|
|
1472
|
-
this.rules = placeholderMatcher.createDeco(view);
|
|
1473
|
-
}
|
|
1474
|
-
update(update4) {
|
|
1475
|
-
this.rules = placeholderMatcher.updateDeco(update4, this.rules);
|
|
1476
|
-
}
|
|
1477
|
-
}, {
|
|
1478
|
-
decorations: (instance) => instance.rules,
|
|
1479
|
-
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1480
|
-
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
-
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1482
|
-
})
|
|
1483
|
-
})
|
|
1484
|
-
];
|
|
1485
|
-
|
|
1486
|
-
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1487
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1488
|
-
import { RangeSetBuilder, StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
-
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1490
|
-
var image = (options = {}) => {
|
|
1491
|
-
return StateField3.define({
|
|
1492
|
-
create: (state) => update(state, options),
|
|
1493
|
-
update: (_, tr) => update(tr.state, options),
|
|
1494
|
-
provide: (field) => EditorView7.decorations.from(field)
|
|
1495
|
-
});
|
|
1496
|
-
};
|
|
1497
|
-
var update = (state, options) => {
|
|
1498
|
-
const builder = new RangeSetBuilder();
|
|
1499
|
-
const cursor = state.selection.main.head;
|
|
1500
|
-
syntaxTree(state).iterate({
|
|
1501
|
-
enter: (node) => {
|
|
1502
|
-
if (node.name === "Image") {
|
|
1503
|
-
const urlNode = node.node.getChild("URL");
|
|
1504
|
-
if (urlNode) {
|
|
1505
|
-
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1506
|
-
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1507
|
-
builder.add(hide ? node.from : node.to, node.to, Decoration5.replace({
|
|
1508
|
-
block: true,
|
|
1509
|
-
widget: new ImageWidget(url)
|
|
1510
|
-
}));
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
});
|
|
1515
|
-
return builder.finish();
|
|
1516
|
-
};
|
|
1517
|
-
var ImageWidget = class extends WidgetType4 {
|
|
1518
|
-
constructor(_url) {
|
|
1519
|
-
super();
|
|
1520
|
-
this._url = _url;
|
|
1521
|
-
}
|
|
1522
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1523
|
-
eq(other) {
|
|
1524
|
-
return this._url === other._url;
|
|
1525
|
-
}
|
|
1526
|
-
toDOM(view) {
|
|
1527
|
-
const img = document.createElement("img");
|
|
1528
|
-
img.setAttribute("src", this._url);
|
|
1529
|
-
img.setAttribute("class", "cm-image");
|
|
1530
|
-
return img;
|
|
1531
|
-
}
|
|
1532
|
-
};
|
|
1533
|
-
|
|
1534
|
-
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1535
|
-
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1536
|
-
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
|
|
1537
|
-
import { Decoration as Decoration6, EditorView as EditorView8, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2 } from "@codemirror/view";
|
|
1538
|
-
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1539
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1540
|
-
var link = (options = {}) => {
|
|
1541
|
-
const extensions = [
|
|
1542
|
-
StateField4.define({
|
|
1543
|
-
create: (state) => update2(state, options),
|
|
1544
|
-
update: (_, tr) => update2(tr.state, options),
|
|
1545
|
-
provide: (field) => EditorView8.decorations.from(field)
|
|
1546
|
-
})
|
|
1547
|
-
];
|
|
1548
|
-
if (options.onHover) {
|
|
1549
|
-
extensions.push(
|
|
1550
|
-
// https://codemirror.net/examples/tooltip
|
|
1551
|
-
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1552
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1553
|
-
hoverTooltip2((view, pos) => {
|
|
1554
|
-
const { from, text } = view.state.doc.lineAt(pos);
|
|
1555
|
-
const p = pos - from;
|
|
1556
|
-
let idx = 0;
|
|
1557
|
-
let match;
|
|
1558
|
-
do {
|
|
1559
|
-
match = text.substring(idx).match(markdownLinkRegexp);
|
|
1560
|
-
if (!match) {
|
|
1561
|
-
match = void 0;
|
|
1562
|
-
break;
|
|
1563
|
-
}
|
|
1564
|
-
idx = text.indexOf(match[0]);
|
|
1565
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1566
|
-
break;
|
|
1567
|
-
}
|
|
1568
|
-
idx += match[0].length;
|
|
1569
|
-
} while (true);
|
|
1570
|
-
if (!match) {
|
|
1571
|
-
return null;
|
|
1572
1401
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
pos: idx + from,
|
|
1576
|
-
end: idx + from + match[0].length,
|
|
1577
|
-
above: true,
|
|
1578
|
-
create: () => {
|
|
1579
|
-
const el = document.createElement("div");
|
|
1580
|
-
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1581
|
-
options.onHover(el, url);
|
|
1582
|
-
return {
|
|
1583
|
-
dom: el,
|
|
1584
|
-
offset: {
|
|
1585
|
-
x: 0,
|
|
1586
|
-
y: 4
|
|
1587
|
-
}
|
|
1588
|
-
};
|
|
1589
|
-
}
|
|
1590
|
-
};
|
|
1591
|
-
})
|
|
1592
|
-
);
|
|
1593
|
-
}
|
|
1594
|
-
return extensions;
|
|
1595
|
-
};
|
|
1596
|
-
var LinkButton = class extends WidgetType5 {
|
|
1597
|
-
constructor(_pos, _url, _onAttach) {
|
|
1598
|
-
super();
|
|
1599
|
-
this._pos = _pos;
|
|
1600
|
-
this._url = _url;
|
|
1601
|
-
this._onAttach = _onAttach;
|
|
1602
|
-
}
|
|
1603
|
-
eq(other) {
|
|
1604
|
-
return this._pos === other._pos && this._url === other._url;
|
|
1605
|
-
}
|
|
1606
|
-
toDOM(view) {
|
|
1607
|
-
const el = document.createElement("span");
|
|
1608
|
-
this._onAttach(el, this._url);
|
|
1609
|
-
return el;
|
|
1610
|
-
}
|
|
1611
|
-
};
|
|
1612
|
-
var LinkText = class extends WidgetType5 {
|
|
1613
|
-
constructor(_text, _url) {
|
|
1614
|
-
super();
|
|
1615
|
-
this._text = _text;
|
|
1616
|
-
this._url = _url;
|
|
1617
|
-
}
|
|
1618
|
-
eq(other) {
|
|
1619
|
-
return this._url === other._url;
|
|
1620
|
-
}
|
|
1621
|
-
toDOM(view) {
|
|
1622
|
-
const link2 = document.createElement("a");
|
|
1623
|
-
link2.setAttribute("class", "cm-link");
|
|
1624
|
-
link2.textContent = this._text;
|
|
1625
|
-
if (this._url) {
|
|
1626
|
-
link2.setAttribute("rel", "noreferrer");
|
|
1627
|
-
link2.setAttribute("target", "_blank");
|
|
1628
|
-
link2.href = this._url;
|
|
1629
|
-
} else {
|
|
1630
|
-
link2.onclick = () => {
|
|
1402
|
+
});
|
|
1403
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1631
1404
|
view.dispatch({
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
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
|
+
}))
|
|
1635
1414
|
});
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
return link2;
|
|
1639
|
-
}
|
|
1640
|
-
};
|
|
1641
|
-
var update2 = (state, options) => {
|
|
1642
|
-
const builder = new RangeSetBuilder2();
|
|
1643
|
-
const cursor = state.selection.main.head;
|
|
1644
|
-
syntaxTree2(state).iterate({
|
|
1645
|
-
enter: (node) => {
|
|
1646
|
-
if (node.name === "Link") {
|
|
1647
|
-
const marks2 = node.node.getChildren("LinkMark");
|
|
1648
|
-
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1649
|
-
const urlNode = node.node.getChild("URL");
|
|
1650
|
-
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1651
|
-
if (!url) {
|
|
1652
|
-
return false;
|
|
1653
|
-
}
|
|
1654
|
-
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1655
|
-
builder.add(node.from, node.to, Decoration6.replace({
|
|
1656
|
-
widget: new LinkText(text, options.link ? url : void 0)
|
|
1657
|
-
}));
|
|
1658
|
-
}
|
|
1659
|
-
if (options.onRender) {
|
|
1660
|
-
builder.add(node.to, node.to, Decoration6.replace({
|
|
1661
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1662
|
-
}));
|
|
1663
|
-
}
|
|
1664
|
-
return false;
|
|
1665
1415
|
}
|
|
1416
|
+
}),
|
|
1417
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1418
|
+
];
|
|
1419
|
+
};
|
|
1420
|
+
var useComments = (view, comments2 = []) => {
|
|
1421
|
+
useEffect(() => {
|
|
1422
|
+
if (view) {
|
|
1423
|
+
view.dispatch({
|
|
1424
|
+
effects: setComments.of(comments2)
|
|
1425
|
+
});
|
|
1666
1426
|
}
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1427
|
+
}, [
|
|
1428
|
+
view,
|
|
1429
|
+
comments2
|
|
1430
|
+
]);
|
|
1669
1431
|
};
|
|
1670
1432
|
|
|
1671
1433
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1672
|
-
import { EditorView as
|
|
1434
|
+
import { EditorView as EditorView6 } from "@codemirror/view";
|
|
1673
1435
|
var listener = ({ onFocus, onChange }) => {
|
|
1674
1436
|
const extensions = [];
|
|
1675
|
-
onFocus && extensions.push(
|
|
1437
|
+
onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
|
|
1676
1438
|
onFocus(focused);
|
|
1677
1439
|
return null;
|
|
1678
1440
|
}));
|
|
1679
|
-
onChange && extensions.push(
|
|
1680
|
-
onChange(
|
|
1441
|
+
onChange && extensions.push(EditorView6.updateListener.of((update2) => {
|
|
1442
|
+
onChange(update2.state.doc.toString());
|
|
1681
1443
|
}));
|
|
1682
1444
|
return extensions;
|
|
1683
1445
|
};
|
|
1684
1446
|
|
|
1685
1447
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1686
1448
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1687
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1688
|
-
import { markdownLanguage as
|
|
1449
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1450
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1689
1451
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1690
1452
|
import { languages } from "@codemirror/language-data";
|
|
1691
1453
|
import { searchKeymap } from "@codemirror/search";
|
|
1692
1454
|
import { EditorState } from "@codemirror/state";
|
|
1693
1455
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1694
|
-
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";
|
|
1695
1458
|
|
|
1696
1459
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1697
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1460
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1698
1461
|
import { HighlightStyle } from "@codemirror/language";
|
|
1699
1462
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1700
1463
|
import { Table } from "@lezer/markdown";
|
|
1701
|
-
import get5 from "lodash.get";
|
|
1702
1464
|
var markdownTags = {
|
|
1703
1465
|
Blockquote: Tag.define(),
|
|
1704
1466
|
CodeMark: Tag.define(),
|
|
1705
1467
|
CodeText: Tag.define(),
|
|
1706
1468
|
EmphasisMark: Tag.define(),
|
|
1707
1469
|
HeaderMark: Tag.define(),
|
|
1708
|
-
// HorizontalRule: Tag.define(),
|
|
1709
1470
|
InlineCode: Tag.define(),
|
|
1710
1471
|
LinkLabel: Tag.define(),
|
|
1711
1472
|
LinkReference: Tag.define(),
|
|
@@ -1790,7 +1551,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1790
1551
|
markdownTags.QuoteMark,
|
|
1791
1552
|
markdownTags.EmphasisMark
|
|
1792
1553
|
],
|
|
1793
|
-
class:
|
|
1554
|
+
class: mark
|
|
1794
1555
|
},
|
|
1795
1556
|
// E.g., code block language (after ```).
|
|
1796
1557
|
{
|
|
@@ -1798,7 +1559,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1798
1559
|
tags.function(tags.variableName),
|
|
1799
1560
|
tags.labelName
|
|
1800
1561
|
],
|
|
1801
|
-
class:
|
|
1562
|
+
class: codeMark
|
|
1802
1563
|
},
|
|
1803
1564
|
{
|
|
1804
1565
|
tag: [
|
|
@@ -1809,27 +1570,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1809
1570
|
// Headings.
|
|
1810
1571
|
{
|
|
1811
1572
|
tag: tags.heading1,
|
|
1812
|
-
class: heading(1
|
|
1573
|
+
class: heading(1)
|
|
1813
1574
|
},
|
|
1814
1575
|
{
|
|
1815
1576
|
tag: tags.heading2,
|
|
1816
|
-
class: heading(2
|
|
1577
|
+
class: heading(2)
|
|
1817
1578
|
},
|
|
1818
1579
|
{
|
|
1819
1580
|
tag: tags.heading3,
|
|
1820
|
-
class: heading(3
|
|
1581
|
+
class: heading(3)
|
|
1821
1582
|
},
|
|
1822
1583
|
{
|
|
1823
1584
|
tag: tags.heading4,
|
|
1824
|
-
class: heading(4
|
|
1585
|
+
class: heading(4)
|
|
1825
1586
|
},
|
|
1826
1587
|
{
|
|
1827
1588
|
tag: tags.heading5,
|
|
1828
|
-
class: heading(5
|
|
1589
|
+
class: heading(5)
|
|
1829
1590
|
},
|
|
1830
1591
|
{
|
|
1831
1592
|
tag: tags.heading6,
|
|
1832
|
-
class: heading(6
|
|
1593
|
+
class: heading(6)
|
|
1833
1594
|
},
|
|
1834
1595
|
// Emphasis.
|
|
1835
1596
|
{
|
|
@@ -1855,7 +1616,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1855
1616
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1856
1617
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1857
1618
|
// the code, but all other CSS properties will be inherited.
|
|
1858
|
-
// 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.
|
|
1859
1620
|
{
|
|
1860
1621
|
tag: [
|
|
1861
1622
|
markdownTags.CodeText,
|
|
@@ -1869,12 +1630,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1869
1630
|
],
|
|
1870
1631
|
class: blockquote
|
|
1871
1632
|
},
|
|
1872
|
-
// TODO(burdon): Replace with extension.
|
|
1873
|
-
// {
|
|
1874
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1875
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1876
|
-
// },
|
|
1877
|
-
// TODO(burdon): Only if being edited.
|
|
1878
1633
|
{
|
|
1879
1634
|
tag: [
|
|
1880
1635
|
markdownTags.TableCell
|
|
@@ -1882,27 +1637,27 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1882
1637
|
class: "font-mono"
|
|
1883
1638
|
}
|
|
1884
1639
|
], {
|
|
1885
|
-
scope:
|
|
1640
|
+
scope: markdownLanguage2,
|
|
1886
1641
|
all: {
|
|
1887
|
-
fontFamily:
|
|
1642
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1888
1643
|
}
|
|
1889
1644
|
});
|
|
1890
1645
|
};
|
|
1891
1646
|
|
|
1892
1647
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1893
|
-
var
|
|
1648
|
+
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1894
1649
|
return [
|
|
1650
|
+
lineWrapping && EditorView7.lineWrapping,
|
|
1895
1651
|
EditorState.allowMultipleSelections.of(true),
|
|
1896
1652
|
EditorState.tabSize.of(2),
|
|
1897
|
-
|
|
1898
|
-
customKeymap(),
|
|
1653
|
+
// https://github.com/codemirror/basic-setup
|
|
1899
1654
|
bracketMatching2(),
|
|
1900
1655
|
closeBrackets2(),
|
|
1901
1656
|
crosshairCursor(),
|
|
1902
1657
|
dropCursor(),
|
|
1903
1658
|
drawSelection2(),
|
|
1904
|
-
|
|
1905
|
-
|
|
1659
|
+
highlightActiveLine2(),
|
|
1660
|
+
history2(),
|
|
1906
1661
|
indentOnInput(),
|
|
1907
1662
|
_placeholder && placeholder2(_placeholder),
|
|
1908
1663
|
// Main extension.
|
|
@@ -1914,7 +1669,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1914
1669
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1915
1670
|
// https://github.github.com/gfm
|
|
1916
1671
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1917
|
-
base:
|
|
1672
|
+
base: markdownLanguage3,
|
|
1918
1673
|
// Languages for syntax highlighting fenced code blocks.
|
|
1919
1674
|
codeLanguages: languages,
|
|
1920
1675
|
// Parser extensions.
|
|
@@ -1926,81 +1681,620 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1926
1681
|
// https://github.com/codemirror/theme-one-dark
|
|
1927
1682
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1928
1683
|
// Custom styles.
|
|
1929
|
-
syntaxHighlighting2(markdownHighlightStyle(
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
]);
|
|
1944
|
-
|
|
1945
|
-
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1946
|
-
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1947
|
-
var mention = ({ onSearch }) => {
|
|
1948
|
-
return autocompletion2({
|
|
1949
|
-
closeOnBlur: false,
|
|
1950
|
-
override: [
|
|
1951
|
-
(context) => {
|
|
1952
|
-
const match = context.matchBefore(/@(\w+)?/);
|
|
1953
|
-
if (!match || match.from === match.to && !context.explicit) {
|
|
1954
|
-
return null;
|
|
1955
|
-
}
|
|
1956
|
-
console.log(match);
|
|
1957
|
-
return {
|
|
1958
|
-
from: match.from,
|
|
1959
|
-
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1960
|
-
label: `@${value}`
|
|
1961
|
-
}))
|
|
1962
|
-
};
|
|
1963
|
-
}
|
|
1964
|
-
]
|
|
1965
|
-
});
|
|
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);
|
|
1966
1698
|
};
|
|
1967
1699
|
|
|
1968
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1969
|
-
|
|
1970
|
-
|
|
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
|
+
];
|
|
1971
1753
|
};
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
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
|
+
}
|
|
1983
1765
|
};
|
|
1984
|
-
var
|
|
1985
|
-
|
|
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;
|
|
1986
1772
|
const cursor = state.selection.main.head;
|
|
1987
|
-
const
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
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
|
+
}
|
|
2002
1791
|
}
|
|
2003
|
-
|
|
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
|
|
1956
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
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";
|
|
2271
|
+
var table = (options = {}) => {
|
|
2272
|
+
return StateField4.define({
|
|
2273
|
+
create: (state) => update(state, options),
|
|
2274
|
+
update: (_, tr) => update(tr.state, options),
|
|
2275
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
2276
|
+
});
|
|
2277
|
+
};
|
|
2278
|
+
var update = (state, options) => {
|
|
2279
|
+
const builder = new RangeSetBuilder6();
|
|
2280
|
+
const cursor = state.selection.main.head;
|
|
2281
|
+
const tables = [];
|
|
2282
|
+
const getTable = () => tables[tables.length - 1];
|
|
2283
|
+
const getRow = () => {
|
|
2284
|
+
const table2 = getTable();
|
|
2285
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
2286
|
+
};
|
|
2287
|
+
syntaxTree7(state).iterate({
|
|
2288
|
+
enter: (node) => {
|
|
2289
|
+
switch (node.name) {
|
|
2290
|
+
case "Table": {
|
|
2291
|
+
tables.push({
|
|
2292
|
+
from: node.from,
|
|
2293
|
+
to: node.to
|
|
2294
|
+
});
|
|
2295
|
+
break;
|
|
2296
|
+
}
|
|
2297
|
+
case "TableHeader": {
|
|
2004
2298
|
getTable().header = [];
|
|
2005
2299
|
break;
|
|
2006
2300
|
}
|
|
@@ -2022,11 +2316,10 @@ var update3 = (state, options) => {
|
|
|
2022
2316
|
});
|
|
2023
2317
|
tables.forEach((table2) => {
|
|
2024
2318
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
2025
|
-
hide && builder.add(table2.from, table2.to,
|
|
2026
|
-
block: true,
|
|
2319
|
+
hide && builder.add(table2.from, table2.to, Decoration9.replace({
|
|
2027
2320
|
widget: new TableWidget(table2)
|
|
2028
2321
|
}));
|
|
2029
|
-
builder.add(table2.from, table2.to,
|
|
2322
|
+
builder.add(table2.from, table2.to, Decoration9.mark({
|
|
2030
2323
|
class: "cm-table"
|
|
2031
2324
|
}));
|
|
2032
2325
|
});
|
|
@@ -2038,7 +2331,7 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2038
2331
|
this._table = _table;
|
|
2039
2332
|
}
|
|
2040
2333
|
eq(other) {
|
|
2041
|
-
return this._table.
|
|
2334
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
2042
2335
|
}
|
|
2043
2336
|
toDOM(view) {
|
|
2044
2337
|
const table2 = document.createElement("table");
|
|
@@ -2064,95 +2357,144 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2064
2357
|
}
|
|
2065
2358
|
return table2;
|
|
2066
2359
|
}
|
|
2360
|
+
ignoreEvent(e) {
|
|
2361
|
+
return !/^mouse/.test(e.type);
|
|
2362
|
+
}
|
|
2067
2363
|
};
|
|
2068
2364
|
|
|
2069
|
-
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
2070
|
-
import {
|
|
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";
|
|
2071
2369
|
var styles5 = EditorView12.baseTheme({
|
|
2072
|
-
"& .cm-task
|
|
2073
|
-
|
|
2074
|
-
|
|
2370
|
+
"& .cm-task": {
|
|
2371
|
+
color: getToken("extend.colors.blue.500")
|
|
2372
|
+
},
|
|
2373
|
+
"& .cm-task-checkbox": {
|
|
2374
|
+
marginLeft: "4px",
|
|
2375
|
+
marginRight: "4px"
|
|
2075
2376
|
}
|
|
2076
2377
|
});
|
|
2077
2378
|
var CheckboxWidget = class extends WidgetType7 {
|
|
2078
|
-
constructor(
|
|
2379
|
+
constructor(_checked) {
|
|
2079
2380
|
super();
|
|
2080
|
-
this._pos = _pos;
|
|
2081
2381
|
this._checked = _checked;
|
|
2082
|
-
this._indent = _indent;
|
|
2083
|
-
this._onCheck = _onCheck;
|
|
2084
2382
|
}
|
|
2085
2383
|
eq(other) {
|
|
2086
|
-
return this.
|
|
2384
|
+
return this._checked === other._checked;
|
|
2087
2385
|
}
|
|
2088
2386
|
toDOM(view) {
|
|
2089
|
-
const
|
|
2090
|
-
|
|
2091
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2092
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2093
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2387
|
+
const input = document.createElement("input");
|
|
2388
|
+
input.className = "cm-task-checkbox";
|
|
2094
2389
|
input.type = "checkbox";
|
|
2095
2390
|
input.checked = this._checked;
|
|
2096
|
-
if (
|
|
2391
|
+
if (view.state.readOnly) {
|
|
2097
2392
|
input.setAttribute("disabled", "true");
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
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
|
+
}
|
|
2103
2407
|
};
|
|
2104
2408
|
}
|
|
2105
|
-
return
|
|
2409
|
+
return input;
|
|
2106
2410
|
}
|
|
2107
2411
|
ignoreEvent() {
|
|
2108
2412
|
return false;
|
|
2109
2413
|
}
|
|
2110
2414
|
};
|
|
2111
|
-
var
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
}
|
|
2142
|
-
}, {
|
|
2143
|
-
decorations: (value) => value.tasks,
|
|
2144
|
-
provide: (plugin) => EditorView12.atomicRanges.of((view) => {
|
|
2145
|
-
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2146
|
-
})
|
|
2147
|
-
});
|
|
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
|
+
};
|
|
2444
|
+
var tasklist = (options = {}) => {
|
|
2148
2445
|
return [
|
|
2149
|
-
|
|
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
|
+
}),
|
|
2150
2458
|
styles5
|
|
2151
2459
|
];
|
|
2152
2460
|
};
|
|
2153
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
|
+
|
|
2154
2496
|
// packages/ui/react-ui-editor/src/extensions/typewriter.ts
|
|
2155
|
-
import { keymap as
|
|
2497
|
+
import { keymap as keymap6 } from "@codemirror/view";
|
|
2156
2498
|
var defaultItems = [
|
|
2157
2499
|
"hello world!",
|
|
2158
2500
|
"this is a test.",
|
|
@@ -2162,7 +2504,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2162
2504
|
let t;
|
|
2163
2505
|
let idx = 0;
|
|
2164
2506
|
return [
|
|
2165
|
-
|
|
2507
|
+
keymap6.of([
|
|
2166
2508
|
{
|
|
2167
2509
|
// Reset.
|
|
2168
2510
|
key: "alt-meta-'",
|
|
@@ -2208,29 +2550,8 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2208
2550
|
];
|
|
2209
2551
|
};
|
|
2210
2552
|
|
|
2211
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2212
|
-
import { yCollab } from "y-codemirror.next";
|
|
2213
|
-
|
|
2214
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2215
|
-
import * as Y from "yjs";
|
|
2216
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2217
|
-
var cursorConverter2 = (text) => ({
|
|
2218
|
-
toCursor: (index, assoc) => {
|
|
2219
|
-
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2220
|
-
},
|
|
2221
|
-
fromCursor: (cursor) => {
|
|
2222
|
-
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2223
|
-
}
|
|
2224
|
-
});
|
|
2225
|
-
|
|
2226
|
-
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2227
|
-
var yjs = (content, awareness2) => [
|
|
2228
|
-
CursorConverter.of(cursorConverter2(content)),
|
|
2229
|
-
yCollab(content, awareness2)
|
|
2230
|
-
];
|
|
2231
|
-
|
|
2232
2553
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2233
|
-
import
|
|
2554
|
+
import get3 from "lodash.get";
|
|
2234
2555
|
var defaultTheme = {
|
|
2235
2556
|
//
|
|
2236
2557
|
// Main layout:
|
|
@@ -2259,21 +2580,22 @@ var defaultTheme = {
|
|
|
2259
2580
|
"&.cm-focused": {
|
|
2260
2581
|
outline: "none"
|
|
2261
2582
|
},
|
|
2262
|
-
"
|
|
2263
|
-
overflow:
|
|
2264
|
-
fontFamily:
|
|
2583
|
+
".cm-scroller": {
|
|
2584
|
+
// overflow: 'visible',
|
|
2585
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
|
|
2586
|
+
lineHeight: 1.4
|
|
2265
2587
|
},
|
|
2266
|
-
"
|
|
2588
|
+
".cm-content": {
|
|
2267
2589
|
padding: 0,
|
|
2268
2590
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2269
2591
|
fontSize: "16px"
|
|
2270
2592
|
},
|
|
2271
2593
|
"&light .cm-content": {
|
|
2272
|
-
color:
|
|
2594
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2273
2595
|
caretColor: "black"
|
|
2274
2596
|
},
|
|
2275
2597
|
"&dark .cm-content": {
|
|
2276
|
-
color:
|
|
2598
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2277
2599
|
caretColor: "white"
|
|
2278
2600
|
},
|
|
2279
2601
|
//
|
|
@@ -2285,158 +2607,123 @@ var defaultTheme = {
|
|
|
2285
2607
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2286
2608
|
borderLeft: "2px solid white"
|
|
2287
2609
|
},
|
|
2288
|
-
"& .cm-placeholder": {
|
|
2289
|
-
|
|
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)")
|
|
2290
2615
|
},
|
|
2291
2616
|
//
|
|
2292
2617
|
// line
|
|
2293
2618
|
//
|
|
2294
|
-
"
|
|
2619
|
+
".cm-line": {
|
|
2295
2620
|
paddingInline: 0
|
|
2296
2621
|
},
|
|
2297
|
-
"
|
|
2298
|
-
background: "
|
|
2622
|
+
".cm-activeLine": {
|
|
2623
|
+
background: "transparent"
|
|
2299
2624
|
},
|
|
2300
2625
|
//
|
|
2301
2626
|
// Selection
|
|
2302
2627
|
//
|
|
2303
2628
|
"&light .cm-selectionBackground": {
|
|
2304
|
-
background:
|
|
2629
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2305
2630
|
},
|
|
2306
2631
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2307
|
-
background:
|
|
2632
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2308
2633
|
},
|
|
2309
2634
|
"&dark .cm-selectionBackground": {
|
|
2310
|
-
background:
|
|
2635
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2311
2636
|
},
|
|
2312
2637
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2313
|
-
background:
|
|
2638
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2314
2639
|
},
|
|
2315
2640
|
//
|
|
2316
2641
|
// Search
|
|
2317
2642
|
//
|
|
2318
2643
|
"&light .cm-searchMatch": {
|
|
2319
|
-
backgroundColor:
|
|
2644
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2320
2645
|
},
|
|
2321
2646
|
"&dark .cm-searchMatch": {
|
|
2322
|
-
backgroundColor:
|
|
2323
|
-
},
|
|
2324
|
-
//
|
|
2325
|
-
// collaboration
|
|
2326
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2327
|
-
//
|
|
2328
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2329
|
-
mixBlendMode: "multiply"
|
|
2330
|
-
},
|
|
2331
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2332
|
-
mixBlendMode: "screen"
|
|
2333
|
-
},
|
|
2334
|
-
"& .cm-ySelectionInfo": {
|
|
2335
|
-
padding: "2px 4px",
|
|
2336
|
-
marginBlockStart: "-4px"
|
|
2337
|
-
},
|
|
2338
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2339
|
-
paddingBlockStart: ".15em",
|
|
2340
|
-
paddingBlockEnd: ".15em"
|
|
2341
|
-
},
|
|
2342
|
-
"& .cm-ySelectionCaret": {
|
|
2343
|
-
display: "inline-block",
|
|
2344
|
-
insetBlockStart: ".1em",
|
|
2345
|
-
blockSize: "1.4em",
|
|
2346
|
-
verticalAlign: "top"
|
|
2347
|
-
},
|
|
2348
|
-
"& .cm-yLineSelection": {
|
|
2349
|
-
margin: 0
|
|
2647
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2350
2648
|
},
|
|
2351
2649
|
//
|
|
2352
2650
|
// link
|
|
2353
2651
|
//
|
|
2354
|
-
"
|
|
2355
|
-
color:
|
|
2652
|
+
".cm-link": {
|
|
2653
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2356
2654
|
textDecorationLine: "underline",
|
|
2357
2655
|
textDecorationThickness: "1px",
|
|
2358
2656
|
textUnderlineOffset: "2px",
|
|
2359
2657
|
borderRadius: ".125rem",
|
|
2360
|
-
fontFamily:
|
|
2658
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2361
2659
|
},
|
|
2362
2660
|
//
|
|
2363
2661
|
// tooltip
|
|
2364
2662
|
//
|
|
2365
|
-
"
|
|
2663
|
+
".cm-tooltip": {
|
|
2366
2664
|
border: "none"
|
|
2367
2665
|
},
|
|
2368
|
-
"
|
|
2666
|
+
".cm-tooltip-below": {},
|
|
2369
2667
|
//
|
|
2370
2668
|
// autocomplete
|
|
2371
2669
|
//
|
|
2372
|
-
"
|
|
2670
|
+
".cm-tooltip-autocomplete": {
|
|
2373
2671
|
marginTop: "4px",
|
|
2374
2672
|
marginLeft: "-3px"
|
|
2375
2673
|
},
|
|
2376
|
-
"
|
|
2377
|
-
"
|
|
2378
|
-
"
|
|
2674
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2675
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2676
|
+
".cm-completionIcon": {
|
|
2379
2677
|
display: "none"
|
|
2380
2678
|
},
|
|
2381
|
-
"
|
|
2382
|
-
fontFamily:
|
|
2679
|
+
".cm-completionLabel": {
|
|
2680
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2383
2681
|
},
|
|
2384
|
-
"
|
|
2682
|
+
".cm-completionMatchedText": {
|
|
2385
2683
|
textDecoration: "none"
|
|
2386
2684
|
},
|
|
2387
2685
|
//
|
|
2388
|
-
// widgets
|
|
2389
|
-
//
|
|
2390
|
-
"& .cm-widgetBuffer": {
|
|
2391
|
-
display: "none",
|
|
2392
|
-
height: 0
|
|
2393
|
-
},
|
|
2394
|
-
//
|
|
2395
2686
|
// table
|
|
2396
2687
|
//
|
|
2397
|
-
"
|
|
2398
|
-
fontFamily: `${
|
|
2688
|
+
".cm-table *": {
|
|
2689
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2399
2690
|
textDecoration: "none !important"
|
|
2400
2691
|
},
|
|
2401
|
-
"
|
|
2692
|
+
".cm-table-head": {
|
|
2402
2693
|
padding: "2px 16px 2px 0px",
|
|
2403
|
-
borderBottom: `1px solid ${
|
|
2694
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2404
2695
|
fontWeight: 100,
|
|
2405
2696
|
textAlign: "left",
|
|
2406
|
-
color:
|
|
2697
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2407
2698
|
},
|
|
2408
|
-
"
|
|
2699
|
+
".cm-table-cell": {
|
|
2409
2700
|
padding: "2px 16px 2px 0px"
|
|
2410
2701
|
},
|
|
2411
2702
|
//
|
|
2412
2703
|
// image
|
|
2413
2704
|
//
|
|
2414
|
-
"
|
|
2415
|
-
|
|
2705
|
+
".cm-image": {
|
|
2706
|
+
display: "block",
|
|
2707
|
+
height: "0"
|
|
2708
|
+
},
|
|
2709
|
+
".cm-image.cm-loaded-image": {
|
|
2710
|
+
height: "auto",
|
|
2711
|
+
borderTop: "0.5rem solid transparent",
|
|
2712
|
+
borderBottom: "0.5rem solid transparent"
|
|
2416
2713
|
},
|
|
2417
2714
|
//
|
|
2418
2715
|
// font size
|
|
2419
|
-
// 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.
|
|
2420
2718
|
//
|
|
2421
|
-
...Object.keys(
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2430
|
-
height
|
|
2431
|
-
};
|
|
2432
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2433
|
-
height
|
|
2434
|
-
};
|
|
2435
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2436
|
-
height
|
|
2437
|
-
};
|
|
2438
|
-
return acc;
|
|
2439
|
-
}, {}),
|
|
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
|
+
// }, {}),
|
|
2440
2727
|
/**
|
|
2441
2728
|
* Panels
|
|
2442
2729
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2453,144 +2740,146 @@ var defaultTheme = {
|
|
|
2453
2740
|
* </div>
|
|
2454
2741
|
* </div
|
|
2455
2742
|
*/
|
|
2456
|
-
"
|
|
2457
|
-
border: `1px solid ${
|
|
2743
|
+
".cm-panels": {
|
|
2744
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2458
2745
|
},
|
|
2459
|
-
"
|
|
2460
|
-
background:
|
|
2461
|
-
fontFamily:
|
|
2746
|
+
".cm-panel": {
|
|
2747
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2748
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2462
2749
|
},
|
|
2463
|
-
"
|
|
2750
|
+
".cm-button": {
|
|
2464
2751
|
margin: "4px",
|
|
2465
|
-
fontFamily:
|
|
2466
|
-
background:
|
|
2752
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2753
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2467
2754
|
backgroundImage: "none",
|
|
2468
2755
|
border: "none",
|
|
2469
2756
|
"&:hover": {
|
|
2470
|
-
background:
|
|
2757
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2471
2758
|
},
|
|
2472
2759
|
"&:active": {
|
|
2473
|
-
background:
|
|
2760
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2474
2761
|
backgroundImage: "none"
|
|
2475
2762
|
}
|
|
2476
2763
|
},
|
|
2477
|
-
"
|
|
2764
|
+
".cm-panel input[type=checkbox]": {
|
|
2478
2765
|
marginRight: "0.4rem !important"
|
|
2479
2766
|
}
|
|
2480
2767
|
};
|
|
2481
2768
|
var textTheme = {
|
|
2482
|
-
"
|
|
2483
|
-
fontFamily:
|
|
2769
|
+
".cm-scroller": {
|
|
2770
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2484
2771
|
},
|
|
2485
|
-
"
|
|
2486
|
-
fontFamily:
|
|
2772
|
+
".cm-placeholder": {
|
|
2773
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2487
2774
|
}
|
|
2488
2775
|
};
|
|
2489
2776
|
var markdownTheme = {
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2777
|
+
".cm-scroller": {
|
|
2778
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2779
|
+
},
|
|
2780
|
+
".cm-placeholder": {
|
|
2781
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2493
2782
|
}
|
|
2494
2783
|
};
|
|
2495
2784
|
var codeTheme = {
|
|
2496
|
-
"
|
|
2497
|
-
fontFamily:
|
|
2785
|
+
".cm-scroller": {
|
|
2786
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2498
2787
|
},
|
|
2499
|
-
"
|
|
2500
|
-
fontFamily:
|
|
2788
|
+
".cm-placeholder": {
|
|
2789
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2501
2790
|
}
|
|
2502
2791
|
};
|
|
2503
2792
|
|
|
2504
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";
|
|
2505
2795
|
var EditorModes = [
|
|
2506
2796
|
"default",
|
|
2507
2797
|
"vim"
|
|
2508
2798
|
];
|
|
2509
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2799
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2510
2800
|
const { themeMode } = useThemeContext();
|
|
2511
|
-
const
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
const [root, setRoot] = useState(null);
|
|
2515
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2516
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
2517
|
-
root,
|
|
2518
|
-
state,
|
|
2801
|
+
const rootRef = useRef(null);
|
|
2802
|
+
const [view, setView] = useState(null);
|
|
2803
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2519
2804
|
view
|
|
2520
|
-
}), [
|
|
2521
|
-
view,
|
|
2522
|
-
state,
|
|
2523
|
-
root
|
|
2524
|
-
]);
|
|
2525
|
-
const { awareness: awareness2, peer } = model;
|
|
2526
|
-
useEffect(() => {
|
|
2527
|
-
if (awareness2 && peer) {
|
|
2528
|
-
awareness2.setLocalStateField("user", {
|
|
2529
|
-
name: peer.name ?? generateName(peer.id),
|
|
2530
|
-
color: getColorForValue({
|
|
2531
|
-
value: peer.id,
|
|
2532
|
-
type: "color"
|
|
2533
|
-
}),
|
|
2534
|
-
colorLight: getColorForValue({
|
|
2535
|
-
value: peer.id,
|
|
2536
|
-
themeMode,
|
|
2537
|
-
type: "highlight"
|
|
2538
|
-
})
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
}, [
|
|
2542
|
-
awareness2,
|
|
2543
|
-
peer,
|
|
2544
|
-
themeMode
|
|
2545
2805
|
]);
|
|
2546
|
-
|
|
2547
|
-
if (
|
|
2548
|
-
view.
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
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();
|
|
2554
2817
|
}
|
|
2555
2818
|
}, [
|
|
2556
2819
|
view,
|
|
2557
|
-
|
|
2820
|
+
autoFocus
|
|
2558
2821
|
]);
|
|
2559
|
-
|
|
2560
|
-
if (!
|
|
2822
|
+
useEffect2(() => {
|
|
2823
|
+
if (!model || !rootRef.current) {
|
|
2561
2824
|
return;
|
|
2562
2825
|
}
|
|
2563
|
-
const
|
|
2826
|
+
const state = EditorState2.create({
|
|
2564
2827
|
doc: model.text(),
|
|
2828
|
+
selection,
|
|
2565
2829
|
extensions: [
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
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
|
+
}),
|
|
2569
2839
|
// Theme.
|
|
2570
|
-
// TODO(burdon): Make
|
|
2840
|
+
// TODO(burdon): Make configurable.
|
|
2571
2841
|
EditorView13.baseTheme(defaultTheme),
|
|
2572
|
-
EditorView13.theme(
|
|
2842
|
+
EditorView13.theme(theme ?? {}),
|
|
2573
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),
|
|
2574
2853
|
// Storage and replication.
|
|
2854
|
+
// NOTE: This must come before user extensions.
|
|
2575
2855
|
model.extension,
|
|
2856
|
+
// TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
|
|
2857
|
+
editorMode === "vim" && vim(),
|
|
2576
2858
|
// Custom.
|
|
2577
2859
|
...extensions
|
|
2578
|
-
].filter(
|
|
2860
|
+
].filter(isNotFalsy3)
|
|
2579
2861
|
});
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
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
|
+
}
|
|
2587
2874
|
});
|
|
2875
|
+
view?.destroy();
|
|
2876
|
+
setView(newView);
|
|
2588
2877
|
return () => {
|
|
2589
|
-
|
|
2590
|
-
|
|
2878
|
+
newView?.destroy();
|
|
2879
|
+
setView(null);
|
|
2591
2880
|
};
|
|
2592
2881
|
}, [
|
|
2593
|
-
|
|
2882
|
+
rootRef,
|
|
2594
2883
|
model,
|
|
2595
2884
|
readonly,
|
|
2596
2885
|
editorMode,
|
|
@@ -2600,11 +2889,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2600
2889
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2601
2890
|
switch (key) {
|
|
2602
2891
|
case "Enter": {
|
|
2603
|
-
view?.
|
|
2892
|
+
view?.focus();
|
|
2604
2893
|
break;
|
|
2605
2894
|
}
|
|
2606
2895
|
case "Escape": {
|
|
2607
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2896
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2897
|
+
view?.focus();
|
|
2898
|
+
}
|
|
2608
2899
|
break;
|
|
2609
2900
|
}
|
|
2610
2901
|
}
|
|
@@ -2614,83 +2905,238 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2614
2905
|
]);
|
|
2615
2906
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2616
2907
|
key: model.id,
|
|
2617
|
-
|
|
2908
|
+
role: "none",
|
|
2618
2909
|
tabIndex: 0,
|
|
2619
|
-
...slots
|
|
2620
|
-
...editorMode !==
|
|
2621
|
-
onKeyUp: handleKeyUp
|
|
2910
|
+
...slots.root,
|
|
2911
|
+
// {...(editorMode !== 'vim' && tabsterDOMAttribute)}
|
|
2912
|
+
onKeyUp: handleKeyUp,
|
|
2913
|
+
ref: rootRef
|
|
2622
2914
|
});
|
|
2623
2915
|
});
|
|
2624
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2916
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2625
2917
|
const { themeMode } = useThemeContext();
|
|
2626
|
-
const
|
|
2918
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2627
2919
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2628
2920
|
ref: forwardedRef,
|
|
2629
2921
|
readonly,
|
|
2630
2922
|
extensions: [
|
|
2631
|
-
|
|
2632
|
-
readonly,
|
|
2923
|
+
createBasicBundle({
|
|
2633
2924
|
themeMode,
|
|
2634
|
-
placeholder:
|
|
2925
|
+
placeholder: placeholder3,
|
|
2926
|
+
lineWrapping
|
|
2635
2927
|
}),
|
|
2636
2928
|
...extensions
|
|
2637
2929
|
],
|
|
2638
|
-
|
|
2930
|
+
theme,
|
|
2931
|
+
slots: updatedSlots,
|
|
2639
2932
|
...props
|
|
2640
2933
|
});
|
|
2641
2934
|
});
|
|
2642
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2935
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2643
2936
|
const { themeMode } = useThemeContext();
|
|
2644
|
-
const
|
|
2937
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2645
2938
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2646
2939
|
ref: forwardedRef,
|
|
2647
2940
|
readonly,
|
|
2648
2941
|
extensions: [
|
|
2649
|
-
|
|
2650
|
-
readonly,
|
|
2942
|
+
createMarkdownExtensions({
|
|
2651
2943
|
themeMode,
|
|
2652
|
-
placeholder:
|
|
2944
|
+
placeholder: placeholder3
|
|
2653
2945
|
}),
|
|
2654
2946
|
...extensions
|
|
2655
2947
|
],
|
|
2656
|
-
|
|
2948
|
+
theme,
|
|
2949
|
+
slots: updatedSlots,
|
|
2657
2950
|
...props
|
|
2658
2951
|
});
|
|
2659
2952
|
});
|
|
2660
2953
|
var defaultSlots = {
|
|
2661
2954
|
root: {
|
|
2662
|
-
className: mx3("
|
|
2955
|
+
className: mx3("grow", focusRing)
|
|
2956
|
+
},
|
|
2957
|
+
editor: {
|
|
2958
|
+
className: "bs-full"
|
|
2663
2959
|
}
|
|
2664
2960
|
};
|
|
2665
2961
|
var defaultTextSlots = {
|
|
2666
|
-
...defaultSlots
|
|
2667
|
-
editor: {
|
|
2668
|
-
theme: textTheme
|
|
2669
|
-
}
|
|
2962
|
+
...defaultSlots
|
|
2670
2963
|
};
|
|
2671
2964
|
var defaultMarkdownSlots = {
|
|
2672
|
-
...defaultSlots
|
|
2673
|
-
editor: {
|
|
2674
|
-
theme: markdownTheme
|
|
2675
|
-
}
|
|
2965
|
+
...defaultSlots
|
|
2676
2966
|
};
|
|
2677
2967
|
|
|
2678
|
-
// packages/ui/react-ui-editor/src/
|
|
2679
|
-
import
|
|
2680
|
-
import {
|
|
2681
|
-
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
|
+
};
|
|
2682
3128
|
|
|
2683
3129
|
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2684
3130
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2685
3131
|
import { Context as Context2 } from "@dxos/context";
|
|
2686
|
-
import { invariant as
|
|
3132
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
2687
3133
|
import { log as log3 } from "@dxos/log";
|
|
2688
3134
|
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2689
3135
|
var DEBOUNCE_INTERVAL = 100;
|
|
2690
3136
|
var SpaceAwarenessProvider = class {
|
|
2691
3137
|
constructor(params) {
|
|
2692
|
-
this.remoteStateChange = new Event2();
|
|
2693
3138
|
this._remoteStates = /* @__PURE__ */ new Map();
|
|
3139
|
+
this.remoteStateChange = new Event2();
|
|
2694
3140
|
this._space = params.space;
|
|
2695
3141
|
this._channel = params.channel;
|
|
2696
3142
|
this._peerId = params.peerId;
|
|
@@ -2707,7 +3153,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2707
3153
|
await sleep(DEBOUNCE_INTERVAL);
|
|
2708
3154
|
}
|
|
2709
3155
|
});
|
|
2710
|
-
|
|
3156
|
+
this._ctx.onDispose(this._space.listen(this._channel, (message) => {
|
|
2711
3157
|
switch (message.payload.kind) {
|
|
2712
3158
|
case "query": {
|
|
2713
3159
|
this._handleQueryMessage();
|
|
@@ -2718,8 +3164,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2718
3164
|
break;
|
|
2719
3165
|
}
|
|
2720
3166
|
}
|
|
2721
|
-
});
|
|
2722
|
-
this._ctx.onDispose(unsubscribe);
|
|
3167
|
+
}));
|
|
2723
3168
|
void this._space.postMessage(this._channel, {
|
|
2724
3169
|
kind: "query"
|
|
2725
3170
|
}).catch((err) => {
|
|
@@ -2727,7 +3172,7 @@ var SpaceAwarenessProvider = class {
|
|
|
2727
3172
|
err
|
|
2728
3173
|
}, {
|
|
2729
3174
|
F: __dxlog_file4,
|
|
2730
|
-
L:
|
|
3175
|
+
L: 89,
|
|
2731
3176
|
S: this,
|
|
2732
3177
|
C: (f, a) => f(...a)
|
|
2733
3178
|
});
|
|
@@ -2738,10 +3183,13 @@ var SpaceAwarenessProvider = class {
|
|
|
2738
3183
|
this._ctx = void 0;
|
|
2739
3184
|
this._postTask = void 0;
|
|
2740
3185
|
}
|
|
3186
|
+
getRemoteStates() {
|
|
3187
|
+
return Array.from(this._remoteStates.values());
|
|
3188
|
+
}
|
|
2741
3189
|
update(position) {
|
|
2742
|
-
|
|
3190
|
+
invariant2(this._postTask, void 0, {
|
|
2743
3191
|
F: __dxlog_file4,
|
|
2744
|
-
L:
|
|
3192
|
+
L: 104,
|
|
2745
3193
|
S: this,
|
|
2746
3194
|
A: [
|
|
2747
3195
|
"this._postTask",
|
|
@@ -2755,13 +3203,10 @@ var SpaceAwarenessProvider = class {
|
|
|
2755
3203
|
};
|
|
2756
3204
|
this._postTask.schedule();
|
|
2757
3205
|
}
|
|
2758
|
-
getRemoteStates() {
|
|
2759
|
-
return Array.from(this._remoteStates.values());
|
|
2760
|
-
}
|
|
2761
3206
|
_handleQueryMessage() {
|
|
2762
|
-
|
|
3207
|
+
invariant2(this._postTask, void 0, {
|
|
2763
3208
|
F: __dxlog_file4,
|
|
2764
|
-
L:
|
|
3209
|
+
L: 115,
|
|
2765
3210
|
S: this,
|
|
2766
3211
|
A: [
|
|
2767
3212
|
"this._postTask",
|
|
@@ -2771,9 +3216,9 @@ var SpaceAwarenessProvider = class {
|
|
|
2771
3216
|
this._postTask.schedule();
|
|
2772
3217
|
}
|
|
2773
3218
|
_handlePostMessage(message) {
|
|
2774
|
-
|
|
3219
|
+
invariant2(message.kind === "post", void 0, {
|
|
2775
3220
|
F: __dxlog_file4,
|
|
2776
|
-
L:
|
|
3221
|
+
L: 120,
|
|
2777
3222
|
S: this,
|
|
2778
3223
|
A: [
|
|
2779
3224
|
"message.kind === 'post'",
|
|
@@ -2785,229 +3230,240 @@ var SpaceAwarenessProvider = class {
|
|
|
2785
3230
|
}
|
|
2786
3231
|
};
|
|
2787
3232
|
|
|
2788
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2789
|
-
import { StateField as
|
|
2790
|
-
|
|
2791
|
-
|
|
3233
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
3234
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
3235
|
+
var modelState = StateField5.define({
|
|
3236
|
+
create: () => void 0,
|
|
3237
|
+
update: (model) => model
|
|
3238
|
+
});
|
|
2792
3239
|
|
|
2793
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
arrayToString2(to)
|
|
2830
|
-
].join(":");
|
|
2831
|
-
},
|
|
2832
|
-
getRangeFromCursor: (cursor) => {
|
|
2833
|
-
invariant4(text.doc, void 0, {
|
|
2834
|
-
F: __dxlog_file5,
|
|
2835
|
-
L: 40,
|
|
2836
|
-
S: void 0,
|
|
2837
|
-
A: [
|
|
2838
|
-
"text.doc",
|
|
2839
|
-
""
|
|
2840
|
-
]
|
|
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
|
|
2841
3276
|
});
|
|
2842
|
-
|
|
2843
|
-
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2844
|
-
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2845
|
-
return from && to ? {
|
|
2846
|
-
from: from.index,
|
|
2847
|
-
to: to.index
|
|
2848
|
-
} : void 0;
|
|
2849
|
-
},
|
|
2850
|
-
extension: [
|
|
2851
|
-
modelState.init(() => model),
|
|
2852
|
-
yjs(text.content, provider?.awareness)
|
|
2853
|
-
],
|
|
2854
|
-
awareness: provider?.awareness,
|
|
2855
|
-
peer: identity ? {
|
|
2856
|
-
id: identity.identityKey.toHex(),
|
|
2857
|
-
name: identity.profile?.displayName
|
|
2858
|
-
} : void 0
|
|
3277
|
+
});
|
|
2859
3278
|
};
|
|
2860
|
-
return model;
|
|
2861
3279
|
};
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
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);
|
|
2920
3339
|
}
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
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);
|
|
2931
3350
|
}
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
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
|
+
};
|
|
2937
3362
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
return encoder;
|
|
3363
|
+
if (autoFocus) {
|
|
3364
|
+
view.focus();
|
|
2941
3365
|
}
|
|
2942
3366
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
}
|
|
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);
|
|
2953
3398
|
};
|
|
2954
3399
|
|
|
2955
3400
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
}
|
|
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";
|
|
2960
3408
|
var useTextModel = (props) => {
|
|
2961
3409
|
const { identity, space, text } = props;
|
|
2962
|
-
const [model, setModel] =
|
|
2963
|
-
|
|
3410
|
+
const [model, setModel] = useState4();
|
|
3411
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
2964
3412
|
identity,
|
|
2965
3413
|
space,
|
|
2966
3414
|
text
|
|
2967
3415
|
]);
|
|
2968
3416
|
return model;
|
|
2969
3417
|
};
|
|
2970
|
-
var
|
|
2971
|
-
const
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
}
|
|
3418
|
+
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
3419
|
+
const [content, setContent] = useState4(defaultContent ?? "");
|
|
3420
|
+
return {
|
|
3421
|
+
id,
|
|
3422
|
+
content,
|
|
3423
|
+
setContent,
|
|
3424
|
+
text: () => content
|
|
3425
|
+
};
|
|
2979
3426
|
};
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
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
|
+
});
|
|
2983
3437
|
const obj = text;
|
|
2984
3438
|
const doc = getRawDoc(obj, [
|
|
2985
3439
|
obj.field
|
|
2986
3440
|
]);
|
|
2987
|
-
const
|
|
3441
|
+
const awarenessProvider2 = space && new SpaceAwarenessProvider({
|
|
2988
3442
|
space,
|
|
2989
3443
|
channel: `automerge.awareness.${obj.id}`,
|
|
2990
3444
|
info: {
|
|
2991
|
-
displayName: identity
|
|
3445
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
|
|
2992
3446
|
color: cursorColor.color,
|
|
2993
3447
|
lightColor: cursorColor.light
|
|
2994
3448
|
},
|
|
2995
3449
|
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2996
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
|
+
}
|
|
2997
3462
|
const model = {
|
|
2998
3463
|
id: obj.id,
|
|
2999
3464
|
content: doc,
|
|
3000
|
-
text: () =>
|
|
3001
|
-
|
|
3002
|
-
extension: [
|
|
3003
|
-
modelState.init(() => model),
|
|
3004
|
-
automerge3({
|
|
3005
|
-
handle: doc.handle,
|
|
3006
|
-
path: doc.path
|
|
3007
|
-
}),
|
|
3008
|
-
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3009
|
-
awareness()
|
|
3010
|
-
].filter(isNotNullOrUndefined),
|
|
3465
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3466
|
+
extension: extensions,
|
|
3011
3467
|
peer: identity ? {
|
|
3012
3468
|
id: identity.identityKey.toHex(),
|
|
3013
3469
|
name: identity.profile?.displayName
|
|
@@ -3016,8 +3472,8 @@ var createAutomergeModel = ({ space, identity, text }) => {
|
|
|
3016
3472
|
return model;
|
|
3017
3473
|
};
|
|
3018
3474
|
export {
|
|
3019
|
-
AwarenessProvider,
|
|
3020
3475
|
BaseTextEditor,
|
|
3476
|
+
Cursor,
|
|
3021
3477
|
Doc,
|
|
3022
3478
|
EditorModes,
|
|
3023
3479
|
MarkdownEditor,
|
|
@@ -3025,45 +3481,66 @@ export {
|
|
|
3025
3481
|
SpaceAwarenessProvider,
|
|
3026
3482
|
TextEditor,
|
|
3027
3483
|
TextKind,
|
|
3028
|
-
|
|
3484
|
+
Toolbar,
|
|
3029
3485
|
YText,
|
|
3030
3486
|
YXmlFragment,
|
|
3031
3487
|
autocomplete,
|
|
3032
|
-
|
|
3488
|
+
automerge,
|
|
3033
3489
|
awareness,
|
|
3034
|
-
|
|
3490
|
+
awarenessProvider,
|
|
3035
3491
|
blast,
|
|
3492
|
+
callbackWrapper,
|
|
3036
3493
|
code2 as code,
|
|
3037
3494
|
codeTheme,
|
|
3038
3495
|
comments,
|
|
3039
|
-
|
|
3040
|
-
|
|
3496
|
+
createBasicBundle,
|
|
3497
|
+
createComment,
|
|
3498
|
+
createDataExtensions,
|
|
3499
|
+
createMarkdownExtensions,
|
|
3500
|
+
createThemeExtensions,
|
|
3041
3501
|
defaultMarkdownSlots,
|
|
3042
3502
|
defaultOptions,
|
|
3043
3503
|
defaultSlots,
|
|
3044
3504
|
defaultTextSlots,
|
|
3045
3505
|
defaultTheme,
|
|
3506
|
+
focusComment,
|
|
3507
|
+
formatting,
|
|
3508
|
+
getToken,
|
|
3509
|
+
heading2 as heading,
|
|
3046
3510
|
hr,
|
|
3047
3511
|
image,
|
|
3512
|
+
insertCodeblock,
|
|
3513
|
+
insertTable,
|
|
3514
|
+
keymap7 as keymap,
|
|
3048
3515
|
link,
|
|
3049
3516
|
listener,
|
|
3050
|
-
|
|
3517
|
+
logChanges,
|
|
3051
3518
|
markdownHighlightStyle,
|
|
3052
3519
|
markdownTags,
|
|
3053
3520
|
markdownTagsExtensions,
|
|
3054
3521
|
markdownTheme,
|
|
3055
3522
|
mention,
|
|
3056
|
-
mermaid,
|
|
3057
3523
|
modelState,
|
|
3058
|
-
|
|
3059
|
-
|
|
3524
|
+
outliner,
|
|
3525
|
+
setComments,
|
|
3526
|
+
setHeading,
|
|
3060
3527
|
setSelection,
|
|
3061
3528
|
table,
|
|
3062
3529
|
tags2 as tags,
|
|
3063
3530
|
tasklist,
|
|
3064
3531
|
textTheme,
|
|
3532
|
+
toggleBold,
|
|
3533
|
+
toggleItalic,
|
|
3534
|
+
toggleList,
|
|
3535
|
+
toggleStrikethrough,
|
|
3536
|
+
toggleStyle,
|
|
3065
3537
|
typewriter,
|
|
3538
|
+
useActionHandler,
|
|
3539
|
+
useComments,
|
|
3540
|
+
useEditorView,
|
|
3541
|
+
useInMemoryTextModel,
|
|
3542
|
+
useTextEditor,
|
|
3066
3543
|
useTextModel,
|
|
3067
|
-
|
|
3544
|
+
useToolbarContext
|
|
3068
3545
|
};
|
|
3069
3546
|
//# sourceMappingURL=index.mjs.map
|