react-native-keyboard-controller
Version:
Keyboard manager which works in identical way on both iOS and Android
126 lines (120 loc) • 5.21 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useSmoothKeyboardHandler = void 0;
var _reactNative = require("react-native");
var _reactNativeReanimated = require("react-native-reanimated");
var _hooks = require("../../hooks");
const IS_ANDROID_ELEVEN_OR_HIGHER = _reactNative.Platform.OS === "android" && _reactNative.Platform.Version >= 30;
// on these platforms keyboard transitions will be smooth
const IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS = IS_ANDROID_ELEVEN_OR_HIGHER || _reactNative.Platform.OS === "ios";
// on Android Telegram is not using androidx.core values and uses custom interpolation
// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39
// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40
const TELEGRAM_ANDROID_TIMING_CONFIG = {
duration: 250,
easing: _reactNativeReanimated.Easing.bezier(0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625)
};
/**
* Hook that uses default transitions for iOS and Android > 11, and uses
* custom interpolation on Android < 11 to achieve more smooth animation.
*
* @param handler - Object containing keyboard event handlers.
* @param [deps] - Dependencies array for the effect.
* @example
* ```ts
* useSmoothKeyboardHandler(
* {
* onStart: (e) => {
* "worklet";
*
* // your handler for keyboard start
* },
* },
* [],
* );
* ```
*/
const useSmoothKeyboardHandler = (handler, deps) => {
const target = (0, _reactNativeReanimated.useSharedValue)(-1);
const height = (0, _reactNativeReanimated.useSharedValue)(0);
const persistedHeight = (0, _reactNativeReanimated.useSharedValue)(0);
const animatedKeyboardHeight = (0, _reactNativeReanimated.useSharedValue)(0);
(0, _reactNativeReanimated.useAnimatedReaction)(() => {
if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
return;
}
if (persistedHeight.value === 0) {
return;
}
const event = {
// it'll be always `TELEGRAM_ANDROID_TIMING_CONFIG.duration`, since we're running animation via `withTiming`
duration: TELEGRAM_ANDROID_TIMING_CONFIG.duration,
target: target.value,
height: animatedKeyboardHeight.value,
progress: animatedKeyboardHeight.value / persistedHeight.value
};
return event;
}, evt => {
var _handler$onMove;
if (!evt) {
return;
}
(_handler$onMove = handler.onMove) === null || _handler$onMove === void 0 || _handler$onMove.call(handler, evt);
// dispatch `onEnd`
if (evt.height === height.value) {
var _handler$onEnd;
(_handler$onEnd = handler.onEnd) === null || _handler$onEnd === void 0 || _handler$onEnd.call(handler, evt);
// eslint-disable-next-line react-compiler/react-compiler
persistedHeight.value = height.value;
}
},
// REA uses own version of `DependencyList` and it's not compatible with the same type from React
deps);
(0, _hooks.useKeyboardHandler)({
onStart: e => {
"worklet";
// immediately dispatch onStart/onEnd events if onStart dispatched with the same height
// and don't wait for animation 250ms
var _handler$onStart2;
if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS && e.height === persistedHeight.value) {
var _handler$onStart, _handler$onEnd2;
(_handler$onStart = handler.onStart) === null || _handler$onStart === void 0 || _handler$onStart.call(handler, e);
(_handler$onEnd2 = handler.onEnd) === null || _handler$onEnd2 === void 0 || _handler$onEnd2.call(handler, e);
return;
}
target.value = e.target;
height.value = e.height;
if (e.height > 0) {
persistedHeight.value = e.height;
}
// if we are running on Android < 9, then we are using custom interpolation
// to achieve smoother animation and use `animatedKeyboardHeight` as animation
// driver
if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
animatedKeyboardHeight.value = (0, _reactNativeReanimated.withTiming)(e.height, TELEGRAM_ANDROID_TIMING_CONFIG);
}
(_handler$onStart2 = handler.onStart) === null || _handler$onStart2 === void 0 || _handler$onStart2.call(handler, {
...e,
duration: IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS ? e.duration : TELEGRAM_ANDROID_TIMING_CONFIG.duration
});
},
onMove: e => {
"worklet";
if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
var _handler$onMove2;
(_handler$onMove2 = handler.onMove) === null || _handler$onMove2 === void 0 || _handler$onMove2.call(handler, e);
}
},
onEnd: e => {
"worklet";
if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
var _handler$onEnd3;
(_handler$onEnd3 = handler.onEnd) === null || _handler$onEnd3 === void 0 || _handler$onEnd3.call(handler, e);
}
}
}, deps);
};
exports.useSmoothKeyboardHandler = useSmoothKeyboardHandler;
//# sourceMappingURL=useSmoothKeyboardHandler.js.map