react-native-keyboard-controller 1.10.2 → 1.10.3

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.
@@ -13,7 +13,7 @@ var _utils = require("./utils");
13
13
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
14
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
15
15
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
16
- /**
16
+ /*
17
17
  * Everything begins from `onStart` handler. This handler is called every time,
18
18
  * when keyboard changes its size or when focused `TextInput` was changed. In
19
19
  * this handler we are calculating/memoizing values which later will be used
@@ -55,6 +55,7 @@ const KeyboardAwareScrollView = _ref => {
55
55
  let {
56
56
  children,
57
57
  bottomOffset = 0,
58
+ disableScrollOnKeyboardHide = false,
58
59
  ...rest
59
60
  } = _ref;
60
61
  const scrollViewAnimatedRef = (0, _reactNativeReanimated.useAnimatedRef)();
@@ -62,6 +63,7 @@ const KeyboardAwareScrollView = _ref => {
62
63
  const position = (0, _reactNativeReanimated.useSharedValue)(0);
63
64
  const currentKeyboardFrameHeight = (0, _reactNativeReanimated.useSharedValue)(0);
64
65
  const keyboardHeight = (0, _reactNativeReanimated.useSharedValue)(0);
66
+ const keyboardWillAppear = (0, _reactNativeReanimated.useSharedValue)(false);
65
67
  const tag = (0, _reactNativeReanimated.useSharedValue)(-1);
66
68
  const initialKeyboardSize = (0, _reactNativeReanimated.useSharedValue)(0);
67
69
  const scrollBeforeKeyboardMovement = (0, _reactNativeReanimated.useSharedValue)(0);
@@ -129,7 +131,7 @@ const KeyboardAwareScrollView = _ref => {
129
131
  "worklet";
130
132
 
131
133
  const keyboardWillChangeSize = keyboardHeight.value !== e.height && e.height > 0;
132
- const keyboardWillAppear = e.height > 0 && keyboardHeight.value === 0;
134
+ keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;
133
135
  const keyboardWillHide = e.height === 0;
134
136
  const focusWasChanged = tag.value !== e.target && e.target !== -1 || keyboardWillChangeSize;
135
137
  if (keyboardWillChangeSize) {
@@ -140,7 +142,7 @@ const KeyboardAwareScrollView = _ref => {
140
142
  initialKeyboardSize.value = 0;
141
143
  scrollPosition.value = scrollBeforeKeyboardMovement.value;
142
144
  }
143
- if (keyboardWillAppear || keyboardWillChangeSize || focusWasChanged) {
145
+ if (keyboardWillAppear.value || keyboardWillChangeSize || focusWasChanged) {
144
146
  // persist scroll value
145
147
  scrollPosition.value = position.value;
146
148
  // just persist height - later will be used in interpolation
@@ -157,7 +159,7 @@ const KeyboardAwareScrollView = _ref => {
157
159
  // this value to achieve smooth hide effect
158
160
  scrollBeforeKeyboardMovement.value = position.value;
159
161
  }
160
- if (focusWasChanged && !keyboardWillAppear) {
162
+ if (focusWasChanged && !keyboardWillAppear.value) {
161
163
  // update position on scroll value, so `onEnd` handler
162
164
  // will pick up correct values
163
165
  position.value += maybeScroll(e.height, true);
@@ -167,7 +169,11 @@ const KeyboardAwareScrollView = _ref => {
167
169
  "worklet";
168
170
 
169
171
  currentKeyboardFrameHeight.value = e.height;
170
- maybeScroll(e.height);
172
+
173
+ // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
174
+ if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
175
+ maybeScroll(e.height);
176
+ }
171
177
  },
172
178
  onEnd: e => {
173
179
  "worklet";
@@ -175,7 +181,7 @@ const KeyboardAwareScrollView = _ref => {
175
181
  keyboardHeight.value = e.height;
176
182
  scrollPosition.value = position.value;
177
183
  }
178
- }, [height, maybeScroll]);
184
+ }, [height, maybeScroll, disableScrollOnKeyboardHide]);
179
185
  (0, _reactNativeReanimated.useAnimatedReaction)(() => input.value, (current, previous) => {
180
186
  if ((current === null || current === void 0 ? void 0 : current.target) === (previous === null || previous === void 0 ? void 0 : previous.target) && (current === null || current === void 0 ? void 0 : current.layout.height) !== (previous === null || previous === void 0 ? void 0 : previous.layout.height)) {
181
187
  const prevLayout = layout.value;
@@ -190,7 +196,8 @@ const KeyboardAwareScrollView = _ref => {
190
196
  return /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.ScrollView, _extends({
191
197
  ref: scrollViewAnimatedRef
192
198
  }, rest, {
193
- onScroll: onScroll,
199
+ // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
200
+ onScrollReanimated: onScroll,
194
201
  scrollEventThrottle: 16
195
202
  }), children, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
196
203
  style: view
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_reactNativeKeyboardController","_useSmoothKeyboardHandler","_utils","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","_extends","assign","bind","target","i","arguments","length","source","apply","KeyboardAwareScrollView","_ref","children","bottomOffset","rest","scrollViewAnimatedRef","useAnimatedRef","scrollPosition","useSharedValue","position","currentKeyboardFrameHeight","keyboardHeight","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","useReanimatedFocusedInput","layout","height","useWindowDimensions","onScroll","useAnimatedScrollHandler","e","value","contentOffset","y","maybeScroll","useCallback","_layout$value","_layout$value2","animated","undefined","visibleRect","absoluteY","inputHeight","point","interpolatedScrollTo","interpolate","targetScrollY","Math","max","scrollTo","positionOnScreen","topOfScreen","onChangeText","_layout$value3","_input$value","prevScrollPosition","prevLayout","onChangeTextHandler","useMemo","debounce","useFocusedInputHandler","useSmoothKeyboardHandler","onStart","keyboardWillChangeSize","keyboardWillAppear","keyboardWillHide","focusWasChanged","onMove","onEnd","useAnimatedReaction","current","previous","view","useAnimatedStyle","paddingBottom","createElement","ScrollView","ref","scrollEventThrottle","View","style","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { useWindowDimensions } from \"react-native\";\nimport Reanimated, {\n interpolate,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n} from \"react-native-keyboard-controller\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce } from \"./utils\";\n\nimport type { FC } from \"react\";\nimport type { ScrollViewProps } from \"react-native\";\nimport type { FocusedInputLayoutChangedEvent } from \"react-native-keyboard-controller\";\n\ntype KeyboardAwareScrollViewProps = {\n bottomOffset?: number;\n} & ScrollViewProps;\n\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 * +============================+ +============================+ +=====================================+\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 */\nconst KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({\n children,\n bottomOffset = 0,\n ...rest\n}) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollPosition = useSharedValue(0);\n const position = useSharedValue(0);\n const currentKeyboardFrameHeight = useSharedValue(0);\n const keyboardHeight = useSharedValue(0);\n const tag = useSharedValue(-1);\n const initialKeyboardSize = useSharedValue(0);\n const scrollBeforeKeyboardMovement = useSharedValue(0);\n const { input } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n\n const { height } = useWindowDimensions();\n\n const onScroll = useAnimatedScrollHandler(\n {\n onScroll: (e) => {\n position.value = e.contentOffset.y;\n },\n },\n [],\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 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 interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [0, keyboardHeight.value - (height - point) + bottomOffset],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (absoluteY < 0) {\n const positionOnScreen = visibleRect - inputHeight - bottomOffset;\n const topOfScreen = scrollPosition.value + absoluteY;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset],\n );\n\n const onChangeText = useCallback(() => {\n \"worklet\";\n\n // if typing a text caused layout shift, then we need to ignore this handler\n // because this event will be handled in `useAnimatedReaction` below\n if (layout.value?.layout.height !== input.value?.layout.height) {\n return;\n }\n\n const prevScrollPosition = scrollPosition.value;\n const prevLayout = layout.value;\n\n scrollPosition.value = position.value;\n layout.value = input.value;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScrollPosition;\n layout.value = prevLayout;\n }, [maybeScroll]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n\n useFocusedInputHandler(\n {\n onChangeText: onChangeTextHandler,\n },\n [onChangeTextHandler],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n const keyboardWillAppear = e.height > 0 && keyboardHeight.value === 0;\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) || 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 }\n\n if (keyboardWillAppear || keyboardWillChangeSize || focusWasChanged) {\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\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n // save position of focused text input when keyboard starts to move\n layout.value = input.value;\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) {\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 onMove: (e) => {\n \"worklet\";\n\n currentKeyboardFrameHeight.value = e.height;\n\n maybeScroll(e.height);\n },\n onEnd: (e) => {\n \"worklet\";\n\n keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n },\n },\n [height, maybeScroll],\n );\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 const prevLayout = layout.value;\n\n layout.value = input.value;\n scrollPosition.value += maybeScroll(keyboardHeight.value, true);\n layout.value = prevLayout;\n }\n },\n [],\n );\n\n const view = useAnimatedStyle(\n () => ({\n paddingBottom: currentKeyboardFrameHeight.value,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={scrollViewAnimatedRef}\n {...rest}\n onScroll={onScroll}\n scrollEventThrottle={16}\n >\n {children}\n <Reanimated.View style={view} />\n </Reanimated.ScrollView>\n );\n};\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_reactNativeKeyboardController","_useSmoothKeyboardHandler","_utils","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","_extends","assign","bind","target","i","arguments","length","source","apply","KeyboardAwareScrollView","_ref","children","bottomOffset","disableScrollOnKeyboardHide","rest","scrollViewAnimatedRef","useAnimatedRef","scrollPosition","useSharedValue","position","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","useReanimatedFocusedInput","layout","height","useWindowDimensions","onScroll","useAnimatedScrollHandler","e","value","contentOffset","y","maybeScroll","useCallback","_layout$value","_layout$value2","animated","undefined","visibleRect","absoluteY","inputHeight","point","interpolatedScrollTo","interpolate","targetScrollY","Math","max","scrollTo","positionOnScreen","topOfScreen","onChangeText","_layout$value3","_input$value","prevScrollPosition","prevLayout","onChangeTextHandler","useMemo","debounce","useFocusedInputHandler","useSmoothKeyboardHandler","onStart","keyboardWillChangeSize","keyboardWillHide","focusWasChanged","onMove","onEnd","useAnimatedReaction","current","previous","view","useAnimatedStyle","paddingBottom","createElement","ScrollView","ref","onScrollReanimated","scrollEventThrottle","View","style","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { useWindowDimensions } from \"react-native\";\nimport Reanimated, {\n interpolate,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n} from \"react-native-keyboard-controller\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce } from \"./utils\";\n\nimport type { FC } from \"react\";\nimport type { ScrollViewProps } from \"react-native\";\nimport type { FocusedInputLayoutChangedEvent } from \"react-native-keyboard-controller\";\n\ntype KeyboardAwareScrollViewProps = {\n /** The distance between keyboard and focused `TextInput` when 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} & ScrollViewProps;\n\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 * +============================+ +============================+ +=====================================+\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 */\nconst KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({\n children,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n ...rest\n}) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollPosition = useSharedValue(0);\n const position = useSharedValue(0);\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 } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n\n const { height } = useWindowDimensions();\n\n const onScroll = useAnimatedScrollHandler(\n {\n onScroll: (e) => {\n position.value = e.contentOffset.y;\n },\n },\n [],\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 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 interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [0, keyboardHeight.value - (height - point) + bottomOffset],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (absoluteY < 0) {\n const positionOnScreen = visibleRect - inputHeight - bottomOffset;\n const topOfScreen = scrollPosition.value + absoluteY;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset],\n );\n\n const onChangeText = useCallback(() => {\n \"worklet\";\n\n // if typing a text caused layout shift, then we need to ignore this handler\n // because this event will be handled in `useAnimatedReaction` below\n if (layout.value?.layout.height !== input.value?.layout.height) {\n return;\n }\n\n const prevScrollPosition = scrollPosition.value;\n const prevLayout = layout.value;\n\n scrollPosition.value = position.value;\n layout.value = input.value;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScrollPosition;\n layout.value = prevLayout;\n }, [maybeScroll]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n\n useFocusedInputHandler(\n {\n onChangeText: onChangeTextHandler,\n },\n [onChangeTextHandler],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) || 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 }\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\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n // save position of focused text input when keyboard starts to move\n layout.value = input.value;\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 // update position on scroll value, so `onEnd` handler\n // will pick up correct values\n position.value += maybeScroll(e.height, true);\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n currentKeyboardFrameHeight.value = e.height;\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 keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n },\n },\n [height, maybeScroll, disableScrollOnKeyboardHide],\n );\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 const prevLayout = layout.value;\n\n layout.value = input.value;\n scrollPosition.value += maybeScroll(keyboardHeight.value, true);\n layout.value = prevLayout;\n }\n },\n [],\n );\n\n const view = useAnimatedStyle(\n () => ({\n paddingBottom: currentKeyboardFrameHeight.value,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={scrollViewAnimatedRef}\n {...rest}\n // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events\n onScrollReanimated={onScroll}\n scrollEventThrottle={16}\n >\n {children}\n <Reanimated.View style={view} />\n </Reanimated.ScrollView>\n );\n};\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import Reanimated, { interpolate, scrollTo, useAnimatedReaction, useAnimatedRef,
5
5
  import { useFocusedInputHandler, useReanimatedFocusedInput } from "react-native-keyboard-controller";
6
6
  import { useSmoothKeyboardHandler } from "./useSmoothKeyboardHandler";
7
7
  import { debounce } from "./utils";
8
- /**
8
+ /*
9
9
  * Everything begins from `onStart` handler. This handler is called every time,
10
10
  * when keyboard changes its size or when focused `TextInput` was changed. In
11
11
  * this handler we are calculating/memoizing values which later will be used
@@ -47,6 +47,7 @@ const KeyboardAwareScrollView = _ref => {
47
47
  let {
48
48
  children,
49
49
  bottomOffset = 0,
50
+ disableScrollOnKeyboardHide = false,
50
51
  ...rest
51
52
  } = _ref;
52
53
  const scrollViewAnimatedRef = useAnimatedRef();
@@ -54,6 +55,7 @@ const KeyboardAwareScrollView = _ref => {
54
55
  const position = useSharedValue(0);
55
56
  const currentKeyboardFrameHeight = useSharedValue(0);
56
57
  const keyboardHeight = useSharedValue(0);
58
+ const keyboardWillAppear = useSharedValue(false);
57
59
  const tag = useSharedValue(-1);
58
60
  const initialKeyboardSize = useSharedValue(0);
59
61
  const scrollBeforeKeyboardMovement = useSharedValue(0);
@@ -121,7 +123,7 @@ const KeyboardAwareScrollView = _ref => {
121
123
  "worklet";
122
124
 
123
125
  const keyboardWillChangeSize = keyboardHeight.value !== e.height && e.height > 0;
124
- const keyboardWillAppear = e.height > 0 && keyboardHeight.value === 0;
126
+ keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;
125
127
  const keyboardWillHide = e.height === 0;
126
128
  const focusWasChanged = tag.value !== e.target && e.target !== -1 || keyboardWillChangeSize;
127
129
  if (keyboardWillChangeSize) {
@@ -132,7 +134,7 @@ const KeyboardAwareScrollView = _ref => {
132
134
  initialKeyboardSize.value = 0;
133
135
  scrollPosition.value = scrollBeforeKeyboardMovement.value;
134
136
  }
135
- if (keyboardWillAppear || keyboardWillChangeSize || focusWasChanged) {
137
+ if (keyboardWillAppear.value || keyboardWillChangeSize || focusWasChanged) {
136
138
  // persist scroll value
137
139
  scrollPosition.value = position.value;
138
140
  // just persist height - later will be used in interpolation
@@ -149,7 +151,7 @@ const KeyboardAwareScrollView = _ref => {
149
151
  // this value to achieve smooth hide effect
150
152
  scrollBeforeKeyboardMovement.value = position.value;
151
153
  }
152
- if (focusWasChanged && !keyboardWillAppear) {
154
+ if (focusWasChanged && !keyboardWillAppear.value) {
153
155
  // update position on scroll value, so `onEnd` handler
154
156
  // will pick up correct values
155
157
  position.value += maybeScroll(e.height, true);
@@ -159,7 +161,11 @@ const KeyboardAwareScrollView = _ref => {
159
161
  "worklet";
160
162
 
161
163
  currentKeyboardFrameHeight.value = e.height;
162
- maybeScroll(e.height);
164
+
165
+ // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
166
+ if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
167
+ maybeScroll(e.height);
168
+ }
163
169
  },
164
170
  onEnd: e => {
165
171
  "worklet";
@@ -167,7 +173,7 @@ const KeyboardAwareScrollView = _ref => {
167
173
  keyboardHeight.value = e.height;
168
174
  scrollPosition.value = position.value;
169
175
  }
170
- }, [height, maybeScroll]);
176
+ }, [height, maybeScroll, disableScrollOnKeyboardHide]);
171
177
  useAnimatedReaction(() => input.value, (current, previous) => {
172
178
  if ((current === null || current === void 0 ? void 0 : current.target) === (previous === null || previous === void 0 ? void 0 : previous.target) && (current === null || current === void 0 ? void 0 : current.layout.height) !== (previous === null || previous === void 0 ? void 0 : previous.layout.height)) {
173
179
  const prevLayout = layout.value;
@@ -182,7 +188,8 @@ const KeyboardAwareScrollView = _ref => {
182
188
  return /*#__PURE__*/React.createElement(Reanimated.ScrollView, _extends({
183
189
  ref: scrollViewAnimatedRef
184
190
  }, rest, {
185
- onScroll: onScroll,
191
+ // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
192
+ onScrollReanimated: onScroll,
186
193
  scrollEventThrottle: 16
187
194
  }), children, /*#__PURE__*/React.createElement(Reanimated.View, {
188
195
  style: view
@@ -1 +1 @@
1
- {"version":3,"names":["React","useCallback","useMemo","useWindowDimensions","Reanimated","interpolate","scrollTo","useAnimatedReaction","useAnimatedRef","useAnimatedScrollHandler","useAnimatedStyle","useSharedValue","useFocusedInputHandler","useReanimatedFocusedInput","useSmoothKeyboardHandler","debounce","KeyboardAwareScrollView","_ref","children","bottomOffset","rest","scrollViewAnimatedRef","scrollPosition","position","currentKeyboardFrameHeight","keyboardHeight","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","layout","height","onScroll","e","value","contentOffset","y","maybeScroll","_layout$value","_layout$value2","animated","arguments","length","undefined","visibleRect","absoluteY","inputHeight","point","interpolatedScrollTo","targetScrollY","Math","max","positionOnScreen","topOfScreen","onChangeText","_layout$value3","_input$value","prevScrollPosition","prevLayout","onChangeTextHandler","onStart","keyboardWillChangeSize","keyboardWillAppear","keyboardWillHide","focusWasChanged","target","onMove","onEnd","current","previous","view","paddingBottom","createElement","ScrollView","_extends","ref","scrollEventThrottle","View","style"],"sources":["index.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { useWindowDimensions } from \"react-native\";\nimport Reanimated, {\n interpolate,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n} from \"react-native-keyboard-controller\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce } from \"./utils\";\n\nimport type { FC } from \"react\";\nimport type { ScrollViewProps } from \"react-native\";\nimport type { FocusedInputLayoutChangedEvent } from \"react-native-keyboard-controller\";\n\ntype KeyboardAwareScrollViewProps = {\n bottomOffset?: number;\n} & ScrollViewProps;\n\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 * +============================+ +============================+ +=====================================+\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 */\nconst KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({\n children,\n bottomOffset = 0,\n ...rest\n}) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollPosition = useSharedValue(0);\n const position = useSharedValue(0);\n const currentKeyboardFrameHeight = useSharedValue(0);\n const keyboardHeight = useSharedValue(0);\n const tag = useSharedValue(-1);\n const initialKeyboardSize = useSharedValue(0);\n const scrollBeforeKeyboardMovement = useSharedValue(0);\n const { input } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n\n const { height } = useWindowDimensions();\n\n const onScroll = useAnimatedScrollHandler(\n {\n onScroll: (e) => {\n position.value = e.contentOffset.y;\n },\n },\n [],\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 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 interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [0, keyboardHeight.value - (height - point) + bottomOffset],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (absoluteY < 0) {\n const positionOnScreen = visibleRect - inputHeight - bottomOffset;\n const topOfScreen = scrollPosition.value + absoluteY;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset],\n );\n\n const onChangeText = useCallback(() => {\n \"worklet\";\n\n // if typing a text caused layout shift, then we need to ignore this handler\n // because this event will be handled in `useAnimatedReaction` below\n if (layout.value?.layout.height !== input.value?.layout.height) {\n return;\n }\n\n const prevScrollPosition = scrollPosition.value;\n const prevLayout = layout.value;\n\n scrollPosition.value = position.value;\n layout.value = input.value;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScrollPosition;\n layout.value = prevLayout;\n }, [maybeScroll]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n\n useFocusedInputHandler(\n {\n onChangeText: onChangeTextHandler,\n },\n [onChangeTextHandler],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n const keyboardWillAppear = e.height > 0 && keyboardHeight.value === 0;\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) || 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 }\n\n if (keyboardWillAppear || keyboardWillChangeSize || focusWasChanged) {\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\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n // save position of focused text input when keyboard starts to move\n layout.value = input.value;\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) {\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 onMove: (e) => {\n \"worklet\";\n\n currentKeyboardFrameHeight.value = e.height;\n\n maybeScroll(e.height);\n },\n onEnd: (e) => {\n \"worklet\";\n\n keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n },\n },\n [height, maybeScroll],\n );\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 const prevLayout = layout.value;\n\n layout.value = input.value;\n scrollPosition.value += maybeScroll(keyboardHeight.value, true);\n layout.value = prevLayout;\n }\n },\n [],\n );\n\n const view = useAnimatedStyle(\n () => ({\n paddingBottom: currentKeyboardFrameHeight.value,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={scrollViewAnimatedRef}\n {...rest}\n onScroll={onScroll}\n scrollEventThrottle={16}\n >\n {children}\n <Reanimated.View style={view} />\n </Reanimated.ScrollView>\n );\n};\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
1
+ {"version":3,"names":["React","useCallback","useMemo","useWindowDimensions","Reanimated","interpolate","scrollTo","useAnimatedReaction","useAnimatedRef","useAnimatedScrollHandler","useAnimatedStyle","useSharedValue","useFocusedInputHandler","useReanimatedFocusedInput","useSmoothKeyboardHandler","debounce","KeyboardAwareScrollView","_ref","children","bottomOffset","disableScrollOnKeyboardHide","rest","scrollViewAnimatedRef","scrollPosition","position","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","layout","height","onScroll","e","value","contentOffset","y","maybeScroll","_layout$value","_layout$value2","animated","arguments","length","undefined","visibleRect","absoluteY","inputHeight","point","interpolatedScrollTo","targetScrollY","Math","max","positionOnScreen","topOfScreen","onChangeText","_layout$value3","_input$value","prevScrollPosition","prevLayout","onChangeTextHandler","onStart","keyboardWillChangeSize","keyboardWillHide","focusWasChanged","target","onMove","onEnd","current","previous","view","paddingBottom","createElement","ScrollView","_extends","ref","onScrollReanimated","scrollEventThrottle","View","style"],"sources":["index.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { useWindowDimensions } from \"react-native\";\nimport Reanimated, {\n interpolate,\n scrollTo,\n useAnimatedReaction,\n useAnimatedRef,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport {\n useFocusedInputHandler,\n useReanimatedFocusedInput,\n} from \"react-native-keyboard-controller\";\n\nimport { useSmoothKeyboardHandler } from \"./useSmoothKeyboardHandler\";\nimport { debounce } from \"./utils\";\n\nimport type { FC } from \"react\";\nimport type { ScrollViewProps } from \"react-native\";\nimport type { FocusedInputLayoutChangedEvent } from \"react-native-keyboard-controller\";\n\ntype KeyboardAwareScrollViewProps = {\n /** The distance between keyboard and focused `TextInput` when 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} & ScrollViewProps;\n\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 * +============================+ +============================+ +=====================================+\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 */\nconst KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({\n children,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n ...rest\n}) => {\n const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();\n const scrollPosition = useSharedValue(0);\n const position = useSharedValue(0);\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 } = useReanimatedFocusedInput();\n const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);\n\n const { height } = useWindowDimensions();\n\n const onScroll = useAnimatedScrollHandler(\n {\n onScroll: (e) => {\n position.value = e.contentOffset.y;\n },\n },\n [],\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 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 interpolatedScrollTo = interpolate(\n e,\n [initialKeyboardSize.value, keyboardHeight.value],\n [0, keyboardHeight.value - (height - point) + bottomOffset],\n );\n const targetScrollY =\n Math.max(interpolatedScrollTo, 0) + scrollPosition.value;\n scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);\n\n return interpolatedScrollTo;\n }\n\n if (absoluteY < 0) {\n const positionOnScreen = visibleRect - inputHeight - bottomOffset;\n const topOfScreen = scrollPosition.value + absoluteY;\n\n scrollTo(\n scrollViewAnimatedRef,\n 0,\n topOfScreen - positionOnScreen,\n animated,\n );\n }\n\n return 0;\n },\n [bottomOffset],\n );\n\n const onChangeText = useCallback(() => {\n \"worklet\";\n\n // if typing a text caused layout shift, then we need to ignore this handler\n // because this event will be handled in `useAnimatedReaction` below\n if (layout.value?.layout.height !== input.value?.layout.height) {\n return;\n }\n\n const prevScrollPosition = scrollPosition.value;\n const prevLayout = layout.value;\n\n scrollPosition.value = position.value;\n layout.value = input.value;\n maybeScroll(keyboardHeight.value, true);\n scrollPosition.value = prevScrollPosition;\n layout.value = prevLayout;\n }, [maybeScroll]);\n const onChangeTextHandler = useMemo(\n () => debounce(onChangeText, 200),\n [onChangeText],\n );\n\n useFocusedInputHandler(\n {\n onChangeText: onChangeTextHandler,\n },\n [onChangeTextHandler],\n );\n\n useSmoothKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;\n const keyboardWillHide = e.height === 0;\n const focusWasChanged =\n (tag.value !== e.target && e.target !== -1) || 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 }\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\n // focus was changed\n if (focusWasChanged) {\n tag.value = e.target;\n\n // save position of focused text input when keyboard starts to move\n layout.value = input.value;\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 // update position on scroll value, so `onEnd` handler\n // will pick up correct values\n position.value += maybeScroll(e.height, true);\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n currentKeyboardFrameHeight.value = e.height;\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 keyboardHeight.value = e.height;\n scrollPosition.value = position.value;\n },\n },\n [height, maybeScroll, disableScrollOnKeyboardHide],\n );\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 const prevLayout = layout.value;\n\n layout.value = input.value;\n scrollPosition.value += maybeScroll(keyboardHeight.value, true);\n layout.value = prevLayout;\n }\n },\n [],\n );\n\n const view = useAnimatedStyle(\n () => ({\n paddingBottom: currentKeyboardFrameHeight.value,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={scrollViewAnimatedRef}\n {...rest}\n // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events\n onScrollReanimated={onScroll}\n scrollEventThrottle={16}\n >\n {children}\n <Reanimated.View style={view} />\n </Reanimated.ScrollView>\n );\n};\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
@@ -1,45 +1,10 @@
1
1
  import type { FC } from "react";
2
2
  import type { ScrollViewProps } from "react-native";
3
3
  type KeyboardAwareScrollViewProps = {
4
+ /** The distance between keyboard and focused `TextInput` when keyboard is shown. Default is `0`. */
4
5
  bottomOffset?: number;
6
+ /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
7
+ disableScrollOnKeyboardHide?: boolean;
5
8
  } & ScrollViewProps;
6
- /**
7
- * Everything begins from `onStart` handler. This handler is called every time,
8
- * when keyboard changes its size or when focused `TextInput` was changed. In
9
- * this handler we are calculating/memoizing values which later will be used
10
- * during layout movement. For that we calculate:
11
- * - layout of focused field (`layout`) - to understand whether there will be overlap
12
- * - initial keyboard size (`initialKeyboardSize`) - used in scroll interpolation
13
- * - future keyboard height (`keyboardHeight`) - used in scroll interpolation
14
- * - current scroll position (`scrollPosition`) - used to scroll from this point
15
- *
16
- * Once we've calculated all necessary variables - we can actually start to use them.
17
- * It happens in `onMove` handler - this function simply calls `maybeScroll` with
18
- * current keyboard frame height. This functions makes the smooth transition.
19
- *
20
- * When the transition has finished we go to `onEnd` handler. In this handler
21
- * we verify, that the current field is not overlapped within a keyboard frame.
22
- * For full `onStart`/`onMove`/`onEnd` flow it may look like a redundant thing,
23
- * however there could be some cases, when `onMove` is not called:
24
- * - on iOS when TextInput was changed - keyboard transition is instant
25
- * - on Android when TextInput was changed and keyboard size wasn't changed
26
- * So `onEnd` handler handle the case, when `onMove` wasn't triggered.
27
- *
28
- * ====================================================================================================================+
29
- * -----------------------------------------------------Flow chart-----------------------------------------------------+
30
- * ====================================================================================================================+
31
- *
32
- * +============================+ +============================+ +==================================+
33
- * + User Press on TextInput + => + Keyboard starts showing + => + As keyboard moves frame by frame + =>
34
- * + + + (run `onStart`) + + `onMove` is getting called +
35
- * +============================+ +============================+ +==================================+
36
- *
37
- *
38
- * +============================+ +============================+ +=====================================+
39
- * + Keyboard is shown and we + => + User moved focus to + => + Only `onStart`/`onEnd` maybe called +
40
- * + call `onEnd` handler + + another `TextInput` + + (without involving `onMove`) +
41
- * +============================+ +============================+ +=====================================+
42
- *
43
- */
44
9
  declare const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps>;
45
10
  export default KeyboardAwareScrollView;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
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",
@@ -23,10 +23,13 @@ import type { ScrollViewProps } from "react-native";
23
23
  import type { FocusedInputLayoutChangedEvent } from "react-native-keyboard-controller";
24
24
 
25
25
  type KeyboardAwareScrollViewProps = {
26
+ /** The distance between keyboard and focused `TextInput` when keyboard is shown. Default is `0`. */
26
27
  bottomOffset?: number;
28
+ /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
29
+ disableScrollOnKeyboardHide?: boolean;
27
30
  } & ScrollViewProps;
28
31
 
29
- /**
32
+ /*
30
33
  * Everything begins from `onStart` handler. This handler is called every time,
31
34
  * when keyboard changes its size or when focused `TextInput` was changed. In
32
35
  * this handler we are calculating/memoizing values which later will be used
@@ -67,6 +70,7 @@ type KeyboardAwareScrollViewProps = {
67
70
  const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
68
71
  children,
69
72
  bottomOffset = 0,
73
+ disableScrollOnKeyboardHide = false,
70
74
  ...rest
71
75
  }) => {
72
76
  const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();
@@ -74,6 +78,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
74
78
  const position = useSharedValue(0);
75
79
  const currentKeyboardFrameHeight = useSharedValue(0);
76
80
  const keyboardHeight = useSharedValue(0);
81
+ const keyboardWillAppear = useSharedValue(false);
77
82
  const tag = useSharedValue(-1);
78
83
  const initialKeyboardSize = useSharedValue(0);
79
84
  const scrollBeforeKeyboardMovement = useSharedValue(0);
@@ -170,7 +175,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
170
175
 
171
176
  const keyboardWillChangeSize =
172
177
  keyboardHeight.value !== e.height && e.height > 0;
173
- const keyboardWillAppear = e.height > 0 && keyboardHeight.value === 0;
178
+ keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;
174
179
  const keyboardWillHide = e.height === 0;
175
180
  const focusWasChanged =
176
181
  (tag.value !== e.target && e.target !== -1) || keyboardWillChangeSize;
@@ -185,7 +190,11 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
185
190
  scrollPosition.value = scrollBeforeKeyboardMovement.value;
186
191
  }
187
192
 
188
- if (keyboardWillAppear || keyboardWillChangeSize || focusWasChanged) {
193
+ if (
194
+ keyboardWillAppear.value ||
195
+ keyboardWillChangeSize ||
196
+ focusWasChanged
197
+ ) {
189
198
  // persist scroll value
190
199
  scrollPosition.value = position.value;
191
200
  // just persist height - later will be used in interpolation
@@ -203,7 +212,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
203
212
  scrollBeforeKeyboardMovement.value = position.value;
204
213
  }
205
214
 
206
- if (focusWasChanged && !keyboardWillAppear) {
215
+ if (focusWasChanged && !keyboardWillAppear.value) {
207
216
  // update position on scroll value, so `onEnd` handler
208
217
  // will pick up correct values
209
218
  position.value += maybeScroll(e.height, true);
@@ -214,7 +223,10 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
214
223
 
215
224
  currentKeyboardFrameHeight.value = e.height;
216
225
 
217
- maybeScroll(e.height);
226
+ // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
227
+ if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
228
+ maybeScroll(e.height);
229
+ }
218
230
  },
219
231
  onEnd: (e) => {
220
232
  "worklet";
@@ -223,7 +235,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
223
235
  scrollPosition.value = position.value;
224
236
  },
225
237
  },
226
- [height, maybeScroll],
238
+ [height, maybeScroll, disableScrollOnKeyboardHide],
227
239
  );
228
240
 
229
241
  useAnimatedReaction(
@@ -254,7 +266,8 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
254
266
  <Reanimated.ScrollView
255
267
  ref={scrollViewAnimatedRef}
256
268
  {...rest}
257
- onScroll={onScroll}
269
+ // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
270
+ onScrollReanimated={onScroll}
258
271
  scrollEventThrottle={16}
259
272
  >
260
273
  {children}