@jobber/components-native 0.9.0 → 0.11.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 (66) hide show
  1. package/dist/src/Button/Button.js +78 -0
  2. package/dist/src/Button/Button.style.js +92 -0
  3. package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.js +36 -0
  4. package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.js +4 -0
  5. package/dist/src/Button/components/InternalButtonLoading/index.js +1 -0
  6. package/dist/src/Button/index.js +1 -0
  7. package/dist/src/Button/types.js +1 -0
  8. package/dist/src/InputFieldWrapper/CommonInputStyles.style.js +33 -0
  9. package/dist/src/InputFieldWrapper/InputFieldWrapper.js +88 -0
  10. package/dist/src/InputFieldWrapper/InputFieldWrapper.style.js +79 -0
  11. package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.js +12 -0
  12. package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.style.js +25 -0
  13. package/dist/src/InputFieldWrapper/components/ClearAction/index.js +2 -0
  14. package/dist/src/InputFieldWrapper/components/ClearAction/messages.js +8 -0
  15. package/dist/src/InputFieldWrapper/components/Prefix/Prefix.js +34 -0
  16. package/dist/src/InputFieldWrapper/components/Suffix/Suffix.js +35 -0
  17. package/dist/src/InputFieldWrapper/hooks/useShowClear.js +15 -0
  18. package/dist/src/InputFieldWrapper/index.js +3 -0
  19. package/dist/src/index.js +2 -0
  20. package/dist/tsconfig.tsbuildinfo +1 -1
  21. package/dist/types/src/Button/Button.d.ts +71 -0
  22. package/dist/types/src/Button/Button.style.d.ts +86 -0
  23. package/dist/types/src/Button/components/InternalButtonLoading/InternalButtonLoading.d.ts +11 -0
  24. package/dist/types/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.d.ts +4 -0
  25. package/dist/types/src/Button/components/InternalButtonLoading/index.d.ts +1 -0
  26. package/dist/types/src/Button/index.d.ts +2 -0
  27. package/dist/types/src/Button/types.d.ts +3 -0
  28. package/dist/types/src/InputFieldWrapper/CommonInputStyles.style.d.ts +30 -0
  29. package/dist/types/src/InputFieldWrapper/InputFieldWrapper.d.ts +63 -0
  30. package/dist/types/src/InputFieldWrapper/InputFieldWrapper.style.d.ts +82 -0
  31. package/dist/types/src/InputFieldWrapper/components/ClearAction/ClearAction.d.ts +10 -0
  32. package/dist/types/src/InputFieldWrapper/components/ClearAction/ClearAction.style.d.ts +22 -0
  33. package/dist/types/src/InputFieldWrapper/components/ClearAction/index.d.ts +2 -0
  34. package/dist/types/src/InputFieldWrapper/components/ClearAction/messages.d.ts +7 -0
  35. package/dist/types/src/InputFieldWrapper/components/Prefix/Prefix.d.ts +23 -0
  36. package/dist/types/src/InputFieldWrapper/components/Suffix/Suffix.d.ts +25 -0
  37. package/dist/types/src/InputFieldWrapper/hooks/useShowClear.d.ts +10 -0
  38. package/dist/types/src/InputFieldWrapper/index.d.ts +4 -0
  39. package/dist/types/src/index.d.ts +2 -0
  40. package/package.json +5 -2
  41. package/src/Button/Button.style.ts +116 -0
  42. package/src/Button/Button.test.tsx +298 -0
  43. package/src/Button/Button.tsx +223 -0
  44. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.ts +5 -0
  45. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.test.tsx +39 -0
  46. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.tsx +77 -0
  47. package/src/Button/components/InternalButtonLoading/index.ts +1 -0
  48. package/src/Button/index.ts +2 -0
  49. package/src/Button/types.ts +3 -0
  50. package/src/InputFieldWrapper/CommonInputStyles.style.ts +37 -0
  51. package/src/InputFieldWrapper/InputFieldWrapper.style.ts +93 -0
  52. package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +243 -0
  53. package/src/InputFieldWrapper/InputFieldWrapper.tsx +317 -0
  54. package/src/InputFieldWrapper/components/ClearAction/ClearAction.style.ts +27 -0
  55. package/src/InputFieldWrapper/components/ClearAction/ClearAction.test.tsx +15 -0
  56. package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +32 -0
  57. package/src/InputFieldWrapper/components/ClearAction/index.ts +2 -0
  58. package/src/InputFieldWrapper/components/ClearAction/messages.ts +9 -0
  59. package/src/InputFieldWrapper/components/Prefix/Prefix.test.tsx +221 -0
  60. package/src/InputFieldWrapper/components/Prefix/Prefix.tsx +104 -0
  61. package/src/InputFieldWrapper/components/Suffix/Suffix.test.tsx +101 -0
  62. package/src/InputFieldWrapper/components/Suffix/Suffix.tsx +113 -0
  63. package/src/InputFieldWrapper/hooks/useShowClear.test.ts +158 -0
  64. package/src/InputFieldWrapper/hooks/useShowClear.ts +31 -0
  65. package/src/InputFieldWrapper/index.ts +4 -0
  66. package/src/index.ts +2 -0
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { Pressable, View } from "react-native";
3
+ import { useIntl } from "react-intl";
4
+ import { styles } from "./ClearAction.style";
5
+ import { messages } from "./messages";
6
+ import { Icon } from "../../../Icon";
7
+
8
+ interface ClearActionProps {
9
+ /**
10
+ * Press handler
11
+ */
12
+ readonly onPress: () => void;
13
+ readonly hasMarginRight?: boolean;
14
+ }
15
+
16
+ export function ClearAction({
17
+ onPress,
18
+ hasMarginRight = false,
19
+ }: ClearActionProps): JSX.Element {
20
+ const { formatMessage } = useIntl();
21
+ return (
22
+ <Pressable
23
+ style={[styles.container, hasMarginRight && styles.addedMargin]}
24
+ onPress={onPress}
25
+ accessibilityLabel={formatMessage(messages.clearTextLabel)}
26
+ >
27
+ <View style={styles.circle}>
28
+ <Icon size="small" name="cross" color="interactiveSubtle" />
29
+ </View>
30
+ </Pressable>
31
+ );
32
+ }
@@ -0,0 +1,2 @@
1
+ export { ClearAction } from "./ClearAction";
2
+ export { messages } from "./messages";
@@ -0,0 +1,9 @@
1
+ import { defineMessages } from "react-intl";
2
+
3
+ export const messages = defineMessages({
4
+ clearTextLabel: {
5
+ id: "clearTextLabel",
6
+ defaultMessage: "Clear input",
7
+ description: "Accessiblity label for the clear input button",
8
+ },
9
+ });
@@ -0,0 +1,221 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { TextStyle } from "react-native";
4
+ import { ReactTestInstance } from "react-test-renderer";
5
+ import {
6
+ PrefixIcon,
7
+ PrefixIconProps,
8
+ PrefixLabel,
9
+ PrefixLabelProps,
10
+ prefixIconTestId,
11
+ prefixLabelTestId,
12
+ } from "./Prefix";
13
+ import { typographyStyles } from "../../../Typography";
14
+ import { styles } from "../../InputFieldWrapper.style";
15
+ import { tokens } from "../../../utils/design";
16
+ import * as IconComponent from "../../../Icon/Icon";
17
+
18
+ const iconSpy = jest.spyOn(IconComponent, "Icon");
19
+
20
+ const mockLabel = "$";
21
+
22
+ function setupLabel({
23
+ disabled = false,
24
+ focused = false,
25
+ hasMiniLabel = false,
26
+ inputInvalid = false,
27
+ label = mockLabel,
28
+ styleOverride,
29
+ }: Partial<PrefixLabelProps>) {
30
+ return render(
31
+ <PrefixLabel
32
+ disabled={disabled}
33
+ focused={focused}
34
+ hasMiniLabel={hasMiniLabel}
35
+ inputInvalid={inputInvalid}
36
+ label={label}
37
+ styleOverride={styleOverride}
38
+ />,
39
+ );
40
+ }
41
+
42
+ function setupIcon({
43
+ disabled = false,
44
+ focused = false,
45
+ hasMiniLabel = false,
46
+ inputInvalid = false,
47
+ icon = "invoice",
48
+ }: Partial<PrefixIconProps>) {
49
+ return render(
50
+ <PrefixIcon
51
+ disabled={disabled}
52
+ focused={focused}
53
+ hasMiniLabel={hasMiniLabel}
54
+ inputInvalid={inputInvalid}
55
+ icon={icon}
56
+ />,
57
+ );
58
+ }
59
+
60
+ describe("Prefix", () => {
61
+ it("renders a prefix label when specified", () => {
62
+ const { getByText } = setupLabel({});
63
+ expect(getByText(mockLabel)).toBeDefined();
64
+ });
65
+
66
+ it("renders a prefix icon when specified", () => {
67
+ const { getByTestId } = setupIcon({});
68
+ expect(getByTestId("invoice")).toBeDefined();
69
+ });
70
+
71
+ describe("updates the styles when focused", () => {
72
+ it("for the label", () => {
73
+ const tree = setupLabel({
74
+ focused: true,
75
+ });
76
+ const expectedStyle = { ...styles.fieldAffix, ...styles.inputFocused };
77
+ const prefixLabel = tree.getByTestId(prefixLabelTestId);
78
+ const flattenedStyle = prefixLabel.props.style.reduce(
79
+ (style: TextStyle, additionalStyles: TextStyle) => ({
80
+ ...style,
81
+ ...additionalStyles,
82
+ }),
83
+ {},
84
+ );
85
+
86
+ expect(flattenedStyle).toEqual(expectedStyle);
87
+ });
88
+
89
+ it("for the icon", () => {
90
+ const tree = setupIcon({
91
+ focused: true,
92
+ });
93
+ const expectedStyle = { ...styles.fieldAffix, ...styles.inputFocused };
94
+ const icon = tree.getByTestId(prefixIconTestId);
95
+ const flattenedStyle = icon.props.style.reduce(
96
+ (style: TextStyle, additionalStyles: TextStyle) => ({
97
+ ...style,
98
+ ...additionalStyles,
99
+ }),
100
+ {},
101
+ );
102
+
103
+ expect(flattenedStyle).toEqual(expectedStyle);
104
+ });
105
+ });
106
+
107
+ describe("updates the styles when input is invalid", () => {
108
+ it("for the label", () => {
109
+ const tree = setupLabel({
110
+ inputInvalid: true,
111
+ });
112
+ const expectedStyle = { ...styles.fieldAffix, ...styles.inputInvalid };
113
+ const prefixLabel = tree.getByTestId(prefixLabelTestId);
114
+ const flattenedStyle = prefixLabel.props.style.reduce(
115
+ (style: TextStyle, additionalStyles: TextStyle) => ({
116
+ ...style,
117
+ ...additionalStyles,
118
+ }),
119
+ {},
120
+ );
121
+
122
+ expect(flattenedStyle).toEqual(expectedStyle);
123
+ });
124
+
125
+ it("for the icon", () => {
126
+ const tree = setupIcon({
127
+ inputInvalid: true,
128
+ });
129
+ const expectedStyle = { ...styles.fieldAffix, ...styles.inputInvalid };
130
+ const prefixIcon = tree.getByTestId(prefixIconTestId);
131
+ const flattenedStyle = prefixIcon.props.style.reduce(
132
+ (style: TextStyle, additionalStyles: TextStyle) => ({
133
+ ...style,
134
+ ...additionalStyles,
135
+ }),
136
+ {},
137
+ );
138
+
139
+ expect(flattenedStyle).toEqual(expectedStyle);
140
+ });
141
+ });
142
+
143
+ it("updates the position of the label when a value is entered", () => {
144
+ const tree = setupLabel({
145
+ hasMiniLabel: true,
146
+ });
147
+ const prefixLabel = tree.getByTestId(prefixLabelTestId);
148
+ const labelWrapper = prefixLabel.children[0] as ReactTestInstance;
149
+ const expectedStyle = [styles.prefixLabel, styles.fieldAffixMiniLabel];
150
+ expect(labelWrapper.props.style).toEqual(expectedStyle);
151
+ });
152
+
153
+ describe("when disabled", () => {
154
+ it("updates the label", () => {
155
+ const tree = setupLabel({
156
+ disabled: true,
157
+ });
158
+ const prefixLabel = tree.getByText(mockLabel);
159
+ const expectedStyle = [
160
+ typographyStyles.baseRegularRegular,
161
+ typographyStyles.disabled,
162
+ typographyStyles.startAlign,
163
+ typographyStyles.defaultSize,
164
+ typographyStyles.baseLetterSpacing,
165
+ ];
166
+ expect(prefixLabel.props.style).toEqual(expectedStyle);
167
+ });
168
+
169
+ it("updates the icon", () => {
170
+ setupIcon({
171
+ disabled: true,
172
+ });
173
+ expect(iconSpy).toHaveBeenCalledWith(
174
+ {
175
+ customColor: tokens["color-disabled"],
176
+ name: "invoice",
177
+ },
178
+ {},
179
+ );
180
+ });
181
+ });
182
+
183
+ describe("Custom Label Style", () => {
184
+ it("uses default styling when style override not used", () => {
185
+ const { getByText } = setupLabel({});
186
+ const prefix = getByText(mockLabel);
187
+ const expectedStyle = [
188
+ typographyStyles.baseRegularRegular,
189
+ typographyStyles.base,
190
+ typographyStyles.startAlign,
191
+ typographyStyles.defaultSize,
192
+ typographyStyles.baseLetterSpacing,
193
+ ];
194
+ expect(prefix.props.style).toEqual(expectedStyle);
195
+ });
196
+
197
+ it("uses style override for label when provided", () => {
198
+ const styleOverride = {
199
+ fontSize: 50,
200
+ color: "purple",
201
+ };
202
+ const { getByText } = setupLabel({ styleOverride });
203
+ const prefix = getByText(mockLabel);
204
+ const flattenedStyle = prefix.props.style.reduce(
205
+ (style: TextStyle, additionalStyles: TextStyle) => ({
206
+ ...style,
207
+ ...additionalStyles,
208
+ }),
209
+ {},
210
+ );
211
+
212
+ const expectedStyle = {
213
+ ...styleOverride,
214
+ ...typographyStyles.baseRegularRegular,
215
+ lineHeight: typographyStyles.defaultSize.lineHeight,
216
+ };
217
+
218
+ expect(flattenedStyle).toEqual(expectedStyle);
219
+ });
220
+ });
221
+ });
@@ -0,0 +1,104 @@
1
+ import React from "react";
2
+ import {
3
+ // eslint-disable-next-line no-restricted-imports
4
+ Text as RNText,
5
+ StyleProp,
6
+ TextStyle,
7
+ View,
8
+ ViewStyle,
9
+ } from "react-native";
10
+ import { IconNames } from "@jobber/design";
11
+ import { Icon } from "../../../Icon";
12
+ import { Text } from "../../../Text";
13
+ import { tokens } from "../../../utils/design";
14
+ import { typographyStyles } from "../../../Typography";
15
+ import { styles } from "../../InputFieldWrapper.style";
16
+
17
+ export interface PrefixLabelProps {
18
+ focused: boolean;
19
+ disabled?: boolean;
20
+ hasMiniLabel: boolean;
21
+ inputInvalid: boolean;
22
+ label: string;
23
+ styleOverride?: StyleProp<TextStyle>;
24
+ }
25
+
26
+ export const prefixLabelTestId = "ATL-InputFieldWrapper-PrefixLabel";
27
+ export const prefixIconTestId = "ATL-InputFieldWrapper-PrefixIcon";
28
+
29
+ export function PrefixLabel({
30
+ focused,
31
+ disabled,
32
+ hasMiniLabel,
33
+ inputInvalid,
34
+ label,
35
+ styleOverride,
36
+ }: PrefixLabelProps): JSX.Element {
37
+ return (
38
+ <View
39
+ style={[
40
+ styles.fieldAffix,
41
+ focused && styles.inputFocused,
42
+ inputInvalid && styles.inputInvalid,
43
+ ]}
44
+ testID={prefixLabelTestId}
45
+ >
46
+ <View
47
+ style={[styles.prefixLabel, hasMiniLabel && styles.fieldAffixMiniLabel]}
48
+ >
49
+ {!styleOverride ? (
50
+ <Text variation={disabled ? "disabled" : "base"}>{label}</Text>
51
+ ) : (
52
+ <RNText
53
+ allowFontScaling={true}
54
+ style={[
55
+ typographyStyles.baseRegularRegular,
56
+ typographyStyles.base,
57
+ typographyStyles.defaultSize,
58
+ disabled ? typographyStyles.subdued : typographyStyles.base,
59
+ styleOverride,
60
+ ]}
61
+ >
62
+ {label}
63
+ </RNText>
64
+ )}
65
+ </View>
66
+ </View>
67
+ );
68
+ }
69
+
70
+ export interface PrefixIconProps {
71
+ focused: boolean;
72
+ disabled?: boolean;
73
+ hasMiniLabel: boolean;
74
+ inputInvalid?: boolean;
75
+ icon: IconNames;
76
+ styleOverride?: StyleProp<ViewStyle>;
77
+ }
78
+
79
+ export function PrefixIcon({
80
+ focused,
81
+ disabled,
82
+ inputInvalid,
83
+ icon,
84
+ }: PrefixIconProps): JSX.Element {
85
+ return (
86
+ <View
87
+ testID={prefixIconTestId}
88
+ style={[
89
+ styles.fieldAffix,
90
+ focused && styles.inputFocused,
91
+ inputInvalid && styles.inputInvalid,
92
+ ]}
93
+ >
94
+ <View style={styles.prefixIcon}>
95
+ <Icon
96
+ customColor={
97
+ disabled ? tokens["color-disabled"] : tokens["color-greyBlue"]
98
+ }
99
+ name={icon}
100
+ />
101
+ </View>
102
+ </View>
103
+ );
104
+ }
@@ -0,0 +1,101 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { TextStyle } from "react-native";
4
+ import {
5
+ SuffixIcon,
6
+ SuffixIconProps,
7
+ SuffixLabel,
8
+ SuffixLabelProps,
9
+ } from "./Suffix";
10
+ import { typographyStyles } from "../../../Typography";
11
+
12
+ const mockLabel = "$";
13
+
14
+ function setupLabel({
15
+ disabled = false,
16
+ focused = false,
17
+ hasMiniLabel = false,
18
+ inputInvalid = false,
19
+ label = mockLabel,
20
+ styleOverride,
21
+ }: Partial<SuffixLabelProps>) {
22
+ return render(
23
+ <SuffixLabel
24
+ disabled={disabled}
25
+ focused={focused}
26
+ hasMiniLabel={hasMiniLabel}
27
+ inputInvalid={inputInvalid}
28
+ label={label}
29
+ styleOverride={styleOverride}
30
+ />,
31
+ );
32
+ }
33
+
34
+ function setupIcon({
35
+ disabled = false,
36
+ focused = false,
37
+ hasMiniLabel = false,
38
+ inputInvalid = false,
39
+ icon = "invoice",
40
+ }: Partial<SuffixIconProps>) {
41
+ return render(
42
+ <SuffixIcon
43
+ disabled={disabled}
44
+ focused={focused}
45
+ hasMiniLabel={hasMiniLabel}
46
+ inputInvalid={inputInvalid}
47
+ icon={icon}
48
+ />,
49
+ );
50
+ }
51
+
52
+ describe("Suffix", () => {
53
+ it("renders a suffix label when specified", () => {
54
+ const { getByText } = setupLabel({});
55
+ expect(getByText(mockLabel)).toBeDefined();
56
+ });
57
+
58
+ it("renders a suffix icon when specified", () => {
59
+ const { getByTestId } = setupIcon({});
60
+ expect(getByTestId("invoice")).toBeDefined();
61
+ });
62
+
63
+ describe("Custom Label Style", () => {
64
+ it("uses default styling when no style override is provided", () => {
65
+ const { getByText } = setupLabel({});
66
+ const suffix = getByText(mockLabel);
67
+ const expectedStyle = [
68
+ typographyStyles.baseRegularRegular,
69
+ typographyStyles.base,
70
+ typographyStyles.startAlign,
71
+ typographyStyles.defaultSize,
72
+ typographyStyles.baseLetterSpacing,
73
+ ];
74
+ expect(suffix.props.style).toEqual(expectedStyle);
75
+ });
76
+
77
+ it("uses style override for label when provided", () => {
78
+ const styleOverride = {
79
+ fontSize: 50,
80
+ color: "purple",
81
+ };
82
+ const { getByText } = setupLabel({ styleOverride });
83
+ const suffix = getByText(mockLabel);
84
+ const flattenedStyle = suffix.props.style.reduce(
85
+ (style: TextStyle, additionalStyles: TextStyle) => ({
86
+ ...style,
87
+ ...additionalStyles,
88
+ }),
89
+ {},
90
+ );
91
+
92
+ const expectedStyle = {
93
+ ...typographyStyles.baseRegularRegular,
94
+ lineHeight: typographyStyles.defaultSize.lineHeight,
95
+ ...styleOverride,
96
+ };
97
+
98
+ expect(flattenedStyle).toEqual(expectedStyle);
99
+ });
100
+ });
101
+ });
@@ -0,0 +1,113 @@
1
+ import React from "react";
2
+ import {
3
+ Pressable,
4
+ // eslint-disable-next-line no-restricted-imports
5
+ Text as RNText,
6
+ StyleProp,
7
+ TextStyle,
8
+ View,
9
+ } from "react-native";
10
+ import { IconNames } from "@jobber/design";
11
+ import { tokens } from "../../../utils/design";
12
+ import { Icon } from "../../../Icon";
13
+ import { Text } from "../../../Text";
14
+ import { typographyStyles } from "../../../Typography";
15
+ import { styles } from "../../InputFieldWrapper.style";
16
+
17
+ export interface SuffixLabelProps {
18
+ focused: boolean;
19
+ disabled?: boolean;
20
+ hasMiniLabel: boolean;
21
+ inputInvalid?: boolean;
22
+ label: string;
23
+ hasLeftMargin?: boolean;
24
+ styleOverride?: StyleProp<TextStyle>;
25
+ }
26
+
27
+ export const suffixLabelTestId = "ATL-InputFieldWrapper-SuffixLabel";
28
+ export const suffixIconTestId = "ATL-InputFieldWrapper-SuffixIcon";
29
+
30
+ export function SuffixLabel({
31
+ focused,
32
+ disabled,
33
+ hasMiniLabel,
34
+ inputInvalid,
35
+ label,
36
+ hasLeftMargin = true,
37
+ styleOverride,
38
+ }: SuffixLabelProps): JSX.Element {
39
+ return (
40
+ <View
41
+ testID={suffixLabelTestId}
42
+ style={[
43
+ styles.fieldAffix,
44
+ focused && styles.inputFocused,
45
+ inputInvalid && styles.inputInvalid,
46
+ hasLeftMargin && styles.suffixLabelMargin,
47
+ ]}
48
+ >
49
+ <View
50
+ style={[styles.suffixLabel, hasMiniLabel && styles.fieldAffixMiniLabel]}
51
+ >
52
+ {!styleOverride ? (
53
+ <Text variation={disabled ? "disabled" : "base"}>{label}</Text>
54
+ ) : (
55
+ <RNText
56
+ allowFontScaling={true}
57
+ style={[
58
+ typographyStyles.baseRegularRegular,
59
+ typographyStyles.base,
60
+ typographyStyles.defaultSize,
61
+ disabled ? typographyStyles.subdued : typographyStyles.base,
62
+ styleOverride,
63
+ ]}
64
+ >
65
+ {label}
66
+ </RNText>
67
+ )}
68
+ </View>
69
+ </View>
70
+ );
71
+ }
72
+
73
+ export interface SuffixIconProps {
74
+ focused: boolean;
75
+ disabled?: boolean;
76
+ hasMiniLabel: boolean;
77
+ inputInvalid?: boolean;
78
+ icon: IconNames;
79
+ hasLeftMargin?: boolean;
80
+ onPress?: () => void;
81
+ }
82
+
83
+ export function SuffixIcon({
84
+ focused,
85
+ disabled,
86
+ inputInvalid,
87
+ icon,
88
+ hasLeftMargin = false,
89
+ onPress,
90
+ }: SuffixIconProps): JSX.Element {
91
+ return (
92
+ <View
93
+ testID={suffixIconTestId}
94
+ style={[
95
+ styles.fieldAffix,
96
+ focused && styles.inputFocused,
97
+ inputInvalid && styles.inputInvalid,
98
+ ]}
99
+ >
100
+ <Pressable
101
+ style={[styles.suffixIcon, hasLeftMargin && styles.suffixIconMargin]}
102
+ onPress={onPress}
103
+ >
104
+ <Icon
105
+ customColor={
106
+ disabled ? tokens["color-disabled"] : tokens["color-greyBlue"]
107
+ }
108
+ name={icon}
109
+ />
110
+ </Pressable>
111
+ </View>
112
+ );
113
+ }