@retray-dev/ui-kit 2.8.0 → 3.1.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 (55) hide show
  1. package/COMPONENTS.md +73 -17
  2. package/README.md +23 -3
  3. package/dist/index.d.mts +17 -6
  4. package/dist/index.d.ts +17 -6
  5. package/dist/index.js +446 -329
  6. package/dist/index.mjs +447 -330
  7. package/package.json +6 -3
  8. package/src/assets/fonts/Poppins-Black.ttf +0 -0
  9. package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
  10. package/src/assets/fonts/Poppins-Bold.ttf +0 -0
  11. package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
  12. package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
  13. package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
  14. package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
  15. package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
  16. package/src/assets/fonts/Poppins-Italic.ttf +0 -0
  17. package/src/assets/fonts/Poppins-Light.ttf +0 -0
  18. package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
  19. package/src/assets/fonts/Poppins-Medium.ttf +0 -0
  20. package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
  21. package/src/assets/fonts/Poppins-Regular.ttf +0 -0
  22. package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  23. package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
  24. package/src/assets/fonts/Poppins-Thin.ttf +0 -0
  25. package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
  26. package/src/components/Accordion/Accordion.tsx +16 -9
  27. package/src/components/AlertBanner/AlertBanner.tsx +36 -36
  28. package/src/components/Avatar/Avatar.tsx +1 -1
  29. package/src/components/Badge/Badge.tsx +12 -8
  30. package/src/components/Button/Button.tsx +8 -8
  31. package/src/components/Card/Card.tsx +12 -9
  32. package/src/components/Checkbox/Checkbox.tsx +8 -8
  33. package/src/components/Chip/Chip.tsx +22 -6
  34. package/src/components/ConfirmDialog/ConfirmDialog.tsx +86 -38
  35. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +1 -1
  36. package/src/components/CurrencyInput/CurrencyInput.tsx +14 -4
  37. package/src/components/EmptyState/EmptyState.tsx +2 -1
  38. package/src/components/Input/Input.tsx +16 -9
  39. package/src/components/LabelValue/LabelValue.tsx +4 -3
  40. package/src/components/ListItem/ListItem.tsx +10 -9
  41. package/src/components/MonthPicker/MonthPicker.tsx +1 -1
  42. package/src/components/RadioGroup/RadioGroup.tsx +36 -36
  43. package/src/components/Select/Select.tsx +17 -19
  44. package/src/components/Sheet/Sheet.tsx +2 -1
  45. package/src/components/Slider/Slider.tsx +3 -3
  46. package/src/components/Spinner/Spinner.tsx +36 -2
  47. package/src/components/Switch/Switch.tsx +4 -4
  48. package/src/components/Tabs/Tabs.tsx +9 -16
  49. package/src/components/Text/Text.tsx +6 -6
  50. package/src/components/Textarea/Textarea.tsx +8 -6
  51. package/src/components/Toast/Toast.tsx +27 -21
  52. package/src/components/Toggle/Toggle.tsx +6 -4
  53. package/src/fonts.ts +30 -0
  54. package/src/theme/colors.ts +22 -14
  55. package/src/theme/types.ts +4 -0
@@ -1,5 +1,13 @@
1
- import React from 'react'
2
- import { Modal, View, Text, StyleSheet, TouchableOpacity } from 'react-native'
1
+ import React, { useEffect, useRef } from 'react'
2
+ import { View, Text, StyleSheet } from 'react-native'
3
+ import {
4
+ BottomSheetModal,
5
+ BottomSheetView,
6
+ BottomSheetBackdrop,
7
+ type BottomSheetBackdropProps,
8
+ } from '@gorhom/bottom-sheet'
9
+ import { Feather } from '@expo/vector-icons'
10
+ import { impactLight } from '../../utils/haptics'
3
11
  import { useTheme } from '../../theme'
4
12
  import { Button } from '../Button'
5
13
  import { s, vs, ms, mvs } from '../../utils/scaling'
