react-native-varia 0.2.2 → 0.2.4

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 (40) hide show
  1. package/bin/cli.js +316 -139
  2. package/lib/components/Accordion.tsx +113 -0
  3. package/lib/components/Button.tsx +19 -8
  4. package/lib/components/CircleProgress.tsx +46 -28
  5. package/lib/components/Divider.tsx +18 -15
  6. package/lib/components/Drawer.tsx +496 -0
  7. package/lib/components/Field.tsx +24 -39
  8. package/lib/components/GradientBackground.tsx +25 -7
  9. package/lib/components/GradientText.tsx +38 -11
  10. package/lib/components/IconWrapper.tsx +20 -14
  11. package/lib/components/Input.tsx +106 -25
  12. package/lib/components/NumberInput.tsx +88 -19
  13. package/lib/components/OldSlider.tsx +327 -0
  14. package/lib/components/RadioGroup.tsx +55 -17
  15. package/lib/components/ReText.tsx +1 -1
  16. package/lib/components/Select.tsx +58 -22
  17. package/lib/components/Slider.tsx +176 -115
  18. package/lib/components/Slideshow.tsx +68 -69
  19. package/lib/components/SlidingDrawer.tsx +72 -29
  20. package/lib/components/Spinner.tsx +6 -2
  21. package/lib/components/Toast.tsx +89 -0
  22. package/lib/components/context/Field.tsx +27 -0
  23. package/lib/icons/Minus.tsx +24 -0
  24. package/lib/icons/Plus.tsx +23 -0
  25. package/lib/theme/Button.recipe.tsx +11 -1
  26. package/lib/theme/CircleProgress.recipe.tsx +3 -3
  27. package/lib/theme/Field.recipe.tsx +17 -2
  28. package/lib/theme/Input.recipe.tsx +12 -3
  29. package/lib/theme/NumberInput.recipe.tsx +9 -4
  30. package/lib/theme/RadioGroup.recipe.tsx +7 -1
  31. package/lib/theme/Select.recipe.tsx +7 -7
  32. package/lib/theme/Slider.recipe.tsx +366 -22
  33. package/lib/theme/Slideshow.recipe.tsx +1 -1
  34. package/lib/theme/SlidingDrawer.recipe.tsx +58 -4
  35. package/lib/theme/Toast.recipe.tsx +71 -0
  36. package/package.json +3 -2
  37. package/lib/components/NewSelect.tsx +0 -202
  38. package/lib/components/index.tsx +0 -83
  39. package/lib/components/layoutTest.tsx +0 -74
  40. package/lib/theme/Button.recipe-old.tsx +0 -67
