From 4ffdf5cc2a216ccebb4c6d60a2de4de32342f6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?avery=20=E2=9C=BF?= Date: Sun, 17 Mar 2024 16:52:15 -0700 Subject: [PATCH 1/6] feat: rewrite gesture apis with gesture handler 2 (#1126) * chore: updated dependencies * feat: rewrite the gesture api with gh2 https://github.com/gorhom/react-native-bottom-sheet/commit/6a4d2967684b01e28f23b1b35afbb4cc4dabaf1d fix(#1119): fixed race condition between onmount and keyboard animations --- example/bare/ios/Podfile.lock | 8 +- example/bare/package.json | 4 +- lint-staged.config.js | 2 +- package.json | 16 +- src/components/bottomSheet/BottomSheet.tsx | 91 ++- src/components/bottomSheet/types.d.ts | 27 +- .../BottomSheetDraggableView.tsx | 91 ++- .../bottomSheetDraggableView/types.d.ts | 16 +- .../BottomSheetGestureHandlersProvider.tsx | 29 +- .../BottomSheetHandleContainer.tsx | 67 +- .../BottomSheetRefreshControl.android.tsx | 44 +- .../bottomSheetRefreshControl/index.ts | 6 +- .../ScrollableContainer.android.tsx | 51 ++ .../ScrollableContainer.tsx | 23 + .../createBottomSheetScrollableComponent.tsx | 130 ++-- src/contexts/gesture.ts | 10 +- src/contexts/internal.ts | 16 +- src/hooks/useGestureEventsHandlersDefault.tsx | 645 ++++++++--------- src/hooks/useGestureHandler.ts | 131 ++-- src/types.d.ts | 31 +- yarn.lock | 651 +++++++++--------- 21 files changed, 1113 insertions(+), 976 deletions(-) create mode 100644 src/components/bottomSheetScrollable/ScrollableContainer.android.tsx create mode 100644 src/components/bottomSheetScrollable/ScrollableContainer.tsx diff --git a/example/bare/ios/Podfile.lock b/example/bare/ios/Podfile.lock index 05c4758de..644322743 100644 --- a/example/bare/ios/Podfile.lock +++ b/example/bare/ios/Podfile.lock @@ -382,9 +382,9 @@ PODS: - React-perflogger (= 0.69.4) - RNCMaskedView (0.1.11): - React - - RNGestureHandler (2.5.0): + - RNGestureHandler (2.6.2): - React-Core - - RNReanimated (2.9.1): + - RNReanimated (2.10.0): - DoubleConversion - FBLazyVector - FBReactNativeSpec @@ -644,8 +644,8 @@ SPEC CHECKSUMS: React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196 ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83 RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489 - RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50 - RNReanimated: 2cf7451318bb9cc430abeec8d67693f9cf4e039c + RNGestureHandler: 4defbd70b2faf3d6761b82fa7880285241762cb0 + RNReanimated: 7faa787e8d4493fbc95fab2ad331fa7625828cfa RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74 diff --git a/example/bare/package.json b/example/bare/package.json index 183945ee2..3f5c31e6c 100644 --- a/example/bare/package.json +++ b/example/bare/package.json @@ -24,10 +24,10 @@ "nanoid": "^3.3.3", "react": "18.0.0", "react-native": "0.69.4", - "react-native-gesture-handler": "^2.5.0", + "react-native-gesture-handler": "^2.6.2", "react-native-maps": "^0.30.1", "react-native-pager-view": "^5.4.9", - "react-native-reanimated": "^2.9.1", + "react-native-reanimated": "^2.10.0", "react-native-redash": "^16.0.11", "react-native-safe-area-context": "4.2.4", "react-native-screens": "^3.15.0", diff --git a/lint-staged.config.js b/lint-staged.config.js index 8efb35dc5..9a93ff059 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,4 +1,4 @@ module.exports = { '**/*.js': ['eslint'], - '**/*.{ts,tsx}': [() => 'tsc --skipLibCheck --noEmit', 'eslint'], + '**/*.{ts,tsx}': [() => 'tsc --skipLibCheck --noEmit', 'eslint --fix'], }; diff --git a/package.json b/package.json index faea499ac..60104eabc 100644 --- a/package.json +++ b/package.json @@ -50,16 +50,16 @@ "@types/react-native": "^0.67.7", "auto-changelog": "^2.4.0", "copyfiles": "^2.4.1", - "eslint": "^7.32.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", + "eslint": "^8.21.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", "husky": "^4.3.8", - "lint-staged": "^11.1.2", - "prettier": "^2.3.2", + "lint-staged": "^13.0.3", + "prettier": "^2.7.1", "react": "~16.9.0", "react-native": "^0.62.2", "react-native-builder-bob": "^0.18.1", - "react-native-gesture-handler": "^1.10.3", + "react-native-gesture-handler": "^2.12.0", "react-native-reanimated": "^3.4.2", "release-it": "^17.0.1", "typescript": "^5.0.3" @@ -70,8 +70,8 @@ "@shopify/flash-list": "*", "react": "*", "react-native": "*", - "react-native-gesture-handler": ">=1.10.1", - "react-native-reanimated": ">=2.2.0" + "react-native-gesture-handler": ">=2.5.0", + "react-native-reanimated": ">=2.9.0" }, "peerDependenciesMeta": { "@types/react-native": { diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx index 36d676085..30085c3e4 100644 --- a/src/components/bottomSheet/BottomSheet.tsx +++ b/src/components/bottomSheet/BottomSheet.tsx @@ -593,6 +593,10 @@ const BottomSheetComponent = forwardRef( return animatedPosition.value; } + if (!isAnimatedOnMount.value) { + return snapPoints[_providedIndex]; + } + return snapPoints[currentIndex]; }, [ @@ -605,8 +609,10 @@ const BottomSheetComponent = forwardRef( animatedPosition, animatedSnapPoints, isInTemporaryPosition, + isAnimatedOnMount, keyboardBehavior, keyboardBlurBehavior, + _providedIndex, ] ); const handleOnChange = useCallback( @@ -1271,7 +1277,7 @@ const BottomSheetComponent = forwardRef( nextPosition = animatedClosedPosition.value; animatedNextPositionIndex.value = -1; } else { - nextPosition = animatedSnapPoints.value[_providedIndex]; + nextPosition = getNextPosition(); } runOnJS(print)({ @@ -1425,41 +1431,52 @@ const BottomSheetComponent = forwardRef( ) : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom); + /** + * if keyboard state is equal to the previous state, then exit the method + */ + if ( + _keyboardState === _previousKeyboardState && + _keyboardHeight === _previousKeyboardHeight + ) { + return; + } + + /** + * if user is interacting with sheet, then exit the method + */ const hasActiveGesture = animatedContentGestureState.value === State.ACTIVE || animatedContentGestureState.value === State.BEGAN || animatedHandleGestureState.value === State.ACTIVE || animatedHandleGestureState.value === State.BEGAN; + if (hasActiveGesture) { + return; + } + + /** + * if sheet not animated on mount yet, then exit the method + */ + if (!isAnimatedOnMount.value) { + return; + } + + /** + * if new keyboard state is hidden and blur behavior is none, then exit the method + */ + if ( + _keyboardState === KEYBOARD_STATE.HIDDEN && + keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none + ) { + return; + } + /** + * if platform is android and the input mode is resize, then exit the method + */ if ( - /** - * if keyboard state is equal to the previous state, then exit the method - */ - (_keyboardState === _previousKeyboardState && - _keyboardHeight === _previousKeyboardHeight) || - /** - * if user is interacting with sheet, then exit the method - */ - hasActiveGesture || - /** - * if sheet not animated on mount yet, then exit the method - */ - !isAnimatedOnMount.value || - /** - * if new keyboard state is hidden and blur behavior is none, then exit the method - */ - (_keyboardState === KEYBOARD_STATE.HIDDEN && - keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none) || - /** - * if platform is android and the input mode is resize, then exit the method - */ - (Platform.OS === 'android' && - keyboardBehavior === KEYBOARD_BEHAVIOR.interactive && - android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize) || - /** - * if the sheet is closing, then exit then method - */ - animatedNextPositionIndex.value === -1 + Platform.OS === 'android' && + keyboardBehavior === KEYBOARD_BEHAVIOR.interactive && + android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize ) { animatedKeyboardHeightInContainer.value = 0; return; @@ -1706,13 +1723,15 @@ const BottomSheetComponent = forwardRef( // isScrollableRefreshable, // animatedScrollableContentOffsetY, // keyboardState, - // animatedIndex, - // animatedCurrentIndex, - // animatedPosition, - animatedContainerHeight, - animatedSheetHeight, - animatedHandleHeight, - animatedContentHeight, + animatedIndex, + animatedCurrentIndex, + animatedPosition, + animatedHandleGestureState, + animatedContentGestureState, + // animatedContainerHeight, + // animatedSheetHeight, + // animatedHandleHeight, + // animatedContentHeight, // // keyboardHeight, // isLayoutCalculated, // isContentHeightFixed, diff --git a/src/components/bottomSheet/types.d.ts b/src/components/bottomSheet/types.d.ts index 516497651..a06bd58f3 100644 --- a/src/components/bottomSheet/types.d.ts +++ b/src/components/bottomSheet/types.d.ts @@ -6,7 +6,7 @@ import type { WithSpringConfig, WithTimingConfig, } from 'react-native-reanimated'; -import type { PanGestureHandlerProps } from 'react-native-gesture-handler'; +import type { PanGesture } from 'react-native-gesture-handler'; import type { BottomSheetHandleProps } from '../bottomSheetHandle'; import type { BottomSheetBackdropProps } from '../bottomSheetBackdrop'; import type { BottomSheetBackgroundProps } from '../bottomSheetBackground'; @@ -24,17 +24,7 @@ import type { export interface BottomSheetProps extends BottomSheetAnimationConfigs, - Partial< - Pick< - PanGestureHandlerProps, - | 'activeOffsetY' - | 'activeOffsetX' - | 'failOffsetY' - | 'failOffsetX' - | 'waitFor' - | 'simultaneousHandlers' - > - >, + Partial, Omit { //#region configuration /** @@ -346,3 +336,16 @@ export type AnimateToPositionType = ( velocity?: number, configs?: WithTimingConfig | WithSpringConfig ) => void; + +export type BottomSheetGestureProps = { + activeOffsetX: Parameters[0]; + activeOffsetY: Parameters[0]; + + failOffsetY: Parameters[0]; + failOffsetX: Parameters[0]; + + simultaneousHandlers: Parameters< + PanGesture['simultaneousWithExternalGesture'] + >[0]; + waitFor: Parameters[0]; +}; diff --git a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx index 377b2d5a8..ec137bb5f 100644 --- a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx +++ b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx @@ -1,15 +1,14 @@ -import React, { useMemo, useRef, memo } from 'react'; +import React, { useMemo, memo } from 'react'; import Animated from 'react-native-reanimated'; -import { PanGestureHandler } from 'react-native-gesture-handler'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; import { useBottomSheetGestureHandlers, useBottomSheetInternal, } from '../../hooks'; -import { GESTURE_SOURCE } from '../../constants'; import type { BottomSheetDraggableViewProps } from './types'; +import { BottomSheetDraggableContext } from '../../contexts/gesture'; const BottomSheetDraggableViewComponent = ({ - gestureType = GESTURE_SOURCE.CONTENT, nativeGestureRef, refreshControlGestureRef, style, @@ -26,19 +25,10 @@ const BottomSheetDraggableViewComponent = ({ failOffsetX, failOffsetY, } = useBottomSheetInternal(); - const { contentPanGestureHandler, scrollablePanGestureHandler } = - useBottomSheetGestureHandlers(); + const { contentPanGestureHandler } = useBottomSheetGestureHandlers(); //#endregion //#region variables - const panGestureRef = useRef(null); - const gestureHandler = useMemo( - () => - gestureType === GESTURE_SOURCE.CONTENT - ? contentPanGestureHandler - : scrollablePanGestureHandler, - [gestureType, contentPanGestureHandler, scrollablePanGestureHandler] - ); const simultaneousHandlers = useMemo(() => { const refs = []; @@ -64,25 +54,66 @@ const BottomSheetDraggableViewComponent = ({ nativeGestureRef, refreshControlGestureRef, ]); + const draggableGesture = useMemo(() => { + let gesture = Gesture.Pan() + .enabled(enableContentPanningGesture) + .shouldCancelWhenOutside(false) + .runOnJS(false) + .onStart(contentPanGestureHandler.handleOnStart) + .onChange(contentPanGestureHandler.handleOnChange) + .onEnd(contentPanGestureHandler.handleOnEnd) + .onFinalize(contentPanGestureHandler.handleOnFinalize); + + if (waitFor) { + gesture = gesture.requireExternalGestureToFail(waitFor); + } + + if (simultaneousHandlers) { + gesture = gesture.simultaneousWithExternalGesture( + simultaneousHandlers as any + ); + } + + if (activeOffsetX) { + gesture = gesture.activeOffsetX(activeOffsetX); + } + + if (activeOffsetY) { + gesture = gesture.activeOffsetY(activeOffsetY); + } + + if (failOffsetX) { + gesture = gesture.failOffsetX(failOffsetX); + } + + if (failOffsetY) { + gesture = gesture.failOffsetY(failOffsetY); + } + + return gesture; + }, [ + activeOffsetX, + activeOffsetY, + enableContentPanningGesture, + failOffsetX, + failOffsetY, + simultaneousHandlers, + waitFor, + contentPanGestureHandler.handleOnChange, + contentPanGestureHandler.handleOnEnd, + contentPanGestureHandler.handleOnFinalize, + contentPanGestureHandler.handleOnStart, + ]); //#endregion return ( - - - {children} - - + + + + {children} + + + ); }; diff --git a/src/components/bottomSheetDraggableView/types.d.ts b/src/components/bottomSheetDraggableView/types.d.ts index 8d38987e2..5ed61d78c 100644 --- a/src/components/bottomSheetDraggableView/types.d.ts +++ b/src/components/bottomSheetDraggableView/types.d.ts @@ -1,17 +1,9 @@ -import type { ReactNode, Ref } from 'react'; +import type { ReactNode } from 'react'; import type { ViewProps as RNViewProps } from 'react-native'; -import type { NativeViewGestureHandler } from 'react-native-gesture-handler'; -import type { GESTURE_SOURCE } from '../../constants'; +import type { GestureRef } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture'; export type BottomSheetDraggableViewProps = RNViewProps & { - /** - * Defines the gesture type of the draggable view. - * - * @default GESTURE_SOURCE.CONTENT - * @type GESTURE_SOURCE - */ - gestureType?: GESTURE_SOURCE; - nativeGestureRef?: Ref | null; - refreshControlGestureRef?: Ref | null; + nativeGestureRef?: Exclude; + refreshControlGestureRef?: Exclude; children: ReactNode[] | ReactNode; }; diff --git a/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx b/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx index e3314b812..9e2a8ca7b 100644 --- a/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx +++ b/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx @@ -23,7 +23,7 @@ const BottomSheetGestureHandlersProvider = ({ //#region hooks const { animatedContentGestureState, animatedHandleGestureState } = useBottomSheetInternal(); - const { handleOnStart, handleOnActive, handleOnEnd } = + const { handleOnStart, handleOnChange, handleOnEnd, handleOnFinalize } = useGestureEventsHandlers(); //#endregion @@ -33,17 +33,9 @@ const BottomSheetGestureHandlersProvider = ({ animatedContentGestureState, animatedGestureSource, handleOnStart, - handleOnActive, - handleOnEnd - ); - - const scrollablePanGestureHandler = useGestureHandler( - GESTURE_SOURCE.SCROLLABLE, - animatedContentGestureState, - animatedGestureSource, - handleOnStart, - handleOnActive, - handleOnEnd + handleOnChange, + handleOnEnd, + handleOnFinalize ); const handlePanGestureHandler = useGestureHandler( @@ -51,8 +43,9 @@ const BottomSheetGestureHandlersProvider = ({ animatedHandleGestureState, animatedGestureSource, handleOnStart, - handleOnActive, - handleOnEnd + handleOnChange, + handleOnEnd, + handleOnFinalize ); //#endregion @@ -61,15 +54,9 @@ const BottomSheetGestureHandlersProvider = ({ () => ({ contentPanGestureHandler, handlePanGestureHandler, - scrollablePanGestureHandler, animatedGestureSource, }), - [ - contentPanGestureHandler, - handlePanGestureHandler, - scrollablePanGestureHandler, - animatedGestureSource, - ] + [contentPanGestureHandler, handlePanGestureHandler, animatedGestureSource] ); //#endregion return ( diff --git a/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx b/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx index 59f90ba92..7dddcc113 100644 --- a/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx +++ b/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx @@ -1,6 +1,6 @@ import React, { memo, useCallback, useMemo } from 'react'; import type { LayoutChangeEvent } from 'react-native'; -import { PanGestureHandler } from 'react-native-gesture-handler'; +import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import Animated from 'react-native-reanimated'; import BottomSheetHandle from '../bottomSheetHandle'; import { @@ -50,6 +50,57 @@ function BottomSheetHandleContainerComponent({ return refs; }, [_providedSimultaneousHandlers, _internalSimultaneousHandlers]); + + const panGesture = useMemo(() => { + let gesture = Gesture.Pan() + .enabled(enableHandlePanningGesture!) + .shouldCancelWhenOutside(false) + .runOnJS(false) + .onStart(handlePanGestureHandler.handleOnStart) + .onChange(handlePanGestureHandler.handleOnChange) + .onEnd(handlePanGestureHandler.handleOnEnd) + .onFinalize(handlePanGestureHandler.handleOnFinalize); + + if (waitFor) { + gesture = gesture.requireExternalGestureToFail(waitFor); + } + + if (simultaneousHandlers) { + gesture = gesture.simultaneousWithExternalGesture( + simultaneousHandlers as any + ); + } + + if (activeOffsetX) { + gesture = gesture.activeOffsetX(activeOffsetX); + } + + if (activeOffsetY) { + gesture = gesture.activeOffsetY(activeOffsetY); + } + + if (failOffsetX) { + gesture = gesture.failOffsetX(failOffsetX); + } + + if (failOffsetY) { + gesture = gesture.failOffsetY(failOffsetY); + } + + return gesture; + }, [ + activeOffsetX, + activeOffsetY, + enableHandlePanningGesture, + failOffsetX, + failOffsetY, + simultaneousHandlers, + waitFor, + handlePanGestureHandler.handleOnChange, + handlePanGestureHandler.handleOnEnd, + handlePanGestureHandler.handleOnFinalize, + handlePanGestureHandler.handleOnStart, + ]); //#endregion //#region callbacks @@ -79,17 +130,7 @@ function BottomSheetHandleContainerComponent({ ? BottomSheetHandle : _providedHandleComponent; return HandleComponent !== null ? ( - + - + ) : null; //#endregion } diff --git a/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx b/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx index be502259c..2bce722bf 100644 --- a/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx +++ b/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx @@ -1,35 +1,57 @@ -import React, { forwardRef, memo } from 'react'; +import React, { memo, useContext, useMemo } from 'react'; import { RefreshControl, RefreshControlProps } from 'react-native'; -import { NativeViewGestureHandler } from 'react-native-gesture-handler'; +import { + Gesture, + GestureDetector, + SimultaneousGesture, +} from 'react-native-gesture-handler'; import Animated, { useAnimatedProps } from 'react-native-reanimated'; +import { BottomSheetDraggableContext } from '../../contexts/gesture'; import { SCROLLABLE_STATE } from '../../constants'; import { useBottomSheetInternal } from '../../hooks'; const AnimatedRefreshControl = Animated.createAnimatedComponent(RefreshControl); -const BottomSheetRefreshControlComponent = forwardRef< - NativeViewGestureHandler, - RefreshControlProps ->(({ onRefresh, ...rest }, ref) => { - // hooks +interface BottomSheetRefreshControlProps extends RefreshControlProps { + scrollableGesture: SimultaneousGesture; +} + +function BottomSheetRefreshControlComponent({ + onRefresh, + scrollableGesture, + ...rest +}: BottomSheetRefreshControlProps) { + //#region hooks + const draggableGesture = useContext(BottomSheetDraggableContext); const { animatedScrollableState } = useBottomSheetInternal(); + //#endregion - // variables + //#region variables const animatedProps = useAnimatedProps(() => ({ enabled: animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED, })); + const gesture = useMemo( + () => + Gesture.Simultaneous( + Gesture.Native().shouldCancelWhenOutside(false), + scrollableGesture, + draggableGesture! + ), + [draggableGesture, scrollableGesture] + ); + //#endregion // render return ( - + - + ); -}); +} const BottomSheetRefreshControl = memo(BottomSheetRefreshControlComponent); BottomSheetRefreshControl.displayName = 'BottomSheetRefreshControl'; diff --git a/src/components/bottomSheetRefreshControl/index.ts b/src/components/bottomSheetRefreshControl/index.ts index ac07963d2..e295515b0 100644 --- a/src/components/bottomSheetRefreshControl/index.ts +++ b/src/components/bottomSheetRefreshControl/index.ts @@ -1,11 +1,15 @@ import type React from 'react'; import type { RefreshControlProps } from 'react-native'; -import type { NativeViewGestureHandlerProps } from 'react-native-gesture-handler'; +import type { + NativeViewGestureHandlerProps, + SimultaneousGesture, +} from 'react-native-gesture-handler'; import BottomSheetRefreshControl from './BottomSheetRefreshControl'; export default BottomSheetRefreshControl as any as React.MemoExoticComponent< React.ForwardRefExoticComponent< RefreshControlProps & { + scrollableGesture: SimultaneousGesture; children: React.ReactNode | React.ReactNode[]; } & React.RefAttributes< React.ComponentType< diff --git a/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx b/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx new file mode 100644 index 000000000..9a152af3b --- /dev/null +++ b/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx @@ -0,0 +1,51 @@ +import React, { forwardRef } from 'react'; +import { + GestureDetector, + SimultaneousGesture, +} from 'react-native-gesture-handler'; +import BottomSheetRefreshControl from '../bottomSheetRefreshControl'; +import { styles } from './styles'; + +interface ScrollableContainerProps { + nativeGesture: SimultaneousGesture; + refreshControl: any; + progressViewOffset: any; + refreshing: any; + onRefresh: any; + ScrollableComponent: any; +} + +export const ScrollableContainer = forwardRef( + function ScrollableContainer( + { + nativeGesture, + refreshControl: _refreshControl, + refreshing, + progressViewOffset, + onRefresh, + ScrollableComponent, + ...rest + }, + ref + ) { + const Scrollable = ( + + + + ); + + return onRefresh ? ( + + {Scrollable} + + ) : ( + Scrollable + ); + } +); diff --git a/src/components/bottomSheetScrollable/ScrollableContainer.tsx b/src/components/bottomSheetScrollable/ScrollableContainer.tsx new file mode 100644 index 000000000..e8aff0de3 --- /dev/null +++ b/src/components/bottomSheetScrollable/ScrollableContainer.tsx @@ -0,0 +1,23 @@ +import React, { forwardRef } from 'react'; +import { + GestureDetector, + SimultaneousGesture, +} from 'react-native-gesture-handler'; + +interface ScrollableContainerProps { + nativeGesture: SimultaneousGesture; + ScrollableComponent: any; +} + +export const ScrollableContainer = forwardRef( + function ScrollableContainer( + { nativeGesture, ScrollableComponent, ...rest }, + ref + ) { + return ( + + + + ); + } +); diff --git a/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx b/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx index bdcb48200..dd99b99ad 100644 --- a/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx +++ b/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx @@ -1,9 +1,12 @@ -import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react'; -import { Platform } from 'react-native'; +import React, { + forwardRef, + useContext, + useImperativeHandle, + useMemo, +} from 'react'; import { useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated'; -import { NativeViewGestureHandler } from 'react-native-gesture-handler'; -import BottomSheetDraggableView from '../bottomSheetDraggableView'; -import BottomSheetRefreshControl from '../bottomSheetRefreshControl'; +import { Gesture } from 'react-native-gesture-handler'; +import { BottomSheetDraggableContext } from '../../contexts/gesture'; import { useScrollHandler, useScrollableSetter, @@ -11,12 +14,11 @@ import { useStableCallback, } from '../../hooks'; import { - GESTURE_SOURCE, SCROLLABLE_DECELERATION_RATE_MAPPER, SCROLLABLE_STATE, SCROLLABLE_TYPE, } from '../../constants'; -import { styles } from './styles'; +import { ScrollableContainer } from './ScrollableContainer'; export function createBottomSheetScrollableComponent( type: SCROLLABLE_TYPE, @@ -49,12 +51,8 @@ export function createBottomSheetScrollableComponent( ...rest }: any = props; - //#region refs - const nativeGestureRef = useRef(null); - const refreshControlGestureRef = useRef(null); - //#endregion - //#region hooks + const draggableGesture = useContext(BottomSheetDraggableContext); const { scrollableRef, scrollableContentOffsetY, scrollHandler } = useScrollHandler( scrollEventsHandlersHook, @@ -66,24 +64,39 @@ export function createBottomSheetScrollableComponent( lockableScrollableContentOffsetY ); const { - enableContentPanningGesture, animatedFooterHeight, animatedScrollableState, - animatedContentHeight, enableDynamicSizing, + animatedContentHeight, } = useBottomSheetInternal(); //#endregion //#region variables const scrollableAnimatedProps = useAnimatedProps( () => ({ - ...(preserveScrollMomentum ? {} : {decelerationRate: SCROLLABLE_DECELERATION_RATE_MAPPER[animatedScrollableState.value]}), + ...(preserveScrollMomentum + ? {} + : { + decelerationRate: + SCROLLABLE_DECELERATION_RATE_MAPPER[ + animatedScrollableState.value + ], + }), showsVerticalScrollIndicator: showsVerticalScrollIndicator ? animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED : showsVerticalScrollIndicator, }), [showsVerticalScrollIndicator] ); + + const nativeGesture = useMemo( + () => + Gesture.Simultaneous( + Gesture.Native().shouldCancelWhenOutside(false), + draggableGesture! + ), + [draggableGesture] + ); //#endregion //#region callbacks @@ -136,77 +149,24 @@ export function createBottomSheetScrollableComponent( //#endregion //#region render - if (Platform.OS === 'android') { - const scrollableContent = ( - - - - ); - return ( - - {onRefresh ? ( - - {scrollableContent} - - ) : ( - scrollableContent - )} - - ); - } return ( - - - - - + ); //#endregion }); diff --git a/src/contexts/gesture.ts b/src/contexts/gesture.ts index 79ce72d30..a6b2d217a 100644 --- a/src/contexts/gesture.ts +++ b/src/contexts/gesture.ts @@ -1,11 +1,13 @@ import { createContext } from 'react'; -import type { PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; +import type { Gesture } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture'; +import type { GestureHandlersHookType } from '../types'; export interface BottomSheetGestureHandlersContextType { - contentPanGestureHandler: (event: PanGestureHandlerGestureEvent) => void; - handlePanGestureHandler: (event: PanGestureHandlerGestureEvent) => void; - scrollablePanGestureHandler: (event: PanGestureHandlerGestureEvent) => void; + contentPanGestureHandler: ReturnType; + handlePanGestureHandler: ReturnType; } export const BottomSheetGestureHandlersContext = createContext(null); + +export const BottomSheetDraggableContext = createContext(null); diff --git a/src/contexts/internal.ts b/src/contexts/internal.ts index 1b2dc75ea..416bba227 100644 --- a/src/contexts/internal.ts +++ b/src/contexts/internal.ts @@ -1,11 +1,9 @@ import { createContext, RefObject } from 'react'; -import type { - PanGestureHandlerProps, - State, -} from 'react-native-gesture-handler'; +import type { State } from 'react-native-gesture-handler'; import type Animated from 'react-native-reanimated'; import type { AnimateToPositionType, + BottomSheetGestureProps, BottomSheetProps, } from '../components/bottomSheet/types'; import type { @@ -18,15 +16,7 @@ import type { import type { Scrollable, ScrollableRef } from '../types'; export interface BottomSheetInternalContextType - extends Pick< - PanGestureHandlerProps, - | 'activeOffsetY' - | 'activeOffsetX' - | 'failOffsetY' - | 'failOffsetX' - | 'waitFor' - | 'simultaneousHandlers' - >, + extends Partial, Required< Pick< BottomSheetProps, diff --git a/src/hooks/useGestureEventsHandlersDefault.tsx b/src/hooks/useGestureEventsHandlersDefault.tsx index a5aa3140e..efd28dc1a 100644 --- a/src/hooks/useGestureEventsHandlersDefault.tsx +++ b/src/hooks/useGestureEventsHandlersDefault.tsx @@ -1,5 +1,9 @@ import { Keyboard, Platform } from 'react-native'; -import { runOnJS, useWorkletCallback } from 'react-native-reanimated'; +import { + runOnJS, + useSharedValue, + useWorkletCallback, +} from 'react-native-reanimated'; import { useBottomSheetInternal } from './useBottomSheetInternal'; import { ANIMATION_SOURCE, @@ -21,7 +25,19 @@ type GestureEventContextType = { isScrollablePositionLocked: boolean; }; -const dismissKeyboard = Keyboard.dismiss; +const INITIAL_CONTEXT: GestureEventContextType = { + initialPosition: 0, + initialKeyboardState: KEYBOARD_STATE.UNDETERMINED, + isScrollablePositionLocked: false, +}; + +const resetContext = (context: any) => { + 'worklet'; + + Object.keys(context).map(key => { + context[key] = undefined; + }); +}; export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = () => { @@ -41,350 +57,349 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = overDragResistanceFactor, isInTemporaryPosition, isScrollableRefreshable, - isScrollableLocked, animateToPosition, stopAnimation, } = useBottomSheetInternal(); + + const context = useSharedValue({ + ...INITIAL_CONTEXT, + }); //#endregion //#region gesture methods - const handleOnStart: GestureEventHandlerCallbackType = - useWorkletCallback( - function handleOnStart(__, _, context) { - // cancel current animation - stopAnimation(); - - // store current animated position - context.initialPosition = animatedPosition.value; - context.initialKeyboardState = animatedKeyboardState.value; - - /** - * if the scrollable content is scrolled, then - * we lock the position. - */ - if (animatedScrollableContentOffsetY.value > 0) { - context.isScrollablePositionLocked = true; - } - }, - [ - stopAnimation, - animatedPosition, - animatedKeyboardState, - animatedScrollableContentOffsetY, - ] - ); - const handleOnActive: GestureEventHandlerCallbackType = - useWorkletCallback( - function handleOnActive(source, { translationY }, context) { - let highestSnapPoint = animatedHighestSnapPoint.value; - - /** - * if keyboard is shown, then we set the highest point to the current - * position which includes the keyboard height. - */ - if ( - isInTemporaryPosition.value && - context.initialKeyboardState === KEYBOARD_STATE.SHOWN - ) { - highestSnapPoint = context.initialPosition; - } - - /** - * if current position is out of provided `snapPoints` and smaller then - * highest snap pont, then we set the highest point to the current position. - */ - if ( - isInTemporaryPosition.value && - context.initialPosition < highestSnapPoint - ) { - highestSnapPoint = context.initialPosition; - } - - const lowestSnapPoint = enablePanDownToClose - ? animatedContainerHeight.value - : animatedSnapPoints.value[0]; - - /** - * if scrollable is refreshable and sheet position at the highest - * point, then do not interact with current gesture. - */ + const handleOnStart: GestureEventHandlerCallbackType = useWorkletCallback( + function handleOnStart(__, _) { + // cancel current animation + stopAnimation(); + + // store current animated position + context.value = { + ...context.value, + initialPosition: animatedPosition.value, + initialKeyboardState: animatedKeyboardState.value, + }; + + /** + * if the scrollable content is scrolled, then + * we lock the position. + */ + if (animatedScrollableContentOffsetY.value > 0) { + context.value = { + ...context.value, + isScrollablePositionLocked: true, + }; + } + }, + [ + stopAnimation, + animatedPosition, + animatedKeyboardState, + animatedScrollableContentOffsetY, + ] + ); + const handleOnChange: GestureEventHandlerCallbackType = useWorkletCallback( + function handleOnChange(source, { translationY }) { + let highestSnapPoint = animatedHighestSnapPoint.value; + + /** + * if keyboard is shown, then we set the highest point to the current + * position which includes the keyboard height. + */ + if ( + isInTemporaryPosition.value && + context.value.initialKeyboardState === KEYBOARD_STATE.SHOWN + ) { + highestSnapPoint = context.value.initialPosition; + } + + /** + * if current position is out of provided `snapPoints` and smaller then + * highest snap pont, then we set the highest point to the current position. + */ + if ( + isInTemporaryPosition.value && + context.value.initialPosition < highestSnapPoint + ) { + highestSnapPoint = context.value.initialPosition; + } + + const lowestSnapPoint = enablePanDownToClose + ? animatedContainerHeight.value + : animatedSnapPoints.value[0]; + + /** + * if scrollable is refreshable and sheet position at the highest + * point, then do not interact with current gesture. + */ + if ( + source === GESTURE_SOURCE.CONTENT && + isScrollableRefreshable.value && + animatedPosition.value === highestSnapPoint + ) { + return; + } + + /** + * a negative scrollable content offset to be subtracted from accumulated + * current position and gesture translation Y to allow user to drag the sheet, + * when scrollable position at the top. + * a negative scrollable content offset when the scrollable is not locked. + */ + const negativeScrollableContentOffset = + (context.value.initialPosition === highestSnapPoint && + source === GESTURE_SOURCE.CONTENT) || + !context.value.isScrollablePositionLocked + ? animatedScrollableContentOffsetY.value * -1 + : 0; + + /** + * an accumulated value of starting position with gesture translation y. + */ + const draggedPosition = context.value.initialPosition + translationY; + + /** + * an accumulated value of dragged position and negative scrollable content offset, + * this will insure locking sheet position when user is scrolling the scrollable until, + * they reach to the top of the scrollable. + */ + const accumulatedDraggedPosition = + draggedPosition + negativeScrollableContentOffset; + + /** + * a clamped value of the accumulated dragged position, to insure keeping the dragged + * position between the highest and lowest snap points. + */ + const clampedPosition = clamp( + accumulatedDraggedPosition, + highestSnapPoint, + lowestSnapPoint + ); + + /** + * if scrollable position is locked and the animated position + * reaches the highest point, then we unlock the scrollable position. + */ + if ( + context.value.isScrollablePositionLocked && + source === GESTURE_SOURCE.CONTENT && + animatedPosition.value === highestSnapPoint + ) { + context.value = { + ...context.value, + isScrollablePositionLocked: false, + }; + } + + /** + * over-drag implementation. + */ + if (enableOverDrag) { if ( - source === GESTURE_SOURCE.SCROLLABLE && - isScrollableRefreshable.value && - animatedPosition.value === highestSnapPoint + (source === GESTURE_SOURCE.HANDLE || + animatedScrollableType.value === SCROLLABLE_TYPE.VIEW) && + draggedPosition < highestSnapPoint ) { + const resistedPosition = + highestSnapPoint - + Math.sqrt(1 + (highestSnapPoint - draggedPosition)) * + overDragResistanceFactor; + animatedPosition.value = resistedPosition; return; } - /** - * if scrollable isn't currently marked as translatable, then do not - * interact with current gesture. - */ - if (source === GESTURE_SOURCE.SCROLLABLE && !isScrollableLocked.value) { - return; - } - - /** - * a negative scrollable content offset to be subtracted from accumulated - * current position and gesture translation Y to allow user to drag the sheet, - * when scrollable position at the top. - * a negative scrollable content offset when the scrollable is not locked. - */ - const negativeScrollableContentOffset = - (context.initialPosition === highestSnapPoint && - source === GESTURE_SOURCE.SCROLLABLE) || - !context.isScrollablePositionLocked - ? animatedScrollableContentOffsetY.value * -1 - : 0; - - /** - * an accumulated value of starting position with gesture translation y. - */ - const draggedPosition = context.initialPosition + translationY; - - /** - * an accumulated value of dragged position and negative scrollable content offset, - * this will insure locking sheet position when user is scrolling the scrollable until, - * they reach to the top of the scrollable. - */ - const accumulatedDraggedPosition = - draggedPosition + negativeScrollableContentOffset; - - /** - * a clamped value of the accumulated dragged position, to insure keeping the dragged - * position between the highest and lowest snap points. - */ - const clampedPosition = clamp( - accumulatedDraggedPosition, - highestSnapPoint, - lowestSnapPoint - ); - - /** - * if scrollable position is locked and the animated position - * reaches the highest point, then we unlock the scrollable position. - */ - if ( - context.isScrollablePositionLocked && - source === GESTURE_SOURCE.SCROLLABLE && - animatedPosition.value === highestSnapPoint - ) { - context.isScrollablePositionLocked = false; - } - - /** - * over-drag implementation. - */ - if (enableOverDrag) { - if ( - (source === GESTURE_SOURCE.HANDLE || - animatedScrollableType.value === SCROLLABLE_TYPE.VIEW) && - draggedPosition < highestSnapPoint - ) { - const resistedPosition = - highestSnapPoint - - Math.sqrt(1 + (highestSnapPoint - draggedPosition)) * - overDragResistanceFactor; - animatedPosition.value = resistedPosition; - return; - } - - if ( - source === GESTURE_SOURCE.HANDLE && - draggedPosition > lowestSnapPoint - ) { - const resistedPosition = - lowestSnapPoint + - Math.sqrt(1 + (draggedPosition - lowestSnapPoint)) * - overDragResistanceFactor; - animatedPosition.value = resistedPosition; - return; - } - - if ( - source === GESTURE_SOURCE.SCROLLABLE && - draggedPosition + negativeScrollableContentOffset > - lowestSnapPoint - ) { - const resistedPosition = - lowestSnapPoint + - Math.sqrt( - 1 + - (draggedPosition + - negativeScrollableContentOffset - - lowestSnapPoint) - ) * - overDragResistanceFactor; - animatedPosition.value = resistedPosition; - return; - } - } - - animatedPosition.value = clampedPosition; - }, - [ - enableOverDrag, - enablePanDownToClose, - overDragResistanceFactor, - isInTemporaryPosition, - isScrollableRefreshable, - animatedHighestSnapPoint, - animatedContainerHeight, - animatedSnapPoints, - animatedPosition, - animatedScrollableType, - animatedScrollableContentOffsetY, - ] - ); - const handleOnEnd: GestureEventHandlerCallbackType = - useWorkletCallback( - function handleOnEnd( - source, - { translationY, absoluteY, velocityY }, - context - ) { - const highestSnapPoint = animatedHighestSnapPoint.value; - - const isSheetAtHighestSnapPoint = - animatedPosition.value === highestSnapPoint; - - /** - * if scrollable is refreshable and sheet position at the highest - * point, then do not interact with current gesture. - */ if ( - source === GESTURE_SOURCE.SCROLLABLE && - isScrollableRefreshable.value && - isSheetAtHighestSnapPoint + source === GESTURE_SOURCE.HANDLE && + draggedPosition > lowestSnapPoint ) { + const resistedPosition = + lowestSnapPoint + + Math.sqrt(1 + (draggedPosition - lowestSnapPoint)) * + overDragResistanceFactor; + animatedPosition.value = resistedPosition; return; } - if (!isScrollableLocked.value && animatedSnapPoints.value.includes(animatedPosition.value)) { - return; - } - - /** - * if the sheet is in a temporary position and the gesture ended above - * the current position, then we snap back to the temporary position. - */ if ( - isInTemporaryPosition.value && - context.initialPosition >= animatedPosition.value + source === GESTURE_SOURCE.CONTENT && + draggedPosition + negativeScrollableContentOffset > lowestSnapPoint ) { - if (context.initialPosition > animatedPosition.value) { - animateToPosition( - context.initialPosition, - ANIMATION_SOURCE.GESTURE, - velocityY / 2 - ); - } + const resistedPosition = + lowestSnapPoint + + Math.sqrt( + 1 + + (draggedPosition + + negativeScrollableContentOffset - + lowestSnapPoint) + ) * + overDragResistanceFactor; + animatedPosition.value = resistedPosition; return; } - - /** - * close keyboard if current position is below the recorded - * start position and keyboard still shown. - */ - const isScrollable = - animatedScrollableType.value !== SCROLLABLE_TYPE.UNDETERMINED && - animatedScrollableType.value !== SCROLLABLE_TYPE.VIEW; - + } + + animatedPosition.value = clampedPosition; + }, + [ + enableOverDrag, + enablePanDownToClose, + overDragResistanceFactor, + isInTemporaryPosition, + isScrollableRefreshable, + animatedHighestSnapPoint, + animatedContainerHeight, + animatedSnapPoints, + animatedPosition, + animatedScrollableType, + animatedScrollableContentOffsetY, + ] + ); + const handleOnEnd: GestureEventHandlerCallbackType = useWorkletCallback( + function handleOnEnd(source, { translationY, absoluteY, velocityY }) { + const highestSnapPoint = animatedHighestSnapPoint.value; + const isSheetAtHighestSnapPoint = + animatedPosition.value === highestSnapPoint; + + /** + * if scrollable is refreshable and sheet position at the highest + * point, then do not interact with current gesture. + */ + if ( + source === GESTURE_SOURCE.CONTENT && + isScrollableRefreshable.value && + isSheetAtHighestSnapPoint + ) { + return; + } + + /** + * if the sheet is in a temporary position and the gesture ended above + * the current position, then we snap back to the temporary position. + */ + if ( + isInTemporaryPosition.value && + context.value.initialPosition >= animatedPosition.value + ) { + if (context.value.initialPosition > animatedPosition.value) { + animateToPosition( + context.value.initialPosition, + ANIMATION_SOURCE.GESTURE, + velocityY / 2 + ); + } + return; + } + + /** + * close keyboard if current position is below the recorded + * start position and keyboard still shown. + */ + const isScrollable = + animatedScrollableType.value !== SCROLLABLE_TYPE.UNDETERMINED && + animatedScrollableType.value !== SCROLLABLE_TYPE.VIEW; + + /** + * if keyboard is shown and the sheet is dragged down, + * then we dismiss the keyboard. + */ + if ( + context.value.initialKeyboardState === KEYBOARD_STATE.SHOWN && + animatedPosition.value > context.value.initialPosition + ) { /** - * if keyboard is shown and the sheet is dragged down, - * then we dismiss the keyboard. + * if the platform is ios, current content is scrollable and + * the end touch point is below the keyboard position then + * we exit the method. + * + * because the the keyboard dismiss is interactive in iOS. */ if ( - context.initialKeyboardState === KEYBOARD_STATE.SHOWN && - animatedPosition.value > context.initialPosition + !( + Platform.OS === 'ios' && + isScrollable && + absoluteY > WINDOW_HEIGHT - animatedKeyboardHeight.value + ) ) { - /** - * if the platform is ios, current content is scrollable and - * the end touch point is below the keyboard position then - * we exit the method. - * - * because the the keyboard dismiss is interactive in iOS. - */ - if ( - !( - Platform.OS === 'ios' && - isScrollable && - absoluteY > WINDOW_HEIGHT - animatedKeyboardHeight.value - ) - ) { - runOnJS(dismissKeyboard)(); - } - } - - /** - * reset isInTemporaryPosition value - */ - if (isInTemporaryPosition.value) { - isInTemporaryPosition.value = false; - } - - /** - * clone snap points array, and insert the container height - * if pan down to close is enabled. - */ - const snapPoints = animatedSnapPoints.value.slice(); - if (enablePanDownToClose) { - snapPoints.unshift(animatedClosedPosition.value); - } - - /** - * calculate the destination point, using redash. - */ - const destinationPoint = snapPoint( - translationY + context.initialPosition, - velocityY, - snapPoints - ); - - /** - * if destination point is the same as the current position, - * then no need to perform animation. - */ - if (destinationPoint === animatedPosition.value) { - return; + runOnJS(Keyboard.dismiss)(); } - - const wasGestureHandledByScrollView = - source === GESTURE_SOURCE.SCROLLABLE && - animatedScrollableContentOffsetY.value > 0; - /** - * prevents snapping from top to middle / bottom with repeated interrupted scrolls - */ - if (wasGestureHandledByScrollView && isSheetAtHighestSnapPoint) { - return; - } - - animateToPosition( - destinationPoint, - ANIMATION_SOURCE.GESTURE, - velocityY / 2 - ); + } + + /** + * reset isInTemporaryPosition value + */ + if (isInTemporaryPosition.value) { + isInTemporaryPosition.value = false; + } + + /** + * clone snap points array, and insert the container height + * if pan down to close is enabled. + */ + const snapPoints = animatedSnapPoints.value.slice(); + if (enablePanDownToClose) { + snapPoints.unshift(animatedClosedPosition.value); + } + + /** + * calculate the destination point, using redash. + */ + const destinationPoint = snapPoint( + translationY + context.value.initialPosition, + velocityY, + snapPoints + ); + + /** + * if destination point is the same as the current position, + * then no need to perform animation. + */ + if (destinationPoint === animatedPosition.value) { + return; + } + + const wasGestureHandledByScrollView = + source === GESTURE_SOURCE.CONTENT && + animatedScrollableContentOffsetY.value > 0; + /** + * prevents snapping from top to middle / bottom with repeated interrupted scrolls + */ + if (wasGestureHandledByScrollView && isSheetAtHighestSnapPoint) { + return; + } + + animateToPosition( + destinationPoint, + ANIMATION_SOURCE.GESTURE, + velocityY / 2 + ); + }, + [ + enablePanDownToClose, + isInTemporaryPosition, + isScrollableRefreshable, + animatedClosedPosition, + animatedHighestSnapPoint, + animatedKeyboardHeight, + animatedPosition, + animatedScrollableType, + animatedSnapPoints, + animatedScrollableContentOffsetY, + animateToPosition, + ] + ); + + const handleOnFinalize: GestureEventHandlerCallbackType = + useWorkletCallback( + function handleOnFinalize() { + resetContext(context); }, - [ - enablePanDownToClose, - isInTemporaryPosition, - isScrollableRefreshable, - isScrollableLocked, - animatedClosedPosition, - animatedHighestSnapPoint, - animatedKeyboardHeight, - animatedPosition, - animatedScrollableType, - animatedSnapPoints, - animatedScrollableContentOffsetY, - animateToPosition, - ] + [context] ); //#endregion return { handleOnStart, - handleOnActive, + handleOnChange, handleOnEnd, + handleOnFinalize, }; }; diff --git a/src/hooks/useGestureHandler.ts b/src/hooks/useGestureHandler.ts index eb50e72be..8e4168a2d 100644 --- a/src/hooks/useGestureHandler.ts +++ b/src/hooks/useGestureHandler.ts @@ -1,96 +1,79 @@ -import Animated, { useAnimatedGestureHandler } from 'react-native-reanimated'; +import Animated, { useWorkletCallback } from 'react-native-reanimated'; import { State, - PanGestureHandlerGestureEvent, + GestureStateChangeEvent, + PanGestureHandlerEventPayload, } from 'react-native-gesture-handler'; import { GESTURE_SOURCE } from '../constants'; import type { - GestureEventContextType, GestureEventHandlerCallbackType, + GestureHandlersHookType, } from '../types'; -const resetContext = (context: any) => { - 'worklet'; - - Object.keys(context).map(key => { - context[key] = undefined; - }); -}; - -export const useGestureHandler = ( - type: GESTURE_SOURCE, +export const useGestureHandler: GestureHandlersHookType = ( + source: GESTURE_SOURCE, state: Animated.SharedValue, gestureSource: Animated.SharedValue, - handleOnStart: GestureEventHandlerCallbackType, - handleOnActive: GestureEventHandlerCallbackType, - handleOnEnd: GestureEventHandlerCallbackType -): ((event: PanGestureHandlerGestureEvent) => void) => { - const gestureHandler = useAnimatedGestureHandler< - PanGestureHandlerGestureEvent, - GestureEventContextType - >( - { - onActive: (payload, context) => { - if (!context.didStart) { - context.didStart = true; - - state.value = State.BEGAN; - gestureSource.value = type; + onStart: GestureEventHandlerCallbackType, + onChange: GestureEventHandlerCallbackType, + onEnd: GestureEventHandlerCallbackType, + onFinalize: GestureEventHandlerCallbackType +) => { + const handleOnStart = useWorkletCallback( + (event: GestureStateChangeEvent) => { + state.value = State.BEGAN; + gestureSource.value = source; - handleOnStart(type, payload, context); - return; - } - - if (gestureSource.value !== type) { - return; - } - - state.value = payload.state; - handleOnActive(type, payload, context); - }, - onEnd: (payload, context) => { - if (gestureSource.value !== type) { - return; - } + onStart(source, event); + return; + }, + [state, gestureSource, source, onStart] + ); - state.value = payload.state; - gestureSource.value = GESTURE_SOURCE.UNDETERMINED; + const handleOnChange = useWorkletCallback( + (event: GestureStateChangeEvent) => { + if (gestureSource.value !== source) { + return; + } - handleOnEnd(type, payload, context); - resetContext(context); - }, - onCancel: (payload, context) => { - if (gestureSource.value !== type) { - return; - } + state.value = event.state; + onChange(source, event); + }, + [state, gestureSource, source, onChange] + ); - state.value = payload.state; - gestureSource.value = GESTURE_SOURCE.UNDETERMINED; + const handleOnEnd = useWorkletCallback( + (event: GestureStateChangeEvent) => { + if (gestureSource.value !== source) { + return; + } - resetContext(context); - }, - onFail: (payload, context) => { - if (gestureSource.value !== type) { - return; - } + state.value = event.state; + gestureSource.value = GESTURE_SOURCE.UNDETERMINED; - state.value = payload.state; - gestureSource.value = GESTURE_SOURCE.UNDETERMINED; + onEnd(source, event); + }, + [state, gestureSource, source, onEnd] + ); - resetContext(context); - }, - onFinish: (payload, context) => { - if (gestureSource.value !== type) { - return; - } + const handleOnFinalize = useWorkletCallback( + (event: GestureStateChangeEvent) => { + if (gestureSource.value !== source) { + return; + } - state.value = payload.state; - gestureSource.value = GESTURE_SOURCE.UNDETERMINED; + state.value = event.state; + gestureSource.value = GESTURE_SOURCE.UNDETERMINED; - resetContext(context); - }, + onFinalize(source, event); }, - [type, state, handleOnStart, handleOnActive, handleOnEnd] + [state, gestureSource, source, onFinalize] ); - return gestureHandler; + + return { + handleOnStart, + handleOnChange, + handleOnEnd, + handleOnFinalize, + }; }; diff --git a/src/types.d.ts b/src/types.d.ts index a7cd4fe19..d949ad24f 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -137,16 +137,39 @@ export type GestureEventContextType = { didStart?: boolean; }; -export type GestureEventHandlerCallbackType = ( +export type GestureEventHandlerCallbackType = ( source: GESTURE_SOURCE, - payload: GestureEventPayloadType, - context: C + event: GestureStateChangeEvent ) => void; export type GestureEventsHandlersHookType = () => { handleOnStart: GestureEventHandlerCallbackType; - handleOnActive: GestureEventHandlerCallbackType; + handleOnChange: GestureEventHandlerCallbackType; handleOnEnd: GestureEventHandlerCallbackType; + handleOnFinalize: GestureEventHandlerCallbackType; +}; + +export type GestureHandlersHookType = ( + source: GESTURE_SOURCE, + state: Animated.SharedValue, + gestureSource: Animated.SharedValue, + onStart: GestureEventHandlerCallbackType, + onChange: GestureEventHandlerCallbackType, + onEnd: GestureEventHandlerCallbackType, + onFinalize: GestureEventHandlerCallbackType +) => { + handleOnStart: ( + event: GestureStateChangeEvent + ) => void; + handleOnChange: ( + event: GestureStateChangeEvent + ) => void; + handleOnEnd: ( + event: GestureStateChangeEvent + ) => void; + handleOnFinalize: ( + event: GestureStateChangeEvent + ) => void; }; type ScrollEventHandlerCallbackType = ( diff --git a/yarn.lock b/yarn.lock index b4e31bdb1..b684cf790 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,12 +2,10 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5": version "7.14.5" @@ -367,7 +365,7 @@ "@babel/traverse" "^7.14.8" "@babel/types" "^7.14.8" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": +"@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== @@ -1431,21 +1429,38 @@ dependencies: "@types/hammerjs" "^2.0.36" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + "@gorhom/portal@1.0.14": version "1.0.14" resolved "https://registry.yarnpkg.com/@gorhom/portal/-/portal-1.0.14.tgz#1953edb76aaba80fb24021dc774550194a18e111" @@ -1485,19 +1500,24 @@ dependencies: "@hapi/hoek" "^8.3.0" -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== "@hutson/parse-repository-url@^5.0.0": version "5.0.0" @@ -1602,7 +1622,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2137,6 +2157,11 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -2165,7 +2190,7 @@ accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -2175,16 +2200,16 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - acorn@^8.4.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -2205,7 +2230,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2215,16 +2240,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" - integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ajv@^8.11.0: version "8.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" @@ -2254,11 +2269,6 @@ ansi-colors@^1.0.1: dependencies: ansi-wrap "^0.1.0" -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-cyan@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" @@ -2271,13 +2281,20 @@ ansi-escapes@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== -ansi-escapes@^4.3.0, ansi-escapes@^4.3.2: +ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" +ansi-escapes@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6" + integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== + dependencies: + type-fest "^1.0.2" + ansi-fragments@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-fragments/-/ansi-fragments-0.2.1.tgz#24409c56c4cc37817c3d7caa99d8969e2de5a05e" @@ -2340,6 +2357,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-styles@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.1.tgz#63cd61c72283a71cb30bd881dbb60adada74bc70" @@ -2518,11 +2540,6 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - async-retry@1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -2759,7 +2776,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.1, braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2958,7 +2975,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3042,13 +3059,13 @@ cli-spinners@^2.5.0, cli-spinners@^2.9.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.1.tgz#9c0b9dad69a6d47cbb4333c14319b060ed395a35" integrity sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ== -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" + slice-ansi "^5.0.0" + string-width "^5.0.0" cli-width@^2.0.0: version "2.2.1" @@ -3150,11 +3167,21 @@ colorette@^1.0.7, colorette@^1.2.2: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + command-exists@^1.2.8: version "1.2.9" resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== +commander@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" + integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== + commander@^2.19.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -3516,13 +3543,6 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^3.0.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" - integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== - dependencies: - node-fetch "2.6.1" - cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -3596,14 +3616,14 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@^4.3.4: +debug@4, debug@4.3.4, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -3882,13 +3902,6 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enquirer@^2.3.5, enquirer@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - envinfo@^7.7.2: version "7.8.1" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" @@ -4074,10 +4087,10 @@ eslint-config-prettier@^6.10.1: dependencies: get-stdin "^6.0.0" -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== +eslint-config-prettier@^8.5.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" + integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== eslint-plugin-eslint-comments@^3.1.2: version "3.2.0" @@ -4106,10 +4119,10 @@ eslint-plugin-prettier@3.1.2: dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-prettier@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" - integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" @@ -4164,12 +4177,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -4178,7 +4192,7 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -4188,70 +4202,73 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.21.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" + optionator "^0.9.3" + strip-ansi "^6.0.1" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -4292,11 +4309,31 @@ eventemitter3@^3.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + exec-sh@^0.3.2: version "0.3.6" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== +execa@7.2.0, execa@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + execa@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" @@ -4355,21 +4392,6 @@ execa@^5.0.0, execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -4538,19 +4560,6 @@ fbjs@^1.0.0: setimmediate "^1.0.5" ua-parser-js "^0.7.18" -fbjs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" - integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== - dependencies: - cross-fetch "^3.0.4" - fbjs-css-vars "^1.0.0" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - fetch-blob@^3.1.2, fetch-blob@^3.1.4: version "3.2.0" resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" @@ -4821,11 +4830,6 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: has-proto "^1.0.1" has-symbols "^1.0.3" -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -4928,6 +4932,13 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.0.0, glob@^7.0.5, glob@^7.1.3, glob@^7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -4959,10 +4970,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0, globals@^13.9.0: - version "13.10.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.10.0.tgz#60ba56c3ac2ca845cfbf4faeca727ad9dd204676" - integrity sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" @@ -5049,6 +5060,11 @@ graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + graphql@^14.0.0: version "14.7.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.7.0.tgz#7fa79a80a69be4a31c27dda824dc04dac2035a72" @@ -5298,16 +5314,16 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.0.5, ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" @@ -5639,6 +5655,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + is-git-dirty@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-git-dirty/-/is-git-dirty-2.0.1.tgz#29ca82fb0924ccbeaa0bae08de217546df593012" @@ -5662,6 +5683,13 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-in-ci@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-in-ci/-/is-in-ci-0.1.0.tgz#5e07d6a02ec3a8292d3f590973357efa3fceb0d3" @@ -5731,11 +5759,6 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - is-obj@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" @@ -5746,7 +5769,7 @@ is-path-cwd@^2.2.0: resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== -is-path-inside@^3.0.2: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -5771,11 +5794,6 @@ is-regex@^1.1.3, is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - is-relative@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" @@ -6265,6 +6283,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -6275,38 +6298,33 @@ lines-and-columns@^2.0.3: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== -lint-staged@^11.1.2: - version "11.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90" - integrity sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w== +lint-staged@^13.0.3: + version "13.3.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.3.0.tgz#7965d72a8d6a6c932f85e9c13ccf3596782d28a5" + integrity sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ== dependencies: - chalk "^4.1.1" - cli-truncate "^2.1.0" - commander "^7.2.0" - cosmiconfig "^7.0.0" - debug "^4.3.1" - enquirer "^2.3.6" - execa "^5.0.0" - listr2 "^3.8.2" - log-symbols "^4.1.0" - micromatch "^4.0.4" - normalize-path "^3.0.0" - please-upgrade-node "^3.2.0" - string-argv "0.3.1" - stringify-object "^3.3.0" - -listr2@^3.8.2: - version "3.11.0" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.11.0.tgz#9771b02407875aa78e73d6e0ff6541bbec0aaee9" - integrity sha512-XLJVe2JgXCyQTa3FbSv11lkKExYmEyA4jltVo8z4FX10Vt1Yj8IMekBfwim0BSOM9uj1QMTJvDQQpHyuPbB/dQ== - dependencies: - cli-truncate "^2.1.0" - colorette "^1.2.2" - log-update "^4.0.0" - p-map "^4.0.0" - rxjs "^6.6.7" - through "^2.3.8" - wrap-ansi "^7.0.0" + chalk "5.3.0" + commander "11.0.0" + debug "4.3.4" + execa "7.2.0" + lilconfig "2.1.0" + listr2 "6.6.1" + micromatch "4.0.5" + pidtree "0.6.0" + string-argv "0.3.2" + yaml "2.3.1" + +listr2@6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d" + integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== + dependencies: + cli-truncate "^3.1.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^5.0.1" + rfdc "^1.3.0" + wrap-ansi "^8.1.0" locate-path@^3.0.0: version "3.0.0" @@ -6347,11 +6365,6 @@ lodash.capitalize@^4.2.1: resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" integrity sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw== -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -6407,11 +6420,6 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -6455,15 +6463,16 @@ log-symbols@^5.1.0: chalk "^5.0.0" is-unicode-supported "^1.1.0" -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== +log-update@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" + integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" + ansi-escapes "^5.0.0" + cli-cursor "^4.0.0" + slice-ansi "^5.0.0" + strip-ansi "^7.0.1" + wrap-ansi "^8.0.1" logkitty@^0.7.1: version "0.7.1" @@ -6922,6 +6931,14 @@ metro@0.59.0, metro@^0.59.0: xpipe "^1.0.5" yargs "^14.2.0" +micromatch@4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -7037,6 +7054,13 @@ minimatch@^3.0.3, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^3.0.5, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -7170,11 +7194,6 @@ node-domexception@^1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@2.6.1, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-fetch@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" @@ -7192,6 +7211,11 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -7257,11 +7281,6 @@ normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -7461,17 +7480,17 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" options@>=0.0.5: version "0.0.6" @@ -7762,6 +7781,16 @@ picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -7832,11 +7861,16 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.0.2, prettier@^2.3.2: +prettier@^2.0.2: version "2.3.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prettier@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + pretty-format@^24.7.0, pretty-format@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" @@ -7862,11 +7896,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - promise.allsettled@1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.7.tgz#b9dd51e9cffe496243f5271515652c468865f2d8" @@ -8027,15 +8056,15 @@ react-native-builder-bob@^0.18.1: optionalDependencies: jetifier "^1.6.6" -react-native-gesture-handler@^1.10.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz#942bbf2963bbf49fa79593600ee9d7b5dab3cfc0" - integrity sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw== +react-native-gesture-handler@^2.12.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.15.0.tgz#f8e6c0451a7bdf065edb7b9be605480db402baa0" + integrity sha512-cmMGW8k86o/xgVTBZZOPohvR5re4Vh65PUxH4HbBBJAYTog4aN4wTVTUlnoky01HuSN8/X4h3tI/K3XLPoDnsg== dependencies: "@egjs/hammerjs" "^2.0.17" - fbjs "^3.0.0" hoist-non-react-statics "^3.3.0" invariant "^2.2.4" + lodash "^4.17.21" prop-types "^15.7.2" react-native-reanimated@^3.4.2: @@ -8440,6 +8469,11 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" + integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== + rimraf@^2.5.4: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -8500,13 +8534,6 @@ rx-lite@*, rx-lite@^4.0.8: resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= -rxjs@^6.6.7: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" @@ -8622,7 +8649,7 @@ semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: +semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -8821,23 +8848,13 @@ slice-ansi@^2.0.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" smart-buffer@^4.2.0: version "4.2.0" @@ -9024,10 +9041,10 @@ stream-buffers@~2.2.0: resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" integrity sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ= -string-argv@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== +string-argv@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== string-width@^2.1.0: version "2.1.1" @@ -9064,7 +9081,7 @@ string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: +string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -9158,15 +9175,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -9231,7 +9239,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -9267,18 +9275,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^6.0.9: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== - dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" - temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -9322,7 +9318,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8: +"through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -9415,7 +9411,7 @@ ts-node@^10.8.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -9469,7 +9465,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^1.0.1: +type-fest@^1.0.1, type-fest@^1.0.2: version "1.4.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== @@ -9738,11 +9734,6 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -9850,11 +9841,6 @@ windows-release@^5.0.1: dependencies: execa "^5.1.1" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -9887,7 +9873,7 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^8.1.0: +wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== @@ -9984,6 +9970,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" From afb2f9fd635bf66c52e1bc3e17dbce43b5793dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?avery=20=E2=9C=BF?= Date: Sun, 17 Mar 2024 17:01:03 -0700 Subject: [PATCH 2/6] fix: fixed keyboard dismissing issue with Reanimated v3 (#1346) fix: crash on swipe down (#1367) --- src/hooks/useGestureEventsHandlersDefault.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hooks/useGestureEventsHandlersDefault.tsx b/src/hooks/useGestureEventsHandlersDefault.tsx index efd28dc1a..450e2acf7 100644 --- a/src/hooks/useGestureEventsHandlersDefault.tsx +++ b/src/hooks/useGestureEventsHandlersDefault.tsx @@ -31,6 +31,8 @@ const INITIAL_CONTEXT: GestureEventContextType = { isScrollablePositionLocked: false, }; +const dismissKeyboard = Keyboard.dismiss; + const resetContext = (context: any) => { 'worklet'; @@ -319,7 +321,7 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = absoluteY > WINDOW_HEIGHT - animatedKeyboardHeight.value ) ) { - runOnJS(Keyboard.dismiss)(); + runOnJS(dismissKeyboard)(); } } From ed75bb70edfbe7fc327d5b8d97bd111cbf1eca6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?avery=20=E2=9C=BF?= Date: Sun, 17 Mar 2024 17:13:07 -0700 Subject: [PATCH 3/6] fix: fixed position x index sequencing with container resizing (#1675) https://github.com/gorhom/react-native-bottom-sheet/commit/f0ec705cd74ea6e31614ab12c0b4fdc097d3820d --- src/components/bottomSheet/BottomSheet.tsx | 81 +++++++++++++++++----- src/hooks/useBottomSheetTimingConfigs.ts | 12 +++- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx index 30085c3e4..6a304a9ab 100644 --- a/src/components/bottomSheet/BottomSheet.tsx +++ b/src/components/bottomSheet/BottomSheet.tsx @@ -713,9 +713,9 @@ const BottomSheetComponent = forwardRef( method: animateToPosition.name, params: { currentPosition: animatedPosition.value, - position, + nextPosition: position, velocity, - animatedContainerHeight: animatedContainerHeight.value, + source, }, }); @@ -763,6 +763,47 @@ const BottomSheetComponent = forwardRef( }, [handleOnAnimate, _providedAnimationConfigs] ); + /** + * Set to position without animation. + * + * @param targetPosition position to be set. + */ + const setToPosition = useWorkletCallback(function setToPosition( + targetPosition: number + ) { + if ( + targetPosition === animatedPosition.value || + targetPosition === undefined || + (animatedAnimationState.value === ANIMATION_STATE.RUNNING && + targetPosition === animatedNextPosition.value) + ) { + return; + } + + runOnJS(print)({ + component: BottomSheet.name, + method: setToPosition.name, + params: { + currentPosition: animatedPosition.value, + targetPosition, + }, + }); + + /** + * store next position + */ + animatedNextPosition.value = targetPosition; + animatedNextPositionIndex.value = + animatedSnapPoints.value.indexOf(targetPosition); + + stopAnimation(); + + /** + * set position. + */ + animatedPosition.value = targetPosition; + }, + []); //#endregion //#region public methods @@ -1343,16 +1384,8 @@ const BottomSheetComponent = forwardRef( animatedNextPositionIndex.value === -1 && _previousContainerHeight !== containerHeight ) { - animationSource = ANIMATION_SOURCE.CONTAINER_RESIZE; - animationConfig = { - duration: 0, - }; - animateToPosition( - containerHeight, - animationSource, - 0, - animationConfig - ); + setToPosition(containerHeight); + return; } if ( @@ -1393,13 +1426,11 @@ const BottomSheetComponent = forwardRef( /** * if snap points changes because of the container height change, - * then we skip the snap animation by setting the duration to 0. + * then we set the new position without animation. */ if (containerHeight !== _previousContainerHeight) { - animationSource = ANIMATION_SOURCE.CONTAINER_RESIZE; - animationConfig = { - duration: 0, - }; + setToPosition(nextPosition); + return; } } animateToPosition(nextPosition, animationSource, 0, animationConfig); @@ -1553,6 +1584,7 @@ const BottomSheetComponent = forwardRef( }), ({ _animatedIndex, + _animatedPosition, _animationState, _contentGestureState, _handleGestureState, @@ -1564,6 +1596,21 @@ const BottomSheetComponent = forwardRef( return; } + /** + * exit the method if index value is not synced with + * position value. + * + * [read more](https://github.com/gorhom/react-native-bottom-sheet/issues/1356) + */ + if ( + animatedNextPosition.value !== INITIAL_VALUE && + animatedNextPositionIndex.value !== INITIAL_VALUE && + (_animatedPosition !== animatedNextPosition.value || + _animatedIndex !== animatedNextPositionIndex.value) + ) { + return; + } + /** * exit the method if animated index value * has fraction, e.g. 1.99, 0.52 diff --git a/src/hooks/useBottomSheetTimingConfigs.ts b/src/hooks/useBottomSheetTimingConfigs.ts index 9d2f61dc6..1c9ad7e3f 100644 --- a/src/hooks/useBottomSheetTimingConfigs.ts +++ b/src/hooks/useBottomSheetTimingConfigs.ts @@ -1,7 +1,13 @@ import { useMemo } from 'react'; -import type { WithTimingConfig } from 'react-native-reanimated'; +import type { EasingFunction } from 'react-native'; +import type { EasingFunctionFactory } from 'react-native-reanimated'; import { ANIMATION_DURATION, ANIMATION_EASING } from '../constants'; +interface TimingConfig { + duration?: number; + easing?: EasingFunction | EasingFunctionFactory; +} + /** * Generate timing animation configs. * @default @@ -9,9 +15,9 @@ import { ANIMATION_DURATION, ANIMATION_EASING } from '../constants'; * - duration 250 * @param configs overridable configs. */ -export const useBottomSheetTimingConfigs = (configs: WithTimingConfig) => { +export const useBottomSheetTimingConfigs = (configs: TimingConfig) => { return useMemo(() => { - const _configs: WithTimingConfig = { + const _configs: TimingConfig = { easing: configs.easing || ANIMATION_EASING, duration: configs.duration || ANIMATION_DURATION, }; From fc1a76f3db1808407343d60b8b57074bb5ce9c3a Mon Sep 17 00:00:00 2001 From: gorhom Date: Sun, 25 Feb 2024 18:12:30 +0100 Subject: [PATCH 4/6] fix: fixed the mount animation with reduce motion enabled (#1560, #1674) fix: bottom sheet not appearing for users that have reduced motion turned on (#1743)(by @fobos531) --- src/components/bottomSheet/BottomSheet.tsx | 32 ++++++++-------------- src/hooks/useBottomSheetSpringConfigs.ts | 3 +- src/hooks/useBottomSheetTimingConfigs.ts | 17 ++++-------- src/utilities/animate.ts | 6 ++++ 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx index 6a304a9ab..d02266c30 100644 --- a/src/components/bottomSheet/BottomSheet.tsx +++ b/src/components/bottomSheet/BottomSheet.tsx @@ -740,26 +740,14 @@ const BottomSheetComponent = forwardRef( runOnJS(handleOnAnimate)(position, source, animatedSnapPoints.value); /** - * force animation configs from parameters, if provided + * start animation */ - if (configs !== undefined) { - animatedPosition.value = animate({ - point: position, - configs, - velocity, - onComplete: animateToPositionCompleted, - }); - } else { - /** - * use animationConfigs callback, if provided - */ - animatedPosition.value = animate({ - point: position, - velocity, - configs: _providedAnimationConfigs, - onComplete: animateToPositionCompleted, - }); - } + animatedPosition.value = animate({ + point: position, + configs: configs || _providedAnimationConfigs, + velocity, + onComplete: animateToPositionCompleted, + }); }, [handleOnAnimate, _providedAnimationConfigs] ); @@ -1313,7 +1301,7 @@ const BottomSheetComponent = forwardRef( return; } - let nextPosition; + let nextPosition: number; if (_providedIndex === -1) { nextPosition = animatedClosedPosition.value; animatedNextPositionIndex.value = -1; @@ -1346,7 +1334,9 @@ const BottomSheetComponent = forwardRef( } if (animateOnMount) { - animateToPosition(nextPosition, ANIMATION_SOURCE.MOUNT); + requestAnimationFrame(() => { + animateToPosition(nextPosition, ANIMATION_SOURCE.MOUNT); + }); } else { animatedPosition.value = nextPosition; } diff --git a/src/hooks/useBottomSheetSpringConfigs.ts b/src/hooks/useBottomSheetSpringConfigs.ts index aef93b862..f379aa668 100644 --- a/src/hooks/useBottomSheetSpringConfigs.ts +++ b/src/hooks/useBottomSheetSpringConfigs.ts @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import type { WithSpringConfig } from 'react-native-reanimated'; /** @@ -8,5 +7,5 @@ import type { WithSpringConfig } from 'react-native-reanimated'; export const useBottomSheetSpringConfigs = ( configs: Omit ) => { - return useMemo(() => configs, [configs]); + return configs; }; diff --git a/src/hooks/useBottomSheetTimingConfigs.ts b/src/hooks/useBottomSheetTimingConfigs.ts index 1c9ad7e3f..3ce20ea8e 100644 --- a/src/hooks/useBottomSheetTimingConfigs.ts +++ b/src/hooks/useBottomSheetTimingConfigs.ts @@ -1,27 +1,22 @@ import { useMemo } from 'react'; -import type { EasingFunction } from 'react-native'; -import type { EasingFunctionFactory } from 'react-native-reanimated'; +import type { WithTimingConfig } from 'react-native-reanimated'; import { ANIMATION_DURATION, ANIMATION_EASING } from '../constants'; -interface TimingConfig { - duration?: number; - easing?: EasingFunction | EasingFunctionFactory; -} - /** * Generate timing animation configs. * @default * - easing: Easing.out(Easing.exp) - * - duration 250 + * - duration: 250 * @param configs overridable configs. */ -export const useBottomSheetTimingConfigs = (configs: TimingConfig) => { +export const useBottomSheetTimingConfigs = (configs: WithTimingConfig) => { return useMemo(() => { - const _configs: TimingConfig = { + const _configs: WithTimingConfig = { easing: configs.easing || ANIMATION_EASING, duration: configs.duration || ANIMATION_DURATION, + reduceMotion: configs.reduceMotion, }; return _configs; - }, [configs.duration, configs.easing]); + }, [configs.duration, configs.easing, configs.reduceMotion]); }; diff --git a/src/utilities/animate.ts b/src/utilities/animate.ts index 0ce4c9a50..77d762e35 100644 --- a/src/utilities/animate.ts +++ b/src/utilities/animate.ts @@ -4,6 +4,7 @@ import { withTiming, withSpring, AnimationCallback, + ReduceMotion, } from 'react-native-reanimated'; import { ANIMATION_CONFIGS, ANIMATION_METHOD } from '../constants'; @@ -26,6 +27,11 @@ export const animate = ({ configs = ANIMATION_CONFIGS; } + // Users might have an accessibililty setting to reduce motion turned on. + // This prevents the animation from running when presenting the sheet, which results in + // the bottom sheet not even appearing so we need to override it to ensure the animation runs. + configs.reduceMotion = ReduceMotion.Never; + // detect animation type const type = 'duration' in configs || 'easing' in configs From 8093e969ca319abe2fd176a114cdf12fd6bd6c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?avery=20=E2=9C=BF?= Date: Sun, 17 Mar 2024 21:37:00 -0700 Subject: [PATCH 5/6] fix android floating point issues --- src/components/bottomSheet/BottomSheet.tsx | 22 +++++++++++++------ src/hooks/useGestureEventsHandlersDefault.tsx | 18 ++++++++++----- src/utilities/floatingPointEquals.ts | 6 +++++ src/utilities/index.ts | 1 + 4 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 src/utilities/floatingPointEquals.ts diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx index d02266c30..ed6e27f24 100644 --- a/src/components/bottomSheet/BottomSheet.tsx +++ b/src/components/bottomSheet/BottomSheet.tsx @@ -58,6 +58,7 @@ import { getKeyboardAnimationConfigs, normalizeSnapPoint, print, + floatingPointEquals, } from '../../utilities'; import { DEFAULT_OVER_DRAG_RESISTANCE_FACTOR, @@ -78,7 +79,7 @@ import { DEFAULT_DYNAMIC_SIZING, DEFAULT_ACCESSIBLE, DEFAULT_ACCESSIBILITY_LABEL, - DEFAULT_ACCESSIBILITY_ROLE + DEFAULT_ACCESSIBILITY_ROLE, } from './constants'; import type { BottomSheetMethods, Insets } from '../../types'; import type { BottomSheetProps, AnimateToPositionType } from './types'; @@ -328,7 +329,7 @@ const BottomSheetComponent = forwardRef( // extended position = container height - sheet height const extendedPosition = animatedContainerHeight.value - animatedSheetHeight.value; - if (animatedPosition.value === extendedPosition) + if (floatingPointEquals(animatedPosition.value, extendedPosition)) return SHEET_STATE.EXTENDED; // extended position with keyboard = @@ -344,13 +345,16 @@ const BottomSheetComponent = forwardRef( if ( keyboardBehavior === KEYBOARD_BEHAVIOR.interactive && isInTemporaryPosition.value && - animatedPosition.value === extendedPositionWithKeyboard + floatingPointEquals( + animatedPosition.value, + extendedPositionWithKeyboard + ) ) { return SHEET_STATE.EXTENDED; } // fill parent = 0 - if (animatedPosition.value === 0) { + if (floatingPointEquals(animatedPosition.value, 0)) { return SHEET_STATE.FILL_PARENT; } @@ -633,7 +637,11 @@ const BottomSheetComponent = forwardRef( [_providedOnChange, animatedCurrentIndex] ); const handleOnAnimate = useCallback( - function handleOnAnimate(toPoint: number, source: ANIMATION_SOURCE, snapPoints: number[]) { + function handleOnAnimate( + toPoint: number, + source: ANIMATION_SOURCE, + snapPoints: number[] + ) { const closedPosition = animatedClosedPosition.value; const toIndex = toPoint === closedPosition ? -1 : snapPoints.indexOf(toPoint); @@ -700,10 +708,10 @@ const BottomSheetComponent = forwardRef( configs?: WithTimingConfig | WithSpringConfig ) { if ( - position === animatedPosition.value || + floatingPointEquals(position, animatedPosition.value) || position === undefined || (animatedAnimationState.value === ANIMATION_STATE.RUNNING && - position === animatedNextPosition.value) + floatingPointEquals(position, animatedNextPosition.value)) ) { return; } diff --git a/src/hooks/useGestureEventsHandlersDefault.tsx b/src/hooks/useGestureEventsHandlersDefault.tsx index 450e2acf7..a41cd91b5 100644 --- a/src/hooks/useGestureEventsHandlersDefault.tsx +++ b/src/hooks/useGestureEventsHandlersDefault.tsx @@ -18,6 +18,7 @@ import type { } from '../types'; import { clamp } from '../utilities/clamp'; import { snapPoint } from '../utilities/snapPoint'; +import { floatingPointEquals } from '../utilities'; type GestureEventContextType = { initialPosition: number; @@ -136,7 +137,7 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = if ( source === GESTURE_SOURCE.CONTENT && isScrollableRefreshable.value && - animatedPosition.value === highestSnapPoint + floatingPointEquals(animatedPosition.value, highestSnapPoint) ) { return; } @@ -148,7 +149,10 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = * a negative scrollable content offset when the scrollable is not locked. */ const negativeScrollableContentOffset = - (context.value.initialPosition === highestSnapPoint && + (floatingPointEquals( + context.value.initialPosition, + highestSnapPoint + ) && source === GESTURE_SOURCE.CONTENT) || !context.value.isScrollablePositionLocked ? animatedScrollableContentOffsetY.value * -1 @@ -184,7 +188,7 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = if ( context.value.isScrollablePositionLocked && source === GESTURE_SOURCE.CONTENT && - animatedPosition.value === highestSnapPoint + floatingPointEquals(animatedPosition.value, highestSnapPoint) ) { context.value = { ...context.value, @@ -258,8 +262,10 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = const handleOnEnd: GestureEventHandlerCallbackType = useWorkletCallback( function handleOnEnd(source, { translationY, absoluteY, velocityY }) { const highestSnapPoint = animatedHighestSnapPoint.value; - const isSheetAtHighestSnapPoint = - animatedPosition.value === highestSnapPoint; + const isSheetAtHighestSnapPoint = floatingPointEquals( + animatedPosition.value, + highestSnapPoint + ); /** * if scrollable is refreshable and sheet position at the highest @@ -354,7 +360,7 @@ export const useGestureEventsHandlersDefault: GestureEventsHandlersHookType = * if destination point is the same as the current position, * then no need to perform animation. */ - if (destinationPoint === animatedPosition.value) { + if (floatingPointEquals(destinationPoint, animatedPosition.value)) { return; } diff --git a/src/utilities/floatingPointEquals.ts b/src/utilities/floatingPointEquals.ts new file mode 100644 index 000000000..e4af0e2fa --- /dev/null +++ b/src/utilities/floatingPointEquals.ts @@ -0,0 +1,6 @@ +const EPSILON = 0.1; + +export function floatingPointEquals(valueA: number, valueB: number) { + 'worklet'; + return Math.abs(valueB - valueA) < EPSILON; +} diff --git a/src/utilities/index.ts b/src/utilities/index.ts index a50b4da63..266072ca8 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -3,3 +3,4 @@ export { animate } from './animate'; export { getKeyboardAnimationConfigs } from './getKeyboardAnimationConfigs'; export { print } from './logger'; export { noop, workletNoop } from './noop'; +export { floatingPointEquals } from './floatingPointEquals'; From df1cc1c55cfd5fb887494947cf87676ab6f904a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?avery=20=E2=9C=BF?= Date: Sun, 17 Mar 2024 22:53:40 -0700 Subject: [PATCH 6/6] refactor ref/gestures remove preserveScrollMomentum + scrollBuffer + lockableScrollableContentOffsetY props we're using `preserveScrollMomentum` in the media picker, but i'm removing it because i feel the behavior is actually detrimental to the UX, and to simplify the refactor to scrollEnabled in the next commit. `lockableScrollableContentOffsetY` is removed since it won't be necessary after the scrollEnabled refactor `scrollBuffer` was no longer used. removed custom gesture/scroll handling hooks after refactoring to use scrollEnabled, we can add other props to add custom behaviors if needed. refactored scroll/pan gesture interaction based on https://github.com/software-mansion/react-native-gesture-handler/issues/420#issuecomment-1356861934 and approach from rngh example https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/new_api/bottom_sheet/index.tsx#L87 scrollEnabled inspired by react-native-swipe-modal https://github.com/birdwingo/react-native-swipe-modal --- .../CustomGestureHandling.tsx | 115 --- .../GestureTranslationContext.tsx | 12 - .../useCustomGestureEventsHandlers.ts | 356 --------- .../useCustomScrollEventsHandlers.tsx | 209 ------ example/app/src/screens/index.ts | 7 - src/components/bottomSheet/BottomSheet.tsx | 99 +-- src/components/bottomSheet/types.d.ts | 14 +- .../BottomSheetDraggableView.tsx | 21 +- .../bottomSheetDraggableView/types.d.ts | 1 - .../BottomSheetGestureHandlersProvider.tsx | 18 +- .../types.d.ts | 4 +- .../BottomSheetHandleContainer.tsx | 2 + .../BottomSheetRefreshControl.android.tsx | 5 +- .../bottomSheetRefreshControl/index.ts | 6 +- .../BottomSheetScrollView.tsx | 8 +- .../ScrollableContainer.android.tsx | 13 +- .../ScrollableContainer.tsx | 16 +- .../createBottomSheetScrollableComponent.tsx | 112 ++- .../bottomSheetScrollable/types.d.ts | 30 +- src/constants.ts | 18 - src/contexts/internal.ts | 20 +- src/hooks/index.ts | 2 +- src/hooks/useGestureEventsHandlersDefault.tsx | 676 +++++++++--------- src/hooks/useGestureHandler.ts | 19 + src/hooks/useScrollEventsHandlersDefault.ts | 204 +----- src/hooks/useScrollHandler.ts | 28 +- src/hooks/useScrollable.ts | 58 +- src/hooks/useScrollableSetter.ts | 42 +- src/index.ts | 4 +- src/types.d.ts | 37 +- 30 files changed, 520 insertions(+), 1636 deletions(-) delete mode 100644 example/app/src/screens/advanced/customGestureHandling/CustomGestureHandling.tsx delete mode 100644 example/app/src/screens/advanced/customGestureHandling/GestureTranslationContext.tsx delete mode 100644 example/app/src/screens/advanced/customGestureHandling/useCustomGestureEventsHandlers.ts delete mode 100644 example/app/src/screens/advanced/customGestureHandling/useCustomScrollEventsHandlers.tsx diff --git a/example/app/src/screens/advanced/customGestureHandling/CustomGestureHandling.tsx b/example/app/src/screens/advanced/customGestureHandling/CustomGestureHandling.tsx deleted file mode 100644 index ec3a4ea14..000000000 --- a/example/app/src/screens/advanced/customGestureHandling/CustomGestureHandling.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, { useCallback, useMemo, useRef } from 'react'; -import { StyleSheet, View } from 'react-native'; -import { useAnimatedProps, useSharedValue } from 'react-native-reanimated'; -import BottomSheet, { - BottomSheetScrollView, - SCROLLABLE_STATE, - useBottomSheetInternal, -} from '@gorhom/bottom-sheet'; -import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { Button } from '../../../components/button'; -import { ContactItem } from '../../../components/contactItem'; -import { createContactListMockData } from '../../../utilities/createMockData'; -import { GestureTranslationProvider } from './GestureTranslationContext'; -import { useCustomGestureEventsHandlers } from './useCustomGestureEventsHandlers'; -import { useCustomScrollEventsHandlers } from './useCustomScrollEventsHandlers'; - -const count = 60; - -const CustomGestureHandling = () => { - // refs - const bottomSheetRef = useRef(null); - - // variables - const snapPoints = useMemo(() => ['25%', '75%', '100%'], []); - const gestureTranslationY = useSharedValue(0); - - //#region callbacks - const handleSnapPress = useCallback(index => { - bottomSheetRef.current?.snapToIndex(index); - }, []); - const handleExpandPress = useCallback(() => { - bottomSheetRef.current?.expand(); - }, []); - const handleCollapsePress = useCallback(() => { - bottomSheetRef.current?.collapse(); - }, []); - const handleClosePress = useCallback(() => { - bottomSheetRef.current?.close(); - }, []); - //#endregion - - return ( - -