@applicaster/zapp-react-native-ui-components 16.0.0-rc.81 → 16.0.0-rc.83
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/Components/MasterCell/DefaultComponents/ActionButton.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/package.json +5 -5
|
@@ -105,6 +105,7 @@ export const ActionButton = React.memo(function ActionButtonComponent(
|
|
|
105
105
|
testID={props?.testID || `${item?.id}`}
|
|
106
106
|
accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
|
|
107
107
|
accessibilityHint={props?.accessibilityHint}
|
|
108
|
+
accessibilityRole="button"
|
|
108
109
|
accessible={!!(props?.testID || props?.accessibilityLabel)}
|
|
109
110
|
style={props?.style}
|
|
110
111
|
>
|
|
@@ -91,6 +91,7 @@ function ButtonComponent(props: Props) {
|
|
|
91
91
|
onPress={onPress}
|
|
92
92
|
testID={props?.testID || `${item?.id}`}
|
|
93
93
|
accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
|
|
94
|
+
accessibilityRole="button"
|
|
94
95
|
accessible={!!(props?.testID || props?.accessibilityLabel)}
|
|
95
96
|
style={props?.style}
|
|
96
97
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { TouchableOpacity } from "react-native";
|
|
3
3
|
import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components";
|
|
4
|
+
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
4
5
|
// @ts-ignore
|
|
5
6
|
import { defaultCloseAsset } from "./assets";
|
|
6
7
|
|
|
@@ -40,9 +41,20 @@ export function CloseButton(props: CloseButtonProps) {
|
|
|
40
41
|
|
|
41
42
|
if (!enabled) return null;
|
|
42
43
|
|
|
44
|
+
// Expose the close button as its own accessible control so screen readers
|
|
45
|
+
// (e.g. iOS VoiceOver) can focus and activate it. The image-only button
|
|
46
|
+
// otherwise has no label/role, leaving it unreachable/unannounced. Uses the
|
|
47
|
+
// framework's localized "close" button config (label + hint + button role).
|
|
48
|
+
// Computed each render (not memoized) so runtime localization updates via
|
|
49
|
+
// AccessibilityManager.updateLocalizations() are picked up on re-render.
|
|
50
|
+
const accessibilityProps =
|
|
51
|
+
AccessibilityManager.getInstance().getButtonAccessibilityProps("close");
|
|
52
|
+
|
|
43
53
|
return (
|
|
44
54
|
<TouchableOpacity
|
|
45
55
|
activeOpacity={1}
|
|
56
|
+
testID="closeButton"
|
|
57
|
+
{...accessibilityProps}
|
|
46
58
|
style={{
|
|
47
59
|
marginBottom,
|
|
48
60
|
marginTop,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react-native";
|
|
3
|
+
import { CloseButton, CloseButtonProps } from "../CloseButton";
|
|
4
|
+
|
|
5
|
+
jest.mock("@applicaster/zapp-react-native-ui-components/Components", () => {
|
|
6
|
+
const { Image } = require("react-native");
|
|
7
|
+
|
|
8
|
+
return { QBImage: Image };
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const mockGetButtonA11yProps = jest.fn(() => ({
|
|
12
|
+
accessible: true,
|
|
13
|
+
accessibilityLabel: "Close",
|
|
14
|
+
accessibilityHint: "Closes the sheet",
|
|
15
|
+
accessibilityRole: "button",
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
jest.mock(
|
|
19
|
+
"@applicaster/zapp-react-native-utils/appUtils/accessibilityManager",
|
|
20
|
+
() => ({
|
|
21
|
+
AccessibilityManager: {
|
|
22
|
+
getInstance: () => ({
|
|
23
|
+
getButtonAccessibilityProps: mockGetButtonA11yProps,
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const baseProps: CloseButtonProps = {
|
|
30
|
+
enabled: true,
|
|
31
|
+
close: jest.fn(),
|
|
32
|
+
asset: "close.png",
|
|
33
|
+
assetFocused: "close_focused.png",
|
|
34
|
+
height: 24,
|
|
35
|
+
width: 24,
|
|
36
|
+
marginTop: 0,
|
|
37
|
+
marginBottom: 0,
|
|
38
|
+
marginLeft: 0,
|
|
39
|
+
marginRight: 0,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
describe("ModalComponent Header CloseButton", () => {
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
jest.clearAllMocks();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("renders as an accessible button reachable by screen readers", () => {
|
|
48
|
+
render(<CloseButton {...baseProps} />);
|
|
49
|
+
|
|
50
|
+
const button = screen.getByTestId("closeButton");
|
|
51
|
+
|
|
52
|
+
expect(button.props.accessible).toBe(true);
|
|
53
|
+
expect(button.props.accessibilityRole).toBe("button");
|
|
54
|
+
expect(button.props.accessibilityLabel).toBe("Close");
|
|
55
|
+
expect(mockGetButtonA11yProps).toHaveBeenCalledWith("close");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("invokes close on press", () => {
|
|
59
|
+
const close = jest.fn();
|
|
60
|
+
render(<CloseButton {...baseProps} close={close} />);
|
|
61
|
+
|
|
62
|
+
fireEvent.press(screen.getByTestId("closeButton"));
|
|
63
|
+
|
|
64
|
+
expect(close).toHaveBeenCalledTimes(1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("renders nothing when disabled", () => {
|
|
68
|
+
render(<CloseButton {...baseProps} enabled={false} />);
|
|
69
|
+
|
|
70
|
+
expect(screen.queryByTestId("closeButton")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -20,6 +20,8 @@ type Props = ZappScreenProps & {
|
|
|
20
20
|
setIsScreenWrappedInContainer: (isInsideContainer: boolean) => void;
|
|
21
21
|
screenContext: ZappRiver;
|
|
22
22
|
river: ZappRiver;
|
|
23
|
+
/** Result channel for screens presented as a modal; forwarded to the resolved screen. */
|
|
24
|
+
resultCallback?: hookCallback;
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export class RiverComponent extends React.Component<Props> {
|
|
@@ -64,6 +66,7 @@ export class RiverComponent extends React.Component<Props> {
|
|
|
64
66
|
isInsideContainer,
|
|
65
67
|
groupId,
|
|
66
68
|
scrollViewExtraProps,
|
|
69
|
+
resultCallback,
|
|
67
70
|
} = this.props;
|
|
68
71
|
|
|
69
72
|
const { id, type } = river;
|
|
@@ -77,6 +80,7 @@ export class RiverComponent extends React.Component<Props> {
|
|
|
77
80
|
})}
|
|
78
81
|
screenId={id}
|
|
79
82
|
screenType={type}
|
|
83
|
+
resultCallback={resultCallback}
|
|
80
84
|
/>
|
|
81
85
|
);
|
|
82
86
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
|
|
4
|
+
import { RiverComponent } from "../River";
|
|
5
|
+
|
|
6
|
+
const mockResolverProps: any[] = [];
|
|
7
|
+
|
|
8
|
+
jest.mock("../../ScreenResolver", () => ({
|
|
9
|
+
ScreenResolver: (props: any) => {
|
|
10
|
+
mockResolverProps.push(props);
|
|
11
|
+
|
|
12
|
+
return null;
|
|
13
|
+
},
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const river = { id: "river-parent-lock", type: "parent_lock" } as any;
|
|
17
|
+
|
|
18
|
+
const baseProps = {
|
|
19
|
+
river,
|
|
20
|
+
screenData: {},
|
|
21
|
+
groupId: "group-1",
|
|
22
|
+
scrollViewExtraProps: {},
|
|
23
|
+
setIsScreenWrappedInContainer: jest.fn(),
|
|
24
|
+
screenContext: { navBar: { setTitle: jest.fn(), setSummary: jest.fn() } },
|
|
25
|
+
} as any;
|
|
26
|
+
|
|
27
|
+
const resolved = () => mockResolverProps[mockResolverProps.length - 1];
|
|
28
|
+
|
|
29
|
+
describe("RiverComponent", () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
mockResolverProps.length = 0;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("forwards resultCallback to the screen it resolves", () => {
|
|
35
|
+
const resultCallback = jest.fn();
|
|
36
|
+
|
|
37
|
+
render(<RiverComponent {...baseProps} resultCallback={resultCallback} />);
|
|
38
|
+
|
|
39
|
+
expect(resolved().resultCallback).toBe(resultCallback);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("resolves the screen without a resultCallback when none was given", () => {
|
|
43
|
+
render(<RiverComponent {...baseProps} />);
|
|
44
|
+
|
|
45
|
+
expect(resolved().resultCallback).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "16.0.0-rc.
|
|
3
|
+
"version": "16.0.0-rc.83",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "16.0.0-rc.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "16.0.0-rc.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "16.0.0-rc.
|
|
31
|
+
"@applicaster/applicaster-types": "16.0.0-rc.83",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.83",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "16.0.0-rc.83",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "16.0.0-rc.83",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
37
|
"react-native-sortables": "1.7.1",
|