react-native-varia 0.5.1 → 0.6.0

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.
Files changed (31) hide show
  1. package/lib/components/{ui/Accordion.tsx → Accordion.tsx} +55 -27
  2. package/lib/components/{ui/Badge.tsx → Badge.tsx} +12 -6
  3. package/lib/components/{ui/Button.tsx → Button.tsx} +18 -6
  4. package/lib/components/{ui/Checkbox.tsx → Checkbox.tsx} +22 -4
  5. package/lib/components/{ui/CircleProgress.tsx → CircleProgress.tsx} +7 -3
  6. package/lib/components/{ui/Divider.tsx → Divider.tsx} +7 -3
  7. package/lib/components/{ui/Drawer.tsx → Drawer.tsx} +73 -25
  8. package/lib/components/{ui/Field.tsx → Field.tsx} +12 -6
  9. package/lib/components/{ui/FloatingAction.tsx → FloatingAction.tsx} +15 -4
  10. package/lib/components/{ui/GradientBackground.tsx → GradientBackground.tsx} +1 -1
  11. package/lib/components/{ui/GradientText.tsx → GradientText.tsx} +15 -5
  12. package/lib/components/{ui/IconWrapper.tsx → IconWrapper.tsx} +2 -2
  13. package/lib/components/{ui/Input.tsx → Input.tsx} +11 -6
  14. package/lib/components/{ui/Link.tsx → Link.tsx} +7 -7
  15. package/lib/components/{ui/Modal.tsx → Modal.tsx} +42 -13
  16. package/lib/components/{ui/NumberInput.tsx → NumberInput.tsx} +44 -23
  17. package/lib/components/{ui/RadioGroup.tsx → RadioGroup.tsx} +35 -6
  18. package/lib/components/{ui/ReText.tsx → ReText.tsx} +1 -1
  19. package/lib/components/{ui/Select.tsx → Select.tsx} +61 -8
  20. package/lib/components/Slider.tsx +500 -0
  21. package/lib/components/{ui/Slideshow.tsx → Slideshow.tsx} +12 -3
  22. package/lib/components/{ui/Switch.tsx → Switch.tsx} +15 -3
  23. package/lib/components/{ui/Text.tsx → Text.tsx} +2 -2
  24. package/lib/components/{ui/Toast.tsx → Toast.tsx} +14 -3
  25. package/lib/components/context/Field.tsx +4 -2
  26. package/lib/varia/types.ts +6 -0
  27. package/lib/varia/utils.ts +7 -0
  28. package/package.json +1 -1
  29. package/lib/components/ui/Slider.tsx +0 -498
  30. package/lib/components/ui/context/Field.tsx +0 -27
  31. /package/lib/components/{ui/Spinner.tsx → Spinner.tsx} +0 -0
