@applicaster/zapp-react-native-ui-components 15.0.0-alpha.2239032089 → 15.0.0-alpha.2349550201

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.
Files changed (50) hide show
  1. package/Components/AnimatedInOut/index.tsx +69 -26
  2. package/Components/Cell/Cell.tsx +8 -3
  3. package/Components/Cell/FocusableWrapper.tsx +44 -0
  4. package/Components/Cell/TvOSCellComponent.tsx +80 -14
  5. package/Components/Focusable/Focusable.tsx +2 -4
  6. package/Components/Focusable/FocusableTvOS.tsx +1 -5
  7. package/Components/FocusableGroup/FocusableTvOS.tsx +0 -5
  8. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +9 -11
  9. package/Components/HandlePlayable/HandlePlayable.tsx +14 -65
  10. package/Components/HandlePlayable/const.ts +3 -0
  11. package/Components/HandlePlayable/utils.ts +74 -0
  12. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
  13. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
  14. package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
  15. package/Components/MasterCell/index.tsx +2 -0
  16. package/Components/PlayerContainer/PlayerContainer.tsx +1 -16
  17. package/Components/PlayerImageBackground/index.tsx +3 -22
  18. package/Components/River/TV/River.tsx +3 -9
  19. package/Components/River/TV/index.tsx +3 -3
  20. package/Components/River/TV/withTVEventHandler.tsx +27 -0
  21. package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
  22. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  23. package/Components/Screen/index.tsx +22 -5
  24. package/Components/ScreenResolver/index.tsx +8 -2
  25. package/Components/ScreenRevealManager/utils/index.ts +23 -0
  26. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
  27. package/Components/Tabs/TV/Tabs.tsx +20 -3
  28. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  29. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +3 -153
  30. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  31. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  32. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  33. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  34. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  35. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  36. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  37. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  38. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  39. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
  40. package/events/index.ts +0 -2
  41. package/index.d.ts +7 -0
  42. package/package.json +5 -5
  43. package/Components/River/TV/withFocusableGroupForContent.tsx +0 -60
  44. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  45. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
  46. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
  47. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  48. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
  49. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  50. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
@@ -1,10 +1,16 @@
1
- import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
2
- import * as React from "react";
1
+ import React, { useMemo, useContext, useEffect } from "react";
3
2
  import { ImageStyle, StyleSheet, View, ViewStyle } from "react-native";
3
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
5
+ import { MeasurementPortalContext } from "../../../MeasurmentsPortal/MeasurementsPortal";
4
6
 
5
7
  type BorderPosition = "inside" | "outside" | "center";
6
8
 
