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.
@@ -14,6 +14,7 @@ import {
14
14
  SlidingDrawerStyles,
15
15
  } from '../theme/SlidingDrawer.recipe'
16
16
  import {PalettesWithNestedKeys} from '../style/varia/types'
17
+ import {TouchableWithoutFeedback} from 'react-native'
17
18
 
18
19
  export type SlidingDrawerRef = {
19
20
  snapTo: (point: number) => void | null
@@ -26,6 +27,7 @@ type SlidingDrawerVariants = UnistylesVariants<typeof SlidingDrawerStyles>
26
27
  type SlidingDrawerProps = SlidingDrawerVariants & {
27
28
  colorPalette?: PalettesWithNestedKeys
28
29
  animation?: keyof typeof SlidingDrawerTokens.variants.animation
30
+ width?: string
29
31
  flex?: number
30
32
  direction?: 1 | -1
31
33
  onCollapse?: () => void
@@ -35,14 +37,20 @@ type SlidingDrawerProps = SlidingDrawerVariants & {
35
37
  axis: 'y' | 'x'
36
38
  allowGestures?: boolean
37
39
  overlay?: boolean
40
+ closeOnOverlayPress?: boolean
38
41
  children?: React.ReactNode
39
- ref?: React.RefObject<SlidingDrawerRef>
42
+ ref?: React.RefObject<SlidingDrawerRef | null>
40
43
  }
41
44
 
45
+ const AnimatedTouchableOpacity = Animated.createAnimatedComponent(
46
+ TouchableWithoutFeedback,
47
+ )
48
+
42
49
  const SlidingDrawer = ({
43
50
  colorPalette = 'accent',
44
51
  variant = SlidingDrawerTokens.defaultProps.variant,
45
52
  animation = SlidingDrawerTokens.defaultProps.animation,
53
+ width = '100%',
46
54
  flex = 0,
47
55
  direction = 1,
48
56
  onCollapse,
@@ -52,6 +60,7 @@ const SlidingDrawer = ({
52
60
  axis,
53
61
  allowGestures = true,
54
62
  overlay = false,
63
+ closeOnOverlayPress = true,
55
64
  children,
56
65
  ref,
57
66
  }: SlidingDrawerProps) => {
@@ -147,12 +156,44 @@ const SlidingDrawer = ({
147
156
  })
148
157
  .onUpdate(event => {
149
158
  const delta = axis === 'y' ? event.translationY : event.translationX
150
- translate.value = delta + (context.value.position ?? 0)
159
+
160
+ const proposed = delta + (context.value.position ?? 0)
161
+
162
+ const minPoint = Math.min(...points)
163
+ const maxPoint = Math.max(...points)
164
+
165
+ let clamped = proposed
166
+
167
+ // Si se pasa del rango, aplicamos resistencia
168
+ if (proposed < minPoint) {
169
+ const overdrag = minPoint - proposed
170
+ // Cuanto mayor sea el exceso, menos se mueve (efecto pesado)
171
+ clamped = minPoint - overdrag / (1 + overdrag / 60)
172
+ } else if (proposed > maxPoint) {
173
+ const overdrag = proposed - maxPoint
174
+ clamped = maxPoint + overdrag / (1 + overdrag / 60)
175
+ }
176
+
177
+ translate.value = clamped
178
+ // translate.value = delta + (context.value.position ?? 0)
151
179
  })
152
180
  .onEnd(({velocityX, velocityY, translationX, translationY}) => {
153
181
  const velocity = axis === 'y' ? velocityY : velocityX
154
182
  const translation = axis === 'y' ? translationY : translationX
155
183
 
184
+ const minPoint = Math.min(...points)
185
+ const maxPoint = Math.max(...points)
186
+
187
+ // 🧲 1. Si está fuera del rango, lo regresamos suavemente
188
+ if (translate.value < minPoint) {
189
+ translate.value = withSpring(minPoint, {velocity})
190
+ return
191
+ } else if (translate.value > maxPoint) {
192
+ translate.value = withSpring(maxPoint, {velocity})
193
+ return
194
+ }
195
+
196
+ // 🧭 2. Lógica original de snapping
156
197
  const forwardsThreshold =
157
198
  (points[context.value.snapPoint] +
158
199
  points[context.value.snapPoint + 1]) /
@@ -214,20 +255,21 @@ const SlidingDrawer = ({
214
255
  return (
215
256
  <>
216
257
  {overlay && (
217
- <Animated.View
218
- style={[
219
- {
220
- ...StyleSheet.absoluteFillObject,
221
- },
222
- displayOverlayStyle,
223
- SlidingDrawerStyles.backdrop(colorPalette),
224
- ]}
225
- />
258
+ <AnimatedTouchableOpacity
259
+ onPress={() => closeOnOverlayPress && collapse()}>
260
+ <Animated.View
261
+ style={[
262
+ StyleSheet.absoluteFillObject,
263
+ displayOverlayStyle,
264
+ SlidingDrawerStyles.backdrop(colorPalette),
265
+ ]}
266
+ />
267
+ </AnimatedTouchableOpacity>
226
268
  )}
227
269
  <GestureDetector gesture={slideGesture}>
228
270
  <Animated.View
229
271
  style={[
230
- styles.container(flex, direction, axis, SlidingDrawerTokens),
272
+ styles.container(flex, direction, axis, width),
231
273
  blockAnimatedStyle,
232
274
  SlidingDrawerStyles.container(colorPalette),
233
275
  ]}>
@@ -240,14 +282,16 @@ const SlidingDrawer = ({
240
282
  export default SlidingDrawer
241
283
 
242
284
  const styles = StyleSheet.create({
243
- container: (flex, direction, axis, slidingDrawerTokens): any => ({
285
+ container: (flex, direction, axis, width): any => ({
244
286
  position: flex === 0 ? 'absolute' : 'relative',
245
- bottom: axis === 'y' && direction === 1 ? 0 : 'auto',
246
- top: axis === 'y' && direction === -1 ? 0 : 'auto',
287
+ bottom: axis === 'y' && direction === -1 ? 0 : 'auto',
288
+ top: axis === 'y' && direction === 1 ? 0 : 'auto',
247
289
  left: axis === 'x' ? 0 : 'auto',
248
290
  flex: flex === 0 ? 1 : flex,
249
291
  height: '100%',
250
- width: '100%',
292
+ width,
293
+ flexDirection: 'column',
294
+ alignSelf: 'stretch',
251
295
  alignItems: 'center',
252
296
  justifyContent: 'flex-start',
253
297
  zIndex: 100,
@@ -0,0 +1,24 @@
1
+ import * as React from 'react'
2
+ import {IconWrapperProps, ThemedIcon} from '../components/IconWrapper'
3
+ import {Path} from 'react-native-svg'
4
+ import {View} from 'react-native'
5
+
6
+ const Minus = ({
7
+ color,
8
+ ...props
9
+ }: Omit<IconWrapperProps, 'children' | 'colors'>) => {
10
+ return (
11
+ <ThemedIcon {...props} color={color}>
12
+ <>
13
+ <Path
14
+ stroke={color}
15
+ strokeLinecap="round"
16
+ strokeLinejoin="round"
17
+ strokeWidth="2.5"
18
+ d="M1.5 12h20"
19
+ />
20
+ </>
21
+ </ThemedIcon>
22
+ )
23
+ }
24
+ export default Minus
@@ -0,0 +1,23 @@
1
+ import * as React from 'react'
2
+ import {IconWrapperProps, ThemedIcon} from '../components/IconWrapper'
3
+ import {Path} from 'react-native-svg'
4
+
5
+ const Plus = ({
6
+ color,
7
+ ...props
8
+ }: Omit<IconWrapperProps, 'children' | 'colors'>) => {
9
+ return (
10
+ <ThemedIcon {...props} color={color}>
11
+ <>
12
+ <Path
13
+ stroke={color}
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ strokeWidth="2.5"
17
+ d="M1.5 11.5h20m-10-10v20"
18
+ />
19
+ </>
20
+ </ThemedIcon>
21
+ )
22
+ }
23
+ export default Plus
@@ -38,7 +38,7 @@ export const NumberInputStyles = StyleSheet.create(theme => ({
38
38
  },
39
39
  variant: {
40
40
  solid: {
41
- color: theme.colors[colorPalette]['1'],
41
+ color: theme.colors[colorPalette].text,
42
42
  borderColor: theme.colors.border.default,
43
43
  borderWidth: 1,
44
44
  borderRadius: theme.radii.sm,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-varia",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "bin": {
5
5
  "varia": "bin/cli.js"
6
6
  },
@@ -13,6 +13,7 @@
13
13
  "description": "",
14
14
  "dependencies": {
15
15
  "commander": "^14.0.0",
16
- "fs-extra": "^11.3.1"
16
+ "fs-extra": "^11.3.1",
17
+ "inquirer": "^8.2.7"
17
18
  }
18
19
  }
@@ -1,202 +0,0 @@
1
- import React, {createContext, useContext, useState, ReactNode} from 'react'
2
- import {
3
- View,
4
- // Text,
5
- TouchableOpacity,
6
- ScrollView,
7
- TouchableWithoutFeedback,
8
- StyleSheet,
9
- } from 'react-native'
10
- import Text from './Text'
11
- import {StyleSheet as UniStyleSheet} from 'react-native-unistyles'
12
- import {SelectStyles, SelectDefaultVariants} from '../theme/Select.recipe'
13
- import {PalettesWithNestedKeys} from '../style/varia/types'
14
- import {UnistylesVariants} from 'react-native-unistyles'
15
- import {Portal} from '@gorhom/portal'
16
-
17
- type SelectVariants = UnistylesVariants<typeof SelectStyles>
18
-
19
- interface Option {
20
- label: string
21
- value: string
22
- }
23
-
24
- interface SelectContextType {
25
- value: string
26
- setValue: (val: string) => void
27
- isOpen: boolean
28
- setIsOpen: (open: boolean) => void
29
- options: Option[]
30
- colorPalette: PalettesWithNestedKeys
31
- variant: SelectVariants['variant']
32
- size: SelectVariants['size']
33
- }
34
-
35
- const SelectContext = createContext<SelectContextType | undefined>(undefined)
36
-
37
- const useSelect = () => {
38
- const context = useContext(SelectContext)
39
- if (!context)
40
- throw new Error('Select subcomponent must be used within Select.Root')
41
- return context
42
- }
43
-
44
- type RootProps = SelectVariants & {
45
- options: Option[]
46
- value?: string
47
- onChange?: (val: string) => void
48
- defaultValue?: string
49
- placeholder?: string
50
- colorPalette?: PalettesWithNestedKeys
51
- flex?: number
52
- children: ReactNode
53
- portalHostName?: string
54
- }
55
-
56
- export const Select = {
57
- Root: ({
58
- options,
59
- value: propValue,
60
- onChange: propOnChange,
61
- defaultValue = '',
62
- placeholder = 'Selecciona una opción',
63
- variant = SelectDefaultVariants.variant,
64
- size = SelectDefaultVariants.size,
65
- colorPalette = 'accent',
66
- flex = 1,
67
- children,
68
- portalHostName = 'select',
69
- }: RootProps) => {
70
- SelectStyles.useVariants({variant, size})
71
-
72
- const [internalValue, setInternalValue] = useState<string>(defaultValue)
73
- const [isOpen, setIsOpen] = useState(false)
74
- const isControlled = propValue !== undefined && propOnChange !== undefined
75
- const value = isControlled ? propValue! : internalValue
76
-
77
- const setValue = (val: string) => {
78
- if (isControlled) propOnChange!(val)
79
- else setInternalValue(val)
80
- setIsOpen(false)
81
- }
82
-
83
- return (
84
- <SelectContext.Provider
85
- value={{
86
- value,
87
- setValue,
88
- isOpen,
89
- setIsOpen,
90
- options,
91
- colorPalette,
92
- variant,
93
- size,
94
- }}>
95
- <View style={[styles.container(flex)]}>{children}</View>
96
-
97
- {isOpen && (
98
- <Portal hostName={portalHostName}>
99
- <View style={styles.modalOverlay}>
100
- <TouchableWithoutFeedback onPress={() => setIsOpen(false)}>
101
- <View style={styles.backdrop} />
102
- </TouchableWithoutFeedback>
103
- <View
104
- style={[
105
- styles.modalContent,
106
- SelectStyles.ModalContainer(colorPalette),
107
- ]}>
108
- <ScrollView
109
- contentContainerStyle={SelectStyles.itemsContainer(
110
- colorPalette,
111
- )}>
112
- {options.map(opt => (
113
- <TouchableOpacity
114
- key={opt.value}
115
- onPress={() => setValue(opt.value)}>
116
- <View
117
- style={[
118
- styles.item,
119
- SelectStyles.item(colorPalette, value === opt.value),
120
- ]}>
121
- <Text
122
- style={SelectStyles.itemText(
123
- colorPalette,
124
- value === opt.value,
125
- )}>
126
- {opt.label}
127
- </Text>
128
- </View>
129
- </TouchableOpacity>
130
- ))}
131
- </ScrollView>
132
- </View>
133
- </View>
134
- </Portal>
135
- )}
136
- </SelectContext.Provider>
137
- )
138
- },
139
-
140
- Trigger: ({placeholder = 'Selecciona una opción'}) => {
141
- const {
142
- variant,
143
- size,
144
- value,
145
- setIsOpen,
146
- options,
147
- colorPalette = 'accent',
148
- } = useSelect()
149
- SelectStyles.useVariants({variant, size})
150
- const selectedOption = options.find(opt => opt.value === value)
151
-
152
- return (
153
- <TouchableWithoutFeedback onPress={() => setIsOpen(true)}>
154
- <View style={[styles.input, SelectStyles.input(colorPalette)]}>
155
- <Text style={SelectStyles.valueText(colorPalette, !!selectedOption)}>
156
- {selectedOption ? selectedOption.label : placeholder}
157
- </Text>
158
- </View>
159
- </TouchableWithoutFeedback>
160
- )
161
- },
162
- }
163
-
164
- const styles = UniStyleSheet.create({
165
- container: (flex: number) => ({
166
- flexGrow: flex,
167
- flexDirection: 'row',
168
- justifyContent: 'center',
169
- }),
170
- input: {
171
- flex: 1,
172
- flexDirection: 'row',
173
- alignItems: 'center',
174
- justifyContent: 'center',
175
- },
176
- item: {
177
- paddingVertical: 2,
178
- paddingHorizontal: 8,
179
- alignItems: 'center',
180
- flexDirection: 'row',
181
- },
182
- modalOverlay: {
183
- position: 'absolute',
184
- top: 0,
185
- left: 0,
186
- right: 0,
187
- bottom: 0,
188
- justifyContent: 'center',
189
- alignItems: 'center',
190
- },
191
- backdrop: {
192
- ...StyleSheet.absoluteFillObject,
193
- backgroundColor: 'rgba(0,0,0,0.3)',
194
- },
195
- modalContent: {
196
- maxHeight: '50%',
197
- width: '80%',
198
- backgroundColor: 'white',
199
- borderRadius: 8,
200
- overflow: 'hidden',
201
- },
202
- })
@@ -1,83 +0,0 @@
1
- import { StyleSheet, UnistylesVariants } from "react-native-unistyles"
2
- import ButtonRaw from "./Button-old"
3
- import ButtonStyles from "../theme/Button.recipe-old"
4
-
5
- // const ButtonStyles = StyleSheet.create(theme => ({
6
- // container: {
7
- // variants: {
8
- // colorPalette: {
9
- // primary: {
10
- // backgroundColor: 'tomato',
11
- // },
12
- // secondary: {
13
- // backgroundColor: theme.colors.foreground2,
14
- // }
15
- // },
16
- // size: {
17
- // sm: {
18
- // height: 32,
19
- // maxHeight: 32,
20
- // padding: 6,
21
- // },
22
- // md: {
23
- // maxHeight: 48,
24
- // height: 48,
25
- // padding: 8,
26
- // },
27
- // lg: {
28
- // maxHeight: 64,
29
- // height: 64,
30
- // padding: 12,
31
- // },
32
- // xl: {
33
- // maxHeight: 80,
34
- // height: 80,
35
- // padding: 16,
36
- // }
37
- // }
38
- // },
39
- // },
40
- // text: {
41
- // variants: {
42
- // colorPalette: {
43
- // primary: {
44
- // color: 'white',
45
- // },
46
- // secondary: {
47
- // color: theme.colors.categoryAquamarine,
48
- // }
49
- // },
50
- // size: {
51
- // sm: {
52
- // fontSize: 24,
53
- // },
54
- // md: {
55
- // fontSize: 28,
56
- // },
57
- // lg: {
58
- // fontSize: 32,
59
- // },
60
- // xl: {
61
- // fontSize: 36,
62
- // }
63
- // }
64
- // }
65
- // }
66
- // }))
67
-
68
- type ButtonVariants = UnistylesVariants<typeof ButtonStyles>;
69
-
70
- type ButtonProps = ButtonVariants & {
71
- onPress: () => void;
72
- };
73
-
74
- export const Button = ({ size, colorPalette, ...props }: ButtonProps) => {
75
- return (
76
- <ButtonRaw
77
- buttonStyles={ButtonStyles}
78
- size={size}
79
- colorPalette={colorPalette}
80
- {...props}
81
- />
82
- );
83
- };
@@ -1,74 +0,0 @@
1
- import {VStack, HStack} from '../patterns'
2
- import Text from './Text'
3
-
4
- const LayoutTest = () => {
5
- return (
6
- <VStack
7
- // flex={1}
8
- style={{
9
- flexGrow: 1,
10
- // flexShrink: 1,
11
- alignSelf: 'stretch',
12
- alignItems: 'stretch',
13
- backgroundColor: 'red',
14
- gap: 10,
15
- }}>
16
- <VStack
17
- style={{
18
- // flexGrow: 1,
19
- // flexShrink: 1,
20
- // alignSelf: 'stretch',
21
- backgroundColor: 'pink',
22
- }}>
23
- <Component />
24
- <Component />
25
- </VStack>
26
- <VStack
27
- style={{
28
- borderWidth: 5,
29
- borderColor: 'yellow',
30
- // flexGrow: 1,
31
- // flexShrink: 1,
32
- // alignSelf: 'stretch',
33
- backgroundColor: 'pink',
34
- }}>
35
- <Component />
36
- <Component />
37
- </VStack>
38
- </VStack>
39
- )
40
- }
41
-
42
- const Component = () => {
43
- return (
44
- <VStack
45
- style={{
46
- borderWidth: 1,
47
- borderColor: 'black',
48
- // flexGrow: 1,
49
- alignSelf: 'stretch',
50
- backgroundColor: 'blue',
51
- // flexShrink: 0,
52
- // alignSelf: 'flex-start',
53
- }}>
54
- <Text>hola</Text>
55
- <HStack
56
- style={{
57
- flexShrink: 0,
58
- flexGrow: 1,
59
- backgroundColor: 'green',
60
- minHeight: 50,
61
- maxHeight: 50,
62
- width: '100%',
63
- // opacity: 0.5,
64
- }}
65
- />
66
- <VStack>
67
- <Text>hola</Text>
68
- <Text>hola</Text>
69
- </VStack>
70
- </VStack>
71
- )
72
- }
73
-
74
- export default LayoutTest