@pagopa/io-app-design-system 1.17.1 → 1.18.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 (170) hide show
  1. package/lib/commonjs/components/buttons/ButtonLink.js +14 -0
  2. package/lib/commonjs/components/buttons/ButtonLink.js.map +1 -1
  3. package/lib/commonjs/components/checkbox/CheckboxLabel.js +6 -29
  4. package/lib/commonjs/components/checkbox/CheckboxLabel.js.map +1 -1
  5. package/lib/commonjs/components/codeInput/CodeInput.js +10 -25
  6. package/lib/commonjs/components/codeInput/CodeInput.js.map +1 -1
  7. package/lib/commonjs/components/common/ScaleInOutAnimation.js +69 -0
  8. package/lib/commonjs/components/common/ScaleInOutAnimation.js.map +1 -0
  9. package/lib/commonjs/components/icons/Icon.js +52 -48
  10. package/lib/commonjs/components/icons/Icon.js.map +1 -1
  11. package/lib/commonjs/components/icons/svg/IconSystemPermissionsAndroid.js +34 -0
  12. package/lib/commonjs/components/icons/svg/IconSystemPermissionsAndroid.js.map +1 -0
  13. package/lib/commonjs/components/index.js +11 -0
  14. package/lib/commonjs/components/index.js.map +1 -1
  15. package/lib/commonjs/components/layout/ForceScrollDownView.js +161 -0
  16. package/lib/commonjs/components/layout/ForceScrollDownView.js.map +1 -0
  17. package/lib/commonjs/components/layout/HeaderFirstLevel.js +4 -4
  18. package/lib/commonjs/components/layout/HeaderFirstLevel.js.map +1 -1
  19. package/lib/commonjs/components/layout/__test__/ForceScrollDownView.test.js +94 -0
  20. package/lib/commonjs/components/layout/__test__/ForceScrollDownView.test.js.map +1 -0
  21. package/lib/commonjs/components/layout/__test__/__snapshots__/ForceScrollDownView.test.tsx.snap +23 -0
  22. package/lib/commonjs/components/layout/index.js +11 -0
  23. package/lib/commonjs/components/layout/index.js.map +1 -1
  24. package/lib/commonjs/components/listitems/ListItemTransaction.js +6 -3
  25. package/lib/commonjs/components/listitems/ListItemTransaction.js.map +1 -1
  26. package/lib/commonjs/components/otpInput/BoxedInput.js +72 -0
  27. package/lib/commonjs/components/otpInput/BoxedInput.js.map +1 -0
  28. package/lib/commonjs/components/otpInput/OTPInput.js +131 -0
  29. package/lib/commonjs/components/otpInput/OTPInput.js.map +1 -0
  30. package/lib/commonjs/components/otpInput/index.js +17 -0
  31. package/lib/commonjs/components/otpInput/index.js.map +1 -0
  32. package/lib/commonjs/components/pictograms/Pictogram.js +74 -68
  33. package/lib/commonjs/components/pictograms/Pictogram.js.map +1 -1
  34. package/lib/commonjs/components/pictograms/svg/PictogramComunicationProblem.js +85 -0
  35. package/lib/commonjs/components/pictograms/svg/PictogramComunicationProblem.js.map +1 -0
  36. package/lib/commonjs/components/pictograms/svg/PictogramEventClose.js +40 -0
  37. package/lib/commonjs/components/pictograms/svg/PictogramEventClose.js.map +1 -0
  38. package/lib/commonjs/components/pictograms/svg/PictogramHello.js +61 -0
  39. package/lib/commonjs/components/pictograms/svg/PictogramHello.js.map +1 -0
  40. package/lib/commonjs/components/pictograms/svg/originals/PictogramComunicationProblem.svg +91 -0
  41. package/lib/commonjs/components/pictograms/svg/originals/PictogramEventClose.svg +34 -0
  42. package/lib/commonjs/components/pictograms/svg/originals/PictogramHello.svg +46 -0
  43. package/lib/commonjs/components/radio/RadioButtonLabel.js +70 -0
  44. package/lib/commonjs/components/radio/RadioButtonLabel.js.map +1 -0
  45. package/lib/commonjs/components/radio/index.js +11 -0
  46. package/lib/commonjs/components/radio/index.js.map +1 -1
  47. package/lib/commonjs/core/IOStyles.js +3 -1
  48. package/lib/commonjs/core/IOStyles.js.map +1 -1
  49. package/lib/commonjs/utils/hooks/useErrorShakeAnimation.js +44 -0
  50. package/lib/commonjs/utils/hooks/useErrorShakeAnimation.js.map +1 -0
  51. package/lib/module/components/buttons/ButtonLink.js +15 -1
  52. package/lib/module/components/buttons/ButtonLink.js.map +1 -1
  53. package/lib/module/components/checkbox/CheckboxLabel.js +7 -30
  54. package/lib/module/components/checkbox/CheckboxLabel.js.map +1 -1
  55. package/lib/module/components/codeInput/CodeInput.js +9 -25
  56. package/lib/module/components/codeInput/CodeInput.js.map +1 -1
  57. package/lib/module/components/common/ScaleInOutAnimation.js +59 -0
  58. package/lib/module/components/common/ScaleInOutAnimation.js.map +1 -0
  59. package/lib/module/components/icons/Icon.js +52 -48
  60. package/lib/module/components/icons/Icon.js.map +1 -1
  61. package/lib/module/components/icons/svg/IconSystemPermissionsAndroid.js +26 -0
  62. package/lib/module/components/icons/svg/IconSystemPermissionsAndroid.js.map +1 -0
  63. package/lib/module/components/index.js +1 -0
  64. package/lib/module/components/index.js.map +1 -1
  65. package/lib/module/components/layout/ForceScrollDownView.js +153 -0
  66. package/lib/module/components/layout/ForceScrollDownView.js.map +1 -0
  67. package/lib/module/components/layout/HeaderFirstLevel.js +4 -4
  68. package/lib/module/components/layout/HeaderFirstLevel.js.map +1 -1
  69. package/lib/module/components/layout/__test__/ForceScrollDownView.test.js +90 -0
  70. package/lib/module/components/layout/__test__/ForceScrollDownView.test.js.map +1 -0
  71. package/lib/module/components/layout/__test__/__snapshots__/ForceScrollDownView.test.tsx.snap +23 -0
  72. package/lib/module/components/layout/index.js +1 -0
  73. package/lib/module/components/layout/index.js.map +1 -1
  74. package/lib/module/components/listitems/ListItemTransaction.js +6 -3
  75. package/lib/module/components/listitems/ListItemTransaction.js.map +1 -1
  76. package/lib/module/components/otpInput/BoxedInput.js +64 -0
  77. package/lib/module/components/otpInput/BoxedInput.js.map +1 -0
  78. package/lib/module/components/otpInput/OTPInput.js +121 -0
  79. package/lib/module/components/otpInput/OTPInput.js.map +1 -0
  80. package/lib/module/components/otpInput/index.js +2 -0
  81. package/lib/module/components/otpInput/index.js.map +1 -0
  82. package/lib/module/components/pictograms/Pictogram.js +74 -68
  83. package/lib/module/components/pictograms/Pictogram.js.map +1 -1
  84. package/lib/module/components/pictograms/svg/PictogramComunicationProblem.js +77 -0
  85. package/lib/module/components/pictograms/svg/PictogramComunicationProblem.js.map +1 -0
  86. package/lib/module/components/pictograms/svg/PictogramEventClose.js +32 -0
  87. package/lib/module/components/pictograms/svg/PictogramEventClose.js.map +1 -0
  88. package/lib/module/components/pictograms/svg/PictogramHello.js +53 -0
  89. package/lib/module/components/pictograms/svg/PictogramHello.js.map +1 -0
  90. package/lib/module/components/pictograms/svg/originals/PictogramComunicationProblem.svg +91 -0
  91. package/lib/module/components/pictograms/svg/originals/PictogramEventClose.svg +34 -0
  92. package/lib/module/components/pictograms/svg/originals/PictogramHello.svg +46 -0
  93. package/lib/module/components/radio/RadioButtonLabel.js +62 -0
  94. package/lib/module/components/radio/RadioButtonLabel.js.map +1 -0
  95. package/lib/module/components/radio/index.js +1 -0
  96. package/lib/module/components/radio/index.js.map +1 -1
  97. package/lib/module/core/IOStyles.js +3 -1
  98. package/lib/module/core/IOStyles.js.map +1 -1
  99. package/lib/module/utils/hooks/useErrorShakeAnimation.js +37 -0
  100. package/lib/module/utils/hooks/useErrorShakeAnimation.js.map +1 -0
  101. package/lib/typescript/components/buttons/ButtonLink.d.ts +1 -1
  102. package/lib/typescript/components/buttons/ButtonLink.d.ts.map +1 -1
  103. package/lib/typescript/components/checkbox/CheckboxLabel.d.ts.map +1 -1
  104. package/lib/typescript/components/codeInput/CodeInput.d.ts.map +1 -1
  105. package/lib/typescript/components/common/ScaleInOutAnimation.d.ts +14 -0
  106. package/lib/typescript/components/common/ScaleInOutAnimation.d.ts.map +1 -0
  107. package/lib/typescript/components/icons/Icon.d.ts +2 -0
  108. package/lib/typescript/components/icons/Icon.d.ts.map +1 -1
  109. package/lib/typescript/components/icons/svg/IconSystemPermissionsAndroid.d.ts +5 -0
  110. package/lib/typescript/components/icons/svg/IconSystemPermissionsAndroid.d.ts.map +1 -0
  111. package/lib/typescript/components/index.d.ts +1 -0
  112. package/lib/typescript/components/index.d.ts.map +1 -1
  113. package/lib/typescript/components/layout/ForceScrollDownView.d.ts +27 -0
  114. package/lib/typescript/components/layout/ForceScrollDownView.d.ts.map +1 -0
  115. package/lib/typescript/components/layout/__test__/ForceScrollDownView.test.d.ts +2 -0
  116. package/lib/typescript/components/layout/__test__/ForceScrollDownView.test.d.ts.map +1 -0
  117. package/lib/typescript/components/layout/index.d.ts +1 -0
  118. package/lib/typescript/components/layout/index.d.ts.map +1 -1
  119. package/lib/typescript/components/listitems/ListItemTransaction.d.ts +6 -1
  120. package/lib/typescript/components/listitems/ListItemTransaction.d.ts.map +1 -1
  121. package/lib/typescript/components/otpInput/BoxedInput.d.ts +9 -0
  122. package/lib/typescript/components/otpInput/BoxedInput.d.ts.map +1 -0
  123. package/lib/typescript/components/otpInput/OTPInput.d.ts +26 -0
  124. package/lib/typescript/components/otpInput/OTPInput.d.ts.map +1 -0
  125. package/lib/typescript/components/otpInput/index.d.ts +2 -0
  126. package/lib/typescript/components/otpInput/index.d.ts.map +1 -0
  127. package/lib/typescript/components/pictograms/Pictogram.d.ts +3 -0
  128. package/lib/typescript/components/pictograms/Pictogram.d.ts.map +1 -1
  129. package/lib/typescript/components/pictograms/svg/PictogramComunicationProblem.d.ts +5 -0
  130. package/lib/typescript/components/pictograms/svg/PictogramComunicationProblem.d.ts.map +1 -0
  131. package/lib/typescript/components/pictograms/svg/PictogramEventClose.d.ts +5 -0
  132. package/lib/typescript/components/pictograms/svg/PictogramEventClose.d.ts.map +1 -0
  133. package/lib/typescript/components/pictograms/svg/PictogramHello.d.ts +5 -0
  134. package/lib/typescript/components/pictograms/svg/PictogramHello.d.ts.map +1 -0
  135. package/lib/typescript/components/radio/RadioButtonLabel.d.ts +18 -0
  136. package/lib/typescript/components/radio/RadioButtonLabel.d.ts.map +1 -0
  137. package/lib/typescript/components/radio/index.d.ts +1 -0
  138. package/lib/typescript/components/radio/index.d.ts.map +1 -1
  139. package/lib/typescript/core/IOStyles.d.ts +2 -0
  140. package/lib/typescript/core/IOStyles.d.ts.map +1 -1
  141. package/lib/typescript/utils/hooks/useErrorShakeAnimation.d.ts +11 -0
  142. package/lib/typescript/utils/hooks/useErrorShakeAnimation.d.ts.map +1 -0
  143. package/package.json +5 -2
  144. package/src/components/buttons/ButtonLink.tsx +17 -1
  145. package/src/components/checkbox/CheckboxLabel.tsx +4 -31
  146. package/src/components/codeInput/CodeInput.tsx +5 -33
  147. package/src/components/common/ScaleInOutAnimation.tsx +68 -0
  148. package/src/components/icons/Icon.tsx +52 -48
  149. package/src/components/icons/svg/IconSystemPermissionsAndroid.tsx +19 -0
  150. package/src/components/index.tsx +1 -0
  151. package/src/components/layout/ForceScrollDownView.tsx +210 -0
  152. package/src/components/layout/HeaderFirstLevel.tsx +4 -4
  153. package/src/components/layout/__test__/ForceScrollDownView.test.tsx +106 -0
  154. package/src/components/layout/__test__/__snapshots__/ForceScrollDownView.test.tsx.snap +23 -0
  155. package/src/components/layout/index.tsx +1 -0
  156. package/src/components/listitems/ListItemTransaction.tsx +12 -1
  157. package/src/components/otpInput/BoxedInput.tsx +67 -0
  158. package/src/components/otpInput/OTPInput.tsx +135 -0
  159. package/src/components/otpInput/index.tsx +1 -0
  160. package/src/components/pictograms/Pictogram.tsx +74 -68
  161. package/src/components/pictograms/svg/PictogramComunicationProblem.tsx +94 -0
  162. package/src/components/pictograms/svg/PictogramEventClose.tsx +34 -0
  163. package/src/components/pictograms/svg/PictogramHello.tsx +54 -0
  164. package/src/components/pictograms/svg/originals/PictogramComunicationProblem.svg +91 -0
  165. package/src/components/pictograms/svg/originals/PictogramEventClose.svg +34 -0
  166. package/src/components/pictograms/svg/originals/PictogramHello.svg +46 -0
  167. package/src/components/radio/RadioButtonLabel.tsx +73 -0
  168. package/src/components/radio/index.tsx +1 -0
  169. package/src/core/IOStyles.ts +5 -1
  170. package/src/utils/hooks/useErrorShakeAnimation.ts +43 -0