@@ -0,0 +1,500 @@
1
+ import React from 'react'
2
+ import {type LayoutChangeEvent, StyleProp, View, ViewStyle} from 'react-native'
3
+ import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
4
+ import {Gesture, GestureDetector} from 'react-native-gesture-handler'
5
+ import Animated, {
6
+ useAnimatedReaction,
7
+ useAnimatedStyle,
8
+ useSharedValue,
9
+ } from 'react-native-reanimated'
10
+ import {runOnJS} from 'react-native-worklets'
11
+ import {SliderStyles, SliderDefaultVariants} from '../../theme/Slider.recipe'
12
+ import {PalettesWithNestedKeys} from '../../style/varia/types'
13
+ import {getCompoundVariantValue, getVariantValue} from '../../style/varia/utils'
14
+
15
+ function throttle<T extends (...args: any[]) => any>(
16
+ func: T,
17
+ limit = 50,
18
+ ): (...args: Parameters<T>) => void {
19
+ let inThrottle = false
20
+ return (...args: Parameters<T>) => {
21
+ if (!inThrottle) {
22
+ func(...(args as Parameters<T>))
23
+ inThrottle = true
24
+ setTimeout(() => {
25
+ inThrottle = false
26
+ }, limit)
27
+ }
28
+ }
29
+ }
30
+
31
+ type SliderVariants = UnistylesVariants<typeof SliderStyles>
32
+
33
+ const AnimatedView = Animated.createAnimatedComponent(View)
34
+
35
+ type SliderProps = SliderVariants & {
36
+ colorPalette?: PalettesWithNestedKeys
37
+ thickness?: number
38
+ minimumTrackThickness?: number
39
+ minimumTrackColor?: string
40
+ thumbSize?: {
41
+ width: number
42
+ height: number
43
+ }
44
+ thumbChildren?: React.ReactNode
45
+ steps?: number
46
+ value?: number
47
+ onSlidingStart?: (value: number) => void
48
+ onValueChange?: (value: number) => void
49
+ onSlidingComplete?: (value: number) => void
50
+ flex?: ViewStyle['flex']
51
+ alignSelf?: ViewStyle['alignSelf']
52
+ allowGestures?: boolean
53
+ mode?: 'normal' | 'wrap'
54
+ containerStyles?: StyleProp<ViewStyle>
55
+ maximumTrackStyles?: StyleProp<ViewStyle>
56
+ minimumTrackStyles?: StyleProp<ViewStyle>
57
+ thumbStyles?: StyleProp<ViewStyle>
58
+ }
59
+
60
+ const Slider = ({
61
+ colorPalette = 'accent',
62
+ variant = SliderDefaultVariants.variant,
63
+ size = SliderDefaultVariants.size,
64
+ thumbChildren: ThumbChildren,
65
+ axis = 'x',
66
+ value = 0,
67
+ steps,
68
+ onSlidingStart,
69
+ onValueChange,
70
+ onSlidingComplete,
71
+ flex = 0,
72
+ alignSelf = 'auto',
73
+ allowGestures = true,
74
+ mode = 'normal',
75
+ containerStyles,
76
+ maximumTrackStyles,
77
+ minimumTrackStyles,
78
+ thumbStyles,
79
+ }: SliderProps) => {
80
+ SliderStyles.useVariants({
81
+ size,
82
+ variant,
83
+ axis,
84
+ })
85
+ styles.useVariants({
86
+ axis,
87
+ })
88
+
89
+ const normalizedValue = useSharedValue(0)
90
+
91
+ const throttledOnValueChange = React.useMemo(() => {
92
+ if (!onValueChange) return undefined
93
+ return throttle(onValueChange, 50)
94
+ }, [onValueChange])
95
+
96
+ const thumbWidth = getCompoundVariantValue(
97
+ SliderStyles.thumb(colorPalette),
98
+ {axis, size},
99
+ 'width',
100
+ )
101
+ const thumbHeight = getCompoundVariantValue(
102
+ SliderStyles.thumb(colorPalette),
103
+ {axis, size},
104
+ 'height',
105
+ )
106
+
107
+ const maximumTrackColor =
108
+ getVariantValue(
109
+ SliderStyles.maximumTrack(colorPalette),
110
+ 'variant',
111
+ variant,
112
+ 'backgroundColor',
113
+ ) || 'transparent'
114
+
115
+ console.log(SliderStyles.maximumTrack(colorPalette))
116
+
117
+ const halfSize = ((axis === 'x' ? thumbWidth : thumbHeight) ?? 0) / 2
118
+
119
+ const context = useSharedValue({x: 0})
120
+
121
+ // ❗️CAMBIO 1: translate SIEMPRE en píxeles
122
+ const translate = useSharedValue(0)
123
+
124
+ const trackLength = useSharedValue(0)
125
+ const isInsideChild = useSharedValue(false)
126
+
127
+ const handleTrackLayout = (event: LayoutChangeEvent) => {
128
+ const {width, height} = event.nativeEvent.layout
129
+ trackLength.value = axis === 'x' ? width : height
130
+ }
131
+
132
+ // ❗️CAMBIO 2: sincronizar value → translate cuando hay layout
133
+ React.useEffect(() => {
134
+ if (trackLength.value <= 0) return
135
+
136
+ if (steps) {
137
+ const stepLength = trackLength.value / steps
138
+ translate.value = value * stepLength
139
+ } else {
140
+ translate.value = value * trackLength.value
141
+ }
142
+ }, [value, steps])
143
+
144
+ useAnimatedReaction(
145
+ () => normalizedValue.value,
146
+ (value, prev) => {
147
+ if (value === prev) return
148
+
149
+ if (onValueChange) {
150
+ runOnJS(onValueChange)(steps ? value : Math.round(value * 100) / 100)
151
+ }
152
+ },
153
+ [steps],
154
+ )
155
+
156
+ const isInteracting = useSharedValue(false)
157
+
158
+ const computeSnappedValue = (position: number) => {
159
+ 'worklet'
160
+ const clamped = Math.max(0, Math.min(position, trackLength.value))
161
+ if (!steps) return clamped
162
+
163
+ const stepLength = trackLength.value / steps
164
+ return Math.round(clamped / stepLength) * stepLength
165
+ }
166
+
167
+ const toNormalizedValue = (px: number) => {
168
+ 'worklet'
169
+ return steps
170
+ ? Math.round(px / (trackLength.value / steps))
171
+ : px / trackLength.value
172
+ }
173
+
174
+ const beginInteraction = (value: number) => {
175
+ 'worklet'
176
+ if (isInteracting.value) return
177
+ isInteracting.value = true
178
+ onSlidingStart && runOnJS(onSlidingStart)(value)
179
+ }
180
+
181
+ const updateInteraction = (value: number) => {
182
+ 'worklet'
183
+ onValueChange && runOnJS(onValueChange)(value)
184
+ }
185
+
186
+ const endInteraction = (value: number) => {
187
+ 'worklet'
188
+ if (!isInteracting.value) return
189
+ isInteracting.value = false
190
+ onSlidingComplete && runOnJS(onSlidingComplete)(value)
191
+ }
192
+
193
+ const panGesture = Gesture.Pan()
194
+ .enabled(allowGestures)
195
+ .minDistance(0)
196
+
197
+ .onBegin(e => {
198
+ const pos = axis === 'y' ? trackLength.value - e.y : e.x
199
+ const snapped = computeSnappedValue(pos)
200
+
201
+ context.value.x = snapped
202
+ translate.value = snapped
203
+
204
+ beginInteraction(toNormalizedValue(snapped))
205
+ updateInteraction(toNormalizedValue(snapped))
206
+ })
207
+
208
+ .onUpdate(e => {
209
+ const delta = axis === 'y' ? -e.translationY : e.translationX
210
+ const snapped = computeSnappedValue(context.value.x + delta)
211
+
212
+ translate.value = snapped
213
+ updateInteraction(toNormalizedValue(snapped))
214
+ })
215
+
216
+ .onEnd(() => {
217
+ endInteraction(toNormalizedValue(translate.value))
218
+ })
219
+
220
+ .onFinalize(() => {
221
+ // 🔒 garantiza cleanup incluso en cancelaciones
222
+ endInteraction(toNormalizedValue(translate.value))
223
+ })
224
+
225
+ const animatedTrack = useAnimatedStyle(() => ({
226
+ [axis === 'y' ? 'height' : 'width']:
227
+ translate.value + (mode === 'wrap' ? halfSize : 0),
228
+ }))
229
+
230
+ const animatedThumb = useAnimatedStyle(() => {
231
+ if (axis === 'x') {
232
+ return {transform: [{translateX: translate.value - halfSize}]}
233
+ }
234
+ return {
235
+ transform: [{translateY: trackLength.value - translate.value - halfSize}],
236
+ }
237
+ })
238
+
239
+ console.log('maximum color', maximumTrackColor)
240
+
241
+ return (
242
+ <View
243
+ testID="varia-slider-container"
244
+ style={[
245
+ SliderStyles.container(colorPalette),
246
+ containerStyles,
247
+ styles.container(
248
+ halfSize,
249
+ flex,
250
+ alignSelf,
251
+ mode === 'wrap' ? maximumTrackColor : 'transparent',
252
+ ),
253
+ ]}>
254
+ <GestureDetector gesture={panGesture}>
255
+ <View
256
+ testID="varia-slider-maximun-track"
257
+ style={[
258
+ styles.maximumTrack(mode),
259
+ maximumTrackStyles,
260
+ SliderStyles.maximumTrack(colorPalette),
261
+ ]}
262
+ onLayout={handleTrackLayout}>
263
+ <AnimatedView
264
+ testID="varia-slider-minimum-track"
265
+ style={[
266
+ SliderStyles.minimumTrack(colorPalette),
267
+ minimumTrackStyles,
268
+ styles.minimumTrack(halfSize, mode),
269
+ animatedTrack,
270
+ ]}
271
+ />
272
+
273
+ {steps && (
274
+ <View style={styles.stepsOverlay} pointerEvents="none">
275
+ <View style={styles.steps}>
276
+ {Array.from({length: steps + 1}, (_, i) => (
277
+ <View
278
+ key={i}
279
+ style={[
280
+ styles.step(i, steps),
281
+ SliderStyles.step(colorPalette),
282
+ ]}
283
+ />
284
+ ))}
285
+ </View>
286
+ </View>
287
+ )}
288
+
289
+ <View style={styles.thumbContainerFull}>
290
+ <AnimatedView style={[animatedThumb, styles.thumbContainer]}>
291
+ <View
292
+ style={[
293
+ SliderStyles.thumb(colorPalette),
294
+ thumbStyles,
295
+ styles.thumb(halfSize),
296
+ ]}>
297
+ {ThumbChildren || null}
298
+ </View>
299
+ </AnimatedView>
300
+ </View>
301
+ {/* <GestureDetector gesture={slideGesture}>
302
+ </GestureDetector> */}
303
+ </View>
304
+ </GestureDetector>
305
+ </View>
306
+ )
307
+ }
308
+
309
+ const styles = StyleSheet.create(theme => ({
310
+ container: (
311
+ halfSize: number,
312
+ flex: ViewStyle['flex'],
313
+ alignSelf: ViewStyle['alignSelf'],
314
+ backgroundColor: ViewStyle['backgroundColor'],
315
+ ) => ({
316
+ flex,
317
+ alignSelf,
318
+ overflow: 'hidden',
319
+ backgroundColor,
320
+ alignItems: 'center',
321
+ // flexBasis: 'auto',
322
+ variants: {
323
+ axis: {
324
+ x: {
325
+ // maxWidth: 'auto',
326
+ paddingTop: 0,
327
+ // paddingRight: halfSize,
328
+ paddingHorizontal: halfSize,
329
+ flexDirection: 'row',
330
+ },
331
+ y: {
332
+ // maxHeight: 'auto',
333
+ // height: '100%',
334
+ // paddingTop: halfSize,
335
+ paddingVertical: halfSize,
336
+ paddingRight: 0,
337
+ flexDirection: 'column',
338
+ },
339
+ },
340
+ },
341
+ _web: {
342
+ _classNames: 'slider-container-base',
343
+ flex: flex === 0 ? undefined : flex,
344
+ },
345
+ }),
346
+ maximumTrack: (mode: 'normal' | 'wrap') => ({
347
+ flex: 1,
348
+ position: 'relative',
349
+ overflow: 'visible',
350
+ flexBasis: 'auto',
351
+ variants: {
352
+ axis: {
353
+ x: {
354
+ ...(mode === 'wrap' ? {height: '100%'} : {}),
355
+ justifyContent: 'center',
356
+ },
357
+ y: {
358
+ ...(mode === 'wrap' ? {width: '100%'} : {}),
359
+ flexDirection: 'row',
360
+ justifyContent: 'center',
361
+ alignItems: 'flex-end',
362
+ },
363
+ },
364
+ },
365
+ _web: {
366
+ _classNames: 'slider-maximun-track-base',
367
+ },
368
+ }),
369
+ minimumTrack: (halfSize: number, mode) => ({
370
+ flexBasis: 'auto',
371
+ variants: {
372
+ axis: {
373
+ x: {
374
+ // flex: 1,
375
+ // marginLeft: halfSize * -1,
376
+ width: '100%',
377
+ bottom: 'auto',
378
+ paddingBottom: 0,
379
+ // paddingLeft: halfSize,
380
+ justifyContent: 'center',
381
+ alignItems: 'flex-end',
382
+ ...(mode === 'wrap'
383
+ ? {transform: [{translateX: halfSize * -1}]}
384
+ : {}),
385
+ },
386
+ y: {
387
+ // flex: 1,
388
+ height: '100%',
389
+ // paddingBottom: halfSize,
390
+ // marginBottom: halfSize * -1,
391
+ paddingLeft: 0,
392
+ alignItems: 'flex-start',
393
+ ...(mode === 'wrap' ? {transform: [{translateY: halfSize}]} : {}),
394
+ },
395
+ },
396
+ },
397
+ _web: {
398
+ _classNames: 'slider-minimum-track-base',
399
+ },
400
+ }),
401
+ thumbContainerFull: {
402
+ // overflow: 'hidden',
403
+ position: 'absolute',
404
+ left: 0,
405
+ right: 0,
406
+ top: 0,
407
+ bottom: 0,
408
+ zIndex: 2,
409
+ _web: {
410
+ _classNames: 'thumb-container-full-base',
411
+ },
412
+ },
413
+ thumbContainer: {
414
+ flex: 1,
415
+ variants: {
416
+ axis: {
417
+ x: {
418
+ justifyContent: 'center',
419
+ },
420
+ y: {
421
+ alignItems: 'center',
422
+ },
423
+ },
424
+ },
425
+ },
426
+ thumb: (halfSize: number) => ({
427
+ variants: {
428
+ axis: {
429
+ x: {
430
+ // height: '100%',
431
+ justifyContent: 'center',
432
+ alignItems: 'center',
433
+ // transform: [{translateX: halfSize * -1}],
434
+ },
435
+ y: {
436
+ // width: '100%',
437
+ justifyContent: 'center',
438
+ alignItems: 'center',
439
+ // transform: [{translateY: halfSize * -1}],
440
+ },
441
+ },
442
+ },
443
+ _web: {
444
+ _classNames: 'slider-thumb-base',
445
+ },
446
+ }),
447
+
448
+ stepsOverlay: {
449
+ position: 'absolute',
450
+ left: 0,
451
+ right: 0,
452
+ top: 0,
453
+ bottom: 0,
454
+ zIndex: 1,
455
+ _web: {
456
+ _classNames: 'slider-steps-overlay-base',
457
+ },
458
+ },
459
+ steps: {
460
+ width: '100%',
461
+ height: '100%',
462
+ justifyContent: 'space-between',
463
+ alignItems: 'center',
464
+ zIndex: 0,
465
+ position: 'absolute',
466
+ variants: {
467
+ axis: {
468
+ x: {
469
+ flexDirection: 'row',
470
+ },
471
+ y: {
472
+ flexDirection: 'column',
473
+ },
474
+ },
475
+ },
476
+ _web: {
477
+ _classNames: 'slider-steps-base',
478
+ },
479
+ },
480
+ step: (index, length) => ({
481
+ backgroundColor:
482
+ index === 0 || index === length ? 'transparent' : theme.colors.fg.default,
483
+ variants: {
484
+ axis: {
485
+ x: {
486
+ width: 1,
487
+ height: '100%',
488
+ },
489
+ y: {
490
+ width: '100%',
491
+ height: 1,
492
+ },
493
+ },
494
+ },
495
+ _web: {
496
+ _classNames: 'slider-step-base',
497
+ },
498
+ }),
499
+ }))
500
+ export default Slider
@@ -1,5 +1,5 @@
1
1
  import {Children, type ReactNode, useImperativeHandle, useState} from 'react'
