@applicaster/zapp-react-native-ui-components 15.1.4 → 16.0.0-alpha.1042942411
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/index.ts +1 -8
- package/Components/BaseFocusable/index.ios.ts +12 -2
- package/Components/Cell/FocusableWrapper.tsx +3 -0
- package/Components/Cell/TvOSCellComponent.tsx +6 -3
- package/Components/CellRendererResolver/index.ts +1 -1
- 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 +30 -1
- package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +39 -0
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
- package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +124 -0
- package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
- package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
- package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +72 -0
- package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
- package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
- package/Components/GeneralContentScreen/index.ts +2 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +13 -8
- package/Components/Layout/TV/NavBarContainer.tsx +1 -10
- package/Components/Layout/TV/ScreenContainer.tsx +2 -6
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/index.tsx +3 -4
- package/Components/Layout/TV/index.web.tsx +3 -4
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +27 -48
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +213 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +198 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +217 -46
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +50 -119
- package/Components/MasterCell/DefaultComponents/Button.tsx +50 -58
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.android.tv.tsx +58 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
- package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
- package/Components/MasterCell/DefaultComponents/CellBadge/__tests__/__snapshots__/index.test.tsx.snap +18 -0
- package/Components/MasterCell/DefaultComponents/CellBadge/__tests__/index.test.tsx +90 -0
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +13 -14
- package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
- package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +8 -2
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +1 -2
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +54 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +46 -50
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +47 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +19 -6
- package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +15 -0
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +45 -15
- package/Components/MasterCell/DefaultComponents/UIKitAdapters/Badge.tsx +49 -0
- package/Components/MasterCell/DefaultComponents/__tests__/ActionButton.test.tsx +122 -0
- package/Components/MasterCell/DefaultComponents/__tests__/Button.test.tsx +186 -0
- package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
- package/Components/MasterCell/DefaultComponents/__tests__/DynamicBadge.test.tsx +156 -0
- package/Components/MasterCell/DefaultComponents/__tests__/__snapshots__/ActionButton.test.tsx.snap +60 -0
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +196 -67
- package/Components/MasterCell/DefaultComponents/index.ts +13 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +189 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +33 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +159 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +18 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +39 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +402 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +354 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +129 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +123 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -48
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +101 -144
- package/Components/MasterCell/MappingFunctions/index.js +3 -2
- package/Components/MasterCell/README.md +4 -0
- package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
- package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
- package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
- package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
- package/Components/MasterCell/dataAdapter.ts +4 -1
- package/Components/MasterCell/elementMapper.tsx +54 -7
- package/Components/MasterCell/hooks/index.ts +2 -0
- package/Components/MasterCell/hooks/usePressedState.ts +4 -0
- package/Components/MasterCell/index.tsx +20 -4
- package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
- package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
- package/Components/MasterCell/utils/index.ts +82 -16
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +33 -69
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +25 -47
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +122 -39
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +671 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +257 -88
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +6 -4
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +17 -10
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
- package/Components/OfflineHandler/__tests__/index.test.tsx +101 -32
- package/Components/OfflineHandler/hooks.ts +123 -0
- package/Components/OfflineHandler/index.tsx +51 -73
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +6 -5
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +2 -4
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +8 -21
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +19 -105
- package/Components/River/River.tsx +9 -82
- 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 +4 -0
- package/Components/River/__tests__/componentsMap.test.js +38 -0
- package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
- package/Components/River/hooks/index.ts +1 -0
- package/Components/River/hooks/usePullToRefresh.ts +51 -0
- package/Components/Screen/TV/index.web.tsx +4 -2
- package/Components/Screen/__tests__/Screen.test.tsx +65 -42
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
- package/Components/Screen/hooks.ts +2 -3
- package/Components/Screen/index.tsx +2 -3
- package/Components/Screen/orientationHandler.ts +3 -3
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
- package/Components/ScreenResolver/index.tsx +9 -5
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +1 -1
- package/Components/Tabs/TabContent.tsx +7 -4
- package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
- package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
- package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
- package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
- package/Components/TopCutoffOverlay/index.tsx +55 -0
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/VideoModal/utils.ts +12 -10
- 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/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
- package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
- package/Contexts/ScreenContext/index.tsx +25 -18
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Decorators/Analytics/index.tsx +6 -5
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
- package/Decorators/ConfigurationWrapper/const.ts +1 -0
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- 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/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
- package/Helpers/DataSourceHelper/index.ts +19 -0
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -67
- package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
- package/Components/River/TV/withTVEventHandler.tsx +0 -36
- package/Helpers/DataSourceHelper/index.js +0 -19
- /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
- /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
- /package/Components/BackgroundImage/{BackgroundImage.tv.web.tsx → BackgroundImage.tsx} +0 -0
|
@@ -9,7 +9,7 @@ import { useScreenConfiguration } from "../useScreenConfiguration";
|
|
|
9
9
|
import { RefreshControl } from "../RefreshControl";
|
|
10
10
|
import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
useMarkPipesDataStale,
|
|
13
13
|
useProfilerLogging,
|
|
14
14
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
15
15
|
import { useLoadingState } from "./hooks/useLoadingState";
|
|
@@ -39,8 +39,6 @@ type Props = {
|
|
|
39
39
|
scrollViewExtraProps?: {};
|
|
40
40
|
riverId?: string;
|
|
41
41
|
getStaticComponentFeed: any;
|
|
42
|
-
pullToRefreshPipesV1RefreshingStateUpdater: () => boolean;
|
|
43
|
-
refreshingPipesV1?: boolean;
|
|
44
42
|
stickyHeaderIndices?: number[];
|
|
45
43
|
};
|
|
46
44
|
|
|
@@ -65,10 +63,6 @@ function ComponentsMapComponent(props: Props) {
|
|
|
65
63
|
groupId,
|
|
66
64
|
riverId,
|
|
67
65
|
getStaticComponentFeed,
|
|
68
|
-
// Method added to keep pipes v1 logic up to date with the pullToRefresh state.
|
|
69
|
-
// TODO: Remove when pipes v1 is deprecated.
|
|
70
|
-
pullToRefreshPipesV1RefreshingStateUpdater,
|
|
71
|
-
refreshingPipesV1,
|
|
72
66
|
stickyHeaderIndices,
|
|
73
67
|
} = props;
|
|
74
68
|
|
|
@@ -160,19 +154,11 @@ function ComponentsMapComponent(props: Props) {
|
|
|
160
154
|
[flatListHeight]
|
|
161
155
|
);
|
|
162
156
|
|
|
163
|
-
|
|
157
|
+
useMarkPipesDataStale(riverId, riverComponents);
|
|
164
158
|
|
|
165
159
|
const refreshControl = React.useMemo(
|
|
166
|
-
() =>
|
|
167
|
-
|
|
168
|
-
<RefreshControl
|
|
169
|
-
pullToRefreshPipesV1RefreshingStateUpdater={
|
|
170
|
-
pullToRefreshPipesV1RefreshingStateUpdater
|
|
171
|
-
}
|
|
172
|
-
refreshingPipesV1={refreshingPipesV1}
|
|
173
|
-
/>
|
|
174
|
-
) : null,
|
|
175
|
-
[]
|
|
160
|
+
() => (pullToRefreshEnabled ? <RefreshControl /> : null),
|
|
161
|
+
[pullToRefreshEnabled]
|
|
176
162
|
);
|
|
177
163
|
|
|
178
164
|
const navBarStore = useScreenContextV2()._navBarStore;
|
|
@@ -281,6 +267,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
281
267
|
>
|
|
282
268
|
<ViewportTracker>
|
|
283
269
|
<FlatList
|
|
270
|
+
testID="components-map-flat-list"
|
|
284
271
|
ref={(ref) => {
|
|
285
272
|
flatListRef.current = ref;
|
|
286
273
|
}}
|
|
@@ -312,10 +299,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
312
299
|
onScrollEndDrag={_onScrollEndDrag}
|
|
313
300
|
scrollEventThrottle={16}
|
|
314
301
|
{...scrollViewExtraProps}
|
|
315
|
-
/* When wrapped in a parent ScrollView (e.g. tabs),
|
|
316
|
-
this FlatList doesn't scroll so onEndReached can fire repeatedly;
|
|
317
|
-
skip it here and let the parent ScrollView emit scroll-end instead. */
|
|
318
302
|
onEndReached={
|
|
303
|
+
/* When wrapped in a parent ScrollView (e.g. tabs),
|
|
304
|
+
this FlatList doesn't scroll so onEndReached can fire repeatedly;
|
|
305
|
+
skip it here and let the parent ScrollView emit scroll-end instead. */
|
|
319
306
|
isScreenWrappedInContainer
|
|
320
307
|
? undefined
|
|
321
308
|
: () => {
|
|
@@ -4,9 +4,7 @@ import {
|
|
|
4
4
|
RefreshControl as RNRefreshControl,
|
|
5
5
|
StyleSheet,
|
|
6
6
|
} from "react-native";
|
|
7
|
-
import
|
|
8
|
-
import { path } from "@applicaster/zapp-react-native-utils/utils";
|
|
9
|
-
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
7
|
+
import { get } from "@applicaster/zapp-react-native-utils/utils";
|
|
10
8
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
11
9
|
import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
12
10
|
import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
@@ -15,8 +13,7 @@ import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/react
|
|
|
15
13
|
import { useShallow } from "zustand/react/shallow";
|
|
16
14
|
import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
17
15
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
18
|
-
import {
|
|
19
|
-
import { useGetUrlInflater } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl";
|
|
16
|
+
import { usePullToRefresh } from "./hooks";
|
|
20
17
|
|
|
21
18
|
const BRIGHTNESS_THRESHOLD = 160;
|
|
22
19
|
const ABOVE_DEFAULT_COLOR = "gray";
|
|
@@ -56,82 +53,6 @@ const getBrightness = (RGBcolor) => {
|
|
|
56
53
|
);
|
|
57
54
|
};
|
|
58
55
|
|
|
59
|
-
export const usePullToRefresh = (
|
|
60
|
-
riverComponents,
|
|
61
|
-
pullToRefreshPipesV1RefreshingStateUpdater,
|
|
62
|
-
refreshingPipesV1
|
|
63
|
-
) => {
|
|
64
|
-
const isPipesV1 = !!pullToRefreshPipesV1RefreshingStateUpdater;
|
|
65
|
-
|
|
66
|
-
const [refreshing, setRefreshing] = React.useState(false);
|
|
67
|
-
|
|
68
|
-
const feedSources = React.useMemo(
|
|
69
|
-
() =>
|
|
70
|
-
(riverComponents || [])
|
|
71
|
-
.map((riverComponent) => ({
|
|
72
|
-
source: path(["data", "source"], riverComponent),
|
|
73
|
-
mapping: path(["data", "mapping"], riverComponent),
|
|
74
|
-
}))
|
|
75
|
-
.filter(({ source }) => !isNilOrEmpty(source)),
|
|
76
|
-
[riverComponents]
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const feedsLength = feedSources.length;
|
|
80
|
-
|
|
81
|
-
const [requestsCompletedCounter, setRequestsCompletedCounter] =
|
|
82
|
-
React.useState(0);
|
|
83
|
-
|
|
84
|
-
const loadPipesDataDispatcher = useLoadPipesDataDispatch();
|
|
85
|
-
const urlInflater = useGetUrlInflater();
|
|
86
|
-
|
|
87
|
-
React.useEffect(() => {
|
|
88
|
-
// will not work for pipes v1 on 1st level screens
|
|
89
|
-
if (refreshing && !isPipesV1) {
|
|
90
|
-
feedSources.forEach(({ source, mapping }) => {
|
|
91
|
-
const inflatedUrl = urlInflater(source, mapping);
|
|
92
|
-
|
|
93
|
-
if (inflatedUrl) {
|
|
94
|
-
loadPipesDataDispatcher(inflatedUrl, {
|
|
95
|
-
silentRefresh: true,
|
|
96
|
-
clearCache: true,
|
|
97
|
-
callback: () => {
|
|
98
|
-
setRequestsCompletedCounter(R.inc);
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
} else {
|
|
102
|
-
setRequestsCompletedCounter(R.inc);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}, [
|
|
107
|
-
refreshing,
|
|
108
|
-
isPipesV1,
|
|
109
|
-
feedSources,
|
|
110
|
-
loadPipesDataDispatcher,
|
|
111
|
-
urlInflater,
|
|
112
|
-
]);
|
|
113
|
-
|
|
114
|
-
React.useEffect(() => {
|
|
115
|
-
if (requestsCompletedCounter === feedsLength) {
|
|
116
|
-
setRefreshing(false);
|
|
117
|
-
}
|
|
118
|
-
}, [requestsCompletedCounter, feedsLength]);
|
|
119
|
-
|
|
120
|
-
const onRefresh = React.useCallback(() => {
|
|
121
|
-
if (isPipesV1) {
|
|
122
|
-
pullToRefreshPipesV1RefreshingStateUpdater(true);
|
|
123
|
-
} else {
|
|
124
|
-
setRefreshing(true);
|
|
125
|
-
setRequestsCompletedCounter(0);
|
|
126
|
-
}
|
|
127
|
-
}, [isPipesV1]);
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
refreshing: isPipesV1 ? refreshingPipesV1 : refreshing,
|
|
131
|
-
onRefresh,
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
|
|
135
56
|
/** Returns the offset for the progress view of the RefreshControl component
|
|
136
57
|
* based on navbar content position */
|
|
137
58
|
export const useGetProgressViewOffset = () => {
|
|
@@ -160,16 +81,12 @@ export const useGetProgressViewOffset = () => {
|
|
|
160
81
|
}
|
|
161
82
|
};
|
|
162
83
|
|
|
163
|
-
export function RefreshControl(props
|
|
164
|
-
pullToRefreshPipesV1RefreshingStateUpdater?: (refreshing: boolean) => void;
|
|
165
|
-
refreshingPipesV1?: boolean;
|
|
166
|
-
}) {
|
|
84
|
+
export function RefreshControl(props) {
|
|
167
85
|
const screenData = useCurrentScreenData();
|
|
168
86
|
|
|
169
87
|
const { refreshing, onRefresh } = usePullToRefresh(
|
|
170
|
-
screenData.
|
|
171
|
-
|
|
172
|
-
props.refreshingPipesV1
|
|
88
|
+
screenData.id,
|
|
89
|
+
screenData.ui_components
|
|
173
90
|
);
|
|
174
91
|
|
|
175
92
|
const { app_background_color: themeBackgroundColor } = useTheme();
|
|
@@ -187,29 +104,26 @@ export function RefreshControl(props: {
|
|
|
187
104
|
displayTitleIOS,
|
|
188
105
|
} = React.useMemo(
|
|
189
106
|
() => ({
|
|
190
|
-
indicatorColor:
|
|
191
|
-
|
|
192
|
-
screenData.styles
|
|
193
|
-
|
|
194
|
-
titleUnderIndicatorColor: R.prop(
|
|
195
|
-
"pull_to_refresh_title_color_under_indicator",
|
|
196
|
-
screenData.styles
|
|
107
|
+
indicatorColor: get(screenData.styles, "pull_to_refresh_indicator_color"),
|
|
108
|
+
titleUnderIndicatorColor: get(
|
|
109
|
+
screenData.styles,
|
|
110
|
+
"pull_to_refresh_title_color_under_indicator"
|
|
197
111
|
),
|
|
198
|
-
indicatorBackgroundColor:
|
|
199
|
-
|
|
200
|
-
|
|
112
|
+
indicatorBackgroundColor: get(
|
|
113
|
+
screenData.styles,
|
|
114
|
+
"pull_to_refresh_indicator_bg_color"
|
|
201
115
|
),
|
|
202
116
|
indicatorSize:
|
|
203
|
-
|
|
117
|
+
get(screenData.styles, "pull_to_refresh_indicator_size") === "large"
|
|
204
118
|
? "large"
|
|
205
119
|
: "default",
|
|
206
|
-
generalContentBackgroungColor:
|
|
207
|
-
|
|
208
|
-
|
|
120
|
+
generalContentBackgroungColor: get(
|
|
121
|
+
screenData.styles,
|
|
122
|
+
"screen_background_color"
|
|
209
123
|
),
|
|
210
|
-
displayTitleIOS:
|
|
211
|
-
|
|
212
|
-
|
|
124
|
+
displayTitleIOS: get(
|
|
125
|
+
screenData.styles,
|
|
126
|
+
"pull_to_refresh_display_title_ios"
|
|
213
127
|
),
|
|
214
128
|
}),
|
|
215
129
|
[screenData]
|
|
@@ -2,7 +2,6 @@ import * as React from "react";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { GeneralContentScreen } from "@applicaster/zapp-react-native-ui-components/Components/GeneralContentScreen";
|
|
4
4
|
|
|
5
|
-
import { FeedLoader } from "../FeedLoader";
|
|
6
5
|
import { ScreenResolver } from "../ScreenResolver";
|
|
7
6
|
|
|
8
7
|
type Props = ZappScreenProps & {
|
|
@@ -23,24 +22,13 @@ type Props = ZappScreenProps & {
|
|
|
23
22
|
river: ZappRiver;
|
|
24
23
|
};
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
refreshing: boolean;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export class RiverComponent extends React.Component<Props, State> {
|
|
25
|
+
export class RiverComponent extends React.Component<Props> {
|
|
31
26
|
private currentScreenTitle: string;
|
|
32
27
|
private currentScreenSummary: string;
|
|
33
28
|
constructor(props: Props) {
|
|
34
29
|
super(props);
|
|
35
30
|
|
|
36
|
-
this.state = {
|
|
37
|
-
refreshing: false,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
31
|
this.applyContexts();
|
|
41
|
-
|
|
42
|
-
this.pullToRefreshPipesV1RefreshingStateUpdater =
|
|
43
|
-
this.pullToRefreshPipesV1RefreshingStateUpdater.bind(this);
|
|
44
32
|
}
|
|
45
33
|
|
|
46
34
|
applyContexts() {
|
|
@@ -69,20 +57,9 @@ export class RiverComponent extends React.Component<Props, State> {
|
|
|
69
57
|
}
|
|
70
58
|
}
|
|
71
59
|
|
|
72
|
-
usesPipesV1Layout() {
|
|
73
|
-
return this.props?.appData?.layoutVersion === "v1";
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Method added to keep pipes v1 logic up to date with the pullToRefresh state.
|
|
77
|
-
// TODO: Remove when pipes v1 is deprecated.
|
|
78
|
-
pullToRefreshPipesV1RefreshingStateUpdater(refreshing) {
|
|
79
|
-
this.setState({ refreshing });
|
|
80
|
-
}
|
|
81
|
-
|
|
82
60
|
render() {
|
|
83
61
|
const {
|
|
84
62
|
river,
|
|
85
|
-
feedUrl,
|
|
86
63
|
screenData,
|
|
87
64
|
isInsideContainer,
|
|
88
65
|
groupId,
|
|
@@ -91,22 +68,10 @@ export class RiverComponent extends React.Component<Props, State> {
|
|
|
91
68
|
|
|
92
69
|
const { id, type } = river;
|
|
93
70
|
|
|
94
|
-
const connectedFeedURL = R.path(["content", "src"], screenData);
|
|
95
|
-
const _feedUrl = feedUrl || connectedFeedURL;
|
|
96
|
-
|
|
97
71
|
if (type !== "general_content") {
|
|
98
|
-
let riverWithConnectedDatasource;
|
|
99
|
-
|
|
100
|
-
if (_feedUrl && this.usesPipesV1Layout()) {
|
|
101
|
-
riverWithConnectedDatasource = {
|
|
102
|
-
...river,
|
|
103
|
-
data: R.merge(river.data || {}, { source: _feedUrl }),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
72
|
return (
|
|
108
73
|
<ScreenResolver
|
|
109
|
-
screenData={R.mergeLeft(
|
|
74
|
+
screenData={R.mergeLeft(river, {
|
|
110
75
|
groupId,
|
|
111
76
|
...screenData,
|
|
112
77
|
})}
|
|
@@ -116,53 +81,15 @@ export class RiverComponent extends React.Component<Props, State> {
|
|
|
116
81
|
);
|
|
117
82
|
}
|
|
118
83
|
|
|
119
|
-
|
|
120
|
-
this.currentScreenTitle = (screenData && screenData.title) || null;
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<GeneralContentScreen
|
|
124
|
-
screenId={id}
|
|
125
|
-
isScreenWrappedInContainer={isInsideContainer}
|
|
126
|
-
groupId={groupId}
|
|
127
|
-
scrollViewExtraProps={scrollViewExtraProps}
|
|
128
|
-
/>
|
|
129
|
-
);
|
|
130
|
-
}
|
|
84
|
+
this.currentScreenTitle = (screenData && screenData.title) || null;
|
|
131
85
|
|
|
132
86
|
return (
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
>
|
|
140
|
-
{(feed) => {
|
|
141
|
-
if (!feed) {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this.currentScreenSummary = (feed && feed.summary) || null;
|
|
146
|
-
|
|
147
|
-
this.currentScreenTitle =
|
|
148
|
-
(feed && feed.title) || (screenData && screenData.title) || null;
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<GeneralContentScreen
|
|
152
|
-
screenId={id}
|
|
153
|
-
groupId={groupId}
|
|
154
|
-
feed={feed}
|
|
155
|
-
isScreenWrappedInContainer={isInsideContainer}
|
|
156
|
-
scrollViewExtraProps={scrollViewExtraProps}
|
|
157
|
-
componentsMapExtraProps={{
|
|
158
|
-
pullToRefreshPipesV1RefreshingStateUpdater:
|
|
159
|
-
this.pullToRefreshPipesV1RefreshingStateUpdater,
|
|
160
|
-
refreshingPipesV1: this.state.refreshing,
|
|
161
|
-
}}
|
|
162
|
-
/>
|
|
163
|
-
);
|
|
164
|
-
}}
|
|
165
|
-
</FeedLoader>
|
|
87
|
+
<GeneralContentScreen
|
|
88
|
+
screenId={id}
|
|
89
|
+
isScreenWrappedInContainer={isInsideContainer}
|
|
90
|
+
groupId={groupId}
|
|
91
|
+
scrollViewExtraProps={scrollViewExtraProps}
|
|
92
|
+
/>
|
|
166
93
|
);
|
|
167
94
|
}
|
|
168
95
|
}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Text } from "react-native";
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
import { mergeRight } from "@applicaster/zapp-react-native-utils/utils";
|
|
6
7
|
|
|
7
8
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
8
9
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
} from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
14
15
|
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
15
16
|
|
|
17
|
+
import { toStringOrEmpty } from "./utils";
|
|
18
|
+
|
|
16
19
|
type Props = {
|
|
17
20
|
screenId: string;
|
|
18
21
|
screenData: ZappRiver | ZappEntry;
|
|
@@ -24,6 +27,7 @@ type Props = {
|
|
|
24
27
|
isInsideContainer?: boolean;
|
|
25
28
|
extraAnchorPointYOffset: number;
|
|
26
29
|
river?: ZappRiver | ZappEntry;
|
|
30
|
+
groupId: string;
|
|
27
31
|
};
|
|
28
32
|
|
|
29
33
|
export const River = (props: Props) => {
|
|
@@ -35,6 +39,7 @@ export const River = (props: Props) => {
|
|
|
35
39
|
componentsMapExtraProps,
|
|
36
40
|
isInsideContainer,
|
|
37
41
|
extraAnchorPointYOffset,
|
|
42
|
+
groupId,
|
|
38
43
|
} = props;
|
|
39
44
|
|
|
40
45
|
const { title: screenTitle, summary: screenSummary } = useNavbarState();
|
|
@@ -51,28 +56,41 @@ export const River = (props: Props) => {
|
|
|
51
56
|
[screenId]
|
|
52
57
|
);
|
|
53
58
|
|
|
54
|
-
const
|
|
55
|
-
|
|
59
|
+
const screenResolverData = React.useMemo(() => {
|
|
60
|
+
const extraData = mergeRight(extraProps, screenResolverExtraProps);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
extraData,
|
|
64
|
+
screenData: mergeRight(river, { groupId: extraData?.groupId }),
|
|
65
|
+
componentsMapExtraProps: mergeRight(componentsMapExtraProps, { groupId }),
|
|
66
|
+
};
|
|
67
|
+
}, [
|
|
68
|
+
extraProps,
|
|
69
|
+
screenResolverExtraProps,
|
|
70
|
+
river,
|
|
71
|
+
componentsMapExtraProps,
|
|
72
|
+
groupId,
|
|
73
|
+
]);
|
|
56
74
|
|
|
57
75
|
React.useEffect(() => {
|
|
58
76
|
if (!isInsideContainer) {
|
|
59
|
-
setScreenTitle(
|
|
60
|
-
setScreenSummary(
|
|
77
|
+
setScreenTitle(toStringOrEmpty(screenData?.title));
|
|
78
|
+
setScreenSummary(toStringOrEmpty(screenData?.summary));
|
|
61
79
|
}
|
|
62
80
|
}, [screenData.id]);
|
|
63
81
|
|
|
64
82
|
React.useEffect(() => {
|
|
65
83
|
if (feedData && !isInsideContainer) {
|
|
66
84
|
if (feedData.title && feedData.title !== screenTitle) {
|
|
67
|
-
setScreenTitle(
|
|
85
|
+
setScreenTitle(toStringOrEmpty(feedData.title));
|
|
68
86
|
}
|
|
69
87
|
|
|
70
88
|
if (feedData.summary && feedData.summary !== screenSummary) {
|
|
71
|
-
setScreenSummary(
|
|
89
|
+
setScreenSummary(toStringOrEmpty(feedData.summary));
|
|
72
90
|
}
|
|
73
91
|
} else {
|
|
74
|
-
setScreenTitle(
|
|
75
|
-
setScreenSummary(
|
|
92
|
+
setScreenTitle(toStringOrEmpty(screenData?.title));
|
|
93
|
+
setScreenSummary(toStringOrEmpty(screenData?.summary));
|
|
76
94
|
}
|
|
77
95
|
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
78
96
|
|
|
@@ -86,15 +104,13 @@ export const River = (props: Props) => {
|
|
|
86
104
|
}
|
|
87
105
|
|
|
88
106
|
if (river.type !== "general_content") {
|
|
89
|
-
const extraData = { ...R.mergeRight(extraProps, screenResolverExtraProps) };
|
|
90
|
-
|
|
91
107
|
return (
|
|
92
108
|
<ScreenResolver
|
|
93
109
|
screenType={river.type}
|
|
94
110
|
screenId={screenId}
|
|
95
|
-
screenData={
|
|
96
|
-
componentsMapExtraProps={componentsMapExtraProps}
|
|
97
|
-
{...extraData}
|
|
111
|
+
screenData={screenResolverData.screenData}
|
|
112
|
+
componentsMapExtraProps={screenResolverData.componentsMapExtraProps}
|
|
113
|
+
{...screenResolverData.extraData}
|
|
98
114
|
/>
|
|
99
115
|
);
|
|
100
116
|
}
|
|
@@ -106,6 +122,7 @@ export const River = (props: Props) => {
|
|
|
106
122
|
isScreenWrappedInContainer={isInsideContainer}
|
|
107
123
|
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
108
124
|
componentsMapExtraProps={componentsMapExtraProps}
|
|
125
|
+
groupId={groupId}
|
|
109
126
|
/>
|
|
110
127
|
);
|
|
111
128
|
};
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { compose } from "
|
|
1
|
+
import { compose, identity } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
+
|
|
2
4
|
import { River as RiverComponent } from "./River";
|
|
3
|
-
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
5
|
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
5
6
|
import { withRiverDataLoader } from "./withRiverDataLoader";
|
|
7
|
+
import { withFocusableGroupForContent } from "./withFocusableGroupForContent";
|
|
8
|
+
|
|
9
|
+
const isTVOS = isTvOSPlatform();
|
|
6
10
|
|
|
7
11
|
export const River = compose(
|
|
8
|
-
withTvEventHandler,
|
|
9
12
|
withComponentsMapOffsetContext,
|
|
10
|
-
withRiverDataLoader
|
|
13
|
+
withRiverDataLoader,
|
|
14
|
+
isTVOS ? withFocusableGroupForContent : identity
|
|
11
15
|
)(RiverComponent);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { toStringOrEmpty } from "..";
|
|
2
|
+
|
|
3
|
+
describe("toStringOrEmpty", () => {
|
|
4
|
+
test("returns empty string for undefined", () => {
|
|
5
|
+
expect(toStringOrEmpty(undefined)).toBe("");
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test("returns empty string for null", () => {
|
|
9
|
+
expect(toStringOrEmpty(null)).toBe("");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("converts number to string", () => {
|
|
13
|
+
expect(toStringOrEmpty(0)).toBe("0");
|
|
14
|
+
expect(toStringOrEmpty(123)).toBe("123");
|
|
15
|
+
expect(toStringOrEmpty(-42)).toBe("-42");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("returns string as is", () => {
|
|
19
|
+
expect(toStringOrEmpty("hello")).toBe("hello");
|
|
20
|
+
expect(toStringOrEmpty("")).toBe("");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("works with numeric strings", () => {
|
|
24
|
+
expect(toStringOrEmpty("123")).toBe("123");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("does not throw on falsy values like 0", () => {
|
|
28
|
+
expect(toStringOrEmpty(0)).toBe("0");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
|
|
5
|
+
import { riverFocusManager } from "@applicaster/zapp-react-native-utils/appUtils/RiverFocusManager";
|
|
6
|
+
|
|
7
|
+
import { topMenuLayoutChange$ } from "@applicaster/zapp-react-native-tvos-app/Layout/topMenu";
|
|
8
|
+
|
|
9
|
+
const styles = StyleSheet.create({
|
|
10
|
+
flexOne: {
|
|
11
|
+
flex: 1,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const withFocusableGroupForContent = (Component) => {
|
|
16
|
+
return function WithFocusableGroupForContent(props) {
|
|
17
|
+
const { screenId, isInsideContainer } = props;
|
|
18
|
+
|
|
19
|
+
const [topMenuHeight, setTopMenuHeight] = React.useState(0);
|
|
20
|
+
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
const subscription = topMenuLayoutChange$.subscribe((layout) => {
|
|
23
|
+
setTopMenuHeight(layout.height);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
subscription.unsubscribe();
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const focusableId = React.useMemo(
|
|
32
|
+
() =>
|
|
33
|
+
riverFocusManager.screenFocusableGroupId({
|
|
34
|
+
screenId,
|
|
35
|
+
isInsideContainer,
|
|
36
|
+
}),
|
|
37
|
+
[screenId, isInsideContainer]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (isInsideContainer) {
|
|
41
|
+
return <Component {...props} />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<FocusableGroup
|
|
46
|
+
key={focusableId}
|
|
47
|
+
id={focusableId}
|
|
48
|
+
// The top menu is rendered in its own FocusableGroup, anchored at the top of the screen.
|
|
49
|
+
// When the "content" FocusableGroup starts at y = 0 as well, the two groups visually overlap.
|
|
50
|
+
// On TvOS platform this overlap can confuse the focus engine, because the focusable bounds of
|
|
51
|
+
// the top-menu group and the content group intersect, leading to erratic navigation between
|
|
52
|
+
// the menu and the content (e.g. unexpected jumps or focus getting "stuck").
|
|
53
|
+
//
|
|
54
|
+
// To avoid this, we shift the entire content FocusableGroup down by the dynamic top menu
|
|
55
|
+
// height (marginTop: topMenuHeight). This separates the focus regions of the two groups in
|
|
56
|
+
// focus space, so they no longer intersect.
|
|
57
|
+
//
|
|
58
|
+
// The inner <View> below then applies the inverse margin (marginTop: -topMenuHeight) so that
|
|
59
|
+
// the actual visual position of the content on screen does not change; only the focusable
|
|
60
|
+
// bounds of the outer group are offset.
|
|
61
|
+
style={[styles.flexOne, { marginTop: topMenuHeight }]}
|
|
62
|
+
// this group does not have parent
|
|
63
|
+
groupId={undefined}
|
|
64
|
+
>
|
|
65
|
+
<View style={[styles.flexOne, { marginTop: -1 * topMenuHeight }]}>
|
|
66
|
+
<Component {...props} groupId={focusableId} />
|
|
67
|
+
</View>
|
|
68
|
+
</FocusableGroup>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
};
|
|
@@ -10,6 +10,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
10
10
|
>
|
|
11
11
|
<View
|
|
12
12
|
onLayout={[Function]}
|
|
13
|
+
style={{}}
|
|
13
14
|
>
|
|
14
15
|
<RCTScrollView
|
|
15
16
|
ListFooterComponent={
|
|
@@ -150,6 +151,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
stickyHeaderIndices={[]}
|
|
154
|
+
testID="components-map-flat-list"
|
|
153
155
|
viewabilityConfigCallbackPairs={[]}
|
|
154
156
|
windowSize={12}
|
|
155
157
|
>
|
|
@@ -161,6 +163,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
161
163
|
>
|
|
162
164
|
<View
|
|
163
165
|
onLayout={[Function]}
|
|
166
|
+
style={{}}
|
|
164
167
|
>
|
|
165
168
|
<View />
|
|
166
169
|
</View>
|
|
@@ -172,6 +175,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
172
175
|
>
|
|
173
176
|
<View
|
|
174
177
|
onLayout={[Function]}
|
|
178
|
+
style={{}}
|
|
175
179
|
/>
|
|
176
180
|
</View>
|
|
177
181
|
<View
|