react-native-keyboard-controller
Version:
Keyboard manager which works in identical way on both iOS and Android
97 lines (93 loc) • 3.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useExtraContentPadding = useExtraContentPadding;
var _react = require("react");
var _reactNative = require("react-native");
var _reactNativeReanimated = require("react-native-reanimated");
var _architecture = require("../../../architecture");
var _helpers = require("../useChatKeyboard/helpers");
/**
* Hook that reacts to `extraContentPadding` changes and conditionally
* adjusts the scroll position using `scrollTo` on both iOS and Android.
*
* Padding extension (scrollable range) is handled externally via a
* `useDerivedValue` that sums keyboard padding + extra content padding.
* This hook only handles the scroll correction.
*
* @param options - Configuration and shared values.
* @example
* ```tsx
* useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });
* ```
*/
function useExtraContentPadding(options) {
const {
scrollViewRef,
extraContentPadding,
keyboardPadding,
blankSpace,
scroll,
layout,
size,
contentOffsetY,
inverted,
keyboardLiftBehavior,
freeze
} = options;
const scrollToTarget = (0, _react.useCallback)(target => {
"worklet";
if (contentOffsetY && _architecture.IS_FABRIC) {
// eslint-disable-next-line react-compiler/react-compiler
contentOffsetY.value = target;
} else if (_reactNative.Platform.OS === "android") {
// Defer scrollTo so the animatedProps inset commit lands first;
// otherwise the native ScrollView clamps to the old range.
requestAnimationFrame(() => {
// check that view is still mounted and ref is actual
// otherwise it may lead to a crash
if (!scrollViewRef()) {
return;
}
(0, _reactNativeReanimated.scrollTo)(scrollViewRef, 0, target, false);
});
} else {
(0, _reactNativeReanimated.scrollTo)(scrollViewRef, 0, target, false);
}
}, [scrollViewRef, contentOffsetY]);
(0, _reactNativeReanimated.useAnimatedReaction)(() => extraContentPadding.value, (current, previous) => {
if (freeze.value || previous === null) {
return;
}
const rawDelta = current - previous;
if (rawDelta === 0) {
return;
}
// Compute effective delta considering blankSpace floor
const previousTotal = Math.max(blankSpace.value, keyboardPadding.value + previous);
const currentTotal = Math.max(blankSpace.value, keyboardPadding.value + current);
const effectiveDelta = currentTotal - previousTotal;
if (effectiveDelta === 0) {
// blankSpace absorbed the change
return;
}
const atEnd = (0, _helpers.isScrollAtEnd)(scroll.value, layout.value.height, size.value.height, inverted);
// "persistent": scroll on grow, hold position on shrink (unless at end)
if (keyboardLiftBehavior === "persistent" && effectiveDelta < 0 && !atEnd) {
return;
}
if (!(0, _helpers.shouldShiftContent)(keyboardLiftBehavior, atEnd)) {
return;
}
if (inverted) {
const target = Math.max(scroll.value - effectiveDelta, -currentTotal);
scrollToTarget(target);
} else {
const maxScroll = Math.max(size.value.height - layout.value.height + currentTotal, 0);
const target = Math.min(scroll.value + effectiveDelta, maxScroll);
scrollToTarget(target);
}
}, [inverted, keyboardLiftBehavior]);
}
//# sourceMappingURL=index.js.map