@jobber/components-native 0.44.2 → 0.45.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.
- package/dist/package.json +88 -0
- package/dist/src/AtlantisContext/AtlantisContext.js +1 -0
- package/dist/src/BottomSheet/BottomSheet.js +3 -4
- package/dist/src/ButtonGroup/ButtonGroup.js +3 -4
- package/dist/src/ButtonGroup/utils.js +4 -5
- package/dist/src/ContentOverlay/ContentOverlay.js +3 -4
- package/dist/src/Form/components/FormErrorBanner/FormErrorBanner.js +5 -13
- package/dist/src/Form/components/FormMask/FormMask.js +3 -4
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.js +4 -5
- package/dist/src/Form/components/FormSaveButton/FormSaveButton.js +4 -5
- package/dist/src/Form/hooks/useOfflineHandler.js +6 -7
- package/dist/src/FormatFile/FormatFile.js +3 -4
- package/dist/src/FormatFile/components/FileView/FileView.js +3 -3
- package/dist/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.js +6 -7
- package/dist/src/FormatFile/components/MediaView/MediaView.js +3 -3
- package/dist/src/FormatFile/utils/computeA11yLabel.js +4 -5
- package/dist/src/InputCurrency/InputCurrency.js +3 -3
- package/dist/src/InputDate/InputDate.js +4 -5
- package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.js +3 -4
- package/dist/src/InputFieldWrapper/components/ClearAction/index.js +0 -1
- package/dist/src/InputNumber/InputNumber.js +3 -4
- package/dist/src/InputPassword/InputPassword.js +3 -4
- package/dist/src/InputTime/InputTime.js +3 -4
- package/dist/src/Menu/Menu.js +3 -4
- package/dist/src/ProgressBar/ProgressBar.js +14 -8
- package/dist/src/Select/Select.js +5 -6
- package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.js +3 -4
- package/dist/src/Toast/Toast.js +4 -5
- package/dist/src/hooks/useAtlantisI18n/index.js +1 -0
- package/dist/src/hooks/useAtlantisI18n/locales/en.json +31 -0
- package/dist/src/hooks/useAtlantisI18n/locales/es.json +31 -0
- package/dist/src/hooks/useAtlantisI18n/useAtlantisI18n.js +22 -0
- package/dist/tsconfig.json +38 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/AtlantisContext/AtlantisContext.d.ts +8 -0
- package/dist/types/src/FormatFile/utils/computeA11yLabel.d.ts +6 -6
- package/dist/types/src/InputFieldWrapper/components/ClearAction/index.d.ts +0 -1
- package/dist/types/src/hooks/useAtlantisI18n/index.d.ts +1 -0
- package/dist/types/src/hooks/useAtlantisI18n/useAtlantisI18n.d.ts +6 -0
- package/package.json +2 -2
- package/src/AtlantisContext/AtlantisContext.tsx +10 -0
- package/src/BottomSheet/BottomSheet.test.tsx +3 -4
- package/src/BottomSheet/BottomSheet.tsx +3 -4
- package/src/ButtonGroup/ButtonGroup.test.tsx +8 -9
- package/src/ButtonGroup/ButtonGroup.tsx +3 -4
- package/src/ButtonGroup/utils.ts +5 -6
- package/src/ContentOverlay/ContentOverlay.test.tsx +1 -11
- package/src/ContentOverlay/ContentOverlay.tsx +5 -9
- package/src/Form/Form.test.tsx +9 -40
- package/src/Form/components/FormErrorBanner/FormErrorBanner.test.tsx +9 -72
- package/src/Form/components/FormErrorBanner/FormErrorBanner.tsx +6 -15
- package/src/Form/components/FormMask/FormMask.tsx +3 -7
- package/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.tsx +4 -5
- package/src/Form/components/FormSaveButton/FormSaveButton.test.tsx +3 -7
- package/src/Form/components/FormSaveButton/FormSaveButton.tsx +4 -5
- package/src/Form/hooks/useOfflineHandler.ts +7 -8
- package/src/FormatFile/FormatFile.test.tsx +7 -31
- package/src/FormatFile/FormatFile.tsx +3 -7
- package/src/FormatFile/components/FileView/FileView.tsx +3 -3
- package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.test.tsx +2 -9
- package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.tsx +6 -7
- package/src/FormatFile/components/MediaView/MediaView.tsx +3 -3
- package/src/FormatFile/utils/computeA11yLabel.ts +9 -12
- package/src/InputCurrency/InputCurrency.test.tsx +6 -1
- package/src/InputCurrency/InputCurrency.tsx +3 -3
- package/src/InputDate/InputDate.tsx +6 -5
- package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +4 -15
- package/src/InputFieldWrapper/components/ClearAction/ClearAction.test.tsx +1 -5
- package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +3 -4
- package/src/InputFieldWrapper/components/ClearAction/index.ts +0 -1
- package/src/InputNumber/InputNumber.test.tsx +10 -18
- package/src/InputNumber/InputNumber.tsx +3 -4
- package/src/InputPassword/InputPassword.test.tsx +1 -2
- package/src/InputPassword/InputPassword.tsx +3 -4
- package/src/InputSearch/InputSearch.test.tsx +1 -6
- package/src/InputText/InputText.test.tsx +10 -38
- package/src/InputTime/InputTime.tsx +3 -4
- package/src/Menu/Menu.test.tsx +10 -9
- package/src/Menu/Menu.tsx +3 -4
- package/src/ProgressBar/ProgressBar.tsx +17 -8
- package/src/Select/Select.test.tsx +4 -5
- package/src/Select/Select.tsx +5 -8
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.tsx +3 -4
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.test.tsx +1 -2
- package/src/Toast/Toast.tsx +4 -9
- package/src/hooks/useAtlantisI18n/index.ts +1 -0
- package/src/hooks/useAtlantisI18n/locales/en.json +31 -0
- package/src/hooks/useAtlantisI18n/locales/es.json +31 -0
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.test.ts +53 -0
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.ts +43 -0
- package/dist/src/BottomSheet/messages.js +0 -8
- package/dist/src/ButtonGroup/messages.js +0 -18
- package/dist/src/ContentOverlay/messages.js +0 -8
- package/dist/src/Form/components/FormErrorBanner/messages.js +0 -13
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/messages.js +0 -8
- package/dist/src/Form/components/FormSaveButton/messages.js +0 -8
- package/dist/src/Form/messages.js +0 -28
- package/dist/src/FormatFile/components/FormatFileBottomSheet/messages.js +0 -13
- package/dist/src/FormatFile/messages.js +0 -23
- package/dist/src/InputCurrency/messages.js +0 -8
- package/dist/src/InputDate/messages.js +0 -8
- package/dist/src/InputFieldWrapper/components/ClearAction/messages.js +0 -8
- package/dist/src/InputNumber/messages.js +0 -8
- package/dist/src/InputPassword/messages.js +0 -8
- package/dist/src/InputTime/messages.js +0 -8
- package/dist/src/Menu/messages.js +0 -8
- package/dist/src/ProgressBar/messages.js +0 -13
- package/dist/src/Select/components/SelectDefaultPicker/messages.js +0 -8
- package/dist/src/Select/messages.js +0 -13
- package/dist/src/Toast/messages.js +0 -13
- package/dist/types/src/BottomSheet/messages.d.ts +0 -7
- package/dist/types/src/ButtonGroup/messages.d.ts +0 -17
- package/dist/types/src/ContentOverlay/messages.d.ts +0 -7
- package/dist/types/src/Form/components/FormErrorBanner/messages.d.ts +0 -12
- package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/messages.d.ts +0 -7
- package/dist/types/src/Form/components/FormSaveButton/messages.d.ts +0 -7
- package/dist/types/src/Form/messages.d.ts +0 -27
- package/dist/types/src/FormatFile/components/FormatFileBottomSheet/messages.d.ts +0 -12
- package/dist/types/src/FormatFile/messages.d.ts +0 -22
- package/dist/types/src/InputCurrency/messages.d.ts +0 -7
- package/dist/types/src/InputDate/messages.d.ts +0 -7
- package/dist/types/src/InputFieldWrapper/components/ClearAction/messages.d.ts +0 -7
- package/dist/types/src/InputNumber/messages.d.ts +0 -7
- package/dist/types/src/InputPassword/messages.d.ts +0 -7
- package/dist/types/src/InputTime/messages.d.ts +0 -7
- package/dist/types/src/Menu/messages.d.ts +0 -7
- package/dist/types/src/ProgressBar/messages.d.ts +0 -12
- package/dist/types/src/Select/components/SelectDefaultPicker/messages.d.ts +0 -7
- package/dist/types/src/Select/messages.d.ts +0 -12
- package/dist/types/src/Toast/messages.d.ts +0 -12
- package/src/BottomSheet/messages.ts +0 -9
- package/src/ButtonGroup/messages.ts +0 -19
- package/src/ContentOverlay/messages.ts +0 -9
- package/src/Form/components/FormErrorBanner/messages.ts +0 -14
- package/src/Form/components/FormMessage/components/InternalFormMessage/messages.ts +0 -10
- package/src/Form/components/FormSaveButton/messages.ts +0 -9
- package/src/Form/messages.ts +0 -33
- package/src/FormatFile/components/FormatFileBottomSheet/messages.ts +0 -14
- package/src/FormatFile/messages.ts +0 -24
- package/src/InputCurrency/messages.ts +0 -10
- package/src/InputDate/messages.ts +0 -9
- package/src/InputFieldWrapper/components/ClearAction/messages.ts +0 -9
- package/src/InputNumber/messages.ts +0 -10
- package/src/InputPassword/messages.ts +0 -9
- package/src/InputTime/messages.ts +0 -9
- package/src/Menu/messages.ts +0 -9
- package/src/ProgressBar/messages.ts +0 -14
- package/src/Select/components/SelectDefaultPicker/messages.ts +0 -9
- package/src/Select/messages.ts +0 -14
- package/src/Toast/messages.ts +0 -14
|
@@ -36,6 +36,14 @@ export interface AtlantisContextProps {
|
|
|
36
36
|
* By accurately defining this value, Atlantis can effectively calculate the layout and alignment of its components.
|
|
37
37
|
*/
|
|
38
38
|
readonly headerHeight: number;
|
|
39
|
+
/**
|
|
40
|
+
* Change the locale of the components. This updates the strings that comes
|
|
41
|
+
* with the components, updates the date and time formats, and/or the
|
|
42
|
+
* native 3rd-party packages.
|
|
43
|
+
*
|
|
44
|
+
* @default "en"
|
|
45
|
+
*/
|
|
46
|
+
readonly locale: string;
|
|
39
47
|
/**
|
|
40
48
|
* The `setHeaderHeight` method allows you to set the height of the app header in Atlantis.
|
|
41
49
|
* Adjusting this height is essential for ensuring the correct positioning and alignment of various elements within the app.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useAtlantisI18nValue } from "../../hooks/useAtlantisI18n";
|
|
2
2
|
interface params {
|
|
3
|
-
accessibilityLabel?: string;
|
|
4
|
-
showOverlay: boolean;
|
|
5
|
-
showError: boolean;
|
|
6
|
-
|
|
3
|
+
readonly accessibilityLabel?: string;
|
|
4
|
+
readonly showOverlay: boolean;
|
|
5
|
+
readonly showError: boolean;
|
|
6
|
+
readonly t: useAtlantisI18nValue["t"];
|
|
7
7
|
}
|
|
8
|
-
export declare function computeA11yLabel({ accessibilityLabel, showOverlay, showError,
|
|
8
|
+
export declare function computeA11yLabel({ accessibilityLabel, showOverlay, showError, t, }: params): string;
|
|
9
9
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./useAtlantisI18n";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"react-native-reanimated": "^2.17.0",
|
|
85
85
|
"react-native-safe-area-context": "^4.5.2"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "90e9d2a124e1d65d678364063f6ef57e066939af"
|
|
88
88
|
}
|
|
@@ -47,6 +47,15 @@ export interface AtlantisContextProps {
|
|
|
47
47
|
*/
|
|
48
48
|
readonly headerHeight: number;
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Change the locale of the components. This updates the strings that comes
|
|
52
|
+
* with the components, updates the date and time formats, and/or the
|
|
53
|
+
* native 3rd-party packages.
|
|
54
|
+
*
|
|
55
|
+
* @default "en"
|
|
56
|
+
*/
|
|
57
|
+
readonly locale: string;
|
|
58
|
+
|
|
50
59
|
/**
|
|
51
60
|
* The `setHeaderHeight` method allows you to set the height of the app header in Atlantis.
|
|
52
61
|
* Adjusting this height is essential for ensuring the correct positioning and alignment of various elements within the app.
|
|
@@ -67,6 +76,7 @@ export const defaultValues: AtlantisContextProps = {
|
|
|
67
76
|
floatSeparators: { group: ",", decimal: "." },
|
|
68
77
|
currencySymbol: DEFAULT_CURRENCY_SYMBOL,
|
|
69
78
|
headerHeight: 0,
|
|
79
|
+
locale: "en",
|
|
70
80
|
setHeaderHeight: _ => {
|
|
71
81
|
return;
|
|
72
82
|
},
|
|
@@ -4,7 +4,6 @@ import { AccessibilityInfo, View } from "react-native";
|
|
|
4
4
|
import { Host, Portal } from "react-native-portalize";
|
|
5
5
|
import { BottomSheet } from ".";
|
|
6
6
|
import { BottomSheetRef } from "./BottomSheet";
|
|
7
|
-
import { messages } from "./messages";
|
|
8
7
|
import { waitForUntestableRender } from "../utils/test/wait";
|
|
9
8
|
import { Text } from "../Text";
|
|
10
9
|
|
|
@@ -79,7 +78,7 @@ it("BottomSheet can be closed with the cancel action", async () => {
|
|
|
79
78
|
ref.current?.open();
|
|
80
79
|
});
|
|
81
80
|
|
|
82
|
-
fireEvent.press(getByText(
|
|
81
|
+
fireEvent.press(getByText("Cancel"));
|
|
83
82
|
|
|
84
83
|
await waitFor(() => {
|
|
85
84
|
expect(queryByText("BottomSheet")).toBeNull();
|
|
@@ -98,7 +97,7 @@ describe("when loading is provided and true", () => {
|
|
|
98
97
|
ref.current?.open();
|
|
99
98
|
});
|
|
100
99
|
|
|
101
|
-
expect(queryByText(
|
|
100
|
+
expect(queryByText("Cancel")).toBeNull();
|
|
102
101
|
});
|
|
103
102
|
});
|
|
104
103
|
|
|
@@ -143,7 +142,7 @@ describe("when there is a screen reader enabled", () => {
|
|
|
143
142
|
ref.current?.open();
|
|
144
143
|
});
|
|
145
144
|
|
|
146
|
-
fireEvent.press(getByText(
|
|
145
|
+
fireEvent.press(getByText("Cancel"));
|
|
147
146
|
|
|
148
147
|
await waitFor(() => {
|
|
149
148
|
expect(queryByText("BottomSheet")).toBeNull();
|
|
@@ -2,13 +2,12 @@ import React, { ReactNode, Ref, RefObject, forwardRef, useState } from "react";
|
|
|
2
2
|
import { Modalize } from "react-native-modalize";
|
|
3
3
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
4
|
import { Keyboard, View } from "react-native";
|
|
5
|
-
import { useIntl } from "react-intl";
|
|
6
5
|
import { BottomSheetOption } from "./components/BottomSheetOption";
|
|
7
6
|
import { styles } from "./BottomSheet.style";
|
|
8
|
-
import { messages } from "./messages";
|
|
9
7
|
import { useIsScreenReaderEnabled } from "../hooks";
|
|
10
8
|
import { Divider } from "../Divider";
|
|
11
9
|
import { Heading } from "../Heading";
|
|
10
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
12
11
|
|
|
13
12
|
export interface BottomSheetProps {
|
|
14
13
|
readonly children: ReactNode;
|
|
@@ -118,7 +117,7 @@ function Footer({
|
|
|
118
117
|
onCancel: () => void;
|
|
119
118
|
}) {
|
|
120
119
|
const insets = useSafeAreaInsets();
|
|
121
|
-
const {
|
|
120
|
+
const { t } = useAtlantisI18n();
|
|
122
121
|
|
|
123
122
|
return (
|
|
124
123
|
<View style={{ marginBottom: insets.bottom }}>
|
|
@@ -128,7 +127,7 @@ function Footer({
|
|
|
128
127
|
<Divider />
|
|
129
128
|
</View>
|
|
130
129
|
<BottomSheetOption
|
|
131
|
-
text={
|
|
130
|
+
text={t("cancel")}
|
|
132
131
|
icon={"remove"}
|
|
133
132
|
onPress={onCancel}
|
|
134
133
|
/>
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
import { fireEvent, render } from "@testing-library/react-native";
|
|
3
3
|
import { Host } from "react-native-portalize";
|
|
4
4
|
import { Alert } from "react-native";
|
|
5
|
-
import { messages } from "./messages";
|
|
6
5
|
import { ButtonGroup, ButtonGroupProps } from "./ButtonGroup";
|
|
7
6
|
import { Button } from "../Button";
|
|
8
7
|
import * as atlantisContext from "../AtlantisContext/AtlantisContext";
|
|
@@ -37,7 +36,7 @@ it("renders a single primary action", () => {
|
|
|
37
36
|
);
|
|
38
37
|
|
|
39
38
|
expect(getByText("Create")).not.toBeNull();
|
|
40
|
-
expect(queryByLabelText(
|
|
39
|
+
expect(queryByLabelText("More")).toBeNull();
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
it("renders 2 primary actions", () => {
|
|
@@ -60,7 +59,7 @@ it("renders 2 primary actions", () => {
|
|
|
60
59
|
|
|
61
60
|
expect(getByText("Create")).not.toBeNull();
|
|
62
61
|
expect(getByText("Edit")).not.toBeNull();
|
|
63
|
-
expect(queryByLabelText(
|
|
62
|
+
expect(queryByLabelText("More")).toBeNull();
|
|
64
63
|
});
|
|
65
64
|
|
|
66
65
|
it("does not render more than 2 primary actions but adds a More button", () => {
|
|
@@ -90,7 +89,7 @@ it("does not render more than 2 primary actions but adds a More button", () => {
|
|
|
90
89
|
expect(getByText("Create")).not.toBeNull();
|
|
91
90
|
expect(getByText("Edit")).not.toBeNull();
|
|
92
91
|
expect(queryByText("Mystery")).toBeNull();
|
|
93
|
-
expect(getByLabelText(
|
|
92
|
+
expect(getByLabelText("More")).toBeDefined();
|
|
94
93
|
});
|
|
95
94
|
|
|
96
95
|
it("does not render secondary actions", () => {
|
|
@@ -119,7 +118,7 @@ it("does not render secondary actions", () => {
|
|
|
119
118
|
expect(getByText("Create")).not.toBeNull();
|
|
120
119
|
expect(queryByText("Edit")).toBeNull();
|
|
121
120
|
expect(queryByText("Delete")).toBeNull();
|
|
122
|
-
expect(getByLabelText(
|
|
121
|
+
expect(getByLabelText("More")).toBeDefined();
|
|
123
122
|
});
|
|
124
123
|
|
|
125
124
|
it("renders first secondary action as a primary action button if no primary action specified", () => {
|
|
@@ -141,7 +140,7 @@ it("renders first secondary action as a primary action button if no primary acti
|
|
|
141
140
|
);
|
|
142
141
|
expect(getByText("Edit")).not.toBeNull();
|
|
143
142
|
expect(queryByText("Delete")).toBeNull();
|
|
144
|
-
expect(getByLabelText(
|
|
143
|
+
expect(getByLabelText("More")).toBeDefined();
|
|
145
144
|
});
|
|
146
145
|
|
|
147
146
|
it("fires the press handlers when the primary action buttons are pressed", () => {
|
|
@@ -194,7 +193,7 @@ it("opens the secondary action menu when the More button is pressed", () => {
|
|
|
194
193
|
|
|
195
194
|
expect(queryByText("Edit")).toBeNull();
|
|
196
195
|
|
|
197
|
-
fireEvent.press(getByLabelText(
|
|
196
|
+
fireEvent.press(getByLabelText("More"));
|
|
198
197
|
|
|
199
198
|
expect(getByText("Edit")).not.toBeNull();
|
|
200
199
|
expect(getByText("Delete")).not.toBeNull();
|
|
@@ -221,7 +220,7 @@ it("renders heading and cancel options if passed in", () => {
|
|
|
221
220
|
</ButtonGroupForTest>,
|
|
222
221
|
);
|
|
223
222
|
|
|
224
|
-
fireEvent.press(getByLabelText(
|
|
223
|
+
fireEvent.press(getByLabelText("More"));
|
|
225
224
|
|
|
226
225
|
expect(getByText("Heading")).not.toBeNull();
|
|
227
226
|
expect(getByText("Cancel")).not.toBeNull();
|
|
@@ -273,7 +272,7 @@ it("calls onOpenBottomSheet when the secondary actions are opened", () => {
|
|
|
273
272
|
</ButtonGroupForTest>,
|
|
274
273
|
);
|
|
275
274
|
|
|
276
|
-
fireEvent.press(getByLabelText(
|
|
275
|
+
fireEvent.press(getByLabelText("More"));
|
|
277
276
|
|
|
278
277
|
expect(mockOnOpen).toHaveBeenCalled();
|
|
279
278
|
});
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import React, { useRef } from "react";
|
|
2
|
-
import { useIntl } from "react-intl";
|
|
3
2
|
import { View } from "react-native";
|
|
4
3
|
import { PrimaryAction, SecondaryAction } from "./ButtonGroupAction";
|
|
5
|
-
import { messages } from "./messages";
|
|
6
4
|
import { styles } from "./ButtonGroup.style";
|
|
7
5
|
import { SecondaryActionSheet } from "./components/SecondaryActionSheet";
|
|
8
6
|
import { getActions, usePreventTapWhenOffline } from "./utils";
|
|
9
7
|
import { ButtonGroupActionElement } from "./types";
|
|
10
8
|
import { Button } from "../Button";
|
|
11
9
|
import { BottomSheetRef } from "../BottomSheet/BottomSheet";
|
|
10
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
12
11
|
|
|
13
12
|
export interface ButtonGroupProps {
|
|
14
13
|
readonly children: ButtonGroupActionElement | ButtonGroupActionElement[];
|
|
@@ -47,7 +46,7 @@ export function ButtonGroup({
|
|
|
47
46
|
onCloseBottomSheet,
|
|
48
47
|
allowTapWhenOffline = false,
|
|
49
48
|
}: ButtonGroupProps): JSX.Element {
|
|
50
|
-
const {
|
|
49
|
+
const { t } = useAtlantisI18n();
|
|
51
50
|
const { handlePress } = usePreventTapWhenOffline();
|
|
52
51
|
const secondaryActionsRef = useRef<BottomSheetRef>();
|
|
53
52
|
const { primaryActions, secondaryActions } = getActions(children);
|
|
@@ -86,7 +85,7 @@ export function ButtonGroup({
|
|
|
86
85
|
<View style={styles.moreButton}>
|
|
87
86
|
<Button
|
|
88
87
|
icon={"more"}
|
|
89
|
-
accessibilityLabel={
|
|
88
|
+
accessibilityLabel={t("more")}
|
|
90
89
|
onPress={handlePress(openBottomSheet)}
|
|
91
90
|
fullHeight={true}
|
|
92
91
|
/>
|
package/src/ButtonGroup/utils.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
|
-
import { useIntl } from "react-intl";
|
|
3
2
|
import { Alert } from "react-native";
|
|
4
|
-
import { messages } from "./messages";
|
|
5
3
|
import {
|
|
6
4
|
ButtonGroupActionElement,
|
|
7
5
|
ButtonGroupPrimaryActionElement,
|
|
@@ -12,6 +10,7 @@ import {
|
|
|
12
10
|
SecondaryAction,
|
|
13
11
|
} from "./ButtonGroupAction";
|
|
14
12
|
import { useAtlantisContext } from "../AtlantisContext/AtlantisContext";
|
|
13
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
15
14
|
|
|
16
15
|
interface UsePreventTapWhenOfflineShape {
|
|
17
16
|
readonly handlePress: (
|
|
@@ -24,7 +23,7 @@ interface UsePreventTapWhenOfflineShape {
|
|
|
24
23
|
* online or offline
|
|
25
24
|
*/
|
|
26
25
|
export function usePreventTapWhenOffline(): UsePreventTapWhenOfflineShape {
|
|
27
|
-
const {
|
|
26
|
+
const { t } = useAtlantisI18n();
|
|
28
27
|
const { isOnline } = useAtlantisContext();
|
|
29
28
|
|
|
30
29
|
const handlePress = useCallback(
|
|
@@ -33,11 +32,11 @@ export function usePreventTapWhenOffline(): UsePreventTapWhenOfflineShape {
|
|
|
33
32
|
|
|
34
33
|
return () =>
|
|
35
34
|
Alert.alert(
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
t("networkUnavailableTitle"),
|
|
36
|
+
t("networkUnavailableDescription"),
|
|
38
37
|
);
|
|
39
38
|
},
|
|
40
|
-
[
|
|
39
|
+
[isOnline],
|
|
41
40
|
);
|
|
42
41
|
|
|
43
42
|
return { handlePress };
|
|
@@ -3,13 +3,11 @@ import { fireEvent, render, waitFor } from "@testing-library/react-native";
|
|
|
3
3
|
import { AccessibilityInfo, View } from "react-native";
|
|
4
4
|
import { Host } from "react-native-portalize";
|
|
5
5
|
import { ReactTestInstance, act } from "react-test-renderer";
|
|
6
|
-
import { useIntl } from "react-intl";
|
|
7
6
|
import {
|
|
8
7
|
ContentOverlay,
|
|
9
8
|
ContentOverlayRef,
|
|
10
9
|
ModalBackgroundColor,
|
|
11
10
|
} from "./ContentOverlay";
|
|
12
|
-
import { messages } from "./messages";
|
|
13
11
|
import { tokens } from "../utils/design";
|
|
14
12
|
import { Button } from "../Button";
|
|
15
13
|
import { Content } from "../Content";
|
|
@@ -232,8 +230,6 @@ describe("when accessibilityLabel prop passed to content overlay", () => {
|
|
|
232
230
|
|
|
233
231
|
describe("when accessibilityLabel prop NOT passed to content overlay", () => {
|
|
234
232
|
it("should use default accessibilityLabel", () => {
|
|
235
|
-
const { formatMessage } = useIntl();
|
|
236
|
-
|
|
237
233
|
const options: testRendererOptions = {
|
|
238
234
|
...getDefaultOptions(),
|
|
239
235
|
title: "Awesome Title",
|
|
@@ -241,14 +237,8 @@ describe("when accessibilityLabel prop NOT passed to content overlay", () => {
|
|
|
241
237
|
};
|
|
242
238
|
const contentOverlayScreen = renderAndOpenContentOverlay(options);
|
|
243
239
|
|
|
244
|
-
const defaultCloseOverlayA11YLabel = formatMessage(
|
|
245
|
-
messages.closeOverlayA11YLabel,
|
|
246
|
-
{
|
|
247
|
-
title: options.title,
|
|
248
|
-
},
|
|
249
|
-
);
|
|
250
240
|
expect(
|
|
251
|
-
contentOverlayScreen.getAllByLabelText(
|
|
241
|
+
contentOverlayScreen.getAllByLabelText(`Close ${options.title} modal`),
|
|
252
242
|
).toHaveLength(2);
|
|
253
243
|
});
|
|
254
244
|
});
|
|
@@ -19,10 +19,8 @@ import {
|
|
|
19
19
|
useWindowDimensions,
|
|
20
20
|
} from "react-native";
|
|
21
21
|
import { Portal } from "react-native-portalize";
|
|
22
|
-
import { useIntl } from "react-intl";
|
|
23
22
|
import { useKeyboardVisibility } from "./hooks/useKeyboardVisibility";
|
|
24
23
|
import { styles } from "./ContentOverlay.style";
|
|
25
|
-
import { messages } from "./messages";
|
|
26
24
|
import { useViewLayoutHeight } from "./hooks/useViewLayoutHeight";
|
|
27
25
|
import {
|
|
28
26
|
ContentOverlayProps,
|
|
@@ -33,6 +31,7 @@ import { useIsScreenReaderEnabled } from "../hooks";
|
|
|
33
31
|
import { IconButton } from "../IconButton";
|
|
34
32
|
import { tokens } from "../utils/design";
|
|
35
33
|
import { Heading } from "../Heading";
|
|
34
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
36
35
|
|
|
37
36
|
export const ContentOverlay = forwardRef(ContentOverlayPortal);
|
|
38
37
|
const ContentOverlayModal = forwardRef(ContentOverlayInternal);
|
|
@@ -61,7 +60,7 @@ function ContentOverlayInternal(
|
|
|
61
60
|
): JSX.Element {
|
|
62
61
|
isDraggable = onBeforeExit ? false : isDraggable;
|
|
63
62
|
const isCloseableOnOverlayTap = onBeforeExit ? false : true;
|
|
64
|
-
const {
|
|
63
|
+
const { t } = useAtlantisI18n();
|
|
65
64
|
const { width: windowWidth, height: windowHeight } = useWindowDimensions();
|
|
66
65
|
const insets = useSafeAreaInsets();
|
|
67
66
|
const [position, setPosition] = useState<"top" | "initial">("initial");
|
|
@@ -203,12 +202,9 @@ function ContentOverlayInternal(
|
|
|
203
202
|
);
|
|
204
203
|
|
|
205
204
|
function renderHeader() {
|
|
206
|
-
const closeOverlayA11YLabel =
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
title: title,
|
|
210
|
-
},
|
|
211
|
-
);
|
|
205
|
+
const closeOverlayA11YLabel = t("ContentOverlay.close", {
|
|
206
|
+
title: title,
|
|
207
|
+
});
|
|
212
208
|
|
|
213
209
|
const headerStyles = [
|
|
214
210
|
styles.header,
|
package/src/Form/Form.test.tsx
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { act, fireEvent, render, waitFor } from "@testing-library/react-native";
|
|
3
3
|
import { Alert, Keyboard } from "react-native";
|
|
4
|
-
import { useIntl } from "react-intl";
|
|
5
4
|
import { Host } from "react-native-portalize";
|
|
6
5
|
import { Form, FormBannerMessage, FormBannerMessageType } from ".";
|
|
7
|
-
import { messages as formErrorBannerMessages } from "./components/FormErrorBanner/messages";
|
|
8
|
-
import { messages } from "./components/FormSaveButton/messages";
|
|
9
|
-
import { messages as formMessages } from "./messages";
|
|
10
6
|
import { FormBannerErrors, FormSubmitErrorType } from "./types";
|
|
11
7
|
import { defaultValues as contextDefaultValue } from "../AtlantisContext";
|
|
12
8
|
import * as atlantisContext from "../AtlantisContext/AtlantisContext";
|
|
@@ -74,7 +70,7 @@ const testCheckboxName = "testCheckbox";
|
|
|
74
70
|
const switchLabel = "switchLabel";
|
|
75
71
|
const checkboxLabel = "checkboxLabel";
|
|
76
72
|
const selectLabel = "selectLabel";
|
|
77
|
-
const saveButtonText =
|
|
73
|
+
const saveButtonText = "Save";
|
|
78
74
|
|
|
79
75
|
const requiredInputText = "This field is required";
|
|
80
76
|
const minLengthText = "Test is too short";
|
|
@@ -207,15 +203,15 @@ afterEach(() => {
|
|
|
207
203
|
jest.clearAllMocks();
|
|
208
204
|
});
|
|
209
205
|
|
|
206
|
+
const loadingLabel = "Loading";
|
|
207
|
+
const tryAgainLabel = "Try again";
|
|
210
208
|
describe("Form", () => {
|
|
211
209
|
describe("Initial Load", () => {
|
|
212
210
|
it("should show activity indicator", () => {
|
|
213
211
|
const { getByLabelText } = render(
|
|
214
212
|
<FormTest initialLoading={true} onSubmit={onSubmitMock} />,
|
|
215
213
|
);
|
|
216
|
-
expect(
|
|
217
|
-
getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
|
|
218
|
-
).toBeTruthy();
|
|
214
|
+
expect(getByLabelText(loadingLabel)).toBeTruthy();
|
|
219
215
|
});
|
|
220
216
|
|
|
221
217
|
it("should be populated with provided initialValues", () => {
|
|
@@ -362,9 +358,7 @@ describe("Form", () => {
|
|
|
362
358
|
const saveButton = getByLabelText(saveButtonText);
|
|
363
359
|
fireEvent.press(saveButton);
|
|
364
360
|
|
|
365
|
-
expect(
|
|
366
|
-
getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
|
|
367
|
-
).toBeTruthy();
|
|
361
|
+
expect(getByLabelText(loadingLabel)).toBeTruthy();
|
|
368
362
|
});
|
|
369
363
|
|
|
370
364
|
it("should call beforeSubmit if one is provided", async () => {
|
|
@@ -432,14 +426,13 @@ describe("Form", () => {
|
|
|
432
426
|
|
|
433
427
|
it("should show offline alert when attempting to save while offline", async () => {
|
|
434
428
|
const alertSpy = jest.spyOn(Alert, "alert");
|
|
435
|
-
const { formatMessage } = useIntl();
|
|
436
429
|
setup();
|
|
437
430
|
|
|
438
431
|
await act(wait);
|
|
439
432
|
expect(alertSpy).toHaveBeenCalledTimes(1);
|
|
440
433
|
expect(alertSpy).toHaveBeenCalledWith(
|
|
441
|
-
|
|
442
|
-
|
|
434
|
+
"Network Unavailable",
|
|
435
|
+
"Check your internet connection and try again later.",
|
|
443
436
|
expect.anything(),
|
|
444
437
|
);
|
|
445
438
|
});
|
|
@@ -450,8 +443,7 @@ describe("Form", () => {
|
|
|
450
443
|
await act(wait);
|
|
451
444
|
const alertActions = alertSpy.mock.calls[0][2];
|
|
452
445
|
const retryAction = alertActions?.find(
|
|
453
|
-
action =>
|
|
454
|
-
action.text === formMessages.retryAlertButton.defaultMessage,
|
|
446
|
+
action => action.text === tryAgainLabel,
|
|
455
447
|
);
|
|
456
448
|
mockSubmit.mockImplementationOnce(() => Promise.resolve());
|
|
457
449
|
retryAction?.onPress?.();
|
|
@@ -467,8 +459,7 @@ describe("Form", () => {
|
|
|
467
459
|
await act(wait);
|
|
468
460
|
const alertActions = alertSpy.mock.calls[0][2];
|
|
469
461
|
const retryAction = alertActions?.find(
|
|
470
|
-
action =>
|
|
471
|
-
action.text === formMessages.retryAlertButton.defaultMessage,
|
|
462
|
+
action => action.text === tryAgainLabel,
|
|
472
463
|
);
|
|
473
464
|
retryAction?.onPress?.();
|
|
474
465
|
|
|
@@ -489,28 +480,6 @@ describe("Form", () => {
|
|
|
489
480
|
isOnline: false,
|
|
490
481
|
});
|
|
491
482
|
|
|
492
|
-
it("renders Offline Banner when disconnected", async () => {
|
|
493
|
-
const { getByText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
494
|
-
const { formatMessage } = useIntl();
|
|
495
|
-
|
|
496
|
-
expect(
|
|
497
|
-
getByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
498
|
-
).toBeDefined();
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
it("does not render Offline Banner when connected", async () => {
|
|
502
|
-
atlantisContextSpy.mockReturnValue({
|
|
503
|
-
...contextDefaultValue,
|
|
504
|
-
isOnline: true,
|
|
505
|
-
});
|
|
506
|
-
const { queryByText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
507
|
-
const { formatMessage } = useIntl();
|
|
508
|
-
|
|
509
|
-
expect(
|
|
510
|
-
queryByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
511
|
-
).toBeNull();
|
|
512
|
-
});
|
|
513
|
-
|
|
514
483
|
it("renders user errors when provided", async () => {
|
|
515
484
|
const { getByText } = render(
|
|
516
485
|
<FormTest onSubmit={onSubmitMock} sendBannerErrors={true} />,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { cleanup, render } from "@testing-library/react-native";
|
|
3
|
-
import { useIntl } from "react-intl";
|
|
4
3
|
import { FormErrorBanner } from "./FormErrorBanner";
|
|
5
|
-
import { messages as formErrorBannerMessages } from "./messages";
|
|
6
4
|
import { defaultValues as contextDefaultValue } from "../../../AtlantisContext";
|
|
7
5
|
import * as atlantisContext from "../../../AtlantisContext/AtlantisContext";
|
|
8
6
|
|
|
@@ -16,65 +14,20 @@ describe("FormErrorBanner", () => {
|
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
|
|
19
|
-
const
|
|
20
|
-
const networkError = new Error();
|
|
17
|
+
const networkError = "An error occurred";
|
|
21
18
|
const userError = {
|
|
22
19
|
title: "My error",
|
|
23
20
|
messages: ["userError1", "userError2"],
|
|
24
21
|
};
|
|
25
|
-
const
|
|
26
|
-
"This is the first validation error",
|
|
27
|
-
"This is the second validation error",
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
it("should render Offline banner when offline", () => {
|
|
31
|
-
atlantisContextSpy.mockReturnValue({
|
|
32
|
-
...contextDefaultValue,
|
|
33
|
-
isOnline: false,
|
|
34
|
-
});
|
|
35
|
-
const { getByText, queryByText } = render(
|
|
36
|
-
<FormErrorBanner
|
|
37
|
-
// @ts-expect-error tsc-ci
|
|
38
|
-
networkError={networkError}
|
|
39
|
-
bannerError={userError}
|
|
40
|
-
validationErrors={validationErrors}
|
|
41
|
-
actionLabel="Action"
|
|
42
|
-
/>,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
// Show: Offline Message
|
|
46
|
-
expect(
|
|
47
|
-
getByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
48
|
-
).toBeDefined();
|
|
49
|
-
|
|
50
|
-
// Hide: Network Error, User Error, Validation Error
|
|
51
|
-
expect(
|
|
52
|
-
queryByText(formatMessage(formErrorBannerMessages.networkError)),
|
|
53
|
-
).toBeNull();
|
|
54
|
-
|
|
55
|
-
expect(queryByText(userError.title)).toBeNull();
|
|
56
|
-
});
|
|
22
|
+
const couldNotSavechanges = "Could not save changes";
|
|
57
23
|
|
|
58
24
|
it("should render network error banner when online and network errors exist", () => {
|
|
59
25
|
const { getByText, queryByText } = render(
|
|
60
|
-
<FormErrorBanner
|
|
61
|
-
// @ts-expect-error tsc-ci
|
|
62
|
-
networkError={networkError}
|
|
63
|
-
bannerError={userError}
|
|
64
|
-
actionLabel="action"
|
|
65
|
-
/>,
|
|
26
|
+
<FormErrorBanner networkError={networkError} bannerError={userError} />,
|
|
66
27
|
);
|
|
67
28
|
|
|
68
|
-
// Show: Network Error
|
|
69
|
-
expect(
|
|
70
|
-
getByText(formatMessage(formErrorBannerMessages.networkError)),
|
|
71
|
-
).toBeDefined();
|
|
72
|
-
|
|
73
|
-
// Hide: Offline Message, User Error, Validation Error
|
|
74
|
-
expect(
|
|
75
|
-
queryByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
76
|
-
).toBeNull();
|
|
77
|
-
|
|
29
|
+
// Show: Network Error only
|
|
30
|
+
expect(getByText(couldNotSavechanges)).toBeDefined();
|
|
78
31
|
expect(queryByText(userError.title)).toBeNull();
|
|
79
32
|
});
|
|
80
33
|
|
|
@@ -83,19 +36,11 @@ describe("FormErrorBanner", () => {
|
|
|
83
36
|
<FormErrorBanner bannerError={userError} />,
|
|
84
37
|
);
|
|
85
38
|
|
|
86
|
-
// Show: User Error
|
|
39
|
+
// Show: User Error only
|
|
87
40
|
expect(getByText(userError.title)).toBeDefined();
|
|
88
41
|
expect(getByText(userError.messages[0])).toBeDefined();
|
|
89
42
|
expect(getByText(userError.messages[1])).toBeDefined();
|
|
90
|
-
|
|
91
|
-
// Hide: Offline Message, Network Error, Validation Error
|
|
92
|
-
expect(
|
|
93
|
-
queryByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
94
|
-
).toBeNull();
|
|
95
|
-
|
|
96
|
-
expect(
|
|
97
|
-
queryByText(formatMessage(formErrorBannerMessages.networkError)),
|
|
98
|
-
).toBeNull();
|
|
43
|
+
expect(queryByText(couldNotSavechanges)).toBeNull();
|
|
99
44
|
});
|
|
100
45
|
|
|
101
46
|
it("should render user error banner with just title when online", () => {
|
|
@@ -106,17 +51,9 @@ describe("FormErrorBanner", () => {
|
|
|
106
51
|
<FormErrorBanner bannerError={userErrorJustTitle} />,
|
|
107
52
|
);
|
|
108
53
|
|
|
109
|
-
// Show: User Error
|
|
54
|
+
// Show: User Error only
|
|
110
55
|
expect(getByText(userErrorJustTitle.title)).toBeDefined();
|
|
111
|
-
|
|
112
|
-
// Hide: Offline Message, Network Error, Validation Error
|
|
113
|
-
expect(
|
|
114
|
-
queryByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
115
|
-
).toBeNull();
|
|
116
|
-
|
|
117
|
-
expect(
|
|
118
|
-
queryByText(formatMessage(formErrorBannerMessages.networkError)),
|
|
119
|
-
).toBeNull();
|
|
56
|
+
expect(queryByText(couldNotSavechanges)).toBeNull();
|
|
120
57
|
});
|
|
121
58
|
});
|
|
122
59
|
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { useIntl } from "react-intl";
|
|
3
|
-
import { messages } from "./messages";
|
|
4
2
|
import { FormBannerErrors } from "../../types";
|
|
5
|
-
import { useAtlantisContext } from "../../../AtlantisContext";
|
|
6
3
|
import { Banner } from "../../../Banner";
|
|
4
|
+
import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
7
5
|
|
|
8
6
|
export function FormErrorBanner({
|
|
9
7
|
networkError,
|
|
10
8
|
bannerError,
|
|
11
9
|
}: FormBannerErrors): JSX.Element {
|
|
12
|
-
const {
|
|
13
|
-
const { isOnline } = useAtlantisContext();
|
|
10
|
+
const { t } = useAtlantisI18n();
|
|
14
11
|
|
|
15
|
-
if (
|
|
16
|
-
return (
|
|
17
|
-
<Banner text={formatMessage(messages.offlineError)} type={"error"} />
|
|
18
|
-
);
|
|
19
|
-
} else if (networkError) {
|
|
20
|
-
return (
|
|
21
|
-
<Banner text={formatMessage(messages.networkError)} type={"error"} />
|
|
22
|
-
);
|
|
12
|
+
if (networkError) {
|
|
13
|
+
return <Banner type={"error"}>{t("errors.couldNotSave")}</Banner>;
|
|
23
14
|
} else if (bannerError) {
|
|
24
15
|
return (
|
|
25
16
|
<Banner
|
|
@@ -28,7 +19,7 @@ export function FormErrorBanner({
|
|
|
28
19
|
type={"error"}
|
|
29
20
|
/>
|
|
30
21
|
);
|
|
31
|
-
} else {
|
|
32
|
-
return <></>;
|
|
33
22
|
}
|
|
23
|
+
|
|
24
|
+
return <></>;
|
|
34
25
|
}
|