@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-alpha.4285753931
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/BackgroundImage/BackgroundImage.tv.android.tsx +28 -0
- package/Components/BackgroundImage/BackgroundImage.tv.ios.tsx +24 -0
- package/Components/BackgroundImage/BackgroundImage.tv.web.tsx +42 -0
- package/Components/BackgroundImage/index.ts +8 -0
- package/Components/BaseFocusable/index.ios.ts +2 -12
- package/Components/Cell/FocusableWrapper.tsx +0 -3
- package/Components/Cell/TvOSCellComponent.tsx +0 -5
- package/Components/CellRendererResolver/index.ts +1 -1
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
- package/Components/Focusable/Focusable.tsx +2 -4
- package/Components/Focusable/FocusableTvOS.tsx +1 -18
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +0 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +12 -37
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
- package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +24 -42
- package/Components/HandlePlayable/utils.ts +31 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/FullWidthRow.tsx +38 -0
- package/Components/Layout/TV/ScreenContainer.tsx +11 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -1
- package/Components/Layout/TV/index.tsx +6 -6
- package/Components/Layout/TV/index.web.tsx +6 -6
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +10 -4
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +1 -5
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -11
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +1 -9
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +14 -15
- package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -16
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +6 -7
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +11 -233
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +15 -19
- package/Components/Navigator/StackNavigator.tsx +6 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +18 -17
- package/Components/OfflineHandler/__tests__/index.test.tsx +18 -27
- package/Components/PlayerContainer/PlayerContainer.tsx +13 -31
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +286 -0
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -4
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +9 -3
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/TV/River.tsx +14 -31
- package/Components/River/TV/index.tsx +4 -8
- package/Components/River/TV/withTVEventHandler.tsx +36 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +0 -16
- package/Components/River/__tests__/componentsMap.test.js +0 -38
- package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
- package/Components/Screen/TV/hooks/index.ts +2 -0
- package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
- package/Components/Screen/TV/index.web.tsx +18 -11
- package/Components/Screen/__tests__/Screen.test.tsx +43 -65
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +44 -68
- package/Components/Screen/hooks.ts +76 -5
- package/Components/Screen/index.tsx +10 -3
- package/Components/Screen/orientationHandler.ts +3 -3
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
- package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
- package/Components/ScreenFeedLoader/index.ts +1 -0
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
- package/Components/ScreenResolver/hooks/index.ts +3 -0
- package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
- package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
- package/Components/ScreenResolver/index.tsx +9 -115
- package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
- package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
- package/Components/ScreenResolver/utils/index.ts +1 -0
- package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
- package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
- package/Components/ScreenResolverFeedProvider/index.ts +1 -0
- package/Components/ScreenRevealManager/Overlay.tsx +34 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +8 -40
- package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +10 -18
- package/Components/Tabs/TabContent.tsx +4 -7
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/LiveImageManager.ts +209 -53
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +32 -32
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +7 -15
- package/Components/VideoModal/utils.ts +16 -13
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/index.js +1 -1
- package/Contexts/CachedDimensionsContext/index.ts +17 -2
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +64 -26
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Decorators/Analytics/index.tsx +5 -6
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +0 -1
- package/Decorators/ConfigurationWrapper/const.ts +0 -1
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/DataSourceHelper/index.js +19 -0
- package/Helpers/index.js +7 -40
- package/package.json +5 -5
- package/Components/Layout/TV/LayoutBackground.tsx +0 -31
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -101
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +0 -30
- package/Components/River/TV/utils/index.ts +0 -4
- package/Components/River/TV/withFocusableGroupForContent.tsx +0 -71
- package/Helpers/Analytics/index.js +0 -95
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +0 -80
- package/Helpers/DataSourceHelper/index.ts +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -139,13 +139,7 @@ jest.mock(
|
|
|
139
139
|
})
|
|
140
140
|
);
|
|
141
141
|
|
|
142
|
-
jest.mock("@applicaster/zapp-react-native-ui-components/events", () => ({
|
|
143
|
-
...jest.requireActual("@applicaster/zapp-react-native-ui-components/events"),
|
|
144
|
-
emitScrollEndReached: jest.fn(),
|
|
145
|
-
}));
|
|
146
|
-
|
|
147
142
|
const { View } = require("react-native");
|
|
148
|
-
const events = require("@applicaster/zapp-react-native-ui-components/events");
|
|
149
143
|
const { ComponentsMap } = require("../ComponentsMap/ComponentsMap");
|
|
150
144
|
const theme = require("./theme-mock.json");
|
|
151
145
|
|
|
@@ -196,36 +190,4 @@ describe("componentsMap", () => {
|
|
|
196
190
|
|
|
197
191
|
expect(toJSON()).toMatchSnapshot();
|
|
198
192
|
});
|
|
199
|
-
|
|
200
|
-
it("calls emitScrollEndReached when onScroll was called and isScreenWrappedInContainer is false", () => {
|
|
201
|
-
themeSpy = jest
|
|
202
|
-
.spyOn(themeUtils, "useTheme")
|
|
203
|
-
.mockImplementation(() => () => theme);
|
|
204
|
-
|
|
205
|
-
events.emitScrollEndReached.mockClear();
|
|
206
|
-
|
|
207
|
-
const { getByTestId } = render(
|
|
208
|
-
<Provider store={store}>
|
|
209
|
-
<ComponentsMap
|
|
210
|
-
{...props}
|
|
211
|
-
isScreenWrappedInContainer={false}
|
|
212
|
-
feed={{ entry: [] }}
|
|
213
|
-
/>
|
|
214
|
-
</Provider>
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
const flatList = getByTestId("components-map-flat-list");
|
|
218
|
-
|
|
219
|
-
flatList.props.onScroll({
|
|
220
|
-
nativeEvent: {
|
|
221
|
-
contentOffset: { y: 0 },
|
|
222
|
-
layoutMeasurement: { height: 100 },
|
|
223
|
-
contentSize: { height: 200 },
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
flatList.props.onEndReached();
|
|
228
|
-
|
|
229
|
-
expect(events.emitScrollEndReached).toHaveBeenCalledTimes(1);
|
|
230
|
-
});
|
|
231
193
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
import { useAfterPaint } from "../useAfterPaint";
|
|
4
|
+
|
|
5
|
+
describe("useAfterPaint", () => {
|
|
6
|
+
let frameCallbacks: FrameRequestCallback[];
|
|
7
|
+
let originalRaf: typeof requestAnimationFrame;
|
|
8
|
+
let originalCancelRaf: typeof cancelAnimationFrame;
|
|
9
|
+
|
|
10
|
+
const flushFrame = () => {
|
|
11
|
+
const callbacks = frameCallbacks;
|
|
12
|
+
frameCallbacks = [];
|
|
13
|
+
|
|
14
|
+
act(() => {
|
|
15
|
+
callbacks.forEach((cb) => cb(0));
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
frameCallbacks = [];
|
|
21
|
+
originalRaf = global.requestAnimationFrame;
|
|
22
|
+
originalCancelRaf = global.cancelAnimationFrame;
|
|
23
|
+
|
|
24
|
+
global.requestAnimationFrame = jest.fn((cb: FrameRequestCallback) => {
|
|
25
|
+
frameCallbacks.push(cb);
|
|
26
|
+
|
|
27
|
+
return frameCallbacks.length;
|
|
28
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
29
|
+
|
|
30
|
+
global.cancelAnimationFrame = jest.fn();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
global.requestAnimationFrame = originalRaf;
|
|
35
|
+
global.cancelAnimationFrame = originalCancelRaf;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("returns false on the initial render", () => {
|
|
39
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
40
|
+
|
|
41
|
+
expect(result.current).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("stays false after only one animation frame (before paint completes)", () => {
|
|
45
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
46
|
+
|
|
47
|
+
flushFrame();
|
|
48
|
+
|
|
49
|
+
expect(result.current).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns true after two animation frames (a real post-paint boundary)", () => {
|
|
53
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
54
|
+
|
|
55
|
+
flushFrame();
|
|
56
|
+
flushFrame();
|
|
57
|
+
|
|
58
|
+
expect(result.current).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export const useAfterPaint = (): boolean => {
|
|
4
|
+
const [painted, setPainted] = React.useState(false);
|
|
5
|
+
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
let secondFrame: number | undefined;
|
|
8
|
+
|
|
9
|
+
const firstFrame = requestAnimationFrame(() => {
|
|
10
|
+
secondFrame = requestAnimationFrame(() => setPainted(true));
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return () => {
|
|
14
|
+
cancelAnimationFrame(firstFrame);
|
|
15
|
+
|
|
16
|
+
if (secondFrame !== undefined) {
|
|
17
|
+
cancelAnimationFrame(secondFrame);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
return painted;
|
|
23
|
+
};
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
useIsScreenActive,
|
|
11
11
|
useNavigation,
|
|
12
|
-
useRivers,
|
|
13
12
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
14
13
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
|
-
import {
|
|
14
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
16
15
|
import {
|
|
17
16
|
useNavbarState,
|
|
18
17
|
useScreenBackgroundColor,
|
|
@@ -21,7 +20,7 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
21
20
|
|
|
22
21
|
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
23
22
|
import { ScreenResolver } from "../../ScreenResolver";
|
|
24
|
-
import { useInitialFocus } from "./hooks";
|
|
23
|
+
import { useInitialFocus, useAfterPaint } from "./hooks";
|
|
25
24
|
import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
26
25
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
27
26
|
import { FreezeWithCallback } from "../../FreezeWithCallback";
|
|
@@ -103,8 +102,7 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
const navigator = useNavigation();
|
|
106
|
-
const plugins =
|
|
107
|
-
const rivers = useRivers();
|
|
105
|
+
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
108
106
|
|
|
109
107
|
const pathAttributes = getPathAttributes({ pathname: route });
|
|
110
108
|
const routeState = navigator.getStackForPathname(route);
|
|
@@ -157,6 +155,13 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
157
155
|
|
|
158
156
|
const isScreenActive = useIsScreenActive();
|
|
159
157
|
|
|
158
|
+
// We need to render menu first and then proceed with screen content,
|
|
159
|
+
// otherwise screen will stay black until everything is loaded and screen
|
|
160
|
+
// rendering put huge load the CPU pushing rendering even further.
|
|
161
|
+
// With this approach, menu will be rendered immediately and screen content
|
|
162
|
+
// will be rendered after paint, which makes it more responsive and prevents black screen.
|
|
163
|
+
const isContentReady = useAfterPaint();
|
|
164
|
+
|
|
160
165
|
return (
|
|
161
166
|
<FreezeWithCallback freeze={!isScreenActive} onRelease={onRelease}>
|
|
162
167
|
<View style={[styles.container, { backgroundColor }]}>
|
|
@@ -167,12 +172,14 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
167
172
|
navigationProps={navigationProps}
|
|
168
173
|
/>
|
|
169
174
|
</NavBarContainer>
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
{isContentReady ? (
|
|
176
|
+
<ScreenResolver
|
|
177
|
+
screenType={screenType}
|
|
178
|
+
screenId={screenId}
|
|
179
|
+
screenData={screenData}
|
|
180
|
+
groupId={route}
|
|
181
|
+
/>
|
|
182
|
+
) : null}
|
|
176
183
|
</View>
|
|
177
184
|
</FreezeWithCallback>
|
|
178
185
|
);
|
|
@@ -1,16 +1,20 @@
|
|
|
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} />
|
|
7
7
|
));
|
|
8
8
|
|
|
9
|
+
const mock_navBarVisibleFlag = true;
|
|
10
|
+
|
|
11
|
+
const mockIsNavBarVisible = jest.fn(() => mock_navBarVisibleFlag);
|
|
12
|
+
|
|
9
13
|
const mockIsOrientationCompatible = jest.fn(() => true);
|
|
10
14
|
|
|
11
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
12
|
-
...jest.requireActual("react-native-safe-area-context"),
|
|
13
16
|
useSafeAreaInsets: () => ({ top: 44 }),
|
|
17
|
+
useSafeAreaFrame: () => ({ x: 0, y: 0, width: 375, height: 812 }),
|
|
14
18
|
}));
|
|
15
19
|
|
|
16
20
|
jest.mock("../../RouteManager", () => ({
|
|
@@ -32,14 +36,12 @@ jest.mock(
|
|
|
32
36
|
);
|
|
33
37
|
|
|
34
38
|
jest.mock("@applicaster/zapp-react-native-utils/analyticsUtils", () => ({
|
|
35
|
-
...jest.requireActual("@applicaster/zapp-react-native-utils/analyticsUtils"),
|
|
36
39
|
useAnalytics: jest.fn(() => ({
|
|
37
40
|
sendScreenEvent: jest.fn(),
|
|
38
41
|
})),
|
|
39
42
|
}));
|
|
40
43
|
|
|
41
44
|
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
42
|
-
...jest.requireActual("@applicaster/zapp-react-native-utils/theme"),
|
|
43
45
|
useTheme: jest.fn(() => ({
|
|
44
46
|
app_background_color: "blue",
|
|
45
47
|
})),
|
|
@@ -76,44 +78,21 @@ jest.mock(
|
|
|
76
78
|
})
|
|
77
79
|
);
|
|
78
80
|
|
|
79
|
-
jest.mock(
|
|
80
|
-
|
|
81
|
-
()
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
jest.mock(
|
|
96
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
|
|
97
|
-
() => ({
|
|
98
|
-
...jest.requireActual(
|
|
99
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive"
|
|
100
|
-
),
|
|
101
|
-
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
jest.mock(
|
|
106
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute",
|
|
107
|
-
() => ({
|
|
108
|
-
...jest.requireActual(
|
|
109
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute"
|
|
110
|
-
),
|
|
111
|
-
useRoute: jest.fn(() => ({
|
|
112
|
-
pathname: "/river/testId",
|
|
113
|
-
screenData: { id: "testId" },
|
|
114
|
-
})),
|
|
115
|
-
})
|
|
116
|
-
);
|
|
81
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
82
|
+
isNavBarVisible: mockIsNavBarVisible,
|
|
83
|
+
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
84
|
+
useNavigation: jest.fn(() => ({
|
|
85
|
+
canGoBack: () => false,
|
|
86
|
+
currentRoute: "/river/testId",
|
|
87
|
+
activeRiver: { id: "testId" },
|
|
88
|
+
screenData: { id: "testId" },
|
|
89
|
+
data: { screen: { id: "testId" } },
|
|
90
|
+
})),
|
|
91
|
+
useRoute: jest.fn(() => ({
|
|
92
|
+
pathname: "/river/testId",
|
|
93
|
+
screenData: { id: "testId" },
|
|
94
|
+
})),
|
|
95
|
+
}));
|
|
117
96
|
|
|
118
97
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
119
98
|
...jest.requireActual("@applicaster/zapp-react-native-utils/reactHooks"),
|
|
@@ -134,6 +113,26 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
|
134
113
|
useIsTablet: jest.fn(() => false),
|
|
135
114
|
}));
|
|
136
115
|
|
|
116
|
+
jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
|
|
117
|
+
const View = jest.requireActual("react-native").View;
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
|
|
121
|
+
usePickFromState: () => ({
|
|
122
|
+
plugins: [
|
|
123
|
+
{
|
|
124
|
+
name: "Offline Plugin",
|
|
125
|
+
identifier: "offline-experience",
|
|
126
|
+
type: "general",
|
|
127
|
+
module: {
|
|
128
|
+
OfflineFallbackScreen: ({ children }) => <View>{children}</View>, // eslint-disable-line
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
|
|
137
136
|
const {
|
|
138
137
|
allowedOrientationsForScreen,
|
|
139
138
|
getOrientation,
|
|
@@ -153,19 +152,6 @@ const screenProps = {
|
|
|
153
152
|
|
|
154
153
|
const { Screen } = require("..");
|
|
155
154
|
|
|
156
|
-
const store = {
|
|
157
|
-
plugins: [
|
|
158
|
-
{
|
|
159
|
-
name: "Offline Plugin",
|
|
160
|
-
identifier: "offline-experience",
|
|
161
|
-
type: "general",
|
|
162
|
-
module: {
|
|
163
|
-
OfflineFallbackScreen: ({ children }) => <View>{children}</View>, // eslint-disable-line
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
};
|
|
168
|
-
|
|
169
155
|
describe("<Screen Component />", () => {
|
|
170
156
|
beforeEach(() => {
|
|
171
157
|
allowedOrientationsForScreen.mockClear();
|
|
@@ -175,22 +161,14 @@ describe("<Screen Component />", () => {
|
|
|
175
161
|
|
|
176
162
|
describe("when the navbar should show", () => {
|
|
177
163
|
it("renders correctly", () => {
|
|
178
|
-
const { toJSON } =
|
|
179
|
-
<Screen {...screenProps} />,
|
|
180
|
-
store
|
|
181
|
-
);
|
|
182
|
-
|
|
164
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
183
165
|
expect(toJSON()).toMatchSnapshot();
|
|
184
166
|
});
|
|
185
167
|
});
|
|
186
168
|
|
|
187
169
|
describe("when the navbar should be hidden", () => {
|
|
188
170
|
it("renders correctly", () => {
|
|
189
|
-
const { toJSON } =
|
|
190
|
-
<Screen {...screenProps} />,
|
|
191
|
-
store
|
|
192
|
-
);
|
|
193
|
-
|
|
171
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
194
172
|
expect(toJSON()).toMatchSnapshot();
|
|
195
173
|
});
|
|
196
174
|
});
|
|
@@ -1,91 +1,67 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`<Screen Component /> when the navbar should be hidden renders correctly 1`] = `
|
|
4
|
-
<
|
|
5
|
-
|
|
4
|
+
<View
|
|
5
|
+
importantForAccessibility="yes"
|
|
6
6
|
style={
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
]
|
|
7
|
+
{
|
|
8
|
+
"backgroundColor": "blue",
|
|
9
|
+
"flex": 1,
|
|
10
|
+
"paddingTop": 0,
|
|
11
|
+
}
|
|
13
12
|
}
|
|
14
13
|
>
|
|
15
14
|
<View
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
>
|
|
15
|
+
hasMenu={false}
|
|
16
|
+
id="/river/testId"
|
|
17
|
+
pathname="/river/testId"
|
|
18
|
+
selected="testId"
|
|
19
|
+
testID="navBar"
|
|
20
|
+
title="Test Title"
|
|
21
|
+
/>
|
|
22
|
+
<View>
|
|
25
23
|
<View
|
|
26
|
-
hasMenu={false}
|
|
27
|
-
id="/river/testId"
|
|
28
24
|
pathname="/river/testId"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
/>
|
|
33
|
-
<View>
|
|
34
|
-
<View
|
|
35
|
-
pathname="/river/testId"
|
|
36
|
-
screenData={
|
|
37
|
-
{
|
|
38
|
-
"id": "testId",
|
|
39
|
-
}
|
|
25
|
+
screenData={
|
|
26
|
+
{
|
|
27
|
+
"id": "testId",
|
|
40
28
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
}
|
|
30
|
+
testID="routeManager"
|
|
31
|
+
/>
|
|
44
32
|
</View>
|
|
45
|
-
</
|
|
33
|
+
</View>
|
|
46
34
|
`;
|
|
47
35
|
|
|
48
36
|
exports[`<Screen Component /> when the navbar should show renders correctly 1`] = `
|
|
49
|
-
<
|
|
50
|
-
|
|
37
|
+
<View
|
|
38
|
+
importantForAccessibility="yes"
|
|
51
39
|
style={
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
]
|
|
40
|
+
{
|
|
41
|
+
"backgroundColor": "blue",
|
|
42
|
+
"flex": 1,
|
|
43
|
+
"paddingTop": 0,
|
|
44
|
+
}
|
|
58
45
|
}
|
|
59
46
|
>
|
|
60
47
|
<View
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
>
|
|
48
|
+
hasMenu={false}
|
|
49
|
+
id="/river/testId"
|
|
50
|
+
pathname="/river/testId"
|
|
51
|
+
selected="testId"
|
|
52
|
+
testID="navBar"
|
|
53
|
+
title="Test Title"
|
|
54
|
+
/>
|
|
55
|
+
<View>
|
|
70
56
|
<View
|
|
71
|
-
hasMenu={false}
|
|
72
|
-
id="/river/testId"
|
|
73
57
|
pathname="/river/testId"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/>
|
|
78
|
-
<View>
|
|
79
|
-
<View
|
|
80
|
-
pathname="/river/testId"
|
|
81
|
-
screenData={
|
|
82
|
-
{
|
|
83
|
-
"id": "testId",
|
|
84
|
-
}
|
|
58
|
+
screenData={
|
|
59
|
+
{
|
|
60
|
+
"id": "testId",
|
|
85
61
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
62
|
+
}
|
|
63
|
+
testID="routeManager"
|
|
64
|
+
/>
|
|
89
65
|
</View>
|
|
90
|
-
</
|
|
66
|
+
</View>
|
|
91
67
|
`;
|
|
@@ -1,19 +1,89 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
2
2
|
import {
|
|
3
3
|
useGetScreenOrientation,
|
|
4
4
|
isOrientationCompatible,
|
|
5
5
|
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
6
6
|
import {
|
|
7
7
|
useCurrentScreenData,
|
|
8
|
-
useDimensions,
|
|
9
8
|
useRoute,
|
|
10
9
|
useIsTablet,
|
|
10
|
+
useIsScreenActive,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
12
|
import { useMemo, useEffect, useState } from "react";
|
|
13
|
+
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
14
|
+
|
|
15
|
+
type MemoizedSafeAreaFrameWithActiveStateOptions = {
|
|
16
|
+
updateForInactiveScreens?: boolean;
|
|
17
|
+
isActive: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Base hook that wraps useSafeAreaFrame with memoization and inactive screen filtering.
|
|
22
|
+
* Requires isActive to be passed explicitly - use useMemoizedSafeAreaFrame for automatic detection.
|
|
23
|
+
*
|
|
24
|
+
* @param options.updateForInactiveScreens - If false, frame won't update when screen is inactive (default: true)
|
|
25
|
+
* @param options.isActive - Whether the screen is currently active
|
|
26
|
+
* @returns The memoized safe area frame { x, y, width, height }
|
|
27
|
+
*/
|
|
28
|
+
export const useMemoizedSafeAreaFrameWithActiveState = (
|
|
29
|
+
options: MemoizedSafeAreaFrameWithActiveStateOptions
|
|
30
|
+
) => {
|
|
31
|
+
const { updateForInactiveScreens = true, isActive } = options;
|
|
32
|
+
const frame = useSafeAreaFrame();
|
|
33
|
+
|
|
34
|
+
const [memoFrame, setMemoFrame] = useState(frame);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const shouldUpdate = isActive || updateForInactiveScreens;
|
|
38
|
+
|
|
39
|
+
const dimensionsChanged =
|
|
40
|
+
frame.width !== memoFrame.width || frame.height !== memoFrame.height;
|
|
41
|
+
|
|
42
|
+
if (shouldUpdate && dimensionsChanged) {
|
|
43
|
+
setMemoFrame(frame);
|
|
44
|
+
}
|
|
45
|
+
}, [
|
|
46
|
+
frame.width,
|
|
47
|
+
frame.height,
|
|
48
|
+
isActive,
|
|
49
|
+
updateForInactiveScreens,
|
|
50
|
+
frame,
|
|
51
|
+
memoFrame.width,
|
|
52
|
+
memoFrame.height,
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
return memoFrame;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type MemoizedSafeAreaFrameOptions = {
|
|
59
|
+
updateForInactiveScreens?: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hook that wraps useSafeAreaFrame with memoization and inactive screen filtering.
|
|
64
|
+
* Uses useIsScreenActive() internally to determine active state - use useMemoizedSafeAreaFrameWithActiveState
|
|
65
|
+
* if you need to pass isActive explicitly.
|
|
66
|
+
*
|
|
67
|
+
* @param options.updateForInactiveScreens - If false, frame won't update when screen is inactive (default: true)
|
|
68
|
+
* @returns The memoized safe area frame { x, y, width, height }
|
|
69
|
+
*/
|
|
70
|
+
export const useMemoizedSafeAreaFrame = (
|
|
71
|
+
options: MemoizedSafeAreaFrameOptions = {}
|
|
72
|
+
) => {
|
|
73
|
+
const { updateForInactiveScreens = true } = options;
|
|
74
|
+
const isActive = useIsScreenActive();
|
|
75
|
+
|
|
76
|
+
return useMemoizedSafeAreaFrameWithActiveState({
|
|
77
|
+
updateForInactiveScreens,
|
|
78
|
+
isActive,
|
|
79
|
+
});
|
|
80
|
+
};
|
|
13
81
|
|
|
14
82
|
export const useWaitForValidOrientation = () => {
|
|
15
|
-
|
|
16
|
-
|
|
83
|
+
// Use memoized safe area frame to synchronize with Scene's dimension source
|
|
84
|
+
// This prevents race conditions where the orientation check passes before
|
|
85
|
+
// Scene's memoFrame has updated to the new dimensions
|
|
86
|
+
const { width: screenWidth, height } = useMemoizedSafeAreaFrame({
|
|
17
87
|
updateForInactiveScreens: false,
|
|
18
88
|
});
|
|
19
89
|
|
|
@@ -25,7 +95,8 @@ export const useWaitForValidOrientation = () => {
|
|
|
25
95
|
|
|
26
96
|
const isTablet = useIsTablet();
|
|
27
97
|
|
|
28
|
-
const {
|
|
98
|
+
const { appData } = usePickFromState(["appData"]);
|
|
99
|
+
const isTabletPortrait = appData?.isTabletPortrait;
|
|
29
100
|
|
|
30
101
|
const layoutData = useMemo(
|
|
31
102
|
() => ({ isTablet, isTabletPortrait, width: screenWidth, height }),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { AccessibilityInfo, findNodeHandle, View } from "react-native";
|
|
4
|
-
import {
|
|
4
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
|
+
|
|
5
6
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
7
|
import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
7
8
|
import {
|
|
@@ -40,7 +41,7 @@ type Props = {
|
|
|
40
41
|
export function Screen(_props: Props) {
|
|
41
42
|
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
42
43
|
const navigation = useNavigation();
|
|
43
|
-
const plugins =
|
|
44
|
+
const { plugins } = usePickFromState(["plugins"]);
|
|
44
45
|
|
|
45
46
|
// Gets the data for the current screen configuration
|
|
46
47
|
const currentScreenData = useCurrentScreenData();
|
|
@@ -92,7 +93,13 @@ export function Screen(_props: Props) {
|
|
|
92
93
|
const isActive = useIsScreenActive();
|
|
93
94
|
|
|
94
95
|
const ref = React.useRef(null);
|
|
95
|
-
const
|
|
96
|
+
const isOrientationReady = useWaitForValidOrientation();
|
|
97
|
+
|
|
98
|
+
// Playable screens handle their own orientation via the native player plugin,
|
|
99
|
+
// so we skip the orientation wait gate to avoid a deadlock where the screen
|
|
100
|
+
// waits for landscape but blocks rendering that would trigger the rotation.
|
|
101
|
+
const isPlayableRoute = pathname?.includes("/playable");
|
|
102
|
+
const isReady = isOrientationReady || isPlayableRoute;
|
|
96
103
|
|
|
97
104
|
React.useEffect(() => {
|
|
98
105
|
if (ref.current && isActive && isReady) {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useGetScreenOrientation,
|
|
8
8
|
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
9
9
|
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
10
|
-
import {
|
|
10
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
11
11
|
import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
12
12
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
13
|
import { zappHookModalStore } from "../../Contexts/ZappHookModalContext";
|
|
@@ -63,8 +63,8 @@ export function useNewOrientationForScreenData({
|
|
|
63
63
|
}: OrientationHookArgs) {
|
|
64
64
|
const isTablet = useIsTablet();
|
|
65
65
|
|
|
66
|
-
const plugins =
|
|
67
|
-
const
|
|
66
|
+
const { appData, plugins } = usePickFromState(["appData", "plugins"]);
|
|
67
|
+
const isTabletPortrait = appData?.isTabletPortrait;
|
|
68
68
|
const isLandscapeTablet = isTablet && !isTabletPortrait;
|
|
69
69
|
|
|
70
70
|
const screenOrientation = useGetScreenOrientation(screenData);
|