@retray-dev/ui-kit 1.6.0 → 1.8.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/COMPONENTS.md +264 -15
- package/README.md +7 -6
- package/dist/index.d.mts +114 -11
- package/dist/index.d.ts +114 -11
- package/dist/index.js +660 -134
- package/dist/index.mjs +656 -138
- package/package.json +8 -8
- package/src/components/Accordion/Accordion.tsx +4 -4
- package/src/components/Alert/Alert.tsx +32 -8
- package/src/components/Alert/index.ts +2 -2
- package/src/components/Avatar/Avatar.tsx +8 -8
- package/src/components/Badge/Badge.tsx +4 -4
- package/src/components/Button/Button.tsx +21 -14
- package/src/components/Card/Card.tsx +9 -9
- package/src/components/Checkbox/Checkbox.tsx +8 -8
- package/src/components/Chip/Chip.tsx +142 -0
- package/src/components/Chip/index.ts +2 -0
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +87 -0
- package/src/components/ConfirmDialog/index.ts +2 -0
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +48 -0
- package/src/components/CurrencyDisplay/index.ts +1 -0
- package/src/components/CurrencyInputLarge/CurrencyInputLarge.tsx +66 -0
- package/src/components/CurrencyInputLarge/index.ts +1 -0
- package/src/components/EmptyState/EmptyState.tsx +40 -6
- package/src/components/Input/Input.tsx +8 -8
- package/src/components/LabelValue/LabelValue.tsx +47 -0
- package/src/components/LabelValue/index.ts +2 -0
- package/src/components/ListItem/ListItem.tsx +121 -0
- package/src/components/ListItem/index.ts +2 -0
- package/src/components/MonthPicker/MonthPicker.tsx +92 -0
- package/src/components/MonthPicker/index.ts +2 -0
- package/src/components/Select/Select.tsx +19 -19
- package/src/components/Switch/Switch.tsx +12 -7
- package/src/components/Tabs/Tabs.tsx +34 -15
- package/src/components/Text/Text.tsx +6 -6
- package/src/components/Textarea/Textarea.tsx +9 -9
- package/src/components/Toast/Toast.tsx +25 -7
- package/src/components/Toggle/Toggle.tsx +93 -24
- package/src/index.ts +7 -0
|
@@ -10,12 +10,12 @@ export interface TextProps extends RNTextProps {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const variantStyles: Record<TextVariant, TextStyle> = {
|
|
13
|
-
h1: { fontSize:
|
|
14
|
-
h2: { fontSize:
|
|
15
|
-
h3: { fontSize:
|
|
16
|
-
body: { fontSize:
|
|
17
|
-
caption: { fontSize:
|
|
18
|
-
label: { fontSize:
|
|
13
|
+
h1: { fontSize: 40, fontWeight: '700', lineHeight: 52 },
|
|
14
|
+
h2: { fontSize: 28, fontWeight: '700', lineHeight: 36 },
|
|
15
|
+
h3: { fontSize: 22, fontWeight: '600', lineHeight: 30 },
|
|
16
|
+
body: { fontSize: 17, fontWeight: '400', lineHeight: 26 },
|
|
17
|
+
caption: { fontSize: 13, fontWeight: '400', lineHeight: 20 },
|
|
18
|
+
label: { fontSize: 15, fontWeight: '500', lineHeight: 22 },
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function Text({ variant = 'body', color, style, children, ...props }: TextProps) {
|
|
@@ -41,7 +41,7 @@ export function Textarea({
|
|
|
41
41
|
borderColor: error ? colors.destructive : focused ? colors.ring : colors.border,
|
|
42
42
|
color: colors.foreground,
|
|
43
43
|
backgroundColor: colors.background,
|
|
44
|
-
minHeight: rows *
|
|
44
|
+
minHeight: rows * 30,
|
|
45
45
|
},
|
|
46
46
|
style,
|
|
47
47
|
]}
|
|
@@ -69,21 +69,21 @@ export function Textarea({
|
|
|
69
69
|
|
|
70
70
|
const styles = StyleSheet.create({
|
|
71
71
|
container: {
|
|
72
|
-
gap:
|
|
72
|
+
gap: 6,
|
|
73
73
|
},
|
|
74
74
|
label: {
|
|
75
|
-
fontSize:
|
|
75
|
+
fontSize: 15,
|
|
76
76
|
fontWeight: '500',
|
|
77
|
-
marginBottom:
|
|
77
|
+
marginBottom: 6,
|
|
78
78
|
},
|
|
79
79
|
input: {
|
|
80
80
|
borderWidth: 1.5,
|
|
81
|
-
borderRadius:
|
|
82
|
-
paddingHorizontal:
|
|
83
|
-
paddingVertical:
|
|
84
|
-
fontSize:
|
|
81
|
+
borderRadius: 14,
|
|
82
|
+
paddingHorizontal: 20,
|
|
83
|
+
paddingVertical: 16,
|
|
84
|
+
fontSize: 17,
|
|
85
85
|
},
|
|
86
86
|
helperText: {
|
|
87
|
-
fontSize:
|
|
87
|
+
fontSize: 13,
|
|
88
88
|
},
|
|
89
89
|
})
|
|
@@ -20,6 +20,7 @@ export interface ToastItem {
|
|
|
20
20
|
title?: string
|
|
21
21
|
description?: string
|
|
22
22
|
variant?: ToastVariant
|
|
23
|
+
icon?: React.ReactNode
|
|
23
24
|
/** Auto-dismiss delay in milliseconds. Defaults to `3000`. */
|
|
24
25
|
duration?: number
|
|
25
26
|
}
|
|
@@ -97,15 +98,22 @@ function ToastNotification({ item, onDismiss }: { item: ToastItem; onDismiss: ()
|
|
|
97
98
|
success: colors.successForeground,
|
|
98
99
|
}[item.variant ?? 'default']
|
|
99
100
|
|
|
101
|
+
const leftIcon = item.icon ?? (
|
|
102
|
+
<Text style={[styles.defaultIcon, { color: textColor }]}>
|
|
103
|
+
{item.variant === 'success' ? '✓' : item.variant === 'destructive' ? '✖' : 'ℹ'}
|
|
104
|
+
</Text>
|
|
105
|
+
)
|
|
106
|
+
|
|
100
107
|
return (
|
|
101
108
|
<GestureDetector gesture={panGesture}>
|
|
102
109
|
<Animated.View style={[styles.toast, { backgroundColor: bgColor }, animatedStyle]}>
|
|
110
|
+
<View style={styles.leftIconContainer}>{leftIcon}</View>
|
|
103
111
|
<View style={styles.toastContent}>
|
|
104
112
|
{item.title ? (
|
|
105
113
|
<Text style={[styles.toastTitle, { color: textColor }]}>{item.title}</Text>
|
|
106
114
|
) : null}
|
|
107
115
|
{item.description ? (
|
|
108
|
-
<Text style={[styles.toastDescription, { color: textColor, opacity: 0.85 }]}>
|
|
116
|
+
<Text style={[styles.toastDescription, { color: textColor, opacity: 0.85 }]}>
|
|
109
117
|
{item.description}
|
|
110
118
|
</Text>
|
|
111
119
|
) : null}
|
|
@@ -170,9 +178,9 @@ const styles = StyleSheet.create({
|
|
|
170
178
|
toast: {
|
|
171
179
|
flexDirection: 'row',
|
|
172
180
|
alignItems: 'center',
|
|
173
|
-
borderRadius:
|
|
174
|
-
paddingHorizontal:
|
|
175
|
-
paddingVertical:
|
|
181
|
+
borderRadius: 16,
|
|
182
|
+
paddingHorizontal: 20,
|
|
183
|
+
paddingVertical: 14,
|
|
176
184
|
shadowColor: '#000',
|
|
177
185
|
shadowOffset: { width: 0, height: 4 },
|
|
178
186
|
shadowOpacity: 0.15,
|
|
@@ -183,18 +191,28 @@ const styles = StyleSheet.create({
|
|
|
183
191
|
flex: 1,
|
|
184
192
|
gap: 4,
|
|
185
193
|
},
|
|
194
|
+
leftIconContainer: {
|
|
195
|
+
width: 36,
|
|
196
|
+
alignItems: 'center',
|
|
197
|
+
justifyContent: 'center',
|
|
198
|
+
marginRight: 8,
|
|
199
|
+
},
|
|
200
|
+
defaultIcon: {
|
|
201
|
+
fontSize: 22,
|
|
202
|
+
fontWeight: '700',
|
|
203
|
+
},
|
|
186
204
|
toastTitle: {
|
|
187
|
-
fontSize:
|
|
205
|
+
fontSize: 15,
|
|
188
206
|
fontWeight: '600',
|
|
189
207
|
},
|
|
190
208
|
toastDescription: {
|
|
191
|
-
fontSize:
|
|
209
|
+
fontSize: 14,
|
|
192
210
|
},
|
|
193
211
|
dismissButton: {
|
|
194
212
|
padding: 12,
|
|
195
213
|
marginLeft: 4,
|
|
196
214
|
},
|
|
197
215
|
dismissIcon: {
|
|
198
|
-
fontSize:
|
|
216
|
+
fontSize: 14,
|
|
199
217
|
},
|
|
200
218
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useRef } from 'react'
|
|
2
|
-
import { TouchableOpacity, Animated, Text, StyleSheet, TouchableOpacityProps, ViewStyle } from 'react-native'
|
|
1
|
+
import React, { useRef, useEffect } from 'react'
|
|
2
|
+
import { TouchableOpacity, Animated, Text, StyleSheet, TouchableOpacityProps, ViewStyle, View, Easing } from 'react-native'
|
|
3
3
|
import * as Haptics from 'expo-haptics'
|
|
4
4
|
import { useTheme } from '../../theme'
|
|
5
5
|
|
|
@@ -12,7 +12,10 @@ export interface ToggleProps extends TouchableOpacityProps {
|
|
|
12
12
|
variant?: ToggleVariant
|
|
13
13
|
size?: ToggleSize
|
|
14
14
|
label?: string
|
|
15
|
-
|
|
15
|
+
/** Icon to show when not pressed */
|
|
16
|
+
icon?: React.ReactNode | ((pressed: boolean) => React.ReactNode)
|
|
17
|
+
/** Icon to show when pressed/active. If omitted, a default check mark is used. */
|
|
18
|
+
activeIcon?: React.ReactNode | ((pressed: boolean) => React.ReactNode)
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
const sizeStyles: Record<ToggleSize, ViewStyle> = {
|
|
@@ -28,12 +31,24 @@ export function Toggle({
|
|
|
28
31
|
size = 'md',
|
|
29
32
|
label,
|
|
30
33
|
icon,
|
|
34
|
+
activeIcon,
|
|
31
35
|
disabled,
|
|
32
36
|
style,
|
|
33
37
|
...props
|
|
34
38
|
}: ToggleProps) {
|
|
35
39
|
const { colors } = useTheme()
|
|
36
40
|
const scale = useRef(new Animated.Value(1)).current
|
|
41
|
+
// 0 = unpressed, 1 = pressed — used to interpolate colors (JS thread)
|
|
42
|
+
const pressAnim = useRef(new Animated.Value(pressed ? 1 : 0)).current
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
Animated.timing(pressAnim, {
|
|
46
|
+
toValue: pressed ? 1 : 0,
|
|
47
|
+
duration: 150,
|
|
48
|
+
easing: Easing.out(Easing.ease),
|
|
49
|
+
useNativeDriver: false,
|
|
50
|
+
}).start()
|
|
51
|
+
}, [pressed, pressAnim])
|
|
37
52
|
|
|
38
53
|
const handlePressIn = () => {
|
|
39
54
|
if (disabled) return
|
|
@@ -44,32 +59,70 @@ export function Toggle({
|
|
|
44
59
|
Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start()
|
|
45
60
|
}
|
|
46
61
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
// Keep borderWidth constant at 2 to prevent layout jumps when pressing.
|
|
63
|
+
// Animate borderColor and backgroundColor instead.
|
|
64
|
+
const borderColor = pressAnim.interpolate({
|
|
65
|
+
inputRange: [0, 1],
|
|
66
|
+
outputRange: [variant === 'outline' ? colors.border : 'transparent', colors.primary],
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const backgroundColor = pressAnim.interpolate({
|
|
70
|
+
inputRange: [0, 1],
|
|
71
|
+
outputRange: ['transparent', colors.accent],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const textColor = pressAnim.interpolate({
|
|
75
|
+
inputRange: [0, 1],
|
|
76
|
+
outputRange: [colors.foreground, colors.primary],
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const LeftIcon = () => {
|
|
80
|
+
const renderProp = (prop?: any) => {
|
|
81
|
+
if (!prop) return null
|
|
82
|
+
if (typeof prop === 'function') return prop(pressed)
|
|
83
|
+
return prop
|
|
84
|
+
}
|
|
52
85
|
|
|
53
|
-
|
|
86
|
+
if (!pressed) return renderProp(icon)
|
|
87
|
+
|
|
88
|
+
const active = renderProp(activeIcon)
|
|
89
|
+
if (active) return <>{active}</>
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View style={[styles.checkContainer, { borderColor: colors.primary }]}>
|
|
93
|
+
<Text style={[styles.checkMark, { color: colors.primary }]}>✓</Text>
|
|
94
|
+
</View>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
54
97
|
|
|
55
98
|
return (
|
|
56
99
|
<Animated.View style={{ transform: [{ scale }] }}>
|
|
57
|
-
<
|
|
58
|
-
style={[
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
disabled={disabled}
|
|
66
|
-
activeOpacity={1}
|
|
67
|
-
touchSoundDisabled={true}
|
|
68
|
-
{...props}
|
|
100
|
+
<Animated.View
|
|
101
|
+
style={[
|
|
102
|
+
styles.base,
|
|
103
|
+
sizeStyles[size],
|
|
104
|
+
{ borderColor, backgroundColor, borderWidth: 2 },
|
|
105
|
+
disabled && styles.disabled,
|
|
106
|
+
style,
|
|
107
|
+
]}
|
|
69
108
|
>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
109
|
+
<TouchableOpacity
|
|
110
|
+
style={styles.touchable}
|
|
111
|
+
onPress={() => {
|
|
112
|
+
Haptics.selectionAsync()
|
|
113
|
+
onPressedChange?.(!pressed)
|
|
114
|
+
}}
|
|
115
|
+
onPressIn={handlePressIn}
|
|
116
|
+
onPressOut={handlePressOut}
|
|
117
|
+
disabled={disabled}
|
|
118
|
+
activeOpacity={1}
|
|
119
|
+
touchSoundDisabled={true}
|
|
120
|
+
{...props}
|
|
121
|
+
>
|
|
122
|
+
<LeftIcon />
|
|
123
|
+
{label ? <Animated.Text style={[styles.label, { color: textColor }]}>{label}</Animated.Text> : null}
|
|
124
|
+
</TouchableOpacity>
|
|
125
|
+
</Animated.View>
|
|
73
126
|
</Animated.View>
|
|
74
127
|
)
|
|
75
128
|
}
|
|
@@ -77,10 +130,14 @@ export function Toggle({
|
|
|
77
130
|
const styles = StyleSheet.create({
|
|
78
131
|
base: {
|
|
79
132
|
borderRadius: 8,
|
|
133
|
+
overflow: 'hidden',
|
|
134
|
+
},
|
|
135
|
+
touchable: {
|
|
80
136
|
flexDirection: 'row',
|
|
81
137
|
alignItems: 'center',
|
|
82
138
|
justifyContent: 'center',
|
|
83
139
|
gap: 8,
|
|
140
|
+
flex: 1,
|
|
84
141
|
},
|
|
85
142
|
disabled: {
|
|
86
143
|
opacity: 0.45,
|
|
@@ -89,4 +146,16 @@ const styles = StyleSheet.create({
|
|
|
89
146
|
fontSize: 14,
|
|
90
147
|
fontWeight: '500',
|
|
91
148
|
},
|
|
149
|
+
checkContainer: {
|
|
150
|
+
width: 24,
|
|
151
|
+
height: 24,
|
|
152
|
+
borderRadius: 12,
|
|
153
|
+
borderWidth: 2,
|
|
154
|
+
alignItems: 'center',
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
},
|
|
157
|
+
checkMark: {
|
|
158
|
+
fontSize: 14,
|
|
159
|
+
fontWeight: '700',
|
|
160
|
+
},
|
|
92
161
|
})
|
package/src/index.ts
CHANGED
|
@@ -28,3 +28,10 @@ export * from './components/Sheet'
|
|
|
28
28
|
export * from './components/Select'
|
|
29
29
|
export * from './components/Toast'
|
|
30
30
|
export * from './components/CurrencyInput'
|
|
31
|
+
export * from './components/CurrencyDisplay'
|
|
32
|
+
export * from './components/CurrencyInputLarge'
|
|
33
|
+
export * from './components/ListItem'
|
|
34
|
+
export * from './components/Chip'
|
|
35
|
+
export * from './components/ConfirmDialog'
|
|
36
|
+
export * from './components/LabelValue'
|
|
37
|
+
export * from './components/MonthPicker'
|