@@ -0,0 +1,496 @@
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
+ export type DrawerSliderProps = Omit<
206
+ InternalDrawerSliderProps,
207
+ 'direction' | 'axis'
208
+ >
209
+
210
+ export const DrawerSlider = (props: DrawerSliderProps) => {
211
+ return <DrawerSliderInternal {...(props as InternalDrawerSliderProps)} />
212
+ }
213
+
214
+ const DrawerSliderInternal = ({
215
+ axis,
216
+ direction,
217
+ lockAtEdges = false,
218
+ snapPoints = ['hidden', 'content'],
219
+ animation = SlidingDrawerTokens.defaultProps.animation,
220
+ onExpand,
221
+ onCollapse,
222
+ onSnap,
223
+ allowGestures = true,
224
+ children,
225
+ externalTranslate,
226
+ ref,
227
+ }: InternalDrawerSliderProps) => {
228
+ const {variant, colorPalette, overlayOpacity} = useDrawer()
229
+
230
+ SlidingDrawerStyles.useVariants({variant})
231
+
232
+ const screenHeight =
233
+ UnistylesRuntime.screen.height - UnistylesRuntime.insets.top
234
+ const screenWidth = UnistylesRuntime.screen.width
235
+
236
+ const animations = {withSpring, withTiming}
237
+ const animationVariant = SlidingDrawerTokens.variants.animation[animation]
238
+ const VELOCITY_THRESHOLD = 2000
239
+
240
+ const viewRef = useAnimatedRef<Animated.View>()
241
+ const translate = useSharedValue(screenHeight)
242
+ const context = useSharedValue({position: screenHeight, snapPoint: 0})
243
+ const contentHeight = useSharedValue(0)
244
+ const resolvedSnapPoints = useSharedValue<number[]>([])
245
+
246
+ if (externalTranslate) {
247
+ useAnimatedReaction(
248
+ () => translate.value,
249
+ value => {
250
+ externalTranslate.value = value
251
+ },
252
+ )
253
+ }
254
+
255
+ const onLayout = () => {
256
+ const _screenHeight = screenHeight
257
+ const _screenWidth = screenWidth
258
+ const _axis = axis
259
+ const _direction = direction
260
+ const _snapPoints = snapPoints
261
+
262
+ scheduleOnUI(() => {
263
+ 'worklet'
264
+ const measured = measure(viewRef)
265
+ if (measured) {
266
+ const {height, width} = measured
267
+ const size = _axis === 'y' ? height : width
268
+ const screenSize = _axis === 'y' ? _screenHeight : _screenWidth
269
+
270
+ const resolved = _snapPoints.map(p => {
271
+ if (p === 'hidden') return screenSize * _direction
272
+ if (p === 'content') return (screenSize - size) * _direction
273
+ return (p as number) * _direction
274
+ })
275
+
276
+ resolvedSnapPoints.value = resolved
277
+ translate.value = resolved[0]
278
+ context.value = {position: resolved[0], snapPoint: 0}
279
+ }
280
+ })
281
+ }
282
+
283
+ const getPoints = () => {
284
+ 'worklet'
285
+ return resolvedSnapPoints.value.length > 0
286
+ ? resolvedSnapPoints.value
287
+ : snapPoints.map(p => {
288
+ // if (p === 'hidden') return screenHeight * direction
289
+ // if (p === 'content') return (screenHeight - contentHeight.value) * direction
290
+ return (p as number) * direction
291
+ })
292
+ }
293
+
294
+ const updateCurrentSnapPoint = (snapPoint: number) => {
295
+ 'worklet'
296
+ context.value = {position: context.value.position, snapPoint}
297
+ }
298
+
299
+ const snapTo = (destination: number) => {
300
+ 'worklet'
301
+ const points = getPoints()
302
+ const point = points[destination]
303
+ if (animationVariant?.type && point != null) {
304
+ translate.value = animations[animationVariant.type](
305
+ point,
306
+ animationVariant.props,
307
+ )
308
+ updateCurrentSnapPoint(destination)
309
+ onSnap && scheduleOnRN(onSnap, destination)
310
+ }
311
+ }
312
+
313
+ const isCollapsed = () => {
314
+ 'worklet'
315
+ return context.value.snapPoint === 0
316
+ }
317
+
318
+ const showOverlay = () => {
319
+ 'worklet'
320
+ overlayOpacity.value = withTiming(1, {duration: 200})
321
+ }
322
+
323
+ const hideOverlay = () => {
324
+ 'worklet'
325
+ overlayOpacity.value = withTiming(0, {duration: 200})
326
+ }
327
+
328
+ const expand = () => {
329
+ const points = getPoints()
330
+ snapTo(points.length - 1)
331
+ showOverlay()
332
+ onExpand && scheduleOnRN(onExpand)
333
+ }
334
+
335
+ const collapse = () => {
336
+ snapTo(0)
337
+ hideOverlay()
338
+ onCollapse && scheduleOnRN(onCollapse)
339
+ }
340
+
341
+ useImperativeHandle(ref, () => ({
342
+ expand,
343
+ collapse,
344
+ snapTo,
345
+ isCollapsed,
346
+ }))
347
+
348
+ useAnimatedReaction(
349
+ () => translate.value,
350
+ value => {
351
+ const points = getPoints()
352
+ if (points.length < 2) return
353
+
354
+ const collapsed = points[0]
355
+ const next = points[1] ?? collapsed
356
+ const threshold = 20
357
+ const opensUpward = next < collapsed
358
+ const delta = value - collapsed
359
+ const isExpanded = opensUpward ? delta < -threshold : delta > threshold
360
+
361
+ overlayOpacity.value = withTiming(isExpanded ? 1 : 0, {duration: 150})
362
+ },
363
+ )
364
+
365
+ const slideGesture = Gesture.Pan()
366
+ .enabled(allowGestures)
367
+ .onBegin(() => {
368
+ context.value.position = translate.value
369
+ })
370
+ .onUpdate(event => {
371
+ const delta = axis === 'y' ? event.translationY : event.translationX
372
+ const proposed = delta + (context.value.position ?? 0)
373
+ const points = getPoints()
374
+ const minPoint = Math.min(...points)
375
+ const maxPoint = Math.max(...points)
376
+ let clamped = proposed
377
+
378
+ if (proposed < minPoint) {
379
+ if (lockAtEdges) {
380
+ clamped = minPoint
381
+ } else {
382
+ const overdrag = minPoint - proposed
383
+ clamped = minPoint - overdrag / (1 + overdrag / 60)
384
+ }
385
+ } else if (proposed > maxPoint) {
386
+ if (lockAtEdges) {
387
+ clamped = maxPoint
388
+ } else {
389
+ const overdrag = proposed - maxPoint
390
+ clamped = maxPoint + overdrag / (1 + overdrag / 60)
391
+ }
392
+ }
393
+
394
+ translate.value = clamped
395
+ })
396
+ .onEnd(({velocityX, velocityY, translationX, translationY}) => {
397
+ const velocity = axis === 'y' ? velocityY : velocityX
398
+ const translation = axis === 'y' ? translationY : translationX
399
+ const points = getPoints()
400
+
401
+ const minPoint = Math.min(...points)
402
+ const maxPoint = Math.max(...points)
403
+
404
+ if (translate.value < minPoint) {
405
+ translate.value = withSpring(minPoint, {velocity})
406
+ return
407
+ } else if (translate.value > maxPoint) {
408
+ translate.value = withSpring(maxPoint, {velocity})
409
+ return
410
+ }
411
+
412
+ const forwardsThreshold =
413
+ (points[context.value.snapPoint] +
414
+ points[context.value.snapPoint + 1]) /
415
+ 2
416
+ const backwardsThreshold =
417
+ (points[context.value.snapPoint] +
418
+ points[context.value.snapPoint - 1]) /
419
+ 2
420
+
421
+ if (translation * direction < 0) {
422
+ if (
423
+ ((direction === 1 && translate.value < forwardsThreshold) ||
424
+ (direction === -1 && translate.value > forwardsThreshold) ||
425
+ velocity * direction < -VELOCITY_THRESHOLD) &&
426
+ context.value.snapPoint < points.length - 1
427
+ ) {
428
+ snapTo(context.value.snapPoint + 1)
429
+ } else {
430
+ snapTo(context.value.snapPoint)
431
+ }
432
+ } else {
433
+ if (
434
+ ((direction === 1 && translate.value > backwardsThreshold) ||
435
+ (direction === -1 && translate.value < backwardsThreshold) ||
436
+ velocity * direction > VELOCITY_THRESHOLD) &&
437
+ context.value.snapPoint > 0
438
+ ) {
439
+ snapTo(context.value.snapPoint - 1)
440
+ } else {
441
+ snapTo(context.value.snapPoint)
442
+ }
443
+ }
444
+ })
445
+
446
+ const blockAnimatedStyle = useAnimatedStyle(() => {
447
+ return {
448
+ transform: [
449
+ axis === 'y'
450
+ ? {translateY: translate.value}
451
+ : {translateX: translate.value},
452
+ ],
453
+ }
454
+ })
455
+
456
+ return (
457
+ <GestureDetector gesture={slideGesture}>
458
+ <Animated.View
459
+ ref={viewRef}
460
+ onLayout={onLayout}
461
+ style={[
462
+ styles.slider,
463
+ blockAnimatedStyle,
464
+ SlidingDrawerStyles.slider(colorPalette),
465
+ ]}>
466
+ {children}
467
+ </Animated.View>
468
+ </GestureDetector>
469
+ )
470
+ }
471
+
472
+ export const Drawer = {
473
+ Root: DrawerRoot,
474
+ Positioner: DrawerPositioner,
475
+ Overlay: DrawerOverlay,
476
+ Slider: DrawerSlider,
477
+ }
478
+
479
+ const styles = StyleSheet.create((theme, rt) => ({
480
+ positioner: {
481
+ flex: 1,
482
+ alignSelf: 'stretch',
483
+ position: 'absolute',
484
+ top: 0,
485
+ left: 0,
486
+ right: 0,
487
+ bottom: 0,
488
+ },
489
+ slider: {
490
+ flex: 1,
491
+ alignSelf: 'stretch',
492
+ alignItems: 'center',
493
+ justifyContent: 'flex-start',
494
+ zIndex: 100,
495
+ },
496
+ }))
@@ -1,36 +1,21 @@
1
- import React, {createContext, useContext} from 'react'
2
- import {UnistylesVariants} from 'react-native-unistyles'
1
+ import React from 'react'
3
2
  import Text from './Text'
