@applicaster/zapp-react-native-ui-components 12.0.0-rc.14 → 12.0.0-rc.141

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 (171) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/BaseFocusable/index.tsx +3 -3
  5. package/Components/Cell/Cell.tsx +40 -12
  6. package/Components/Cell/CellWithFocusable.tsx +40 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +5 -9
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/Focusable/Focusable.tsx +6 -1
  10. package/Components/Focusable/__tests__/index.android.test.tsx +72 -0
  11. package/Components/Focusable/index.android.tsx +15 -9
  12. package/Components/FocusableCell/index.tsx +7 -7
  13. package/Components/FocusableGroup/index.tsx +11 -2
  14. package/Components/FocusableList/FocusableChild.ts +26 -16
  15. package/Components/FocusableList/FocusableItem.tsx +1 -1
  16. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  17. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  18. package/Components/FocusableList/index.tsx +37 -37
  19. package/Components/FocusableScrollView/index.tsx +1 -1
  20. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  21. package/Components/FreezeWithCallback/LICENSE +21 -0
  22. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  23. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  24. package/Components/FreezeWithCallback/index.tsx +3 -0
  25. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  26. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  27. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  28. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  29. package/Components/HookRenderer/index.tsx +1 -6
  30. package/Components/Image/Image.android.tsx +4 -26
  31. package/Components/Image/Image.tsx +18 -2
  32. package/Components/Image/utils/index.ts +39 -0
  33. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  34. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  35. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  36. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  37. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  38. package/Components/Layout/TV/__tests__/index.test.tsx +20 -108
  39. package/Components/Layout/TV/index.tsx +15 -84
  40. package/Components/Layout/TV/index.web.tsx +33 -0
  41. package/Components/Layout/index.tsx +15 -11
  42. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +14 -7
  43. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -117
  44. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +27 -9
  45. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  46. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +16 -1
  47. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  48. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -0
  49. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
  50. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  51. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  52. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  53. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +37 -2
  54. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  55. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  56. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  57. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  58. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  59. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  60. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  61. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  62. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  63. package/Components/MasterCell/dataAdapter.ts +21 -7
  64. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  65. package/Components/MasterCell/index.tsx +5 -3
  66. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  67. package/Components/MasterCell/utils/index.ts +31 -34
  68. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  69. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  70. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  71. package/Components/ModalComponent/Button/Item.tsx +82 -0
  72. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  73. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  74. package/Components/ModalComponent/Button/assets.ts +4 -0
  75. package/Components/ModalComponent/Button/index.tsx +111 -0
  76. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  77. package/Components/ModalComponent/Header/Title.tsx +70 -0
  78. package/Components/ModalComponent/Header/assets.ts +4 -0
  79. package/Components/ModalComponent/Header/index.tsx +71 -0
  80. package/Components/ModalComponent/Header/utils.ts +79 -0
  81. package/Components/ModalComponent/index.tsx +38 -0
  82. package/Components/ModalComponent/utils.ts +126 -0
  83. package/Components/Navigator/StackNavigator.tsx +57 -0
  84. package/Components/Navigator/index.ts +1 -0
  85. package/Components/PlayerContainer/PlayerContainer.tsx +80 -39
  86. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  87. package/Components/PlayerImageBackground/index.tsx +34 -8
  88. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  89. package/Components/River/RefreshControl.tsx +55 -1
  90. package/Components/River/TV/River.tsx +2 -25
  91. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  92. package/Components/River/__tests__/componentsMap.test.js +7 -0
  93. package/Components/River/useScreenConfiguration.ts +2 -2
  94. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  95. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  96. package/Components/RouteManager/index.tsx +4 -2
  97. package/Components/Screen/TV/hooks/index.ts +1 -0
  98. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  99. package/Components/Screen/TV/index.web.tsx +178 -0
  100. package/Components/Screen/__tests__/Screen.test.tsx +43 -75
  101. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  102. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  103. package/Components/Screen/index.tsx +104 -65
  104. package/Components/Screen/navigationHandler.ts +6 -85
  105. package/Components/Screen/orientationHandler.ts +18 -7
  106. package/Components/Screen/utils.ts +16 -0
  107. package/Components/ScreenResolver/index.tsx +10 -13
  108. package/Components/Tabs/TV/styles.ts +1 -1
  109. package/Components/TrackedView/index.tsx +6 -3
  110. package/Components/Transitioner/Scene.tsx +39 -26
  111. package/Components/Transitioner/Transitioner.tsx +56 -48
  112. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  113. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  114. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
  115. package/Components/VideoLive/LiveImageManager.ts +65 -11
  116. package/Components/VideoLive/PlayerLiveImageComponent.tsx +132 -95
  117. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  118. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +24 -27
  119. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +60 -0
  120. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +401 -0
  121. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +172 -0
  122. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +475 -0
  123. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
  124. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  125. package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
  126. package/Components/VideoModal/PlayerDetails.tsx +21 -4
  127. package/Components/VideoModal/PlayerWrapper.tsx +115 -55
  128. package/Components/VideoModal/VideoModal.tsx +32 -43
  129. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +6 -1
  130. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  131. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
  132. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +358 -166
  133. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  134. package/Components/VideoModal/utils.ts +8 -5
  135. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  136. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  137. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  138. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  139. package/Components/Viewport/utils.js +1 -1
  140. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +7 -3
  141. package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
  142. package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
  143. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
  144. package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
  145. package/Components/ZappUIComponent/index.tsx +22 -12
  146. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  147. package/Components/index.js +2 -0
  148. package/Contexts/CachedDimensionsContext/index.ts +13 -9
  149. package/Contexts/ConfirmDialogState/index.ts +1 -1
  150. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  151. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  152. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  153. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  154. package/Contexts/FocusableGroupContext/index.ts +7 -0
  155. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  156. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  157. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  158. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  159. package/Contexts/ScreenContext/index.tsx +101 -30
  160. package/Contexts/ScreenDataContext/index.tsx +20 -0
  161. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  162. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  163. package/const.ts +6 -0
  164. package/events/index.ts +1 -0
  165. package/index.js +3 -0
  166. package/package.json +5 -5
  167. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  168. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  169. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  170. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  171. /package/Contexts/{index.js → index.ts} +0 -0
