@jobber/components-native 0.44.2 → 0.45.1
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/AutoLink/components/ComposeTextWithLinks/ComposeTextWithLinks.js +3 -3
- package/dist/src/AutoLink/utils.js +14 -3
- 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 +35 -0
- package/dist/src/hooks/useAtlantisI18n/locales/es.json +35 -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/AutoLink/utils.d.ts +2 -2
- 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 +7 -0
- package/package.json +2 -2
- package/src/AtlantisContext/AtlantisContext.tsx +10 -0
- package/src/AutoLink/AutoLink.test.tsx +3 -4
- package/src/AutoLink/components/ComposeTextWithLinks/ComposeTextWithLinks.tsx +3 -3
- package/src/AutoLink/utils.ts +16 -5
- 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 +35 -0
- package/src/hooks/useAtlantisI18n/locales/es.json +35 -0
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.test.ts +53 -0
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.ts +42 -0
- package/dist/src/AutoLink/messages.js +0 -18
- 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/AutoLink/messages.d.ts +0 -17
- 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/AutoLink/messages.ts +0 -19
- 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
package/src/Menu/Menu.test.tsx
CHANGED
|
@@ -4,7 +4,6 @@ import { Host } from "react-native-portalize";
|
|
|
4
4
|
import { View } from "react-native";
|
|
5
5
|
import { tokens } from "@jobber/design/foundation";
|
|
6
6
|
import { Menu, MenuOptionProps, MenuProps } from ".";
|
|
7
|
-
import { messages } from "./messages";
|
|
8
7
|
import { Icon } from "../Icon";
|
|
9
8
|
import { Button } from "../Button";
|
|
10
9
|
|
|
@@ -24,6 +23,8 @@ const setup = (props?: MenuProps) => {
|
|
|
24
23
|
);
|
|
25
24
|
};
|
|
26
25
|
|
|
26
|
+
const menuLabel = "Menu";
|
|
27
|
+
|
|
27
28
|
describe("Menu", () => {
|
|
28
29
|
beforeEach(() => {
|
|
29
30
|
mockOnPress.mockClear();
|
|
@@ -35,7 +36,7 @@ describe("Menu", () => {
|
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
expect(getByTestId("more")).toBeDefined();
|
|
38
|
-
expect(getByLabelText(
|
|
39
|
+
expect(getByLabelText(menuLabel)).toBeDefined();
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
it("renders every menu option when menu is opened", () => {
|
|
@@ -48,7 +49,7 @@ describe("Menu", () => {
|
|
|
48
49
|
menuOptions,
|
|
49
50
|
});
|
|
50
51
|
|
|
51
|
-
fireEvent.press(getByLabelText(
|
|
52
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
52
53
|
expect(getByLabelText(menuOptions[0].label)).toBeDefined();
|
|
53
54
|
expect(getByLabelText(menuOptions[1].label)).toBeDefined();
|
|
54
55
|
expect(getByLabelText(menuOptions[2].label)).toBeDefined();
|
|
@@ -116,7 +117,7 @@ describe("Menu", () => {
|
|
|
116
117
|
],
|
|
117
118
|
});
|
|
118
119
|
|
|
119
|
-
fireEvent.press(getByLabelText(
|
|
120
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
120
121
|
fireEvent.press(getByLabelText("hi"));
|
|
121
122
|
expect(mockOnPress).toHaveBeenCalled();
|
|
122
123
|
});
|
|
@@ -128,7 +129,7 @@ describe("Menu", () => {
|
|
|
128
129
|
],
|
|
129
130
|
});
|
|
130
131
|
|
|
131
|
-
fireEvent.press(getByLabelText(
|
|
132
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
132
133
|
expect(getByTestId("add").props.style).toContainEqual({
|
|
133
134
|
display: "flex",
|
|
134
135
|
fill: tokens["color-critical"],
|
|
@@ -150,7 +151,7 @@ describe("Menu", () => {
|
|
|
150
151
|
],
|
|
151
152
|
});
|
|
152
153
|
|
|
153
|
-
fireEvent.press(getByLabelText(
|
|
154
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
154
155
|
fireEvent.press(getByLabelText("hi"));
|
|
155
156
|
expect(mockOnPress).toHaveBeenCalled();
|
|
156
157
|
expect(queryByLabelText("hi")).toBeNull();
|
|
@@ -167,7 +168,7 @@ describe("Menu", () => {
|
|
|
167
168
|
},
|
|
168
169
|
],
|
|
169
170
|
});
|
|
170
|
-
fireEvent.press(getByLabelText(
|
|
171
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
171
172
|
expect(getByText("Hi")).toBeDefined();
|
|
172
173
|
});
|
|
173
174
|
|
|
@@ -182,7 +183,7 @@ describe("Menu", () => {
|
|
|
182
183
|
},
|
|
183
184
|
],
|
|
184
185
|
});
|
|
185
|
-
fireEvent.press(getByLabelText(
|
|
186
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
186
187
|
expect(getByText("hi")).toBeDefined();
|
|
187
188
|
});
|
|
188
189
|
});
|
|
@@ -192,7 +193,7 @@ describe("Menu", () => {
|
|
|
192
193
|
menuOptions: [{ label: "hi", icon: "add", onPress: mockOnPress }],
|
|
193
194
|
});
|
|
194
195
|
|
|
195
|
-
fireEvent.press(getByLabelText(
|
|
196
|
+
fireEvent.press(getByLabelText(menuLabel));
|
|
196
197
|
|
|
197
198
|
expect(getByTestId("ATL-MENU-OPTIONS")).toBeDefined();
|
|
198
199
|
expect(getByTestId("add")).toBeDefined();
|
package/src/Menu/Menu.tsx
CHANGED
|
@@ -6,10 +6,8 @@ import {
|
|
|
6
6
|
useWindowDimensions,
|
|
7
7
|
} from "react-native";
|
|
8
8
|
import { Portal } from "react-native-portalize";
|
|
9
|
-
import { useIntl } from "react-intl";
|
|
10
9
|
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
11
10
|
import { styles } from "./Menu.style";
|
|
12
|
-
import { messages } from "./messages";
|
|
13
11
|
import { findViewpoint } from "./utils";
|
|
14
12
|
import { MenuProps } from "./types";
|
|
15
13
|
import { MenuOption } from "./components/MenuOption";
|
|
@@ -18,6 +16,7 @@ import { tokens } from "../utils/design";
|
|
|
18
16
|
import { Button } from "../Button";
|
|
19
17
|
import { Content } from "../Content";
|
|
20
18
|
import { useAtlantisContext } from "../AtlantisContext";
|
|
19
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
21
20
|
|
|
22
21
|
export function Menu({ menuOptions, customActivator }: MenuProps): JSX.Element {
|
|
23
22
|
const [open, setOpen] = useState<boolean>(false);
|
|
@@ -26,7 +25,7 @@ export function Menu({ menuOptions, customActivator }: MenuProps): JSX.Element {
|
|
|
26
25
|
const menuButtonRef = useRef<View | null>();
|
|
27
26
|
const screenInfo = useScreenInformation();
|
|
28
27
|
|
|
29
|
-
const {
|
|
28
|
+
const { t } = useAtlantisI18n();
|
|
30
29
|
|
|
31
30
|
const findMenuLayout = useCallback(() => {
|
|
32
31
|
if (activatorLayout.current) {
|
|
@@ -78,7 +77,7 @@ export function Menu({ menuOptions, customActivator }: MenuProps): JSX.Element {
|
|
|
78
77
|
{!customActivator && (
|
|
79
78
|
<Button
|
|
80
79
|
icon="more"
|
|
81
|
-
accessibilityLabel={
|
|
80
|
+
accessibilityLabel={t("menu")}
|
|
82
81
|
variation="cancel"
|
|
83
82
|
type="tertiary"
|
|
84
83
|
onPress={() => {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import { useIntl } from "react-intl";
|
|
4
3
|
import { ProgressBarProps } from "./types";
|
|
5
4
|
import { styles } from "./ProgressBar.style";
|
|
6
5
|
import { ProgressBarInner, calculateWidth } from "./ProgressBarInner";
|
|
7
|
-
import { messages } from "./messages";
|
|
8
6
|
import { tokens } from "../utils/design";
|
|
7
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
9
8
|
|
|
10
9
|
export function ProgressBar({
|
|
11
10
|
loading,
|
|
@@ -15,17 +14,13 @@ export function ProgressBar({
|
|
|
15
14
|
reverseTheme = false,
|
|
16
15
|
header,
|
|
17
16
|
}: ProgressBarProps): JSX.Element {
|
|
18
|
-
const {
|
|
19
|
-
const accessibilityLabel = [];
|
|
20
|
-
accessibilityLabel.push(formatMessage(messages.complete, { current, total }));
|
|
21
|
-
inProgress &&
|
|
22
|
-
accessibilityLabel.push(formatMessage(messages.inProgress, { inProgress }));
|
|
17
|
+
const { t } = useAtlantisI18n();
|
|
23
18
|
|
|
24
19
|
return (
|
|
25
20
|
<View
|
|
26
21
|
accessible
|
|
27
22
|
accessibilityRole="progressbar"
|
|
28
|
-
accessibilityLabel={
|
|
23
|
+
accessibilityLabel={getA11yLabel()}
|
|
29
24
|
>
|
|
30
25
|
{header}
|
|
31
26
|
<View style={styles.progressBarContainer}>
|
|
@@ -55,4 +50,18 @@ export function ProgressBar({
|
|
|
55
50
|
</View>
|
|
56
51
|
</View>
|
|
57
52
|
);
|
|
53
|
+
|
|
54
|
+
function getA11yLabel(): string {
|
|
55
|
+
const a11yLabelValues = {
|
|
56
|
+
current: String(current),
|
|
57
|
+
total: String(total),
|
|
58
|
+
inProgress: String(inProgress),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (inProgress) {
|
|
62
|
+
return t("ProgressBar.inProgress", a11yLabelValues);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return t("ProgressBar.complete", a11yLabelValues);
|
|
66
|
+
}
|
|
58
67
|
}
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
import { tokens } from "@jobber/design/foundation";
|
|
9
9
|
import { AccessibilityInfo } from "react-native";
|
|
10
10
|
import { Option, Select } from ".";
|
|
11
|
-
import { messages } from "./messages";
|
|
12
11
|
import { SelectInternalPicker } from "./components/SelectInternalPicker";
|
|
13
12
|
|
|
14
13
|
const A11yInfoSpy = jest.spyOn(AccessibilityInfo, "isScreenReaderEnabled");
|
|
@@ -24,6 +23,8 @@ afterEach(() => {
|
|
|
24
23
|
jest.resetAllMocks();
|
|
25
24
|
});
|
|
26
25
|
|
|
26
|
+
const defaultPlaceholder = "Select an option";
|
|
27
|
+
|
|
27
28
|
describe("Select", () => {
|
|
28
29
|
it("renders a Select", () => {
|
|
29
30
|
const component = render(
|
|
@@ -34,7 +35,7 @@ describe("Select", () => {
|
|
|
34
35
|
);
|
|
35
36
|
expect(component.getByTestId("arrowDown")).toBeDefined();
|
|
36
37
|
expect(
|
|
37
|
-
component.getByText(
|
|
38
|
+
component.getByText(defaultPlaceholder, {
|
|
38
39
|
includeHiddenElements: true,
|
|
39
40
|
}),
|
|
40
41
|
).toBeDefined();
|
|
@@ -191,9 +192,7 @@ describe("Select", () => {
|
|
|
191
192
|
);
|
|
192
193
|
|
|
193
194
|
expect(
|
|
194
|
-
getByText(
|
|
195
|
-
includeHiddenElements: true,
|
|
196
|
-
}),
|
|
195
|
+
getByText(defaultPlaceholder, { includeHiddenElements: true }),
|
|
197
196
|
).toBeDefined();
|
|
198
197
|
});
|
|
199
198
|
|
package/src/Select/Select.tsx
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import React, { ReactElement } from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import { useIntl } from "react-intl";
|
|
4
3
|
import { RegisterOptions } from "react-hook-form";
|
|
5
4
|
import { styles } from "./Select.style";
|
|
6
5
|
import { SelectInternalPicker } from "./components/SelectInternalPicker";
|
|
7
|
-
import { messages } from "./messages";
|
|
8
6
|
import { InputFieldWrapper } from "../InputFieldWrapper";
|
|
9
7
|
import { Icon } from "../Icon";
|
|
10
8
|
import { TextVariation } from "../Typography";
|
|
11
9
|
import { Text } from "../Text";
|
|
12
10
|
import { useFormController } from "../hooks";
|
|
11
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
13
12
|
|
|
14
13
|
export interface SelectOption {
|
|
15
14
|
/**
|
|
@@ -111,7 +110,7 @@ export function Select({
|
|
|
111
110
|
value: value ?? defaultValue,
|
|
112
111
|
});
|
|
113
112
|
|
|
114
|
-
const {
|
|
113
|
+
const { t } = useAtlantisI18n();
|
|
115
114
|
const internalValue = value ?? field.value;
|
|
116
115
|
const textVariation = getTextVariation({
|
|
117
116
|
disabled,
|
|
@@ -134,7 +133,7 @@ export function Select({
|
|
|
134
133
|
accessible={true}
|
|
135
134
|
accessibilityLabel={getA11yLabel()}
|
|
136
135
|
accessibilityValue={{ text: getValue() }}
|
|
137
|
-
accessibilityHint={
|
|
136
|
+
accessibilityHint={t("Select.a11yHint")}
|
|
138
137
|
accessibilityRole="button"
|
|
139
138
|
accessibilityState={{ disabled: disabled }}
|
|
140
139
|
>
|
|
@@ -207,7 +206,7 @@ export function Select({
|
|
|
207
206
|
|
|
208
207
|
if (!internalValue || placeholder) {
|
|
209
208
|
options.unshift({
|
|
210
|
-
label: placeholder ||
|
|
209
|
+
label: placeholder || t("Select.emptyValue"),
|
|
211
210
|
value: "",
|
|
212
211
|
isActive: !internalValue,
|
|
213
212
|
});
|
|
@@ -220,9 +219,7 @@ export function Select({
|
|
|
220
219
|
const options = getOptions();
|
|
221
220
|
|
|
222
221
|
const activeValue = options.find(option => option.isActive);
|
|
223
|
-
return (
|
|
224
|
-
activeValue?.label || placeholder || formatMessage(messages.emptyValue)
|
|
225
|
-
);
|
|
222
|
+
return activeValue?.label || placeholder || t("Select.emptyValue");
|
|
226
223
|
}
|
|
227
224
|
}
|
|
228
225
|
|
|
@@ -8,11 +8,10 @@ import {
|
|
|
8
8
|
} from "react-native";
|
|
9
9
|
import { Picker } from "@react-native-picker/picker";
|
|
10
10
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
11
|
-
import { useIntl } from "react-intl";
|
|
12
11
|
import { styles } from "./SelectDefaultPicker.style";
|
|
13
|
-
import { messages } from "./messages";
|
|
14
12
|
import { SelectInternalPickerProps } from "../../types";
|
|
15
13
|
import { SelectPressable } from "../SelectPressable/SelectPressable";
|
|
14
|
+
import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
16
15
|
|
|
17
16
|
type SelectDefaultPickerProps = SelectInternalPickerProps;
|
|
18
17
|
|
|
@@ -22,7 +21,7 @@ export function SelectDefaultPicker({
|
|
|
22
21
|
onChange,
|
|
23
22
|
}: SelectDefaultPickerProps): JSX.Element {
|
|
24
23
|
const [show, setShow] = useState(false);
|
|
25
|
-
const {
|
|
24
|
+
const { t } = useAtlantisI18n();
|
|
26
25
|
const selectedLanguage = options.find(option => option.isActive);
|
|
27
26
|
|
|
28
27
|
return (
|
|
@@ -36,7 +35,7 @@ export function SelectDefaultPicker({
|
|
|
36
35
|
>
|
|
37
36
|
<TouchableOpacity style={styles.overlay} onPress={hidePicker} />
|
|
38
37
|
<View style={styles.actionBar}>
|
|
39
|
-
<Button title={
|
|
38
|
+
<Button title={t("done")} onPress={hidePicker} />
|
|
40
39
|
</View>
|
|
41
40
|
<View style={styles.pickerContainer} testID="select-wheel-picker">
|
|
42
41
|
<SafeAreaView edges={["bottom"]}>
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
import { cleanup, fireEvent, render } from "@testing-library/react-native";
|
|
3
3
|
import { AccessibilityInfo, View } from "react-native";
|
|
4
4
|
import { SelectDefaultPicker } from "./SelectDefaultPicker";
|
|
5
|
-
import { messages } from "./messages";
|
|
6
5
|
import { Text } from "../../../Text";
|
|
7
6
|
|
|
8
7
|
const A11yInfoSpy = jest.spyOn(AccessibilityInfo, "isScreenReaderEnabled");
|
|
@@ -55,7 +54,7 @@ describe("SelectDefaultPicker", () => {
|
|
|
55
54
|
const screen = setup();
|
|
56
55
|
|
|
57
56
|
fireEvent.press(screen.getByText(childText));
|
|
58
|
-
fireEvent.press(screen.getByText(
|
|
57
|
+
fireEvent.press(screen.getByText("Done"));
|
|
59
58
|
expect(
|
|
60
59
|
screen.getByTestId("SelectDefaultPicker").findAllByType(MockPicker),
|
|
61
60
|
).toEqual([]);
|
package/src/Toast/Toast.tsx
CHANGED
|
@@ -6,28 +6,23 @@ import Toast, {
|
|
|
6
6
|
} from "react-native-toast-message";
|
|
7
7
|
import { AccessibilityInfo, TouchableOpacity, View } from "react-native";
|
|
8
8
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
9
|
-
import { useIntl } from "react-intl";
|
|
10
9
|
import { styles } from "./Toast.styles";
|
|
11
|
-
import { messages } from "./messages";
|
|
12
10
|
import { tokens } from "../utils/design";
|
|
13
11
|
import { Text } from "../Text";
|
|
14
12
|
import { IconButton } from "../IconButton";
|
|
13
|
+
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
15
14
|
|
|
16
15
|
const MAX_TOAST_MESSAGE_LENGTH = 60;
|
|
17
16
|
const ANNOUNCEMENT_DELAY = 100;
|
|
18
17
|
|
|
19
18
|
function DefaultToast({ text1 }: ToastConfigParams<string>): JSX.Element {
|
|
20
19
|
const { bottom } = useSafeAreaInsets();
|
|
21
|
-
const {
|
|
20
|
+
const { t } = useAtlantisI18n();
|
|
22
21
|
const toastContainerStyles = [styles.container, { paddingBottom: bottom }];
|
|
23
22
|
return (
|
|
24
23
|
<View style={toastContainerStyles}>
|
|
25
24
|
<View style={styles.toast}>
|
|
26
|
-
<TouchableOpacity
|
|
27
|
-
style={styles.toastMessage}
|
|
28
|
-
accessibilityRole="alert"
|
|
29
|
-
accessibilityLabel={formatMessage(messages.toastNotificationLabel)}
|
|
30
|
-
>
|
|
25
|
+
<TouchableOpacity style={styles.toastMessage} accessibilityRole="alert">
|
|
31
26
|
<Text reverseTheme>{text1}</Text>
|
|
32
27
|
</TouchableOpacity>
|
|
33
28
|
<View style={styles.toastIcon}>
|
|
@@ -35,7 +30,7 @@ function DefaultToast({ text1 }: ToastConfigParams<string>): JSX.Element {
|
|
|
35
30
|
onPress={Toast.hide}
|
|
36
31
|
name="remove"
|
|
37
32
|
customColor={tokens["color-greyBlue--light"]}
|
|
38
|
-
accessibilityLabel={
|
|
33
|
+
accessibilityLabel={t("dismiss")}
|
|
39
34
|
/>
|
|
40
35
|
</View>
|
|
41
36
|
</View>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./useAtlantisI18n";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"AutoLink.emailCopied": "Email copied",
|
|
3
|
+
"AutoLink.phoneCopied": "Phone number copied",
|
|
4
|
+
"AutoLink.urlCopied": "URL copied",
|
|
5
|
+
"cancel": "Cancel",
|
|
6
|
+
"confirm": "Confirm",
|
|
7
|
+
"copied": "Copied",
|
|
8
|
+
"date": "Date",
|
|
9
|
+
"dismiss": "Dismiss",
|
|
10
|
+
"done": "Done",
|
|
11
|
+
"ContentOverlay.close": "Close {title} modal",
|
|
12
|
+
"errors.couldNotSave": "Could not save changes",
|
|
13
|
+
"errors.notANumber": "Enter a number",
|
|
14
|
+
"FormatFile.label": "Attachment Preview",
|
|
15
|
+
"FormatFile.hint": "Select for more options",
|
|
16
|
+
"FormatFile.preview": "Preview {item}",
|
|
17
|
+
"FormatFile.remove": "Remove {item}",
|
|
18
|
+
"goBack": "Go back",
|
|
19
|
+
"InputFieldWrapper.clear": "Clear input",
|
|
20
|
+
"InputPassword.enterPassword": "Enter a password",
|
|
21
|
+
"loading": "Loading",
|
|
22
|
+
"menu": "Menu",
|
|
23
|
+
"more": "More",
|
|
24
|
+
"networkUnavailableTitle": "Network Unavailable",
|
|
25
|
+
"networkUnavailableDescription": "Check your internet connection and try again later.",
|
|
26
|
+
"ProgressBar.complete": "{current} of {total} complete",
|
|
27
|
+
"ProgressBar.inProgress": "{current} of {total} complete, {inProgress} in progress",
|
|
28
|
+
"save": "Save",
|
|
29
|
+
"Select.a11yHint": "Select to open the picker",
|
|
30
|
+
"Select.emptyValue": "Select an option",
|
|
31
|
+
"time": "Time",
|
|
32
|
+
"tryAgain": "Try again",
|
|
33
|
+
"upload.failed": "Failed to upload.",
|
|
34
|
+
"upload.inProgress": "Upload in progress."
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"AutoLink.emailCopied": "Correo electrónico copiado",
|
|
3
|
+
"AutoLink.phoneCopied": "Número de teléfono copiado",
|
|
4
|
+
"AutoLink.urlCopied": "URL copiada",
|
|
5
|
+
"cancel": "Cancelar",
|
|
6
|
+
"confirm": "Confirmar",
|
|
7
|
+
"copied": "Copiado",
|
|
8
|
+
"date": "Fecha",
|
|
9
|
+
"dismiss": "Descartar",
|
|
10
|
+
"done": "Listo",
|
|
11
|
+
"ContentOverlay.close": "Close {title} modal",
|
|
12
|
+
"errors.couldNotSave": "No se pudieron guardar los cambios",
|
|
13
|
+
"errors.notANumber": "Escriba un número",
|
|
14
|
+
"FormatFile.label": "Attachment Preview",
|
|
15
|
+
"FormatFile.hint": "Select for more options",
|
|
16
|
+
"FormatFile.preview": "Vista previa de {item}",
|
|
17
|
+
"FormatFile.remove": "Eliminar {item}",
|
|
18
|
+
"goBack": "Volver",
|
|
19
|
+
"InputFieldWrapper.clear": "Borrar",
|
|
20
|
+
"InputPassword.enterPassword": "Escriba una contraseña",
|
|
21
|
+
"loading": "Cargando",
|
|
22
|
+
"menu": "Menú",
|
|
23
|
+
"more": "Más",
|
|
24
|
+
"networkUnavailableTitle": "Red no disponible",
|
|
25
|
+
"networkUnavailableDescription": "Compruebe su conexión a Internet e inténtelo de nuevo más adelante.",
|
|
26
|
+
"ProgressBar.complete": "{current} de {total} completo",
|
|
27
|
+
"ProgressBar.inProgress": "{current} de {total} completo, {inProgress} en progreso",
|
|
28
|
+
"save": "Guardar",
|
|
29
|
+
"Select.a11yHint": "Seleccionar para abrir el selector",
|
|
30
|
+
"Select.emptyValue": "Seleccione una opción",
|
|
31
|
+
"time": "Hora",
|
|
32
|
+
"tryAgain": "Intentar de nuevo",
|
|
33
|
+
"upload.failed": "No se pudo adjuntar el archivo.",
|
|
34
|
+
"upload.inProgress": "Carga de archivo en curso."
|
|
35
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-native";
|
|
2
|
+
import { useAtlantisI18n } from ".";
|
|
3
|
+
import en from "./locales/en.json";
|
|
4
|
+
import es from "./locales/es.json";
|
|
5
|
+
import * as context from "../../AtlantisContext";
|
|
6
|
+
|
|
7
|
+
jest.mock("../../AtlantisContext", () => ({
|
|
8
|
+
// need to mark this as a module so that we can spy on it
|
|
9
|
+
__esModule: true,
|
|
10
|
+
...jest.requireActual("../../AtlantisContext"),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe("useAtlantisI18n", () => {
|
|
14
|
+
it("should return english by default", () => {
|
|
15
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
16
|
+
|
|
17
|
+
expect(result.current.t("cancel")).toBe("Cancel");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should interpolate the strings wrapped in {}", () => {
|
|
21
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
22
|
+
|
|
23
|
+
expect(result.current.t("FormatFile.preview", { item: "🔱" })).toBe(
|
|
24
|
+
"Preview 🔱",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("Español", () => {
|
|
29
|
+
it("should return español", () => {
|
|
30
|
+
const spy = jest.spyOn(context, "useAtlantisContext");
|
|
31
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "es" });
|
|
32
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
33
|
+
|
|
34
|
+
expect(result.current.t("cancel")).toBe("Cancelar");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("Unsupported language", () => {
|
|
39
|
+
it("should return the english translation", () => {
|
|
40
|
+
const spy = jest.spyOn(context, "useAtlantisContext");
|
|
41
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "fr" });
|
|
42
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
43
|
+
|
|
44
|
+
expect(result.current.t("cancel")).toBe("Cancel");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("Translation files", () => {
|
|
49
|
+
it("should have the same keys for en and es", () => {
|
|
50
|
+
expect(Object.keys(en)).toEqual(Object.keys(es));
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import en from "./locales/en.json";
|
|
2
|
+
import es from "./locales/es.json";
|
|
3
|
+
import { useAtlantisContext } from "../../AtlantisContext";
|
|
4
|
+
|
|
5
|
+
export type I18nKeys = keyof typeof en;
|
|
6
|
+
|
|
7
|
+
export interface useAtlantisI18nValue {
|
|
8
|
+
readonly locale: string;
|
|
9
|
+
readonly t: (message: I18nKeys, values?: Record<string, string>) => string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useAtlantisI18n(): useAtlantisI18nValue {
|
|
13
|
+
const { locale } = useAtlantisContext();
|
|
14
|
+
const t = (messageKey: keyof typeof en, values?: Record<string, string>) =>
|
|
15
|
+
formatMessage(messageKey, values, locale);
|
|
16
|
+
|
|
17
|
+
return { locale, t };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getLocalizedStrings(locale: string): typeof en {
|
|
21
|
+
switch (locale) {
|
|
22
|
+
case "es":
|
|
23
|
+
return es;
|
|
24
|
+
default:
|
|
25
|
+
return en;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function formatMessage(
|
|
30
|
+
messageKey: keyof typeof en,
|
|
31
|
+
values?: Record<string, string>,
|
|
32
|
+
locale = "en",
|
|
33
|
+
) {
|
|
34
|
+
const message = getLocalizedStrings(locale)[messageKey];
|
|
35
|
+
|
|
36
|
+
if (!values) return message;
|
|
37
|
+
|
|
38
|
+
return Object.entries(values).reduce(
|
|
39
|
+
(acc, [key, value]) => acc.replace(`{${key}}`, value),
|
|
40
|
+
message,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
phoneCopied: {
|
|
4
|
-
id: "phoneCopied",
|
|
5
|
-
defaultMessage: "Phone number copied",
|
|
6
|
-
description: "Message shown after copying a phone number",
|
|
7
|
-
},
|
|
8
|
-
emailCopied: {
|
|
9
|
-
id: "emailCopied",
|
|
10
|
-
defaultMessage: "Email copied",
|
|
11
|
-
description: "Message shown after copying an email",
|
|
12
|
-
},
|
|
13
|
-
urlCopied: {
|
|
14
|
-
id: "urlCopied",
|
|
15
|
-
defaultMessage: "URL copied",
|
|
16
|
-
description: "Message shown after copying a URL",
|
|
17
|
-
},
|
|
18
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
more: {
|
|
4
|
-
id: "more",
|
|
5
|
-
defaultMessage: "More",
|
|
6
|
-
description: "Accessibility label for the More button",
|
|
7
|
-
},
|
|
8
|
-
unavailableNetworkTitle: {
|
|
9
|
-
id: "unavailableNetworkTitle",
|
|
10
|
-
defaultMessage: "Network unavailable",
|
|
11
|
-
description: "The title for alert about network unavailable",
|
|
12
|
-
},
|
|
13
|
-
unavailableNetworkMessage: {
|
|
14
|
-
id: "unavailableNetworkMessage",
|
|
15
|
-
defaultMessage: "Check your internet connection and try again later.",
|
|
16
|
-
description: "The message for alert about network unavailable",
|
|
17
|
-
},
|
|
18
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
closeOverlayA11YLabel: {
|
|
4
|
-
id: "closeOverlayA11yLabel",
|
|
5
|
-
defaultMessage: "Close {title} modal",
|
|
6
|
-
description: "Accessibility label for button to close the overlay modal",
|
|
7
|
-
},
|
|
8
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
networkError: {
|
|
4
|
-
id: "networkError",
|
|
5
|
-
defaultMessage: "Could not save changes",
|
|
6
|
-
description: "Displayed when a general server error occurs during save",
|
|
7
|
-
},
|
|
8
|
-
offlineError: {
|
|
9
|
-
id: "offlineError",
|
|
10
|
-
defaultMessage: "Currently offline. Check your internet connection.",
|
|
11
|
-
description: "Error message to be shown when the app is offline",
|
|
12
|
-
},
|
|
13
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
loadingA11YLabel: {
|
|
4
|
-
id: "loadingA11yLabel",
|
|
5
|
-
defaultMessage: "Loading",
|
|
6
|
-
description: "Accessibility label for the loading indicator",
|
|
7
|
-
},
|
|
8
|
-
dismissAlertButton: {
|
|
9
|
-
id: "dismiss",
|
|
10
|
-
defaultMessage: "Dismiss",
|
|
11
|
-
description: "The label for the button to dismiss the alert ",
|
|
12
|
-
},
|
|
13
|
-
retryAlertButton: {
|
|
14
|
-
id: "retry",
|
|
15
|
-
defaultMessage: "Try Again",
|
|
16
|
-
description: "The label for the alert button to try action again",
|
|
17
|
-
},
|
|
18
|
-
unavailableNetworkTitle: {
|
|
19
|
-
id: "unavailableNetworkTitle",
|
|
20
|
-
defaultMessage: "Network unavailable",
|
|
21
|
-
description: "The title for alert about network unavailable",
|
|
22
|
-
},
|
|
23
|
-
unavailableNetworkMessage: {
|
|
24
|
-
id: "unavailableNetworkMessage",
|
|
25
|
-
defaultMessage: "Check your internet connection and try again later.",
|
|
26
|
-
description: "The message for alert about network unavailable",
|
|
27
|
-
},
|
|
28
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
lightBoxPreviewButton: {
|
|
4
|
-
id: "lightBoxPreviewButton",
|
|
5
|
-
defaultMessage: "Preview {bottomSheetOptionsSuffix}",
|
|
6
|
-
description: "Label for button when preview the file",
|
|
7
|
-
},
|
|
8
|
-
removeButton: {
|
|
9
|
-
id: "removeButton",
|
|
10
|
-
defaultMessage: "Remove {bottomSheetOptionsSuffix}",
|
|
11
|
-
description: "Label for button when remove the file",
|
|
12
|
-
},
|
|
13
|
-
});
|