veryfront 0.1.29 → 0.1.31
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/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-template.d.ts","sourceRoot":"","sources":["../../../src/src/studio/bridge-template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"bridge-template.d.ts","sourceRoot":"","sources":["../../../src/src/studio/bridge-template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAyqI/E"}
|
|
@@ -69,6 +69,13 @@ export function generateStudioBridgeScript(options) {
|
|
|
69
69
|
let markdownLatestPresenceUsers = [];
|
|
70
70
|
let markdownLatestSelections = [];
|
|
71
71
|
let markdownHasUnsavedChanges = false;
|
|
72
|
+
let markdownSaveInProgress = false;
|
|
73
|
+
let markdownYDoc = null;
|
|
74
|
+
let markdownYProvider = null;
|
|
75
|
+
let markdownYText = null;
|
|
76
|
+
let markdownYjsConnected = false;
|
|
77
|
+
let markdownYjsSetupId = 0;
|
|
78
|
+
const LEXICAL_YJS_ORIGIN = 'lexical-yjs-binding';
|
|
72
79
|
|
|
73
80
|
const MARKDOWN_SLASH_COMMANDS = [
|
|
74
81
|
{
|
|
@@ -1409,6 +1416,142 @@ export function generateStudioBridgeScript(options) {
|
|
|
1409
1416
|
}, 120);
|
|
1410
1417
|
}
|
|
1411
1418
|
|
|
1419
|
+
function computeTextDiff(oldText, newText) {
|
|
1420
|
+
var prefixLen = 0;
|
|
1421
|
+
var minLen = Math.min(oldText.length, newText.length);
|
|
1422
|
+
while (prefixLen < minLen && oldText.charCodeAt(prefixLen) === newText.charCodeAt(prefixLen)) {
|
|
1423
|
+
prefixLen++;
|
|
1424
|
+
}
|
|
1425
|
+
var suffixLen = 0;
|
|
1426
|
+
var maxSuffix = minLen - prefixLen;
|
|
1427
|
+
while (suffixLen < maxSuffix &&
|
|
1428
|
+
oldText.charCodeAt(oldText.length - 1 - suffixLen) === newText.charCodeAt(newText.length - 1 - suffixLen)) {
|
|
1429
|
+
suffixLen++;
|
|
1430
|
+
}
|
|
1431
|
+
return {
|
|
1432
|
+
index: prefixLen,
|
|
1433
|
+
deleteCount: oldText.length - prefixLen - suffixLen,
|
|
1434
|
+
insertText: newText.slice(prefixLen, suffixLen > 0 ? newText.length - suffixLen : undefined)
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
function syncLocalChangeToYText(fullContent) {
|
|
1439
|
+
if (!markdownYText || !markdownYDoc) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
var currentYContent = markdownYText.toString();
|
|
1443
|
+
if (currentYContent === fullContent) {
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
var diff = computeTextDiff(currentYContent, fullContent);
|
|
1447
|
+
if (diff.deleteCount === 0 && diff.insertText === '') {
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
markdownYDoc.transact(function() {
|
|
1451
|
+
if (diff.deleteCount > 0) {
|
|
1452
|
+
markdownYText.delete(diff.index, diff.deleteCount);
|
|
1453
|
+
}
|
|
1454
|
+
if (diff.insertText) {
|
|
1455
|
+
markdownYText.insert(diff.index, diff.insertText);
|
|
1456
|
+
}
|
|
1457
|
+
}, LEXICAL_YJS_ORIGIN);
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
function setupMarkdownYjsConnection(config) {
|
|
1461
|
+
if (markdownYDoc) {
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
var setupId = ++markdownYjsSetupId;
|
|
1466
|
+
|
|
1467
|
+
Promise.all([
|
|
1468
|
+
import('https://esm.sh/yjs@13.6.28?target=es2022'),
|
|
1469
|
+
import('https://esm.sh/y-websocket@2.1.0?target=es2022')
|
|
1470
|
+
]).then(function(modules) {
|
|
1471
|
+
// Abort if edit mode was closed while imports were loading
|
|
1472
|
+
if (setupId !== markdownYjsSetupId) {
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
var Y = modules[0];
|
|
1477
|
+
var WebsocketProvider = modules[1].WebsocketProvider;
|
|
1478
|
+
|
|
1479
|
+
var doc = new Y.Doc({ guid: config.guid });
|
|
1480
|
+
var provider = new WebsocketProvider(config.wsUrl, config.guid, doc, {
|
|
1481
|
+
resyncInterval: -1,
|
|
1482
|
+
params: { token: config.authToken }
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
var ytext = doc.getText(config.fileId);
|
|
1486
|
+
|
|
1487
|
+
markdownYDoc = doc;
|
|
1488
|
+
markdownYProvider = provider;
|
|
1489
|
+
markdownYText = ytext;
|
|
1490
|
+
|
|
1491
|
+
// Filter non-binary messages to prevent y-websocket parse errors
|
|
1492
|
+
provider.on('status', function(event) {
|
|
1493
|
+
console.debug('[StudioBridge] Yjs status:', event.status);
|
|
1494
|
+
if (event.status === 'connected' && provider.ws) {
|
|
1495
|
+
var origOnMessage = provider.ws.onmessage;
|
|
1496
|
+
provider.ws.onmessage = function(wsEvent) {
|
|
1497
|
+
if (typeof wsEvent.data === 'string') {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
if (origOnMessage) {
|
|
1501
|
+
origOnMessage.call(provider.ws, wsEvent);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
provider.on('sync', function(synced) {
|
|
1508
|
+
if (synced && !markdownYjsConnected) {
|
|
1509
|
+
markdownYjsConnected = true;
|
|
1510
|
+
|
|
1511
|
+
var ytextContent = ytext.toString();
|
|
1512
|
+
if (markdownCurrentContent && markdownCurrentContent !== ytextContent) {
|
|
1513
|
+
// User typed before sync completed — push local edits to Y.Text
|
|
1514
|
+
syncLocalChangeToYText(markdownCurrentContent);
|
|
1515
|
+
} else if (ytextContent) {
|
|
1516
|
+
// No local edits — seed editor from Y.Text
|
|
1517
|
+
applyMarkdownContent(ytextContent);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// Observe Y.Text for remote changes (from other users / Monaco)
|
|
1521
|
+
ytext.observe(function(event) {
|
|
1522
|
+
if (event.transaction.origin === LEXICAL_YJS_ORIGIN) {
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
var fullContent = ytext.toString();
|
|
1526
|
+
if (fullContent === markdownCurrentContent) {
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
applyMarkdownContent(fullContent);
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
console.debug('[StudioBridge] Yjs synced, bound to Y.Text for fileId:', config.fileId);
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
}).catch(function(error) {
|
|
1536
|
+
console.error('[StudioBridge] Failed to setup Yjs connection:', error);
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function disposeMarkdownYjs() {
|
|
1541
|
+
markdownYjsSetupId++;
|
|
1542
|
+
if (markdownYProvider) {
|
|
1543
|
+
markdownYProvider.disconnect();
|
|
1544
|
+
markdownYProvider.destroy();
|
|
1545
|
+
markdownYProvider = null;
|
|
1546
|
+
}
|
|
1547
|
+
if (markdownYDoc) {
|
|
1548
|
+
markdownYDoc.destroy();
|
|
1549
|
+
markdownYDoc = null;
|
|
1550
|
+
}
|
|
1551
|
+
markdownYText = null;
|
|
1552
|
+
markdownYjsConnected = false;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1412
1555
|
function getTextOffsetWithinRoot(root, targetNode, targetOffset) {
|
|
1413
1556
|
if (!root || !targetNode) {
|
|
1414
1557
|
return 0;
|
|
@@ -2908,7 +3051,11 @@ export function generateStudioBridgeScript(options) {
|
|
|
2908
3051
|
}
|
|
2909
3052
|
markdownCurrentContent = fullContent;
|
|
2910
3053
|
markdownHasUnsavedChanges = true;
|
|
2911
|
-
|
|
3054
|
+
if (markdownYjsConnected) {
|
|
3055
|
+
syncLocalChangeToYText(fullContent);
|
|
3056
|
+
} else {
|
|
3057
|
+
scheduleMarkdownSync(fullContent);
|
|
3058
|
+
}
|
|
2912
3059
|
scheduleMarkdownSelectionOverlayRender();
|
|
2913
3060
|
}
|
|
2914
3061
|
|
|
@@ -2916,6 +3063,7 @@ export function generateStudioBridgeScript(options) {
|
|
|
2916
3063
|
if (!markdownHasUnsavedChanges) {
|
|
2917
3064
|
return;
|
|
2918
3065
|
}
|
|
3066
|
+
markdownSaveInProgress = true;
|
|
2919
3067
|
setMarkdownPersistStatus('saving');
|
|
2920
3068
|
if (markdownSyncTimer) {
|
|
2921
3069
|
clearTimeout(markdownSyncTimer);
|
|
@@ -3068,7 +3216,8 @@ export function generateStudioBridgeScript(options) {
|
|
|
3068
3216
|
return;
|
|
3069
3217
|
}
|
|
3070
3218
|
|
|
3071
|
-
if (markdownLexicalApi && markdownLexicalRenderedContent === content) {
|
|
3219
|
+
if (markdownLexicalApi && (markdownLexicalRenderedContent === content || markdownCurrentContent === content)) {
|
|
3220
|
+
console.debug('[StudioBridge] applyMarkdownContent: skipped (content unchanged)');
|
|
3072
3221
|
markdownCurrentContent = content;
|
|
3073
3222
|
scheduleMarkdownSelectionOverlayRender();
|
|
3074
3223
|
scheduleMarkdownSlashMenuUpdate();
|
|
@@ -3077,6 +3226,8 @@ export function generateStudioBridgeScript(options) {
|
|
|
3077
3226
|
return;
|
|
3078
3227
|
}
|
|
3079
3228
|
|
|
3229
|
+
console.debug('[StudioBridge] applyMarkdownContent: rebuilding Lexical DOM, content length:', content.length, 'rendered match:', markdownLexicalRenderedContent === content, 'current match:', markdownCurrentContent === content);
|
|
3230
|
+
|
|
3080
3231
|
const mdxImportMap = parseMdxImportMap(content);
|
|
3081
3232
|
const parts = extractMarkdownParts(content);
|
|
3082
3233
|
const extracted = extractRawBlocksForEditor(parts.body, mdxImportMap);
|
|
@@ -3706,6 +3857,7 @@ export function generateStudioBridgeScript(options) {
|
|
|
3706
3857
|
markdownOverlaySelections = [];
|
|
3707
3858
|
clearMarkdownSelectionOverlay();
|
|
3708
3859
|
clearMarkdownSelectionSync();
|
|
3860
|
+
disposeMarkdownYjs();
|
|
3709
3861
|
}
|
|
3710
3862
|
|
|
3711
3863
|
const nextUrl = new URL(window.location.href);
|
|
@@ -3936,9 +4088,30 @@ export function generateStudioBridgeScript(options) {
|
|
|
3936
4088
|
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
3937
4089
|
return;
|
|
3938
4090
|
}
|
|
4091
|
+
if (markdownYjsConnected) {
|
|
4092
|
+
return;
|
|
4093
|
+
}
|
|
3939
4094
|
applyMarkdownContent(message.content || '');
|
|
3940
4095
|
return;
|
|
3941
4096
|
|
|
4097
|
+
case 'initYjsConnection':
|
|
4098
|
+
if (!isMarkdownPage()) {
|
|
4099
|
+
return;
|
|
4100
|
+
}
|
|
4101
|
+
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
if (message.initialContent) {
|
|
4105
|
+
applyMarkdownContent(message.initialContent);
|
|
4106
|
+
}
|
|
4107
|
+
setupMarkdownYjsConnection({
|
|
4108
|
+
wsUrl: message.wsUrl,
|
|
4109
|
+
guid: message.guid,
|
|
4110
|
+
fileId: message.fileId || markdownFileId,
|
|
4111
|
+
authToken: message.authToken
|
|
4112
|
+
});
|
|
4113
|
+
return;
|
|
4114
|
+
|
|
3942
4115
|
case 'setMarkdownPersistState':
|
|
3943
4116
|
if (!isMarkdownPage()) {
|
|
3944
4117
|
return;
|
|
@@ -3946,9 +4119,12 @@ export function generateStudioBridgeScript(options) {
|
|
|
3946
4119
|
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
3947
4120
|
return;
|
|
3948
4121
|
}
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
4122
|
+
if (markdownSaveInProgress) {
|
|
4123
|
+
setMarkdownPersistStatus(message.status || 'saved');
|
|
4124
|
+
if (message.status === 'saved' || message.status === 'error') {
|
|
4125
|
+
markdownSaveInProgress = false;
|
|
4126
|
+
markdownHasUnsavedChanges = false;
|
|
4127
|
+
}
|
|
3952
4128
|
}
|
|
3953
4129
|
return;
|
|
3954
4130
|
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -77,6 +77,13 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
77
77
|
let markdownLatestPresenceUsers = [];
|
|
78
78
|
let markdownLatestSelections = [];
|
|
79
79
|
let markdownHasUnsavedChanges = false;
|
|
80
|
+
let markdownSaveInProgress = false;
|
|
81
|
+
let markdownYDoc = null;
|
|
82
|
+
let markdownYProvider = null;
|
|
83
|
+
let markdownYText = null;
|
|
84
|
+
let markdownYjsConnected = false;
|
|
85
|
+
let markdownYjsSetupId = 0;
|
|
86
|
+
const LEXICAL_YJS_ORIGIN = 'lexical-yjs-binding';
|
|
80
87
|
|
|
81
88
|
const MARKDOWN_SLASH_COMMANDS = [
|
|
82
89
|
{
|
|
@@ -1417,6 +1424,142 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
1417
1424
|
}, 120);
|
|
1418
1425
|
}
|
|
1419
1426
|
|
|
1427
|
+
function computeTextDiff(oldText, newText) {
|
|
1428
|
+
var prefixLen = 0;
|
|
1429
|
+
var minLen = Math.min(oldText.length, newText.length);
|
|
1430
|
+
while (prefixLen < minLen && oldText.charCodeAt(prefixLen) === newText.charCodeAt(prefixLen)) {
|
|
1431
|
+
prefixLen++;
|
|
1432
|
+
}
|
|
1433
|
+
var suffixLen = 0;
|
|
1434
|
+
var maxSuffix = minLen - prefixLen;
|
|
1435
|
+
while (suffixLen < maxSuffix &&
|
|
1436
|
+
oldText.charCodeAt(oldText.length - 1 - suffixLen) === newText.charCodeAt(newText.length - 1 - suffixLen)) {
|
|
1437
|
+
suffixLen++;
|
|
1438
|
+
}
|
|
1439
|
+
return {
|
|
1440
|
+
index: prefixLen,
|
|
1441
|
+
deleteCount: oldText.length - prefixLen - suffixLen,
|
|
1442
|
+
insertText: newText.slice(prefixLen, suffixLen > 0 ? newText.length - suffixLen : undefined)
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
function syncLocalChangeToYText(fullContent) {
|
|
1447
|
+
if (!markdownYText || !markdownYDoc) {
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
var currentYContent = markdownYText.toString();
|
|
1451
|
+
if (currentYContent === fullContent) {
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
var diff = computeTextDiff(currentYContent, fullContent);
|
|
1455
|
+
if (diff.deleteCount === 0 && diff.insertText === '') {
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
markdownYDoc.transact(function() {
|
|
1459
|
+
if (diff.deleteCount > 0) {
|
|
1460
|
+
markdownYText.delete(diff.index, diff.deleteCount);
|
|
1461
|
+
}
|
|
1462
|
+
if (diff.insertText) {
|
|
1463
|
+
markdownYText.insert(diff.index, diff.insertText);
|
|
1464
|
+
}
|
|
1465
|
+
}, LEXICAL_YJS_ORIGIN);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
function setupMarkdownYjsConnection(config) {
|
|
1469
|
+
if (markdownYDoc) {
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
var setupId = ++markdownYjsSetupId;
|
|
1474
|
+
|
|
1475
|
+
Promise.all([
|
|
1476
|
+
import('https://esm.sh/yjs@13.6.28?target=es2022'),
|
|
1477
|
+
import('https://esm.sh/y-websocket@2.1.0?target=es2022')
|
|
1478
|
+
]).then(function(modules) {
|
|
1479
|
+
// Abort if edit mode was closed while imports were loading
|
|
1480
|
+
if (setupId !== markdownYjsSetupId) {
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
var Y = modules[0];
|
|
1485
|
+
var WebsocketProvider = modules[1].WebsocketProvider;
|
|
1486
|
+
|
|
1487
|
+
var doc = new Y.Doc({ guid: config.guid });
|
|
1488
|
+
var provider = new WebsocketProvider(config.wsUrl, config.guid, doc, {
|
|
1489
|
+
resyncInterval: -1,
|
|
1490
|
+
params: { token: config.authToken }
|
|
1491
|
+
});
|
|
1492
|
+
|
|
1493
|
+
var ytext = doc.getText(config.fileId);
|
|
1494
|
+
|
|
1495
|
+
markdownYDoc = doc;
|
|
1496
|
+
markdownYProvider = provider;
|
|
1497
|
+
markdownYText = ytext;
|
|
1498
|
+
|
|
1499
|
+
// Filter non-binary messages to prevent y-websocket parse errors
|
|
1500
|
+
provider.on('status', function(event) {
|
|
1501
|
+
console.debug('[StudioBridge] Yjs status:', event.status);
|
|
1502
|
+
if (event.status === 'connected' && provider.ws) {
|
|
1503
|
+
var origOnMessage = provider.ws.onmessage;
|
|
1504
|
+
provider.ws.onmessage = function(wsEvent) {
|
|
1505
|
+
if (typeof wsEvent.data === 'string') {
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
if (origOnMessage) {
|
|
1509
|
+
origOnMessage.call(provider.ws, wsEvent);
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
provider.on('sync', function(synced) {
|
|
1516
|
+
if (synced && !markdownYjsConnected) {
|
|
1517
|
+
markdownYjsConnected = true;
|
|
1518
|
+
|
|
1519
|
+
var ytextContent = ytext.toString();
|
|
1520
|
+
if (markdownCurrentContent && markdownCurrentContent !== ytextContent) {
|
|
1521
|
+
// User typed before sync completed — push local edits to Y.Text
|
|
1522
|
+
syncLocalChangeToYText(markdownCurrentContent);
|
|
1523
|
+
} else if (ytextContent) {
|
|
1524
|
+
// No local edits — seed editor from Y.Text
|
|
1525
|
+
applyMarkdownContent(ytextContent);
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// Observe Y.Text for remote changes (from other users / Monaco)
|
|
1529
|
+
ytext.observe(function(event) {
|
|
1530
|
+
if (event.transaction.origin === LEXICAL_YJS_ORIGIN) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
var fullContent = ytext.toString();
|
|
1534
|
+
if (fullContent === markdownCurrentContent) {
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
applyMarkdownContent(fullContent);
|
|
1538
|
+
});
|
|
1539
|
+
|
|
1540
|
+
console.debug('[StudioBridge] Yjs synced, bound to Y.Text for fileId:', config.fileId);
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
}).catch(function(error) {
|
|
1544
|
+
console.error('[StudioBridge] Failed to setup Yjs connection:', error);
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
function disposeMarkdownYjs() {
|
|
1549
|
+
markdownYjsSetupId++;
|
|
1550
|
+
if (markdownYProvider) {
|
|
1551
|
+
markdownYProvider.disconnect();
|
|
1552
|
+
markdownYProvider.destroy();
|
|
1553
|
+
markdownYProvider = null;
|
|
1554
|
+
}
|
|
1555
|
+
if (markdownYDoc) {
|
|
1556
|
+
markdownYDoc.destroy();
|
|
1557
|
+
markdownYDoc = null;
|
|
1558
|
+
}
|
|
1559
|
+
markdownYText = null;
|
|
1560
|
+
markdownYjsConnected = false;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1420
1563
|
function getTextOffsetWithinRoot(root, targetNode, targetOffset) {
|
|
1421
1564
|
if (!root || !targetNode) {
|
|
1422
1565
|
return 0;
|
|
@@ -2916,7 +3059,11 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
2916
3059
|
}
|
|
2917
3060
|
markdownCurrentContent = fullContent;
|
|
2918
3061
|
markdownHasUnsavedChanges = true;
|
|
2919
|
-
|
|
3062
|
+
if (markdownYjsConnected) {
|
|
3063
|
+
syncLocalChangeToYText(fullContent);
|
|
3064
|
+
} else {
|
|
3065
|
+
scheduleMarkdownSync(fullContent);
|
|
3066
|
+
}
|
|
2920
3067
|
scheduleMarkdownSelectionOverlayRender();
|
|
2921
3068
|
}
|
|
2922
3069
|
|
|
@@ -2924,6 +3071,7 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
2924
3071
|
if (!markdownHasUnsavedChanges) {
|
|
2925
3072
|
return;
|
|
2926
3073
|
}
|
|
3074
|
+
markdownSaveInProgress = true;
|
|
2927
3075
|
setMarkdownPersistStatus('saving');
|
|
2928
3076
|
if (markdownSyncTimer) {
|
|
2929
3077
|
clearTimeout(markdownSyncTimer);
|
|
@@ -3076,7 +3224,8 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
3076
3224
|
return;
|
|
3077
3225
|
}
|
|
3078
3226
|
|
|
3079
|
-
if (markdownLexicalApi && markdownLexicalRenderedContent === content) {
|
|
3227
|
+
if (markdownLexicalApi && (markdownLexicalRenderedContent === content || markdownCurrentContent === content)) {
|
|
3228
|
+
console.debug('[StudioBridge] applyMarkdownContent: skipped (content unchanged)');
|
|
3080
3229
|
markdownCurrentContent = content;
|
|
3081
3230
|
scheduleMarkdownSelectionOverlayRender();
|
|
3082
3231
|
scheduleMarkdownSlashMenuUpdate();
|
|
@@ -3085,6 +3234,8 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
3085
3234
|
return;
|
|
3086
3235
|
}
|
|
3087
3236
|
|
|
3237
|
+
console.debug('[StudioBridge] applyMarkdownContent: rebuilding Lexical DOM, content length:', content.length, 'rendered match:', markdownLexicalRenderedContent === content, 'current match:', markdownCurrentContent === content);
|
|
3238
|
+
|
|
3088
3239
|
const mdxImportMap = parseMdxImportMap(content);
|
|
3089
3240
|
const parts = extractMarkdownParts(content);
|
|
3090
3241
|
const extracted = extractRawBlocksForEditor(parts.body, mdxImportMap);
|
|
@@ -3714,6 +3865,7 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
3714
3865
|
markdownOverlaySelections = [];
|
|
3715
3866
|
clearMarkdownSelectionOverlay();
|
|
3716
3867
|
clearMarkdownSelectionSync();
|
|
3868
|
+
disposeMarkdownYjs();
|
|
3717
3869
|
}
|
|
3718
3870
|
|
|
3719
3871
|
const nextUrl = new URL(window.location.href);
|
|
@@ -3944,9 +4096,30 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
3944
4096
|
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
3945
4097
|
return;
|
|
3946
4098
|
}
|
|
4099
|
+
if (markdownYjsConnected) {
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
3947
4102
|
applyMarkdownContent(message.content || '');
|
|
3948
4103
|
return;
|
|
3949
4104
|
|
|
4105
|
+
case 'initYjsConnection':
|
|
4106
|
+
if (!isMarkdownPage()) {
|
|
4107
|
+
return;
|
|
4108
|
+
}
|
|
4109
|
+
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
4110
|
+
return;
|
|
4111
|
+
}
|
|
4112
|
+
if (message.initialContent) {
|
|
4113
|
+
applyMarkdownContent(message.initialContent);
|
|
4114
|
+
}
|
|
4115
|
+
setupMarkdownYjsConnection({
|
|
4116
|
+
wsUrl: message.wsUrl,
|
|
4117
|
+
guid: message.guid,
|
|
4118
|
+
fileId: message.fileId || markdownFileId,
|
|
4119
|
+
authToken: message.authToken
|
|
4120
|
+
});
|
|
4121
|
+
return;
|
|
4122
|
+
|
|
3950
4123
|
case 'setMarkdownPersistState':
|
|
3951
4124
|
if (!isMarkdownPage()) {
|
|
3952
4125
|
return;
|
|
@@ -3954,9 +4127,12 @@ export function generateStudioBridgeScript(options: StudioBridgeOptions): string
|
|
|
3954
4127
|
if (message.fileId && markdownFileId && message.fileId !== markdownFileId) {
|
|
3955
4128
|
return;
|
|
3956
4129
|
}
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
4130
|
+
if (markdownSaveInProgress) {
|
|
4131
|
+
setMarkdownPersistStatus(message.status || 'saved');
|
|
4132
|
+
if (message.status === 'saved' || message.status === 'error') {
|
|
4133
|
+
markdownSaveInProgress = false;
|
|
4134
|
+
markdownHasUnsavedChanges = false;
|
|
4135
|
+
}
|
|
3960
4136
|
}
|
|
3961
4137
|
return;
|
|
3962
4138
|
|