-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
26401 avoid scroll on virtual viewport #35256
Changes from 8 commits
2d9b870
3e58eba
b903773
fba4a1f
cdee492
39e085e
0110a65
4a8488f
9af226c
f1e15ca
9a78767
c9acdde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -10,6 +10,7 @@ import useEnvironment from '@hooks/useEnvironment'; | |||||
import useInitialDimensions from '@hooks/useInitialWindowDimensions'; | ||||||
import useKeyboardState from '@hooks/useKeyboardState'; | ||||||
import useNetwork from '@hooks/useNetwork'; | ||||||
import useTackInputFocus from '@hooks/useTackInputFocus'; | ||||||
import useThemeStyles from '@hooks/useThemeStyles'; | ||||||
import useWindowDimensions from '@hooks/useWindowDimensions'; | ||||||
import * as Browser from '@libs/Browser'; | ||||||
|
@@ -79,6 +80,9 @@ type ScreenWrapperProps = { | |||||
/** Whether to show offline indicator */ | ||||||
shouldShowOfflineIndicator?: boolean; | ||||||
|
||||||
/** Whether to avoid scroll on virtual viewport */ | ||||||
shouldAwareViewportScroll?: boolean; | ||||||
|
||||||
/** | ||||||
* The navigation prop is passed by the navigator. It is used to trigger the onEntryTransitionEnd callback | ||||||
* when the screen transition ends. | ||||||
|
@@ -109,6 +113,7 @@ function ScreenWrapper( | |||||
onEntryTransitionEnd, | ||||||
testID, | ||||||
navigation: navigationProp, | ||||||
shouldAwareViewportScroll = true, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
shouldShowOfflineIndicatorInWideScreen = false, | ||||||
}: ScreenWrapperProps, | ||||||
ref: ForwardedRef<View>, | ||||||
|
@@ -192,6 +197,8 @@ function ScreenWrapper( | |||||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||||||
}, []); | ||||||
|
||||||
const isAwareViewportScroll = useTackInputFocus(shouldEnableMaxHeight && shouldAwareViewportScroll && Browser.isMobileSafari()); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
return ( | ||||||
<SafeAreaConsumer> | ||||||
{({insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle}) => { | ||||||
|
@@ -220,12 +227,12 @@ function ScreenWrapper( | |||||
{...keyboardDissmissPanResponder.panHandlers} | ||||||
> | ||||||
<KeyboardAvoidingView | ||||||
style={[styles.w100, styles.h100, {maxHeight}]} | ||||||
style={[styles.w100, styles.h100, {maxHeight}, isAwareViewportScroll && [styles.overflowAuto, styles.overscrollBehaviorContain]]} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
To avoid applying |
||||||
behavior={keyboardAvoidingViewBehavior} | ||||||
enabled={shouldEnableKeyboardAvoidingView} | ||||||
> | ||||||
<PickerAvoidingView | ||||||
style={styles.flex1} | ||||||
style={isAwareViewportScroll ? [styles.h100, {marginTop: 1}] : styles.flex1} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
enabled={shouldEnablePickerAvoiding} | ||||||
> | ||||||
<HeaderGap styles={headerGapStyles} /> | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* This hook to detech input or text area focus on browser on native doesn't support DOM so default return false | ||
*/ | ||
export default function useTackInputFocus(): boolean { | ||
return false; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,49 @@ | ||||||
import {useCallback, useEffect} from 'react'; | ||||||
import useDebouncedState from '@hooks/useDebouncedState'; | ||||||
|
||||||
/** | ||||||
* This hook to detech input or text area focus on browser, to avoid scroll on vitual viewport | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
little typo. |
||||||
*/ | ||||||
export default function useTackInputFocus(enable = false): boolean { | ||||||
const [, isInputFocusDebounced, setIsInputFocus] = useDebouncedState(false); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we define the first value? Or does that throw lint errors? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hi @luacmartins I have updated your suggestions and when we define the first value but not using that will throw eslint error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, let's keep it empty then |
||||||
|
||||||
const handleFocusIn = useCallback( | ||||||
(event: FocusEvent) => { | ||||||
const targetElement = event.target as HTMLElement; | ||||||
if (targetElement.tagName === 'INPUT' || targetElement.tagName === 'TEXTAREA') { | ||||||
setIsInputFocus(true); | ||||||
} | ||||||
}, | ||||||
[setIsInputFocus], | ||||||
); | ||||||
|
||||||
const handleFocusOut = useCallback( | ||||||
(event: FocusEvent) => { | ||||||
const targetElement = event.target as HTMLElement; | ||||||
if (targetElement.tagName === 'INPUT' || targetElement.tagName === 'TEXTAREA') { | ||||||
setIsInputFocus(false); | ||||||
} | ||||||
}, | ||||||
[setIsInputFocus], | ||||||
); | ||||||
|
||||||
const resetScrollPositionOnVisualViewport = useCallback(() => { | ||||||
window.scrollTo({top: 0}); | ||||||
}, []); | ||||||
|
||||||
useEffect(() => { | ||||||
if (!enable) { | ||||||
return; | ||||||
} | ||||||
window.addEventListener('focusin', handleFocusIn); | ||||||
window.addEventListener('focusout', handleFocusOut); | ||||||
window.visualViewport?.addEventListener('scroll', resetScrollPositionOnVisualViewport); | ||||||
return () => { | ||||||
window.removeEventListener('focusin', handleFocusIn); | ||||||
window.removeEventListener('focusout', handleFocusOut); | ||||||
window.visualViewport?.removeEventListener('scroll', resetScrollPositionOnVisualViewport); | ||||||
}; | ||||||
}, [enable, handleFocusIn, handleFocusOut, resetScrollPositionOnVisualViewport]); | ||||||
|
||||||
return isInputFocusDebounced; | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.