{image && (
{tooling ? (
diff --git a/ts/components/Modal.tsx b/ts/components/Modal.tsx
index 4e0250e917bb..19c0b8fe63d4 100644
--- a/ts/components/Modal.tsx
+++ b/ts/components/Modal.tsx
@@ -3,8 +3,6 @@
import type { ReactElement, ReactNode } from 'react';
import React, { useEffect, useRef, useState } from 'react';
-import type { ContentRect, MeasuredComponentProps } from 'react-measure';
-import Measure from 'react-measure';
import classNames from 'classnames';
import { noop } from 'lodash';
import { animated } from '@react-spring/web';
@@ -16,8 +14,12 @@ import { assertDev } from '../util/assert';
import { getClassNamesFor } from '../util/getClassNamesFor';
import { useAnimated } from '../hooks/useAnimated';
import { useHasWrapped } from '../hooks/useHasWrapped';
-import { useRefMerger } from '../hooks/useRefMerger';
import * as log from '../logging/log';
+import {
+ isOverflowing,
+ isScrolled,
+ useScrollObserver,
+} from '../hooks/useSizeObserver';
type PropsType = {
children: ReactNode;
@@ -169,24 +171,19 @@ export function ModalPage({
}: ModalPageProps): JSX.Element {
const modalRef = useRef(null);
- const refMerger = useRefMerger();
+ const bodyRef = useRef(null);
+ const bodyInnerRef = useRef(null);
- const bodyRef = useRef(null);
const [scrolled, setScrolled] = useState(false);
const [hasOverflow, setHasOverflow] = useState(false);
const hasHeader = Boolean(hasXButton || title || onBackButtonClick);
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);
- }
- }
+ useScrollObserver(bodyRef, bodyInnerRef, scroll => {
+ setScrolled(isScrolled(scroll));
+ setHasOverflow(isOverflowing(scroll));
+ });
return (
<>
@@ -249,26 +246,16 @@ export function ModalPage({
)}
)}
-
- {({ measureRef }: MeasuredComponentProps) => (
- {
- const scrollTop = bodyRef.current?.scrollTop || 0;
- setScrolled(scrollTop > 2);
- }}
- ref={refMerger(measureRef, bodyRef)}
- >
- {children}
-
+
+ ref={bodyRef}
+ >
+
{children}
+
{modalFooter && {modalFooter}}
>
diff --git a/ts/components/StoriesSettingsModal.tsx b/ts/components/StoriesSettingsModal.tsx
index a5350d7d1a68..f2e4d1b8de04 100644
--- a/ts/components/StoriesSettingsModal.tsx
+++ b/ts/components/StoriesSettingsModal.tsx
@@ -1,10 +1,8 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
-import type { MeasuredComponentProps } from 'react-measure';
import type { ReactNode } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import Measure from 'react-measure';
import { noop } from 'lodash';
import type { ConversationType } from '../state/ducks/conversations';
@@ -41,6 +39,7 @@ import { useConfirmDiscard } from '../hooks/useConfirmDiscard';
import { getGroupMemberships } from '../util/getGroupMemberships';
import { strictAssert } from '../util/assert';
import { UserText } from './UserText';
+import { SizeObserver } from '../hooks/useSizeObserver';
export type PropsType = {
candidateConversations: Array