@jobber/components-native 0.54.4-JOB-88641.9 → 0.54.4-fix-inline.6
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/dist/package.json +7 -7
- package/dist/src/ActionItem/ActionItem.js +1 -1
- package/dist/src/Banner/Banner.js +1 -1
- package/dist/src/Button/Button.js +2 -2
- package/dist/src/Button/Button.style.js +2 -2
- package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.js +3 -0
- package/dist/src/ButtonGroup/ButtonGroup.js +1 -1
- package/dist/src/ButtonGroup/ButtonGroup.style.js +1 -1
- package/dist/src/Card/Card.js +7 -8
- package/dist/src/Disclosure/Disclosure.js +3 -3
- package/dist/src/Glimmer/Glimmer.js +42 -0
- package/dist/src/Glimmer/Glimmer.shape.style.js +16 -0
- package/dist/src/Glimmer/Glimmer.size.style.js +9 -0
- package/dist/src/Glimmer/Glimmer.style.js +20 -0
- package/dist/src/Glimmer/index.js +1 -0
- package/dist/src/InputCurrency/InputCurrency.js +16 -17
- package/dist/src/InputFieldWrapper/InputFieldWrapper.js +39 -18
- package/dist/src/InputFieldWrapper/InputFieldWrapper.style.js +38 -1
- package/dist/src/InputText/InputText.js +6 -3
- package/dist/src/Menu/Menu.js +20 -3
- package/dist/src/Menu/Menu.style.js +1 -1
- package/dist/src/Menu/utils.js +2 -7
- package/dist/src/index.js +6 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.d.ts +1 -1
- package/dist/types/src/ButtonGroup/ButtonGroup.style.d.ts +1 -1
- package/dist/types/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.d.ts +6 -6
- package/dist/types/src/Checkbox/CheckboxGroup.d.ts +2 -2
- package/dist/types/src/Form/components/FormBody/FormBody.d.ts +3 -3
- package/dist/types/src/Form/components/FormCache/FormCache.d.ts +4 -4
- package/dist/types/src/Form/components/FormMessageBanner/FormMessageBanner.d.ts +1 -1
- package/dist/types/src/FormField/FormField.d.ts +2 -2
- package/dist/types/src/FormatFile/FormatFile.d.ts +6 -6
- package/dist/types/src/FormatFile/components/FileView/FileView.d.ts +6 -6
- package/dist/types/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.d.ts +4 -4
- package/dist/types/src/FormatFile/components/MediaView/MediaView.d.ts +6 -6
- package/dist/types/src/FormatFile/components/ProgressBar/ProgressBar.d.ts +3 -3
- package/dist/types/src/Glimmer/Glimmer.d.ts +31 -0
- package/dist/types/src/Glimmer/Glimmer.shape.style.d.ts +14 -0
- package/dist/types/src/Glimmer/Glimmer.size.style.d.ts +17 -0
- package/dist/types/src/Glimmer/Glimmer.style.d.ts +18 -0
- package/dist/types/src/Glimmer/index.d.ts +1 -0
- package/dist/types/src/InputCurrency/InputCurrency.d.ts +3 -3
- package/dist/types/src/InputFieldWrapper/InputFieldWrapper.d.ts +19 -1
- package/dist/types/src/InputFieldWrapper/InputFieldWrapper.style.d.ts +34 -0
- package/dist/types/src/InputFieldWrapper/components/Prefix/Prefix.d.ts +12 -12
- package/dist/types/src/InputFieldWrapper/components/Suffix/Suffix.d.ts +14 -14
- package/dist/types/src/InputPassword/InputPassword.d.ts +1 -1
- package/dist/types/src/InputText/InputText.d.ts +6 -2
- package/dist/types/src/InputText/context/InputAccessoriesProvider.d.ts +1 -1
- package/dist/types/src/Toast/Toast.d.ts +1 -1
- package/dist/types/src/index.d.ts +6 -5
- package/dist/types/src/utils/test/MockSafeAreaProvider.d.ts +3 -3
- package/jestSetup.js +2 -0
- package/package.json +7 -7
- package/src/ActionItem/ActionItem.test.tsx +2 -2
- package/src/ActionItem/ActionItem.tsx +3 -1
- package/src/ActionItem/ActionItemGroup.tsx +1 -0
- package/src/AutoLink/hooks/useCreateLinkedText.ts +1 -0
- package/src/AutoLink/hooks/useTokenGenerator.ts +1 -0
- package/src/Banner/Banner.tsx +1 -1
- package/src/BottomSheet/BottomSheet.tsx +3 -3
- package/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.tsx +3 -1
- package/src/Button/Button.style.ts +2 -2
- package/src/Button/Button.test.tsx +2 -2
- package/src/Button/Button.tsx +2 -2
- package/src/Button/components/InternalButtonLoading/InternalButtonLoading.tsx +4 -0
- package/src/ButtonGroup/ButtonGroup.style.ts +1 -1
- package/src/ButtonGroup/ButtonGroup.tsx +1 -0
- package/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.tsx +7 -6
- package/src/Card/Card.tsx +31 -32
- package/src/Card/components/InternalCardHeader.tsx +1 -0
- package/src/Checkbox/CheckboxGroup.tsx +12 -2
- package/src/Chip/Chip.tsx +2 -0
- package/src/Content/Content.test.tsx +1 -0
- package/src/Content/Content.tsx +1 -0
- package/src/ContentOverlay/ContentOverlay.test.tsx +1 -0
- package/src/Disclosure/Disclosure.tsx +3 -8
- package/src/Disclosure/__snapshots__/Disclosure.test.tsx.snap +18 -24
- package/src/Divider/Divider.tsx +1 -0
- package/src/EmptyState/EmptyState.tsx +2 -2
- package/src/Flex/Flex.styles.tsx +1 -0
- package/src/Flex/Flex.test.tsx +2 -0
- package/src/Form/Form.test.tsx +19 -14
- package/src/Form/components/FormBody/FormBody.tsx +4 -3
- package/src/Form/components/FormCache/FormCache.tsx +5 -4
- package/src/Form/components/FormMessage/FormMessage.tsx +1 -0
- package/src/Form/components/FormMessageBanner/FormMessageBanner.tsx +1 -1
- package/src/Form/components/FormSaveButton/FormSaveButton.test.tsx +5 -5
- package/src/Form/context/AtlantisFormContext.tsx +1 -0
- package/src/Form/hooks/useFormViewRefs.ts +1 -0
- package/src/Form/hooks/useOfflineHandler.ts +1 -0
- package/src/Form/hooks/useScrollToError/useScrollToError.ts +2 -0
- package/src/FormField/FormField.test.tsx +6 -8
- package/src/FormField/FormField.tsx +2 -2
- package/src/FormatFile/FormatFile.tsx +15 -14
- package/src/FormatFile/components/FileView/FileView.tsx +9 -6
- package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.tsx +4 -4
- package/src/FormatFile/components/MediaView/MediaView.tsx +15 -14
- package/src/FormatFile/components/ProgressBar/ProgressBar.tsx +3 -3
- package/src/FormatFile/utils/createUseCreateThumbnail.ts +1 -0
- package/src/Glimmer/Glimmer.shape.style.ts +17 -0
- package/src/Glimmer/Glimmer.size.style.ts +10 -0
- package/src/Glimmer/Glimmer.style.ts +23 -0
- package/src/Glimmer/Glimmer.test.tsx +73 -0
- package/src/Glimmer/Glimmer.tsx +106 -0
- package/src/Glimmer/index.ts +1 -0
- package/src/Heading/__snapshots__/Heading.test.tsx.snap +7 -7
- package/src/Icon/Icon.tsx +1 -0
- package/src/Icon/__snapshots__/Icon.test.tsx.snap +96 -31
- package/src/InputCurrency/InputCurrency.tsx +40 -38
- package/src/InputCurrency/utils.ts +9 -0
- package/src/InputDate/InputDate.test.tsx +1 -0
- package/src/InputFieldWrapper/InputFieldWrapper.style.ts +46 -1
- package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +74 -0
- package/src/InputFieldWrapper/InputFieldWrapper.tsx +131 -64
- package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +1 -0
- package/src/InputFieldWrapper/components/Prefix/Prefix.tsx +12 -12
- package/src/InputFieldWrapper/components/Suffix/Suffix.tsx +14 -14
- package/src/InputNumber/InputNumber.tsx +8 -0
- package/src/InputPassword/InputPassword.test.tsx +1 -0
- package/src/InputPassword/InputPassword.tsx +2 -1
- package/src/InputPressable/InputPressable.test.tsx +1 -0
- package/src/InputSearch/InputSearch.tsx +1 -0
- package/src/InputText/InputText.test.tsx +11 -0
- package/src/InputText/InputText.tsx +27 -2
- package/src/InputText/context/InputAccessoriesProvider.test.tsx +6 -1
- package/src/InputText/context/InputAccessoriesProvider.tsx +1 -1
- package/src/InputTime/utils/index.ts +1 -0
- package/src/Menu/Menu.style.ts +1 -1
- package/src/Menu/Menu.tsx +23 -2
- package/src/Menu/components/MenuOption/MenuOption.tsx +1 -0
- package/src/Menu/utils.ts +3 -7
- package/src/ProgressBar/ProgressBarInner.tsx +1 -0
- package/src/ProgressBar/__snapshots__/ProgressBar.test.tsx.snap +4 -4
- package/src/Select/components/SelectInternalPicker/SelectInternalPicker.tsx +1 -0
- package/src/Select/components/SelectInternalPicker/utils.ts +1 -0
- package/src/StatusLabel/StatusLabel.tsx +1 -1
- package/src/StatusLabel/__snapshots__/StatusLabel.test.tsx.snap +20 -20
- package/src/Switch/components/BaseSwitch/BaseSwitch.tsx +1 -0
- package/src/Switch/components/BaseSwitch/__snapshots__/BaseSwitch.test.tsx.snap +18 -18
- package/src/Text/Text.tsx +1 -0
- package/src/Text/__snapshots__/Text.test.tsx.snap +9 -9
- package/src/ThumbnailList/__snapshots__/ThumbnailList.test.tsx.snap +3 -3
- package/src/Toast/Toast.tsx +2 -1
- package/src/Typography/Typography.tsx +5 -0
- package/src/Typography/__snapshots__/Typography.test.tsx.snap +3 -3
- package/src/hooks/useAtlantisI18n/utils/dateFormatter.ts +1 -0
- package/src/hooks/useFormController.ts +2 -0
- package/src/index.ts +6 -5
- package/src/utils/intl/capitalize.ts +1 -0
- package/src/utils/test/MockSafeAreaProvider.tsx +3 -3
|
@@ -13,9 +13,11 @@ import { styles } from "./InputFieldWrapper.style";
|
|
|
13
13
|
import { PrefixIcon, PrefixLabel } from "./components/Prefix/Prefix";
|
|
14
14
|
import { SuffixIcon, SuffixLabel } from "./components/Suffix/Suffix";
|
|
15
15
|
import { ClearAction } from "./components/ClearAction";
|
|
16
|
+
import { Glimmer } from "../Glimmer/Glimmer";
|
|
16
17
|
import { ErrorMessageWrapper } from "../ErrorMessageWrapper";
|
|
17
18
|
import { TextVariation, typographyStyles } from "../Typography";
|
|
18
19
|
import { Text } from "../Text";
|
|
20
|
+
import { ActivityIndicator } from "../ActivityIndicator";
|
|
19
21
|
|
|
20
22
|
export type Clearable = "never" | "while-editing" | "always";
|
|
21
23
|
|
|
@@ -88,8 +90,33 @@ export interface InputFieldWrapperProps {
|
|
|
88
90
|
* Custom styling to override default style of the input field
|
|
89
91
|
*/
|
|
90
92
|
readonly styleOverride?: InputFieldStyleOverride;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Add a toolbar below the input field for actions like rewriting the text.
|
|
96
|
+
*/
|
|
97
|
+
readonly toolbar?: React.ReactNode;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Change the behaviour of when the toolbar becomes visible.
|
|
101
|
+
*/
|
|
102
|
+
readonly toolbarVisibility?: "always" | "while-editing";
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Show loading indicator.
|
|
106
|
+
*/
|
|
107
|
+
readonly loading?: boolean;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Change the type of loading indicator to spinner or glimmer.
|
|
111
|
+
*/
|
|
112
|
+
readonly loadingType?: "spinner" | "glimmer";
|
|
91
113
|
}
|
|
92
114
|
|
|
115
|
+
export const INPUT_FIELD_WRAPPER_GLIMMERS_TEST_ID =
|
|
116
|
+
"ATL-InputFieldWrapper-Glimmers";
|
|
117
|
+
export const INPUT_FIELD_WRAPPER_SPINNER_TEST_ID =
|
|
118
|
+
"ATL-InputFieldWrapper-Spinner";
|
|
119
|
+
|
|
93
120
|
export function InputFieldWrapper({
|
|
94
121
|
invalid,
|
|
95
122
|
disabled,
|
|
@@ -105,11 +132,20 @@ export function InputFieldWrapper({
|
|
|
105
132
|
onClear,
|
|
106
133
|
showClearAction = false,
|
|
107
134
|
styleOverride,
|
|
135
|
+
toolbar,
|
|
136
|
+
toolbarVisibility = "while-editing",
|
|
137
|
+
loading = false,
|
|
138
|
+
loadingType = "spinner",
|
|
108
139
|
}: InputFieldWrapperProps): JSX.Element {
|
|
109
140
|
fieldAffixRequiredPropsCheck([prefix, suffix]);
|
|
110
141
|
const handleClear = onClear ?? noopClear;
|
|
111
142
|
warnIfClearActionWithNoOnClear(onClear, showClearAction);
|
|
112
143
|
const inputInvalid = Boolean(invalid) || Boolean(error);
|
|
144
|
+
const isToolbarVisible =
|
|
145
|
+
toolbar && (toolbarVisibility === "always" || focused);
|
|
146
|
+
|
|
147
|
+
const showLoadingSpinner = loading && loadingType === "spinner";
|
|
148
|
+
const showLoadingGlimmer = loading && loadingType === "glimmer";
|
|
113
149
|
|
|
114
150
|
return (
|
|
115
151
|
<ErrorMessageWrapper message={getMessage({ invalid, error })}>
|
|
@@ -123,78 +159,109 @@ export function InputFieldWrapper({
|
|
|
123
159
|
styleOverride?.container,
|
|
124
160
|
]}
|
|
125
161
|
>
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
focused={focused}
|
|
130
|
-
hasMiniLabel={hasMiniLabel}
|
|
131
|
-
inputInvalid={inputInvalid}
|
|
132
|
-
icon={prefix.icon}
|
|
133
|
-
/>
|
|
134
|
-
)}
|
|
135
|
-
<View style={[styles.inputContainer]}>
|
|
136
|
-
<View
|
|
137
|
-
style={[
|
|
138
|
-
!!placeholder && styles.label,
|
|
139
|
-
hasMiniLabel && styles.miniLabel,
|
|
140
|
-
disabled && styles.disabled,
|
|
141
|
-
hasMiniLabel &&
|
|
142
|
-
showClearAction &&
|
|
143
|
-
styles.miniLabelShowClearAction,
|
|
144
|
-
]}
|
|
145
|
-
pointerEvents="none"
|
|
146
|
-
>
|
|
147
|
-
<Placeholder
|
|
148
|
-
placeholder={placeholder}
|
|
149
|
-
labelVariation={getLabelVariation(error, invalid, disabled)}
|
|
150
|
-
hasMiniLabel={hasMiniLabel}
|
|
151
|
-
styleOverride={styleOverride?.placeholderText}
|
|
152
|
-
/>
|
|
153
|
-
</View>
|
|
154
|
-
{prefix?.label && hasValue && (
|
|
155
|
-
<PrefixLabel
|
|
162
|
+
<View style={styles.field}>
|
|
163
|
+
{prefix?.icon && (
|
|
164
|
+
<PrefixIcon
|
|
156
165
|
disabled={disabled}
|
|
157
166
|
focused={focused}
|
|
158
167
|
hasMiniLabel={hasMiniLabel}
|
|
159
168
|
inputInvalid={inputInvalid}
|
|
160
|
-
|
|
161
|
-
styleOverride={styleOverride?.prefixLabel}
|
|
169
|
+
icon={prefix.icon}
|
|
162
170
|
/>
|
|
163
171
|
)}
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
/>
|
|
183
|
-
)}
|
|
184
|
-
{suffix?.icon && (
|
|
185
|
-
<SuffixIcon
|
|
186
|
-
disabled={disabled}
|
|
187
|
-
focused={focused}
|
|
188
|
-
hasMiniLabel={hasMiniLabel}
|
|
189
|
-
hasLeftMargin={!!(!showClearAction || suffix?.label)}
|
|
190
|
-
inputInvalid={inputInvalid}
|
|
191
|
-
icon={suffix.icon}
|
|
192
|
-
onPress={suffix.onPress}
|
|
193
|
-
/>
|
|
194
|
-
)}
|
|
172
|
+
<View style={[styles.inputContainer]}>
|
|
173
|
+
<View
|
|
174
|
+
style={[
|
|
175
|
+
!!placeholder && styles.label,
|
|
176
|
+
hasMiniLabel && styles.miniLabel,
|
|
177
|
+
disabled && styles.disabled,
|
|
178
|
+
hasMiniLabel &&
|
|
179
|
+
showClearAction &&
|
|
180
|
+
styles.miniLabelShowClearAction,
|
|
181
|
+
]}
|
|
182
|
+
pointerEvents="none"
|
|
183
|
+
>
|
|
184
|
+
<Placeholder
|
|
185
|
+
placeholder={placeholder}
|
|
186
|
+
labelVariation={getLabelVariation(error, invalid, disabled)}
|
|
187
|
+
hasMiniLabel={hasMiniLabel}
|
|
188
|
+
styleOverride={styleOverride?.placeholderText}
|
|
189
|
+
/>
|
|
195
190
|
</View>
|
|
196
|
-
|
|
191
|
+
{prefix?.label && hasValue && (
|
|
192
|
+
<PrefixLabel
|
|
193
|
+
disabled={disabled}
|
|
194
|
+
focused={focused}
|
|
195
|
+
hasMiniLabel={hasMiniLabel}
|
|
196
|
+
inputInvalid={inputInvalid}
|
|
197
|
+
label={prefix.label}
|
|
198
|
+
styleOverride={styleOverride?.prefixLabel}
|
|
199
|
+
/>
|
|
200
|
+
)}
|
|
201
|
+
{children}
|
|
202
|
+
|
|
203
|
+
{showLoadingGlimmer && (
|
|
204
|
+
<View
|
|
205
|
+
testID={INPUT_FIELD_WRAPPER_GLIMMERS_TEST_ID}
|
|
206
|
+
style={[
|
|
207
|
+
styles.loadingGlimmers,
|
|
208
|
+
hasValue && styles.loadingGlimmersHasValue,
|
|
209
|
+
]}
|
|
210
|
+
>
|
|
211
|
+
<Glimmer size="small" width="80%" />
|
|
212
|
+
<Glimmer size="small" />
|
|
213
|
+
<Glimmer size="small" width="70%" />
|
|
214
|
+
</View>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
{(showClearAction ||
|
|
218
|
+
suffix?.label ||
|
|
219
|
+
suffix?.icon ||
|
|
220
|
+
showLoadingSpinner) && (
|
|
221
|
+
<View style={styles.inputEndContainer}>
|
|
222
|
+
{showClearAction && (
|
|
223
|
+
<ClearAction
|
|
224
|
+
hasMarginRight={!!suffix?.icon || !!suffix?.label}
|
|
225
|
+
onPress={handleClear}
|
|
226
|
+
/>
|
|
227
|
+
)}
|
|
228
|
+
{suffix?.label && hasValue && (
|
|
229
|
+
<SuffixLabel
|
|
230
|
+
disabled={disabled}
|
|
231
|
+
focused={focused}
|
|
232
|
+
hasMiniLabel={hasMiniLabel}
|
|
233
|
+
inputInvalid={inputInvalid}
|
|
234
|
+
label={suffix.label}
|
|
235
|
+
hasLeftMargin={!showClearAction}
|
|
236
|
+
styleOverride={styleOverride?.suffixLabel}
|
|
237
|
+
/>
|
|
238
|
+
)}
|
|
239
|
+
|
|
240
|
+
{showLoadingSpinner && (
|
|
241
|
+
<View style={styles.loadingSpinner}>
|
|
242
|
+
<ActivityIndicator
|
|
243
|
+
testID={INPUT_FIELD_WRAPPER_SPINNER_TEST_ID}
|
|
244
|
+
/>
|
|
245
|
+
</View>
|
|
246
|
+
)}
|
|
247
|
+
|
|
248
|
+
{suffix?.icon && (
|
|
249
|
+
<SuffixIcon
|
|
250
|
+
disabled={disabled}
|
|
251
|
+
focused={focused}
|
|
252
|
+
hasMiniLabel={hasMiniLabel}
|
|
253
|
+
hasLeftMargin={!!(!showClearAction || suffix?.label)}
|
|
254
|
+
inputInvalid={inputInvalid}
|
|
255
|
+
icon={suffix.icon}
|
|
256
|
+
onPress={suffix.onPress}
|
|
257
|
+
/>
|
|
258
|
+
)}
|
|
259
|
+
</View>
|
|
260
|
+
)}
|
|
261
|
+
</View>
|
|
197
262
|
</View>
|
|
263
|
+
|
|
264
|
+
{isToolbarVisible && <View style={styles.toolbar}>{toolbar}</View>}
|
|
198
265
|
</View>
|
|
199
266
|
{assistiveText && !error && !invalid && (
|
|
200
267
|
<Text
|
|
@@ -15,12 +15,12 @@ import { typographyStyles } from "../../../Typography";
|
|
|
15
15
|
import { styles } from "../../InputFieldWrapper.style";
|
|
16
16
|
|
|
17
17
|
export interface PrefixLabelProps {
|
|
18
|
-
focused: boolean;
|
|
19
|
-
disabled?: boolean;
|
|
20
|
-
hasMiniLabel: boolean;
|
|
21
|
-
inputInvalid: boolean;
|
|
22
|
-
label: string;
|
|
23
|
-
styleOverride?: StyleProp<TextStyle>;
|
|
18
|
+
readonly focused: boolean;
|
|
19
|
+
readonly disabled?: boolean;
|
|
20
|
+
readonly hasMiniLabel: boolean;
|
|
21
|
+
readonly inputInvalid: boolean;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly styleOverride?: StyleProp<TextStyle>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export const prefixLabelTestId = "ATL-InputFieldWrapper-PrefixLabel";
|
|
@@ -68,12 +68,12 @@ export function PrefixLabel({
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export interface PrefixIconProps {
|
|
71
|
-
focused: boolean;
|
|
72
|
-
disabled?: boolean;
|
|
73
|
-
hasMiniLabel: boolean;
|
|
74
|
-
inputInvalid?: boolean;
|
|
75
|
-
icon: IconNames;
|
|
76
|
-
styleOverride?: StyleProp<ViewStyle>;
|
|
71
|
+
readonly focused: boolean;
|
|
72
|
+
readonly disabled?: boolean;
|
|
73
|
+
readonly hasMiniLabel: boolean;
|
|
74
|
+
readonly inputInvalid?: boolean;
|
|
75
|
+
readonly icon: IconNames;
|
|
76
|
+
readonly styleOverride?: StyleProp<ViewStyle>;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export function PrefixIcon({
|
|
@@ -15,13 +15,13 @@ import { typographyStyles } from "../../../Typography";
|
|
|
15
15
|
import { styles } from "../../InputFieldWrapper.style";
|
|
16
16
|
|
|
17
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>;
|
|
18
|
+
readonly focused: boolean;
|
|
19
|
+
readonly disabled?: boolean;
|
|
20
|
+
readonly hasMiniLabel: boolean;
|
|
21
|
+
readonly inputInvalid?: boolean;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly hasLeftMargin?: boolean;
|
|
24
|
+
readonly styleOverride?: StyleProp<TextStyle>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const suffixLabelTestId = "ATL-InputFieldWrapper-SuffixLabel";
|
|
@@ -71,13 +71,13 @@ export function SuffixLabel({
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
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;
|
|
74
|
+
readonly focused: boolean;
|
|
75
|
+
readonly disabled?: boolean;
|
|
76
|
+
readonly hasMiniLabel: boolean;
|
|
77
|
+
readonly inputInvalid?: boolean;
|
|
78
|
+
readonly icon: IconNames;
|
|
79
|
+
readonly hasLeftMargin?: boolean;
|
|
80
|
+
readonly onPress?: () => void;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export function SuffixIcon({
|
|
@@ -36,12 +36,14 @@ function InputNumberInternal(props: InputNumberProps, ref: Ref<InputTextRef>) {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
const { t } = useAtlantisI18n();
|
|
39
|
+
|
|
39
40
|
const handleChange = (newValue: number | string | undefined) => {
|
|
40
41
|
props.onChange?.(newValue);
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
const { inputTransform: convertToString, outputTransform: convertToNumber } =
|
|
44
45
|
useNumberTransform(props.value);
|
|
46
|
+
|
|
45
47
|
return (
|
|
46
48
|
<InputText
|
|
47
49
|
{...props}
|
|
@@ -69,10 +71,12 @@ function hasPeriodAtEnd(value: string) {
|
|
|
69
71
|
// matches patterns like ".", "0.", "12.", "+1.", and "-0."
|
|
70
72
|
return !!value?.match(/^[-+]?[0-9]*\.$/);
|
|
71
73
|
}
|
|
74
|
+
|
|
72
75
|
function hasScientificNotationAtEnd(value: string) {
|
|
73
76
|
// matches patterns like "1e", "+2e", "1.2e" and "-3e"
|
|
74
77
|
return !!value?.match(/^[-+]?[0-9]+(\.?[0-9]+)?e$/);
|
|
75
78
|
}
|
|
79
|
+
|
|
76
80
|
function hasPlusMinusAtEnd(value: string) {
|
|
77
81
|
// matches "+" and "-"
|
|
78
82
|
return !!value?.match(/^[-+]+$/);
|
|
@@ -92,6 +96,7 @@ export function shouldShowUserValue(value: string): boolean {
|
|
|
92
96
|
];
|
|
93
97
|
const isSpecial = (v: string) =>
|
|
94
98
|
specialCasesFn.reduce((acc, fn) => acc || fn(v), false);
|
|
99
|
+
|
|
95
100
|
return isSpecial(value);
|
|
96
101
|
}
|
|
97
102
|
|
|
@@ -105,9 +110,11 @@ export function useNumberTransform(controlledValue: number | undefined): {
|
|
|
105
110
|
|
|
106
111
|
const convertToNumber = (newValue: string) => {
|
|
107
112
|
setTypedValue(newValue);
|
|
113
|
+
|
|
108
114
|
if (newValue?.match?.(NUMBER_VALIDATION_REGEX)) {
|
|
109
115
|
return parseFloat(newValue);
|
|
110
116
|
}
|
|
117
|
+
|
|
111
118
|
return newValue;
|
|
112
119
|
};
|
|
113
120
|
|
|
@@ -115,6 +122,7 @@ export function useNumberTransform(controlledValue: number | undefined): {
|
|
|
115
122
|
if (shouldShowUserValue(typedValue)) {
|
|
116
123
|
return typedValue;
|
|
117
124
|
}
|
|
125
|
+
|
|
118
126
|
return internalValue?.toString() || undefined;
|
|
119
127
|
};
|
|
120
128
|
|
|
@@ -8,6 +8,7 @@ jest.mock("../InputFieldWrapper", () => ({
|
|
|
8
8
|
...jest.requireActual("../InputFieldWrapper"),
|
|
9
9
|
InputFieldWrapper: function Mock(props: InputFieldWrapperProps) {
|
|
10
10
|
MockInputFieldWrapper(props);
|
|
11
|
+
|
|
11
12
|
return jest.requireActual("../InputFieldWrapper").InputFieldWrapper(props);
|
|
12
13
|
},
|
|
13
14
|
}));
|
|
@@ -15,7 +15,7 @@ export interface InputPasswordProps
|
|
|
15
15
|
*
|
|
16
16
|
* @default true
|
|
17
17
|
*/
|
|
18
|
-
usePrivacyEye?: boolean;
|
|
18
|
+
readonly usePrivacyEye?: boolean;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function InputPasswordInternal(
|
|
@@ -43,6 +43,7 @@ function InputPasswordInternal(
|
|
|
43
43
|
onPress: handleOnPress,
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
+
|
|
46
47
|
return undefined;
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -8,6 +8,7 @@ jest.mock("../InputFieldWrapper", () => ({
|
|
|
8
8
|
...jest.requireActual("../InputFieldWrapper"),
|
|
9
9
|
InputFieldWrapper: function Mock(props: InputFieldWrapperProps) {
|
|
10
10
|
MockInputFieldWrapper(props);
|
|
11
|
+
|
|
11
12
|
return jest.requireActual("../InputFieldWrapper").InputFieldWrapper(props);
|
|
12
13
|
},
|
|
13
14
|
}));
|
|
@@ -75,6 +75,17 @@ describe("InputText", () => {
|
|
|
75
75
|
);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
describe("readonly", () => {
|
|
79
|
+
it.each([[false], [true]])("sets the readOnly to %s", expected => {
|
|
80
|
+
const { getByTestId } = renderInputText({
|
|
81
|
+
testID: "InputText",
|
|
82
|
+
readonly: expected,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(getByTestId("InputText").props.readOnly).toBe(expected);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
78
89
|
it("renders a InputText with placeholder", () => {
|
|
79
90
|
const props = { placeholder: "Foobar" };
|
|
80
91
|
renderInputText(props);
|
|
@@ -25,11 +25,18 @@ import { Clearable, useShowClear } from "@jobber/hooks";
|
|
|
25
25
|
import { styles } from "./InputText.style";
|
|
26
26
|
import { useInputAccessoriesContext } from "./context";
|
|
27
27
|
import { useFormController } from "../hooks";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
InputFieldStyleOverride,
|
|
30
|
+
InputFieldWrapperProps,
|
|
31
|
+
} from "../InputFieldWrapper/InputFieldWrapper";
|
|
29
32
|
import { InputFieldWrapper } from "../InputFieldWrapper";
|
|
30
33
|
import { commonInputStyles } from "../InputFieldWrapper/CommonInputStyles.style";
|
|
31
34
|
|
|
32
|
-
export interface InputTextProps
|
|
35
|
+
export interface InputTextProps
|
|
36
|
+
extends Pick<
|
|
37
|
+
InputFieldWrapperProps,
|
|
38
|
+
"toolbar" | "toolbarVisibility" | "loading" | "loadingType"
|
|
39
|
+
> {
|
|
33
40
|
/**
|
|
34
41
|
* Highlights the field red and shows message below (if string) to indicate an error
|
|
35
42
|
*/
|
|
@@ -40,6 +47,11 @@ export interface InputTextProps {
|
|
|
40
47
|
*/
|
|
41
48
|
readonly disabled?: boolean;
|
|
42
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Makes the input read-only
|
|
52
|
+
*/
|
|
53
|
+
readonly readonly?: boolean;
|
|
54
|
+
|
|
43
55
|
/**
|
|
44
56
|
* Name of the input.
|
|
45
57
|
*/
|
|
@@ -233,6 +245,7 @@ function InputTextInternal(
|
|
|
233
245
|
{
|
|
234
246
|
invalid,
|
|
235
247
|
disabled,
|
|
248
|
+
readonly = false,
|
|
236
249
|
name,
|
|
237
250
|
placeholder,
|
|
238
251
|
assistiveText,
|
|
@@ -260,6 +273,10 @@ function InputTextInternal(
|
|
|
260
273
|
testID,
|
|
261
274
|
secureTextEntry,
|
|
262
275
|
styleOverride,
|
|
276
|
+
toolbar,
|
|
277
|
+
toolbarVisibility,
|
|
278
|
+
loading,
|
|
279
|
+
loadingType,
|
|
263
280
|
}: InputTextProps,
|
|
264
281
|
ref: Ref<InputTextRef>,
|
|
265
282
|
) {
|
|
@@ -361,6 +378,10 @@ function InputTextInternal(
|
|
|
361
378
|
onClear={handleClear}
|
|
362
379
|
showClearAction={showClear}
|
|
363
380
|
styleOverride={styleOverride}
|
|
381
|
+
toolbar={toolbar}
|
|
382
|
+
toolbarVisibility={toolbarVisibility}
|
|
383
|
+
loading={loading}
|
|
384
|
+
loadingType={loadingType}
|
|
364
385
|
>
|
|
365
386
|
<TextInput
|
|
366
387
|
inputAccessoryViewID={inputAccessoryID || undefined}
|
|
@@ -377,7 +398,10 @@ function InputTextInternal(
|
|
|
377
398
|
multiline && Platform.OS === "ios" && styles.multilineInputiOS,
|
|
378
399
|
multiline && hasMiniLabel && styles.multiLineInputWithMini,
|
|
379
400
|
styleOverride?.inputText,
|
|
401
|
+
loading && loadingType === "glimmer" && { color: "transparent" },
|
|
380
402
|
]}
|
|
403
|
+
// @ts-expect-error - does exist on 0.71 and up https://github.com/facebook/react-native/pull/39281
|
|
404
|
+
readOnly={readonly}
|
|
381
405
|
editable={!disabled}
|
|
382
406
|
keyboardType={keyboard}
|
|
383
407
|
value={inputTransform(internalValue)}
|
|
@@ -392,6 +416,7 @@ function InputTextInternal(
|
|
|
392
416
|
blurOnSubmit={shouldBlurOnSubmit}
|
|
393
417
|
accessibilityLabel={accessibilityLabel || placeholder}
|
|
394
418
|
accessibilityHint={accessibilityHint}
|
|
419
|
+
accessibilityState={{ busy: loading }}
|
|
395
420
|
secureTextEntry={secureTextEntry}
|
|
396
421
|
{...androidA11yProps}
|
|
397
422
|
onFocus={event => {
|
|
@@ -31,7 +31,7 @@ describe("InputAccessories", () => {
|
|
|
31
31
|
const mockInputOneFocus = jest.fn();
|
|
32
32
|
const mockInputTwoFocus = jest.fn();
|
|
33
33
|
|
|
34
|
-
function InputWrapper({ focusedInput }: { focusedInput: string }) {
|
|
34
|
+
function InputWrapper({ focusedInput }: { readonly focusedInput: string }) {
|
|
35
35
|
const { register, setFocusedInput, unregister } = useContext(
|
|
36
36
|
InputAccessoriesContext,
|
|
37
37
|
);
|
|
@@ -40,12 +40,14 @@ describe("InputAccessories", () => {
|
|
|
40
40
|
register(inputOneName, () => mockInputOneFocus());
|
|
41
41
|
register(inputTwoName, () => mockInputTwoFocus());
|
|
42
42
|
setFocusedInput(focusedInput);
|
|
43
|
+
|
|
43
44
|
return () => {
|
|
44
45
|
unregister(inputOneName);
|
|
45
46
|
unregister(inputTwoName);
|
|
46
47
|
setFocusedInput("");
|
|
47
48
|
};
|
|
48
49
|
}, [register, setFocusedInput, unregister, focusedInput]);
|
|
50
|
+
|
|
49
51
|
return (
|
|
50
52
|
<>
|
|
51
53
|
<InputText
|
|
@@ -58,6 +60,7 @@ describe("InputAccessories", () => {
|
|
|
58
60
|
</>
|
|
59
61
|
);
|
|
60
62
|
}
|
|
63
|
+
|
|
61
64
|
function SetupInputAccessoriesTest(focusedInput: string) {
|
|
62
65
|
mockUseFormController.mockImplementation(({ name, value, validations }) => {
|
|
63
66
|
const { field, error } = actualUseFormController({
|
|
@@ -65,8 +68,10 @@ describe("InputAccessories", () => {
|
|
|
65
68
|
value,
|
|
66
69
|
validations,
|
|
67
70
|
});
|
|
71
|
+
|
|
68
72
|
return { field, error };
|
|
69
73
|
});
|
|
74
|
+
|
|
70
75
|
return render(<InputWrapper focusedInput={focusedInput} />, {
|
|
71
76
|
wrapper: InputAccessoriesProvider,
|
|
72
77
|
});
|
|
@@ -15,7 +15,7 @@ import { styles } from "./InputAccessoriesProvider.style";
|
|
|
15
15
|
export function InputAccessoriesProvider({
|
|
16
16
|
children,
|
|
17
17
|
}: {
|
|
18
|
-
children: ReactNode;
|
|
18
|
+
readonly children: ReactNode;
|
|
19
19
|
}): JSX.Element {
|
|
20
20
|
const inputAccessoryID = useRef(v4()).current;
|
|
21
21
|
const {
|
package/src/Menu/Menu.style.ts
CHANGED
|
@@ -9,7 +9,7 @@ export const styles = StyleSheet.create({
|
|
|
9
9
|
backgroundColor: tokens["color-surface"],
|
|
10
10
|
paddingHorizontal: tokens["space-small"],
|
|
11
11
|
paddingVertical: tokens["space-small"] + tokens["space-smallest"],
|
|
12
|
-
borderRadius: tokens["radius-
|
|
12
|
+
borderRadius: tokens["radius-base"],
|
|
13
13
|
width: menuWidth,
|
|
14
14
|
...tokens["shadow-high"],
|
|
15
15
|
},
|
package/src/Menu/Menu.tsx
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
+
Keyboard,
|
|
3
4
|
LayoutRectangle,
|
|
5
|
+
Platform,
|
|
4
6
|
Pressable,
|
|
5
7
|
View,
|
|
6
8
|
useWindowDimensions,
|
|
@@ -33,7 +35,7 @@ export function Menu({ menuOptions, customActivator }: MenuProps): JSX.Element {
|
|
|
33
35
|
}
|
|
34
36
|
}, [screenInfo, activatorLayout]);
|
|
35
37
|
|
|
36
|
-
const
|
|
38
|
+
const openMenu = () => {
|
|
37
39
|
menuButtonRef.current?.measureInWindow(
|
|
38
40
|
(x: number, y: number, width: number, height: number) => {
|
|
39
41
|
activatorLayout.current = {
|
|
@@ -44,11 +46,23 @@ export function Menu({ menuOptions, customActivator }: MenuProps): JSX.Element {
|
|
|
44
46
|
};
|
|
45
47
|
findMenuLayout();
|
|
46
48
|
setOpen(true);
|
|
47
|
-
onPress && onPress();
|
|
48
49
|
},
|
|
49
50
|
);
|
|
50
51
|
};
|
|
51
52
|
|
|
53
|
+
const activatorOnPress = (onPress?: () => void) => {
|
|
54
|
+
onPress && onPress();
|
|
55
|
+
|
|
56
|
+
if (Platform.OS === "ios" && Keyboard.isVisible()) {
|
|
57
|
+
// On iOS, the keyboard height causes problems with the menu positioning logic.
|
|
58
|
+
// Wait until the keyboard is fully hidden before we show the menu.
|
|
59
|
+
onKeyboardDidHide(openMenu);
|
|
60
|
+
Keyboard.dismiss();
|
|
61
|
+
} else {
|
|
62
|
+
openMenu();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
52
66
|
return (
|
|
53
67
|
<>
|
|
54
68
|
<View
|
|
@@ -113,3 +127,10 @@ function useScreenInformation() {
|
|
|
113
127
|
|
|
114
128
|
return { headerHeight, windowWidth, windowHeight };
|
|
115
129
|
}
|
|
130
|
+
|
|
131
|
+
function onKeyboardDidHide(callback: () => void) {
|
|
132
|
+
const listener = Keyboard.addListener("keyboardDidHide", () => {
|
|
133
|
+
listener.remove();
|
|
134
|
+
callback();
|
|
135
|
+
});
|
|
136
|
+
}
|