@dxos/react-ui-editor 0.3.11-main.baa8c4d → 0.3.11-main.bc6b68b
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 +1882 -1531
- 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 +14 -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 -3
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +0 -2
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +9 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +5 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +24 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts +14 -0
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/basic.d.ts +8 -0
- package/dist/types/src/extensions/basic.d.ts.map +1 -0
- package/dist/types/src/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/extensions/code.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/comments.d.ts +33 -18
- package/dist/types/src/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/extensions/cursor.d.ts +25 -0
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/image.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/index.d.ts +4 -2
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/link.d.ts +1 -0
- package/dist/types/src/extensions/link.d.ts.map +1 -0
- package/dist/types/src/extensions/listener.d.ts +10 -0
- package/dist/types/src/extensions/listener.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/bundle.d.ts +2 -5
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -0
- 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/extensions/table.d.ts.map +1 -0
- package/dist/types/src/extensions/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/typewriter.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +31 -0
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/hooks/defs.d.ts +25 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +3 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -31
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- 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/{components/TextEditor/themes → themes}/default.d.ts +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -0
- package/dist/types/src/themes/index.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +33 -34
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +86 -91
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -34
- package/src/components/TextEditor/TextEditor.tsx +124 -95
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/components/TextEditor/index.ts +0 -3
- package/src/{components/TextEditor/extensions → extensions}/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.ts +88 -0
- package/src/extensions/automerge/cursor.ts +52 -0
- package/src/extensions/automerge/defs.ts +41 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +34 -29
- package/src/{hooks → extensions}/automerge/update-automerge.ts +5 -6
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +13 -5
- package/src/extensions/awareness.ts +310 -0
- package/src/extensions/basic.ts +37 -0
- package/src/{components/TextEditor/extensions → extensions}/code.ts +28 -23
- package/src/extensions/comments.ts +428 -0
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/hr.ts +72 -0
- package/src/extensions/image.ts +87 -0
- package/src/{components/TextEditor/extensions → extensions}/index.ts +4 -2
- package/src/{components/TextEditor/extensions → extensions}/link.ts +116 -62
- package/src/extensions/listener.ts +35 -0
- package/src/{components/TextEditor/extensions → extensions}/markdown/bundle.ts +18 -24
- package/src/{components/TextEditor/extensions → extensions}/markdown/highlight.ts +4 -13
- package/src/{components/TextEditor/extensions → extensions}/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/{components/TextEditor/extensions → extensions}/table.ts +10 -4
- package/src/extensions/tasklist.ts +111 -0
- package/src/{components/TextEditor/extensions → extensions}/typewriter.ts +1 -1
- package/src/hooks/awareness-provider.ts +124 -0
- package/src/hooks/defs.ts +42 -0
- package/src/hooks/index.ts +4 -1
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +30 -115
- package/src/index.ts +5 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/markdown.ts +0 -2
- package/src/styles/tokens.ts +3 -0
- package/src/{components/TextEditor/themes → themes}/default.ts +52 -79
- package/src/util.ts +41 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts +0 -9
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts +0 -9
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +0 -12
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/typewriter.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/util.d.ts +0 -5
- package/dist/types/src/components/TextEditor/extensions/util.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/handle.d.ts +0 -9
- package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/index.d.ts +0 -3
- package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts +0 -26
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/semaphore.d.ts +0 -19
- package/dist/types/src/hooks/automerge/semaphore.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-automerge.d.ts +0 -6
- package/dist/types/src/hooks/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/index.d.ts +0 -3
- package/dist/types/src/hooks/yjs/index.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/space-provider.d.ts +0 -27
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts +0 -12
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.test.d.ts +0 -2
- package/dist/types/src/hooks/yjs/yjs.test.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/src/components/TextEditor/codemirror.stories.ts +0 -114
- package/src/components/TextEditor/extensions/basic.ts +0 -32
- package/src/components/TextEditor/extensions/comments.ts +0 -388
- package/src/components/TextEditor/extensions/hr.ts +0 -74
- package/src/components/TextEditor/extensions/image.ts +0 -69
- package/src/components/TextEditor/extensions/listener.ts +0 -23
- package/src/components/TextEditor/extensions/mermaid.ts +0 -11
- package/src/components/TextEditor/extensions/tasklist.ts +0 -121
- package/src/components/TextEditor/extensions/tooltip.ts +0 -61
- package/src/components/TextEditor/extensions/util.ts +0 -18
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -134
- package/src/hooks/yjs/index.ts +0 -6
- package/src/hooks/yjs/space-provider.ts +0 -126
- package/src/hooks/yjs/yjs.stories.tsx +0 -56
- package/src/hooks/yjs/yjs.test.ts +0 -59
- 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 -189
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/autocomplete.d.ts +0 -0
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/blast.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/code.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/hr.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/image.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/highlight.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/index.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/mention.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/table.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/tasklist.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/typewriter.d.ts +0 -0
- /package/dist/types/src/{hooks/yjs → styles}/cursors.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/themes → themes}/index.d.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/blast.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/markdown/index.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{components/TextEditor/themes → themes}/index.ts +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { DeferredTask, Event, sleep } from '@dxos/async';
|
|
6
|
+
import { Context } from '@dxos/context';
|
|
7
|
+
import { invariant } from '@dxos/invariant';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
10
|
+
import { type GossipMessage } from '@dxos/react-client/mesh';
|
|
11
|
+
|
|
12
|
+
import { type AwarenessInfo, type AwarenessPosition, type AwarenessProvider, type AwarenessState } from '../extensions';
|
|
13
|
+
|
|
14
|
+
type ProtocolMessage =
|
|
15
|
+
| {
|
|
16
|
+
kind: 'query';
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
kind: 'post';
|
|
20
|
+
state: AwarenessState;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const DEBOUNCE_INTERVAL = 100; // ms
|
|
24
|
+
|
|
25
|
+
export type AwarenessProviderParams = {
|
|
26
|
+
space: Space;
|
|
27
|
+
channel: string;
|
|
28
|
+
peerId: string;
|
|
29
|
+
info: AwarenessInfo;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Receives and broadcasts profile and cursor position.
|
|
34
|
+
*/
|
|
35
|
+
export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
36
|
+
private readonly _remoteStates = new Map<string, AwarenessState>();
|
|
37
|
+
|
|
38
|
+
private readonly _space: Space;
|
|
39
|
+
private readonly _channel: string;
|
|
40
|
+
private readonly _peerId: string;
|
|
41
|
+
private readonly _info: AwarenessInfo;
|
|
42
|
+
|
|
43
|
+
private _ctx?: Context;
|
|
44
|
+
private _postTask?: DeferredTask;
|
|
45
|
+
private _localState?: AwarenessState;
|
|
46
|
+
|
|
47
|
+
public readonly remoteStateChange = new Event<void>();
|
|
48
|
+
|
|
49
|
+
constructor(params: AwarenessProviderParams) {
|
|
50
|
+
this._space = params.space;
|
|
51
|
+
this._channel = params.channel;
|
|
52
|
+
this._peerId = params.peerId;
|
|
53
|
+
this._info = params.info;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
open() {
|
|
57
|
+
this._ctx = new Context();
|
|
58
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
59
|
+
if (this._localState) {
|
|
60
|
+
await this._space.postMessage(this._channel, {
|
|
61
|
+
kind: 'post',
|
|
62
|
+
state: this._localState,
|
|
63
|
+
} satisfies ProtocolMessage);
|
|
64
|
+
|
|
65
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
this._ctx.onDispose(
|
|
70
|
+
this._space.listen(this._channel, (message: GossipMessage) => {
|
|
71
|
+
switch (message.payload.kind) {
|
|
72
|
+
case 'query': {
|
|
73
|
+
this._handleQueryMessage();
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case 'post': {
|
|
77
|
+
this._handlePostMessage(message.payload);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
void this._space
|
|
85
|
+
.postMessage(this._channel, {
|
|
86
|
+
kind: 'query',
|
|
87
|
+
} satisfies ProtocolMessage)
|
|
88
|
+
.catch((err) => {
|
|
89
|
+
log.debug('failed to query awareness', { err });
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
close() {
|
|
94
|
+
void this._ctx?.dispose();
|
|
95
|
+
this._ctx = undefined;
|
|
96
|
+
this._postTask = undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getRemoteStates(): AwarenessState[] {
|
|
100
|
+
return Array.from(this._remoteStates.values());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
update(position: AwarenessPosition | undefined): void {
|
|
104
|
+
invariant(this._postTask);
|
|
105
|
+
this._localState = {
|
|
106
|
+
peerId: this._peerId,
|
|
107
|
+
position,
|
|
108
|
+
info: this._info,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
this._postTask.schedule();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _handleQueryMessage() {
|
|
115
|
+
invariant(this._postTask);
|
|
116
|
+
this._postTask.schedule();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private _handlePostMessage(message: ProtocolMessage) {
|
|
120
|
+
invariant(message.kind === 'post');
|
|
121
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
122
|
+
this.remoteStateChange.emit();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Extension, StateField } from '@codemirror/state';
|
|
6
|
+
|
|
7
|
+
import { type DocAccessor } from '@dxos/echo-schema';
|
|
8
|
+
|
|
9
|
+
// Runtime data structure.
|
|
10
|
+
export type Range = {
|
|
11
|
+
from: number;
|
|
12
|
+
to: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Persistent data structure.
|
|
16
|
+
export type Comment = {
|
|
17
|
+
id: string;
|
|
18
|
+
cursor?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type EditorModel = {
|
|
22
|
+
id: string;
|
|
23
|
+
text: () => string;
|
|
24
|
+
extension?: Extension;
|
|
25
|
+
|
|
26
|
+
// TODO(burdon): Remove.
|
|
27
|
+
content: string | DocAccessor;
|
|
28
|
+
|
|
29
|
+
// TODO(burdon): Remove.
|
|
30
|
+
peer?: {
|
|
31
|
+
id: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* State field makes the model available to other extensions.
|
|
38
|
+
*/
|
|
39
|
+
export const modelState = StateField.define<EditorModel | undefined>({
|
|
40
|
+
create: () => undefined,
|
|
41
|
+
update: (model) => model,
|
|
42
|
+
});
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
|
6
|
+
import { type RefCallback, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hook for accessing the editor view.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const Test = () => {
|
|
13
|
+
* const [editorRef, editorView] = useTextEditor();
|
|
14
|
+
* useEffect(() => {
|
|
15
|
+
* editorView?.focus();
|
|
16
|
+
* }, [editorView]);
|
|
17
|
+
* return <TextEditor ref={editorRef} />;
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export const useTextEditor = (): [RefCallback<EditorView | null>, EditorView | null] => {
|
|
22
|
+
const [view, setView] = useState<EditorView | null>(null);
|
|
23
|
+
return [
|
|
24
|
+
(ref: EditorView | null) => {
|
|
25
|
+
setView(ref);
|
|
26
|
+
},
|
|
27
|
+
view,
|
|
28
|
+
];
|
|
29
|
+
};
|
|
@@ -2,67 +2,20 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Extension, StateField } from '@codemirror/state';
|
|
6
5
|
import get from 'lodash.get';
|
|
7
6
|
import { useEffect, useState } from 'react';
|
|
8
|
-
import { yCollab } from 'y-codemirror.next';
|
|
9
|
-
import type * as awarenessProtocol from 'y-protocols/awareness';
|
|
10
|
-
import * as Y from 'yjs';
|
|
11
7
|
|
|
8
|
+
import { generateName } from '@dxos/display-name';
|
|
9
|
+
import { type AutomergeTextCompat, getRawDoc } from '@dxos/echo-schema';
|
|
12
10
|
import { invariant } from '@dxos/invariant';
|
|
13
|
-
import {
|
|
14
|
-
type DocAccessor,
|
|
15
|
-
type Space,
|
|
16
|
-
type TextObject,
|
|
17
|
-
type AutomergeTextCompat,
|
|
18
|
-
getRawDoc,
|
|
19
|
-
isActualAutomergeObject,
|
|
20
|
-
} from '@dxos/react-client/echo';
|
|
11
|
+
import { isAutomergeObject, type Space, type TextObject } from '@dxos/react-client/echo';
|
|
21
12
|
import { type Identity } from '@dxos/react-client/halo';
|
|
22
|
-
import
|
|
23
|
-
import { arrayToString, stringToArray } from '@dxos/util';
|
|
13
|
+
import { isNotNullOrUndefined } from '@dxos/util';
|
|
24
14
|
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type Awareness = awarenessProtocol.Awareness;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* State field makes the model available to other extensions.
|
|
33
|
-
*/
|
|
34
|
-
// TODO(burdon): Use facet?
|
|
35
|
-
export const modelState = StateField.define<EditorModel | undefined>({
|
|
36
|
-
create: () => undefined,
|
|
37
|
-
update: (model) => model,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
export type Range = {
|
|
41
|
-
from: number;
|
|
42
|
-
to: number;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type CommentRange = {
|
|
46
|
-
id: string;
|
|
47
|
-
// TODO(burdon): Split into begin/end?
|
|
48
|
-
cursor: string;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
52
|
-
export type EditorModel = {
|
|
53
|
-
id: string;
|
|
54
|
-
// TODO(burdon): Remove.
|
|
55
|
-
content: string | YText | YXmlFragment | DocAccessor;
|
|
56
|
-
text: () => string;
|
|
57
|
-
getCursorFromRange?: (value: Range) => string;
|
|
58
|
-
getRangeFromCursor?: (cursor: string) => Range;
|
|
59
|
-
extension?: Extension;
|
|
60
|
-
awareness?: Awareness;
|
|
61
|
-
peer?: {
|
|
62
|
-
id: string;
|
|
63
|
-
name?: string;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
15
|
+
import { SpaceAwarenessProvider } from './awareness-provider';
|
|
16
|
+
import { type EditorModel, modelState } from './defs';
|
|
17
|
+
import { automerge, awareness, AwarenessProvider } from '../extensions';
|
|
18
|
+
import { cursorColor } from '../styles';
|
|
66
19
|
|
|
67
20
|
// TODO(burdon): Remove space/identity dependency. Define interface for the framework re content and presence.
|
|
68
21
|
export type UseTextModelProps = {
|
|
@@ -71,79 +24,41 @@ export type UseTextModelProps = {
|
|
|
71
24
|
text?: TextObject;
|
|
72
25
|
};
|
|
73
26
|
|
|
74
|
-
// TODO(burdon): Remove YJS/Automerge deps (from UI component -- create abstraction; incl. all ECHO/Space deps).
|
|
75
|
-
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
76
27
|
export const useTextModel = (props: UseTextModelProps): EditorModel | undefined => {
|
|
77
28
|
const { identity, space, text } = props;
|
|
78
|
-
const [model, setModel] = useState<EditorModel | undefined>(
|
|
29
|
+
const [model, setModel] = useState<EditorModel | undefined>();
|
|
79
30
|
useEffect(() => setModel(createModel(props)), [identity, space, text]);
|
|
80
31
|
return model;
|
|
81
32
|
};
|
|
82
33
|
|
|
83
|
-
const createModel = (
|
|
84
|
-
|
|
85
|
-
if (isActualAutomergeObject(text)) {
|
|
86
|
-
return createAutomergeModel(props);
|
|
87
|
-
} else {
|
|
88
|
-
if (!text?.doc) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return createYjsModel(props);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const createYjsModel = ({ identity, space, text }: UseTextModelProps): EditorModel => {
|
|
97
|
-
invariant(text?.doc && text?.content);
|
|
98
|
-
const provider = space
|
|
99
|
-
? new SpaceAwarenessProvider({ space, doc: text.doc, channel: `yjs.awareness.${text.id}` })
|
|
100
|
-
: undefined;
|
|
101
|
-
|
|
102
|
-
const model: EditorModel = {
|
|
103
|
-
id: text.doc.guid,
|
|
104
|
-
content: text.content,
|
|
105
|
-
text: () => text.content!.toString(),
|
|
106
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
107
|
-
getCursorFromRange: (range: Range) => {
|
|
108
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.from));
|
|
109
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.to, -1));
|
|
110
|
-
return [arrayToString(from), arrayToString(to)].join(':');
|
|
111
|
-
},
|
|
112
|
-
getRangeFromCursor: (cursor: string) => {
|
|
113
|
-
const parts = cursor.split(':');
|
|
114
|
-
const from = Y.createAbsolutePositionFromRelativePosition(
|
|
115
|
-
Y.decodeRelativePosition(stringToArray(parts[0])),
|
|
116
|
-
text.doc!,
|
|
117
|
-
);
|
|
118
|
-
const to = Y.createAbsolutePositionFromRelativePosition(
|
|
119
|
-
Y.decodeRelativePosition(stringToArray(parts[1])),
|
|
120
|
-
text.doc!,
|
|
121
|
-
);
|
|
122
|
-
return { from: from!.index, to: to!.index };
|
|
123
|
-
},
|
|
124
|
-
extension: [yCollab(text.content as YText, provider?.awareness), modelState.init(() => model)],
|
|
125
|
-
awareness: provider?.awareness,
|
|
126
|
-
peer: identity
|
|
127
|
-
? {
|
|
128
|
-
id: identity.identityKey.toHex(),
|
|
129
|
-
name: identity.profile?.displayName,
|
|
130
|
-
}
|
|
131
|
-
: undefined,
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
return model;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const createAutomergeModel = ({ identity, text }: UseTextModelProps): EditorModel => {
|
|
34
|
+
const createModel = ({ space, identity, text }: UseTextModelProps) => {
|
|
35
|
+
invariant(isAutomergeObject(text));
|
|
138
36
|
const obj = text as any as AutomergeTextCompat;
|
|
139
37
|
const doc = getRawDoc(obj, [obj.field]);
|
|
140
38
|
|
|
39
|
+
const awarenessProvider =
|
|
40
|
+
space &&
|
|
41
|
+
new SpaceAwarenessProvider({
|
|
42
|
+
space,
|
|
43
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
44
|
+
info: {
|
|
45
|
+
displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : undefined,
|
|
46
|
+
color: cursorColor.color,
|
|
47
|
+
lightColor: cursorColor.light,
|
|
48
|
+
},
|
|
49
|
+
peerId: identity?.identityKey.toHex() ?? 'Anonymous',
|
|
50
|
+
});
|
|
51
|
+
|
|
141
52
|
const model: EditorModel = {
|
|
142
53
|
id: obj.id,
|
|
143
54
|
content: doc,
|
|
144
55
|
text: () => get(doc.handle.docSync(), doc.path),
|
|
145
|
-
|
|
146
|
-
|
|
56
|
+
extension: [
|
|
57
|
+
modelState.init(() => model),
|
|
58
|
+
automerge({ handle: doc.handle, path: doc.path }),
|
|
59
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
60
|
+
awareness(),
|
|
61
|
+
].filter(isNotNullOrUndefined),
|
|
147
62
|
peer: identity
|
|
148
63
|
? {
|
|
149
64
|
id: identity.identityKey.toHex(),
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
export { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
|
|
6
6
|
export { Doc, YText, YXmlFragment } from '@dxos/text-model';
|
|
7
7
|
export { type Extension } from '@codemirror/state';
|
|
8
|
+
export { type EditorView } from '@codemirror/view';
|
|
8
9
|
|
|
9
10
|
export * from './components';
|
|
11
|
+
export * from './extensions';
|
|
10
12
|
export * from './hooks';
|
|
13
|
+
export { getToken } from './styles';
|
|
14
|
+
export * from './themes';
|
|
15
|
+
export * from './util';
|
package/src/styles/index.ts
CHANGED
package/src/styles/markdown.ts
CHANGED
|
@@ -39,10 +39,8 @@ export const codeBlock = 'mlb-2 font-mono bg-neutral-500/10 p-3 rounded';
|
|
|
39
39
|
|
|
40
40
|
export const inlineUrl = mx(code, 'px-1');
|
|
41
41
|
|
|
42
|
-
// TODO(burdon): Replace with widget.
|
|
43
42
|
export const blockquote = mx('pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30', light);
|
|
44
43
|
|
|
45
|
-
// TODO(burdon): Replace with widget.
|
|
46
44
|
export const horizontalRule =
|
|
47
45
|
'flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800';
|
|
48
46
|
|
package/src/styles/tokens.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import get from 'lodash.get';
|
|
5
6
|
import type { StyleSpec } from 'style-mod';
|
|
6
7
|
|
|
7
8
|
import { tailwindConfig, type TailwindConfig } from '@dxos/react-ui-theme';
|
|
@@ -12,3 +13,5 @@ export type ThemeStyles = {
|
|
|
12
13
|
|
|
13
14
|
// TODO(thure): Why export the whole theme? Can this be done differently?
|
|
14
15
|
export const tokens: TailwindConfig['theme'] = tailwindConfig({}).theme;
|
|
16
|
+
|
|
17
|
+
export const getToken = (path: string, defaultValue: any = undefined) => get(tokens, path, defaultValue);
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import get from 'lodash.get';
|
|
6
6
|
|
|
7
|
-
import { type ThemeStyles, tokens } from '
|
|
7
|
+
import { type ThemeStyles, tokens } from '../styles';
|
|
8
8
|
|
|
9
|
-
// TODO(burdon): Can we
|
|
10
|
-
//
|
|
9
|
+
// TODO(burdon): Can we use @apply and import css file?
|
|
10
|
+
// https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply?
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Minimal styles.
|
|
@@ -49,12 +49,12 @@ export const defaultTheme: ThemeStyles = {
|
|
|
49
49
|
'&.cm-focused': {
|
|
50
50
|
outline: 'none',
|
|
51
51
|
},
|
|
52
|
-
'
|
|
52
|
+
'.cm-scroller': {
|
|
53
53
|
overflow: 'visible',
|
|
54
54
|
fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
|
|
55
55
|
},
|
|
56
56
|
|
|
57
|
-
'
|
|
57
|
+
'.cm-content': {
|
|
58
58
|
padding: 0,
|
|
59
59
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
60
60
|
fontSize: '16px',
|
|
@@ -77,17 +77,19 @@ export const defaultTheme: ThemeStyles = {
|
|
|
77
77
|
'&dark .cm-cursor, &dark .cm-dropCursor': {
|
|
78
78
|
borderLeft: '2px solid white',
|
|
79
79
|
},
|
|
80
|
-
'
|
|
80
|
+
'.cm-placeholder': {
|
|
81
81
|
fontWeight: 100,
|
|
82
82
|
},
|
|
83
83
|
|
|
84
84
|
//
|
|
85
85
|
// line
|
|
86
86
|
//
|
|
87
|
-
'
|
|
87
|
+
'.cm-line': {
|
|
88
88
|
paddingInline: 0,
|
|
89
|
+
// TODO(burdon): Other values leave gaps between lines when highlighted.
|
|
90
|
+
// lineHeight: 'normal',
|
|
89
91
|
},
|
|
90
|
-
'
|
|
92
|
+
'.cm-activeLine': {
|
|
91
93
|
background: 'inherit',
|
|
92
94
|
},
|
|
93
95
|
|
|
@@ -119,40 +121,10 @@ export const defaultTheme: ThemeStyles = {
|
|
|
119
121
|
backgroundColor: get(tokens, 'extend.colors.yellow.700'),
|
|
120
122
|
},
|
|
121
123
|
|
|
122
|
-
//
|
|
123
|
-
// collaboration
|
|
124
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
'&light .cm-ySelection, &light .cm-yLineSelection': {
|
|
128
|
-
mixBlendMode: 'multiply',
|
|
129
|
-
},
|
|
130
|
-
'&dark .cm-ySelection, &dark .cm-yLineSelection': {
|
|
131
|
-
mixBlendMode: 'screen',
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
'& .cm-ySelectionInfo': {
|
|
135
|
-
padding: '2px 4px',
|
|
136
|
-
marginBlockStart: '-4px',
|
|
137
|
-
},
|
|
138
|
-
'& .cm-ySelection, & .cm-selectionMatch': {
|
|
139
|
-
paddingBlockStart: '.15em',
|
|
140
|
-
paddingBlockEnd: '.15em',
|
|
141
|
-
},
|
|
142
|
-
'& .cm-ySelectionCaret': {
|
|
143
|
-
display: 'inline-block',
|
|
144
|
-
insetBlockStart: '.1em',
|
|
145
|
-
blockSize: '1.4em',
|
|
146
|
-
verticalAlign: 'top',
|
|
147
|
-
},
|
|
148
|
-
'& .cm-yLineSelection': {
|
|
149
|
-
margin: 0,
|
|
150
|
-
},
|
|
151
|
-
|
|
152
124
|
//
|
|
153
125
|
// link
|
|
154
126
|
//
|
|
155
|
-
'
|
|
127
|
+
'.cm-link': {
|
|
156
128
|
color: get(tokens, 'extend.colors.primary.500'),
|
|
157
129
|
textDecorationLine: 'underline',
|
|
158
130
|
textDecorationThickness: '1px',
|
|
@@ -164,75 +136,74 @@ export const defaultTheme: ThemeStyles = {
|
|
|
164
136
|
//
|
|
165
137
|
// tooltip
|
|
166
138
|
//
|
|
167
|
-
'
|
|
139
|
+
'.cm-tooltip': {
|
|
168
140
|
border: 'none',
|
|
169
141
|
},
|
|
170
|
-
'
|
|
142
|
+
'.cm-tooltip-below': {},
|
|
171
143
|
|
|
172
144
|
//
|
|
173
145
|
// autocomplete
|
|
174
146
|
//
|
|
175
|
-
'
|
|
147
|
+
'.cm-tooltip-autocomplete': {
|
|
176
148
|
marginTop: '4px',
|
|
177
149
|
marginLeft: '-3px',
|
|
178
150
|
},
|
|
179
|
-
'
|
|
180
|
-
'
|
|
181
|
-
'
|
|
151
|
+
'.cm-tooltip-autocomplete ul li': {},
|
|
152
|
+
'.cm-tooltip-autocomplete ul li[aria-selected]': {},
|
|
153
|
+
'.cm-completionIcon': {
|
|
182
154
|
display: 'none',
|
|
183
155
|
},
|
|
184
|
-
'
|
|
156
|
+
'.cm-completionLabel': {
|
|
185
157
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
186
158
|
},
|
|
187
|
-
'
|
|
159
|
+
'.cm-completionMatchedText': {
|
|
188
160
|
textDecoration: 'none',
|
|
189
161
|
},
|
|
190
162
|
|
|
191
|
-
//
|
|
192
|
-
// widgets
|
|
193
|
-
//
|
|
194
|
-
'& .cm-widgetBuffer': {
|
|
195
|
-
display: 'none',
|
|
196
|
-
height: 0,
|
|
197
|
-
},
|
|
198
|
-
|
|
199
163
|
//
|
|
200
164
|
// table
|
|
201
165
|
//
|
|
202
|
-
'
|
|
166
|
+
'.cm-table *': {
|
|
203
167
|
fontFamily: `${get(tokens, 'fontFamily.mono', []).join(',')} !important`,
|
|
204
168
|
textDecoration: 'none !important',
|
|
205
169
|
},
|
|
206
|
-
'
|
|
170
|
+
'.cm-table-head': {
|
|
207
171
|
padding: '2px 16px 2px 0px',
|
|
208
172
|
borderBottom: `1px solid ${get(tokens, 'extend.colors.neutral.500')}`,
|
|
209
173
|
fontWeight: 100,
|
|
210
174
|
textAlign: 'left',
|
|
211
175
|
color: get(tokens, 'extend.colors.neutral.500'),
|
|
212
176
|
},
|
|
213
|
-
'
|
|
177
|
+
'.cm-table-cell': {
|
|
214
178
|
padding: '2px 16px 2px 0px',
|
|
215
179
|
},
|
|
216
180
|
|
|
217
181
|
//
|
|
218
182
|
// image
|
|
219
183
|
//
|
|
220
|
-
'
|
|
221
|
-
|
|
184
|
+
'.cm-image': {
|
|
185
|
+
display: 'block',
|
|
186
|
+
height: '0',
|
|
187
|
+
},
|
|
188
|
+
'.cm-image.cm-loaded-image': {
|
|
189
|
+
height: 'auto',
|
|
190
|
+
borderTop: '0.5rem solid transparent',
|
|
191
|
+
borderBottom: '0.5rem solid transparent',
|
|
222
192
|
},
|
|
223
193
|
|
|
224
194
|
//
|
|
225
195
|
// font size
|
|
226
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
196
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
197
|
+
// but it's far more verbose than it needs to be.
|
|
227
198
|
//
|
|
228
|
-
...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}, {}),
|
|
199
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
200
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
201
|
+
//
|
|
202
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
203
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
204
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
205
|
+
// return acc;
|
|
206
|
+
// }, {}),
|
|
236
207
|
|
|
237
208
|
/**
|
|
238
209
|
* Panels
|
|
@@ -250,14 +221,14 @@ export const defaultTheme: ThemeStyles = {
|
|
|
250
221
|
* </div>
|
|
251
222
|
* </div
|
|
252
223
|
*/
|
|
253
|
-
'
|
|
224
|
+
'.cm-panels': {
|
|
254
225
|
border: `1px solid ${get(tokens, 'extend.colors.neutral.200')}`,
|
|
255
226
|
},
|
|
256
|
-
'
|
|
227
|
+
'.cm-panel': {
|
|
257
228
|
background: get(tokens, 'extend.colors.neutral.50'),
|
|
258
229
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
259
230
|
},
|
|
260
|
-
'
|
|
231
|
+
'.cm-button': {
|
|
261
232
|
margin: '4px',
|
|
262
233
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
263
234
|
background: get(tokens, 'extend.colors.neutral.100'),
|
|
@@ -271,32 +242,34 @@ export const defaultTheme: ThemeStyles = {
|
|
|
271
242
|
backgroundImage: 'none',
|
|
272
243
|
},
|
|
273
244
|
},
|
|
274
|
-
'
|
|
245
|
+
'.cm-panel input[type=checkbox]': {
|
|
275
246
|
marginRight: '0.4rem !important',
|
|
276
247
|
},
|
|
277
248
|
};
|
|
278
249
|
|
|
279
250
|
export const textTheme: ThemeStyles = {
|
|
280
|
-
'
|
|
251
|
+
'.cm-scroller': {
|
|
281
252
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
282
253
|
},
|
|
283
|
-
'
|
|
254
|
+
'.cm-placeholder': {
|
|
284
255
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
285
256
|
},
|
|
286
257
|
};
|
|
287
258
|
|
|
288
259
|
export const markdownTheme: ThemeStyles = {
|
|
289
|
-
|
|
290
|
-
|
|
260
|
+
'.cm-scroller': {
|
|
261
|
+
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
262
|
+
},
|
|
263
|
+
'.cm-placeholder': {
|
|
291
264
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
292
265
|
},
|
|
293
266
|
};
|
|
294
267
|
|
|
295
268
|
export const codeTheme: ThemeStyles = {
|
|
296
|
-
'
|
|
269
|
+
'.cm-scroller': {
|
|
297
270
|
fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
|
|
298
271
|
},
|
|
299
|
-
'
|
|
272
|
+
'.cm-placeholder': {
|
|
300
273
|
fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
|
|
301
274
|
},
|
|
302
275
|
};
|