4
- import {VStack} from '../patterns'
5
3
  import {DefaultFieldVariants, FieldStyles} from '../theme/Field.recipe'
6
- import {PalettesWithNestedKeys} from '../style/varia/types'
7
-
8
- type FieldVariants = UnistylesVariants<typeof FieldStyles>
9
-
10
- type FieldContextType = {
11
- error?: string
12
- variant?: FieldVariants['variant']
13
- size?: FieldVariants['size']
14
- colorPalette?: PalettesWithNestedKeys
15
- }
16
-
17
- const FieldContext = createContext<FieldContextType | undefined>(undefined)
18
-
19
- function useField() {
20
- const context = useContext(FieldContext)
21
- if (!context) {
22
- throw new Error(
23
- 'Field subcomponents (Label, Error) must be used inside Field.Root',
24
- )
25
- }
26
- return context
27
- }
4
+ import {Flex, PalettesWithNestedKeys} from '../style/varia/types'
5
+ import FieldContext, {
6
+ FieldContextType,
7
+ FieldVariants,
8
+ useField,
9
+ } from './context/Field'
10
+ import {StyleProp, View, ViewStyle} from 'react-native'
11
+ import {StyleSheet} from 'react-native-unistyles'
28
12
 
29
13
  type FieldRootProps = FieldVariants & {
30
14
  children: React.ReactNode
31
15
  error?: string
32
16
  colorPalette?: PalettesWithNestedKeys
33
17
  flex?: number
18
+ style?: StyleProp<ViewStyle>
34
19
  }
