react-native-keyboard-controller 1.21.3 → 1.21.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -0
  2. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +10 -0
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +0 -40
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +1 -0
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +5 -1
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +10 -10
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +19 -22
  8. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -0
  9. package/ios/KeyboardControllerModule.mm +12 -0
  10. package/ios/observers/FocusedInputObserver.swift +9 -2
  11. package/ios/views/KeyboardExtenderContainerView.swift +14 -4
  12. package/lib/commonjs/bindings.js +4 -1
  13. package/lib/commonjs/bindings.js.map +1 -1
  14. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +47 -10
  15. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  16. package/lib/commonjs/components/KeyboardAwareScrollView/types.js.map +1 -1
  17. package/lib/commonjs/components/KeyboardToolbar/constants.js +2 -2
  18. package/lib/commonjs/components/KeyboardToolbar/constants.js.map +1 -1
  19. package/lib/commonjs/components/index.js.map +1 -1
  20. package/lib/commonjs/constants.js +3 -1
  21. package/lib/commonjs/constants.js.map +1 -1
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
  24. package/lib/commonjs/types/module.js.map +1 -1
  25. package/lib/module/bindings.js +4 -1
  26. package/lib/module/bindings.js.map +1 -1
  27. package/lib/module/components/KeyboardAwareScrollView/index.js +48 -11
  28. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  29. package/lib/module/components/KeyboardAwareScrollView/types.js.map +1 -1
  30. package/lib/module/components/KeyboardToolbar/constants.js +2 -2
  31. package/lib/module/components/KeyboardToolbar/constants.js.map +1 -1
  32. package/lib/module/components/index.js.map +1 -1
  33. package/lib/module/constants.js +3 -0
  34. package/lib/module/constants.js.map +1 -1
  35. package/lib/module/index.js.map +1 -1
  36. package/lib/module/specs/NativeKeyboardController.js.map +1 -1
  37. package/lib/module/types/module.js.map +1 -1
  38. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +1 -0
  39. package/lib/typescript/components/KeyboardAwareScrollView/types.d.ts +10 -0
  40. package/lib/typescript/components/index.d.ts +1 -1
  41. package/lib/typescript/constants.d.ts +1 -0
  42. package/lib/typescript/index.d.ts +1 -1
  43. package/lib/typescript/specs/NativeKeyboardController.d.ts +3 -1
  44. package/lib/typescript/types/module.d.ts +3 -0
  45. package/package.json +1 -1
  46. package/src/bindings.ts +3 -0
  47. package/src/components/KeyboardAwareScrollView/index.tsx +79 -29
  48. package/src/components/KeyboardAwareScrollView/types.ts +11 -0
  49. package/src/components/KeyboardToolbar/constants.ts +2 -3
  50. package/src/components/index.ts +1 -0
  51. package/src/constants.ts +4 -0
  52. package/src/index.ts +1 -0
  53. package/src/specs/NativeKeyboardController.ts +3 -1
  54. package/src/types/module.ts +4 -0