@@ -26,58 +34,98 @@ export function ConfirmDialog({
26
34
  onCancel,
27
35
  }: ConfirmDialogProps) {
28
36
  const { colors } = useTheme()
37
+ const ref = useRef<BottomSheetModal>(null)
38
+
39
+ useEffect(() => {
40
+ if (visible) {
41
+ impactLight()
42
+ ref.current?.present()
43
+ } else {
44
+ ref.current?.dismiss()
45
+ }
46
+ }, [visible])
47
+
48
+ const renderBackdrop = (props: BottomSheetBackdropProps) => (
49
+ <BottomSheetBackdrop
50
+ {...props}
51
+ disappearsOnIndex={-1}
52
+ appearsOnIndex={0}
53
+ pressBehavior="close"
54
+ />
55
+ )
29
56
 
30
57
  return (
31
- <Modal visible={visible} transparent animationType="fade" onRequestClose={onCancel}>
32
- <TouchableOpacity style={styles.overlay} activeOpacity={1} onPress={onCancel}>
33
- <View
34
- style={[styles.dialog, { backgroundColor: colors.card }]}
35
- onStartShouldSetResponder={() => true}
36
- >
37
- <Text style={[styles.title, { color: colors.cardForeground }]} allowFontScaling={true}>
38
- {title}
58
+ <BottomSheetModal
59
+ ref={ref}
60
+ snapPoints={['35%']}
61
+ onDismiss={onCancel}
62
+ backdropComponent={renderBackdrop}
63
+ backgroundStyle={[styles.background, { backgroundColor: colors.card }]}
64
+ handleIndicatorStyle={[styles.handle, { backgroundColor: colors.border }]}
65
+ enablePanDownToClose
66
+ >
67
+ <BottomSheetView style={styles.content}>
68
+ <Text style={[styles.title, { color: colors.cardForeground }]} allowFontScaling={true}>
69
+ {title}
70
+ </Text>
71
+ {description ? (
72
+ <Text style={[styles.description, { color: colors.mutedForeground }]} allowFontScaling={true}>
73
+ {description}
39
74
  </Text>
40
- {description ? (
41
- <Text style={[styles.description, { color: colors.mutedForeground }]} allowFontScaling={true}>
42
- {description}
43
- </Text>
44
- ) : null}
45
- <View style={styles.actions}>
46
- <Button label={cancelLabel} variant="outline" fullWidth onPress={onCancel} />
47
- <Button label={confirmLabel} variant={confirmVariant} fullWidth onPress={onConfirm} />
48
- </View>
75
+ ) : null}
76
+ <View style={styles.actions}>
77
+ <Button
78
+ label={cancelLabel}
79
+ variant="outline"
80
+ fullWidth
81
+ onPress={onCancel}
82
+ icon={<Feather name="x" size={15} color={colors.foreground} />}
83
+ />
84
+ <Button
85
+ label={confirmLabel}
86
+ variant={confirmVariant}
87
+ fullWidth
88
+ onPress={onConfirm}
89
+ icon={
90
+ <Feather
91
+ name={confirmVariant === 'destructive' ? 'trash-2' : 'check'}
92
+ size={15}
93
+ color={
94
+ confirmVariant === 'destructive'
95
+ ? colors.destructiveForeground
96
+ : colors.primaryForeground
97
+ }
98
+ />
99
+ }
100
+ />
49
101
  </View>
50
- </TouchableOpacity>
51
- </Modal>
102
+ </BottomSheetView>
103
+ </BottomSheetModal>
52
104
  )
53
105
  }
54
106
 