@@ -1,28 +1,17 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
- import {
5
- useIsNavBarVisible,
6
- useNavigation,
7
- } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
5
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
9
6
 
10
- import {
11
- getNavigationProps,
12
- resolveNavigationPlugin,
13
- routeIsPlayerScreen,
14
- } from "@applicaster/zapp-react-native-utils/navigationUtils";
15
-
16
7
  import { getBackgroundImageUrl } from "../utils";
17
8
  import { LayoutContainer } from "./LayoutContainer";
18
- import { NavBarContainer } from "./NavBarContainer";
19
9
  import { ScreenContainer } from "./ScreenContainer";
20
- import { TransitionOverlay } from "./TransitionOverlay";
21
10
 
22
11
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
23
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
24
12
  import { PathnameContext } from "../../../Contexts/PathnameContext";
25
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
13
+ import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
14
+ import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
26
15
 
27
16
  type Components = {
28
17
  NavBar: React.ComponentType<any>;
@@ -43,20 +32,9 @@ type Props = {
43
32
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
44
33
  const navigator = useNavigation();
45
34
  const theme = useTheme();
46
- const { title } = useNavbarState();
47
- const { activeRiver, currentRoute } = navigator;
48
-
49
- const {
50
- appState: { appReady = false } = {},
51
- remoteConfigurations,
52
- plugins = [],
53
- } = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
54
35
 
55
- const navigationProps = getNavigationProps({
56
- navigator,
57
- title,
58
- category: "menu",
59
- });
36
+ const { appState: { appReady = false } = {}, remoteConfigurations } =
37
+ usePickFromState(["appState", "remoteConfigurations", "plugins"]);
60
38
 
61
39
  const backgroundColor = React.useMemo(() => theme.app_background_color, []);
62
40
 
@@ -65,25 +43,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
65
43
  [remoteConfigurations]
66
44
  );
67
45
 
68
- const menuPlugin = React.useMemo(
69
- () =>
70
- resolveNavigationPlugin({
71
- category: "menu",
72
- navigations: activeRiver?.navigations,
73
- plugins,
74
- }) as QuickBrickPlugin,
75
- []
76
- );
77
-
78
- const NavBar = React.useMemo(
79
- () => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
80
- []
81
- );
82
-
83
- const navBarVisible = useIsNavBarVisible();
84
-
85
- const [navBarReady, setNavBarReady] = React.useState(false);
86
-
87
46
  if (!appReady) {
88
47
  return null;
89
48
  }
@@ -96,46 +55,18 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
96
55
  backgroundImageUrl={backgroundImageUrl}
97
56
  {...R.omit(["ref"])(ComponentsExtraProps?.Background)}
98
57
  >
99
- {!isApplePlatform() ? (
100
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
101
- <NavBar
102
- ref={ComponentsExtraProps?.NavBar?.ref}
103
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
104
- menuPlugin={menuPlugin}
105
- navigationProps={navigationProps}
106
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
107
- />
108
- </NavBarContainer>
109
- ) : null}
110
-
111
- {navBarReady ? (
112
- /**
113
- Need to re-mount this component on each navigation event
114
- It's a hack to work around the fact that we don't support
115
- correct screen rendering in our navigator (shared currentRoute state)
116
- **/
58
+ <ScreenDataContext.Provider value={navigator.data}>
117
59
  <PathnameContext.Provider value={navigator.currentRoute}>
118
- <ScreenContainer>{children}</ScreenContainer>
60
+ <ScreenContextProvider pathname={navigator.currentRoute}>
61
+ <ScreenContainer
62
+ ComponentsExtraProps={ComponentsExtraProps}
63
+ NavBar={Components.NavBar}
64
+ >
65
+ {children}
66
+ </ScreenContainer>
67
+ </ScreenContextProvider>
119
68
  </PathnameContext.Provider>
120
- ) : null}
121
-
122
- {isApplePlatform() ? (
123
- /**
124
- Render NavBarContainer over ScreenContainer to let tvOS native
125
- focus manager works correctly to focus nav bar items first
126
- **/
127
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
128
- <NavBar
129
- ref={ComponentsExtraProps?.NavBar?.ref}
130
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
131
- menuPlugin={menuPlugin}
132
- navigationProps={navigationProps}
133
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
134
- />
135
- </NavBarContainer>
136
- ) : null}
137
-
138
- <TransitionOverlay />
69
+ </ScreenDataContext.Provider>
139
70
  </Components.Background>
140
71
  </ScreenLayoutContextProvider>
141
72
  </LayoutContainer>
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import { pathOr } from "ramda";
3
+
4
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
+
6
+ import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
7
+ import { StackNavigator } from "../../Navigator";
8
+
9
+ type Components = {
10
+ NavBar: React.ComponentType<any>;
11
+ Background: React.ComponentType<any>;
12
+ };
13
+
14
+ type Props = {
15
+ Components: Components;
16
+ };
17
+
18
+ const Layout = ({ Components }: Props) => {
19
+ const { appState } = usePickFromState(["appState"]);
20
+ const appReady = pathOr(false, ["appReady"], appState);
21
+
22
+ if (!appReady) {
23
+ return null;
24
+ }
25
+
26
+ return (
27
+ <ScreenLayoutContextProvider>
28
+ <StackNavigator Components={Components} />
29
+ </ScreenLayoutContextProvider>
30
+ );
31
+ };
32
+
33
+ export default Layout;
@@ -1,20 +1,24 @@
1
1
  import * as React from "react";
2
- import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
3
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
2
+ import {
3
+ isTV,
4
+ platformSelect,
5
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
5
6
 
6
7
  import Mobile from "./Mobile";
7
- import TV from "./TV";
8
8
 
9
- export default function Layout(props) {
10
- const { currentRoute: pathname } = useNavigation();
9
+ import TVWeb from "./TV/index.web";
10
+ import TVDefault from "./TV/index";
11
+
12
+ const TV = platformSelect({
13
+ samsung_tv: TVWeb,
14
+ lg_tv: TVWeb,
15
+ web: TVWeb,
16
+ default: TVDefault,
17
+ });
11
18
 
19
+ export default function Layout(props) {
12
20
  if (isTV()) {
13
- return (
14
- <ScreenContextProvider pathname={pathname}>
15
- <TV {...props} />
16
- </ScreenContextProvider>
17
- );
21
+ return <TV {...props} />;
18
22
  } else {
19
23
  return <Mobile {...props} />;
20
24
  }
@@ -25,6 +25,7 @@ type Props = {
25
25
  testID?: string;
26
26
  accessibilityLabel?: string;
27
27
  cellUUID?: string;
28
+ extraProps?: Record<string, any>;
28
29
  };
29
30
 
30
31
  function isStringAsset(asset) {
@@ -52,6 +53,7 @@ export function ActionButton(props: Props) {
52
53
  const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
53
54
  const actionContext = useActions(action?.identifier);
54
55
 
56
+ // TODO: add subscription API for action availability
55
57
  const actionDisabled =
56
58
  typeof actionContext?.isActionAvailable === "function" &&
57
59
  !actionContext.isActionAvailable(item);
@@ -64,20 +66,24 @@ export function ActionButton(props: Props) {
64
66
  );
65
67
 
66
68
  useEffect(() => {
67
- if (actionDisabled || !actionContext) return;
68
-
69
- setActionState(actionContext.initialEntryState(item));
70
- }, [actionDisabled, item?.id]);
69
+ if (!((actionDisabled || !actionContext) && actionState !== null)) {
70
+ setActionState(actionContext.initialEntryState(item));
71
+ }
72
+ }, [actionDisabled, item?.id, actionContext, action]);
71
73
 
72
74
  const onPress = useCallback(() => {
73
75
  actionContext.invokeAction(item, {
74
- updateState: setActionState,
76
+ updateState: (state) => {
77
+ setActionState(state);
78
+ },
75
79
  });
76
- }, [actionState, actionContext?.state, setActionState, item?.id]);
80
+ }, [actionState, actionContext?.state, item?.id]);
77
81
 
78
82
  useEffect(() => {
79
83
  if (typeof actionContext?.addListener === "function") {
80
- return actionContext?.addListener(item.id as string, setActionState);
84
+ return actionContext?.addListener(String(item.id), (state) => {
85
+ setActionState(state);
86
+ });
81
87
  }
82
88
  }, [item?.id]);
83
89
 
@@ -108,6 +114,7 @@ export function ActionButton(props: Props) {
108
114
  flavour={flavour}
109
115
  asset={getAssetValue(asset, flavour)}
110
116
  cellUUID={cellUUID}
117
+ {...(props?.extraProps ?? {})}
111
118
  />
112
119
  )}
113
120
  </TouchableOpacity>
@@ -7,50 +7,28 @@ type BorderPosition = "inside" | "outside" | "center";
7
7
  interface Props {
8
8
  style: ImageStyle | ViewStyle;
9
9
  borderPosition: BorderPosition;
10
+ borderPaddingTop: number;
11
+ borderPaddingRight: number;
12
+ borderPaddingBottom: number;
13
+ borderPaddingLeft: number;
10
14
  children: React.ReactNode;
11
15
  }
12
16
 
13
- const MARGINS = [
14
- "marginTop",
15
- "marginBottom",
16
- "marginLeft",
17
- "marginRight",
18
- ] as const;
19
-
20
- const PADDINGS = [
21
- "paddingTop",
22
- "paddingBottom",
23
- "paddingLeft",
24
- "paddingRight",
25
- ] as const;
26
-
27
- const isPercentageValue = (value: number | string) => {
28
- if (typeof value === "string" && value.endsWith("%")) {
29
- return true;
30
- }
31
-
32
- return false;
33
- };
34
-
35
- const calculateContainerSpacing = ({
36
- spacingKey,
37
- style,
38
- additionalSpacing,
39
- }: {
40
- spacingKey: typeof MARGINS[number] | typeof PADDINGS[number];
41
- style: ImageStyle | ViewStyle;
42
- additionalSpacing: number;
43
- }) => {
44
- return {
45
- [spacingKey]:
46
- toNumberWithDefaultZero(style[spacingKey]) + additionalSpacing,
47
- };
48
- };
49
-
50
- const getContainerBorderWidth = (
51
- borderPosition: BorderPosition,
52
- borderWidth
53
- ) => {
17
+ const COLOR_TRANSPARENT = "transparent";
18
+
19
+ const styles = StyleSheet.create({
20
+ container: {
21
+ overflow: "visible",
22
+ borderWidth: 0,
23
+ borderColor: COLOR_TRANSPARENT,
24
+ },
25
+ border: {
26
+ ...StyleSheet.absoluteFillObject,
27
+ zIndex: 1,
28
+ },
29
+ });
30
+
31
+ const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
54
32
  switch (borderPosition) {
55
33
  case "inside":
56
34
  return 0;
@@ -63,105 +41,96 @@ const getContainerBorderWidth = (
63
41
  }
64
42
  };
65
43
 
66
- const getContainerPadding = (borderPosition: BorderPosition, borderWidth) => {
67
- switch (borderPosition) {
68
- case "inside":
69
- return borderWidth;
70
- case "center":
71
- return borderWidth / 2;
72
- case "outside":
73
- return 0;
74
- default:
75
- return 0;
76
- }
77
- };
78
-
79
- const InsideBorder = ({
44
+ const Border = ({
80
45
  style,
46
+ padding,
81
47
  borderPosition,
82
48
  }: {
83
49
  style: ViewStyle;
50
+ padding: ViewStyle;
84
51
  borderPosition: BorderPosition;
85
52
  }) => {
86
- if (borderPosition === "outside") {
53
+ if (!borderPosition) {
87
54
  return null;
88
55
  }
89
56
 
90
- const insideBorderWidth =
91
- borderPosition === "center" ? style.borderWidth / 2 : style.borderWidth;
57
+ const borderWidth = toNumberWithDefaultZero(style.borderWidth);
58
+ const containerPadding = getBorderPadding(borderPosition, borderWidth);
59
+
60
+ const initialBorderRadius = toNumberWithDefaultZero(style.borderRadius);
61
+ const paddingTop = toNumberWithDefaultZero(padding.paddingTop);
62
+ const paddingRight = toNumberWithDefaultZero(padding.paddingRight);
63
+ const paddingBottom = toNumberWithDefaultZero(padding.paddingBottom);
64
+ const paddingLeft = toNumberWithDefaultZero(padding.paddingLeft);
65
+
66
+ const borderRadiusStyle = initialBorderRadius
67
+ ? {
68
+ borderTopLeftRadius:
69
+ initialBorderRadius +
70
+ containerPadding +
71
+ Math.min(paddingTop, paddingLeft),
72
+ borderTopRightRadius:
73
+ initialBorderRadius +
74
+ containerPadding +
75
+ Math.min(paddingTop, paddingRight),
76
+ borderBottomLeftRadius:
77
+ initialBorderRadius +
78
+ containerPadding +
79
+ Math.min(paddingBottom, paddingLeft),
80
+ borderBottomRightRadius:
81
+ initialBorderRadius +
82
+ containerPadding +
83
+ Math.min(paddingBottom, paddingRight),
84
+ }
85
+ : {
86
+ borderTopLeftRadius: 0,
87
+ borderTopRightRadius: 0,
88
+ borderBottomLeftRadius: 0,
89
+ borderBottomRightRadius: 0,
90
+ };
92
91
 
93
92
  return (
94
93
  <View
94
+ pointerEvents="none"
95
95
  style={{
96
- ...StyleSheet.absoluteFillObject,
97
- borderWidth: insideBorderWidth,
96
+ ...styles.border,
97
+ right: -containerPadding - paddingRight,
98
+ bottom: -containerPadding - paddingBottom,
99
+ left: -containerPadding - paddingLeft,
100
+ top: -containerPadding - paddingTop,
101
+ borderWidth,
98
102
  borderColor: style.borderColor,
99
- borderRadius: style.borderRadius,
103
+ ...borderRadiusStyle,
100
104
  }}
101
105
  />
102
106
  );
103
107
  };
104
108
 
105
109
  export const BorderContainerView = (props: Props) => {
106
- const { style, children } = props;
107
- // Return border position prop after re-implementing
108
- const borderPosition = "outside";
109
-
110
- const borderWidth = toNumberWithDefaultZero(style.borderWidth);
111
- const spacing = getContainerPadding(borderPosition, borderWidth);
112
-
113
- const borderStyleForMissingBorder =
114
- style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
115
-
116
- const updatedMargins = MARGINS.reduce((acc, margin) => {
117
- const marginValue = calculateContainerSpacing({
118
- spacingKey: margin,
119
- style,
120
- additionalSpacing: spacing,
121
- });
122
-
123
- return { ...acc, ...marginValue };
124
- }, {});
125
-
126
- const updatedPaddings = PADDINGS.reduce((acc, padding) => {
127
- const paddingValue = calculateContainerSpacing({
128
- spacingKey: padding,
129
- style,
130
- additionalSpacing: spacing,
131
- });
132
-
133
- return { ...acc, ...paddingValue };
134
- }, {});
135
-
136
- const updatedWidth = style.width
137
- ? isPercentageValue(style.width)
138
- ? style.width
139
- : toNumberWithDefaultZero(style.width) - spacing * 2
140
- : undefined;
141
-
142
- const updatedHeight = style.height
143
- ? isPercentageValue(style.height)
144
- ? style.height
145
- : toNumberWithDefaultZero(style.height) - spacing * 2
146
- : undefined;
147
-
148
- const containerStyle = {
149
- borderWidth: getContainerBorderWidth(borderPosition, borderWidth),
150
- padding: spacing,
151
- ...updatedMargins,
152
- ...updatedPaddings,
153
- width: updatedWidth,
154
- height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
- };
110
+ const {
111
+ borderPosition,
112
+ borderPaddingTop,
113
+ borderPaddingRight,
114
+ borderPaddingBottom,
115
+ borderPaddingLeft,
116
+ style,
117
+ children,
118
+ } = props;
119
+
120
+ const padding =
121
+ borderPosition === "outside"
122
+ ? {
123
+ paddingTop: borderPaddingTop,
124
+ paddingRight: borderPaddingRight,
125
+ paddingBottom: borderPaddingBottom,
126
+ paddingLeft: borderPaddingLeft,
127
+ }
128
+ : {};
157
129
 
158
130
  return (
159
- <View {...props} style={[style, containerStyle]}>
131
+ <View pointerEvents="box-none" {...props} style={[style, styles.container]}>
132
+ <Border style={style} padding={padding} borderPosition={borderPosition} />
160
133
  {children}
161
- <InsideBorder
162
- style={{ ...style, ...borderStyleForMissingBorder }}
163
- borderPosition={borderPosition}
164
- />
165
134
  </View>
166
135
  );
167
136
  };
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  compact,
3
3
  ifElseFocusedSelected,
4
+ ifElseSelected,
4
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
6
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
7
 
6
8
  import { getPositionStyles } from "./utils";
7
9
 
@@ -12,9 +14,15 @@ type Props = {
12
14
  value: Function;
13
15
  state: string;
14
16
  visible?: Boolean;
17
+ isMobile?: Boolean;
15
18
  };
16
19
 
17
- export const CellBadge = ({ value, state, visible = true }: Props) => {
20
+ export const CellBadge = ({
21
+ value,
22
+ state,
23
+ visible = true,
24
+ isMobile = false,
25
+ }: Props) => {
18
26
  if (!value("cell_badge_switch") || !visible) {
19
27
  return null;
20
28
  }
@@ -24,7 +32,11 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
24
32
  return {
25
33
  type: View, // Cell badge view
26
34
  style: {
27
- flex: 1,
35
+ flex: platformSelect({
36
+ tvos: 0,
37
+ android_tv: 0,
38
+ default: 1,
39
+ }),
28
40
  position: "absolute",
29
41
  ...getPositionStyles(position, {
30
42
  width: value("cell_badge_width"),
@@ -45,13 +57,19 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
45
57
  data: [
46
58
  {
47
59
  func: () => {
48
- return ifElseFocusedSelected(
49
- state,
50
- value("cell_badge_focused"),
51
- value("cell_badge_selected"),
52
- value("cell_badge_focused_selected"),
53
- value("cell_badge_default")
54
- );
60
+ return isMobile
61
+ ? ifElseSelected(
62
+ state,
63
+ value("cell_badge_selected"),
64
+ value("cell_badge_default")
65
+ )
66
+ : ifElseFocusedSelected(
67
+ state,
68
+ value("cell_badge_focused"),
69
+ value("cell_badge_selected"),
70
+ value("cell_badge_focused_selected"),
71
+ value("cell_badge_default")
72
+ );
55
73
  },
56
74
  args: [],
57
75
  propName: "uri",
@@ -4,6 +4,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
4
4
 
5
5
  type DynamicBadgeProps = {
6
6
  cellUUID?: string;
7
+ uri?: string;
7
8
  };
8
9
 
9
10
  const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
@@ -12,11 +13,12 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
12
13
  // TODO: Initial value should depends on player state (playing or not)
13
14
  const [showImage, setShowImage] = React.useState(true);
14
15
  const player = usePlayer(playerId);
16
+ const uri = props?.uri;
15
17
 
16
18
  React.useEffect(() => {
17
19
  if (playerId && player) {
18
20
  return player.addListener({
19
- id: "dynamic-badges",
21
+ id: `dynamic-badges-${uri}`,
20
22
  listener: {
21
23
  onPlayerClose: () => {
22
24
  setShowImage(true);
@@ -35,7 +37,7 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
35
37
  } else {
36
38
  setShowImage(true);
37
39
  }
38
- }, [player]);
40
+ }, [player, uri]);
39
41
 
40
42
  if (!showImage) {
41
43
  return null;
@@ -4,6 +4,8 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
5
  import * as R from "ramda";
6
6
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
8
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
7
9
 
8
10
  const { Logger } = getXray();
9
11
 
@@ -35,12 +37,19 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
35
37
 
36
38
  const focusableId = getFocusableId(prefixId, suffixId);
37
39
 
38
- const focused = focusableId === focusedButtonId;
40
+ const focused =
41
+ focusableId === focusedButtonId ||
42
+ toBooleanWithDefaultFalse(otherProps.focused);
39
43
 
40
44
  const additionalStyles = focused ? focusedStyles : normalStyles;
41
45
 
42
46
  const actionContext = useActions(pluginIdentifier);
43
47
 
48
+ const accessibilityManager = useAccessibilityManager({});
49
+
50
+ const { ttsLabel = "" } =
51
+ actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
52
+
44
53
  const onPress = (event) => {
45
54
  event?.preventDefault?.();
46
55
 
@@ -85,6 +94,12 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
85
94
  mouse: focusable.mouse,
86
95
  });
87
96
  });
97
+
98
+ if (ttsLabel) {
99
+ accessibilityManager.readText({
100
+ text: ttsLabel,
101
+ });
102
+ }
88
103
  };
89
104
 
90
105
  const handleBlur = (_focusable, _direction) => {