@applicaster/zapp-react-native-ui-components 15.0.0-alpha.8680244503 → 15.0.0-alpha.9102777840
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 +12 -2
- package/Components/Cell/Cell.tsx +6 -0
- package/Components/Cell/CellWithFocusable.tsx +9 -0
- package/Components/Cell/FocusableWrapper.tsx +3 -0
- package/Components/Cell/TvOSCellComponent.tsx +5 -0
- package/Components/Focusable/Focusable.tsx +4 -2
- package/Components/Focusable/FocusableTvOS.tsx +18 -1
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
- package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -8
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +22 -6
- package/Components/HandlePlayable/HandlePlayable.tsx +16 -29
- package/Components/HandlePlayable/utils.ts +31 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +233 -11
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +19 -15
- package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
- package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
- package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +40 -47
- package/Components/River/ComponentsMap/ComponentsMap.tsx +16 -0
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +9 -3
- package/Components/River/TV/River.tsx +31 -14
- package/Components/River/TV/index.tsx +8 -4
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
- package/Components/River/TV/utils/index.ts +4 -0
- package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/__tests__/componentsMap.test.js +38 -0
- package/Components/Screen/__tests__/Screen.test.tsx +1 -0
- package/Components/Screen/hooks.ts +73 -3
- package/Components/Screen/index.tsx +7 -1
- package/Components/Screen/orientationHandler.ts +7 -10
- package/Components/ScreenResolver/index.tsx +14 -10
- package/Components/Tabs/TabContent.tsx +7 -4
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
- package/Components/Viewport/ViewportAware/index.tsx +16 -7
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Contexts/ScreenContext/index.tsx +54 -19
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappHookModalContext/index.tsx +37 -61
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Contexts/index.ts +0 -2
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
- package/Decorators/ConfigurationWrapper/const.ts +1 -0
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/events/index.ts +3 -0
- package/events/scrollEndReached.ts +15 -0
- package/package.json +5 -5
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/River/TV/withTVEventHandler.tsx +0 -27
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useLayoutEffect } from "react";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
allowedOrientationsForScreen,
|
|
5
|
-
ORIENTATIONS,
|
|
6
5
|
getOrientation,
|
|
6
|
+
ORIENTATIONS,
|
|
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
10
|
import { usePlugins, useAppData } from "@applicaster/zapp-react-native-redux";
|
|
11
11
|
import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
12
12
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
-
|
|
14
|
-
import { ZappHookModalContext } from "../../Contexts";
|
|
15
|
-
import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
|
|
13
|
+
import { zappHookModalStore } from "../../Contexts/ZappHookModalContext";
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* This function calls the native module needed to set orientation
|
|
@@ -89,10 +87,6 @@ type Props = {
|
|
|
89
87
|
};
|
|
90
88
|
|
|
91
89
|
export function useScreenOrientationHandler({ screenData, isActive }: Props) {
|
|
92
|
-
const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
|
|
93
|
-
ZappHookModalContext.ReactContext
|
|
94
|
-
);
|
|
95
|
-
|
|
96
90
|
const prevIsActive = usePrevious(isActive);
|
|
97
91
|
|
|
98
92
|
const newOrientation = useNewOrientationForScreenData({
|
|
@@ -105,6 +99,9 @@ export function useScreenOrientationHandler({ screenData, isActive }: Props) {
|
|
|
105
99
|
return;
|
|
106
100
|
}
|
|
107
101
|
|
|
102
|
+
// TODO: make sure it can be static getter and subscription is not needed
|
|
103
|
+
const { isHooksExecutionInProgress } = zappHookModalStore.getState();
|
|
104
|
+
|
|
108
105
|
// If modal hook presented we need to skip
|
|
109
106
|
// Change orientation for presenter screen
|
|
110
107
|
if (isHooksExecutionInProgress) {
|
|
@@ -116,7 +113,7 @@ export function useScreenOrientationHandler({ screenData, isActive }: Props) {
|
|
|
116
113
|
|
|
117
114
|
setOrientation(newOrientation);
|
|
118
115
|
}
|
|
119
|
-
}, [newOrientation,
|
|
116
|
+
}, [newOrientation, prevIsActive, isActive]);
|
|
120
117
|
}
|
|
121
118
|
|
|
122
119
|
export function useOrientationHandler({ screenData }: OrientationHookArgs) {
|
|
@@ -57,7 +57,6 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
57
57
|
const { hookPlugin } = screenData || {};
|
|
58
58
|
|
|
59
59
|
const plugins = usePlugins();
|
|
60
|
-
const rivers = useRivers();
|
|
61
60
|
|
|
62
61
|
const components = useAppSelector(selectComponents);
|
|
63
62
|
|
|
@@ -65,12 +64,6 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
65
64
|
videoModalState: { mode },
|
|
66
65
|
} = useNavigation();
|
|
67
66
|
|
|
68
|
-
const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
69
|
-
|
|
70
|
-
React.useEffect(() => {
|
|
71
|
-
setScreenContext(rivers[screenId]);
|
|
72
|
-
}, [rivers, screenId, setScreenContext]);
|
|
73
|
-
|
|
74
67
|
const parentCallback = props.resultCallback;
|
|
75
68
|
|
|
76
69
|
const screenAction = useCallbackActions(
|
|
@@ -150,6 +143,17 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
150
143
|
return null;
|
|
151
144
|
}
|
|
152
145
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
146
|
+
function withDefaultScreenContext(Component: React.ComponentType<any>) {
|
|
147
|
+
return function WithDefaultScreenContext(props: any) {
|
|
148
|
+
const screenId = props.screenId;
|
|
149
|
+
const rivers = useRivers();
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<ZappPipesScreenContext.Provider initialContextValue={rivers[screenId]}>
|
|
153
|
+
<Component {...props} />
|
|
154
|
+
</ZappPipesScreenContext.Provider>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const ScreenResolver = withDefaultScreenContext(ScreenResolverComponent);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { View,
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { River } from "@applicaster/zapp-react-native-ui-components/Components";
|
|
5
5
|
import { withNestedNavigationContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
|
-
styles: Record<string, ViewStyle>;
|
|
9
8
|
minHeight: number;
|
|
10
9
|
changingTab: boolean;
|
|
11
10
|
feedUrl: string;
|
|
@@ -14,9 +13,14 @@ type Props = {
|
|
|
14
13
|
backgroundColor: string;
|
|
15
14
|
};
|
|
16
15
|
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
riverWrapper: {
|
|
18
|
+
flex: 1,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
17
22
|
function TabContentComponent(props: Props) {
|
|
18
23
|
const {
|
|
19
|
-
styles,
|
|
20
24
|
minHeight,
|
|
21
25
|
backgroundColor,
|
|
22
26
|
changingTab,
|
|
@@ -29,7 +33,6 @@ function TabContentComponent(props: Props) {
|
|
|
29
33
|
<View
|
|
30
34
|
style={[
|
|
31
35
|
styles.riverWrapper,
|
|
32
|
-
|
|
33
36
|
{
|
|
34
37
|
backgroundColor,
|
|
35
38
|
minHeight,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { equals } from "ramda";
|
|
3
3
|
import { Animated, ViewProps, ViewStyle } from "react-native";
|
|
4
|
-
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
5
4
|
|
|
6
5
|
import { useScreenOrientationHandler } from "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler";
|
|
6
|
+
import { useMemoizedSafeAreaFrameWithActiveState } from "@applicaster/zapp-react-native-ui-components/Components/Screen/hooks";
|
|
7
7
|
|
|
8
8
|
import { PathnameContext } from "../../Contexts/PathnameContext";
|
|
9
9
|
import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
|
|
@@ -94,19 +94,13 @@ function SceneComponent({
|
|
|
94
94
|
isActive,
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
oldFrame.width === frame.width && oldFrame.height === frame.height
|
|
105
|
-
? oldFrame
|
|
106
|
-
: frame
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}, [isActive, frame.width, frame.height]);
|
|
97
|
+
// Use shared memoized frame hook - synchronized with useWaitForValidOrientation
|
|
98
|
+
// to prevent race conditions during orientation changes
|
|
99
|
+
// Pass isActive from props since Scene knows its active state from Transitioner
|
|
100
|
+
const memoFrame = useMemoizedSafeAreaFrameWithActiveState({
|
|
101
|
+
updateForInactiveScreens: false,
|
|
102
|
+
isActive,
|
|
103
|
+
});
|
|
110
104
|
|
|
111
105
|
const isAnimating = animating && overlayStyle;
|
|
112
106
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-
|
|
1
|
+
import { act, renderHook, waitFor } from "@testing-library/react-native";
|
|
2
2
|
import { useDelayedPlayerDetails } from "../useDelayedPlayerDetails";
|
|
3
3
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
4
4
|
|
|
@@ -13,16 +13,20 @@ describe("useDelayedPlayerDetails", () => {
|
|
|
13
13
|
jest.clearAllMocks();
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
it("should return false initially, that changes after 1 second", () => {
|
|
16
|
+
it("should return false initially, that changes after 1 second", async () => {
|
|
17
17
|
const { result } = renderHook(() =>
|
|
18
18
|
useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
|
|
19
19
|
);
|
|
20
20
|
|
|
21
21
|
expect(result.current).toBe(false);
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
act(() => {
|
|
24
|
+
jest.advanceTimersByTime(1000);
|
|
25
|
+
});
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
await waitFor(() => {
|
|
28
|
+
expect(result.current).toBe(true);
|
|
29
|
+
});
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
it("should return false when isPip is true", () => {
|
|
@@ -41,7 +45,7 @@ describe("useDelayedPlayerDetails", () => {
|
|
|
41
45
|
expect(result.current).toBe(false);
|
|
42
46
|
});
|
|
43
47
|
|
|
44
|
-
it("should return true for tablet regardless of other flags", () => {
|
|
48
|
+
it("should return true for tablet regardless of other flags", async () => {
|
|
45
49
|
(useIsTablet as jest.Mock).mockReturnValue(true);
|
|
46
50
|
|
|
47
51
|
const { result } = renderHook(() =>
|
|
@@ -52,8 +56,12 @@ describe("useDelayedPlayerDetails", () => {
|
|
|
52
56
|
})
|
|
53
57
|
);
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
act(() => {
|
|
60
|
+
jest.advanceTimersByTime(1000);
|
|
61
|
+
});
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(result.current).toBe(true);
|
|
65
|
+
});
|
|
58
66
|
});
|
|
59
67
|
});
|
|
@@ -32,7 +32,7 @@ function getTestDimensions(testDimensions) {
|
|
|
32
32
|
return (process.env.NODE_ENV === "test" && testDimensions) || null;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function ViewportAwareComponent(props: Props,
|
|
35
|
+
function ViewportAwareComponent(props: Props, forwardedRef) {
|
|
36
36
|
const viewportEvents = useViewportEventsContext();
|
|
37
37
|
|
|
38
38
|
const {
|
|
@@ -47,13 +47,22 @@ function ViewportAwareComponent(props: Props, ref) {
|
|
|
47
47
|
getTestDimensions(testDimensions) || initialDimensions
|
|
48
48
|
);
|
|
49
49
|
|
|
50
|
+
const localRef = React.useRef(null);
|
|
51
|
+
|
|
50
52
|
const [viewportChangeEvent, setViewportChangeEvent] = React.useState(null);
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const assignRef = React.useCallback(
|
|
55
|
+
(_ref) => {
|
|
56
|
+
localRef.current = _ref;
|
|
57
|
+
|
|
58
|
+
if (typeof forwardedRef === "function") {
|
|
59
|
+
forwardedRef(_ref);
|
|
60
|
+
} else if (forwardedRef) {
|
|
61
|
+
forwardedRef.current = _ref;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
[forwardedRef]
|
|
65
|
+
);
|
|
57
66
|
|
|
58
67
|
const checkInViewport = (viewportChangeEvent, layoutEvent) => {
|
|
59
68
|
const inVerticalViewport = Utils.isInViewport(
|
|
@@ -94,7 +103,7 @@ function ViewportAwareComponent(props: Props, ref) {
|
|
|
94
103
|
const onViewportChange = (viewportChangeEvent) => {
|
|
95
104
|
setViewportChangeEvent(viewportChangeEvent);
|
|
96
105
|
|
|
97
|
-
const nodeHandle = findNodeHandle(
|
|
106
|
+
const nodeHandle = findNodeHandle(localRef.current);
|
|
98
107
|
|
|
99
108
|
if (!nodeHandle) {
|
|
100
109
|
return;
|
|
@@ -16,6 +16,7 @@ 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
|
+
|
|
19
20
|
import { Animated } from "react-native";
|
|
20
21
|
|
|
21
22
|
interface NavBarStoreState {
|
|
@@ -29,6 +30,8 @@ interface NavBarStoreState {
|
|
|
29
30
|
scrollState: number;
|
|
30
31
|
contentPosition: string;
|
|
31
32
|
scrollYAnimated: Animated.Value;
|
|
33
|
+
hideOnScrollAnimated: Animated.Value;
|
|
34
|
+
hideOnScroll: boolean;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
interface NavBarState {
|
|
@@ -62,30 +65,52 @@ const createStateStore = () =>
|
|
|
62
65
|
);
|
|
63
66
|
|
|
64
67
|
const createStore = () =>
|
|
65
|
-
create
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
create(
|
|
69
|
+
subscribeWithSelector<NavBarStoreState>((set) => ({
|
|
70
|
+
title: "",
|
|
71
|
+
summary: "",
|
|
72
|
+
visible: true,
|
|
73
|
+
height: 0,
|
|
74
|
+
scrollState: 0,
|
|
75
|
+
contentPosition: "",
|
|
76
|
+
scrollYAnimated: new Animated.Value(0),
|
|
77
|
+
hideOnScrollAnimated: new Animated.Value(0),
|
|
78
|
+
hideOnScroll: false,
|
|
79
|
+
setTitle(title) {
|
|
80
|
+
set({ title });
|
|
81
|
+
},
|
|
82
|
+
setSummary(summary) {
|
|
83
|
+
set({ summary });
|
|
84
|
+
},
|
|
85
|
+
setVisible(visible) {
|
|
86
|
+
set({ visible });
|
|
87
|
+
},
|
|
88
|
+
}))
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const createScreenComponentsStore = () =>
|
|
92
|
+
create(subscribeWithSelector<Record<string, unknown>>((_) => ({})));
|
|
83
93
|
|
|
84
94
|
type ScreenContextType = {
|
|
85
95
|
_navBarStore: ReturnType<typeof createStore>;
|
|
86
96
|
_stateStore: ReturnType<typeof createStateStore>;
|
|
87
97
|
navBar: NavBarState;
|
|
88
98
|
legacyFormatScreenData: LegacyNavigationScreenData | null;
|
|
99
|
+
/**
|
|
100
|
+
* Zustand store for component-level state within a screen.
|
|
101
|
+
*
|
|
102
|
+
* **Purpose:** Persists state across component mount/unmount cycles (e.g., during virtualization)
|
|
103
|
+
* and enables state sharing between components using the same key within the same screen.
|
|
104
|
+
*
|
|
105
|
+
* **Lifecycle:** Tied to the screen/route — recreated on each route change.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* // Used by useComponentScreenState hook:
|
|
109
|
+
* const store = useScreenContextV2()._componentStateStore;
|
|
110
|
+
* store.setState({ 'my-key': value });
|
|
111
|
+
* const value = store.getState()['my-key'];
|
|
112
|
+
*/
|
|
113
|
+
_componentStateStore: ReturnType<typeof createScreenComponentsStore>;
|
|
89
114
|
};
|
|
90
115
|
|
|
91
116
|
export const ScreenContext = createContext<ScreenContextType>({
|
|
@@ -100,6 +125,7 @@ export const ScreenContext = createContext<ScreenContextType>({
|
|
|
100
125
|
setSummary: (_subtitle) => void 0,
|
|
101
126
|
},
|
|
102
127
|
legacyFormatScreenData: {} as LegacyNavigationScreenData,
|
|
128
|
+
_componentStateStore: createScreenComponentsStore(),
|
|
103
129
|
});
|
|
104
130
|
|
|
105
131
|
export function ScreenContextProvider({
|
|
@@ -153,6 +179,14 @@ export function ScreenContextProvider({
|
|
|
153
179
|
return navBarState;
|
|
154
180
|
}, []);
|
|
155
181
|
|
|
182
|
+
// Component state store - recreated when pathname changes (route change).
|
|
183
|
+
// Unlike _navBarStore and _stateStore (cached via refs), this store
|
|
184
|
+
// resets only when pathname changes to provide a clean state for the new route.
|
|
185
|
+
const componentStateStore = useMemo(
|
|
186
|
+
() => createScreenComponentsStore(),
|
|
187
|
+
[pathname]
|
|
188
|
+
);
|
|
189
|
+
|
|
156
190
|
const screenNavBarState = getScreenNavBarState()(
|
|
157
191
|
useShallow((state) => ({
|
|
158
192
|
visible: state.visible,
|
|
@@ -205,8 +239,9 @@ export function ScreenContextProvider({
|
|
|
205
239
|
_stateStore: getScreenState(),
|
|
206
240
|
navBar: navBarState,
|
|
207
241
|
legacyFormatScreenData: routeScreenData,
|
|
242
|
+
_componentStateStore: componentStateStore,
|
|
208
243
|
}),
|
|
209
|
-
[navBarState, screenData, routeScreenData]
|
|
244
|
+
[navBarState, screenData, routeScreenData, componentStateStore]
|
|
210
245
|
)}
|
|
211
246
|
>
|
|
212
247
|
{children}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { create } from "zustand";
|
|
2
2
|
|
|
3
3
|
type HookModalState = {
|
|
4
4
|
path: string;
|
|
@@ -10,11 +10,12 @@ export type HookModalContextT = {
|
|
|
10
10
|
setIsHooksExecutionInProgress: (hookExecutionState?: boolean) => void;
|
|
11
11
|
isRunningInBackground: boolean;
|
|
12
12
|
isPresentationFullScreen: boolean;
|
|
13
|
-
setIsRunningInBackground: (
|
|
14
|
-
setIsPresentingFullScreen: (
|
|
13
|
+
setIsRunningInBackground: () => void;
|
|
14
|
+
setIsPresentingFullScreen: () => void;
|
|
15
15
|
state: HookModalState;
|
|
16
16
|
setState: (state: HookModalState) => void;
|
|
17
17
|
resetState: () => void;
|
|
18
|
+
hookPresentationMode: HookPresentationMode;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const initialState = {
|
|
@@ -24,68 +25,43 @@ const initialState = {
|
|
|
24
25
|
|
|
25
26
|
type HookPresentationMode = "background" | "fullScreen";
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
isRunningInBackground: null,
|
|
31
|
-
setIsRunningInBackground: () => {},
|
|
32
|
-
setIsPresentingFullScreen: () => {},
|
|
33
|
-
isPresentationFullScreen: null,
|
|
28
|
+
// Use useZappHookModalStore() in React components (hooks)
|
|
29
|
+
// Use zappHookModalStore.getState() in non-React functions (utility functions, etc.)
|
|
30
|
+
export const useZappHookModalStore = create<HookModalContextT>()((set) => ({
|
|
34
31
|
state: initialState,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
40
|
-
const [state, setState] = React.useState<HookModalState>(initialState);
|
|
41
|
-
|
|
42
|
-
const [hookPresentationMode, setHookPresentationMode] =
|
|
43
|
-
React.useState<HookPresentationMode>(null);
|
|
44
|
-
|
|
45
|
-
const resetState = useCallback(() => {
|
|
46
|
-
setState(initialState);
|
|
47
|
-
}, [setState]);
|
|
48
|
-
|
|
49
|
-
const [isHooksExecutionInProgress, setIsHooksExecutionInProgress] =
|
|
50
|
-
React.useState(false);
|
|
32
|
+
isHooksExecutionInProgress: false,
|
|
33
|
+
hookPresentationMode: null as HookPresentationMode,
|
|
34
|
+
isRunningInBackground: false,
|
|
35
|
+
isPresentationFullScreen: false,
|
|
51
36
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
37
|
+
setState: (newState: HookModalState) => {
|
|
38
|
+
set({ state: newState });
|
|
39
|
+
},
|
|
55
40
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
41
|
+
setIsHooksExecutionInProgress: (hookExecutionState?: boolean) => {
|
|
42
|
+
set({ isHooksExecutionInProgress: hookExecutionState ?? false });
|
|
43
|
+
},
|
|
59
44
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
isHooksExecutionInProgress,
|
|
68
|
-
setIsHooksExecutionInProgress,
|
|
69
|
-
state,
|
|
70
|
-
setState,
|
|
71
|
-
resetState,
|
|
72
|
-
}}
|
|
73
|
-
>
|
|
74
|
-
{children}
|
|
75
|
-
</ReactContext.Provider>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
45
|
+
setIsRunningInBackground: () => {
|
|
46
|
+
set({
|
|
47
|
+
hookPresentationMode: "background",
|
|
48
|
+
isRunningInBackground: true,
|
|
49
|
+
isPresentationFullScreen: false,
|
|
50
|
+
});
|
|
51
|
+
},
|
|
78
52
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
};
|
|
53
|
+
setIsPresentingFullScreen: () => {
|
|
54
|
+
set({
|
|
55
|
+
hookPresentationMode: "fullScreen",
|
|
56
|
+
isRunningInBackground: false,
|
|
57
|
+
isPresentationFullScreen: true,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
87
60
|
|
|
88
|
-
|
|
89
|
-
};
|
|
61
|
+
resetState: () => {
|
|
62
|
+
set({ state: initialState });
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
90
65
|
|
|
91
|
-
|
|
66
|
+
// Export an alias for clearer non-React usage (utility functions, etc.)
|
|
67
|
+
export const zappHookModalStore = useZappHookModalStore;
|
|
@@ -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 }}>
|
package/Contexts/index.ts
CHANGED
|
@@ -12,8 +12,6 @@ export { HorizontalScrollContext } from "./HorizontalScrollContext";
|
|
|
12
12
|
|
|
13
13
|
export { RiverOffsetContext } from "./RiverOffsetContext";
|
|
14
14
|
|
|
15
|
-
export { ZappHookModalContext } from "./ZappHookModalContext";
|
|
16
|
-
|
|
17
15
|
export { MeasurementContext } from "./MeasurementContext";
|
|
18
16
|
|
|
19
17
|
export * from "./ZappPipesContext";
|
|
@@ -88,6 +88,7 @@ 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"
|
|
91
92
|
target={false}
|
|
92
93
|
target_screen_switch={false}
|
|
93
94
|
text_label_active_font_color="rgba(239, 239, 239, 0.5)"
|
|
@@ -208,4 +208,5 @@ 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"),
|
|
211
212
|
};
|
|
@@ -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
|
}
|