@applicaster/zapp-react-native-ui-components 13.0.0-alpha.5385326185 → 13.0.0-alpha.5638327338

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.
@@ -1,17 +1,31 @@
1
1
  import * as React from "react";
2
2
  import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
3
3
  import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
4
-
5
- function noop() {}
4
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
5
+
6
+ const { log_verbose } = createLogger({
7
+ subsystem: "General",
8
+ category: "FocusableGroup",
9
+ });
10
+
11
+ type FocusableGroupNativeEvent = {
12
+ nativeEvent: {
13
+ focusHeading: FocusManager.Direction;
14
+ groupId: string;
15
+ isActive: boolean;
16
+ isFocusDisabled: boolean;
17
+ isFocusingByUser: boolean;
18
+ itemId: string;
19
+ target: number;
20
+ };
21
+ };
6
22
 
7
23
  type Props = {
8
24
  id: string;
9
25
  children: (arg1: boolean) => React.ComponentType<any>;
10
- onWillUpdateFocus: (nativeEvent: any) => void;
11
- onDidUpdateFocus: (nativeEvent: any) => void;
12
26
  isFocusDisabled: boolean;
13
27
  initialItemId: string;
14
- resetFocusToInitialValue: boolean;
28
+ isPreferredFocusDisabled: boolean;
15
29
  focusGroupRef: React.Component;
16
30
  shouldUsePreferredFocus: boolean;
17
31
  groupId: string;
@@ -21,86 +35,27 @@ type Props = {
21
35
  };
22
36
 
23
37
  export class FocusableGroup extends BaseFocusable<Props> {
24
- focusableGroupNativeRef: React.Component | null;
25
- constructor(props) {
26
- super(props);
27
- this.focusableGroupNativeRef = null;
28
-
29
- this.state = {
30
- isActive: false,
31
- };
32
-
33
- this.onWillUpdateFocus = this.onWillUpdateFocus.bind(this);
34
- this.onDidUpdateFocus = this.onDidUpdateFocus.bind(this);
35
- this.isGroup = true;
36
-
37
- this.shouldUsePreferredFocus = this.shouldUsePreferredFocus.bind(this);
38
- this.measureView = this.measureView.bind(this);
39
- }
40
-
41
- connectedScreenId() {
42
- const {
43
- screenData: { screenId, parentScreenId },
44
- } = this.props;
45
-
46
- if (screenId) {
47
- return null;
48
- }
49
-
50
- return parentScreenId ? `${parentScreenId}-${screenId}` : screenId;
51
- }
52
-
53
- /**
54
- * tells whether the group should give focus to a preferred item when it gains focus from another
55
- * group
56
- * @returns {boolean}
57
- */
58
- shouldUsePreferredFocus() {
59
- return this.props.shouldUsePreferredFocus || false;
60
- }
61
-
62
- /**
63
- * indicates whether the underlying component should claim preferred focus
64
- * when navigating into the group of this item
65
- * @returns {boolean}
66
- */
67
- isPreferredFocus() {
68
- return this.props.preferredFocus || false;
69
- }
70
-
71
- onWillUpdateFocus({ nativeEvent }) {
72
- const { isActive } = nativeEvent;
73
- this.setState({ isActive });
74
- const { onWillUpdateFocus = noop } = this.props;
75
- onWillUpdateFocus(nativeEvent);
76
- }
77
-
78
- onDidUpdateFocus({ nativeEvent }) {
79
- const { onDidUpdateFocus = noop } = this.props;
80
- onDidUpdateFocus(nativeEvent);
81
- }
82
-
83
- setFocusDisabled(isFocusDisabled) {
84
- if (this.ref) {
85
- this.ref.current.setNativeProps({
86
- isFocusDisabled,
87
- });
88
- }
89
- }
90
-
91
38
  render() {
92
39
  const {
93
40
  children,
94
41
  id,
95
42
  isFocusDisabled,
96
43
  initialItemId,
97
- resetFocusToInitialValue,
98
- style,
44
+ isPreferredFocusDisabled,
45
+ style = {},
99
46
  groupId,
100
47
  ...otherProps
101
48
  } = this.props;
102
49
 
103
- const focusableStyles = style || {};
50
+ const onGroupFocus = ({ nativeEvent }: FocusableGroupNativeEvent) => {
51
+ log_verbose("FOCUSABLE_GROUP: onGroupFocus", { nativeEvent });
52
+ this.onFocus(this.ref, nativeEvent.focusHeading);
53
+ };
54
+
55
+ const onGroupBlur = ({ nativeEvent }: FocusableGroupNativeEvent) => {
56
+ log_verbose("FOCUSABLE_GROUP: onGroupBlur", { nativeEvent });
57
+ this.onBlur(this.ref, nativeEvent.focusHeading);
58
+ };
104
59
 
105
60
  return (
106
61
  <FocusableGroupNative
@@ -109,15 +64,11 @@ export class FocusableGroup extends BaseFocusable<Props> {
109
64
  ref={this.ref}
110
65
  isFocusDisabled={isFocusDisabled}
111
66
  initialItemId={initialItemId}
112
- resetFocusToInitialValue={resetFocusToInitialValue}
113
- onLayout={this.measureView}
114
- onViewFocus={this.onFocus}
115
- onViewPress={this.onPress}
116
- onViewBlur={this.onBlur}
117
- style={focusableStyles}
67
+ isPreferredFocusDisabled={isPreferredFocusDisabled}
68
+ onGroupFocus={onGroupFocus}
69
+ onGroupBlur={onGroupBlur}
70
+ style={style}
118
71
  {...otherProps}
119
- onWillUpdateFocus={this.onWillUpdateFocus}
120
- onDidUpdateFocus={this.onDidUpdateFocus}
121
72
  >
122
73
  {children}
123
74
  </FocusableGroupNative>
@@ -16,12 +16,10 @@ type Props = {
16
16
  prioritiseFocusOn?: number;
17
17
  groupId?: string;
18
18
  hasTVPreferredFocus?: boolean;
19
- resetFocusToInitialValue?: boolean;
19
+ isPreferredFocusDisabled?: boolean;
20
20
  onFocus?: () => void;
21
21
  onBlur?: () => void;
22
- onWillUpdateFocus?: (event?: any) => void;
23
22
  willReceiveFocus?: (event?: any) => void;
24
- onDidUpdateFocus?: (event?: any) => void;
25
23
  hasLostFocus?: any;
26
24
  nextFocusUp?: any;
27
25
  nextFocusDown?: any;
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { View, StyleSheet } from "react-native";
2
+ import { StyleSheet, View } from "react-native";
3
3
 
4
4
  type Props = {
5
5
  children: React.ReactNode;
@@ -13,6 +13,7 @@ const styles = StyleSheet.create({
13
13
  top: 0,
14
14
  zIndex: 10,
15
15
  flex: 1,
16
+ width: "100%",
16
17
  },
17
18
  themeStyles: {
18
19
  // limits the height of the focusable container of the TopMenuBarTV component
@@ -55,8 +55,11 @@ export const ScreenContainer = React.memo(function ScreenContainer({
55
55
  ComponentsExtraProps,
56
56
  NavBar,
57
57
  }: Props) {
58
- const { screenMarginBottom } = React.useContext(ScreenLayoutContext);
58
+ const { screenMarginBottom, resetScreenLayout } =
59
+ React.useContext(ScreenLayoutContext);
60
+
59
61
  const { currentRoute, screenData } = useNavigation();
62
+
60
63
  const screen = useCurrentScreenData();
61
64
 
62
65
  const { marginBottom, backgroundColor, paddingTop, paddingBottom } =
@@ -65,6 +68,10 @@ export const ScreenContainer = React.memo(function ScreenContainer({
65
68
  const theme = useTheme();
66
69
  const getThemeValue = React.useCallback(R.propOr(0, R.__, theme), [theme]);
67
70
 
71
+ React.useEffect(() => {
72
+ resetScreenLayout();
73
+ }, [currentRoute]);
74
+
68
75
  const fullscreen = React.useCallback(
69
76
  displayFullScreen({ currentRoute, screenData }),
70
77
  [currentRoute, screenData]
@@ -60,10 +60,15 @@ export function ScreenLayoutContextProvider(props: {
60
60
  initialState
61
61
  );
62
62
 
63
+ const resetScreenLayout = React.useCallback(() => {
64
+ setScreenLayout(initialState);
65
+ }, [initialState]);
66
+
63
67
  const screenLayoutValue = React.useMemo(
64
68
  () => ({
65
69
  ...screenLayout,
66
70
  setScreenLayout,
71
+ resetScreenLayout,
67
72
  }),
68
73
  [screenLayout]
69
74
  );
@@ -56,11 +56,12 @@ describe("ScreenContainer", () => {
56
56
  };
57
57
 
58
58
  const setScreenLayout = () => {};
59
+ const resetScreenLayout = () => {};
59
60
 
60
61
  const wrapper = ({ children }) => (
61
62
  <WrappedWithProviders>
62
63
  <ScreenLayoutContext.Provider
63
- value={{ ...screenLayout, setScreenLayout }}
64
+ value={{ ...screenLayout, setScreenLayout, resetScreenLayout }}
64
65
  >
65
66
  <ScreenContainer NavBar={View}>{children}</ScreenContainer>
66
67
  </ScreenLayoutContext.Provider>
@@ -8,6 +8,7 @@ exports[`NavBarContainer renders 1`] = `
8
8
  "flex": 1,
9
9
  "position": "absolute",
10
10
  "top": 0,
11
+ "width": "100%",
11
12
  "zIndex": 10,
12
13
  },
13
14
  {
@@ -19,6 +19,7 @@ exports[`ScreenContainer renders 1`] = `
19
19
  "flex": 1,
20
20
  "position": "absolute",
21
21
  "top": 0,
22
+ "width": "100%",
22
23
  "zIndex": 10,
23
24
  },
24
25
  {
@@ -4,7 +4,6 @@ import { TouchableOpacity, ViewStyle } from "react-native";
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
5
 
6
6
  import Image from "./Image";
7
-
8
7
  type Props = {
9
8
  item: ZappEntry | ZappFeed;
10
9
  flavour?: "flavour_1" | "flavour_2";
@@ -69,7 +68,7 @@ export function ActionButton(props: Props) {
69
68
  if (!((actionDisabled || !actionContext) && actionState !== null)) {
70
69
  setActionState(actionContext.initialEntryState(item));
71
70
  }
72
- }, [actionDisabled, item?.id, actionContext, action]);
71
+ }, [actionDisabled, item?.id, actionContext, action, setActionState]);
73
72
 
74
73
  const onPress = useCallback(() => {
75
74
  actionContext.invokeAction(item, {
@@ -85,7 +84,7 @@ export function ActionButton(props: Props) {
85
84
  setActionState(state);
86
85
  });
87
86
  }
88
- }, [item?.id]);
87
+ }, [item?.id, setActionState, actionContext]);
89
88
 
90
89
  if (actionDisabled || !actionContext) return null;
91
90
  const AssetComponent = actionState?.asset;
@@ -34,7 +34,6 @@ export const useFillInPercent = (entry: ZappEntry): number => {
34
34
  React.useState<number>(DEFAULT_FILL);
35
35
 
36
36
  React.useEffect(() => {
37
- // setup progress in UI on mount
38
37
  getProgressValue(action, entry, (progress) => {
39
38
  setFillInPercent(progress);
40
39
  });
@@ -45,17 +44,12 @@ export const useFillInPercent = (entry: ZappEntry): number => {
45
44
  return;
46
45
  }
47
46
 
48
- // refresh progress in UI when it was changed in CW
49
- const unsubscribe = action?.addDataSourceListener?.(() => {
47
+ return action?.addDataSourceListener?.(() => {
50
48
  getProgressValue(action, entry, (progress) => {
51
49
  setFillInPercent(progress);
52
50
  });
53
51
  });
54
-
55
- return () => {
56
- unsubscribe?.();
57
- };
58
- }, [isActive]);
52
+ }, [isActive, action, entry, setFillInPercent]);
59
53
 
60
54
  return fillInPercent;
61
55
  };
@@ -1,4 +1,4 @@
1
- import React, { PropsWithChildren } from "react";
1
+ import React, { PropsWithChildren, useEffect, useState } from "react";
2
2
  import { ImageBackground, View } from "react-native";
3
3
 
4
4
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
@@ -12,6 +12,7 @@ import {
12
12
  type Props = PropsWithChildren<{
13
13
  entry: ZappEntry;
14
14
  style?: { [K: string]: any };
15
+ docked?: boolean;
15
16
  imageStyle?: { [K: string]: any };
16
17
  imageKey?: string;
17
18
  defaultImageDimensions?: { [K: string]: any };
@@ -23,6 +24,7 @@ const PlayerImageBackgroundComponent = ({
23
24
  entry,
24
25
  children,
25
26
  style,
27
+ docked,
26
28
  imageStyle,
27
29
  imageKey,
28
30
  defaultImageDimensions,
@@ -34,8 +36,22 @@ const PlayerImageBackgroundComponent = ({
34
36
 
35
37
  const { playerAnimationState } = useModalAnimationContext();
36
38
 
39
+ const [lastNonNullAnimationState, setLastNonNullAnimationState] =
40
+ useState(playerAnimationState);
41
+
42
+ useEffect(() => {
43
+ if (playerAnimationState !== null) {
44
+ setLastNonNullAnimationState(playerAnimationState);
45
+ }
46
+ }, [playerAnimationState]);
47
+
37
48
  if (!source) return <>{children}</>;
38
49
 
50
+ const imageBackgroundStyle =
51
+ lastNonNullAnimationState !== PlayerAnimationStateEnum.minimize && !docked
52
+ ? defaultImageDimensions
53
+ : imageSize;
54
+
39
55
  return (
40
56
  <View
41
57
  style={
@@ -45,13 +61,17 @@ const PlayerImageBackgroundComponent = ({
45
61
  }
46
62
  >
47
63
  <AnimationComponent
48
- style={style}
64
+ style={
65
+ playerAnimationState === PlayerAnimationStateEnum.maximaze
66
+ ? defaultImageDimensions
67
+ : style
68
+ }
49
69
  animationType={ComponentAnimationType.player}
50
70
  additionalData={defaultImageDimensions}
51
71
  >
52
72
  <ImageBackground
53
73
  resizeMode="cover"
54
- style={imageSize}
74
+ style={imageBackgroundStyle}
55
75
  imageStyle={imageStyle}
56
76
  source={source}
57
77
  >
@@ -5,6 +5,7 @@ import {
5
5
  Easing,
6
6
  StyleProp,
7
7
  ViewStyle,
8
+ StyleSheet,
8
9
  } from "react-native";
9
10
  import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
10
11
  import { ComponentsMap } from "@applicaster/zapp-react-native-ui-components/Components/River/ComponentsMap";
@@ -90,7 +91,9 @@ export const PlayerDetails = ({
90
91
  {
91
92
  // workaround for avoid wrong text-height after going back to portrait rotation
92
93
  // we don't see this view in landscape mode, so we are able to use fixed width from portrait mode
93
- width: isTablet ? undefined : SCREEN_WIDTH,
94
+ width: isTablet
95
+ ? undefined
96
+ : (StyleSheet.flatten(style)?.width ?? SCREEN_WIDTH),
94
97
  },
95
98
  ]}
96
99
  >
@@ -8,10 +8,11 @@ type LayoutContext = {
8
8
  componentAnchorPointY: number | null;
9
9
  componentAvailableWidth: number | null;
10
10
  setScreenLayout?: (properties: {}) => void;
11
+ resetScreenLayout?: () => void;
11
12
  extraAnchorPointYOffset: number;
12
13
  };
13
14
 
14
- const screenLayoutContext: LayoutContext = {
15
+ const initialScreenLayoutContext: LayoutContext = {
15
16
  screenMarginTop: null,
16
17
  screenMarginBottom: null,
17
18
  screenHeight: null,
@@ -21,8 +22,9 @@ const screenLayoutContext: LayoutContext = {
21
22
  extraAnchorPointYOffset: 0,
22
23
  };
23
24
 
24
- export const ScreenLayoutContext =
25
- React.createContext<LayoutContext>(screenLayoutContext);
25
+ export const ScreenLayoutContext = React.createContext<LayoutContext>(
26
+ initialScreenLayoutContext
27
+ );
26
28
 
27
29
  export function ScreenLayoutContextConsumer(Component) {
28
30
  return function WithConsumer(props) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "13.0.0-alpha.5385326185",
3
+ "version": "13.0.0-alpha.5638327338",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "redux-mock-store": "^1.5.3"
35
35
  },
36
36
  "dependencies": {
37
- "@applicaster/applicaster-types": "13.0.0-alpha.5385326185",
38
- "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.5385326185",
39
- "@applicaster/zapp-react-native-redux": "13.0.0-alpha.5385326185",
40
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.5385326185",
37
+ "@applicaster/applicaster-types": "13.0.0-alpha.5638327338",
38
+ "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.5638327338",
39
+ "@applicaster/zapp-react-native-redux": "13.0.0-alpha.5638327338",
40
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.5638327338",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",
@@ -1,126 +0,0 @@
1
- /** TODO: Remove this file when tvos FocusableGroup
2
- * behaviour is aligned to the web one
3
- * FocusableGroup should only send onFocus and onBlur events when
4
- * Focus enters and leaves the Focusables inside the branch
5
- */
6
- import * as React from "react";
7
-
8
- import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
9
- import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
10
- import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
- import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
12
-
13
- import { isAppleTV } from "../../Helpers/Platform";
14
- import { useCellState } from "../MasterCell/utils";
15
-
16
- const useCellFocusedState = (
17
- skipFocusManagerRegistration: boolean,
18
- groupId: string,
19
- id: string
20
- ) => {
21
- const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
22
-
23
- React.useEffect(() => {
24
- const isGroupItemFocused = () => {
25
- if (!skipFocusManagerRegistration) {
26
- const isFocused = focusManager.isGroupItemFocused(groupId, id);
27
- setCurrentCellFocused(isFocused);
28
- }
29
- };
30
-
31
- const handler = () => {
32
- // tvOS hack for properly checking focus
33
- if (isAppleTV()) {
34
- setTimeout(() => {
35
- isGroupItemFocused();
36
- }, 0);
37
- } else {
38
- isGroupItemFocused();
39
- }
40
- };
41
-
42
- focusManager.on(FOCUS_EVENTS.FOCUS, handler);
43
-
44
- return () => {
45
- focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
46
- };
47
- }, [groupId, skipFocusManagerRegistration]);
48
-
49
- return currentCellFocused;
50
- };
51
-
52
- type Props = {
53
- item: ZappEntry;
54
- CellRenderer: React.FunctionComponent<any>;
55
- id: string;
56
- groupId: string;
57
- onFocus: Function;
58
- index: number;
59
- scrollTo: Function;
60
- preferredFocus?: boolean;
61
- skipFocusManagerRegistration?: boolean;
62
- isFocusable?: boolean;
63
- behavior: Behavior;
64
- focused?: boolean;
65
- };
66
-
67
- export function CellWithFocusable(props: Props) {
68
- const {
69
- index,
70
- item,
71
- CellRenderer,
72
- id,
73
- groupId,
74
- onFocus,
75
- scrollTo = noop,
76
- preferredFocus,
77
- skipFocusManagerRegistration,
78
- isFocusable,
79
- behavior,
80
- focused,
81
- } = props;
82
-
83
- const isFocused = useCellFocusedState(
84
- skipFocusManagerRegistration,
85
- groupId,
86
- id
87
- );
88
-
89
- const state = useCellState({
90
- id: item.id,
91
- behavior,
92
- focused: isFocused || toBooleanWithDefaultFalse(focused),
93
- });
94
-
95
- const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
96
-
97
- // for horizontal scrolling
98
- React.useEffect(() => {
99
- if (focusedButtonId) {
100
- scrollTo(index);
101
- }
102
- }, [focusedButtonId]);
103
-
104
- const handleToggleFocus = (value) => {
105
- setFocusedButtonId(value.focusedButtonId);
106
-
107
- if (value.focusable) {
108
- onFocus(value.focusable, value.mouse);
109
- }
110
- };
111
-
112
- return (
113
- <CellRenderer
114
- item={item}
115
- groupId={groupId}
116
- onToggleFocus={handleToggleFocus}
117
- state={state}
118
- prefixId={id}
119
- focusedButtonId={focusedButtonId}
120
- preferredFocus={preferredFocus}
121
- skipFocusManagerRegistration={skipFocusManagerRegistration}
122
- isFocusable={isFocusable}
123
- focused={focused}
124
- />
125
- );
126
- }