@applicaster/zapp-react-native-ui-components 14.0.0-alpha.1539862321 → 14.0.0-alpha.1574463810
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/AnimatedInOut/index.tsx +5 -3
- package/Components/AudioPlayer/mobile/Layout.tsx +1 -1
- package/Components/AudioPlayer/tv/helpers.tsx +10 -3
- package/Components/BaseFocusable/index.tsx +23 -12
- package/Components/Cell/index.js +1 -1
- package/Components/ComponentResolver/index.ts +1 -1
- package/Components/FeedLoader/index.js +1 -1
- package/Components/Focusable/Focusable.tsx +5 -3
- package/Components/Focusable/FocusableTvOS.tsx +3 -3
- package/Components/Focusable/FocusableiOS.tsx +2 -2
- package/Components/Focusable/index.tsx +1 -1
- package/Components/FocusableList/index.tsx +4 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +12 -8
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -8
- package/Components/Layout/TV/LayoutBackground.tsx +1 -1
- package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
- package/Components/MasterCell/elementMapper.tsx +1 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
- package/Components/OfflineHandler/__tests__/index.test.tsx +26 -35
- package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +41 -28
- package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
- package/Components/PlayerContainer/index.ts +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +378 -0
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
- package/Components/River/RefreshControl.tsx +6 -4
- package/Components/River/TV/River.tsx +2 -17
- package/Components/River/TV/index.tsx +3 -1
- package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
- package/Components/River/TV/withRiverDataLoader.tsx +17 -0
- package/Components/River/TV/withTVEventHandler.tsx +1 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/index.tsx +1 -1
- package/Components/Screen/__tests__/Screen.test.tsx +28 -29
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
- package/Components/ScreenRevealManager/index.ts +1 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
- package/Components/Tabs/TV/Tabs.android.tsx +0 -2
- package/Components/Tabs/Tabs.tsx +2 -3
- package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
- package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
- package/Components/VideoLive/animationUtils.ts +3 -3
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -8
- package/Components/VideoModal/PlayerDetails.tsx +24 -2
- package/Components/VideoModal/PlayerWrapper.tsx +26 -142
- package/Components/VideoModal/VideoModal.tsx +3 -17
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
- package/Components/VideoModal/hooks/index.ts +0 -2
- package/Components/VideoModal/hooks/useModalSize.ts +18 -2
- package/Components/VideoModal/utils.ts +6 -0
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
- package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
- package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
- package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
- package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
- package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
- package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +241 -0
- package/Decorators/ZappPipesDataConnector/types.ts +29 -0
- package/events/index.ts +1 -0
- package/package.json +5 -10
- package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { path } from "ramda";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
useFeedLoader,
|
|
6
|
+
useRivers,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
screenId: string;
|
|
11
|
+
screenData: ZappRiver | ZappEntry;
|
|
12
|
+
feedUrl?: string;
|
|
13
|
+
river?: ZappRiver | ZappEntry;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const withPipesV1DataLoader = (
|
|
17
|
+
WrappedComponent: React.ComponentType<any>
|
|
18
|
+
) => {
|
|
19
|
+
return function WithPipesV1DataLoaderComponent(props: Props) {
|
|
20
|
+
const { screenId, feedUrl } = props;
|
|
21
|
+
|
|
22
|
+
const rivers = useRivers();
|
|
23
|
+
|
|
24
|
+
const river = React.useMemo(() => rivers?.[screenId], [screenId]);
|
|
25
|
+
|
|
26
|
+
const screenData = React.useMemo(
|
|
27
|
+
() => props.screenData || props.river || river,
|
|
28
|
+
[screenId]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const connectedScreenUrl = useMemo(() => {
|
|
32
|
+
// Avoid using feedUrl or content.src on layouts v2
|
|
33
|
+
|
|
34
|
+
return feedUrl || path(["content", "src"], screenData);
|
|
35
|
+
}, [feedUrl, screenData]);
|
|
36
|
+
|
|
37
|
+
const { data: feedData } = useFeedLoader({
|
|
38
|
+
feedUrl: connectedScreenUrl,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return <WrappedComponent {...props} feedData={feedData} />;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useLayoutVersion } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { withPipesV1DataLoader } from "./withPipesV1DataLoader";
|
|
4
|
+
|
|
5
|
+
export const withRiverDataLoader = (
|
|
6
|
+
WrappedComponent: React.ComponentType<any>
|
|
7
|
+
) => {
|
|
8
|
+
return function WithRiverDataLoaderComponent(props) {
|
|
9
|
+
const isV2 = useLayoutVersion({ isV2: true });
|
|
10
|
+
|
|
11
|
+
if (isV2) {
|
|
12
|
+
return <WrappedComponent {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return withPipesV1DataLoader(WrappedComponent)(props);
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
|
|
|
8
8
|
return function WithTVEventHandler(props) {
|
|
9
9
|
const navigator = useNavigation();
|
|
10
10
|
|
|
11
|
-
const remoteHandler = (
|
|
11
|
+
const remoteHandler = (event) => {
|
|
12
12
|
const { eventType } = event;
|
|
13
13
|
|
|
14
14
|
const canGoBack = navigator.canGoBack();
|
|
@@ -159,6 +159,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
159
159
|
>
|
|
160
160
|
<View>
|
|
161
161
|
<View
|
|
162
|
+
onFocusCapture={[Function]}
|
|
162
163
|
onLayout={[Function]}
|
|
163
164
|
style={null}
|
|
164
165
|
>
|
|
@@ -174,6 +175,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
174
175
|
</View>
|
|
175
176
|
</View>
|
|
176
177
|
<View
|
|
178
|
+
onFocusCapture={[Function]}
|
|
177
179
|
onLayout={[Function]}
|
|
178
180
|
style={null}
|
|
179
181
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
|
-
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
2
|
+
import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
|
|
3
3
|
|
|
4
4
|
import { withRiver } from "../../Decorators/RiverResolver";
|
|
5
5
|
import { withNavigator } from "../../Decorators/Navigator";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import {
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
4
|
|
|
5
5
|
const Mocked_RouteManager = jest.fn((props) => (
|
|
6
6
|
<View testID="routeManager" {...props} />
|
|
@@ -68,12 +68,33 @@ jest.mock(
|
|
|
68
68
|
})
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
+
jest.mock(
|
|
72
|
+
"@applicaster/zapp-react-native-utils/reactHooks/state/useRivers",
|
|
73
|
+
() => ({
|
|
74
|
+
useRivers: jest.fn(() => ({
|
|
75
|
+
rivers: [{ id: "testId", name: "Test River" }],
|
|
76
|
+
})),
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
71
80
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
72
81
|
isNavBarVisible: mockIsNavBarVisible,
|
|
73
82
|
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
83
|
+
useNavigation: jest.fn(() => ({
|
|
84
|
+
canGoBack: () => false,
|
|
85
|
+
currentRoute: "/river/testId",
|
|
86
|
+
activeRiver: { id: "testId" },
|
|
87
|
+
screenData: { id: "testId" },
|
|
88
|
+
data: { screen: { id: "testId" } },
|
|
89
|
+
})),
|
|
90
|
+
useRoute: jest.fn(() => ({
|
|
91
|
+
pathname: "/river/testId",
|
|
92
|
+
screenData: { id: "testId" },
|
|
93
|
+
})),
|
|
74
94
|
}));
|
|
75
95
|
|
|
76
96
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
97
|
+
...jest.requireActual("@applicaster/zapp-react-native-utils/reactHooks"),
|
|
77
98
|
useCurrentScreenData: jest.fn(() => ({
|
|
78
99
|
id: "testId",
|
|
79
100
|
})),
|
|
@@ -84,17 +105,6 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
|
84
105
|
id: "testId",
|
|
85
106
|
navigations: [{ id: "testId", category: "nav_bar" }],
|
|
86
107
|
})),
|
|
87
|
-
useNavigation: jest.fn(() => ({
|
|
88
|
-
canGoBack: () => false,
|
|
89
|
-
currentRoute: "/river/testId",
|
|
90
|
-
activeRiver: { id: "testId" },
|
|
91
|
-
screenData: { id: "testId" },
|
|
92
|
-
data: { screen: { id: "testId" } },
|
|
93
|
-
})),
|
|
94
|
-
useRoute: jest.fn(() => ({
|
|
95
|
-
pathname: "/river/testId",
|
|
96
|
-
screenData: { id: "testId" },
|
|
97
|
-
})),
|
|
98
108
|
useDimensions: jest.fn(() => ({
|
|
99
109
|
width: 1920,
|
|
100
110
|
height: 1080,
|
|
@@ -102,10 +112,11 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
|
102
112
|
useIsTablet: jest.fn(() => false),
|
|
103
113
|
}));
|
|
104
114
|
|
|
105
|
-
jest.mock("@applicaster/zapp-react-native-redux/hooks
|
|
115
|
+
jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
|
|
106
116
|
const View = jest.requireActual("react-native").View;
|
|
107
117
|
|
|
108
118
|
return {
|
|
119
|
+
...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
|
|
109
120
|
usePickFromState: () => ({
|
|
110
121
|
plugins: [
|
|
111
122
|
{
|
|
@@ -141,8 +152,6 @@ const screenProps = {
|
|
|
141
152
|
const { Screen } = require("..");
|
|
142
153
|
|
|
143
154
|
describe("<Screen Component />", () => {
|
|
144
|
-
let wrapper;
|
|
145
|
-
|
|
146
155
|
beforeEach(() => {
|
|
147
156
|
allowedOrientationsForScreen.mockClear();
|
|
148
157
|
getOrientation.mockClear();
|
|
@@ -150,26 +159,16 @@ describe("<Screen Component />", () => {
|
|
|
150
159
|
});
|
|
151
160
|
|
|
152
161
|
describe("when the navbar should show", () => {
|
|
153
|
-
act(() => {
|
|
154
|
-
wrapper = create(<Screen {...screenProps} />);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
162
|
it("renders correctly", () => {
|
|
158
|
-
|
|
163
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
164
|
+
expect(toJSON()).toMatchSnapshot();
|
|
159
165
|
});
|
|
160
166
|
});
|
|
161
167
|
|
|
162
168
|
describe("when the navbar should be hidden", () => {
|
|
163
|
-
beforeEach(() => {
|
|
164
|
-
wrapper = create(<Screen {...screenProps} />);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
169
|
it("renders correctly", () => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
170
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
171
|
+
expect(toJSON()).toMatchSnapshot();
|
|
173
172
|
});
|
|
174
173
|
});
|
|
175
174
|
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
2
|
+
import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
3
|
+
import { once } from "ramda";
|
|
4
|
+
|
|
5
|
+
const INITIAL_NUMBER_TO_LOAD = 3;
|
|
6
|
+
|
|
7
|
+
// Infer the values of COMPONENT_LOADING_STATE as a type
|
|
8
|
+
type ComponentLoadingState =
|
|
9
|
+
(typeof COMPONENT_LOADING_STATE)[keyof typeof COMPONENT_LOADING_STATE];
|
|
10
|
+
|
|
11
|
+
export const COMPONENT_LOADING_STATE = {
|
|
12
|
+
UNKNOWN: "UNKNOWN",
|
|
13
|
+
LOADED_WITH_SUCCESS: "LOADED_WITH_SUCCESS",
|
|
14
|
+
LOADED_WITH_FAILURE: "LOADED_WITH_FAILURE",
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
// Function to get the number of loaded components
|
|
18
|
+
const getNumberOfLoaded = (states: ComponentLoadingState[]): number => {
|
|
19
|
+
return states.filter((value) => value !== COMPONENT_LOADING_STATE.UNKNOWN)
|
|
20
|
+
.length;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getNumberOfComponentsWaitToLoadBeforePresent = (
|
|
24
|
+
componentsToRender: ZappUIComponent[]
|
|
25
|
+
): number => {
|
|
26
|
+
// when Gallery is the first component, no need to wait the others
|
|
27
|
+
if (isFirstComponentGallery(componentsToRender)) {
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Math.min(INITIAL_NUMBER_TO_LOAD, componentsToRender.length);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export class ScreenRevealManager {
|
|
35
|
+
public numberOfComponentsWaitToLoadBeforePresent: number;
|
|
36
|
+
private renderingState: Array<ComponentLoadingState>;
|
|
37
|
+
private callback: Callback;
|
|
38
|
+
|
|
39
|
+
constructor(componentsToRender: ZappUIComponent[], callback: Callback) {
|
|
40
|
+
this.numberOfComponentsWaitToLoadBeforePresent =
|
|
41
|
+
getNumberOfComponentsWaitToLoadBeforePresent(componentsToRender);
|
|
42
|
+
|
|
43
|
+
this.renderingState = makeListOf<ComponentLoadingState>(
|
|
44
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
45
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
this.callback = once(callback);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onLoadFinished = (index: number): void => {
|
|
52
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS;
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
56
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
57
|
+
) {
|
|
58
|
+
this.setIsReadyToShow();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
onLoadFailed = (index: number): void => {
|
|
63
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE;
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
67
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
68
|
+
) {
|
|
69
|
+
this.setIsReadyToShow();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
setIsReadyToShow = (): void => {
|
|
74
|
+
this.callback();
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ScreenRevealManager,
|
|
3
|
+
COMPONENT_LOADING_STATE,
|
|
4
|
+
} from "../ScreenRevealManager";
|
|
5
|
+
|
|
6
|
+
describe("ScreenRevealManager", () => {
|
|
7
|
+
const mockCallback = jest.fn();
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should initialize with the correct number of components to wait for", () => {
|
|
14
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
15
|
+
{ component_type: "component1" },
|
|
16
|
+
{ component_type: "component2" },
|
|
17
|
+
{ component_type: "component3" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
21
|
+
|
|
22
|
+
expect(manager["numberOfComponentsWaitToLoadBeforePresent"]).toBe(3);
|
|
23
|
+
|
|
24
|
+
expect(manager["renderingState"]).toEqual([
|
|
25
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
26
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
27
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should call the callback when the required number of components are loaded successfully", () => {
|
|
32
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
33
|
+
{ component_type: "component1" },
|
|
34
|
+
{ component_type: "component2" },
|
|
35
|
+
{ component_type: "component3" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
39
|
+
|
|
40
|
+
manager.onLoadFinished(0);
|
|
41
|
+
manager.onLoadFinished(1);
|
|
42
|
+
manager.onLoadFinished(2);
|
|
43
|
+
|
|
44
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should call the callback when the required number of components fail to load", () => {
|
|
48
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
49
|
+
{ component_type: "component1" },
|
|
50
|
+
{ component_type: "component2" },
|
|
51
|
+
{ component_type: "component3" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
55
|
+
|
|
56
|
+
manager.onLoadFailed(0);
|
|
57
|
+
manager.onLoadFailed(1);
|
|
58
|
+
manager.onLoadFailed(2);
|
|
59
|
+
|
|
60
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should call the callback when a mix of successful and failed loads meet the required number", () => {
|
|
64
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
65
|
+
{ component_type: "component1" },
|
|
66
|
+
{ component_type: "component2" },
|
|
67
|
+
{ component_type: "component3" },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
71
|
+
|
|
72
|
+
manager.onLoadFinished(0);
|
|
73
|
+
manager.onLoadFailed(1);
|
|
74
|
+
manager.onLoadFinished(2);
|
|
75
|
+
|
|
76
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should not call the callback if the required number of components are not loaded", () => {
|
|
80
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
81
|
+
{ component_type: "component1" },
|
|
82
|
+
{ component_type: "component2" },
|
|
83
|
+
{ component_type: "component3" },
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
87
|
+
|
|
88
|
+
manager.onLoadFinished(0);
|
|
89
|
+
manager.onLoadFailed(1);
|
|
90
|
+
|
|
91
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should call the callback when the when first component is gallery and it was loaded successfully", () => {
|
|
95
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
96
|
+
{ component_type: "gallery-qb" },
|
|
97
|
+
{ component_type: "component2" },
|
|
98
|
+
{ component_type: "component3" },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
102
|
+
|
|
103
|
+
manager.onLoadFinished(0);
|
|
104
|
+
|
|
105
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { render, screen, act } from "@testing-library/react-native";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import {
|
|
7
|
+
withScreenRevealManager,
|
|
8
|
+
SHOWN,
|
|
9
|
+
TIMEOUT,
|
|
10
|
+
} from "../withScreenRevealManager";
|
|
11
|
+
|
|
12
|
+
// jest.mock("react-native/Libraries/Animated/NativeAnimatedHelper");
|
|
13
|
+
|
|
14
|
+
const MockComponent = ({
|
|
15
|
+
initialNumberToLoad,
|
|
16
|
+
onLoadFinishedFromScreenRevealManager,
|
|
17
|
+
onLoadFailedFromScreenRevealManager,
|
|
18
|
+
}) => {
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
// Simulate loading components
|
|
21
|
+
for (let i = 0; i < initialNumberToLoad; i++) {
|
|
22
|
+
onLoadFinishedFromScreenRevealManager(i);
|
|
23
|
+
}
|
|
24
|
+
}, [initialNumberToLoad, onLoadFinishedFromScreenRevealManager]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<View
|
|
28
|
+
testID="mock-component"
|
|
29
|
+
initialNumberToLoad={initialNumberToLoad}
|
|
30
|
+
onLoadFinishedFromScreenRevealManager={
|
|
31
|
+
onLoadFinishedFromScreenRevealManager
|
|
32
|
+
}
|
|
33
|
+
onLoadFailedFromScreenRevealManager={onLoadFailedFromScreenRevealManager}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const WrappedComponent = withScreenRevealManager(MockComponent);
|
|
39
|
+
|
|
40
|
+
describe.skip("withScreenRevealManager", () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
jest.clearAllMocks();
|
|
43
|
+
jest.useFakeTimers();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
jest.runOnlyPendingTimers();
|
|
48
|
+
jest.useRealTimers();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should render the wrapped component", () => {
|
|
52
|
+
render(
|
|
53
|
+
<WrappedComponent
|
|
54
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(screen.getByTestId("mock-component")).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should animate opacity when ready to show", () => {
|
|
62
|
+
render(
|
|
63
|
+
<WrappedComponent
|
|
64
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const animatedView = screen.getByTestId("animated-component");
|
|
69
|
+
|
|
70
|
+
act(() => {
|
|
71
|
+
jest.advanceTimersByTime(TIMEOUT + 100);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(animatedView.props.style.opacity).toBe(SHOWN);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should pass initialNumberToLoad, onLoadFinishedFromScreenRevealManager, and onLoadFailedFromScreenRevealManager to the wrapped component", () => {
|
|
78
|
+
render(
|
|
79
|
+
<WrappedComponent
|
|
80
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const mockComponent = screen.getByTestId("mock-component");
|
|
85
|
+
|
|
86
|
+
expect(mockComponent.props.initialNumberToLoad).toBe(3);
|
|
87
|
+
|
|
88
|
+
expect(
|
|
89
|
+
mockComponent.props.onLoadFinishedFromScreenRevealManager
|
|
90
|
+
).toBeInstanceOf(Function);
|
|
91
|
+
|
|
92
|
+
expect(
|
|
93
|
+
mockComponent.props.onLoadFailedFromScreenRevealManager
|
|
94
|
+
).toBeInstanceOf(Function);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withScreenRevealManager } from "./withScreenRevealManager";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
4
|
+
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
|
+
import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
|
|
6
|
+
|
|
7
|
+
import { ScreenRevealManager } from "./ScreenRevealManager";
|
|
8
|
+
|
|
9
|
+
const flex = platformSelect({
|
|
10
|
+
tvos: 1,
|
|
11
|
+
android_tv: 1,
|
|
12
|
+
web: undefined,
|
|
13
|
+
samsung_tv: undefined,
|
|
14
|
+
lg_tv: undefined,
|
|
15
|
+
default: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const TIMEOUT = 500; // 500 ms
|
|
19
|
+
|
|
20
|
+
const HIDDEN = 0; // opacity = 0
|
|
21
|
+
|
|
22
|
+
export const SHOWN = 1; // opacity = 1
|
|
23
|
+
|
|
24
|
+
type Props = {
|
|
25
|
+
componentsToRender: ZappUIComponent[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const withScreenRevealManager = (Component) => {
|
|
29
|
+
return function WithScreenRevealManager(props: Props) {
|
|
30
|
+
const { componentsToRender } = props;
|
|
31
|
+
|
|
32
|
+
const [isReadyToShow, setIsReadyToShow] = React.useState(false);
|
|
33
|
+
|
|
34
|
+
const handleSetIsReadyToShow = React.useCallback(() => {
|
|
35
|
+
setIsReadyToShow(true);
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
const managerRef = useRefWithInitialValue<ScreenRevealManager>(
|
|
39
|
+
() => new ScreenRevealManager(componentsToRender, handleSetIsReadyToShow)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const opacityRef = useRefWithInitialValue<Animated.Value>(
|
|
43
|
+
() => new Animated.Value(HIDDEN)
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
if (isReadyToShow) {
|
|
48
|
+
Animated.timing(opacityRef.current, {
|
|
49
|
+
toValue: SHOWN,
|
|
50
|
+
duration: TIMEOUT,
|
|
51
|
+
useNativeDriver: true,
|
|
52
|
+
}).start();
|
|
53
|
+
}
|
|
54
|
+
}, [isReadyToShow]);
|
|
55
|
+
|
|
56
|
+
if (isFirstComponentScreenPicker(componentsToRender)) {
|
|
57
|
+
// for screen-picker with have additional internal ComponentsMap, no need to add this wrapper
|
|
58
|
+
return <Component {...props} />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Animated.View
|
|
63
|
+
style={{ opacity: opacityRef.current, flex }}
|
|
64
|
+
testID="animated-component"
|
|
65
|
+
>
|
|
66
|
+
<Component
|
|
67
|
+
{...props}
|
|
68
|
+
initialNumberToLoad={
|
|
69
|
+
managerRef.current.numberOfComponentsWaitToLoadBeforePresent
|
|
70
|
+
}
|
|
71
|
+
onLoadFinishedFromScreenRevealManager={
|
|
72
|
+
managerRef.current.onLoadFinished
|
|
73
|
+
}
|
|
74
|
+
onLoadFailedFromScreenRevealManager={managerRef.current.onLoadFailed}
|
|
75
|
+
/>
|
|
76
|
+
</Animated.View>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
};
|
|
@@ -7,7 +7,6 @@ import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
|
7
7
|
|
|
8
8
|
import Tab from "./Tab";
|
|
9
9
|
import { Gutter } from "../Gutter";
|
|
10
|
-
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
11
10
|
import { ImageBackground, View } from "react-native";
|
|
12
11
|
import { getStyles } from "./styles";
|
|
13
12
|
import {
|
|
@@ -100,7 +99,6 @@ const TabsComponent = ({
|
|
|
100
99
|
>
|
|
101
100
|
<FocusableList
|
|
102
101
|
horizontal
|
|
103
|
-
onScrollToIndexFailed={noop}
|
|
104
102
|
onLayout={onLayoutChange}
|
|
105
103
|
contentContainerStyle={tabsListContentContainer}
|
|
106
104
|
ref={flatListRef}
|
package/Components/Tabs/Tabs.tsx
CHANGED
|
@@ -158,12 +158,11 @@ const TabsComponent = ({
|
|
|
158
158
|
|
|
159
159
|
const renderItem = React.useCallback(
|
|
160
160
|
({ item, index, item: { id } }: RenderItemProps) => (
|
|
161
|
-
|
|
161
|
+
<React.Fragment key={id}>
|
|
162
162
|
<Tab
|
|
163
163
|
ref={(ref) => {
|
|
164
164
|
tabRefs.current[index] = ref;
|
|
165
165
|
}}
|
|
166
|
-
key={id}
|
|
167
166
|
{...{
|
|
168
167
|
title: getTitle(item),
|
|
169
168
|
id,
|
|
@@ -177,7 +176,7 @@ const TabsComponent = ({
|
|
|
177
176
|
{display_mode === "fractional" &&
|
|
178
177
|
index !== tabs?.length - 1 &&
|
|
179
178
|
renderGutter()}
|
|
180
|
-
|
|
179
|
+
</React.Fragment>
|
|
181
180
|
),
|
|
182
181
|
[tabs, display_mode, configuration, onTabPress, getTitle, getSelectedItem]
|
|
183
182
|
);
|
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
exports[`<Touchable /> when not running in automated tests environment renders correctly 1`] = `
|
|
4
4
|
<View
|
|
5
5
|
accessibilityLabel="some-test-id"
|
|
6
|
+
accessibilityState={
|
|
7
|
+
{
|
|
8
|
+
"busy": undefined,
|
|
9
|
+
"checked": undefined,
|
|
10
|
+
"disabled": undefined,
|
|
11
|
+
"expanded": undefined,
|
|
12
|
+
"selected": undefined,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
accessibilityValue={
|
|
16
|
+
{
|
|
17
|
+
"max": undefined,
|
|
18
|
+
"min": undefined,
|
|
19
|
+
"now": undefined,
|
|
20
|
+
"text": undefined,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
6
23
|
accessible={true}
|
|
7
24
|
collapsable={false}
|
|
8
25
|
focusable={true}
|
|
@@ -29,6 +46,23 @@ exports[`<Touchable /> when not running in automated tests environment renders c
|
|
|
29
46
|
exports[`<Touchable /> when running in automated tests environment has accessible flag set to false 1`] = `
|
|
30
47
|
<View
|
|
31
48
|
accessibilityLabel="some-test-id"
|
|
49
|
+
accessibilityState={
|
|
50
|
+
{
|
|
51
|
+
"busy": undefined,
|
|
52
|
+
"checked": undefined,
|
|
53
|
+
"disabled": undefined,
|
|
54
|
+
"expanded": undefined,
|
|
55
|
+
"selected": undefined,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
accessibilityValue={
|
|
59
|
+
{
|
|
60
|
+
"max": undefined,
|
|
61
|
+
"min": undefined,
|
|
62
|
+
"now": undefined,
|
|
63
|
+
"text": undefined,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
32
66
|
accessible={false}
|
|
33
67
|
collapsable={false}
|
|
34
68
|
focusable={true}
|