@attio/react-native-bottom-sheet-toolbox
Version:
113 lines (110 loc) • 5.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useBottomSheetDragGesture = useBottomSheetDragGesture;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _reactNativeGestureHandler = require("react-native-gesture-handler");
var _reactNativeReanimated = require("react-native-reanimated");
var _context = require("../context");
var _utils = require("../utils");
var _useBottomSheetPositionLock = require("./use-bottom-sheet-position-lock");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const LOCK_ID_NAMESPACE = "useBottomSheetDragGesture";
// Gesture velocity is calculated between gesture updates.
// If the user does not move their finger, the gesture doesn't see update
// and so the velocity is miss-leading (i.e. not 0)
// We detect this by checking the time between the last gesture update.
const SUPPRESS_VELOCITY_TIME_MS = 150;
function useBottomSheetDragGesture({
id,
disabled = false,
clamped = false,
frozenSharedValue
}) {
const {
currentPositionSharedValue,
currentPositionLastVelocitySharedValue,
wrapperHeightSharedValue,
normalizedSnapPointsSharedValue
} = (0, _context.useBottomSheetToolboxInternalContext)();
const {
lock,
release,
setPosition,
setVelocity,
canLockSharedValue,
hasLockSharedValue
} = (0, _useBottomSheetPositionLock.useBottomSheetPositionLock)(`${LOCK_ID_NAMESPACE}:${id}`, _utils.BottomSheetPositionBuiltInLockPriority.GESTURE);
const lastLockRef = React.useRef(id);
React.useEffect(() => {
if (id !== lastLockRef.current) throw new Error("Lock id can't be changed.");
}, [id]);
const startPositionSharedValue = (0, _reactNativeReanimated.useSharedValue)(0);
const lastUpdateTime = (0, _reactNativeReanimated.useSharedValue)(0);
const [enabled, setEnabled] = React.useState(false);
(0, _reactNativeReanimated.useAnimatedReaction)(() => canLockSharedValue.get() || hasLockSharedValue.get(), (lockable, lastLockable) => {
if (lockable === lastLockable) return;
(0, _reactNativeReanimated.runOnJS)(setEnabled)(lockable);
}, [canLockSharedValue, hasLockSharedValue.get]);
const [windowHeight, setWindowHeight] = React.useState(_reactNative.Dimensions.get("window").height);
React.useEffect(() => {
const handle = _reactNative.Dimensions.addEventListener("change", ({
window
}) => {
setWindowHeight(window.height);
});
return () => handle.remove();
}, []);
const frozenOriginOffsetYSharedValue = (0, _reactNativeReanimated.useSharedValue)(0);
return _reactNativeGestureHandler.Gesture.Pan().onBegin(() => {
if (!canLockSharedValue.get()) return;
startPositionSharedValue.set(currentPositionSharedValue.get());
frozenOriginOffsetYSharedValue.set(0);
}).onUpdate(evt => {
const normalizedSnapPoints = normalizedSnapPointsSharedValue.get();
const wrapperHeight = wrapperHeightSharedValue.get();
const lockable = canLockSharedValue.get() || hasLockSharedValue.get();
if (!lockable || !normalizedSnapPoints || !wrapperHeight) return;
// We want to lock onUpdate, rather than onBegin, so nested
// touches do no unnecessarily lock the position.
if (!hasLockSharedValue.get()) {
lock();
}
if (frozenSharedValue?.get()) {
frozenOriginOffsetYSharedValue.set(evt.translationY);
return;
}
setVelocity(evt.velocityY);
const rawPosition = startPositionSharedValue.get() - evt.translationY + frozenOriginOffsetYSharedValue.get();
const maxSnapPoint = Math.max(...normalizedSnapPoints);
const overshoot = Math.max(0, rawPosition - maxSnapPoint);
if (clamped) {
const clampedPosition = Math.max(Math.min(rawPosition, maxSnapPoint), 0);
setPosition(clampedPosition);
} else if (overshoot > 0) {
const topInset = Math.max(1, windowHeight - wrapperHeight);
const frictionRatio = (0, _utils.friction)(overshoot / topInset);
const frictionPosition = maxSnapPoint + topInset * frictionRatio;
const finalPosition = Math.min(frictionPosition, wrapperHeight + topInset);
setPosition(finalPosition);
} else {
setPosition(rawPosition);
}
lastUpdateTime.set(Date.now());
}).onFinalize(evt => {
if (!hasLockSharedValue.get()) return;
if (frozenSharedValue?.get()) {
setVelocity(0);
} else {
const currentTime = Date.now();
const velocity = -evt.velocityY;
const timeSinceLastUpdate = currentTime - lastUpdateTime.get();
currentPositionLastVelocitySharedValue.set(timeSinceLastUpdate > SUPPRESS_VELOCITY_TIME_MS ? 0 : velocity);
setVelocity(velocity);
}
release();
}).enabled(enabled && !disabled);
}
//# sourceMappingURL=use-bottom-sheet-drag-gesture.js.map