@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5353184830 → 12.0.0-alpha.5367216235
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/AudioPlayer/AudioPlayer.tsx +9 -1
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/BaseFocusable/index.tsx +3 -3
- package/Components/Cell/Cell.tsx +32 -11
- package/Components/Cell/CellWithFocusable.tsx +40 -19
- package/Components/Cell/TvOSCellComponent.tsx +5 -9
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableCell/index.tsx +7 -7
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/FocusableList/FocusableChild.ts +24 -14
- package/Components/FocusableList/FocusableItem.tsx +1 -1
- package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
- package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
- package/Components/FocusableList/index.tsx +26 -25
- package/Components/FreezeWithCallback/Freeze.tsx +31 -0
- package/Components/FreezeWithCallback/LICENSE +21 -0
- package/Components/FreezeWithCallback/Suspender.tsx +17 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
- package/Components/FreezeWithCallback/index.tsx +3 -0
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
- package/Components/HookRenderer/index.tsx +1 -6
- package/Components/Image/Image.android.tsx +3 -26
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +39 -0
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +20 -108
- package/Components/Layout/TV/index.tsx +15 -84
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -117
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +37 -2
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +33 -35
- package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
- package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
- package/Components/ModalComponent/Button/Item.tsx +82 -0
- package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
- package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
- package/Components/ModalComponent/Button/assets.ts +4 -0
- package/Components/ModalComponent/Button/index.tsx +111 -0
- package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
- package/Components/ModalComponent/Header/Title.tsx +70 -0
- package/Components/ModalComponent/Header/assets.ts +4 -0
- package/Components/ModalComponent/Header/index.tsx +71 -0
- package/Components/ModalComponent/Header/utils.ts +79 -0
- package/Components/ModalComponent/index.tsx +38 -0
- package/Components/ModalComponent/utils.ts +126 -0
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +66 -31
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
- package/Components/River/RefreshControl.tsx +55 -1
- package/Components/River/River.tsx +8 -5
- package/Components/River/TV/River.tsx +2 -25
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
- package/Components/River/__tests__/componentsMap.test.js +7 -0
- package/Components/River/useScreenConfiguration.ts +5 -6
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
- package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
- package/Components/RouteManager/index.tsx +4 -2
- package/Components/Screen/TV/hooks/index.ts +1 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/index.web.tsx +178 -0
- package/Components/Screen/__tests__/Screen.test.tsx +57 -102
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
- package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
- package/Components/Screen/index.tsx +104 -66
- package/Components/Screen/navigationHandler.ts +6 -85
- package/Components/Screen/orientationHandler.ts +18 -7
- package/Components/Screen/utils.ts +16 -0
- package/Components/ScreenResolver/index.tsx +10 -13
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/TrackedView/index.tsx +6 -3
- package/Components/Transitioner/Scene.tsx +39 -26
- package/Components/Transitioner/Transitioner.tsx +46 -48
- package/Components/Transitioner/__tests__/Scene.test.js +7 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
- package/Components/VideoLive/LiveImageManager.ts +70 -14
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +132 -95
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +21 -29
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +66 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +376 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +473 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
- package/Components/VideoModal/PlayerDetails.tsx +6 -3
- package/Components/VideoModal/PlayerWrapper.tsx +81 -49
- package/Components/VideoModal/VideoModal.tsx +23 -40
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +312 -166
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +8 -5
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
- package/Components/Viewport/ViewportTracker/index.tsx +1 -0
- package/Components/Viewport/utils.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
- package/Components/ZappUIComponent/index.tsx +22 -12
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
- package/Components/index.js +2 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
- package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
- package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
- package/Contexts/ScreenContext/index.tsx +95 -29
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/Decorators/RiverResolver/index.tsx +0 -4
- package/Decorators/index.tsx +0 -4
- package/events/index.ts +1 -0
- package/package.json +5 -6
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -23,6 +23,7 @@ type Props = {
|
|
|
23
23
|
audio_player_summary_color?: string;
|
|
24
24
|
audio_player_rtl?: boolean;
|
|
25
25
|
magic_background?: boolean;
|
|
26
|
+
audio_player_background_image_query?: string;
|
|
26
27
|
start_time?: string;
|
|
27
28
|
end_time?: string;
|
|
28
29
|
};
|
|
@@ -33,6 +34,7 @@ type Props = {
|
|
|
33
34
|
audio_player_summary_color?: string;
|
|
34
35
|
audio_player_rtl?: string;
|
|
35
36
|
magic_background?: string;
|
|
37
|
+
audio_player_background_image_query?: string;
|
|
36
38
|
audio_player_background_image?: string;
|
|
37
39
|
audio_player_artwork_aspect_ratio?: string;
|
|
38
40
|
lg_tv_audio_player_title_font_family?: string;
|
|
@@ -73,6 +75,11 @@ export function AudioPlayer(props: Props) {
|
|
|
73
75
|
const channelIcon = getProp("audio_player_channel_icon");
|
|
74
76
|
const rtlFlag = getProp("audio_player_rtl");
|
|
75
77
|
const magicBackground = getProp("magic_background");
|
|
78
|
+
|
|
79
|
+
const audioPlayerBackgroundImageQuery = getProp(
|
|
80
|
+
"audio_player_background_image_query"
|
|
81
|
+
);
|
|
82
|
+
|
|
76
83
|
const isRTL = rtlFlag === "1" || rtlFlag === "true" || rtlFlag === true;
|
|
77
84
|
|
|
78
85
|
const titleFontFamily = getProp(
|
|
@@ -149,7 +156,8 @@ export function AudioPlayer(props: Props) {
|
|
|
149
156
|
runTimeFontSize,
|
|
150
157
|
artworkAspectRatio,
|
|
151
158
|
channelIcon,
|
|
152
|
-
magicBackground
|
|
159
|
+
magicBackground,
|
|
160
|
+
audioPlayerBackgroundImageQuery,
|
|
153
161
|
};
|
|
154
162
|
}, [getProp]);
|
|
155
163
|
|
|
@@ -5,6 +5,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
5
5
|
config={
|
|
6
6
|
Object {
|
|
7
7
|
"artworkAspectRatio": "1:1",
|
|
8
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
8
9
|
"backgroundColor": "black",
|
|
9
10
|
"backgroundImage": "https://example.com",
|
|
10
11
|
"channelIcon": "https://example.com",
|
|
@@ -26,6 +27,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
26
27
|
config={
|
|
27
28
|
Object {
|
|
28
29
|
"artworkAspectRatio": "1:1",
|
|
30
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
29
31
|
"backgroundColor": "black",
|
|
30
32
|
"backgroundImage": "https://example.com",
|
|
31
33
|
"channelIcon": "https://example.com",
|
|
@@ -47,6 +49,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
47
49
|
config={
|
|
48
50
|
Object {
|
|
49
51
|
"artworkAspectRatio": "1:1",
|
|
52
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
50
53
|
"backgroundColor": "black",
|
|
51
54
|
"backgroundImage": "https://example.com",
|
|
52
55
|
"channelIcon": "https://example.com",
|
|
@@ -68,6 +71,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
68
71
|
config={
|
|
69
72
|
Object {
|
|
70
73
|
"artworkAspectRatio": "1:1",
|
|
74
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
71
75
|
"backgroundColor": "black",
|
|
72
76
|
"backgroundImage": "https://example.com",
|
|
73
77
|
"channelIcon": "https://example.com",
|
|
@@ -96,6 +100,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
96
100
|
config={
|
|
97
101
|
Object {
|
|
98
102
|
"artworkAspectRatio": "1:1",
|
|
103
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
99
104
|
"backgroundColor": "black",
|
|
100
105
|
"backgroundImage": "https://example.com",
|
|
101
106
|
"channelIcon": "https://example.com",
|
|
@@ -66,14 +66,14 @@ export class BaseFocusable<
|
|
|
66
66
|
const { initialFocus } = this.props;
|
|
67
67
|
|
|
68
68
|
if (initialFocus) {
|
|
69
|
-
focusManager.
|
|
69
|
+
focusManager.setFocus(this.getId());
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
getId(props?: { id: string; groupId: string }) {
|
|
74
|
-
const { id
|
|
74
|
+
const { id } = props || this.props;
|
|
75
75
|
|
|
76
|
-
return
|
|
76
|
+
return id;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
getRect() {
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { join, merge, path } from "ramda";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
|
|
5
5
|
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
@@ -11,6 +11,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
11
11
|
|
|
12
12
|
import { CellWithFocusable } from "./CellWithFocusable";
|
|
13
13
|
import { BaseFocusable } from "../BaseFocusable";
|
|
14
|
+
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
14
15
|
|
|
15
16
|
type Props = {
|
|
16
17
|
item: {
|
|
@@ -66,6 +67,10 @@ type Props = {
|
|
|
66
67
|
behavior: Behavior;
|
|
67
68
|
};
|
|
68
69
|
|
|
70
|
+
type State = {
|
|
71
|
+
hasFocusableInside: boolean;
|
|
72
|
+
};
|
|
73
|
+
|
|
69
74
|
const baseCellStyles = {
|
|
70
75
|
height: "100%",
|
|
71
76
|
display: "flex",
|
|
@@ -77,7 +82,7 @@ const touchableStyles = {
|
|
|
77
82
|
height: "100%",
|
|
78
83
|
} as const;
|
|
79
84
|
|
|
80
|
-
export class CellComponent extends React.Component<Props> {
|
|
85
|
+
export class CellComponent extends React.Component<Props, State> {
|
|
81
86
|
constructor(props) {
|
|
82
87
|
super(props);
|
|
83
88
|
this.onPress = this.onPress.bind(this);
|
|
@@ -87,6 +92,10 @@ export class CellComponent extends React.Component<Props> {
|
|
|
87
92
|
this.hasReceivedFocus = this.hasReceivedFocus.bind(this);
|
|
88
93
|
this.scrollVertically = this.scrollVertically.bind(this);
|
|
89
94
|
this.scrollToIndex = this.scrollToIndex.bind(this);
|
|
95
|
+
|
|
96
|
+
this.state = {
|
|
97
|
+
hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
|
|
98
|
+
};
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
setScreenLayout(componentAnchorPointY, screenLayout) {
|
|
@@ -105,8 +114,8 @@ export class CellComponent extends React.Component<Props> {
|
|
|
105
114
|
onPress(item, index);
|
|
106
115
|
} else {
|
|
107
116
|
const { item, navigator, component, appData } = this.props;
|
|
108
|
-
const itemTargetScreen =
|
|
109
|
-
const componentTargetScreen =
|
|
117
|
+
const itemTargetScreen = path(["screen_type"], item);
|
|
118
|
+
const componentTargetScreen = path(["data", "target"], component);
|
|
110
119
|
const itemType = getItemType(item, appData?.layoutVersion);
|
|
111
120
|
|
|
112
121
|
sendSelectCellEvent(item, component, item.title, index);
|
|
@@ -116,7 +125,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
116
125
|
componentTargetScreen &&
|
|
117
126
|
!itemTargetScreen
|
|
118
127
|
) {
|
|
119
|
-
navigator.push(
|
|
128
|
+
navigator.push(merge(item, { screen_type: componentTargetScreen }));
|
|
120
129
|
|
|
121
130
|
return;
|
|
122
131
|
}
|
|
@@ -139,6 +148,10 @@ export class CellComponent extends React.Component<Props> {
|
|
|
139
148
|
shouldScrollVertically?.(mouse, focusable, id, title)
|
|
140
149
|
) {
|
|
141
150
|
this.scrollVertically(focusable);
|
|
151
|
+
|
|
152
|
+
const accessibilityManager = AccessibilityManager.getInstance();
|
|
153
|
+
// Text from DSP should be localized already
|
|
154
|
+
accessibilityManager.readText({ text: title });
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
157
|
}
|
|
@@ -187,6 +200,16 @@ export class CellComponent extends React.Component<Props> {
|
|
|
187
200
|
return !isFocusable ? false : focused || focusableFocused;
|
|
188
201
|
}
|
|
189
202
|
|
|
203
|
+
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
204
|
+
if (prevProps.item !== this.props.item) {
|
|
205
|
+
this.setState({
|
|
206
|
+
hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
|
|
207
|
+
this.props.item
|
|
208
|
+
),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
190
213
|
render() {
|
|
191
214
|
const {
|
|
192
215
|
item,
|
|
@@ -202,12 +225,12 @@ export class CellComponent extends React.Component<Props> {
|
|
|
202
225
|
groupId,
|
|
203
226
|
isFocusable = true,
|
|
204
227
|
skipFocusManagerRegistration,
|
|
205
|
-
behavior
|
|
228
|
+
behavior,
|
|
206
229
|
} = this.props;
|
|
207
230
|
|
|
208
231
|
const { id } = item;
|
|
209
232
|
|
|
210
|
-
const focusableId =
|
|
233
|
+
const focusableId = join("-", [component?.id, id, index]);
|
|
211
234
|
|
|
212
235
|
const handleFocus = (focusable, mouse) => {
|
|
213
236
|
const focusFn = onFocus || noop;
|
|
@@ -215,9 +238,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
215
238
|
this.onFocus(focusable, mouse);
|
|
216
239
|
};
|
|
217
240
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (hasFocusableInside) {
|
|
241
|
+
if (this.state.hasFocusableInside) {
|
|
221
242
|
return (
|
|
222
243
|
<CellWithFocusable
|
|
223
244
|
CellRenderer={CellRenderer}
|
|
@@ -263,7 +284,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
263
284
|
item,
|
|
264
285
|
focused: this.isCellFocused(focused),
|
|
265
286
|
scrollTo: this.scrollToIndex(event),
|
|
266
|
-
behavior
|
|
287
|
+
behavior,
|
|
267
288
|
}}
|
|
268
289
|
/>
|
|
269
290
|
);
|
|
@@ -3,15 +3,25 @@ import * as React from "react";
|
|
|
3
3
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
4
4
|
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
5
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
+
|
|
6
8
|
import { isAppleTV } from "../../Helpers/Platform";
|
|
7
9
|
import { useCellState } from "../MasterCell/utils";
|
|
8
10
|
|
|
9
|
-
const useCellFocusedState = (
|
|
11
|
+
const useCellFocusedState = (
|
|
12
|
+
skipFocusManagerRegistration: boolean,
|
|
13
|
+
groupId: string,
|
|
14
|
+
id: string
|
|
15
|
+
) => {
|
|
10
16
|
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
11
17
|
|
|
12
18
|
React.useEffect(() => {
|
|
13
|
-
const isGroupItemFocused = () =>
|
|
14
|
-
|
|
19
|
+
const isGroupItemFocused = () => {
|
|
20
|
+
if (!skipFocusManagerRegistration) {
|
|
21
|
+
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
22
|
+
setCurrentCellFocused(isFocused);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
15
25
|
|
|
16
26
|
const handler = () => {
|
|
17
27
|
// tvOS hack for properly checking focus
|
|
@@ -29,24 +39,24 @@ const useCellFocusedState = (groupId: string, id: string) => {
|
|
|
29
39
|
return () => {
|
|
30
40
|
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
31
41
|
};
|
|
32
|
-
}, [groupId]);
|
|
42
|
+
}, [groupId, skipFocusManagerRegistration]);
|
|
33
43
|
|
|
34
44
|
return currentCellFocused;
|
|
35
45
|
};
|
|
36
46
|
|
|
37
47
|
type Props = {
|
|
38
|
-
item: ZappEntry
|
|
39
|
-
CellRenderer: React.ComponentType<{ item: Object
|
|
40
|
-
id: string
|
|
41
|
-
groupId: string
|
|
42
|
-
onFocus: Function
|
|
43
|
-
index: number
|
|
44
|
-
scrollTo: Function
|
|
45
|
-
preferredFocus?: boolean
|
|
46
|
-
skipFocusManagerRegistration?: boolean
|
|
47
|
-
isFocusable?: boolean
|
|
48
|
-
behavior: Behavior
|
|
49
|
-
|
|
48
|
+
item: ZappEntry;
|
|
49
|
+
CellRenderer: React.ComponentType<{ item: Object; state: string }>;
|
|
50
|
+
id: string;
|
|
51
|
+
groupId: string;
|
|
52
|
+
onFocus: Function;
|
|
53
|
+
index: number;
|
|
54
|
+
scrollTo: Function;
|
|
55
|
+
preferredFocus?: boolean;
|
|
56
|
+
skipFocusManagerRegistration?: boolean;
|
|
57
|
+
isFocusable?: boolean;
|
|
58
|
+
behavior: Behavior;
|
|
59
|
+
focused?: boolean;
|
|
50
60
|
};
|
|
51
61
|
|
|
52
62
|
export function CellWithFocusable(props: Props) {
|
|
@@ -62,11 +72,21 @@ export function CellWithFocusable(props: Props) {
|
|
|
62
72
|
skipFocusManagerRegistration,
|
|
63
73
|
isFocusable,
|
|
64
74
|
behavior,
|
|
65
|
-
|
|
75
|
+
focused,
|
|
66
76
|
} = props;
|
|
67
77
|
|
|
68
|
-
const isFocused = useCellFocusedState(
|
|
69
|
-
|
|
78
|
+
const isFocused = useCellFocusedState(
|
|
79
|
+
skipFocusManagerRegistration,
|
|
80
|
+
groupId,
|
|
81
|
+
id
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const state = useCellState({
|
|
85
|
+
id: item.id,
|
|
86
|
+
behavior,
|
|
87
|
+
focused: isFocused || toBooleanWithDefaultFalse(focused),
|
|
88
|
+
});
|
|
89
|
+
|
|
70
90
|
const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
|
|
71
91
|
|
|
72
92
|
// for horizontal scrolling
|
|
@@ -95,6 +115,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
95
115
|
preferredFocus={preferredFocus}
|
|
96
116
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
97
117
|
isFocusable={isFocusable}
|
|
118
|
+
focused={focused}
|
|
98
119
|
/>
|
|
99
120
|
);
|
|
100
121
|
}
|
|
@@ -226,13 +226,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
226
226
|
|
|
227
227
|
hasReceivedFocus() {}
|
|
228
228
|
|
|
229
|
-
scrollTo(
|
|
230
|
-
// Workaround for HL autoscroll/autoloop feature, we scroll manually on tvOS.
|
|
231
|
-
// Should be removed after refactoring autoscroll/autoloop feature
|
|
232
|
-
if (this.props.component?.component_type !== "horizontal_list_qb") {
|
|
233
|
-
this.props?.scrollToIndex?.(index);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
229
|
+
scrollTo() {}
|
|
236
230
|
|
|
237
231
|
render() {
|
|
238
232
|
const {
|
|
@@ -249,7 +243,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
249
243
|
hasReceivedFocus,
|
|
250
244
|
groupId,
|
|
251
245
|
isFocusable,
|
|
252
|
-
behavior
|
|
246
|
+
behavior,
|
|
253
247
|
} = this.props;
|
|
254
248
|
|
|
255
249
|
const { id } = item;
|
|
@@ -279,7 +273,9 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
279
273
|
index={index}
|
|
280
274
|
scrollTo={this.scrollTo}
|
|
281
275
|
preferredFocus={preferredFocus}
|
|
276
|
+
focused={this.props.focused}
|
|
282
277
|
behavior={behavior}
|
|
278
|
+
isFocusable={isFocusable}
|
|
283
279
|
/>
|
|
284
280
|
</View>
|
|
285
281
|
);
|
|
@@ -310,7 +306,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
310
306
|
item,
|
|
311
307
|
focused: this.props.focused || selectedCell || focused,
|
|
312
308
|
scrollTo: this.scrollTo,
|
|
313
|
-
behavior
|
|
309
|
+
behavior,
|
|
314
310
|
}}
|
|
315
311
|
/>
|
|
316
312
|
);
|
|
@@ -3,7 +3,6 @@ import * as R from "ramda";
|
|
|
3
3
|
import {
|
|
4
4
|
View,
|
|
5
5
|
StyleSheet,
|
|
6
|
-
Image,
|
|
7
6
|
Text,
|
|
8
7
|
ViewStyle,
|
|
9
8
|
TextStyle,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { defaultAsset } from "./defaultAsset";
|
|
14
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
15
14
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
15
|
+
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
16
16
|
import { Button } from "./Button";
|
|
17
17
|
|
|
18
18
|
type ButtonProp = {
|
|
@@ -4,6 +4,7 @@ import * as R from "ramda";
|
|
|
4
4
|
import { BaseFocusable } from "../BaseFocusable";
|
|
5
5
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
6
6
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
7
|
+
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
initialFocus?: boolean;
|
|
@@ -23,7 +24,7 @@ type Props = {
|
|
|
23
24
|
style?: React.CSSProperties;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
class Focusable extends BaseFocusable<Props> {
|
|
27
28
|
isGroup: boolean;
|
|
28
29
|
mouse: boolean;
|
|
29
30
|
longPressTimeout = null;
|
|
@@ -198,3 +199,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
198
199
|
);
|
|
199
200
|
}
|
|
200
201
|
}
|
|
202
|
+
|
|
203
|
+
const FocusableWithFocusableContext = withFocusableContext(Focusable);
|
|
204
|
+
|
|
205
|
+
export { FocusableWithFocusableContext as Focusable };
|
|
@@ -3,12 +3,12 @@ import { Platform } from "react-native";
|
|
|
3
3
|
import { useCellState } from "../MasterCell/utils";
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
6
|
-
index: number
|
|
7
|
-
item: ZappEntry
|
|
8
|
-
focused: boolean
|
|
9
|
-
scrollTo?: (index: number) => void
|
|
10
|
-
CellRenderer: React.ComponentType<{ item: Object
|
|
11
|
-
behavior: Behavior
|
|
6
|
+
index: number;
|
|
7
|
+
item: ZappEntry;
|
|
8
|
+
focused: boolean;
|
|
9
|
+
scrollTo?: (index: number) => void;
|
|
10
|
+
CellRenderer: React.ComponentType<{ item: Object; state: string }>;
|
|
11
|
+
behavior: Behavior;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const isAndroid = Platform.OS === "android";
|
|
@@ -20,7 +20,7 @@ export function FocusableCell(props: Props) {
|
|
|
20
20
|
CellRenderer,
|
|
21
21
|
focused,
|
|
22
22
|
scrollTo = null,
|
|
23
|
-
behavior
|
|
23
|
+
behavior,
|
|
24
24
|
} = props;
|
|
25
25
|
|
|
26
26
|
const state = useCellState({ id: item.id, behavior, focused });
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import { BaseFocusable } from "../BaseFocusable";
|
|
4
|
+
import { FocusableGroupContextProvider } from "../../Contexts/FocusableGroupContext";
|
|
5
|
+
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
4
6
|
|
|
5
7
|
type Props = {
|
|
6
8
|
testID?: string;
|
|
@@ -26,9 +28,10 @@ type Props = {
|
|
|
26
28
|
nextFocusLeft?: any;
|
|
27
29
|
nextFocusRight?: any;
|
|
28
30
|
onLayout?: any;
|
|
31
|
+
excludeFromFocusSearching?: boolean;
|
|
29
32
|
};
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
class FocusableGroup extends BaseFocusable<Props> {
|
|
32
35
|
constructor(props) {
|
|
33
36
|
super(props);
|
|
34
37
|
this.isGroup = true;
|
|
@@ -81,8 +84,14 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
81
84
|
style={style}
|
|
82
85
|
ref={this.ref}
|
|
83
86
|
>
|
|
84
|
-
{
|
|
87
|
+
<FocusableGroupContextProvider id={id}>
|
|
88
|
+
{children}
|
|
89
|
+
</FocusableGroupContextProvider>
|
|
85
90
|
</div>
|
|
86
91
|
);
|
|
87
92
|
}
|
|
88
93
|
}
|
|
94
|
+
|
|
95
|
+
const FocusableGroupWithFocusableContext = withFocusableContext(FocusableGroup);
|
|
96
|
+
|
|
97
|
+
export { FocusableGroupWithFocusableContext as FocusableGroup };
|
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { isEqual } from "@applicaster/zapp-react-native-utils/equalUtils";
|
|
3
|
-
import {
|
|
3
|
+
import { useFocusable } from "../Focusable/index.android";
|
|
4
4
|
import { useCellState } from "./hooks/useCellState.android";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const nextFocusLeft = props.nextFocusLeft ?? context.nextFocusLeft;
|
|
15
|
-
|
|
16
|
-
const parentFocus = React.useMemo(
|
|
6
|
+
/**
|
|
7
|
+
* returns parent focus from prop or from context
|
|
8
|
+
* */
|
|
9
|
+
const useParentFocus = (
|
|
10
|
+
{ nextFocusDown, nextFocusUp, nextFocusRight, nextFocusLeft },
|
|
11
|
+
context
|
|
12
|
+
) =>
|
|
13
|
+
React.useMemo(
|
|
17
14
|
() => ({
|
|
15
|
+
nextFocusRight: nextFocusRight ?? context.nextFocusRight,
|
|
16
|
+
nextFocusDown: nextFocusDown ?? context.nextFocusDown,
|
|
17
|
+
nextFocusLeft: nextFocusLeft ?? context.nextFocusLeft,
|
|
18
|
+
nextFocusUp: nextFocusUp ?? context.nextFocusUp,
|
|
19
|
+
}),
|
|
20
|
+
[
|
|
18
21
|
nextFocusRight,
|
|
19
22
|
nextFocusDown,
|
|
20
23
|
nextFocusLeft,
|
|
21
24
|
nextFocusUp,
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
context.nextFocusLeft,
|
|
26
|
+
context.nextFocusRight,
|
|
27
|
+
context.nextFocusUp,
|
|
28
|
+
context.nextFocusDown,
|
|
29
|
+
]
|
|
24
30
|
);
|
|
25
31
|
|
|
32
|
+
function FocusableChildComponent(props) {
|
|
33
|
+
const { setIsFocusable, ...focusableContext } = useFocusable();
|
|
34
|
+
const parentFocus = useParentFocus(props, focusableContext);
|
|
35
|
+
|
|
26
36
|
const onLoadFailed = React.useCallback(() => {
|
|
27
37
|
setIsFocusable(false);
|
|
28
38
|
}, []);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Focusable } from "../Focusable";
|
|
2
|
+
import { Focusable } from "../Focusable/index.android";
|
|
3
3
|
import { FocusableChild } from "./FocusableChild";
|
|
4
4
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
5
|
import { IListRenderItem } from "./index";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ListRenderItemInfo as IListRenderItemInfo } from "react-native";
|
|
3
|
+
import { FocusableItem } from "./FocusableItem";
|
|
4
|
+
|
|
5
|
+
export type IListRenderItem<ItemT> = (
|
|
6
|
+
info: IListRenderItemInfo<ItemT> & {
|
|
7
|
+
focused: boolean;
|
|
8
|
+
onLoadFinished: () => void;
|
|
9
|
+
onLoadFailed: () => void;
|
|
10
|
+
}
|
|
11
|
+
) => React.ReactElement | null;
|
|
12
|
+
|
|
13
|
+
type Item = ZappEntry | ZappUIComponent | any;
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
item: Item;
|
|
17
|
+
onFocus: (
|
|
18
|
+
element: FocusManager.FocusableRef,
|
|
19
|
+
renderArgs: { item: Item; index: number },
|
|
20
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
21
|
+
) => void;
|
|
22
|
+
onListElementBlur?: (any, RenderItemProps, Direction) => void;
|
|
23
|
+
onListElementPress?: (any, RenderItemProps) => void;
|
|
24
|
+
onListElementLongPress?: (any, RenderItemProps) => void;
|
|
25
|
+
onListElementPressOut?: (any, RenderItemProps) => void;
|
|
26
|
+
focusableItemProps: any;
|
|
27
|
+
id: string;
|
|
28
|
+
index: number;
|
|
29
|
+
extraData: any;
|
|
30
|
+
extraChildrenData: any;
|
|
31
|
+
renderItem: IListRenderItem<any> | null | undefined;
|
|
32
|
+
getNextFocus: (index: number) => ParentFocus;
|
|
33
|
+
} & ParentFocus;
|
|
34
|
+
|
|
35
|
+
export const FocusableListItemWrapper = React.memo(
|
|
36
|
+
({
|
|
37
|
+
onFocus,
|
|
38
|
+
onListElementBlur,
|
|
39
|
+
onListElementPress,
|
|
40
|
+
onListElementLongPress,
|
|
41
|
+
onListElementPressOut,
|
|
42
|
+
focusableItemProps,
|
|
43
|
+
id,
|
|
44
|
+
getNextFocus,
|
|
45
|
+
item,
|
|
46
|
+
index,
|
|
47
|
+
extraData,
|
|
48
|
+
extraChildrenData,
|
|
49
|
+
renderItem,
|
|
50
|
+
}: Props) => {
|
|
51
|
+
const nextFocus = getNextFocus(index);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<FocusableItem
|
|
55
|
+
nextFocusDown={nextFocus.nextFocusDown}
|
|
56
|
+
nextFocusRight={nextFocus.nextFocusRight}
|
|
57
|
+
nextFocusLeft={nextFocus.nextFocusLeft}
|
|
58
|
+
nextFocusUp={nextFocus.nextFocusUp}
|
|
59
|
+
id={id}
|
|
60
|
+
focusableItemProps={focusableItemProps}
|
|
61
|
+
onFocus={onFocus}
|
|
62
|
+
item={item}
|
|
63
|
+
index={index}
|
|
64
|
+
renderItem={renderItem}
|
|
65
|
+
extraChildrenData={extraChildrenData}
|
|
66
|
+
extraData={extraData}
|
|
67
|
+
onListElementBlur={onListElementBlur}
|
|
68
|
+
onListElementPress={onListElementPress}
|
|
69
|
+
onListElementLongPress={onListElementLongPress}
|
|
70
|
+
onListElementPressOut={onListElementPressOut}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
FocusableListItemWrapper.displayName = "FocusableListItemWrapper";
|
|
@@ -5,7 +5,9 @@ import { useFocusManager } from "@applicaster/zapp-react-native-utils/focusManag
|
|
|
5
5
|
export const useCellState = (id: string) => {
|
|
6
6
|
const focusManager = useFocusManager();
|
|
7
7
|
|
|
8
|
-
const [currentCellFocused, setCurrentCellFocused] = React.useState(
|
|
8
|
+
const [currentCellFocused, setCurrentCellFocused] = React.useState(
|
|
9
|
+
focusManager.isFocused(id)
|
|
10
|
+
);
|
|
9
11
|
|
|
10
12
|
React.useEffect(() => {
|
|
11
13
|
const handler = (focusable) => {
|