react-native-varia 0.2.2 → 0.2.3
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/bin/cli.js +316 -129
- package/lib/components/Button.tsx +9 -7
- package/lib/components/CircleProgress.tsx +18 -9
- package/lib/components/Drawer.tsx +539 -0
- package/lib/components/NumberInput.tsx +34 -8
- package/lib/components/Slideshow.tsx +3 -6
- package/lib/components/SlidingDrawer.tsx +60 -16
- package/lib/icons/Minus.tsx +24 -0
- package/lib/icons/Plus.tsx +23 -0
- package/lib/theme/NumberInput.recipe.tsx +1 -1
- package/package.json +3 -2
- package/lib/components/NewSelect.tsx +0 -202
- package/lib/components/index.tsx +0 -83
- package/lib/components/layoutTest.tsx +0 -74
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useImperativeHandle,
|
|
5
|
+
useMemo,
|
|
6
|
+
} from 'react'
|
|
7
|
+
import {TouchableWithoutFeedback} from 'react-native'
|
|
8
|
+
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
|
9
|
+
import Animated, {
|
|
10
|
+
measure,
|
|
11
|
+
SharedValue,
|
|
12
|
+
useAnimatedReaction,
|
|
13
|
+
useAnimatedRef,
|
|
14
|
+
useAnimatedStyle,
|
|
15
|
+
useSharedValue,
|
|
16
|
+
withSpring,
|
|
17
|
+
withTiming,
|
|
18
|
+
} from 'react-native-reanimated'
|
|
19
|
+
import {runOnUI, scheduleOnRN, scheduleOnUI} from 'react-native-worklets'
|
|
20
|
+
import {
|
|
21
|
+
SlidingDrawerTokens,
|
|
22
|
+
SlidingDrawerStyles,
|
|
23
|
+
} from '../theme/SlidingDrawer.recipe'
|
|
24
|
+
import {PalettesWithNestedKeys} from '../style/varia/types'
|
|
25
|
+
import {
|
|
26
|
+
StyleSheet,
|
|
27
|
+
UnistylesRuntime,
|
|
28
|
+
UnistylesVariants,
|
|
29
|
+
} from 'react-native-unistyles'
|
|
30
|
+
import {HStack} from '../patterns'
|
|
31
|
+
|
|
32
|
+
/* -----------------------------
|
|
33
|
+
* Types
|
|
34
|
+
* ----------------------------*/
|
|
35
|
+
|
|
36
|
+
export type SlidingDrawerRef = {
|
|
37
|
+
expand: () => void | null
|
|
38
|
+
collapse: () => void | null
|
|
39
|
+
snapTo: (point: number) => void | null
|
|
40
|
+
isCollapsed: () => boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type SlidingDrawerVariants = UnistylesVariants<typeof SlidingDrawerStyles>
|
|
44
|
+
|
|
45
|
+
type DrawerContextType = SlidingDrawerVariants & {
|
|
46
|
+
colorPalette: PalettesWithNestedKeys
|
|
47
|
+
overlayOpacity: SharedValue<number>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type DrawerRootProps = SlidingDrawerVariants & {
|
|
51
|
+
colorPalette?: PalettesWithNestedKeys
|
|
52
|
+
children?: React.ReactNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* -----------------------------
|
|
56
|
+
* Context
|
|
57
|
+
* ----------------------------*/
|
|
58
|
+
|
|
59
|
+
const DrawerContext = createContext<DrawerContextType | null>(null)
|
|
60
|
+
const useDrawer = () => {
|
|
61
|
+
const ctx = useContext(DrawerContext)
|
|
62
|
+
if (!ctx)
|
|
63
|
+
throw new Error('Drawer subcomponents must be used within Drawer.Root')
|
|
64
|
+
return ctx
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* -----------------------------
|
|
68
|
+
* Root
|
|
69
|
+
* ----------------------------*/
|
|
70
|
+
|
|
71
|
+
const DrawerRoot = ({
|
|
72
|
+
colorPalette = 'accent',
|
|
73
|
+
variant = SlidingDrawerTokens.defaultProps.variant,
|
|
74
|
+
children,
|
|
75
|
+
}: DrawerRootProps) => {
|
|
76
|
+
SlidingDrawerStyles.useVariants({variant})
|
|
77
|
+
|
|
78
|
+
const overlayOpacity = useSharedValue(0)
|
|
79
|
+
const value = useMemo(
|
|
80
|
+
() => ({
|
|
81
|
+
colorPalette,
|
|
82
|
+
variant,
|
|
83
|
+
overlayOpacity,
|
|
84
|
+
}),
|
|
85
|
+
[colorPalette, variant],
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<DrawerContext.Provider value={value}>{children}</DrawerContext.Provider>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* -----------------------------
|
|
94
|
+
* Positioner
|
|
95
|
+
* ----------------------------*/
|
|
96
|
+
const DrawerPositioner = ({
|
|
97
|
+
children,
|
|
98
|
+
direction,
|
|
99
|
+
axis,
|
|
100
|
+
}: {
|
|
101
|
+
children?: React.ReactNode
|
|
102
|
+
direction: 1 | -1
|
|
103
|
+
axis: 'x' | 'y'
|
|
104
|
+
}) => {
|
|
105
|
+
const {variant} = useDrawer()
|
|
106
|
+
SlidingDrawerStyles.useVariants({variant})
|
|
107
|
+
|
|
108
|
+
type WithDirection = {direction?: 1 | -1; axis?: 'x' | 'y'}
|
|
109
|
+
|
|
110
|
+
const enhancedChildren = React.Children.map(children, child => {
|
|
111
|
+
if (React.isValidElement(child)) {
|
|
112
|
+
return React.cloneElement(child as React.ReactElement<WithDirection>, {
|
|
113
|
+
direction,
|
|
114
|
+
axis,
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
return child
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<HStack
|
|
122
|
+
style={[
|
|
123
|
+
styles.positioner,
|
|
124
|
+
SlidingDrawerStyles.positioner,
|
|
125
|
+
{
|
|
126
|
+
justifyContent:
|
|
127
|
+
axis === 'y'
|
|
128
|
+
? 'center'
|
|
129
|
+
: direction === 1
|
|
130
|
+
? 'flex-start'
|
|
131
|
+
: 'flex-end',
|
|
132
|
+
alignItems:
|
|
133
|
+
axis === 'x'
|
|
134
|
+
? 'center'
|
|
135
|
+
: direction === 1
|
|
136
|
+
? 'flex-start'
|
|
137
|
+
: 'flex-end',
|
|
138
|
+
},
|
|
139
|
+
]}>
|
|
140
|
+
{enhancedChildren}
|
|
141
|
+
</HStack>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* -----------------------------
|
|
146
|
+
* Overlay
|
|
147
|
+
* ----------------------------*/
|
|
148
|
+
const AnimatedTouchable = Animated.createAnimatedComponent(
|
|
149
|
+
TouchableWithoutFeedback,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const DrawerOverlay = ({onPress}: {onPress?: () => void}) => {
|
|
153
|
+
const {colorPalette, overlayOpacity, variant} = useDrawer()
|
|
154
|
+
SlidingDrawerStyles.useVariants({variant})
|
|
155
|
+
const visible = useSharedValue(0)
|
|
156
|
+
|
|
157
|
+
useAnimatedReaction(
|
|
158
|
+
() => overlayOpacity.value,
|
|
159
|
+
value => {
|
|
160
|
+
if (value === 0) {
|
|
161
|
+
visible.value = 0
|
|
162
|
+
} else {
|
|
163
|
+
visible.value = 1
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
const displayOverlayStyle = useAnimatedStyle(() => ({
|
|
169
|
+
opacity: withTiming(overlayOpacity.value, {duration: 50}),
|
|
170
|
+
display: visible.value === 0 ? 'none' : 'flex',
|
|
171
|
+
}))
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<AnimatedTouchable onPress={onPress}>
|
|
175
|
+
<Animated.View
|
|
176
|
+
style={[
|
|
177
|
+
StyleSheet.absoluteFillObject,
|
|
178
|
+
displayOverlayStyle,
|
|
179
|
+
SlidingDrawerStyles.overlay(colorPalette),
|
|
180
|
+
]}
|
|
181
|
+
/>
|
|
182
|
+
</AnimatedTouchable>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* -----------------------------
|
|
187
|
+
* Slider (gestión independiente)
|
|
188
|
+
* ----------------------------*/
|
|
189
|
+
|
|
190
|
+
type InternalDrawerSliderProps = {
|
|
191
|
+
axis: 'x' | 'y'
|
|
192
|
+
direction: 1 | -1
|
|
193
|
+
lockAtEdges?: boolean
|
|
194
|
+
snapPoints?: number[] | ('hidden' | 'content')[]
|
|
195
|
+
animation?: keyof typeof SlidingDrawerTokens.variants.animation
|
|
196
|
+
onExpand?: () => void
|
|
197
|
+
onCollapse?: () => void
|
|
198
|
+
onSnap?: (point: number) => void
|
|
199
|
+
allowGestures?: boolean
|
|
200
|
+
children?: React.ReactNode
|
|
201
|
+
ref?: React.RefObject<SlidingDrawerRef | null>
|
|
202
|
+
externalTranslate?: SharedValue<number>
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Tipo público — el que exportas (sin direction)
|
|
206
|
+
export type DrawerSliderProps = Omit<
|
|
207
|
+
InternalDrawerSliderProps,
|
|
208
|
+
'direction' | 'axis'
|
|
209
|
+
>
|
|
210
|
+
|
|
211
|
+
export const DrawerSlider = (props: DrawerSliderProps) => {
|
|
212
|
+
return <DrawerSliderInternal {...(props as InternalDrawerSliderProps)} />
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const DrawerSliderInternal = ({
|
|
216
|
+
axis,
|
|
217
|
+
direction,
|
|
218
|
+
lockAtEdges = false,
|
|
219
|
+
snapPoints = ['hidden', 'content'],
|
|
220
|
+
animation = SlidingDrawerTokens.defaultProps.animation,
|
|
221
|
+
onExpand,
|
|
222
|
+
onCollapse,
|
|
223
|
+
onSnap,
|
|
224
|
+
allowGestures = true,
|
|
225
|
+
children,
|
|
226
|
+
externalTranslate,
|
|
227
|
+
ref,
|
|
228
|
+
}: InternalDrawerSliderProps) => {
|
|
229
|
+
const {variant, colorPalette, overlayOpacity} = useDrawer()
|
|
230
|
+
|
|
231
|
+
SlidingDrawerStyles.useVariants({variant})
|
|
232
|
+
|
|
233
|
+
const screenHeight =
|
|
234
|
+
UnistylesRuntime.screen.height - UnistylesRuntime.insets.top
|
|
235
|
+
const screenWidth = UnistylesRuntime.screen.width
|
|
236
|
+
|
|
237
|
+
const animations = {withSpring, withTiming}
|
|
238
|
+
const animationVariant = SlidingDrawerTokens.variants.animation[animation]
|
|
239
|
+
const VELOCITY_THRESHOLD = 2000
|
|
240
|
+
|
|
241
|
+
// --- shared values base ---
|
|
242
|
+
const viewRef = useAnimatedRef<Animated.View>()
|
|
243
|
+
const translate = useSharedValue(screenHeight)
|
|
244
|
+
const context = useSharedValue({position: screenHeight, snapPoint: 0})
|
|
245
|
+
const contentHeight = useSharedValue(0)
|
|
246
|
+
const resolvedSnapPoints = useSharedValue<number[]>([])
|
|
247
|
+
|
|
248
|
+
if (externalTranslate) {
|
|
249
|
+
useAnimatedReaction(
|
|
250
|
+
() => translate.value,
|
|
251
|
+
value => {
|
|
252
|
+
externalTranslate.value = value
|
|
253
|
+
},
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- medir el contenido dinámicamente ---
|
|
258
|
+
// const onLayout = () => {
|
|
259
|
+
// scheduleOnUI(() => {
|
|
260
|
+
// 'worklet'
|
|
261
|
+
// const measured = measure(viewRef)
|
|
262
|
+
// if (measured) {
|
|
263
|
+
// const {height} = measured
|
|
264
|
+
// contentHeight.value = height
|
|
265
|
+
|
|
266
|
+
// // resuelve snapPoints declarativos
|
|
267
|
+
// const resolved = snapPoints.map(p => {
|
|
268
|
+
// if (p === 'hidden') return screenHeight * direction
|
|
269
|
+
// if (p === 'content') return (screenHeight - height) * direction
|
|
270
|
+
// // if (typeof p === 'string' && p.endsWith('%')) {
|
|
271
|
+
// // const percentage = parseFloat(p) / 100
|
|
272
|
+
// // return screenHeight * (1 - percentage) * direction
|
|
273
|
+
// // }
|
|
274
|
+
// return p * direction
|
|
275
|
+
// })
|
|
276
|
+
|
|
277
|
+
// resolvedSnapPoints.value = resolved
|
|
278
|
+
|
|
279
|
+
// // inicializa la posición (oculto)
|
|
280
|
+
// translate.value = resolved[0]
|
|
281
|
+
// context.value = {position: resolved[0], snapPoint: 0}
|
|
282
|
+
// }
|
|
283
|
+
// })
|
|
284
|
+
// }
|
|
285
|
+
|
|
286
|
+
const onLayout = () => {
|
|
287
|
+
// captura valores aquí (en JS)
|
|
288
|
+
const _screenHeight = screenHeight
|
|
289
|
+
const _screenWidth = screenWidth
|
|
290
|
+
const _axis = axis
|
|
291
|
+
const _direction = direction
|
|
292
|
+
const _snapPoints = snapPoints
|
|
293
|
+
|
|
294
|
+
scheduleOnUI(() => {
|
|
295
|
+
'worklet'
|
|
296
|
+
const measured = measure(viewRef)
|
|
297
|
+
if (measured) {
|
|
298
|
+
const {height, width} = measured
|
|
299
|
+
const size = _axis === 'y' ? height : width
|
|
300
|
+
const screenSize = _axis === 'y' ? _screenHeight : _screenWidth
|
|
301
|
+
|
|
302
|
+
const resolved = _snapPoints.map(p => {
|
|
303
|
+
if (p === 'hidden') return screenSize * _direction
|
|
304
|
+
if (p === 'content') return (screenSize - size) * _direction
|
|
305
|
+
return (p as number) * _direction
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
resolvedSnapPoints.value = resolved
|
|
309
|
+
translate.value = resolved[0]
|
|
310
|
+
context.value = {position: resolved[0], snapPoint: 0}
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const getPoints = () => {
|
|
316
|
+
'worklet'
|
|
317
|
+
return resolvedSnapPoints.value.length > 0
|
|
318
|
+
? resolvedSnapPoints.value
|
|
319
|
+
: snapPoints.map(p => (p as any) * direction)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// --- lógica de snapping ---
|
|
323
|
+
const updateCurrentSnapPoint = (snapPoint: number) => {
|
|
324
|
+
'worklet'
|
|
325
|
+
context.value = {position: context.value.position, snapPoint}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const snapTo = (destination: number) => {
|
|
329
|
+
'worklet'
|
|
330
|
+
const points = getPoints()
|
|
331
|
+
const point = points[destination]
|
|
332
|
+
if (animationVariant?.type && point != null) {
|
|
333
|
+
translate.value = animations[animationVariant.type](
|
|
334
|
+
point,
|
|
335
|
+
animationVariant.props,
|
|
336
|
+
)
|
|
337
|
+
updateCurrentSnapPoint(destination)
|
|
338
|
+
onSnap && scheduleOnRN(onSnap, destination)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const isCollapsed = () => {
|
|
343
|
+
'worklet'
|
|
344
|
+
return context.value.snapPoint === 0
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const showOverlay = () => {
|
|
348
|
+
'worklet'
|
|
349
|
+
overlayOpacity.value = withTiming(1, {duration: 200})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const hideOverlay = () => {
|
|
353
|
+
'worklet'
|
|
354
|
+
overlayOpacity.value = withTiming(0, {duration: 200})
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const expand = () => {
|
|
358
|
+
const points = getPoints()
|
|
359
|
+
snapTo(points.length - 1)
|
|
360
|
+
showOverlay()
|
|
361
|
+
onExpand && scheduleOnRN(onExpand)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const collapse = () => {
|
|
365
|
+
snapTo(0)
|
|
366
|
+
hideOverlay()
|
|
367
|
+
onCollapse && scheduleOnRN(onCollapse)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
useImperativeHandle(ref, () => ({
|
|
371
|
+
expand,
|
|
372
|
+
collapse,
|
|
373
|
+
snapTo,
|
|
374
|
+
isCollapsed,
|
|
375
|
+
}))
|
|
376
|
+
|
|
377
|
+
// --- sincronizar overlay con movimiento ---
|
|
378
|
+
useAnimatedReaction(
|
|
379
|
+
() => translate.value,
|
|
380
|
+
value => {
|
|
381
|
+
const points = getPoints()
|
|
382
|
+
if (points.length < 2) return
|
|
383
|
+
|
|
384
|
+
const collapsed = points[0]
|
|
385
|
+
const next = points[1] ?? collapsed
|
|
386
|
+
const threshold = 20
|
|
387
|
+
const opensUpward = next < collapsed
|
|
388
|
+
const delta = value - collapsed
|
|
389
|
+
const isExpanded = opensUpward ? delta < -threshold : delta > threshold
|
|
390
|
+
|
|
391
|
+
overlayOpacity.value = withTiming(isExpanded ? 1 : 0, {duration: 150})
|
|
392
|
+
},
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
// --- Gestures ---
|
|
396
|
+
const slideGesture = Gesture.Pan()
|
|
397
|
+
.enabled(allowGestures)
|
|
398
|
+
.onBegin(() => {
|
|
399
|
+
context.value.position = translate.value
|
|
400
|
+
})
|
|
401
|
+
.onUpdate(event => {
|
|
402
|
+
const delta = axis === 'y' ? event.translationY : event.translationX
|
|
403
|
+
const proposed = delta + (context.value.position ?? 0)
|
|
404
|
+
const points = getPoints()
|
|
405
|
+
const minPoint = Math.min(...points)
|
|
406
|
+
const maxPoint = Math.max(...points)
|
|
407
|
+
let clamped = proposed
|
|
408
|
+
|
|
409
|
+
if (proposed < minPoint) {
|
|
410
|
+
if (lockAtEdges) {
|
|
411
|
+
// Bloquea overscroll superior (cuando ya estás en el extremo)
|
|
412
|
+
clamped = minPoint
|
|
413
|
+
} else {
|
|
414
|
+
// Aplica resistencia
|
|
415
|
+
const overdrag = minPoint - proposed
|
|
416
|
+
clamped = minPoint - overdrag / (1 + overdrag / 60)
|
|
417
|
+
}
|
|
418
|
+
} else if (proposed > maxPoint) {
|
|
419
|
+
if (lockAtEdges) {
|
|
420
|
+
// Bloquea overscroll inferior
|
|
421
|
+
clamped = maxPoint
|
|
422
|
+
} else {
|
|
423
|
+
const overdrag = proposed - maxPoint
|
|
424
|
+
clamped = maxPoint + overdrag / (1 + overdrag / 60)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
translate.value = clamped
|
|
429
|
+
})
|
|
430
|
+
.onEnd(({velocityX, velocityY, translationX, translationY}) => {
|
|
431
|
+
const velocity = axis === 'y' ? velocityY : velocityX
|
|
432
|
+
const translation = axis === 'y' ? translationY : translationX
|
|
433
|
+
const points = getPoints()
|
|
434
|
+
|
|
435
|
+
const minPoint = Math.min(...points)
|
|
436
|
+
const maxPoint = Math.max(...points)
|
|
437
|
+
|
|
438
|
+
if (translate.value < minPoint) {
|
|
439
|
+
translate.value = withSpring(minPoint, {velocity})
|
|
440
|
+
return
|
|
441
|
+
} else if (translate.value > maxPoint) {
|
|
442
|
+
translate.value = withSpring(maxPoint, {velocity})
|
|
443
|
+
return
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const forwardsThreshold =
|
|
447
|
+
(points[context.value.snapPoint] +
|
|
448
|
+
points[context.value.snapPoint + 1]) /
|
|
449
|
+
2
|
|
450
|
+
const backwardsThreshold =
|
|
451
|
+
(points[context.value.snapPoint] +
|
|
452
|
+
points[context.value.snapPoint - 1]) /
|
|
453
|
+
2
|
|
454
|
+
|
|
455
|
+
if (translation * direction < 0) {
|
|
456
|
+
if (
|
|
457
|
+
((direction === 1 && translate.value < forwardsThreshold) ||
|
|
458
|
+
(direction === -1 && translate.value > forwardsThreshold) ||
|
|
459
|
+
velocity * direction < -VELOCITY_THRESHOLD) &&
|
|
460
|
+
context.value.snapPoint < points.length - 1
|
|
461
|
+
) {
|
|
462
|
+
snapTo(context.value.snapPoint + 1)
|
|
463
|
+
} else {
|
|
464
|
+
snapTo(context.value.snapPoint)
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
if (
|
|
468
|
+
((direction === 1 && translate.value > backwardsThreshold) ||
|
|
469
|
+
(direction === -1 && translate.value < backwardsThreshold) ||
|
|
470
|
+
velocity * direction > VELOCITY_THRESHOLD) &&
|
|
471
|
+
context.value.snapPoint > 0
|
|
472
|
+
) {
|
|
473
|
+
snapTo(context.value.snapPoint - 1)
|
|
474
|
+
} else {
|
|
475
|
+
snapTo(context.value.snapPoint)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
// --- estilos animados ---
|
|
481
|
+
const blockAnimatedStyle = useAnimatedStyle(() => {
|
|
482
|
+
return {
|
|
483
|
+
transform: [
|
|
484
|
+
axis === 'y'
|
|
485
|
+
? {translateY: translate.value}
|
|
486
|
+
: {translateX: translate.value},
|
|
487
|
+
],
|
|
488
|
+
}
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
return (
|
|
492
|
+
<GestureDetector gesture={slideGesture}>
|
|
493
|
+
<Animated.View
|
|
494
|
+
ref={viewRef}
|
|
495
|
+
onLayout={onLayout}
|
|
496
|
+
style={[
|
|
497
|
+
styles.slider,
|
|
498
|
+
blockAnimatedStyle,
|
|
499
|
+
SlidingDrawerStyles.slider(colorPalette),
|
|
500
|
+
]}>
|
|
501
|
+
{children}
|
|
502
|
+
</Animated.View>
|
|
503
|
+
</GestureDetector>
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* -----------------------------
|
|
508
|
+
* Export grouped
|
|
509
|
+
* ----------------------------*/
|
|
510
|
+
|
|
511
|
+
export const Drawer = {
|
|
512
|
+
Root: DrawerRoot,
|
|
513
|
+
Positioner: DrawerPositioner,
|
|
514
|
+
Overlay: DrawerOverlay,
|
|
515
|
+
Slider: DrawerSlider,
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/* -----------------------------
|
|
519
|
+
* Styles
|
|
520
|
+
* ----------------------------*/
|
|
521
|
+
|
|
522
|
+
const styles = StyleSheet.create((theme, rt) => ({
|
|
523
|
+
positioner: {
|
|
524
|
+
flex: 1,
|
|
525
|
+
alignSelf: 'stretch',
|
|
526
|
+
position: 'absolute',
|
|
527
|
+
top: 0,
|
|
528
|
+
left: 0,
|
|
529
|
+
right: 0,
|
|
530
|
+
bottom: 0,
|
|
531
|
+
},
|
|
532
|
+
slider: {
|
|
533
|
+
flex: 1,
|
|
534
|
+
alignSelf: 'stretch',
|
|
535
|
+
alignItems: 'center',
|
|
536
|
+
justifyContent: 'flex-start',
|
|
537
|
+
zIndex: 100,
|
|
538
|
+
},
|
|
539
|
+
}))
|
|
@@ -14,6 +14,12 @@ type NumberInputVariants = UnistylesVariants<typeof NumberInputStyles>
|
|
|
14
14
|
type PublicInputProps = Omit<NumberInputVariants, 'variant' | 'size'> & {
|
|
15
15
|
placeholder?: string
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
interface IconProps {
|
|
19
|
+
color?: string
|
|
20
|
+
size?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
type PublicTriggerProps = {
|
|
18
24
|
children?: React.ReactNode
|
|
19
25
|
variant?: NumberInputVariants['variant']
|
|
@@ -153,10 +159,20 @@ const NumberInput = {
|
|
|
153
159
|
distribution = NumberInputDefaultVariants.distribution,
|
|
154
160
|
colorPalette = 'accent',
|
|
155
161
|
children,
|
|
156
|
-
min,
|
|
157
162
|
max,
|
|
158
163
|
} = {...useSimpleNumberInputContext(), ...props}
|
|
159
164
|
NumberInputStyles.useVariants({variant, size, distribution})
|
|
165
|
+
|
|
166
|
+
const color = (NumberInputStyles.buttons(colorPalette) as {color: string})
|
|
167
|
+
.color
|
|
168
|
+
|
|
169
|
+
const iconElement = children || <IncreaseTriggerIcon />
|
|
170
|
+
const iconWithProps = React.isValidElement<IconProps>(iconElement)
|
|
171
|
+
? React.cloneElement(iconElement, {
|
|
172
|
+
color,
|
|
173
|
+
})
|
|
174
|
+
: iconElement
|
|
175
|
+
|
|
160
176
|
return (
|
|
161
177
|
<Pressable
|
|
162
178
|
onPress={() => setValue(value + 1)}
|
|
@@ -166,7 +182,7 @@ const NumberInput = {
|
|
|
166
182
|
NumberInputStyles.buttons(colorPalette),
|
|
167
183
|
NumberInputStyles.increaseTrigger(colorPalette),
|
|
168
184
|
]}>
|
|
169
|
-
{
|
|
185
|
+
{iconWithProps}
|
|
170
186
|
</Pressable>
|
|
171
187
|
)
|
|
172
188
|
},
|
|
@@ -181,9 +197,19 @@ const NumberInput = {
|
|
|
181
197
|
colorPalette = 'accent',
|
|
182
198
|
children,
|
|
183
199
|
min,
|
|
184
|
-
max,
|
|
185
200
|
} = {...useSimpleNumberInputContext(), ...props}
|
|
186
201
|
NumberInputStyles.useVariants({variant, size, distribution})
|
|
202
|
+
|
|
203
|
+
const color = (NumberInputStyles.buttons(colorPalette) as {color: string})
|
|
204
|
+
.color
|
|
205
|
+
|
|
206
|
+
const iconElement = children || <DecreaseTriggerIcon />
|
|
207
|
+
const iconWithProps = React.isValidElement<IconProps>(iconElement)
|
|
208
|
+
? React.cloneElement(iconElement, {
|
|
209
|
+
color,
|
|
210
|
+
})
|
|
211
|
+
: iconElement
|
|
212
|
+
|
|
187
213
|
return (
|
|
188
214
|
<Pressable
|
|
189
215
|
onPress={() => setValue(value - 1)}
|
|
@@ -193,18 +219,18 @@ const NumberInput = {
|
|
|
193
219
|
NumberInputStyles.buttons(colorPalette),
|
|
194
220
|
NumberInputStyles.decreaseTrigger(colorPalette),
|
|
195
221
|
]}>
|
|
196
|
-
{
|
|
222
|
+
{iconWithProps}
|
|
197
223
|
</Pressable>
|
|
198
224
|
)
|
|
199
225
|
},
|
|
200
226
|
}
|
|
201
227
|
|
|
202
|
-
const IncreaseTriggerIcon = () => {
|
|
203
|
-
return <Plus
|
|
228
|
+
const IncreaseTriggerIcon = ({color}: {color?: string}) => {
|
|
229
|
+
return <Plus color={color} />
|
|
204
230
|
}
|
|
205
231
|
|
|
206
|
-
const DecreaseTriggerIcon = () => {
|
|
207
|
-
return <Minus
|
|
232
|
+
const DecreaseTriggerIcon = ({color}: {color?: string}) => {
|
|
233
|
+
return <Minus color={color} />
|
|
208
234
|
}
|
|
209
235
|
|
|
210
236
|
export default NumberInput
|
|
@@ -7,7 +7,7 @@ import Animated, {
|
|
|
7
7
|
withSpring,
|
|
8
8
|
withTiming,
|
|
9
9
|
} from 'react-native-reanimated'
|
|
10
|
-
import {
|
|
10
|
+
import {scheduleOnRN} from 'react-native-worklets'
|
|
11
11
|
import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
|
|
12
12
|
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
|
13
13
|
import {SlideshowStyles, SlideshowTokens} from '../theme/Slideshow.recipe'
|
|
@@ -28,7 +28,7 @@ type SlideshowProps = SlideshowVariants & {
|
|
|
28
28
|
onSlideChange?: (index: number) => void
|
|
29
29
|
slideContainerType?: any
|
|
30
30
|
children: ReactNode
|
|
31
|
-
ref?: React.RefObject<SlideshowRef>
|
|
31
|
+
ref?: React.RefObject<SlideshowRef | null>
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -99,7 +99,7 @@ const Slideshow = ({
|
|
|
99
99
|
)
|
|
100
100
|
|
|
101
101
|
if (onSlideChange) {
|
|
102
|
-
|
|
102
|
+
scheduleOnRN(onSlideChange, (destination / 100) * NUM_PAGES * -1)
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -207,14 +207,11 @@ const styles = StyleSheet.create({
|
|
|
207
207
|
flexDirection: 'row',
|
|
208
208
|
}),
|
|
209
209
|
container: () => ({
|
|
210
|
-
zIndex: 1,
|
|
211
210
|
width: '100%',
|
|
212
211
|
height: '100%',
|
|
213
212
|
overflow: 'hidden',
|
|
214
213
|
justifyContent: 'flex-start',
|
|
215
214
|
alignItems: 'flex-start',
|
|
216
|
-
backgroundColor: 'white',
|
|
217
|
-
borderRadius: 16,
|
|
218
215
|
}),
|
|
219
216
|
slidesContainer: width => ({
|
|
220
217
|
flexDirection: 'row',
|