Skip to content

fix(navigation): hold a neutral surface during the tab-switch activation gap#771

Merged
mremond merged 1 commit into
mainfrom
claude/dreamy-northcutt-8bc0b8
Jun 30, 2026
Merged

fix(navigation): hold a neutral surface during the tab-switch activation gap#771
mremond merged 1 commit into
mainfrom
claude/dreamy-northcutt-8bc0b8

Conversation

@mremond

@mremond mremond commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

Switching content tabs (Messages / Rooms / Archive) via the rail icons briefly flashed the empty-state hero before the conversation or room rendered.

navigateToView() synchronously flips sidebarView and clears the opposite store, then fires the hydrating activateConversation / activateRoom action. Those await an IndexedDB cache read before setting the active id — by design, so the view never renders with an empty message list and the unread-divider is computed against loaded messages. That await is a real macrotask, so React commits and paints the in-between frame where both activeConversationId and activeRoomJid are null while sidebarView is already a content view, and the render cascade falls through to the EmptyState hero. The lazy tabs (Settings / Admin / Search) never showed this because they sit behind a Suspense skeleton; the content tabs had nothing covering the gap.

This adds a token-correct activationPending flag to chatStore and roomStore — set synchronously before the cache-read await and cleared atomically when the active id lands (the existing monotonic activation token means a superseded activation leaves the flag for the winner to clear). ChatLayout renders the existing ViewLoadingFallback skeleton instead of the EmptyState hero while it is true, so content-tab switches now match the lazy tabs and the hero no longer pops in and out.

activationPending is also a useful signal for any client built on the SDK, which hits the same flash.

…ion gap

Switching content tabs (messages/rooms/archive) via the rail icons briefly flashed the empty-state hero. navigateToView() flips sidebarView and clears the opposite store synchronously, then fires the hydrating activate* action, which awaits an IndexedDB cache read before setting the active id. During that painted gap both active ids are null, so the render cascade fell through to the EmptyState hero.

Expose a token-correct activationPending flag on chatStore/roomStore (set before the cache-read await, cleared atomically when the active id lands) and render the existing ViewLoadingFallback skeleton instead of the hero while it is true, matching the lazy views and removing the flash.
@mremond mremond added this to the 0.17.0 milestone Jun 30, 2026
@mremond mremond merged commit d05ae09 into main Jun 30, 2026
3 checks passed
@mremond mremond deleted the claude/dreamy-northcutt-8bc0b8 branch June 30, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant