Skip to content

feat: migrate to components from ChannelActionContext and ChannelState context to dedicated StateStore instances and add layout control API #2909

Open
MartinCupela wants to merge 36 commits intomasterfrom
feat/message-paginator
Open

feat: migrate to components from ChannelActionContext and ChannelState context to dedicated StateStore instances and add layout control API #2909
MartinCupela wants to merge 36 commits intomasterfrom
feat/message-paginator

Conversation

@MartinCupela
Copy link
Contributor

@MartinCupela MartinCupela commented Jan 12, 2026

Depends on

GetStream/stream-chat-js#1674

Summary

This PR is a major architecture migration, not just message pagination.

It moves chat/thread runtime behavior from React-owned channel contexts to instance APIs in stream-chat-js, introduces a slot-based ChatView layout controller, and rewires navigation/state to reactive StateStore-driven sources (messagePaginator, configState, threads.state, etc.).

Scope

  • Introduces a new ChatView layout control API with slot-based entity binding and view-aware state.
  • Replaces ChannelActionContext and ChannelStateContext runtime usage with instance APIs from stream-chat-js.
  • Migrates message/thread interactions to messagePaginator and client instance APIs.
  • Adds React adapters/hooks for slot-resolved channel/thread rendering and navigation.
  • Reworks Channel/Thread request handler wiring to instance configState.requestHandlers.
  • Updates components/stories/tests across the SDK to use the new contracts.

What Changed

1) New ChatView Layout Control API

  • Added LayoutController state model for slot topology, bindings, visibility, and per-slot history.
  • Added ChatViewNavigation API:
    • openView(view, { slot? })
    • openChannel(channel, { slot? })
    • closeChannel({ slot? })
    • openThread(threadOrTarget, { slot? })
    • closeThread({ slot? })
    • hideChannelList({ slot? })
    • unhideChannelList({ slot? })
  • Added slot-oriented primitives:
    • ChannelSlot
    • ThreadSlot
    • ChannelListSlot
    • ThreadListSlot
    • useSlotEntity, useSlotChannel, useSlotThread
  • Added layout state serialization helpers:
    • serializeLayoutState
    • restoreLayoutState
  • Added resolver utilities in layoutSlotResolvers for deterministic slot targeting.

2) Channel/Thread Ownership Moved to stream-chat-js Instances

  • Channel/thread message state now comes from instance-level messagePaginator and thread manager state.
  • Channel and Thread flows are instance-driven and reactive via StateStore.
  • Thread open/close behavior is routed through useChatViewNavigation() (with legacy fallback deactivation in Thread).

3) Context Removal and Replacement

  • Removed runtime/public usage of:
    • ChannelActionContext
    • ChannelStateContext
    • TypingContext provider path from Channel runtime
  • Added ChannelInstanceContext + useChannel() as the channel resolution contract.
  • useChannel() resolves from:
    • active thread context first
    • otherwise ChannelInstanceContext

4) Message Pagination + Unread/Focus Migration

  • Added public hook:
    • useMessagePaginator()
  • Message list/thread operations now use:
    • messagePaginator.jumpToMessage(...)
    • messagePaginator.jumpToTheFirstUnreadMessage(...)
    • messagePaginator.jumpToTheLatestMessage()
    • messagePaginator.toHead()/toTail()
    • messagePaginator.ingestItem(...)
    • messagePaginator.removeItem(...)
    • messagePaginator.unreadStateSnapshot
  • Unread UI controls now use instance APIs and client.messageDeliveryReporter instead of context actions.

5) Request Handler Customization Moved to Instance Config

  • Channel and Thread now register custom request handlers into:
    • channel.configState.requestHandlers
    • thread.configState.requestHandlers
  • Covers custom send/update/delete/markRead paths without ChannelActionContext callbacks.

API Changes and Migration Guide

Navigation: setActiveChannel/context actions -> ChatView navigation

// Before
setActiveChannel(channel);
openThread(message);
closeThread();

// After
const { openChannel, openThread, closeThread } = useChatViewNavigation();
openChannel(channel);
openThread({ channel, message });
closeThread();

### Message list updates: context mutation helpers -> paginator reconciliation

```js
// Before
updateMessage(message);
removeMessage(message);

// After
const paginator = useMessagePaginator();
paginator.ingestItem(message);
paginator.removeItem({ item: message });

Message jump/pagination: context methods -> paginator methods

// Before
jumpToMessage(id);
jumpToFirstUnreadMessage();
loadMore();
loadMoreNewer();

// After
const paginator = useMessagePaginator();
paginator.jumpToMessage(id);
paginator.jumpToTheFirstUnreadMessage();
paginator.toTail();
paginator.toHead();

Channel access: ChannelState/Action context -> useChannel()

// Before
const { channel } = useChannelStateContext();

// After
const channel = useChannel();

Slot-based rendering (new recommended pattern)

<ChatView>
  <ChatView.Channels slots={['list', 'main', 'thread']}>
    <ChannelListSlot slot='list' />
    <ChannelSlot slot='main' />
    <ThreadSlot slot='thread' />
  </ChatView.Channels>
</ChatView>

Behavioral Notes

  • Active entity routing is now layout/slot-driven instead of ChatContext active-channel ownership.
  • Thread/channel can coexist as sibling slot entities.
  • Channel list “open on mount” flows now open via navigation API.
  • Unread and notification behavior is now aligned with instance stores/reporters.

Testing

  • Broad test migration to the new contracts across Channel, Thread, MessageActions, MessageList, ChatView -navigation/layout, and slot hooks/components.
  • Added focused tests for:
  • useChannelRequestHandlers
  • useThreadRequestHandlers
  • ChatViewNavigation
  • layout controller behavior
  • slot resolution helpers

Breaking/Important for Integrators

  • Stop relying on ChannelActionContext and ChannelStateContext APIs.
  • Use useChatViewNavigation() for open/close channel/thread flows.
  • Use useMessagePaginator() + instance APIs for list mutations/jump/pagination.
  • Use slot adapters (ChannelSlot, ThreadSlot, list slots) for deterministic multi-pane ChatView layouts.
  • Prefer instance-scoped request handler overrides (Channel/Thread props wired to configState.requestHandlers).

🎨 UI Changes

No planned UI changes

# Conflicts:
#	src/components/MessageList/MessageList.tsx
#	src/components/MessageList/renderMessages.tsx
…rops) and Header Toggle Wiring for Entity List Pane
… and Remove Entity Semantics from LayoutController (Slot-Only Controller)
…read-on-mount, search-focused jump for Channel and rewrite Channel tests
@MartinCupela MartinCupela marked this pull request as ready for review March 6, 2026 12:25
@MartinCupela MartinCupela changed the title WIP: feat: use LLC message pagination and message list state optimistic updates feat: migrate to components from ChannelActionContext and ChannelState context to dedicated StateStore instances and add layout control API Mar 6, 2026
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