import React, { ElementRef, useRef } from "react";
import { DialogAnchor } from "stream-chat-react";
import { ComponentToDisplayOnDialog } from "./ComponentToDisplayOnDialog";
import { generateUniqueId } from "./generateUniqueId";
const Container = () => {
// DialogAnchor needs a reference to the element that will toggle the open state. Based on this reference the dialog positioning is calculated
const buttonRef = useRef<ElementRef<"button">>(null);
// providing the dialog is necessary for the dialog to be retrieved from anywhere in the DialogManagerProviderContext
const dialogId = generateUniqueId();
return (
<>
<DialogAnchor
id={dialogId}
placement="top"
referenceElement={buttonRef.current}
trapFocus
>
<ComponentToDisplayOnDialog />
</DialogAnchor>
</>
);
};
Dialog Management
The dialog management in React SDK controls:
- dialog popups like menus (
ReactionSelector
,MessageActionsBox
,AttachmentSelector
,ShareLocationDialog
) - modals (if
GlobalModal
is used)
Setup dialog popup display
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.
Rendering a dialog
Component we want to be rendered as a floating dialog should be wrapped inside DialogAnchor
:
Controlling a dialog’s display
The dialog display is controlled via Dialog API. You can access the API via useDialog()
hook.
import React, { ElementRef, useRef } from "react";
import { DialogAnchor, useDialog, useDialogIsOpen } from "stream-chat-react";
import { ComponentToDisplayOnDialog } from "./ComponentToDisplayOnDialog";
import { generateUniqueId } from "./generateUniqueId";
const Container = () => {
const buttonRef = useRef<ElementRef<"button">>(null);
const dialogId = generateUniqueId();
// access the dialog controller which provides the dialog API
const dialog = useDialog({ id: dialogId });
// subscribe to dialog open state changes
const dialogIsOpen = useDialogIsOpen(dialogId);
return (
<>
<DialogAnchor
id={dialogId}
placement="top"
referenceElement={buttonRef.current}
trapFocus
>
<ComponentToDisplayOnDialog />
</DialogAnchor>
<button
aria-expanded={dialogIsOpen}
onClick={() => dialog.toggle()}
ref={buttonRef}
>
Toggle
</button>
</>
);
};
Dialog API
Dialog can be controlled via Dialog
object retrieved using useDialog()
hook. The hook returns an object with the following API:
dialog.open()
- opens the dialogdialog.close()
- closes the dialogdialog.toggle()
- toggles the dialog open state. Accepts boolean argumentcloseAll
. If enabled closes any other dialog that would be open.dialog.remove()
- removes the dialog object reference from the state (primarily for cleanup purposes)
Every Dialog
object carries its own id
and isOpen
flag.
Dialog utility hooks
There are the following utility hooks that can be used to subscribe to state changes or access a given dialog:
useDialogIsOpen(id: string)
- allows to observe the open state of a particularDialog
instanceuseDialog({ id }: GetOrCreateDialogParams)
- retrieves a dialog object that exposes API to manage ituseOpenedDialogCount()
- allows to observe changes in the open dialog count
Custom dialog management context
Those who would like to render dialogs outside the MessageList
and VirtualizedMessageList
, will need to create a dialog management context using DialogManagerProvider
.
import { DialogManagerProvider } from "stream-chat-react";
const Container = () => {
return (
<DialogManagerProvider id="custom-dialog-manager-id"></DialogManagerProvider>
);
};
Now the children of DialogAnchor
will be anchored to the parent DialogManagerProvider
.
Render Modal with Dialog API
The advantage of rendering modals with Dialog API is that the modal will be rendered at the top of the Chat
application thus avoiding UI glitches caused by browser interpretation of CSS rules (e.g. Safari interpretation of position: fixed
in the context of the nearest relatively positioned parent thus cutting off the modal overlay to the dimensions of the parent).
To start rendering the modal at the top of the chat tree, it is necessary to use GlobalModal
for modal rendering:
import { GlobalModal } from "stream-chat-react";
const Component = () => <Channel Modal={GlobalModal}></Channel>;
Then the modal can be rendered as follows:
import { ModalGallery, useComponentContext } from "stream-chat-react";
const Component = () => {
const { Modal } = useComponentContext();
return (
<>
<button>Open Modal</button>
{/* Modal will be renderd via React portal at the top of the tree */}
<Modal
className="modal-gallery-modal"
onClose={closeModal}
open={modalIsOpen}
>
<ModalGallery images={[props]} index={0} />
</Modal>
</>
);
};