react-native-keyboard-controller 1.10.3 → 1.10.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.
@@ -51,11 +51,12 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
51
51
  * +============================+ +============================+ +=====================================+
52
52
  *
53
53
  */
54
- const KeyboardAwareScrollView = _ref => {
54
+ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
55
55
  let {
56
56
  children,
57
57
  bottomOffset = 0,
58
58
  disableScrollOnKeyboardHide = false,
59
+ enabled = true,
59
60
  ...rest
60
61
  } = _ref;
61
62
  const scrollViewAnimatedRef = (0, _reactNativeReanimated.useAnimatedRef)();
@@ -79,6 +80,14 @@ const KeyboardAwareScrollView = _ref => {
79
80
  position.value = e.contentOffset.y;
80
81
  }
81
82
  }, []);
83
+ const onRef = (0, _react.useCallback)(assignedRef => {
84
+ if (typeof ref === "function") {
85
+ ref(assignedRef);
86
+ } else if (ref) {
87
+ ref.current = assignedRef;
88
+ }
89
+ scrollViewAnimatedRef(assignedRef);
90
+ }, []);
82
91
 
83
92
  /**
84
93
  * Function that will scroll a ScrollView as keyboard gets moving
@@ -88,6 +97,9 @@ const KeyboardAwareScrollView = _ref => {
88
97
 
89
98
  var _layout$value, _layout$value2;
90
99
  let animated = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
100
+ if (!enabled) {
101
+ return 0;
102
+ }
91
103
  const visibleRect = height - keyboardHeight.value;
92
104
  const absoluteY = ((_layout$value = layout.value) === null || _layout$value === void 0 ? void 0 : _layout$value.layout.absoluteY) || 0;
93
105
  const inputHeight = ((_layout$value2 = layout.value) === null || _layout$value2 === void 0 ? void 0 : _layout$value2.layout.height) || 0;
@@ -104,7 +116,7 @@ const KeyboardAwareScrollView = _ref => {
104
116
  (0, _reactNativeReanimated.scrollTo)(scrollViewAnimatedRef, 0, topOfScreen - positionOnScreen, animated);
105
117
  }
106
118
  return 0;
107
- }, [bottomOffset]);
119
+ }, [bottomOffset, enabled]);
108
120
  const onChangeText = (0, _react.useCallback)(() => {
109
121
  "worklet";
110
122
 
@@ -126,7 +138,7 @@ const KeyboardAwareScrollView = _ref => {
126
138
  (0, _reactNativeKeyboardController.useFocusedInputHandler)({
127
139
  onChangeText: onChangeTextHandler
128
140
  }, [onChangeTextHandler]);
129
- (0, _useSmoothKeyboardHandler.useSmoothKeyboardHandler)({
141
+ (0, _useSmoothKeyboardHandler.useSmoothKeyboardHandler)(enabled ? {
130
142
  onStart: e => {
131
143
  "worklet";
132
144
 
@@ -181,7 +193,7 @@ const KeyboardAwareScrollView = _ref => {
181
193
  keyboardHeight.value = e.height;
182
194
  scrollPosition.value = position.value;
183
195
  }
184
- }, [height, maybeScroll, disableScrollOnKeyboardHide]);
196
+ } : {}, [height, maybeScroll, disableScrollOnKeyboardHide, enabled]);
185
197
  (0, _reactNativeReanimated.useAnimatedReaction)(() => input.value, (current, previous) => {
186
198
  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)) {
187
199
  const prevLayout = layout.value;
@@ -191,10 +203,16 @@ const KeyboardAwareScrollView = _ref => {
191
203
  }
192
204
  }, []);
193
205
  const view = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
194
- paddingBottom: currentKeyboardFrameHeight.value
206
+ // animations become laggy when scrolling to the end of the `ScrollView` (when the last input is focused)
207
+ // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
208
+ // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
209
+ // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
210
+ // re-calculation on every animation frame and it helps to achieve smooth animation.
211
+ // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
212
+ paddingBottom: currentKeyboardFrameHeight.value + 1
195
213
  }), []);
196
214
  return /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.ScrollView, _extends({
197
- ref: scrollViewAnimatedRef
215
+ ref: onRef
198
216
  }, rest, {
199
217
  // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
200
218
  onScrollReanimated: onScroll,
@@ -202,7 +220,7 @@ const KeyboardAwareScrollView = _ref => {
202
220
  }), children, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
203
221
  style: view
204
222
  }));
205
- };
223
+ });
206
224
  var _default = KeyboardAwareScrollView;
207
225
  exports.default = _default;
208
226
  //# sourceMappingURL=index.js.map
@@ -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","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":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,sBAAA,GAAAH,uBAAA,CAAAC,OAAA;AAUA,IAAAG,8BAAA,GAAAH,OAAA;AAKA,IAAAI,yBAAA,GAAAJ,OAAA;AACA,IAAAK,MAAA,GAAAL,OAAA;AAAmC,SAAAM,yBAAAC,WAAA,eAAAC,OAAA,kCAAAC,iBAAA,OAAAD,OAAA,QAAAE,gBAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,WAAA,WAAAA,WAAA,GAAAG,gBAAA,GAAAD,iBAAA,KAAAF,WAAA;AAAA,SAAAR,wBAAAY,GAAA,EAAAJ,WAAA,SAAAA,WAAA,IAAAI,GAAA,IAAAA,GAAA,CAAAC,UAAA,WAAAD,GAAA,QAAAA,GAAA,oBAAAA,GAAA,wBAAAA,GAAA,4BAAAE,OAAA,EAAAF,GAAA,UAAAG,KAAA,GAAAR,wBAAA,CAAAC,WAAA,OAAAO,KAAA,IAAAA,KAAA,CAAAC,GAAA,CAAAJ,GAAA,YAAAG,KAAA,CAAAE,GAAA,CAAAL,GAAA,SAAAM,MAAA,WAAAC,qBAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,GAAA,IAAAX,GAAA,QAAAW,GAAA,kBAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAd,GAAA,EAAAW,GAAA,SAAAI,IAAA,GAAAR,qBAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAV,GAAA,EAAAW,GAAA,cAAAI,IAAA,KAAAA,IAAA,CAAAV,GAAA,IAAAU,IAAA,CAAAC,GAAA,KAAAR,MAAA,CAAAC,cAAA,CAAAH,MAAA,EAAAK,GAAA,EAAAI,IAAA,YAAAT,MAAA,CAAAK,GAAA,IAAAX,GAAA,CAAAW,GAAA,SAAAL,MAAA,CAAAJ,OAAA,GAAAF,GAAA,MAAAG,KAAA,IAAAA,KAAA,CAAAa,GAAA,CAAAhB,GAAA,EAAAM,MAAA,YAAAA,MAAA;AAAA,SAAAW,SAAA,IAAAA,QAAA,GAAAT,MAAA,CAAAU,MAAA,GAAAV,MAAA,CAAAU,MAAA,CAAAC,IAAA,eAAAC,MAAA,aAAAC,CAAA,MAAAA,CAAA,GAAAC,SAAA,CAAAC,MAAA,EAAAF,CAAA,UAAAG,MAAA,GAAAF,SAAA,CAAAD,CAAA,YAAAV,GAAA,IAAAa,MAAA,QAAAhB,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAU,MAAA,EAAAb,GAAA,KAAAS,MAAA,CAAAT,GAAA,IAAAa,MAAA,CAAAb,GAAA,gBAAAS,MAAA,YAAAH,QAAA,CAAAQ,KAAA,OAAAH,SAAA;AAanC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMI,uBAAyD,GAAGC,IAAA,IAK5D;EAAA,IAL6D;IACjEC,QAAQ;IACRC,YAAY,GAAG,CAAC;IAChBC,2BAA2B,GAAG,KAAK;IACnC,GAAGC;EACL,CAAC,GAAAJ,IAAA;EACC,MAAMK,qBAAqB,GAAG,IAAAC,qCAAc,EAAwB,CAAC;EACrE,MAAMC,cAAc,GAAG,IAAAC,qCAAc,EAAC,CAAC,CAAC;EACxC,MAAMC,QAAQ,GAAG,IAAAD,qCAAc,EAAC,CAAC,CAAC;EAClC,MAAME,0BAA0B,GAAG,IAAAF,qCAAc,EAAC,CAAC,CAAC;EACpD,MAAMG,cAAc,GAAG,IAAAH,qCAAc,EAAC,CAAC,CAAC;EACxC,MAAMI,kBAAkB,GAAG,IAAAJ,qCAAc,EAAC,KAAK,CAAC;EAChD,MAAMK,GAAG,GAAG,IAAAL,qCAAc,EAAC,CAAC,CAAC,CAAC;EAC9B,MAAMM,mBAAmB,GAAG,IAAAN,qCAAc,EAAC,CAAC,CAAC;EAC7C,MAAMO,4BAA4B,GAAG,IAAAP,qCAAc,EAAC,CAAC,CAAC;EACtD,MAAM;IAAEQ;EAAM,CAAC,GAAG,IAAAC,wDAAyB,EAAC,CAAC;EAC7C,MAAMC,MAAM,GAAG,IAAAV,qCAAc,EAAwC,IAAI,CAAC;EAE1E,MAAM;IAAEW;EAAO,CAAC,GAAG,IAAAC,gCAAmB,EAAC,CAAC;EAExC,MAAMC,QAAQ,GAAG,IAAAC,+CAAwB,EACvC;IACED,QAAQ,EAAGE,CAAC,IAAK;MACfd,QAAQ,CAACe,KAAK,GAAGD,CAAC,CAACE,aAAa,CAACC,CAAC;IACpC;EACF,CAAC,EACD,EACF,CAAC;;EAED;AACF;AACA;EACE,MAAMC,WAAW,GAAG,IAAAC,kBAAW,EAC7B,UAACL,CAAS,EAAgC;IACxC,SAAS;;IAAC,IAAAM,aAAA,EAAAC,cAAA;IAAA,IADAC,QAAiB,GAAApC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAqC,SAAA,GAAArC,SAAA,MAAG,KAAK;IAGnC,MAAMsC,WAAW,GAAGd,MAAM,GAAGR,cAAc,CAACa,KAAK;IACjD,MAAMU,SAAS,GAAG,EAAAL,aAAA,GAAAX,MAAM,CAACM,KAAK,cAAAK,aAAA,uBAAZA,aAAA,CAAcX,MAAM,CAACgB,SAAS,KAAI,CAAC;IACrD,MAAMC,WAAW,GAAG,EAAAL,cAAA,GAAAZ,MAAM,CAACM,KAAK,cAAAM,cAAA,uBAAZA,cAAA,CAAcZ,MAAM,CAACC,MAAM,KAAI,CAAC;IACpD,MAAMiB,KAAK,GAAGF,SAAS,GAAGC,WAAW;IAErC,IAAIF,WAAW,GAAGG,KAAK,IAAIlC,YAAY,EAAE;MACvC,MAAMmC,oBAAoB,GAAG,IAAAC,kCAAW,EACtCf,CAAC,EACD,CAACT,mBAAmB,CAACU,KAAK,EAAEb,cAAc,CAACa,KAAK,CAAC,EACjD,CAAC,CAAC,EAAEb,cAAc,CAACa,KAAK,IAAIL,MAAM,GAAGiB,KAAK,CAAC,GAAGlC,YAAY,CAC5D,CAAC;MACD,MAAMqC,aAAa,GACjBC,IAAI,CAACC,GAAG,CAACJ,oBAAoB,EAAE,CAAC,CAAC,GAAG9B,cAAc,CAACiB,KAAK;MAC1D,IAAAkB,+BAAQ,EAACrC,qBAAqB,EAAE,CAAC,EAAEkC,aAAa,EAAER,QAAQ,CAAC;MAE3D,OAAOM,oBAAoB;IAC7B;IAEA,IAAIH,SAAS,GAAG,CAAC,EAAE;MACjB,MAAMS,gBAAgB,GAAGV,WAAW,GAAGE,WAAW,GAAGjC,YAAY;MACjE,MAAM0C,WAAW,GAAGrC,cAAc,CAACiB,KAAK,GAAGU,SAAS;MAEpD,IAAAQ,+BAAQ,EACNrC,qBAAqB,EACrB,CAAC,EACDuC,WAAW,GAAGD,gBAAgB,EAC9BZ,QACF,CAAC;IACH;IAEA,OAAO,CAAC;EACV,CAAC,EACD,CAAC7B,YAAY,CACf,CAAC;EAED,MAAM2C,YAAY,GAAG,IAAAjB,kBAAW,EAAC,MAAM;IACrC,SAAS;;IAET;IACA;IAAA,IAAAkB,cAAA,EAAAC,YAAA;IACA,IAAI,EAAAD,cAAA,GAAA5B,MAAM,CAACM,KAAK,cAAAsB,cAAA,uBAAZA,cAAA,CAAc5B,MAAM,CAACC,MAAM,QAAA4B,YAAA,GAAK/B,KAAK,CAACQ,KAAK,cAAAuB,YAAA,uBAAXA,YAAA,CAAa7B,MAAM,CAACC,MAAM,GAAE;MAC9D;IACF;IAEA,MAAM6B,kBAAkB,GAAGzC,cAAc,CAACiB,KAAK;IAC/C,MAAMyB,UAAU,GAAG/B,MAAM,CAACM,KAAK;IAE/BjB,cAAc,CAACiB,KAAK,GAAGf,QAAQ,CAACe,KAAK;IACrCN,MAAM,CAACM,KAAK,GAAGR,KAAK,CAACQ,KAAK;IAC1BG,WAAW,CAAChB,cAAc,CAACa,KAAK,EAAE,IAAI,CAAC;IACvCjB,cAAc,CAACiB,KAAK,GAAGwB,kBAAkB;IACzC9B,MAAM,CAACM,KAAK,GAAGyB,UAAU;EAC3B,CAAC,EAAE,CAACtB,WAAW,CAAC,CAAC;EACjB,MAAMuB,mBAAmB,GAAG,IAAAC,cAAO,EACjC,MAAM,IAAAC,eAAQ,EAACP,YAAY,EAAE,GAAG,CAAC,EACjC,CAACA,YAAY,CACf,CAAC;EAED,IAAAQ,qDAAsB,EACpB;IACER,YAAY,EAAEK;EAChB,CAAC,EACD,CAACA,mBAAmB,CACtB,CAAC;EAED,IAAAI,kDAAwB,EACtB;IACEC,OAAO,EAAGhC,CAAC,IAAK;MACd,SAAS;;MAET,MAAMiC,sBAAsB,GAC1B7C,cAAc,CAACa,KAAK,KAAKD,CAAC,CAACJ,MAAM,IAAII,CAAC,CAACJ,MAAM,GAAG,CAAC;MACnDP,kBAAkB,CAACY,KAAK,GAAGD,CAAC,CAACJ,MAAM,GAAG,CAAC,IAAIR,cAAc,CAACa,KAAK,KAAK,CAAC;MACrE,MAAMiC,gBAAgB,GAAGlC,CAAC,CAACJ,MAAM,KAAK,CAAC;MACvC,MAAMuC,eAAe,GAClB7C,GAAG,CAACW,KAAK,KAAKD,CAAC,CAAC9B,MAAM,IAAI8B,CAAC,CAAC9B,MAAM,KAAK,CAAC,CAAC,IAAK+D,sBAAsB;MAEvE,IAAIA,sBAAsB,EAAE;QAC1B1C,mBAAmB,CAACU,KAAK,GAAGb,cAAc,CAACa,KAAK;MAClD;MAEA,IAAIiC,gBAAgB,EAAE;QACpB;QACA3C,mBAAmB,CAACU,KAAK,GAAG,CAAC;QAC7BjB,cAAc,CAACiB,KAAK,GAAGT,4BAA4B,CAACS,KAAK;MAC3D;MAEA,IACEZ,kBAAkB,CAACY,KAAK,IACxBgC,sBAAsB,IACtBE,eAAe,EACf;QACA;QACAnD,cAAc,CAACiB,KAAK,GAAGf,QAAQ,CAACe,KAAK;QACrC;QACAb,cAAc,CAACa,KAAK,GAAGD,CAAC,CAACJ,MAAM;MACjC;;MAEA;MACA,IAAIuC,eAAe,EAAE;QACnB7C,GAAG,CAACW,KAAK,GAAGD,CAAC,CAAC9B,MAAM;;QAEpB;QACAyB,MAAM,CAACM,KAAK,GAAGR,KAAK,CAACQ,KAAK;QAC1B;QACA;QACAT,4BAA4B,CAACS,KAAK,GAAGf,QAAQ,CAACe,KAAK;MACrD;MAEA,IAAIkC,eAAe,IAAI,CAAC9C,kBAAkB,CAACY,KAAK,EAAE;QAChD;QACA;QACAf,QAAQ,CAACe,KAAK,IAAIG,WAAW,CAACJ,CAAC,CAACJ,MAAM,EAAE,IAAI,CAAC;MAC/C;IACF,CAAC;IACDwC,MAAM,EAAGpC,CAAC,IAAK;MACb,SAAS;;MAETb,0BAA0B,CAACc,KAAK,GAAGD,CAAC,CAACJ,MAAM;;MAE3C;MACA,IAAI,CAAChB,2BAA2B,IAAIS,kBAAkB,CAACY,KAAK,EAAE;QAC5DG,WAAW,CAACJ,CAAC,CAACJ,MAAM,CAAC;MACvB;IACF,CAAC;IACDyC,KAAK,EAAGrC,CAAC,IAAK;MACZ,SAAS;;MAETZ,cAAc,CAACa,KAAK,GAAGD,CAAC,CAACJ,MAAM;MAC/BZ,cAAc,CAACiB,KAAK,GAAGf,QAAQ,CAACe,KAAK;IACvC;EACF,CAAC,EACD,CAACL,MAAM,EAAEQ,WAAW,EAAExB,2BAA2B,CACnD,CAAC;EAED,IAAA0D,0CAAmB,EACjB,MAAM7C,KAAK,CAACQ,KAAK,EACjB,CAACsC,OAAO,EAAEC,QAAQ,KAAK;IACrB,IACE,CAAAD,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAErE,MAAM,OAAKsE,QAAQ,aAARA,QAAQ,uBAARA,QAAQ,CAAEtE,MAAM,KACpC,CAAAqE,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAE5C,MAAM,CAACC,MAAM,OAAK4C,QAAQ,aAARA,QAAQ,uBAARA,QAAQ,CAAE7C,MAAM,CAACC,MAAM,GAClD;MACA,MAAM8B,UAAU,GAAG/B,MAAM,CAACM,KAAK;MAE/BN,MAAM,CAACM,KAAK,GAAGR,KAAK,CAACQ,KAAK;MAC1BjB,cAAc,CAACiB,KAAK,IAAIG,WAAW,CAAChB,cAAc,CAACa,KAAK,EAAE,IAAI,CAAC;MAC/DN,MAAM,CAACM,KAAK,GAAGyB,UAAU;IAC3B;EACF,CAAC,EACD,EACF,CAAC;EAED,MAAMe,IAAI,GAAG,IAAAC,uCAAgB,EAC3B,OAAO;IACLC,aAAa,EAAExD,0BAA0B,CAACc;EAC5C,CAAC,CAAC,EACF,EACF,CAAC;EAED,oBACEhE,MAAA,CAAAe,OAAA,CAAA4F,aAAA,CAACvG,sBAAA,CAAAW,OAAU,CAAC6F,UAAU,EAAA9E,QAAA;IACpB+E,GAAG,EAAEhE;EAAsB,GACvBD,IAAI;IACR;IACAkE,kBAAkB,EAAEjD,QAAS;IAC7BkD,mBAAmB,EAAE;EAAG,IAEvBtE,QAAQ,eACTzC,MAAA,CAAAe,OAAA,CAAA4F,aAAA,CAACvG,sBAAA,CAAAW,OAAU,CAACiG,IAAI;IAACC,KAAK,EAAET;EAAK,CAAE,CACV,CAAC;AAE5B,CAAC;AAAC,IAAAU,QAAA,GAEa3E,uBAAuB;AAAA4E,OAAA,CAAApG,OAAA,GAAAmG,QAAA"}
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","forwardRef","_ref","ref","children","bottomOffset","disableScrollOnKeyboardHide","enabled","rest","scrollViewAnimatedRef","useAnimatedRef","scrollPosition","useSharedValue","position","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","useReanimatedFocusedInput","layout","height","useWindowDimensions","onScroll","useAnimatedScrollHandler","e","value","contentOffset","y","onRef","useCallback","assignedRef","current","maybeScroll","_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","previous","view","useAnimatedStyle","paddingBottom","createElement","ScrollView","onScrollReanimated","scrollEventThrottle","View","style","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, 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 { ScrollView, 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 /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true` */\n enabled?: 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 = forwardRef<\n ScrollView,\n React.PropsWithChildren<KeyboardAwareScrollViewProps>\n>(\n (\n {\n children,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n enabled = true,\n ...rest\n },\n ref,\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 const onRef = useCallback((assignedRef: Reanimated.ScrollView) => {\n if (typeof ref === \"function\") {\n ref(assignedRef);\n } else if (ref) {\n ref.current = assignedRef;\n }\n\n scrollViewAnimatedRef(assignedRef);\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 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, enabled],\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\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 enabled\n ? {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n keyboardWillAppear.value =\n e.height > 0 && keyboardHeight.value === 0;\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 }\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 : {},\n [height, maybeScroll, disableScrollOnKeyboardHide, enabled],\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 // animations become laggy when scrolling to the end of the `ScrollView` (when the last input is focused)\n // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding\n // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation\n // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout\n // re-calculation on every animation frame and it helps to achieve smooth animation.\n // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342\n paddingBottom: currentKeyboardFrameHeight.value + 1,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={onRef}\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);\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
@@ -24,16 +24,19 @@ const TELEGRAM_ANDROID_TIMING_CONFIG = {
24
24
  */
25
25
  const useSmoothKeyboardHandler = (handler, deps) => {
26
26
  const target = (0, _reactNativeReanimated.useSharedValue)(-1);
27
+ const height = (0, _reactNativeReanimated.useSharedValue)(0);
27
28
  const persistedHeight = (0, _reactNativeReanimated.useSharedValue)(0);
28
29
  const animatedKeyboardHeight = (0, _reactNativeReanimated.useSharedValue)(0);
29
30
  (0, _reactNativeReanimated.useAnimatedReaction)(() => {
30
31
  if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
31
32
  return;
32
33
  }
34
+ if (persistedHeight.value === 0) {
35
+ return;
36
+ }
33
37
  const event = {
34
- // it'll be always 250, since we're running animation via `withTiming` where
35
- // duration in config (TELEGRAM_ANDROID_TIMING_CONFIG.duration) = 250ms
36
- duration: 250,
38
+ // it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`
39
+ duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,
37
40
  target: target.value,
38
41
  height: animatedKeyboardHeight.value,
39
42
  progress: animatedKeyboardHeight.value / persistedHeight.value
@@ -47,9 +50,10 @@ const useSmoothKeyboardHandler = (handler, deps) => {
47
50
  (_handler$onMove = handler.onMove) === null || _handler$onMove === void 0 ? void 0 : _handler$onMove.call(handler, evt);
48
51
 
49
52
  // dispatch `onEnd`
50
- if (evt.height === persistedHeight.value) {
53
+ if (evt.height === height.value) {
51
54
  var _handler$onEnd;
52
55
  (_handler$onEnd = handler.onEnd) === null || _handler$onEnd === void 0 ? void 0 : _handler$onEnd.call(handler, evt);
56
+ persistedHeight.value = height.value;
53
57
  }
54
58
  }, [handler]);
55
59
  (0, _reactNativeKeyboardController.useKeyboardHandler)({
@@ -66,6 +70,7 @@ const useSmoothKeyboardHandler = (handler, deps) => {
66
70
  return;
67
71
  }
68
72
  target.value = e.target;
73
+ height.value = e.height;
69
74
  if (e.height > 0) {
70
75
  persistedHeight.value = e.height;
71
76
  }
@@ -75,7 +80,10 @@ const useSmoothKeyboardHandler = (handler, deps) => {
75
80
  if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
76
81
  animatedKeyboardHeight.value = (0, _reactNativeReanimated.withTiming)(e.height, TELEGRAM_ANDROID_TIMING_CONFIG);
77
82
  }
78
- (_handler$onStart2 = handler.onStart) === null || _handler$onStart2 === void 0 ? void 0 : _handler$onStart2.call(handler, e);
83
+ (_handler$onStart2 = handler.onStart) === null || _handler$onStart2 === void 0 ? void 0 : _handler$onStart2.call(handler, {
84
+ ...e,
85
+ duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS ? e.duration : TELEGRAM_ANDROID_TIMING_CONFIG.duration
86
+ });
79
87
  },
80
88
  onMove: e => {
81
89
  "worklet";
@@ -92,7 +100,6 @@ const useSmoothKeyboardHandler = (handler, deps) => {
92
100
  var _handler$onEnd3;
93
101
  (_handler$onEnd3 = handler.onEnd) === null || _handler$onEnd3 === void 0 ? void 0 : _handler$onEnd3.call(handler, e);
94
102
  }
95
- persistedHeight.value = e.height;
96
103
  }
97
104
  }, deps);
98
105
  };
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_reactNativeReanimated","_reactNativeKeyboardController","IS_ANDROID_ELEVEN_OR_HIGHER","Platform","OS","Version","IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS","TELEGRAM_ANDROID_TIMING_CONFIG","duration","easing","Easing","bezier","useSmoothKeyboardHandler","handler","deps","target","useSharedValue","persistedHeight","animatedKeyboardHeight","useAnimatedReaction","event","value","height","progress","evt","_handler$onMove","onMove","call","_handler$onEnd","onEnd","useKeyboardHandler","onStart","e","_handler$onStart2","_handler$onStart","_handler$onEnd2","withTiming","_handler$onMove2","_handler$onEnd3","exports"],"sources":["useSmoothKeyboardHandler.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport {\n Easing,\n useAnimatedReaction,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport { useKeyboardHandler } from \"react-native-keyboard-controller\";\n\nconst IS_ANDROID_ELEVEN_OR_HIGHER =\n Platform.OS === \"android\" && Platform.Version >= 30;\n// on these platforms keyboard transitions will be smooth\nconst IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS =\n IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS === \"ios\";\n// on Android Telegram is not using androidx.core values and uses custom interpolation\n// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39\n// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40\nconst TELEGRAM_ANDROID_TIMING_CONFIG = {\n duration: 250,\n easing: Easing.bezier(\n 0.19919472913616398,\n 0.010644531250000006,\n 0.27920937042459737,\n 0.91025390625,\n ),\n};\n\n/**\n * Hook that uses default transitions for iOS and Android > 11, and uses\n * custom interpolation on Android < 11 to achieve more smooth animation\n */\nexport const useSmoothKeyboardHandler: typeof useKeyboardHandler = (\n handler,\n deps,\n) => {\n const target = useSharedValue(-1);\n const persistedHeight = useSharedValue(0);\n const animatedKeyboardHeight = useSharedValue(0);\n\n useAnimatedReaction(\n () => {\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n return;\n }\n const event = {\n // it'll be always 250, since we're running animation via `withTiming` where\n // duration in config (TELEGRAM_ANDROID_TIMING_CONFIG.duration) = 250ms\n duration: 250,\n target: target.value,\n height: animatedKeyboardHeight.value,\n progress: animatedKeyboardHeight.value / persistedHeight.value,\n };\n return event;\n },\n (evt) => {\n if (!evt) {\n return;\n }\n handler.onMove?.(evt);\n\n // dispatch `onEnd`\n if (evt.height === persistedHeight.value) {\n handler.onEnd?.(evt);\n }\n },\n [handler],\n );\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n // immediately dispatch onStart/onEnd events if onStart dispatched with the same height\n // and don't wait for animation 250ms\n if (\n !IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS &&\n e.height === persistedHeight.value\n ) {\n handler.onStart?.(e);\n handler.onEnd?.(e);\n\n return;\n }\n\n target.value = e.target;\n\n if (e.height > 0) {\n persistedHeight.value = e.height;\n }\n // if we are running on Android < 9, then we are using custom interpolation\n // to achieve smoother animation and use `animatedKeyboardHeight` as animation\n // driver\n if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n animatedKeyboardHeight.value = withTiming(\n e.height,\n TELEGRAM_ANDROID_TIMING_CONFIG,\n );\n }\n\n handler.onStart?.(e);\n },\n onMove: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onMove?.(e);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onEnd?.(e);\n }\n\n persistedHeight.value = e.height;\n },\n },\n deps,\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["_reactNative","require","_reactNativeReanimated","_reactNativeKeyboardController","IS_ANDROID_ELEVEN_OR_HIGHER","Platform","OS","Version","IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS","TELEGRAM_ANDROID_TIMING_CONFIG","duration","easing","Easing","bezier","useSmoothKeyboardHandler","handler","deps","target","useSharedValue","height","persistedHeight","animatedKeyboardHeight","useAnimatedReaction","value","event","progress","evt","_handler$onMove","onMove","call","_handler$onEnd","onEnd","useKeyboardHandler","onStart","e","_handler$onStart2","_handler$onStart","_handler$onEnd2","withTiming","_handler$onMove2","_handler$onEnd3","exports"],"sources":["useSmoothKeyboardHandler.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport {\n Easing,\n useAnimatedReaction,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport { useKeyboardHandler } from \"react-native-keyboard-controller\";\n\nconst IS_ANDROID_ELEVEN_OR_HIGHER =\n Platform.OS === \"android\" && Platform.Version >= 30;\n// on these platforms keyboard transitions will be smooth\nconst IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS =\n IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS === \"ios\";\n// on Android Telegram is not using androidx.core values and uses custom interpolation\n// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39\n// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40\nconst TELEGRAM_ANDROID_TIMING_CONFIG = {\n duration: 250,\n easing: Easing.bezier(\n 0.19919472913616398,\n 0.010644531250000006,\n 0.27920937042459737,\n 0.91025390625,\n ),\n};\n\n/**\n * Hook that uses default transitions for iOS and Android > 11, and uses\n * custom interpolation on Android < 11 to achieve more smooth animation\n */\nexport const useSmoothKeyboardHandler: typeof useKeyboardHandler = (\n handler,\n deps,\n) => {\n const target = useSharedValue(-1);\n const height = useSharedValue(0);\n const persistedHeight = useSharedValue(0);\n const animatedKeyboardHeight = useSharedValue(0);\n\n useAnimatedReaction(\n () => {\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n return;\n }\n if (persistedHeight.value === 0) {\n return;\n }\n const event = {\n // it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`\n duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,\n target: target.value,\n height: animatedKeyboardHeight.value,\n progress: animatedKeyboardHeight.value / persistedHeight.value,\n };\n return event;\n },\n (evt) => {\n if (!evt) {\n return;\n }\n handler.onMove?.(evt);\n\n // dispatch `onEnd`\n if (evt.height === height.value) {\n handler.onEnd?.(evt);\n persistedHeight.value = height.value;\n }\n },\n [handler],\n );\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n // immediately dispatch onStart/onEnd events if onStart dispatched with the same height\n // and don't wait for animation 250ms\n if (\n !IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS &&\n e.height === persistedHeight.value\n ) {\n handler.onStart?.(e);\n handler.onEnd?.(e);\n\n return;\n }\n\n target.value = e.target;\n height.value = e.height;\n\n if (e.height > 0) {\n persistedHeight.value = e.height;\n }\n // if we are running on Android < 9, then we are using custom interpolation\n // to achieve smoother animation and use `animatedKeyboardHeight` as animation\n // driver\n if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n animatedKeyboardHeight.value = withTiming(\n e.height,\n TELEGRAM_ANDROID_TIMING_CONFIG,\n );\n }\n\n handler.onStart?.({\n ...e,\n duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS\n ? e.duration\n : TELEGRAM_ANDROID_TIMING_CONFIG.duration,\n });\n },\n onMove: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onMove?.(e);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onEnd?.(e);\n }\n },\n },\n deps,\n );\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  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); }
2
- import React, { useCallback, useMemo } from "react";
2
+ import React, { forwardRef, useCallback, useMemo } from "react";
3
3
  import { useWindowDimensions } from "react-native";
4
4
  import Reanimated, { interpolate, scrollTo, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
5
5
  import { useFocusedInputHandler, useReanimatedFocusedInput } from "react-native-keyboard-controller";
@@ -43,11 +43,12 @@ import { debounce } from "./utils";
43
43
  * +============================+ +============================+ +=====================================+
44
44
  *
45
45
  */
46
- const KeyboardAwareScrollView = _ref => {
46
+ const KeyboardAwareScrollView = /*#__PURE__*/forwardRef((_ref, ref) => {
47
47
  let {
48
48
  children,
49
49
  bottomOffset = 0,
50
50
  disableScrollOnKeyboardHide = false,
51
+ enabled = true,
51
52
  ...rest
52
53
  } = _ref;
53
54
  const scrollViewAnimatedRef = useAnimatedRef();
@@ -71,6 +72,14 @@ const KeyboardAwareScrollView = _ref => {
71
72
  position.value = e.contentOffset.y;
72
73
  }
73
74
  }, []);
75
+ const onRef = useCallback(assignedRef => {
76
+ if (typeof ref === "function") {
77
+ ref(assignedRef);
78
+ } else if (ref) {
79
+ ref.current = assignedRef;
80
+ }
81
+ scrollViewAnimatedRef(assignedRef);
82
+ }, []);
74
83
 
75
84
  /**
76
85
  * Function that will scroll a ScrollView as keyboard gets moving
@@ -80,6 +89,9 @@ const KeyboardAwareScrollView = _ref => {
80
89
 
81
90
  var _layout$value, _layout$value2;
82
91
  let animated = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
92
+ if (!enabled) {
93
+ return 0;
94
+ }
83
95
  const visibleRect = height - keyboardHeight.value;
84
96
  const absoluteY = ((_layout$value = layout.value) === null || _layout$value === void 0 ? void 0 : _layout$value.layout.absoluteY) || 0;
85
97
  const inputHeight = ((_layout$value2 = layout.value) === null || _layout$value2 === void 0 ? void 0 : _layout$value2.layout.height) || 0;
@@ -96,7 +108,7 @@ const KeyboardAwareScrollView = _ref => {
96
108
  scrollTo(scrollViewAnimatedRef, 0, topOfScreen - positionOnScreen, animated);
97
109
  }
98
110
  return 0;
99
- }, [bottomOffset]);
111
+ }, [bottomOffset, enabled]);
100
112
  const onChangeText = useCallback(() => {
101
113
  "worklet";
102
114
 
@@ -118,7 +130,7 @@ const KeyboardAwareScrollView = _ref => {
118
130
  useFocusedInputHandler({
119
131
  onChangeText: onChangeTextHandler
120
132
  }, [onChangeTextHandler]);
121
- useSmoothKeyboardHandler({
133
+ useSmoothKeyboardHandler(enabled ? {
122
134
  onStart: e => {
123
135
  "worklet";
124
136
 
@@ -173,7 +185,7 @@ const KeyboardAwareScrollView = _ref => {
173
185
  keyboardHeight.value = e.height;
174
186
  scrollPosition.value = position.value;
175
187
  }
176
- }, [height, maybeScroll, disableScrollOnKeyboardHide]);
188
+ } : {}, [height, maybeScroll, disableScrollOnKeyboardHide, enabled]);
177
189
  useAnimatedReaction(() => input.value, (current, previous) => {
178
190
  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)) {
179
191
  const prevLayout = layout.value;
@@ -183,10 +195,16 @@ const KeyboardAwareScrollView = _ref => {
183
195
  }
184
196
  }, []);
185
197
  const view = useAnimatedStyle(() => ({
186
- paddingBottom: currentKeyboardFrameHeight.value
198
+ // animations become laggy when scrolling to the end of the `ScrollView` (when the last input is focused)
199
+ // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
200
+ // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
201
+ // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
202
+ // re-calculation on every animation frame and it helps to achieve smooth animation.
203
+ // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
204
+ paddingBottom: currentKeyboardFrameHeight.value + 1
187
205
  }), []);
188
206
  return /*#__PURE__*/React.createElement(Reanimated.ScrollView, _extends({
189
- ref: scrollViewAnimatedRef
207
+ ref: onRef
190
208
  }, rest, {
191
209
  // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
192
210
  onScrollReanimated: onScroll,
@@ -194,6 +212,6 @@ const KeyboardAwareScrollView = _ref => {
194
212
  }), children, /*#__PURE__*/React.createElement(Reanimated.View, {
195
213
  style: view
196
214
  }));
197
- };
215
+ });
198
216
  export default KeyboardAwareScrollView;
199
217
  //# sourceMappingURL=index.js.map
@@ -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","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
+ {"version":3,"names":["React","forwardRef","useCallback","useMemo","useWindowDimensions","Reanimated","interpolate","scrollTo","useAnimatedReaction","useAnimatedRef","useAnimatedScrollHandler","useAnimatedStyle","useSharedValue","useFocusedInputHandler","useReanimatedFocusedInput","useSmoothKeyboardHandler","debounce","KeyboardAwareScrollView","_ref","ref","children","bottomOffset","disableScrollOnKeyboardHide","enabled","rest","scrollViewAnimatedRef","scrollPosition","position","currentKeyboardFrameHeight","keyboardHeight","keyboardWillAppear","tag","initialKeyboardSize","scrollBeforeKeyboardMovement","input","layout","height","onScroll","e","value","contentOffset","y","onRef","assignedRef","current","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","previous","view","paddingBottom","createElement","ScrollView","_extends","onScrollReanimated","scrollEventThrottle","View","style"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, 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 { ScrollView, 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 /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true` */\n enabled?: 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 = forwardRef<\n ScrollView,\n React.PropsWithChildren<KeyboardAwareScrollViewProps>\n>(\n (\n {\n children,\n bottomOffset = 0,\n disableScrollOnKeyboardHide = false,\n enabled = true,\n ...rest\n },\n ref,\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 const onRef = useCallback((assignedRef: Reanimated.ScrollView) => {\n if (typeof ref === \"function\") {\n ref(assignedRef);\n } else if (ref) {\n ref.current = assignedRef;\n }\n\n scrollViewAnimatedRef(assignedRef);\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 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, enabled],\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\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 enabled\n ? {\n onStart: (e) => {\n \"worklet\";\n\n const keyboardWillChangeSize =\n keyboardHeight.value !== e.height && e.height > 0;\n keyboardWillAppear.value =\n e.height > 0 && keyboardHeight.value === 0;\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 }\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 : {},\n [height, maybeScroll, disableScrollOnKeyboardHide, enabled],\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 // animations become laggy when scrolling to the end of the `ScrollView` (when the last input is focused)\n // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding\n // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation\n // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout\n // re-calculation on every animation frame and it helps to achieve smooth animation.\n // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342\n paddingBottom: currentKeyboardFrameHeight.value + 1,\n }),\n [],\n );\n\n return (\n <Reanimated.ScrollView\n ref={onRef}\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);\n\nexport default KeyboardAwareScrollView;\n"],"mappings":"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"}
@@ -18,16 +18,19 @@ const TELEGRAM_ANDROID_TIMING_CONFIG = {
18
18
  */
19
19
  export const useSmoothKeyboardHandler = (handler, deps) => {
20
20
  const target = useSharedValue(-1);
21
+ const height = useSharedValue(0);
21
22
  const persistedHeight = useSharedValue(0);
22
23
  const animatedKeyboardHeight = useSharedValue(0);
23
24
  useAnimatedReaction(() => {
24
25
  if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
25
26
  return;
26
27
  }
28
+ if (persistedHeight.value === 0) {
29
+ return;
30
+ }
27
31
  const event = {
28
- // it'll be always 250, since we're running animation via `withTiming` where
29
- // duration in config (TELEGRAM_ANDROID_TIMING_CONFIG.duration) = 250ms
30
- duration: 250,
32
+ // it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`
33
+ duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,
31
34
  target: target.value,
32
35
  height: animatedKeyboardHeight.value,
33
36
  progress: animatedKeyboardHeight.value / persistedHeight.value
@@ -41,9 +44,10 @@ export const useSmoothKeyboardHandler = (handler, deps) => {
41
44
  (_handler$onMove = handler.onMove) === null || _handler$onMove === void 0 ? void 0 : _handler$onMove.call(handler, evt);
42
45
 
43
46
  // dispatch `onEnd`
44
- if (evt.height === persistedHeight.value) {
47
+ if (evt.height === height.value) {
45
48
  var _handler$onEnd;
46
49
  (_handler$onEnd = handler.onEnd) === null || _handler$onEnd === void 0 ? void 0 : _handler$onEnd.call(handler, evt);
50
+ persistedHeight.value = height.value;
47
51
  }
48
52
  }, [handler]);
49
53
  useKeyboardHandler({
@@ -60,6 +64,7 @@ export const useSmoothKeyboardHandler = (handler, deps) => {
60
64
  return;
61
65
  }
62
66
  target.value = e.target;
67
+ height.value = e.height;
63
68
  if (e.height > 0) {
64
69
  persistedHeight.value = e.height;
65
70
  }
@@ -69,7 +74,10 @@ export const useSmoothKeyboardHandler = (handler, deps) => {
69
74
  if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
70
75
  animatedKeyboardHeight.value = withTiming(e.height, TELEGRAM_ANDROID_TIMING_CONFIG);
71
76
  }
72
- (_handler$onStart2 = handler.onStart) === null || _handler$onStart2 === void 0 ? void 0 : _handler$onStart2.call(handler, e);
77
+ (_handler$onStart2 = handler.onStart) === null || _handler$onStart2 === void 0 ? void 0 : _handler$onStart2.call(handler, {
78
+ ...e,
79
+ duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS ? e.duration : TELEGRAM_ANDROID_TIMING_CONFIG.duration
80
+ });
73
81
  },
74
82
  onMove: e => {
75
83
  "worklet";
@@ -86,7 +94,6 @@ export const useSmoothKeyboardHandler = (handler, deps) => {
86
94
  var _handler$onEnd3;
87
95
  (_handler$onEnd3 = handler.onEnd) === null || _handler$onEnd3 === void 0 ? void 0 : _handler$onEnd3.call(handler, e);
88
96
  }
89
- persistedHeight.value = e.height;
90
97
  }
91
98
  }, deps);
92
99
  };
@@ -1 +1 @@
1
- {"version":3,"names":["Platform","Easing","useAnimatedReaction","useSharedValue","withTiming","useKeyboardHandler","IS_ANDROID_ELEVEN_OR_HIGHER","OS","Version","IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS","TELEGRAM_ANDROID_TIMING_CONFIG","duration","easing","bezier","useSmoothKeyboardHandler","handler","deps","target","persistedHeight","animatedKeyboardHeight","event","value","height","progress","evt","_handler$onMove","onMove","call","_handler$onEnd","onEnd","onStart","e","_handler$onStart2","_handler$onStart","_handler$onEnd2","_handler$onMove2","_handler$onEnd3"],"sources":["useSmoothKeyboardHandler.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport {\n Easing,\n useAnimatedReaction,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport { useKeyboardHandler } from \"react-native-keyboard-controller\";\n\nconst IS_ANDROID_ELEVEN_OR_HIGHER =\n Platform.OS === \"android\" && Platform.Version >= 30;\n// on these platforms keyboard transitions will be smooth\nconst IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS =\n IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS === \"ios\";\n// on Android Telegram is not using androidx.core values and uses custom interpolation\n// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39\n// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40\nconst TELEGRAM_ANDROID_TIMING_CONFIG = {\n duration: 250,\n easing: Easing.bezier(\n 0.19919472913616398,\n 0.010644531250000006,\n 0.27920937042459737,\n 0.91025390625,\n ),\n};\n\n/**\n * Hook that uses default transitions for iOS and Android > 11, and uses\n * custom interpolation on Android < 11 to achieve more smooth animation\n */\nexport const useSmoothKeyboardHandler: typeof useKeyboardHandler = (\n handler,\n deps,\n) => {\n const target = useSharedValue(-1);\n const persistedHeight = useSharedValue(0);\n const animatedKeyboardHeight = useSharedValue(0);\n\n useAnimatedReaction(\n () => {\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n return;\n }\n const event = {\n // it'll be always 250, since we're running animation via `withTiming` where\n // duration in config (TELEGRAM_ANDROID_TIMING_CONFIG.duration) = 250ms\n duration: 250,\n target: target.value,\n height: animatedKeyboardHeight.value,\n progress: animatedKeyboardHeight.value / persistedHeight.value,\n };\n return event;\n },\n (evt) => {\n if (!evt) {\n return;\n }\n handler.onMove?.(evt);\n\n // dispatch `onEnd`\n if (evt.height === persistedHeight.value) {\n handler.onEnd?.(evt);\n }\n },\n [handler],\n );\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n // immediately dispatch onStart/onEnd events if onStart dispatched with the same height\n // and don't wait for animation 250ms\n if (\n !IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS &&\n e.height === persistedHeight.value\n ) {\n handler.onStart?.(e);\n handler.onEnd?.(e);\n\n return;\n }\n\n target.value = e.target;\n\n if (e.height > 0) {\n persistedHeight.value = e.height;\n }\n // if we are running on Android < 9, then we are using custom interpolation\n // to achieve smoother animation and use `animatedKeyboardHeight` as animation\n // driver\n if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n animatedKeyboardHeight.value = withTiming(\n e.height,\n TELEGRAM_ANDROID_TIMING_CONFIG,\n );\n }\n\n handler.onStart?.(e);\n },\n onMove: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onMove?.(e);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onEnd?.(e);\n }\n\n persistedHeight.value = e.height;\n },\n },\n deps,\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["Platform","Easing","useAnimatedReaction","useSharedValue","withTiming","useKeyboardHandler","IS_ANDROID_ELEVEN_OR_HIGHER","OS","Version","IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS","TELEGRAM_ANDROID_TIMING_CONFIG","duration","easing","bezier","useSmoothKeyboardHandler","handler","deps","target","height","persistedHeight","animatedKeyboardHeight","value","event","progress","evt","_handler$onMove","onMove","call","_handler$onEnd","onEnd","onStart","e","_handler$onStart2","_handler$onStart","_handler$onEnd2","_handler$onMove2","_handler$onEnd3"],"sources":["useSmoothKeyboardHandler.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport {\n Easing,\n useAnimatedReaction,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport { useKeyboardHandler } from \"react-native-keyboard-controller\";\n\nconst IS_ANDROID_ELEVEN_OR_HIGHER =\n Platform.OS === \"android\" && Platform.Version >= 30;\n// on these platforms keyboard transitions will be smooth\nconst IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS =\n IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS === \"ios\";\n// on Android Telegram is not using androidx.core values and uses custom interpolation\n// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39\n// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40\nconst TELEGRAM_ANDROID_TIMING_CONFIG = {\n duration: 250,\n easing: Easing.bezier(\n 0.19919472913616398,\n 0.010644531250000006,\n 0.27920937042459737,\n 0.91025390625,\n ),\n};\n\n/**\n * Hook that uses default transitions for iOS and Android > 11, and uses\n * custom interpolation on Android < 11 to achieve more smooth animation\n */\nexport const useSmoothKeyboardHandler: typeof useKeyboardHandler = (\n handler,\n deps,\n) => {\n const target = useSharedValue(-1);\n const height = useSharedValue(0);\n const persistedHeight = useSharedValue(0);\n const animatedKeyboardHeight = useSharedValue(0);\n\n useAnimatedReaction(\n () => {\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n return;\n }\n if (persistedHeight.value === 0) {\n return;\n }\n const event = {\n // it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`\n duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,\n target: target.value,\n height: animatedKeyboardHeight.value,\n progress: animatedKeyboardHeight.value / persistedHeight.value,\n };\n return event;\n },\n (evt) => {\n if (!evt) {\n return;\n }\n handler.onMove?.(evt);\n\n // dispatch `onEnd`\n if (evt.height === height.value) {\n handler.onEnd?.(evt);\n persistedHeight.value = height.value;\n }\n },\n [handler],\n );\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n // immediately dispatch onStart/onEnd events if onStart dispatched with the same height\n // and don't wait for animation 250ms\n if (\n !IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS &&\n e.height === persistedHeight.value\n ) {\n handler.onStart?.(e);\n handler.onEnd?.(e);\n\n return;\n }\n\n target.value = e.target;\n height.value = e.height;\n\n if (e.height > 0) {\n persistedHeight.value = e.height;\n }\n // if we are running on Android < 9, then we are using custom interpolation\n // to achieve smoother animation and use `animatedKeyboardHeight` as animation\n // driver\n if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n animatedKeyboardHeight.value = withTiming(\n e.height,\n TELEGRAM_ANDROID_TIMING_CONFIG,\n );\n }\n\n handler.onStart?.({\n ...e,\n duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS\n ? e.duration\n : TELEGRAM_ANDROID_TIMING_CONFIG.duration,\n });\n },\n onMove: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onMove?.(e);\n }\n },\n onEnd: (e) => {\n \"worklet\";\n\n if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {\n handler.onEnd?.(e);\n }\n },\n },\n deps,\n );\n};\n"],"mappings":"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"}
@@ -1,10 +1,13 @@
1
- import type { FC } from "react";
2
- import type { ScrollViewProps } from "react-native";
3
- type KeyboardAwareScrollViewProps = {
1
+ import React from "react";
2
+ import type { ScrollView, ScrollViewProps } from "react-native";
3
+ declare const KeyboardAwareScrollView: React.ForwardRefExoticComponent<{
4
4
  /** The distance between keyboard and focused `TextInput` when keyboard is shown. Default is `0`. */
5
- bottomOffset?: number;
5
+ bottomOffset?: number | undefined;
6
6
  /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
7
- disableScrollOnKeyboardHide?: boolean;
8
- } & ScrollViewProps;
9
- declare const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps>;
7
+ disableScrollOnKeyboardHide?: boolean | undefined;
8
+ /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true` */
9
+ enabled?: boolean | undefined;
10
+ } & ScrollViewProps & {
11
+ children?: React.ReactNode;
12
+ } & React.RefAttributes<ScrollView>>;
10
13
  export default KeyboardAwareScrollView;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.10.3",
3
+ "version": "1.10.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",
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useMemo } from "react";
1
+ import React, { forwardRef, useCallback, useMemo } from "react";
2
2
  import { useWindowDimensions } from "react-native";
3
3
  import Reanimated, {
4
4
  interpolate,
@@ -18,8 +18,7 @@ import {
18
18
  import { useSmoothKeyboardHandler } from "./useSmoothKeyboardHandler";
19
19
  import { debounce } from "./utils";
20
20
 
21
- import type { FC } from "react";
22
- import type { ScrollViewProps } from "react-native";
21
+ import type { ScrollView, ScrollViewProps } from "react-native";
23
22
  import type { FocusedInputLayoutChangedEvent } from "react-native-keyboard-controller";
24
23
 
25
24
  type KeyboardAwareScrollViewProps = {
@@ -27,6 +26,8 @@ type KeyboardAwareScrollViewProps = {
27
26
  bottomOffset?: number;
28
27
  /** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
29
28
  disableScrollOnKeyboardHide?: boolean;
29
+ /** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true` */
30
+ enabled?: boolean;
30
31
  } & ScrollViewProps;
31
32
 
32
33
  /*
@@ -67,213 +68,247 @@ type KeyboardAwareScrollViewProps = {
67
68
  * +============================+ +============================+ +=====================================+
68
69
  *
69
70
  */
70
- const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
71
- children,
72
- bottomOffset = 0,
73
- disableScrollOnKeyboardHide = false,
74
- ...rest
75
- }) => {
76
- const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();
77
- const scrollPosition = useSharedValue(0);
78
- const position = useSharedValue(0);
79
- const currentKeyboardFrameHeight = useSharedValue(0);
80
- const keyboardHeight = useSharedValue(0);
81
- const keyboardWillAppear = useSharedValue(false);
82
- const tag = useSharedValue(-1);
83
- const initialKeyboardSize = useSharedValue(0);
84
- const scrollBeforeKeyboardMovement = useSharedValue(0);
85
- const { input } = useReanimatedFocusedInput();
86
- const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
87
-
88
- const { height } = useWindowDimensions();
89
-
90
- const onScroll = useAnimatedScrollHandler(
71
+ const KeyboardAwareScrollView = forwardRef<
72
+ ScrollView,
73
+ React.PropsWithChildren<KeyboardAwareScrollViewProps>
74
+ >(
75
+ (
91
76
  {
92
- onScroll: (e) => {
93
- position.value = e.contentOffset.y;
94
- },
77
+ children,
78
+ bottomOffset = 0,
79
+ disableScrollOnKeyboardHide = false,
80
+ enabled = true,
81
+ ...rest
95
82
  },
96
- [],
97
- );
98
-
99
- /**
100
- * Function that will scroll a ScrollView as keyboard gets moving
101
- */
102
- const maybeScroll = useCallback(
103
- (e: number, animated: boolean = false) => {
104
- "worklet";
105
-
106
- const visibleRect = height - keyboardHeight.value;
107
- const absoluteY = layout.value?.layout.absoluteY || 0;
108
- const inputHeight = layout.value?.layout.height || 0;
109
- const point = absoluteY + inputHeight;
110
-
111
- if (visibleRect - point <= bottomOffset) {
112
- const interpolatedScrollTo = interpolate(
113
- e,
114
- [initialKeyboardSize.value, keyboardHeight.value],
115
- [0, keyboardHeight.value - (height - point) + bottomOffset],
116
- );
117
- const targetScrollY =
118
- Math.max(interpolatedScrollTo, 0) + scrollPosition.value;
119
- scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);
120
-
121
- return interpolatedScrollTo;
83
+ ref,
84
+ ) => {
85
+ const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();
86
+ const scrollPosition = useSharedValue(0);
87
+ const position = useSharedValue(0);
88
+ const currentKeyboardFrameHeight = useSharedValue(0);
89
+ const keyboardHeight = useSharedValue(0);
90
+ const keyboardWillAppear = useSharedValue(false);
91
+ const tag = useSharedValue(-1);
92
+ const initialKeyboardSize = useSharedValue(0);
93
+ const scrollBeforeKeyboardMovement = useSharedValue(0);
94
+ const { input } = useReanimatedFocusedInput();
95
+ const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
96
+
97
+ const { height } = useWindowDimensions();
98
+
99
+ const onScroll = useAnimatedScrollHandler(
100
+ {
101
+ onScroll: (e) => {
102
+ position.value = e.contentOffset.y;
103
+ },
104
+ },
105
+ [],
106
+ );
107
+
108
+ const onRef = useCallback((assignedRef: Reanimated.ScrollView) => {
109
+ if (typeof ref === "function") {
110
+ ref(assignedRef);
111
+ } else if (ref) {
112
+ ref.current = assignedRef;
122
113
  }
123
114
 
124
- if (absoluteY < 0) {
125
- const positionOnScreen = visibleRect - inputHeight - bottomOffset;
126
- const topOfScreen = scrollPosition.value + absoluteY;
115
+ scrollViewAnimatedRef(assignedRef);
116
+ }, []);
127
117
 
128
- scrollTo(
129
- scrollViewAnimatedRef,
130
- 0,
131
- topOfScreen - positionOnScreen,
132
- animated,
133
- );
134
- }
135
-
136
- return 0;
137
- },
138
- [bottomOffset],
139
- );
140
-
141
- const onChangeText = useCallback(() => {
142
- "worklet";
143
-
144
- // if typing a text caused layout shift, then we need to ignore this handler
145
- // because this event will be handled in `useAnimatedReaction` below
146
- if (layout.value?.layout.height !== input.value?.layout.height) {
147
- return;
148
- }
149
-
150
- const prevScrollPosition = scrollPosition.value;
151
- const prevLayout = layout.value;
152
-
153
- scrollPosition.value = position.value;
154
- layout.value = input.value;
155
- maybeScroll(keyboardHeight.value, true);
156
- scrollPosition.value = prevScrollPosition;
157
- layout.value = prevLayout;
158
- }, [maybeScroll]);
159
- const onChangeTextHandler = useMemo(
160
- () => debounce(onChangeText, 200),
161
- [onChangeText],
162
- );
163
-
164
- useFocusedInputHandler(
165
- {
166
- onChangeText: onChangeTextHandler,
167
- },
168
- [onChangeTextHandler],
169
- );
170
-
171
- useSmoothKeyboardHandler(
172
- {
173
- onStart: (e) => {
118
+ /**
119
+ * Function that will scroll a ScrollView as keyboard gets moving
120
+ */
121
+ const maybeScroll = useCallback(
122
+ (e: number, animated: boolean = false) => {
174
123
  "worklet";
175
124
 
176
- const keyboardWillChangeSize =
177
- keyboardHeight.value !== e.height && e.height > 0;
178
- keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;
179
- const keyboardWillHide = e.height === 0;
180
- const focusWasChanged =
181
- (tag.value !== e.target && e.target !== -1) || keyboardWillChangeSize;
182
-
183
- if (keyboardWillChangeSize) {
184
- initialKeyboardSize.value = keyboardHeight.value;
185
- }
186
-
187
- if (keyboardWillHide) {
188
- // on back transition need to interpolate as [0, keyboardHeight]
189
- initialKeyboardSize.value = 0;
190
- scrollPosition.value = scrollBeforeKeyboardMovement.value;
125
+ if (!enabled) {
126
+ return 0;
191
127
  }
192
128
 
193
- if (
194
- keyboardWillAppear.value ||
195
- keyboardWillChangeSize ||
196
- focusWasChanged
197
- ) {
198
- // persist scroll value
199
- scrollPosition.value = position.value;
200
- // just persist height - later will be used in interpolation
201
- keyboardHeight.value = e.height;
129
+ const visibleRect = height - keyboardHeight.value;
130
+ const absoluteY = layout.value?.layout.absoluteY || 0;
131
+ const inputHeight = layout.value?.layout.height || 0;
132
+ const point = absoluteY + inputHeight;
133
+
134
+ if (visibleRect - point <= bottomOffset) {
135
+ const interpolatedScrollTo = interpolate(
136
+ e,
137
+ [initialKeyboardSize.value, keyboardHeight.value],
138
+ [0, keyboardHeight.value - (height - point) + bottomOffset],
139
+ );
140
+ const targetScrollY =
141
+ Math.max(interpolatedScrollTo, 0) + scrollPosition.value;
142
+ scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);
143
+
144
+ return interpolatedScrollTo;
202
145
  }
203
146
 
204
- // focus was changed
205
- if (focusWasChanged) {
206
- tag.value = e.target;
147
+ if (absoluteY < 0) {
148
+ const positionOnScreen = visibleRect - inputHeight - bottomOffset;
149
+ const topOfScreen = scrollPosition.value + absoluteY;
207
150
 
208
- // save position of focused text input when keyboard starts to move
209
- layout.value = input.value;
210
- // save current scroll position - when keyboard will hide we'll reuse
211
- // this value to achieve smooth hide effect
212
- scrollBeforeKeyboardMovement.value = position.value;
151
+ scrollTo(
152
+ scrollViewAnimatedRef,
153
+ 0,
154
+ topOfScreen - positionOnScreen,
155
+ animated,
156
+ );
213
157
  }
214
158
 
215
- if (focusWasChanged && !keyboardWillAppear.value) {
216
- // update position on scroll value, so `onEnd` handler
217
- // will pick up correct values
218
- position.value += maybeScroll(e.height, true);
219
- }
159
+ return 0;
220
160
  },
221
- onMove: (e) => {
222
- "worklet";
161
+ [bottomOffset, enabled],
162
+ );
223
163
 
224
- currentKeyboardFrameHeight.value = e.height;
164
+ const onChangeText = useCallback(() => {
165
+ "worklet";
225
166
 
226
- // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
227
- if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
228
- maybeScroll(e.height);
229
- }
167
+ // if typing a text caused layout shift, then we need to ignore this handler
168
+ // because this event will be handled in `useAnimatedReaction` below
169
+ if (layout.value?.layout.height !== input.value?.layout.height) {
170
+ return;
171
+ }
172
+
173
+ const prevScrollPosition = scrollPosition.value;
174
+ const prevLayout = layout.value;
175
+
176
+ scrollPosition.value = position.value;
177
+ layout.value = input.value;
178
+ maybeScroll(keyboardHeight.value, true);
179
+ scrollPosition.value = prevScrollPosition;
180
+ layout.value = prevLayout;
181
+ }, [maybeScroll]);
182
+
183
+ const onChangeTextHandler = useMemo(
184
+ () => debounce(onChangeText, 200),
185
+ [onChangeText],
186
+ );
187
+
188
+ useFocusedInputHandler(
189
+ {
190
+ onChangeText: onChangeTextHandler,
230
191
  },
231
- onEnd: (e) => {
232
- "worklet";
192
+ [onChangeTextHandler],
193
+ );
194
+
195
+ useSmoothKeyboardHandler(
196
+ enabled
197
+ ? {
198
+ onStart: (e) => {
199
+ "worklet";
200
+
201
+ const keyboardWillChangeSize =
202
+ keyboardHeight.value !== e.height && e.height > 0;
203
+ keyboardWillAppear.value =
204
+ e.height > 0 && keyboardHeight.value === 0;
205
+ const keyboardWillHide = e.height === 0;
206
+ const focusWasChanged =
207
+ (tag.value !== e.target && e.target !== -1) ||
208
+ keyboardWillChangeSize;
209
+
210
+ if (keyboardWillChangeSize) {
211
+ initialKeyboardSize.value = keyboardHeight.value;
212
+ }
213
+
214
+ if (keyboardWillHide) {
215
+ // on back transition need to interpolate as [0, keyboardHeight]
216
+ initialKeyboardSize.value = 0;
217
+ scrollPosition.value = scrollBeforeKeyboardMovement.value;
218
+ }
219
+
220
+ if (
221
+ keyboardWillAppear.value ||
222
+ keyboardWillChangeSize ||
223
+ focusWasChanged
224
+ ) {
225
+ // persist scroll value
226
+ scrollPosition.value = position.value;
227
+ // just persist height - later will be used in interpolation
228
+ keyboardHeight.value = e.height;
229
+ }
230
+
231
+ // focus was changed
232
+ if (focusWasChanged) {
233
+ tag.value = e.target;
234
+
235
+ // save position of focused text input when keyboard starts to move
236
+ layout.value = input.value;
237
+ // save current scroll position - when keyboard will hide we'll reuse
238
+ // this value to achieve smooth hide effect
239
+ scrollBeforeKeyboardMovement.value = position.value;
240
+ }
241
+
242
+ if (focusWasChanged && !keyboardWillAppear.value) {
243
+ // update position on scroll value, so `onEnd` handler
244
+ // will pick up correct values
245
+ position.value += maybeScroll(e.height, true);
246
+ }
247
+ },
248
+ onMove: (e) => {
249
+ "worklet";
250
+
251
+ currentKeyboardFrameHeight.value = e.height;
252
+
253
+ // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
254
+ if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
255
+ maybeScroll(e.height);
256
+ }
257
+ },
258
+ onEnd: (e) => {
259
+ "worklet";
260
+
261
+ keyboardHeight.value = e.height;
262
+ scrollPosition.value = position.value;
263
+ },
264
+ }
265
+ : {},
266
+ [height, maybeScroll, disableScrollOnKeyboardHide, enabled],
267
+ );
268
+
269
+ useAnimatedReaction(
270
+ () => input.value,
271
+ (current, previous) => {
272
+ if (
273
+ current?.target === previous?.target &&
274
+ current?.layout.height !== previous?.layout.height
275
+ ) {
276
+ const prevLayout = layout.value;
233
277
 
234
- keyboardHeight.value = e.height;
235
- scrollPosition.value = position.value;
278
+ layout.value = input.value;
279
+ scrollPosition.value += maybeScroll(keyboardHeight.value, true);
280
+ layout.value = prevLayout;
281
+ }
236
282
  },
237
- },
238
- [height, maybeScroll, disableScrollOnKeyboardHide],
239
- );
240
-
241
- useAnimatedReaction(
242
- () => input.value,
243
- (current, previous) => {
244
- if (
245
- current?.target === previous?.target &&
246
- current?.layout.height !== previous?.layout.height
247
- ) {
248
- const prevLayout = layout.value;
249
-
250
- layout.value = input.value;
251
- scrollPosition.value += maybeScroll(keyboardHeight.value, true);
252
- layout.value = prevLayout;
253
- }
254
- },
255
- [],
256
- );
257
-
258
- const view = useAnimatedStyle(
259
- () => ({
260
- paddingBottom: currentKeyboardFrameHeight.value,
261
- }),
262
- [],
263
- );
264
-
265
- return (
266
- <Reanimated.ScrollView
267
- ref={scrollViewAnimatedRef}
268
- {...rest}
269
- // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
270
- onScrollReanimated={onScroll}
271
- scrollEventThrottle={16}
272
- >
273
- {children}
274
- <Reanimated.View style={view} />
275
- </Reanimated.ScrollView>
276
- );
277
- };
283
+ [],
284
+ );
285
+
286
+ const view = useAnimatedStyle(
287
+ () => ({
288
+ // animations become laggy when scrolling to the end of the `ScrollView` (when the last input is focused)
289
+ // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
290
+ // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
291
+ // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
292
+ // re-calculation on every animation frame and it helps to achieve smooth animation.
293
+ // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
294
+ paddingBottom: currentKeyboardFrameHeight.value + 1,
295
+ }),
296
+ [],
297
+ );
298
+
299
+ return (
300
+ <Reanimated.ScrollView
301
+ ref={onRef}
302
+ {...rest}
303
+ // @ts-expect-error `onScrollReanimated` is a fake prop needed for reanimated to intercept scroll events
304
+ onScrollReanimated={onScroll}
305
+ scrollEventThrottle={16}
306
+ >
307
+ {children}
308
+ <Reanimated.View style={view} />
309
+ </Reanimated.ScrollView>
310
+ );
311
+ },
312
+ );
278
313
 
279
314
  export default KeyboardAwareScrollView;
@@ -35,6 +35,7 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
35
35
  deps,
36
36
  ) => {
37
37
  const target = useSharedValue(-1);
38
+ const height = useSharedValue(0);
38
39
  const persistedHeight = useSharedValue(0);
39
40
  const animatedKeyboardHeight = useSharedValue(0);
40
41
 
@@ -43,10 +44,12 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
43
44
  if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
44
45
  return;
45
46
  }
47
+ if (persistedHeight.value === 0) {
48
+ return;
49
+ }
46
50
  const event = {
47
- // it'll be always 250, since we're running animation via `withTiming` where
48
- // duration in config (TELEGRAM_ANDROID_TIMING_CONFIG.duration) = 250ms
49
- duration: 250,
51
+ // it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`
52
+ duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,
50
53
  target: target.value,
51
54
  height: animatedKeyboardHeight.value,
52
55
  progress: animatedKeyboardHeight.value / persistedHeight.value,
@@ -60,8 +63,9 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
60
63
  handler.onMove?.(evt);
61
64
 
62
65
  // dispatch `onEnd`
63
- if (evt.height === persistedHeight.value) {
66
+ if (evt.height === height.value) {
64
67
  handler.onEnd?.(evt);
68
+ persistedHeight.value = height.value;
65
69
  }
66
70
  },
67
71
  [handler],
@@ -85,6 +89,7 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
85
89
  }
86
90
 
87
91
  target.value = e.target;
92
+ height.value = e.height;
88
93
 
89
94
  if (e.height > 0) {
90
95
  persistedHeight.value = e.height;
@@ -99,7 +104,12 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
99
104
  );
100
105
  }
101
106
 
102
- handler.onStart?.(e);
107
+ handler.onStart?.({
108
+ ...e,
109
+ duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS
110
+ ? e.duration
111
+ : TELEGRAM_ANDROID_TIMING_CONFIG.duration,
112
+ });
103
113
  },
104
114
  onMove: (e) => {
105
115
  "worklet";
@@ -114,8 +124,6 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
114
124
  if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
115
125
  handler.onEnd?.(e);
116
126
  }
117
-
118
- persistedHeight.value = e.height;
119
127
  },
120
128
  },
121
129
  deps,