// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useRef, useState, ReactElement, ReactNode } from 'react'; import Measure, { ContentRect, MeasuredComponentProps } from 'react-measure'; import classNames from 'classnames'; import { noop } from 'lodash'; import { LocalizerType } from '../types/Util'; import { ModalHost } from './ModalHost'; import { Theme } from '../util/theme'; import { getClassNamesFor } from '../util/getClassNamesFor'; import { useHasWrapped } from '../hooks/useHasWrapped'; type PropsType = { children: ReactNode; hasStickyButtons?: boolean; hasXButton?: boolean; i18n: LocalizerType; moduleClassName?: string; noMouseClose?: boolean; onClose?: () => void; title?: ReactNode; theme?: Theme; }; const BASE_CLASS_NAME = 'module-Modal'; export function Modal({ children, hasStickyButtons, hasXButton, i18n, moduleClassName, noMouseClose, onClose = noop, title, theme, }: Readonly): ReactElement { const modalRef = useRef(null); const bodyRef = useRef(null); const [scrolled, setScrolled] = useState(false); const [hasOverflow, setHasOverflow] = useState(false); const hasHeader = Boolean(hasXButton || title); const getClassName = getClassNamesFor(BASE_CLASS_NAME, moduleClassName); function handleResize({ scroll }: ContentRect) { const modalNode = modalRef?.current; if (!modalNode) { return; } if (scroll) { setHasOverflow(scroll.height > modalNode.clientHeight); } } return ( {/* We don't want the click event to propagate to its container node. */} {/* eslint-disable jsx-a11y/no-static-element-interactions */} {/* eslint-disable jsx-a11y/click-events-have-key-events */}
{ event.stopPropagation(); }} > {/* eslint-enable jsx-a11y/no-static-element-interactions */} {/* eslint-enable jsx-a11y/click-events-have-key-events */} {hasHeader && (
{hasXButton && (
)} {({ measureRef }: MeasuredComponentProps) => (
{ const scrollTop = bodyRef.current?.scrollTop || 0; setScrolled(scrollTop > 2); }} ref={bodyEl => { measureRef(bodyEl); bodyRef.current = bodyEl; }} > {children}
)}
); } Modal.ButtonFooter = function ButtonFooter({ children, moduleClassName, }: Readonly<{ children: ReactNode; moduleClassName?: string; }>): ReactElement { const [ref, hasWrapped] = useHasWrapped(); const className = getClassNamesFor( BASE_CLASS_NAME, moduleClassName )('__button-footer'); return (
{children}
); };