stream-chat-react
Version:
React components to create chat conversations or livestream style chat
74 lines (73 loc) • 2.98 kB
JavaScript
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import { FocusScope } from '@react-aria/focus';
import { usePopper } from 'react-popper';
import { DialogPortalEntry } from './DialogPortal';
import { useDialog, useDialogIsOpen } from './hooks';
export function useDialogAnchor({ allowFlip, open, placement, referenceElement, }) {
const [popperElement, setPopperElement] = useState(null);
const { attributes, styles, update } = usePopper(referenceElement, popperElement, {
modifiers: [
{
enabled: !!allowFlip, // Prevent flipping
name: 'flip',
},
{
name: 'eventListeners',
options: {
// It's not safe to update popper position on resize and scroll, since popper's
// reference element might not be visible at the time.
resize: false,
scroll: false,
},
},
],
placement,
});
useEffect(() => {
if (open && popperElement) {
// Since the popper's reference element might not be (and usually is not) visible
// all the time, it's safer to force popper update before showing it.
// update is non-null only if popperElement is non-null
update?.();
}
}, [open, popperElement, update]);
if (popperElement && !open) {
setPopperElement(null);
}
return {
attributes,
setPopperElement,
styles,
};
}
export const DialogAnchor = ({ allowFlip = true, children, className, focus = true, id, placement = 'auto', referenceElement = null, tabIndex, trapFocus, ...restDivProps }) => {
const dialog = useDialog({ id });
const open = useDialogIsOpen(id);
const { attributes, setPopperElement, styles } = useDialogAnchor({
allowFlip,
open,
placement,
referenceElement,
});
useEffect(() => {
if (!open)
return;
const hideOnEscape = (event) => {
if (event.key !== 'Escape')
return;
dialog?.close();
};
document.addEventListener('keyup', hideOnEscape);
return () => {
document.removeEventListener('keyup', hideOnEscape);
};
}, [dialog, open]);
// prevent rendering the dialog contents if the dialog should not be open / shown
if (!open) {
return null;
}
return (React.createElement(DialogPortalEntry, { dialogId: id },
React.createElement(FocusScope, { autoFocus: focus, contain: trapFocus, restoreFocus: true },
React.createElement("div", { ...restDivProps, ...attributes.popper, className: clsx('str-chat__dialog-contents', className), "data-testid": 'str-chat__dialog-contents', ref: setPopperElement, style: styles.popper, tabIndex: typeof tabIndex !== 'undefined' ? tabIndex : 0 }, children))));
};