@applicaster/zapp-react-native-ui-components 13.0.0-alpha.7222542422 → 13.0.0-alpha.7330390362
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.ios.ts +1 -1
- package/Components/BaseFocusable/index.tsx +1 -1
- package/Components/Cell/Cell.tsx +7 -4
- package/Components/Cell/CellWithFocusable.ios.tsx +126 -0
- package/Components/Cell/CellWithFocusable.tsx +43 -59
- package/Components/Cell/TvOSCellComponent.tsx +22 -20
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
- package/Components/Cell/index.js +1 -3
- package/Components/Focusable/FocusableTvOS.tsx +1 -5
- package/Components/Focusable/Touchable.tsx +19 -20
- package/Components/FocusableList/index.tsx +9 -25
- package/Components/FocusableScrollView/index.tsx +12 -39
- package/Components/Layout/TV/NavBarContainer.tsx +7 -8
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +66 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +6 -0
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -11
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
- package/Components/MasterCell/utils/index.ts +1 -1
- package/Components/ModalComponent/Header/index.tsx +3 -3
- package/Components/River/ComponentsMap/ComponentsMap.tsx +39 -65
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
- package/Components/River/RiverFooter.tsx +39 -9
- package/Components/River/RiverItem.tsx +37 -2
- package/Components/River/TV/index.tsx +1 -6
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +100 -31
- package/Components/River/__tests__/componentsMap.test.js +17 -5
- package/Components/Screen/hooks.ts +56 -0
- package/Components/Screen/index.tsx +13 -39
- package/Components/Tabs/Tab.tsx +6 -6
- package/Components/TextInputTv/index.tsx +2 -2
- package/Components/Transitioner/AnimationManager.js +8 -8
- package/Components/Transitioner/Scene.tsx +52 -23
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +59 -43
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
- package/Components/Transitioner/index.js +8 -4
- package/Components/VideoLive/LiveImageManager.ts +27 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +29 -21
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +51 -1
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +0 -5
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +7 -6
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +2 -3
- package/Components/VideoModal/ModalAnimation/utils.ts +2 -2
- package/Components/VideoModal/OpaqueLayer.tsx +33 -0
- package/Components/VideoModal/PlayerWrapper.tsx +16 -35
- package/Components/VideoModal/VideoModal.tsx +14 -23
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +0 -90
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +89 -0
- package/Components/VideoModal/hooks/index.ts +7 -0
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +49 -0
- package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +91 -0
- package/Components/VideoModal/hooks/utils/index.ts +33 -0
- package/Components/VideoModal/utils.ts +1 -1
- package/Contexts/ScreenContext/index.tsx +3 -2
- package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +31 -1
- package/package.json +5 -5
- package/Contexts/ComponentsMapOffsetContext/index.tsx +0 -41
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -61,7 +61,6 @@ type Props = {
|
|
|
61
61
|
skipFocusManagerRegistration?: boolean;
|
|
62
62
|
shouldUpdate: boolean;
|
|
63
63
|
behavior: Behavior;
|
|
64
|
-
componentsMapOffset: number;
|
|
65
64
|
};
|
|
66
65
|
|
|
67
66
|
type State = {
|
|
@@ -274,10 +273,14 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
274
273
|
if (isFocused) {
|
|
275
274
|
const accessibilityManager = AccessibilityManager.getInstance();
|
|
276
275
|
|
|
276
|
+
const accessibilityTitle =
|
|
277
|
+
item?.extensions?.accessibility?.label || item?.title || "";
|
|
278
|
+
|
|
279
|
+
const accessibilityHint =
|
|
280
|
+
item?.extensions?.accessibility?.hint || "";
|
|
281
|
+
|
|
277
282
|
accessibilityManager.readText({
|
|
278
|
-
text:
|
|
279
|
-
item.extensions?.accessibility?.label || item.title
|
|
280
|
-
),
|
|
283
|
+
text: `${accessibilityTitle} ${accessibilityHint}`,
|
|
281
284
|
});
|
|
282
285
|
}
|
|
283
286
|
|
|
@@ -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 =
|
|
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 = (
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
|
|
74
|
+
const onGroupBlur = React.useCallback(() => {
|
|
75
|
+
if (!skipFocusManagerRegistration) {
|
|
76
|
+
setIsFocused(false);
|
|
104
77
|
}
|
|
105
|
-
};
|
|
78
|
+
}, [skipFocusManagerRegistration]);
|
|
106
79
|
|
|
107
80
|
return (
|
|
108
|
-
<
|
|
109
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
}
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
4
|
|
|
5
|
-
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable
|
|
5
|
+
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
6
6
|
import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
|
|
7
7
|
import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
8
8
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
@@ -65,7 +65,6 @@ type Props = {
|
|
|
65
65
|
isFocusable: boolean;
|
|
66
66
|
shouldUpdate: boolean;
|
|
67
67
|
behavior: Behavior;
|
|
68
|
-
componentsMapOffset: number;
|
|
69
68
|
};
|
|
70
69
|
|
|
71
70
|
type State = {
|
|
@@ -180,7 +179,6 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
180
179
|
groupId,
|
|
181
180
|
component,
|
|
182
181
|
index,
|
|
183
|
-
componentsMapOffset,
|
|
184
182
|
} = this.props;
|
|
185
183
|
|
|
186
184
|
this.setScreenLayout(componentAnchorPointY, screenLayout);
|
|
@@ -195,11 +193,13 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
195
193
|
const extraAnchorPointYOffset =
|
|
196
194
|
screenLayout?.extraAnchorPointYOffset || 0;
|
|
197
195
|
|
|
196
|
+
const marginTop = screenLayout?.screenMarginTop || 0;
|
|
197
|
+
|
|
198
198
|
const totalOffset =
|
|
199
199
|
headerOffset +
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
(componentAnchorPointY || 0) +
|
|
201
|
+
extraAnchorPointYOffset -
|
|
202
|
+
marginTop;
|
|
203
203
|
|
|
204
204
|
mainOffsetUpdater?.(
|
|
205
205
|
{ tag: this.target },
|
|
@@ -247,7 +247,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
247
247
|
|
|
248
248
|
const focusableId = R.join("-", [component?.id, id, index]);
|
|
249
249
|
|
|
250
|
-
const handleFocus = (arg1: any, index
|
|
250
|
+
const handleFocus = (arg1: any, index: number) => {
|
|
251
251
|
const focusFn = onFocus || noop;
|
|
252
252
|
focusFn(arg1, index);
|
|
253
253
|
|
|
@@ -280,7 +280,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
280
280
|
<View onLayout={this.onLayout} style={styles.container}>
|
|
281
281
|
<Focusable
|
|
282
282
|
id={focusableId}
|
|
283
|
-
groupId={
|
|
283
|
+
groupId={groupId || component?.id}
|
|
284
284
|
onFocus={handleFocus}
|
|
285
285
|
onBlur={onBlur || this.onBlur}
|
|
286
286
|
isParallaxDisabled={this.layout?.width > 1740}
|
|
@@ -292,18 +292,20 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
292
292
|
style={baseCellStyles}
|
|
293
293
|
isFocusable={isFocusable}
|
|
294
294
|
>
|
|
295
|
-
{(focused) =>
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
295
|
+
{(focused) => {
|
|
296
|
+
return (
|
|
297
|
+
<FocusableCell
|
|
298
|
+
{...{
|
|
299
|
+
index,
|
|
300
|
+
CellRenderer,
|
|
301
|
+
item,
|
|
302
|
+
focused: this.props.focused || selectedCell || focused,
|
|
303
|
+
scrollTo: this.scrollTo,
|
|
304
|
+
behavior,
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
}}
|
|
307
309
|
</Focusable>
|
|
308
310
|
</View>
|
|
309
311
|
);
|
|
@@ -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
|
-
|
|
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(
|
|
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
|
-
|
|
68
|
+
focusableGroupComponent.props.onFocus();
|
|
63
69
|
});
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
const element = wrapper.getByTestId("cell-with-focusable-cell-renderer");
|
|
72
|
+
expect(element.props.state).toBe("focused");
|
|
66
73
|
});
|
|
67
74
|
});
|
package/Components/Cell/index.js
CHANGED
|
@@ -11,7 +11,6 @@ import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
|
|
|
11
11
|
|
|
12
12
|
import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
|
|
13
13
|
import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
|
|
14
|
-
import { withComponentsMapOffsetContextConsumer } from "../../Contexts/ComponentsMapOffsetContext";
|
|
15
14
|
|
|
16
15
|
// TODO | Gallery QB | Extract this
|
|
17
16
|
export const ScrollInterceptorContext = createContext(
|
|
@@ -31,6 +30,5 @@ export const Cell = R.compose(
|
|
|
31
30
|
RiverOffsetContext.withConsumer,
|
|
32
31
|
HorizontalScrollContext.withConsumer,
|
|
33
32
|
withConsumer,
|
|
34
|
-
ScreenLayoutContextConsumer
|
|
35
|
-
withComponentsMapOffsetContextConsumer
|
|
33
|
+
ScreenLayoutContextConsumer
|
|
36
34
|
)(Component);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
focusManager,
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
|
-
import { findNodeHandle
|
|
12
|
+
import { findNodeHandle } from "react-native";
|
|
13
13
|
|
|
14
14
|
function noop() {}
|
|
15
15
|
|
|
@@ -35,10 +35,6 @@ type Props = {
|
|
|
35
35
|
forceFocus?: boolean;
|
|
36
36
|
initialFocus?: boolean;
|
|
37
37
|
onLayout?: (e: any) => void;
|
|
38
|
-
willReceiveFocus: () => void;
|
|
39
|
-
hasReceivedFocus: () => void;
|
|
40
|
-
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
41
|
-
style: ViewStyle;
|
|
42
38
|
};
|
|
43
39
|
|
|
44
40
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
type Props =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} & Partial<ParentFocus>;
|
|
3
|
+
type Props = {
|
|
4
|
+
id: string;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
onPress?: (ref: FocusManager.TouchableRef) => void;
|
|
7
|
+
onPressIn?: (ref: FocusManager.TouchableRef) => void;
|
|
8
|
+
onPressOut?: (ref: FocusManager.TouchableRef) => void;
|
|
9
|
+
onLongPress?: (ref: FocusManager.TouchableRef) => void;
|
|
10
|
+
onFocus?: (
|
|
11
|
+
ref: FocusManager.TouchableRef,
|
|
12
|
+
options: FocusManager.Android.CallbackOptions
|
|
13
|
+
) => void;
|
|
14
|
+
onBlur?: (
|
|
15
|
+
ref: FocusManager.TouchableRef,
|
|
16
|
+
options: FocusManager.Android.CallbackOptions
|
|
17
|
+
) => void;
|
|
18
|
+
|
|
19
|
+
disableFocus?: boolean;
|
|
20
|
+
blockFocus?: boolean;
|
|
21
|
+
} & Partial<ParentFocus>;
|
|
23
22
|
|
|
24
23
|
export class Touchable extends React.Component<Props> {
|
|
25
24
|
onPress(focusableRef: FocusManager.TouchableRef): void {
|
|
@@ -15,7 +15,6 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
15
15
|
|
|
16
16
|
import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
|
|
17
17
|
import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
|
|
18
|
-
import { FocusableScrollView } from "../FocusableScrollView";
|
|
19
18
|
|
|
20
19
|
const mapIndexed = R.addIndex(R.map);
|
|
21
20
|
|
|
@@ -55,7 +54,6 @@ export type Props<ItemT> = FlatListProps<ItemT> & {
|
|
|
55
54
|
disableNextFocusUp?: boolean;
|
|
56
55
|
disableNextFocusLeft?: boolean;
|
|
57
56
|
disableNextFocusRight?: boolean;
|
|
58
|
-
useScrollView?: boolean;
|
|
59
57
|
} & ParentFocus;
|
|
60
58
|
|
|
61
59
|
function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
@@ -90,7 +88,6 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
90
88
|
data = [],
|
|
91
89
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
92
90
|
omitPropsPropagation = [],
|
|
93
|
-
useScrollView = false,
|
|
94
91
|
} = props;
|
|
95
92
|
|
|
96
93
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -276,7 +273,6 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
276
273
|
"initialFocusDirection",
|
|
277
274
|
"withStateMemory",
|
|
278
275
|
"useSequentialLoading",
|
|
279
|
-
"useScrollView",
|
|
280
276
|
...omitPropsPropagation,
|
|
281
277
|
],
|
|
282
278
|
R.__
|
|
@@ -299,27 +295,15 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
299
295
|
return (
|
|
300
296
|
// @ts-ignore
|
|
301
297
|
<ChildrenFocusDeactivatorView flex={1}>
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
/>
|
|
312
|
-
) : (
|
|
313
|
-
<FlatList
|
|
314
|
-
focusable={false}
|
|
315
|
-
scrollEnabled={false}
|
|
316
|
-
ref={ref}
|
|
317
|
-
{...getFlatListProps(props)}
|
|
318
|
-
renderItem={renderItem}
|
|
319
|
-
onEndReached={onEndReached}
|
|
320
|
-
initialNumToRender={initialNumToRender}
|
|
321
|
-
/>
|
|
322
|
-
)}
|
|
298
|
+
<FlatList
|
|
299
|
+
focusable={false}
|
|
300
|
+
scrollEnabled={false}
|
|
301
|
+
ref={ref}
|
|
302
|
+
{...getFlatListProps(props)}
|
|
303
|
+
renderItem={renderItem}
|
|
304
|
+
onEndReached={onEndReached}
|
|
305
|
+
initialNumToRender={initialNumToRender}
|
|
306
|
+
/>
|
|
323
307
|
</ChildrenFocusDeactivatorView>
|
|
324
308
|
);
|
|
325
309
|
}
|
|
@@ -11,13 +11,6 @@ import {
|
|
|
11
11
|
useInitialFocus,
|
|
12
12
|
} from "@applicaster/zapp-react-native-utils/focusManager";
|
|
13
13
|
|
|
14
|
-
export type FocusableScrollViewRenderItem = (info: {
|
|
15
|
-
item: ZappUIComponent;
|
|
16
|
-
index: number;
|
|
17
|
-
focused: boolean;
|
|
18
|
-
parentFocus: ParentFocus;
|
|
19
|
-
}) => React.ReactElement;
|
|
20
|
-
|
|
21
14
|
export type Props = ScrollViewProps & {
|
|
22
15
|
id?: number | string;
|
|
23
16
|
horizontal?: boolean;
|
|
@@ -39,27 +32,17 @@ export type Props = ScrollViewProps & {
|
|
|
39
32
|
initialFocusDirection?: FocusManager.Android.FocusNavigationDirections;
|
|
40
33
|
onAllComponentsLoaded?: () => void;
|
|
41
34
|
omitPropsPropagation?: Array<keyof FlatListProps<any>>;
|
|
42
|
-
renderItem:
|
|
35
|
+
renderItem: (info: {
|
|
36
|
+
item: ZappUIComponent;
|
|
37
|
+
index: number;
|
|
38
|
+
focused: boolean;
|
|
39
|
+
parentFocus: ParentFocus;
|
|
40
|
+
}) => React.ReactElement;
|
|
43
41
|
} & ParentFocus;
|
|
44
42
|
|
|
45
43
|
type State = boolean[];
|
|
46
44
|
type Action = { index?: number; isFocusable: boolean; type?: string };
|
|
47
45
|
|
|
48
|
-
const unwrapArray = (maybeArray) =>
|
|
49
|
-
Array.isArray(maybeArray) ? maybeArray[0] : maybeArray;
|
|
50
|
-
|
|
51
|
-
function getEntry<T>(data: T | T[], index: unknown): T {
|
|
52
|
-
let entry;
|
|
53
|
-
|
|
54
|
-
if (R.isNil(index)) {
|
|
55
|
-
entry = unwrapArray(data);
|
|
56
|
-
} else if (typeof index === "number") {
|
|
57
|
-
entry = unwrapArray(data[index]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return entry;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
46
|
const focusableStateReducer = (
|
|
64
47
|
state: State,
|
|
65
48
|
{ index = null, isFocusable, type = null }: Action
|
|
@@ -90,7 +73,7 @@ const extendScrollViewRef = (_ref, childCompsMeasurementsMap) => {
|
|
|
90
73
|
};
|
|
91
74
|
|
|
92
75
|
_ref.scrollToIndex = (params) => {
|
|
93
|
-
const { index, viewOffset
|
|
76
|
+
const { index, viewOffset } = params;
|
|
94
77
|
|
|
95
78
|
const itemByIndex = R.find(R.propEq("index", index))(
|
|
96
79
|
R.values(childCompsMeasurementsMap)
|
|
@@ -146,11 +129,8 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
146
129
|
);
|
|
147
130
|
|
|
148
131
|
const getFocusableEntryId = React.useCallback(
|
|
149
|
-
(_entry: ZappEntry
|
|
150
|
-
const entry
|
|
151
|
-
R.isNil(index) ? _entry : data,
|
|
152
|
-
index
|
|
153
|
-
);
|
|
132
|
+
(_entry: ZappEntry, index?: number) => {
|
|
133
|
+
const entry = R.isNil(index) ? _entry : data[index];
|
|
154
134
|
|
|
155
135
|
return entry ? `${props.id}--${entry?.id}` : undefined;
|
|
156
136
|
},
|
|
@@ -293,18 +273,11 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
293
273
|
const renderItem = React.useCallback(
|
|
294
274
|
(item, index) => {
|
|
295
275
|
const renderArgs = { item, index };
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
Array.isArray(item) ? item[0] : item,
|
|
299
|
-
index
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
const nextFocus = getNextFocus(index);
|
|
276
|
+
const id = `${props.id}--${renderArgs?.item?.id}`;
|
|
277
|
+
const nextFocus = getNextFocus(renderArgs?.index);
|
|
303
278
|
|
|
304
279
|
const onItemLayout = (event) => {
|
|
305
|
-
childCompsMeasurementsMap.current[
|
|
306
|
-
Array.isArray(item) ? index : item.id
|
|
307
|
-
] = {
|
|
280
|
+
childCompsMeasurementsMap.current[item.id] = {
|
|
308
281
|
index,
|
|
309
282
|
layout: event.nativeEvent.layout,
|
|
310
283
|
};
|