react-native-varia 0.3.0 → 0.4.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.
Files changed (45) hide show
  1. package/lib/components/Accordion.tsx +61 -21
  2. package/lib/components/Badge.tsx +9 -0
  3. package/lib/components/Button.tsx +19 -8
  4. package/lib/components/Checkbox.tsx +21 -12
  5. package/lib/components/CircleProgress.tsx +8 -0
  6. package/lib/components/Divider.tsx +6 -0
  7. package/lib/components/Drawer.tsx +16 -4
  8. package/lib/components/Field.tsx +4 -0
  9. package/lib/components/FloatingAction.tsx +215 -0
  10. package/lib/components/GradientBackground.tsx +3 -0
  11. package/lib/components/GradientText.tsx +27 -14
  12. package/lib/components/IconWrapper.tsx +4 -3
  13. package/lib/components/Input.tsx +47 -21
  14. package/lib/components/Link.tsx +4 -0
  15. package/lib/components/Modal.tsx +18 -5
  16. package/lib/components/NumberInput.tsx +27 -5
  17. package/lib/components/RadioGroup.tsx +16 -5
  18. package/lib/components/ReText.tsx +4 -1
  19. package/lib/components/Select.tsx +20 -0
  20. package/lib/components/Slider.tsx +59 -23
  21. package/lib/components/Slideshow.tsx +19 -3
  22. package/lib/components/Spinner.tsx +9 -3
  23. package/lib/components/Switch.tsx +57 -26
  24. package/lib/components/Text.tsx +3 -0
  25. package/lib/components/Toast.tsx +110 -36
  26. package/lib/patterns/index.tsx +299 -90
  27. package/lib/theme/Accordion.tsx +184 -0
  28. package/lib/theme/Button.recipe.tsx +24 -7
  29. package/lib/theme/Drawer.recipe.tsx +2 -4
  30. package/lib/theme/Field.recipe.tsx +45 -15
  31. package/lib/theme/FloatingAction.tsx +112 -0
  32. package/lib/theme/GradientText.recipe.tsx +103 -34
  33. package/lib/theme/Input.recipe.tsx +14 -6
  34. package/lib/theme/Select.recipe.tsx +3 -0
  35. package/lib/theme/Slider.recipe.tsx +86 -150
  36. package/lib/theme/Spinner.recipe.tsx +4 -0
  37. package/lib/theme/Switch.recipe.tsx +19 -0
  38. package/lib/theme/Text.recipe.tsx +63 -12
  39. package/lib/theme/Toast.recipe.tsx +40 -7
  40. package/lib/varia/types.ts +3 -0
  41. package/lib/varia/utils.ts +110 -18
  42. package/package.json +1 -1
  43. package/lib/components/OldSlider.tsx +0 -327
  44. package/lib/components/SlidingDrawer.tsx +0 -301
  45. package/lib/patterns/newPatterns.tsx +0 -285
@@ -1,23 +1,28 @@
1
- import React, {useEffect} from 'react'
2
- import {StyleSheet} from 'react-native'
1
+ import React, {useEffect, useState} from 'react'
2
+ import {StyleSheet} from 'react-native-unistyles'
3
3
  import Animated, {
4
4
  useSharedValue,
5
5
  useAnimatedStyle,
6
+ useAnimatedRef,
7
+ measure,
6
8
  withTiming,
7
9
  Easing,
8
10
  } from 'react-native-reanimated'
9
- import {scheduleOnRN} from 'react-native-worklets'
11
+ import {scheduleOnRN, scheduleOnUI} from 'react-native-worklets'
10
12
  import {ToastStyles, ToastDefaultVariants} from '../theme/Toast.recipe'
11
13
  import {UnistylesVariants} from 'react-native-unistyles'
12
14
  import {PalettesWithNestedKeys} from '../style/varia/types'
13
15
  import Text from './Text'
16
+ import {AnimatedHStack, VStack} from '../patterns/newPatterns'
14
17
 
15
18
  type ToastVariants = UnistylesVariants<typeof ToastStyles>
