/
swipe-to-close.ts
100 lines (82 loc) · 2.68 KB
/
swipe-to-close.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { Animation } from '../../../interface';
import { getTimeGivenProgression } from '../../../utils/animation/cubic-bezier';
import { GestureDetail, createGesture } from '../../../utils/gesture';
import { clamp } from '../../../utils/helpers';
// Defaults for the card swipe animation
export const SwipeToCloseDefaults = {
MIN_PRESENTING_SCALE: 0.93,
};
export const createSwipeToCloseGesture = (
el: HTMLIonModalElement,
animation: Animation,
onDismiss: () => void
) => {
const height = el.offsetHeight;
let isOpen = false;
const canStart = (detail: GestureDetail) => {
const target = detail.event.target as HTMLElement | null;
if (target === null ||
!(target as any).closest) {
return true;
}
const content = target.closest('ion-content');
if (content === null) {
return true;
}
// Target is in the content so we don't start the gesture.
// We could be more nuanced here and allow it for content that
// does not need to scroll.
return false;
};
const onStart = () => {
animation.progressStart(true, (isOpen) ? 1 : 0);
};
const onMove = (detail: GestureDetail) => {
const step = detail.deltaY / height;
if (step < 0) { return; }
animation.progressStep(step);
};
const onEnd = (detail: GestureDetail) => {
const velocity = detail.velocityY;
const step = detail.deltaY / height;
if (step < 0) { return; }
const threshold = (detail.deltaY + velocity * 1000) / height;
const shouldComplete = threshold >= 0.5;
let newStepValue = (shouldComplete) ? -0.001 : 0.001;
if (!shouldComplete) {
animation.easing('cubic-bezier(1, 0, 0.68, 0.28)');
newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], step)[0];
} else {
animation.easing('cubic-bezier(0.32, 0.72, 0, 1)');
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
}
const duration = (shouldComplete) ? computeDuration(step * height, velocity) : computeDuration((1 - step) * height, velocity);
isOpen = shouldComplete;
gesture.enable(false);
animation
.onFinish(() => {
if (!shouldComplete) {
gesture.enable(true);
}
})
.progressEnd((shouldComplete) ? 1 : 0, newStepValue, duration);
if (shouldComplete) {
onDismiss();
}
};
const gesture = createGesture({
el,
gestureName: 'modalSwipeToClose',
gesturePriority: 40,
direction: 'y',
threshold: 10,
canStart,
onStart,
onMove,
onEnd
});
return gesture;
};
const computeDuration = (remaining: number, velocity: number) => {
return clamp(400, remaining / Math.abs(velocity * 1.1), 500);
};