7
9
  interface Props {
10
+ hasFocusableInside: (entry: ZappEntry) => boolean;
11
+ entry: ZappEntry;
12
+ state: CellState;
13
+ hasTextLabels: boolean;
8
14
  style: ImageStyle | ViewStyle;
9
15
  borderPosition: BorderPosition;
10
16
  borderPaddingTop: number;
@@ -118,8 +124,30 @@ export const BorderContainerView = (props: Props) => {
118
124
  borderPaddingLeft,
119
125
  style,
120
126
  children,
127
+ hasFocusableInside,
128
+ entry,
129
+ state,
130
+ hasTextLabels,
121
131
  } = props;
122
132
 
133
+ const accessibilityManager = useAccessibilityManager();
134
+ const isMeasurement = useContext(MeasurementPortalContext);
135
+
136
+ const isImageOnlyCell = useMemo(
137
+ () =>
138
+ !hasFocusableInside(entry) &&
139
+ !hasTextLabels &&
140
+ state === "focused" &&
141
+ !isMeasurement,
142
+ [hasFocusableInside, entry, hasTextLabels, state, isMeasurement]
143
+ );
144
+
145
+ useEffect(() => {
146
+ if (isImageOnlyCell && entry?.title) {
147
+ accessibilityManager.addHeading(String(entry.title));
148
+ }
149
+ }, [isImageOnlyCell, entry?.title]);
150
+
123
151
  const padding =
124
152
  borderPosition === "outside"
125
153
  ? {
@@ -52,14 +52,14 @@ const _Text = ({
52
52
  : textTransform(transformText, _label);
53
53
 
54
54
  React.useLayoutEffect(() => {
55
- // For FocusableCells with action buttons
56
- if (otherProps.state) {
57
- if (otherProps.state === "focused" && cellFocused === true) {
58
- accessibilityManager.addHeading(textLabel);
59
- }
60
- } else {
61
- if (cellFocused === true) {
62
- accessibilityManager.addHeading(textLabel);
55
+ if (cellFocused) {
56
+ switch (otherProps.state) {
57
+ case "focused":
58
+ accessibilityManager.addHeading(textLabel);
59
+ break;
60
+ case "focused_selected":
61
+ accessibilityManager.addHeading(`${textLabel}, Selected`);
62
+ break;
63
63
  }
64
64
  }
65
65
  }, [cellFocused, otherProps.state, textLabel]);
@@ -103,6 +103,8 @@ export function masterCellBuilder({
103
103
  wrapperRef,
104
104
  cellUUID,
105
105
  skipButtons,
106
+ hasFocusableInside,
107
+ entry: item,
106
108
  })
107
109
  );
108
110
 
@@ -56,11 +56,6 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
56
56
  import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
57
57
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
58
58
 
59
- import {
60
- PlayerAnimationStateEnum,
61
- useModalAnimationContext,
62
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
63
-
64
59
  import {
65
60
  PlayerNativeCommandTypes,
66
61
  PlayerNativeSendCommand,
@@ -248,9 +243,6 @@ const PlayerContainerComponent = (props: Props) => {
248
243
  const screenData = useTargetScreenData(item);
249
244
  const { setVisible: showNavBar } = useSetNavbarState();
250
245
 
251
- const { isActiveGesture, startComponentsAnimation, setPlayerAnimationState } =
252
- useModalAnimationContext();
253
-
254
246
  const playerEvent = (event, ...args) => {
255
247
  playerManager.invokeHandler(event, ...args);
256
248
  };
@@ -482,8 +474,6 @@ const PlayerContainerComponent = (props: Props) => {
482
474
  if (isModal && mode === VideoModalMode.MAXIMIZED) {
483
475
  if (disableMiniPlayer) {
484
476
  navigator.closeVideoModal();
485
- } else {
486
- setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
487
477
  }
488
478
  }
489
479
 
@@ -680,11 +670,7 @@ const PlayerContainerComponent = (props: Props) => {
680
670
  autoplay={true}
681
671
  controls={false}
682
672
  disableCastAction={disableCastAction}
683
- docked={
684
- navigator.isVideoModalDocked() &&
685
- !startComponentsAnimation &&
686
- !isActiveGesture
687
- }
673
+ docked={navigator.isVideoModalDocked()}
688
674
  entry={item}
689
675
  fullscreen={mode === VideoModalMode.FULLSCREEN}
690
676
  inline={inline}
@@ -702,7 +688,6 @@ const PlayerContainerComponent = (props: Props) => {
702
688
  setNextVideoPreloadThresholdPercentage={
703
689
  setNextVideoPreloadThresholdPercentage
704
690
  }
705
- startComponentsAnimation={startComponentsAnimation}
706
691
  >
707
692
  {renderApplePlayer(applePlayerProps)}
708
693
  </Player>
@@ -2,12 +2,6 @@ import React, { PropsWithChildren } from "react";
2
2
  import { ImageBackground, View } from "react-native";
3
3
 
4
4
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
- import {
6
- AnimationComponent,
7
- ComponentAnimationType,
8
- useModalAnimationContext,
9
- PlayerAnimationStateEnum,
10
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
11
5
 
12
6
  type Props = PropsWithChildren<{
13
7
  entry: ZappEntry;
@@ -25,30 +19,17 @@ const PlayerImageBackgroundComponent = ({
25
19
  style,
26
20
  imageStyle,
27
21
  imageKey,
28
- defaultImageDimensions,
29
22
  }: Props) => {
30
23
  const source = React.useMemo(
31
24
  () => ({ uri: imageSrcFromMediaItem(entry, [imageKey]) }),
32
25
  [imageKey, entry]
33
26
  );
34
27
 
35
- const { playerAnimationState } = useModalAnimationContext();
36
-
37
28
  if (!source) return <>{children}</>;
38
29
 
39
30
  return (
40
- <View
41
- style={
42
- playerAnimationState === PlayerAnimationStateEnum.maximize
43
- ? defaultImageDimensions
44
- : style
45
- }
46
- >
47
- <AnimationComponent
48
- style={style}
49
- animationType={ComponentAnimationType.player}
50
- additionalData={defaultImageDimensions}
51
- >
31
+ <View style={style}>
32
+ <View style={style}>
52
33
  <ImageBackground
53
34
  resizeMode="cover"
54
35
  style={imageSize}
@@ -57,7 +38,7 @@ const PlayerImageBackgroundComponent = ({
57
38
  >
58
39
  {children}
59
40
  </ImageBackground>
60
- </AnimationComponent>
41
+ </View>
61
42
  </View>
62
43
  );
63
44
  };
@@ -4,7 +4,6 @@ import * as React from "react";
4
4
  import { Text } from "react-native";
5
5
  import * as R from "ramda";
6
6
 
7
- import { isNil } from "@applicaster/zapp-react-native-utils/utils";
8
7
  import { GeneralContentScreen } from "../../GeneralContentScreen";
9
8
  import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
10
9
  import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
@@ -25,7 +24,6 @@ type Props = {
25
24
  isInsideContainer?: boolean;
26
25
  extraAnchorPointYOffset: number;
27
26
  river?: ZappRiver | ZappEntry;
28
- groupId: string;
29
27
  };
30
28
 
31
29
  export const River = (props: Props) => {
@@ -37,7 +35,6 @@ export const River = (props: Props) => {
37
35
  componentsMapExtraProps,
38
36
  isInsideContainer,
39
37
  extraAnchorPointYOffset,
40
- groupId,
41
38
  } = props;
42
39
 
43
40
  const { title: screenTitle, summary: screenSummary } = useNavbarState();
@@ -55,7 +52,7 @@ export const River = (props: Props) => {
55
52
  );
56
53
 
57
54
  const stringOrEmpty = (value: string | number | undefined): string =>
58
- isNil(value) ? "" : String(value);
55
+ R.isNil(value) ? "" : String(value);
59
56
 
60
57
  React.useEffect(() => {
61
58
  if (!isInsideContainer) {
@@ -95,10 +92,8 @@ export const River = (props: Props) => {
95
92
  <ScreenResolver
96
93
  screenType={river.type}
97
94
  screenId={screenId}
98
- screenData={Object.assign(river || {}, { groupId: extraData?.groupId })}
99
- componentsMapExtraProps={Object.assign(componentsMapExtraProps || {}, {
100
- groupId,
101
- })}
95
+ screenData={R.merge(river, { groupId: extraData?.groupId })}
96
+ componentsMapExtraProps={componentsMapExtraProps}
102
97
  {...extraData}
103
98
  />
104
99
  );
@@ -111,7 +106,6 @@ export const River = (props: Props) => {
111
106
  isScreenWrappedInContainer={isInsideContainer}
112
107
  extraAnchorPointYOffset={extraAnchorPointYOffset}
113
108
  componentsMapExtraProps={componentsMapExtraProps}
114
- groupId={groupId}
115
109
  />
116
110
  );
117
111
  };
@@ -1,11 +1,11 @@
1
1
  import { compose } from "ramda";
2
2
  import { River as RiverComponent } from "./River";
3
+ import { withTvEventHandler } from "./withTVEventHandler";
3
4
  import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
4
5
  import { withRiverDataLoader } from "./withRiverDataLoader";
5
- import { withFocusableGroupForContent } from "./withFocusableGroupForContent";
6
6
 
7
7
  export const River = compose(
8
+ withTvEventHandler,
8
9
  withComponentsMapOffsetContext,
9
- withRiverDataLoader,
10
- withFocusableGroupForContent
10
+ withRiverDataLoader
11
11
  )(RiverComponent);
@@ -0,0 +1,27 @@
1
+ /* eslint max-len: off */
2
+
3
+ import React from "react";
4
+ import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
5
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
6
+
7
+ export const withTvEventHandler = (Component) => {
8
+ return function WithTVEventHandler(props) {
9
+ const navigator = useNavigation();
10
+
11
+ const remoteHandler = (event) => {
12
+ const { eventType } = event;
13
+
14
+ const canGoBack = navigator.canGoBack();
15
+
16
+ if (eventType === "menu" && canGoBack) {
17
+ navigator.goBack();
18
+ }
19
+ };
20
+
21
+ return (
22
+ <TVEventHandlerComponent tvEventHandler={remoteHandler}>
23
+ <Component {...props} />
24
+ </TVEventHandlerComponent>
25
+ );
26
+ };
27
+ };
@@ -10,6 +10,8 @@ import {
10
10
  setFocusOnMenu,
11
11
  } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux";
12
12
 
13
+ import { waitUntilScreenRevealManagerIsReady } from "@applicaster/zapp-react-native-ui-components/Components/ScreenRevealManager/utils";
14
+
13
15
  type Return =
14
16
  | {
15
17
  onContent: true;
@@ -57,14 +59,22 @@ export const useInitialFocus = (): void => {
57
59
  React.useEffect(() => {
58
60
  const initialFocus = getInitialFocus(focusOnContent, isNavBarVisible);
59
61
 
60
- if (initialFocus.onContent) {
61
- setFocusOnContent(currentRoute);
62
+ if (initialFocus.onMenu) {
63
+ setFocusOnMenu(currentRoute);
62
64
 
63
65
  return;
64
66
  }
65
67
 
66
- if (initialFocus.onMenu) {
67
- setFocusOnMenu(currentRoute);
68
+ if (initialFocus.onContent) {
69
+ const subscription = waitUntilScreenRevealManagerIsReady().subscribe(
70
+ () => {
71
+ setFocusOnContent(currentRoute);
72
+ }
73
+ );
74
+
75
+ return () => {
76
+ subscription.unsubscribe();
77
+ };
68
78
  }
69
79
  }, []);
70
80
  };
@@ -2,6 +2,7 @@
2
2
 
3
3
  exports[`<Screen Component /> when the navbar should be hidden renders correctly 1`] = `
4
4
  <View
5
+ importantForAccessibility="yes"
5
6
  style={
6
7
  {
7
8
  "backgroundColor": "blue",
@@ -34,6 +35,7 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
34
35
 
35
36
  exports[`<Screen Component /> when the navbar should show renders correctly 1`] = `
36
37
  <View
38
+ importantForAccessibility="yes"
37
39
  style={
38
40
  {
39
41
  "backgroundColor": "blue",
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import React from "react";
3
- import { View } from "react-native";
3
+ import { AccessibilityInfo, findNodeHandle, View } from "react-native";
4
4
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
5
 
6
6
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
@@ -12,6 +12,7 @@ import {
12
12
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
13
13
  import {
14
14
  useCurrentScreenData,
15
+ useIsScreenActive,
15
16
  useNavbarState,
16
17
  useNavigation,
17
18
  useRoute,
@@ -57,8 +58,8 @@ export function Screen(_props: Props) {
57
58
  const hasMenu = shouldNavBarDisplayMenu(currentRiver, plugins);
58
59
 
59
60
  const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(
60
- getNavBarProps(currentRiver, pathname, title),
61
- [currentRiver, pathname]
61
+ () => getNavBarProps(currentRiver, pathname, title),
62
+ [currentRiver, pathname, title]
62
63
  );
63
64
 
64
65
  const NavBar = React.useMemo(
@@ -89,13 +90,29 @@ export function Screen(_props: Props) {
89
90
  [theme.app_background_color, backgroundColor]
90
91
  );
91
92
 
92
- // Set ready state when screen is rotated to desired orientation
93
+ const isActive = useIsScreenActive();
94
+
95
+ const ref = React.useRef(null);
93
96
  const isReady = useWaitForValidOrientation();
94
97
 
98
+ React.useEffect(() => {
99
+ if (ref.current && isActive && isReady) {
100
+ const nodeHandle = findNodeHandle(ref.current);
101
+
102
+ if (nodeHandle != null) {
103
+ AccessibilityInfo.setAccessibilityFocus(nodeHandle);
104
+ }
105
+ }
106
+ }, [isActive, isReady]);
107
+
95
108
  // We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
96
109
  // This saves unnecessary re-renders and user will not see distorted aspect screen.
97
110
  return (
98
- <View style={style}>
111
+ <View
112
+ ref={ref}
113
+ style={style}
114
+ importantForAccessibility={!isActive ? "no-hide-descendants" : "yes"}
115
+ >
99
116
  {isReady ? (
100
117
  <>
101
118
  {navBarProps ? <NavBar {...navBarProps} hasMenu={hasMenu} /> : null}
@@ -16,6 +16,7 @@ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
16
16
  import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
17
17
 
18
18
  import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
19
+ import { ScreenResultCallback } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/callbackNavigationAction";
19
20
 
20
21
  const logger = componentsLogger.addSubsystem("ScreenResolver");
21
22
 
@@ -26,6 +27,7 @@ type Props = {
26
27
  feedId?: string;
27
28
  feedTitle?: string;
28
29
  focused?: boolean;
30
+ resultCallback?: ScreenResultCallback;
29
31
  parentFocus?: {
30
32
  nextFocusDown?: React.Ref<any>;
31
33
  nextFocusRight?: React.Ref<any>;
@@ -61,13 +63,17 @@ export function ScreenResolverComponent(props: Props) {
61
63
 
62
64
  React.useEffect(() => {
63
65
  setScreenContext(rivers[screenId]);
64
- }, [screenId]);
66
+ }, [rivers, screenId, setScreenContext]);
65
67
 
66
- const callbackAction = useCallbackActions(
68
+ const parentCallback = props.resultCallback;
69
+
70
+ const screenAction = useCallbackActions(
67
71
  hookPlugin || screenData,
68
72
  screenData.callback
69
73
  );
70
74
 
75
+ const callbackAction = parentCallback || screenAction;
76
+
71
77
  const ScreenPlugin =
72
78
  findPluginByType(screenType, plugins, { skipWarning: true }) ||
73
79
  findPluginByIdentifier(screenType, plugins) ||
@@ -0,0 +1,23 @@
1
+ import { ReplaySubject } from "rxjs";
2
+ import { pairwise, filter, first } from "rxjs/operators";
3
+
4
+ // we are interested in last 2 events, because we wait transition from <false> to <true>
5
+ const screenRevealManagerSubject$ = new ReplaySubject<boolean>(2);
6
+
7
+ export const emitScreenRevealManagerIsReadyToShow = () => {
8
+ screenRevealManagerSubject$.next(true);
9
+ };
10
+
11
+ export const emitScreenRevealManagerIsNotReadyToShow = () => {
12
+ screenRevealManagerSubject$.next(false);
13
+ };
14
+
15
+ export const waitUntilScreenRevealManagerIsReady = () => {
16
+ return screenRevealManagerSubject$.pipe(
17
+ pairwise(), // emit consecutive pairs: [prev, curr]
18
+ filter(
19
+ ([previousIsReady, currentIsReady]) => !previousIsReady && currentIsReady
20
+ ), // detect transition from not_ready to ready
21
+ first()
22
+ );
23
+ };
@@ -1,21 +1,23 @@
1
1
  import * as React from "react";
2
- import { Animated } from "react-native";
2
+ import { Animated, StyleSheet } from "react-native";
3
3
  import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
4
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
4
  import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
5
+ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
6
6
 
7
7
  import { ScreenRevealManager } from "./ScreenRevealManager";
8
+ import {
9
+ emitScreenRevealManagerIsReadyToShow,
10
+ emitScreenRevealManagerIsNotReadyToShow,
11
+ } from "./utils";
8
12
 
9
- const flex = platformSelect({
10
- tvos: 1,
11
- android_tv: 1,
12
- web: undefined,
13
- samsung_tv: undefined,
14
- lg_tv: undefined,
15
- default: undefined,
13
+ const styles = StyleSheet.create({
14
+ container: {
15
+ ...StyleSheet.absoluteFillObject,
16
+ position: "absolute",
17
+ },
16
18
  });
17
19
 
18
- export const TIMEOUT = 500; // 500 ms
20
+ export const TIMEOUT = 300; // 300 ms
19
21
 
20
22
  const HIDDEN = 0; // opacity = 0
21
23
 
@@ -29,29 +31,48 @@ export const withScreenRevealManager = (Component) => {
29
31
  return function WithScreenRevealManager(props: Props) {
30
32
  const { componentsToRender } = props;
31
33
 
32
- const [isReadyToShow, setIsReadyToShow] = React.useState(false);
34
+ const [isContentReadyToBeShown, setIsContentReadyToBeShown] =
35
+ React.useState(false);
33
36
 
34
- const handleSetIsReadyToShow = React.useCallback(() => {
35
- setIsReadyToShow(true);
37
+ const [isShowOverlay, setIsShowOverlay] = React.useState(true);
38
+
39
+ const theme = useTheme<BaseThemePropertiesTV>();
40
+
41
+ const handleSetIsContentReadyToBeShown = React.useCallback(() => {
42
+ setIsContentReadyToBeShown(true);
36
43
  }, []);
37
44
 
38
45
  const managerRef = useRefWithInitialValue<ScreenRevealManager>(
39
- () => new ScreenRevealManager(componentsToRender, handleSetIsReadyToShow)
46
+ () =>
47
+ new ScreenRevealManager(
48
+ componentsToRender,
49
+ handleSetIsContentReadyToBeShown
50
+ )
40
51
  );
41
52
 
42
53
  const opacityRef = useRefWithInitialValue<Animated.Value>(
43
- () => new Animated.Value(HIDDEN)
54
+ () => new Animated.Value(SHOWN)
44
55
  );
45
56
 
46
57
  React.useEffect(() => {
47
- if (isReadyToShow) {
58
+ if (!isContentReadyToBeShown) {
59
+ emitScreenRevealManagerIsNotReadyToShow();
60
+ } else {
61
+ emitScreenRevealManagerIsReadyToShow();
62
+ }
63
+ }, [isContentReadyToBeShown]);
64
+
65
+ React.useEffect(() => {
66
+ if (isContentReadyToBeShown) {
48
67
  Animated.timing(opacityRef.current, {
49
- toValue: SHOWN,
68
+ toValue: HIDDEN,
50
69
  duration: TIMEOUT,
51
70
  useNativeDriver: true,
52
- }).start();
71
+ }).start(() => {
72
+ setIsShowOverlay(false);
73
+ });
53
74
  }
54
- }, [isReadyToShow]);
75
+ }, [isContentReadyToBeShown]);
55
76
 
56
77
  if (isFirstComponentScreenPicker(componentsToRender)) {
57
78
  // for screen-picker with have additional internal ComponentsMap, no need to add this wrapper
@@ -59,10 +80,7 @@ export const withScreenRevealManager = (Component) => {
59
80
  }
60
81
 
61
82
  return (
62
- <Animated.View
63
- style={{ opacity: opacityRef.current, flex }}
64
- testID="animated-component"
65
- >
83
+ <>
66
84
  <Component
67
85
  {...props}
68
86
  initialNumberToLoad={
@@ -73,7 +91,19 @@ export const withScreenRevealManager = (Component) => {
73
91
  }
74
92
  onLoadFailedFromScreenRevealManager={managerRef.current.onLoadFailed}
75
93
  />
76
- </Animated.View>
94
+ {isShowOverlay ? (
95
+ <Animated.View
96
+ style={[
97
+ styles.container,
98
+ {
99
+ opacity: opacityRef.current,
100
+ backgroundColor: theme.app_background_color,
101
+ },
102
+ ]}
103
+ testID="animated-component"
104
+ />
105
+ ) : null}
106
+ </>
77
107
  );
78
108
  };
79
109
  };
@@ -8,6 +8,7 @@ import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
8
8
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
9
9
  import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
10
10
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
11
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
11
12
  import { Gutter } from "../Gutter";
12
13
  import Tab from "./Tab";
13
14
  import { getStyles } from "./styles";
@@ -28,11 +29,14 @@ const TabsComponent = ({
28
29
  style,
29
30
  selectedEntryIndex,
30
31
  setSelectedEntry,
32
+ accessibility,
31
33
  }: TabsProps & Partial<TabsSelectionContextType>) => {
32
34
  const configuration = useConfiguration();
33
35
  const config = applyFontConfig(configuration);
34
36
  const styles = useMemo(() => getStyles(config), [config]);
35
37
 
38
+ const accessibilityManager = useAccessibilityManager({});
39
+
36
40
  const {
37
41
  tab_bar_gutter: horizontalGutter,
38
42
  tab_bar_background_image: bgImage,
@@ -60,10 +64,20 @@ const TabsComponent = ({
60
64
  );
61
65
 
62
66
  const onListElementFocus = useCallback(
63
- (index) => {
67
+ (index, isSelected: boolean, item: ZappEntry) => {
68
+ if (isSelected) {
69
+ accessibilityManager.readText({
70
+ text: `${accessibility?.selectedHint} ${item.title}`,
71
+ });
72
+ } else {
73
+ accessibilityManager.readText({
74
+ text: `${accessibility?.hint} ${item.title}`,
75
+ });
76
+ }
77
+
64
78
  scrollToSelectedIndex(index, VIEW_POSITION);
65
79
  },
66
- [scrollToSelectedIndex]
80
+ [scrollToSelectedIndex, accessibility]
67
81
  );
68
82
 
69
83
  const renderItem = useCallback(
@@ -94,7 +108,7 @@ const TabsComponent = ({
94
108
  id={itemId}
95
109
  testID={itemId}
96
110
  preferredFocus={isSelected}
97
- onFocus={() => onListElementFocus(index)}
111
+ onFocus={() => onListElementFocus(index, isSelected, item)}
98
112
  onPress={() => setSelectedEntry && setSelectedEntry(item)}
99
113
  style={style}
100
114
  >
@@ -149,6 +163,9 @@ const TabsComponent = ({
149
163
  shouldUsePreferredFocus
150
164
  isWithMemory={false}
151
165
  nextFocusDown={parentFocus?.nextFocusDown}
166
+ onFocus={() => {
167
+ accessibilityManager.addHeading(accessibility?.announcement);
168
+ }}
152
169
  >
153
170
  <View style={tabs}>
154
171
  <ImageBackground
@@ -9,6 +9,7 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
9
9
  <View>
10
10
  <View
11
11
  collapsable={false}
12
+ renderToHardwareTextureAndroid={false}
12
13
  style={
13
14
  {
14
15
  "opacity": 1,