55
107
  const styles = StyleSheet.create({
56
- overlay: {
57
- flex: 1,
58
- backgroundColor: 'rgba(0,0,0,0.5)',
59
- justifyContent: 'center',
60
- alignItems: 'center',
61
- padding: s(24),
108
+ background: {
109
+ borderTopLeftRadius: ms(16),
110
+ borderTopRightRadius: ms(16),
111
+ },
112
+ handle: {
113
+ width: s(36),
114
+ height: vs(4),
115
+ borderRadius: ms(2),
62
116
  },
63
- dialog: {
64
- width: '100%',
65
- maxWidth: s(400),
66
- borderRadius: ms(16),
67
- padding: s(24),
117
+ content: {
118
+ paddingHorizontal: s(24),
119
+ paddingBottom: vs(32),
68
120
  gap: vs(12),
69
- shadowColor: '#000',
70
- shadowOffset: { width: 0, height: 8 },
71
- shadowOpacity: 0.15,
72
- shadowRadius: 16,
73
- elevation: 8,
74
121
  },
75
122
  title: {
123
+ fontFamily: 'Poppins-SemiBold',
76
124
  fontSize: ms(18),
77
- fontWeight: '600',
78
125
  lineHeight: mvs(26),
79
126
  },
80
127
  description: {
128
+ fontFamily: 'Poppins-Regular',
81
129
  fontSize: ms(15),
82
130
  lineHeight: mvs(22),
83
131
  },
@@ -43,7 +43,7 @@ export function CurrencyDisplay({ value, prefix = '$', showDecimals = false, tex
43
43
  const styles = StyleSheet.create({
44
44
  container: {},
45
45
  amount: {
46
+ fontFamily: 'Poppins-Bold',
46
47
  fontSize: ms(56),
47
- fontWeight: '700',
48
48
  },
49
49
  })
@@ -2,6 +2,8 @@ import React from 'react'
2
2
  import { ViewStyle, TextStyle } from 'react-native'
3
3
  import { Input } from '../Input'
4
4
  import { ms } from '../../utils/scaling'
5
+ import { renderIcon } from '../../utils/icons'
6
+ import { useTheme } from '../../theme'
5
7
 
6
8
  export interface CurrencyInputProps {
7
9
  value?: string
@@ -45,29 +47,37 @@ export function CurrencyInput({
45
47
  containerStyle,
46
48
  style,
47
49
  }: CurrencyInputProps) {
50
+ const { colors } = useTheme()
48
51
  const handleChange = (text: string) => {
49
52
  const withoutPrefix = prefix && text.startsWith(prefix) ? text.slice(prefix.length) : text
50
53
  const formatted = formatCurrency(withoutPrefix, thousandsSeparator)
51
- const display = formatted ? `${prefix}${formatted}` : ''
54
+ const display = formatted
52
55
  onChangeText?.(display)
53
56
  const separatorRegex = new RegExp(`\\${thousandsSeparator}`, 'g')
54
57
  const raw = parseFloat(formatted.replace(separatorRegex, '') || '0')
55
58
  onChangeValue?.(isNaN(raw) ? 0 : raw)
56
59
  }
57
60
 
58
- const inputStyle: TextStyle = size === 'large' ? { fontSize: ms(36) } : {}
61
+ const inputStyle: TextStyle = size === 'large' ? { fontFamily: 'Poppins-Regular', fontSize: ms(36) } : { fontFamily: 'Poppins-Regular' }
62
+
63
+ const dollarIcon = renderIcon('dollar-sign', size === 'large' ? 24 : 16, colors.mutedForeground)
64
+
65
+ // Remove prefix from display value if present
66
+ const displayValue = value && prefix && value.startsWith(prefix) ? value.slice(prefix.length) : value
59
67
 
60
68
  return (
61
69
  <Input
62
- value={value}
70
+ value={displayValue}
63
71
  onChangeText={handleChange}
64
72
  keyboardType="numeric"
65
73
  label={label}
66
74
  error={error}
67
75
  hint={hint}
68
- placeholder={placeholder ?? `${prefix}0`}
76
+ placeholder={placeholder ?? '0'}
69
77
  editable={editable}
78
+ prefix={dollarIcon}
70
79
  containerStyle={containerStyle}
80
+ inputWrapperStyle={size === 'large' ? { paddingVertical: 10 } : undefined}
71
81
  style={[inputStyle, style]}
72
82
  />
73
83
  )
@@ -97,14 +97,15 @@ const styles = StyleSheet.create({
97
97
  maxWidth: s(320),
98
98
  },
99
99
  title: {
100
+ fontFamily: 'Poppins-Medium',
100
101
  fontSize: ms(18),
101
- fontWeight: '500',
102
102
  textAlign: 'center',
103
103
  },
104
104
  titleCompact: {
105
105
  fontSize: ms(15),
106
106
  },
107
107
  description: {
108
+ fontFamily: 'Poppins-Regular',
108
109
  fontSize: ms(14),
109
110
  lineHeight: mvs(20),
110
111
  textAlign: 'center',
@@ -42,9 +42,11 @@ export interface InputProps extends TextInputProps {
42
42
  type?: 'text' | 'password'
43
43
  /** Style for the outer container \`View\`. Use \`style\` (from \`TextInputProps\`) to style the \`TextInput\` itself. */
44
44
  containerStyle?: ViewStyle
45
+ /** Style for the inner border wrapper (overrides padding, etc). */
46
+ inputWrapperStyle?: ViewStyle
45
47
  }
46
48
 
47
- export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, style, onFocus, onBlur, secureTextEntry, ...props }: InputProps) {
49
+ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, ...props }: InputProps) {
48
50
  const { colors } = useTheme()
49
51
  const [focused, setFocused] = useState(false)
50
52
  const [showPassword, setShowPassword] = useState(false)
@@ -79,6 +81,7 @@ export function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixS
79
81
  : colors.border,
80
82
  backgroundColor: colors.background,
81
83
  },
84
+ inputWrapperStyle,
82
85
  ]}
83
86
  >
84
87
  {effectivePrefix ? (
@@ -137,40 +140,44 @@ const styles = StyleSheet.create({
137
140
  gap: vs(8),
138
141
  },
139
142
  label: {
140
- fontSize: ms(15),
141
- fontWeight: '500',
143
+ fontFamily: 'Poppins-Medium',
144
+ fontSize: ms(13),
142
145
  },
143
146
  inputWrapper: {
144
147
  flexDirection: 'row',
145
148
  alignItems: 'center',
146
- borderWidth: 1.5,
149
+ borderWidth: 1,
147
150
  borderRadius: ms(8),
148
- paddingHorizontal: s(16),
149
- paddingVertical: vs(14),
151
+ paddingHorizontal: s(14),
152
+ paddingVertical: vs(11),
150
153
  },
151
154
  input: {
155
+ fontFamily: 'Poppins-Regular',
152
156
  flex: 1,
153
- fontSize: ms(17),
157
+ fontSize: ms(15),
154
158
  paddingVertical: 0,
155
159
  },
156
160
  prefixContainer: {
157
161
  marginRight: s(8),
158
162
  },
159
163
  prefixText: {
160
- fontSize: ms(17),
164
+ fontFamily: 'Poppins-Regular',
165
+ fontSize: ms(15),
161
166
  marginRight: s(8),
162
167
  },
163
168
  suffixContainer: {
164
169
  marginLeft: s(8),
165
170
  },
166
171
  suffixText: {
167
- fontSize: ms(17),
172
+ fontFamily: 'Poppins-Regular',
173
+ fontSize: ms(15),
168
174
  marginLeft: s(8),
169
175
  },
170
176
  passwordToggle: {
171
177
  padding: s(4),
172
178
  },
173
179
  helperText: {
180
+ fontFamily: 'Poppins-Regular',
174
181
  fontSize: ms(13),
175
182
  },
176
183
  })
@@ -36,13 +36,14 @@ const styles = StyleSheet.create({
36
36
  gap: s(12),
37
37
  },
38
38
  label: {
39
+ fontFamily: 'Poppins-Regular',
39
40
  fontSize: ms(13),
40
41
  lineHeight: mvs(18),
41
42
  },
42
43
  value: {
43
- fontSize: ms(15),
44
- fontWeight: '500',
45
- lineHeight: mvs(22),
44
+ fontFamily: 'Poppins-Medium',
45
+ fontSize: ms(14),
46
+ lineHeight: mvs(20),
46
47
  textAlign: 'right',
47
48
  },
48
49
  })
@@ -229,7 +229,7 @@ const styles = StyleSheet.create({
229
229
  flexDirection: 'row',
230
230
  alignItems: 'center',
231
231
  paddingHorizontal: s(16),
232
- paddingVertical: vs(14),
232
+ paddingVertical: vs(10),
233
233
  gap: s(12),
234
234
  },
235
235
  leftContainer: {
@@ -244,18 +244,18 @@ const styles = StyleSheet.create({
244
244
  gap: vs(4),
245
245
  },
246
246
  title: {
247
- fontSize: ms(17),
248
- fontWeight: '500',
249
- lineHeight: mvs(24),
247
+ fontFamily: 'Poppins-Medium',
248
+ fontSize: ms(15),
249
+ lineHeight: mvs(22),
250
250
  },
251
251
  subtitle: {
252
- fontSize: ms(14),
253
- fontWeight: '400',
254
- lineHeight: mvs(20),
252
+ fontFamily: 'Poppins-Regular',
253
+ fontSize: ms(13),
254
+ lineHeight: mvs(18),
255
255
  },
256
256
  caption: {
257
+ fontFamily: 'Poppins-Regular',
257
258
  fontSize: ms(12),
258
- fontWeight: '400',
259
259
  lineHeight: mvs(16),
260
260
  opacity: 0.7,
261
261
  },
@@ -266,7 +266,8 @@ const styles = StyleSheet.create({
266
266
  maxWidth: s(160),
267
267
  },
268
268
  rightText: {
269
- fontSize: ms(15),
269
+ fontFamily: 'Poppins-Regular',
270
+ fontSize: ms(14),
270
271
  },
271
272
  chevron: {
272
273
  marginLeft: s(4),
@@ -81,8 +81,8 @@ const styles = StyleSheet.create({
81
81
  justifyContent: 'center',
82
82
  },
83
83
  label: {
84
+ fontFamily: 'Poppins-Medium',
84
85
  fontSize: ms(17),
85
- fontWeight: '500',
86
86
  lineHeight: mvs(24),
87
87
  textAlign: 'center',
88
88
  minWidth: s(160),
@@ -42,43 +42,42 @@ function RadioItem({
42
42
  }
43
43
 
44
44
  return (
45
- <Animated.View style={{ transform: [{ scale }] }}>
46
- <TouchableOpacity
47
- style={styles.row}
48
- onPress={() => {
49
- if (!option.disabled) {
50
- hapticSelection()
51
- onSelect()
52
- }
53
- }}
54
- onPressIn={handlePressIn}
55
- onPressOut={handlePressOut}
56
- activeOpacity={1}
57
- touchSoundDisabled={true}
58
- disabled={option.disabled}
45
+ <TouchableOpacity
46
+ style={styles.row}
47
+ onPress={() => {
48
+ if (!option.disabled) {
49
+ hapticSelection()
50
+ onSelect()
51
+ }
52
+ }}
53
+ onPressIn={handlePressIn}
54
+ onPressOut={handlePressOut}
55
+ activeOpacity={1}
56
+ touchSoundDisabled={true}
57
+ disabled={option.disabled}
58
+ >
59
+ <Animated.View
60
+ style={[
61
+ styles.radio,
62
+ {
63
+ borderColor: selected ? colors.primary : colors.border,
64
+ opacity: option.disabled ? 0.45 : 1,
65
+ transform: [{ scale }],
66
+ },
67
+ ]}
59
68
  >
60
- <View
61
- style={[
62
- styles.radio,
63
- {
64
- borderColor: selected ? colors.primary : colors.border,
65
- opacity: option.disabled ? 0.45 : 1,
66
- },
67
- ]}
68
- >
69
- {selected ? <View style={[styles.dot, { backgroundColor: colors.primary }]} /> : null}
70
- </View>
71
- <Text
72
- style={[
73
- styles.label,
74
- { color: option.disabled ? colors.mutedForeground : colors.foreground },
75
- ]}
76
- allowFontScaling={true}
77
- >
78
- {option.label}
79
- </Text>
80
- </TouchableOpacity>
81
- </Animated.View>
69
+ {selected ? <View style={[styles.dot, { backgroundColor: colors.primary }]} /> : null}
70
+ </Animated.View>
71
+ <Text
72
+ style={[
73
+ styles.label,
74
+ { color: option.disabled ? colors.mutedForeground : colors.foreground },
75
+ ]}
76
+ allowFontScaling={true}
77
+ >
78
+ {option.label}
79
+ </Text>
80
+ </TouchableOpacity>
82
81
  )
83
82
  }
84
83
 
@@ -130,6 +129,7 @@ const styles = StyleSheet.create({
130
129
  borderRadius: s(5),
131
130
  },
132
131
  label: {
132
+ fontFamily: 'Poppins-Regular',
133
133
  fontSize: ms(14),
134
134
  lineHeight: mvs(20),
135
135
  },
@@ -9,6 +9,7 @@ import { s, vs, ms } from '../../utils/scaling'
9
9
  const isIOS = Platform.OS === 'ios'
10
10
  const isAndroid = Platform.OS === 'android'
11
11
  const isWeb = Platform.OS === 'web'
12
+ const nativeDriver = Platform.OS !== 'web'
12
13
 
13
14
  export interface SelectOption {
14
15
  label: string
@@ -47,11 +48,11 @@ export function Select({
47
48
 
48
49
  const handlePressIn = () => {
49
50
  if (disabled) return
50
- Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start()
51
+ Animated.spring(scale, { toValue: 0.95, useNativeDriver: nativeDriver, speed: 40, bounciness: 0 }).start()
51
52
  }
52
53
 
53
54
  const handlePressOut = () => {
54
- Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start()
55
+ Animated.spring(scale, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 4 }).start()
55
56
  }
56
57
 
57
58
  const handleOpen = () => {
@@ -231,31 +232,28 @@ const styles = StyleSheet.create({
231
232
  gap: vs(8),
232
233
  },
233
234
  label: {
234
- fontSize: ms(15),
235
- fontWeight: '500',
235
+ fontFamily: 'Poppins-Medium',
236
+ fontSize: ms(13),
236
237
  },
237
238
  trigger: {
238
239
  flexDirection: 'row',
239
240
  alignItems: 'center',
240
241
  justifyContent: 'space-between',
241
- borderWidth: 1.5,
242
+ borderWidth: 1,
242
243
  borderRadius: ms(8),
243
- paddingHorizontal: s(16),
244
- paddingVertical: vs(14),
245
- shadowColor: '#000',
246
- shadowOffset: { width: 0, height: 1 },
247
- shadowOpacity: 0.04,
248
- shadowRadius: 2,
249
- elevation: 1,
244
+ paddingHorizontal: s(14),
245
+ paddingVertical: vs(11),
250
246
  },
251
247
  triggerText: {
252
- fontSize: ms(17),
248
+ fontFamily: 'Poppins-Regular',
249
+ fontSize: ms(15),
253
250
  flex: 1,
254
251
  },
255
252
  chevron: {
256
253
  marginLeft: s(8),
257
254
  },
258
255
  helperText: {
256
+ fontFamily: 'Poppins-Regular',
259
257
  fontSize: ms(13),
260
258
  },
261
259
  iosBackdrop: {
@@ -276,15 +274,15 @@ const styles = StyleSheet.create({
276
274
  borderBottomWidth: 1,
277
275
  },
278
276
  iosToolbarTitle: {
277
+ fontFamily: 'Poppins-SemiBold',
279
278
  fontSize: ms(17),
280
- fontWeight: '600',
281
279
  },
282
280
  iosDoneBtn: {
283
281
  padding: s(4),
284
282
  },
285
283
  iosDoneBtnText: {
284
+ fontFamily: 'Poppins-SemiBold',
286
285
  fontSize: ms(17),
287
- fontWeight: '600',
288
286
  },
289
287
  androidHiddenPicker: {
290
288
  height: 0,
@@ -292,10 +290,10 @@ const styles = StyleSheet.create({
292
290
  position: 'absolute',
293
291
  },
294
292
  webPicker: {
295
- borderWidth: 1.5,
293
+ borderWidth: 1,
296
294
  borderRadius: ms(8),
297
- paddingHorizontal: s(16),
298
- paddingVertical: vs(14),
299
- fontSize: ms(17),
295
+ paddingHorizontal: s(14),
296
+ paddingVertical: vs(11),
297
+ fontSize: ms(15),
300
298
  },
301
299
  })
@@ -106,10 +106,11 @@ const styles = StyleSheet.create({
106
106
  marginBottom: vs(16),
107
107
  },
108
108
  title: {
109
+ fontFamily: 'Poppins-SemiBold',
109
110
  fontSize: ms(18),
110
- fontWeight: '600',
111
111
  },
112
112
  description: {
113
+ fontFamily: 'Poppins-Regular',
113
114
  fontSize: ms(14),
114
115
  lineHeight: mvs(20),
115
116
  },
@@ -91,16 +91,16 @@ const styles = StyleSheet.create({
91
91
  alignItems: 'center',
92
92
  },
93
93
  label: {
94
+ fontFamily: 'Poppins-Medium',
94
95
  fontSize: ms(15),
95
- fontWeight: '500',
96
96
  },
97
97
  valueText: {
98
+ fontFamily: 'Poppins-Medium',
98
99
  fontSize: ms(14),
99
- fontWeight: '500',
100
100
  },
101
101
  slider: {
102
102
  width: '100%',
103
- height: vs(40),
103
+ height: vs(60),
104
104
  },
105
105
  disabled: {
106
106
  opacity: 0.45,
@@ -1,12 +1,14 @@
1
1
  import React from 'react'
2
- import { ActivityIndicator, ActivityIndicatorProps } from 'react-native'
2
+ import { ActivityIndicator, ActivityIndicatorProps, View, Text, StyleSheet } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
+ import { vs, ms, mvs } from '../../utils/scaling'
4
5
 
5
6
  export type SpinnerSize = 'sm' | 'md' | 'lg'
6
7
 
7
8
  export interface SpinnerProps extends Omit<ActivityIndicatorProps, 'size'> {
8
9
  size?: SpinnerSize
9
10
  color?: string
11
+ label?: string
10
12
  }
11
13
 
12
14
  const sizeMap: Record<SpinnerSize, 'small' | 'large'> = {
@@ -15,7 +17,39 @@ const sizeMap: Record<SpinnerSize, 'small' | 'large'> = {
15
17
  lg: 'large',
16
18
  }
17
19
 
18
- export function Spinner({ size = 'md', color, ...props }: SpinnerProps) {
20
+ const labelFontSize: Record<SpinnerSize, number> = {
21
+ sm: ms(11),
22
+ md: ms(13),
23
+ lg: ms(14),
24
+ }
25
+
26
+ export function Spinner({ size = 'md', color, label, ...props }: SpinnerProps) {
19
27
  const { colors } = useTheme()
28
+
29
+ if (label) {
30
+ return (
31
+ <View style={styles.wrapper}>
32
+ <ActivityIndicator size={sizeMap[size]} color={color ?? colors.primary} {...props} />
33
+ <Text
34
+ style={[styles.label, { color: colors.mutedForeground, fontSize: labelFontSize[size] }]}
35
+ allowFontScaling={true}
36
+ >
37
+ {label}
38
+ </Text>
39
+ </View>
40
+ )
41
+ }
42
+
20
43
  return <ActivityIndicator size={sizeMap[size]} color={color ?? colors.primary} {...props} />
21
44
  }
45
+
46
+ const styles = StyleSheet.create({
47
+ wrapper: {
48
+ alignItems: 'center',
49
+ gap: vs(6),
50
+ },
51
+ label: {
52
+ fontFamily: 'Poppins-Regular',
53
+ lineHeight: mvs(18),
54
+ },
55
+ })
@@ -6,10 +6,10 @@ import { selectionAsync as hapticSelection } from '../../utils/haptics'
6
6
  import { useTheme } from '../../theme'
7
7
  import { s, vs } from '../../utils/scaling'
8
8
 
9
- const TRACK_WIDTH = s(60)
10
- const TRACK_HEIGHT = vs(36)
11
- const THUMB_SIZE = s(28)
12
- const THUMB_OFFSET = s(4)
9
+ const TRACK_WIDTH = s(52)
10
+ const TRACK_HEIGHT = s(30)
11
+ const THUMB_SIZE = s(24)
12
+ const THUMB_OFFSET = s(3)
13
13
  const THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2
14
14
 
15
15
  export interface SwitchProps {