@wordpress/block-editor
Version:
118 lines (110 loc) • 4.22 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useScrollWhenDragging;
var _reactNative = require("react-native");
var _reactNativeReanimated = require("react-native-reanimated");
var _blockListContext = require("../block-list/block-list-context");
/**
* External dependencies
*/
/**
* Internal dependencies
*/
const SCROLL_INACTIVE_DISTANCE_PX = 50;
const SCROLL_INTERVAL_MS = 1000;
const VELOCITY_MULTIPLIER = 5000;
/**
* React hook that scrolls the scroll container when a block is being dragged.
*
* @return {Function[]} `startScrolling`, `scrollOnDragOver`, `stopScrolling`
* functions to be called in `onDragStart`, `onDragOver`
* and `onDragEnd` events respectively. Additionally,
* `scrollHandler` function is returned which should be
* called in the `onScroll` event of the block list.
*/
function useScrollWhenDragging() {
const {
scrollRef
} = (0, _blockListContext.useBlockListContext)();
const animatedScrollRef = (0, _reactNativeReanimated.useAnimatedRef)();
animatedScrollRef(scrollRef?.scrollViewRef);
const {
height: windowHeight
} = (0, _reactNative.useWindowDimensions)();
const velocityY = (0, _reactNativeReanimated.useSharedValue)(0);
const offsetY = (0, _reactNativeReanimated.useSharedValue)(0);
const dragStartY = (0, _reactNativeReanimated.useSharedValue)(0);
const animationTimer = (0, _reactNativeReanimated.useSharedValue)(0);
const isAnimationTimerActive = (0, _reactNativeReanimated.useSharedValue)(false);
const isScrollActive = (0, _reactNativeReanimated.useSharedValue)(false);
const scroll = {
offsetY: (0, _reactNativeReanimated.useSharedValue)(0),
maxOffsetY: (0, _reactNativeReanimated.useSharedValue)(0)
};
const scrollHandler = event => {
'worklet';
const {
contentSize,
contentOffset,
layoutMeasurement
} = event;
scroll.offsetY.value = contentOffset.y;
scroll.maxOffsetY.value = contentSize.height - layoutMeasurement.height;
};
const stopScrolling = () => {
'worklet';
(0, _reactNativeReanimated.cancelAnimation)(animationTimer);
isAnimationTimerActive.value = false;
isScrollActive.value = false;
velocityY.value = 0;
};
const startScrolling = y => {
'worklet';
stopScrolling();
offsetY.value = scroll.offsetY.value;
dragStartY.value = y;
animationTimer.value = 0;
animationTimer.value = (0, _reactNativeReanimated.withRepeat)((0, _reactNativeReanimated.withTiming)(1, {
duration: SCROLL_INTERVAL_MS,
easing: _reactNativeReanimated.Easing.linear
}), -1, true);
isAnimationTimerActive.value = true;
};
const scrollOnDragOver = y => {
'worklet';
const dragDistance = Math.max(Math.abs(y - dragStartY.value) - SCROLL_INACTIVE_DISTANCE_PX, 0);
const distancePercentage = dragDistance / windowHeight;
if (!isScrollActive.value) {
isScrollActive.value = dragDistance > 0;
} else if (y > dragStartY.value) {
// User is dragging downwards.
velocityY.value = VELOCITY_MULTIPLIER * distancePercentage;
} else if (y < dragStartY.value) {
// User is dragging upwards.
velocityY.value = -VELOCITY_MULTIPLIER * distancePercentage;
} else {
velocityY.value = 0;
}
};
(0, _reactNativeReanimated.useAnimatedReaction)(() => animationTimer.value, (value, previous) => {
if (velocityY.value === 0) {
return;
}
const delta = Math.abs(value - previous);
let newOffset = offsetY.value + delta * velocityY.value;
if (scroll.maxOffsetY.value !== 0) {
newOffset = Math.max(0, Math.min(scroll.maxOffsetY.value, newOffset));
} else {
// Scroll values are empty until receiving the first scroll event.
// In that case, the max offset is unknown and we can't clamp the
// new offset value.
newOffset = Math.max(0, newOffset);
}
offsetY.value = newOffset;
(0, _reactNativeReanimated.scrollTo)(animatedScrollRef, 0, offsetY.value, false);
});
return [startScrolling, scrollOnDragOver, stopScrolling, scrollHandler];
}
//# sourceMappingURL=use-scroll-when-dragging.native.js.map
;