@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4837064762 → 12.0.0-alpha.4945500007
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.tsx +1 -1
- package/Components/Cell/Cell.tsx +1 -5
- package/Components/Cell/CellWithFocusable.tsx +5 -17
- package/Components/FocusableGroup/index.tsx +0 -1
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +0 -3
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/index.tsx +25 -124
- package/Components/PlayerContainer/PlayerContainer.tsx +1 -3
- package/Components/River/ComponentsMap/ComponentsMap.tsx +18 -17
- package/Components/ScreenResolver/index.tsx +1 -3
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Screen/TV/index.web.tsx +0 -151
|
@@ -73,7 +73,7 @@ export class BaseFocusable<
|
|
|
73
73
|
getId(props?: { id: string; groupId: string }) {
|
|
74
74
|
const { id, groupId = null } = props || this.props;
|
|
75
75
|
|
|
76
|
-
return groupId ?
|
|
76
|
+
return groupId ? `${groupId}-${id}` : id;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
getRect() {
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -207,11 +207,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
207
207
|
|
|
208
208
|
const { id } = item;
|
|
209
209
|
|
|
210
|
-
const focusableId = R.join("-", [
|
|
211
|
-
`componentId:${component?.id}`,
|
|
212
|
-
`id:${id}`,
|
|
213
|
-
`index:${index}`,
|
|
214
|
-
]);
|
|
210
|
+
const focusableId = R.join("-", [component?.id, id, index]);
|
|
215
211
|
|
|
216
212
|
const handleFocus = (focusable, mouse) => {
|
|
217
213
|
const focusFn = onFocus || noop;
|
|
@@ -6,20 +6,12 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
6
6
|
import { isAppleTV } from "../../Helpers/Platform";
|
|
7
7
|
import { useCellState } from "../MasterCell/utils";
|
|
8
8
|
|
|
9
|
-
const useCellFocusedState = (
|
|
10
|
-
skipFocusManagerRegistration: boolean,
|
|
11
|
-
groupId: string,
|
|
12
|
-
id: string
|
|
13
|
-
) => {
|
|
9
|
+
const useCellFocusedState = (groupId: string, id: string) => {
|
|
14
10
|
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
15
11
|
|
|
16
12
|
React.useEffect(() => {
|
|
17
|
-
const isGroupItemFocused = () =>
|
|
18
|
-
|
|
19
|
-
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
20
|
-
setCurrentCellFocused(isFocused);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
13
|
+
const isGroupItemFocused = () =>
|
|
14
|
+
setCurrentCellFocused(focusManager.isGroupItemFocused(groupId, id));
|
|
23
15
|
|
|
24
16
|
const handler = () => {
|
|
25
17
|
// tvOS hack for properly checking focus
|
|
@@ -37,7 +29,7 @@ const useCellFocusedState = (
|
|
|
37
29
|
return () => {
|
|
38
30
|
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
39
31
|
};
|
|
40
|
-
}, [groupId
|
|
32
|
+
}, [groupId]);
|
|
41
33
|
|
|
42
34
|
return currentCellFocused;
|
|
43
35
|
};
|
|
@@ -73,11 +65,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
73
65
|
selected,
|
|
74
66
|
} = props;
|
|
75
67
|
|
|
76
|
-
const isFocused = useCellFocusedState(
|
|
77
|
-
skipFocusManagerRegistration,
|
|
78
|
-
groupId,
|
|
79
|
-
id
|
|
80
|
-
);
|
|
68
|
+
const isFocused = useCellFocusedState(groupId, id);
|
|
81
69
|
|
|
82
70
|
const state = useCellState({
|
|
83
71
|
id: item.id,
|
|
@@ -50,7 +50,11 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
expect(transformed_preset).toBeDefined();
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
expect(transformed_preset.id).toEqual(
|
|
55
|
+
`${mockComp.id}-${mockPreset.feed_url}-0`
|
|
56
|
+
); // id was transformed
|
|
57
|
+
|
|
54
58
|
expect(transformed_preset.data.source).toEqual(mockPreset.feed_url); // source was replaced with preset feed_url.
|
|
55
59
|
});
|
|
56
60
|
});
|
|
@@ -117,7 +121,10 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
117
121
|
|
|
118
122
|
expect(Array.isArray(result)).toBe(true);
|
|
119
123
|
expect(result).toHaveLength(2);
|
|
120
|
-
|
|
124
|
+
|
|
125
|
+
expect(result[0].id).toEqual(
|
|
126
|
+
`${mockSmartComp.id}-${mockFeeds.preset_source.data.entry[0].feed_url}-0`
|
|
127
|
+
);
|
|
121
128
|
|
|
122
129
|
expect(result[0].data.source).toEqual(
|
|
123
130
|
mockFeeds.preset_source.data.entry[0].feed_url
|
|
@@ -287,7 +294,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
287
294
|
mockComponents[0],
|
|
288
295
|
{
|
|
289
296
|
...mockLayoutPresets.preset_one,
|
|
290
|
-
id: mockComponents[1].id
|
|
297
|
+
id: `${mockComponents[1].id}-${mockPresetEntry[0].feed_url}-1`,
|
|
291
298
|
data: { source: mockPresetEntry[0].feed_url },
|
|
292
299
|
},
|
|
293
300
|
];
|
|
@@ -344,12 +351,12 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
344
351
|
const mockTransformedComponents = [
|
|
345
352
|
{
|
|
346
353
|
...mockLayoutPresets.preset_one,
|
|
347
|
-
id: mockComponents[0].id
|
|
354
|
+
id: `${mockComponents[0].id}-${mockPresetEntry1[0].feed_url}-0`,
|
|
348
355
|
data: { source: mockPresetEntry1[0].feed_url },
|
|
349
356
|
},
|
|
350
357
|
{
|
|
351
358
|
...mockLayoutPresets.preset_one,
|
|
352
|
-
id: mockComponents[1].id
|
|
359
|
+
id: `${mockComponents[1].id}-${mockPresetEntry2[0].feed_url}-1`,
|
|
353
360
|
data: { source: mockPresetEntry2[0].feed_url },
|
|
354
361
|
},
|
|
355
362
|
];
|
|
@@ -412,7 +419,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
412
419
|
const mockTransformedComponents = mockPresetEntry.map((preset, i) => {
|
|
413
420
|
return {
|
|
414
421
|
...mockLayoutPresets[preset.preset_name],
|
|
415
|
-
id: mockComponents[0].id
|
|
422
|
+
id: `${mockComponents[0].id}-${preset.feed_url}-${i}`,
|
|
416
423
|
data: { source: preset.feed_url },
|
|
417
424
|
};
|
|
418
425
|
});
|
|
@@ -41,7 +41,7 @@ export const getTransformedPreset = (
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const updatedPresetComponent = produce(presetComponent, (draft) => {
|
|
44
|
-
draft.id = `${componentId}
|
|
44
|
+
draft.id = `${componentId}-${preset?.feed_url}-${index}`;
|
|
45
45
|
draft.data.source = preset?.feed_url;
|
|
46
46
|
|
|
47
47
|
if (draft.ui_components) {
|
|
@@ -19,7 +19,6 @@ type Props = {
|
|
|
19
19
|
modalHeight?: number;
|
|
20
20
|
modalWidth?: number;
|
|
21
21
|
mode: VideoModalMode;
|
|
22
|
-
groupId?: string;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
@@ -94,7 +93,6 @@ export function HandlePlayable({
|
|
|
94
93
|
modalHeight,
|
|
95
94
|
modalWidth,
|
|
96
95
|
mode,
|
|
97
|
-
groupId,
|
|
98
96
|
}: Props): React.ReactElement | null {
|
|
99
97
|
const state = usePickFromState();
|
|
100
98
|
|
|
@@ -169,7 +167,6 @@ export function HandlePlayable({
|
|
|
169
167
|
isModal={isModal}
|
|
170
168
|
mode={mode}
|
|
171
169
|
disableCastAction={playerModuleProperties?.disableCastAction}
|
|
172
|
-
groupId={groupId}
|
|
173
170
|
/>
|
|
174
171
|
);
|
|
175
172
|
}
|
|
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
60
60
|
initialState
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const
|
|
63
|
+
const screeenLayoutValue = React.useMemo(
|
|
64
64
|
() => ({
|
|
65
65
|
...screenLayout,
|
|
66
66
|
setScreenLayout,
|
|
@@ -69,7 +69,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
return (
|
|
72
|
-
<ScreenLayoutContext.Provider value={
|
|
72
|
+
<ScreenLayoutContext.Provider value={screeenLayoutValue}>
|
|
73
73
|
{props.children}
|
|
74
74
|
</ScreenLayoutContext.Provider>
|
|
75
75
|
);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View, StyleSheet } from "react-native";
|
|
4
3
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
6
5
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
7
|
-
import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
8
|
-
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
9
6
|
|
|
10
7
|
import {
|
|
11
8
|
getNavigationProps,
|
|
12
|
-
getPathAttributes,
|
|
13
9
|
resolveNavigationPlugin,
|
|
14
10
|
routeIsPlayerScreen,
|
|
15
11
|
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
@@ -21,25 +17,9 @@ import { ScreenContainer } from "./ScreenContainer";
|
|
|
21
17
|
import { TransitionOverlay } from "./TransitionOverlay";
|
|
22
18
|
|
|
23
19
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
20
|
+
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
24
21
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
25
|
-
|
|
26
|
-
import { FocusableGroup } from "../../FocusableGroup";
|
|
27
|
-
import { Screen } from "../../Screen/TV/index.web";
|
|
28
|
-
|
|
29
|
-
export const ScreenDataContext = React.createContext(null);
|
|
30
|
-
|
|
31
|
-
const styles = StyleSheet.create({
|
|
32
|
-
container: {
|
|
33
|
-
position: "absolute",
|
|
34
|
-
width: 1920,
|
|
35
|
-
height: 1080,
|
|
36
|
-
backgroundColor: "black",
|
|
37
|
-
// opacity: 0.5,
|
|
38
|
-
|
|
39
|
-
borderWidth: 4,
|
|
40
|
-
borderColor: "magenta",
|
|
41
|
-
},
|
|
42
|
-
});
|
|
22
|
+
import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
43
23
|
|
|
44
24
|
type Components = {
|
|
45
25
|
NavBar: React.ComponentType<any>;
|
|
@@ -47,73 +27,16 @@ type Components = {
|
|
|
47
27
|
};
|
|
48
28
|
|
|
49
29
|
type ComponentsExtraProps = {
|
|
50
|
-
NavBar?: Record<string, any>;
|
|
51
30
|
Background?: Record<string, any>;
|
|
31
|
+
NavBar?: Record<string, any>;
|
|
52
32
|
};
|
|
53
33
|
|
|
54
34
|
type Props = {
|
|
55
35
|
Components: Components;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const StackNavigator = ({ Components }: Props) => {
|
|
60
|
-
// @ts-ignore
|
|
61
|
-
const { mainStack, currentRoute } = useNavigation();
|
|
62
|
-
|
|
63
|
-
// console.log("debug_2", "DEBUG", { mainStack });
|
|
64
|
-
|
|
65
|
-
const renderScreen = ({ route, action, key, state }, index) => {
|
|
66
|
-
const pathAttributes = getPathAttributes({ pathname: route });
|
|
67
|
-
|
|
68
|
-
if (R.isEmpty(pathAttributes)) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// console.log("debug_2", "StackNavigator - renderScreen", {
|
|
73
|
-
// index,
|
|
74
|
-
// route,
|
|
75
|
-
// state,
|
|
76
|
-
// key,
|
|
77
|
-
// action,
|
|
78
|
-
// });
|
|
79
|
-
|
|
80
|
-
const id = `${route}`;
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<FocusableGroup
|
|
84
|
-
id={id}
|
|
85
|
-
preferredFocus={route === currentRoute}
|
|
86
|
-
excludeFromFocusSearching
|
|
87
|
-
key={id}
|
|
88
|
-
>
|
|
89
|
-
<View style={styles.container}>
|
|
90
|
-
<ScreenDataContext.Provider value={state}>
|
|
91
|
-
<PathnameContext.Provider value={route}>
|
|
92
|
-
<Screen route={route} Components={Components} />
|
|
93
|
-
</PathnameContext.Provider>
|
|
94
|
-
</ScreenDataContext.Provider>
|
|
95
|
-
</View>
|
|
96
|
-
</FocusableGroup>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
return mainStack.map(renderScreen);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const TransitionerTV = ({ componentsExtraProps, Components }: Props) => {
|
|
104
|
-
return (
|
|
105
|
-
<>
|
|
106
|
-
<ScreenLayoutContextProvider>
|
|
107
|
-
<StackNavigator
|
|
108
|
-
componentsExtraProps={componentsExtraProps}
|
|
109
|
-
Components={Components}
|
|
110
|
-
/>
|
|
111
|
-
</ScreenLayoutContextProvider>
|
|
112
|
-
</>
|
|
113
|
-
);
|
|
36
|
+
ComponentsExtraProps?: ComponentsExtraProps;
|
|
37
|
+
children: React.ReactNode;
|
|
114
38
|
};
|
|
115
39
|
|
|
116
|
-
// @ts-ignore
|
|
117
40
|
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
118
41
|
const navigator = useNavigation();
|
|
119
42
|
const theme = useTheme();
|
|
@@ -175,54 +98,32 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
175
98
|
}
|
|
176
99
|
|
|
177
100
|
return (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
189
|
-
>
|
|
190
|
-
{!isTVOS ? navBarContainer : null}
|
|
191
|
-
{navBarReady ? (
|
|
192
|
-
/**
|
|
101
|
+
<LayoutContainer>
|
|
102
|
+
<ScreenLayoutContextProvider>
|
|
103
|
+
<Components.Background
|
|
104
|
+
backgroundColor={backgroundColor}
|
|
105
|
+
backgroundImageUrl={backgroundImageUrl}
|
|
106
|
+
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
107
|
+
>
|
|
108
|
+
{!isTVOS ? navBarContainer : null}
|
|
109
|
+
{navBarReady ? (
|
|
110
|
+
/**
|
|
193
111
|
Need to re-mount this component on each navigation event
|
|
194
112
|
It's a hack to work around the fact that we don't support
|
|
195
113
|
correct screen rendering in our navigator (shared currentRoute state)
|
|
196
114
|
**/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
115
|
+
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
116
|
+
<ScreenContainer>{children}</ScreenContainer>
|
|
117
|
+
</PathnameContext.Provider>
|
|
118
|
+
) : null}
|
|
119
|
+
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
202
120
|
focus manager works correctly to focus nav bar items first **/}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
</TransitionerTV>
|
|
121
|
+
{isTVOS ? navBarContainer : null}
|
|
122
|
+
<TransitionOverlay />
|
|
123
|
+
</Components.Background>
|
|
124
|
+
</ScreenLayoutContextProvider>
|
|
125
|
+
</LayoutContainer>
|
|
209
126
|
);
|
|
210
127
|
};
|
|
211
128
|
|
|
212
129
|
export default Layout;
|
|
213
|
-
|
|
214
|
-
/// Transitioner:
|
|
215
|
-
/*
|
|
216
|
-
Component: Transitioner
|
|
217
|
-
Responsibilities:
|
|
218
|
-
- Transitione between screens.
|
|
219
|
-
Tehere is no transition on Tv so no need for transitioner.
|
|
220
|
-
|
|
221
|
-
Component: StackNavigator
|
|
222
|
-
Responsibilities:
|
|
223
|
-
- Render the screens in the stack.
|
|
224
|
-
- Render the NavBar? I guess navbar should be part of the screen
|
|
225
|
-
- Render the screen.
|
|
226
|
-
|
|
227
|
-
Q
|
|
228
|
-
*/
|
|
@@ -68,7 +68,6 @@ type Props = {
|
|
|
68
68
|
mode?: VideoModalMode;
|
|
69
69
|
loadPipesData: (url: string, options: {}) => void;
|
|
70
70
|
disableCastAction?: boolean;
|
|
71
|
-
groupId?: string;
|
|
72
71
|
};
|
|
73
72
|
|
|
74
73
|
type ScreenStyles = ZappRiver["styles"] & {
|
|
@@ -201,7 +200,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
201
200
|
style: videoStyle,
|
|
202
201
|
mode = VideoModalMode.MAXIMIZED,
|
|
203
202
|
disableCastAction = false,
|
|
204
|
-
groupId,
|
|
205
203
|
} = props;
|
|
206
204
|
|
|
207
205
|
// Hooks
|
|
@@ -251,6 +249,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
251
249
|
return;
|
|
252
250
|
}
|
|
253
251
|
|
|
252
|
+
navigator.goBack();
|
|
254
253
|
showNavBar(true);
|
|
255
254
|
}, [isModal, navigator.goBack, showNavBar]);
|
|
256
255
|
|
|
@@ -630,7 +629,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
630
629
|
style={styles.focusableGroup}
|
|
631
630
|
preferredFocus
|
|
632
631
|
shouldUsePreferredFocus
|
|
633
|
-
groupId={groupId}
|
|
634
632
|
>
|
|
635
633
|
{/* Video player and components */}
|
|
636
634
|
<View
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View, StyleSheet, Platform,
|
|
3
|
+
import { View, StyleSheet, Platform, FlatList } from "react-native";
|
|
4
4
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
5
5
|
import { RiverItem } from "../RiverItem";
|
|
6
6
|
import { RiverFooter } from "../RiverFooter";
|
|
@@ -217,7 +217,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
217
217
|
|
|
218
218
|
const { height: headerHeight, scrollState } = navBarStore.getState();
|
|
219
219
|
|
|
220
|
-
const offsetY = nativeEvent.contentOffset.y;
|
|
220
|
+
const offsetY = Math.max(0, nativeEvent.contentOffset.y);
|
|
221
221
|
|
|
222
222
|
if (
|
|
223
223
|
!(scrollState === 0 || scrollState === -headerHeight) &&
|
|
@@ -240,7 +240,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
240
240
|
const _onScrollEndDrag = React.useCallback(({ nativeEvent }) => {
|
|
241
241
|
const { height: headerHeight, scrollState } = navBarStore.getState();
|
|
242
242
|
|
|
243
|
-
const offsetY = nativeEvent.contentOffset.y;
|
|
243
|
+
const offsetY = Math.max(0, nativeEvent.contentOffset.y);
|
|
244
244
|
|
|
245
245
|
if (
|
|
246
246
|
!(scrollState === 0 || scrollState === -headerHeight) &&
|
|
@@ -260,6 +260,20 @@ function ComponentsMapComponent(props: Props) {
|
|
|
260
260
|
}
|
|
261
261
|
}, []);
|
|
262
262
|
|
|
263
|
+
const onScroll = React.useCallback((event) => {
|
|
264
|
+
const {
|
|
265
|
+
nativeEvent: {
|
|
266
|
+
contentOffset: { y },
|
|
267
|
+
layoutMeasurement: { height },
|
|
268
|
+
contentSize: { height: contentHeight },
|
|
269
|
+
},
|
|
270
|
+
} = event;
|
|
271
|
+
|
|
272
|
+
if (y >= 0 && y + height <= contentHeight) {
|
|
273
|
+
scrollY.setValue(y);
|
|
274
|
+
}
|
|
275
|
+
}, []);
|
|
276
|
+
|
|
263
277
|
if (shouldShowLoadingError) {
|
|
264
278
|
return <RiverError />;
|
|
265
279
|
}
|
|
@@ -298,20 +312,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
298
312
|
ListFooterComponent={renderFooter}
|
|
299
313
|
refreshControl={refreshControl}
|
|
300
314
|
onScrollBeginDrag={onScrollBeginDrag}
|
|
301
|
-
onScroll={
|
|
302
|
-
[
|
|
303
|
-
{
|
|
304
|
-
nativeEvent: {
|
|
305
|
-
contentOffset: {
|
|
306
|
-
y: scrollY,
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
],
|
|
311
|
-
{
|
|
312
|
-
useNativeDriver: false,
|
|
313
|
-
}
|
|
314
|
-
)}
|
|
315
|
+
onScroll={onScroll}
|
|
315
316
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
316
317
|
onScrollEndDrag={_onScrollEndDrag}
|
|
317
318
|
scrollEventThrottle={16}
|
|
@@ -32,13 +32,12 @@ type Props = {
|
|
|
32
32
|
nextFocusLeft?: React.Ref<any>;
|
|
33
33
|
nextFocusUp?: React.Ref<any>;
|
|
34
34
|
};
|
|
35
|
-
groupId?: string;
|
|
36
35
|
};
|
|
37
36
|
|
|
38
37
|
export function ScreenResolverComponent(props: Props) {
|
|
39
38
|
useScreenAnalytics(props);
|
|
40
39
|
|
|
41
|
-
const { screenType, screenId, screenData
|
|
40
|
+
const { screenType, screenId, screenData } = props;
|
|
42
41
|
|
|
43
42
|
const { hookPlugin } = screenData || {};
|
|
44
43
|
|
|
@@ -82,7 +81,6 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
82
81
|
item={screenData}
|
|
83
82
|
mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
|
|
84
83
|
isModal={false}
|
|
85
|
-
groupId={groupId}
|
|
86
84
|
/>
|
|
87
85
|
);
|
|
88
86
|
}
|
|
@@ -6,23 +6,23 @@ import { callOnChildren } from "../utils";
|
|
|
6
6
|
|
|
7
7
|
export function ViewportTracker(props) {
|
|
8
8
|
const viewportEvents = useViewportEventsContext();
|
|
9
|
-
const { children } = props;
|
|
10
|
-
const [width, setWidth] = React.useState(0);
|
|
11
|
-
const [height, setHeight] = React.useState(0);
|
|
12
|
-
const [offsetX, setOffsetX] = React.useState(0);
|
|
13
|
-
const [offsetY, setOffsetY] = React.useState(0);
|
|
14
9
|
const [nodeHandle, setNodeHandle] = React.useState(null);
|
|
15
10
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
const childrenRef = React.useRef(props.children);
|
|
12
|
+
|
|
13
|
+
const dimensionsRef = React.useRef({ width: 0, height: 0 });
|
|
14
|
+
const offsetRef = React.useRef({ offsetX: 0, offsetY: 0 });
|
|
15
|
+
|
|
16
|
+
const assignRef = React.useCallback((ref) => {
|
|
17
|
+
childrenRef.current?.ref?.(ref);
|
|
18
|
+
setNodeHandle(findNodeHandle(ref));
|
|
19
|
+
}, []);
|
|
23
20
|
|
|
24
21
|
const onViewportChange = React.useCallback(
|
|
25
|
-
(
|
|
22
|
+
({
|
|
23
|
+
event = { ...dimensionsRef.current, ...offsetRef.current },
|
|
24
|
+
shouldMeasureLayout = true,
|
|
25
|
+
} = {}) => {
|
|
26
26
|
if (nodeHandle && event?.width > 0 && event?.height > 0) {
|
|
27
27
|
viewportEvents?.notify?.({
|
|
28
28
|
parentHandle: nodeHandle,
|
|
@@ -36,54 +36,45 @@ export function ViewportTracker(props) {
|
|
|
36
36
|
|
|
37
37
|
const onLayout = React.useCallback(
|
|
38
38
|
(event) => {
|
|
39
|
-
callOnChildren(
|
|
40
|
-
|
|
41
|
-
setHeight(event?.nativeEvent?.layout?.height);
|
|
39
|
+
callOnChildren(childrenRef.current, "onLayout", event);
|
|
40
|
+
dimensionsRef.current = event?.nativeEvent?.layout;
|
|
42
41
|
|
|
43
|
-
onViewportChange(
|
|
44
|
-
width: event?.nativeEvent?.layout?.width,
|
|
45
|
-
height: event?.nativeEvent?.layout?.height,
|
|
46
|
-
offsetX,
|
|
47
|
-
offsetY,
|
|
48
|
-
});
|
|
42
|
+
onViewportChange();
|
|
49
43
|
},
|
|
50
|
-
[
|
|
44
|
+
[onViewportChange]
|
|
51
45
|
);
|
|
52
46
|
|
|
53
47
|
const onContentSizeChange = React.useCallback(
|
|
54
48
|
(contentWidth, contentHeight) => {
|
|
55
49
|
callOnChildren(
|
|
56
|
-
|
|
50
|
+
childrenRef.current,
|
|
57
51
|
"onContentSizeChange",
|
|
58
52
|
contentWidth,
|
|
59
53
|
contentHeight
|
|
60
54
|
);
|
|
61
55
|
|
|
62
|
-
onViewportChange(
|
|
56
|
+
onViewportChange();
|
|
63
57
|
},
|
|
64
|
-
[onViewportChange
|
|
58
|
+
[onViewportChange]
|
|
65
59
|
);
|
|
66
60
|
|
|
67
61
|
const onScroll = React.useCallback(
|
|
68
62
|
(event) => {
|
|
69
|
-
callOnChildren(
|
|
70
|
-
|
|
71
|
-
setOffsetY(event?.nativeEvent?.contentOffset?.y);
|
|
63
|
+
callOnChildren(childrenRef.current, "onScroll", event);
|
|
64
|
+
offsetRef.current = event?.nativeEvent?.contentOffset;
|
|
72
65
|
|
|
73
|
-
onViewportChange(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
height,
|
|
77
|
-
offsetX: event?.nativeEvent?.contentOffset?.x,
|
|
78
|
-
offsetY: event?.nativeEvent?.contentOffset?.y,
|
|
79
|
-
},
|
|
80
|
-
false
|
|
81
|
-
);
|
|
66
|
+
onViewportChange({
|
|
67
|
+
shouldMeasureLayout: false,
|
|
68
|
+
});
|
|
82
69
|
},
|
|
83
|
-
[onViewportChange
|
|
70
|
+
[onViewportChange]
|
|
84
71
|
);
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
childrenRef.current = props.children;
|
|
75
|
+
}, [props.children]);
|
|
76
|
+
|
|
77
|
+
return React.cloneElement(React.Children.only(props.children), {
|
|
87
78
|
ref: assignRef,
|
|
88
79
|
onLayout,
|
|
89
80
|
onContentSizeChange,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.4945500007",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"redux-mock-store": "^1.5.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
38
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
39
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
40
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
37
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.4945500007",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4945500007",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.4945500007",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.4945500007",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { last, pathOr } from "ramda";
|
|
3
|
-
import { ScreenResolver } from "../../ScreenResolver";
|
|
4
|
-
import {
|
|
5
|
-
getNavigationProps,
|
|
6
|
-
getPathAttributes,
|
|
7
|
-
resolveNavigationPlugin,
|
|
8
|
-
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
9
|
-
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
10
|
-
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
11
|
-
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
12
|
-
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
13
|
-
|
|
14
|
-
type Components = {
|
|
15
|
-
NavBar: React.ComponentType<any>;
|
|
16
|
-
Background: React.ComponentType<any>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type Props = {
|
|
20
|
-
route: string;
|
|
21
|
-
Components: Components;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const isPlayer = (routeState): boolean => {
|
|
25
|
-
const pluginType = pathOr(
|
|
26
|
-
"unknown_plugin_type",
|
|
27
|
-
["state", "screen", "plugin_type"],
|
|
28
|
-
routeState
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return pluginType === "player";
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const getActiveRiver = ({
|
|
35
|
-
screenId,
|
|
36
|
-
screenType,
|
|
37
|
-
routeState,
|
|
38
|
-
rivers,
|
|
39
|
-
fallbackActiveRiver,
|
|
40
|
-
}) => {
|
|
41
|
-
if (rivers[screenId]) {
|
|
42
|
-
// river presents
|
|
43
|
-
return screenType === "hooks"
|
|
44
|
-
? routeState?.state?.entry?.payload
|
|
45
|
-
: routeState?.state?.screen;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// screenId is not presented into rivers, use fallback instead
|
|
49
|
-
return fallbackActiveRiver;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const getNavigations = ({
|
|
53
|
-
screenId,
|
|
54
|
-
screenType,
|
|
55
|
-
routeState,
|
|
56
|
-
rivers,
|
|
57
|
-
fallbackNavigations,
|
|
58
|
-
}) => {
|
|
59
|
-
if (rivers[screenId]) {
|
|
60
|
-
// river presents
|
|
61
|
-
return screenType === "hooks"
|
|
62
|
-
? routeState?.state?.entry?.payload.navigations
|
|
63
|
-
: routeState?.state?.screen?.navigations;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// screenId is not presented into rivers, use fallback instead
|
|
67
|
-
return fallbackNavigations;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export const Screen = (props: Props) => {
|
|
71
|
-
if (!props.route) {
|
|
72
|
-
throw new Error("Required props route is missing");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const navigator = useNavigation();
|
|
76
|
-
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
77
|
-
|
|
78
|
-
const pathAttributes = getPathAttributes({ pathname: props.route });
|
|
79
|
-
const routeState = navigator.getStackForPathname(props.route);
|
|
80
|
-
|
|
81
|
-
const { screenType, screenId } = last(pathAttributes);
|
|
82
|
-
|
|
83
|
-
// console.log("debug_2", "Screen", {
|
|
84
|
-
// screenType,
|
|
85
|
-
// routeState,
|
|
86
|
-
// route: props.route,
|
|
87
|
-
// navigator,
|
|
88
|
-
// });
|
|
89
|
-
|
|
90
|
-
const activeRiver = getActiveRiver({
|
|
91
|
-
screenId,
|
|
92
|
-
screenType,
|
|
93
|
-
routeState,
|
|
94
|
-
rivers,
|
|
95
|
-
fallbackActiveRiver: navigator.activeRiver,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const navigationProps = getNavigationProps({
|
|
99
|
-
navigator: {
|
|
100
|
-
// @ts-ignore
|
|
101
|
-
activeRiver,
|
|
102
|
-
// @ts-ignore
|
|
103
|
-
screenTitle: routeState.state.entry?.title || routeState.screen?.name,
|
|
104
|
-
},
|
|
105
|
-
category: "menu",
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const navigations = getNavigations({
|
|
109
|
-
screenId,
|
|
110
|
-
screenType,
|
|
111
|
-
routeState,
|
|
112
|
-
rivers,
|
|
113
|
-
fallbackNavigations: navigator.activeRiver.navigations,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const menuPlugin = resolveNavigationPlugin({
|
|
117
|
-
category: "menu",
|
|
118
|
-
navigations,
|
|
119
|
-
plugins,
|
|
120
|
-
}) as QuickBrickPlugin;
|
|
121
|
-
|
|
122
|
-
const NavBar = (props.Components.NavBar ||
|
|
123
|
-
menuPlugin.module) as React.ComponentType<any>;
|
|
124
|
-
|
|
125
|
-
const isNavBarVisible = !isPlayer(routeState);
|
|
126
|
-
|
|
127
|
-
const screenData =
|
|
128
|
-
screenType === "hooks"
|
|
129
|
-
? routeState?.state?.entry
|
|
130
|
-
: routeState?.state?.screen;
|
|
131
|
-
|
|
132
|
-
return (
|
|
133
|
-
<>
|
|
134
|
-
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
135
|
-
<NavBar
|
|
136
|
-
groupId={props.route}
|
|
137
|
-
isVisible={isNavBarVisible}
|
|
138
|
-
menuPlugin={menuPlugin}
|
|
139
|
-
navigationProps={navigationProps}
|
|
140
|
-
// Maybe activeRiver?
|
|
141
|
-
/>
|
|
142
|
-
</NavBarContainer>
|
|
143
|
-
<ScreenResolver
|
|
144
|
-
screenType={screenType}
|
|
145
|
-
screenId={screenId}
|
|
146
|
-
screenData={screenData}
|
|
147
|
-
groupId={props.route}
|
|
148
|
-
/>
|
|
149
|
-
</>
|
|
150
|
-
);
|
|
151
|
-
};
|