-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add ThreadList and ThreadProvider (Threads 2.0) (#2407)
π GetStream/stream-chat-js#1330 This PR adds components for implementing a thread list view: ThreadList and ChatView. It also adds support for reactive state stores, like the ones that handle the thread list logic in the client. Implements a binding from the reactive state store in the client to React components. Implements a thread list. The component itself consists mostly of binding to the `ThreadManager` instance in the client. The Thread component was modified to optionally use a reactive `Thread` instance from the `ThreadContext`. The component checks if `ThreadContext` is provided, and if so uses the thread instance from that context. Otherwise, it falls back to the `ChannelContext` as usual. Currently, we use `ThreadContext` in the thread list view, where it is provided by the `ChatView.ThreadAdapter` component. Note that even when `ThreadContext` is used, `ChannelContext` also must be provided. Most our components, including the ones used in threads, still expect the channel context to be there. A set of components implementing a simple in-memory router to switch between channel view and thread list view. Using it is totally optional. Most integrations will probably use their own router instead. Still, nice to have something out-of-the-box. A new way to provide component overrides. Previously we allowed passing component overrides as props to `Channel` component, and then in some nested components as well, although not consistently. `WithComponents` is a new recommended way to provide component overrides, which requires far less prop drilling and nests nicely. BREAKING CHANGE: ComponentContext no longer provides any defaults --------- Co-authored-by: Matvei Andrienko <[email protected]>
- Loading branch information
1 parent
a39ceda
commit 941707d
Showing
61 changed files
with
3,161 additions
and
279 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
docusaurus/docs/React/components/contexts/thread-context.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
id: thread-context | ||
title: ThreadContext | ||
--- | ||
|
||
`ThreadContext` - just like any other React context - is used for dependency injection. What makes it different in this case is `ThreadProvider`. | ||
|
||
## ThreadProvider | ||
|
||
Is a provider which wraps [`Channel`](../core-components/channel.mdx) component and takes [`Thread` instance]() as a value. The [`Channel`](../core-components/channel.mdx) wrapper acts as a temporary measure to make [`Thread` component](../core-components/thread.mdx) compatible with the new architecture which relies on [`Thread` instance](). The reliance on channel is temporary and will become deprecated in the future. | ||
|
||
Thread component newly prioritizes [`Thread` instance]() if rendered under [`ThreadProvider`](../contexts/thread-context.mdx#threadprovider) otherwise falls back to accessing thread from [`Channel` state](../contexts/channel-state-context.mdx). | ||
|
||
### Basic Usage | ||
|
||
```tsx | ||
import { Thread, ThreadProvider } from 'stream-chat-react'; | ||
|
||
<ThreadProvider thread={/*...*/}> | ||
<Thread /> | ||
</ThreadProvider>; | ||
``` |
21 changes: 21 additions & 0 deletions
21
docusaurus/docs/React/components/core-components/thread-list-item.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
id: thread-list-item | ||
title: ThreadListItem | ||
--- | ||
|
||
An item component rendered within [`ThreadList` component](./thread-list.mdx). The item is divided into two components: | ||
|
||
`ThreadListItem` - a component and provider which renders `ThreadListItemUi` | ||
`ThreadListItemUi` - a component which renders the actual UI elements | ||
|
||
The goal is that as integrator you can provide a different look to your component while preserving the behavior or you can replace the behavior while keeping the default UI or you can change both if you require so. | ||
|
||
## Props | ||
|
||
### thread | ||
|
||
A thread instance provided by the [`ThreadList`](../core-components/thread-list.mdx). | ||
|
||
| Type | | ||
| ------ | | ||
| Thread | |
27 changes: 27 additions & 0 deletions
27
docusaurus/docs/React/components/core-components/thread-list.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
id: thread-list | ||
title: ThreadList | ||
--- | ||
|
||
`ThreadList` is a component which renders individual thread instances ([`Thread`](https://github.com/GetStream/stream-chat-js/blob/master/src/thread.ts)) stored within `ThreadManager`. It handles pagination triggers and virtualization through the help of the [Virtuoso](https://virtuoso.dev) virtualized list component. The rest of the business logic lives within ThreadManager and Thread classes. ThreadManager instance gets activated whenever ThreadList renders - activation is necessary as it tells the SDK that user "sees" this list and can update state accordingly whenever appropriate events arrive. | ||
|
||
If used in default form and rendered within `ThreadView` component it also allows to set active thread and handles `Thread` activation (similar to `ThreadManager` activation). | ||
|
||
## Basic Usage | ||
|
||
```tsx | ||
<Chat client={client}> | ||
{/*...*/} | ||
<ThreadList /> | ||
</Chat> | ||
``` | ||
|
||
## Props | ||
|
||
### virtuosoProps | ||
|
||
Props to be passed to the underlying [`react-virtuoso` virtualized list dependency](https://virtuoso.dev/virtuoso-api/interfaces/VirtuosoProps). | ||
|
||
| Type | | ||
| ------ | | ||
| object | |
53 changes: 53 additions & 0 deletions
53
docusaurus/docs/React/components/utility-components/chat-view.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--- | ||
id: chat-view | ||
title: ChatView | ||
keywords: [example, chat view, channel view, thread view, thread adapter] | ||
--- | ||
|
||
`ChatView` is component itself and a set of components which allow for a drop-in implementation of different chat views - the channel view and thread view. This drop-in solution allows your users to easily switch between said views without having to implement such mechanism yourself. It consists of: | ||
|
||
- `ChatView` - a provider that holds information about the selected view | ||
- `ChatView.Selector` - selector which allows to set the required view | ||
- `ChatView.Channels` - a wrapper that renders its children when `ChatView` value is equal to `channels` | ||
- `ChatView.Threads` - a provider and a wrapper that renders its children when `ChatView` value is equal to `threads`, exposes `ThreadsViewContext` under which `ThreadList` can set an active thread | ||
- `ChatView.ThreadAdapter` - a wrapper which can access an active thread from the `ThreadsViewContext` and forwards it to the [`ThreadProvider`](../contexts/thread-context.mdx) | ||
|
||
## Basic Usage | ||
|
||
```tsx | ||
import { | ||
Chat, | ||
ChatView, | ||
ChannelList, | ||
Channel, | ||
ThreadList, | ||
Thread, | ||
useCreateChatClient, | ||
} from 'stream-chat-react'; | ||
|
||
const App = () => { | ||
const chatClient = useCreateChatClient(/*...*/); | ||
|
||
if (!chatClient) return null; | ||
|
||
return ( | ||
<Chat client={chatClient}> | ||
<ChatView> | ||
<ChatView.Selector /> | ||
{/* Channel View */} | ||
<ChatView.Channels> | ||
<ChannelList /> | ||
<Channel>{/*...*/}</Channel> | ||
</ChatView.Channels> | ||
{/* Thread View */} | ||
<ChatView.Threads> | ||
<ThreadList /> | ||
<ChatView.ThreadAdapter> | ||
<Thread /> | ||
</ChatView.ThreadAdapter> | ||
</ChatView.Threads> | ||
</ChatView> | ||
</Chat> | ||
); | ||
}; | ||
``` |
97 changes: 97 additions & 0 deletions
97
docusaurus/docs/React/components/utility-components/view-components.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
id: view-components-and-thread-adapter | ||
title: View Components and Thread Adapter | ||
--- | ||
|
||
ChatView set of components is a view switching mechanism that can be utilised by integrators to quickly implement switching between thread and channel views. | ||
|
||
Available components: | ||
|
||
- `ChatView` - wrapper with context holding the information about currently active view (`channels` & `threads`) | ||
- `ChatView.Threads` - view used for thread-focused application structure with `ThreadsViewContext` that _can be_ utilised by `ThreadList` to set active thread | ||
- `ChatView.Channels` - view used for channel-focused application structure | ||
- `ChatView.Selector` - list with buttons with bound actions for switching views | ||
- `ChatView.ThreadAdapter` - utilises `ThreadsViewContext` and wraps `Thread` component in necessary `ThreadProvider` | ||
|
||
This set of components is provided as-is and offers very limited customizability as the underlying logic is super simple. Integrators are encouraged to build their own switching system if they require it. | ||
|
||
### Usage | ||
|
||
```tsx | ||
import { | ||
Chat, | ||
ChatView, | ||
ChannelList, | ||
Channel, | ||
ThreadList, | ||
Thread, | ||
Window, | ||
} from 'stream-chat-react'; | ||
|
||
// application structure which allows users to switch between views | ||
<Chat client={client}> | ||
<ChatView> | ||
<ChatView.Selector /> | ||
{/* channel-focused structure */} | ||
<ChatView.Channels> | ||
<ChannelList filters={filters} options={options} sort={sort} /> | ||
<Channel> | ||
<Window> | ||
<ChannelHeader /> | ||
<MessageList /> | ||
<MessageInput focus /> | ||
</Window> | ||
<Thread /> | ||
</Channel> | ||
</ChatView.Channels> | ||
{/* thread-focused structure */} | ||
<ChatView.Threads> | ||
<ThreadList /> | ||
<ChatView.ThreadAdapter> | ||
<Thread /> | ||
</ChatView.ThreadAdapter> | ||
</ChatView.Threads> | ||
</ChatView> | ||
</Chat>; | ||
``` | ||
|
||
### Custom Thread-focused Structure | ||
|
||
To build your custom thread-focused structure you'll need these four baseline components; `Thread`, `ThreadList`, `ThreadProvier` and `WithComponents` for component overrides. | ||
|
||
:::note | ||
For presentation purposes our custom `ThreadListItemUi` component is loosely defined within `CustomThreadsView` and thus it isn't stable. To achieve best performance make sure your components | ||
are stable and defined outside other component's scope. | ||
::: | ||
|
||
```tsx | ||
import { WithComponents, ThreadListItemUi, ThreadList, ThreadProvider } from 'stream-chat-react'; | ||
|
||
export const CustomThreadsView = () => { | ||
const [activeThread, setActiveThread] = useState(undefined); | ||
|
||
return ( | ||
<div className='custom-threads-view'> | ||
<WithComponents | ||
overrides={{ | ||
ThreadListItemUi: () => { | ||
const thread = useThreadListItemContext()!; | ||
return ( | ||
<ThreadListItemUi | ||
onPointerDown={() => setActiveThread(thread)} | ||
aria-selected={thread === activeThread} | ||
/> | ||
); | ||
}, | ||
}} | ||
> | ||
<ThreadList /> | ||
</WithComponents> | ||
|
||
<ThreadProvider thread={activeThread}> | ||
<Thread /> | ||
</ThreadProvider> | ||
</div> | ||
); | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
id: custom-threads-view | ||
title: Custom Threads View | ||
keywords: [cookbook, threads, view] | ||
--- | ||
|
||
Our SDK comes with [`ChatView`](../components/utility-components/chat-view.mdx) which allows for an easy integration of different views. In this guide we'll show how to implement custom threads view while utilising core components and hooks. | ||
|
||
## Required Components & Hooks | ||
|
||
These components and hooks are required for your own implementation to work properly: | ||
|
||
- `ThreadList` | ||
- `ThreadListItem` - a provider for `ThreadListItemUi` with thread information, will be used to forward custom click event to the `ThreadListItemUi` button | ||
- `ThreadProvider` - "adapter" for Thread component to work properly with [`Thread` instance](https://github.com/GetStream/stream-chat-js/blob/master/src/thread.ts) | ||
- `Thread` - provides [`MessageList`](../components/core-components/message-list.mdx) with [`MessageInput`](../components/message-input-components/message-input.mdx) adjusted for threads | ||
- `useActiveThread` - takes your selected thread instance and handles its activity state (`Thread.activate()` & `Thread.deactivate()`) based on document focus and visibility | ||
|
||
## Building Custom Threads View | ||
|
||
```tsx | ||
import { | ||
ThreadList, | ||
ThreadListItem, | ||
ThreadProvider, | ||
Thread, | ||
WithComponents, | ||
useActiveThread, | ||
} from 'stream-chat-react'; | ||
|
||
export const CustomThreadsView = () => { | ||
const [activeThread, setActiveThread] = useState(undefined); | ||
|
||
useActiveThread({ activeThread }); | ||
|
||
return ( | ||
<div className='custom-threads-view'> | ||
<ThreadList | ||
virtuosoProps={{ | ||
itemContent: (_, thread) => ( | ||
<ThreadListItem | ||
thread={thread} | ||
threadListItemUiProps={{ | ||
'aria-selected': thread === activeThread, | ||
onClick: () => { | ||
setActiveThread(thread); | ||
}, | ||
}} | ||
/> | ||
), | ||
}} | ||
/> | ||
|
||
{activeThread && ( | ||
<ThreadProvider thread={activeThread}> | ||
<Thread /> | ||
</ThreadProvider> | ||
)} | ||
</div> | ||
); | ||
}; | ||
``` |
Oops, something went wrong.