@applicaster/zapp-react-native-ui-components 13.0.0-rc.35 → 13.0.0-rc.37

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.
@@ -0,0 +1,126 @@
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
+ }
@@ -1,48 +1,10 @@
1
1
  import * as React from "react";
2
2
 
3
- import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
4
- import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
5
3
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
6
4
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
5
 
8
- import { isAppleTV } from "../../Helpers/Platform";
9
6
  import { useCellState } from "../MasterCell/utils";
10
-
11
- const useCellFocusedState = (
12
- skipFocusManagerRegistration: boolean,
13
- groupId: string,
14
- id: string
15
- ) => {
16
- const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
17
-
18
- React.useEffect(() => {
19
- const isGroupItemFocused = () => {
20
- if (!skipFocusManagerRegistration) {
21
- const isFocused = focusManager.isGroupItemFocused(groupId, id);
22
- setCurrentCellFocused(isFocused);
23
- }
24
- };
25
-
26
- const handler = () => {
27
- // tvOS hack for properly checking focus
28
- if (isAppleTV()) {
29
- setTimeout(() => {
30
- isGroupItemFocused();
31
- }, 0);
32
- } else {
33
- isGroupItemFocused();
34
- }
35
- };
36
-
37
- focusManager.on(FOCUS_EVENTS.FOCUS, handler);
38
-
39
- return () => {
40
- focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
41
- };
42
- }, [groupId, skipFocusManagerRegistration]);
43
-
44
- return currentCellFocused;
45
- };
7
+ import { FocusableGroup } from "../FocusableGroup";
46
8
 
