@draftbit/core 49.0.1-c3bbf3.2 → 49.0.1-ecd6ba.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/BottomSheet/BottomSheet.js +1 -1
- package/lib/commonjs/components/PinInput/PinInput.js +1 -1
- package/lib/typescript/src/components/BottomSheet/BottomSheet.d.ts +5 -3
- package/lib/typescript/src/components/BottomSheet/BottomSheet.js +56 -47
- package/lib/typescript/src/components/BottomSheet/BottomSheet.js.map +1 -1
- package/lib/typescript/src/components/PinInput/PinInput.js +7 -2
- package/lib/typescript/src/components/PinInput/PinInput.js.map +1 -1
- package/lib/typescript/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/components/BottomSheet/BottomSheet.js +56 -47
- package/src/components/BottomSheet/BottomSheet.js.map +1 -1
- package/src/components/BottomSheet/BottomSheet.tsx +82 -73
- package/src/components/PinInput/PinInput.js +7 -2
- package/src/components/PinInput/PinInput.js.map +1 -1
- package/src/components/PinInput/PinInput.tsx +7 -1
- package/lib/commonjs/components/BottomSheet/BottomSheetComponent.js +0 -1
- package/lib/typescript/src/components/BottomSheet/BottomSheetComponent.d.ts +0 -176
- package/lib/typescript/src/components/BottomSheet/BottomSheetComponent.js +0 -445
- package/lib/typescript/src/components/BottomSheet/BottomSheetComponent.js.map +0 -1
- package/src/components/BottomSheet/BottomSheetComponent.js +0 -445
- package/src/components/BottomSheet/BottomSheetComponent.js.map +0 -1
- package/src/components/BottomSheet/BottomSheetComponent.tsx +0 -903
|
@@ -1,903 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: Replace with https://github.com/gorhom/react-native-bottom-sheet. (@gorhom/bottom-sheet)
|
|
3
|
-
* @gorhom/bottom-sheet v5 (which is not ready yet) will support web, allowing us to transition to that better supported library
|
|
4
|
-
*
|
|
5
|
-
* This legacy component uses an outdated reanimated v1, under a self published version (@youssefhenna/react-native-reanimated2) since
|
|
6
|
-
* the latest reanimated version removes the v1 APIs
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Slightly modfied version as taken from https://github.com/rgommezz/react-native-scroll-bottom-sheet
|
|
11
|
-
* Main previously breaking change:
|
|
12
|
-
* const node = this.props.innerRef.current?.getNode() ==> const node = this.props.innerRef.current as any
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Copyright (c) 2020 Raul Gomez Acuna
|
|
17
|
-
*
|
|
18
|
-
* This source code is licensed under the MIT license found in the
|
|
19
|
-
* LICENSE file in the root directory of this source tree.
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import React, { Component, RefObject } from "react";
|
|
24
|
-
import {
|
|
25
|
-
Dimensions,
|
|
26
|
-
FlatList,
|
|
27
|
-
FlatListProps,
|
|
28
|
-
Platform,
|
|
29
|
-
ScrollView,
|
|
30
|
-
ScrollViewProps,
|
|
31
|
-
SectionList,
|
|
32
|
-
SectionListProps,
|
|
33
|
-
StyleSheet,
|
|
34
|
-
View,
|
|
35
|
-
ViewStyle,
|
|
36
|
-
} from "react-native";
|
|
37
|
-
import Animated, {
|
|
38
|
-
abs,
|
|
39
|
-
add,
|
|
40
|
-
and,
|
|
41
|
-
call,
|
|
42
|
-
Clock,
|
|
43
|
-
clockRunning,
|
|
44
|
-
cond,
|
|
45
|
-
Easing as EasingDeprecated,
|
|
46
|
-
// @ts-ignore: this property is only present in Reanimated 2
|
|
47
|
-
EasingNode,
|
|
48
|
-
eq,
|
|
49
|
-
event,
|
|
50
|
-
Extrapolate,
|
|
51
|
-
greaterOrEq,
|
|
52
|
-
greaterThan,
|
|
53
|
-
multiply,
|
|
54
|
-
not,
|
|
55
|
-
onChange,
|
|
56
|
-
or,
|
|
57
|
-
set,
|
|
58
|
-
startClock,
|
|
59
|
-
stopClock,
|
|
60
|
-
sub,
|
|
61
|
-
spring,
|
|
62
|
-
timing,
|
|
63
|
-
Value,
|
|
64
|
-
} from "@youssefhenna/react-native-reanimated2";
|
|
65
|
-
import {
|
|
66
|
-
NativeViewGestureHandler,
|
|
67
|
-
PanGestureHandler,
|
|
68
|
-
PanGestureHandlerProperties,
|
|
69
|
-
State as GestureState,
|
|
70
|
-
TapGestureHandler,
|
|
71
|
-
} from "react-native-gesture-handler";
|
|
72
|
-
import { Assign } from "utility-types";
|
|
73
|
-
|
|
74
|
-
const {
|
|
75
|
-
//@ts-ignore
|
|
76
|
-
interpolate: interpolateDeprecated,
|
|
77
|
-
// @ts-ignore: this property is only present in Reanimated 2
|
|
78
|
-
interpolateNode,
|
|
79
|
-
} = Animated;
|
|
80
|
-
|
|
81
|
-
const interpolate: typeof interpolateDeprecated =
|
|
82
|
-
interpolateNode ?? interpolateDeprecated;
|
|
83
|
-
//@ts-ignore
|
|
84
|
-
const Easing: typeof EasingDeprecated = EasingNode ?? EasingDeprecated;
|
|
85
|
-
|
|
86
|
-
const FlatListComponentType = "FlatList" as const;
|
|
87
|
-
const ScrollViewComponentType = "ScrollView" as const;
|
|
88
|
-
const SectionListComponentType = "SectionList" as const;
|
|
89
|
-
const TimingAnimationType = "timing" as const;
|
|
90
|
-
const SpringAnimationType = "spring" as const;
|
|
91
|
-
|
|
92
|
-
const DEFAULT_SPRING_PARAMS = {
|
|
93
|
-
damping: 50,
|
|
94
|
-
mass: 0.3,
|
|
95
|
-
stiffness: 121.6,
|
|
96
|
-
overshootClamping: true,
|
|
97
|
-
restSpeedThreshold: 0.3,
|
|
98
|
-
restDisplacementThreshold: 0.3,
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const { height: windowHeight } = Dimensions.get("window");
|
|
102
|
-
const IOS_NORMAL_DECELERATION_RATE = 0.998;
|
|
103
|
-
const ANDROID_NORMAL_DECELERATION_RATE = 0.985;
|
|
104
|
-
const DEFAULT_ANIMATION_DURATION = 250;
|
|
105
|
-
const DEFAULT_EASING = Easing.inOut(Easing.linear);
|
|
106
|
-
const imperativeScrollOptions = {
|
|
107
|
-
[FlatListComponentType]: {
|
|
108
|
-
method: "scrollToIndex",
|
|
109
|
-
args: {
|
|
110
|
-
index: 0,
|
|
111
|
-
viewPosition: 0,
|
|
112
|
-
viewOffset: 1000,
|
|
113
|
-
animated: true,
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
[ScrollViewComponentType]: {
|
|
117
|
-
method: "scrollTo",
|
|
118
|
-
args: {
|
|
119
|
-
x: 0,
|
|
120
|
-
y: 0,
|
|
121
|
-
animated: true,
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
[SectionListComponentType]: {
|
|
125
|
-
method: "scrollToLocation",
|
|
126
|
-
args: {
|
|
127
|
-
itemIndex: 0,
|
|
128
|
-
sectionIndex: 0,
|
|
129
|
-
viewPosition: 0,
|
|
130
|
-
viewOffset: 1000,
|
|
131
|
-
animated: true,
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
type AnimatedScrollableComponent = FlatList | ScrollView | SectionList;
|
|
137
|
-
|
|
138
|
-
type FlatListOption<T> = Assign<
|
|
139
|
-
{ componentType: typeof FlatListComponentType },
|
|
140
|
-
FlatListProps<T>
|
|
141
|
-
>;
|
|
142
|
-
type ScrollViewOption = Assign<
|
|
143
|
-
{ componentType: typeof ScrollViewComponentType },
|
|
144
|
-
ScrollViewProps
|
|
145
|
-
>;
|
|
146
|
-
type SectionListOption<T> = Assign<
|
|
147
|
-
{ componentType: typeof SectionListComponentType },
|
|
148
|
-
SectionListProps<T>
|
|
149
|
-
>;
|
|
150
|
-
|
|
151
|
-
interface TimingParams {
|
|
152
|
-
clock: Animated.Clock;
|
|
153
|
-
from: Animated.Node<number>;
|
|
154
|
-
to: Animated.Node<number>;
|
|
155
|
-
position: Animated.Value<number>;
|
|
156
|
-
finished: Animated.Value<number>;
|
|
157
|
-
frameTime: Animated.Value<number>;
|
|
158
|
-
velocity: Animated.Node<number>;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
type CommonProps = {
|
|
162
|
-
/**
|
|
163
|
-
* Array of numbers that indicate the different resting positions of the bottom sheet (in dp or %), starting from the top.
|
|
164
|
-
* If a percentage is used, that would translate to the relative amount of the total window height.
|
|
165
|
-
* For instance, if 50% is used, that'd be windowHeight * 0.5. If you wanna take into account safe areas during
|
|
166
|
-
* the calculation, such as status bars and notches, please use 'topInset' prop
|
|
167
|
-
*/
|
|
168
|
-
snapPoints: Array<string | number>;
|
|
169
|
-
/**
|
|
170
|
-
* Index that references the initial resting position of the drawer, starting from the top
|
|
171
|
-
*/
|
|
172
|
-
initialSnapIndex: number;
|
|
173
|
-
/**
|
|
174
|
-
* Render prop for the handle
|
|
175
|
-
*/
|
|
176
|
-
renderHandle: () => React.ReactNode;
|
|
177
|
-
/**
|
|
178
|
-
* Callback that is executed right after the drawer settles on one of the snapping points.
|
|
179
|
-
* The new index is provided on the callback
|
|
180
|
-
* @param index
|
|
181
|
-
*/
|
|
182
|
-
onSettle?: (index: number) => void;
|
|
183
|
-
/**
|
|
184
|
-
* Animated value that tracks the position of the drawer, being:
|
|
185
|
-
* 0 => closed
|
|
186
|
-
* 1 => fully opened
|
|
187
|
-
*/
|
|
188
|
-
animatedPosition?: Animated.Value<number>;
|
|
189
|
-
/**
|
|
190
|
-
* This value is useful if you want to take into consideration safe area insets
|
|
191
|
-
* when applying percentages for snapping points. We recommend using react-native-safe-area-context
|
|
192
|
-
* library for that.
|
|
193
|
-
* @see https://github.com/th3rdwave/react-native-safe-area-context#usage, insets.top
|
|
194
|
-
*/
|
|
195
|
-
topInset: number;
|
|
196
|
-
/**
|
|
197
|
-
* Reference to FlatList, ScrollView or SectionList in order to execute its imperative methods.
|
|
198
|
-
*/
|
|
199
|
-
innerRef: RefObject<FlatList | ScrollView | SectionList>;
|
|
200
|
-
/*
|
|
201
|
-
* Style to be applied to the container.
|
|
202
|
-
*/
|
|
203
|
-
containerStyle?: Animated.AnimateStyle<ViewStyle>;
|
|
204
|
-
/*
|
|
205
|
-
* Factor of resistance when the gesture is released. A value of 0 offers maximum
|
|
206
|
-
* acceleration, whereas 1 acts as the opposite. Defaults to 0.95
|
|
207
|
-
*/
|
|
208
|
-
friction: number;
|
|
209
|
-
/*
|
|
210
|
-
* Allow drawer to be dragged beyond lowest snap point
|
|
211
|
-
*/
|
|
212
|
-
enableOverScroll: boolean;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
type TimingAnimationProps = {
|
|
216
|
-
animationType: typeof TimingAnimationType;
|
|
217
|
-
/**
|
|
218
|
-
* Configuration for the timing reanimated function
|
|
219
|
-
*/
|
|
220
|
-
animationConfig?: Partial<Animated.TimingConfig>;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
type SpringAnimationProps = {
|
|
224
|
-
animationType: typeof SpringAnimationType;
|
|
225
|
-
/**
|
|
226
|
-
* Configuration for the spring reanimated function
|
|
227
|
-
*/
|
|
228
|
-
animationConfig?: Partial<Animated.SpringConfig>;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
type Props<T> = CommonProps &
|
|
232
|
-
(FlatListOption<T> | ScrollViewOption | SectionListOption<T>) &
|
|
233
|
-
(TimingAnimationProps | SpringAnimationProps);
|
|
234
|
-
|
|
235
|
-
export class ScrollBottomSheet<T extends any> extends Component<Props<T>> {
|
|
236
|
-
static defaultProps = {
|
|
237
|
-
topInset: 0,
|
|
238
|
-
friction: 0.95,
|
|
239
|
-
animationType: "timing",
|
|
240
|
-
innerRef: React.createRef<AnimatedScrollableComponent>(),
|
|
241
|
-
enableOverScroll: false,
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Gesture Handler references
|
|
246
|
-
*/
|
|
247
|
-
private masterDrawer = React.createRef<TapGestureHandler>();
|
|
248
|
-
private drawerHandleRef = React.createRef<PanGestureHandler>();
|
|
249
|
-
private drawerContentRef = React.createRef<PanGestureHandler>();
|
|
250
|
-
private scrollComponentRef = React.createRef<NativeViewGestureHandler>();
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* ScrollView prop
|
|
254
|
-
*/
|
|
255
|
-
private onScrollBeginDrag: ScrollViewProps["onScrollBeginDrag"];
|
|
256
|
-
/**
|
|
257
|
-
* Pan gesture handler events for drawer handle and content
|
|
258
|
-
*/
|
|
259
|
-
private onHandleGestureEvent: PanGestureHandlerProperties["onGestureEvent"];
|
|
260
|
-
private onDrawerGestureEvent: PanGestureHandlerProperties["onGestureEvent"];
|
|
261
|
-
/**
|
|
262
|
-
* Main Animated Value that drives the top position of the UI drawer at any point in time
|
|
263
|
-
*/
|
|
264
|
-
private translateY: Animated.Node<number>;
|
|
265
|
-
/**
|
|
266
|
-
* Animated value that keeps track of the position: 0 => closed, 1 => opened
|
|
267
|
-
*/
|
|
268
|
-
private position: Animated.Node<number>;
|
|
269
|
-
/**
|
|
270
|
-
* Flag to indicate imperative snapping
|
|
271
|
-
*/
|
|
272
|
-
private isManuallySetValue: Animated.Value<number> = new Value(0);
|
|
273
|
-
/**
|
|
274
|
-
* Manual snapping amount
|
|
275
|
-
*/
|
|
276
|
-
private manualYOffset: Animated.Value<number> = new Value(0);
|
|
277
|
-
/**
|
|
278
|
-
* Keeps track of the current index
|
|
279
|
-
*/
|
|
280
|
-
private nextSnapIndex: Animated.Value<number>;
|
|
281
|
-
/**
|
|
282
|
-
* Deceleration rate of the scroll component. This is used only on Android to
|
|
283
|
-
* compensate the unexpected glide it gets sometimes.
|
|
284
|
-
*/
|
|
285
|
-
private decelerationRate: Animated.Value<number>;
|
|
286
|
-
private prevSnapIndex = -1;
|
|
287
|
-
private dragY = new Value(0);
|
|
288
|
-
private prevDragY = new Value(0);
|
|
289
|
-
private tempDestSnapPoint = new Value(0);
|
|
290
|
-
private isAndroid = new Value(Number(Platform.OS === "android"));
|
|
291
|
-
private animationClock = new Clock();
|
|
292
|
-
private animationPosition = new Value(0);
|
|
293
|
-
private animationFinished = new Value(0);
|
|
294
|
-
private animationFrameTime = new Value(0);
|
|
295
|
-
private velocityY = new Value(0);
|
|
296
|
-
private lastStartScrollY: Animated.Value<number> = new Value(0);
|
|
297
|
-
private prevTranslateYOffset: Animated.Value<number>;
|
|
298
|
-
private translationY: Animated.Value<number>;
|
|
299
|
-
private destSnapPoint = new Value(0);
|
|
300
|
-
|
|
301
|
-
private lastSnap: Animated.Value<number>;
|
|
302
|
-
private dragWithHandle = new Value(0);
|
|
303
|
-
private scrollUpAndPullDown = new Value(0);
|
|
304
|
-
private didGestureFinish: Animated.Node<0 | 1>;
|
|
305
|
-
private didScrollUpAndPullDown: Animated.Node<number>;
|
|
306
|
-
private setTranslationY: Animated.Node<number>;
|
|
307
|
-
private extraOffset: Animated.Node<number>;
|
|
308
|
-
private calculateNextSnapPoint: (
|
|
309
|
-
i?: number
|
|
310
|
-
) => number | Animated.Node<number>;
|
|
311
|
-
|
|
312
|
-
private scrollComponent: React.ComponentType<
|
|
313
|
-
FlatListProps<T> | ScrollViewProps | SectionListProps<T>
|
|
314
|
-
>;
|
|
315
|
-
|
|
316
|
-
convertPercentageToDp = (str: string) =>
|
|
317
|
-
(Number(str.split("%")[0]) * (windowHeight - this.props.topInset)) / 100;
|
|
318
|
-
|
|
319
|
-
constructor(props: Props<T>) {
|
|
320
|
-
super(props);
|
|
321
|
-
const { initialSnapIndex, animationType } = props;
|
|
322
|
-
|
|
323
|
-
const animationDriver = animationType === "timing" ? 0 : 1;
|
|
324
|
-
const animationDuration =
|
|
325
|
-
(props.animationType === "timing" && props.animationConfig?.duration) ||
|
|
326
|
-
DEFAULT_ANIMATION_DURATION;
|
|
327
|
-
|
|
328
|
-
const ScrollComponent = this.getScrollComponent();
|
|
329
|
-
// @ts-ignore
|
|
330
|
-
this.scrollComponent = Animated.createAnimatedComponent(ScrollComponent);
|
|
331
|
-
|
|
332
|
-
const snapPoints = this.getNormalisedSnapPoints();
|
|
333
|
-
const openPosition = snapPoints[0];
|
|
334
|
-
const closedPosition = this.props.enableOverScroll
|
|
335
|
-
? windowHeight
|
|
336
|
-
: snapPoints[snapPoints.length - 1];
|
|
337
|
-
const initialSnap = snapPoints[initialSnapIndex];
|
|
338
|
-
this.nextSnapIndex = new Value(initialSnapIndex);
|
|
339
|
-
|
|
340
|
-
const initialDecelerationRate = Platform.select({
|
|
341
|
-
android:
|
|
342
|
-
props.initialSnapIndex === 0 ? ANDROID_NORMAL_DECELERATION_RATE : 0,
|
|
343
|
-
ios: IOS_NORMAL_DECELERATION_RATE,
|
|
344
|
-
});
|
|
345
|
-
this.decelerationRate = new Value(initialDecelerationRate);
|
|
346
|
-
|
|
347
|
-
//@ts-ignore
|
|
348
|
-
const handleGestureState = new Value<GestureState>(-1);
|
|
349
|
-
//@ts-ignore
|
|
350
|
-
const handleOldGestureState = new Value<GestureState>(-1);
|
|
351
|
-
//@ts-ignore
|
|
352
|
-
const drawerGestureState = new Value<GestureState>(-1);
|
|
353
|
-
//@ts-ignore
|
|
354
|
-
const drawerOldGestureState = new Value<GestureState>(-1);
|
|
355
|
-
|
|
356
|
-
const lastSnapInRange = new Value(1);
|
|
357
|
-
this.prevTranslateYOffset = new Value(initialSnap);
|
|
358
|
-
this.translationY = new Value(initialSnap);
|
|
359
|
-
|
|
360
|
-
this.lastSnap = new Value(initialSnap);
|
|
361
|
-
|
|
362
|
-
this.onHandleGestureEvent = event([
|
|
363
|
-
{
|
|
364
|
-
nativeEvent: {
|
|
365
|
-
translationY: this.dragY,
|
|
366
|
-
oldState: handleOldGestureState,
|
|
367
|
-
state: handleGestureState,
|
|
368
|
-
velocityY: this.velocityY,
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
]);
|
|
372
|
-
this.onDrawerGestureEvent = event([
|
|
373
|
-
{
|
|
374
|
-
nativeEvent: {
|
|
375
|
-
translationY: this.dragY,
|
|
376
|
-
oldState: drawerOldGestureState,
|
|
377
|
-
state: drawerGestureState,
|
|
378
|
-
velocityY: this.velocityY,
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
]);
|
|
382
|
-
this.onScrollBeginDrag = event([
|
|
383
|
-
{
|
|
384
|
-
nativeEvent: {
|
|
385
|
-
contentOffset: { y: this.lastStartScrollY },
|
|
386
|
-
},
|
|
387
|
-
},
|
|
388
|
-
]);
|
|
389
|
-
|
|
390
|
-
const didHandleGestureBegin = eq(handleGestureState, GestureState.ACTIVE);
|
|
391
|
-
|
|
392
|
-
const isAnimationInterrupted = and(
|
|
393
|
-
or(
|
|
394
|
-
eq(handleGestureState, GestureState.BEGAN),
|
|
395
|
-
eq(drawerGestureState, GestureState.BEGAN),
|
|
396
|
-
and(
|
|
397
|
-
eq(this.isAndroid, 0),
|
|
398
|
-
eq(animationDriver, 1),
|
|
399
|
-
or(
|
|
400
|
-
eq(drawerGestureState, GestureState.ACTIVE),
|
|
401
|
-
eq(handleGestureState, GestureState.ACTIVE)
|
|
402
|
-
)
|
|
403
|
-
)
|
|
404
|
-
),
|
|
405
|
-
clockRunning(this.animationClock)
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
this.didGestureFinish = or(
|
|
409
|
-
and(
|
|
410
|
-
eq(handleOldGestureState, GestureState.ACTIVE),
|
|
411
|
-
eq(handleGestureState, GestureState.END)
|
|
412
|
-
),
|
|
413
|
-
and(
|
|
414
|
-
eq(drawerOldGestureState, GestureState.ACTIVE),
|
|
415
|
-
eq(drawerGestureState, GestureState.END)
|
|
416
|
-
)
|
|
417
|
-
);
|
|
418
|
-
|
|
419
|
-
// Function that determines if the last snap point is in the range {snapPoints}
|
|
420
|
-
// In the case of interruptions in the middle of an animation, we'll get
|
|
421
|
-
// lastSnap values outside the range
|
|
422
|
-
const isLastSnapPointInRange = (i: number = 0): Animated.Node<number> =>
|
|
423
|
-
i === snapPoints.length
|
|
424
|
-
? lastSnapInRange
|
|
425
|
-
: cond(
|
|
426
|
-
eq(this.lastSnap, snapPoints[i]),
|
|
427
|
-
[set(lastSnapInRange, 1)],
|
|
428
|
-
isLastSnapPointInRange(i + 1)
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
const scrollY = [
|
|
432
|
-
set(lastSnapInRange, 0),
|
|
433
|
-
isLastSnapPointInRange(),
|
|
434
|
-
cond(
|
|
435
|
-
or(
|
|
436
|
-
didHandleGestureBegin,
|
|
437
|
-
and(
|
|
438
|
-
this.isManuallySetValue,
|
|
439
|
-
not(eq(this.manualYOffset, snapPoints[0]))
|
|
440
|
-
)
|
|
441
|
-
),
|
|
442
|
-
[set(this.dragWithHandle, 1), 0]
|
|
443
|
-
),
|
|
444
|
-
cond(
|
|
445
|
-
// This is to account for a continuous scroll on the drawer from a snap point
|
|
446
|
-
// Different than top, bringing the drawer to the top position, so that if we
|
|
447
|
-
// change scroll direction without releasing the gesture, it doesn't pull down the drawer again
|
|
448
|
-
and(
|
|
449
|
-
eq(this.dragWithHandle, 1),
|
|
450
|
-
greaterThan(snapPoints[0], add(this.lastSnap, this.dragY)),
|
|
451
|
-
and(not(eq(this.lastSnap, snapPoints[0])), lastSnapInRange)
|
|
452
|
-
),
|
|
453
|
-
[
|
|
454
|
-
set(this.lastSnap, snapPoints[0]),
|
|
455
|
-
set(this.dragWithHandle, 0),
|
|
456
|
-
this.lastStartScrollY,
|
|
457
|
-
],
|
|
458
|
-
cond(eq(this.dragWithHandle, 1), 0, this.lastStartScrollY)
|
|
459
|
-
),
|
|
460
|
-
];
|
|
461
|
-
|
|
462
|
-
this.didScrollUpAndPullDown = cond(
|
|
463
|
-
and(
|
|
464
|
-
greaterOrEq(this.dragY, this.lastStartScrollY),
|
|
465
|
-
greaterThan(this.lastStartScrollY, 0)
|
|
466
|
-
),
|
|
467
|
-
set(this.scrollUpAndPullDown, 1)
|
|
468
|
-
);
|
|
469
|
-
|
|
470
|
-
this.setTranslationY = cond(
|
|
471
|
-
and(
|
|
472
|
-
not(this.dragWithHandle),
|
|
473
|
-
not(greaterOrEq(this.dragY, this.lastStartScrollY))
|
|
474
|
-
),
|
|
475
|
-
set(this.translationY, sub(this.dragY, this.lastStartScrollY)),
|
|
476
|
-
set(this.translationY, this.dragY)
|
|
477
|
-
);
|
|
478
|
-
|
|
479
|
-
this.extraOffset = cond(
|
|
480
|
-
eq(this.scrollUpAndPullDown, 1),
|
|
481
|
-
this.lastStartScrollY,
|
|
482
|
-
0
|
|
483
|
-
);
|
|
484
|
-
const endOffsetY = add(
|
|
485
|
-
this.lastSnap,
|
|
486
|
-
this.translationY,
|
|
487
|
-
multiply(1 - props.friction, this.velocityY)
|
|
488
|
-
);
|
|
489
|
-
|
|
490
|
-
this.calculateNextSnapPoint = (i = 0): Animated.Node<number> | number =>
|
|
491
|
-
i === snapPoints.length
|
|
492
|
-
? this.tempDestSnapPoint
|
|
493
|
-
: cond(
|
|
494
|
-
greaterThan(
|
|
495
|
-
abs(sub(this.tempDestSnapPoint, endOffsetY)),
|
|
496
|
-
abs(sub(add(snapPoints[i], this.extraOffset), endOffsetY))
|
|
497
|
-
),
|
|
498
|
-
[
|
|
499
|
-
set(this.tempDestSnapPoint, add(snapPoints[i], this.extraOffset)),
|
|
500
|
-
set(this.nextSnapIndex, i),
|
|
501
|
-
this.calculateNextSnapPoint(i + 1),
|
|
502
|
-
],
|
|
503
|
-
this.calculateNextSnapPoint(i + 1)
|
|
504
|
-
);
|
|
505
|
-
|
|
506
|
-
const runAnimation = ({
|
|
507
|
-
clock,
|
|
508
|
-
from,
|
|
509
|
-
to,
|
|
510
|
-
position,
|
|
511
|
-
finished,
|
|
512
|
-
velocity,
|
|
513
|
-
frameTime,
|
|
514
|
-
}: TimingParams) => {
|
|
515
|
-
const state = {
|
|
516
|
-
finished,
|
|
517
|
-
velocity: new Value(0),
|
|
518
|
-
position,
|
|
519
|
-
time: new Value(0),
|
|
520
|
-
frameTime,
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
const timingConfig = {
|
|
524
|
-
duration: animationDuration,
|
|
525
|
-
easing:
|
|
526
|
-
(props.animationType === "timing" && props.animationConfig?.easing) ||
|
|
527
|
-
DEFAULT_EASING,
|
|
528
|
-
toValue: new Value(0),
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
const springConfig = {
|
|
532
|
-
...DEFAULT_SPRING_PARAMS,
|
|
533
|
-
...((props.animationType === "spring" && props.animationConfig) || {}),
|
|
534
|
-
toValue: new Value(0),
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
return [
|
|
538
|
-
cond(and(not(clockRunning(clock)), not(eq(finished, 1))), [
|
|
539
|
-
// If the clock isn't running, we reset all the animation params and start the clock
|
|
540
|
-
set(state.finished, 0),
|
|
541
|
-
set(state.velocity, velocity),
|
|
542
|
-
set(state.time, 0),
|
|
543
|
-
set(state.position, from),
|
|
544
|
-
set(state.frameTime, 0),
|
|
545
|
-
set(timingConfig.toValue, to),
|
|
546
|
-
set(springConfig.toValue, to),
|
|
547
|
-
startClock(clock),
|
|
548
|
-
]),
|
|
549
|
-
// We run the step here that is going to update position
|
|
550
|
-
cond(
|
|
551
|
-
eq(animationDriver, 0),
|
|
552
|
-
//@ts-ignore
|
|
553
|
-
timing(clock, state, timingConfig),
|
|
554
|
-
spring(clock, state, springConfig)
|
|
555
|
-
),
|
|
556
|
-
cond(
|
|
557
|
-
state.finished,
|
|
558
|
-
[
|
|
559
|
-
call([this.nextSnapIndex], ([value]) => {
|
|
560
|
-
if (value !== this.prevSnapIndex) {
|
|
561
|
-
this.props.onSettle?.(value);
|
|
562
|
-
}
|
|
563
|
-
this.prevSnapIndex = value;
|
|
564
|
-
}),
|
|
565
|
-
// Resetting appropriate values
|
|
566
|
-
set(drawerOldGestureState, GestureState.END),
|
|
567
|
-
set(handleOldGestureState, GestureState.END),
|
|
568
|
-
set(this.prevTranslateYOffset, state.position),
|
|
569
|
-
cond(eq(this.scrollUpAndPullDown, 1), [
|
|
570
|
-
set(
|
|
571
|
-
this.prevTranslateYOffset,
|
|
572
|
-
sub(this.prevTranslateYOffset, this.lastStartScrollY)
|
|
573
|
-
),
|
|
574
|
-
set(this.lastStartScrollY, 0),
|
|
575
|
-
set(this.scrollUpAndPullDown, 0),
|
|
576
|
-
]),
|
|
577
|
-
cond(eq(this.destSnapPoint, snapPoints[0]), [
|
|
578
|
-
set(this.dragWithHandle, 0),
|
|
579
|
-
]),
|
|
580
|
-
set(this.isManuallySetValue, 0),
|
|
581
|
-
set(this.manualYOffset, 0),
|
|
582
|
-
stopClock(clock),
|
|
583
|
-
this.prevTranslateYOffset,
|
|
584
|
-
],
|
|
585
|
-
// We made the block return the updated position,
|
|
586
|
-
state.position
|
|
587
|
-
),
|
|
588
|
-
];
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
const translateYOffset = cond(
|
|
592
|
-
isAnimationInterrupted,
|
|
593
|
-
[
|
|
594
|
-
// set(prevTranslateYOffset, animationPosition) should only run if we are
|
|
595
|
-
// interrupting an animation when the drawer is currently in a different
|
|
596
|
-
// position than the top
|
|
597
|
-
cond(
|
|
598
|
-
or(
|
|
599
|
-
this.dragWithHandle,
|
|
600
|
-
greaterOrEq(abs(this.prevDragY), this.lastStartScrollY)
|
|
601
|
-
),
|
|
602
|
-
set(this.prevTranslateYOffset, this.animationPosition)
|
|
603
|
-
),
|
|
604
|
-
set(this.animationFinished, 1),
|
|
605
|
-
set(this.translationY, 0),
|
|
606
|
-
// Resetting appropriate values
|
|
607
|
-
set(drawerOldGestureState, GestureState.END),
|
|
608
|
-
set(handleOldGestureState, GestureState.END),
|
|
609
|
-
// By forcing that frameTime exceeds duration, it has the effect of stopping the animation
|
|
610
|
-
set(this.animationFrameTime, add(animationDuration, 1000)),
|
|
611
|
-
set(this.velocityY, 0),
|
|
612
|
-
stopClock(this.animationClock),
|
|
613
|
-
this.prevTranslateYOffset,
|
|
614
|
-
],
|
|
615
|
-
cond(
|
|
616
|
-
or(
|
|
617
|
-
this.didGestureFinish,
|
|
618
|
-
this.isManuallySetValue,
|
|
619
|
-
clockRunning(this.animationClock)
|
|
620
|
-
),
|
|
621
|
-
[
|
|
622
|
-
runAnimation({
|
|
623
|
-
clock: this.animationClock,
|
|
624
|
-
from: cond(
|
|
625
|
-
this.isManuallySetValue,
|
|
626
|
-
this.prevTranslateYOffset,
|
|
627
|
-
add(this.prevTranslateYOffset, this.translationY)
|
|
628
|
-
),
|
|
629
|
-
to: this.destSnapPoint,
|
|
630
|
-
position: this.animationPosition,
|
|
631
|
-
finished: this.animationFinished,
|
|
632
|
-
frameTime: this.animationFrameTime,
|
|
633
|
-
velocity: this.velocityY,
|
|
634
|
-
}),
|
|
635
|
-
],
|
|
636
|
-
[
|
|
637
|
-
set(this.animationFrameTime, 0),
|
|
638
|
-
set(this.animationFinished, 0),
|
|
639
|
-
// @ts-ignore
|
|
640
|
-
this.prevTranslateYOffset,
|
|
641
|
-
]
|
|
642
|
-
)
|
|
643
|
-
);
|
|
644
|
-
|
|
645
|
-
this.translateY = interpolate(
|
|
646
|
-
add(translateYOffset, this.dragY, multiply(scrollY, -1)),
|
|
647
|
-
{
|
|
648
|
-
inputRange: [openPosition, closedPosition],
|
|
649
|
-
outputRange: [openPosition, closedPosition],
|
|
650
|
-
extrapolate: Extrapolate.CLAMP,
|
|
651
|
-
}
|
|
652
|
-
);
|
|
653
|
-
|
|
654
|
-
this.position = interpolate(this.translateY, {
|
|
655
|
-
inputRange: [openPosition, snapPoints[snapPoints.length - 1]],
|
|
656
|
-
outputRange: [1, 0],
|
|
657
|
-
extrapolate: Extrapolate.CLAMP,
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
private getNormalisedSnapPoints = () => {
|
|
662
|
-
return this.props.snapPoints.map((p) => {
|
|
663
|
-
if (typeof p === "string") {
|
|
664
|
-
return this.convertPercentageToDp(p);
|
|
665
|
-
} else if (typeof p === "number") {
|
|
666
|
-
return p;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
throw new Error(
|
|
670
|
-
`Invalid type for value ${p}: ${typeof p}. It should be either a percentage string or a number`
|
|
671
|
-
);
|
|
672
|
-
});
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
private getScrollComponent = () => {
|
|
676
|
-
switch (this.props.componentType) {
|
|
677
|
-
case "FlatList":
|
|
678
|
-
return FlatList;
|
|
679
|
-
case "ScrollView":
|
|
680
|
-
return ScrollView;
|
|
681
|
-
case "SectionList":
|
|
682
|
-
return SectionList;
|
|
683
|
-
default:
|
|
684
|
-
throw new Error(
|
|
685
|
-
"Component type not supported: it should be one of `FlatList`, `ScrollView` or `SectionList`"
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
snapTo = (index: number) => {
|
|
691
|
-
const snapPoints = this.getNormalisedSnapPoints();
|
|
692
|
-
this.isManuallySetValue.setValue(1);
|
|
693
|
-
this.manualYOffset.setValue(snapPoints[index]);
|
|
694
|
-
this.nextSnapIndex.setValue(index);
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
render() {
|
|
698
|
-
const { renderHandle, initialSnapIndex, containerStyle, ...rest } =
|
|
699
|
-
this.props;
|
|
700
|
-
const AnimatedScrollableComponent = this.scrollComponent;
|
|
701
|
-
const normalisedSnapPoints = this.getNormalisedSnapPoints();
|
|
702
|
-
const initialSnap = normalisedSnapPoints[initialSnapIndex];
|
|
703
|
-
|
|
704
|
-
const Content = (
|
|
705
|
-
<Animated.View
|
|
706
|
-
style={[
|
|
707
|
-
StyleSheet.absoluteFillObject,
|
|
708
|
-
containerStyle,
|
|
709
|
-
// @ts-ignore
|
|
710
|
-
{
|
|
711
|
-
transform: [{ translateY: this.translateY }],
|
|
712
|
-
},
|
|
713
|
-
]}
|
|
714
|
-
>
|
|
715
|
-
<PanGestureHandler
|
|
716
|
-
ref={this.drawerHandleRef}
|
|
717
|
-
shouldCancelWhenOutside={false}
|
|
718
|
-
simultaneousHandlers={this.masterDrawer}
|
|
719
|
-
onGestureEvent={this.onHandleGestureEvent}
|
|
720
|
-
onHandlerStateChange={this.onHandleGestureEvent}
|
|
721
|
-
>
|
|
722
|
-
<Animated.View>{renderHandle()}</Animated.View>
|
|
723
|
-
</PanGestureHandler>
|
|
724
|
-
<PanGestureHandler
|
|
725
|
-
ref={this.drawerContentRef}
|
|
726
|
-
simultaneousHandlers={[this.scrollComponentRef, this.masterDrawer]}
|
|
727
|
-
shouldCancelWhenOutside={false}
|
|
728
|
-
onGestureEvent={this.onDrawerGestureEvent}
|
|
729
|
-
onHandlerStateChange={this.onDrawerGestureEvent}
|
|
730
|
-
>
|
|
731
|
-
<Animated.View style={styles.container}>
|
|
732
|
-
<NativeViewGestureHandler
|
|
733
|
-
ref={this.scrollComponentRef}
|
|
734
|
-
waitFor={this.masterDrawer}
|
|
735
|
-
simultaneousHandlers={this.drawerContentRef}
|
|
736
|
-
>
|
|
737
|
-
<AnimatedScrollableComponent
|
|
738
|
-
overScrollMode="never"
|
|
739
|
-
bounces={false}
|
|
740
|
-
{...rest}
|
|
741
|
-
ref={this.props.innerRef}
|
|
742
|
-
// @ts-ignore
|
|
743
|
-
decelerationRate={this.decelerationRate}
|
|
744
|
-
onScrollBeginDrag={this.onScrollBeginDrag}
|
|
745
|
-
scrollEventThrottle={1}
|
|
746
|
-
contentContainerStyle={[
|
|
747
|
-
rest.contentContainerStyle,
|
|
748
|
-
{ paddingBottom: this.getNormalisedSnapPoints()[0] },
|
|
749
|
-
]}
|
|
750
|
-
/>
|
|
751
|
-
</NativeViewGestureHandler>
|
|
752
|
-
</Animated.View>
|
|
753
|
-
</PanGestureHandler>
|
|
754
|
-
{this.props.animatedPosition && (
|
|
755
|
-
<Animated.Code
|
|
756
|
-
exec={onChange(
|
|
757
|
-
this.position,
|
|
758
|
-
set(this.props.animatedPosition, this.position)
|
|
759
|
-
)}
|
|
760
|
-
/>
|
|
761
|
-
)}
|
|
762
|
-
<Animated.Code
|
|
763
|
-
exec={onChange(
|
|
764
|
-
this.dragY,
|
|
765
|
-
cond(not(eq(this.dragY, 0)), set(this.prevDragY, this.dragY))
|
|
766
|
-
)}
|
|
767
|
-
/>
|
|
768
|
-
<Animated.Code
|
|
769
|
-
exec={onChange(
|
|
770
|
-
this.didGestureFinish,
|
|
771
|
-
cond(this.didGestureFinish, [
|
|
772
|
-
this.didScrollUpAndPullDown,
|
|
773
|
-
this.setTranslationY,
|
|
774
|
-
set(
|
|
775
|
-
this.tempDestSnapPoint,
|
|
776
|
-
add(normalisedSnapPoints[0], this.extraOffset)
|
|
777
|
-
),
|
|
778
|
-
set(this.nextSnapIndex, 0),
|
|
779
|
-
set(this.destSnapPoint, this.calculateNextSnapPoint()),
|
|
780
|
-
cond(
|
|
781
|
-
and(
|
|
782
|
-
greaterThan(this.dragY, this.lastStartScrollY),
|
|
783
|
-
this.isAndroid,
|
|
784
|
-
not(this.dragWithHandle)
|
|
785
|
-
),
|
|
786
|
-
call([], () => {
|
|
787
|
-
// This prevents the scroll glide from happening on Android when pulling down with inertia.
|
|
788
|
-
// It's not perfect, but does the job for now
|
|
789
|
-
const { method, args } =
|
|
790
|
-
imperativeScrollOptions[this.props.componentType];
|
|
791
|
-
// @ts-ignore
|
|
792
|
-
const node = this.props.innerRef.current as any;
|
|
793
|
-
|
|
794
|
-
if (
|
|
795
|
-
node &&
|
|
796
|
-
node[method] &&
|
|
797
|
-
((this.props.componentType === "FlatList" &&
|
|
798
|
-
(this.props?.data?.length || 0) > 0) ||
|
|
799
|
-
(this.props.componentType === "SectionList" &&
|
|
800
|
-
this.props.sections.length > 0) ||
|
|
801
|
-
this.props.componentType === "ScrollView")
|
|
802
|
-
) {
|
|
803
|
-
node[method](args);
|
|
804
|
-
}
|
|
805
|
-
})
|
|
806
|
-
),
|
|
807
|
-
set(this.dragY, 0),
|
|
808
|
-
set(this.velocityY, 0),
|
|
809
|
-
set(
|
|
810
|
-
this.lastSnap,
|
|
811
|
-
sub(
|
|
812
|
-
this.destSnapPoint,
|
|
813
|
-
cond(
|
|
814
|
-
eq(this.scrollUpAndPullDown, 1),
|
|
815
|
-
this.lastStartScrollY,
|
|
816
|
-
0
|
|
817
|
-
)
|
|
818
|
-
)
|
|
819
|
-
),
|
|
820
|
-
call([this.lastSnap], ([value]) => {
|
|
821
|
-
// This is the TapGHandler trick
|
|
822
|
-
// @ts-ignore
|
|
823
|
-
this.masterDrawer?.current?.setNativeProps({
|
|
824
|
-
maxDeltaY: value - this.getNormalisedSnapPoints()[0],
|
|
825
|
-
});
|
|
826
|
-
}),
|
|
827
|
-
set(
|
|
828
|
-
this.decelerationRate,
|
|
829
|
-
cond(
|
|
830
|
-
eq(this.isAndroid, 1),
|
|
831
|
-
cond(
|
|
832
|
-
eq(this.lastSnap, normalisedSnapPoints[0]),
|
|
833
|
-
ANDROID_NORMAL_DECELERATION_RATE,
|
|
834
|
-
0
|
|
835
|
-
),
|
|
836
|
-
IOS_NORMAL_DECELERATION_RATE
|
|
837
|
-
)
|
|
838
|
-
),
|
|
839
|
-
])
|
|
840
|
-
)}
|
|
841
|
-
/>
|
|
842
|
-
<Animated.Code
|
|
843
|
-
exec={onChange(this.isManuallySetValue, [
|
|
844
|
-
cond(
|
|
845
|
-
this.isManuallySetValue,
|
|
846
|
-
[
|
|
847
|
-
set(this.destSnapPoint, this.manualYOffset),
|
|
848
|
-
set(this.animationFinished, 0),
|
|
849
|
-
set(this.lastSnap, this.manualYOffset),
|
|
850
|
-
call([this.lastSnap], ([value]) => {
|
|
851
|
-
// This is the TapGHandler trick
|
|
852
|
-
// @ts-ignore
|
|
853
|
-
this.masterDrawer?.current?.setNativeProps({
|
|
854
|
-
maxDeltaY: value - this.getNormalisedSnapPoints()[0],
|
|
855
|
-
});
|
|
856
|
-
}),
|
|
857
|
-
],
|
|
858
|
-
[set(this.nextSnapIndex, 0)]
|
|
859
|
-
),
|
|
860
|
-
])}
|
|
861
|
-
/>
|
|
862
|
-
</Animated.View>
|
|
863
|
-
);
|
|
864
|
-
|
|
865
|
-
// On Android, having an intermediary view with pointerEvents="box-none", breaks the
|
|
866
|
-
// waitFor logic
|
|
867
|
-
if (Platform.OS === "android") {
|
|
868
|
-
return (
|
|
869
|
-
<TapGestureHandler
|
|
870
|
-
maxDurationMs={100000}
|
|
871
|
-
ref={this.masterDrawer}
|
|
872
|
-
maxDeltaY={initialSnap - this.getNormalisedSnapPoints()[0]}
|
|
873
|
-
shouldCancelWhenOutside={false}
|
|
874
|
-
>
|
|
875
|
-
{Content}
|
|
876
|
-
</TapGestureHandler>
|
|
877
|
-
);
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
// On iOS, We need to wrap the content on a view with PointerEvents box-none
|
|
881
|
-
// So that we can start scrolling automatically when reaching the top without
|
|
882
|
-
// Stopping the gesture
|
|
883
|
-
return (
|
|
884
|
-
<TapGestureHandler
|
|
885
|
-
maxDurationMs={100000}
|
|
886
|
-
ref={this.masterDrawer}
|
|
887
|
-
maxDeltaY={initialSnap - this.getNormalisedSnapPoints()[0]}
|
|
888
|
-
>
|
|
889
|
-
<View style={StyleSheet.absoluteFillObject} pointerEvents="box-none">
|
|
890
|
-
{Content}
|
|
891
|
-
</View>
|
|
892
|
-
</TapGestureHandler>
|
|
893
|
-
);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
export default ScrollBottomSheet;
|
|
898
|
-
|
|
899
|
-
const styles = StyleSheet.create({
|
|
900
|
-
container: {
|
|
901
|
-
flex: 1,
|
|
902
|
-
},
|
|
903
|
-
});
|