@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-rc.2
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/BaseFocusable/index.ios.ts +2 -12
- package/Components/Cell/FocusableWrapper.tsx +0 -3
- package/Components/Cell/TvOSCellComponent.tsx +0 -5
- 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 +1 -30
- 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/TV/LayoutBackground.tsx +2 -5
- package/Components/Layout/TV/ScreenContainer.tsx +6 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
- package/Components/Layout/TV/index.tsx +4 -3
- package/Components/Layout/TV/index.web.tsx +4 -3
- 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 +14 -32
- 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 -1
- package/Components/River/__tests__/componentsMap.test.js +0 -38
- package/Components/Screen/TV/index.web.tsx +2 -4
- 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/ScreenRevealManager.ts +8 -40
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +4 -1
- 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 +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- 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 +9 -12
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +6 -4
- 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/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/DataSourceHelper/index.js +19 -0
- package/package.json +5 -5
- 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/DataSourceHelper/__tests__/itemLimitForData.test.ts +0 -80
- package/Helpers/DataSourceHelper/index.ts +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -1,35 +1,32 @@
|
|
|
1
1
|
import { mergeRight } from "ramda";
|
|
2
2
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
-
import {
|
|
4
|
-
useAppSelector,
|
|
5
|
-
useContentTypes,
|
|
6
|
-
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
7
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
8
5
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
|
|
9
6
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
10
7
|
import { create } from "zustand";
|
|
11
|
-
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
|
-
import { selectPluginConfigurationsByPluginId } from "@applicaster/zapp-react-native-redux";
|
|
13
8
|
|
|
14
9
|
export const useConfiguration = () => {
|
|
15
10
|
const {
|
|
16
11
|
videoModalState: { item },
|
|
17
12
|
} = useNavigation();
|
|
18
13
|
|
|
19
|
-
const rivers =
|
|
20
|
-
|
|
14
|
+
const { rivers, contentTypes, pluginConfigurations } = usePickFromState([
|
|
15
|
+
"rivers",
|
|
16
|
+
"contentTypes",
|
|
17
|
+
"pluginConfigurations",
|
|
18
|
+
]);
|
|
21
19
|
|
|
22
20
|
const targetScreenId = contentTypes?.[item?.type?.value]?.screen_id;
|
|
23
21
|
const targetScreenConfiguration = rivers?.[targetScreenId];
|
|
24
22
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
);
|
|
23
|
+
const pluginConfiguration =
|
|
24
|
+
pluginConfigurations[targetScreenConfiguration?.type]?.configuration_json;
|
|
28
25
|
|
|
29
26
|
const playerPluginConfig = playerManager.getPluginConfiguration();
|
|
30
27
|
|
|
31
28
|
const config = mergeRight(playerPluginConfig, {
|
|
32
|
-
...
|
|
29
|
+
...pluginConfiguration,
|
|
33
30
|
...targetScreenConfiguration?.general,
|
|
34
31
|
...targetScreenConfiguration?.styles,
|
|
35
32
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { StyleSheet
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
3
4
|
|
|
4
5
|
import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
5
6
|
import CloseButton from "./Buttons/CloseButton";
|
|
@@ -44,14 +45,15 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
|
|
|
44
45
|
);
|
|
45
46
|
|
|
46
47
|
return (
|
|
47
|
-
<
|
|
48
|
+
<SafeAreaView
|
|
49
|
+
edges={["top", "left", "right"]}
|
|
48
50
|
style={[style.view, isRTL ? style.rtlStyle : {}]}
|
|
49
|
-
testID="BarView-
|
|
51
|
+
testID="BarView-safeAreaView"
|
|
50
52
|
>
|
|
51
53
|
{backButton}
|
|
52
54
|
<BarTitle title={barState.title} screenStyles={screenStyles} />
|
|
53
55
|
{closeButton}
|
|
54
|
-
</
|
|
56
|
+
</SafeAreaView>
|
|
55
57
|
);
|
|
56
58
|
};
|
|
57
59
|
|
|
@@ -46,7 +46,7 @@ describe("BarView", () => {
|
|
|
46
46
|
<BarView screenStyles={screenStyles} barState={barState} />
|
|
47
47
|
);
|
|
48
48
|
|
|
49
|
-
expect(getByTestId("BarView-
|
|
49
|
+
expect(getByTestId("BarView-safeAreaView").props.style).toContainEqual({
|
|
50
50
|
transform: [{ scaleX: -1 }],
|
|
51
51
|
});
|
|
52
52
|
});
|
|
@@ -58,7 +58,7 @@ describe("BarView", () => {
|
|
|
58
58
|
<BarView screenStyles={screenStyles} barState={barState} />
|
|
59
59
|
);
|
|
60
60
|
|
|
61
|
-
expect(getByTestId("BarView-
|
|
61
|
+
expect(getByTestId("BarView-safeAreaView").props.style).not.toContainEqual({
|
|
62
62
|
transform: [{ scaleX: -1 }],
|
|
63
63
|
});
|
|
64
64
|
});
|
|
@@ -144,12 +144,23 @@ New signature: {Component, ErrorComponent, LoadingComponent, options}`
|
|
|
144
144
|
[props, parent]
|
|
145
145
|
);
|
|
146
146
|
|
|
147
|
+
const hasError = !!zappPipesData?.error;
|
|
148
|
+
|
|
147
149
|
React.useEffect(() => {
|
|
148
150
|
if (!skipOnLoadFinished && !isLoading) {
|
|
149
151
|
onLoadFinished();
|
|
150
152
|
}
|
|
151
153
|
}, [isLoading]);
|
|
152
154
|
|
|
155
|
+
React.useEffect(() => {
|
|
156
|
+
if (hasError) {
|
|
157
|
+
onLoadFailed?.({
|
|
158
|
+
error: zappPipesData.error,
|
|
159
|
+
index: componentIndex,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}, [hasError, componentIndex, onLoadFailed, zappPipesData?.error]);
|
|
163
|
+
|
|
153
164
|
if (isDataSourceEmpty(props) && allowsEmptyDataSource) {
|
|
154
165
|
return RenderComponent(Component, componentProps);
|
|
155
166
|
}
|
|
@@ -158,12 +169,7 @@ New signature: {Component, ErrorComponent, LoadingComponent, options}`
|
|
|
158
169
|
return RenderComponent(LoadingComponent || Placeholder, componentProps);
|
|
159
170
|
}
|
|
160
171
|
|
|
161
|
-
if (
|
|
162
|
-
onLoadFailed?.({
|
|
163
|
-
error: zappPipesData.error,
|
|
164
|
-
index: componentIndex,
|
|
165
|
-
});
|
|
166
|
-
|
|
172
|
+
if (hasError) {
|
|
167
173
|
return RenderComponent(ErrorComponent, componentProps);
|
|
168
174
|
}
|
|
169
175
|
|
package/Components/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export { ContentScreen } from "./ContentScreen";
|
|
|
10
10
|
|
|
11
11
|
export { TextInputTv } from "./TextInputTv";
|
|
12
12
|
|
|
13
|
-
export { HookRenderer } from "./HookRenderer";
|
|
13
|
+
export { HookRenderer } from "./HookRenderer/HookRenderer";
|
|
14
14
|
|
|
15
15
|
export { Touchable } from "./Touchable";
|
|
16
16
|
|
|
@@ -2,6 +2,32 @@ import { render } from "@testing-library/react-native";
|
|
|
2
2
|
import { ScreenContext, ScreenContextProvider, withScreenContext } from "../";
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
6
|
+
useCurrentScreenData: jest.fn(() => ({})),
|
|
7
|
+
useNavigation: jest.fn(() => ({
|
|
8
|
+
data: {},
|
|
9
|
+
modalData: null,
|
|
10
|
+
videoModalState: {},
|
|
11
|
+
canGoBack: jest.fn(() => false),
|
|
12
|
+
})),
|
|
13
|
+
useRoute: jest.fn(() => ({ screenData: null })),
|
|
14
|
+
isNavBarVisible: jest.fn(() => true),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
jest.mock(
|
|
18
|
+
"@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext",
|
|
19
|
+
() => ({
|
|
20
|
+
useModalNavigationContext: jest.fn(() => false),
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
jest.mock(
|
|
25
|
+
"@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext",
|
|
26
|
+
() => ({
|
|
27
|
+
useNestedNavigationContext: jest.fn(() => false),
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
5
31
|
describe("ScreenContext", () => {
|
|
6
32
|
describe("ScreneContext context", () => {
|
|
7
33
|
it("should return the context", () => {
|
|
@@ -13,6 +39,37 @@ describe("ScreenContext", () => {
|
|
|
13
39
|
it("should return the provider", () => {
|
|
14
40
|
expect(ScreenContextProvider).toBeDefined();
|
|
15
41
|
});
|
|
42
|
+
|
|
43
|
+
it("recreates _feedStore when pathname changes", () => {
|
|
44
|
+
const contexts = [];
|
|
45
|
+
|
|
46
|
+
const CaptureContext = () => {
|
|
47
|
+
const context = React.useContext(ScreenContext);
|
|
48
|
+
contexts.push(context);
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const { rerender } = render(
|
|
54
|
+
<ScreenContextProvider pathname="/screen-a">
|
|
55
|
+
<CaptureContext />
|
|
56
|
+
</ScreenContextProvider>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const first = contexts[contexts.length - 1];
|
|
60
|
+
first._feedStore.setState({ screenFeed: "screen-a" });
|
|
61
|
+
|
|
62
|
+
rerender(
|
|
63
|
+
<ScreenContextProvider pathname="/screen-b">
|
|
64
|
+
<CaptureContext />
|
|
65
|
+
</ScreenContextProvider>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const second = contexts[contexts.length - 1];
|
|
69
|
+
|
|
70
|
+
expect(second._feedStore).not.toBe(first._feedStore);
|
|
71
|
+
expect(second._feedStore.getState()).toEqual({});
|
|
72
|
+
});
|
|
16
73
|
});
|
|
17
74
|
|
|
18
75
|
describe("withScreenContext", () => {
|
|
@@ -16,7 +16,6 @@ import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-co
|
|
|
16
16
|
import { create } from "zustand";
|
|
17
17
|
import { subscribeWithSelector } from "zustand/middleware";
|
|
18
18
|
import { useShallow } from "zustand/react/shallow";
|
|
19
|
-
|
|
20
19
|
import { Animated } from "react-native";
|
|
21
20
|
|
|
22
21
|
interface NavBarStoreState {
|
|
@@ -30,8 +29,6 @@ interface NavBarStoreState {
|
|
|
30
29
|
scrollState: number;
|
|
31
30
|
contentPosition: string;
|
|
32
31
|
scrollYAnimated: Animated.Value;
|
|
33
|
-
hideOnScrollAnimated: Animated.Value;
|
|
34
|
-
hideOnScroll: boolean;
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
interface NavBarState {
|
|
@@ -65,39 +62,58 @@ const createStateStore = () =>
|
|
|
65
62
|
);
|
|
66
63
|
|
|
67
64
|
const createStore = () =>
|
|
68
|
-
create(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
65
|
+
create<NavBarStoreState>((set) => ({
|
|
66
|
+
title: "",
|
|
67
|
+
summary: "",
|
|
68
|
+
visible: true,
|
|
69
|
+
height: 0,
|
|
70
|
+
scrollState: 0,
|
|
71
|
+
contentPosition: "",
|
|
72
|
+
scrollYAnimated: new Animated.Value(0),
|
|
73
|
+
setTitle(title) {
|
|
74
|
+
set({ title });
|
|
75
|
+
},
|
|
76
|
+
setSummary(summary) {
|
|
77
|
+
set({ summary });
|
|
78
|
+
},
|
|
79
|
+
setVisible(visible) {
|
|
80
|
+
set({ visible });
|
|
81
|
+
},
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const createScreenComponentsStore = () =>
|
|
85
|
+
create(subscribeWithSelector<Record<string, unknown>>((_) => ({})));
|
|
86
|
+
|
|
87
|
+
const createFeedStore = () =>
|
|
88
|
+
create(subscribeWithSelector<Record<string, unknown>>((_) => ({})));
|
|
90
89
|
|
|
91
90
|
type ScreenContextType = {
|
|
92
91
|
_navBarStore: ReturnType<typeof createStore>;
|
|
93
92
|
_stateStore: ReturnType<typeof createStateStore>;
|
|
93
|
+
_feedStore: ReturnType<typeof createFeedStore>;
|
|
94
94
|
navBar: NavBarState;
|
|
95
95
|
legacyFormatScreenData: LegacyNavigationScreenData | null;
|
|
96
|
+
/**
|
|
97
|
+
* Zustand store for component-level state within a screen.
|
|
98
|
+
*
|
|
99
|
+
* **Purpose:** Persists state across component mount/unmount cycles (e.g., during virtualization)
|
|
100
|
+
* and enables state sharing between components using the same key within the same screen.
|
|
101
|
+
*
|
|
102
|
+
* **Lifecycle:** Tied to the screen/route — recreated on each route change.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* // Used by useComponentScreenState hook:
|
|
106
|
+
* const store = useScreenContextV2()._componentStateStore;
|
|
107
|
+
* store.setState({ 'my-key': value });
|
|
108
|
+
* const value = store.getState()['my-key'];
|
|
109
|
+
*/
|
|
110
|
+
_componentStateStore: ReturnType<typeof createScreenComponentsStore>;
|
|
96
111
|
};
|
|
97
112
|
|
|
98
113
|
export const ScreenContext = createContext<ScreenContextType>({
|
|
99
114
|
_stateStore: createStateStore(),
|
|
100
115
|
_navBarStore: createStore(),
|
|
116
|
+
_feedStore: createFeedStore(),
|
|
101
117
|
navBar: {
|
|
102
118
|
visible: true,
|
|
103
119
|
title: "",
|
|
@@ -107,6 +123,7 @@ export const ScreenContext = createContext<ScreenContextType>({
|
|
|
107
123
|
setSummary: (_subtitle) => void 0,
|
|
108
124
|
},
|
|
109
125
|
legacyFormatScreenData: {} as LegacyNavigationScreenData,
|
|
126
|
+
_componentStateStore: createScreenComponentsStore(),
|
|
110
127
|
});
|
|
111
128
|
|
|
112
129
|
export function ScreenContextProvider({
|
|
@@ -138,6 +155,10 @@ export function ScreenContextProvider({
|
|
|
138
155
|
null
|
|
139
156
|
);
|
|
140
157
|
|
|
158
|
+
const screenFeedStoreRef = useRef<null | ReturnType<typeof createFeedStore>>(
|
|
159
|
+
null
|
|
160
|
+
);
|
|
161
|
+
|
|
141
162
|
const getScreenState = useCallback(() => {
|
|
142
163
|
if (screenStateRef.current !== null) {
|
|
143
164
|
return screenStateRef.current;
|
|
@@ -160,6 +181,21 @@ export function ScreenContextProvider({
|
|
|
160
181
|
return navBarState;
|
|
161
182
|
}, []);
|
|
162
183
|
|
|
184
|
+
// Assign feed store to ref to persist it across re-renders, but recreate on pathname change
|
|
185
|
+
const screenFeedStore = useMemo(() => createFeedStore(), [pathname]);
|
|
186
|
+
|
|
187
|
+
if (screenFeedStoreRef.current !== screenFeedStore) {
|
|
188
|
+
screenFeedStoreRef.current = screenFeedStore;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Component state store - recreated when pathname changes (route change).
|
|
192
|
+
// Unlike _navBarStore and _stateStore (cached via refs), this store
|
|
193
|
+
// resets only when pathname changes to provide a clean state for the new route.
|
|
194
|
+
const componentStateStore = useMemo(
|
|
195
|
+
() => createScreenComponentsStore(),
|
|
196
|
+
[pathname]
|
|
197
|
+
);
|
|
198
|
+
|
|
163
199
|
const screenNavBarState = getScreenNavBarState()(
|
|
164
200
|
useShallow((state) => ({
|
|
165
201
|
visible: state.visible,
|
|
@@ -210,10 +246,12 @@ export function ScreenContextProvider({
|
|
|
210
246
|
() => ({
|
|
211
247
|
_navBarStore: getScreenNavBarState(),
|
|
212
248
|
_stateStore: getScreenState(),
|
|
249
|
+
_feedStore: screenFeedStoreRef.current,
|
|
213
250
|
navBar: navBarState,
|
|
214
251
|
legacyFormatScreenData: routeScreenData,
|
|
252
|
+
_componentStateStore: componentStateStore,
|
|
215
253
|
}),
|
|
216
|
-
[navBarState, screenData, routeScreenData]
|
|
254
|
+
[navBarState, screenData, routeScreenData, componentStateStore]
|
|
217
255
|
)}
|
|
218
256
|
>
|
|
219
257
|
{children}
|
|
@@ -5,10 +5,10 @@ import React, {
|
|
|
5
5
|
useMemo,
|
|
6
6
|
useState,
|
|
7
7
|
} from "react";
|
|
8
|
-
import * as R from "ramda";
|
|
9
8
|
|
|
10
|
-
type ProviderProps = {
|
|
9
|
+
type ProviderProps<S> = {
|
|
11
10
|
children: React.ReactChild;
|
|
11
|
+
initialContextValue?: S;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
type ContextType<T> = {
|
|
@@ -27,21 +27,29 @@ export function createZappPipesContext<T, S = T>(
|
|
|
27
27
|
) {
|
|
28
28
|
const Context = createContext<ContextType<S>>(initialContext);
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const defaultSelector = (c: any) => c;
|
|
31
|
+
const defaultPrepareContext = (n: any) => n;
|
|
32
|
+
const joinArgs = (args: any[]) => args.join("-");
|
|
33
|
+
|
|
34
|
+
const { selector = defaultSelector, prepareContext = defaultPrepareContext } =
|
|
35
|
+
options || {};
|
|
31
36
|
|
|
32
37
|
function useZappPipesContext(...hookArgs: any[]): [T, (T) => void] {
|
|
33
38
|
const { context, setContext } = useContext(Context);
|
|
39
|
+
const joinedArgs = joinArgs(hookArgs);
|
|
34
40
|
|
|
35
41
|
const contextValue = useMemo(
|
|
36
42
|
() => selector(context, ...hookArgs),
|
|
37
|
-
|
|
43
|
+
// eslint-disable-next-line @wogns3623/better-exhaustive-deps/exhaustive-deps
|
|
44
|
+
[context, joinedArgs]
|
|
38
45
|
);
|
|
39
46
|
|
|
40
47
|
const contextSetter = useCallback(
|
|
41
48
|
(newContext: T) => {
|
|
42
49
|
setContext(prepareContext(newContext, context, ...hookArgs));
|
|
43
50
|
},
|
|
44
|
-
|
|
51
|
+
// eslint-disable-next-line @wogns3623/better-exhaustive-deps/exhaustive-deps
|
|
52
|
+
[context, joinedArgs]
|
|
45
53
|
);
|
|
46
54
|
|
|
47
55
|
return useMemo(
|
|
@@ -50,8 +58,11 @@ export function createZappPipesContext<T, S = T>(
|
|
|
50
58
|
);
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
/** Provider accepts `initialContextValue` prop to set the initial context value */
|
|
62
|
+
function Provider({ children, initialContextValue }: ProviderProps<S>) {
|
|
63
|
+
const [context, setContext] = useState<S>(
|
|
64
|
+
initialContextValue ?? initialContext.context
|
|
65
|
+
);
|
|
55
66
|
|
|
56
67
|
return (
|
|
57
68
|
<Context.Provider value={{ context, setContext }}>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import { getAnalyticsFunctions } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
4
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
5
|
|
|
5
6
|
type ComponentProps = {
|
|
6
7
|
component: {
|
|
@@ -20,13 +21,11 @@ type ComponentProps = {
|
|
|
20
21
|
|
|
21
22
|
function withAnalytics(Component) {
|
|
22
23
|
return function WithAnalytics(props: ComponentProps) {
|
|
24
|
+
const { appData } = usePickFromState(["appData"]);
|
|
25
|
+
|
|
23
26
|
const analyticsFunctions = React.useMemo(
|
|
24
|
-
() =>
|
|
25
|
-
|
|
26
|
-
component: props.component,
|
|
27
|
-
zappPipesData: props.zappPipesData,
|
|
28
|
-
} as any),
|
|
29
|
-
[props.component, props.zappPipesData]
|
|
27
|
+
() => getAnalyticsFunctions({ props, appData }),
|
|
28
|
+
[props, appData]
|
|
30
29
|
);
|
|
31
30
|
|
|
32
31
|
return (
|
|
@@ -88,7 +88,6 @@ exports[`withConfigurationProvider correctly passes all the configuration keys c
|
|
|
88
88
|
tab_cell_padding_right={10}
|
|
89
89
|
tab_cell_padding_top={14}
|
|
90
90
|
tablet_theme={false}
|
|
91
|
-
tabs_screen_background_color="transparent"
|
|
92
91
|
target={false}
|
|
93
92
|
target_screen_switch={false}
|
|
94
93
|
text_label_active_font_color="rgba(239, 239, 239, 0.5)"
|
|
@@ -208,5 +208,4 @@ export const keysMap: Record<string, Function> = {
|
|
|
208
208
|
tab_bar_item_margin_right: castOrDefaultValue(Number, 0),
|
|
209
209
|
tab_bar_item_margin_bottom: castOrDefaultValue(Number, 0),
|
|
210
210
|
tab_bar_item_margin_left: castOrDefaultValue(Number, 0),
|
|
211
|
-
tabs_screen_background_color: castOrDefaultValue(R.identity, "transparent"),
|
|
212
211
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// ResolverSelector.tsx
|
|
2
1
|
import React from "react";
|
|
3
2
|
import { ComponentDataSourceContext, ZappPipesDataProps } from "./types";
|
|
4
3
|
import { StaticFeedResolver } from "./resolvers/StaticFeedResolver";
|
|
@@ -12,14 +11,33 @@ type ResolverSelectorProps = ComponentDataSourceContext & {
|
|
|
12
11
|
export function ResolverSelector(props: ResolverSelectorProps) {
|
|
13
12
|
const { getStaticComponentFeed, component, feedUrl, children } = props;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
const renderDefaultResolver = (
|
|
15
|
+
fallbackChildren: (dataProps: ZappPipesDataProps) => React.ReactNode
|
|
16
|
+
) => {
|
|
17
|
+
if (feedUrl || component?.data?.source) {
|
|
18
|
+
return <UrlFeedResolver {...props}>{fallbackChildren}</UrlFeedResolver>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return <NullFeedResolver>{fallbackChildren}</NullFeedResolver>;
|
|
22
|
+
};
|
|
23
|
+
|
|
16
24
|
if (getStaticComponentFeed) {
|
|
17
|
-
return
|
|
18
|
-
|
|
25
|
+
return (
|
|
26
|
+
<StaticFeedResolver {...props}>
|
|
27
|
+
{(zappPipesDataProps) => {
|
|
28
|
+
const { data, loading, error } = zappPipesDataProps.zappPipesData;
|
|
29
|
+
|
|
30
|
+
const shouldFallback = !loading && data === null && !error;
|
|
31
|
+
|
|
32
|
+
if (shouldFallback) {
|
|
33
|
+
return renderDefaultResolver(children);
|
|
34
|
+
}
|
|
19
35
|
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
return children(zappPipesDataProps);
|
|
37
|
+
}}
|
|
38
|
+
</StaticFeedResolver>
|
|
39
|
+
);
|
|
22
40
|
}
|
|
23
41
|
|
|
24
|
-
return
|
|
42
|
+
return renderDefaultResolver(children);
|
|
25
43
|
}
|