Remote resize doesn't relayout object content — text drifts outside shapes in the other window #78

Open
opened 2026-04-27 11:31:38 +00:00 by AhmedHanafy725 · 3 comments
Member

Bug

When a board is open in two browser windows and one user resizes an object that has internal content (markdown text inside a shape, sticky note text, document content, etc.), the other window receives the new dimensions and applies them to the background shape, but does not re-lay-out the internal content. The text stays at its pre-resize position/wrap-width and visibly drifts outside the new shape bounds.

Reproduction

  1. Open the same board in two windows (A and B).
  2. In window A, place a shape (rectangle) and add a few lines of markdown text to it.
  3. In window A, drag a corner handle to resize the shape (smaller or bigger).
  4. Observe window B: the shape's background changes size correctly, but the text remains at its old wrap width / vertical-centering offset and ends up outside or visibly misaligned inside the new shape.

Reliable repro with: shape (rect/ellipse/diamond/star/etc.) + text. Same root-cause symptom is expected with sticky notes (markdown body), text objects (wrap), document cards (markdown content), and likely frame label, calendar widget, kanban board, mindmap, image, and webframe (their internal children also need to follow the resized bg).

Root cause

crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js -- applySyncUpdate:

  • Lines 442-453 apply bg.width(obj.width) / bg.height(obj.height) (or radius equivalents) to the remote object's background shape.
  • The type-specific branches that follow (sticky 464-478, text 479-491, shape 492-510, document 511-528) only call the relevant WhiteboardObjects.rerenderXxx(node) when the text content has changed (obj.text !== node._mdSource). A dimension-only update therefore never triggers a content relayout.
  • The widget branches (calendar 535-543, kanban 544-553, group 554-562, mindmap 563-567) only call their redraw when their state-data fields change. A pure dimension-only update doesn't redraw them either.
  • image, webframe similarly only sync bg dims, leaving their image/iframe-overlay child sizes (set from the local resize handler in objects.js) out of sync.

Meanwhile, the local resize path in objects.js (the transformend handler around lines 990-1085) updates bg dims and calls the content rerender / widget redraw / image scaling — so the originating window looks correct. Only the remote window drifts.

Affected file

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.jsapplySyncUpdate function, dimension-update path.

Expected behavior

After applySyncUpdate updates the bg dimensions of a remote object, the content should be re-laid-out so the remote view matches what the originating user just saw locally — text wraps to the new width, vertical-centering recomputes against the new height, widgets redraw at the new size, image/iframe children resize to track the new bg.

Fix sketch

In applySyncUpdate, after the bg dimensions are applied (around line 453), detect that dimensions actually changed and dispatch the appropriate relayout per type:

var dimsChanged = bg && obj.width > 0 && obj.height > 0;
// ... existing dimension-update block ...
if (dimsChanged) {
    if (type === 'sticky') WhiteboardObjects.rerenderSticky(node);
    else if (type === 'text') WhiteboardObjects.rerenderText(node);
    else if (type === 'shape') WhiteboardObjects.rerenderShape(node);
    else if (type === 'document') WhiteboardObjects.rerenderDocument(node);
    else if (type === 'calendar' && WhiteboardCalendar && WhiteboardCalendar.redraw) WhiteboardCalendar.redraw(node);
    else if (type === 'kanban' && WhiteboardKanban && WhiteboardKanban.redraw) WhiteboardKanban.redraw(node);
    else if (type === 'mindmap' && WhiteboardMindmap && WhiteboardMindmap.redraw) WhiteboardMindmap.redraw(node);
    else if (type === 'group' && WhiteboardGroups && WhiteboardGroups.redraw) WhiteboardGroups.redraw(node);
    else if (type === 'image') {
        var imgContent = node.findOne('.img-content');
        if (imgContent) { imgContent.width(obj.width); imgContent.height(obj.height); }
    }
    else if (type === 'webframe') {
        // webframe-overlay sizing follows bg via WhiteboardWebframe (overlay re-sync on canvas redraw)
    }
}

Notes:

  • The call to rerenderXxx (which calls WhiteboardSync.onUpdate) is safe because onUpdate early-returns when _applyingSync is true (sync.js:333).
  • Dispatch should be type-driven; avoid double-render if the type-specific branch already called rerender for a text-content change in the same update (a cheap idempotency check via obj.text !== node._mdSource before the new dispatch will avoid the double call).

