collabmd 0.1.38 → 0.1.39
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/client/assets/{CodeMirrorEditor-UCMRAMCV-DnBV8gCm.js → CodeMirrorEditor-UCMRAMCV-75Zi8U_A.js} +1 -1
- package/dist/client/assets/{dist-BPEi1dEF.js → dist-1SMeCZhf.js} +1 -1
- package/dist/client/assets/{dist-Dbg8P4C5.js → dist-8EAyH6_p.js} +1 -1
- package/dist/client/assets/{dist-BEKQo64E.js → dist-B7XQNod9.js} +1 -1
- package/dist/client/assets/dist-BCzW2jDH.js +1 -0
- package/dist/client/assets/{dist-CQVTTk81.js → dist-BEk5kTf_.js} +1 -1
- package/dist/client/assets/dist-BOn786F3.js +1 -0
- package/dist/client/assets/{dist-Bn8WRPs1.js → dist-BXiFOexW.js} +1 -1
- package/dist/client/assets/{dist-v3i1ifes.js → dist-Bp_j2hKC.js} +1 -1
- package/dist/client/assets/dist-BwUX6zpo.js +1 -0
- package/dist/client/assets/{dist-DwvSvkOE.js → dist-Bz-8_JmE.js} +1 -1
- package/dist/client/assets/{dist-CBEw2W2P.js → dist-CH3l6nVf.js} +1 -1
- package/dist/client/assets/{dist-DQiph4qx.js → dist-CIt_ogHO.js} +1 -1
- package/dist/client/assets/{dist-BOP-dC-R.js → dist-CQZDuOJ9.js} +1 -1
- package/dist/client/assets/{dist-DdAqzGFU.js → dist-CRyP6okk.js} +1 -1
- package/dist/client/assets/dist-D-ixVAsS2.js +1 -0
- package/dist/client/assets/{dist-Brrlevif.js → dist-D8d0IGSI.js} +1 -1
- package/dist/client/assets/{dist-DZ2t5lUX.js → dist-Das5WX49.js} +1 -1
- package/dist/client/assets/{dist-CaMl1R6P.js → dist-DplP0BiK.js} +1 -1
- package/dist/client/assets/{dist-BE8C_ouo.js → dist-DwgKARew.js} +1 -1
- package/dist/client/assets/dist-GgGgSSbl.js +1 -0
- package/dist/client/assets/{dist-D34Xzrah.js → dist-NcJIpTJ8.js} +1 -1
- package/dist/client/assets/dist-QktK6LIH.js +1 -0
- package/dist/client/assets/{dist-BiCgLddE.js → dist-ZuMKSK7c.js} +1 -1
- package/dist/client/assets/{dist-DPCUH5MO.js → dist-_THc9HiJ.js} +1 -1
- package/dist/client/assets/{dist-mPPUaHhq.js → dist-bkoMCmF7.js} +1 -1
- package/dist/client/assets/{dist-B98fHn5m.js → dist-eAgBpkKv.js} +1 -1
- package/dist/client/assets/{dist-BScEL4VP.js → dist-fpFkgu34.js} +1 -1
- package/dist/client/assets/{dist-aE0_04fl.js → dist-tRNsnttY.js} +1 -1
- package/dist/client/assets/{dist-DWRyOl2w.js → dist-uyVGTnZh.js} +1 -1
- package/dist/client/assets/{dist-CJWCCWEW.js → dist-yy8SO13g.js} +1 -1
- package/dist/client/assets/{drawioEditor-DOaXwaY2.js → drawioEditor-DBSyP3_d.js} +2 -2
- package/dist/client/assets/editor-session-C1scHGLl.js +16 -0
- package/dist/client/assets/{embedded-editor-base-CgEkjNYn.css → embedded-editor-base-Bb8ywn1e.css} +1 -1
- package/dist/client/assets/excalidraw-editor-B0XXVLHd.js +9 -0
- package/dist/client/assets/{excalidraw-scene-MyNAJi2A.js → excalidraw-scene-wAbVSY1L.js} +2 -2
- package/dist/client/assets/{excalidrawEditor-Ck9hgrTa.js → excalidrawEditor-37sk03H8.js} +2 -2
- package/dist/client/assets/{export-page-4M8Zo-AL.js → export-page-Bnk-YQp-.js} +1 -1
- package/dist/client/assets/{exportDocument-mlXOym-R.js → exportDocument-WQNApAbg.js} +2 -2
- package/dist/client/assets/{index-CCfHrm_9.js → index-BoKmcqkH.js} +2 -2
- package/dist/client/assets/{main-BQMPQ4CW.js → main-BKumyd95.js} +2 -2
- package/dist/client/drawio-editor.html +1 -1
- package/dist/client/excalidraw-editor.html +1 -1
- package/dist/client/export-document.html +1 -1
- package/dist/client/index.html +1 -1
- package/package.json +3 -3
- package/src/client/domain/excalidraw-collaboration.js +50 -0
- package/src/client/domain/excalidraw-scene-reconcile.js +38 -0
- package/src/client/domain/mermaid-language.js +179 -0
- package/src/client/excalidraw-editor.js +76 -47
- package/src/client/infrastructure/editor-view-adapter.js +7 -2
- package/src/client/infrastructure/excalidraw-room-client.js +139 -27
- package/src/client/styles/surfaces/embedded-editor-base.css +2 -1
- package/src/domain/excalidraw-room-codec.js +1 -17
- package/dist/client/assets/dist-BfVljg0L2.js +0 -1
- package/dist/client/assets/dist-CcG3Y7Wp.js +0 -1
- package/dist/client/assets/dist-CghBwrO3.js +0 -1
- package/dist/client/assets/dist-Csbx9lQ-.js +0 -1
- package/dist/client/assets/dist-DLyohOXi.js +0 -1
- package/dist/client/assets/dist-WXLmfDGg.js +0 -1
- package/dist/client/assets/editor-session-BFsA-WRc.js +0 -16
- package/dist/client/assets/excalidraw-editor-6pgH2kf5.js +0 -9
- /package/dist/client/assets/{drawio-editor-BHI0pLby.js → drawio-editor-B_Sr8Z_Z.js} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>CollabMD Export</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/exportDocument-
|
|
7
|
+
<script type="module" crossorigin src="./assets/exportDocument-WQNApAbg.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/base-h1uscjTi.js">
|
package/dist/client/index.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
document.documentElement.setAttribute('data-initial-file-requested', 'true');
|
|
16
16
|
}
|
|
17
17
|
</script>
|
|
18
|
-
<script type="module" crossorigin src="./assets/index-
|
|
18
|
+
<script type="module" crossorigin src="./assets/index-BoKmcqkH.js"></script>
|
|
19
19
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
20
20
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="./assets/base-h1uscjTi.js">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "collabmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Collaborative markdown vault — like Obsidian, but online. Serve any directory of markdown files for realtime collaborative editing.",
|
|
6
6
|
"repository": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@codemirror/autocomplete": "^6.20.
|
|
66
|
+
"@codemirror/autocomplete": "^6.20.2",
|
|
67
67
|
"@codemirror/commands": "^6.10.3",
|
|
68
68
|
"@codemirror/lang-markdown": "^6.5.0",
|
|
69
69
|
"@codemirror/lang-yaml": "^6.1.3",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@codemirror/search": "^6.7.0",
|
|
73
73
|
"@codemirror/state": "^6.6.0",
|
|
74
74
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
75
|
-
"@codemirror/view": "^6.
|
|
75
|
+
"@codemirror/view": "^6.42.0",
|
|
76
76
|
"@excalidraw/excalidraw": "0.18.0-b1c6bfc",
|
|
77
77
|
"@fontsource-variable/inter": "^5.2.8",
|
|
78
78
|
"@fontsource/jetbrains-mono": "^5.2.8",
|
|
@@ -138,6 +138,56 @@ export function buildCollaboratorsMap(awareness) {
|
|
|
138
138
|
return collaborators;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
export function buildRenderableCollaboratorsMap(collaborators) {
|
|
142
|
+
const renderable = new Map();
|
|
143
|
+
if (!(collaborators instanceof Map)) {
|
|
144
|
+
return renderable;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
collaborators.forEach((collaborator, key) => {
|
|
148
|
+
if (!collaborator?.isCurrentUser) {
|
|
149
|
+
renderable.set(key, collaborator);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return renderable;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function serializeCollaboratorForRenderSignature(key, collaborator = {}) {
|
|
157
|
+
const pointer = collaborator.pointer || {};
|
|
158
|
+
const viewport = collaborator.viewport || {};
|
|
159
|
+
const selectedElementIds = collaborator.selectedElementIds && typeof collaborator.selectedElementIds === 'object'
|
|
160
|
+
? Object.keys(collaborator.selectedElementIds).sort()
|
|
161
|
+
: [];
|
|
162
|
+
|
|
163
|
+
return [
|
|
164
|
+
key,
|
|
165
|
+
collaborator.button || 'up',
|
|
166
|
+
collaborator.color?.background || '',
|
|
167
|
+
collaborator.color?.stroke || '',
|
|
168
|
+
collaborator.id || '',
|
|
169
|
+
pointer.tool || '',
|
|
170
|
+
pointer.x ?? null,
|
|
171
|
+
pointer.y ?? null,
|
|
172
|
+
selectedElementIds,
|
|
173
|
+
collaborator.socketId || '',
|
|
174
|
+
collaborator.username || '',
|
|
175
|
+
viewport.scrollX ?? null,
|
|
176
|
+
viewport.scrollY ?? null,
|
|
177
|
+
viewport.zoom ?? null,
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function getCollaboratorsRenderSignature(collaborators) {
|
|
182
|
+
if (!(collaborators instanceof Map) || collaborators.size === 0) {
|
|
183
|
+
return '';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return JSON.stringify([...collaborators.entries()]
|
|
187
|
+
.sort(([leftKey], [rightKey]) => String(leftKey).localeCompare(String(rightKey)))
|
|
188
|
+
.map(([key, collaborator]) => serializeCollaboratorForRenderSignature(key, collaborator)));
|
|
189
|
+
}
|
|
190
|
+
|
|
141
191
|
export function findCollaboratorByPeerId(collaborators, peerId) {
|
|
142
192
|
if (!(collaborators instanceof Map) || !peerId) {
|
|
143
193
|
return null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function buildReconciledExcalidrawSceneUpdate({
|
|
2
|
+
appStateOverrides = {},
|
|
3
|
+
currentAppState,
|
|
4
|
+
currentElements = [],
|
|
5
|
+
documentViewState = {},
|
|
6
|
+
includeUnchangedAppState = false,
|
|
7
|
+
reconcileElementsFn,
|
|
8
|
+
restoreAppStateFn,
|
|
9
|
+
restoreElementsFn,
|
|
10
|
+
scene,
|
|
11
|
+
theme = 'dark',
|
|
12
|
+
} = {}) {
|
|
13
|
+
const restoredElements = restoreElementsFn(scene?.elements || [], currentElements, {
|
|
14
|
+
repairBindings: true,
|
|
15
|
+
});
|
|
16
|
+
const restoredAppState = restoreAppStateFn(scene?.appState || {}, currentAppState);
|
|
17
|
+
const nextAppState = {
|
|
18
|
+
theme,
|
|
19
|
+
viewBackgroundColor: restoredAppState.viewBackgroundColor ?? '#ffffff',
|
|
20
|
+
gridSize: restoredAppState.gridSize ?? null,
|
|
21
|
+
...documentViewState,
|
|
22
|
+
...appStateOverrides,
|
|
23
|
+
};
|
|
24
|
+
const appStateUpdate = Object.fromEntries(
|
|
25
|
+
Object.entries(nextAppState).filter(([key, value]) => (
|
|
26
|
+
includeUnchangedAppState || currentAppState?.[key] !== value
|
|
27
|
+
)),
|
|
28
|
+
);
|
|
29
|
+
const update = {
|
|
30
|
+
elements: reconcileElementsFn(currentElements, restoredElements, currentAppState),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (Object.keys(appStateUpdate).length > 0) {
|
|
34
|
+
update.appState = appStateUpdate;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return update;
|
|
38
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { LanguageDescription, LanguageSupport, StreamLanguage } from '@codemirror/language';
|
|
2
|
+
|
|
3
|
+
const DIAGRAM_DECLARATIONS = new Set([
|
|
4
|
+
'block-beta',
|
|
5
|
+
'classdiagram',
|
|
6
|
+
'erdiagram',
|
|
7
|
+
'flowchart',
|
|
8
|
+
'gantt',
|
|
9
|
+
'gitgraph',
|
|
10
|
+
'graph',
|
|
11
|
+
'journey',
|
|
12
|
+
'mindmap',
|
|
13
|
+
'pie',
|
|
14
|
+
'quadrantchart',
|
|
15
|
+
'sankey-beta',
|
|
16
|
+
'sequencediagram',
|
|
17
|
+
'statediagram',
|
|
18
|
+
'statediagram-v2',
|
|
19
|
+
'timeline',
|
|
20
|
+
'xychart-beta',
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const KEYWORDS = new Set([
|
|
24
|
+
'accdescr',
|
|
25
|
+
'acctitle',
|
|
26
|
+
'actor',
|
|
27
|
+
'alt',
|
|
28
|
+
'and',
|
|
29
|
+
'autonumber',
|
|
30
|
+
'break',
|
|
31
|
+
'callback',
|
|
32
|
+
'class',
|
|
33
|
+
'classdef',
|
|
34
|
+
'click',
|
|
35
|
+
'critical',
|
|
36
|
+
'dateformat',
|
|
37
|
+
'direction',
|
|
38
|
+
'else',
|
|
39
|
+
'end',
|
|
40
|
+
'exclude',
|
|
41
|
+
'include',
|
|
42
|
+
'interpolate',
|
|
43
|
+
'link',
|
|
44
|
+
'linkstyle',
|
|
45
|
+
'loop',
|
|
46
|
+
'note',
|
|
47
|
+
'opt',
|
|
48
|
+
'par',
|
|
49
|
+
'participant',
|
|
50
|
+
'rect',
|
|
51
|
+
'section',
|
|
52
|
+
'state',
|
|
53
|
+
'style',
|
|
54
|
+
'subgraph',
|
|
55
|
+
'theme',
|
|
56
|
+
'title',
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const BOOLEAN_LITERALS = new Set([
|
|
60
|
+
'false',
|
|
61
|
+
'no',
|
|
62
|
+
'off',
|
|
63
|
+
'on',
|
|
64
|
+
'true',
|
|
65
|
+
'yes',
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const FLOW_DIRECTIONS = new Set([
|
|
69
|
+
'bt',
|
|
70
|
+
'lr',
|
|
71
|
+
'rl',
|
|
72
|
+
'tb',
|
|
73
|
+
'td',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
function readWord(stream) {
|
|
77
|
+
const match = stream.match(/[A-Za-z_][\w.]*(?:-[A-Za-z0-9_][\w.]*)*/u, false);
|
|
78
|
+
if (!match) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stream.match(/[A-Za-z_][\w.]*(?:-[A-Za-z0-9_][\w.]*)*/u);
|
|
83
|
+
return match[0];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function readDirective(stream) {
|
|
87
|
+
if (!stream.match('%%{')) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (stream.skipTo('}%%')) {
|
|
92
|
+
stream.match('}%%');
|
|
93
|
+
} else {
|
|
94
|
+
stream.skipToEnd();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const mermaidStreamLanguage = StreamLanguage.define({
|
|
101
|
+
languageData: {
|
|
102
|
+
commentTokens: {
|
|
103
|
+
line: '%%',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
token(stream) {
|
|
107
|
+
if (stream.eatSpace()) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (readDirective(stream)) {
|
|
112
|
+
return 'meta';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (stream.match('%%')) {
|
|
116
|
+
stream.skipToEnd();
|
|
117
|
+
return 'comment';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (stream.match(/"(?:[^"\\]|\\.)*"?/u) || stream.match(/'(?:[^'\\]|\\.)*'?/u)) {
|
|
121
|
+
return 'string';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (stream.match(/#[0-9a-f]{3,8}\b/iu) || stream.match(/#[A-Za-z][\w-]*/u)) {
|
|
125
|
+
return 'atom';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (stream.match(/\b\d+(?:\.\d+)?%?\b/u)) {
|
|
129
|
+
return 'number';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (stream.match(/[ox*+<#]?[-=.\\/]+(?:left|right|up|down)?[-=.\\/]*[ox*+>#]?/iu)) {
|
|
133
|
+
return 'operator';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (stream.match(/[{}[\]():,;|]/u)) {
|
|
137
|
+
return 'punctuation';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const word = readWord(stream);
|
|
141
|
+
if (word) {
|
|
142
|
+
const normalized = word.toLowerCase();
|
|
143
|
+
|
|
144
|
+
if (DIAGRAM_DECLARATIONS.has(normalized)) {
|
|
145
|
+
return 'meta';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (KEYWORDS.has(normalized)) {
|
|
149
|
+
return 'keyword';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (BOOLEAN_LITERALS.has(normalized)) {
|
|
153
|
+
return 'bool';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (FLOW_DIRECTIONS.has(normalized)) {
|
|
157
|
+
return 'atom';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (/^[A-Z][A-Z0-9_]*$/u.test(word)) {
|
|
161
|
+
return 'typeName';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return 'variableName';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
stream.next();
|
|
168
|
+
return null;
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
export const mermaidLanguage = new LanguageSupport(mermaidStreamLanguage);
|
|
173
|
+
|
|
174
|
+
export const mermaidLanguageDescription = LanguageDescription.of({
|
|
175
|
+
alias: ['mermaid', 'mmd'],
|
|
176
|
+
extensions: ['mermaid', 'mmd'],
|
|
177
|
+
name: 'Mermaid',
|
|
178
|
+
support: mermaidLanguage,
|
|
179
|
+
});
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
import '@excalidraw/excalidraw/index.css';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
|
+
buildRenderableCollaboratorsMap,
|
|
13
14
|
findCollaboratorByPeerId,
|
|
15
|
+
getCollaboratorsRenderSignature,
|
|
14
16
|
mergeAwarenessUserPatch,
|
|
15
17
|
resolveLocalAwarenessUser,
|
|
16
18
|
} from './domain/excalidraw-collaboration.js';
|
|
@@ -24,6 +26,9 @@ import {
|
|
|
24
26
|
parseSceneJson,
|
|
25
27
|
sceneToInitialData,
|
|
26
28
|
} from './domain/excalidraw-scene.js';
|
|
29
|
+
import {
|
|
30
|
+
buildReconciledExcalidrawSceneUpdate,
|
|
31
|
+
} from './domain/excalidraw-scene-reconcile.js';
|
|
27
32
|
import {
|
|
28
33
|
normalizeDocumentMode,
|
|
29
34
|
} from './domain/excalidraw-document-switch.js';
|
|
@@ -60,6 +65,7 @@ let pendingHostFollowPeerId = null;
|
|
|
60
65
|
let suppressViewportBroadcast = false;
|
|
61
66
|
let pendingViewportSuppressionReleases = 0;
|
|
62
67
|
let lastAppliedFollowViewportSignature = '';
|
|
68
|
+
let lastRenderedCollaboratorsSignature = '';
|
|
63
69
|
let apiStateCleanupCallbacks = [];
|
|
64
70
|
let collaboratorRenderFrame = 0;
|
|
65
71
|
let queuedCollaborators = null;
|
|
@@ -295,16 +301,21 @@ if (isTestMode) {
|
|
|
295
301
|
|
|
296
302
|
function applyCollaborators(collaborators) {
|
|
297
303
|
activeCollaborators = collaborators instanceof Map ? collaborators : new Map();
|
|
304
|
+
const renderableCollaborators = buildRenderableCollaboratorsMap(activeCollaborators);
|
|
305
|
+
const renderSignature = getCollaboratorsRenderSignature(renderableCollaborators);
|
|
298
306
|
|
|
299
307
|
if (!excalidrawAPI) {
|
|
300
308
|
pendingCollaborators = activeCollaborators;
|
|
301
309
|
return;
|
|
302
310
|
}
|
|
303
311
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
312
|
+
if (renderSignature !== lastRenderedCollaboratorsSignature) {
|
|
313
|
+
lastRenderedCollaboratorsSignature = renderSignature;
|
|
314
|
+
excalidrawAPI.updateScene({
|
|
315
|
+
collaborators: renderableCollaborators,
|
|
316
|
+
captureUpdate: CaptureUpdateAction.NEVER,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
308
319
|
|
|
309
320
|
if (pendingHostFollowPeerId) {
|
|
310
321
|
applyHostFollowRequest(pendingHostFollowPeerId);
|
|
@@ -328,10 +339,29 @@ function queueCollaboratorsRender(collaborators) {
|
|
|
328
339
|
});
|
|
329
340
|
}
|
|
330
341
|
|
|
331
|
-
function
|
|
342
|
+
function isEditingTextElement() {
|
|
343
|
+
return Boolean(excalidrawAPI?.getAppState?.()?.editingTextElement);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function flushPendingRemoteScene() {
|
|
347
|
+
if (!pendingRemoteSceneJson || !excalidrawAPI || !collabReady || isEditingTextElement()) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const sceneJson = pendingRemoteSceneJson;
|
|
352
|
+
pendingRemoteSceneJson = '';
|
|
353
|
+
applySceneFromJson(sceneJson, {
|
|
354
|
+
force: true,
|
|
355
|
+
});
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function applySceneFromJson(rawJson, {
|
|
360
|
+
force = false,
|
|
361
|
+
} = {}) {
|
|
332
362
|
const scene = parseSceneJson(rawJson);
|
|
333
363
|
const normalizedJson = JSON.stringify(scene);
|
|
334
|
-
if (normalizedJson === appliedSceneJson && !pendingRemoteSceneJson) {
|
|
364
|
+
if (!force && normalizedJson === appliedSceneJson && !pendingRemoteSceneJson) {
|
|
335
365
|
return;
|
|
336
366
|
}
|
|
337
367
|
|
|
@@ -342,9 +372,12 @@ function applySceneFromJson(rawJson) {
|
|
|
342
372
|
return;
|
|
343
373
|
}
|
|
344
374
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
375
|
+
if (!force && isEditingTextElement()) {
|
|
376
|
+
pendingRemoteSceneJson = normalizedJson;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
updateApiScene(scene);
|
|
348
381
|
}
|
|
349
382
|
|
|
350
383
|
function releaseOnChangeSuppressionAfterPaint({ trackedSharedSnapshot = false } = {}) {
|
|
@@ -376,30 +409,21 @@ function releaseViewportBroadcastSuppressionAfterPaint() {
|
|
|
376
409
|
|
|
377
410
|
function buildApiSceneUpdate(scene, {
|
|
378
411
|
appStateOverrides = {},
|
|
379
|
-
replaceElements = false,
|
|
380
412
|
} = {}) {
|
|
381
413
|
const currentAppState = excalidrawAPI.getAppState();
|
|
382
|
-
const currentElements =
|
|
383
|
-
? []
|
|
384
|
-
: (excalidrawAPI.getSceneElementsIncludingDeleted?.() || excalidrawAPI.getSceneElements());
|
|
385
|
-
const restoredElements = restoreElements(scene?.elements || [], currentElements, {
|
|
386
|
-
repairBindings: true,
|
|
387
|
-
});
|
|
388
|
-
const restoredAppState = restoreAppState(scene?.appState || {}, currentAppState);
|
|
389
|
-
const reconciledElements = replaceElements
|
|
390
|
-
? restoredElements
|
|
391
|
-
: reconcileElements(currentElements, restoredElements, currentAppState);
|
|
414
|
+
const currentElements = excalidrawAPI.getSceneElementsIncludingDeleted?.() || excalidrawAPI.getSceneElements();
|
|
392
415
|
|
|
393
|
-
return {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
416
|
+
return buildReconciledExcalidrawSceneUpdate({
|
|
417
|
+
appStateOverrides,
|
|
418
|
+
currentAppState,
|
|
419
|
+
currentElements,
|
|
420
|
+
documentViewState: getDocumentViewState(),
|
|
421
|
+
reconcileElementsFn: reconcileElements,
|
|
422
|
+
restoreAppStateFn: restoreAppState,
|
|
423
|
+
restoreElementsFn: restoreElements,
|
|
424
|
+
scene,
|
|
425
|
+
theme: currentTheme,
|
|
426
|
+
});
|
|
403
427
|
}
|
|
404
428
|
|
|
405
429
|
function logFileConflictOnce(conflictingFileIds = []) {
|
|
@@ -437,12 +461,10 @@ function requestEditorRemount(scene) {
|
|
|
437
461
|
function applySceneToMountedApi(scene, {
|
|
438
462
|
appStateOverrides = {},
|
|
439
463
|
captureUpdate = CaptureUpdateAction.NEVER,
|
|
440
|
-
replaceElements = false,
|
|
441
464
|
trackedSharedSnapshot = false,
|
|
442
465
|
} = {}) {
|
|
443
466
|
const nextSceneUpdate = buildApiSceneUpdate(scene, {
|
|
444
467
|
appStateOverrides,
|
|
445
|
-
replaceElements,
|
|
446
468
|
});
|
|
447
469
|
let applyResult = null;
|
|
448
470
|
|
|
@@ -484,13 +506,11 @@ function applySceneToMountedApi(scene, {
|
|
|
484
506
|
function updateApiScene(scene, {
|
|
485
507
|
appStateOverrides = {},
|
|
486
508
|
captureUpdate = CaptureUpdateAction.NEVER,
|
|
487
|
-
replaceElements = false,
|
|
488
509
|
trackedSharedSnapshot = true,
|
|
489
510
|
} = {}) {
|
|
490
511
|
applySceneToMountedApi(scene, {
|
|
491
512
|
appStateOverrides,
|
|
492
513
|
captureUpdate,
|
|
493
|
-
replaceElements,
|
|
494
514
|
trackedSharedSnapshot,
|
|
495
515
|
});
|
|
496
516
|
}
|
|
@@ -520,6 +540,10 @@ function onRoomTextUpdate() {
|
|
|
520
540
|
applySceneFromJson(roomClient?.getLastSceneJson?.() || '');
|
|
521
541
|
}
|
|
522
542
|
|
|
543
|
+
function getLiveSceneElementsForSync(fallbackElements = []) {
|
|
544
|
+
return excalidrawAPI?.getSceneElementsIncludingDeleted?.() || fallbackElements;
|
|
545
|
+
}
|
|
546
|
+
|
|
523
547
|
function postToParent(type, payload = {}) {
|
|
524
548
|
window.parent.postMessage({ source: 'excalidraw-editor', type, ...payload }, parentOrigin);
|
|
525
549
|
}
|
|
@@ -674,6 +698,7 @@ function resetRealtimeRoomState() {
|
|
|
674
698
|
suppressViewportBroadcast = false;
|
|
675
699
|
pendingViewportSuppressionReleases = 0;
|
|
676
700
|
lastAppliedFollowViewportSignature = '';
|
|
701
|
+
lastRenderedCollaboratorsSignature = '';
|
|
677
702
|
if (collaboratorRenderFrame) {
|
|
678
703
|
cancelAnimationFrame(collaboratorRenderFrame);
|
|
679
704
|
}
|
|
@@ -799,17 +824,8 @@ function scheduleSyncToRoom(elements, appState, files) {
|
|
|
799
824
|
return;
|
|
800
825
|
}
|
|
801
826
|
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
appState,
|
|
805
|
-
files,
|
|
806
|
-
}));
|
|
807
|
-
if (nextSceneJson === appliedSceneJson) {
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
appliedSceneJson = nextSceneJson;
|
|
812
|
-
roomClient.scheduleSceneSync(elements, appState, files);
|
|
827
|
+
const liveElements = getLiveSceneElementsForSync(elements);
|
|
828
|
+
roomClient.scheduleSceneSync(liveElements, appState, files);
|
|
813
829
|
}
|
|
814
830
|
|
|
815
831
|
function initializeEditor(api) {
|
|
@@ -828,14 +844,27 @@ function initializeEditor(api) {
|
|
|
828
844
|
|
|
829
845
|
setFollowedSocket(null, { force: true });
|
|
830
846
|
}));
|
|
847
|
+
apiStateCleanupCallbacks.push(api.onStateChange('editingTextElement', (editingTextElement) => {
|
|
848
|
+
if (!editingTextElement) {
|
|
849
|
+
requestAnimationFrame(() => {
|
|
850
|
+
requestAnimationFrame(() => {
|
|
851
|
+
flushPendingRemoteScene();
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
}));
|
|
831
856
|
|
|
832
857
|
const sceneJson = pendingRemoteSceneJson || roomClient?.getLastSceneJson?.() || '';
|
|
858
|
+
const initialScene = parseSceneJson(sceneJson);
|
|
833
859
|
pendingRemoteSceneJson = '';
|
|
834
|
-
|
|
860
|
+
appliedSceneJson = JSON.stringify(initialScene);
|
|
861
|
+
updateApiScene(initialScene);
|
|
835
862
|
|
|
836
863
|
if (pendingCollaborators) {
|
|
864
|
+
const renderableCollaborators = buildRenderableCollaboratorsMap(pendingCollaborators);
|
|
865
|
+
lastRenderedCollaboratorsSignature = getCollaboratorsRenderSignature(renderableCollaborators);
|
|
837
866
|
excalidrawAPI.updateScene({
|
|
838
|
-
collaborators:
|
|
867
|
+
collaborators: renderableCollaborators,
|
|
839
868
|
captureUpdate: CaptureUpdateAction.NEVER,
|
|
840
869
|
});
|
|
841
870
|
pendingCollaborators = null;
|
|
@@ -38,14 +38,15 @@ import {
|
|
|
38
38
|
} from '@codemirror/view';
|
|
39
39
|
import { yCollab } from 'y-codemirror.next';
|
|
40
40
|
|
|
41
|
-
import { isBaseFilePath, isPlantUmlFilePath } from '../../domain/file-kind.js';
|
|
41
|
+
import { isBaseFilePath, isMermaidFilePath, isPlantUmlFilePath } from '../../domain/file-kind.js';
|
|
42
42
|
import { normalizeCommentQuote } from '../../domain/comment-threads.js';
|
|
43
43
|
import { createMarkdownToolbarEdit } from '../domain/markdown-formatting.js';
|
|
44
|
+
import { mermaidLanguage, mermaidLanguageDescription } from '../domain/mermaid-language.js';
|
|
44
45
|
import { wikiLinkCompletions } from '../domain/wiki-link-completions.js';
|
|
45
46
|
import { plantUmlLanguage, plantUmlLanguageDescription } from '../domain/plantuml-language.js';
|
|
46
47
|
import { handleImagePasteEvent } from './editor-paste-utils.js';
|
|
47
48
|
|
|
48
|
-
const markdownCodeLanguages = [...languages, plantUmlLanguageDescription];
|
|
49
|
+
const markdownCodeLanguages = [...languages, mermaidLanguageDescription, plantUmlLanguageDescription];
|
|
49
50
|
const pairedMatchingBracketMark = Decoration.mark({ class: 'cm-matchingBracket cm-matchingBracket-paired' });
|
|
50
51
|
const nonmatchingBracketMark = Decoration.mark({ class: 'cm-nonmatchingBracket' });
|
|
51
52
|
const remoteUpdateMark = Decoration.mark({ class: 'cm-remoteUpdateFlash' });
|
|
@@ -299,6 +300,10 @@ function createEditorTheme(theme) {
|
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
export function createLanguageExtension(filePath) {
|
|
303
|
+
if (isMermaidFilePath(filePath)) {
|
|
304
|
+
return mermaidLanguage;
|
|
305
|
+
}
|
|
306
|
+
|
|
302
307
|
if (isPlantUmlFilePath(filePath)) {
|
|
303
308
|
return plantUmlLanguage;
|
|
304
309
|
}
|