47
9
  type Props = {
48
10
  item: ZappEntry;
@@ -75,11 +37,7 @@ export function CellWithFocusable(props: Props) {
75
37
  focused,
76
38
  } = props;
77
39
 
78
- const isFocused = useCellFocusedState(
79
- skipFocusManagerRegistration,
80
- groupId,
81
- id
82
- );
40
+ const [isFocused, setIsFocused] = React.useState(false);
83
41
 
84
42
  const state = useCellState({
85
43
  id: item.id,
@@ -96,26 +54,52 @@ export function CellWithFocusable(props: Props) {
96
54
  }
97
55
  }, [focusedButtonId]);
98
56
 
99
- const handleToggleFocus = (value) => {
100
- setFocusedButtonId(value.focusedButtonId);
57
+ const handleToggleFocus = React.useCallback(
58
+ (value) => {
59
+ setFocusedButtonId(value.focusedButtonId);
60
+
61
+ if (value.focusable) {
62
+ onFocus(value.focusable, value.mouse);
63
+ }
64
+ },
65
+ [onFocus]
66
+ );
67
+
68
+ const onGroupFocus = React.useCallback(() => {
69
+ if (!skipFocusManagerRegistration) {
70
+ setIsFocused(true);
71
+ }
72
+ }, [skipFocusManagerRegistration]);
101
73
 
102
- if (value.focusable) {
103
- onFocus(value.focusable, value.mouse);
74
+ const onGroupBlur = React.useCallback(() => {
75
+ if (!skipFocusManagerRegistration) {
76
+ setIsFocused(false);
104
77
  }
105
- };
78
+ }, [skipFocusManagerRegistration]);
106
79
 
107
80
  return (
108
- <CellRenderer
109
- item={item}
81
+ <FocusableGroup
82
+ id={`focusable-cell-wrapper-${id}`}
83
+ testID={"cell-with-focusable-cell-renderer-focusable-group"}
110
84
  groupId={groupId}
111
- onToggleFocus={handleToggleFocus}
112
- state={state}
113
- prefixId={id}
114
- focusedButtonId={focusedButtonId}
115
85
  preferredFocus={preferredFocus}
116
- skipFocusManagerRegistration={skipFocusManagerRegistration}
117
- isFocusable={isFocusable}
118
- focused={focused}
119
- />
86
+ shouldUsePreferredFocus
87
+ onFocus={onGroupFocus}
88
+ onBlur={onGroupBlur}
89
+ >
90
+ <CellRenderer
91
+ testID={"cell-with-focusable-cell-renderer"}
92
+ item={item}
93
+ groupId={`focusable-cell-wrapper-${id}`}
94
+ onToggleFocus={handleToggleFocus}
95
+ state={state}
96
+ prefixId={id}
97
+ focusedButtonId={focusedButtonId}
98
+ preferredFocus={true}
99
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
100
+ isFocusable={isFocusable}
101
+ focused={focused}
102
+ />
103
+ </FocusableGroup>
120
104
  );
121
105
  }
@@ -1,7 +1,7 @@
1
1
  import { View } from "react-native";
2
2
  import React from "react";
3
3
  import { act, render } from "@testing-library/react-native";
4
- import { CellWithFocusable } from "../CellWithFocusable";
4
+ import { CellWithFocusable } from "../CellWithFocusable.tsx";
5
5
 
6
6
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
7
7
 
@@ -23,7 +23,9 @@ describe("CellWithFocusable", () => {
23
23
 
24
24
  const wrapper = renderWith(props);
25
25
 
26
- expect(wrapper.UNSAFE_getByType("View").props.state).toBe("default");
26
+ const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
27
+
28
+ expect(element.props.state).toBe("default");
27
29
  });
28
30
 
29
31
  it("should render in default state", () => {
@@ -40,8 +42,9 @@ describe("CellWithFocusable", () => {
40
42
  focusManager.isGroupItemFocused = jest.fn(() => true);
41
43
 
42
44
  const wrapper = renderWith(props);
45
+ const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
43
46
 
44
- expect(wrapper.UNSAFE_getByType("View").props.state).toBe("default");
47
+ expect(element.props.state).toBe("default");
45
48
  });
46
49
 
47
50
  it("should render in focused state", () => {
@@ -55,13 +58,17 @@ describe("CellWithFocusable", () => {
55
58
  scrollTo: jest.fn(),
56
59
  };
57
60
 
58
- focusManager.isGroupItemFocused = jest.fn(() => true);
59
61
  const wrapper = renderWith(props);
60
62
 
63
+ const focusableGroupComponent = wrapper.getByTestId(
64
+ "cell-with-focusable-cell-renderer-focusable-group"
65
+ );
66
+
61
67
  act(() => {
62
- focusManager.on.mock.calls[focusManager.on.mock.calls.length - 1][1]();
68
+ focusableGroupComponent.props.onFocus();
63
69
  });
64
70
 
65
- expect(wrapper.UNSAFE_getByType("View").props.state).toBe("focused");
71
+ const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
72
+ expect(element.props.state).toBe("focused");
66
73
  });
67
74
  });
@@ -118,11 +118,10 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
118
118
  If bottomTabBarHeight is equal 0 it means an app does not use bottomTabBar.
119
119
  Because of this we need to minus bottom SafeArea offset.
120
120
  */
121
+
121
122
  const minValue =
122
123
  height -
123
- minimisedHeight -
124
- (bottomTabBarHeight || bottomSafeArea) -
125
- progressBarHeight;
124
+ (minimisedHeight + bottomTabBarHeight + progressBarHeight + bottomSafeArea);
126
125
 
127
126
  const modalSnapPoints = React.useMemo(() => [0, minValue], [minValue]);
128
127
  // Last snap state which will helps us to make smooth responder to scrollview animation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "13.0.0-rc.35",
3
+ "version": "13.0.0-rc.37",
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-rc.35",
38
- "@applicaster/zapp-react-native-bridge": "13.0.0-rc.35",
39
- "@applicaster/zapp-react-native-redux": "13.0.0-rc.35",
40
- "@applicaster/zapp-react-native-utils": "13.0.0-rc.35",
37
+ "@applicaster/applicaster-types": "13.0.0-rc.37",
38
+ "@applicaster/zapp-react-native-bridge": "13.0.0-rc.37",
39
+ "@applicaster/zapp-react-native-redux": "13.0.0-rc.37",
40
+ "@applicaster/zapp-react-native-utils": "13.0.0-rc.37",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",