35
20
 
36
21
  const FieldRoot = ({
@@ -39,7 +24,8 @@ const FieldRoot = ({
39
24
  variant = DefaultFieldVariants.variant,
40
25
  size = DefaultFieldVariants.size,
41
26
  colorPalette = 'accent',
42
- flex = 1,
27
+ flex = 0,
28
+ style,
43
29
  }: FieldRootProps) => {
44
30
  FieldStyles.useVariants({size})
45
31
 
@@ -53,20 +39,16 @@ const FieldRoot = ({
53
39
  FieldStyles.useVariants({variant, size})
54
40
 
55
41
  return (
56
- <VStack
42
+ <View
57
43
  style={[
58
- {
59
- flexShrink: 1,
60
- flexGrow: flex,
61
- alignItems: 'stretch',
62
- alignSelf: 'stretch',
63
- },
44
+ styles.root(flex),
64
45
  FieldStyles.root(colorPalette),
46
+ style && style,
65
47
  ]}>
66
48
  <FieldContext.Provider value={contextValue}>
67
49
  {children}
68
50
  </FieldContext.Provider>
69
- </VStack>
51
+ </View>
70
52
  )
71
53
  }
72
54
 
@@ -89,11 +71,7 @@ const FieldLabel = ({children, ...props}: FieldLabelProps) => {
89
71
 
90
72
  FieldStyles.useVariants({variant, size})
91
73
 
92
- return (
93
- <Text size={size} color={FieldStyles.label(colorPalette).color}>
94
- {children}
95
- </Text>
96
- )
74
+ return <Text style={FieldStyles.label(colorPalette)}>{children}</Text>
97
75
  }
98
76
 
99
77
  type FieldErrorProps = {
@@ -124,6 +102,13 @@ const FieldError = ({...props}: FieldErrorProps) => {
124
102
  )
125
103
  }
126
104
 
105
+ const styles = StyleSheet.create({
106
+ root: (flex: Flex) => ({
107
+ flex,
108
+ flexDirection: 'column',
109
+ }),
110
+ })
111
+
127
112
  export const Field = Object.assign(FieldRoot, {
128
113
  Root: FieldRoot,
129
114
  Label: FieldLabel,
@@ -1,16 +1,23 @@
1
- import {View, StyleSheet, StyleProp, ViewStyle} from 'react-native'
1
+ import {View, StyleProp, ViewStyle} from 'react-native'
2
2
  import Svg, {Defs, LinearGradient, Stop, Rect} from 'react-native-svg'
3
3
  import {withUnistyles} from 'react-native-unistyles'
4
4
  import {gradientBackgroundTokens} from '../theme/GradientBackground.recipe'
5
- import {PalettesWithNestedKeys} from '../style/varia/types'
5
+ import {
6
+ NestedColorsType,
7
+ PalettesWithNestedKeys,
8
+ ThemeColors,
9
+ } from '../style/varia/types'
6
10
  import {resolveColor} from '../style/varia/utils'
11
+ import {StyleSheet} from 'react-native-unistyles'
7
12
 
8
13
  interface GradientBackgroundProps {
9
14
  colorPalette?: PalettesWithNestedKeys
10
15
  variant?: keyof typeof gradientBackgroundTokens.variants.variant
11
16
  direction?: keyof typeof gradientBackgroundTokens.variants.direction
12
17
  containerStyles?: StyleProp<ViewStyle>
13
- colors: any
18
+ colors: NestedColorsType
19
+ startColor?: ThemeColors
20
+ endColor?: ThemeColors
14
21
  }
15
22
 
16
23
  const BaseGradientBackground = ({
@@ -19,10 +26,20 @@ const BaseGradientBackground = ({
19
26
  direction = gradientBackgroundTokens.defaultProps.direction,
20
27
  containerStyles,
21
28
  colors,
29
+ startColor,
30
+ endColor,
22
31
  }: GradientBackgroundProps) => {
23
32
  const colorValue = gradientBackgroundTokens.variants.variant[variant]
24
- const startColor = resolveColor(colorValue.startColor, colors, colorPalette)
25
- const endColor = resolveColor(colorValue.endColor, colors, colorPalette)
33
+ const resolvedStartColor = resolveColor(
34
+ startColor || colorValue.startColor,
35
+ colors,
36
+ colorPalette,
37
+ )
38
+ const resolvedEndColor = resolveColor(
39
+ endColor || colorValue.endColor,
40
+ colors,
41
+ colorPalette,
42
+ )
26
43
 
27
44
  const directionVariant =
28
45
  gradientBackgroundTokens.variants.direction[direction]
@@ -41,8 +58,8 @@ const BaseGradientBackground = ({
41
58
  y1={directionVariant?.y1}
42
59
  x2={directionVariant?.x2}
43
60
  y2={directionVariant?.y2}>
44
- <Stop offset="0%" stopColor={startColor} stopOpacity="1" />
45
- <Stop offset="100%" stopColor={endColor} stopOpacity="1" />
61
+ <Stop offset="0%" stopColor={resolvedStartColor} stopOpacity="1" />
62
+ <Stop offset="100%" stopColor={resolvedEndColor} stopOpacity="1" />
46
63
  </LinearGradient>
47
64
  </Defs>
48
65
  <Rect width="100" height="100" fill="url(#grad)" />
@@ -54,6 +71,7 @@ const BaseGradientBackground = ({
54
71
  const styles = StyleSheet.create({
55
72
  container: {
56
73
  ...StyleSheet.absoluteFillObject,
74
+ alignSelf: 'stretch',
57
75
  borderWidth: 0,
58
76
  overflow: 'hidden',
59
77
  borderColor: 'transparent',