16
- type ToastProps = ToastVariants & {
19
+
20
+ export type ToastProps = ToastVariants & {
17
21
  colorPalette?: PalettesWithNestedKeys
18
22
  message: string
19
23
  duration?: number
20
24
  onClose?: () => void
25
+ position?: 'top' | 'bottom'
21
26
  }
22
27
 
23
28
  const Toast: React.FC<ToastProps> = ({
@@ -27,13 +32,13 @@ const Toast: React.FC<ToastProps> = ({
27
32
  message,
28
33
  duration = 5000,
29
34
  onClose,
35
+ position = 'bottom',
30
36
  }) => {
31
- ToastStyles.useVariants({
32
- variant,
33
- size,
34
- })
37
+ ToastStyles.useVariants({variant, size})
38
+
39
+ const animatedRef = useAnimatedRef<Animated.View>()
40
+ const translateY = useSharedValue(0)
35
41
  const opacity = useSharedValue(0)
36
- const translateY = useSharedValue(50) // Aparece desde abajo
37
42
 
38
43
  const animatedStyle = useAnimatedStyle(() => ({
39
44
  opacity: opacity.value,
@@ -41,49 +46,118 @@ const Toast: React.FC<ToastProps> = ({
41
46
  }))
42
47
 
43
48
  useEffect(() => {
44
- // Animación de entrada
45
- opacity.value = withTiming(1, {
46
- duration: 200,
47
- easing: Easing.out(Easing.ease),
48
- })
49
- translateY.value = withTiming(0, {
50
- duration: 200,
51
- easing: Easing.out(Easing.ease),
52
- })
49
+ scheduleOnUI(() => {
50
+ 'worklet'
51
+ const m = measure(animatedRef)
52
+ if (m === null) return
53
+ const height = m.height
54
+
55
+ translateY.value = position === 'bottom' ? height : -height
56
+ opacity.value = 0
53
57
 
54
- // Animación de salida
55
- const timeout = setTimeout(() => {
56
- opacity.value = withTiming(0, {duration: 300})
57
- translateY.value = withTiming(50, {duration: 300}, () => {
58
- if (onClose) scheduleOnRN(onClose)
58
+ translateY.value = withTiming(0, {
59
+ duration: 200,
60
+ easing: Easing.out(Easing.ease),
61
+ })
62
+ opacity.value = withTiming(1, {
63
+ duration: 200,
64
+ easing: Easing.out(Easing.ease),
59
65
  })
60
- }, duration)
61
66
 
62
- return () => clearTimeout(timeout)
67
+ const timeout = setTimeout(() => {
68
+ opacity.value = withTiming(0, {duration: 300})
69
+ translateY.value = withTiming(
70
+ position === 'bottom' ? height : -height,
71
+ {duration: 300},
72
+ () => {
73
+ if (onClose) {
74
+ scheduleOnRN(onClose)
75
+ }
76
+ },
77
+ )
78
+ }, duration)
79
+ })
63
80
  }, [])
64
81
 
65
82
  return (
66
- <Animated.View
83
+ <VStack
67
84
  style={[
85
+ {
86
+ ...StyleSheet.absoluteFill,
87
+ justifyContent:
88
+ position === 'bottom' || !position ? 'flex-end' : 'flex-start',
89
+ },
68
90
  styles.container,
69
- animatedStyle,
70
- ToastStyles.container(colorPalette),
91
+ ToastStyles.root,
71
92
  ]}>
72
- <Text style={ToastStyles.text(colorPalette)}>{message}</Text>
73
- </Animated.View>
93
+ <AnimatedHStack
94
+ ref={animatedRef}
95
+ style={[animatedStyle, ToastStyles.container(colorPalette)]}>
96
+ <Text style={ToastStyles.text(colorPalette)}>{message}</Text>
97
+ </AnimatedHStack>
98
+ </VStack>
74
99
  )
75
100
  }
76
101
 
77
102
  const styles = StyleSheet.create({
78
103
  container: {
79
- position: 'absolute',
80
- bottom: 50,
81
- // left: 20,
82
- // right: 20,
83
- padding: 15,
84
- borderRadius: 8,
85
104
  alignItems: 'center',
105
+ overflow: 'hidden',
106
+ zIndex: 100,
107
+ pointerEvents: 'box-none',
108
+ _web: {
109
+ pointerEvents: 'none',
110
+ _classNames: 'toast-container-base',
111
+ },
86
112
  },
87
113
  })
88
114
 
89
115
  export default Toast
116
+
117
+ type ToastItem = ToastProps & {id: number}
118
+
119
+ let nextId = 0
120
+ let enqueueToastInternal: ((opts: ToastProps) => number | void) | null = null
121
+
122
+ export function showToast(opts: ToastProps): number | void {
123
+ if (enqueueToastInternal) {
124
+ return enqueueToastInternal(opts)
125
+ } else {
126
+ console.warn('ToastController not mounted — no toast shown')
127
+ }
128
+ }
129
+
130
+ export const ToastController: React.FC = () => {
131
+ const [currentToast, setCurrentToast] = useState<ToastItem | null>(null)
132
+ const [queue, setQueue] = useState<ToastItem[]>([])
133
+
134
+ useEffect(() => {
135
+ enqueueToastInternal = (opts: ToastProps) => {
136
+ const id = nextId++
137
+ const toastItem = {...opts, id}
138
+
139
+ setQueue(prev => [...prev, toastItem])
140
+ return id
141
+ }
142
+
143
+ return () => {
144
+ enqueueToastInternal = null
145
+ }
146
+ }, [])
147
+
148
+ const handleClose = () => {
149
+ setCurrentToast(null)
150
+ }
151
+
152
+ useEffect(() => {
153
+ if (!currentToast && queue.length > 0) {
154
+ const [nextToast, ...rest] = queue
155
+ setCurrentToast(nextToast)
156
+ setQueue(rest)
157
+ }
158
+ }, [currentToast, queue])
159
+
160
+ if (!currentToast) return null
161
+
162
+ return <Toast key={currentToast.id} {...currentToast} onClose={handleClose} />
163
+ }
@@ -1,102 +1,331 @@
1
- import React from 'react'
1
+ import React, {useMemo} from 'react'
2
2
  import {Children, useLayoutEffect, useRef, useState} from 'react'
3
3
  import type {ReactNode} from 'react'
4
4
  import {ScrollView, View} from 'react-native'
5
5
  import type {StyleProp, ViewProps, ViewStyle} from 'react-native'
6
+ import Animated, {AnimatedRef} from 'react-native-reanimated'
6
7
  import {StyleSheet, UnistylesRuntime} from 'react-native-unistyles'
7
8
 
8
- type SpacingValue = number | string
9
-
10
- export interface SpacingProps {
11
- m?: SpacingValue
12
- mt?: SpacingValue
13
- mb?: SpacingValue
14
- ml?: SpacingValue
15
- mr?: SpacingValue
16
- mx?: SpacingValue
17
- my?: SpacingValue
18
- p?: SpacingValue
19
- pt?: SpacingValue
20
- pb?: SpacingValue
21
- pl?: SpacingValue
22
- pr?: SpacingValue
23
- px?: SpacingValue
24
- py?: SpacingValue
25
-
9
+ interface StackProps {
10
+ backgroundColor?: ViewStyle['backgroundColor']
11
+ bg?: ViewStyle['backgroundColor']
12
+ width?: ViewStyle['width']
13
+ w?: ViewStyle['width']
14
+ minWidth?: ViewStyle['width']
15
+ maxWidth?: ViewStyle['width']
16
+ height?: ViewStyle['height']
17
+ h?: ViewStyle['height']
18
+ minHeight?: ViewStyle['height']
19
+ maxHeight?: ViewStyle['height']
20
+ borderColor?: ViewStyle['borderColor']
21
+ borderWidth?: ViewStyle['borderWidth']
22
+ borderStyle?: ViewStyle['borderStyle']
23
+ borderRadius?: ViewStyle['borderRadius']
24
+ br?: ViewStyle['borderRadius']
26
25
  alignSelf?: ViewStyle['alignSelf']
27
-
28
26
  alignItems?: ViewStyle['alignItems']
29
27
  justifyContent?: ViewStyle['justifyContent']
28
+ flex?: ViewStyle['flex']
29
+ flexShrink?: ViewStyle['flexShrink']
30
+ flexGrow?: ViewStyle['flexGrow']
31
+ flexBasis?: ViewStyle['flexBasis']
32
+ flexWrap?: ViewStyle['flexWrap']
33
+ gap?: ViewStyle['gap']
34
+ m?: ViewStyle['margin']
35
+ mt?: ViewStyle['marginTop']
36
+ mb?: ViewStyle['marginBottom']
37
+ ml?: ViewStyle['marginLeft']
38
+ mr?: ViewStyle['marginRight']
39
+ mx?: ViewStyle['marginHorizontal']
40
+ my?: ViewStyle['marginVertical']
41
+ margin?: ViewStyle['margin']
42
+ marginVertical?: ViewStyle['marginVertical']
43
+ marginHorizontal?: ViewStyle['marginHorizontal']
44
+ marginTop?: ViewStyle['marginTop']
45
+ marginBottom?: ViewStyle['marginBottom']
46
+ marginLeft?: ViewStyle['marginLeft']
47
+ marginRight?: ViewStyle['marginRight']
48
+ p?: ViewStyle['padding']
49
+ pt?: ViewStyle['paddingVertical']
50
+ pb?: ViewStyle['paddingVertical']
51
+ pl?: ViewStyle['paddingLeft']
52
+ pr?: ViewStyle['paddingRight']
53
+ px?: ViewStyle['paddingHorizontal']
54
+ py?: ViewStyle['paddingVertical']
55
+ padding?: ViewStyle['padding']
56
+ paddingVertical?: ViewStyle['paddingVertical']
57
+ paddingHorizontal?: ViewStyle['paddingHorizontal']
58
+ paddingTop?: ViewStyle['paddingTop']
59
+ paddingBottom?: ViewStyle['paddingBottom']
60
+ paddingLeft?: ViewStyle['paddingLeft']
61
+ paddingRight?: ViewStyle['paddingRight']
62
+ children?: React.ReactNode
63
+ // style?: ViewStyle
64
+ style?: StyleProp<ViewStyle>
65
+ align?: 'center' | 'vCenter' | 'hCenter'
30
66
  }
31
67
 
32
- type LayoutProps = {
33
- center?: boolean
34
- vCenter?: boolean
35
- hCenter?: boolean
36
- flex?: number
37
- gap?: number
68
+ function mapProps(props: StackProps) {
69
+ const stylesArr: any[] = []
70
+
71
+ Object.entries(props).forEach(([key, value]) => {
72
+ if (value == null) return
73
+
74
+ const fn = (stackStyles as any)[key]
75
+ if (typeof fn === 'function') {
76
+ stylesArr.push(fn(value))
77
+ }
78
+ })
79
+
80
+ return stylesArr
38
81
  }
39
82
 
40
- export type HStackProps = SpacingProps &
41
- LayoutProps &
42
- Omit<React.ComponentProps<'View'>, keyof SpacingProps | keyof LayoutProps>
83
+ const VStack = ({children, style, align, ...props}: StackProps) => {
84
+ stackStyles.useVariants({align})
85
+ const styleArr = useMemo(() => mapProps(props), [props])
43
86
 
44
- export type HstackProps = {
45
- children?: ReactNode
46
- style?: StyleProp<ViewStyle>
47
- center?: boolean
48
- vCenter?: boolean
49
- hCenter?: boolean
50
- flex?: number
51
- gap?: number
52
- stretch?: boolean
53
- } & ViewProps
87
+ return (
88
+ <View style={[stackStyles.stack, stackStyles.vstack, styleArr, style]}>
89
+ {children}
90
+ </View>
91
+ )
92
+ }
93
+
94
+ const HStack = ({children, style, align, ...props}: StackProps) => {
95
+ stackStyles.useVariants({align})
96
+ const styleArr = useMemo(() => mapProps(props), [props])
54
97
 
55
- const HStack: React.FC<HstackProps> = ({
56
- children,
57
- style,
58
- center,
59
- vCenter,
60
- hCenter,
61
- flex = 0,
62
- gap = 0,
63
- stretch,
64
- ...props
65
- }) => {
66
98
  return (
67
- <View
68
- style={[
69
- styles.hStack(center, vCenter, hCenter, gap, flex, stretch),
70
- style,
71
- ]}
72
- {...props}>
99
+ <View style={[stackStyles.stack, stackStyles.hstack, styleArr, style]}>
73
100
  {children}
74
101
  </View>
75
102
  )
76
103
  }
77
- const VStack: React.FC<HstackProps> = ({
104
+ const AnimatedView = Animated.createAnimatedComponent(View)
105
+
106
+ const AnimatedHStack = ({
78
107
  children,
79
108
  style,
80
- center,
81
- vCenter,
82
- hCenter,
83
- flex = 0,
84
- gap = 0,
85
- stretch,
109
+ align,
110
+ ref,
86
111
  ...props
112
+ }: StackProps & {
113
+ ref?: AnimatedRef<Animated.View>
87
114
  }) => {
115
+ stackStyles.useVariants({align})
116
+ const styleArr = useMemo(() => mapProps(props), [props])
117
+
88
118
  return (
89
- <View
90
- style={[
91
- styles.vStack(center, vCenter, hCenter, gap, flex, stretch),
92
- style,
93
- ]}
94
- {...props}>
119
+ <AnimatedView
120
+ ref={ref && ref}
121
+ style={[stackStyles.stack, stackStyles.vstack, styleArr, style]}>
95
122
  {children}
96
- </View>
123
+ </AnimatedView>
97
124
  )
98
125
  }
99
126
 
127
+ const stackStyles = StyleSheet.create({
128
+ stack: {},
129
+ vstack: {
130
+ flexDirection: 'column',
131
+ variants: {
132
+ align: {
133
+ center: {
134
+ alignItems: 'center',
135
+ justifyContent: 'center',
136
+ },
137
+ vCenter: {
138
+ justifyContent: 'center',
139
+ },
140
+ hCenter: {
141
+ alignItems: 'center',
142
+ },
143
+ },
144
+ },
145
+ },
146
+ hstack: {
147
+ flexDirection: 'row',
148
+ variants: {
149
+ align: {
150
+ center: {
151
+ alignItems: 'center',
152
+ justifyContent: 'center',
153
+ },
154
+ vCenter: {
155
+ alignItems: 'center',
156
+ },
157
+ hCenter: {
158
+ justifyContent: 'center',
159
+ },
160
+ },
161
+ },
162
+ },
163
+
164
+ backgroundColor: value => ({
165
+ backgroundColor: value,
166
+ }),
167
+ bg: value => ({
168
+ backgroundColor: value,
169
+ }),
170
+
171
+ width: value => ({
172
+ width: value,
173
+ }),
174
+ w: value => ({
175
+ width: value,
176
+ }),
177
+ minWidth: value => ({
178
+ minWidth: value,
179
+ }),
180
+ maxWidth: value => ({
181
+ maxWidth: value,
182
+ }),
183
+ height: value => ({
184
+ height: value,
185
+ }),
186
+ h: value => ({
187
+ height: value,
188
+ }),
189
+ minHeight: value => ({
190
+ minHeight: value,
191
+ }),
192
+ maxHeight: value => ({
193
+ maxHeight: value,
194
+ }),
195
+
196
+ borderColor: value => ({
197
+ borderColor: value,
198
+ }),
199
+ borderWidth: value => ({
200
+ borderWidth: value,
201
+ }),
202
+ borderStyle: value => ({
203
+ borderStyle: value,
204
+ }),
205
+ borderRadius: value => ({
206
+ borderRadius: value,
207
+ }),
208
+ br: value => ({
209
+ borderRadius: value,
210
+ }),
211
+
212
+ flex: value => ({
213
+ flex: value,
214
+ }),
215
+ flexShrink: value => ({
216
+ flexShrink: value,
217
+ }),
218
+ flexGrow: value => ({
219
+ flexGrow: value,
220
+ }),
221
+ flexBasis: value => ({
222
+ flexBasis: value,
223
+ }),
224
+ flexWrap: value => ({
225
+ flexWrap: value,
226
+ }),
227
+ alignSelf: value => ({
228
+ alignSelf: value,
229
+ }),
230
+ alignItems: value => ({
231
+ alignItems: value,
232
+ }),
233
+ justifyContent: value => ({
234
+ justifyContent: value,
235
+ }),
236
+ gap: value => ({
237
+ gap: value,
238
+ }),
239
+
240
+ m: value => ({
241
+ margin: value,
242
+ }),
243
+ mt: value => ({
244
+ marginTop: value,
245
+ }),
246
+ mb: value => ({
247
+ marginBottom: value,
248
+ }),
249
+ ml: value => ({
250
+ marginLeft: value,
251
+ }),
252
+ mr: value => ({
253
+ marginRight: value,
254
+ }),
255
+ mx: value => ({
256
+ marginHorizontal: value,
257
+ }),
258
+ my: value => ({
259
+ marginVertical: value,
260
+ }),
261
+ margin: value => ({
262
+ margin: value,
263
+ }),
264
+ marginVertical: value => ({
265
+ marginVertical: value,
266
+ }),
267
+ marginHorizontal: value => ({
268
+ marginHorizontal: value,
269
+ }),
270
+ marginLeft: value => ({
271
+ marginLeft: value,
272
+ }),
273
+ marginRight: value => ({
274
+ marginRight: value,
275
+ }),
276
+ marginTop: value => ({
277
+ marginTop: value,
278
+ }),
279
+ marginBottom: value => ({
280
+ marginBottom: value,
281
+ }),
282
+
283
+ p: value => ({
284
+ padding: value,
285
+ }),
286
+ pt: value => ({
287
+ paddingTop: value,
288
+ }),
289
+ pb: value => ({
290
+ paddingBottom: value,
291
+ }),
292
+ pl: value => ({
293
+ paddingLeft: value,
294
+ }),
295
+ pr: value => ({
296
+ paddingRight: value,
297
+ }),
298
+ px: value => ({
299
+ paddingHorizontal: value,
300
+ }),
301
+ py: value => ({
302
+ paddingVertical: value,
303
+ }),
304
+ padding: value => ({
305
+ padding: value,
306
+ }),
307
+ paddingHorizontal: value => ({
308
+ paddingHorizontal: value,
309
+ }),
310
+ paddingVertical: value => ({
311
+ paddingVertical: value,
312
+ }),
313
+ paddingLeft: value => ({
314
+ paddingLeft: value,
315
+ }),
316
+ paddingRight: value => ({
317
+ paddingRight: value,
318
+ }),
319
+ paddingTop: value => ({
320
+ paddingTop: value,
321
+ }),
322
+ paddingBottom: value => ({
323
+ paddingBottom: value,
324
+ }),
325
+ })
326
+
327
+ export {VStack, HStack, AnimatedHStack}
328
+
100
329
  export const VSpacer = ({size}: {size?: number}) => {
101
330
  return (
102
331
  <View
@@ -126,26 +355,6 @@ export const FlexSpacer = () => {
126
355
  />
127
356
  )
128
357
  }
129
- const styles = StyleSheet.create(() => ({
130
- hStack: (center, vCenter, hCenter, gap, flex, stretch) => ({
131
- flex,
132
- gap,
133
- flexDirection: 'row',
134
- alignItems: center ? 'center' : vCenter ? 'center' : 'stretch',
135
- justifyContent: center ? 'center' : hCenter ? 'center' : 'flex-start',
136
- ...(stretch ? {alignSelf: 'stretch'} : {}),
137
- }),
138
- vStack: (center, vCenter, hCenter, gap, flex, stretch) => ({
139
- flex,
140
- gap,
141
- flexDirection: 'column',
142
- alignItems: center ? 'center' : vCenter ? 'center' : 'stretch',
143
- justifyContent: center ? 'center' : hCenter ? 'center' : 'flex-start',
144
- ...(stretch ? {alignSelf: 'stretch'} : {}),
145
- }),
146
- }))
147
-
148
- export {HStack, VStack}
149
358
 
150
359
  export const gap = (size: number) => ({
151
360
  gap: size,