@retray-dev/ui-kit 6.2.0 → 7.0.1
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 +444 -10
- package/EXAMPLES.md +248 -0
- package/README.md +11 -10
- package/dist/Accordion.d.mts +28 -0
- package/dist/Accordion.d.ts +28 -0
- package/dist/Accordion.js +340 -0
- package/dist/Accordion.mjs +6 -0
- package/dist/AlertBanner.d.mts +16 -0
- package/dist/AlertBanner.d.ts +16 -0
- package/dist/AlertBanner.js +247 -0
- package/dist/AlertBanner.mjs +5 -0
- package/dist/Avatar.d.mts +20 -0
- package/dist/Avatar.d.ts +20 -0
- package/dist/Avatar.js +234 -0
- package/dist/Avatar.mjs +3 -0
- package/dist/Badge.d.mts +26 -0
- package/dist/Badge.d.ts +26 -0
- package/dist/Badge.js +247 -0
- package/dist/Badge.mjs +4 -0
- package/dist/Button.d.mts +25 -0
- package/dist/Button.d.ts +25 -0
- package/dist/Button.js +414 -0
- package/dist/Button.mjs +8 -0
- package/dist/ButtonGroup.d.mts +26 -0
- package/dist/ButtonGroup.d.ts +26 -0
- package/dist/ButtonGroup.js +52 -0
- package/dist/ButtonGroup.mjs +2 -0
- package/dist/Card.d.mts +39 -0
- package/dist/Card.d.ts +39 -0
- package/dist/Card.js +329 -0
- package/dist/Card.mjs +7 -0
- package/dist/CategoryStrip.d.mts +26 -0
- package/dist/CategoryStrip.d.ts +26 -0
- package/dist/CategoryStrip.js +396 -0
- package/dist/CategoryStrip.mjs +9 -0
- package/dist/Checkbox.d.mts +14 -0
- package/dist/Checkbox.d.ts +14 -0
- package/dist/Checkbox.js +304 -0
- package/dist/Checkbox.mjs +7 -0
- package/dist/Chip.d.mts +31 -0
- package/dist/Chip.d.ts +31 -0
- package/dist/Chip.js +370 -0
- package/dist/Chip.mjs +8 -0
- package/dist/ConfirmDialog.d.mts +15 -0
- package/dist/ConfirmDialog.d.ts +15 -0
- package/dist/ConfirmDialog.js +530 -0
- package/dist/ConfirmDialog.mjs +9 -0
- package/dist/CurrencyDisplay.d.mts +24 -0
- package/dist/CurrencyDisplay.d.ts +24 -0
- package/dist/CurrencyDisplay.js +189 -0
- package/dist/CurrencyDisplay.mjs +3 -0
- package/dist/CurrencyInput.d.mts +26 -0
- package/dist/CurrencyInput.d.ts +26 -0
- package/dist/CurrencyInput.js +404 -0
- package/dist/CurrencyInput.mjs +7 -0
- package/dist/DetailRow.d.mts +32 -0
- package/dist/DetailRow.d.ts +32 -0
- package/dist/DetailRow.js +275 -0
- package/dist/DetailRow.mjs +4 -0
- package/dist/EmptyState.d.mts +27 -0
- package/dist/EmptyState.d.ts +27 -0
- package/dist/EmptyState.js +503 -0
- package/dist/EmptyState.mjs +9 -0
- package/dist/Form.d.mts +52 -0
- package/dist/Form.d.ts +52 -0
- package/dist/Form.js +204 -0
- package/dist/Form.mjs +3 -0
- package/dist/IconButton.d.mts +22 -0
- package/dist/IconButton.d.ts +22 -0
- package/dist/IconButton.js +383 -0
- package/dist/IconButton.mjs +7 -0
- package/dist/Input.d.mts +23 -0
- package/dist/Input.d.ts +23 -0
- package/dist/Input.js +351 -0
- package/dist/Input.mjs +6 -0
- package/dist/LabelValue.d.mts +16 -0
- package/dist/LabelValue.d.ts +16 -0
- package/dist/LabelValue.js +225 -0
- package/dist/LabelValue.mjs +4 -0
- package/dist/ListGroup.d.mts +34 -0
- package/dist/ListGroup.d.ts +34 -0
- package/dist/ListGroup.js +217 -0
- package/dist/ListGroup.mjs +4 -0
- package/dist/ListItem.d.mts +64 -0
- package/dist/ListItem.d.ts +64 -0
- package/dist/ListItem.js +430 -0
- package/dist/ListItem.mjs +8 -0
- package/dist/MediaCard.d.mts +39 -0
- package/dist/MediaCard.d.ts +39 -0
- package/dist/MediaCard.js +427 -0
- package/dist/MediaCard.mjs +8 -0
- package/dist/MenuGroup.d.mts +34 -0
- package/dist/MenuGroup.d.ts +34 -0
- package/dist/MenuGroup.js +217 -0
- package/dist/MenuGroup.mjs +4 -0
- package/dist/MenuItem.d.mts +48 -0
- package/dist/MenuItem.d.ts +48 -0
- package/dist/MenuItem.js +403 -0
- package/dist/MenuItem.mjs +8 -0
- package/dist/MonthPicker.d.mts +20 -0
- package/dist/MonthPicker.d.ts +20 -0
- package/dist/MonthPicker.js +234 -0
- package/dist/MonthPicker.mjs +4 -0
- package/dist/Pressable.d.mts +34 -0
- package/dist/Pressable.d.ts +34 -0
- package/dist/Pressable.js +132 -0
- package/dist/Pressable.mjs +4 -0
- package/dist/Progress.d.mts +14 -0
- package/dist/Progress.d.ts +14 -0
- package/dist/Progress.js +191 -0
- package/dist/Progress.mjs +4 -0
- package/dist/RadioGroup.d.mts +19 -0
- package/dist/RadioGroup.d.ts +19 -0
- package/dist/RadioGroup.js +341 -0
- package/dist/RadioGroup.mjs +7 -0
- package/dist/Select.d.mts +22 -0
- package/dist/Select.d.ts +22 -0
- package/dist/Select.js +441 -0
- package/dist/Select.mjs +6 -0
- package/dist/Separator.d.mts +10 -0
- package/dist/Separator.d.ts +10 -0
- package/dist/Separator.js +156 -0
- package/dist/Separator.mjs +2 -0
- package/dist/Sheet.d.mts +81 -0
- package/dist/Sheet.d.ts +81 -0
- package/dist/Sheet.js +340 -0
- package/dist/Sheet.mjs +4 -0
- package/dist/Skeleton.d.mts +17 -0
- package/dist/Skeleton.d.ts +17 -0
- package/dist/Skeleton.js +205 -0
- package/dist/Skeleton.mjs +4 -0
- package/dist/Slider.d.mts +20 -0
- package/dist/Slider.d.ts +20 -0
- package/dist/Slider.js +232 -0
- package/dist/Slider.mjs +4 -0
- package/dist/Spinner.d.mts +12 -0
- package/dist/Spinner.d.ts +12 -0
- package/dist/Spinner.js +172 -0
- package/dist/Spinner.mjs +3 -0
- package/dist/Switch.d.mts +13 -0
- package/dist/Switch.d.ts +13 -0
- package/dist/Switch.js +261 -0
- package/dist/Switch.mjs +5 -0
- package/dist/Tabs.d.mts +27 -0
- package/dist/Tabs.d.ts +27 -0
- package/dist/Tabs.js +389 -0
- package/dist/Tabs.mjs +6 -0
- package/dist/Text.d.mts +12 -0
- package/dist/Text.d.ts +12 -0
- package/dist/Text.js +311 -0
- package/dist/Text.mjs +4 -0
- package/dist/Textarea.d.mts +16 -0
- package/dist/Textarea.d.ts +16 -0
- package/dist/Textarea.js +333 -0
- package/dist/Textarea.mjs +6 -0
- package/dist/Toast.d.mts +47 -0
- package/dist/Toast.d.ts +47 -0
- package/dist/Toast.js +185 -0
- package/dist/Toast.mjs +3 -0
- package/dist/Toggle.d.mts +33 -0
- package/dist/Toggle.d.ts +33 -0
- package/dist/Toggle.js +397 -0
- package/dist/Toggle.mjs +8 -0
- package/dist/VirtualList.d.mts +19 -0
- package/dist/VirtualList.d.ts +19 -0
- package/dist/VirtualList.js +38 -0
- package/dist/VirtualList.mjs +1 -0
- package/dist/chunk-2CE3TQVY.mjs +11 -0
- package/dist/chunk-2UYENBLV.mjs +49 -0
- package/dist/chunk-3BBOZ3OQ.mjs +41 -0
- package/dist/chunk-5IKW3VNC.mjs +43 -0
- package/dist/chunk-63357L2X.mjs +51 -0
- package/dist/chunk-6LQYY7HC.mjs +127 -0
- package/dist/chunk-6Q64UFIA.mjs +71 -0
- package/dist/chunk-76PFOSM2.mjs +41 -0
- package/dist/chunk-7H2OR44A.mjs +14 -0
- package/dist/chunk-A4MDAP7G.mjs +42 -0
- package/dist/chunk-AU2VDY4P.mjs +190 -0
- package/dist/chunk-BRKYVJVV.mjs +60 -0
- package/dist/chunk-CRYBX2CM.mjs +146 -0
- package/dist/chunk-DITNP6PL.mjs +106 -0
- package/dist/chunk-FTLJOUOQ.mjs +97 -0
- package/dist/chunk-GCWOGZYL.mjs +104 -0
- package/dist/chunk-GNGLDL6Z.mjs +60 -0
- package/dist/chunk-GPOUINK5.mjs +148 -0
- package/dist/chunk-HSPSMN6U.mjs +115 -0
- package/dist/chunk-IRRY3CRZ.mjs +82 -0
- package/dist/chunk-JB67UOB5.mjs +92 -0
- package/dist/chunk-JBLL7U3U.mjs +64 -0
- package/dist/chunk-KWCPOM6W.mjs +136 -0
- package/dist/chunk-KZJRQOIU.mjs +64 -0
- package/dist/chunk-L7E7TVEZ.mjs +145 -0
- package/dist/chunk-LG4DO3DK.mjs +174 -0
- package/dist/chunk-LWG526VX.mjs +139 -0
- package/dist/chunk-MN7OG7IY.mjs +96 -0
- package/dist/chunk-MX6HRKMI.mjs +29 -0
- package/dist/chunk-NC5ZTR2Y.mjs +32 -0
- package/dist/chunk-NQGVLMWG.mjs +90 -0
- package/dist/chunk-QCNARS3X.mjs +46 -0
- package/dist/chunk-QXGYKWI7.mjs +134 -0
- package/dist/chunk-QY3X2UYR.mjs +191 -0
- package/dist/chunk-RKLHUDZS.mjs +92 -0
- package/dist/chunk-RMMK64W5.mjs +54 -0
- package/dist/chunk-RR2VQLKE.mjs +190 -0
- package/dist/chunk-RTC3CFXF.mjs +29 -0
- package/dist/chunk-SBZYEV4S.mjs +61 -0
- package/dist/chunk-SOA2Z4RB.mjs +82 -0
- package/dist/chunk-SOYNZDVY.mjs +151 -0
- package/dist/chunk-T7XZ7H7Y.mjs +57 -0
- package/dist/chunk-TAJ2PQ2O.mjs +163 -0
- package/dist/chunk-U4N7WF4Z.mjs +108 -0
- package/dist/chunk-URDE3EUU.mjs +132 -0
- package/dist/chunk-URLL5JBR.mjs +245 -0
- package/dist/chunk-XDMN67KV.mjs +59 -0
- package/dist/chunk-Y6MXOREN.mjs +120 -0
- package/dist/chunk-YZJAFS4P.mjs +131 -0
- package/dist/index.d.mts +94 -873
- package/dist/index.d.ts +94 -873
- package/dist/index.js +751 -357
- package/dist/index.mjs +50 -3895
- package/package.json +23 -14
- package/src/assets/fonts/Sohne-Bold.otf +0 -0
- package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Italic.otf +0 -0
- package/src/assets/fonts/Sohne-Light.otf +0 -0
- package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Medium.otf +0 -0
- package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Regular.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Bold.otf +0 -0
- package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Italic.otf +0 -0
- package/src/assets/fonts/SohneMono-Light.otf +0 -0
- package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Medium.otf +0 -0
- package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Regular.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
- package/src/components/Accordion/Accordion.tsx +3 -3
- package/src/components/AlertBanner/AlertBanner.tsx +33 -12
- package/src/components/Avatar/Avatar.tsx +4 -2
- package/src/components/Badge/Badge.tsx +4 -2
- package/src/components/Button/Button.tsx +10 -11
- package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
- package/src/components/Card/Card.tsx +17 -34
- package/src/components/CategoryStrip/CategoryStrip.tsx +24 -21
- package/src/components/Checkbox/Checkbox.tsx +11 -6
- package/src/components/Chip/Chip.tsx +17 -15
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
- package/src/components/CurrencyInput/CurrencyInput.tsx +2 -2
- package/src/components/DetailRow/DetailRow.tsx +9 -7
- package/src/components/EmptyState/EmptyState.tsx +2 -2
- package/src/components/Form/Form.tsx +149 -0
- package/src/components/Form/index.ts +1 -0
- package/src/components/IconButton/IconButton.tsx +4 -2
- package/src/components/Input/Input.tsx +27 -31
- package/src/components/LabelValue/LabelValue.tsx +6 -4
- package/src/components/ListGroup/ListGroup.tsx +145 -0
- package/src/components/ListGroup/index.ts +1 -0
- package/src/components/ListItem/ListItem.tsx +9 -10
- package/src/components/MediaCard/MediaCard.tsx +7 -5
- package/src/components/MenuGroup/MenuGroup.tsx +145 -0
- package/src/components/MenuGroup/index.ts +1 -0
- package/src/components/MenuItem/MenuItem.tsx +7 -9
- package/src/components/MonthPicker/MonthPicker.tsx +2 -2
- package/src/components/RadioGroup/RadioGroup.tsx +11 -14
- package/src/components/Select/Select.tsx +6 -6
- package/src/components/Separator/Separator.tsx +1 -3
- package/src/components/Sheet/Sheet.tsx +81 -17
- package/src/components/Skeleton/Skeleton.tsx +1 -1
- package/src/components/Slider/Slider.tsx +2 -2
- package/src/components/Spinner/Spinner.tsx +1 -1
- package/src/components/Switch/Switch.tsx +28 -5
- package/src/components/Tabs/Tabs.tsx +22 -18
- package/src/components/Text/Text.tsx +3 -1
- package/src/components/Textarea/Textarea.tsx +18 -14
- package/src/components/Toast/Toast.tsx +6 -6
- package/src/components/Toggle/Toggle.tsx +47 -23
- package/src/components/VirtualList/VirtualList.tsx +60 -0
- package/src/components/VirtualList/index.ts +1 -0
- package/src/fonts.ts +38 -20
- package/src/index.ts +5 -1
- package/src/theme/colors.ts +53 -39
- package/src/theme/types.ts +3 -0
- package/src/tokens.ts +49 -39
- package/src/utils/icons.ts +47 -20
- package/src/utils/usePressScale.ts +2 -0
- package/src/assets/fonts/Poppins-Black.ttf +0 -0
- package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Bold.ttf +0 -0
- package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Italic.ttf +0 -0
- package/src/assets/fonts/Poppins-Light.ttf +0 -0
- package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Medium.ttf +0 -0
- package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Regular.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Thin.ttf +0 -0
- package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
|
@@ -46,8 +46,11 @@ export function Checkbox({
|
|
|
46
46
|
}))
|
|
47
47
|
|
|
48
48
|
return (
|
|
49
|
+
// AUDIT FIX: opacity was applied only to the box, leaving the label at full
|
|
50
|
+
// opacity when disabled — a contradictory visual signal. Now the entire row
|
|
51
|
+
// dims uniformly so label and control communicate the same disabled state.
|
|
49
52
|
<TouchableOpacity
|
|
50
|
-
style={[styles.row, style]}
|
|
53
|
+
style={[styles.row, disabled && styles.rowDisabled, style]}
|
|
51
54
|
onPress={() => {
|
|
52
55
|
hapticSelection()
|
|
53
56
|
onCheckedChange?.(!checked)
|
|
@@ -62,9 +65,7 @@ export function Checkbox({
|
|
|
62
65
|
accessibilityState={{ checked, disabled: !!disabled }}
|
|
63
66
|
>
|
|
64
67
|
<Animated.View style={scaleStyle}>
|
|
65
|
-
<Animated.View
|
|
66
|
-
style={[styles.box, { opacity: disabled ? 0.45 : 1 }, boxStyle]}
|
|
67
|
-
>
|
|
68
|
+
<Animated.View style={[styles.box, boxStyle]}>
|
|
68
69
|
<Animated.View style={checkStyle}>
|
|
69
70
|
<View style={[styles.checkmark, { borderColor: colors.primaryForeground }]} />
|
|
70
71
|
</Animated.View>
|
|
@@ -72,7 +73,7 @@ export function Checkbox({
|
|
|
72
73
|
</Animated.View>
|
|
73
74
|
{label ? (
|
|
74
75
|
<Text
|
|
75
|
-
style={[styles.label, { color:
|
|
76
|
+
style={[styles.label, { color: colors.foreground }]}
|
|
76
77
|
allowFontScaling={true}
|
|
77
78
|
>
|
|
78
79
|
{label}
|
|
@@ -88,6 +89,10 @@ const styles = StyleSheet.create({
|
|
|
88
89
|
alignItems: 'center',
|
|
89
90
|
gap: s(12),
|
|
90
91
|
},
|
|
92
|
+
// AUDIT FIX: was inline opacity on the box only
|
|
93
|
+
rowDisabled: {
|
|
94
|
+
opacity: 0.45,
|
|
95
|
+
},
|
|
91
96
|
box: {
|
|
92
97
|
width: s(24),
|
|
93
98
|
height: s(24),
|
|
@@ -104,7 +109,7 @@ const styles = StyleSheet.create({
|
|
|
104
109
|
transform: [{ rotate: '-45deg' }, { translateY: -1 }],
|
|
105
110
|
},
|
|
106
111
|
label: {
|
|
107
|
-
fontFamily: '
|
|
112
|
+
fontFamily: 'Sohne-Regular',
|
|
108
113
|
fontSize: ms(14),
|
|
109
114
|
lineHeight: mvs(20),
|
|
110
115
|
},
|
|
@@ -16,9 +16,7 @@ export interface ChipProps {
|
|
|
16
16
|
label: string
|
|
17
17
|
selected?: boolean
|
|
18
18
|
onPress?: () => void
|
|
19
|
-
/** JSX icon rendered before the label. */
|
|
20
19
|
icon?: React.ReactNode
|
|
21
|
-
/** Icon name from @expo/vector-icons resolved automatically. */
|
|
22
20
|
iconName?: string
|
|
23
21
|
style?: ViewStyle
|
|
24
22
|
accessibilityLabel?: string
|
|
@@ -27,9 +25,7 @@ export interface ChipProps {
|
|
|
27
25
|
export interface ChipOption {
|
|
28
26
|
label: string
|
|
29
27
|
value: string | number
|
|
30
|
-
/** Icon name resolved via renderIcon (Feather, AntDesign, etc.). */
|
|
31
28
|
iconName?: string
|
|
32
|
-
/** Icon tint color override. */
|
|
33
29
|
iconColor?: string
|
|
34
30
|
disabled?: boolean
|
|
35
31
|
}
|
|
@@ -38,12 +34,11 @@ export interface ChipGroupProps {
|
|
|
38
34
|
options: ChipOption[]
|
|
39
35
|
value?: string | number | (string | number)[]
|
|
40
36
|
onValueChange?: (value: string | number | (string | number)[]) => void
|
|
41
|
-
/** When true, allows selecting multiple chips. `value` and `onValueChange` will use arrays. */
|
|
42
37
|
multiSelect?: boolean
|
|
43
38
|
style?: ViewStyle
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
function ChipBase({ label, selected = false, onPress, icon, iconName, style, accessibilityLabel }: ChipProps) {
|
|
47
42
|
const { colors } = useTheme()
|
|
48
43
|
const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
49
44
|
pressScale: PRESS_SCALE.chip,
|
|
@@ -91,27 +86,24 @@ export function Chip({ label, selected = false, onPress, icon, iconName, style,
|
|
|
91
86
|
)
|
|
92
87
|
}
|
|
93
88
|
|
|
89
|
+
export const Chip = React.memo(ChipBase)
|
|
90
|
+
|
|
94
91
|
export function ChipGroup({ options, value, onValueChange, multiSelect = false, style }: ChipGroupProps) {
|
|
95
92
|
const handlePress = (optionValue: string | number) => {
|
|
96
93
|
if (!multiSelect) {
|
|
97
94
|
onValueChange?.(optionValue)
|
|
98
95
|
return
|
|
99
96
|
}
|
|
100
|
-
|
|
101
97
|
const currentArray = Array.isArray(value) ? value : value ? [value] : []
|
|
102
98
|
const isSelected = currentArray.includes(optionValue)
|
|
103
|
-
|
|
104
99
|
const newArray: (string | number)[] = isSelected
|
|
105
100
|
? currentArray.filter((v) => v !== optionValue)
|
|
106
101
|
: [...currentArray, optionValue]
|
|
107
|
-
|
|
108
102
|
onValueChange?.(newArray)
|
|
109
103
|
}
|
|
110
104
|
|
|
111
105
|
const isSelected = (optionValue: string | number): boolean => {
|
|
112
|
-
if (Array.isArray(value))
|
|
113
|
-
return value.includes(optionValue)
|
|
114
|
-
}
|
|
106
|
+
if (Array.isArray(value)) return value.includes(optionValue)
|
|
115
107
|
return optionValue === value
|
|
116
108
|
}
|
|
117
109
|
|
|
@@ -124,7 +116,11 @@ export function ChipGroup({ options, value, onValueChange, multiSelect = false,
|
|
|
124
116
|
selected={isSelected(opt.value)}
|
|
125
117
|
onPress={opt.disabled ? undefined : () => handlePress(opt.value)}
|
|
126
118
|
iconName={opt.iconName}
|
|
127
|
-
style={
|
|
119
|
+
// AUDIT FIX: was style={{ opacity: 0.4 }} with no accessibilityState.
|
|
120
|
+
// Now passes disabled state to the Chip's TouchableOpacity via onPress=undefined
|
|
121
|
+
// and adds explicit accessibility state for screen readers.
|
|
122
|
+
style={opt.disabled ? styles.chipDisabled : undefined}
|
|
123
|
+
accessibilityLabel={opt.disabled ? `${opt.label}, unavailable` : opt.label}
|
|
128
124
|
/>
|
|
129
125
|
))}
|
|
130
126
|
</View>
|
|
@@ -136,19 +132,25 @@ const styles = StyleSheet.create({
|
|
|
136
132
|
chip: {
|
|
137
133
|
borderRadius: 999,
|
|
138
134
|
paddingHorizontal: s(14),
|
|
139
|
-
|
|
135
|
+
// AUDIT FIX: was vs(5) → ~28px total height — below WCAG 44px tap target.
|
|
136
|
+
// vs(10) → ~44px total height meets WCAG 2.5.5 (AAA) minimum.
|
|
137
|
+
paddingVertical: vs(10),
|
|
138
|
+
minHeight: 44,
|
|
140
139
|
borderWidth: 1,
|
|
141
140
|
alignItems: 'center',
|
|
142
141
|
justifyContent: 'center',
|
|
143
142
|
flexDirection: 'row',
|
|
144
143
|
gap: s(5),
|
|
145
144
|
},
|
|
145
|
+
chipDisabled: {
|
|
146
|
+
opacity: 0.4,
|
|
147
|
+
},
|
|
146
148
|
chipIcon: {
|
|
147
149
|
alignItems: 'center',
|
|
148
150
|
justifyContent: 'center',
|
|
149
151
|
},
|
|
150
152
|
label: {
|
|
151
|
-
fontFamily: '
|
|
153
|
+
fontFamily: 'Sohne-Medium',
|
|
152
154
|
fontSize: ms(13),
|
|
153
155
|
lineHeight: mvs(18),
|
|
154
156
|
},
|
|
@@ -120,12 +120,12 @@ const styles = StyleSheet.create({
|
|
|
120
120
|
gap: vs(12),
|
|
121
121
|
},
|
|
122
122
|
title: {
|
|
123
|
-
fontFamily: '
|
|
123
|
+
fontFamily: 'Sohne-SemiBold',
|
|
124
124
|
fontSize: ms(18),
|
|
125
125
|
lineHeight: mvs(26),
|
|
126
126
|
},
|
|
127
127
|
description: {
|
|
128
|
-
fontFamily: '
|
|
128
|
+
fontFamily: 'Sohne-Regular',
|
|
129
129
|
fontSize: ms(15),
|
|
130
130
|
lineHeight: mvs(22),
|
|
131
131
|
},
|
|
@@ -49,7 +49,7 @@ function formatValue(value: number | string, prefix: string, showDecimals: boole
|
|
|
49
49
|
return `${sign}${prefix}${intPart}`
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
function CurrencyDisplayBase({ value, prefix = '$', showDecimals = false, textColor, variant, autoScale, maxFontSize, style }: CurrencyDisplayProps) {
|
|
53
53
|
const { colors } = useTheme()
|
|
54
54
|
const formatted = formatValue(value, prefix, showDecimals)
|
|
55
55
|
const baseFontSize = variant ? variantFontSize[variant] : ms(56)
|
|
@@ -71,12 +71,14 @@ export function CurrencyDisplay({ value, prefix = '$', showDecimals = false, tex
|
|
|
71
71
|
)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
export const CurrencyDisplay = React.memo(CurrencyDisplayBase)
|
|
75
|
+
|
|
74
76
|
const styles = StyleSheet.create({
|
|
75
77
|
container: {
|
|
76
78
|
alignSelf: 'flex-start',
|
|
77
79
|
},
|
|
78
80
|
amount: {
|
|
79
|
-
fontFamily: '
|
|
81
|
+
fontFamily: 'Sohne-Bold',
|
|
80
82
|
includeFontPadding: false,
|
|
81
83
|
textAlignVertical: 'top',
|
|
82
84
|
},
|
|
@@ -59,8 +59,8 @@ export function CurrencyInput({
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const inputStyle: TextStyle = size === 'large'
|
|
62
|
-
? { fontFamily: '
|
|
63
|
-
: { fontFamily: '
|
|
62
|
+
? { fontFamily: 'Sohne-Regular', fontSize: ms(36) }
|
|
63
|
+
: { fontFamily: 'Sohne-Regular' }
|
|
64
64
|
|
|
65
65
|
const dollarIcon = renderIcon('dollar-sign', size === 'large' ? 24 : 16, colors.foregroundMuted)
|
|
66
66
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native'
|
|
3
3
|
import { useTheme } from '../../theme'
|
|
4
|
-
import { s,
|
|
4
|
+
import { s, ms, mvs } from '../../utils/scaling'
|
|
5
5
|
import { renderIcon } from '../../utils/icons'
|
|
6
6
|
|
|
7
7
|
export type DetailRowSeparator = 'dotted' | 'solid' | 'dashed' | 'none'
|
|
8
8
|
export type DetailRowLabelWeight = 'normal' | 'medium' | 'semibold' | 'bold'
|
|
9
9
|
|
|
10
10
|
const weightMap: Record<DetailRowLabelWeight, string> = {
|
|
11
|
-
normal: '
|
|
12
|
-
medium: '
|
|
13
|
-
semibold: '
|
|
14
|
-
bold: '
|
|
11
|
+
normal: 'Sohne-Regular',
|
|
12
|
+
medium: 'Sohne-Medium',
|
|
13
|
+
semibold: 'Sohne-SemiBold',
|
|
14
|
+
bold: 'Sohne-Bold',
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface DetailRowProps {
|
|
@@ -38,7 +38,7 @@ export interface DetailRowProps {
|
|
|
38
38
|
valueStyle?: TextStyle
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
function DetailRowBase({
|
|
42
42
|
label,
|
|
43
43
|
value,
|
|
44
44
|
separator = 'dotted',
|
|
@@ -108,6 +108,8 @@ export function DetailRow({
|
|
|
108
108
|
)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
export const DetailRow = React.memo(DetailRowBase)
|
|
112
|
+
|
|
111
113
|
const styles = StyleSheet.create({
|
|
112
114
|
row: {
|
|
113
115
|
flexDirection: 'row',
|
|
@@ -138,7 +140,7 @@ const styles = StyleSheet.create({
|
|
|
138
140
|
flexShrink: 0,
|
|
139
141
|
},
|
|
140
142
|
valueText: {
|
|
141
|
-
fontFamily: '
|
|
143
|
+
fontFamily: 'Sohne-SemiBold',
|
|
142
144
|
fontSize: ms(13),
|
|
143
145
|
lineHeight: mvs(18),
|
|
144
146
|
},
|
|
@@ -109,7 +109,7 @@ const styles = StyleSheet.create({
|
|
|
109
109
|
marginTop: vs(16),
|
|
110
110
|
},
|
|
111
111
|
title: {
|
|
112
|
-
fontFamily: '
|
|
112
|
+
fontFamily: 'Sohne-Medium',
|
|
113
113
|
fontSize: ms(18),
|
|
114
114
|
textAlign: 'center',
|
|
115
115
|
},
|
|
@@ -118,7 +118,7 @@ const styles = StyleSheet.create({
|
|
|
118
118
|
marginTop: vs(10),
|
|
119
119
|
},
|
|
120
120
|
description: {
|
|
121
|
-
fontFamily: '
|
|
121
|
+
fontFamily: 'Sohne-Regular',
|
|
122
122
|
fontSize: ms(14),
|
|
123
123
|
lineHeight: mvs(20),
|
|
124
124
|
textAlign: 'center',
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native'
|
|
3
|
+
import { useTheme } from '../../theme'
|
|
4
|
+
import { s, vs } from '../../utils/scaling'
|
|
5
|
+
|
|
6
|
+
export interface FormProps {
|
|
7
|
+
children: React.ReactNode
|
|
8
|
+
style?: ViewStyle
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FormFieldProps {
|
|
12
|
+
children: React.ReactNode
|
|
13
|
+
label?: string
|
|
14
|
+
error?: string
|
|
15
|
+
required?: boolean
|
|
16
|
+
style?: ViewStyle
|
|
17
|
+
labelStyle?: TextStyle
|
|
18
|
+
errorStyle?: TextStyle
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface FormSectionProps {
|
|
22
|
+
children: React.ReactNode
|
|
23
|
+
title?: string
|
|
24
|
+
description?: string
|
|
25
|
+
style?: ViewStyle
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FormFooterProps {
|
|
29
|
+
children: React.ReactNode
|
|
30
|
+
style?: ViewStyle
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Form wrapper with consistent spacing between fields.
|
|
35
|
+
* Use Form.Field for individual inputs with label + error,
|
|
36
|
+
* Form.Section for grouped fields, and Form.Footer for action buttons.
|
|
37
|
+
*/
|
|
38
|
+
export function Form({ children, style }: FormProps) {
|
|
39
|
+
return <View style={[styles.form, style]}>{children}</View>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Wraps a single form input with optional label and error message.
|
|
44
|
+
* Automatically spaces children properly.
|
|
45
|
+
*/
|
|
46
|
+
export function FormField({
|
|
47
|
+
children,
|
|
48
|
+
label,
|
|
49
|
+
error,
|
|
50
|
+
required,
|
|
51
|
+
style,
|
|
52
|
+
labelStyle,
|
|
53
|
+
errorStyle,
|
|
54
|
+
}: FormFieldProps) {
|
|
55
|
+
const { colors } = useTheme()
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View style={[styles.field, style]}>
|
|
59
|
+
{label ? (
|
|
60
|
+
<Text style={[styles.label, { color: colors.foreground }, labelStyle]} allowFontScaling={true}>
|
|
61
|
+
{label}
|
|
62
|
+
{required ? <Text style={{ color: colors.destructive }}> *</Text> : null}
|
|
63
|
+
</Text>
|
|
64
|
+
) : null}
|
|
65
|
+
{children}
|
|
66
|
+
{error ? (
|
|
67
|
+
<Text style={[styles.error, { color: colors.destructive }, errorStyle]} allowFontScaling={true}>
|
|
68
|
+
{error}
|
|
69
|
+
</Text>
|
|
70
|
+
) : null}
|
|
71
|
+
</View>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Groups related form fields with optional title and description.
|
|
77
|
+
*/
|
|
78
|
+
export function FormSection({ children, title, description, style }: FormSectionProps) {
|
|
79
|
+
const { colors } = useTheme()
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<View style={[styles.section, style]}>
|
|
83
|
+
{title ? (
|
|
84
|
+
<View style={styles.sectionHeader}>
|
|
85
|
+
<Text style={[styles.sectionTitle, { color: colors.foreground }]} allowFontScaling={true}>
|
|
86
|
+
{title}
|
|
87
|
+
</Text>
|
|
88
|
+
{description ? (
|
|
89
|
+
<Text style={[styles.sectionDescription, { color: colors.foregroundMuted }]} allowFontScaling={true}>
|
|
90
|
+
{description}
|
|
91
|
+
</Text>
|
|
92
|
+
) : null}
|
|
93
|
+
</View>
|
|
94
|
+
) : null}
|
|
95
|
+
{children}
|
|
96
|
+
</View>
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Footer area for submit/cancel buttons or form actions.
|
|
102
|
+
*/
|
|
103
|
+
export function FormFooter({ children, style }: FormFooterProps) {
|
|
104
|
+
return <View style={[styles.footer, style]}>{children}</View>
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Form.Field = FormField
|
|
108
|
+
Form.Section = FormSection
|
|
109
|
+
Form.Footer = FormFooter
|
|
110
|
+
|
|
111
|
+
const styles = StyleSheet.create({
|
|
112
|
+
form: {
|
|
113
|
+
gap: vs(16),
|
|
114
|
+
},
|
|
115
|
+
field: {
|
|
116
|
+
gap: vs(6),
|
|
117
|
+
},
|
|
118
|
+
label: {
|
|
119
|
+
fontFamily: 'Sohne-Medium',
|
|
120
|
+
fontSize: 14,
|
|
121
|
+
lineHeight: 20,
|
|
122
|
+
},
|
|
123
|
+
error: {
|
|
124
|
+
fontFamily: 'Sohne-Regular',
|
|
125
|
+
fontSize: 12,
|
|
126
|
+
lineHeight: 16,
|
|
127
|
+
},
|
|
128
|
+
section: {
|
|
129
|
+
gap: vs(16),
|
|
130
|
+
},
|
|
131
|
+
sectionHeader: {
|
|
132
|
+
gap: vs(4),
|
|
133
|
+
},
|
|
134
|
+
sectionTitle: {
|
|
135
|
+
fontFamily: 'Sohne-SemiBold',
|
|
136
|
+
fontSize: 16,
|
|
137
|
+
lineHeight: 24,
|
|
138
|
+
},
|
|
139
|
+
sectionDescription: {
|
|
140
|
+
fontFamily: 'Sohne-Regular',
|
|
141
|
+
fontSize: 14,
|
|
142
|
+
lineHeight: 20,
|
|
143
|
+
},
|
|
144
|
+
footer: {
|
|
145
|
+
flexDirection: 'row',
|
|
146
|
+
gap: s(12),
|
|
147
|
+
paddingTop: vs(8),
|
|
148
|
+
},
|
|
149
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Form'
|
|
@@ -44,7 +44,7 @@ const sizeMap: Record<IconButtonSize, { container: number; icon: number }> = {
|
|
|
44
44
|
lg: { container: s(52), icon: 24 },
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
function IconButtonBase({
|
|
48
48
|
iconName,
|
|
49
49
|
icon,
|
|
50
50
|
iconColor,
|
|
@@ -151,6 +151,8 @@ export function IconButton({
|
|
|
151
151
|
)
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
export const IconButton = React.memo(IconButtonBase)
|
|
155
|
+
|
|
154
156
|
const styles = StyleSheet.create({
|
|
155
157
|
wrapper: {
|
|
156
158
|
alignSelf: 'flex-start',
|
|
@@ -182,7 +184,7 @@ const styles = StyleSheet.create({
|
|
|
182
184
|
paddingHorizontal: 3,
|
|
183
185
|
},
|
|
184
186
|
badgeText: {
|
|
185
|
-
fontFamily: '
|
|
187
|
+
fontFamily: 'Sohne-Bold',
|
|
186
188
|
fontSize: ms(9),
|
|
187
189
|
lineHeight: 14,
|
|
188
190
|
},
|
|
@@ -3,6 +3,7 @@ import { TextInput, View, Text, StyleSheet, TextInputProps, ViewStyle, TextStyle
|
|
|
3
3
|
import Animated, {
|
|
4
4
|
useAnimatedStyle,
|
|
5
5
|
interpolateColor,
|
|
6
|
+
interpolate,
|
|
6
7
|
} from 'react-native-reanimated'
|
|
7
8
|
import { AntDesign } from '@expo/vector-icons'
|
|
8
9
|
import { useTheme } from '../../theme'
|
|
@@ -11,46 +12,26 @@ import { renderIcon } from '../../utils/icons'
|
|
|
11
12
|
import { useColorTransition } from '../../utils/useColorTransition'
|
|
12
13
|
import { TIMINGS } from '../../utils/animations'
|
|
13
14
|
|
|
14
|
-
const webInputResetStyle:
|
|
15
|
+
const webInputResetStyle: Record<string, unknown> =
|
|
15
16
|
Platform.OS === 'web'
|
|
16
17
|
? { outlineStyle: 'none', outlineWidth: 0, outlineColor: 'transparent', boxShadow: 'none' }
|
|
17
18
|
: {}
|
|
18
19
|
|
|
19
20
|
export interface InputProps extends TextInputProps {
|
|
20
21
|
label?: string
|
|
21
|
-
/** Red helper text below the input; also changes border to `destructive` color. Takes priority over `hint`. */
|
|
22
22
|
error?: string
|
|
23
|
-
/** Helper text shown below the input when there is no error. */
|
|
24
23
|
hint?: string
|
|
25
|
-
/** Disabled visual state — dimmed appearance, not editable. Also sets `editable={false}`. */
|
|
26
24
|
disabled?: boolean
|
|
27
|
-
/** Text or component rendered before the input text. */
|
|
28
25
|
prefix?: React.ReactNode
|
|
29
|
-
/** Text or component rendered after the input text. */
|
|
30
26
|
suffix?: React.ReactNode
|
|
31
|
-
/** Style applied to prefix text if prefix is a string. */
|
|
32
27
|
prefixStyle?: TextStyle
|
|
33
|
-
/** Style applied to suffix text if suffix is a string. */
|
|
34
28
|
suffixStyle?: TextStyle
|
|
35
|
-
/**
|
|
36
|
-
* Icon name from `@expo/vector-icons` rendered before the input text.
|
|
37
|
-
* See https://icons.expo.fyi. Takes precedence over `prefix`.
|
|
38
|
-
*/
|
|
39
29
|
prefixIcon?: string
|
|
40
|
-
/**
|
|
41
|
-
* Icon name from `@expo/vector-icons` rendered after the input text.
|
|
42
|
-
* See https://icons.expo.fyi. Takes precedence over `suffix` (unless `type="password"`).
|
|
43
|
-
*/
|
|
44
30
|
suffixIcon?: string
|
|
45
|
-
/** Override the resolved prefix icon color. Defaults to `mutedForeground`. */
|
|
46
31
|
prefixIconColor?: string
|
|
47
|
-
/** Override the resolved suffix icon color. Defaults to `mutedForeground`. */
|
|
48
32
|
suffixIconColor?: string
|
|
49
|
-
/** Input type. When set to \`'password'\`, shows a toggle button to reveal/hide text. */
|
|
50
33
|
type?: 'text' | 'password'
|
|
51
|
-
/** Style for the outer container \`View\`. Use \`style\` (from \`TextInputProps\`) to style the \`TextInput\` itself. */
|
|
52
34
|
containerStyle?: ViewStyle
|
|
53
|
-
/** Style for the inner border wrapper (overrides padding, etc). */
|
|
54
35
|
inputWrapperStyle?: ViewStyle
|
|
55
36
|
}
|
|
56
37
|
|
|
@@ -59,7 +40,6 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
59
40
|
const [focused, setFocused] = useState(false)
|
|
60
41
|
const [showPassword, setShowPassword] = useState(false)
|
|
61
42
|
|
|
62
|
-
// Asymmetric durations — focus snaps in, blurs out subtly. Runs on UI thread.
|
|
63
43
|
const focusProgress = useColorTransition(focused, {
|
|
64
44
|
duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration,
|
|
65
45
|
})
|
|
@@ -75,6 +55,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
75
55
|
const effectiveSuffix: React.ReactNode = isPassword && !suffix && !suffixIcon ? (
|
|
76
56
|
<TouchableOpacity
|
|
77
57
|
onPress={() => setShowPassword(!showPassword)}
|
|
58
|
+
// AUDIT FIX: was padding: s(4) → ~28px target (below 44px minimum).
|
|
59
|
+
// padding: s(12) with negative margin keeps visual size but expands hit area.
|
|
78
60
|
style={styles.passwordToggle}
|
|
79
61
|
activeOpacity={0.6}
|
|
80
62
|
accessibilityRole="button"
|
|
@@ -86,10 +68,16 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
86
68
|
? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted)
|
|
87
69
|
: suffix
|
|
88
70
|
|
|
89
|
-
|
|
71
|
+
// Border drawn on an absolute overlay so the 1px→2px weight change never
|
|
72
|
+
// resizes the layout box (which would reflow content / shift the interface).
|
|
73
|
+
// Wrapper keeps borderWidth: 0; overlay grows inward and is non-interactive.
|
|
74
|
+
const borderAnimStyle = useAnimatedStyle(() => ({
|
|
90
75
|
borderColor: error
|
|
91
76
|
? colors.destructive
|
|
92
77
|
: interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
|
|
78
|
+
borderWidth: error
|
|
79
|
+
? 2
|
|
80
|
+
: interpolate(focusProgress.value, [0, 1], [1, 2]),
|
|
93
81
|
}))
|
|
94
82
|
|
|
95
83
|
return (
|
|
@@ -99,10 +87,10 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
99
87
|
style={[
|
|
100
88
|
styles.inputWrapper,
|
|
101
89
|
{ backgroundColor: isDisabled ? colors.surface : colors.background },
|
|
102
|
-
borderColorStyle,
|
|
103
90
|
inputWrapperStyle,
|
|
104
91
|
]}
|
|
105
92
|
>
|
|
93
|
+
<Animated.View style={[styles.borderOverlay, borderAnimStyle]} pointerEvents="none" />
|
|
106
94
|
{effectivePrefix ? (
|
|
107
95
|
typeof effectivePrefix === 'string' ? (
|
|
108
96
|
<Text style={[styles.prefixText, { color: colors.foregroundMuted }, prefixStyle]} allowFontScaling={true}>
|
|
@@ -168,20 +156,25 @@ const styles = StyleSheet.create({
|
|
|
168
156
|
opacity: 0.6,
|
|
169
157
|
},
|
|
170
158
|
label: {
|
|
171
|
-
fontFamily: '
|
|
159
|
+
fontFamily: 'Sohne-Medium',
|
|
172
160
|
fontSize: ms(14),
|
|
173
161
|
},
|
|
174
162
|
inputWrapper: {
|
|
175
163
|
flexDirection: 'row',
|
|
176
164
|
alignItems: 'center',
|
|
177
|
-
|
|
165
|
+
// Border lives on borderOverlay (absolute) so its 1px→2px focus change
|
|
166
|
+
// never resizes this box. Wrapper itself carries no border.
|
|
178
167
|
borderRadius: 8,
|
|
179
168
|
paddingHorizontal: s(14),
|
|
180
169
|
paddingVertical: vs(11),
|
|
181
170
|
minHeight: 48,
|
|
182
171
|
},
|
|
172
|
+
borderOverlay: {
|
|
173
|
+
...StyleSheet.absoluteFillObject,
|
|
174
|
+
borderRadius: 8,
|
|
175
|
+
},
|
|
183
176
|
input: {
|
|
184
|
-
fontFamily: '
|
|
177
|
+
fontFamily: 'Sohne-Regular',
|
|
185
178
|
flex: 1,
|
|
186
179
|
fontSize: ms(16),
|
|
187
180
|
paddingVertical: vs(2),
|
|
@@ -191,7 +184,7 @@ const styles = StyleSheet.create({
|
|
|
191
184
|
marginRight: s(8),
|
|
192
185
|
},
|
|
193
186
|
prefixText: {
|
|
194
|
-
fontFamily: '
|
|
187
|
+
fontFamily: 'Sohne-Regular',
|
|
195
188
|
fontSize: ms(15),
|
|
196
189
|
marginRight: s(8),
|
|
197
190
|
},
|
|
@@ -199,15 +192,18 @@ const styles = StyleSheet.create({
|
|
|
199
192
|
marginLeft: s(8),
|
|
200
193
|
},
|
|
201
194
|
suffixText: {
|
|
202
|
-
fontFamily: '
|
|
195
|
+
fontFamily: 'Sohne-Regular',
|
|
203
196
|
fontSize: ms(15),
|
|
204
197
|
marginLeft: s(8),
|
|
205
198
|
},
|
|
199
|
+
// AUDIT FIX: was padding: s(4) → ~28px tap target. Now 12px padding → ~44px.
|
|
200
|
+
// Negative margin compensates so the visual icon position is unchanged.
|
|
206
201
|
passwordToggle: {
|
|
207
|
-
padding: s(
|
|
202
|
+
padding: s(12),
|
|
203
|
+
margin: -s(8),
|
|
208
204
|
},
|
|
209
205
|
helperText: {
|
|
210
|
-
fontFamily: '
|
|
206
|
+
fontFamily: 'Sohne-Regular',
|
|
211
207
|
fontSize: ms(13),
|
|
212
208
|
},
|
|
213
209
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
3
|
import { useTheme } from '../../theme'
|
|
4
|
-
import { s,
|
|
4
|
+
import { s, ms, mvs } from '../../utils/scaling'
|
|
5
5
|
import { renderIcon } from '../../utils/icons'
|
|
6
6
|
|
|
7
7
|
export interface LabelValueProps {
|
|
@@ -14,7 +14,7 @@ export interface LabelValueProps {
|
|
|
14
14
|
style?: ViewStyle
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
function LabelValueBase({ label, value, iconName, iconColor, style }: LabelValueProps) {
|
|
18
18
|
const { colors } = useTheme()
|
|
19
19
|
|
|
20
20
|
const resolvedIcon = iconName
|
|
@@ -40,6 +40,8 @@ export function LabelValue({ label, value, iconName, iconColor, style }: LabelVa
|
|
|
40
40
|
)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export const LabelValue = React.memo(LabelValueBase)
|
|
44
|
+
|
|
43
45
|
const styles = StyleSheet.create({
|
|
44
46
|
container: {
|
|
45
47
|
flexDirection: 'row',
|
|
@@ -57,12 +59,12 @@ const styles = StyleSheet.create({
|
|
|
57
59
|
justifyContent: 'center',
|
|
58
60
|
},
|
|
59
61
|
label: {
|
|
60
|
-
fontFamily: '
|
|
62
|
+
fontFamily: 'Sohne-Regular',
|
|
61
63
|
fontSize: ms(13),
|
|
62
64
|
lineHeight: mvs(18),
|
|
63
65
|
},
|
|
64
66
|
value: {
|
|
65
|
-
fontFamily: '
|
|
67
|
+
fontFamily: 'Sohne-Medium',
|
|
66
68
|
fontSize: ms(14),
|
|
67
69
|
lineHeight: mvs(20),
|
|
68
70
|
textAlign: 'right',
|