2
- import {View} from 'react-native'
2
+ import {StyleProp, View, ViewStyle} from 'react-native'
3
3
  import Animated, {
4
4
  useAnimatedReaction,
5
5
  useAnimatedStyle,
@@ -32,6 +32,8 @@ type SlideshowProps = SlideshowVariants & {
32
32
  onSlideChange?: (index: number) => void
33
33
  children: ReactNode
34
34
  ref?: React.RefObject<SlideshowRef | null>
35
+ containerStyles?: StyleProp<ViewStyle>
36
+ slideContainerStyles?: StyleProp<ViewStyle>
35
37
  }
36
38
 
37
39
  const Slideshow = ({
@@ -44,6 +46,8 @@ const Slideshow = ({
44
46
  animation = SlideshowTokens.defaultProps.animation,
45
47
  children,
46
48
  ref,
49
+ containerStyles,
50
+ slideContainerStyles,
47
51
  }: SlideshowProps) => {
48
52
  const isHorizontal = axis === 'x'
49
53
 
@@ -171,7 +175,11 @@ const Slideshow = ({
171
175
  <GestureDetector gesture={slideGesture}>
172
176
  <View
173
177
  testID="varia-slideshow"
174
- style={[styles.container(), SlideshowStyles.container(colorPalette)]}
178
+ style={[
179
+ SlideshowStyles.container(colorPalette),
180
+ containerStyles,
181
+ styles.container(),
182
+ ]}
175
183
  onLayout={e => {
176
184
  setContainerWidth(e.nativeEvent.layout.width)
177
185
  setContainerHeight(e.nativeEvent.layout.height)
@@ -186,8 +194,9 @@ const Slideshow = ({
186
194
  testID={`varia-slides-slide-${index}`}
187
195
  key={index}
188
196
  style={[
189
- styles.slide(`${slideSize}%`, isHorizontal),
190
197
  SlideshowStyles.slideContainer(colorPalette),
198
+ slideContainerStyles,
199
+ styles.slide(`${slideSize}%`, isHorizontal),
191
200
  ]}>
192
201
  {Slide}
193
202
  </View>
@@ -1,4 +1,10 @@
1
- import {Platform, TouchableWithoutFeedback, View} from 'react-native'
1
+ import {
2
+ Platform,
3
+ StyleProp,
4
+ TouchableWithoutFeedback,
5
+ View,
6
+ ViewStyle,
7
+ } from 'react-native'
2
8
  import Animated, {
3
9
  useAnimatedStyle,
4
10
  useSharedValue,
@@ -31,6 +37,8 @@ type SwitchProps = SwitchVariants & {
31
37
  enabledIcon?: ReactNode
32
38
  disabledIcon?: ReactNode
33
39
  alignSelf?: AlignSelf
40
+ containerStyles?: StyleProp<ViewStyle>
41
+ thumbStyles?: StyleProp<ViewStyle>
34
42
  }
35
43
 
36
44
  const Switch = ({
@@ -44,6 +52,8 @@ const Switch = ({
44
52
  size = SwitchTokens.defaultProps.size,
45
53
  flex = 0,
46
54
  alignSelf = 'flex-start',
55
+ containerStyles,
56
+ thumbStyles,
47
57
  }: SwitchProps) => {
48
58
  const animatedRef = useRef<View>(null)
49
59
 
@@ -166,15 +176,17 @@ const Switch = ({
166
176
  <AnimatedView
167
177
  ref={animatedRef}
168
178
  style={[
179
+ SwitchStyles.container(colorPalette),
180
+ containerStyles,
169
181
  styles.container(flex, alignSelf),
170
182
  animatedStyle,
171
- SwitchStyles.container(colorPalette),
172
183
  ]}>
173
184
  <AnimatedView
174
185
  testID="varia-switch-thumb"
175
186
  style={[
176
- styles.thumb,
177
187
  SwitchStyles.thumb(colorPalette),
188
+ thumbStyles,
189
+ styles.thumb,
178
190
  thumbAnimatedStyle,
179
191
  circleTranslationStyle,
180
192
  ]}>
@@ -11,7 +11,7 @@ type TextProps = TextVariants &
11
11
  colorPalette?: PalettesWithNestedKeys
12
12
  fontSize?: number | undefined
13
13
  color?: ThemeColors
14
- style?: TextStyle
14
+ style?: StyleProp<TextStyle>
15
15
  children?: React.ReactNode
16
16
  mixins?: StyleProp<TextStyle> | StyleProp<TextStyle>[]
17
17
  }
@@ -37,8 +37,8 @@ const Text = ({
37
37
  style={[
38
38
  TextStyles.text(colorPalette),
39
39
  styles.text(color, fontSize),
40
- mixins && mixins,
41
40
  style,
41
+ mixins && mixins,
42
42
  ]}
43
43
  {...props}>
44
44
  {children}
@@ -15,6 +15,7 @@ import {PalettesWithNestedKeys, ZIndex} from '../../style/varia/types'
15
15
  import Text from './Text'
16
16
  import {AnimatedHStack, VStack} from '../../patterns'
17
17
  import {ZINDEXES} from '../../style/varia/constants'
18
+ import {StyleProp, TextStyle, ViewStyle} from 'react-native'
18
19
 
19
20
  type ToastVariants = UnistylesVariants<typeof ToastStyles>
20
21
 
@@ -25,6 +26,8 @@ export type ToastProps = ToastVariants & {
25
26
  onClose?: () => void
26
27
  position?: 'top' | 'bottom'
27
28
  zIndex?: ZIndex
29
+ containerStyles?: StyleProp<ViewStyle>
30
+ textStyles?: StyleProp<TextStyle>
28
31
  }
29
32
 
30
33
  const Toast: React.FC<ToastProps> = ({
@@ -36,6 +39,8 @@ const Toast: React.FC<ToastProps> = ({
36
39
  onClose,
37
40
  position = 'bottom',
38
41
  zIndex,
42
+ containerStyles,
43
+ textStyles,
39
44
  }) => {
40
45
  ToastStyles.useVariants({variant, size})
41
46
 
@@ -91,13 +96,19 @@ const Toast: React.FC<ToastProps> = ({
91
96
  justifyContent:
92
97
  position === 'bottom' || !position ? 'flex-end' : 'flex-start',
93
98
  },
94
- styles.container(zIndex || ZINDEXES.toast),
95
99
  ToastStyles.root,
100
+ styles.container(zIndex || ZINDEXES.toast),
96
101
  ]}>
97
102
  <AnimatedHStack
98
103
  ref={animatedRef}
99
- style={[animatedStyle, ToastStyles.container(colorPalette)]}>
100
- <Text style={ToastStyles.text(colorPalette)}>{message}</Text>
104
+ style={[
105
+ animatedStyle,
106
+ ToastStyles.container(colorPalette),
107
+ containerStyles,
108
+ ]}>
109
+ <Text style={[ToastStyles.text(colorPalette), textStyles]}>
110
+ {message}
111
+ </Text>
101
112
  </AnimatedHStack>
102
113
  </VStack>
103
114
  )
@@ -1,7 +1,8 @@
1
1
  import {createContext, useContext} from 'react'
2
2
  import {UnistylesVariants} from 'react-native-unistyles'
3
- import {FieldStyles} from '../../theme/Field.recipe'
4
- import {PalettesWithNestedKeys} from '../../style/varia/types'
3
+ import {FieldStyles} from '../../../theme/Field.recipe'
4
+ import {PalettesWithNestedKeys} from '../../../style/varia/types'
5
+ import {StyleProp, TextStyle} from 'react-native'
5
6
 
6
7
  export type FieldVariants = UnistylesVariants<typeof FieldStyles>
7
8
 
@@ -10,6 +11,7 @@ export type FieldContextType = {
10
11
  variant?: FieldVariants['variant']
11
12
  size?: FieldVariants['size']
12
13
  colorPalette?: PalettesWithNestedKeys
14
+ labelStyles?: StyleProp<TextStyle>
13
15
  }
14
16
 
15
17
  const FieldContext = createContext<FieldContextType | undefined>(undefined)
@@ -287,3 +287,9 @@ export type rotationDirection = 'clockwise' | 'counterclockwise'
287
287
  export type Flex = ViewStyle['flex']
288
288
  export type MaxWidth = ViewStyle['maxWidth']
289
289
  export type ZIndex = ViewStyle['zIndex']
290
+
291
+ export type Axis = 'x' | 'y'
292
+ export type SizeEntry = {
293
+ x?: Record<string, any>
294
+ y?: Record<string, any>
295
+ }
@@ -37,6 +37,7 @@ import {
37
37
  ColorScheme,
38
38
  CreatePresetDTO,
39
39
  CustomColorScheme,
40
+ SizeEntry,
40
41
  ThemeColors,
41
42
  ThemePresetDTO,
42
43
  } from './types'
@@ -439,3 +440,9 @@ export function getCompoundVariantValue<
439
440
 
440
441
  return match.styles[propName]
441
442
  }
443
+
444
+ export const generateCompoundVariants = (sizes: Record<string, SizeEntry>) =>
445
+ Object.entries(sizes).flatMap(([size, axes]) => [
446
+ {axis: 'x', size, styles: axes.x ?? {}},
447
+ {axis: 'y', size, styles: axes.y ?? {}},
448
+ ])