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