react-native-actions-sheet
Version:
A Cross Platform(Android & iOS) ActionSheet with a robust and flexible api, native performance and zero dependency code for react native. Create anything you want inside ActionSheet.
158 lines (156 loc) • 5.84 kB
JavaScript
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Platform } from 'react-native';
import { useDraggableNodesContext, usePanGestureContext, } from '../context';
export var ScrollState = {
END: -1,
};
var InitialLayoutRect = {
w: 0,
h: 0,
x: 0,
y: 0,
px: 0,
py: 0,
};
export function resolveScrollRef(ref) {
var _a, _b, _c, _d, _e, _f;
// FlatList
if ((_a = ref.current) === null || _a === void 0 ? void 0 : _a._listRef) {
return (_b = ref.current._listRef) === null || _b === void 0 ? void 0 : _b._scrollRef;
}
// FlashList
if ((_c = ref.current) === null || _c === void 0 ? void 0 : _c.rlvRef) {
return (_f = (_e = (_d = ref.current) === null || _d === void 0 ? void 0 : _d.rlvRef) === null || _e === void 0 ? void 0 : _e._scrollComponent) === null || _f === void 0 ? void 0 : _f._scrollViewRef;
}
// ScrollView
return ref.current;
}
export function useDraggable(options) {
var gestureContext = usePanGestureContext();
var draggableNodes = useDraggableNodesContext();
var nodeRef = useRef(null);
var offset = useRef({ x: 0, y: 0 });
var layout = useRef(InitialLayoutRect);
useEffect(function () {
var pushNode = function () {
var _a, _b;
var index = (_a = draggableNodes.nodes.current) === null || _a === void 0 ? void 0 : _a.findIndex(function (node) { return node.ref === nodeRef; });
if (index === undefined || index === -1) {
(_b = draggableNodes.nodes.current) === null || _b === void 0 ? void 0 : _b.push({
ref: nodeRef,
offset: offset,
rect: layout,
handlerConfig: options,
});
}
};
var popNode = function () {
var _a, _b;
var index = (_a = draggableNodes.nodes.current) === null || _a === void 0 ? void 0 : _a.findIndex(function (node) { return node.ref === nodeRef; });
if (index === undefined || index > -1) {
(_b = draggableNodes.nodes.current) === null || _b === void 0 ? void 0 : _b.splice(index, 1);
}
};
pushNode();
return function () {
popNode();
};
}, [draggableNodes.nodes, options]);
return {
nodeRef: nodeRef,
offset: offset,
draggableNodes: draggableNodes,
layout: layout,
gestureContext: gestureContext,
};
}
/**
* Create a custom scrollable view inside the action sheet.
* The scrollable view must implement `onScroll`, and `onLayout` props.
* @example
* ```tsx
const handlers = useScrollHandlers<RNScrollView>();
return <NativeViewGestureHandler
simultaneousHandlers={handlers.simultaneousHandlers}
>
<ScrollableView
{...handlers}
>
</ScrollableView>
</NativeViewGestureHandler>
* ```
*/
export function useScrollHandlers(options) {
var _a = useState(false), _render = _a[0], setRender = _a[1];
var _b = useDraggable(options), nodeRef = _b.nodeRef, gestureContext = _b.gestureContext, offset = _b.offset, layout = _b.layout;
var timer = useRef();
var subscription = useRef();
var onMeasure = useCallback(function (x, y, w, h, px, py) {
layout.current = {
x: x,
y: y,
w: w,
h: h + 10,
px: px,
py: py,
};
}, [layout]);
var measureAndLayout = React.useCallback(function () {
clearTimeout(timer.current);
timer.current = setTimeout(function () {
var _a;
var ref = resolveScrollRef(nodeRef);
if (Platform.OS == 'web') {
var rect = ref.getBoundingClientRect();
ref.style.overflow = "auto";
onMeasure(rect.x, rect.y, rect.width, rect.height, rect.left, rect.top);
}
else {
(_a = ref === null || ref === void 0 ? void 0 : ref.measure) === null || _a === void 0 ? void 0 : _a.call(ref, onMeasure);
}
}, 300);
}, [nodeRef, onMeasure]);
useEffect(function () {
if (Platform.OS === 'web' || !gestureContext.ref)
return;
var interval = setInterval(function () {
// Trigger a rerender when gestureContext gets populated.
if (gestureContext.ref.current) {
clearInterval(interval);
setRender(true);
}
}, 10);
}, [gestureContext.ref]);
var memoizedProps = React.useMemo(function () {
return {
ref: nodeRef,
simultaneousHandlers: gestureContext.ref,
onScroll: function (event) {
var _a = event.nativeEvent.contentOffset, x = _a.x, y = _a.y;
var maxOffsetX = event.nativeEvent.contentSize.width - layout.current.w;
var maxOffsetY = event.nativeEvent.contentSize.height - layout.current.h;
offset.current = {
x: x === maxOffsetX || x > maxOffsetX - 5 ? ScrollState.END : x,
y: y === maxOffsetY || y > maxOffsetY - 5 ? ScrollState.END : y,
};
},
scrollEventThrottle: 1,
onLayout: function () {
var _a;
measureAndLayout();
(_a = subscription.current) === null || _a === void 0 ? void 0 : _a.unsubscribe();
subscription.current = gestureContext.eventManager.subscribe('onoffsetchange', function () {
measureAndLayout();
});
},
};
}, [
gestureContext.eventManager,
gestureContext.ref,
layout,
measureAndLayout,
nodeRef,
offset,
]);
return memoizedProps;
}