Skip to content

Commit

Permalink
Merge pull request #32930 from suneox/fix/19642-report-screen-unexpec…
Browse files Browse the repository at this point in the history
…ted-scroll

Fix/19642 report screen unexpected scroll
  • Loading branch information
thienlnam authored Dec 13, 2023
2 parents 6039f5b + 83a1e4c commit 77847d3
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 3 deletions.
21 changes: 18 additions & 3 deletions src/components/Composer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import RNTextInput from '@components/RNTextInput';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withNavigation from '@components/withNavigation';
import useIsScrollBarVisible from '@hooks/useIsScrollBarVisible';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
import compose from '@libs/compose';
Expand Down Expand Up @@ -86,6 +87,9 @@ const propTypes = {
/** Whether the sull composer is open */
isComposerFullSize: PropTypes.bool,

/** Should make the input only scroll inside the element avoid scroll out to parent */
shouldContainScroll: PropTypes.bool,

...withLocalizePropTypes,
};

Expand Down Expand Up @@ -113,6 +117,7 @@ const defaultProps = {
checkComposerVisibility: () => false,
isReportActionCompose: false,
isComposerFullSize: false,
shouldContainScroll: false,
};

/**
Expand Down Expand Up @@ -164,6 +169,7 @@ function Composer({
selection: selectionProp,
isReportActionCompose,
isComposerFullSize,
shouldContainScroll,
...props
}) {
const theme = useTheme();
Expand All @@ -180,6 +186,7 @@ function Composer({
const [caretContent, setCaretContent] = useState('');
const [valueBeforeCaret, setValueBeforeCaret] = useState('');
const [textInputWidth, setTextInputWidth] = useState('');
const isScrollBarVisible = useIsScrollBarVisible(textInput, value);

useEffect(() => {
if (!shouldClear) {
Expand Down Expand Up @@ -418,18 +425,26 @@ function Composer({
</View>
);

const inputStyleMemo = useMemo(
() => [
const scrollStyleMemo = useMemo(() => {
if (shouldContainScroll) {
return isScrollBarVisible ? [styles.overflowScroll, styles.overscrollBehaviorContain] : styles.overflowHidden;
}
return [
// We are hiding the scrollbar to prevent it from reducing the text input width,
// so we can get the correct scroll height while calculating the number of lines.
numberOfLines < maxLines ? styles.overflowHidden : {},
];
}, [shouldContainScroll, isScrollBarVisible, maxLines, numberOfLines, styles.overflowHidden, styles.overflowScroll, styles.overscrollBehaviorContain]);

const inputStyleMemo = useMemo(
() => [
StyleSheet.flatten([style, {outline: 'none'}]),
StyleUtils.getComposeTextAreaPadding(numberOfLines, isComposerFullSize),
Browser.isMobileSafari() || Browser.isSafari() ? styles.rtlTextRenderForSafari : {},
scrollStyleMemo,
],

[numberOfLines, maxLines, styles.overflowHidden, styles.rtlTextRenderForSafari, style, StyleUtils, isComposerFullSize],
[numberOfLines, scrollStyleMemo, styles.rtlTextRenderForSafari, style, StyleUtils, isComposerFullSize],
);

return (
Expand Down
7 changes: 7 additions & 0 deletions src/hooks/useIsScrollBarVisible/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Native doesn't have the DOM, so we just return null.
*
*/
const useIsScrollBarVisible = () => null;

export default useIsScrollBarVisible;
28 changes: 28 additions & 0 deletions src/hooks/useIsScrollBarVisible/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {useCallback, useEffect, useState} from 'react';

const useIsScrollBarVisible = (ref: React.RefObject<HTMLDivElement | HTMLTextAreaElement>, value: string) => {
const [isScrollBarVisible, setIsScrollBarVisible] = useState(false);

const handleResize = useCallback(() => {
if (!ref.current) {
return;
}
const {scrollHeight, clientHeight} = ref.current;
setIsScrollBarVisible(scrollHeight > clientHeight);
}, [ref]);

useEffect(() => {
if (!ref.current || !('ResizeObserver' in (window || {}))) {
return;
}

const resizeObserver = new ResizeObserver(handleResize);
resizeObserver.observe(ref.current);
return () => {
resizeObserver.disconnect();
};
}, [handleResize, ref, value]);
return isScrollBarVisible;
};

export default useIsScrollBarVisible;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useDebounce from '@hooks/useDebounce';
import useLocalize from '@hooks/useLocalize';
import usePrevious from '@hooks/usePrevious';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import compose from '@libs/compose';
import * as ComposerUtils from '@libs/ComposerUtils';
Expand Down Expand Up @@ -561,6 +562,7 @@ function ComposerWithSuggestions({
setComposerHeight(composerLayoutHeight);
}}
onScroll={hideSuggestionMenu}
shouldContainScroll={Browser.isMobileSafari()}
/>
</View>

Expand Down

0 comments on commit 77847d3

Please sign in to comment.