UNPKG

@wordpress/block-editor

Version:
118 lines (110 loc) 4.22 kB
"use strict"; 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