canvu-react 0.4.8 → 0.4.10
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/realtime.cjs +105 -9
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.js +105 -9
- package/dist/realtime.js.map +1 -1
- package/package.json +1 -1
package/dist/realtime.js
CHANGED
|
@@ -2373,6 +2373,30 @@ function prepareRealtimeItems(items) {
|
|
|
2373
2373
|
return null;
|
|
2374
2374
|
}
|
|
2375
2375
|
}
|
|
2376
|
+
function getRealtimeItemId(item) {
|
|
2377
|
+
const id = item.id;
|
|
2378
|
+
return typeof id === "string" ? id : null;
|
|
2379
|
+
}
|
|
2380
|
+
function serializeRealtimeItem(item) {
|
|
2381
|
+
try {
|
|
2382
|
+
return JSON.stringify(sanitizeRealtimeItem(item));
|
|
2383
|
+
} catch {
|
|
2384
|
+
return null;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
function resolvePendingDraftItemIds(board, items) {
|
|
2388
|
+
const pendingIds = /* @__PURE__ */ new Set();
|
|
2389
|
+
for (const item of items) {
|
|
2390
|
+
const id = getRealtimeItemId(item);
|
|
2391
|
+
if (!id) continue;
|
|
2392
|
+
const confirmedSerialized = board.lastServerConfirmedItemSerializations.get(id);
|
|
2393
|
+
const serialized = serializeRealtimeItem(item);
|
|
2394
|
+
if (!confirmedSerialized || !serialized || serialized !== confirmedSerialized) {
|
|
2395
|
+
pendingIds.add(id);
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return pendingIds.size > 0 ? Array.from(pendingIds) : void 0;
|
|
2399
|
+
}
|
|
2376
2400
|
function useRealtimeSession(options) {
|
|
2377
2401
|
const {
|
|
2378
2402
|
url,
|
|
@@ -2563,7 +2587,8 @@ function useRealtimeSession(options) {
|
|
|
2563
2587
|
}
|
|
2564
2588
|
const board = boardRef.current;
|
|
2565
2589
|
const draft = localDraftRef.current;
|
|
2566
|
-
const
|
|
2590
|
+
const canEncodeYDocState = board && draft.yDocState == null && sameSerializedItems(readVectorItems(board.yItems), draft.items);
|
|
2591
|
+
const draftToWrite = canEncodeYDocState ? { ...draft, yDocState: encodeYDocState(board) } : draft;
|
|
2567
2592
|
writeRealtimeOfflineDraft(draftToWrite);
|
|
2568
2593
|
}, [clearDraftPersistSchedule, roomId]);
|
|
2569
2594
|
const scheduleDraftPersistence = useCallback(() => {
|
|
@@ -2703,13 +2728,26 @@ function useRealtimeSession(options) {
|
|
|
2703
2728
|
}, DOCUMENT_FLUSH_DEBOUNCE_MS);
|
|
2704
2729
|
}, DOCUMENT_FLUSH_DEBOUNCE_MS);
|
|
2705
2730
|
}, [clearDocumentFlushSchedule, flushQueuedDocument]);
|
|
2706
|
-
const queueDocumentSend = useCallback(
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2731
|
+
const queueDocumentSend = useCallback(
|
|
2732
|
+
(items) => {
|
|
2733
|
+
pendingLocalItemsRef.current = items;
|
|
2734
|
+
queuedDirtyRef.current = true;
|
|
2735
|
+
setHasPendingDocumentSync(true);
|
|
2736
|
+
setHasLocalOfflineDraft(true);
|
|
2737
|
+
const board = boardRef.current;
|
|
2738
|
+
const draftItems = sanitizeRealtimeItems(items);
|
|
2739
|
+
setLocalDraftRef.current({
|
|
2740
|
+
roomId,
|
|
2741
|
+
baseRevision: currentRevisionRef.current,
|
|
2742
|
+
items: draftItems,
|
|
2743
|
+
updatedAt: nowMs(),
|
|
2744
|
+
pendingIds: board ? resolvePendingDraftItemIds(board, draftItems) : void 0
|
|
2745
|
+
});
|
|
2746
|
+
scheduleDraftPersistenceRef.current?.();
|
|
2747
|
+
scheduleDocumentFlushRef.current();
|
|
2748
|
+
},
|
|
2749
|
+
[roomId]
|
|
2750
|
+
);
|
|
2713
2751
|
const applyDraftSnapshot = useCallback(
|
|
2714
2752
|
(draft, options2) => {
|
|
2715
2753
|
const board = boardRef.current;
|
|
@@ -2873,6 +2911,25 @@ function useRealtimeSession(options) {
|
|
|
2873
2911
|
setLocalDraftRef.current = setLocalDraft;
|
|
2874
2912
|
const scheduleDraftPersistenceRef = useRef(scheduleDraftPersistence);
|
|
2875
2913
|
scheduleDraftPersistenceRef.current = scheduleDraftPersistence;
|
|
2914
|
+
const persistLocalDraftRef = useRef(persistLocalDraft);
|
|
2915
|
+
persistLocalDraftRef.current = persistLocalDraft;
|
|
2916
|
+
useEffect(() => {
|
|
2917
|
+
const persistDraft = () => {
|
|
2918
|
+
persistLocalDraftRef.current();
|
|
2919
|
+
};
|
|
2920
|
+
const handleVisibilityChange = () => {
|
|
2921
|
+
if (window.document.visibilityState === "hidden") persistDraft();
|
|
2922
|
+
};
|
|
2923
|
+
window.addEventListener("pagehide", persistDraft);
|
|
2924
|
+
window.document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2925
|
+
return () => {
|
|
2926
|
+
window.removeEventListener("pagehide", persistDraft);
|
|
2927
|
+
window.document.removeEventListener(
|
|
2928
|
+
"visibilitychange",
|
|
2929
|
+
handleVisibilityChange
|
|
2930
|
+
);
|
|
2931
|
+
};
|
|
2932
|
+
}, []);
|
|
2876
2933
|
useEffect(() => {
|
|
2877
2934
|
if (boardRef.current) {
|
|
2878
2935
|
boardRef.current.doc.destroy();
|
|
@@ -3506,6 +3563,22 @@ function realtimeSessionPlugin(options) {
|
|
|
3506
3563
|
render: () => /* @__PURE__ */ jsx(RealtimeSessionPanel, { ...options })
|
|
3507
3564
|
};
|
|
3508
3565
|
}
|
|
3566
|
+
function getSceneItemId(item) {
|
|
3567
|
+
const id = item.id;
|
|
3568
|
+
return typeof id === "string" ? id : null;
|
|
3569
|
+
}
|
|
3570
|
+
function hasMissingLocalItems(localItems, incomingItems) {
|
|
3571
|
+
const incomingIds = /* @__PURE__ */ new Set();
|
|
3572
|
+
for (const item of incomingItems) {
|
|
3573
|
+
const id = getSceneItemId(item);
|
|
3574
|
+
if (id) incomingIds.add(id);
|
|
3575
|
+
}
|
|
3576
|
+
for (const item of localItems) {
|
|
3577
|
+
const id = getSceneItemId(item);
|
|
3578
|
+
if (id && !incomingIds.has(id)) return true;
|
|
3579
|
+
}
|
|
3580
|
+
return false;
|
|
3581
|
+
}
|
|
3509
3582
|
function useRealtimeCanvasDocument(options) {
|
|
3510
3583
|
const {
|
|
3511
3584
|
session,
|
|
@@ -3524,6 +3597,8 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3524
3597
|
const documentItems = session?.document?.items;
|
|
3525
3598
|
const documentUpdatedByClientId = session?.document?.updatedByClientId ?? null;
|
|
3526
3599
|
const connectionClientId = session?.connection.clientId ?? null;
|
|
3600
|
+
const hasLocalOfflineDraft = session?.hasLocalOfflineDraft ?? false;
|
|
3601
|
+
const hasPendingDocumentSync = session?.hasPendingDocumentSync ?? false;
|
|
3527
3602
|
const applyIncomingItems = useCallback(
|
|
3528
3603
|
async (nextItems) => {
|
|
3529
3604
|
const normalizedItems = normalizeItems ? normalizeItems(nextItems) : [...nextItems];
|
|
@@ -3544,6 +3619,11 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3544
3619
|
},
|
|
3545
3620
|
[enabled, normalizeItems, onItemsChange, session]
|
|
3546
3621
|
);
|
|
3622
|
+
useEffect(() => {
|
|
3623
|
+
if (items.length > 0) {
|
|
3624
|
+
hasEverPropagatedItemsRef.current = true;
|
|
3625
|
+
}
|
|
3626
|
+
}, [items.length]);
|
|
3547
3627
|
useEffect(() => {
|
|
3548
3628
|
if (!realtimeEnabled || !onItemsChange || !session?.document) return;
|
|
3549
3629
|
if (documentUpdatedByClientId === connectionClientId) return;
|
|
@@ -3557,7 +3637,18 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3557
3637
|
if (cancelled) return;
|
|
3558
3638
|
if (inFlightRevisionRef.current !== documentRevision) return;
|
|
3559
3639
|
lastAppliedRevisionRef.current = documentRevision;
|
|
3560
|
-
|
|
3640
|
+
const hasLocalItems = items.length > 0;
|
|
3641
|
+
const hasPendingLocalChanges = hasLocalOfflineDraft || hasPendingDocumentSync;
|
|
3642
|
+
if (resolvedItems.length === 0 && (hasEverPropagatedItemsRef.current || hasLocalItems || hasPendingLocalChanges)) {
|
|
3643
|
+
if (hasLocalItems) {
|
|
3644
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(items) : [...items];
|
|
3645
|
+
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3646
|
+
}
|
|
3647
|
+
return;
|
|
3648
|
+
}
|
|
3649
|
+
if (hasPendingLocalChanges && hasLocalItems && hasMissingLocalItems(items, resolvedItems)) {
|
|
3650
|
+
const normalizedLocalItems = normalizeItems ? normalizeItems(items) : [...items];
|
|
3651
|
+
session.remoteAdapter.send?.(normalizedLocalItems);
|
|
3561
3652
|
return;
|
|
3562
3653
|
}
|
|
3563
3654
|
if (resolvedItems.length > 0) {
|
|
@@ -3580,8 +3671,13 @@ function useRealtimeCanvasDocument(options) {
|
|
|
3580
3671
|
documentItems,
|
|
3581
3672
|
documentRevision,
|
|
3582
3673
|
documentUpdatedByClientId,
|
|
3674
|
+
hasLocalOfflineDraft,
|
|
3675
|
+
hasPendingDocumentSync,
|
|
3676
|
+
items,
|
|
3677
|
+
normalizeItems,
|
|
3583
3678
|
onItemsChange,
|
|
3584
3679
|
realtimeEnabled,
|
|
3680
|
+
session?.remoteAdapter,
|
|
3585
3681
|
session?.document
|
|
3586
3682
|
]);
|
|
3587
3683
|
return useMemo(
|