@pagopa/io-app-design-system 7.0.2 → 7.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 (182) hide show
  1. package/lib/commonjs/components/alert/Alert.js +6 -5
  2. package/lib/commonjs/components/alert/Alert.js.map +1 -1
  3. package/lib/commonjs/components/banner/Banner.js +7 -6
  4. package/lib/commonjs/components/banner/Banner.js.map +1 -1
  5. package/lib/commonjs/components/buttons/IOButton/IOButton.js +10 -8
  6. package/lib/commonjs/components/buttons/IOButton/IOButton.js.map +1 -1
  7. package/lib/commonjs/components/layout/ContentWrapper.js +5 -4
  8. package/lib/commonjs/components/layout/ContentWrapper.js.map +1 -1
  9. package/lib/commonjs/components/otpInput/OTPInput.js +6 -4
  10. package/lib/commonjs/components/otpInput/OTPInput.js.map +1 -1
  11. package/lib/commonjs/components/searchInput/SearchInput.js +8 -6
  12. package/lib/commonjs/components/searchInput/SearchInput.js.map +1 -1
  13. package/lib/commonjs/components/tabs/TabItem.js +6 -4
  14. package/lib/commonjs/components/tabs/TabItem.js.map +1 -1
  15. package/lib/commonjs/components/textInput/TextInputValidation.js +5 -3
  16. package/lib/commonjs/components/textInput/TextInputValidation.js.map +1 -1
  17. package/lib/commonjs/components/typography/Body.js +8 -5
  18. package/lib/commonjs/components/typography/Body.js.map +1 -1
  19. package/lib/commonjs/components/typography/BodyMonospace.js +4 -5
  20. package/lib/commonjs/components/typography/BodyMonospace.js.map +1 -1
  21. package/lib/commonjs/components/typography/BodySmall.js +8 -5
  22. package/lib/commonjs/components/typography/BodySmall.js.map +1 -1
  23. package/lib/commonjs/components/typography/ButtonText.js +4 -5
  24. package/lib/commonjs/components/typography/ButtonText.js.map +1 -1
  25. package/lib/commonjs/components/typography/Caption.js +4 -5
  26. package/lib/commonjs/components/typography/Caption.js.map +1 -1
  27. package/lib/commonjs/components/typography/H1.js +4 -5
  28. package/lib/commonjs/components/typography/H1.js.map +1 -1
  29. package/lib/commonjs/components/typography/H2.js +4 -5
  30. package/lib/commonjs/components/typography/H2.js.map +1 -1
  31. package/lib/commonjs/components/typography/H3.js +4 -5
  32. package/lib/commonjs/components/typography/H3.js.map +1 -1
  33. package/lib/commonjs/components/typography/H4.js +4 -5
  34. package/lib/commonjs/components/typography/H4.js.map +1 -1
  35. package/lib/commonjs/components/typography/H5.js +4 -5
  36. package/lib/commonjs/components/typography/H5.js.map +1 -1
  37. package/lib/commonjs/components/typography/H6.js +4 -5
  38. package/lib/commonjs/components/typography/H6.js.map +1 -1
  39. package/lib/commonjs/components/typography/Hero.js +4 -5
  40. package/lib/commonjs/components/typography/Hero.js.map +1 -1
  41. package/lib/commonjs/components/typography/IOText.js +16 -14
  42. package/lib/commonjs/components/typography/IOText.js.map +1 -1
  43. package/lib/commonjs/components/typography/LabelMini.js +8 -5
  44. package/lib/commonjs/components/typography/LabelMini.js.map +1 -1
  45. package/lib/commonjs/components/typography/markdown/MdH1.js +4 -5
  46. package/lib/commonjs/components/typography/markdown/MdH1.js.map +1 -1
  47. package/lib/commonjs/components/typography/markdown/MdH2.js +4 -5
  48. package/lib/commonjs/components/typography/markdown/MdH2.js.map +1 -1
  49. package/lib/commonjs/components/typography/markdown/MdH3.js +4 -5
  50. package/lib/commonjs/components/typography/markdown/MdH3.js.map +1 -1
  51. package/lib/commonjs/context/IOThemeContextProvider.js +3 -4
  52. package/lib/commonjs/context/IOThemeContextProvider.js.map +1 -1
  53. package/lib/module/components/alert/Alert.js +5 -5
  54. package/lib/module/components/alert/Alert.js.map +1 -1
  55. package/lib/module/components/banner/Banner.js +6 -6
  56. package/lib/module/components/banner/Banner.js.map +1 -1
  57. package/lib/module/components/buttons/IOButton/IOButton.js +10 -9
  58. package/lib/module/components/buttons/IOButton/IOButton.js.map +1 -1
  59. package/lib/module/components/layout/ContentWrapper.js +4 -4
  60. package/lib/module/components/layout/ContentWrapper.js.map +1 -1
  61. package/lib/module/components/otpInput/OTPInput.js +6 -5
  62. package/lib/module/components/otpInput/OTPInput.js.map +1 -1
  63. package/lib/module/components/searchInput/SearchInput.js +8 -7
  64. package/lib/module/components/searchInput/SearchInput.js.map +1 -1
  65. package/lib/module/components/tabs/TabItem.js +6 -5
  66. package/lib/module/components/tabs/TabItem.js.map +1 -1
  67. package/lib/module/components/textInput/TextInputValidation.js +5 -4
  68. package/lib/module/components/textInput/TextInputValidation.js.map +1 -1
  69. package/lib/module/components/typography/Body.js +7 -5
  70. package/lib/module/components/typography/Body.js.map +1 -1
  71. package/lib/module/components/typography/BodyMonospace.js +3 -5
  72. package/lib/module/components/typography/BodyMonospace.js.map +1 -1
  73. package/lib/module/components/typography/BodySmall.js +7 -5
  74. package/lib/module/components/typography/BodySmall.js.map +1 -1
  75. package/lib/module/components/typography/ButtonText.js +3 -5
  76. package/lib/module/components/typography/ButtonText.js.map +1 -1
  77. package/lib/module/components/typography/Caption.js +3 -5
  78. package/lib/module/components/typography/Caption.js.map +1 -1
  79. package/lib/module/components/typography/H1.js +3 -5
  80. package/lib/module/components/typography/H1.js.map +1 -1
  81. package/lib/module/components/typography/H2.js +3 -5
  82. package/lib/module/components/typography/H2.js.map +1 -1
  83. package/lib/module/components/typography/H3.js +3 -5
  84. package/lib/module/components/typography/H3.js.map +1 -1
  85. package/lib/module/components/typography/H4.js +3 -5
  86. package/lib/module/components/typography/H4.js.map +1 -1
  87. package/lib/module/components/typography/H5.js +3 -5
  88. package/lib/module/components/typography/H5.js.map +1 -1
  89. package/lib/module/components/typography/H6.js +3 -5
  90. package/lib/module/components/typography/H6.js.map +1 -1
  91. package/lib/module/components/typography/Hero.js +3 -5
  92. package/lib/module/components/typography/Hero.js.map +1 -1
  93. package/lib/module/components/typography/IOText.js +16 -15
  94. package/lib/module/components/typography/IOText.js.map +1 -1
  95. package/lib/module/components/typography/LabelMini.js +7 -5
  96. package/lib/module/components/typography/LabelMini.js.map +1 -1
  97. package/lib/module/components/typography/markdown/MdH1.js +3 -5
  98. package/lib/module/components/typography/markdown/MdH1.js.map +1 -1
  99. package/lib/module/components/typography/markdown/MdH2.js +3 -5
  100. package/lib/module/components/typography/markdown/MdH2.js.map +1 -1
  101. package/lib/module/components/typography/markdown/MdH3.js +3 -5
  102. package/lib/module/components/typography/markdown/MdH3.js.map +1 -1
  103. package/lib/module/context/IOThemeContextProvider.js +3 -4
  104. package/lib/module/context/IOThemeContextProvider.js.map +1 -1
  105. package/lib/typescript/components/alert/Alert.d.ts +3 -1
  106. package/lib/typescript/components/alert/Alert.d.ts.map +1 -1
  107. package/lib/typescript/components/banner/Banner.d.ts +3 -1
  108. package/lib/typescript/components/banner/Banner.d.ts.map +1 -1
  109. package/lib/typescript/components/buttons/IOButton/IOButton.d.ts +3 -2
  110. package/lib/typescript/components/buttons/IOButton/IOButton.d.ts.map +1 -1
  111. package/lib/typescript/components/layout/ContentWrapper.d.ts +10 -6
  112. package/lib/typescript/components/layout/ContentWrapper.d.ts.map +1 -1
  113. package/lib/typescript/components/otpInput/OTPInput.d.ts +3 -1
  114. package/lib/typescript/components/otpInput/OTPInput.d.ts.map +1 -1
  115. package/lib/typescript/components/searchInput/SearchInput.d.ts +3 -1
  116. package/lib/typescript/components/searchInput/SearchInput.d.ts.map +1 -1
  117. package/lib/typescript/components/tabs/TabItem.d.ts +3 -11
  118. package/lib/typescript/components/tabs/TabItem.d.ts.map +1 -1
  119. package/lib/typescript/components/textInput/TextInputValidation.d.ts +7 -24
  120. package/lib/typescript/components/textInput/TextInputValidation.d.ts.map +1 -1
  121. package/lib/typescript/components/typography/Body.d.ts +4 -2
  122. package/lib/typescript/components/typography/Body.d.ts.map +1 -1
  123. package/lib/typescript/components/typography/BodyMonospace.d.ts +2 -8
  124. package/lib/typescript/components/typography/BodyMonospace.d.ts.map +1 -1
  125. package/lib/typescript/components/typography/BodySmall.d.ts +4 -2
  126. package/lib/typescript/components/typography/BodySmall.d.ts.map +1 -1
  127. package/lib/typescript/components/typography/ButtonText.d.ts +2 -8
  128. package/lib/typescript/components/typography/ButtonText.d.ts.map +1 -1
  129. package/lib/typescript/components/typography/Caption.d.ts +2 -8
  130. package/lib/typescript/components/typography/Caption.d.ts.map +1 -1
  131. package/lib/typescript/components/typography/H1.d.ts +2 -8
  132. package/lib/typescript/components/typography/H1.d.ts.map +1 -1
  133. package/lib/typescript/components/typography/H2.d.ts +6 -10
  134. package/lib/typescript/components/typography/H2.d.ts.map +1 -1
  135. package/lib/typescript/components/typography/H3.d.ts +2 -8
  136. package/lib/typescript/components/typography/H3.d.ts.map +1 -1
  137. package/lib/typescript/components/typography/H4.d.ts +2 -8
  138. package/lib/typescript/components/typography/H4.d.ts.map +1 -1
  139. package/lib/typescript/components/typography/H5.d.ts +2 -8
  140. package/lib/typescript/components/typography/H5.d.ts.map +1 -1
  141. package/lib/typescript/components/typography/H6.d.ts +2 -8
  142. package/lib/typescript/components/typography/H6.d.ts.map +1 -1
  143. package/lib/typescript/components/typography/Hero.d.ts +2 -8
  144. package/lib/typescript/components/typography/Hero.d.ts.map +1 -1
  145. package/lib/typescript/components/typography/IOText.d.ts +5 -5
  146. package/lib/typescript/components/typography/IOText.d.ts.map +1 -1
  147. package/lib/typescript/components/typography/LabelMini.d.ts +4 -2
  148. package/lib/typescript/components/typography/LabelMini.d.ts.map +1 -1
  149. package/lib/typescript/components/typography/markdown/MdH1.d.ts +2 -8
  150. package/lib/typescript/components/typography/markdown/MdH1.d.ts.map +1 -1
  151. package/lib/typescript/components/typography/markdown/MdH2.d.ts +2 -8
  152. package/lib/typescript/components/typography/markdown/MdH2.d.ts.map +1 -1
  153. package/lib/typescript/components/typography/markdown/MdH3.d.ts +2 -8
  154. package/lib/typescript/components/typography/markdown/MdH3.d.ts.map +1 -1
  155. package/lib/typescript/context/IOThemeContextProvider.d.ts.map +1 -1
  156. package/package.json +6 -7
  157. package/src/components/alert/Alert.tsx +108 -112
  158. package/src/components/banner/Banner.tsx +121 -125
  159. package/src/components/buttons/IOButton/IOButton.tsx +204 -216
  160. package/src/components/layout/ContentWrapper.tsx +21 -24
  161. package/src/components/otpInput/OTPInput.tsx +156 -167
  162. package/src/components/searchInput/SearchInput.tsx +208 -217
  163. package/src/components/tabs/TabItem.tsx +143 -146
  164. package/src/components/textInput/TextInputValidation.tsx +116 -122
  165. package/src/components/typography/Body.tsx +51 -52
  166. package/src/components/typography/BodyMonospace.tsx +19 -24
  167. package/src/components/typography/BodySmall.tsx +51 -52
  168. package/src/components/typography/ButtonText.tsx +14 -20
  169. package/src/components/typography/Caption.tsx +18 -23
  170. package/src/components/typography/H1.tsx +12 -20
  171. package/src/components/typography/H2.tsx +16 -23
  172. package/src/components/typography/H3.tsx +12 -20
  173. package/src/components/typography/H4.tsx +12 -20
  174. package/src/components/typography/H5.tsx +16 -24
  175. package/src/components/typography/H6.tsx +13 -21
  176. package/src/components/typography/Hero.tsx +14 -19
  177. package/src/components/typography/IOText.tsx +54 -59
  178. package/src/components/typography/LabelMini.tsx +45 -49
  179. package/src/components/typography/markdown/MdH1.tsx +14 -19
  180. package/src/components/typography/markdown/MdH2.tsx +14 -19
  181. package/src/components/typography/markdown/MdH3.tsx +14 -19
  182. package/src/context/IOThemeContextProvider.tsx +4 -12
