@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1102149799 → 13.0.0-alpha.1108246333
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/AppContainer/__tests__/AppContainer.test.js +4 -6
- package/Components/AppContainer/__tests__/__snapshots__/AppContainer.test.js.snap +1 -1
- package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
- package/Components/AudioPlayer/__tests__/__snapshots__/Runtime.test.js.snap +4 -4
- package/Components/AudioPlayer/__tests__/__snapshots__/artWork.test.js.snap +3 -3
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +56 -113
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +39 -23
- package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +3 -3
- package/Components/AudioPlayer/__tests__/__snapshots__/summary.test.js.snap +2 -2
- package/Components/AudioPlayer/__tests__/__snapshots__/title.test.js.snap +2 -2
- package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
- package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
- package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
- package/Components/AudioPlayer/__tests__/title.test.js +3 -5
- package/Components/BaseFocusable/index.ios.ts +1 -1
- package/Components/BaseFocusable/index.tsx +67 -31
- package/Components/Cell/Cell.tsx +8 -3
- package/Components/Cell/CellWithFocusable.tsx +43 -58
- package/Components/Cell/TvOSCellComponent.tsx +20 -26
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
- package/Components/Cell/index.js +3 -1
- package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +50 -50
- package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +26 -30
- package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
- package/Components/DisplayState/__tests__/__snapshots__/displayState.test.js.snap +2 -2
- package/Components/ErrorScreen/index.tsx +6 -6
- package/Components/Focusable/Focusable.tsx +1 -54
- package/Components/Focusable/FocusableTvOS.tsx +6 -2
- package/Components/Focusable/Touchable.tsx +19 -20
- package/Components/Focusable/index.android.tsx +10 -3
- package/Components/FocusableGroup/FocusableTvOS.tsx +34 -83
- package/Components/FocusableGroup/index.tsx +1 -3
- package/Components/FocusableList/index.tsx +26 -10
- package/Components/FocusableScrollView/index.tsx +43 -13
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +9 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/Layout/TV/NavBarContainer.tsx +19 -23
- package/Components/Layout/TV/ScreenContainer.tsx +8 -1
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +3 -1
- package/Components/Layout/TV/__tests__/__snapshots__/LayoutContainer.test.tsx.snap +1 -1
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +6 -5
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +12 -11
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +1 -1
- package/Components/Layout/TV/__tests__/index.test.tsx +7 -3
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +66 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +6 -12
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +3 -3
- package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/__snapshots__/index.test.tsx.snap +1 -1
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
- package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +180 -180
- package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +11 -19
- package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +6 -235
- package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
- package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
- package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +2 -2
- package/Components/MasterCell/utils/behaviorProvider.ts +133 -0
- package/Components/MasterCell/utils/index.ts +4 -130
- package/Components/ModalComponent/Button/index.tsx +6 -6
- package/Components/ModalComponent/Header/index.tsx +3 -3
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +7 -7
- package/Components/OfflineHandler/__tests__/index.test.tsx +28 -25
- package/Components/PlayerContainer/PlayerContainer.tsx +13 -19
- package/Components/PlayerContainer/PlayerContainerContext.tsx +9 -0
- package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
- package/Components/PlayerImageBackground/index.tsx +23 -3
- package/Components/River/ComponentsMap/ComponentsMap.tsx +39 -65
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
- package/Components/River/RefreshControl.tsx +1 -1
- package/Components/River/RiverFooter.tsx +39 -9
- package/Components/River/RiverItem.tsx +37 -2
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +114 -45
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +21 -83
- package/Components/River/__tests__/componentsMap.test.js +64 -17
- package/Components/River/__tests__/river.test.js +75 -40
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +12 -5
- package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
- package/Components/RouteManager/__tests__/testId.test.js +8 -6
- package/Components/Screen/__tests__/Screen.test.tsx +41 -27
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -4
- package/Components/Screen/hooks.ts +56 -0
- package/Components/Screen/index.tsx +16 -42
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +95 -70
- package/Components/Tabs/Tab.tsx +12 -9
- package/Components/TextInputTv/__tests__/TextInputTv.test.js +42 -42
- package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +7 -0
- package/Components/TextInputTv/index.tsx +6 -5
- package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +2 -2
- package/Components/TrackedView/index.tsx +1 -0
- package/Components/Transitioner/AnimationManager.js +15 -15
- package/Components/Transitioner/Scene.tsx +53 -24
- package/Components/Transitioner/Transitioner.tsx +3 -3
- package/Components/Transitioner/__tests__/Scene.test.js +25 -14
- package/Components/Transitioner/__tests__/__snapshots__/AnimationManager.test.js.snap +26 -26
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +10 -50
- package/Components/Transitioner/__tests__/__snapshots__/config.test.js.snap +20 -20
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +4 -4
- package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
- package/Components/Transitioner/index.js +8 -4
- package/Components/VideoLive/LiveImageManager.ts +27 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +36 -24
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +63 -8
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +6 -10
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +16 -12
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +5 -1
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +15 -14
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +6 -13
- package/Components/VideoModal/ModalAnimation/index.ts +2 -1
- package/Components/VideoModal/ModalAnimation/useModalAnimationContext.ts +6 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +2 -2
- package/Components/VideoModal/OpaqueLayer.tsx +33 -0
- package/Components/VideoModal/PlayerDetails.tsx +9 -6
- package/Components/VideoModal/PlayerWrapper.tsx +17 -36
- package/Components/VideoModal/VideoModal.tsx +14 -23
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -2
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -10
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +4 -4
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +66 -156
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +89 -0
- package/Components/VideoModal/hooks/index.ts +7 -0
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +49 -0
- package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +91 -0
- package/Components/VideoModal/hooks/utils/index.ts +33 -0
- package/Components/VideoModal/utils.ts +3 -5
- package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
- package/Components/Viewport/ViewportTracker/__tests__/__snapshots__/viewportTracker.test.js.snap +1 -1
- package/Components/Viewport/__tests__/utils.test.js +5 -4
- package/Components/ZappUIComponent/Placeholder.tsx +3 -1
- package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
- package/Components/ZappUIComponent/index.tsx +3 -16
- package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
- package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
- package/Contexts/ConfigutaionContext/__tests__/__snapshots__/ConfigurationProvider.test.tsx.snap +1 -1
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
- package/Contexts/HeaderOffsetContext/index.tsx +4 -6
- package/Contexts/ScreenContext/index.tsx +6 -12
- package/Contexts/ScreenLayoutContext/index.tsx +5 -3
- package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
- package/Decorators/Navigator/index.tsx +1 -1
- package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +77 -77
- package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +34 -39
- package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -9
- package/Decorators/RiverFeedLoader/index.tsx +1 -1
- package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +39 -0
- package/Decorators/RiverFeedLoader/utils/index.ts +29 -0
- package/Decorators/RiverFeedLoader/utils/usePipesContexts.ts +40 -0
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +27 -27
- package/Decorators/RiverResolver/index.tsx +1 -1
- package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
- package/Decorators/ZappPipesDataConnector/index.tsx +5 -2
- package/package.json +7 -10
- package/tsconfig.json +2 -3
- package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
- package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
- package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
- package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
- package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
- package/Decorators/RiverFeedLoader/utils.ts +0 -100
- package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import * as R from "ramda";
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
BaseFocusable as BaseFocusableInterface,
|
|
5
6
|
BoundingRect,
|
|
6
7
|
} from "./BaseFocusable.interface";
|
|
7
8
|
|
|
8
|
-
import { createReactRef } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
9
9
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
10
|
-
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
11
10
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
12
11
|
|
|
13
12
|
type ScrollDirection = FocusManager.IOS.Direction | FocusManager.Web.Direction;
|
|
@@ -35,7 +34,7 @@ type Props = {
|
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
export class BaseFocusable<
|
|
38
|
-
T extends Props = Props
|
|
37
|
+
T extends Props = Props,
|
|
39
38
|
> extends BaseFocusableInterface<T> {
|
|
40
39
|
constructor(props) {
|
|
41
40
|
super(props);
|
|
@@ -45,7 +44,7 @@ export class BaseFocusable<
|
|
|
45
44
|
focused: initialFocus || false,
|
|
46
45
|
};
|
|
47
46
|
|
|
48
|
-
this.ref =
|
|
47
|
+
this.ref = React.createRef();
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
componentDidMount() {
|
|
@@ -131,12 +130,6 @@ export class BaseFocusable<
|
|
|
131
130
|
willLoseFocus: FocusManager.FocusEventCB = (focusable, scrollDirection) => {
|
|
132
131
|
const { willLoseFocus = noop } = this.props;
|
|
133
132
|
willLoseFocus(focusable, scrollDirection);
|
|
134
|
-
|
|
135
|
-
focusManager.invokeHandler?.(
|
|
136
|
-
FOCUS_EVENTS.WILL_LOSE_FOCUS,
|
|
137
|
-
this,
|
|
138
|
-
scrollDirection
|
|
139
|
-
);
|
|
140
133
|
};
|
|
141
134
|
|
|
142
135
|
willReceiveFocus: FocusManager.FocusEventCB = (
|
|
@@ -145,12 +138,6 @@ export class BaseFocusable<
|
|
|
145
138
|
) => {
|
|
146
139
|
const { willReceiveFocus = noop } = this.props;
|
|
147
140
|
willReceiveFocus(focusable, scrollDirection);
|
|
148
|
-
|
|
149
|
-
focusManager.invokeHandler?.(
|
|
150
|
-
FOCUS_EVENTS.WILL_RECEIVE_FOCUS,
|
|
151
|
-
this,
|
|
152
|
-
scrollDirection
|
|
153
|
-
);
|
|
154
141
|
};
|
|
155
142
|
|
|
156
143
|
/**
|
|
@@ -163,8 +150,6 @@ export class BaseFocusable<
|
|
|
163
150
|
const { onFocus = noop } = this.props;
|
|
164
151
|
this.setFocusedState(true);
|
|
165
152
|
onFocus(focusable, scrollDirection);
|
|
166
|
-
|
|
167
|
-
focusManager.invokeHandler?.(FOCUS_EVENTS.FOCUS, this, scrollDirection);
|
|
168
153
|
};
|
|
169
154
|
|
|
170
155
|
/**
|
|
@@ -179,12 +164,6 @@ export class BaseFocusable<
|
|
|
179
164
|
) => {
|
|
180
165
|
const { hasReceivedFocus = noop } = this.props;
|
|
181
166
|
hasReceivedFocus(focusable, scrollDirection);
|
|
182
|
-
|
|
183
|
-
focusManager.invokeHandler?.(
|
|
184
|
-
FOCUS_EVENTS.HAS_RECEIVED_FOCUS,
|
|
185
|
-
this,
|
|
186
|
-
scrollDirection
|
|
187
|
-
);
|
|
188
167
|
};
|
|
189
168
|
|
|
190
169
|
/**
|
|
@@ -196,12 +175,6 @@ export class BaseFocusable<
|
|
|
196
175
|
hasLostFocus: FocusManager.FocusEventCB = (focusable, scrollDirection) => {
|
|
197
176
|
const { hasLostFocus = noop } = this.props;
|
|
198
177
|
hasLostFocus(focusable, scrollDirection);
|
|
199
|
-
|
|
200
|
-
focusManager.invokeHandler?.(
|
|
201
|
-
FOCUS_EVENTS.HAS_LOST_FOCUS,
|
|
202
|
-
this,
|
|
203
|
-
scrollDirection
|
|
204
|
-
);
|
|
205
178
|
};
|
|
206
179
|
|
|
207
180
|
/**
|
|
@@ -228,7 +201,6 @@ export class BaseFocusable<
|
|
|
228
201
|
const { onBlur = noop } = this.props;
|
|
229
202
|
this.setFocusedState(false);
|
|
230
203
|
onBlur(focusable, scrollDirection);
|
|
231
|
-
focusManager.invokeHandler?.(FOCUS_EVENTS.BLUR, this, scrollDirection);
|
|
232
204
|
};
|
|
233
205
|
|
|
234
206
|
onPress = (keyEvent?: Nullable<React.MouseEvent>) => {
|
|
@@ -269,4 +241,68 @@ export class BaseFocusable<
|
|
|
269
241
|
this.setState({ focused });
|
|
270
242
|
}
|
|
271
243
|
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* will invoke the underlying component's focus method
|
|
247
|
+
* @param {Object} scrollDirection
|
|
248
|
+
* @returns {Promise}
|
|
249
|
+
*/
|
|
250
|
+
focus(_, scrollDirection) {
|
|
251
|
+
return this.onFocus(this, scrollDirection); // invokeComponentMethod(this, "onFocus", scrollDirection);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* will invoke the underlying component's blur method
|
|
256
|
+
* @param {Object} scrollDirection
|
|
257
|
+
* @returns {Promise}
|
|
258
|
+
*/
|
|
259
|
+
blur(
|
|
260
|
+
_,
|
|
261
|
+
scrollDirection?: FocusManager.Web.Direction | FocusManager.IOS.Direction
|
|
262
|
+
) {
|
|
263
|
+
return this.onBlur(this, scrollDirection);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Sets the focus on this item. Will trigger sequentially a sequence of
|
|
268
|
+
* functions (willReceiveFocus, focus, hasReceivedFocus). If these functions (defined in the Focusable
|
|
269
|
+
* Item underlying component) return promises, execution will wait before it proceeds to the next. This
|
|
270
|
+
* is useful for triggering sequential operations that specifically require to fully run before or after
|
|
271
|
+
* focus is actually set on that item.
|
|
272
|
+
* @param {string} scrollDirection string representation of the direction of the navigation which landed
|
|
273
|
+
* to this item being focused
|
|
274
|
+
*/
|
|
275
|
+
_executeFocusSequence(methodNames, scrollDirection) {
|
|
276
|
+
return R.reduce(
|
|
277
|
+
(sequence, methodName) => {
|
|
278
|
+
const method = this[methodName]; // Access the method by name
|
|
279
|
+
|
|
280
|
+
if (typeof method !== "function") {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Method '${methodName}' not found or not a function.`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return sequence
|
|
287
|
+
.then(() => method.call(this, scrollDirection))
|
|
288
|
+
.catch((e) => {
|
|
289
|
+
throw e; // Re-throw for consistent error handling
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
Promise.resolve(),
|
|
293
|
+
methodNames
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
setFocus(scrollDirection) {
|
|
298
|
+
const focusMethods = ["willReceiveFocus", "focus", "hasReceivedFocus"];
|
|
299
|
+
|
|
300
|
+
return this._executeFocusSequence(focusMethods, scrollDirection);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
setBlur(scrollDirection) {
|
|
304
|
+
const blurMethods = ["willLoseFocus", "blur", "hasLostFocus"];
|
|
305
|
+
|
|
306
|
+
return this._executeFocusSequence(blurMethods, scrollDirection);
|
|
307
|
+
}
|
|
272
308
|
}
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -61,6 +61,7 @@ type Props = {
|
|
|
61
61
|
skipFocusManagerRegistration?: boolean;
|
|
62
62
|
shouldUpdate: boolean;
|
|
63
63
|
behavior: Behavior;
|
|
64
|
+
componentsMapOffset: number;
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
type State = {
|
|
@@ -273,10 +274,14 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
273
274
|
if (isFocused) {
|
|
274
275
|
const accessibilityManager = AccessibilityManager.getInstance();
|
|
275
276
|
|
|
277
|
+
const accessibilityTitle =
|
|
278
|
+
item?.extensions?.accessibility?.label || item?.title || "";
|
|
279
|
+
|
|
280
|
+
const accessibilityHint =
|
|
281
|
+
item?.extensions?.accessibility?.hint || "";
|
|
282
|
+
|
|
276
283
|
accessibilityManager.readText({
|
|
277
|
-
text:
|
|
278
|
-
item.extensions?.accessibility?.label || item.title
|
|
279
|
-
),
|
|
284
|
+
text: `${accessibilityTitle} ${accessibilityHint}`,
|
|
280
285
|
});
|
|
281
286
|
}
|
|
282
287
|
|
|
@@ -1,48 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
4
|
-
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
5
3
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
4
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
5
|
|
|
8
|
-
import { isAppleTV } from "../../Helpers/Platform";
|
|
9
6
|
import { useCellState } from "../MasterCell/utils";
|
|
10
|
-
|
|
11
|
-
const useCellFocusedState = (
|
|
12
|
-
skipFocusManagerRegistration: boolean,
|
|
13
|
-
groupId: string,
|
|
14
|
-
id: string
|
|
15
|
-
) => {
|
|
16
|
-
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
17
|
-
|
|
18
|
-
React.useEffect(() => {
|
|
19
|
-
const isGroupItemFocused = () => {
|
|
20
|
-
if (!skipFocusManagerRegistration) {
|
|
21
|
-
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
22
|
-
setCurrentCellFocused(isFocused);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const handler = () => {
|
|
27
|
-
// tvOS hack for properly checking focus
|
|
28
|
-
if (isAppleTV()) {
|
|
29
|
-
setTimeout(() => {
|
|
30
|
-
isGroupItemFocused();
|
|
31
|
-
}, 0);
|
|
32
|
-
} else {
|
|
33
|
-
isGroupItemFocused();
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
focusManager.on(FOCUS_EVENTS.FOCUS, handler);
|
|
38
|
-
|
|
39
|
-
return () => {
|
|
40
|
-
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
41
|
-
};
|
|
42
|
-
}, [groupId, skipFocusManagerRegistration]);
|
|
43
|
-
|
|
44
|
-
return currentCellFocused;
|
|
45
|
-
};
|
|
7
|
+
import { FocusableGroup } from "../FocusableGroup";
|
|
46
8
|
|
|
47
9
|
type Props = {
|
|
48
10
|
item: ZappEntry;
|
|
@@ -75,11 +37,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
75
37
|
focused,
|
|
76
38
|
} = props;
|
|
77
39
|
|
|
78
|
-
const isFocused =
|
|
79
|
-
skipFocusManagerRegistration,
|
|
80
|
-
groupId,
|
|
81
|
-
id
|
|
82
|
-
);
|
|
40
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
83
41
|
|
|
84
42
|
const state = useCellState({
|
|
85
43
|
id: item.id,
|
|
@@ -96,26 +54,53 @@ export function CellWithFocusable(props: Props) {
|
|
|
96
54
|
}
|
|
97
55
|
}, [focusedButtonId]);
|
|
98
56
|
|
|
99
|
-
const handleToggleFocus = (
|
|
100
|
-
|
|
57
|
+
const handleToggleFocus = React.useCallback(
|
|
58
|
+
(value) => {
|
|
59
|
+
setFocusedButtonId(value.focusedButtonId);
|
|
60
|
+
|
|
61
|
+
if (value.focusable) {
|
|
62
|
+
onFocus(value.focusable, value.mouse);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
[onFocus]
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const onGroupFocus = React.useCallback(() => {
|
|
69
|
+
if (!skipFocusManagerRegistration) {
|
|
70
|
+
setIsFocused(true);
|
|
71
|
+
}
|
|
72
|
+
}, [skipFocusManagerRegistration]);
|
|
101
73
|
|
|
102
|
-
|
|
103
|
-
|
|
74
|
+
const onGroupBlur = React.useCallback(() => {
|
|
75
|
+
if (!skipFocusManagerRegistration) {
|
|
76
|
+
setIsFocused(false);
|
|
104
77
|
}
|
|
105
|
-
};
|
|
78
|
+
}, [skipFocusManagerRegistration]);
|
|
106
79
|
|
|
107
80
|
return (
|
|
108
|
-
<
|
|
109
|
-
|
|
81
|
+
<FocusableGroup
|
|
82
|
+
id={`focusable-cell-wrapper-${id}`}
|
|
83
|
+
testID={"cell-with-focusable-cell-renderer-focusable-group"}
|
|
110
84
|
groupId={groupId}
|
|
111
|
-
onToggleFocus={handleToggleFocus}
|
|
112
|
-
state={state}
|
|
113
|
-
prefixId={id}
|
|
114
|
-
focusedButtonId={focusedButtonId}
|
|
115
85
|
preferredFocus={preferredFocus}
|
|
86
|
+
shouldUsePreferredFocus
|
|
87
|
+
onFocus={onGroupFocus}
|
|
88
|
+
onBlur={onGroupBlur}
|
|
116
89
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
90
|
+
>
|
|
91
|
+
<CellRenderer
|
|
92
|
+
testID={"cell-with-focusable-cell-renderer"}
|
|
93
|
+
item={item}
|
|
94
|
+
groupId={`focusable-cell-wrapper-${id}`}
|
|
95
|
+
onToggleFocus={handleToggleFocus}
|
|
96
|
+
state={state}
|
|
97
|
+
prefixId={id}
|
|
98
|
+
focusedButtonId={focusedButtonId}
|
|
99
|
+
preferredFocus={true}
|
|
100
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
101
|
+
isFocusable={isFocusable}
|
|
102
|
+
focused={focused}
|
|
103
|
+
/>
|
|
104
|
+
</FocusableGroup>
|
|
120
105
|
);
|
|
121
106
|
}
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
4
|
|
|
5
|
-
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
5
|
+
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
6
6
|
import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
|
|
7
7
|
import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
8
8
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
@@ -10,10 +10,6 @@ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focu
|
|
|
10
10
|
import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
11
11
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
12
12
|
import { CellWithFocusable } from "./CellWithFocusable";
|
|
13
|
-
import { getCellState } from "./utils";
|
|
14
|
-
|
|
15
|
-
const _getCellState = (focused, selected) =>
|
|
16
|
-
getCellState({ focused, selected });
|
|
17
13
|
|
|
18
14
|
type Props = {
|
|
19
15
|
item: ZappEntry;
|
|
@@ -69,6 +65,7 @@ type Props = {
|
|
|
69
65
|
isFocusable: boolean;
|
|
70
66
|
shouldUpdate: boolean;
|
|
71
67
|
behavior: Behavior;
|
|
68
|
+
componentsMapOffset: number;
|
|
72
69
|
};
|
|
73
70
|
|
|
74
71
|
type State = {
|
|
@@ -183,6 +180,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
183
180
|
groupId,
|
|
184
181
|
component,
|
|
185
182
|
index,
|
|
183
|
+
componentsMapOffset,
|
|
186
184
|
} = this.props;
|
|
187
185
|
|
|
188
186
|
this.setScreenLayout(componentAnchorPointY, screenLayout);
|
|
@@ -197,13 +195,11 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
197
195
|
const extraAnchorPointYOffset =
|
|
198
196
|
screenLayout?.extraAnchorPointYOffset || 0;
|
|
199
197
|
|
|
200
|
-
const marginTop = screenLayout?.screenMarginTop || 0;
|
|
201
|
-
|
|
202
198
|
const totalOffset =
|
|
203
199
|
headerOffset +
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
(componentAnchorPointY || 0) +
|
|
201
|
+
extraAnchorPointYOffset -
|
|
202
|
+
componentsMapOffset || 0;
|
|
207
203
|
|
|
208
204
|
mainOffsetUpdater?.(
|
|
209
205
|
{ tag: this.target },
|
|
@@ -251,7 +247,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
251
247
|
|
|
252
248
|
const focusableId = R.join("-", [component?.id, id, index]);
|
|
253
249
|
|
|
254
|
-
const handleFocus = (arg1: any, index
|
|
250
|
+
const handleFocus = (arg1: any, index?: number) => {
|
|
255
251
|
const focusFn = onFocus || noop;
|
|
256
252
|
focusFn(arg1, index);
|
|
257
253
|
|
|
@@ -284,7 +280,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
284
280
|
<View onLayout={this.onLayout} style={styles.container}>
|
|
285
281
|
<Focusable
|
|
286
282
|
id={focusableId}
|
|
287
|
-
groupId={groupId || component?.id}
|
|
283
|
+
groupId={String(groupId || component?.id)}
|
|
288
284
|
onFocus={handleFocus}
|
|
289
285
|
onBlur={onBlur || this.onBlur}
|
|
290
286
|
isParallaxDisabled={this.layout?.width > 1740}
|
|
@@ -296,20 +292,18 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
296
292
|
style={baseCellStyles}
|
|
297
293
|
isFocusable={isFocusable}
|
|
298
294
|
>
|
|
299
|
-
{(focused) =>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
);
|
|
312
|
-
}}
|
|
295
|
+
{(focused) => (
|
|
296
|
+
<FocusableCell
|
|
297
|
+
{...{
|
|
298
|
+
index,
|
|
299
|
+
CellRenderer,
|
|
300
|
+
item,
|
|
301
|
+
focused: !!(this.props.focused || selectedCell || focused),
|
|
302
|
+
scrollTo: this.scrollTo,
|
|
303
|
+
behavior,
|
|
304
|
+
}}
|
|
305
|
+
/>
|
|
306
|
+
)}
|
|
313
307
|
</Focusable>
|
|
314
308
|
</View>
|
|
315
309
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { View } from "react-native";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { act, render } from "@testing-library/react-native";
|
|
4
|
-
import { CellWithFocusable } from "../CellWithFocusable";
|
|
4
|
+
import { CellWithFocusable } from "../CellWithFocusable.tsx";
|
|
5
5
|
|
|
6
6
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
7
7
|
|
|
@@ -23,7 +23,9 @@ describe("CellWithFocusable", () => {
|
|
|
23
23
|
|
|
24
24
|
const wrapper = renderWith(props);
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
|
|
27
|
+
|
|
28
|
+
expect(element.props.state).toBe("default");
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
it("should render in default state", () => {
|
|
@@ -40,8 +42,9 @@ describe("CellWithFocusable", () => {
|
|
|
40
42
|
focusManager.isGroupItemFocused = jest.fn(() => true);
|
|
41
43
|
|
|
42
44
|
const wrapper = renderWith(props);
|
|
45
|
+
const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
|
|
43
46
|
|
|
44
|
-
expect(
|
|
47
|
+
expect(element.props.state).toBe("default");
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
it("should render in focused state", () => {
|
|
@@ -55,13 +58,17 @@ describe("CellWithFocusable", () => {
|
|
|
55
58
|
scrollTo: jest.fn(),
|
|
56
59
|
};
|
|
57
60
|
|
|
58
|
-
focusManager.isGroupItemFocused = jest.fn(() => true);
|
|
59
61
|
const wrapper = renderWith(props);
|
|
60
62
|
|
|
63
|
+
const focusableGroupComponent = wrapper.getByTestId(
|
|
64
|
+
"cell-with-focusable-cell-renderer-focusable-group"
|
|
65
|
+
);
|
|
66
|
+
|
|
61
67
|
act(() => {
|
|
62
|
-
|
|
68
|
+
focusableGroupComponent.props.onFocus();
|
|
63
69
|
});
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
|
|
72
|
+
expect(element.props.state).toBe("focused");
|
|
66
73
|
});
|
|
67
74
|
});
|
package/Components/Cell/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
|
|
|
11
11
|
|
|
12
12
|
import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
|
|
13
13
|
import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
|
|
14
|
+
import { withComponentsMapOffsetContextConsumer } from "../../Contexts/ComponentsMapOffsetContext";
|
|
14
15
|
|
|
15
16
|
// TODO | Gallery QB | Extract this
|
|
16
17
|
export const ScrollInterceptorContext = createContext(
|
|
@@ -30,5 +31,6 @@ export const Cell = R.compose(
|
|
|
30
31
|
RiverOffsetContext.withConsumer,
|
|
31
32
|
HorizontalScrollContext.withConsumer,
|
|
32
33
|
withConsumer,
|
|
33
|
-
ScreenLayoutContextConsumer
|
|
34
|
+
ScreenLayoutContextConsumer,
|
|
35
|
+
withComponentsMapOffsetContextConsumer
|
|
34
36
|
)(Component);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import {
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { CellRendererResolver } from "../";
|
|
4
5
|
|
|
5
|
-
jest.mock("../../default-cell-renderer", () =>
|
|
6
|
-
|
|
7
|
-
);
|
|
6
|
+
jest.mock("../../default-cell-renderer", () => {
|
|
7
|
+
const View = jest.requireActual("react-native").View;
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
return jest.fn((prop) => <View whoAmI="default renderer" someProp={prop} />);
|
|
10
|
+
});
|
|
10
11
|
|
|
11
12
|
const component = {
|
|
12
13
|
styles: {
|
|
@@ -43,17 +44,9 @@ describe("CellRendererResolver", () => {
|
|
|
43
44
|
cellStyles,
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
it("renders correctly", () => {
|
|
47
|
-
const result = shallow(
|
|
48
|
-
getResult({ component, plugins, styles, cellStyles })
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
expect(result).toMatchSnapshot();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
47
|
describe("with a default renderer plugin", () => {
|
|
55
48
|
it("renders correctly", () => {
|
|
56
|
-
const
|
|
49
|
+
const { UNSAFE_root } = render(
|
|
57
50
|
getResult({
|
|
58
51
|
component,
|
|
59
52
|
plugins,
|
|
@@ -62,56 +55,63 @@ describe("CellRendererResolver", () => {
|
|
|
62
55
|
})
|
|
63
56
|
);
|
|
64
57
|
|
|
65
|
-
expect(
|
|
58
|
+
expect(UNSAFE_root).toBeDefined();
|
|
66
59
|
});
|
|
67
60
|
|
|
68
61
|
it("returns default plugin if component has no cell_plugin_configuration_id", () => {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
const { UNSAFE_getByProps } = render(
|
|
63
|
+
getResult({
|
|
64
|
+
component: {},
|
|
65
|
+
plugins,
|
|
66
|
+
styles,
|
|
67
|
+
cellStyles,
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(UNSAFE_getByProps({ whoAmI: "default renderer" })).toBeTruthy();
|
|
78
72
|
});
|
|
79
73
|
|
|
80
74
|
it("returns default plugin if requested cell plugin configuration does not exist", () => {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
const { UNSAFE_getByProps } = render(
|
|
76
|
+
getResult({
|
|
77
|
+
component: { styles: { cell_plugin_configuration_id: "wrong-id" } },
|
|
78
|
+
plugins,
|
|
79
|
+
styles,
|
|
80
|
+
cellStyles,
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(UNSAFE_getByProps({ whoAmI: "default renderer" })).toBeTruthy();
|
|
89
85
|
});
|
|
90
86
|
|
|
91
87
|
it("returns default plugin if cellStyles store is empty", () => {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
const { UNSAFE_getByProps } = render(
|
|
89
|
+
getResult({
|
|
90
|
+
component,
|
|
91
|
+
plugins,
|
|
92
|
+
styles,
|
|
93
|
+
cellStyles: {},
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect(UNSAFE_getByProps({ whoAmI: "default renderer" })).toBeTruthy();
|
|
100
98
|
});
|
|
101
99
|
|
|
102
100
|
it("returns null if requested renderer plugin does not exist", () => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
const { UNSAFE_getByProps } = render(
|
|
102
|
+
getResult({
|
|
103
|
+
component: {
|
|
104
|
+
styles: {
|
|
105
|
+
cell_plugin_configuration_id: "FGHIJ-123456",
|
|
106
|
+
},
|
|
107
107
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
plugins,
|
|
109
|
+
styles,
|
|
110
|
+
cellStyles,
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
113
|
|
|
114
|
-
expect(
|
|
114
|
+
expect(UNSAFE_getByProps({ whoAmI: "default renderer" })).toBeTruthy();
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
117
|
});
|
|
@@ -1,48 +1,7 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`ComponentResolver renders correctly 1`] = `
|
|
4
|
-
<ContextProvider
|
|
5
|
-
value={null}
|
|
6
|
-
>
|
|
7
|
-
<Memo(ComponentResolver)
|
|
8
|
-
cellStyles={Object {}}
|
|
9
|
-
component={
|
|
10
|
-
Object {
|
|
11
|
-
"component_type": "some_component",
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
components={
|
|
15
|
-
Object {
|
|
16
|
-
"SomeComponent": [MockFunction],
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
decorators={[MockFunction]}
|
|
20
|
-
dispatch={[Function]}
|
|
21
|
-
plugins={Array []}
|
|
22
|
-
store={
|
|
23
|
-
Object {
|
|
24
|
-
"clearActions": [Function],
|
|
25
|
-
"dispatch": [Function],
|
|
26
|
-
"getActions": [Function],
|
|
27
|
-
"getState": [Function],
|
|
28
|
-
"replaceReducer": [Function],
|
|
29
|
-
"subscribe": [Function],
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/>
|
|
33
|
-
</ContextProvider>
|
|
34
|
-
`;
|
|
35
|
-
|
|
36
3
|
exports[`ComponentResolverComponent initializes the cell renderer plugin module if matching plugin exists 1`] = `
|
|
37
|
-
<
|
|
4
|
+
<View
|
|
38
5
|
rendered={true}
|
|
39
6
|
/>
|
|
40
7
|
`;
|
|
41
|
-
|
|
42
|
-
exports[`ComponentResolverComponent renders the Component if it exists 1`] = `
|
|
43
|
-
<mockConstructor
|
|
44
|
-
rendered={true}
|
|
45
|
-
/>
|
|
46
|
-
`;
|
|
47
|
-
|
|
48
|
-
exports[`ComponentResolverComponent returns null if the component doesn't exist 1`] = `""`;
|