Acceptance criteria

  • Resizing a shape-with-text in window A correctly relays out the text in window B (centered vertically, wrapped to the new width, contained within the new bounds).
  • Same for sticky, text, document.
  • Calendar/kanban/mindmap/group widgets redraw at the new size in window B when window A resizes them.
  • Image and webframe children (image content, iframe overlay) follow the new bg dimensions in window B.
  • No infinite sync echo (a remote update doesn't trigger a re-broadcast that loops).
  • No regression in same-window behavior (the originating window still looks correct after its own resize).
## Bug When a board is open in two browser windows and one user resizes an object that has internal content (markdown text inside a shape, sticky note text, document content, etc.), the other window receives the new dimensions and applies them to the background shape, but does **not** re-lay-out the internal content. The text stays at its pre-resize position/wrap-width and visibly drifts outside the new shape bounds. ## Reproduction 1. Open the same board in two windows (A and B). 2. In window A, place a shape (rectangle) and add a few lines of markdown text to it. 3. In window A, drag a corner handle to resize the shape (smaller or bigger). 4. Observe window B: the shape's background changes size correctly, but the text remains at its old wrap width / vertical-centering offset and ends up outside or visibly misaligned inside the new shape. Reliable repro with: shape (rect/ellipse/diamond/star/etc.) + text. Same root-cause symptom is expected with sticky notes (markdown body), text objects (wrap), document cards (markdown content), and likely frame label, calendar widget, kanban board, mindmap, image, and webframe (their internal children also need to follow the resized bg). ## Root cause `crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js` -- `applySyncUpdate`: - Lines 442-453 apply `bg.width(obj.width)` / `bg.height(obj.height)` (or radius equivalents) to the remote object's background shape. - The type-specific branches that follow (sticky 464-478, text 479-491, shape 492-510, document 511-528) only call the relevant `WhiteboardObjects.rerenderXxx(node)` when **the text content has changed** (`obj.text !== node._mdSource`). A dimension-only update therefore never triggers a content relayout. - The widget branches (calendar 535-543, kanban 544-553, group 554-562, mindmap 563-567) only call their `redraw` when their state-data fields change. A pure dimension-only update doesn't redraw them either. - `image`, `webframe` similarly only sync bg dims, leaving their image/iframe-overlay child sizes (set from the local resize handler in `objects.js`) out of sync. Meanwhile, the **local** resize path in `objects.js` (the `transformend` handler around lines 990-1085) updates bg dims **and** calls the content rerender / widget redraw / image scaling — so the originating window looks correct. Only the remote window drifts. ## Affected file - `crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js` — `applySyncUpdate` function, dimension-update path. ## Expected behavior After `applySyncUpdate` updates the bg dimensions of a remote object, the content should be re-laid-out so the remote view matches what the originating user just saw locally — text wraps to the new width, vertical-centering recomputes against the new height, widgets redraw at the new size, image/iframe children resize to track the new bg. ## Fix sketch In `applySyncUpdate`, after the bg dimensions are applied (around line 453), detect that dimensions actually changed and dispatch the appropriate relayout per type: ```js var dimsChanged = bg && obj.width > 0 && obj.height > 0; // ... existing dimension-update block ... if (dimsChanged) { if (type === 'sticky') WhiteboardObjects.rerenderSticky(node); else if (type === 'text') WhiteboardObjects.rerenderText(node); else if (type === 'shape') WhiteboardObjects.rerenderShape(node); else if (type === 'document') WhiteboardObjects.rerenderDocument(node); else if (type === 'calendar' && WhiteboardCalendar && WhiteboardCalendar.redraw) WhiteboardCalendar.redraw(node); else if (type === 'kanban' && WhiteboardKanban && WhiteboardKanban.redraw) WhiteboardKanban.redraw(node); else if (type === 'mindmap' && WhiteboardMindmap && WhiteboardMindmap.redraw) WhiteboardMindmap.redraw(node); else if (type === 'group' && WhiteboardGroups && WhiteboardGroups.redraw) WhiteboardGroups.redraw(node); else if (type === 'image') { var imgContent = node.findOne('.img-content'); if (imgContent) { imgContent.width(obj.width); imgContent.height(obj.height); } } else if (type === 'webframe') { // webframe-overlay sizing follows bg via WhiteboardWebframe (overlay re-sync on canvas redraw) } } ``` Notes: - The call to `rerenderXxx` (which calls `WhiteboardSync.onUpdate`) is safe because `onUpdate` early-returns when `_applyingSync` is true (`sync.js:333`). - Dispatch should be type-driven; avoid double-render if the type-specific branch already called rerender for a text-content change in the same update (a cheap idempotency check via `obj.text !== node._mdSource` before the new dispatch will avoid the double call). ## Acceptance criteria - [ ] Resizing a shape-with-text in window A correctly relays out the text in window B (centered vertically, wrapped to the new width, contained within the new bounds). - [ ] Same for sticky, text, document. - [ ] Calendar/kanban/mindmap/group widgets redraw at the new size in window B when window A resizes them. - [ ] Image and webframe children (image content, iframe overlay) follow the new bg dimensions in window B. - [ ] No infinite sync echo (a remote update doesn't trigger a re-broadcast that loops). - [ ] No regression in same-window behavior (the originating window still looks correct after its own resize).
Author
Member

Implementation Spec for Issue #78

Objective

When applySyncUpdate in sync.js applies dimension changes from a remote user's resize, also relayout the receiving object's internal content so the remote view matches the originating one — text wraps to the new width and centers vertically against the new height, widgets redraw at the new size, and image/iframe children follow the new bg.

Requirements

  • Detect that bg dimensions actually changed (vs. an update with only style/data changes).
  • For text-bearing types (sticky, text, shape, document) call the matching WhiteboardObjects.rerenderXxx(node) to re-lay-out the markdown content.
  • For widget types (calendar, kanban, mindmap, group) call the matching WhiteboardXxx.redraw(node) so the widget redraws at the new size.
  • For image, resize the .img-content child to track the new bg.
  • For webframe, resize .header, .placeholder, .label children — same as the local resize handler does in objects.js:1082-1099.
  • Frame is skipped (its label is at fixed offset (8, -20) and doesn't depend on bg dims — see objects.js:808-815).
  • Avoid double rerender when the type-specific branch already re-rendered for a text-content change in the same update.
  • No infinite sync echo (the call chain rerenderXxx -> WhiteboardSync.onUpdate already early-returns under _applyingSyncsync.js:333).
  • No regression in same-window behavior.

Files to Modify

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.jsapplySyncUpdate function (around lines 414-609).

No other file needs changes. The local transformend handler in objects.js already does the equivalent relayout for the originating user.

Implementation Plan

Step 1: Track dimension change and relayout content after type-specific update block

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js

  1. In applySyncUpdate, before the bg-dimension update at line 442, record whether dimensions are changing. Capture the old bg size and compare to the incoming obj.width/obj.height (only if both are positive, matching the existing guard). Use a small tolerance (e.g. < 0.5 px) to treat sub-pixel jitter as no-change:
    var oldW = 0, oldH = 0;
    if (bg) {
        if (bg.getClassName() === 'Ellipse') {
            oldW = (bg.radiusX() || 0) * 2;
            oldH = (bg.radiusY() || 0) * 2;
        } else if (typeof bg.radius === 'function' && !bg.width) {
            oldW = (bg.radius() || 0) * 2;
            oldH = oldW;
        } else {
            oldW = bg.width ? bg.width() : 0;
            oldH = bg.height ? bg.height() : 0;
        }
    }
    
  2. After the existing dimension-update block (line 453) compute dimsChanged:
    var dimsChanged = bg && obj.width > 0 && obj.height > 0 &&
        (Math.abs((obj.width || 0) - oldW) > 0.5 || Math.abs((obj.height || 0) - oldH) > 0.5);
    
  3. After the type-specific block ends (just before the requestAnimationFrame at line 599), add a second small dispatch that relays out content when dimsChanged is true:
    if (dimsChanged) {
        var textChanged = obj.text != null && obj.text !== node._mdSource;
        // The text-bearing branches above already call rerenderXxx when textChanged.
        // Don't double-rerender.
        if (type === 'sticky' && !textChanged) WhiteboardObjects.rerenderSticky(node);
        else if (type === 'text' && !textChanged) WhiteboardObjects.rerenderText(node);
        else if (type === 'shape' && !textChanged) WhiteboardObjects.rerenderShape(node);
        else if (type === 'document' && !textChanged) WhiteboardObjects.rerenderDocument(node);
        else if (type === 'calendar' && WhiteboardCalendar && WhiteboardCalendar.redraw) WhiteboardCalendar.redraw(node);
        else if (type === 'kanban' && typeof WhiteboardKanban !== 'undefined' && WhiteboardKanban.redraw) WhiteboardKanban.redraw(node);
        else if (type === 'mindmap' && typeof WhiteboardMindmap !== 'undefined' && WhiteboardMindmap.redraw) WhiteboardMindmap.redraw(node);
        else if (type === 'group' && typeof WhiteboardGroups !== 'undefined' && WhiteboardGroups.redraw) WhiteboardGroups.redraw(node);
        else if (type === 'image') {
            var imgContent = node.findOne('.img-content');
            if (imgContent) { imgContent.width(obj.width); imgContent.height(obj.height); }
        } else if (type === 'webframe') {
            var header = node.findOne('.header');
            var headerH = header ? header.height() : 32;
            if (header) header.width(obj.width);
            var placeholder = node.findOne('.placeholder');
            if (placeholder) {
                placeholder.width(obj.width);
                placeholder.height(Math.max(0, obj.height - headerH));
            }
            var wfLabel = node.findOne('.label');
            if (wfLabel) wfLabel.width(Math.max(0, obj.width - 20));
        }
    }
    
  4. The rerender/redraw functions internally call WhiteboardSync.onUpdate(node), which is a no-op when _applyingSync is true (the surrounding try already sets it). No echo risk.

Dependencies: none.

Acceptance Criteria

  • Window B's text inside a shape re-wraps and re-centers when window A resizes the shape.
  • Same for sticky, text, document.
  • Calendar / kanban / mindmap / group redraw at the new size in window B when window A resizes them.
  • Image's .img-content follows the new bg in window B.
  • Webframe's .header, .placeholder, .label follow the new bg in window B.
  • Frame is unaffected (label position is independent of bg).
  • No infinite sync loop (checked by leaving two windows open and resizing back-and-forth).
  • Same-window resize behavior is unchanged.
  • No JS console errors.

Notes

  • The dimsChanged detection compares old bg size against obj.width/obj.height so we don't relayout on every metadata-only sync.
  • For the text-bearing branches, the existing code already calls rerender when text changed; the new dispatch avoids double-render via the textChanged short-circuit so we don't pay the cost twice.
  • Webframe's actual HTML iframe overlay is positioned by WhiteboardWebframe based on Konva node coordinates and re-syncs on the canvas redraw scheduled at the bottom of applySyncUpdate. The new code only resizes the Konva placeholder/header/label children that are visible during drag and used as the stand-in.
  • This is a JS-static-asset-only fix. No Rust/SDK/openrpc/db changes.
## Implementation Spec for Issue #78 ### Objective When `applySyncUpdate` in `sync.js` applies dimension changes from a remote user's resize, also relayout the receiving object's internal content so the remote view matches the originating one — text wraps to the new width and centers vertically against the new height, widgets redraw at the new size, and image/iframe children follow the new bg. ### Requirements - Detect that bg dimensions actually changed (vs. an update with only style/data changes). - For text-bearing types (sticky, text, shape, document) call the matching `WhiteboardObjects.rerenderXxx(node)` to re-lay-out the markdown content. - For widget types (calendar, kanban, mindmap, group) call the matching `WhiteboardXxx.redraw(node)` so the widget redraws at the new size. - For image, resize the `.img-content` child to track the new bg. - For webframe, resize `.header`, `.placeholder`, `.label` children — same as the local resize handler does in `objects.js:1082-1099`. - Frame is skipped (its label is at fixed offset `(8, -20)` and doesn't depend on bg dims — see `objects.js:808-815`). - Avoid double rerender when the type-specific branch already re-rendered for a text-content change in the same update. - No infinite sync echo (the call chain `rerenderXxx -> WhiteboardSync.onUpdate` already early-returns under `_applyingSync` — `sync.js:333`). - No regression in same-window behavior. ### Files to Modify - `crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js` — `applySyncUpdate` function (around lines 414-609). No other file needs changes. The local `transformend` handler in `objects.js` already does the equivalent relayout for the originating user. ### Implementation Plan #### Step 1: Track dimension change and relayout content after type-specific update block Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js` 1. In `applySyncUpdate`, *before* the bg-dimension update at line 442, record whether dimensions are changing. Capture the old bg size and compare to the incoming `obj.width`/`obj.height` (only if both are positive, matching the existing guard). Use a small tolerance (e.g. < 0.5 px) to treat sub-pixel jitter as no-change: ```js var oldW = 0, oldH = 0; if (bg) { if (bg.getClassName() === 'Ellipse') { oldW = (bg.radiusX() || 0) * 2; oldH = (bg.radiusY() || 0) * 2; } else if (typeof bg.radius === 'function' && !bg.width) { oldW = (bg.radius() || 0) * 2; oldH = oldW; } else { oldW = bg.width ? bg.width() : 0; oldH = bg.height ? bg.height() : 0; } } ``` 2. After the existing dimension-update block (line 453) compute `dimsChanged`: ```js var dimsChanged = bg && obj.width > 0 && obj.height > 0 && (Math.abs((obj.width || 0) - oldW) > 0.5 || Math.abs((obj.height || 0) - oldH) > 0.5); ``` 3. After the type-specific block ends (just before the `requestAnimationFrame` at line 599), add a second small dispatch that relays out content when `dimsChanged` is true: ```js if (dimsChanged) { var textChanged = obj.text != null && obj.text !== node._mdSource; // The text-bearing branches above already call rerenderXxx when textChanged. // Don't double-rerender. if (type === 'sticky' && !textChanged) WhiteboardObjects.rerenderSticky(node); else if (type === 'text' && !textChanged) WhiteboardObjects.rerenderText(node); else if (type === 'shape' && !textChanged) WhiteboardObjects.rerenderShape(node); else if (type === 'document' && !textChanged) WhiteboardObjects.rerenderDocument(node); else if (type === 'calendar' && WhiteboardCalendar && WhiteboardCalendar.redraw) WhiteboardCalendar.redraw(node); else if (type === 'kanban' && typeof WhiteboardKanban !== 'undefined' && WhiteboardKanban.redraw) WhiteboardKanban.redraw(node); else if (type === 'mindmap' && typeof WhiteboardMindmap !== 'undefined' && WhiteboardMindmap.redraw) WhiteboardMindmap.redraw(node); else if (type === 'group' && typeof WhiteboardGroups !== 'undefined' && WhiteboardGroups.redraw) WhiteboardGroups.redraw(node); else if (type === 'image') { var imgContent = node.findOne('.img-content'); if (imgContent) { imgContent.width(obj.width); imgContent.height(obj.height); } } else if (type === 'webframe') { var header = node.findOne('.header'); var headerH = header ? header.height() : 32; if (header) header.width(obj.width); var placeholder = node.findOne('.placeholder'); if (placeholder) { placeholder.width(obj.width); placeholder.height(Math.max(0, obj.height - headerH)); } var wfLabel = node.findOne('.label'); if (wfLabel) wfLabel.width(Math.max(0, obj.width - 20)); } } ``` 4. The rerender/redraw functions internally call `WhiteboardSync.onUpdate(node)`, which is a no-op when `_applyingSync` is true (the surrounding `try` already sets it). No echo risk. Dependencies: none. ### Acceptance Criteria - [ ] Window B's text inside a shape re-wraps and re-centers when window A resizes the shape. - [ ] Same for sticky, text, document. - [ ] Calendar / kanban / mindmap / group redraw at the new size in window B when window A resizes them. - [ ] Image's `.img-content` follows the new bg in window B. - [ ] Webframe's `.header`, `.placeholder`, `.label` follow the new bg in window B. - [ ] Frame is unaffected (label position is independent of bg). - [ ] No infinite sync loop (checked by leaving two windows open and resizing back-and-forth). - [ ] Same-window resize behavior is unchanged. - [ ] No JS console errors. ### Notes - The `dimsChanged` detection compares old bg size against `obj.width`/`obj.height` so we don't relayout on every metadata-only sync. - For the text-bearing branches, the existing code already calls rerender when text changed; the new dispatch avoids double-render via the `textChanged` short-circuit so we don't pay the cost twice. - Webframe's actual HTML iframe overlay is positioned by `WhiteboardWebframe` based on Konva node coordinates and re-syncs on the canvas redraw scheduled at the bottom of `applySyncUpdate`. The new code only resizes the Konva placeholder/header/label children that are visible during drag and used as the stand-in. - This is a JS-static-asset-only fix. No Rust/SDK/openrpc/db changes.
Author
Member

Test Results

  • cargo test --workspace --lib: 4 lib targets, 0 tests / 0 passed / 0 failed each (no Rust unit tests for these crates).
  • cargo clippy --workspace -- -D warnings: clean.
  • node --check sync.js: parses cleanly.

This is a JS-static-asset-only change. Manual verification recommended: open the same board in two browser windows, place a shape with markdown text in window A, drag-resize it, and confirm the text in window B re-wraps and re-centers. Repeat with sticky, text, document, calendar, kanban, mindmap, image, webframe.

## Test Results - `cargo test --workspace --lib`: 4 lib targets, 0 tests / 0 passed / 0 failed each (no Rust unit tests for these crates). - `cargo clippy --workspace -- -D warnings`: clean. - `node --check sync.js`: parses cleanly. This is a JS-static-asset-only change. Manual verification recommended: open the same board in two browser windows, place a shape with markdown text in window A, drag-resize it, and confirm the text in window B re-wraps and re-centers. Repeat with sticky, text, document, calendar, kanban, mindmap, image, webframe.
Author
Member

Implementation Summary

Changes

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js (+52 / -1)
    • In applySyncUpdate, snapshot the bg's previous size (handling Ellipse / radius-only / width-height shapes) before applying the incoming obj.width / obj.height.
    • Compute a dimsChanged flag using a 0.5 px tolerance to ignore sub-pixel jitter.
    • After the type-specific update block, if dims changed, dispatch the appropriate relayout:
      • sticky / text / shape / document -> WhiteboardObjects.rerenderXxx(node) (skipped when text content also changed in the same update, to avoid double render).
      • calendar / kanban / mindmap / group -> WhiteboardXxx.redraw(node).
      • image -> resize the .img-content child.
      • webframe -> resize .header, .placeholder, .label children (mirrors the local transformend handler in objects.js:1082-1099).
    • Frame is intentionally skipped (its label is at fixed (8, -20) and doesn't depend on bg dims).

Why no echo loop

rerenderXxx calls WhiteboardSync.onUpdate(node), but onUpdate early-returns when _applyingSync is true (sync.js:333). The whole applySyncUpdate body runs inside _applyingSync = true, so no remote-triggered relayout re-broadcasts.

Verification

  • cargo test --workspace --lib: 4 lib targets pass, 0 tests.
  • cargo clippy --workspace -- -D warnings: clean.
  • node --check sync.js: parses cleanly.

Notes / caveats

  • JS-static-asset-only fix; no Rust / SDK / openrpc / DB changes.
  • The dimsChanged detection compares the current bg size to the incoming dims, so style/data-only sync updates do NOT trigger a relayout (no perf regression).
  • Manual visual check recommended: open two browser windows on the same board, place a shape with markdown text, resize it in window A, and confirm the text in window B re-wraps and re-centers correctly. Repeat for sticky, text, document, calendar, kanban, mindmap, image, webframe.
## Implementation Summary ### Changes - `crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js` (+52 / -1) - In `applySyncUpdate`, snapshot the bg's previous size (handling Ellipse / radius-only / width-height shapes) before applying the incoming `obj.width` / `obj.height`. - Compute a `dimsChanged` flag using a 0.5 px tolerance to ignore sub-pixel jitter. - After the type-specific update block, if dims changed, dispatch the appropriate relayout: - sticky / text / shape / document -> `WhiteboardObjects.rerenderXxx(node)` (skipped when text content also changed in the same update, to avoid double render). - calendar / kanban / mindmap / group -> `WhiteboardXxx.redraw(node)`. - image -> resize the `.img-content` child. - webframe -> resize `.header`, `.placeholder`, `.label` children (mirrors the local `transformend` handler in `objects.js:1082-1099`). - Frame is intentionally skipped (its label is at fixed `(8, -20)` and doesn't depend on bg dims). ### Why no echo loop `rerenderXxx` calls `WhiteboardSync.onUpdate(node)`, but `onUpdate` early-returns when `_applyingSync` is true (`sync.js:333`). The whole `applySyncUpdate` body runs inside `_applyingSync = true`, so no remote-triggered relayout re-broadcasts. ### Verification - `cargo test --workspace --lib`: 4 lib targets pass, 0 tests. - `cargo clippy --workspace -- -D warnings`: clean. - `node --check sync.js`: parses cleanly. ### Notes / caveats - JS-static-asset-only fix; no Rust / SDK / openrpc / DB changes. - The `dimsChanged` detection compares the current bg size to the incoming dims, so style/data-only sync updates do NOT trigger a relayout (no perf regression). - Manual visual check recommended: open two browser windows on the same board, place a shape with markdown text, resize it in window A, and confirm the text in window B re-wraps and re-centers correctly. Repeat for sticky, text, document, calendar, kanban, mindmap, image, webframe.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#78
No description provided.