@retray-dev/ui-kit 5.2.0 → 5.4.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.
@@ -2,6 +2,7 @@ import React, { useState } from 'react'
2
2
  import { TextInput, View, Text, StyleSheet, TextInputProps, ViewStyle, Platform } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
4
  import { s, vs, ms } from '../../utils/scaling'
5
+ import { renderIcon } from '../../utils/icons'
5
6
 
6
7
  const webInputResetStyle: any =
7
8
  Platform.OS === 'web'
@@ -16,6 +17,12 @@ export interface TextareaProps extends TextInputProps {
16
17
  hint?: string
17
18
  /** Number of visible text rows. Defaults to `4`. Controls `numberOfLines` and `minHeight`. */
18
19
  rows?: number
20
+ /** Icon name from @expo/vector-icons rendered inside top-left corner. */
21
+ prefixIcon?: string
22
+ /** Custom icon node rendered top-left. */
23
+ prefixIconNode?: React.ReactNode
24
+ /** Override prefix icon color. Defaults to foregroundMuted. */
25
+ prefixIconColor?: string
19
26
  /** Style for the outer container `View`. Use `style` (from `TextInputProps`) to style the `TextInput` itself. */
20
27
  containerStyle?: ViewStyle
21
28
  }
@@ -25,6 +32,9 @@ export function Textarea({
25
32
  error,
26
33
  hint,
27
34
  rows = 4,
35
+ prefixIcon,
36
+ prefixIconNode,
37
+ prefixIconColor,
28
38
  containerStyle,
29
39
  style,
30
40
  onFocus,
@@ -34,40 +44,53 @@ export function Textarea({
34
44
  const { colors } = useTheme()
35
45
  const [focused, setFocused] = useState(false)
36
46
 
47
+ const resolvedPrefixIcon = prefixIcon
48
+ ? renderIcon(prefixIcon, ms(16), prefixIconColor ?? colors.foregroundMuted)
49
+ : prefixIconNode
50
+
37
51
  return (
38
52
  <View style={[styles.container, containerStyle]}>
39
53
  {label ? <Text style={[styles.label, { color: colors.foreground }]} allowFontScaling={true}>{label}</Text> : null}
40
- <TextInput
41
- multiline
42
- numberOfLines={rows}
43
- textAlignVertical="top"
54
+ <View
44
55
  style={[
45
- styles.input,
56
+ styles.inputWrapper,
46
57
  {
47
58
  borderColor: error
48
59
  ? colors.destructive
49
60
  : focused
50
61
  ? (colors.ring ?? colors.primary)
51
62
  : colors.border,
52
- color: colors.foreground,
53
63
  backgroundColor: colors.background,
54
- minHeight: rows * vs(30),
55
64
  },
56
- webInputResetStyle,
57
- style,
58
65
  ]}
59
- onFocus={(e) => {
60
- setFocused(true)
61
- onFocus?.(e)
62
- }}
63
- onBlur={(e) => {
64
- setFocused(false)
65
- onBlur?.(e)
66
- }}
67
- placeholderTextColor={colors.foregroundMuted}
68
- allowFontScaling={true}
69
- {...props}
70
- />
66
+ >
67
+ {resolvedPrefixIcon ? <View style={styles.prefixIcon}>{resolvedPrefixIcon}</View> : null}
68
+ <TextInput
69
+ multiline
70
+ numberOfLines={rows}
71
+ textAlignVertical="top"
72
+ style={[
73
+ styles.input,
74
+ {
75
+ color: colors.foreground,
76
+ minHeight: rows * vs(30),
77
+ },
78
+ webInputResetStyle,
79
+ style,
80
+ ]}
81
+ onFocus={(e) => {
82
+ setFocused(true)
83
+ onFocus?.(e)
84
+ }}
85
+ onBlur={(e) => {
86
+ setFocused(false)
87
+ onBlur?.(e)
88
+ }}
89
+ placeholderTextColor={colors.foregroundMuted}
90
+ allowFontScaling={true}
91
+ {...props}
92
+ />
93
+ </View>
71
94
  {error ? (
72
95
  <Text style={[styles.helperText, { color: colors.destructive }]} allowFontScaling={true}>{error}</Text>
73
96
  ) : null}
@@ -80,23 +103,37 @@ export function Textarea({
80
103
 
81
104
  const styles = StyleSheet.create({
82
105
  container: {
83
- gap: vs(8),
106
+ gap: vs(4),
84
107
  },
85
108
  label: {
86
109
  fontFamily: 'Poppins-Medium',
87
110
  fontSize: ms(13),
111
+ lineHeight: vs(18),
112
+ marginBottom: vs(2),
88
113
  },
89
- input: {
90
- fontFamily: 'Poppins-Regular',
91
- borderWidth: 2,
92
- borderRadius: ms(8),
114
+ inputWrapper: {
115
+ borderWidth: 1,
116
+ borderRadius: 8,
93
117
  paddingHorizontal: s(14),
94
118
  paddingVertical: vs(11),
95
- fontSize: ms(15),
96
- includeFontPadding: false,
119
+ gap: s(8),
120
+ },
121
+ prefixIcon: {
122
+ alignItems: 'flex-start',
123
+ justifyContent: 'flex-start',
124
+ paddingTop: vs(2),
125
+ },
126
+ input: {
127
+ fontFamily: 'Poppins-Regular',
128
+ fontSize: ms(14),
129
+ lineHeight: vs(22),
130
+ padding: 0,
131
+ margin: 0,
97
132
  },
98
133
  helperText: {
99
134
  fontFamily: 'Poppins-Regular',
100
- fontSize: ms(13),
135
+ fontSize: ms(12),
136
+ lineHeight: vs(16),
137
+ marginTop: vs(4),
101
138
  },
102
139
  })
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export { defaultLight, defaultDark, deriveColors } from './theme'
5
5
 
6
6
  // Components
7
7
  export * from './components/Button'
8
+ export * from './components/ButtonGroup'
8
9
  export * from './components/IconButton'
9
10
  export * from './components/Text'
10
11
  export * from './components/Input'
@@ -40,9 +41,13 @@ export * from './components/MonthPicker'
40
41
  export * from './components/MediaCard'
41
42
  export * from './components/CategoryStrip'
42
43
  export * from './components/Pressable'
44
+ export * from './components/DetailRow'
43
45
 
44
46
  // Icon utility
45
47
  export { Icon, renderIcon } from './utils/icons'
48
+
49
+ // Typography utilities
50
+ export { getResponsiveFontSize } from './utils/typography'
46
51
  export type { IconProps, IconFamily } from './utils/icons'
47
52
 
48
53
  // Design tokens
package/src/tokens.ts CHANGED
@@ -180,7 +180,7 @@ export const TYPOGRAPHY = {
180
180
  fontFamily: 'Poppins-Medium',
181
181
  fontSize: 16,
182
182
  fontWeight: '500' as const,
183
- lineHeight: 20,
183
+ lineHeight: 22,
184
184
  letterSpacing: 0,
185
185
  },
186
186
  'button-sm': {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Returns a font size that steps down as formatted text grows longer.
3
+ * Designed for currency/numeric displays where long values overflow.
4
+ *
5
+ * @param text - The formatted string (e.g. "$1.250.000")
6
+ * @param maxSize - Base (maximum) font size in points
7
+ * @param steps - Custom step config [{ maxLen, subtract }] — sorted ascending by maxLen
8
+ */
9
+ export function getResponsiveFontSize(
10
+ text: string,
11
+ maxSize: number,
12
+ steps: { maxLen: number; subtract: number }[] = [
13
+ { maxLen: 10, subtract: 0 },
14
+ { maxLen: 12, subtract: 4 },
15
+ { maxLen: 14, subtract: 6 },
16
+ ],
17
+ ): number {
18
+ const len = text.length
19
+ const sorted = [...steps].sort((a, b) => a.maxLen - b.maxLen)
20
+ for (const step of sorted) {
21
+ if (len <= step.maxLen) return maxSize - step.subtract
22
+ }
23
+ return maxSize - 8
24
+ }