react-native-varia 0.0.1
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/README.md +53 -0
- package/bin/cli.js +200 -0
- package/lib/components/Badge.tsx +96 -0
- package/lib/components/Button.tsx +131 -0
- package/lib/components/CircleProgress.tsx +180 -0
- package/lib/components/Divider.tsx +43 -0
- package/lib/components/GradientBackground.tsx +68 -0
- package/lib/components/GradientText.tsx +121 -0
- package/lib/components/Icon.tsx +13 -0
- package/lib/components/IconWrapper.tsx +109 -0
- package/lib/components/Input.tsx +120 -0
- package/lib/components/Link.tsx +87 -0
- package/lib/components/Modal.tsx +157 -0
- package/lib/components/ReText.tsx +124 -0
- package/lib/components/Slider.tsx +334 -0
- package/lib/components/Slideshow.tsx +317 -0
- package/lib/components/SlidingDrawer.tsx +307 -0
- package/lib/components/Spinner.tsx +44 -0
- package/lib/components/Switch.tsx +224 -0
- package/lib/components/Text.tsx +107 -0
- package/lib/components/index.tsx +83 -0
- package/lib/mixins.ts +180 -0
- package/lib/patterns/index.tsx +426 -0
- package/lib/theme/Badge.recipe.tsx +68 -0
- package/lib/theme/Button.recipe-old.tsx +67 -0
- package/lib/theme/Button.recipe.tsx +83 -0
- package/lib/theme/CircleProgress.recipe.tsx +42 -0
- package/lib/theme/GradientBackground.recipe.tsx +38 -0
- package/lib/theme/GradientText.recipe.tsx +49 -0
- package/lib/theme/Icon.recipe.tsx +122 -0
- package/lib/theme/IconWrapper.recipe.tsx +121 -0
- package/lib/theme/Input.recipe.tsx +110 -0
- package/lib/theme/Link.recipe.tsx +51 -0
- package/lib/theme/Modal.recipe.tsx +34 -0
- package/lib/theme/ReText.recipe.tsx +7 -0
- package/lib/theme/Slider.recipe.tsx +226 -0
- package/lib/theme/Slideshow.recipe.tsx +142 -0
- package/lib/theme/SlidingDrawer.recipe.tsx +91 -0
- package/lib/theme/Spinner.recipe.tsx +8 -0
- package/lib/theme/Switch.recipe.tsx +70 -0
- package/lib/theme/Text.recipe.tsx +10 -0
- package/lib/types.ts +70 -0
- package/lib/utils.ts +80 -0
- package/package.json +18 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
forwardRef,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import { View } from 'react-native';
|
|
9
|
+
import Animated, {
|
|
10
|
+
useAnimatedReaction,
|
|
11
|
+
useAnimatedStyle,
|
|
12
|
+
useSharedValue,
|
|
13
|
+
withSpring,
|
|
14
|
+
withTiming,
|
|
15
|
+
} from 'react-native-reanimated';
|
|
16
|
+
import {runOnJS} from 'react-native-worklets';
|
|
17
|
+
import { StyleSheet, UnistylesVariants } from 'react-native-unistyles';
|
|
18
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
19
|
+
import { SlideshowStyles, SlideshowTokens } from '../theme/Slideshow.recipe';
|
|
20
|
+
import { SlidingDrawerTokens } from '../theme/SlidingDrawer.recipe';
|
|
21
|
+
// import type { SpringConfig } from 'react-native-reanimated/lib/typescript/animation/springUtils';
|
|
22
|
+
// import type {
|
|
23
|
+
// SlideshowAnimationVariants,
|
|
24
|
+
// SlideshowColorSchemeVariants,
|
|
25
|
+
// } from '../style/styles/types';
|
|
26
|
+
// import { type Tokens } from '../style/tokenManager';
|
|
27
|
+
// import { useTokens } from '../style/useTokens';
|
|
28
|
+
|
|
29
|
+
export type SlideshowRef = {
|
|
30
|
+
handleNext: () => void | null;
|
|
31
|
+
handlePrev: () => void | null;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type SlideshowVariants = UnistylesVariants<typeof SlideshowStyles>;
|
|
35
|
+
|
|
36
|
+
type SlideshowProps = SlideshowVariants & {
|
|
37
|
+
animation?: keyof typeof SlidingDrawerTokens.variants.animation;
|
|
38
|
+
// spacing?: SlideshowSlideContainerSpacing;
|
|
39
|
+
allowGestures?: boolean;
|
|
40
|
+
flex?: number;
|
|
41
|
+
onSlideChange?: (index: number) => void;
|
|
42
|
+
// slideContainerType?: SlideshowSlideContainerColorScheme;
|
|
43
|
+
slideContainerType?: any;
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
ref?: React.RefObject<SlideshowRef>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// const slideshowTokens = getTokens('slideshow');
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Flex Wrapper
|
|
52
|
+
* @param colorScheme ? string: color scheme
|
|
53
|
+
* @param animation ? string: animation props
|
|
54
|
+
* @param allowGestures ? boolean: allow gestures
|
|
55
|
+
* @param flex ? number: flex value
|
|
56
|
+
* @param onSlideChange ? function: callback function
|
|
57
|
+
* @param slideContainerType ? color scheme
|
|
58
|
+
* @param children ? react children
|
|
59
|
+
* @param ref ? react ref
|
|
60
|
+
* @returns Slideshow react component
|
|
61
|
+
*/
|
|
62
|
+
const Slideshow = ({
|
|
63
|
+
allowGestures = true,
|
|
64
|
+
flex = 1,
|
|
65
|
+
onSlideChange,
|
|
66
|
+
colorPalette,
|
|
67
|
+
animation = SlideshowTokens.defaultProps.animation,
|
|
68
|
+
spacing = 'none',
|
|
69
|
+
// slideContainerType = 'primary',
|
|
70
|
+
children,
|
|
71
|
+
ref
|
|
72
|
+
} : SlideshowProps,
|
|
73
|
+
) => {
|
|
74
|
+
// const slideshowTokens = useTokens('slideshow')();
|
|
75
|
+
|
|
76
|
+
// const resolvedColorScheme =
|
|
77
|
+
// colorScheme ??
|
|
78
|
+
// (slideshowTokens.defaultProps
|
|
79
|
+
// .colorScheme as keyof SlideshowColorSchemeVariants);
|
|
80
|
+
|
|
81
|
+
// const resolvedAnimation =
|
|
82
|
+
// animation ??
|
|
83
|
+
// (SlideshowTokens.defaultProps.animation
|
|
84
|
+
// // as keyof SlideshowTokens.variants.animation
|
|
85
|
+
// );
|
|
86
|
+
|
|
87
|
+
// const resolvedSpacing =
|
|
88
|
+
// spacing ??
|
|
89
|
+
// (slideshowTokens.defaultProps
|
|
90
|
+
// .spacing as keyof SlideshowSlideContainerSpacing);
|
|
91
|
+
|
|
92
|
+
const slides = Children.toArray(children);
|
|
93
|
+
const NUM_PAGES = slides.length; // Total number of slides
|
|
94
|
+
const scalingFactor = 1 / NUM_PAGES;
|
|
95
|
+
|
|
96
|
+
// styles.useVariants({
|
|
97
|
+
// colorScheme: resolvedColorScheme,
|
|
98
|
+
// spacing,
|
|
99
|
+
// });
|
|
100
|
+
|
|
101
|
+
SlideshowStyles.useVariants({
|
|
102
|
+
colorPalette,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const [containerWidth, setContainerWidth] = useState(0); // To store the container width
|
|
106
|
+
|
|
107
|
+
const slideWidth = 100 / NUM_PAGES; // Each slide's width as a percentage
|
|
108
|
+
const translateX = useSharedValue(0); // Tracks the animated X position
|
|
109
|
+
const currentSlide = useSharedValue(0); // Tracks the current slide index
|
|
110
|
+
|
|
111
|
+
type AnimationType = 'withSpring' | 'withTiming';
|
|
112
|
+
|
|
113
|
+
const animations = {
|
|
114
|
+
withSpring,
|
|
115
|
+
withTiming,
|
|
116
|
+
};
|
|
117
|
+
const animationVariant =
|
|
118
|
+
SlideshowTokens.variants?.animation && animation
|
|
119
|
+
? SlideshowTokens.variants.animation[animation]
|
|
120
|
+
: {
|
|
121
|
+
type: 'withSpring' as AnimationType, // Type assertion ensures 'withSpring' is a valid value
|
|
122
|
+
props: {
|
|
123
|
+
damping: 15,
|
|
124
|
+
stiffness: 100,
|
|
125
|
+
mass: 1,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const animateSlide = (destination: number) => {
|
|
130
|
+
'worklet';
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
animationVariant &&
|
|
134
|
+
animationVariant.type &&
|
|
135
|
+
animations[animationVariant.type]
|
|
136
|
+
) {
|
|
137
|
+
translateX.value = animations[animationVariant.type](
|
|
138
|
+
destination,
|
|
139
|
+
animationVariant.props
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Optional callback for onSlideChange
|
|
143
|
+
if (onSlideChange) {
|
|
144
|
+
runOnJS(onSlideChange)((destination / 100) * NUM_PAGES * -1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
useAnimatedReaction(
|
|
150
|
+
() => currentSlide.value,
|
|
151
|
+
() => {
|
|
152
|
+
animateSlide(-currentSlide.value * slideWidth);
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Move to the previous slide
|
|
157
|
+
const handlePrev = () => {
|
|
158
|
+
'worklet';
|
|
159
|
+
if (currentSlide.value > 0) {
|
|
160
|
+
currentSlide.value -= 1;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
// Move to the next slide
|
|
164
|
+
const handleNext = () => {
|
|
165
|
+
'worklet';
|
|
166
|
+
if (currentSlide.value < NUM_PAGES - 1) {
|
|
167
|
+
currentSlide.value += 1;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const context = useSharedValue({ x: 0, snapPoint: 0 });
|
|
172
|
+
const velocityThreshold = 500; // Velocity threshold in px/s
|
|
173
|
+
|
|
174
|
+
const slideGesture = Gesture.Pan()
|
|
175
|
+
.enabled(allowGestures)
|
|
176
|
+
.onBegin(() => {
|
|
177
|
+
context.value.x = translateX.value;
|
|
178
|
+
})
|
|
179
|
+
.onUpdate((e) => {
|
|
180
|
+
const pixelToPercentage =
|
|
181
|
+
(e.translationX / containerWidth) * 100 * scalingFactor; // Adjusted conversion (px to %)
|
|
182
|
+
translateX.value = context.value.x + pixelToPercentage;
|
|
183
|
+
})
|
|
184
|
+
.onEnd(({ velocityX, translationX }) => {
|
|
185
|
+
const pixelToPercentage =
|
|
186
|
+
(translationX / containerWidth) * 100 * scalingFactor;
|
|
187
|
+
const slideWidthPercentage = 100 / NUM_PAGES;
|
|
188
|
+
|
|
189
|
+
// Determine current slide index based on translateX
|
|
190
|
+
const currentIndex = Math.round(
|
|
191
|
+
-context.value.x / slideWidthPercentage
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// Decide snapping based on velocity or distance
|
|
195
|
+
let targetIndex;
|
|
196
|
+
if (Math.abs(velocityX) > velocityThreshold) {
|
|
197
|
+
// Use velocity to decide direction
|
|
198
|
+
targetIndex = velocityX > 0 ? currentIndex - 1 : currentIndex + 1;
|
|
199
|
+
} else {
|
|
200
|
+
// Use the 50% distance rule
|
|
201
|
+
const crossedThreshold =
|
|
202
|
+
Math.abs(pixelToPercentage) > slideWidthPercentage / 2;
|
|
203
|
+
targetIndex =
|
|
204
|
+
crossedThreshold && pixelToPercentage < 0
|
|
205
|
+
? currentIndex + 1
|
|
206
|
+
: crossedThreshold
|
|
207
|
+
? currentIndex - 1
|
|
208
|
+
: currentIndex;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Clamp to valid range
|
|
212
|
+
targetIndex = Math.max(0, Math.min(NUM_PAGES - 1, targetIndex));
|
|
213
|
+
|
|
214
|
+
// Animate to the target slide
|
|
215
|
+
animateSlide(-targetIndex * slideWidthPercentage);
|
|
216
|
+
|
|
217
|
+
// Update the currentSlide shared value
|
|
218
|
+
currentSlide.value = targetIndex;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Animated style for the slides container
|
|
222
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
223
|
+
transform: [{ translateX: `${translateX.value}%` }],
|
|
224
|
+
}));
|
|
225
|
+
|
|
226
|
+
useImperativeHandle(ref, () => ({
|
|
227
|
+
handlePrev,
|
|
228
|
+
handleNext,
|
|
229
|
+
}));
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<View style={styles.flex(flex)}>
|
|
233
|
+
<GestureDetector gesture={slideGesture}>
|
|
234
|
+
<View
|
|
235
|
+
//@ts-ignore
|
|
236
|
+
// TODO: fix type
|
|
237
|
+
style={[styles.container(
|
|
238
|
+
// slideshowTokens.variants
|
|
239
|
+
),
|
|
240
|
+
SlideshowStyles.container
|
|
241
|
+
]}
|
|
242
|
+
onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
|
|
243
|
+
>
|
|
244
|
+
<Animated.View
|
|
245
|
+
style={[
|
|
246
|
+
styles.slidesContainer(`${NUM_PAGES * 100}%`),
|
|
247
|
+
animatedStyle,
|
|
248
|
+
]}
|
|
249
|
+
>
|
|
250
|
+
{slides.map((Slide, index) => (
|
|
251
|
+
<View
|
|
252
|
+
key={index}
|
|
253
|
+
style={[
|
|
254
|
+
styles.slide(
|
|
255
|
+
`${slideWidth}%`,
|
|
256
|
+
// SlideshowTokens.slideContainer.variants
|
|
257
|
+
),
|
|
258
|
+
SlideshowStyles.slideContainer
|
|
259
|
+
]}
|
|
260
|
+
>
|
|
261
|
+
{Slide}
|
|
262
|
+
</View>
|
|
263
|
+
))}
|
|
264
|
+
</Animated.View>
|
|
265
|
+
</View>
|
|
266
|
+
</GestureDetector>
|
|
267
|
+
</View>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export default Slideshow;
|
|
272
|
+
|
|
273
|
+
// type SlideshowTokenType = ReturnType<Tokens['slideshow']>; // This is the return of the function
|
|
274
|
+
// type VariantsType = SlideshowTokenType['variants'];
|
|
275
|
+
// type SlideContainerType = SlideshowTokenType['slideContainer']['variants'];
|
|
276
|
+
|
|
277
|
+
const styles = StyleSheet.create({
|
|
278
|
+
flex: (flex) => ({
|
|
279
|
+
flex,
|
|
280
|
+
flexDirection: 'row',
|
|
281
|
+
}),
|
|
282
|
+
container: (
|
|
283
|
+
// variants: VariantsType
|
|
284
|
+
) => ({
|
|
285
|
+
zIndex: 1,
|
|
286
|
+
width: '100%',
|
|
287
|
+
height: '100%',
|
|
288
|
+
overflow: 'hidden',
|
|
289
|
+
justifyContent: 'flex-start',
|
|
290
|
+
alignItems: 'flex-start',
|
|
291
|
+
backgroundColor: 'white',
|
|
292
|
+
borderRadius: 16,
|
|
293
|
+
// backgroundColor: slideshowTokens.baseStyles?.backgroundColor?.(theme),
|
|
294
|
+
// borderRadius: slideshowTokens.baseStyles?.borderRadius,
|
|
295
|
+
// variants: {
|
|
296
|
+
// colorScheme: variants.colorScheme as any,
|
|
297
|
+
// },
|
|
298
|
+
}),
|
|
299
|
+
slidesContainer: (width) => ({
|
|
300
|
+
flexDirection: 'row',
|
|
301
|
+
width,
|
|
302
|
+
flex: 1,
|
|
303
|
+
}),
|
|
304
|
+
slide: (width,
|
|
305
|
+
// variants: SlideContainerType
|
|
306
|
+
) => ({
|
|
307
|
+
width,
|
|
308
|
+
flex: 1,
|
|
309
|
+
// height: '100%',
|
|
310
|
+
justifyContent: 'center',
|
|
311
|
+
alignItems: 'center',
|
|
312
|
+
// variants: {
|
|
313
|
+
// colorScheme: variants.colorScheme as any,
|
|
314
|
+
// spacing: variants.spacing as any,
|
|
315
|
+
// },
|
|
316
|
+
}),
|
|
317
|
+
});
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
3
|
+
import React, { forwardRef, useImperativeHandle } from 'react';
|
|
4
|
+
import { StyleSheet, UnistylesVariants } from 'react-native-unistyles';
|
|
5
|
+
import Animated, {
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
withSpring,
|
|
9
|
+
withTiming,
|
|
10
|
+
type SharedValue,
|
|
11
|
+
} from 'react-native-reanimated';
|
|
12
|
+
import {runOnJS} from 'react-native-worklets';
|
|
13
|
+
// import type { SpringConfig } from 'react-native-reanimated/lib/typescript/animation/springUtils';
|
|
14
|
+
|
|
15
|
+
// import type {
|
|
16
|
+
// SlidingDrawerAnimationVariants,
|
|
17
|
+
// SlidingDrawerColorSchemeVariants,
|
|
18
|
+
// } from '../style/styles/types';
|
|
19
|
+
// import { useTokens } from '../style/useTokens';
|
|
20
|
+
import {SlidingDrawerTokens, SlidingDrawerStyles} from '../theme/SlidingDrawer.recipe';
|
|
21
|
+
|
|
22
|
+
export type SlidingDrawerRef = {
|
|
23
|
+
snapTo: (point: number) => void | null;
|
|
24
|
+
expand: () => void | null;
|
|
25
|
+
collapse: () => void | null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type SlidingDrawerVariants = UnistylesVariants<typeof SlidingDrawerStyles>;
|
|
29
|
+
|
|
30
|
+
type SlidingDrawerProps = SlidingDrawerVariants & {
|
|
31
|
+
// colorScheme?: keyof typeof SlidingDrawerTokens.variants.colorPalette;
|
|
32
|
+
animation?: keyof typeof SlidingDrawerTokens.variants.animation;
|
|
33
|
+
flex?: number;
|
|
34
|
+
direction?: 1 | -1;
|
|
35
|
+
onCollapse?: () => void;
|
|
36
|
+
onExpand?: () => void;
|
|
37
|
+
onSnap?: (point: number) => void;
|
|
38
|
+
snapPoints: number[];
|
|
39
|
+
axis: 'y' | 'x';
|
|
40
|
+
allowGestures?: boolean;
|
|
41
|
+
overlay?: boolean;
|
|
42
|
+
children?: React.ReactNode;
|
|
43
|
+
// style?: StyleProp<ViewStyle>;
|
|
44
|
+
// mixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[];
|
|
45
|
+
ref?: React.RefObject<SlidingDrawerRef>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const SlidingDrawer = ({
|
|
49
|
+
colorPalette,
|
|
50
|
+
animation = SlidingDrawerTokens.defaultProps.animation,
|
|
51
|
+
flex = 0,
|
|
52
|
+
direction = 1,
|
|
53
|
+
onCollapse,
|
|
54
|
+
onExpand,
|
|
55
|
+
onSnap,
|
|
56
|
+
snapPoints,
|
|
57
|
+
axis,
|
|
58
|
+
allowGestures = true,
|
|
59
|
+
overlay = false,
|
|
60
|
+
children,
|
|
61
|
+
// style,
|
|
62
|
+
// mixins,
|
|
63
|
+
ref
|
|
64
|
+
}: SlidingDrawerProps
|
|
65
|
+
) => {
|
|
66
|
+
console.log("🚀 ~ ref:", ref)
|
|
67
|
+
// const slidingDrawerTokens = useTokens('slidingDrawer')();
|
|
68
|
+
|
|
69
|
+
// const resolvedColorScheme =
|
|
70
|
+
// colorScheme ??
|
|
71
|
+
// (slidingDrawerTokens.defaultProps
|
|
72
|
+
// .colorScheme as keyof SlidingDrawerColorSchemeVariants);
|
|
73
|
+
|
|
74
|
+
// const resolvedAnimation =
|
|
75
|
+
// animation ??
|
|
76
|
+
// (slidingDrawerTokens.defaultProps
|
|
77
|
+
// .animation as keyof SlidingDrawerAnimationVariants);
|
|
78
|
+
|
|
79
|
+
SlidingDrawerStyles.useVariants({
|
|
80
|
+
colorPalette,
|
|
81
|
+
// animation,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Adjust points based on direction and axis
|
|
85
|
+
const points = snapPoints.map((point) => point * direction);
|
|
86
|
+
|
|
87
|
+
const translate = useSharedValue(points[0]);
|
|
88
|
+
|
|
89
|
+
const context: SharedValue<{
|
|
90
|
+
position: any;
|
|
91
|
+
snapPoint: number;
|
|
92
|
+
}> = useSharedValue({
|
|
93
|
+
position: points[0], // Default position
|
|
94
|
+
snapPoint: 0, // Default snapPoint
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const changeDisplay = useSharedValue('none');
|
|
98
|
+
const opacity = useSharedValue(0);
|
|
99
|
+
|
|
100
|
+
const VELOCITY_THRESHOLD = 2000;
|
|
101
|
+
|
|
102
|
+
const updateCurrentSnapPoint = (snapPoint: number) => {
|
|
103
|
+
'worklet';
|
|
104
|
+
context.value = { position: context.value.position, snapPoint };
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const animations = {
|
|
108
|
+
withSpring,
|
|
109
|
+
withTiming,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const animationVariant =
|
|
113
|
+
SlidingDrawerTokens.variants.animation[animation];
|
|
114
|
+
// const animationVariant = variants.animation[animation];
|
|
115
|
+
|
|
116
|
+
console.log("🚀 ~ animationVariant:", animationVariant)
|
|
117
|
+
|
|
118
|
+
const snapTo = (destination: number) => {
|
|
119
|
+
'worklet';
|
|
120
|
+
|
|
121
|
+
// Type guard to ensure animationVariant is not undefined
|
|
122
|
+
if (animationVariant && animationVariant.type) {
|
|
123
|
+
translate.value = animations[animationVariant.type](
|
|
124
|
+
points[destination],
|
|
125
|
+
animationVariant.props
|
|
126
|
+
);
|
|
127
|
+
updateCurrentSnapPoint(destination);
|
|
128
|
+
onSnap && runOnJS(onSnap)(destination);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const expand = () => {
|
|
133
|
+
snapTo(points.length - 1);
|
|
134
|
+
if (overlay) {
|
|
135
|
+
showOverlay();
|
|
136
|
+
}
|
|
137
|
+
onExpand && runOnJS(onExpand)();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const isCollapsed = () => {
|
|
141
|
+
'worklet';
|
|
142
|
+
return context.value.snapPoint === 0;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const collapse = () => {
|
|
146
|
+
snapTo(0);
|
|
147
|
+
if (overlay) {
|
|
148
|
+
hideOverlay();
|
|
149
|
+
}
|
|
150
|
+
onCollapse && runOnJS(onCollapse)();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const hideOverlay = () => {
|
|
154
|
+
'worklet';
|
|
155
|
+
changeDisplay.value = 'none';
|
|
156
|
+
opacity.value = withTiming(0, { duration: 200 });
|
|
157
|
+
};
|
|
158
|
+
const showOverlay = () => {
|
|
159
|
+
'worklet';
|
|
160
|
+
changeDisplay.value = 'flex';
|
|
161
|
+
opacity.value = withTiming(1, { duration: 200 });
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
useImperativeHandle(ref, () => ({
|
|
165
|
+
expand,
|
|
166
|
+
collapse,
|
|
167
|
+
snapTo,
|
|
168
|
+
isCollapsed,
|
|
169
|
+
}));
|
|
170
|
+
|
|
171
|
+
// const endLimit = direction === 1 ? points[0] : points[points.length - 1];
|
|
172
|
+
|
|
173
|
+
const slideGesture = Gesture.Pan()
|
|
174
|
+
.enabled(allowGestures)
|
|
175
|
+
.onBegin(() => {
|
|
176
|
+
context.value.position = translate.value;
|
|
177
|
+
})
|
|
178
|
+
.onUpdate((event) => {
|
|
179
|
+
const delta = axis === 'y' ? event.translationY : event.translationX;
|
|
180
|
+
translate.value = delta + (context.value.position ?? 0);
|
|
181
|
+
})
|
|
182
|
+
.onEnd(({ velocityX, velocityY, translationX, translationY }) => {
|
|
183
|
+
const velocity = axis === 'y' ? velocityY : velocityX;
|
|
184
|
+
const translation = axis === 'y' ? translationY : translationX;
|
|
185
|
+
|
|
186
|
+
const forwardsThreshold =
|
|
187
|
+
// @ts-ignore
|
|
188
|
+
(points[context.value.snapPoint] +
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
points[context.value.snapPoint + 1]) /
|
|
191
|
+
2;
|
|
192
|
+
const backwardsThreshold =
|
|
193
|
+
// @ts-ignore
|
|
194
|
+
(points[context.value.snapPoint] +
|
|
195
|
+
// @ts-ignore
|
|
196
|
+
points[context.value.snapPoint - 1]) /
|
|
197
|
+
2;
|
|
198
|
+
|
|
199
|
+
if (translation * direction < 0) {
|
|
200
|
+
if (
|
|
201
|
+
// @ts-ignore
|
|
202
|
+
((direction === 1 && translate.value < forwardsThreshold) ||
|
|
203
|
+
// @ts-ignore
|
|
204
|
+
(direction === -1 && translate.value > forwardsThreshold) ||
|
|
205
|
+
velocity * direction < -VELOCITY_THRESHOLD) &&
|
|
206
|
+
context.value.snapPoint < points.length - 1
|
|
207
|
+
) {
|
|
208
|
+
snapTo(context.value.snapPoint + 1);
|
|
209
|
+
} else {
|
|
210
|
+
snapTo(context.value.snapPoint);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
if (
|
|
214
|
+
// @ts-ignore
|
|
215
|
+
((direction === 1 && translate.value > backwardsThreshold) ||
|
|
216
|
+
// @ts-ignore
|
|
217
|
+
(direction === -1 && translate.value < backwardsThreshold) ||
|
|
218
|
+
velocity * direction > VELOCITY_THRESHOLD) &&
|
|
219
|
+
context.value.snapPoint > 0
|
|
220
|
+
) {
|
|
221
|
+
snapTo(context.value.snapPoint - 1);
|
|
222
|
+
} else {
|
|
223
|
+
snapTo(context.value.snapPoint);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.onFinalize(() => {
|
|
228
|
+
if (overlay) {
|
|
229
|
+
if (isCollapsed()) {
|
|
230
|
+
hideOverlay();
|
|
231
|
+
} else {
|
|
232
|
+
showOverlay();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const blockAnimatedStyle = useAnimatedStyle(() => {
|
|
238
|
+
return {
|
|
239
|
+
transform: [
|
|
240
|
+
{ [axis === 'y' ? 'translateY' : 'translateX']: translate.value },
|
|
241
|
+
],
|
|
242
|
+
} as any;
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const displayOverlayStyle = useAnimatedStyle(() => {
|
|
246
|
+
return {
|
|
247
|
+
display: changeDisplay.value,
|
|
248
|
+
opacity: opacity.value,
|
|
249
|
+
} as any;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return (
|
|
253
|
+
<>
|
|
254
|
+
{overlay && (
|
|
255
|
+
<Animated.View
|
|
256
|
+
style={[
|
|
257
|
+
{
|
|
258
|
+
...StyleSheet.absoluteFillObject,
|
|
259
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
260
|
+
},
|
|
261
|
+
displayOverlayStyle,
|
|
262
|
+
]}
|
|
263
|
+
/>
|
|
264
|
+
)}
|
|
265
|
+
<GestureDetector gesture={slideGesture}>
|
|
266
|
+
<Animated.View
|
|
267
|
+
style={[
|
|
268
|
+
styles.container(flex, direction, axis, SlidingDrawerTokens),
|
|
269
|
+
blockAnimatedStyle,
|
|
270
|
+
SlidingDrawerStyles.container,
|
|
271
|
+
// style && styles.customStyle(style),
|
|
272
|
+
// mixins && mixins,
|
|
273
|
+
]}
|
|
274
|
+
>
|
|
275
|
+
{children}
|
|
276
|
+
</Animated.View>
|
|
277
|
+
</GestureDetector>
|
|
278
|
+
</>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
;
|
|
282
|
+
|
|
283
|
+
export default SlidingDrawer;
|
|
284
|
+
|
|
285
|
+
const styles = StyleSheet.create({
|
|
286
|
+
container: (flex, direction, axis, slidingDrawerTokens): any => ({
|
|
287
|
+
position: flex === 0 ? 'absolute' : 'relative',
|
|
288
|
+
bottom: axis === 'y' && direction === 1 ? 0 : 'auto',
|
|
289
|
+
top: axis === 'y' && direction === -1 ? 0 : 'auto',
|
|
290
|
+
left: axis === 'x' ? 0 : 'auto',
|
|
291
|
+
flex: flex === 0 ? 1 : flex,
|
|
292
|
+
height: '100%',
|
|
293
|
+
width: '100%',
|
|
294
|
+
backgroundColor: slidingDrawerTokens.defaultProps.backgroundColor,
|
|
295
|
+
borderRadius: slidingDrawerTokens.defaultProps.borderRadius,
|
|
296
|
+
alignItems: 'center',
|
|
297
|
+
justifyContent: 'flex-start',
|
|
298
|
+
boxShadow: slidingDrawerTokens.defaultProps.boxShadow,
|
|
299
|
+
zIndex: 5,
|
|
300
|
+
// variants: {
|
|
301
|
+
// colorScheme: slidingDrawerTokens.variants.colorScheme,
|
|
302
|
+
// },
|
|
303
|
+
}),
|
|
304
|
+
customStyle: (style) => ({
|
|
305
|
+
...style,
|
|
306
|
+
}),
|
|
307
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActivityIndicator,
|
|
3
|
+
ColorValue,
|
|
4
|
+
type ActivityIndicatorProps,
|
|
5
|
+
type StyleProp,
|
|
6
|
+
type ViewStyle,
|
|
7
|
+
} from 'react-native'
|
|
8
|
+
import {withUnistyles} from 'react-native-unistyles'
|
|
9
|
+
import {ThemeColors} from '../style/types'
|
|
10
|
+
import {SpinnerTokens} from '../theme/Spinner.recipe'
|
|
11
|
+
|
|
12
|
+
interface SpinnerProps extends ActivityIndicatorProps {
|
|
13
|
+
color?: ThemeColors
|
|
14
|
+
size?: number
|
|
15
|
+
style?: StyleProp<ViewStyle>
|
|
16
|
+
mixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[]
|
|
17
|
+
colors: Record<string, ColorValue>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const BaseSpinner = ({
|
|
21
|
+
size = SpinnerTokens.defaultProps.size,
|
|
22
|
+
color = SpinnerTokens.defaultProps.color,
|
|
23
|
+
style,
|
|
24
|
+
mixins,
|
|
25
|
+
colors,
|
|
26
|
+
...props
|
|
27
|
+
}: SpinnerProps) => {
|
|
28
|
+
const resolvedColor = color && color in colors ? colors[color] : color
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<ActivityIndicator
|
|
32
|
+
color={resolvedColor}
|
|
33
|
+
size={size}
|
|
34
|
+
{...props}
|
|
35
|
+
style={[style && style, mixins && mixins]}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const Spinner = withUnistyles(BaseSpinner, theme => ({
|
|
41
|
+
colors: theme.colors,
|
|
42
|
+
}))
|
|
43
|
+
|
|
44
|
+
export default Spinner
|