react-native-varia 0.2.3 → 0.3.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.
- package/bin/cli.js +24 -34
- package/lib/components/Accordion.tsx +113 -0
- package/lib/components/Button.tsx +16 -3
- package/lib/components/Checkbox.tsx +12 -7
- package/lib/components/CircleProgress.tsx +30 -21
- package/lib/components/Divider.tsx +23 -19
- package/lib/components/Drawer.tsx +23 -69
- package/lib/components/Field.tsx +24 -39
- package/lib/components/GradientBackground.tsx +25 -7
- package/lib/components/GradientText.tsx +61 -21
- package/lib/components/IconWrapper.tsx +20 -14
- package/lib/components/Input.tsx +107 -25
- package/lib/components/Modal.tsx +4 -10
- package/lib/components/NumberInput.tsx +54 -11
- package/lib/components/OldSlider.tsx +327 -0
- package/lib/components/RadioGroup.tsx +58 -18
- package/lib/components/ReText.tsx +1 -1
- package/lib/components/Select.tsx +58 -22
- package/lib/components/Slider.tsx +273 -138
- package/lib/components/Slideshow.tsx +65 -63
- package/lib/components/SlidingDrawer.tsx +20 -21
- package/lib/components/Spinner.tsx +13 -5
- package/lib/components/Toast.tsx +89 -0
- package/lib/components/context/Field.tsx +27 -0
- package/lib/patterns/index.tsx +16 -5
- package/lib/patterns/newPatterns.tsx +285 -0
- package/lib/theme/Button.recipe.tsx +11 -1
- package/lib/theme/CircleProgress.recipe.tsx +3 -3
- package/lib/theme/Drawer.recipe.tsx +107 -0
- package/lib/theme/Field.recipe.tsx +17 -2
- package/lib/theme/Input.recipe.tsx +12 -3
- package/lib/theme/NumberInput.recipe.tsx +8 -3
- package/lib/theme/RadioGroup.recipe.tsx +7 -1
- package/lib/theme/Select.recipe.tsx +7 -7
- package/lib/theme/Slider.recipe.tsx +402 -27
- package/lib/theme/Slideshow.recipe.tsx +1 -1
- package/lib/theme/Toast.recipe.tsx +71 -0
- package/lib/varia/mixins.ts +0 -4
- package/lib/varia/types.ts +8 -0
- package/lib/varia/utils.ts +66 -0
- package/package.json +1 -1
- package/lib/theme/Button.recipe-old.tsx +0 -67
- package/lib/theme/SlidingDrawer.recipe.tsx +0 -53
|
@@ -20,30 +20,21 @@ export type SlideshowRef = {
|
|
|
20
20
|
|
|
21
21
|
type SlideshowVariants = UnistylesVariants<typeof SlideshowStyles>
|
|
22
22
|
|
|
23
|
+
type Axis = 'x' | 'y'
|
|
24
|
+
|
|
23
25
|
type SlideshowProps = SlideshowVariants & {
|
|
26
|
+
axis?: Axis
|
|
24
27
|
animation?: keyof typeof SlideshowTokens.variants.animation
|
|
25
28
|
colorPalette?: PalettesWithNestedKeys
|
|
26
29
|
allowGestures?: boolean
|
|
27
30
|
flex?: number
|
|
28
31
|
onSlideChange?: (index: number) => void
|
|
29
|
-
slideContainerType?: any
|
|
30
32
|
children: ReactNode
|
|
31
33
|
ref?: React.RefObject<SlideshowRef | null>
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
/**
|
|
35
|
-
* Flex Wrapper
|
|
36
|
-
* @param colorScheme ? string: color scheme
|
|
37
|
-
* @param animation ? string: animation props
|
|
38
|
-
* @param allowGestures ? boolean: allow gestures
|
|
39
|
-
* @param flex ? number: flex value
|
|
40
|
-
* @param onSlideChange ? function: callback function
|
|
41
|
-
* @param slideContainerType ? color scheme
|
|
42
|
-
* @param children ? react children
|
|
43
|
-
* @param ref ? react ref
|
|
44
|
-
* @returns Slideshow react component
|
|
45
|
-
*/
|
|
46
36
|
const Slideshow = ({
|
|
37
|
+
axis = 'x',
|
|
47
38
|
colorPalette = 'accent',
|
|
48
39
|
variant = 'solid',
|
|
49
40
|
allowGestures = true,
|
|
@@ -53,6 +44,8 @@ const Slideshow = ({
|
|
|
53
44
|
children,
|
|
54
45
|
ref,
|
|
55
46
|
}: SlideshowProps) => {
|
|
47
|
+
const isHorizontal = axis === 'x'
|
|
48
|
+
|
|
56
49
|
const slides = Children.toArray(children)
|
|
57
50
|
const NUM_PAGES = slides.length
|
|
58
51
|
const scalingFactor = 1 / NUM_PAGES
|
|
@@ -62,17 +55,17 @@ const Slideshow = ({
|
|
|
62
55
|
})
|
|
63
56
|
|
|
64
57
|
const [containerWidth, setContainerWidth] = useState(0)
|
|
58
|
+
const [containerHeight, setContainerHeight] = useState(0)
|
|
59
|
+
|
|
60
|
+
const dimension = isHorizontal ? containerWidth : containerHeight
|
|
61
|
+
const slideSize = 100 / NUM_PAGES
|
|
65
62
|
|
|
66
|
-
const
|
|
67
|
-
const translateX = useSharedValue(0)
|
|
63
|
+
const translate = useSharedValue(0)
|
|
68
64
|
const currentSlide = useSharedValue(0)
|
|
69
65
|
|
|
70
66
|
type AnimationType = 'withSpring' | 'withTiming'
|
|
67
|
+
const animations = {withSpring, withTiming}
|
|
71
68
|
|
|
72
|
-
const animations = {
|
|
73
|
-
withSpring,
|
|
74
|
-
withTiming,
|
|
75
|
-
}
|
|
76
69
|
const animationVariant =
|
|
77
70
|
SlideshowTokens.variants?.animation && animation
|
|
78
71
|
? SlideshowTokens.variants.animation[animation]
|
|
@@ -88,12 +81,8 @@ const Slideshow = ({
|
|
|
88
81
|
const animateSlide = (destination: number) => {
|
|
89
82
|
'worklet'
|
|
90
83
|
|
|
91
|
-
if (
|
|
92
|
-
animationVariant
|
|
93
|
-
animationVariant.type &&
|
|
94
|
-
animations[animationVariant.type]
|
|
95
|
-
) {
|
|
96
|
-
translateX.value = animations[animationVariant.type](
|
|
84
|
+
if (animationVariant.type && animations[animationVariant.type]) {
|
|
85
|
+
translate.value = animations[animationVariant.type](
|
|
97
86
|
destination,
|
|
98
87
|
animationVariant.props,
|
|
99
88
|
)
|
|
@@ -107,68 +96,73 @@ const Slideshow = ({
|
|
|
107
96
|
useAnimatedReaction(
|
|
108
97
|
() => currentSlide.value,
|
|
109
98
|
() => {
|
|
110
|
-
animateSlide(-currentSlide.value *
|
|
99
|
+
animateSlide(-currentSlide.value * slideSize)
|
|
111
100
|
},
|
|
112
101
|
)
|
|
113
102
|
|
|
114
|
-
const
|
|
103
|
+
const nextSlide = () => {
|
|
115
104
|
'worklet'
|
|
116
|
-
if (currentSlide.value > 0)
|
|
117
|
-
currentSlide.value -= 1
|
|
118
|
-
}
|
|
105
|
+
if (currentSlide.value > 0) currentSlide.value -= 1
|
|
119
106
|
}
|
|
120
|
-
|
|
107
|
+
|
|
108
|
+
const prevSlide = () => {
|
|
121
109
|
'worklet'
|
|
122
|
-
if (currentSlide.value < NUM_PAGES - 1)
|
|
123
|
-
currentSlide.value += 1
|
|
124
|
-
}
|
|
110
|
+
if (currentSlide.value < NUM_PAGES - 1) currentSlide.value += 1
|
|
125
111
|
}
|
|
126
112
|
|
|
127
|
-
const context = useSharedValue({x: 0
|
|
113
|
+
const context = useSharedValue({x: 0})
|
|
128
114
|
const velocityThreshold = 500
|
|
129
115
|
|
|
130
116
|
const slideGesture = Gesture.Pan()
|
|
131
117
|
.enabled(allowGestures)
|
|
132
118
|
.onBegin(() => {
|
|
133
|
-
context.value.x =
|
|
119
|
+
context.value.x = translate.value
|
|
134
120
|
})
|
|
135
121
|
.onUpdate(e => {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
122
|
+
const translation = isHorizontal ? e.translationX : e.translationY
|
|
123
|
+
|
|
124
|
+
const pixelToPercentage = (translation / dimension) * 100 * scalingFactor
|
|
125
|
+
|
|
126
|
+
translate.value = context.value.x + pixelToPercentage
|
|
139
127
|
})
|
|
140
|
-
.onEnd(({velocityX, translationX}) => {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
.onEnd(({velocityX, velocityY, translationX, translationY}) => {
|
|
129
|
+
const translation = isHorizontal ? translationX : translationY
|
|
130
|
+
const velocity = isHorizontal ? velocityX : velocityY
|
|
131
|
+
|
|
132
|
+
const pixelToPercentage = (translation / dimension) * 100 * scalingFactor
|
|
144
133
|
|
|
134
|
+
const slideWidthPercentage = 100 / NUM_PAGES
|
|
145
135
|
const currentIndex = Math.round(-context.value.x / slideWidthPercentage)
|
|
146
136
|
|
|
147
137
|
let targetIndex
|
|
148
|
-
if (Math.abs(
|
|
149
|
-
targetIndex =
|
|
138
|
+
if (Math.abs(velocity) > velocityThreshold) {
|
|
139
|
+
targetIndex = velocity > 0 ? currentIndex - 1 : currentIndex + 1
|
|
150
140
|
} else {
|
|
151
|
-
const
|
|
152
|
-
|
|
141
|
+
const crossed = Math.abs(pixelToPercentage) > slideWidthPercentage / 2
|
|
142
|
+
|
|
153
143
|
targetIndex =
|
|
154
|
-
|
|
144
|
+
crossed && pixelToPercentage < 0
|
|
155
145
|
? currentIndex + 1
|
|
156
|
-
:
|
|
146
|
+
: crossed
|
|
157
147
|
? currentIndex - 1
|
|
158
148
|
: currentIndex
|
|
159
149
|
}
|
|
150
|
+
|
|
160
151
|
targetIndex = Math.max(0, Math.min(NUM_PAGES - 1, targetIndex))
|
|
152
|
+
|
|
161
153
|
animateSlide(-targetIndex * slideWidthPercentage)
|
|
162
154
|
currentSlide.value = targetIndex
|
|
163
155
|
})
|
|
164
156
|
|
|
165
|
-
const animatedStyle = useAnimatedStyle(() =>
|
|
166
|
-
|
|
167
|
-
|
|
157
|
+
const animatedStyle = useAnimatedStyle(() =>
|
|
158
|
+
isHorizontal
|
|
159
|
+
? {transform: [{translateX: `${translate.value}%`}]}
|
|
160
|
+
: {transform: [{translateY: `${translate.value}%`}]},
|
|
161
|
+
)
|
|
168
162
|
|
|
169
163
|
useImperativeHandle(ref, () => ({
|
|
170
|
-
handlePrev,
|
|
171
|
-
handleNext,
|
|
164
|
+
handlePrev: nextSlide,
|
|
165
|
+
handleNext: prevSlide,
|
|
172
166
|
}))
|
|
173
167
|
|
|
174
168
|
return (
|
|
@@ -176,17 +170,20 @@ const Slideshow = ({
|
|
|
176
170
|
<GestureDetector gesture={slideGesture}>
|
|
177
171
|
<View
|
|
178
172
|
style={[styles.container(), SlideshowStyles.container(colorPalette)]}
|
|
179
|
-
onLayout={e =>
|
|
173
|
+
onLayout={e => {
|
|
174
|
+
setContainerWidth(e.nativeEvent.layout.width)
|
|
175
|
+
setContainerHeight(e.nativeEvent.layout.height)
|
|
176
|
+
}}>
|
|
180
177
|
<Animated.View
|
|
181
178
|
style={[
|
|
182
|
-
styles.slidesContainer(`${NUM_PAGES * 100}
|
|
179
|
+
styles.slidesContainer(`${NUM_PAGES * 100}%`, isHorizontal),
|
|
183
180
|
animatedStyle,
|
|
184
181
|
]}>
|
|
185
182
|
{slides.map((Slide, index) => (
|
|
186
183
|
<View
|
|
187
184
|
key={index}
|
|
188
185
|
style={[
|
|
189
|
-
styles.slide(`${
|
|
186
|
+
styles.slide(`${slideSize}%`, isHorizontal),
|
|
190
187
|
SlideshowStyles.slideContainer(colorPalette),
|
|
191
188
|
]}>
|
|
192
189
|
{Slide}
|
|
@@ -206,6 +203,7 @@ const styles = StyleSheet.create({
|
|
|
206
203
|
flex,
|
|
207
204
|
flexDirection: 'row',
|
|
208
205
|
}),
|
|
206
|
+
|
|
209
207
|
container: () => ({
|
|
210
208
|
width: '100%',
|
|
211
209
|
height: '100%',
|
|
@@ -213,14 +211,18 @@ const styles = StyleSheet.create({
|
|
|
213
211
|
justifyContent: 'flex-start',
|
|
214
212
|
alignItems: 'flex-start',
|
|
215
213
|
}),
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
|
|
215
|
+
slidesContainer: (size, isHorizontal) => ({
|
|
216
|
+
flexDirection: isHorizontal ? 'row' : 'column',
|
|
217
|
+
width: isHorizontal ? size : '100%',
|
|
218
|
+
minHeight: isHorizontal ? '100%' : size,
|
|
219
219
|
flex: 1,
|
|
220
220
|
}),
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
|
|
222
|
+
slide: (size, isHorizontal) => ({
|
|
223
|
+
overflow: 'hidden',
|
|
224
|
+
width: isHorizontal ? size : '100%',
|
|
225
|
+
height: isHorizontal ? '100%' : size,
|
|
224
226
|
justifyContent: 'center',
|
|
225
227
|
alignItems: 'center',
|
|
226
228
|
}),
|
|
@@ -8,13 +8,13 @@ import Animated, {
|
|
|
8
8
|
withTiming,
|
|
9
9
|
type SharedValue,
|
|
10
10
|
} from 'react-native-reanimated'
|
|
11
|
-
import {
|
|
11
|
+
import {scheduleOnRN} from 'react-native-worklets'
|
|
12
12
|
import {
|
|
13
13
|
SlidingDrawerTokens,
|
|
14
14
|
SlidingDrawerStyles,
|
|
15
15
|
} from '../theme/SlidingDrawer.recipe'
|
|
16
16
|
import {PalettesWithNestedKeys} from '../style/varia/types'
|
|
17
|
-
import {TouchableWithoutFeedback} from 'react-native'
|
|
17
|
+
import {TouchableWithoutFeedback, ViewStyle} from 'react-native'
|
|
18
18
|
|
|
19
19
|
export type SlidingDrawerRef = {
|
|
20
20
|
snapTo: (point: number) => void | null
|
|
@@ -73,7 +73,7 @@ const SlidingDrawer = ({
|
|
|
73
73
|
const translate = useSharedValue(points[0])
|
|
74
74
|
|
|
75
75
|
const context: SharedValue<{
|
|
76
|
-
position:
|
|
76
|
+
position: number
|
|
77
77
|
snapPoint: number
|
|
78
78
|
}> = useSharedValue({
|
|
79
79
|
position: points[0],
|
|
@@ -106,7 +106,7 @@ const SlidingDrawer = ({
|
|
|
106
106
|
animationVariant.props,
|
|
107
107
|
)
|
|
108
108
|
updateCurrentSnapPoint(destination)
|
|
109
|
-
onSnap &&
|
|
109
|
+
onSnap && scheduleOnRN(onSnap, destination)
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -115,7 +115,7 @@ const SlidingDrawer = ({
|
|
|
115
115
|
if (overlay) {
|
|
116
116
|
showOverlay()
|
|
117
117
|
}
|
|
118
|
-
onExpand &&
|
|
118
|
+
onExpand && scheduleOnRN(onExpand)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
const isCollapsed = () => {
|
|
@@ -128,7 +128,7 @@ const SlidingDrawer = ({
|
|
|
128
128
|
if (overlay) {
|
|
129
129
|
hideOverlay()
|
|
130
130
|
}
|
|
131
|
-
onCollapse &&
|
|
131
|
+
onCollapse && scheduleOnRN(onCollapse)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
const hideOverlay = () => {
|
|
@@ -164,10 +164,8 @@ const SlidingDrawer = ({
|
|
|
164
164
|
|
|
165
165
|
let clamped = proposed
|
|
166
166
|
|
|
167
|
-
// Si se pasa del rango, aplicamos resistencia
|
|
168
167
|
if (proposed < minPoint) {
|
|
169
168
|
const overdrag = minPoint - proposed
|
|
170
|
-
// Cuanto mayor sea el exceso, menos se mueve (efecto pesado)
|
|
171
169
|
clamped = minPoint - overdrag / (1 + overdrag / 60)
|
|
172
170
|
} else if (proposed > maxPoint) {
|
|
173
171
|
const overdrag = proposed - maxPoint
|
|
@@ -175,7 +173,6 @@ const SlidingDrawer = ({
|
|
|
175
173
|
}
|
|
176
174
|
|
|
177
175
|
translate.value = clamped
|
|
178
|
-
// translate.value = delta + (context.value.position ?? 0)
|
|
179
176
|
})
|
|
180
177
|
.onEnd(({velocityX, velocityY, translationX, translationY}) => {
|
|
181
178
|
const velocity = axis === 'y' ? velocityY : velocityX
|
|
@@ -184,7 +181,6 @@ const SlidingDrawer = ({
|
|
|
184
181
|
const minPoint = Math.min(...points)
|
|
185
182
|
const maxPoint = Math.max(...points)
|
|
186
183
|
|
|
187
|
-
// 🧲 1. Si está fuera del rango, lo regresamos suavemente
|
|
188
184
|
if (translate.value < minPoint) {
|
|
189
185
|
translate.value = withSpring(minPoint, {velocity})
|
|
190
186
|
return
|
|
@@ -193,7 +189,6 @@ const SlidingDrawer = ({
|
|
|
193
189
|
return
|
|
194
190
|
}
|
|
195
191
|
|
|
196
|
-
// 🧭 2. Lógica original de snapping
|
|
197
192
|
const forwardsThreshold =
|
|
198
193
|
(points[context.value.snapPoint] +
|
|
199
194
|
points[context.value.snapPoint + 1]) /
|
|
@@ -238,18 +233,22 @@ const SlidingDrawer = ({
|
|
|
238
233
|
})
|
|
239
234
|
|
|
240
235
|
const blockAnimatedStyle = useAnimatedStyle(() => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
{
|
|
244
|
-
|
|
245
|
-
}
|
|
236
|
+
if (axis === 'y') {
|
|
237
|
+
return {
|
|
238
|
+
transform: [{translateY: translate.value}],
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
return {
|
|
242
|
+
transform: [{translateX: translate.value}],
|
|
243
|
+
}
|
|
244
|
+
}
|
|
246
245
|
})
|
|
247
246
|
|
|
248
247
|
const displayOverlayStyle = useAnimatedStyle(() => {
|
|
249
248
|
return {
|
|
250
|
-
display: changeDisplay.value,
|
|
249
|
+
display: changeDisplay.value as ViewStyle['display'],
|
|
251
250
|
opacity: opacity.value,
|
|
252
|
-
}
|
|
251
|
+
}
|
|
253
252
|
})
|
|
254
253
|
|
|
255
254
|
return (
|
|
@@ -261,7 +260,7 @@ const SlidingDrawer = ({
|
|
|
261
260
|
style={[
|
|
262
261
|
StyleSheet.absoluteFillObject,
|
|
263
262
|
displayOverlayStyle,
|
|
264
|
-
SlidingDrawerStyles.
|
|
263
|
+
SlidingDrawerStyles.overlay(colorPalette),
|
|
265
264
|
]}
|
|
266
265
|
/>
|
|
267
266
|
</AnimatedTouchableOpacity>
|
|
@@ -271,7 +270,7 @@ const SlidingDrawer = ({
|
|
|
271
270
|
style={[
|
|
272
271
|
styles.container(flex, direction, axis, width),
|
|
273
272
|
blockAnimatedStyle,
|
|
274
|
-
SlidingDrawerStyles.
|
|
273
|
+
SlidingDrawerStyles.slider(colorPalette),
|
|
275
274
|
]}>
|
|
276
275
|
{children}
|
|
277
276
|
</Animated.View>
|
|
@@ -282,7 +281,7 @@ const SlidingDrawer = ({
|
|
|
282
281
|
export default SlidingDrawer
|
|
283
282
|
|
|
284
283
|
const styles = StyleSheet.create({
|
|
285
|
-
container: (flex, direction, axis, width)
|
|
284
|
+
container: (flex, direction, axis, width) => ({
|
|
286
285
|
position: flex === 0 ? 'absolute' : 'relative',
|
|
287
286
|
bottom: axis === 'y' && direction === -1 ? 0 : 'auto',
|
|
288
287
|
top: axis === 'y' && direction === 1 ? 0 : 'auto',
|
|
@@ -5,9 +5,13 @@ import {
|
|
|
5
5
|
type ViewStyle,
|
|
6
6
|
} from 'react-native'
|
|
7
7
|
import {withUnistyles, UnistylesVariants} from 'react-native-unistyles'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
NestedColorsType,
|
|
10
|
+
PalettesWithNestedKeys,
|
|
11
|
+
ThemeColors,
|
|
12
|
+
} from '../style/varia/types'
|
|
9
13
|
import {SpinnerTokens} from '../theme/Spinner.recipe'
|
|
10
|
-
import {resolveColor} from '../style/varia/utils'
|
|
14
|
+
import {getVariantValue, resolveColor} from '../style/varia/utils'
|
|
11
15
|
import {SpinnerStyles} from '../theme/Spinner.recipe'
|
|
12
16
|
|
|
13
17
|
type SpinnerVariants = UnistylesVariants<typeof SpinnerStyles>
|
|
@@ -16,7 +20,7 @@ export type SpinnerProps = SpinnerVariants &
|
|
|
16
20
|
color?: ThemeColors
|
|
17
21
|
style?: StyleProp<ViewStyle>
|
|
18
22
|
mixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[]
|
|
19
|
-
colors:
|
|
23
|
+
colors: NestedColorsType
|
|
20
24
|
colorPalette?: PalettesWithNestedKeys
|
|
21
25
|
}
|
|
22
26
|
|
|
@@ -30,15 +34,19 @@ const BaseSpinner = ({
|
|
|
30
34
|
...props
|
|
31
35
|
}: SpinnerProps) => {
|
|
32
36
|
const resolvedColor = resolveColor(color, colors, colorPalette)
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
SpinnerStyles.useVariants({
|
|
35
39
|
size,
|
|
36
40
|
})
|
|
37
41
|
|
|
42
|
+
// console.log('color', color)
|
|
43
|
+
|
|
44
|
+
const resolvedSize = getVariantValue(SpinnerStyles.base, 'size', size, 'width')
|
|
45
|
+
|
|
38
46
|
return (
|
|
39
47
|
<ActivityIndicator
|
|
40
48
|
color={resolvedColor}
|
|
41
|
-
size={
|
|
49
|
+
size={resolvedSize}
|
|
42
50
|
{...props}
|
|
43
51
|
style={[style && style, mixins && mixins]}
|
|
44
52
|
/>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React, {useEffect} from 'react'
|
|
2
|
+
import {StyleSheet} from 'react-native'
|
|
3
|
+
import Animated, {
|
|
4
|
+
useSharedValue,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
withTiming,
|
|
7
|
+
Easing,
|
|
8
|
+
} from 'react-native-reanimated'
|
|
9
|
+
import {scheduleOnRN} from 'react-native-worklets'
|
|
10
|
+
import {ToastStyles, ToastDefaultVariants} from '../theme/Toast.recipe'
|
|
11
|
+
import {UnistylesVariants} from 'react-native-unistyles'
|
|
12
|
+
import {PalettesWithNestedKeys} from '../style/varia/types'
|
|
13
|
+
import Text from './Text'
|
|
14
|
+
|
|
15
|
+
type ToastVariants = UnistylesVariants<typeof ToastStyles>
|
|
16
|
+
type ToastProps = ToastVariants & {
|
|
17
|
+
colorPalette?: PalettesWithNestedKeys
|
|
18
|
+
message: string
|
|
19
|
+
duration?: number
|
|
20
|
+
onClose?: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Toast: React.FC<ToastProps> = ({
|
|
24
|
+
colorPalette = 'accent',
|
|
25
|
+
variant = ToastDefaultVariants.variant,
|
|
26
|
+
size = ToastDefaultVariants.size,
|
|
27
|
+
message,
|
|
28
|
+
duration = 5000,
|
|
29
|
+
onClose,
|
|
30
|
+
}) => {
|
|
31
|
+
ToastStyles.useVariants({
|
|
32
|
+
variant,
|
|
33
|
+
size,
|
|
34
|
+
})
|
|
35
|
+
const opacity = useSharedValue(0)
|
|
36
|
+
const translateY = useSharedValue(50) // Aparece desde abajo
|
|
37
|
+
|
|
38
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
39
|
+
opacity: opacity.value,
|
|
40
|
+
transform: [{translateY: translateY.value}],
|
|
41
|
+
}))
|
|
42
|
+
|
|
43
|
+
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
|
+
})
|
|
53
|
+
|
|
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)
|
|
59
|
+
})
|
|
60
|
+
}, duration)
|
|
61
|
+
|
|
62
|
+
return () => clearTimeout(timeout)
|
|
63
|
+
}, [])
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Animated.View
|
|
67
|
+
style={[
|
|
68
|
+
styles.container,
|
|
69
|
+
animatedStyle,
|
|
70
|
+
ToastStyles.container(colorPalette),
|
|
71
|
+
]}>
|
|
72
|
+
<Text style={ToastStyles.text(colorPalette)}>{message}</Text>
|
|
73
|
+
</Animated.View>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const styles = StyleSheet.create({
|
|
78
|
+
container: {
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
bottom: 50,
|
|
81
|
+
// left: 20,
|
|
82
|
+
// right: 20,
|
|
83
|
+
padding: 15,
|
|
84
|
+
borderRadius: 8,
|
|
85
|
+
alignItems: 'center',
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
export default Toast
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {createContext, useContext} from 'react'
|
|
2
|
+
import {UnistylesVariants} from 'react-native-unistyles'
|
|
3
|
+
import {FieldStyles} from '../../theme/Field.recipe'
|
|
4
|
+
import {PalettesWithNestedKeys} from '../../style/varia/types'
|
|
5
|
+
|
|
6
|
+
export type FieldVariants = UnistylesVariants<typeof FieldStyles>
|
|
7
|
+
|
|
8
|
+
export type FieldContextType = {
|
|
9
|
+
error?: string
|
|
10
|
+
variant?: FieldVariants['variant']
|
|
11
|
+
size?: FieldVariants['size']
|
|
12
|
+
colorPalette?: PalettesWithNestedKeys
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const FieldContext = createContext<FieldContextType | undefined>(undefined)
|
|
16
|
+
|
|
17
|
+
export function useField() {
|
|
18
|
+
const context = useContext(FieldContext)
|
|
19
|
+
if (!context) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'Field subcomponents (Label, Error) must be used inside Field.Root',
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
return context
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default FieldContext
|
package/lib/patterns/index.tsx
CHANGED
|
@@ -49,6 +49,7 @@ export type HstackProps = {
|
|
|
49
49
|
hCenter?: boolean
|
|
50
50
|
flex?: number
|
|
51
51
|
gap?: number
|
|
52
|
+
stretch?: boolean
|
|
52
53
|
} & ViewProps
|
|
53
54
|
|
|
54
55
|
const HStack: React.FC<HstackProps> = ({
|
|
@@ -59,11 +60,15 @@ const HStack: React.FC<HstackProps> = ({
|
|
|
59
60
|
hCenter,
|
|
60
61
|
flex = 0,
|
|
61
62
|
gap = 0,
|
|
63
|
+
stretch,
|
|
62
64
|
...props
|
|
63
65
|
}) => {
|
|
64
66
|
return (
|
|
65
67
|
<View
|
|
66
|
-
style={[
|
|
68
|
+
style={[
|
|
69
|
+
styles.hStack(center, vCenter, hCenter, gap, flex, stretch),
|
|
70
|
+
style,
|
|
71
|
+
]}
|
|
67
72
|
{...props}>
|
|
68
73
|
{children}
|
|
69
74
|
</View>
|
|
@@ -77,11 +82,15 @@ const VStack: React.FC<HstackProps> = ({
|
|
|
77
82
|
hCenter,
|
|
78
83
|
flex = 0,
|
|
79
84
|
gap = 0,
|
|
85
|
+
stretch,
|
|
80
86
|
...props
|
|
81
87
|
}) => {
|
|
82
88
|
return (
|
|
83
89
|
<View
|
|
84
|
-
style={[
|
|
90
|
+
style={[
|
|
91
|
+
styles.vStack(center, vCenter, hCenter, gap, flex, stretch),
|
|
92
|
+
style,
|
|
93
|
+
]}
|
|
85
94
|
{...props}>
|
|
86
95
|
{children}
|
|
87
96
|
</View>
|
|
@@ -118,19 +127,21 @@ export const FlexSpacer = () => {
|
|
|
118
127
|
)
|
|
119
128
|
}
|
|
120
129
|
const styles = StyleSheet.create(() => ({
|
|
121
|
-
hStack: (center, vCenter, hCenter, gap, flex) => ({
|
|
130
|
+
hStack: (center, vCenter, hCenter, gap, flex, stretch) => ({
|
|
122
131
|
flex,
|
|
123
132
|
gap,
|
|
124
133
|
flexDirection: 'row',
|
|
125
134
|
alignItems: center ? 'center' : vCenter ? 'center' : 'stretch',
|
|
126
135
|
justifyContent: center ? 'center' : hCenter ? 'center' : 'flex-start',
|
|
136
|
+
...(stretch ? {alignSelf: 'stretch'} : {}),
|
|
127
137
|
}),
|
|
128
|
-
vStack: (center, vCenter, hCenter, gap, flex) => ({
|
|
138
|
+
vStack: (center, vCenter, hCenter, gap, flex, stretch) => ({
|
|
129
139
|
flex,
|
|
130
140
|
gap,
|
|
131
141
|
flexDirection: 'column',
|
|
132
|
-
alignItems: center ? 'center' : vCenter ? 'center' : '
|
|
142
|
+
alignItems: center ? 'center' : vCenter ? 'center' : 'stretch',
|
|
133
143
|
justifyContent: center ? 'center' : hCenter ? 'center' : 'flex-start',
|
|
144
|
+
...(stretch ? {alignSelf: 'stretch'} : {}),
|
|
134
145
|
}),
|
|
135
146
|
}))
|
|
136
147
|
|