@retray-dev/ui-kit 4.0.0 → 5.2.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 (50) hide show
  1. package/COMPONENTS.md +1806 -663
  2. package/README.md +14 -10
  3. package/dist/index.d.mts +274 -85
  4. package/dist/index.d.ts +274 -85
  5. package/dist/index.js +1048 -321
  6. package/dist/index.mjs +1046 -324
  7. package/package.json +3 -2
  8. package/src/components/Accordion/Accordion.tsx +1 -1
  9. package/src/components/AlertBanner/AlertBanner.tsx +50 -45
  10. package/src/components/Avatar/Avatar.tsx +61 -17
  11. package/src/components/Badge/Badge.tsx +17 -15
  12. package/src/components/Button/Button.tsx +31 -42
  13. package/src/components/Card/Card.tsx +4 -4
  14. package/src/components/CategoryStrip/CategoryStrip.tsx +185 -0
  15. package/src/components/CategoryStrip/index.ts +2 -0
  16. package/src/components/Checkbox/Checkbox.tsx +44 -16
  17. package/src/components/Chip/Chip.tsx +1 -1
  18. package/src/components/ConfirmDialog/ConfirmDialog.tsx +9 -9
  19. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +1 -0
  20. package/src/components/CurrencyInput/CurrencyInput.tsx +6 -4
  21. package/src/components/EmptyState/EmptyState.tsx +9 -9
  22. package/src/components/IconButton/IconButton.tsx +74 -34
  23. package/src/components/Input/Input.tsx +15 -13
  24. package/src/components/LabelValue/LabelValue.tsx +1 -1
  25. package/src/components/ListItem/ListItem.tsx +5 -5
  26. package/src/components/MediaCard/MediaCard.tsx +249 -0
  27. package/src/components/MediaCard/index.ts +2 -0
  28. package/src/components/Pressable/Pressable.tsx +100 -0
  29. package/src/components/Pressable/index.ts +1 -0
  30. package/src/components/Progress/Progress.tsx +14 -7
  31. package/src/components/RadioGroup/RadioGroup.tsx +1 -1
  32. package/src/components/Select/Select.tsx +5 -5
  33. package/src/components/Sheet/Sheet.tsx +35 -15
  34. package/src/components/Skeleton/Skeleton.tsx +34 -7
  35. package/src/components/Slider/Slider.tsx +2 -2
  36. package/src/components/Spinner/Spinner.tsx +1 -1
  37. package/src/components/Switch/Switch.tsx +31 -4
  38. package/src/components/Tabs/Tabs.tsx +63 -45
  39. package/src/components/Text/Text.tsx +59 -10
  40. package/src/components/Textarea/Textarea.tsx +4 -3
  41. package/src/components/Toast/Toast.tsx +77 -36
  42. package/src/components/Toggle/Toggle.tsx +3 -3
  43. package/src/index.ts +8 -2
  44. package/src/theme/ThemeProvider.tsx +11 -10
  45. package/src/theme/colorUtils.ts +80 -0
  46. package/src/theme/colors.ts +76 -35
  47. package/src/theme/index.ts +2 -2
  48. package/src/theme/types.ts +27 -13
  49. package/src/tokens.ts +150 -13
  50. package/src/utils/hover.ts +25 -0
@@ -55,16 +55,16 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
55
55
  const effectiveSecure = isPassword ? !showPassword : secureTextEntry
56
56
 
57
57
  const effectivePrefix: React.ReactNode = prefixIcon
58
- ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.mutedForeground)
58
+ ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.foregroundMuted)
59
59
  : prefix
60
60
 
61
61
  // If type is password and no suffix override is provided, add the toggle button
62
62
  const effectiveSuffix: React.ReactNode = isPassword && !suffix && !suffixIcon ? (
63
63
  <TouchableOpacity onPress={() => setShowPassword(!showPassword)} style={styles.passwordToggle} activeOpacity={0.6}>
64
- <AntDesign name={showPassword ? 'eye' : 'eye-invisible'} size={20} color={colors.mutedForeground} />
64
+ <AntDesign name={showPassword ? 'eye' : 'eye-invisible'} size={20} color={colors.foregroundMuted} />
65
65
  </TouchableOpacity>
66
66
  ) : suffixIcon
