UNPKG

@attio/react-native-bottom-sheet-toolbox-text-input

Version:
102 lines (88 loc) 3.42 kB
import * as React from "react" import { type NativeSyntheticEvent, type StyleProp, StyleSheet, type TextInputContentSizeChangeEventData, type TextStyle, } from "react-native" import {type SharedValue, useAnimatedReaction, useSharedValue} from "react-native-reanimated" import { useBottomSheetToolboxInternalContext, useKeyboardHeightSharedValue, } from "@attio/react-native-bottom-sheet-toolbox" import {getVerticalBorderWidth} from "../../utils/get-vertical-border-width" import {getVerticalPadding} from "../../utils/get-vertical-padding" export interface UseMinOverlayHeightSharedValueArgs { textInputStyle?: StyleProp<TextStyle> bottomInsetSharedValue: SharedValue<number> topInsetSharedValue: SharedValue<number | null> minTextInputHeightSharedValue: SharedValue<number | null> fallbackLines: number } export function useMinOverlayHeightSharedValue({ textInputStyle, topInsetSharedValue, bottomInsetSharedValue, minTextInputHeightSharedValue, fallbackLines, }: UseMinOverlayHeightSharedValueArgs) { const {wrapperHeightSharedValue} = useBottomSheetToolboxInternalContext() const flatTextInputStyle = React.useMemo( () => StyleSheet.flatten(textInputStyle), [textInputStyle] ) const borderWidth = getVerticalBorderWidth(flatTextInputStyle) const verticalPadding = getVerticalPadding(flatTextInputStyle) /** * There is a bug inside React Native which prevents this from being called * when it should be: https://github.com/facebook/react-native/issues/47186 * * Hence we try to calculate some meaningful default. */ const lineHeight = Number(flatTextInputStyle.lineHeight ?? 16) * fallbackLines const initialContentHeight = typeof flatTextInputStyle.minHeight === "number" ? Math.max(flatTextInputStyle.minHeight, lineHeight) : lineHeight const contentHeightSharedValue = useSharedValue(initialContentHeight) const onContentSizeChange = React.useCallback( (evt: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => { contentHeightSharedValue.set(evt.nativeEvent.contentSize.height) }, [] ) const keyboardHeightSharedValue = useKeyboardHeightSharedValue() useAnimatedReaction( () => { const contentHeight = contentHeightSharedValue.get() const wrapperHeight = wrapperHeightSharedValue.get() const topInset = topInsetSharedValue.get() if (contentHeight === 0 || wrapperHeight === null || topInset === null) { return null } const maxOverlayHeight = wrapperHeight - keyboardHeightSharedValue.get() - topInset - bottomInsetSharedValue.get() const layoutMargins = verticalPadding + borderWidth return Math.min( contentHeight === 0 ? 0 : contentHeight + layoutMargins || 0, maxOverlayHeight ) }, (result) => { minTextInputHeightSharedValue.set(result) }, [ wrapperHeightSharedValue, keyboardHeightSharedValue, topInsetSharedValue, bottomInsetSharedValue, verticalPadding, borderWidth, ] ) return onContentSizeChange }