@@ -0,0 +1,106 @@
1
+ /* eslint-disable functional/immutable-data */
2
+ import { fireEvent, render } from "@testing-library/react-native";
3
+ import React from "react";
4
+ import { Text } from "react-native";
5
+ import { ForceScrollDownView } from "../ForceScrollDownView";
6
+
7
+ const tContent = "Some content";
8
+
9
+ describe("ForceScrollDownView", () => {
10
+ jest.useFakeTimers();
11
+
12
+ it("should match snapshot", () => {
13
+ const tChildren = <Text>{tContent}</Text>;
14
+
15
+ const component = render(
16
+ <ForceScrollDownView>{tChildren}</ForceScrollDownView>
17
+ );
18
+
19
+ expect(component).toMatchSnapshot();
20
+ });
21
+
22
+ it("renders the content correctly", () => {
23
+ const tChildren = <Text>{tContent}</Text>;
24
+
25
+ const { getByText } = render(
26
+ <ForceScrollDownView>{tChildren}</ForceScrollDownView>
27
+ );
28
+
29
+ expect(getByText(tContent)).toBeDefined();
30
+ });
31
+
32
+ it("displays the scroll down button when necessary", async () => {
33
+ const tChildren = <Text>{tContent}</Text>;
34
+
35
+ const tScreenHeight = 1000;
36
+
37
+ const { getByTestId, queryByTestId } = render(
38
+ <ForceScrollDownView>{tChildren}</ForceScrollDownView>
39
+ );
40
+
41
+ const scrollView = getByTestId("ScrollView");
42
+
43
+ // Update scroll view height
44
+ fireEvent(scrollView, "layout", {
45
+ nativeEvent: {
46
+ layout: {
47
+ height: tScreenHeight
48
+ }
49
+ }
50
+ });
51
+
52
+ // Update scroll view content height
53
+ fireEvent(scrollView, "contentSizeChange", null, tScreenHeight - 500);
54
+
55
+ // Button should not be visible because content does not need scrolling
56
+ const buttonBefore = queryByTestId("ScrollDownButton");
57
+ expect(buttonBefore).toBeNull();
58
+
59
+ // Increase content height to force button to be shown
60
+ fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
61
+
62
+ jest.advanceTimersByTime(500);
63
+
64
+ // Button should be visible now beacuse content needs scrolling
65
+ const buttonAfter = queryByTestId("ScrollDownButton");
66
+ expect(buttonAfter).not.toBeNull();
67
+ });
68
+
69
+ it("scrolls to the bottom when the button is pressed", () => {
70
+ const tChildren = <Text>{tContent}</Text>;
71
+
72
+ const tScreenHeight = 1000;
73
+
74
+ const { getByTestId, queryByTestId } = render(
75
+ <ForceScrollDownView>{tChildren}</ForceScrollDownView>
76
+ );
77
+
78
+ const scrollView = getByTestId("ScrollView");
79
+
80
+ // Update scroll view height
81
+ fireEvent(scrollView, "layout", {
82
+ nativeEvent: {
83
+ layout: {
84
+ height: tScreenHeight
85
+ }
86
+ }
87
+ });
88
+
89
+ // Update scroll view content height
90
+ fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
91
+
92
+ // Button should be visible
93
+ const buttonBefore = getByTestId("ScrollDownButton");
94
+ expect(buttonBefore).not.toBeNull();
95
+
96
+ // Fire button press event
97
+ fireEvent.press(buttonBefore);
98
+
99
+ // Wait for the scroll animation
100
+ jest.advanceTimersByTime(500);
101
+
102
+ // Button should not be visible after scrolling
103
+ const buttonAfter = queryByTestId("ScrollDownButton");
104
+ expect(buttonAfter).toBeNull();
105
+ });
106
+ });
@@ -0,0 +1,23 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`ForceScrollDownView should match snapshot 1`] = `
4
+ <RCTScrollView
5
+ onContentSizeChange={[Function]}
6
+ onLayout={[Function]}
7
+ onScroll={[Function]}
8
+ scrollEnabled={true}
9
+ scrollEventThrottle={400}
10
+ scrollIndicatorInsets={
11
+ {
12
+ "right": 1,
13
+ }
14
+ }
15
+ testID="ScrollView"
16
+ >
17
+ <View>
18
+ <Text>
19
+ Some content
20
+ </Text>
21
+ </View>
22
+ </RCTScrollView>
23
+ `;
@@ -3,5 +3,6 @@ export * from "./GradientScrollView";
3
3
  export * from "./GradientBottomActions";