67
- ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.mutedForeground)
67
+ ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted)
68
68
  : suffix
69
69
 
70
70
  return (
@@ -77,7 +77,7 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
77
77
  borderColor: error
78
78
  ? colors.destructive
79
79
  : focused
80
- ? (colors.ring ?? colors.primary)
80
+ ? colors.primary
81
81
  : colors.border,
82
82
  backgroundColor: colors.background,
83
83
  },
@@ -86,7 +86,7 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
86
86
  >
87
87
  {effectivePrefix ? (
88
88
  typeof effectivePrefix === 'string' ? (
89
- <Text style={[styles.prefixText, { color: colors.mutedForeground }, prefixStyle]} allowFontScaling={true}>
89
+ <Text style={[styles.prefixText, { color: colors.foregroundMuted }, prefixStyle]} allowFontScaling={true}>
90
90
  {effectivePrefix}
91
91
  </Text>
92
92
  ) : (
@@ -110,14 +110,14 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
110
110
  setFocused(false)
111
111
  onBlur?.(e)
112
112
  }}
113
- placeholderTextColor={colors.mutedForeground}
113
+ placeholderTextColor={colors.foregroundMuted}
114
114
  allowFontScaling={true}
115
115
  secureTextEntry={effectiveSecure}
116
116
  {...props}
117
117
  />
118
118
  {effectiveSuffix ? (
119
119
  typeof effectiveSuffix === 'string' ? (
120
- <Text style={[styles.suffixText, { color: colors.mutedForeground }, suffixStyle]} allowFontScaling={true}>
120
+ <Text style={[styles.suffixText, { color: colors.foregroundMuted }, suffixStyle]} allowFontScaling={true}>
121
121
  {effectiveSuffix}
122
122
  </Text>
123
123
  ) : (
@@ -129,7 +129,7 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
129
129
  <Text style={[styles.helperText, { color: colors.destructive }]} allowFontScaling={true}>{error}</Text>
130
130
  ) : null}
131
131
  {!error && hint ? (
132
- <Text style={[styles.helperText, { color: colors.mutedForeground }]} allowFontScaling={true}>{hint}</Text>
132
+ <Text style={[styles.helperText, { color: colors.foregroundMuted }]} allowFontScaling={true}>{hint}</Text>
133
133
  ) : null}
134
134
  </View>
135
135
  )
@@ -141,21 +141,23 @@ const styles = StyleSheet.create({
141
141
  },
142
142
  label: {
143
143
  fontFamily: 'Poppins-Medium',
144
- fontSize: ms(13),
144
+ fontSize: ms(14), // caption size for input labels
145
145
  },
146
146
  inputWrapper: {
147
147
  flexDirection: 'row',
148
148
  alignItems: 'center',
149
- borderWidth: 1,
150
- borderRadius: ms(8),
149
+ borderWidth: 2,
150
+ borderRadius: 8,
151
151
  paddingHorizontal: s(14),
152
152
  paddingVertical: vs(11),
153
+ minHeight: 48,
153
154
  },
154
155
  input: {
155
156
  fontFamily: 'Poppins-Regular',
156
157
  flex: 1,
157
- fontSize: ms(15),
158
- paddingVertical: 0,
158
+ fontSize: ms(16),
159
+ paddingVertical: vs(2),
160
+ includeFontPadding: false,
159
161
  },
160
162
  prefixContainer: {
161
163
  marginRight: s(8),
@@ -14,7 +14,7 @@ export function LabelValue({ label, value, style }: LabelValueProps) {
14
14
 
15
15
  return (
16
16
  <View style={[styles.container, style]}>
17
- <Text style={[styles.label, { color: colors.mutedForeground }]} allowFontScaling={true}>
17
+ <Text style={[styles.label, { color: colors.foregroundMuted }]} allowFontScaling={true}>
18
18
  {label}
19
19
  </Text>
20
20
  {typeof value === 'string' ? (
@@ -133,7 +133,7 @@ export function ListItem({
133
133
  : leftRender ?? icon
134
134
 
135
135
  const effectiveRight: React.ReactNode | string | undefined = rightIcon
136
- ? renderIcon(rightIcon, 24, rightIconColor ?? colors.mutedForeground)
136
+ ? renderIcon(rightIcon, 24, rightIconColor ?? colors.foregroundMuted)
137
137
  : rightRender ?? trailing
138
138
 
139
139
  const cardStyle: ViewStyle =
@@ -176,7 +176,7 @@ export function ListItem({
176
176
  </Text>
177
177
  {subtitle ? (
178
178
  <Text
179
- style={[styles.subtitle, { color: colors.mutedForeground }, subtitleStyle]}
179
+ style={[styles.subtitle, { color: colors.foregroundMuted }, subtitleStyle]}
180
180
  numberOfLines={2}
181
181
  allowFontScaling={true}
182
182
  >
@@ -185,7 +185,7 @@ export function ListItem({
185
185
  ) : null}
186
186
  {caption ? (
187
187
  <Text
188
- style={[styles.caption, { color: colors.mutedForeground }, captionStyle]}
188
+ style={[styles.caption, { color: colors.foregroundMuted }, captionStyle]}
189
189
  numberOfLines={1}
190
190
  allowFontScaling={true}
191
191
  >
@@ -198,7 +198,7 @@ export function ListItem({
198
198
  <View style={styles.rightContainer}>
199
199
  {typeof effectiveRight === 'string' ? (
200
200
  <Text
201
- style={[styles.rightText, { color: colors.mutedForeground }]}
201
+ style={[styles.rightText, { color: colors.foregroundMuted }]}
202
202
  allowFontScaling={true}
203
203
  >
204
204
  {effectiveRight}
@@ -208,7 +208,7 @@ export function ListItem({
208
208
  )}
209
209
  </View>
210
210
  ) : showChevron ? (
211
- <Entypo name="chevron-with-circle-right" size={20} color={colors.mutedForeground} />
211
+ <Entypo name="chevron-with-circle-right" size={20} color={colors.foregroundMuted} />
212
212
  ) : null}
213
213
  </TouchableOpacity>
214
214
 
@@ -0,0 +1,249 @@
1
+ import React, { useRef, useState } from 'react'
2
+ import {
3
+ View,
4
+ Image,
5
+ Text,
6
+ TouchableOpacity,
7
+ Animated,
8
+ StyleSheet,
9
+ ViewStyle,
10
+ ImageSourcePropType,
11
+ Platform,
12
+ } from 'react-native'
13
+ import { impactLight } from '../../utils/haptics'
14
+ import { useTheme } from '../../theme'
15
+ import { s, vs, ms, mvs } from '../../utils/scaling'
16
+ import { renderIcon } from '../../utils/icons'
17
+ import { useHover } from '../../utils/hover'
18
+ import { RADIUS, SHADOWS } from '../../tokens'
19
+
20
+ const nativeDriver = Platform.OS !== 'web'
21
+
22
+ export type MediaCardAspectRatio = '1:1' | '4:3' | '16:9' | '4:5' | '3:2'
23
+
24
+ const aspectRatioMap: Record<MediaCardAspectRatio, number> = {
25
+ '1:1': 1,
26
+ '4:3': 3 / 4,
27
+ '16:9': 9 / 16,
28
+ '4:5': 5 / 4,
29
+ '3:2': 2 / 3,
30
+ }
31
+
32
+ export interface MediaCardProps {
33
+ /** Image source — URI string or require(). */
34
+ imageSource?: ImageSourcePropType
35
+ /** Image aspect ratio. Defaults to `'4:3'`. */
36
+ aspectRatio?: MediaCardAspectRatio
37
+ /** Badge content rendered top-left over the image (e.g. a Badge component or Text). */
38
+ badge?: React.ReactNode
39
+ /** Icon rendered in a circle button top-right over the image. Defaults to `'heart'`. */
40
+ actionIcon?: React.ReactNode
41
+ /** Icon name for the action button. Overrides `actionIcon`. */
42
+ actionIconName?: string
43
+ /** Whether the action icon is in active/filled state. */
44
+ actionActive?: boolean
45
+ /** Called when the top-right action icon is pressed. */
46
+ onActionPress?: () => void
47
+ /** Primary text below the image. */
48
+ title?: string
49
+ /** Secondary text below the title. */
50
+ subtitle?: string
51
+ /** Tertiary / caption text below subtitle. */
52
+ caption?: string
53
+ /** Called when the card body is pressed. */
54
+ onPress?: () => void
55
+ style?: ViewStyle
56
+ /** Style for the image container. */
57
+ imageStyle?: ViewStyle
58
+ /** Additional content rendered below caption. */
59
+ footer?: React.ReactNode
60
+ }
61
+
62
+ export function MediaCard({
63
+ imageSource,
64
+ aspectRatio = '4:3',
65
+ badge,
66
+ actionIcon,
67
+ actionIconName,
68
+ actionActive = false,
69
+ onActionPress,
70
+ title,
71
+ subtitle,
72
+ caption,
73
+ onPress,
74
+ style,
75
+ imageStyle,
76
+ footer,
77
+ }: MediaCardProps) {
78
+ const { colors } = useTheme()
79
+ const scale = useRef(new Animated.Value(1)).current
80
+ const { hovered, hoverHandlers } = useHover()
81
+
82
+ const handlePressIn = () => {
83
+ if (!onPress) return
84
+ Animated.spring(scale, { toValue: 0.98, useNativeDriver: nativeDriver, speed: 40, bounciness: 0 }).start()
85
+ }
86
+
87
+ const handlePressOut = () => {
88
+ if (!onPress) return
89
+ Animated.spring(scale, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 4 }).start()
90
+ }
91
+
92
+ const handlePress = () => {
93
+ if (!onPress) return
94
+ impactLight()
95
+ onPress()
96
+ }
97
+
98
+ const ratio = aspectRatioMap[aspectRatio]
99
+
100
+ // Action icon: active = primary fill, inactive = foreground outline
101
+ const resolvedActionIcon = actionIconName
102
+ ? renderIcon(actionIconName, 18, actionActive ? colors.primary : colors.background)
103
+ : actionIcon ?? renderIcon('heart', 18, actionActive ? colors.primary : colors.background)
104
+
105
+ const cardContent = (
106
+ <View
107
+ style={[
108
+ styles.card,
109
+ hovered && styles.cardHovered,
110
+ style,
111
+ ]}
112
+ {...(Platform.OS === 'web' ? hoverHandlers : {})}
113
+ >
114
+ {/* Image area */}
115
+ <View style={[styles.imageContainer, imageStyle]}>
116
+ <View style={{ paddingTop: `${ratio * 100}%` as any }}>
117
+ <View style={StyleSheet.absoluteFill}>
118
+ {imageSource ? (
119
+ <Image
120
+ source={imageSource}
121
+ style={styles.image}
122
+ resizeMode="cover"
123
+ />
124
+ ) : (
125
+ <View style={[styles.imagePlaceholder, { backgroundColor: colors.surface }]} />
126
+ )}
127
+ </View>
128
+ </View>
129
+
130
+ {/* Badge — top left */}
131
+ {badge && (
132
+ <View style={styles.badgeContainer}>
133
+ {badge}
134
+ </View>
135
+ )}
136
+
137
+ {/* Action icon — top right */}
138
+ {(onActionPress || actionIcon || actionIconName) && (
139
+ <TouchableOpacity
140
+ style={[styles.actionButton, { backgroundColor: 'rgba(0,0,0,0.24)' }]}
141
+ onPress={() => { impactLight(); onActionPress?.() }}
142
+ activeOpacity={0.8}
143
+ touchSoundDisabled={true}
144
+ >
145
+ {resolvedActionIcon}
146
+ </TouchableOpacity>
147
+ )}
148
+ </View>
149
+
150
+ {/* Metadata */}
151
+ {(title || subtitle || caption || footer) && (
152
+ <View style={styles.meta}>
153
+ {title ? (
154
+ <Text style={[styles.title, { color: colors.foreground }]} numberOfLines={2} allowFontScaling={true}>
155
+ {title}
156
+ </Text>
157
+ ) : null}
158
+ {subtitle ? (
159
+ <Text style={[styles.subtitle, { color: colors.foregroundSubtle }]} numberOfLines={1} allowFontScaling={true}>
160
+ {subtitle}
161
+ </Text>
162
+ ) : null}
163
+ {caption ? (
164
+ <Text style={[styles.caption, { color: colors.foregroundMuted }]} numberOfLines={1} allowFontScaling={true}>
165
+ {caption}
166
+ </Text>
167
+ ) : null}
168
+ {footer}
169
+ </View>
170
+ )}
171
+ </View>
172
+ )
173
+
174
+ if (onPress) {
175
+ return (
176
+ <Animated.View style={{ transform: [{ scale }] }}>
177
+ <TouchableOpacity
178
+ onPress={handlePress}
179
+ onPressIn={handlePressIn}
180
+ onPressOut={handlePressOut}
181
+ activeOpacity={1}
182
+ touchSoundDisabled={true}
183
+ >
184
+ {cardContent}
185
+ </TouchableOpacity>
186
+ </Animated.View>
187
+ )
188
+ }
189
+
190
+ return cardContent
191
+ }
192
+
193
+ const styles = StyleSheet.create({
194
+ card: {
195
+ borderRadius: RADIUS.md, // 14px — Airbnb property card spec
196
+ overflow: 'hidden',
197
+ backgroundColor: 'transparent',
198
+ },
199
+ cardHovered: {
200
+ // Web hover: lift shadow
201
+ ...SHADOWS.md,
202
+ },
203
+ imageContainer: {
204
+ borderRadius: RADIUS.md,
205
+ overflow: 'hidden',
206
+ },
207
+ image: {
208
+ width: '100%',
209
+ height: '100%',
210
+ },
211
+ imagePlaceholder: {
212
+ width: '100%',
213
+ height: '100%',
214
+ },
215
+ badgeContainer: {
216
+ position: 'absolute',
217
+ top: s(8),
218
+ left: s(8),
219
+ },
220
+ actionButton: {
221
+ position: 'absolute',
222
+ top: s(8),
223
+ right: s(8),
224
+ width: s(32),
225
+ height: s(32),
226
+ borderRadius: 9999,
227
+ alignItems: 'center',
228
+ justifyContent: 'center',
229
+ },
230
+ meta: {
231
+ paddingTop: vs(8),
232
+ gap: vs(2),
233
+ },
234
+ title: {
235
+ fontFamily: 'Poppins-SemiBold',
236
+ fontSize: ms(14),
237
+ lineHeight: mvs(20),
238
+ },
239
+ subtitle: {
240
+ fontFamily: 'Poppins-Regular',
241
+ fontSize: ms(13),
242
+ lineHeight: mvs(18),
243
+ },
244
+ caption: {
245
+ fontFamily: 'Poppins-Regular',
246
+ fontSize: ms(12),
247
+ lineHeight: mvs(16),
248
+ },
249
+ })
@@ -0,0 +1,2 @@
1
+ export { MediaCard } from './MediaCard'
2
+ export type { MediaCardProps, MediaCardAspectRatio } from './MediaCard'
@@ -0,0 +1,100 @@
1
+ import React, { useRef } from 'react'
2
+ import {
3
+ TouchableOpacity,
4
+ Animated,
5
+ ViewStyle,
6
+ Platform,
7
+ TouchableOpacityProps,
8
+ } from 'react-native'
9
+ import { impactLight } from '../../utils/haptics'
10
+ import { useHover } from '../../utils/hover'
11
+
12
+ const nativeDriver = Platform.OS !== 'web'
13
+
14
+ export interface PressableProps extends Omit<TouchableOpacityProps, 'activeOpacity'> {
15
+ /** Children content to render inside the pressable. */
16
+ children: React.ReactNode
17
+ /** Called when pressed. */
18
+ onPress?: () => void
19
+ /** Scale value on press. Defaults to `0.98` (MediaCard-style). */
20
+ pressScale?: number
21
+ /** Bounciness of the spring animation on release. Defaults to `4`. */
22
+ bounciness?: number
23
+ /** Enable haptic feedback on press. Defaults to `true`. */
24
+ haptics?: boolean
25
+ /** Additional style for the Animated wrapper. */
26
+ style?: ViewStyle
27
+ /** Disable interaction. */
28
+ disabled?: boolean
29
+ /** Hover scale (web only). Defaults to `1.02`. Set to `1` to disable. */
30
+ hoverScale?: number
31
+ }
32
+
33
+ /**
34
+ * Generic pressable with beautiful spring bounce effect matching MediaCard interaction.
35
+ * Use for custom pressable content that needs consistent press feel.
36
+ */
37
+ export function Pressable({
38
+ children,
39
+ onPress,
40
+ pressScale = 0.98,
41
+ bounciness = 4,
42
+ haptics = true,
43
+ style,
44
+ disabled,
45
+ hoverScale = 1.02,
46
+ ...touchableProps
47
+ }: PressableProps) {
48
+ const scale = useRef(new Animated.Value(1)).current
49
+ const { hovered, hoverHandlers } = useHover()
50
+
51
+ const handlePressIn = () => {
52
+ if (disabled) return
53
+ Animated.spring(scale, {
54
+ toValue: pressScale,
55
+ useNativeDriver: nativeDriver,
56
+ speed: 40,
57
+ bounciness: 0,
58
+ }).start()
59
+ }
60
+
61
+ const handlePressOut = () => {
62
+ if (disabled) return
63
+ Animated.spring(scale, {
64
+ toValue: 1,
65
+ useNativeDriver: nativeDriver,
66
+ speed: 40,
67
+ bounciness,
68
+ }).start()
69
+ }
70
+
71
+ const handlePress = () => {
72
+ if (disabled || !onPress) return
73
+ if (haptics) impactLight()
74
+ onPress()
75
+ }
76
+
77
+ const hoverScaleValue = hovered && hoverScale !== 1 ? hoverScale : 1
78
+
79
+ return (
80
+ <Animated.View
81
+ style={[
82
+ { transform: [{ scale: Animated.multiply(scale, hoverScaleValue) }] },
83
+ style,
84
+ ]}
85
+ {...(Platform.OS === 'web' ? hoverHandlers : {})}
86
+ >
87
+ <TouchableOpacity
88
+ onPress={handlePress}
89
+ onPressIn={handlePressIn}
90
+ onPressOut={handlePressOut}
91
+ activeOpacity={1}
92
+ disabled={disabled}
93
+ touchSoundDisabled={true}
94
+ {...touchableProps}
95
+ >
96
+ {children}
97
+ </TouchableOpacity>
98
+ </Animated.View>
99
+ )
100
+ }
@@ -0,0 +1 @@
1
+ export * from './Pressable'
@@ -3,15 +3,16 @@ import { View, Animated, StyleSheet, ViewStyle } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
4
  import { vs } from '../../utils/scaling'
5
5
 
6
+ export type ProgressVariant = 'default' | 'success' | 'warning' | 'destructive'
7
+
6
8
  export interface ProgressProps {
7
- /** Current progress value. Clamped to `[0, max]`. Defaults to `0`. */
8
9
  value?: number
9
- /** Maximum value. Defaults to `100`. */
10
10
  max?: number
11
+ variant?: ProgressVariant
11
12
  style?: ViewStyle
12
13
  }
13
14
 
14
- export function Progress({ value = 0, max = 100, style }: ProgressProps) {
15
+ export function Progress({ value = 0, max = 100, variant = 'default', style }: ProgressProps) {
15
16
  const { colors } = useTheme()
16
17
  const percent = Math.min(Math.max((value / max) * 100, 0), 100)
17
18
  const [trackWidth, setTrackWidth] = useState(0)
@@ -27,13 +28,19 @@ export function Progress({ value = 0, max = 100, style }: ProgressProps) {
27
28
  }).start()
28
29
  }, [percent, trackWidth])
29
30
 
31
+ const indicatorColor =
32
+ variant === 'success' ? colors.success
33
+ : variant === 'warning' ? colors.warning
34
+ : variant === 'destructive' ? colors.destructive
35
+ : colors.primary
36
+
30
37
  return (
31
38
  <View
32
- style={[styles.track, { backgroundColor: colors.muted }, style]}
39
+ style={[styles.track, { backgroundColor: colors.surface }, style]}
33
40
  onLayout={(e) => setTrackWidth(e.nativeEvent.layout.width)}
34
41
  >
35
42
  <Animated.View
36
- style={[styles.indicator, { width: animatedWidth, backgroundColor: colors.primary }]}
43
+ style={[styles.indicator, { width: animatedWidth, backgroundColor: indicatorColor }]}
37
44
  />
38
45
  </View>
39
46
  )
@@ -42,12 +49,12 @@ export function Progress({ value = 0, max = 100, style }: ProgressProps) {
42
49
  const styles = StyleSheet.create({
43
50
  track: {
44
51
  height: vs(8),
45
- borderRadius: 999,
52
+ borderRadius: 9999,
46
53
  overflow: 'hidden',
47
54
  width: '100%',
48
55
  },
49
56
  indicator: {
50
57
  height: '100%',
51
- borderRadius: 999,
58
+ borderRadius: 9999,
52
59
  },
53
60
  })
@@ -71,7 +71,7 @@ function RadioItem({
71
71
  <Text
72
72
  style={[
73
73
  styles.label,
74
- { color: option.disabled ? colors.mutedForeground : colors.foreground },
74
+ { color: option.disabled ? colors.foregroundMuted : colors.foreground },
75
75
  ]}
76
76
  allowFontScaling={true}
77
77
  >
@@ -102,14 +102,14 @@ export function Select({
102
102
  <Text
103
103
  style={[
104
104
  styles.triggerText,
105
- { color: selected ? colors.foreground : colors.mutedForeground },
105
+ { color: selected ? colors.foreground : colors.foregroundMuted },
106
106
  ]}
107
107
  numberOfLines={1}
108
108
  allowFontScaling={true}
109
109
  >
110
110
  {selected?.label ?? placeholder}
111
111
  </Text>
112
- <Entypo name="chevron-with-circle-down" size={20} color={colors.mutedForeground} />
112
+ <Entypo name="chevron-with-circle-down" size={20} color={colors.foregroundMuted} />
113
113
  </TouchableOpacity>
114
114
  </Animated.View>
115
115
  ) : null}
@@ -144,7 +144,7 @@ export function Select({
144
144
  itemStyle={{ color: colors.foreground }}
145
145
  >
146
146
  {!value ? (
147
- <Picker.Item label={placeholder} value="" color={colors.mutedForeground} enabled={false} />
147
+ <Picker.Item label={placeholder} value="" color={colors.foregroundMuted} enabled={false} />
148
148
  ) : null}
149
149
  {options.map((o) => (
150
150
  <Picker.Item
@@ -152,7 +152,7 @@ export function Select({
152
152
  label={o.label}
153
153
  value={o.value}
154
154
  enabled={!o.disabled}
155
- color={o.disabled ? colors.mutedForeground : colors.foreground}
155
+ color={o.disabled ? colors.foregroundMuted : colors.foreground}
156
156
  />
157
157
  ))}
158
158
  </Picker>
@@ -202,7 +202,7 @@ export function Select({
202
202
  styles.webPicker,
203
203
  {
204
204
  borderColor: error ? colors.destructive : colors.border,
205
- color: selected ? colors.foreground : colors.mutedForeground,
205
+ color: selected ? colors.foreground : colors.foregroundMuted,
206
206
  backgroundColor: colors.background,
207
207
  opacity: disabled ? 0.45 : 1,
208
208
  },