@@ -1 +1 @@
1
- {"version":3,"names":["React","forwardRef","useCallback","useEffect","useImperativeHandle","useMemo","Reanimated","clamp","interpolate","runOnUI","scrollTo","useAnimatedReaction","useAnimatedRef","useDerivedValue","useSharedValue","KeyboardControllerNative","useFocusedInputHandler","useReanimatedFocusedInput","useWindowDimensions","findNodeHandle","useCombinedRef","useScrollState","ScrollViewWithBottomPadding","useSmoothKeyboardHandler","debounce","scrollDistanceWithRespectToSnapPoints","KeyboardAwareScrollView","children","onLayout","bottomOffset","disableScrollOnKeyboardHide","enabled","extraKeyboardSpace","ScrollViewComponent","ScrollView","snapToOffsets","rest","ref","scrollViewAnimatedRef","scrollViewRef","useRef","onRef","scrollViewTarget","scrollPosition","offset","position","layout","scrollViewLayout","size","scrollViewContentSize","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","update","lastSelection","ghostViewSpace","pendingSelectionForFocus","selectionUpdatedSinceHide","scrollViewPageY","height","onScrollViewLayout","e","handle","current","value","y","viewPositionInWindow","maybeScroll","animated","_layout$value","_layout$value2","_layout$value3","parentScrollViewTarget","visibleRect","absoluteY","inputHeight","point","relativeScrollTo","interpolatedScrollTo","targetScrollY","Math","max","positionOnScreen","topOfScreen","removeGhostPadding","performScrollWithPositionRestoration","newPosition","prevScroll","syncKeyboardFrame","keyboardFrame","updateLayoutFromSelection","_lastSelection$value","_input$value","customHeight","selection","end","scrollFromCurrentPosition","prevLayout","onChangeText","onChangeTextHandler","onSelectionChange","_lastSelection$value2","_lastSelection$value3","lastTarget","target","latestSelection","start","onStart","keyboardWillChangeSize","keyboardWillHide","focusWasChanged","_lastSelection$value4","_lastSelection$value5","onMove","onEnd","synchronize","scrollView","scrollViewWithMethods","assureFocusedInputVisible","previous","padding","createElement","_extends","bottomPadding","scrollEventThrottle"],"sources":["index.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n} from \"react\";\nimport Reanimated, {\n clamp,\n interpolate,\n runOnUI,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { KeyboardControllerNative } from \"../../bindings\";\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n useWindowDimensions,\n} from \"../../hooks\";\nimport { findNodeHandle } from \"../../utils/findNodeHandle\";\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport useScrollState from \"../hooks/useScrollState\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce, scrollDistanceWithRespectToSnapPoints } from \"./utils\";\n\nimport type { LayoutChangeEvent, ScrollView } from \"react-native\";\nimport type {\n FocusedInputLayoutChangedEvent,\n FocusedInputSelectionChangedEvent,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n NativeEvent,\n} from \"react-native-keyboard-controller\";\n\n// Everything begins from `onStart` handler. This handler is called every time,\n// when keyboard changes its size or when focused `TextInput` was changed. In\n// this handler we are calculating/memoizing values which later will be used\n// during layout movement. For that we calculate:\n// - layout of focused field (`layout`) - to understand whether there will be overlap\n// - initial keyboard size (`initialKeyboardSize`) - used in scroll interpolation\n// - future keyboard height (`keyboardHeight`) - used in scroll interpolation\n// - current scroll position (`scrollPosition`) - used to scroll from this point\n//\n// Once we've calculated all necessary variables - we can actually start to use them.\n// It happens in `onMove` handler - this function simply calls `maybeScroll` with\n// current keyboard frame height. This functions makes the smooth transition.\n//\n// When the transition has finished we go to `onEnd` handler. In this handler\n// we verify, that the current field is not overlapped within a keyboard frame.\n// For full `onStart`/`onMove`/`onEnd` flow it may look like a redundant thing,\n// however there could be some cases, when `onMove` is not called:\n// - on iOS when TextInput was changed - keyboard transition is instant\n// - on Android when TextInput was changed and keyboard size wasn't changed\n// So `onEnd` handler handle the case, when `onMove` wasn't triggered.\n//\n// ====================================================================================================================+\n// -----------------------------------------------------Flow chart-----------------------------------------------------+\n// ====================================================================================================================+\n//\n// +============================+ +============================+ +==================================+\n// + User Press on TextInput + => + Keyboard starts showing + => + As keyboard moves frame by frame + =>\n// + + + (run `onStart`) + + `onMove` is getting called +\n// +============================+ +============================+ +==================================+\n//\n// +============================+ +============================+ +=====================================+\n// + Keyboard is shown and we + => + User moved focus to + => + Only `onStart`/`onEnd` maybe called +\n// + call `onEnd` handler + + another `TextInput` + + (without involving `onMove`) +\n// +============================+ +============================+ +=====================================+\n//\n\n/**\n * A ScrollView component that automatically handles keyboard appearance and disappearance\n * by adjusting its content position to ensure the focused input remains visible.\n *\n * The component uses a sophisticated animation system to smoothly handle keyboard transitions\n * and maintain proper scroll position during keyboard interactions.\n *\n * @returns A ScrollView component that handles keyboard interactions.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-aware-scroll-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAwareScrollView bottomOffset={20}>\n * <TextInput placeholder=\"Enter text\" />\n * <TextInput placeholder=\"Another input\" />\n * </KeyboardAwareScrollView>\n * ```\n */\nconst KeyboardAwareScrollView = forwardRef<\n KeyboardAwareScrollViewRef,\n React.PropsWithChildren<KeyboardAwareScrollViewProps>\n>(\n (\n {\n children,\n onLayout,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n enabled = true,\n extraKeyboardSpace = 0,\n ScrollViewComponent = Reanimated.ScrollView,\n snapToOffsets,\n ...rest\n },\n ref,\n ) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollViewRef = React.useRef<ScrollView>(null);\n const onRef = useCombinedRef(scrollViewAnimatedRef, scrollViewRef);\n const scrollViewTarget = useSharedValue<number | null>(null);\n const scrollPosition = useSharedValue(0);\n const {\n offset: position,\n layout: scrollViewLayout,\n size: scrollViewContentSize,\n } = useScrollState(scrollViewAnimatedRef);\n const currentKeyboardFrameHeight = useSharedValue(0);\n const keyboardHeight = useSharedValue(0);\n const keyboardWillAppear = useSharedValue(false);\n const tag = useSharedValue(-1);\n const initialKeyboardSize = useSharedValue(0);\n const scrollBeforeKeyboardMovement = useSharedValue(0);\n const { input, update } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n const lastSelection =\n useSharedValue<FocusedInputSelectionChangedEvent | null>(null);\n const ghostViewSpace = useSharedValue(-1);\n const pendingSelectionForFocus = useSharedValue(false);\n const selectionUpdatedSinceHide = useSharedValue(false);\n const scrollViewPageY = useSharedValue(0);\n\n const { height } = useWindowDimensions();\n\n const onScrollViewLayout = useCallback(\n async (e: LayoutChangeEvent) => {\n const handle = findNodeHandle(scrollViewAnimatedRef.current);\n\n scrollViewTarget.value = handle;\n\n onLayout?.(e);\n\n if (handle !== null) {\n try {\n const { y } = await KeyboardControllerNative.viewPositionInWindow(\n handle,\n );\n\n scrollViewPageY.value = y;\n } catch {\n // ignore\n }\n }\n },\n [onLayout],\n );\n\n /**\n * Function that will scroll a ScrollView as keyboard gets moving.\n */\n const maybeScroll = useCallback(\n (e: number, animated: boolean = false) => {\n \"worklet\";\n\n if (!enabled) {\n return 0;\n }\n\n // input belongs to ScrollView\n if (layout.value?.parentScrollViewTarget !== scrollViewTarget.value) {\n return 0;\n }\n\n const visibleRect = height - keyboardHeight.value;\n const absoluteY = layout.value?.layout.absoluteY || 0;\n const inputHeight = layout.value?.layout.height || 0;\n const point = absoluteY + inputHeight;\n\n if (visibleRect - point <= bottomOffset) {\n const relativeScrollTo =\n keyboardHeight.value - (height - point) + bottomOffset;\n const interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [\n 0,\n scrollDistanceWithRespectToSnapPoints(\n relativeScrollTo + scrollPosition.value,\n snapToOffsets,\n ) - scrollPosition.value,\n ],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (point < scrollViewPageY.value) {\n const positionOnScreen = visibleRect - bottomOffset;\n const topOfScreen = scrollPosition.value + point;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset, enabled, height, snapToOffsets],\n );\n const removeGhostPadding = useCallback((e: number) => {\n \"worklet\";\n\n // new `ScrollViewWithBottomPadding` behavior: if we hide keyboard and we are in the end of `ScrollView`\n // then we always need to scroll back, because we apply a padding that doesn't change layout, so we will\n // not have auto scroll back in this case\n if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n scrollPosition.value -\n interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [ghostViewSpace.value, 0],\n ),\n false,\n );\n\n return true;\n }\n\n return false;\n }, []);\n const performScrollWithPositionRestoration = useCallback(\n (newPosition: number) => {\n \"worklet\";\n\n const prevScroll = scrollPosition.value;\n\n // eslint-disable-next-line react-compiler/react-compiler\n scrollPosition.value = newPosition;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScroll;\n },\n [scrollPosition, keyboardHeight, maybeScroll],\n );\n const syncKeyboardFrame = useCallback(\n (e: NativeEvent) => {\n \"worklet\";\n\n const keyboardFrame = interpolate(\n e.height,\n [0, keyboardHeight.value],\n [0, keyboardHeight.value + extraKeyboardSpace],\n );\n\n currentKeyboardFrameHeight.value = keyboardFrame;\n },\n [extraKeyboardSpace],\n );\n\n const updateLayoutFromSelection = useCallback(() => {\n \"worklet\";\n\n const customHeight = lastSelection.value?.selection.end.y;\n\n if (!input.value?.layout || !customHeight) {\n return false;\n }\n\n layout.value = {\n ...input.value,\n layout: {\n ...input.value.layout,\n // when we have multiline input with limited amount of lines, then custom height can be very big\n // so we clamp it to max input height\n height: clamp(customHeight, 0, input.value.layout.height),\n },\n };\n\n return true;\n }, [input, lastSelection, layout]);\n const scrollFromCurrentPosition = useCallback(() => {\n \"worklet\";\n\n const prevLayout = layout.value;\n\n if (!updateLayoutFromSelection()) {\n return;\n }\n\n performScrollWithPositionRestoration(position.value);\n\n layout.value = prevLayout;\n }, [performScrollWithPositionRestoration]);\n const onChangeText = useCallback(() => {\n \"worklet\";\n scrollFromCurrentPosition();\n }, [scrollFromCurrentPosition]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n const onSelectionChange = useCallback(\n (e: FocusedInputSelectionChangedEvent) => {\n \"worklet\";\n\n const lastTarget = lastSelection.value?.target;\n const latestSelection = lastSelection.value?.selection;\n\n lastSelection.value = e;\n selectionUpdatedSinceHide.value = true;\n\n if (e.target !== lastTarget || pendingSelectionForFocus.value) {\n if (pendingSelectionForFocus.value) {\n // selection arrived after onStart - complete the deferred setup\n pendingSelectionForFocus.value = false;\n updateLayoutFromSelection();\n\n // if keyboard was already visible (focus change, no onMove expected),\n // perform the deferred scroll now\n if (!keyboardWillAppear.value && keyboardHeight.value > 0) {\n position.value += maybeScroll(keyboardHeight.value, true);\n }\n }\n\n return;\n }\n // caret in the end + end coordinates has been changed -> we moved to a new line\n // so input may grow\n if (\n e.selection.end.position === e.selection.start.position &&\n latestSelection?.end.y !== e.selection.end.y\n ) {\n return scrollFromCurrentPosition();\n }\n // selection has been changed\n if (e.selection.start.position !== e.selection.end.position) {\n return scrollFromCurrentPosition();\n }\n\n onChangeTextHandler();\n },\n [\n scrollFromCurrentPosition,\n onChangeTextHandler,\n updateLayoutFromSelection,\n maybeScroll,\n ],\n );\n\n useFocusedInputHandler(\n {\n onSelectionChange: onSelectionChange,\n },\n [onSelectionChange],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n\n keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;\n\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) ||\n keyboardWillChangeSize;\n\n if (keyboardWillChangeSize) {\n initialKeyboardSize.value = keyboardHeight.value;\n }\n\n if (keyboardWillHide) {\n // on back transition need to interpolate as [0, keyboardHeight]\n initialKeyboardSize.value = 0;\n scrollPosition.value = scrollBeforeKeyboardMovement.value;\n pendingSelectionForFocus.value = false;\n }\n\n if (\n keyboardWillAppear.value ||\n keyboardWillChangeSize ||\n focusWasChanged\n ) {\n // persist scroll value\n scrollPosition.value = position.value;\n // just persist height - later will be used in interpolation\n keyboardHeight.value = e.height;\n // and update keyboard spacer size\n syncKeyboardFrame(e);\n }\n\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n if (\n lastSelection.value?.target === e.target &&\n selectionUpdatedSinceHide.value\n ) {\n // fresh selection arrived before onStart - use it to update layout\n updateLayoutFromSelection();\n pendingSelectionForFocus.value = false;\n } else {\n // selection hasn't arrived yet for the new target (iOS 15),\n // or it's stale from previous session (Android refocus same input).\n // Use stale selection as best-effort fallback if available for same target,\n // otherwise fall back to full input layout.\n // Will be corrected if a fresh onSelectionChange arrives.\n if (lastSelection.value?.target === e.target) {\n updateLayoutFromSelection();\n } else if (input.value) {\n layout.value = input.value;\n }\n pendingSelectionForFocus.value = true;\n }\n\n // save current scroll position - when keyboard will hide we'll reuse\n // this value to achieve smooth hide effect\n scrollBeforeKeyboardMovement.value = position.value;\n }\n\n if (focusWasChanged && !keyboardWillAppear.value) {\n if (!pendingSelectionForFocus.value) {\n // update position on scroll value, so `onEnd` handler\n // will pick up correct values\n position.value += maybeScroll(e.height, true);\n }\n }\n\n ghostViewSpace.value =\n position.value +\n scrollViewLayout.value.height -\n scrollViewContentSize.value.height;\n\n if (ghostViewSpace.value > 0) {\n scrollPosition.value = position.value;\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n if (removeGhostPadding(e.height)) {\n return;\n }\n\n // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens\n if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {\n maybeScroll(e.height);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n removeGhostPadding(e.height);\n\n keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n\n if (e.height === 0) {\n selectionUpdatedSinceHide.value = false;\n } else if (keyboardWillAppear.value) {\n // keyboard fully shown after appearing from hidden state — clear\n // pending flag to prevent leaking into next focus-change session.\n // Only when the keyboard was actually appearing (not a focus switch\n // with same keyboard height), otherwise we'd clear the flag before\n // onSelectionChange has a chance to process it.\n pendingSelectionForFocus.value = false;\n }\n\n syncKeyboardFrame(e);\n },\n },\n [\n maybeScroll,\n removeGhostPadding,\n disableScrollOnKeyboardHide,\n syncKeyboardFrame,\n ],\n );\n\n const synchronize = useCallback(async () => {\n await update();\n\n runOnUI(() => {\n \"worklet\";\n\n scrollFromCurrentPosition();\n })();\n }, [update, scrollFromCurrentPosition]);\n\n useImperativeHandle(\n ref,\n () => {\n const scrollView = scrollViewRef.current;\n\n if (scrollView) {\n const scrollViewWithMethods =\n scrollView as KeyboardAwareScrollViewRef;\n\n scrollViewWithMethods.assureFocusedInputVisible = () => {\n synchronize();\n };\n\n return scrollViewWithMethods;\n }\n\n return {\n assureFocusedInputVisible: () => {\n synchronize();\n },\n } as KeyboardAwareScrollViewRef;\n },\n [synchronize],\n );\n\n useEffect(() => {\n synchronize();\n }, [bottomOffset]);\n\n useAnimatedReaction(\n () => input.value,\n (current, previous) => {\n if (\n current?.target === previous?.target &&\n current?.layout.height !== previous?.layout.height\n ) {\n // input has changed layout - let's check if we need to scroll\n // may happen when you paste text, then onSelectionChange will be\n // fired earlier than text actually changes its layout\n scrollFromCurrentPosition();\n }\n },\n [],\n );\n\n const padding = useDerivedValue(\n () => (enabled ? currentKeyboardFrameHeight.value : 0),\n [enabled],\n );\n\n return (\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n bottomPadding={padding}\n scrollEventThrottle={16}\n ScrollViewComponent={ScrollViewComponent}\n onLayout={onScrollViewLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n );\n },\n);\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","forwardRef","useCallback","useEffect","useImperativeHandle","useMemo","Reanimated","clamp","interpolate","runOnUI","scrollTo","useAnimatedReaction","useAnimatedRef","useAnimatedStyle","useDerivedValue","useSharedValue","KeyboardControllerNative","useFocusedInputHandler","useReanimatedFocusedInput","useWindowDimensions","findNodeHandle","useCombinedRef","useScrollState","ScrollViewWithBottomPadding","useSmoothKeyboardHandler","debounce","scrollDistanceWithRespectToSnapPoints","KeyboardAwareScrollView","children","onLayout","bottomOffset","disableScrollOnKeyboardHide","enabled","extraKeyboardSpace","mode","ScrollViewComponent","ScrollView","snapToOffsets","rest","ref","scrollViewAnimatedRef","scrollViewRef","useRef","onRef","scrollViewTarget","scrollPosition","offset","position","layout","scrollViewLayout","size","scrollViewContentSize","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","update","lastSelection","ghostViewSpace","pendingSelectionForFocus","selectionUpdatedSinceHide","scrollViewPageY","height","onScrollViewLayout","e","handle","current","value","y","viewPositionInWindow","maybeScroll","animated","_layout$value","_layout$value2","_layout$value3","parentScrollViewTarget","visibleRect","absoluteY","inputHeight","point","relativeScrollTo","interpolatedScrollTo","targetScrollY","Math","max","positionOnScreen","topOfScreen","removeGhostPadding","performScrollWithPositionRestoration","newPosition","prevScroll","syncKeyboardFrame","keyboardFrame","updateLayoutFromSelection","_lastSelection$value","_input$value","customHeight","selection","end","scrollFromCurrentPosition","prevLayout","onChangeText","onChangeTextHandler","onSelectionChange","_lastSelection$value2","_lastSelection$value3","lastTarget","target","latestSelection","start","onStart","keyboardWillChangeSize","keyboardWillHide","focusWasChanged","_lastSelection$value4","_lastSelection$value5","onMove","onEnd","synchronize","scrollView","scrollViewWithMethods","assureFocusedInputVisible","previous","padding","layoutSpacerStyle","paddingBottom","createElement","_extends","scrollEventThrottle","View","style","bottomPadding"],"sources":["index.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n} from \"react\";\nimport Reanimated, {\n clamp,\n interpolate,\n runOnUI,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { KeyboardControllerNative } from \"../../bindings\";\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n useWindowDimensions,\n} from \"../../hooks\";\nimport { findNodeHandle } from \"../../utils/findNodeHandle\";\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport useScrollState from \"../hooks/useScrollState\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce, scrollDistanceWithRespectToSnapPoints } from \"./utils\";\n\nimport type { LayoutChangeEvent, ScrollView } from \"react-native\";\nimport type {\n FocusedInputLayoutChangedEvent,\n FocusedInputSelectionChangedEvent,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n NativeEvent,\n} from \"react-native-keyboard-controller\";\n\n// Everything begins from `onStart` handler. This handler is called every time,\n// when keyboard changes its size or when focused `TextInput` was changed. In\n// this handler we are calculating/memoizing values which later will be used\n// during layout movement. For that we calculate:\n// - layout of focused field (`layout`) - to understand whether there will be overlap\n// - initial keyboard size (`initialKeyboardSize`) - used in scroll interpolation\n// - future keyboard height (`keyboardHeight`) - used in scroll interpolation\n// - current scroll position (`scrollPosition`) - used to scroll from this point\n//\n// Once we've calculated all necessary variables - we can actually start to use them.\n// It happens in `onMove` handler - this function simply calls `maybeScroll` with\n// current keyboard frame height. This functions makes the smooth transition.\n//\n// When the transition has finished we go to `onEnd` handler. In this handler\n// we verify, that the current field is not overlapped within a keyboard frame.\n// For full `onStart`/`onMove`/`onEnd` flow it may look like a redundant thing,\n// however there could be some cases, when `onMove` is not called:\n// - on iOS when TextInput was changed - keyboard transition is instant\n// - on Android when TextInput was changed and keyboard size wasn't changed\n// So `onEnd` handler handle the case, when `onMove` wasn't triggered.\n//\n// ====================================================================================================================+\n// -----------------------------------------------------Flow chart-----------------------------------------------------+\n// ====================================================================================================================+\n//\n// +============================+ +============================+ +==================================+\n// + User Press on TextInput + => + Keyboard starts showing + => + As keyboard moves frame by frame + =>\n// + + + (run `onStart`) + + `onMove` is getting called +\n// +============================+ +============================+ +==================================+\n//\n// +============================+ +============================+ +=====================================+\n// + Keyboard is shown and we + => + User moved focus to + => + Only `onStart`/`onEnd` maybe called +\n// + call `onEnd` handler + + another `TextInput` + + (without involving `onMove`) +\n// +============================+ +============================+ +=====================================+\n//\n\n/**\n * A ScrollView component that automatically handles keyboard appearance and disappearance\n * by adjusting its content position to ensure the focused input remains visible.\n *\n * The component uses a sophisticated animation system to smoothly handle keyboard transitions\n * and maintain proper scroll position during keyboard interactions.\n *\n * @returns A ScrollView component that handles keyboard interactions.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-aware-scroll-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAwareScrollView bottomOffset={20}>\n * <TextInput placeholder=\"Enter text\" />\n * <TextInput placeholder=\"Another input\" />\n * </KeyboardAwareScrollView>\n * ```\n */\nconst KeyboardAwareScrollView = forwardRef<\n KeyboardAwareScrollViewRef,\n React.PropsWithChildren<KeyboardAwareScrollViewProps>\n>(\n (\n {\n children,\n onLayout,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n enabled = true,\n extraKeyboardSpace = 0,\n mode = \"insets\",\n ScrollViewComponent = Reanimated.ScrollView,\n snapToOffsets,\n ...rest\n },\n ref,\n ) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollViewRef = React.useRef<ScrollView>(null);\n const onRef = useCombinedRef(scrollViewAnimatedRef, scrollViewRef);\n const scrollViewTarget = useSharedValue<number | null>(null);\n const scrollPosition = useSharedValue(0);\n const {\n offset: position,\n layout: scrollViewLayout,\n size: scrollViewContentSize,\n } = useScrollState(scrollViewAnimatedRef);\n const currentKeyboardFrameHeight = useSharedValue(0);\n const keyboardHeight = useSharedValue(0);\n const keyboardWillAppear = useSharedValue(false);\n const tag = useSharedValue(-1);\n const initialKeyboardSize = useSharedValue(0);\n const scrollBeforeKeyboardMovement = useSharedValue(0);\n const { input, update } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n const lastSelection =\n useSharedValue<FocusedInputSelectionChangedEvent | null>(null);\n const ghostViewSpace = useSharedValue(-1);\n const pendingSelectionForFocus = useSharedValue(false);\n const selectionUpdatedSinceHide = useSharedValue(false);\n const scrollViewPageY = useSharedValue(0);\n\n const { height } = useWindowDimensions();\n\n const onScrollViewLayout = useCallback(\n async (e: LayoutChangeEvent) => {\n const handle = findNodeHandle(scrollViewAnimatedRef.current);\n\n scrollViewTarget.value = handle;\n\n onLayout?.(e);\n\n if (handle !== null) {\n try {\n const { y } = await KeyboardControllerNative.viewPositionInWindow(\n handle,\n );\n\n scrollViewPageY.value = y;\n } catch {\n // ignore\n }\n }\n },\n [onLayout],\n );\n\n /**\n * Function that will scroll a ScrollView as keyboard gets moving.\n */\n const maybeScroll = useCallback(\n (e: number, animated: boolean = false) => {\n \"worklet\";\n\n if (!enabled) {\n return 0;\n }\n\n // input belongs to ScrollView\n if (layout.value?.parentScrollViewTarget !== scrollViewTarget.value) {\n return 0;\n }\n\n const visibleRect = height - keyboardHeight.value;\n const absoluteY = layout.value?.layout.absoluteY || 0;\n const inputHeight = layout.value?.layout.height || 0;\n const point = absoluteY + inputHeight;\n\n if (visibleRect - point <= bottomOffset) {\n const relativeScrollTo =\n keyboardHeight.value - (height - point) + bottomOffset;\n const interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [\n 0,\n scrollDistanceWithRespectToSnapPoints(\n relativeScrollTo + scrollPosition.value,\n snapToOffsets,\n ) - scrollPosition.value,\n ],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (point < scrollViewPageY.value) {\n const positionOnScreen = visibleRect - bottomOffset;\n const topOfScreen = scrollPosition.value + point;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset, enabled, height, snapToOffsets],\n );\n const removeGhostPadding = useCallback(\n (e: number) => {\n \"worklet\";\n\n // layout mode: the spacer view participates in layout, so the ScrollView\n // reflows naturally when it shrinks — no manual scroll correction needed.\n if (mode === \"layout\") {\n return false;\n }\n\n // insets mode: `ScrollViewWithBottomPadding` extends scrollable area without\n // changing layout, so when the keyboard hides and we're at the end of the\n // ScrollView we must manually scroll back.\n if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n scrollPosition.value -\n interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [ghostViewSpace.value, 0],\n ),\n false,\n );\n\n return true;\n }\n\n return false;\n },\n [mode],\n );\n const performScrollWithPositionRestoration = useCallback(\n (newPosition: number) => {\n \"worklet\";\n\n const prevScroll = scrollPosition.value;\n\n // eslint-disable-next-line react-compiler/react-compiler\n scrollPosition.value = newPosition;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScroll;\n },\n [scrollPosition, keyboardHeight, maybeScroll],\n );\n const syncKeyboardFrame = useCallback(\n (e: NativeEvent) => {\n \"worklet\";\n\n const keyboardFrame = interpolate(\n e.height,\n [0, keyboardHeight.value],\n [0, keyboardHeight.value + extraKeyboardSpace],\n );\n\n currentKeyboardFrameHeight.value = keyboardFrame;\n },\n [extraKeyboardSpace],\n );\n\n const updateLayoutFromSelection = useCallback(() => {\n \"worklet\";\n\n const customHeight = lastSelection.value?.selection.end.y;\n\n if (!input.value?.layout || !customHeight) {\n return false;\n }\n\n layout.value = {\n ...input.value,\n layout: {\n ...input.value.layout,\n // when we have multiline input with limited amount of lines, then custom height can be very big\n // so we clamp it to max input height\n height: clamp(customHeight, 0, input.value.layout.height),\n },\n };\n\n return true;\n }, [input, lastSelection, layout]);\n const scrollFromCurrentPosition = useCallback(() => {\n \"worklet\";\n\n const prevLayout = layout.value;\n\n if (!updateLayoutFromSelection()) {\n return;\n }\n\n performScrollWithPositionRestoration(position.value);\n\n layout.value = prevLayout;\n }, [performScrollWithPositionRestoration]);\n const onChangeText = useCallback(() => {\n \"worklet\";\n scrollFromCurrentPosition();\n }, [scrollFromCurrentPosition]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n const onSelectionChange = useCallback(\n (e: FocusedInputSelectionChangedEvent) => {\n \"worklet\";\n\n const lastTarget = lastSelection.value?.target;\n const latestSelection = lastSelection.value?.selection;\n\n lastSelection.value = e;\n selectionUpdatedSinceHide.value = true;\n\n if (e.target !== lastTarget || pendingSelectionForFocus.value) {\n if (pendingSelectionForFocus.value) {\n // selection arrived after onStart - complete the deferred setup\n pendingSelectionForFocus.value = false;\n updateLayoutFromSelection();\n\n // if keyboard was already visible (focus change, no onMove expected),\n // perform the deferred scroll now\n if (!keyboardWillAppear.value && keyboardHeight.value > 0) {\n position.value += maybeScroll(keyboardHeight.value, true);\n }\n }\n\n return;\n }\n // caret in the end + end coordinates has been changed -> we moved to a new line\n // so input may grow\n if (\n e.selection.end.position === e.selection.start.position &&\n latestSelection?.end.y !== e.selection.end.y\n ) {\n return scrollFromCurrentPosition();\n }\n // selection has been changed\n if (e.selection.start.position !== e.selection.end.position) {\n return scrollFromCurrentPosition();\n }\n\n onChangeTextHandler();\n },\n [\n scrollFromCurrentPosition,\n onChangeTextHandler,\n updateLayoutFromSelection,\n maybeScroll,\n ],\n );\n\n useFocusedInputHandler(\n {\n onSelectionChange: onSelectionChange,\n },\n [onSelectionChange],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n\n keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;\n\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) ||\n keyboardWillChangeSize;\n\n if (keyboardWillChangeSize) {\n initialKeyboardSize.value = keyboardHeight.value;\n }\n\n if (keyboardWillHide) {\n // on back transition need to interpolate as [0, keyboardHeight]\n initialKeyboardSize.value = 0;\n scrollPosition.value = scrollBeforeKeyboardMovement.value;\n pendingSelectionForFocus.value = false;\n }\n\n if (\n keyboardWillAppear.value ||\n keyboardWillChangeSize ||\n focusWasChanged\n ) {\n // persist scroll value\n scrollPosition.value = position.value;\n // just persist height - later will be used in interpolation\n keyboardHeight.value = e.height;\n\n // insets mode: set the full contentInset upfront so that maybeScroll\n // calculations are correct from the very first onMove frame.\n // layout mode: do NOT set it here — the spacer must grow frame-by-frame\n // in onMove to avoid a premature full-height jump before the keyboard moves.\n if (mode === \"insets\") {\n syncKeyboardFrame(e);\n }\n }\n\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n if (\n lastSelection.value?.target === e.target &&\n selectionUpdatedSinceHide.value\n ) {\n // fresh selection arrived before onStart - use it to update layout\n updateLayoutFromSelection();\n pendingSelectionForFocus.value = false;\n } else {\n // selection hasn't arrived yet for the new target (iOS 15),\n // or it's stale from previous session (Android refocus same input).\n // Use stale selection as best-effort fallback if available for same target,\n // otherwise fall back to full input layout.\n // Will be corrected if a fresh onSelectionChange arrives.\n if (lastSelection.value?.target === e.target) {\n updateLayoutFromSelection();\n } else if (input.value) {\n layout.value = input.value;\n }\n pendingSelectionForFocus.value = true;\n }\n\n // save current scroll position - when keyboard will hide we'll reuse\n // this value to achieve smooth hide effect\n scrollBeforeKeyboardMovement.value = position.value;\n }\n\n if (focusWasChanged && !keyboardWillAppear.value) {\n if (!pendingSelectionForFocus.value) {\n // update position on scroll value, so `onEnd` handler\n // will pick up correct values\n position.value += maybeScroll(e.height, true);\n }\n }\n\n if (mode === \"insets\") {\n ghostViewSpace.value =\n position.value +\n scrollViewLayout.value.height -\n scrollViewContentSize.value.height;\n\n if (ghostViewSpace.value > 0) {\n scrollPosition.value = position.value;\n }\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n if (removeGhostPadding(e.height)) {\n return;\n }\n\n // layout mode: drive the spacer view animation frame-by-frame\n if (mode === \"layout\") {\n syncKeyboardFrame(e);\n }\n\n // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens\n if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {\n maybeScroll(e.height);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n removeGhostPadding(e.height);\n\n keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n\n if (e.height === 0) {\n selectionUpdatedSinceHide.value = false;\n } else if (keyboardWillAppear.value) {\n // keyboard fully shown after appearing from hidden state — clear\n // pending flag to prevent leaking into next focus-change session.\n // Only when the keyboard was actually appearing (not a focus switch\n // with same keyboard height), otherwise we'd clear the flag before\n // onSelectionChange has a chance to process it.\n pendingSelectionForFocus.value = false;\n }\n\n syncKeyboardFrame(e);\n },\n },\n [\n mode,\n maybeScroll,\n removeGhostPadding,\n disableScrollOnKeyboardHide,\n syncKeyboardFrame,\n ],\n );\n\n const synchronize = useCallback(async () => {\n await update();\n\n runOnUI(() => {\n \"worklet\";\n\n scrollFromCurrentPosition();\n })();\n }, [update, scrollFromCurrentPosition]);\n\n useImperativeHandle(\n ref,\n () => {\n const scrollView = scrollViewRef.current;\n\n if (scrollView) {\n const scrollViewWithMethods =\n scrollView as KeyboardAwareScrollViewRef;\n\n scrollViewWithMethods.assureFocusedInputVisible = () => {\n synchronize();\n };\n\n return scrollViewWithMethods;\n }\n\n return {\n assureFocusedInputVisible: () => {\n synchronize();\n },\n } as KeyboardAwareScrollViewRef;\n },\n [synchronize],\n );\n\n useEffect(() => {\n synchronize();\n }, [bottomOffset]);\n\n useAnimatedReaction(\n () => input.value,\n (current, previous) => {\n if (\n current?.target === previous?.target &&\n current?.layout.height !== previous?.layout.height\n ) {\n // input has changed layout - let's check if we need to scroll\n // may happen when you paste text, then onSelectionChange will be\n // fired earlier than text actually changes its layout\n scrollFromCurrentPosition();\n }\n },\n [],\n );\n\n const padding = useDerivedValue(\n () => (enabled ? currentKeyboardFrameHeight.value : 0),\n [enabled],\n );\n // layout mode only: a spacer view whose paddingBottom grows with the keyboard.\n // The `+ 1` ensures the scroll view never reaches its absolute end during animation,\n // avoiding the layout recalculation that triggers on every frame at the boundary.\n // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342\n const layoutSpacerStyle = useAnimatedStyle(\n () =>\n enabled && mode === \"layout\"\n ? { paddingBottom: currentKeyboardFrameHeight.value + 1 }\n : {},\n [enabled, mode],\n );\n\n if (mode === \"layout\") {\n return (\n <ScrollViewComponent\n ref={onRef}\n {...rest}\n scrollEventThrottle={16}\n onLayout={onScrollViewLayout}\n >\n {children}\n {enabled && <Reanimated.View style={layoutSpacerStyle} />}\n </ScrollViewComponent>\n );\n }\n\n return (\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n bottomPadding={padding}\n scrollEventThrottle={16}\n ScrollViewComponent={ScrollViewComponent}\n onLayout={onScrollViewLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n );\n },\n);\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type { AnimatedScrollViewComponent } from \"../ScrollViewWithBottomPadding\";\nimport type { ScrollView, ScrollViewProps } from \"react-native\";\n\nexport type KeyboardAwareScrollViewProps = {\n /** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */\n bottomOffset?: number;\n /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */\n disableScrollOnKeyboardHide?: boolean;\n /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true`. */\n enabled?: boolean;\n /** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */\n extraKeyboardSpace?: number;\n /** Custom component for `ScrollView`. Default is `ScrollView`. */\n ScrollViewComponent?: AnimatedScrollViewComponent;\n} & ScrollViewProps;\nexport type KeyboardAwareScrollViewRef = {\n assureFocusedInputVisible: () => void;\n} & ScrollView;\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type { AnimatedScrollViewComponent } from \"../ScrollViewWithBottomPadding\";\nimport type { ScrollView, ScrollViewProps } from \"react-native\";\n\nexport type KeyboardAwareScrollViewMode = \"insets\" | \"layout\";\n\nexport type KeyboardAwareScrollViewProps = {\n /** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */\n bottomOffset?: number;\n /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */\n disableScrollOnKeyboardHide?: boolean;\n /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true`. */\n enabled?: boolean;\n /** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */\n extraKeyboardSpace?: number;\n /**\n * Controls how keyboard space is created at the bottom of the `ScrollView`.\n *\n * - `\"insets\"` *(default)*: Extends the scrollable area via `contentInset` (iOS) and `ClippingScrollView` (Android). No layout reflow occurs — content positions remain stable during keyboard animation. Recommended for most use cases.\n * - `\"layout\"`: Appends a spacer `View` as the last child of the `ScrollView`. The spacer participates in layout, so flex-based arrangements (e.g. `justifyContent: \"space-between\"`, `gap`) reflow naturally when the keyboard appears. Use this when you need content to physically rearrange around the keyboard space.\n *\n * Default is `\"insets\"`.\n */\n mode?: KeyboardAwareScrollViewMode;\n /** Custom component for `ScrollView`. Default is `ScrollView`. */\n ScrollViewComponent?: AnimatedScrollViewComponent;\n} & ScrollViewProps;\nexport type KeyboardAwareScrollViewRef = {\n assureFocusedInputVisible: () => void;\n} & ScrollView;\n"],"mappings":"","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import { Platform } from "react-native";
1
+ import { KEYBOARD_BORDER_RADIUS } from "../../constants";
2
2
  export const TEST_ID_KEYBOARD_TOOLBAR = "keyboard.toolbar";
3
3
  export const TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS = `${TEST_ID_KEYBOARD_TOOLBAR}.previous`;
4
4
  export const TEST_ID_KEYBOARD_TOOLBAR_NEXT = `${TEST_ID_KEYBOARD_TOOLBAR}.next`;
@@ -6,6 +6,6 @@ export const TEST_ID_KEYBOARD_TOOLBAR_CONTENT = `${TEST_ID_KEYBOARD_TOOLBAR}.con
6
6
  export const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;
7
7
  export const KEYBOARD_TOOLBAR_HEIGHT = 42;
8
8
  export const DEFAULT_OPACITY = "FF";
9
- export const KEYBOARD_HAS_ROUNDED_CORNERS = Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26;
9
+ export const KEYBOARD_HAS_ROUNDED_CORNERS = KEYBOARD_BORDER_RADIUS > 0;
10
10
  export const OPENED_OFFSET = KEYBOARD_HAS_ROUNDED_CORNERS ? -11 : 0;
11
11
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Platform","TEST_ID_KEYBOARD_TOOLBAR","TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS","TEST_ID_KEYBOARD_TOOLBAR_NEXT","TEST_ID_KEYBOARD_TOOLBAR_CONTENT","TEST_ID_KEYBOARD_TOOLBAR_DONE","KEYBOARD_TOOLBAR_HEIGHT","DEFAULT_OPACITY","KEYBOARD_HAS_ROUNDED_CORNERS","OS","parseInt","Version","OPENED_OFFSET"],"sources":["constants.ts"],"sourcesContent":["import { Platform } from \"react-native\";\n\nimport type { HEX } from \"./types\";\n\nexport const TEST_ID_KEYBOARD_TOOLBAR = \"keyboard.toolbar\";\nexport const TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS = `${TEST_ID_KEYBOARD_TOOLBAR}.previous`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_NEXT = `${TEST_ID_KEYBOARD_TOOLBAR}.next`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_CONTENT = `${TEST_ID_KEYBOARD_TOOLBAR}.content`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;\n\nexport const KEYBOARD_TOOLBAR_HEIGHT = 42;\nexport const DEFAULT_OPACITY: HEX = \"FF\";\nexport const KEYBOARD_HAS_ROUNDED_CORNERS =\n Platform.OS === \"ios\" && parseInt(Platform.Version, 10) >= 26;\nexport const OPENED_OFFSET = KEYBOARD_HAS_ROUNDED_CORNERS ? -11 : 0;\n"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,cAAc;AAIvC,OAAO,MAAMC,wBAAwB,GAAG,kBAAkB;AAC1D,OAAO,MAAMC,iCAAiC,GAAG,GAAGD,wBAAwB,WAAW;AACvF,OAAO,MAAME,6BAA6B,GAAG,GAAGF,wBAAwB,OAAO;AAC/E,OAAO,MAAMG,gCAAgC,GAAG,GAAGH,wBAAwB,UAAU;AACrF,OAAO,MAAMI,6BAA6B,GAAG,GAAGJ,wBAAwB,OAAO;AAE/E,OAAO,MAAMK,uBAAuB,GAAG,EAAE;AACzC,OAAO,MAAMC,eAAoB,GAAG,IAAI;AACxC,OAAO,MAAMC,4BAA4B,GACvCR,QAAQ,CAACS,EAAE,KAAK,KAAK,IAAIC,QAAQ,CAACV,QAAQ,CAACW,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE;AAC/D,OAAO,MAAMC,aAAa,GAAGJ,4BAA4B,GAAG,CAAC,EAAE,GAAG,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["KEYBOARD_BORDER_RADIUS","TEST_ID_KEYBOARD_TOOLBAR","TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS","TEST_ID_KEYBOARD_TOOLBAR_NEXT","TEST_ID_KEYBOARD_TOOLBAR_CONTENT","TEST_ID_KEYBOARD_TOOLBAR_DONE","KEYBOARD_TOOLBAR_HEIGHT","DEFAULT_OPACITY","KEYBOARD_HAS_ROUNDED_CORNERS","OPENED_OFFSET"],"sources":["constants.ts"],"sourcesContent":["import { KEYBOARD_BORDER_RADIUS } from \"../../constants\";\n\nimport type { HEX } from \"./types\";\n\nexport const TEST_ID_KEYBOARD_TOOLBAR = \"keyboard.toolbar\";\nexport const TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS = `${TEST_ID_KEYBOARD_TOOLBAR}.previous`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_NEXT = `${TEST_ID_KEYBOARD_TOOLBAR}.next`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_CONTENT = `${TEST_ID_KEYBOARD_TOOLBAR}.content`;\nexport const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;\n\nexport const KEYBOARD_TOOLBAR_HEIGHT = 42;\nexport const DEFAULT_OPACITY: HEX = \"FF\";\nexport const KEYBOARD_HAS_ROUNDED_CORNERS = KEYBOARD_BORDER_RADIUS > 0;\nexport const OPENED_OFFSET = KEYBOARD_HAS_ROUNDED_CORNERS ? -11 : 0;\n"],"mappings":"AAAA,SAASA,sBAAsB,QAAQ,iBAAiB;AAIxD,OAAO,MAAMC,wBAAwB,GAAG,kBAAkB;AAC1D,OAAO,MAAMC,iCAAiC,GAAG,GAAGD,wBAAwB,WAAW;AACvF,OAAO,MAAME,6BAA6B,GAAG,GAAGF,wBAAwB,OAAO;AAC/E,OAAO,MAAMG,gCAAgC,GAAG,GAAGH,wBAAwB,UAAU;AACrF,OAAO,MAAMI,6BAA6B,GAAG,GAAGJ,wBAAwB,OAAO;AAE/E,OAAO,MAAMK,uBAAuB,GAAG,EAAE;AACzC,OAAO,MAAMC,eAAoB,GAAG,IAAI;AACxC,OAAO,MAAMC,4BAA4B,GAAGR,sBAAsB,GAAG,CAAC;AACtE,OAAO,MAAMS,aAAa,GAAGD,4BAA4B,GAAG,CAAC,EAAE,GAAG,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["default","KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","KeyboardChatScrollView"],"sources":["index.ts"],"sourcesContent":["export { default as KeyboardAvoidingView } from \"./KeyboardAvoidingView\";\nexport { default as KeyboardStickyView } from \"./KeyboardStickyView\";\nexport { default as KeyboardAwareScrollView } from \"./KeyboardAwareScrollView\";\nexport {\n default as KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./KeyboardToolbar\";\nexport { default as KeyboardChatScrollView } from \"./KeyboardChatScrollView\";\nexport type { KeyboardAvoidingViewProps } from \"./KeyboardAvoidingView\";\nexport type { KeyboardStickyViewProps } from \"./KeyboardStickyView\";\nexport type {\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n} from \"./KeyboardAwareScrollView/types\";\nexport type { KeyboardToolbarProps } from \"./KeyboardToolbar\";\nexport type { KeyboardChatScrollViewProps } from \"./KeyboardChatScrollView/types\";\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,oBAAoB,QAAQ,wBAAwB;AACxE,SAASD,OAAO,IAAIE,kBAAkB,QAAQ,sBAAsB;AACpE,SAASF,OAAO,IAAIG,uBAAuB,QAAQ,2BAA2B;AAC9E,SACEH,OAAO,IAAII,eAAe,EAC1BC,2BAA2B,QACtB,mBAAmB;AAC1B,SAASL,OAAO,IAAIM,sBAAsB,QAAQ,0BAA0B","ignoreList":[]}
1
+ {"version":3,"names":["default","KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","KeyboardChatScrollView"],"sources":["index.ts"],"sourcesContent":["export { default as KeyboardAvoidingView } from \"./KeyboardAvoidingView\";\nexport { default as KeyboardStickyView } from \"./KeyboardStickyView\";\nexport { default as KeyboardAwareScrollView } from \"./KeyboardAwareScrollView\";\nexport {\n default as KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./KeyboardToolbar\";\nexport { default as KeyboardChatScrollView } from \"./KeyboardChatScrollView\";\nexport type { KeyboardAvoidingViewProps } from \"./KeyboardAvoidingView\";\nexport type { KeyboardStickyViewProps } from \"./KeyboardStickyView\";\nexport type {\n KeyboardAwareScrollViewMode,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n} from \"./KeyboardAwareScrollView/types\";\nexport type { KeyboardToolbarProps } from \"./KeyboardToolbar\";\nexport type { KeyboardChatScrollViewProps } from \"./KeyboardChatScrollView/types\";\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,oBAAoB,QAAQ,wBAAwB;AACxE,SAASD,OAAO,IAAIE,kBAAkB,QAAQ,sBAAsB;AACpE,SAASF,OAAO,IAAIG,uBAAuB,QAAQ,2BAA2B;AAC9E,SACEH,OAAO,IAAII,eAAe,EAC1BC,2BAA2B,QACtB,mBAAmB;AAC1B,SAASL,OAAO,IAAIM,sBAAsB,QAAQ,0BAA0B","ignoreList":[]}
@@ -1,3 +1,5 @@
1
+ import { KeyboardControllerNative } from "./bindings";
2
+
1
3
  // copied from `android.view.WindowManager.LayoutParams`
2
4
  export let AndroidSoftInputModes = /*#__PURE__*/function (AndroidSoftInputModes) {
3
5
  AndroidSoftInputModes[AndroidSoftInputModes["SOFT_INPUT_ADJUST_NOTHING"] = 48] = "SOFT_INPUT_ADJUST_NOTHING";
@@ -18,4 +20,5 @@ export let AndroidSoftInputModes = /*#__PURE__*/function (AndroidSoftInputModes)
18
20
  AndroidSoftInputModes[AndroidSoftInputModes["SOFT_INPUT_STATE_VISIBLE"] = 4] = "SOFT_INPUT_STATE_VISIBLE";
19
21
  return AndroidSoftInputModes;
20
22
  }({});
23
+ export const KEYBOARD_BORDER_RADIUS = KeyboardControllerNative.getConstants().keyboardBorderRadius;
21
24
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["AndroidSoftInputModes"],"sources":["constants.ts"],"sourcesContent":["// copied from `android.view.WindowManager.LayoutParams`\nexport enum AndroidSoftInputModes {\n SOFT_INPUT_ADJUST_NOTHING = 48,\n SOFT_INPUT_ADJUST_PAN = 32,\n SOFT_INPUT_ADJUST_RESIZE = 16,\n SOFT_INPUT_ADJUST_UNSPECIFIED = 0,\n SOFT_INPUT_IS_FORWARD_NAVIGATION = 256,\n SOFT_INPUT_MASK_ADJUST = 240,\n SOFT_INPUT_MASK_STATE = 15,\n SOFT_INPUT_MODE_CHANGED = 512,\n SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3,\n SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5,\n SOFT_INPUT_STATE_HIDDEN = 2,\n SOFT_INPUT_STATE_UNCHANGED = 1,\n // temporarily disable this rule to avoid breaking changes.\n // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values\n SOFT_INPUT_STATE_UNSPECIFIED = 0,\n SOFT_INPUT_STATE_VISIBLE = 4,\n}\n"],"mappings":"AAAA;AACA,WAAYA,qBAAqB,0BAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAa/B;EACA;EAdUA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAAA,OAArBA,qBAAqB;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["KeyboardControllerNative","AndroidSoftInputModes","KEYBOARD_BORDER_RADIUS","getConstants","keyboardBorderRadius"],"sources":["constants.ts"],"sourcesContent":["import { KeyboardControllerNative } from \"./bindings\";\n\n// copied from `android.view.WindowManager.LayoutParams`\nexport enum AndroidSoftInputModes {\n SOFT_INPUT_ADJUST_NOTHING = 48,\n SOFT_INPUT_ADJUST_PAN = 32,\n SOFT_INPUT_ADJUST_RESIZE = 16,\n SOFT_INPUT_ADJUST_UNSPECIFIED = 0,\n SOFT_INPUT_IS_FORWARD_NAVIGATION = 256,\n SOFT_INPUT_MASK_ADJUST = 240,\n SOFT_INPUT_MASK_STATE = 15,\n SOFT_INPUT_MODE_CHANGED = 512,\n SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3,\n SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5,\n SOFT_INPUT_STATE_HIDDEN = 2,\n SOFT_INPUT_STATE_UNCHANGED = 1,\n // temporarily disable this rule to avoid breaking changes.\n // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values\n SOFT_INPUT_STATE_UNSPECIFIED = 0,\n SOFT_INPUT_STATE_VISIBLE = 4,\n}\nexport const KEYBOARD_BORDER_RADIUS =\n KeyboardControllerNative.getConstants().keyboardBorderRadius;\n"],"mappings":"AAAA,SAASA,wBAAwB,QAAQ,YAAY;;AAErD;AACA,WAAYC,qBAAqB,0BAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAa/B;EACA;EAdUA,qBAAqB,CAArBA,qBAAqB;EAArBA,qBAAqB,CAArBA,qBAAqB;EAAA,OAArBA,qBAAqB;AAAA;AAkBjC,OAAO,MAAMC,sBAAsB,GACjCF,wBAAwB,CAACG,YAAY,CAAC,CAAC,CAACC,oBAAoB","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["KeyboardChatScrollView","KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","OverKeyboardView","KeyboardExtender"],"sources":["index.ts"],"sourcesContent":["export * from \"./bindings\";\nexport * from \"./animated\";\nexport * from \"./context\";\nexport * from \"./hooks\";\nexport * from \"./constants\";\nexport * from \"./module\";\nexport * from \"./types\";\nexport * from \"./compat\";\n\nexport {\n KeyboardChatScrollView,\n KeyboardAvoidingView,\n KeyboardStickyView,\n KeyboardAwareScrollView,\n // keyboard toolbar\n KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./components\";\nexport type {\n KeyboardChatScrollViewProps,\n KeyboardAvoidingViewProps,\n KeyboardStickyViewProps,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n KeyboardToolbarProps,\n} from \"./components\";\nexport { OverKeyboardView, KeyboardExtender } from \"./views\";\n"],"mappings":"AAAA,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,UAAU;AACxB,cAAc,SAAS;AACvB,cAAc,UAAU;AAExB,SACEA,sBAAsB,EACtBC,oBAAoB,EACpBC,kBAAkB,EAClBC,uBAAuB;AACvB;AACAC,eAAe,EACfC,2BAA2B,QACtB,cAAc;AASrB,SAASC,gBAAgB,EAAEC,gBAAgB,QAAQ,SAAS","ignoreList":[]}
1
+ {"version":3,"names":["KeyboardChatScrollView","KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","OverKeyboardView","KeyboardExtender"],"sources":["index.ts"],"sourcesContent":["export * from \"./bindings\";\nexport * from \"./animated\";\nexport * from \"./context\";\nexport * from \"./hooks\";\nexport * from \"./constants\";\nexport * from \"./module\";\nexport * from \"./types\";\nexport * from \"./compat\";\n\nexport {\n KeyboardChatScrollView,\n KeyboardAvoidingView,\n KeyboardStickyView,\n KeyboardAwareScrollView,\n // keyboard toolbar\n KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./components\";\nexport type {\n KeyboardChatScrollViewProps,\n KeyboardAvoidingViewProps,\n KeyboardStickyViewProps,\n KeyboardAwareScrollViewMode,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n KeyboardToolbarProps,\n} from \"./components\";\nexport { OverKeyboardView, KeyboardExtender } from \"./views\";\n"],"mappings":"AAAA,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,UAAU;AACxB,cAAc,SAAS;AACvB,cAAc,UAAU;AAExB,SACEA,sBAAsB,EACtBC,oBAAoB,EACpBC,kBAAkB,EAClBC,uBAAuB;AACvB;AACAC,eAAe,EACfC,2BAA2B,QACtB,cAAc;AAUrB,SAASC,gBAAgB,EAAEC,gBAAgB,QAAQ,SAAS","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","get"],"sources":["NativeKeyboardController.ts"],"sourcesContent":["import { TurboModuleRegistry } from \"react-native\";\n\nimport type { TurboModule } from \"react-native\";\n\nexport interface Spec extends TurboModule {\n readonly getConstants: () => {};\n\n // methods\n setInputMode(mode: number): void;\n setDefaultMode(): void;\n preload(): void;\n dismiss(keepFocus: boolean, animated: boolean): void;\n setFocusTo(direction: string): void;\n viewPositionInWindow(viewTag: number): Promise<object>;\n\n // event emitter\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n}\n\nexport default TurboModuleRegistry.get<Spec>(\"KeyboardController\");\n"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAoBlD,eAAeA,mBAAmB,CAACC,GAAG,CAAO,oBAAoB,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","get"],"sources":["NativeKeyboardController.ts"],"sourcesContent":["import { TurboModuleRegistry } from \"react-native\";\n\nimport type { TurboModule } from \"react-native\";\n\nexport interface Spec extends TurboModule {\n readonly getConstants: () => {\n keyboardBorderRadius: number;\n };\n\n // methods\n setInputMode(mode: number): void;\n setDefaultMode(): void;\n preload(): void;\n dismiss(keepFocus: boolean, animated: boolean): void;\n setFocusTo(direction: string): void;\n viewPositionInWindow(viewTag: number): Promise<object>;\n\n // event emitter\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n}\n\nexport default TurboModuleRegistry.get<Spec>(\"KeyboardController\");\n"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAsBlD,eAAeA,mBAAmB,CAACC,GAAG,CAAO,oBAAoB,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["module.ts"],"sourcesContent":["import type { EmitterSubscription, TextInputProps } from \"react-native\";\n\n// Event module declarations\nexport type KeyboardControllerEvents =\n | \"keyboardWillShow\"\n | \"keyboardDidShow\"\n | \"keyboardWillHide\"\n | \"keyboardDidHide\";\nexport type KeyboardEventData = {\n /** Height of the keyboard. */\n height: number;\n /** Duration of the keyboard animation. */\n duration: number;\n /** Timestamp of the last keyboard event. */\n timestamp: number;\n /** Tag of the focused `TextInput`. */\n target: number;\n /** `keyboardType` property from focused `TextInput`. */\n type: NonNullable<TextInputProps[\"keyboardType\"]>;\n /** Keyboard appearance. Can be one of `dark` or `light`. */\n appearance: \"dark\" | \"light\";\n};\n/**\n * An object that represent current keyboard state.\n */\nexport type IKeyboardState = {\n /** Whether the keyboard is currently visible. */\n isVisible: boolean;\n} & KeyboardEventData;\nexport type KeyboardEventsModule = {\n /**\n * The `addListener` function connects a JavaScript function to an identified native\n * keyboard notification event.\n *\n * This function then returns the reference to the listener.\n *\n * `name` is the string that identifies the event you're listening for. This\n * can be any of the following:\n *\n * - `keyboardWillShow`;\n * - `keyboardDidShow`;\n * - `keyboardWillHide`;\n * - `keyboardDidHide`.\n */\n addListener: (\n name: KeyboardControllerEvents,\n cb: (e: KeyboardEventData) => void,\n ) => EmitterSubscription;\n};\nexport type Direction = \"next\" | \"prev\" | \"current\";\nexport type DismissOptions = {\n /**\n * A boolean property indicating whether focus should be kept on the input after dismissing the keyboard. Default is `false`.\n */\n keepFocus: boolean;\n /**\n * A boolean property controlling whether dismissal should be animated. Default is `true`.\n */\n animated: boolean;\n};\nexport type KeyboardControllerModule = {\n // android only\n /**\n * Sets default `windowSoftInputMode` (the one that declared in `AndroidManifest.xml`).\n *\n * @platform android\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setdefaultmode-|docs} page for more details.\n */\n setDefaultMode: () => void;\n /**\n * Changes `windowSoftInputMode` on Android.\n *\n * @platform android\n * @see AndroidSoftInputModes for all possible values and {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setinputmode-|docs} page for more details.\n */\n setInputMode: (mode: number) => void;\n // ios only\n /**\n * A method that preloads the keyboard. It's useful when you want to avoid a delay when the user focuses the first input.\n *\n * @platform ios\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#preload-|docs} page for more details.\n */\n preload: () => void;\n // all platforms\n /**\n * Dismisses the active keyboard. Removes a focus by default, but allows to pass `{keepFocus: true}` to keep focus.\n * If you want to close keyboard immediately pass `{animated: false}`.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#dismiss|docs} page for more details.\n */\n dismiss: (options?: Partial<DismissOptions>) => Promise<void>;\n /**\n * Moves focus to the specified direction (`next`, `prev` or `current` to restore a focus).\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setfocusto|docs} page for more details.\n */\n setFocusTo: (direction: Direction) => void;\n /**\n * Whether the keyboard is fully visible.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#isvisible|docs} page for more details.\n */\n isVisible: () => boolean;\n /**\n * Method that returns current keyboard state.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#state|docs} page for more details.\n */\n state: () => KeyboardEventData;\n};\nexport type ViewPositionInWindowResult = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\nexport type KeyboardControllerNativeModule = {\n // android only\n setDefaultMode: () => void;\n setInputMode: (mode: number) => void;\n // ios only\n preload: () => void;\n // all platforms\n dismiss: (keepFocus: boolean, animated: boolean) => void;\n setFocusTo: (direction: Direction) => void;\n viewPositionInWindow: (\n viewTag: number,\n ) => Promise<ViewPositionInWindowResult>;\n // native event module stuff\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n};\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["module.ts"],"sourcesContent":["import type { EmitterSubscription, TextInputProps } from \"react-native\";\n\n// Event module declarations\nexport type KeyboardControllerEvents =\n | \"keyboardWillShow\"\n | \"keyboardDidShow\"\n | \"keyboardWillHide\"\n | \"keyboardDidHide\";\nexport type KeyboardEventData = {\n /** Height of the keyboard. */\n height: number;\n /** Duration of the keyboard animation. */\n duration: number;\n /** Timestamp of the last keyboard event. */\n timestamp: number;\n /** Tag of the focused `TextInput`. */\n target: number;\n /** `keyboardType` property from focused `TextInput`. */\n type: NonNullable<TextInputProps[\"keyboardType\"]>;\n /** Keyboard appearance. Can be one of `dark` or `light`. */\n appearance: \"dark\" | \"light\";\n};\n/**\n * An object that represent current keyboard state.\n */\nexport type IKeyboardState = {\n /** Whether the keyboard is currently visible. */\n isVisible: boolean;\n} & KeyboardEventData;\nexport type KeyboardEventsModule = {\n /**\n * The `addListener` function connects a JavaScript function to an identified native\n * keyboard notification event.\n *\n * This function then returns the reference to the listener.\n *\n * `name` is the string that identifies the event you're listening for. This\n * can be any of the following:\n *\n * - `keyboardWillShow`;\n * - `keyboardDidShow`;\n * - `keyboardWillHide`;\n * - `keyboardDidHide`.\n */\n addListener: (\n name: KeyboardControllerEvents,\n cb: (e: KeyboardEventData) => void,\n ) => EmitterSubscription;\n};\nexport type Direction = \"next\" | \"prev\" | \"current\";\nexport type DismissOptions = {\n /**\n * A boolean property indicating whether focus should be kept on the input after dismissing the keyboard. Default is `false`.\n */\n keepFocus: boolean;\n /**\n * A boolean property controlling whether dismissal should be animated. Default is `true`.\n */\n animated: boolean;\n};\nexport type KeyboardControllerModule = {\n // android only\n /**\n * Sets default `windowSoftInputMode` (the one that declared in `AndroidManifest.xml`).\n *\n * @platform android\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setdefaultmode-|docs} page for more details.\n */\n setDefaultMode: () => void;\n /**\n * Changes `windowSoftInputMode` on Android.\n *\n * @platform android\n * @see AndroidSoftInputModes for all possible values and {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setinputmode-|docs} page for more details.\n */\n setInputMode: (mode: number) => void;\n // ios only\n /**\n * A method that preloads the keyboard. It's useful when you want to avoid a delay when the user focuses the first input.\n *\n * @platform ios\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#preload-|docs} page for more details.\n */\n preload: () => void;\n // all platforms\n /**\n * Dismisses the active keyboard. Removes a focus by default, but allows to pass `{keepFocus: true}` to keep focus.\n * If you want to close keyboard immediately pass `{animated: false}`.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#dismiss|docs} page for more details.\n */\n dismiss: (options?: Partial<DismissOptions>) => Promise<void>;\n /**\n * Moves focus to the specified direction (`next`, `prev` or `current` to restore a focus).\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#setfocusto|docs} page for more details.\n */\n setFocusTo: (direction: Direction) => void;\n /**\n * Whether the keyboard is fully visible.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#isvisible|docs} page for more details.\n */\n isVisible: () => boolean;\n /**\n * Method that returns current keyboard state.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#state|docs} page for more details.\n */\n state: () => KeyboardEventData;\n};\nexport type ViewPositionInWindowResult = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\nexport type KeyboardControllerNativeModule = {\n // android only\n setDefaultMode: () => void;\n setInputMode: (mode: number) => void;\n // ios only\n preload: () => void;\n // all platforms\n dismiss: (keepFocus: boolean, animated: boolean) => void;\n setFocusTo: (direction: Direction) => void;\n viewPositionInWindow: (\n viewTag: number,\n ) => Promise<ViewPositionInWindowResult>;\n // native event module stuff\n addListener: (eventName: string) => void;\n removeListeners: (count: number) => void;\n // constants\n getConstants: () => {\n keyboardBorderRadius: number;\n };\n};\n"],"mappings":"","ignoreList":[]}
@@ -22,6 +22,7 @@ declare const KeyboardAwareScrollView: React.ForwardRefExoticComponent<{
22
22
  disableScrollOnKeyboardHide?: boolean;
23
23
  enabled?: boolean;
24
24
  extraKeyboardSpace?: number;
25
+ mode?: import("react-native-keyboard-controller").KeyboardAwareScrollViewMode;
25
26
  ScrollViewComponent?: import("../ScrollViewWithBottomPadding").AnimatedScrollViewComponent;
26
27
  } & import("react-native").ScrollViewProps & {
27
28
  children?: React.ReactNode | undefined;
@@ -1,5 +1,6 @@
1
1
  import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
2
2
  import type { ScrollView, ScrollViewProps } from "react-native";
3
+ export type KeyboardAwareScrollViewMode = "insets" | "layout";
3
4
  export type KeyboardAwareScrollViewProps = {
4
5
  /** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */
5
6
  bottomOffset?: number;
@@ -9,6 +10,15 @@ export type KeyboardAwareScrollViewProps = {
9
10
  enabled?: boolean;
10
11
  /** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */
11
12
  extraKeyboardSpace?: number;
13
+ /**
14
+ * Controls how keyboard space is created at the bottom of the `ScrollView`.
15
+ *
16
+ * - `"insets"` *(default)*: Extends the scrollable area via `contentInset` (iOS) and `ClippingScrollView` (Android). No layout reflow occurs — content positions remain stable during keyboard animation. Recommended for most use cases.
17
+ * - `"layout"`: Appends a spacer `View` as the last child of the `ScrollView`. The spacer participates in layout, so flex-based arrangements (e.g. `justifyContent: "space-between"`, `gap`) reflow naturally when the keyboard appears. Use this when you need content to physically rearrange around the keyboard space.
18
+ *
19
+ * Default is `"insets"`.
20
+ */
21
+ mode?: KeyboardAwareScrollViewMode;
12
22
  /** Custom component for `ScrollView`. Default is `ScrollView`. */
13
23
  ScrollViewComponent?: AnimatedScrollViewComponent;
14
24
  } & ScrollViewProps;
@@ -5,6 +5,6 @@ export { default as KeyboardToolbar, DefaultKeyboardToolbarTheme, } from "./Keyb
5
5
  export { default as KeyboardChatScrollView } from "./KeyboardChatScrollView";
6
6
  export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
7
7
  export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
8
- export type { KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, } from "./KeyboardAwareScrollView/types";
8
+ export type { KeyboardAwareScrollViewMode, KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, } from "./KeyboardAwareScrollView/types";
9
9
  export type { KeyboardToolbarProps } from "./KeyboardToolbar";
10
10
  export type { KeyboardChatScrollViewProps } from "./KeyboardChatScrollView/types";
@@ -14,3 +14,4 @@ export declare enum AndroidSoftInputModes {
14
14
  SOFT_INPUT_STATE_UNSPECIFIED = 0,
15
15
  SOFT_INPUT_STATE_VISIBLE = 4
16
16
  }
17
+ export declare const KEYBOARD_BORDER_RADIUS: number;
@@ -7,5 +7,5 @@ export * from "./module";
7
7
  export * from "./types";
8
8
  export * from "./compat";
9
9
  export { KeyboardChatScrollView, KeyboardAvoidingView, KeyboardStickyView, KeyboardAwareScrollView, KeyboardToolbar, DefaultKeyboardToolbarTheme, } from "./components";
10
- export type { KeyboardChatScrollViewProps, KeyboardAvoidingViewProps, KeyboardStickyViewProps, KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, KeyboardToolbarProps, } from "./components";
10
+ export type { KeyboardChatScrollViewProps, KeyboardAvoidingViewProps, KeyboardStickyViewProps, KeyboardAwareScrollViewMode, KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, KeyboardToolbarProps, } from "./components";
11
11
  export { OverKeyboardView, KeyboardExtender } from "./views";
@@ -1,6 +1,8 @@
1
1
  import type { TurboModule } from "react-native";
2
2
  export interface Spec extends TurboModule {
3
- readonly getConstants: () => {};
3
+ readonly getConstants: () => {
4
+ keyboardBorderRadius: number;
5
+ };
4
6
  setInputMode(mode: number): void;
5
7
  setDefaultMode(): void;
6
8
  preload(): void;
@@ -112,4 +112,7 @@ export type KeyboardControllerNativeModule = {
112
112
  viewPositionInWindow: (viewTag: number) => Promise<ViewPositionInWindowResult>;
113
113
  addListener: (eventName: string) => void;
114
114
  removeListeners: (count: number) => void;
115
+ getConstants: () => {
116
+ keyboardBorderRadius: number;
117
+ };
115
118
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.21.3",
3
+ "version": "1.21.5",
4
4
  "description": "Keyboard manager which works in identical way on both iOS and Android",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
package/src/bindings.ts CHANGED
@@ -27,6 +27,9 @@ export const KeyboardControllerNative: KeyboardControllerNativeModule = {
27
27
  Promise.resolve({ x: 0, y: 0, width: 0, height: 0 }),
28
28
  addListener: NOOP,
29
29
  removeListeners: NOOP,
30
+ getConstants: () => ({
31
+ keyboardBorderRadius: 0,
32
+ }),
30
33
  };
31
34
  /**
32
35
  * An event emitter that provides a way to subscribe to next keyboard events:
@@ -12,6 +12,7 @@ import Reanimated, {
12
12
  scrollTo,
13
13
  useAnimatedReaction,
14
14
  useAnimatedRef,
15
+ useAnimatedStyle,
15
16
  useDerivedValue,
16
17
  useSharedValue,
17
18
  } from "react-native-reanimated";
@@ -104,6 +105,7 @@ const KeyboardAwareScrollView = forwardRef<
104
105
  disableScrollOnKeyboardHide = false,
105
106
  enabled = true,
106
107
  extraKeyboardSpace = 0,
108
+ mode = "insets",
107
109
  ScrollViewComponent = Reanimated.ScrollView,
108
110
  snapToOffsets,
109
111
  ...rest
@@ -219,30 +221,39 @@ const KeyboardAwareScrollView = forwardRef<
219
221
  },
220
222
  [bottomOffset, enabled, height, snapToOffsets],
221
223
  );
222
- const removeGhostPadding = useCallback((e: number) => {
223
- "worklet";
224
+ const removeGhostPadding = useCallback(
225
+ (e: number) => {
226
+ "worklet";
224
227
 
225
- // new `ScrollViewWithBottomPadding` behavior: if we hide keyboard and we are in the end of `ScrollView`
226
- // then we always need to scroll back, because we apply a padding that doesn't change layout, so we will
227
- // not have auto scroll back in this case
228
- if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {
229
- scrollTo(
230
- scrollViewAnimatedRef,
231
- 0,
232
- scrollPosition.value -
233
- interpolate(
234
- e,
235
- [initialKeyboardSize.value, keyboardHeight.value],
236
- [ghostViewSpace.value, 0],
237
- ),
238
- false,
239
- );
228
+ // layout mode: the spacer view participates in layout, so the ScrollView
229
+ // reflows naturally when it shrinks no manual scroll correction needed.
230
+ if (mode === "layout") {
231
+ return false;
232
+ }
240
233
 
241
- return true;
242
- }
234
+ // insets mode: `ScrollViewWithBottomPadding` extends scrollable area without
235
+ // changing layout, so when the keyboard hides and we're at the end of the
236
+ // ScrollView we must manually scroll back.
237
+ if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {
238
+ scrollTo(
239
+ scrollViewAnimatedRef,
240
+ 0,
241
+ scrollPosition.value -
242
+ interpolate(
243
+ e,
244
+ [initialKeyboardSize.value, keyboardHeight.value],
245
+ [ghostViewSpace.value, 0],
246
+ ),
247
+ false,
248
+ );
243
249
 
244
- return false;
245
- }, []);
250
+ return true;
251
+ }
252
+
253
+ return false;
254
+ },
255
+ [mode],
256
+ );
246
257
  const performScrollWithPositionRestoration = useCallback(
247
258
  (newPosition: number) => {
248
259
  "worklet";
@@ -403,8 +414,14 @@ const KeyboardAwareScrollView = forwardRef<
403
414
  scrollPosition.value = position.value;
404
415
  // just persist height - later will be used in interpolation
405
416
  keyboardHeight.value = e.height;
406
- // and update keyboard spacer size
407
- syncKeyboardFrame(e);
417
+
418
+ // insets mode: set the full contentInset upfront so that maybeScroll
419
+ // calculations are correct from the very first onMove frame.
420
+ // layout mode: do NOT set it here — the spacer must grow frame-by-frame
421
+ // in onMove to avoid a premature full-height jump before the keyboard moves.
422
+ if (mode === "insets") {
423
+ syncKeyboardFrame(e);
424
+ }
408
425
  }
409
426
 
410
427
  // focus was changed
@@ -445,13 +462,15 @@ const KeyboardAwareScrollView = forwardRef<
445
462
  }
446
463
  }
447
464
 
448
- ghostViewSpace.value =
449
- position.value +
450
- scrollViewLayout.value.height -
451
- scrollViewContentSize.value.height;
465
+ if (mode === "insets") {
466
+ ghostViewSpace.value =
467
+ position.value +
468
+ scrollViewLayout.value.height -
469
+ scrollViewContentSize.value.height;
452
470
 
453
- if (ghostViewSpace.value > 0) {
454
- scrollPosition.value = position.value;
471
+ if (ghostViewSpace.value > 0) {
472
+ scrollPosition.value = position.value;
473
+ }
455
474
  }
456
475
  },
457
476
  onMove: (e) => {
@@ -461,6 +480,11 @@ const KeyboardAwareScrollView = forwardRef<
461
480
  return;
462
481
  }
463
482
 
483
+ // layout mode: drive the spacer view animation frame-by-frame
484
+ if (mode === "layout") {
485
+ syncKeyboardFrame(e);
486
+ }
487
+
464
488
  // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
465
489
  if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
466
490
  maybeScroll(e.height);
@@ -489,6 +513,7 @@ const KeyboardAwareScrollView = forwardRef<
489
513
  },
490
514
  },
491
515
  [
516
+ mode,
492
517
  maybeScroll,
493
518
  removeGhostPadding,
494
519
  disableScrollOnKeyboardHide,
@@ -555,6 +580,31 @@ const KeyboardAwareScrollView = forwardRef<
555
580
  () => (enabled ? currentKeyboardFrameHeight.value : 0),
556
581
  [enabled],
557
582
  );
583
+ // layout mode only: a spacer view whose paddingBottom grows with the keyboard.
584
+ // The `+ 1` ensures the scroll view never reaches its absolute end during animation,
585
+ // avoiding the layout recalculation that triggers on every frame at the boundary.
586
+ // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
587
+ const layoutSpacerStyle = useAnimatedStyle(
588
+ () =>
589
+ enabled && mode === "layout"
590
+ ? { paddingBottom: currentKeyboardFrameHeight.value + 1 }
591
+ : {},
592
+ [enabled, mode],
593
+ );
594
+
595
+ if (mode === "layout") {
596
+ return (
597
+ <ScrollViewComponent
598
+ ref={onRef}
599
+ {...rest}
600
+ scrollEventThrottle={16}
601
+ onLayout={onScrollViewLayout}
602
+ >
603
+ {children}
604
+ {enabled && <Reanimated.View style={layoutSpacerStyle} />}
605
+ </ScrollViewComponent>
606
+ );
607
+ }
558
608
 
559
609
  return (
560
610
  <ScrollViewWithBottomPadding
@@ -1,6 +1,8 @@
1
1
  import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
2
2
  import type { ScrollView, ScrollViewProps } from "react-native";
3
3
 
4
+ export type KeyboardAwareScrollViewMode = "insets" | "layout";
5
+
4
6
  export type KeyboardAwareScrollViewProps = {
5
7
  /** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */
6
8
  bottomOffset?: number;
@@ -10,6 +12,15 @@ export type KeyboardAwareScrollViewProps = {
10
12
  enabled?: boolean;
11
13
  /** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */
12
14
  extraKeyboardSpace?: number;
15
+ /**
16
+ * Controls how keyboard space is created at the bottom of the `ScrollView`.
17
+ *
18
+ * - `"insets"` *(default)*: Extends the scrollable area via `contentInset` (iOS) and `ClippingScrollView` (Android). No layout reflow occurs — content positions remain stable during keyboard animation. Recommended for most use cases.
19
+ * - `"layout"`: Appends a spacer `View` as the last child of the `ScrollView`. The spacer participates in layout, so flex-based arrangements (e.g. `justifyContent: "space-between"`, `gap`) reflow naturally when the keyboard appears. Use this when you need content to physically rearrange around the keyboard space.
20
+ *
21
+ * Default is `"insets"`.
22
+ */
23
+ mode?: KeyboardAwareScrollViewMode;
13
24
  /** Custom component for `ScrollView`. Default is `ScrollView`. */
14
25
  ScrollViewComponent?: AnimatedScrollViewComponent;
15
26
  } & ScrollViewProps;
@@ -1,4 +1,4 @@
1
- import { Platform } from "react-native";
1
+ import { KEYBOARD_BORDER_RADIUS } from "../../constants";
2
2
 
3
3
  import type { HEX } from "./types";
4
4
 
@@ -10,6 +10,5 @@ export const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;
10
10
 
11
11
  export const KEYBOARD_TOOLBAR_HEIGHT = 42;
12
12
  export const DEFAULT_OPACITY: HEX = "FF";
13
- export const KEYBOARD_HAS_ROUNDED_CORNERS =
14
- Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26;
13
+ export const KEYBOARD_HAS_ROUNDED_CORNERS = KEYBOARD_BORDER_RADIUS > 0;
15
14
  export const OPENED_OFFSET = KEYBOARD_HAS_ROUNDED_CORNERS ? -11 : 0;
@@ -9,6 +9,7 @@ export { default as KeyboardChatScrollView } from "./KeyboardChatScrollView";
9
9
  export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
10
10
  export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
11
11
  export type {
12
+ KeyboardAwareScrollViewMode,
12
13
  KeyboardAwareScrollViewProps,
13
14
  KeyboardAwareScrollViewRef,
14
15
  } from "./KeyboardAwareScrollView/types";