UNPKG

@wordpress/components

Version:
233 lines (206 loc) 8.11 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.DraggableTrigger = void 0; var _element = require("@wordpress/element"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _style = _interopRequireDefault(require("./style.scss")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const Context = (0, _element.createContext)({}); const { Provider } = Context; /** * Draggable component. * * @param {Object} props Component props. * @param {JSX.Element} props.children Children to be rendered. * @param {Function} [props.onDragEnd] Callback when dragging ends. * @param {Function} [props.onDragOver] Callback when dragging happens over an element. * @param {Function} [props.onDragStart] Callback when dragging starts. * @param {string} [props.testID] Id used for querying the pan gesture in tests. * * @return {JSX.Element} The component to be rendered. */ const Draggable = _ref => { let { children, onDragEnd, onDragOver, onDragStart, testID } = _ref; const isDragging = (0, _reactNativeReanimated.useSharedValue)(false); const isPanActive = (0, _reactNativeReanimated.useSharedValue)(false); const draggingId = (0, _reactNativeReanimated.useSharedValue)(''); const panGestureRef = (0, _element.useRef)(); const currentFirstTouchId = (0, _reactNativeReanimated.useSharedValue)(null); const initialPosition = { x: (0, _reactNativeReanimated.useSharedValue)(0), y: (0, _reactNativeReanimated.useSharedValue)(0) }; const lastPosition = { x: (0, _reactNativeReanimated.useSharedValue)(0), y: (0, _reactNativeReanimated.useSharedValue)(0) }; (0, _reactNativeReanimated.useAnimatedReaction)(() => isDragging.value, (result, previous) => { if (result === previous || previous === null) { return; } if (result) { if (onDragStart) { onDragStart({ x: initialPosition.x.value, y: initialPosition.y.value, id: draggingId.value }); } } else if (onDragEnd) { onDragEnd({ x: lastPosition.x.value, y: lastPosition.y.value, id: draggingId.value }); } }); function getFirstTouchEvent(event) { 'worklet'; return event.allTouches.find(touch => touch.id === currentFirstTouchId.value); } const panGesture = _reactNativeGestureHandler.Gesture.Pan().manualActivation(true).onTouchesDown(event => { if (!currentFirstTouchId.value) { const firstEvent = event.allTouches[0]; const { x = 0, y = 0 } = firstEvent; currentFirstTouchId.value = firstEvent.id; initialPosition.x.value = x; initialPosition.y.value = y; } }).onTouchesMove((event, state) => { if (!isPanActive.value && isDragging.value) { isPanActive.value = true; state.activate(); } if (isPanActive.value && isDragging.value) { const firstEvent = getFirstTouchEvent(event); if (!firstEvent) { state.end(); return; } lastPosition.x.value = firstEvent.x; lastPosition.y.value = firstEvent.y; if (onDragOver) { onDragOver(firstEvent); } } }).onTouchesCancelled((_event, state) => { state.end(); }).onEnd(() => { currentFirstTouchId.value = null; isPanActive.value = false; isDragging.value = false; }).withRef(panGestureRef).shouldCancelWhenOutside(false).withTestId(testID); const providerValue = (0, _element.useMemo)(() => { return { panGestureRef, isDragging, isPanActive, draggingId }; }, [// `isDragging`, `isPanActive` and `draggingId` are created using the // `useSharedValue` hook provided by the `react-native-reanimated`, which in // theory should guarantee that the value of these variables remains stable. // ESLint can't pick this up, and that's why they have to be specified as // dependencies for this hook call. isDragging, isPanActive, draggingId]); return (0, _element.createElement)(_reactNativeGestureHandler.GestureDetector, { gesture: panGesture }, (0, _element.createElement)(_reactNativeReanimated.default.View, { style: _style.default.draggable__container }, (0, _element.createElement)(Provider, { value: providerValue }, children))); }; /** * Draggable trigger component. * * This component acts as the trigger for the dragging functionality. * * @param {Object} props Component props. * @param {JSX.Element} props.children Children to be rendered. * @param {*} props.id Identifier passed within the event callbacks. * @param {boolean} [props.enabled] Enables the long-press gesture. * @param {number} [props.maxDistance] Maximum distance, that defines how far the finger is allowed to travel during a long press gesture. * @param {number} [props.minDuration] Minimum time, that a finger must remain pressed on the corresponding view. * @param {Function} [props.onLongPress] Callback when long-press gesture is triggered over an element. * @param {Function} [props.onLongPressEnd] Callback when long-press gesture ends. * @param {string} [props.testID] Id used for querying the long-press gesture handler in tests. * * @return {JSX.Element} The component to be rendered. */ const DraggableTrigger = _ref2 => { let { children, enabled = true, id, maxDistance = 1000, minDuration = 500, onLongPress, onLongPressEnd, testID } = _ref2; const { panGestureRef, isDragging, isPanActive, draggingId } = (0, _element.useContext)(Context); const gestureHandler = (0, _reactNativeReanimated.useAnimatedGestureHandler)({ onActive: () => { if (isDragging.value) { return; } draggingId.value = id; isDragging.value = true; if (onLongPress) { (0, _reactNativeReanimated.runOnJS)(onLongPress)(id); } }, onEnd: () => { if (!isPanActive.value) { isDragging.value = false; } if (onLongPressEnd) { (0, _reactNativeReanimated.runOnJS)(onLongPressEnd)(id); } } }); return (0, _element.createElement)(_reactNativeGestureHandler.LongPressGestureHandler, { enabled: enabled, minDurationMs: minDuration, maxDist: maxDistance, simultaneousHandlers: panGestureRef, shouldCancelWhenOutside: false, onGestureEvent: gestureHandler, testID: testID }, children); }; exports.DraggableTrigger = DraggableTrigger; var _default = Draggable; exports.default = _default; //# sourceMappingURL=index.native.js.map