4
4
  export * from "./HeaderFirstLevel";
5
5
  export * from "./HeaderSecondLevel";
6
+ export * from "./ForceScrollDownView";
6
7
  export * from "./FooterWithButtons";
7
8
  export * from "./BlockButtons";
@@ -65,6 +65,11 @@ export type ListItemTransaction = WithTestID<
65
65
  paymentLogoIcon?: ListItemTransactionLogo;
66
66
  subtitle: string;
67
67
  title: string;
68
+ /**
69
+ * The maximum number of lines to display for the title.
70
+ * @default 2
71
+ */
72
+ numberOfLines?: number;
68
73
  accessible?: boolean;
69
74
  } & (
70
75
  | {
@@ -117,6 +122,7 @@ export const ListItemTransaction = ({
117
122
  transactionAmount,
118
123
  badgeText,
119
124
  transactionStatus = "success",
125
+ numberOfLines = 2,
120
126
  accessible
121
127
  }: ListItemTransaction) => {
122
128
  const { isExperimental } = useIOExperimentalDesign();
@@ -144,6 +150,7 @@ export const ListItemTransaction = ({
144
150
  <H6
145
151
  accessibilityLabel={getAccessibleAmountText(transactionAmount)}
146
152
  color={hasChevronRight ? interactiveColor : "black"}
153
+ numberOfLines={numberOfLines}
147
154
  >
148
155
  {transactionAmount || ""}
149
156
  </H6>
@@ -153,6 +160,7 @@ export const ListItemTransaction = ({
153
160
  <H6
154
161
  accessibilityLabel={getAccessibleAmountText(transactionAmount)}
155
162
  color={hasChevronRight ? interactiveColor : "success-700"}
163
+ numberOfLines={numberOfLines}
156
164
  >
157
165
  {transactionAmount || ""}
158
166
  </H6>
@@ -181,7 +189,10 @@ export const ListItemTransaction = ({
181
189
  </View>
182
190
  )}
183
191
  <View style={IOStyles.flex}>
184
- <LabelSmallAlt numberOfLines={2} color={theme["textBody-default"]}>
192
+ <LabelSmallAlt
193
+ numberOfLines={numberOfLines}
194
+ color={theme["textBody-default"]}
195
+ >
185
196
  {title}
186
197
  </LabelSmallAlt>
187
198
  <LabelSmall weight="Regular" color={theme["textBody-tertiary"]}>
@@ -0,0 +1,67 @@
1
+ import * as React from "react";
2
+ import { useMemo } from "react";
3
+ import { View, StyleSheet } from "react-native";
4
+ import { IOColors } from "../../core";
5
+ import { BaseTypography, H6 } from "../typography";
6
+
7
+ type Props = {
8
+ status: "default" | "focus" | "error";
9
+ secret?: boolean;
10
+ value?: string;
11
+ };
12
+
13
+ const styles = StyleSheet.create({
14
+ baseBox: {
15
+ alignItems: "center",
16
+ justifyContent: "center",
17
+ width: 35,
18
+ height: 60,
19
+ borderRadius: 8
20
+ },
21
+ defaultBox: {
22
+ borderWidth: 1,
23
+ borderColor: IOColors["grey-200"]
24
+ },
25
+ focusedBox: {
26
+ borderWidth: 2,
27
+ borderColor: IOColors["blueIO-500"]
28
+ },
29
+ errorBox: {
30
+ borderWidth: 1,
31
+ borderColor: IOColors["error-850"],
32
+ backgroundColor: IOColors["error-100"]
33
+ }
34
+ });
35
+
36
+ // FIXME Replace this component with H3 once the legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153
37
+ const SecretValue = () => (
38
+ <BaseTypography
39
+ font="DMMono"
40
+ weight="SemiBold"
41
+ color="bluegreyDark"
42
+ fontStyle={{ fontSize: 22, lineHeight: 33 }}
43
+ accessible={false}
44
+ >
45
+ {"•"}
46
+ </BaseTypography>
47
+ );
48
+
49
+ export const BoxedInput = ({ status, value, secret }: Props) => {
50
+ const derivedStyle = useMemo(() => {
51
+ switch (status) {
52
+ case "error":
53
+ return styles.errorBox;
54
+ case "focus":
55
+ return styles.focusedBox;
56
+ case "default":
57
+ default:
58
+ return styles.defaultBox;
59
+ }
60
+ }, [status]);
61
+ return (
62
+ <View style={[styles.baseBox, derivedStyle]} accessible={false}>
63
+ {value &&
64
+ (secret ? <SecretValue /> : <H6 accessible={false}>{value}</H6>)}
65
+ </View>
66
+ );
67
+ };
@@ -0,0 +1,135 @@
1
+ import * as React from "react";
2
+ import { Pressable, TextInput } from "react-native";
3
+ import Animated from "react-native-reanimated";
4
+ import { IOStyles } from "../../core/IOStyles";
5
+ import { LabelSmall } from "../typography";
6
+ import { triggerHaptic } from "../../functions";
7
+ import { VSpacer } from "../spacer";
8
+ import { useErrorShakeAnimation } from "../../utils/hooks/useErrorShakeAnimation";
9
+ import { BoxedInput } from "./BoxedInput";
10
+
11
+ type Props = {
12
+ value: string;
13
+ onValueChange: (value: string) => void;
14
+ length: number;
15
+ secret?: boolean;
16
+ autocomplete?: boolean;
17
+ onValidate?: (value: string) => boolean;
18
+ errorMessage?: string;
19
+ };
20
+
21
+ /**
22
+ * `OTPInput` is a component that allows the user to enter a one-time password.
23
+ * It has an hidden `TextInput` that is used to handle the keyboard and the focus.
24
+ * The input handles the autocompletion of the OTP code.
25
+ * @param value - The value of the OTP code
26
+ * @param onValueChange - The function to call when the value changes
27
+ * @param length - The length of the OTP code
28
+ * @param secret - If the OTP code should be hidden
29
+ * @param autocomplete - If the OTP code should be autocompleted
30
+ * @param onValidate - The function to call when the OTP code is validated
31
+ * @param errorMessage - The error message to display
32
+ * @returns
33
+ */
34
+ export const OTPInput = ({
35
+ value,
36
+ onValueChange,
37
+ length,
38
+ onValidate,
39
+ errorMessage = "",
40
+ secret = false,
41
+ autocomplete = false
42
+ }: Props) => {
43
+ const [hasFocus, setHasFocus] = React.useState(false);
44
+ const [hasError, setHasError] = React.useState(false);
45
+ const [inputValue, setInputValue] = React.useState(value);
46
+
47
+ const { translate, animatedStyle, shakeAnimation } = useErrorShakeAnimation();
48
+
49
+ const inputRef = React.createRef<TextInput>();
50
+ const timerRef = React.useRef<NodeJS.Timeout>();
51
+
52
+ const handleValidate = (val: string) => {
53
+ if (!onValidate || val.length < length) {
54
+ return;
55
+ }
56
+ const isValid = onValidate(val);
57
+ if (!isValid) {
58
+ setHasError(true);
59
+ triggerHaptic("notificationError");
60
+ // eslint-disable-next-line functional/immutable-data
61
+ translate.value = shakeAnimation();
62
+
63
+ if (timerRef.current) {
64
+ clearTimeout(timerRef.current);
65
+ }
66
+ // eslint-disable-next-line functional/immutable-data
67
+ timerRef.current = setTimeout(() => {
68
+ setHasError(false);
69
+ setInputValue("");
70
+ onValueChange("");
71
+ }, 500);
72
+ }
73
+ };
74
+
75
+ React.useEffect(() => () => clearTimeout(timerRef.current), []);
76
+
77
+ const handleChange = (value: string) => {
78
+ if (value.length > length) {
79
+ return;
80
+ }
81
+ setInputValue(value);
82
+ onValueChange(value);
83
+ handleValidate(value);
84
+ };
85
+
86
+ return (
87
+ <Animated.View style={[{ flexGrow: 1 }, animatedStyle]}>
88
+ <Pressable
89
+ onPress={() => {
90
+ inputRef.current?.focus();
91
+ setHasFocus(true);
92
+ }}
93
+ style={[IOStyles.row, { justifyContent: "space-around" }]}
94
+ accessible={true}
95
+ accessibilityLabel="OTP Input"
96
+ accessibilityValue={{ text: inputValue }}
97
+ >
98
+ <TextInput
99
+ value={inputValue}
100
+ onChangeText={handleChange}
101
+ style={{ position: "absolute", opacity: 0 }}
102
+ maxLength={length}
103
+ ref={inputRef}
104
+ onBlur={() => setHasFocus(false)}
105
+ keyboardType="numeric"
106
+ inputMode="numeric"
107
+ returnKeyType="done"
108
+ textContentType="oneTimeCode"
109
+ autoComplete={autocomplete ? "sms-otp" : undefined}
110
+ accessible={true}
111
+ />
112
+ {[...Array(length)].map((_, i) => (
113
+ <BoxedInput
114
+ key={i}
115
+ status={
116
+ hasError
117
+ ? "error"
118
+ : hasFocus && inputValue.length === i
119
+ ? "focus"
120
+ : "default"
121
+ }
122
+ secret={secret}
123
+ value={inputValue[i]}
124
+ />
125
+ ))}
126
+ </Pressable>
127
+ <VSpacer size={4} />
128
+ {hasError && errorMessage && (
129
+ <LabelSmall color="error-850" style={{ textAlign: "center" }}>
130
+ {errorMessage}
131
+ </LabelSmall>
132
+ )}
133
+ </Animated.View>
134
+ );
135
+ };
@@ -0,0 +1 @@
1
+ export * from "./OTPInput";
@@ -7,27 +7,50 @@ import {
7
7
  useIOTheme
8
8
  } from "../../core/IOColors";
9
9
 
10
- import PictogramMessages from "./svg/PictogramMessages";
11
10
  import PictogramAbacus from "./svg/PictogramAbacus";
11
+ import PictogramAccessDenied from "./svg/PictogramAccessDenied";
12
12
  import PictogramAirBaloon from "./svg/PictogramAirBaloon";
13
13
  import PictogramAirship from "./svg/PictogramAirship";
14
14
  import PictogramAttention from "./svg/PictogramAttention";
15
15
  import PictogramBaloons from "./svg/PictogramBaloons";
16
16
  import PictogramBeerMug from "./svg/PictogramBeerMug";
17
- import PictogramCameraRequest from "./svg/PictogramCameraRequest";
18
17
  import PictogramCameraDenied from "./svg/PictogramCameraDenied";
18
+ import PictogramCameraRequest from "./svg/PictogramCameraRequest";
19
+ import PictogramCharity from "./svg/PictogramCharity";
20
+ import PictogramCie from "./svg/PictogramCie";
19
21
  import PictogramCompleted from "./svg/PictogramCompleted";
22
+ import PictogramComunicationProblem from "./svg/PictogramComunicationProblem";
20
23
  import PictogramEmailToValidate from "./svg/PictogramEmailToValidate";
21
24
  import PictogramEmailValidation from "./svg/PictogramEmailValidation";
25
+ import PictogramEmpty from "./svg/PictogramEmpty";
22
26
  import PictogramEmptyArchive from "./svg/PictogramEmptyArchive";
23
27
  import PictogramError from "./svg/PictogramError";
28
+ import PictogramFatalError from "./svg/PictogramFatalError";
29
+ import PictogramFeature from "./svg/PictogramFeature";
24
30
  import PictogramFeedback from "./svg/PictogramFeedback";
25
31
  import PictogramFireworks from "./svg/PictogramFireworks";
26
32
  import PictogramHeart from "./svg/PictogramHeart";
33
+ import PictogramHello from "./svg/PictogramHello";
34
+ import PictogramHelp from "./svg/PictogramHelp";
27
35
  import PictogramHourglass from "./svg/PictogramHourglass";
36
+ import PictogramITWallet from "./svg/PictogramITWallet";
37
+ import PictogramIdentity from "./svg/PictogramIdentity";
38
+ import PictogramIdentityAdd from "./svg/PictogramIdentityAdd";
39
+ import PictogramIdentityCheck from "./svg/PictogramIdentityCheck";
40
+ import PictogramIdentityRefresh from "./svg/PictogramIdentityRefresh";
28
41
  import PictogramInProgress from "./svg/PictogramInProgress";
29
42
  import PictogramInbox from "./svg/PictogramInbox";
43
+ import PictogramMessages from "./svg/PictogramMessages";
30
44
  import PictogramNotAvailable from "./svg/PictogramNotAvailable";
45
+ import PictogramNotification from "./svg/PictogramNotification";
46
+ import PictogramObjClock from "./svg/PictogramObjClock";
47
+ import PictogramObjFlyingMessage from "./svg/PictogramObjFlyingMessage";
48
+ import PictogramObjFollowMessage from "./svg/PictogramObjFollowMessage";
49
+ import PictogramObjIbanCard from "./svg/PictogramObjIbanCard";
50
+ import PictogramObjKey from "./svg/PictogramObjKey";
51
+ import PictogramObjManual from "./svg/PictogramObjManual";
52
+ import PictogramObjTrash from "./svg/PictogramObjTrash";
53
+ import PictogramPasscode from "./svg/PictogramPasscode";
31
54
  import PictogramPiggyBank from "./svg/PictogramPiggyBank";
32
55
  import PictogramPin from "./svg/PictogramPin";
33
56
  import PictogramPlaces from "./svg/PictogramPlaces";
@@ -35,99 +58,79 @@ import PictogramProcessing from "./svg/PictogramProcessing";
35
58
  import PictogramPuzzle from "./svg/PictogramPuzzle";
36
59
  import PictogramQuestion from "./svg/PictogramQuestion";
37
60
  import PictogramSearch from "./svg/PictogramSearch";
61
+ import PictogramSecurity from "./svg/PictogramSecurity";
38
62
  import PictogramSms from "./svg/PictogramSms";
63
+ import PictogramStopSecurity from "./svg/PictogramStopSecurity";
64
+ import PictogramSuccess from "./svg/PictogramSuccess";
39
65
  import PictogramTeaBreak from "./svg/PictogramTeaBreak";
66
+ import PictogramTime from "./svg/PictogramTime";
40
67
  import PictogramTimeout from "./svg/PictogramTimeout";
41
68
  import PictogramUmbrella from "./svg/PictogramUmbrella";
42
69
  import PictogramUmbrellaNew from "./svg/PictogramUmbrellaNew";
43
70
  import PictogramUnrecognized from "./svg/PictogramUnrecognized";
44
- import PictogramUploadFile from "./svg/PictogramUploadFile";
45
- import PictogramSuccess from "./svg/PictogramSuccess";
46
- import PictogramHelp from "./svg/PictogramHelp";
47
- import PictogramITWallet from "./svg/PictogramITWallet";
48
- import PictogramFatalError from "./svg/PictogramFatalError";
49
71
  import PictogramUpdateOS from "./svg/PictogramUpdateOS";
50
- import PictogramIdentityAdd from "./svg/PictogramIdentityAdd";
51
- import PictogramIdentityRefresh from "./svg/PictogramIdentityRefresh";
52
- import PictogramIdentity from "./svg/PictogramIdentity";
53
- import PictogramAccessDenied from "./svg/PictogramAccessDenied";
54
- import PictogramTime from "./svg/PictogramTime";
55
- import PictogramStopSecurity from "./svg/PictogramStopSecurity";
56
- import PictogramSecurity from "./svg/PictogramSecurity";
57
- import PictogramPasscode from "./svg/PictogramPasscode";
58
- import PictogramIdentityCheck from "./svg/PictogramIdentityCheck";
59
- import PictogramCharity from "./svg/PictogramCharity";
60
- import PictogramEmpty from "./svg/PictogramEmpty";
61
- import PictogramCie from "./svg/PictogramCie";
62
- import PictogramFeature from "./svg/PictogramFeature";
63
- import PictogramNotification from "./svg/PictogramNotification";
64
- import PictogramObjClock from "./svg/PictogramObjClock";
65
- import PictogramObjIbanCard from "./svg/PictogramObjIbanCard";
66
- import PictogramObjManual from "./svg/PictogramObjManual";
67
- import PictogramObjTrash from "./svg/PictogramObjTrash";
68
- import PictogramObjKey from "./svg/PictogramObjKey";
69
- import PictogramObjFlyingMessage from "./svg/PictogramObjFlyingMessage";
70
- import PictogramObjFollowMessage from "./svg/PictogramObjFollowMessage";
72
+ import PictogramUploadFile from "./svg/PictogramUploadFile";
71
73
  /* Bleed Pictograms */
74
+ import PictogramActivate from "./svg/PictogramActivate";
75
+ import PictogramAttachment from "./svg/PictogramAttachment";
76
+ import PictogramBiometric from "./svg/PictogramBiometric";
77
+ import PictogramBleedAccessDenied from "./svg/PictogramBleedAccessDenied";
78
+ import PictogramBleedAttention from "./svg/PictogramBleedAttention";
79
+ import PictogramBleedCameraDenied from "./svg/PictogramBleedCameraDenied";
80
+ import PictogramBleedCameraRequest from "./svg/PictogramBleedCameraRequest";
81
+ import PictogramBleedCardAdd from "./svg/PictogramBleedCardAdd";
82
+ import PictogramBleedCardFavourite from "./svg/PictogramBleedCardFavourite";
83
+ import PictogramBleedCardIssue from "./svg/PictogramBleedCardIssue";
84
+ import PictogramBleedCardQuestion from "./svg/PictogramBleedCardQuestion";
72
85
  import PictogramBleedCharity from "./svg/PictogramBleedCharity";
73
- import PictogramBleedHelp from "./svg/PictogramBleedHelp";
74
- import PictogramBleedITWallet from "./svg/PictogramBleedITWallet";
75
- import PictogramBleedFeedback from "./svg/PictogramBleedFeedback";
76
- import PictogramBleedSecurity from "./svg/PictogramBleedSecurity";
77
- import PictogramBleedFeature from "./svg/PictogramBleedFeature";
78
86
  import PictogramBleedCie from "./svg/PictogramBleedCie";
79
- import PictogramBleedCameraRequest from "./svg/PictogramBleedCameraRequest";
80
- import PictogramBleedCameraDenied from "./svg/PictogramBleedCameraDenied";
81
- import PictogramBleedNotification from "./svg/PictogramBleedNotification";
82
- import PictogramStar from "./svg/PictogramStar";
83
- import PictogramBleedStar from "./svg/PictogramBleedStar";
87
+ import PictogramBleedDoc from "./svg/PictogramBleedDoc";
84
88
  import PictogramBleedEmpty from "./svg/PictogramBleedEmpty";
85
- import PictogramBleedAttention from "./svg/PictogramBleedAttention";
86
- import PictogramBleedSuccess from "./svg/PictogramBleedSuccess";
89
+ import PictogramBleedEnded from "./svg/PictogramBleedEnded";
87
90
  import PictogramBleedFatalError from "./svg/PictogramBleedFatalError";
91
+ import PictogramBleedFeature from "./svg/PictogramBleedFeature";
92
+ import PictogramBleedFeedback from "./svg/PictogramBleedFeedback";
93
+ import PictogramBleedHelp from "./svg/PictogramBleedHelp";
94
+ import PictogramBleedITWallet from "./svg/PictogramBleedITWallet";
95
+ import PictogramBleedIdea from "./svg/PictogramBleedIdea";
88
96
  import PictogramBleedIdentity from "./svg/PictogramBleedIdentity";
89
97
  import PictogramBleedIdentityAdd from "./svg/PictogramBleedIdentityAdd";
90
98
  import PictogramBleedIdentityCheck from "./svg/PictogramBleedIdentityCheck";
91
99
  import PictogramBleedIdentityRefresh from "./svg/PictogramBleedIdentityRefresh";
92
- import PictogramBleedAccessDenied from "./svg/PictogramBleedAccessDenied";
100
+ import PictogramBleedLostConnection from "./svg/PictogramBleedLostConnection";
101
+ import PictogramBleedMessage from "./svg/PictogramBleedMessage";
102
+ import PictogramBleedNotification from "./svg/PictogramBleedNotification";
103
+ import PictogramBleedPasscode from "./svg/PictogramBleedPasscode";
104
+ import PictogramBleedPending from "./svg/PictogramBleedPending";
105
+ import PictogramBleedQrCode from "./svg/PictogramBleedQrCode";
106
+ import PictogramBleedSearch from "./svg/PictogramBleedSearch";
107
+ import PictogramBleedSecurity from "./svg/PictogramBleedSecurity";
108
+ import PictogramBleedStar from "./svg/PictogramBleedStar";
93
109
  import PictogramBleedStopSecurity from "./svg/PictogramBleedStopSecurity";
110
+ import PictogramBleedSuccess from "./svg/PictogramBleedSuccess";
94
111
  import PictogramBleedTime from "./svg/PictogramBleedTime";
95
- import PictogramBleedPasscode from "./svg/PictogramBleedPasscode";
96
- import PictogramTiming from "./svg/PictogramTiming";
97
112
  import PictogramBleedTiming from "./svg/PictogramBleedTiming";
113
+ import PictogramCardAdd from "./svg/PictogramCardAdd";
114
+ import PictogramCardFavourite from "./svg/PictogramCardFavourite";
98
115
  import PictogramCardIssue from "./svg/PictogramCardIssue";
99
116
  import PictogramCardQuestion from "./svg/PictogramCardQuestion";
100
- import PictogramCardFavourite from "./svg/PictogramCardFavourite";
101
- import PictogramCardAdd from "./svg/PictogramCardAdd";
102
- import PictogramBleedCardAdd from "./svg/PictogramBleedCardAdd";
103
- import PictogramBleedCardFavourite from "./svg/PictogramBleedCardFavourite";
104
- import PictogramBleedCardQuestion from "./svg/PictogramBleedCardQuestion";
105
- import PictogramBleedCardIssue from "./svg/PictogramBleedCardIssue";
106
- import PictogramSearchLens from "./svg/PictogramSearchLens";
107
- import PictogramBleedSearch from "./svg/PictogramBleedSearch";
108
- import PictogramBleedDoc from "./svg/PictogramBleedDoc";
109
117
  import PictogramDoc from "./svg/PictogramDoc";
110
- import PictogramPending from "./svg/PictogramPending";
111
- import PictogramBleedPending from "./svg/PictogramBleedPending";
112
- import PictogramMessage from "./svg/PictogramMessage";
113
- import PictogramBleedMessage from "./svg/PictogramBleedMessage";
118
+ import PictogramEmailDotCheck from "./svg/PictogramEmailDotCheck";
119
+ import PictogramEmailDotNotif from "./svg/PictogramEmailDotNotif";
120
+ import PictogramEnded from "./svg/PictogramEnded";
121
+ import PictogramEventClose from "./svg/PictogramEventClose";
114
122
  import PictogramIdea from "./svg/PictogramIdea";
115
- import PictogramBleedIdea from "./svg/PictogramBleedIdea";
123
+ import PictogramLostConnection from "./svg/PictogramLostConnection";
124
+ import PictogramMessage from "./svg/PictogramMessage";
116
125
  import PictogramMoneyCheck from "./svg/PictogramMoneyCheck";
117
- import PictogramReactivate from "./svg/PictogramReactivate";
118
- import PictogramActivate from "./svg/PictogramActivate";
119
126
  import PictogramNFCScanAndroid from "./svg/PictogramNFCScanAndroid";
120
127
  import PictogramNFCScaniOS from "./svg/PictogramNFCScaniOS";
121
- import PictogramAttachment from "./svg/PictogramAttachment";
122
- import PictogramLostConnection from "./svg/PictogramLostConnection";
128
+ import PictogramPending from "./svg/PictogramPending";
123
129
  import PictogramQrCode from "./svg/PictogramQrCode";
124
- import PictogramBleedQrCode from "./svg/PictogramBleedQrCode";
125
- import PictogramEmailDotNotif from "./svg/PictogramEmailDotNotif";
126
- import PictogramEmailDotCheck from "./svg/PictogramEmailDotCheck";
127
- import PictogramBiometric from "./svg/PictogramBiometric";
128
- import PictogramBleedLostConnection from "./svg/PictogramBleedLostConnection";
129
- import PictogramEnded from "./svg/PictogramEnded";
130
- import PictogramBleedEnded from "./svg/PictogramBleedEnded";
130
+ import PictogramReactivate from "./svg/PictogramReactivate";
131
+ import PictogramSearchLens from "./svg/PictogramSearchLens";
132
+ import PictogramStar from "./svg/PictogramStar";
133
+ import PictogramTiming from "./svg/PictogramTiming";
131
134
 
132
135
  export const IOPictograms = {
133
136
  // Start legacy pictograms //
@@ -209,6 +212,9 @@ export const IOPictograms = {
209
212
  emailDotNotif: PictogramEmailDotNotif,
210
213
  emailDotCheck: PictogramEmailDotCheck,
211
214
  biometric: PictogramBiometric,
215
+ eventClose: PictogramEventClose,
216
+ hello: PictogramHello,
217
+ comunicationProblem: PictogramComunicationProblem,
212
218
  // Start Objects Pictogram
213
219
  ibanCard: PictogramObjIbanCard,
214
220
  followMessage: PictogramObjFollowMessage,