Skip to content

Commit

Permalink
feat: add option to disable swipe gestures (#446)
Browse files Browse the repository at this point in the history
* feat(swipeable): option to disable swipe gestures

* test: update tests for swipeable option

* docs: update api

* ci: run quality checks & tests on push

---------

Co-authored-by: Calin Tamas <calintamas2@gmail.com>
  • Loading branch information
wouterds and calintamas authored Dec 15, 2023
1 parent d64f941 commit 5574c2a
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 10 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Run code quality checks

on: pull_request
on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
quality:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Run tests

on: pull_request
on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
Expand Down
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ The following set of `props` can be passed to the `Toast` component instance to
| `position` | Default Toast position | `top` or `bottom` | `top` |
| `visibilityTime` | Number of milliseconds after which Toast automatically hides. Has effect only in conjunction with `autoHide` prop set to `true` | `number` | `4000` |
| `autoHide` | When `true`, the visible Toast automatically hides after a certain number of milliseconds, specified by the `visibilityTime` prop | `boolean` | `true` |
| `swipeable` | When `true`, the Toast can be swiped to dismiss | `boolean` | `true` |
| `topOffset` | Offset from the top of the screen (in px). Has effect only when `position` is `top` | `number` | `40` |
| `bottomOffset` | Offset from the bottom of the screen (in px). Has effect only when `position` is `bottom` | `number` | `40` |
| `keyboardOffset` | Offset from the Keyboard (in px). Has effect only when `position` is `bottom` and Keyboard is visible (iOS only) | `number` | `10` |
Expand Down
3 changes: 2 additions & 1 deletion src/ToastUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function renderComponent({

export function ToastUI(props: ToastUIProps) {
const { isVisible, options, hide } = props;
const { position, topOffset, bottomOffset, keyboardOffset } = options;
const { position, topOffset, bottomOffset, keyboardOffset, swipeable } = options;

return (
<AnimatedContainer
Expand All @@ -76,6 +76,7 @@ export function ToastUI(props: ToastUIProps) {
topOffset={topOffset}
bottomOffset={bottomOffset}
keyboardOffset={keyboardOffset}
swipeable={swipeable}
onHide={hide}>
{renderComponent(props)}
</AnimatedContainer>
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/useToast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ describe('test useToast hook', () => {
const options: ToastOptions = {
type: 'info',
position: 'bottom',
swipeable: true,
text1Style: null,
text2Style: null,
autoHide: false,
Expand Down
7 changes: 5 additions & 2 deletions src/components/AnimatedContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type AnimatedContainerProps = {
isVisible: boolean;
position: ToastPosition;
topOffset: number;
swipeable: boolean;
bottomOffset: number;
keyboardOffset: number;
onHide: () => void;
Expand Down Expand Up @@ -74,7 +75,8 @@ export function AnimatedContainer({
bottomOffset,
keyboardOffset,
onHide,
onRestorePosition = noop
onRestorePosition = noop,
swipeable
}: AnimatedContainerProps) {
const { log } = useLogger();

Expand Down Expand Up @@ -112,7 +114,8 @@ export function AnimatedContainer({
animatedValue,
computeNewAnimatedValueForGesture,
onDismiss,
onRestore
onRestore,
disable: !swipeable
});

React.useLayoutEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions src/components/__tests__/AnimatedContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const setup = (props?: Omit<Partial<AnimatedContainerProps>, 'children'>) => {
const defaultProps: Omit<AnimatedContainerProps, 'children'> = {
isVisible: false,
position: 'top',
swipeable: true,
topOffset: 40,
bottomOffset: 40,
keyboardOffset: 10,
Expand Down
22 changes: 20 additions & 2 deletions src/hooks/__tests__/usePanResponder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { mockGestureValues } from '../../__helpers__/PanResponder';
import { usePanResponder } from '../usePanResponder';
import { shouldSetPanResponder } from '..';

const setup = ({ newAnimatedValueForGesture = 0 } = {}) => {
const setup = ({ newAnimatedValueForGesture = 0, disable = false } = {}) => {
const animatedValue = {
current: new Animated.Value(0)
};
Expand All @@ -22,7 +22,8 @@ const setup = ({ newAnimatedValueForGesture = 0 } = {}) => {
animatedValue,
computeNewAnimatedValueForGesture,
onDismiss,
onRestore
onRestore,
disable
})
);
return {
Expand Down Expand Up @@ -58,6 +59,23 @@ describe('test usePanResponder hook', () => {
expect(computeNewAnimatedValueForGesture).toBeCalledWith(mockGestureValues);
});

it('should NOT compute new animated value on move/release, if disable: true', () => {
const { result, computeNewAnimatedValueForGesture } = setup({
newAnimatedValueForGesture: 1,
disable: true
});

result.current.onMove({} as GestureResponderEvent, mockGestureValues);
expect(computeNewAnimatedValueForGesture).not.toBeCalledWith(
mockGestureValues
);

result.current.onRelease({} as GestureResponderEvent, mockGestureValues);
expect(computeNewAnimatedValueForGesture).not.toBeCalledWith(
mockGestureValues
);
});

it('calls onDismiss when swipe gesture value is below dismiss threshold', () => {
const { result, computeNewAnimatedValueForGesture, onDismiss } = setup({
newAnimatedValueForGesture: 0.65
Expand Down
16 changes: 13 additions & 3 deletions src/hooks/usePanResponder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,42 @@ export type UsePanResponderParams = {
) => number;
onDismiss: () => void;
onRestore: () => void;
disable?: boolean;
};

export function usePanResponder({
animatedValue,
computeNewAnimatedValueForGesture,
onDismiss,
onRestore
onRestore,
disable
}: UsePanResponderParams) {
const onMove = React.useCallback(
(_event: GestureResponderEvent, gesture: PanResponderGestureState) => {
if (disable) {
return;
}

const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
animatedValue.current?.setValue(newAnimatedValue);
},
[animatedValue, computeNewAnimatedValueForGesture]
[animatedValue, computeNewAnimatedValueForGesture, disable]
);

const onRelease = React.useCallback(
(_event: GestureResponderEvent, gesture: PanResponderGestureState) => {
if (disable) {
return;
}

const newAnimatedValue = computeNewAnimatedValueForGesture(gesture);
if (shouldDismissView(newAnimatedValue, gesture)) {
onDismiss();
} else {
onRestore();
}
},
[computeNewAnimatedValueForGesture, onDismiss, onRestore]
[computeNewAnimatedValueForGesture, onDismiss, onRestore, disable]
);

const panResponder = React.useMemo(
Expand Down
5 changes: 5 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export type ToastOptions = {
* Default value: `4000`
*/
visibilityTime?: number;
/**
* When `true`, the Toast can be dismissed by a swipe gesture, specified by the `swipeable` prop.
* Default value: `true`
*/
swipeable?: boolean;
/**
* Offset from the top of the screen (in px).
* Has effect only when `position` is `top`
Expand Down
3 changes: 3 additions & 0 deletions src/useToast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const DEFAULT_OPTIONS: Required<ToastOptions> = {
text2Style: null,
position: 'top',
autoHide: true,
swipeable: true,
visibilityTime: 4000,
topOffset: 40,
bottomOffset: 40,
Expand Down Expand Up @@ -79,6 +80,7 @@ export function useToast({ defaultOptions }: UseToastParams) {
onShow = initialOptions.onShow,
onHide = initialOptions.onHide,
onPress = initialOptions.onPress,
swipeable = initialOptions.swipeable,
props = initialOptions.props
} = params;
setData({
Expand All @@ -99,6 +101,7 @@ export function useToast({ defaultOptions }: UseToastParams) {
onShow,
onHide,
onPress,
swipeable,
props
}) as Required<ToastOptions>
);
Expand Down

0 comments on commit 5574c2a

Please sign in to comment.