@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4840257570 → 12.0.0-alpha.4885205607
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/BaseFocusable/index.tsx +3 -3
- package/Components/Cell/Cell.tsx +30 -9
- package/Components/Cell/CellWithFocusable.tsx +23 -9
- package/Components/Cell/TvOSCellComponent.tsx +3 -7
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
- package/Components/Layout/TV/index.tsx +14 -67
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -112
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +32 -29
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +5 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -0
- package/Components/River/RefreshControl.tsx +2 -2
- package/Components/River/TV/River.tsx +0 -23
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +165 -0
- package/Components/Screen/__tests__/Screen.test.tsx +3 -0
- package/Components/Screen/index.tsx +55 -58
- package/Components/Screen/navigationHandler.ts +5 -0
- package/Components/ScreenResolver/index.tsx +9 -12
- package/Components/Transitioner/Scene.tsx +32 -26
- package/Components/Transitioner/Transitioner.tsx +38 -43
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +28 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +56 -43
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +42 -32
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
- package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +67 -60
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -1,79 +1,49 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { omit } from "ramda";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
import { render } from "@testing-library/react-native";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
|
-
import { createStore } from "redux";
|
|
7
6
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
7
|
+
import configureStore from "redux-mock-store";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const withoutChildren = omit(["children"]);
|
|
10
10
|
|
|
11
|
-
jest.mock("
|
|
12
|
-
|
|
11
|
+
jest.mock("../../../Screen/TV/index.web", () => ({
|
|
12
|
+
Screen: View,
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const Layout = require("../index.web").default;
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const ResolvedMenuPlug = () => <View testID="resolved-menu-plug" />;
|
|
20
|
-
|
|
21
|
-
const plugins = [
|
|
22
|
-
{
|
|
23
|
-
module: ResolvedMenuPlug,
|
|
24
|
-
type: "menu",
|
|
25
|
-
name: "resolved-menu-plug",
|
|
26
|
-
},
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const bgImage = "http://applicaster.com";
|
|
30
|
-
const isNavBarVisible = true;
|
|
31
|
-
|
|
32
|
-
const store = createStore(() => ({
|
|
17
|
+
const mockStore = configureStore()({
|
|
33
18
|
appState: { appReady: true },
|
|
34
|
-
|
|
35
|
-
plugins,
|
|
36
|
-
}));
|
|
19
|
+
});
|
|
37
20
|
|
|
38
21
|
describe("Layout TV", () => {
|
|
39
|
-
const themes = {
|
|
40
|
-
myTheme: { screen_margin_top: 10, screen_margin_bottom: 10 },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const selectedThemeId = "myTheme";
|
|
44
|
-
|
|
45
22
|
const navigator = {
|
|
46
|
-
activeRiver: {
|
|
47
|
-
navigations: [{ category: "menu", navigation_type: "menu" }],
|
|
48
|
-
},
|
|
49
|
-
canGoBack: () => false,
|
|
50
23
|
currentRoute: "/river/A1234",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
24
|
+
canGoBack: jest.fn(),
|
|
25
|
+
mainStack: [
|
|
26
|
+
{
|
|
27
|
+
route: "/river/A1234",
|
|
28
|
+
state: { screen: {} },
|
|
29
|
+
},
|
|
30
|
+
],
|
|
55
31
|
};
|
|
56
32
|
|
|
57
33
|
const wrapper = ({ children }) => (
|
|
58
|
-
<Provider store={
|
|
34
|
+
<Provider store={mockStore}>
|
|
59
35
|
<NavigationContext.Provider value={navigator}>
|
|
60
|
-
|
|
61
|
-
{children}
|
|
62
|
-
</ThemeContext.Provider>
|
|
36
|
+
{children}
|
|
63
37
|
</NavigationContext.Provider>
|
|
64
38
|
</Provider>
|
|
65
39
|
);
|
|
66
40
|
|
|
67
|
-
const Screen = (props) => (
|
|
68
|
-
<View testID="screen-component" {...R.omit(["children"])(props)} />
|
|
69
|
-
);
|
|
70
|
-
|
|
71
41
|
const NavBar = (props) => (
|
|
72
|
-
<View testID="nav-bar-component" {...
|
|
42
|
+
<View testID="nav-bar-component" {...withoutChildren(props)} />
|
|
73
43
|
);
|
|
74
44
|
|
|
75
45
|
const Background = (props: Record<any, any>) => (
|
|
76
|
-
<View testID="background-component" {...
|
|
46
|
+
<View testID="background-component" {...withoutChildren(props)}>
|
|
77
47
|
{props.children}
|
|
78
48
|
</View>
|
|
79
49
|
);
|
|
@@ -84,33 +54,8 @@ describe("Layout TV", () => {
|
|
|
84
54
|
};
|
|
85
55
|
|
|
86
56
|
it("renders", () => {
|
|
87
|
-
const { toJSON } = render(
|
|
88
|
-
<Layout Components={Components}>
|
|
89
|
-
<Screen />
|
|
90
|
-
</Layout>,
|
|
91
|
-
{ wrapper }
|
|
92
|
-
);
|
|
57
|
+
const { toJSON } = render(<Layout Components={Components} />, { wrapper });
|
|
93
58
|
|
|
94
59
|
expect(toJSON()).toMatchSnapshot();
|
|
95
60
|
});
|
|
96
|
-
|
|
97
|
-
describe("props passed to background component", () => {
|
|
98
|
-
it("passes correct props", () => {
|
|
99
|
-
const { getByTestId } = render(
|
|
100
|
-
<Layout
|
|
101
|
-
Components={Components}
|
|
102
|
-
ComponentsExtraProps={{
|
|
103
|
-
Background: { testProp: true },
|
|
104
|
-
}}
|
|
105
|
-
>
|
|
106
|
-
<Screen />
|
|
107
|
-
</Layout>,
|
|
108
|
-
{ wrapper }
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const bgComponent = getByTestId("background-component");
|
|
112
|
-
expect(bgComponent.props.backgroundImageUrl).toBe(bgImage);
|
|
113
|
-
expect(bgComponent.props.testProp).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
61
|
});
|
|
@@ -4,22 +4,14 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
|
4
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
5
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
getNavigationProps,
|
|
9
|
-
resolveNavigationPlugin,
|
|
10
|
-
routeIsPlayerScreen,
|
|
11
|
-
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
12
|
-
|
|
13
7
|
import { getBackgroundImageUrl } from "../utils";
|
|
14
8
|
import { LayoutContainer } from "./LayoutContainer";
|
|
15
|
-
import { NavBarContainer } from "./NavBarContainer";
|
|
16
9
|
import { ScreenContainer } from "./ScreenContainer";
|
|
17
|
-
import { TransitionOverlay } from "./TransitionOverlay";
|
|
18
10
|
|
|
19
11
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
20
|
-
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
21
12
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
22
|
-
import {
|
|
13
|
+
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
14
|
+
import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
|
|
23
15
|
|
|
24
16
|
type Components = {
|
|
25
17
|
NavBar: React.ComponentType<any>;
|
|
@@ -40,20 +32,9 @@ type Props = {
|
|
|
40
32
|
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
41
33
|
const navigator = useNavigation();
|
|
42
34
|
const theme = useTheme();
|
|
43
|
-
const { title, visible } = useNavbarState();
|
|
44
|
-
const { activeRiver, currentRoute } = navigator;
|
|
45
|
-
|
|
46
|
-
const {
|
|
47
|
-
appState: { appReady = false } = {},
|
|
48
|
-
remoteConfigurations,
|
|
49
|
-
plugins = [],
|
|
50
|
-
} = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
|
|
51
35
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
title,
|
|
55
|
-
category: "menu",
|
|
56
|
-
});
|
|
36
|
+
const { appState: { appReady = false } = {}, remoteConfigurations } =
|
|
37
|
+
usePickFromState(["appState", "remoteConfigurations", "plugins"]);
|
|
57
38
|
|
|
58
39
|
const backgroundColor = React.useMemo(() => theme.app_background_color, []);
|
|
59
40
|
|
|
@@ -62,37 +43,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
62
43
|
[remoteConfigurations]
|
|
63
44
|
);
|
|
64
45
|
|
|
65
|
-
const menuPlugin = React.useMemo(
|
|
66
|
-
() =>
|
|
67
|
-
resolveNavigationPlugin({
|
|
68
|
-
category: "menu",
|
|
69
|
-
navigations: activeRiver?.navigations,
|
|
70
|
-
plugins,
|
|
71
|
-
}) as QuickBrickPlugin,
|
|
72
|
-
[]
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const NavBar = React.useMemo(
|
|
76
|
-
() => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
|
|
77
|
-
[]
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
81
|
-
|
|
82
|
-
const navBarContainer = (
|
|
83
|
-
<NavBarContainer isVisible={visible} onReady={setNavBarReady}>
|
|
84
|
-
<NavBar
|
|
85
|
-
ref={ComponentsExtraProps?.NavBar?.ref}
|
|
86
|
-
isVisible={visible && !routeIsPlayerScreen(currentRoute)}
|
|
87
|
-
menuPlugin={menuPlugin}
|
|
88
|
-
navigationProps={navigationProps}
|
|
89
|
-
{...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
|
|
90
|
-
/>
|
|
91
|
-
</NavBarContainer>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const isTVOS = isApplePlatform();
|
|
95
|
-
|
|
96
46
|
if (!appReady) {
|
|
97
47
|
return null;
|
|
98
48
|
}
|
|
@@ -105,21 +55,18 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
105
55
|
backgroundImageUrl={backgroundImageUrl}
|
|
106
56
|
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
107
57
|
>
|
|
108
|
-
{
|
|
109
|
-
{navBarReady ? (
|
|
110
|
-
/**
|
|
111
|
-
Need to re-mount this component on each navigation event
|
|
112
|
-
It's a hack to work around the fact that we don't support
|
|
113
|
-
correct screen rendering in our navigator (shared currentRoute state)
|
|
114
|
-
**/
|
|
58
|
+
<ScreenDataContext.Provider value={navigator.data}>
|
|
115
59
|
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
116
|
-
<
|
|
60
|
+
<ScreenContextProvider pathname={navigator.currentRoute}>
|
|
61
|
+
<ScreenContainer
|
|
62
|
+
ComponentsExtraProps={ComponentsExtraProps}
|
|
63
|
+
NavBar={Components.NavBar}
|
|
64
|
+
>
|
|
65
|
+
{children}
|
|
66
|
+
</ScreenContainer>
|
|
67
|
+
</ScreenContextProvider>
|
|
117
68
|
</PathnameContext.Provider>
|
|
118
|
-
|
|
119
|
-
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
120
|
-
focus manager works correctly to focus nav bar items first **/}
|
|
121
|
-
{isTVOS ? navBarContainer : null}
|
|
122
|
-
<TransitionOverlay />
|
|
69
|
+
</ScreenDataContext.Provider>
|
|
123
70
|
</Components.Background>
|
|
124
71
|
</ScreenLayoutContextProvider>
|
|
125
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 {
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
}
|
|
@@ -53,6 +53,7 @@ export function ActionButton(props: Props) {
|
|
|
53
53
|
const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
|
|
54
54
|
const actionContext = useActions(action?.identifier);
|
|
55
55
|
|
|
56
|
+
// TODO: add subscription API for action availability
|
|
56
57
|
const actionDisabled =
|
|
57
58
|
typeof actionContext?.isActionAvailable === "function" &&
|
|
58
59
|
!actionContext.isActionAvailable(item);
|
|
@@ -68,7 +69,7 @@ export function ActionButton(props: Props) {
|
|
|
68
69
|
if (actionDisabled || !actionContext) return;
|
|
69
70
|
|
|
70
71
|
setActionState(actionContext.initialEntryState(item));
|
|
71
|
-
}, [actionDisabled, item?.id]);
|
|
72
|
+
}, [actionDisabled, item?.id, actionContext]);
|
|
72
73
|
|
|
73
74
|
const onPress = useCallback(() => {
|
|
74
75
|
actionContext.invokeAction(item, {
|
|
@@ -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
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
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,104 +41,102 @@ const getContainerBorderWidth = (
|
|
|
63
41
|
}
|
|
64
42
|
};
|
|
65
43
|
|
|
66
|
-
const
|
|
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
|
|
53
|
+
if (!borderPosition) {
|
|
87
54
|
return null;
|
|
88
55
|
}
|
|
89
56
|
|
|
90
|
-
const
|
|
91
|
-
|
|
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
|
-
...
|
|
97
|
-
|
|
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
|
-
|
|
103
|
+
...borderRadiusStyle,
|
|
100
104
|
}}
|
|
101
105
|
/>
|
|
102
106
|
);
|
|
103
107
|
};
|
|
104
108
|
|
|
105
109
|
export const BorderContainerView = (props: Props) => {
|
|
106
|
-
const {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const {
|
|
111
|
+
borderPosition,
|
|
112
|
+
borderPaddingTop,
|
|
113
|
+
borderPaddingRight,
|
|
114
|
+
borderPaddingBottom,
|
|
115
|
+
borderPaddingLeft,
|
|
116
|
+
style,
|
|
117
|
+
children,
|
|
118
|
+
} = props;
|
|
112
119
|
|
|
113
120
|
const borderStyleForMissingBorder =
|
|
114
121
|
style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
|
|
115
122
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
};
|
|
123
|
+
const padding =
|
|
124
|
+
borderPosition === "outside"
|
|
125
|
+
? {
|
|
126
|
+
paddingTop: borderPaddingTop,
|
|
127
|
+
paddingRight: borderPaddingRight,
|
|
128
|
+
paddingBottom: borderPaddingBottom,
|
|
129
|
+
paddingLeft: borderPaddingLeft,
|
|
130
|
+
}
|
|
131
|
+
: {};
|
|
156
132
|
|
|
157
133
|
return (
|
|
158
|
-
<View
|
|
134
|
+
<View
|
|
135
|
+
{...props}
|
|
136
|
+
style={[style, styles.container, borderStyleForMissingBorder]}
|
|
137
|
+
>
|
|
138
|
+
<Border style={style} padding={padding} borderPosition={borderPosition} />
|
|
159
139
|
{children}
|
|
160
|
-
<InsideBorder
|
|
161
|
-
style={{ ...style, ...borderStyleForMissingBorder }}
|
|
162
|
-
borderPosition={borderPosition}
|
|
163
|
-
/>
|
|
164
140
|
</View>
|
|
165
141
|
);
|
|
166
142
|
};
|
|
@@ -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:
|
|
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,7 @@ 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";
|
|
7
8
|
|
|
8
9
|
const { Logger } = getXray();
|
|
9
10
|
|
|
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
35
36
|
|
|
36
37
|
const focusableId = getFocusableId(prefixId, suffixId);
|
|
37
38
|
|
|
38
|
-
const focused =
|
|
39
|
+
const focused =
|
|
40
|
+
focusableId === focusedButtonId ||
|
|
41
|
+
toBooleanWithDefaultFalse(otherProps.focused);
|
|
39
42
|
|
|
40
43
|
const additionalStyles = focused ? focusedStyles : normalStyles;
|
|
41
44
|
|
|
@@ -108,6 +108,26 @@ const prepareEntry = (entry) => {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
const previewPlayback =
|
|
112
|
+
entry.extensions?.["brightcove"]?.["preview_playback"];
|
|
113
|
+
|
|
114
|
+
if (previewPlayback) {
|
|
115
|
+
return {
|
|
116
|
+
...entry,
|
|
117
|
+
extensions: {
|
|
118
|
+
...entry.extensions,
|
|
119
|
+
brightcove: {
|
|
120
|
+
...entry?.extensions?.["brightcove"],
|
|
121
|
+
video_id: previewPlayback,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (entry.extensions?.["brightcove"]?.["video_id"]) {
|
|
128
|
+
return entry;
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
const src = entry.content?.src;
|
|
112
132
|
|
|
113
133
|
if (!src) {
|
|
@@ -61,7 +61,10 @@ export function ButtonContainerView({
|
|
|
61
61
|
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
62
62
|
{insertBetween(
|
|
63
63
|
(index) => (
|
|
64
|
-
<HorizontalSeparator
|
|
64
|
+
<HorizontalSeparator
|
|
65
|
+
key={`separator_${index}`}
|
|
66
|
+
width={horizontalGutter}
|
|
67
|
+
/>
|
|
65
68
|
),
|
|
66
69
|
cloneElementsWithIds(buttonIds, filteredChildren)
|
|
67
70
|
)}
|