feat(refboard): incremental sync — stop full-scene broadcast on edits

Replace broadcastSceneNow() with incremental element:update for all
property-modifying operations (align, arrange, flip, resize, rotate,
normalize, frame color). Full scene sync now only fires via debounced
fallback (500ms) for structural changes (add/remove/paste/group).

Changes:
- onCanvasChange() accepts optional changedIds for incremental sync
- SelectionToolbar, context menu, shortcuts all pass item IDs
- TransformBox.onDragEnd passes item IDs instead of full scene
- ShortcutContext, MenuContext, hook interfaces updated

This dramatically reduces sync traffic during normal editing — only
the changed elements are sent instead of the entire board state.
This commit is contained in:
Hiren Kangad
2026-03-10 10:59:04 +05:30
parent 86024464c2
commit 21ee4b2601
8 changed files with 57 additions and 51 deletions
+4 -4
View File
@@ -40,7 +40,7 @@ interface CanvasSetupDeps {
undoRef: React.MutableRefObject<UndoManager | null>;
syncRef: React.MutableRefObject<SyncHandle | null>;
inboxZoneRef: React.MutableRefObject<InboxZone | null>;
onCanvasChange: () => void;
onCanvasChange: (changedIds?: string[]) => void;
showToast: (msg: string) => void;
setOnlineUsers: React.Dispatch<React.SetStateAction<OnlineUser[]>>;
setSelectedLayerIds: React.Dispatch<React.SetStateAction<string[]>>;
@@ -136,9 +136,9 @@ export function useCanvasSetup(deps: CanvasSetupDeps) {
selection.transformBox.onItemTransform = (item) => {
syncRef.current?.broadcastTransform(item);
};
selection.transformBox.onDragEnd = () => {
syncRef.current?.broadcastSceneNow();
onCanvasChange();
selection.transformBox.onDragEnd = (itemIds) => {
syncRef.current?.broadcastElements(itemIds);
onCanvasChange(itemIds);
};
socket.on('user:joined', (data: any) => {
+1 -1
View File
@@ -17,7 +17,7 @@ interface LayerItem {
interface LayerPanelDeps {
canvasRef: React.RefObject<PixiCanvasHandle | null>;
selectionRef: React.RefObject<SelectionManager | null>;
onCanvasChange: () => void;
onCanvasChange: (changedIds?: string[]) => void;
}
function autoName(item: SceneItem, i: number, counters: Record<string, number>): string {
+1 -1
View File
@@ -18,7 +18,7 @@ interface ShortcutHandlerDeps {
undoRef: React.RefObject<UndoManager | null>;
clipboardRef: React.MutableRefObject<SceneItem[]>;
resolvedBoardId: string | undefined;
onCanvasChange: () => void;
onCanvasChange: (changedIds?: string[]) => void;
showToast: (msg: string) => void;
refreshLayers: () => void;
handleGroup: () => void;