Skip to content

Commit 8235d45

Browse files
authored
feat: add centralized dialog management (#2489)
BREAKING CHANGE: - removes the following variables from `MessageContext`: isReactionEnabled, onReactionListClick, showDetailedReactions, reactionSelectorRef - removes prop `messageWrapperRef` from `MessageOptions` and `MessageActions` props.
1 parent 9fa4806 commit 8235d45

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1768
-1228
lines changed

docusaurus/docs/React/components/contexts/message-context.mdx

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,6 @@ Function that runs on hover of an @mention in a message.
304304
| ----------------------------------------------------------- |
305305
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void |
306306

307-
### onReactionListClick
308-
309-
Function that runs on click of the reactions list component.
310-
311-
| Type |
312-
| ----------------------------------------------------------- |
313-
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void |
314-
315307
### onUserClick
316308

317309
Function that runs on click of a user avatar.
@@ -336,14 +328,6 @@ The user roles allowed to pin messages in various channel types (deprecated in f
336328
| ------ | ------------------------------------------------------------------------- |
337329
| object | <GHComponentLink text='defaultPinPermissions' path='/Message/utils.tsx'/> |
338330

339-
### reactionSelectorRef
340-
341-
Ref to be placed on the reaction selector component.
342-
343-
| Type |
344-
| --------------------------------------- |
345-
| React.MutableRefObject<HTMLDivElement\> |
346-
347331
### readBy
348332

349333
An array of users that have read the current message.
@@ -368,14 +352,6 @@ Function to toggle the editing state on a message.
368352
| ----------------------------------------------------------- |
369353
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void |
370354

371-
### showDetailedReactions
372-
373-
When true, show the reactions list component.
374-
375-
| Type |
376-
| ------- |
377-
| boolean |
378-
379355
### reactionDetailsSort
380356

381357
Sort options to provide to a reactions query. Affects the order of reacted users in the default reactions modal.

docusaurus/docs/React/components/message-components/message-ui.mdx

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -397,14 +397,6 @@ Function that runs on hover of an @mention in a message (overrides the function
397397
| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
398398
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void | [MessageContextValue['onMentionsHoverMessage']](../contexts/channel-action-context.mdx#onmentionshovermessage) |
399399

400-
### onReactionListClick
401-
402-
Function that runs on click of the reactions list component (overrides the function stored in `MessageContext`).
403-
404-
| Type | Default |
405-
| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
406-
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void | [MessageContextValue['onReactionListClick']](../contexts/channel-action-context.mdx#onreactionlistclick) |
407-
408400
### onUserClick
409401

410402
Function that runs on click of a user avatar (overrides the function stored in `MessageContext`).
@@ -429,14 +421,6 @@ The user roles allowed to pin messages in various channel types (deprecated in f
429421
| ------ | -------------------------------------------------------------------------------------------------------------------- |
430422
| object | [defaultPinPermissions](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/utils.tsx) |
431423

432-
### reactionSelectorRef
433-
434-
Ref to be placed on the reaction selector component (overrides the ref stored in `MessageContext`).
435-
436-
| Type |
437-
| --------------------------------------- |
438-
| React.MutableRefObject<HTMLDivElement\> |
439-
440424
### readBy
441425

442426
An array of users that have read the current message (overrides the value stored in `MessageContext`).
@@ -461,14 +445,6 @@ Function to toggle the editing state on a message (overrides the function stored
461445
| ----------------------------------------------------------- |
462446
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void |
463447

464-
### showDetailedReactions
465-
466-
When true, show the reactions list component (overrides the value stored in `MessageContext`).
467-
468-
| Type |
469-
| ------- |
470-
| boolean |
471-
472448
### threadList
473449

474450
If true, indicates that the current `MessageList` component is part of a `Thread` (overrides the value stored in `MessageContext`).

docusaurus/docs/React/components/message-components/reactions.mdx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,6 @@ const MyCustomReactionsList = (props) => {
151151
};
152152
```
153153

154-
### onClick
155-
156-
Custom on click handler for an individual reaction in the list (overrides the function coming from `MessageContext`).
157-
158-
| Type | Default |
159-
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
160-
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void | [MessageContextValue['onReactionListClick']](../contexts/message-context.mdx#onreactionlistclick) |
161-
162154
### own_reactions
163155

164156
An array of the own reaction objects to distinguish own reactions visually (overrides `message.own_reactions` from `MessageContext`).

docusaurus/docs/React/components/message-components/ui-components.mdx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,6 @@ The `StreamChat` message object, which provides necessary data to the underlying
126126
| ------ |
127127
| object |
128128

129-
### messageWrapperRef
130-
131-
React mutable ref placed on the message root `div`. It is forwarded by `MessageOptions` down to `MessageActions` ([see the example](../../guides/theming/message-ui.mdx)).
132-
133-
| Type |
134-
| -------------------------------- |
135-
| React.RefObject<HTMLDivElement\> |
136-
137129
### mine
138130

139131
Function that returns whether the message was sent by the connected user.
@@ -178,14 +170,6 @@ Function that opens a [`Thread`](../core-components/thread.mdx) on a message (ov
178170
| ----------------------------------------------------------- |
179171
| (event: React.BaseSyntheticEvent) => Promise<void\> \| void |
180172

181-
### messageWrapperRef
182-
183-
React mutable ref that can be placed on the message root `div`. `MessageOptions` component forwards this prop to [`MessageActions`](#messageactions-props) component ([see the example](../../guides/theming/message-ui.mdx)).
184-
185-
| Type |
186-
| -------------------------------- |
187-
| React.RefObject<HTMLDivElement\> |
188-
189173
### ReactionIcon
190174

191175
Custom component rendering the icon used in a message options button invoking reactions selector for a given message.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
id: dialog-management
3+
title: Dialog Management
4+
---
5+
6+
This article presents the API the integrators can use to toggle display dialogs in their UIs. The default components that are displayed as dialogs are:
7+
8+
- `ReactionSelector` - allows users to post reactions / emojis to a message
9+
- `MessageActionsBox` - allows user to select from a list of permitted message actions
10+
11+
The dialog management following this guide is enabled within `MessageList` and `VirtualizedMessageList`.
12+
13+
## Setup dialog display
14+
15+
There are two actors in the play. The first one is the component that requests the dialog to be closed or open and the other is the component that renders the dialog. We will start with demonstrating how to properly render a component in a dialog.
16+
17+
### Rendering a dialog
18+
19+
Component we want to be rendered as a floating dialog should be wrapped inside `DialogAnchor`:
20+
21+
```tsx
22+
import React, { ElementRef, useRef } from 'react';
23+
import { DialogAnchor } from 'stream-chat-react';
24+
25+
import { ComponentToDisplayOnDialog } from './ComponentToDisplayOnDialog';
26+
import { generateUniqueId } from './generateUniqueId';
27+
28+
const Container = () => {
29+
// DialogAnchor needs a reference to the element that will toggle the open state. Based on this reference the dialog positioning is calculated
30+
const buttonRef = useRef<ElementRef<'button'>>(null);
31+
// providing the dialog is necessary for the dialog to be retrieved from anywhere in the DialogManagerProviderContext
32+
const dialogId = generateUniqueId();
33+
34+
return (
35+
<>
36+
<DialogAnchor id={dialogId} placement='top' referenceElement={buttonRef.current} trapFocus>
37+
<ComponentToDisplayOnDialog />
38+
</DialogAnchor>
39+
</>
40+
);
41+
};
42+
```
43+
44+
### Controlling a dialog's display
45+
46+
The dialog display is controlled via Dialog API. You can access the API via `useDialog()` hook.
47+
48+
```tsx
49+
import React, { ElementRef, useRef } from 'react';
50+
import { DialogAnchor, useDialog, useDialogIsOpen } from 'stream-chat-react';
51+
52+
import { ComponentToDisplayOnDialog } from './ComponentToDisplayOnDialog';
53+
import { generateUniqueId } from './generateUniqueId';
54+
55+
const Container = () => {
56+
const buttonRef = useRef<ElementRef<'button'>>(null);
57+
const dialogId = generateUniqueId();
58+
// access the dialog controller which provides the dialog API
59+
const dialog = useDialog({ id: dialogId });
60+
// subscribe to dialog open state changes
61+
const dialogIsOpen = useDialogIsOpen(dialogId);
62+
63+
return (
64+
<>
65+
<DialogAnchor id={dialogId} placement='top' referenceElement={buttonRef.current} trapFocus>
66+
<ComponentToDisplayOnDialog />
67+
</DialogAnchor>
68+
<button aria-expanded={dialogIsOpen} onClick={dialog.toggleSingle} ref={buttonRef}>
69+
Toggle
70+
</button>
71+
</>
72+
);
73+
};
74+
```
75+
76+
### Dialog API
77+
78+
Dialog can be controlled via `Dialog` object retrieved using `useDialog()` hook. The hook returns an object with the following API:
79+
80+
- `dialog.open()` - opens the dialog
81+
- `dialog.close()` - closes the dialog
82+
- `dialog.toggle()` - toggles the dialog open state. Accepts boolean argument `closeAll`. If enabled closes any other dialog that would be open.
83+
- `dialog.remove()` - removes the dialog object reference from the state (primarily for cleanup purposes)
84+
85+
Every `Dialog` object carries its own `id` and `isOpen` flag.
86+
87+
### Dialog utility hooks
88+
89+
There are the following utility hooks that can be used to subscribe to state changes or access a given dialog:
90+
91+
- `useDialogIsOpen(id: string)` - allows to observe the open state of a particular `Dialog` instance
92+
- `useDialog({ id }: GetOrCreateDialogParams)` - retrieves a dialog object that exposes API to manage it
93+
- `useOpenedDialogCount()` - allows to observe changes in the open dialog count
94+
95+
### Custom dialog management context
96+
97+
Those who would like to render dialogs outside the `MessageList` and `VirtualizedMessageList`, will need to create a dialog management context using `DialogManagerProvider`.
98+
99+
```tsx
100+
import { DialogManagerProvider } from 'stream-chat-react';
101+
102+
const Container = () => {
103+
return <DialogManagerProvider id='custom-dialog-manager-id'></DialogManagerProvider>;
104+
};
105+
```
106+
107+
Now the children of `DialogAnchor` will be anchored to the parent `DialogManagerProvider`.

docusaurus/docs/React/guides/theming/message-ui.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ const CustomMessageUi = () => {
387387

388388
Message grouping is being managed automatically by the SDK and each parent element (which holds our message UI) receives an appropriate class name based on which we can adjust our rules to display metadata elements only when it's appropriate to make our UI look less busy.
389389

390-
{/_ TODO: link to grouping logic (maybe how to adjust it if needed) _/}
390+
[//]: # 'TODO: link to grouping logic (maybe how to adjust it if needed)'
391391

392392
```css
393393
.custom-message-ui__metadata {

docusaurus/docs/React/release-guides/upgrade-to-v12.mdx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,38 @@ import { encodeToMp3 } from 'stream-chat-react/mp3-encoder';
117117

118118
:::
119119

120+
## Unified dialog management
121+
122+
Dialogs will be managed centrally. At the moment, this applies to display of `ReactionSelector` and `MessageActionsBox`. They will be displayed on a transparent overlay that prevents users from opening other dialogs in the message list. Once an option from a dialog is selected or the overlay is clicked, the dialog will disappear. This adjust brings new API and removes some properties from `MessageContextValue`.
123+
124+
### Removed properties from MessageContextValue
125+
126+
- `isReactionEnabled` - served to signal the permission to send reactions by the current user in a given channel. With the current permissions implementation, the permission can be determined by doing the following:
127+
128+
```
129+
import { useMessageContext } from 'stream-chat-react';
130+
131+
const { getMessageActions } = useMessageContext();
132+
const messageActions = getMessageActions();
133+
const canReact = messageActions.includes(MESSAGE_ACTIONS.react);
134+
```
135+
136+
- `onReactionListClick` - handler function that toggled the open state of `ReactionSelector` represented by another removed value - `showDetailedReactions`
137+
- `showDetailedReactions` - flag used to decide, whether the reaction selector should be shown or not
138+
- `reactionSelectorRef` - ref to the root of the reaction selector component (served to control the display of the component)
139+
140+
Also prop `messageWrapperRef` was removed as part of the change from `MessageOptions` and `MessageActions` props.
141+
142+
On the other hand, the `Message` prop (configuration parameter) `closeReactionSelectorOnClick` is now available in the `MessageContextValue`.
143+
144+
:::important
145+
If you used any of these values in your customizations, please make sure to adjust your implementation according to the newly recommended use of Dialog API in [Dialog management guide](../../guides/dialog-management).
146+
:::
147+
148+
### New dialog management API
149+
150+
To learn about the new API, please, take a look at our [Dialog management guide](../../guides/dialog-management).
151+
120152
## EmojiPickerIcon extraction to emojis plugin
121153

122154
The default `EmojiPickerIcon` has been moved to emojis plugin from which we already import `EmojiPicker` component.

docusaurus/sidebars-react.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@
149149
"guides/video-integration/video-integration-stream",
150150
"guides/sdk-state-management",
151151
"guides/date-time-formatting",
152-
"guides/custom-threads-view"
152+
"guides/custom-threads-view",
153+
"guides/dialog-management"
153154
]
154155
},
155156
{

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
"@semantic-release/changelog": "^6.0.2",
172172
"@semantic-release/git": "^10.0.1",
173173
"@stream-io/rollup-plugin-node-builtins": "^2.1.5",
174-
"@stream-io/stream-chat-css": "^5.0.0-rc.5",
174+
"@stream-io/stream-chat-css": "5.0.0-rc.6",
175175
"@testing-library/jest-dom": "^6.1.4",
176176
"@testing-library/react": "^13.1.1",
177177
"@testing-library/react-hooks": "^8.0.0",

src/components/ChatView/ChatView.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
22

3-
import { ThreadProvider, useStateStore } from '../Threads';
3+
import { ThreadProvider } from '../Threads';
44
import { Icon } from '../Threads/icons';
55
import { UnreadCountBadge } from '../Threads/UnreadCountBadge';
66
import { useChatContext } from '../../context';
7+
import { useStateStore } from '../../store';
78

89
import type { PropsWithChildren } from 'react';
910
import type { Thread, ThreadManagerState } from 'stream-chat';

0 commit comments

Comments
 (0)