@@ -1,4 +1,4 @@
1
- import { Ref, forwardRef, useCallback, useMemo } from "react";
1
+ import { Ref, useCallback, useMemo } from "react";
2
2
  import {
3
3
  GestureResponderEvent,
4
4
  Pressable,
@@ -25,6 +25,7 @@ type ColorMode = "light" | "dark";
25
25
  type TabItemState = "default" | "selected" | "disabled";
26
26
 
27
27
  export type TabItem = WithTestID<{
28
+ ref?: Ref<View>;
28
29
  label: string;
29
30
  color?: ColorMode;
30
31
  selected?: boolean;
@@ -57,155 +58,151 @@ type ColorStates = {
57
58
 
58
59
  const DISABLED_OPACITY = 0.5;
59
60
 
60
- const TabItem = forwardRef(
61
- (
62
- {
63
- label,
64
- color = "light",
65
- selected = false,
66
- accessibilityLabel,
67
- accessibilityHint,
68
- testID,
69
- onPress,
70
- disabled = false,
71
- icon,
72
- iconSelected
73
- }: TabItem,
74
- ref: Ref<View>
75
- ) => {
76
- const { onPressIn, onPressOut, scaleAnimatedStyle } =
77
- useScaleAnimation("medium");
78
- const theme = useIOTheme();
79
- const reducedMotion = useReducedMotion();
80
-
81
- const mapColorStates: Record<
82
- NonNullable<TabItem["color"]>,
83
- ColorStates
84
- > = useMemo(
85
- () => ({
86
- light: {
87
- border: {
88
- default: IOColors[theme["tab-item-border-default"]],
89
- selected: hexToRgba(
90
- IOColors[theme["tab-item-foreground-selected"]],
91
- 0.5
92
- )
93
- },
94
- background: {
95
- default: hexToRgba(
96
- IOColors[theme["tab-item-background-selected"]],
97
- 0
98
- ),
99
- selected: hexToRgba(
100
- IOColors[theme["tab-item-background-selected"]],
101
- 0.25
102
- ),
103
- pressed: IOColors[theme["appBackground-primary"]]
104
- },
105
- foreground: {
106
- default: theme["tab-item-foreground-default"],
107
- selected: theme["tab-item-foreground-selected"],
108
- disabled: "grey-700"
109
- }
61
+ const TabItem = ({
62
+ label,
63
+ color = "light",
64
+ selected = false,
65
+ accessibilityLabel,
66
+ accessibilityHint,
67
+ testID,
68
+ onPress,
69
+ disabled = false,
70
+ icon,
71
+ iconSelected,
72
+ ref
73
+ }: TabItem) => {
74
+ const { onPressIn, onPressOut, scaleAnimatedStyle } =
75
+ useScaleAnimation("medium");
76
+ const theme = useIOTheme();
77
+ const reducedMotion = useReducedMotion();
78
+
79
+ const mapColorStates: Record<
80
+ NonNullable<TabItem["color"]>,
81
+ ColorStates
82
+ > = useMemo(
83
+ () => ({
84
+ light: {
85
+ border: {
86
+ default: IOColors[theme["tab-item-border-default"]],
87
+ selected: hexToRgba(
88
+ IOColors[theme["tab-item-foreground-selected"]],
89
+ 0.5
90
+ )
110
91
  },
111
- dark: {
112
- border: {
113
- default: hexToRgba(IOColors.white, 0),
114
- selected: IOColors.white
115
- },
116
- background: {
117
- default: hexToRgba(IOColors.white, 0.1),
118
- selected: IOColors.white,
119
- pressed: IOColors.white
120
- },
121
- foreground: {
122
- default: "white",
123
- selected: "black",
124
- disabled: "white"
125
- }
126
- }
127
- }),
128
- [theme]
129
- );
130
-
131
- const itemState: TabItemState = selected
132
- ? "selected"
133
- : disabled
134
- ? "disabled"
135
- : "default";
136
-
137
- const foregroundColor = mapColorStates[color].foreground[itemState];
138
-
139
- const selectedStateTransition = useDerivedValue(() =>
140
- withSpring(selected ? 1 : 0, IOSpringValues.selection)
141
- );
142
-
143
- // Interpolate animation values from `pressed` values
144
- const animatedStyle = useAnimatedStyle(() => ({
145
- backgroundColor: interpolateColor(
146
- selectedStateTransition.value,
147
- [0, 1],
148
- [
149
- mapColorStates[color].background.default,
150
- mapColorStates[color].background.selected
151
- ]
152
- ),
153
- borderColor: interpolateColor(
154
- selectedStateTransition.value,
155
- [0, 1],
156
- [
157
- mapColorStates[color].border.default,
158
- mapColorStates[color].border.selected
159
- ]
160
- )
161
- }));
162
-
163
- const activeIcon = selected ? iconSelected ?? icon : icon;
164
-
165
- const handleOnPress = useCallback(
166
- (event: GestureResponderEvent) => {
167
- if (onPress) {
168
- ReactNativeHapticFeedback.trigger("impactLight");
169
- onPress(event);
92
+ background: {
93
+ default: hexToRgba(
94
+ IOColors[theme["tab-item-background-selected"]],
95
+ 0
96
+ ),
97
+ selected: hexToRgba(
98
+ IOColors[theme["tab-item-background-selected"]],
99
+ 0.25
100
+ ),
101
+ pressed: IOColors[theme["appBackground-primary"]]
102
+ },
103
+ foreground: {
104
+ default: theme["tab-item-foreground-default"],
105
+ selected: theme["tab-item-foreground-selected"],
106
+ disabled: "grey-700"
170
107
  }
171
108
  },
172
- [onPress]
173
- );
174
-
175
- return (
176
- <Pressable
177
- ref={ref}
178
- accessibilityLabel={accessibilityLabel}
179
- accessibilityHint={accessibilityHint}
180
- accessibilityRole="tab"
181
- accessibilityState={{ checked: !!selected }}
182
- testID={testID}
183
- onPress={handleOnPress}
184
- onPressIn={onPressIn}
185
- onPressOut={onPressOut}
186
- accessible={true}
187
- disabled={disabled}
109
+ dark: {
110
+ border: {
111
+ default: hexToRgba(IOColors.white, 0),
112
+ selected: IOColors.white
113
+ },
114
+ background: {
115
+ default: hexToRgba(IOColors.white, 0.1),
116
+ selected: IOColors.white,
117
+ pressed: IOColors.white
118
+ },
119
+ foreground: {
120
+ default: "white",
121
+ selected: "black",
122
+ disabled: "white"
123
+ }
124
+ }
125
+ }),
126
+ [theme]
127
+ );
128
+
129
+ const itemState: TabItemState = selected
130
+ ? "selected"
131
+ : disabled
132
+ ? "disabled"
133
+ : "default";
134
+
135
+ const foregroundColor = mapColorStates[color].foreground[itemState];
136
+
137
+ const selectedStateTransition = useDerivedValue(() =>
138
+ withSpring(selected ? 1 : 0, IOSpringValues.selection)
139
+ );
140
+
141
+ // Interpolate animation values from `pressed` values
142
+ const animatedStyle = useAnimatedStyle(() => ({
143
+ backgroundColor: interpolateColor(
144
+ selectedStateTransition.value,
145
+ [0, 1],
146
+ [
147
+ mapColorStates[color].background.default,
148
+ mapColorStates[color].background.selected
149
+ ]
150
+ ),
151
+ borderColor: interpolateColor(
152
+ selectedStateTransition.value,
153
+ [0, 1],
154
+ [
155
+ mapColorStates[color].border.default,
156
+ mapColorStates[color].border.selected
157
+ ]
158
+ )
159
+ }));
160
+
161
+ const activeIcon = selected ? iconSelected ?? icon : icon;
162
+
163
+ const handleOnPress = useCallback(
164
+ (event: GestureResponderEvent) => {
165
+ if (onPress) {
166
+ ReactNativeHapticFeedback.trigger("impactLight");
167
+ onPress(event);
168
+ }
169
+ },
170
+ [onPress]
171
+ );
172
+
173
+ return (
174
+ <Pressable
175
+ ref={ref}
176
+ accessibilityLabel={accessibilityLabel}
177
+ accessibilityHint={accessibilityHint}
178
+ accessibilityRole="tab"
179
+ accessibilityState={{ checked: !!selected }}
180
+ testID={testID}
181
+ onPress={handleOnPress}
182
+ onPressIn={onPressIn}
183
+ onPressOut={onPressOut}
184
+ accessible={true}
185
+ disabled={disabled}
186
+ >
187
+ <Animated.View
188
+ style={[
189
+ styles.container,
190
+ { columnGap: 4 },
191
+ !disabled && !reducedMotion && scaleAnimatedStyle,
192
+ animatedStyle,
193
+ disabled && { opacity: DISABLED_OPACITY }
194
+ ]}
188
195
  >
189
- <Animated.View
190
- style={[
191
- styles.container,
192
- { columnGap: 4 },
193
- !disabled && !reducedMotion && scaleAnimatedStyle,
194
- animatedStyle,
195
- disabled && { opacity: DISABLED_OPACITY }
196
- ]}
197
- >
198
- {activeIcon && (
199
- <Icon name={activeIcon} color={foregroundColor} size={16} />
200
- )}
201
- <IOText size={14} weight="Semibold" color={foregroundColor}>
202
- {label}
203
- </IOText>
204
- </Animated.View>
205
- </Pressable>
206
- );
207
- }
208
- );
196
+ {activeIcon && (
197
+ <Icon name={activeIcon} color={foregroundColor} size={16} />
198
+ )}
199
+ <IOText size={14} weight="Semibold" color={foregroundColor}>
200
+ {label}
201
+ </IOText>
202
+ </Animated.View>
203
+ </Pressable>
204
+ );
205
+ };
209
206
 
210
207
  const styles = StyleSheet.create({
211
208
  container: {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ComponentProps,
3
- forwardRef,
3
+ Ref,
4
4
  useCallback,
5
5
  useImperativeHandle,
6
6
  useMemo,
@@ -25,6 +25,7 @@ type TextInputValidationProps = Omit<
25
25
  ComponentProps<typeof TextInputBase>,
26
26
  "rightElement" | "status" | "bottomMessageColor" | "isPassword"
27
27
  > & {
28
+ ref?: Ref<TextInputValidationRefProps>;
28
29
  /**
29
30
  * This function can return either a `boolean` or a `ValidationWithOptions` object.
30
31
  * If a `boolean` is returned and the field is not valid, the value of the errorMessage prop will be displayed/announced.
@@ -57,132 +58,125 @@ function isValidationWithOptions(
57
58
 
58
59
  const feedbackIconSize: IOIconSizeScale = 24;
59
60
 
60
- export const TextInputValidation = forwardRef<
61
- TextInputValidationRefProps,
62
- TextInputValidationProps
63
- >(
64
- (
65
- {
66
- onValidate,
67
- errorMessage,
68
- value,
69
- bottomMessage,
70
- onBlur,
71
- onFocus,
72
- validationMode = "onBlur",
73
- accessibilityErrorLabel,
74
- ...props
75
- },
76
- ref
77
- ) => {
78
- const theme = useIOTheme();
79
- const [isValid, setIsValid] = useState<boolean | undefined>(undefined);
80
- const [errMessage, setErrMessage] = useState(errorMessage);
81
-
82
- const getErrorFeedback = useCallback(
83
- (isValid: boolean, message: string) => {
84
- setIsValid(isValid);
85
- setErrMessage(message);
86
-
87
- if (!isValid) {
88
- triggerHaptic("notificationError");
89
- AccessibilityInfo.announceForAccessibilityWithOptions(
90
- accessibilityErrorLabel ?? message,
91
- {
92
- queue: true
93
- }
94
- );
95
- } else {
96
- triggerHaptic("notificationSuccess");
97
- }
98
- },
99
- [accessibilityErrorLabel]
100
- );
101
-
102
- const validateInput = useCallback(() => {
103
- const validation = onValidate(value);
104
-
105
- if (isValidationWithOptions(validation)) {
106
- getErrorFeedback(validation.isValid, validation.errorMessage);
61
+ export const TextInputValidation = ({
62
+ onValidate,
63
+ errorMessage,
64
+ value,
65
+ bottomMessage,
66
+ onBlur,
67
+ onFocus,
68
+ validationMode = "onBlur",
69
+ accessibilityErrorLabel,
70
+ ref,
71
+ ...props
72
+ }: TextInputValidationProps) => {
73
+ const theme = useIOTheme();
74
+ const [isValid, setIsValid] = useState<boolean | undefined>(undefined);
75
+ const [errMessage, setErrMessage] = useState(errorMessage);
76
+
77
+ const getErrorFeedback = useCallback(
78
+ (isValid: boolean, message: string) => {
79
+ setIsValid(isValid);
80
+ setErrMessage(message);
81
+
82
+ if (!isValid) {
83
+ triggerHaptic("notificationError");
84
+ AccessibilityInfo.announceForAccessibilityWithOptions(
85
+ accessibilityErrorLabel ?? message,
86
+ {
87
+ queue: true
88
+ }
89
+ );
107
90
  } else {
108
- getErrorFeedback(validation, errorMessage);
91
+ triggerHaptic("notificationSuccess");
109
92
  }
110
- }, [value, errorMessage, onValidate, getErrorFeedback]);
111
-
112
- // Expose the validateInput function to the parent component
113
- useImperativeHandle(ref, () => ({
114
- validateInput
115
- }));
116
-
117
- const onBlurHandler = useCallback(() => {
118
- if (validationMode === "onBlur") {
119
- validateInput();
120
- }
121
- onBlur?.();
122
- }, [validationMode, validateInput, onBlur]);
93
+ },
94
+ [accessibilityErrorLabel]
95
+ );
123
96
 
124
- const onFocusHandler = useCallback(() => {
125
- setIsValid(undefined);
126
- onFocus?.();
127
- }, [onFocus]);
97
+ const validateInput = useCallback(() => {
98
+ const validation = onValidate(value);
99
+
100
+ if (isValidationWithOptions(validation)) {
101
+ getErrorFeedback(validation.isValid, validation.errorMessage);
102
+ } else {
103
+ getErrorFeedback(validation, errorMessage);
104
+ }
105
+ }, [value, errorMessage, onValidate, getErrorFeedback]);
106
+
107
+ // Expose the validateInput function to the parent component
108
+ useImperativeHandle(ref, () => ({
109
+ validateInput
110
+ }));
111
+
112
+ const onBlurHandler = useCallback(() => {
113
+ if (validationMode === "onBlur") {
114
+ validateInput();
115
+ }
116
+ onBlur?.();
117
+ }, [validationMode, validateInput, onBlur]);
118
+
119
+ const onFocusHandler = useCallback(() => {
120
+ setIsValid(undefined);
121
+ onFocus?.();
122
+ }, [onFocus]);
123
+
124
+ const labelError = useMemo(
125
+ () => (isValid === false && errMessage ? errMessage : bottomMessage),
126
+ [isValid, errMessage, bottomMessage]
127
+ );
128
128
 
129
- const labelError = useMemo(
130
- () => (isValid === false && errMessage ? errMessage : bottomMessage),
131
- [isValid, errMessage, bottomMessage]
132
- );
129
+ const labelErrorColor: IOColors | undefined = useMemo(
130
+ () => (isValid === false && errMessage ? theme.errorText : undefined),
131
+ [isValid, errMessage, theme.errorText]
132
+ );
133
133
 
134
- const labelErrorColor: IOColors | undefined = useMemo(
135
- () => (isValid === false && errMessage ? theme.errorText : undefined),
136
- [isValid, errMessage, theme.errorText]
137
- );
134
+ const feedbackIconAttrMap: Record<
135
+ string,
136
+ { name: IOIcons; color: IOColors }
137
+ > = useMemo(
138
+ () => ({
139
+ valid: {
140
+ name: "success",
141
+ color: theme.successIcon
142
+ },
143
+ notValid: {
144
+ name: "errorFilled",
145
+ color: theme.errorIcon
146
+ }
147
+ }),
148
+ [theme]
149
+ );
138
150
 
139
- const feedbackIconAttrMap: Record<
140
- string,
141
- { name: IOIcons; color: IOColors }
142
- > = useMemo(
143
- () => ({
144
- valid: {
145
- name: "success",
146
- color: theme.successIcon
147
- },
148
- notValid: {
149
- name: "errorFilled",
150
- color: theme.errorIcon
151
- }
152
- }),
153
- [theme]
151
+ const feedbackIcon = useMemo(() => {
152
+ const validationStatus = isValid ? "valid" : "notValid";
153
+
154
+ return isValid !== undefined ? (
155
+ <Animated.View
156
+ entering={enterTransitionInputIcon}
157
+ exiting={exitTransitionInputIcon}
158
+ >
159
+ <Icon
160
+ name={feedbackIconAttrMap[validationStatus].name}
161
+ color={feedbackIconAttrMap[validationStatus].color}
162
+ size={feedbackIconSize}
163
+ />
164
+ </Animated.View>
165
+ ) : (
166
+ <View style={{ width: feedbackIconSize, height: feedbackIconSize }} />
154
167
  );
168
+ }, [feedbackIconAttrMap, isValid]);
155
169
 
156
- const feedbackIcon = useMemo(() => {
157
- const validationStatus = isValid ? "valid" : "notValid";
158
-
159
- return isValid !== undefined ? (
160
- <Animated.View
161
- entering={enterTransitionInputIcon}
162
- exiting={exitTransitionInputIcon}
163
- >
164
- <Icon
165
- name={feedbackIconAttrMap[validationStatus].name}
166
- color={feedbackIconAttrMap[validationStatus].color}
167
- size={feedbackIconSize}
168
- />
169
- </Animated.View>
170
- ) : (
171
- <View style={{ width: feedbackIconSize, height: feedbackIconSize }} />
172
- );
173
- }, [feedbackIconAttrMap, isValid]);
174
-
175
- return (
176
- <TextInputBase
177
- {...props}
178
- value={value}
179
- status={isValid === false ? "error" : undefined}
180
- bottomMessage={labelError}
181
- bottomMessageColor={labelErrorColor}
182
- rightElement={feedbackIcon}
183
- onBlur={onBlurHandler}
184
- onFocus={onFocusHandler}
185
- />
186
- );
187
- }
188
- );
170
+ return (
171
+ <TextInputBase
172
+ {...props}
173
+ value={value}
174
+ status={isValid === false ? "error" : undefined}
175
+ bottomMessage={labelError}
176
+ bottomMessageColor={labelErrorColor}
177
+ rightElement={feedbackIcon}
178
+ onBlur={onBlurHandler}
179
+ onFocus={onFocusHandler}
180
+ />
181
+ );
182
+ };