@gorhom/bottom-sheet
Advanced tools
Comparing version 5.0.0-alpha.9 to 5.0.0-alpha.10
@@ -104,4 +104,3 @@ "use strict"; | ||
topInset, | ||
bottomInset, | ||
children | ||
bottomInset | ||
}); | ||
@@ -130,3 +129,3 @@ } | ||
const animatedContentHeight = (0, _reactNativeReanimated.useSharedValue)(_constants2.INITIAL_CONTAINER_HEIGHT); | ||
const [animatedSnapPoints, animatedDynamicSnapPointIndex] = (0, _hooks.useNormalizedSnapPoints)(_providedSnapPoints, animatedContainerHeight, animatedContentHeight, animatedHandleHeight, enableDynamicSizing, maxDynamicContentSize); | ||
const [animatedSnapPoints, animatedDynamicSnapPointIndex] = (0, _hooks.useAnimatedSnapPoints)(_providedSnapPoints, animatedContainerHeight, animatedContentHeight, animatedHandleHeight, enableDynamicSizing, maxDynamicContentSize); | ||
const animatedHighestSnapPoint = (0, _reactNativeReanimated.useDerivedValue)(() => animatedSnapPoints.value[animatedSnapPoints.value.length - 1], [animatedSnapPoints.value]); | ||
@@ -178,2 +177,3 @@ const animatedClosedPosition = (0, _reactNativeReanimated.useDerivedValue)(() => { | ||
const isForcedClosing = (0, _reactNativeReanimated.useSharedValue)(false); | ||
const animatedContainerHeightDidChange = (0, _reactNativeReanimated.useSharedValue)(false); | ||
@@ -335,53 +335,2 @@ // gesture | ||
//#region private methods | ||
/** | ||
* Calculate the next position based on keyboard state. | ||
*/ | ||
const getNextPosition = (0, _reactNativeReanimated.useWorkletCallback)(function getNextPosition() { | ||
'worklet'; | ||
const currentIndex = animatedCurrentIndex.value; | ||
const snapPoints = animatedSnapPoints.value; | ||
const keyboardState = animatedKeyboardState.value; | ||
const highestSnapPoint = animatedHighestSnapPoint.value; | ||
/** | ||
* Handle restore sheet position on blur | ||
*/ | ||
if (keyboardBlurBehavior === _constants.KEYBOARD_BLUR_BEHAVIOR.restore && keyboardState === _constants.KEYBOARD_STATE.HIDDEN && animatedContentGestureState.value !== _reactNativeGestureHandler.State.ACTIVE && animatedHandleGestureState.value !== _reactNativeGestureHandler.State.ACTIVE) { | ||
isInTemporaryPosition.value = false; | ||
const nextPosition = snapPoints[currentIndex]; | ||
return nextPosition; | ||
} | ||
/** | ||
* Handle extend behavior | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.extend && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
return highestSnapPoint; | ||
} | ||
/** | ||
* Handle full screen behavior | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.fillParent && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
return 0; | ||
} | ||
/** | ||
* handle interactive behavior | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.interactive && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
const keyboardHeightInContainer = animatedKeyboardHeightInContainer.value; | ||
return Math.max(0, highestSnapPoint - keyboardHeightInContainer); | ||
} | ||
if (isInTemporaryPosition.value) { | ||
return animatedPosition.value; | ||
} | ||
if (!isAnimatedOnMount.value) { | ||
return snapPoints[_providedIndex]; | ||
} | ||
return snapPoints[currentIndex]; | ||
}, [animatedContentGestureState, animatedCurrentIndex, animatedHandleGestureState, animatedHighestSnapPoint, animatedKeyboardHeightInContainer, animatedKeyboardState, animatedPosition, animatedSnapPoints, isInTemporaryPosition, isAnimatedOnMount, keyboardBehavior, keyboardBlurBehavior, _providedIndex]); | ||
const handleOnChange = (0, _react.useCallback)(function handleOnChange(index, position) { | ||
@@ -391,2 +340,3 @@ (0, _utilities.print)({ | ||
method: handleOnChange.name, | ||
category: 'callback', | ||
params: { | ||
@@ -397,14 +347,14 @@ index, | ||
}); | ||
if (_providedOnChange) { | ||
_providedOnChange(index, position, index === animatedDynamicSnapPointIndex.value ? _constants.SNAP_POINT_TYPE.DYNAMIC : _constants.SNAP_POINT_TYPE.PROVIDED); | ||
if (!_providedOnChange) { | ||
return; | ||
} | ||
_providedOnChange(index, position, index === animatedDynamicSnapPointIndex.value ? _constants.SNAP_POINT_TYPE.DYNAMIC : _constants.SNAP_POINT_TYPE.PROVIDED); | ||
}, [_providedOnChange, animatedCurrentIndex, animatedDynamicSnapPointIndex]); | ||
const handleOnAnimate = (0, _react.useCallback)(function handleOnAnimate(toPoint) { | ||
const snapPoints = animatedSnapPoints.value; | ||
const toIndex = snapPoints.indexOf(toPoint); | ||
const handleOnAnimate = (0, _react.useCallback)(function handleOnAnimate(targetIndex) { | ||
(0, _utilities.print)({ | ||
component: BottomSheet.name, | ||
method: handleOnAnimate.name, | ||
category: 'callback', | ||
params: { | ||
toIndex, | ||
toIndex: targetIndex, | ||
fromIndex: animatedCurrentIndex.value | ||
@@ -416,6 +366,6 @@ } | ||
} | ||
if (toIndex !== animatedCurrentIndex.value) { | ||
_providedOnAnimate(animatedCurrentIndex.value, toIndex); | ||
if (targetIndex !== animatedCurrentIndex.value) { | ||
_providedOnAnimate(animatedCurrentIndex.value, targetIndex); | ||
} | ||
}, [_providedOnAnimate, animatedSnapPoints, animatedCurrentIndex]); | ||
}, [_providedOnAnimate, animatedCurrentIndex]); | ||
//#endregion | ||
@@ -444,2 +394,7 @@ | ||
}); | ||
if (animatedAnimationSource.value === _constants.ANIMATION_SOURCE.MOUNT) { | ||
isAnimatedOnMount.value = true; | ||
} | ||
// reset values | ||
animatedAnimationSource.value = _constants.ANIMATION_SOURCE.NONE; | ||
@@ -449,7 +404,5 @@ animatedAnimationState.value = _constants.ANIMATION_STATE.STOPPED; | ||
animatedNextPositionIndex.value = _constants2.INITIAL_VALUE; | ||
animatedContainerHeightDidChange.value = false; | ||
}); | ||
const animateToPosition = (0, _reactNativeReanimated.useWorkletCallback)(function animateToPosition(position, source, velocity = 0, configs) { | ||
if (position === animatedPosition.value || position === undefined || animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING && position === animatedNextPosition.value) { | ||
return; | ||
} | ||
(0, _reactNativeReanimated.runOnJS)(_utilities.print)({ | ||
@@ -460,7 +413,8 @@ component: BottomSheet.name, | ||
currentPosition: animatedPosition.value, | ||
nextPosition: position, | ||
velocity, | ||
source | ||
nextPosition: position | ||
} | ||
}); | ||
if (position === animatedPosition.value || position === undefined || animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING && position === animatedNextPosition.value) { | ||
return; | ||
} | ||
stopAnimation(); | ||
@@ -478,8 +432,16 @@ | ||
animatedNextPosition.value = position; | ||
animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(position); | ||
/** | ||
* offset the position if keyboard is shown | ||
*/ | ||
let offset = 0; | ||
if (animatedKeyboardState.value === _constants.KEYBOARD_STATE.SHOWN) { | ||
offset = animatedKeyboardHeightInContainer.value; | ||
} | ||
animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(position + offset); | ||
/** | ||
* fire `onAnimate` callback | ||
*/ | ||
(0, _reactNativeReanimated.runOnJS)(handleOnAnimate)(position); | ||
(0, _reactNativeReanimated.runOnJS)(handleOnAnimate)(animatedNextPositionIndex.value); | ||
@@ -521,9 +483,160 @@ /** | ||
/** | ||
* set position. | ||
*/ | ||
// set values | ||
animatedPosition.value = targetPosition; | ||
animatedContainerHeightDidChange.value = false; | ||
}, []); | ||
//#endregion | ||
//#region private methods | ||
/** | ||
* Calculate and evaluate the current position based on multiple | ||
* local states. | ||
*/ | ||
const getEvaluatedPosition = (0, _reactNativeReanimated.useWorkletCallback)(function getEvaluatedPosition(source) { | ||
'worklet'; | ||
const currentIndex = animatedCurrentIndex.value; | ||
const snapPoints = animatedSnapPoints.value; | ||
const keyboardState = animatedKeyboardState.value; | ||
const highestSnapPoint = animatedHighestSnapPoint.value; | ||
/** | ||
* if the keyboard blur behavior is restore and keyboard is hidden, | ||
* then we return the previous snap point. | ||
*/ | ||
if (source === _constants.ANIMATION_SOURCE.KEYBOARD && keyboardBlurBehavior === _constants.KEYBOARD_BLUR_BEHAVIOR.restore && keyboardState === _constants.KEYBOARD_STATE.HIDDEN && animatedContentGestureState.value !== _reactNativeGestureHandler.State.ACTIVE && animatedHandleGestureState.value !== _reactNativeGestureHandler.State.ACTIVE) { | ||
isInTemporaryPosition.value = false; | ||
const nextPosition = snapPoints[currentIndex]; | ||
return nextPosition; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is extend and keyboard is shown, | ||
* then we return the heights snap point. | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.extend && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
return highestSnapPoint; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is fill parent and keyboard is shown, | ||
* then we return 0 ( full screen ). | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.fillParent && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
return 0; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is interactive and keyboard is shown, | ||
* then we return the heights points minus the keyboard in container height. | ||
*/ | ||
if (keyboardBehavior === _constants.KEYBOARD_BEHAVIOR.interactive && keyboardState === _constants.KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
const keyboardHeightInContainer = animatedKeyboardHeightInContainer.value; | ||
return Math.max(0, highestSnapPoint - keyboardHeightInContainer); | ||
} | ||
/** | ||
* if the bottom sheet is in temporary position, then we return | ||
* the current position. | ||
*/ | ||
if (isInTemporaryPosition.value) { | ||
return animatedPosition.value; | ||
} | ||
/** | ||
* if the bottom sheet did not animate on mount, | ||
* then we return the provided index or the closed position. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
return _providedIndex === -1 ? animatedClosedPosition.value : snapPoints[_providedIndex]; | ||
} | ||
/** | ||
* return the current index position. | ||
*/ | ||
return snapPoints[currentIndex]; | ||
}, [animatedContentGestureState, animatedCurrentIndex, animatedHandleGestureState, animatedHighestSnapPoint, animatedKeyboardHeightInContainer, animatedKeyboardState, animatedPosition, animatedSnapPoints, isInTemporaryPosition, isAnimatedOnMount, keyboardBehavior, keyboardBlurBehavior, _providedIndex]); | ||
/** | ||
* Evaluate the bottom sheet position based based on a event source and other local states. | ||
*/ | ||
const evaluatePosition = (0, _reactNativeReanimated.useWorkletCallback)(function evaluatePosition(source, animationConfigs) { | ||
/** | ||
* when evaluating the position while layout is not calculated, then we early exit till it is. | ||
*/ | ||
if (!isLayoutCalculated.value) { | ||
return; | ||
} | ||
const proposedPosition = getEvaluatedPosition(source); | ||
/** | ||
* when evaluating the position while the mount animation not been handled, | ||
* then we evaluate on mount use cases. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
/** | ||
* if animate on mount is set to true, then we animate to the propose position, | ||
* else, we set the position with out animation. | ||
*/ | ||
if (animateOnMount) { | ||
animateToPosition(proposedPosition, _constants.ANIMATION_SOURCE.MOUNT, undefined, animationConfigs); | ||
} else { | ||
setToPosition(proposedPosition); | ||
isAnimatedOnMount.value = true; | ||
} | ||
return; | ||
} | ||
/** | ||
* when evaluating the position while the bottom sheet is animating. | ||
*/ | ||
if (animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING) { | ||
/** | ||
* when evaluating the position while the bottom sheet is | ||
* closing, then we force closing the bottom sheet with no animation. | ||
*/ | ||
if (animatedNextPositionIndex.value === -1) { | ||
setToPosition(animatedClosedPosition.value); | ||
return; | ||
} | ||
/** | ||
* when evaluating the position while it's animating to | ||
* a position other than the current position, then we | ||
* restart the animation. | ||
*/ | ||
if (animatedNextPositionIndex.value !== animatedCurrentIndex.value) { | ||
animateToPosition(animatedNextPosition.value, source, undefined, animationConfigs); | ||
return; | ||
} | ||
} | ||
/** | ||
* when evaluating the position while the bottom sheet is in closed | ||
* position and not animating, we re-set the position to closed position. | ||
*/ | ||
if (animatedAnimationState.value !== _constants.ANIMATION_STATE.RUNNING && animatedCurrentIndex.value === -1) { | ||
setToPosition(animatedClosedPosition.value); | ||
return; | ||
} | ||
/** | ||
* when evaluating the position after the container resize, then we | ||
* force the bottom sheet to the proposed position with no | ||
* animation. | ||
*/ | ||
if (animatedContainerHeightDidChange.value) { | ||
setToPosition(proposedPosition); | ||
return; | ||
} | ||
/** | ||
* we fall back to the proposed position. | ||
*/ | ||
animateToPosition(proposedPosition, source, undefined, animationConfigs); | ||
}, [getEvaluatedPosition, animateToPosition, setToPosition]); | ||
//#endregion | ||
//#region public methods | ||
@@ -792,56 +905,11 @@ const handleSnapToIndex = (0, _react.useCallback)(function handleSnapToIndex(index, animationConfigs) { | ||
//#region effects | ||
/** | ||
* React to `isLayoutCalculated` change, to insure that the sheet will | ||
* appears/mounts only when all layout is been calculated. | ||
* | ||
* @alias OnMount | ||
*/ | ||
(0, _reactNativeReanimated.useAnimatedReaction)(() => isLayoutCalculated.value, _isLayoutCalculated => { | ||
/** | ||
* exit method if: | ||
* - layout is not calculated yet. | ||
* - already did animate on mount. | ||
*/ | ||
if (!_isLayoutCalculated || isAnimatedOnMount.value) { | ||
(0, _reactNativeReanimated.useAnimatedReaction)(() => animatedContainerHeight.value, (result, previous) => { | ||
if (result === _constants2.INITIAL_CONTAINER_HEIGHT) { | ||
return; | ||
} | ||
let nextPosition; | ||
if (_providedIndex === -1) { | ||
nextPosition = animatedClosedPosition.value; | ||
animatedNextPositionIndex.value = -1; | ||
} else { | ||
nextPosition = getNextPosition(); | ||
} | ||
(0, _reactNativeReanimated.runOnJS)(_utilities.print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnMount', | ||
params: { | ||
isLayoutCalculated: _isLayoutCalculated, | ||
animatedSnapPoints: animatedSnapPoints.value, | ||
nextPosition | ||
} | ||
}); | ||
animatedContainerHeightDidChange.value = result !== previous; | ||
}); | ||
/** | ||
* here we exit method early because the next position | ||
* is out of the screen, this happens when `snapPoints` | ||
* still being calculated. | ||
*/ | ||
if (nextPosition === _constants2.INITIAL_POSITION || nextPosition === animatedClosedPosition.value) { | ||
isAnimatedOnMount.value = true; | ||
animatedCurrentIndex.value = _providedIndex; | ||
return; | ||
} | ||
if (animateOnMount) { | ||
requestAnimationFrame(() => { | ||
animateToPosition(nextPosition, _constants.ANIMATION_SOURCE.MOUNT); | ||
}); | ||
} else { | ||
animatedPosition.value = nextPosition; | ||
} | ||
isAnimatedOnMount.value = true; | ||
}, [_providedIndex, animateOnMount]); | ||
/** | ||
* React to `snapPoints` change, to insure that the sheet position reflect | ||
* Reaction to the `snapPoints` change, to insure that the sheet position reflect | ||
* to the current point correctly. | ||
@@ -851,25 +919,15 @@ * | ||
*/ | ||
(0, _reactNativeReanimated.useAnimatedReaction)(() => ({ | ||
snapPoints: animatedSnapPoints.value, | ||
containerHeight: animatedContainerHeight.value | ||
}), (result, _previousResult) => { | ||
const { | ||
snapPoints, | ||
containerHeight | ||
} = result; | ||
const _previousSnapPoints = _previousResult?.snapPoints; | ||
const _previousContainerHeight = _previousResult?.containerHeight; | ||
let nextPosition; | ||
let animationConfig; | ||
let animationSource = _constants.ANIMATION_SOURCE.SNAP_POINT_CHANGE; | ||
(0, _reactNativeReanimated.useAnimatedReaction)(() => animatedSnapPoints.value, (result, previous) => { | ||
/** | ||
* if the bottom sheet is closing and the container gets resized, | ||
* then we restart the closing animation to the new position. | ||
* if values did not change, and did handle on mount animation | ||
* then we early exit the method. | ||
*/ | ||
if (animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value === -1 && _previousContainerHeight !== containerHeight) { | ||
setToPosition(containerHeight); | ||
if (JSON.stringify(result) === JSON.stringify(previous) && isAnimatedOnMount.value) { | ||
return; | ||
} | ||
if (JSON.stringify(snapPoints) === JSON.stringify(_previousSnapPoints) || !isLayoutCalculated.value || !isAnimatedOnMount.value || containerHeight <= 0) { | ||
/** | ||
* if layout is not calculated yet, then we exit the method. | ||
*/ | ||
if (!isLayoutCalculated.value) { | ||
return; | ||
@@ -880,34 +938,12 @@ } | ||
method: 'useAnimatedReaction::OnSnapPointChange', | ||
category: 'effect', | ||
params: { | ||
snapPoints | ||
result | ||
} | ||
}); | ||
evaluatePosition(_constants.ANIMATION_SOURCE.SNAP_POINT_CHANGE); | ||
}, [isLayoutCalculated.value, animatedSnapPoints.value]); | ||
/** | ||
* if snap points changed while sheet is animating, then | ||
* we stop the animation and animate to the updated point. | ||
*/ | ||
if (animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value !== animatedCurrentIndex.value) { | ||
nextPosition = animatedNextPositionIndex.value !== -1 ? snapPoints[animatedNextPositionIndex.value] : animatedNextPosition.value; | ||
} else if (animatedCurrentIndex.value === -1) { | ||
nextPosition = animatedClosedPosition.value; | ||
} else if (isInTemporaryPosition.value) { | ||
nextPosition = getNextPosition(); | ||
} else { | ||
nextPosition = snapPoints[animatedCurrentIndex.value]; | ||
/** | ||
* if snap points changes because of the container height change, | ||
* then we set the new position without animation. | ||
*/ | ||
if (containerHeight !== _previousContainerHeight) { | ||
setToPosition(nextPosition); | ||
return; | ||
} | ||
} | ||
animateToPosition(nextPosition, animationSource, 0, animationConfig); | ||
}, []); | ||
/** | ||
* React to keyboard appearance state. | ||
* Reaction to the keyboard state change. | ||
* | ||
@@ -928,10 +964,12 @@ * @alias OnKeyboardStateChange | ||
/** | ||
* Calculate the keyboard height in the container. | ||
* if keyboard state is equal to the previous state, then exit the method | ||
*/ | ||
animatedKeyboardHeightInContainer.value = _keyboardHeight === 0 ? 0 : $modal ? Math.abs(_keyboardHeight - Math.abs(bottomInset - animatedContainerOffset.value.bottom)) : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom); | ||
if (_keyboardState === _previousKeyboardState && _keyboardHeight === _previousKeyboardHeight) { | ||
return; | ||
} | ||
/** | ||
* if keyboard state is equal to the previous state, then exit the method | ||
* if state is undetermined, then we early exit. | ||
*/ | ||
if (_keyboardState === _previousKeyboardState && _keyboardHeight === _previousKeyboardHeight) { | ||
if (_keyboardState === _constants.KEYBOARD_STATE.UNDETERMINED) { | ||
return; | ||
@@ -941,13 +979,27 @@ } | ||
/** | ||
* if user is interacting with sheet, then exit the method | ||
* if keyboard is hidden by customer gesture, then we early exit. | ||
*/ | ||
const hasActiveGesture = animatedContentGestureState.value === _reactNativeGestureHandler.State.ACTIVE || animatedContentGestureState.value === _reactNativeGestureHandler.State.BEGAN || animatedHandleGestureState.value === _reactNativeGestureHandler.State.ACTIVE || animatedHandleGestureState.value === _reactNativeGestureHandler.State.BEGAN; | ||
if (hasActiveGesture) { | ||
if (_keyboardState === _constants.KEYBOARD_STATE.HIDDEN && animatedAnimationState.value === _constants.ANIMATION_STATE.RUNNING && animatedAnimationSource.value === _constants.ANIMATION_SOURCE.GESTURE) { | ||
return; | ||
} | ||
(0, _reactNativeReanimated.runOnJS)(_utilities.print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnKeyboardStateChange', | ||
category: 'effect', | ||
params: { | ||
keyboardState: _keyboardState, | ||
keyboardHeight: _keyboardHeight | ||
} | ||
}); | ||
/** | ||
* if sheet not animated on mount yet, then exit the method | ||
* Calculate the keyboard height in the container. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
animatedKeyboardHeightInContainer.value = _keyboardHeight === 0 ? 0 : $modal ? Math.abs(_keyboardHeight - Math.abs(bottomInset - animatedContainerOffset.value.bottom)) : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom); | ||
/** | ||
* if user is interacting with sheet, then exit the method | ||
*/ | ||
const hasActiveGesture = animatedContentGestureState.value === _reactNativeGestureHandler.State.ACTIVE || animatedContentGestureState.value === _reactNativeGestureHandler.State.BEGAN || animatedHandleGestureState.value === _reactNativeGestureHandler.State.ACTIVE || animatedHandleGestureState.value === _reactNativeGestureHandler.State.BEGAN; | ||
if (hasActiveGesture) { | ||
return; | ||
@@ -970,14 +1022,5 @@ } | ||
} | ||
(0, _reactNativeReanimated.runOnJS)(_utilities.print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnKeyboardStateChange', | ||
params: { | ||
keyboardState: _keyboardState, | ||
keyboardHeight: _keyboardHeight | ||
} | ||
}); | ||
let animationConfigs = (0, _utilities.getKeyboardAnimationConfigs)(keyboardAnimationEasing.value, keyboardAnimationDuration.value); | ||
const nextPosition = getNextPosition(); | ||
animateToPosition(nextPosition, _constants.ANIMATION_SOURCE.KEYBOARD, 0, animationConfigs); | ||
}, [$modal, bottomInset, keyboardBehavior, keyboardBlurBehavior, android_keyboardInputMode, animatedContainerOffset, getNextPosition]); | ||
evaluatePosition(_constants.ANIMATION_SOURCE.KEYBOARD, animationConfigs); | ||
}, [$modal, bottomInset, keyboardBehavior, keyboardBlurBehavior, android_keyboardInputMode, animatedContainerOffset, getEvaluatedPosition]); | ||
@@ -1062,2 +1105,3 @@ /** | ||
method: 'useAnimatedReaction::OnChange', | ||
category: 'effect', | ||
params: { | ||
@@ -1079,2 +1123,3 @@ animatedCurrentIndex: animatedCurrentIndex.value, | ||
method: 'useAnimatedReaction::onClose', | ||
category: 'effect', | ||
params: { | ||
@@ -1081,0 +1126,0 @@ animatedCurrentIndex: animatedCurrentIndex.value, |
@@ -43,2 +43,3 @@ "use strict"; | ||
containerRef.current?.measure((_x, _y, _width, _height, _pageX, pageY) => { | ||
if (!containerOffset.value) return; | ||
containerOffset.value = { | ||
@@ -54,2 +55,3 @@ top: pageY ?? 0, | ||
method: 'handleContainerLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -56,0 +58,0 @@ height |
@@ -92,2 +92,3 @@ "use strict"; | ||
method: 'handleContainerLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -94,0 +95,0 @@ height |
@@ -268,2 +268,3 @@ "use strict"; | ||
method: handleBottomSheetOnChange.name, | ||
category: 'callback', | ||
params: { | ||
@@ -283,2 +284,3 @@ minimized: minimized.current, | ||
method: handleBottomSheetOnClose.name, | ||
category: 'callback', | ||
params: { | ||
@@ -285,0 +287,0 @@ minimized: minimized.current, |
@@ -17,5 +17,3 @@ "use strict"; | ||
BottomSheetFlatList.displayName = 'BottomSheetFlatList'; | ||
//@ts-ignore | ||
BottomSheetFlatList.$bottomSheetIntegrated = true; | ||
var _default = exports.default = BottomSheetFlatList; | ||
//# sourceMappingURL=BottomSheetFlatList.js.map |
@@ -17,5 +17,3 @@ "use strict"; | ||
BottomSheetScrollView.displayName = 'BottomSheetScrollView'; | ||
//@ts-ignore | ||
BottomSheetScrollView.$bottomSheetIntegrated = true; | ||
var _default = exports.default = BottomSheetScrollView; | ||
//# sourceMappingURL=BottomSheetScrollView.js.map |
@@ -17,5 +17,3 @@ "use strict"; | ||
BottomSheetSectionList.displayName = 'BottomSheetSectionList'; | ||
//@ts-ignore | ||
BottomSheetSectionList.$bottomSheetIntegrated = true; | ||
var _default = exports.default = BottomSheetSectionList; | ||
//# sourceMappingURL=BottomSheetSectionList.js.map |
@@ -17,5 +17,3 @@ "use strict"; | ||
BottomSheetVirtualizedList.displayName = 'BottomSheetVirtualizedList'; | ||
//@ts-ignore | ||
BottomSheetVirtualizedList.$bottomSheetIntegrated = true; | ||
var _default = exports.default = BottomSheetVirtualizedList; | ||
//# sourceMappingURL=BottomSheetVirtualizedList.js.map |
@@ -67,2 +67,3 @@ "use strict"; | ||
method: 'handleLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -89,5 +90,3 @@ height: event.nativeEvent.layout.height | ||
BottomSheetView.displayName = 'BottomSheetView'; | ||
//@ts-ignore | ||
BottomSheetView.$bottomSheetIntegrated = true; | ||
var _default = exports.default = BottomSheetView; | ||
//# sourceMappingURL=BottomSheetView.js.map |
@@ -6,2 +6,8 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "useAnimatedSnapPoints", { | ||
enumerable: true, | ||
get: function () { | ||
return _useAnimatedSnapPoints.useAnimatedSnapPoints; | ||
} | ||
}); | ||
Object.defineProperty(exports, "useBottomSheet", { | ||
@@ -55,8 +61,2 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(exports, "useNormalizedSnapPoints", { | ||
enumerable: true, | ||
get: function () { | ||
return _useNormalizedSnapPoints.useNormalizedSnapPoints; | ||
} | ||
}); | ||
Object.defineProperty(exports, "usePropsValidator", { | ||
@@ -110,5 +110,5 @@ enumerable: true, | ||
var _usePropsValidator = require("./usePropsValidator"); | ||
var _useNormalizedSnapPoints = require("./useNormalizedSnapPoints"); | ||
var _useAnimatedSnapPoints = require("./useAnimatedSnapPoints"); | ||
var _useReactiveSharedValue = require("./useReactiveSharedValue"); | ||
var _useBottomSheetGestureHandlers = require("./useBottomSheetGestureHandlers"); | ||
//# sourceMappingURL=index.js.map |
@@ -21,4 +21,3 @@ "use strict"; | ||
topInset, | ||
bottomInset, | ||
children | ||
bottomInset | ||
}) => { | ||
@@ -48,11 +47,4 @@ (0, _react.useMemo)(() => { | ||
}, [index, snapPoints, topInset, bottomInset, enableDynamicSizing]); | ||
(0, _react.useMemo)(() => { | ||
(0, _invariant.default)(enableDynamicSizing && children && | ||
// @ts-ignore | ||
children.type && | ||
// @ts-ignore | ||
children.type.$bottomSheetIntegrated || !enableDynamicSizing, `'enableDynamicSizing' is enabled but children type is not integrated with the library !` + ` expected children types are\n- BottomSheetView\n- BottomSheetFlatList\n- BottomSheetScrollView\n- BottomSheetSectionList\n- BottomSheetVirtualizedList`); | ||
}, [enableDynamicSizing, children]); | ||
}; | ||
exports.usePropsValidator = usePropsValidator; | ||
//# sourceMappingURL=usePropsValidator.js.map |
@@ -7,4 +7,5 @@ "use strict"; | ||
exports.print = exports.enableLogging = void 0; | ||
let isLoggingEnabled = false; | ||
const enableLogging = () => { | ||
let _isLoggingEnabled = false; | ||
let _excludeCategories; | ||
const enableLogging = excludeCategories => { | ||
if (!__DEV__) { | ||
@@ -14,3 +15,4 @@ console.warn('[BottomSheet] could not enable logging on production!'); | ||
} | ||
isLoggingEnabled = true; | ||
_isLoggingEnabled = true; | ||
_excludeCategories = excludeCategories; | ||
}; | ||
@@ -24,7 +26,11 @@ exports.enableLogging = enableLogging; | ||
method, | ||
params | ||
params, | ||
category | ||
}) => { | ||
if (!isLoggingEnabled) { | ||
if (!_isLoggingEnabled) { | ||
return; | ||
} | ||
if (category && _excludeCategories && _excludeCategories.includes(category)) { | ||
return; | ||
} | ||
let message = ''; | ||
@@ -31,0 +37,0 @@ if (typeof params === 'object') { |
@@ -6,3 +6,3 @@ import React, { useMemo, useCallback, forwardRef, useImperativeHandle, memo, useEffect } from 'react'; | ||
import { State } from 'react-native-gesture-handler'; | ||
import { useScrollable, usePropsValidator, useReactiveSharedValue, useNormalizedSnapPoints, useKeyboard } from '../../hooks'; | ||
import { useScrollable, usePropsValidator, useReactiveSharedValue, useAnimatedSnapPoints, useKeyboard } from '../../hooks'; | ||
import { BottomSheetInternalProvider, BottomSheetProvider } from '../../contexts'; | ||
@@ -95,4 +95,3 @@ import BottomSheetContainer from '../bottomSheetContainer'; | ||
topInset, | ||
bottomInset, | ||
children | ||
bottomInset | ||
}); | ||
@@ -121,3 +120,3 @@ } | ||
const animatedContentHeight = useSharedValue(INITIAL_CONTAINER_HEIGHT); | ||
const [animatedSnapPoints, animatedDynamicSnapPointIndex] = useNormalizedSnapPoints(_providedSnapPoints, animatedContainerHeight, animatedContentHeight, animatedHandleHeight, enableDynamicSizing, maxDynamicContentSize); | ||
const [animatedSnapPoints, animatedDynamicSnapPointIndex] = useAnimatedSnapPoints(_providedSnapPoints, animatedContainerHeight, animatedContentHeight, animatedHandleHeight, enableDynamicSizing, maxDynamicContentSize); | ||
const animatedHighestSnapPoint = useDerivedValue(() => animatedSnapPoints.value[animatedSnapPoints.value.length - 1], [animatedSnapPoints.value]); | ||
@@ -169,2 +168,3 @@ const animatedClosedPosition = useDerivedValue(() => { | ||
const isForcedClosing = useSharedValue(false); | ||
const animatedContainerHeightDidChange = useSharedValue(false); | ||
@@ -326,53 +326,2 @@ // gesture | ||
//#region private methods | ||
/** | ||
* Calculate the next position based on keyboard state. | ||
*/ | ||
const getNextPosition = useWorkletCallback(function getNextPosition() { | ||
'worklet'; | ||
const currentIndex = animatedCurrentIndex.value; | ||
const snapPoints = animatedSnapPoints.value; | ||
const keyboardState = animatedKeyboardState.value; | ||
const highestSnapPoint = animatedHighestSnapPoint.value; | ||
/** | ||
* Handle restore sheet position on blur | ||
*/ | ||
if (keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.restore && keyboardState === KEYBOARD_STATE.HIDDEN && animatedContentGestureState.value !== State.ACTIVE && animatedHandleGestureState.value !== State.ACTIVE) { | ||
isInTemporaryPosition.value = false; | ||
const nextPosition = snapPoints[currentIndex]; | ||
return nextPosition; | ||
} | ||
/** | ||
* Handle extend behavior | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.extend && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
return highestSnapPoint; | ||
} | ||
/** | ||
* Handle full screen behavior | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.fillParent && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
return 0; | ||
} | ||
/** | ||
* handle interactive behavior | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.interactive && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
const keyboardHeightInContainer = animatedKeyboardHeightInContainer.value; | ||
return Math.max(0, highestSnapPoint - keyboardHeightInContainer); | ||
} | ||
if (isInTemporaryPosition.value) { | ||
return animatedPosition.value; | ||
} | ||
if (!isAnimatedOnMount.value) { | ||
return snapPoints[_providedIndex]; | ||
} | ||
return snapPoints[currentIndex]; | ||
}, [animatedContentGestureState, animatedCurrentIndex, animatedHandleGestureState, animatedHighestSnapPoint, animatedKeyboardHeightInContainer, animatedKeyboardState, animatedPosition, animatedSnapPoints, isInTemporaryPosition, isAnimatedOnMount, keyboardBehavior, keyboardBlurBehavior, _providedIndex]); | ||
const handleOnChange = useCallback(function handleOnChange(index, position) { | ||
@@ -382,2 +331,3 @@ print({ | ||
method: handleOnChange.name, | ||
category: 'callback', | ||
params: { | ||
@@ -388,14 +338,14 @@ index, | ||
}); | ||
if (_providedOnChange) { | ||
_providedOnChange(index, position, index === animatedDynamicSnapPointIndex.value ? SNAP_POINT_TYPE.DYNAMIC : SNAP_POINT_TYPE.PROVIDED); | ||
if (!_providedOnChange) { | ||
return; | ||
} | ||
_providedOnChange(index, position, index === animatedDynamicSnapPointIndex.value ? SNAP_POINT_TYPE.DYNAMIC : SNAP_POINT_TYPE.PROVIDED); | ||
}, [_providedOnChange, animatedCurrentIndex, animatedDynamicSnapPointIndex]); | ||
const handleOnAnimate = useCallback(function handleOnAnimate(toPoint) { | ||
const snapPoints = animatedSnapPoints.value; | ||
const toIndex = snapPoints.indexOf(toPoint); | ||
const handleOnAnimate = useCallback(function handleOnAnimate(targetIndex) { | ||
print({ | ||
component: BottomSheet.name, | ||
method: handleOnAnimate.name, | ||
category: 'callback', | ||
params: { | ||
toIndex, | ||
toIndex: targetIndex, | ||
fromIndex: animatedCurrentIndex.value | ||
@@ -407,6 +357,6 @@ } | ||
} | ||
if (toIndex !== animatedCurrentIndex.value) { | ||
_providedOnAnimate(animatedCurrentIndex.value, toIndex); | ||
if (targetIndex !== animatedCurrentIndex.value) { | ||
_providedOnAnimate(animatedCurrentIndex.value, targetIndex); | ||
} | ||
}, [_providedOnAnimate, animatedSnapPoints, animatedCurrentIndex]); | ||
}, [_providedOnAnimate, animatedCurrentIndex]); | ||
//#endregion | ||
@@ -435,2 +385,7 @@ | ||
}); | ||
if (animatedAnimationSource.value === ANIMATION_SOURCE.MOUNT) { | ||
isAnimatedOnMount.value = true; | ||
} | ||
// reset values | ||
animatedAnimationSource.value = ANIMATION_SOURCE.NONE; | ||
@@ -440,7 +395,5 @@ animatedAnimationState.value = ANIMATION_STATE.STOPPED; | ||
animatedNextPositionIndex.value = INITIAL_VALUE; | ||
animatedContainerHeightDidChange.value = false; | ||
}); | ||
const animateToPosition = useWorkletCallback(function animateToPosition(position, source, velocity = 0, configs) { | ||
if (position === animatedPosition.value || position === undefined || animatedAnimationState.value === ANIMATION_STATE.RUNNING && position === animatedNextPosition.value) { | ||
return; | ||
} | ||
runOnJS(print)({ | ||
@@ -451,7 +404,8 @@ component: BottomSheet.name, | ||
currentPosition: animatedPosition.value, | ||
nextPosition: position, | ||
velocity, | ||
source | ||
nextPosition: position | ||
} | ||
}); | ||
if (position === animatedPosition.value || position === undefined || animatedAnimationState.value === ANIMATION_STATE.RUNNING && position === animatedNextPosition.value) { | ||
return; | ||
} | ||
stopAnimation(); | ||
@@ -469,8 +423,16 @@ | ||
animatedNextPosition.value = position; | ||
animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(position); | ||
/** | ||
* offset the position if keyboard is shown | ||
*/ | ||
let offset = 0; | ||
if (animatedKeyboardState.value === KEYBOARD_STATE.SHOWN) { | ||
offset = animatedKeyboardHeightInContainer.value; | ||
} | ||
animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(position + offset); | ||
/** | ||
* fire `onAnimate` callback | ||
*/ | ||
runOnJS(handleOnAnimate)(position); | ||
runOnJS(handleOnAnimate)(animatedNextPositionIndex.value); | ||
@@ -512,9 +474,160 @@ /** | ||
/** | ||
* set position. | ||
*/ | ||
// set values | ||
animatedPosition.value = targetPosition; | ||
animatedContainerHeightDidChange.value = false; | ||
}, []); | ||
//#endregion | ||
//#region private methods | ||
/** | ||
* Calculate and evaluate the current position based on multiple | ||
* local states. | ||
*/ | ||
const getEvaluatedPosition = useWorkletCallback(function getEvaluatedPosition(source) { | ||
'worklet'; | ||
const currentIndex = animatedCurrentIndex.value; | ||
const snapPoints = animatedSnapPoints.value; | ||
const keyboardState = animatedKeyboardState.value; | ||
const highestSnapPoint = animatedHighestSnapPoint.value; | ||
/** | ||
* if the keyboard blur behavior is restore and keyboard is hidden, | ||
* then we return the previous snap point. | ||
*/ | ||
if (source === ANIMATION_SOURCE.KEYBOARD && keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.restore && keyboardState === KEYBOARD_STATE.HIDDEN && animatedContentGestureState.value !== State.ACTIVE && animatedHandleGestureState.value !== State.ACTIVE) { | ||
isInTemporaryPosition.value = false; | ||
const nextPosition = snapPoints[currentIndex]; | ||
return nextPosition; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is extend and keyboard is shown, | ||
* then we return the heights snap point. | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.extend && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
return highestSnapPoint; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is fill parent and keyboard is shown, | ||
* then we return 0 ( full screen ). | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.fillParent && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
return 0; | ||
} | ||
/** | ||
* if the keyboard appearance behavior is interactive and keyboard is shown, | ||
* then we return the heights points minus the keyboard in container height. | ||
*/ | ||
if (keyboardBehavior === KEYBOARD_BEHAVIOR.interactive && keyboardState === KEYBOARD_STATE.SHOWN) { | ||
isInTemporaryPosition.value = true; | ||
const keyboardHeightInContainer = animatedKeyboardHeightInContainer.value; | ||
return Math.max(0, highestSnapPoint - keyboardHeightInContainer); | ||
} | ||
/** | ||
* if the bottom sheet is in temporary position, then we return | ||
* the current position. | ||
*/ | ||
if (isInTemporaryPosition.value) { | ||
return animatedPosition.value; | ||
} | ||
/** | ||
* if the bottom sheet did not animate on mount, | ||
* then we return the provided index or the closed position. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
return _providedIndex === -1 ? animatedClosedPosition.value : snapPoints[_providedIndex]; | ||
} | ||
/** | ||
* return the current index position. | ||
*/ | ||
return snapPoints[currentIndex]; | ||
}, [animatedContentGestureState, animatedCurrentIndex, animatedHandleGestureState, animatedHighestSnapPoint, animatedKeyboardHeightInContainer, animatedKeyboardState, animatedPosition, animatedSnapPoints, isInTemporaryPosition, isAnimatedOnMount, keyboardBehavior, keyboardBlurBehavior, _providedIndex]); | ||
/** | ||
* Evaluate the bottom sheet position based based on a event source and other local states. | ||
*/ | ||
const evaluatePosition = useWorkletCallback(function evaluatePosition(source, animationConfigs) { | ||
/** | ||
* when evaluating the position while layout is not calculated, then we early exit till it is. | ||
*/ | ||
if (!isLayoutCalculated.value) { | ||
return; | ||
} | ||
const proposedPosition = getEvaluatedPosition(source); | ||
/** | ||
* when evaluating the position while the mount animation not been handled, | ||
* then we evaluate on mount use cases. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
/** | ||
* if animate on mount is set to true, then we animate to the propose position, | ||
* else, we set the position with out animation. | ||
*/ | ||
if (animateOnMount) { | ||
animateToPosition(proposedPosition, ANIMATION_SOURCE.MOUNT, undefined, animationConfigs); | ||
} else { | ||
setToPosition(proposedPosition); | ||
isAnimatedOnMount.value = true; | ||
} | ||
return; | ||
} | ||
/** | ||
* when evaluating the position while the bottom sheet is animating. | ||
*/ | ||
if (animatedAnimationState.value === ANIMATION_STATE.RUNNING) { | ||
/** | ||
* when evaluating the position while the bottom sheet is | ||
* closing, then we force closing the bottom sheet with no animation. | ||
*/ | ||
if (animatedNextPositionIndex.value === -1) { | ||
setToPosition(animatedClosedPosition.value); | ||
return; | ||
} | ||
/** | ||
* when evaluating the position while it's animating to | ||
* a position other than the current position, then we | ||
* restart the animation. | ||
*/ | ||
if (animatedNextPositionIndex.value !== animatedCurrentIndex.value) { | ||
animateToPosition(animatedNextPosition.value, source, undefined, animationConfigs); | ||
return; | ||
} | ||
} | ||
/** | ||
* when evaluating the position while the bottom sheet is in closed | ||
* position and not animating, we re-set the position to closed position. | ||
*/ | ||
if (animatedAnimationState.value !== ANIMATION_STATE.RUNNING && animatedCurrentIndex.value === -1) { | ||
setToPosition(animatedClosedPosition.value); | ||
return; | ||
} | ||
/** | ||
* when evaluating the position after the container resize, then we | ||
* force the bottom sheet to the proposed position with no | ||
* animation. | ||
*/ | ||
if (animatedContainerHeightDidChange.value) { | ||
setToPosition(proposedPosition); | ||
return; | ||
} | ||
/** | ||
* we fall back to the proposed position. | ||
*/ | ||
animateToPosition(proposedPosition, source, undefined, animationConfigs); | ||
}, [getEvaluatedPosition, animateToPosition, setToPosition]); | ||
//#endregion | ||
//#region public methods | ||
@@ -783,56 +896,11 @@ const handleSnapToIndex = useCallback(function handleSnapToIndex(index, animationConfigs) { | ||
//#region effects | ||
/** | ||
* React to `isLayoutCalculated` change, to insure that the sheet will | ||
* appears/mounts only when all layout is been calculated. | ||
* | ||
* @alias OnMount | ||
*/ | ||
useAnimatedReaction(() => isLayoutCalculated.value, _isLayoutCalculated => { | ||
/** | ||
* exit method if: | ||
* - layout is not calculated yet. | ||
* - already did animate on mount. | ||
*/ | ||
if (!_isLayoutCalculated || isAnimatedOnMount.value) { | ||
useAnimatedReaction(() => animatedContainerHeight.value, (result, previous) => { | ||
if (result === INITIAL_CONTAINER_HEIGHT) { | ||
return; | ||
} | ||
let nextPosition; | ||
if (_providedIndex === -1) { | ||
nextPosition = animatedClosedPosition.value; | ||
animatedNextPositionIndex.value = -1; | ||
} else { | ||
nextPosition = getNextPosition(); | ||
} | ||
runOnJS(print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnMount', | ||
params: { | ||
isLayoutCalculated: _isLayoutCalculated, | ||
animatedSnapPoints: animatedSnapPoints.value, | ||
nextPosition | ||
} | ||
}); | ||
animatedContainerHeightDidChange.value = result !== previous; | ||
}); | ||
/** | ||
* here we exit method early because the next position | ||
* is out of the screen, this happens when `snapPoints` | ||
* still being calculated. | ||
*/ | ||
if (nextPosition === INITIAL_POSITION || nextPosition === animatedClosedPosition.value) { | ||
isAnimatedOnMount.value = true; | ||
animatedCurrentIndex.value = _providedIndex; | ||
return; | ||
} | ||
if (animateOnMount) { | ||
requestAnimationFrame(() => { | ||
animateToPosition(nextPosition, ANIMATION_SOURCE.MOUNT); | ||
}); | ||
} else { | ||
animatedPosition.value = nextPosition; | ||
} | ||
isAnimatedOnMount.value = true; | ||
}, [_providedIndex, animateOnMount]); | ||
/** | ||
* React to `snapPoints` change, to insure that the sheet position reflect | ||
* Reaction to the `snapPoints` change, to insure that the sheet position reflect | ||
* to the current point correctly. | ||
@@ -842,25 +910,15 @@ * | ||
*/ | ||
useAnimatedReaction(() => ({ | ||
snapPoints: animatedSnapPoints.value, | ||
containerHeight: animatedContainerHeight.value | ||
}), (result, _previousResult) => { | ||
const { | ||
snapPoints, | ||
containerHeight | ||
} = result; | ||
const _previousSnapPoints = _previousResult?.snapPoints; | ||
const _previousContainerHeight = _previousResult?.containerHeight; | ||
let nextPosition; | ||
let animationConfig; | ||
let animationSource = ANIMATION_SOURCE.SNAP_POINT_CHANGE; | ||
useAnimatedReaction(() => animatedSnapPoints.value, (result, previous) => { | ||
/** | ||
* if the bottom sheet is closing and the container gets resized, | ||
* then we restart the closing animation to the new position. | ||
* if values did not change, and did handle on mount animation | ||
* then we early exit the method. | ||
*/ | ||
if (animatedAnimationState.value === ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value === -1 && _previousContainerHeight !== containerHeight) { | ||
setToPosition(containerHeight); | ||
if (JSON.stringify(result) === JSON.stringify(previous) && isAnimatedOnMount.value) { | ||
return; | ||
} | ||
if (JSON.stringify(snapPoints) === JSON.stringify(_previousSnapPoints) || !isLayoutCalculated.value || !isAnimatedOnMount.value || containerHeight <= 0) { | ||
/** | ||
* if layout is not calculated yet, then we exit the method. | ||
*/ | ||
if (!isLayoutCalculated.value) { | ||
return; | ||
@@ -871,34 +929,12 @@ } | ||
method: 'useAnimatedReaction::OnSnapPointChange', | ||
category: 'effect', | ||
params: { | ||
snapPoints | ||
result | ||
} | ||
}); | ||
evaluatePosition(ANIMATION_SOURCE.SNAP_POINT_CHANGE); | ||
}, [isLayoutCalculated.value, animatedSnapPoints.value]); | ||
/** | ||
* if snap points changed while sheet is animating, then | ||
* we stop the animation and animate to the updated point. | ||
*/ | ||
if (animatedAnimationState.value === ANIMATION_STATE.RUNNING && animatedNextPositionIndex.value !== animatedCurrentIndex.value) { | ||
nextPosition = animatedNextPositionIndex.value !== -1 ? snapPoints[animatedNextPositionIndex.value] : animatedNextPosition.value; | ||
} else if (animatedCurrentIndex.value === -1) { | ||
nextPosition = animatedClosedPosition.value; | ||
} else if (isInTemporaryPosition.value) { | ||
nextPosition = getNextPosition(); | ||
} else { | ||
nextPosition = snapPoints[animatedCurrentIndex.value]; | ||
/** | ||
* if snap points changes because of the container height change, | ||
* then we set the new position without animation. | ||
*/ | ||
if (containerHeight !== _previousContainerHeight) { | ||
setToPosition(nextPosition); | ||
return; | ||
} | ||
} | ||
animateToPosition(nextPosition, animationSource, 0, animationConfig); | ||
}, []); | ||
/** | ||
* React to keyboard appearance state. | ||
* Reaction to the keyboard state change. | ||
* | ||
@@ -919,10 +955,12 @@ * @alias OnKeyboardStateChange | ||
/** | ||
* Calculate the keyboard height in the container. | ||
* if keyboard state is equal to the previous state, then exit the method | ||
*/ | ||
animatedKeyboardHeightInContainer.value = _keyboardHeight === 0 ? 0 : $modal ? Math.abs(_keyboardHeight - Math.abs(bottomInset - animatedContainerOffset.value.bottom)) : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom); | ||
if (_keyboardState === _previousKeyboardState && _keyboardHeight === _previousKeyboardHeight) { | ||
return; | ||
} | ||
/** | ||
* if keyboard state is equal to the previous state, then exit the method | ||
* if state is undetermined, then we early exit. | ||
*/ | ||
if (_keyboardState === _previousKeyboardState && _keyboardHeight === _previousKeyboardHeight) { | ||
if (_keyboardState === KEYBOARD_STATE.UNDETERMINED) { | ||
return; | ||
@@ -932,13 +970,27 @@ } | ||
/** | ||
* if user is interacting with sheet, then exit the method | ||
* if keyboard is hidden by customer gesture, then we early exit. | ||
*/ | ||
const hasActiveGesture = animatedContentGestureState.value === State.ACTIVE || animatedContentGestureState.value === State.BEGAN || animatedHandleGestureState.value === State.ACTIVE || animatedHandleGestureState.value === State.BEGAN; | ||
if (hasActiveGesture) { | ||
if (_keyboardState === KEYBOARD_STATE.HIDDEN && animatedAnimationState.value === ANIMATION_STATE.RUNNING && animatedAnimationSource.value === ANIMATION_SOURCE.GESTURE) { | ||
return; | ||
} | ||
runOnJS(print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnKeyboardStateChange', | ||
category: 'effect', | ||
params: { | ||
keyboardState: _keyboardState, | ||
keyboardHeight: _keyboardHeight | ||
} | ||
}); | ||
/** | ||
* if sheet not animated on mount yet, then exit the method | ||
* Calculate the keyboard height in the container. | ||
*/ | ||
if (!isAnimatedOnMount.value) { | ||
animatedKeyboardHeightInContainer.value = _keyboardHeight === 0 ? 0 : $modal ? Math.abs(_keyboardHeight - Math.abs(bottomInset - animatedContainerOffset.value.bottom)) : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom); | ||
/** | ||
* 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; | ||
@@ -961,14 +1013,5 @@ } | ||
} | ||
runOnJS(print)({ | ||
component: BottomSheet.name, | ||
method: 'useAnimatedReaction::OnKeyboardStateChange', | ||
params: { | ||
keyboardState: _keyboardState, | ||
keyboardHeight: _keyboardHeight | ||
} | ||
}); | ||
let animationConfigs = getKeyboardAnimationConfigs(keyboardAnimationEasing.value, keyboardAnimationDuration.value); | ||
const nextPosition = getNextPosition(); | ||
animateToPosition(nextPosition, ANIMATION_SOURCE.KEYBOARD, 0, animationConfigs); | ||
}, [$modal, bottomInset, keyboardBehavior, keyboardBlurBehavior, android_keyboardInputMode, animatedContainerOffset, getNextPosition]); | ||
evaluatePosition(ANIMATION_SOURCE.KEYBOARD, animationConfigs); | ||
}, [$modal, bottomInset, keyboardBehavior, keyboardBlurBehavior, android_keyboardInputMode, animatedContainerOffset, getEvaluatedPosition]); | ||
@@ -1053,2 +1096,3 @@ /** | ||
method: 'useAnimatedReaction::OnChange', | ||
category: 'effect', | ||
params: { | ||
@@ -1070,2 +1114,3 @@ animatedCurrentIndex: animatedCurrentIndex.value, | ||
method: 'useAnimatedReaction::onClose', | ||
category: 'effect', | ||
params: { | ||
@@ -1072,0 +1117,0 @@ animatedCurrentIndex: animatedCurrentIndex.value, |
@@ -35,2 +35,3 @@ import React, { memo, useCallback, useMemo, useRef } from 'react'; | ||
containerRef.current?.measure((_x, _y, _width, _height, _pageX, pageY) => { | ||
if (!containerOffset.value) return; | ||
containerOffset.value = { | ||
@@ -46,2 +47,3 @@ top: pageY ?? 0, | ||
method: 'handleContainerLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -48,0 +50,0 @@ height |
@@ -83,2 +83,3 @@ import React, { memo, useCallback, useMemo } from 'react'; | ||
method: 'handleContainerLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -85,0 +86,0 @@ height |
@@ -259,2 +259,3 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
method: handleBottomSheetOnChange.name, | ||
category: 'callback', | ||
params: { | ||
@@ -274,2 +275,3 @@ minimized: minimized.current, | ||
method: handleBottomSheetOnClose.name, | ||
category: 'callback', | ||
params: { | ||
@@ -276,0 +278,0 @@ minimized: minimized.current, |
@@ -10,5 +10,3 @@ import { memo } from 'react'; | ||
BottomSheetFlatList.displayName = 'BottomSheetFlatList'; | ||
//@ts-ignore | ||
BottomSheetFlatList.$bottomSheetIntegrated = true; | ||
export default BottomSheetFlatList; | ||
//# sourceMappingURL=BottomSheetFlatList.js.map |
@@ -10,5 +10,3 @@ import { memo } from 'react'; | ||
BottomSheetScrollView.displayName = 'BottomSheetScrollView'; | ||
//@ts-ignore | ||
BottomSheetScrollView.$bottomSheetIntegrated = true; | ||
export default BottomSheetScrollView; | ||
//# sourceMappingURL=BottomSheetScrollView.js.map |
@@ -10,5 +10,3 @@ import { memo } from 'react'; | ||
BottomSheetSectionList.displayName = 'BottomSheetSectionList'; | ||
//@ts-ignore | ||
BottomSheetSectionList.$bottomSheetIntegrated = true; | ||
export default BottomSheetSectionList; | ||
//# sourceMappingURL=BottomSheetSectionList.js.map |
@@ -10,5 +10,3 @@ import { memo } from 'react'; | ||
BottomSheetVirtualizedList.displayName = 'BottomSheetVirtualizedList'; | ||
//@ts-ignore | ||
BottomSheetVirtualizedList.$bottomSheetIntegrated = true; | ||
export default BottomSheetVirtualizedList; | ||
//# sourceMappingURL=BottomSheetVirtualizedList.js.map |
@@ -59,2 +59,3 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
method: 'handleLayout', | ||
category: 'layout', | ||
params: { | ||
@@ -81,5 +82,3 @@ height: event.nativeEvent.layout.height | ||
BottomSheetView.displayName = 'BottomSheetView'; | ||
//@ts-ignore | ||
BottomSheetView.$bottomSheetIntegrated = true; | ||
export default BottomSheetView; | ||
//# sourceMappingURL=BottomSheetView.js.map |
@@ -21,5 +21,5 @@ export { useBottomSheet } from './useBottomSheet'; | ||
export { usePropsValidator } from './usePropsValidator'; | ||
export { useNormalizedSnapPoints } from './useNormalizedSnapPoints'; | ||
export { useAnimatedSnapPoints } from './useAnimatedSnapPoints'; | ||
export { useReactiveSharedValue } from './useReactiveSharedValue'; | ||
export { useBottomSheetGestureHandlers } from './useBottomSheetGestureHandlers'; | ||
//# sourceMappingURL=index.js.map |
@@ -14,4 +14,3 @@ import { useMemo } from 'react'; | ||
topInset, | ||
bottomInset, | ||
children | ||
bottomInset | ||
}) => { | ||
@@ -41,10 +40,3 @@ useMemo(() => { | ||
}, [index, snapPoints, topInset, bottomInset, enableDynamicSizing]); | ||
useMemo(() => { | ||
invariant(enableDynamicSizing && children && | ||
// @ts-ignore | ||
children.type && | ||
// @ts-ignore | ||
children.type.$bottomSheetIntegrated || !enableDynamicSizing, `'enableDynamicSizing' is enabled but children type is not integrated with the library !` + ` expected children types are\n- BottomSheetView\n- BottomSheetFlatList\n- BottomSheetScrollView\n- BottomSheetSectionList\n- BottomSheetVirtualizedList`); | ||
}, [enableDynamicSizing, children]); | ||
}; | ||
//# sourceMappingURL=usePropsValidator.js.map |
@@ -1,3 +0,4 @@ | ||
let isLoggingEnabled = false; | ||
const enableLogging = () => { | ||
let _isLoggingEnabled = false; | ||
let _excludeCategories; | ||
const enableLogging = excludeCategories => { | ||
if (!__DEV__) { | ||
@@ -7,3 +8,4 @@ console.warn('[BottomSheet] could not enable logging on production!'); | ||
} | ||
isLoggingEnabled = true; | ||
_isLoggingEnabled = true; | ||
_excludeCategories = excludeCategories; | ||
}; | ||
@@ -15,7 +17,11 @@ let print = () => {}; | ||
method, | ||
params | ||
params, | ||
category | ||
}) => { | ||
if (!isLoggingEnabled) { | ||
if (!_isLoggingEnabled) { | ||
return; | ||
} | ||
if (category && _excludeCategories && _excludeCategories.includes(category)) { | ||
return; | ||
} | ||
let message = ''; | ||
@@ -22,0 +28,0 @@ if (typeof params === 'object') { |
@@ -13,5 +13,5 @@ export { useBottomSheet } from './useBottomSheet'; | ||
export { usePropsValidator } from './usePropsValidator'; | ||
export { useNormalizedSnapPoints } from './useNormalizedSnapPoints'; | ||
export { useAnimatedSnapPoints } from './useAnimatedSnapPoints'; | ||
export { useReactiveSharedValue } from './useReactiveSharedValue'; | ||
export { useBottomSheetGestureHandlers } from './useBottomSheetGestureHandlers'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -6,3 +6,3 @@ import type { BottomSheetProps } from '../components/bottomSheet'; | ||
*/ | ||
export declare const usePropsValidator: ({ index, snapPoints, enableDynamicSizing, topInset, bottomInset, children, }: Pick<BottomSheetProps, 'index' | 'snapPoints' | 'enableDynamicSizing' | 'topInset' | 'bottomInset' | 'children'>) => void; | ||
export declare const usePropsValidator: ({ index, snapPoints, enableDynamicSizing, topInset, bottomInset, }: Pick<BottomSheetProps, 'index' | 'snapPoints' | 'enableDynamicSizing' | 'topInset' | 'bottomInset'>) => void; | ||
//# sourceMappingURL=usePropsValidator.d.ts.map |
interface PrintOptions { | ||
component?: string; | ||
category?: 'layout' | 'effect' | 'callback'; | ||
method?: string; | ||
@@ -7,5 +8,5 @@ params?: Record<string, any> | string | number | boolean; | ||
type Print = (options: PrintOptions) => void; | ||
declare const enableLogging: () => void; | ||
declare const enableLogging: (excludeCategories?: PrintOptions['category'][]) => void; | ||
declare let print: Print; | ||
export { print, enableLogging }; | ||
//# sourceMappingURL=logger.d.ts.map |
{ | ||
"name": "@gorhom/bottom-sheet", | ||
"version": "5.0.0-alpha.9", | ||
"version": "5.0.0-alpha.10", | ||
"description": "A performant interactive bottom sheet with fully configurable options 🚀", | ||
@@ -5,0 +5,0 @@ "main": "lib/commonjs/index", |
@@ -21,4 +21,4 @@ export { useBottomSheet } from './useBottomSheet'; | ||
export { usePropsValidator } from './usePropsValidator'; | ||
export { useNormalizedSnapPoints } from './useNormalizedSnapPoints'; | ||
export { useAnimatedSnapPoints } from './useAnimatedSnapPoints'; | ||
export { useReactiveSharedValue } from './useReactiveSharedValue'; | ||
export { useBottomSheetGestureHandlers } from './useBottomSheetGestureHandlers'; |
@@ -17,11 +17,5 @@ import { useMemo } from 'react'; | ||
bottomInset, | ||
children, | ||
}: Pick< | ||
BottomSheetProps, | ||
| 'index' | ||
| 'snapPoints' | ||
| 'enableDynamicSizing' | ||
| 'topInset' | ||
| 'bottomInset' | ||
| 'children' | ||
'index' | 'snapPoints' | 'enableDynamicSizing' | 'topInset' | 'bottomInset' | ||
>) => { | ||
@@ -88,16 +82,2 @@ useMemo(() => { | ||
}, [index, snapPoints, topInset, bottomInset, enableDynamicSizing]); | ||
useMemo(() => { | ||
invariant( | ||
(enableDynamicSizing && | ||
children && | ||
// @ts-ignore | ||
children.type && | ||
// @ts-ignore | ||
children.type.$bottomSheetIntegrated) || | ||
!enableDynamicSizing, | ||
`'enableDynamicSizing' is enabled but children type is not integrated with the library !` + | ||
` expected children types are\n- BottomSheetView\n- BottomSheetFlatList\n- BottomSheetScrollView\n- BottomSheetSectionList\n- BottomSheetVirtualizedList` | ||
); | ||
}, [enableDynamicSizing, children]); | ||
}; |
interface PrintOptions { | ||
component?: string; | ||
category?: 'layout' | 'effect' | 'callback'; | ||
method?: string; | ||
@@ -9,5 +10,6 @@ params?: Record<string, any> | string | number | boolean; | ||
let isLoggingEnabled = false; | ||
let _isLoggingEnabled = false; | ||
let _excludeCategories: PrintOptions['category'][] | undefined; | ||
const enableLogging = () => { | ||
const enableLogging = (excludeCategories?: PrintOptions['category'][]) => { | ||
if (!__DEV__) { | ||
@@ -17,3 +19,5 @@ console.warn('[BottomSheet] could not enable logging on production!'); | ||
} | ||
isLoggingEnabled = true; | ||
_isLoggingEnabled = true; | ||
_excludeCategories = excludeCategories; | ||
}; | ||
@@ -24,6 +28,15 @@ | ||
if (__DEV__) { | ||
print = ({ component, method, params }) => { | ||
if (!isLoggingEnabled) { | ||
print = ({ component, method, params, category }) => { | ||
if (!_isLoggingEnabled) { | ||
return; | ||
} | ||
if ( | ||
category && | ||
_excludeCategories && | ||
_excludeCategories.includes(category) | ||
) { | ||
return; | ||
} | ||
let message = ''; | ||
@@ -30,0 +43,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1148266
18925