@applicaster/zapp-react-native-ui-components 13.0.0-alpha.8357105823 → 13.0.0-alpha.8432878190
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 -3
- package/Components/Cell/CellWithFocusable.ios.tsx +126 -0
- package/Components/Cell/CellWithFocusable.tsx +43 -59
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
- package/Components/ErrorScreen/index.tsx +6 -6
- package/Components/Focusable/Focusable.tsx +1 -0
- package/Components/Focusable/Touchable.tsx +19 -20
- 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.ios.tsx +5 -11
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
- 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/Button/index.tsx +6 -6
- package/Components/ModalComponent/Header/index.tsx +3 -3
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
- package/Components/PlayerContainer/PlayerContainer.tsx +8 -8
- package/Components/PlayerContainer/PlayerContainerContext.tsx +9 -0
- package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
- 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/__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 +16 -42
- package/Components/Tabs/Tab.tsx +11 -9
- package/Components/TextInputTv/index.tsx +4 -3
- package/Components/Transitioner/AnimationManager.js +8 -8
- package/Components/Transitioner/Scene.tsx +53 -24
- package/Components/Transitioner/Transitioner.tsx +3 -3
- 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 +32 -24
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +51 -1
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +0 -5
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +16 -12
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +5 -1
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +14 -13
- 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/PlayerDetails.tsx +5 -5
- package/Components/VideoModal/PlayerWrapper.tsx +17 -36
- 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 +6 -15
- package/package.json +5 -5
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -273,10 +273,14 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
273
273
|
if (isFocused) {
|
|
274
274
|
const accessibilityManager = AccessibilityManager.getInstance();
|
|
275
275
|
|
|
276
|
+
const accessibilityTitle =
|
|
277
|
+
item?.extensions?.accessibility?.label || item?.title || "";
|
|
278
|
+
|
|
279
|
+
const accessibilityHint =
|
|
280
|
+
item?.extensions?.accessibility?.hint || "";
|
|
281
|
+
|
|
276
282
|
accessibilityManager.readText({
|
|
277
|
-
text:
|
|
278
|
-
item.extensions?.accessibility?.label || item.title
|
|
279
|
-
),
|
|
283
|
+
text: `${accessibilityTitle} ${accessibilityHint}`,
|
|
280
284
|
});
|
|
281
285
|
}
|
|
282
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
|
}
|
|
@@ -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
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
ImageStyle,
|
|
5
5
|
StyleSheet,
|
|
6
6
|
Text,
|
|
7
|
-
ViewStyle,
|
|
8
|
-
TextStyle,
|
|
9
|
-
ImageStyle,
|
|
10
7
|
TextProps,
|
|
8
|
+
TextStyle,
|
|
9
|
+
View,
|
|
10
|
+
ViewStyle,
|
|
11
11
|
} from "react-native";
|
|
12
12
|
import { defaultAsset } from "./defaultAsset";
|
|
13
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
@@ -150,13 +150,13 @@ export function ErrorScreen(props: Props) {
|
|
|
150
150
|
return (
|
|
151
151
|
<View style={[baseStyles.container, styles.screen]}>
|
|
152
152
|
<View style={[baseStyles.container, styles.component]}>
|
|
153
|
-
{assetEnabled
|
|
153
|
+
{assetEnabled ? (
|
|
154
154
|
<Image
|
|
155
155
|
fadeDuration={0}
|
|
156
156
|
source={{ uri: asset }}
|
|
157
157
|
style={styles.asset}
|
|
158
158
|
/>
|
|
159
|
-
)}
|
|
159
|
+
) : null}
|
|
160
160
|
<Text style={styles.title} {...titleProps}>
|
|
161
161
|
{title}
|
|
162
162
|
</Text>
|
|
@@ -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 {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BorderContainerView,
|
|
3
|
+
getBorderPadding, // Export for testing (using a double underscore prefix is a common convention)
|
|
4
|
+
} from "../index";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { render } from "@testing-library/react-native";
|
|
7
|
+
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
8
|
+
import { View } from "react-native";
|
|
9
|
+
|
|
10
|
+
jest.mock("@applicaster/zapp-react-native-utils/numberUtils", () => ({
|
|
11
|
+
toNumberWithDefaultZero: jest.fn((value) => Number(value) || 0),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe("BorderContainerView", () => {
|
|
15
|
+
describe("getBorderPadding", () => {
|
|
16
|
+
it("returns 0 for inside", () => {
|
|
17
|
+
expect(getBorderPadding("inside", 10)).toBe(0);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns borderWidth / 2 for center", () => {
|
|
21
|
+
expect(getBorderPadding("center", 10)).toBe(5);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("returns borderWidth for outside", () => {
|
|
25
|
+
expect(getBorderPadding("outside", 10)).toBe(10);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns borderWidth for invalid position", () => {
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
expect(getBorderPadding("other_value", 10)).toBe(10);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("Border component renders null if no borderPosition", () => {
|
|
35
|
+
const style = { borderWidth: 5, borderRadius: 10, borderColor: "red" };
|
|
36
|
+
|
|
37
|
+
const padding = {
|
|
38
|
+
paddingTop: 2,
|
|
39
|
+
paddingRight: 3,
|
|
40
|
+
paddingBottom: 4,
|
|
41
|
+
paddingLeft: 5,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const borderPosition = null;
|
|
45
|
+
|
|
46
|
+
const { queryByTestId } = render(
|
|
47
|
+
<BorderContainerView
|
|
48
|
+
style={style}
|
|
49
|
+
testID="border-container"
|
|
50
|
+
borderPosition={borderPosition}
|
|
51
|
+
borderPaddingTop={toNumberWithDefaultZero(padding.paddingTop)}
|
|
52
|
+
borderPaddingRight={toNumberWithDefaultZero(padding.paddingRight)}
|
|
53
|
+
borderPaddingBottom={toNumberWithDefaultZero(padding.paddingBottom)}
|
|
54
|
+
borderPaddingLeft={toNumberWithDefaultZero(padding.paddingLeft)}
|
|
55
|
+
>
|
|
56
|
+
<View testID="child" />
|
|
57
|
+
</BorderContainerView>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const children = queryByTestId("border-container").children;
|
|
61
|
+
|
|
62
|
+
expect(children[1].props.testID).toBe("child");
|
|
63
|
+
|
|
64
|
+
expect(children[0].children.length).toBe(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -28,7 +28,10 @@ const styles = StyleSheet.create({
|
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const getBorderPadding = (
|
|
31
|
+
export const getBorderPadding = (
|
|
32
|
+
borderPosition: BorderPosition,
|
|
33
|
+
borderWidth: number
|
|
34
|
+
) => {
|
|
32
35
|
switch (borderPosition) {
|
|
33
36
|
case "inside":
|
|
34
37
|
return 0;
|
|
@@ -38,22 +38,16 @@ function Image({
|
|
|
38
38
|
|
|
39
39
|
const shouldRenderImg = source && !error;
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const defaultPlaceHolderImage = React.useMemo(
|
|
45
|
-
() => ({ uri: placeholderImage || "" }),
|
|
46
|
-
[source, error]
|
|
47
|
-
);
|
|
41
|
+
const _source = shouldRenderImg
|
|
42
|
+
? withDimensions(source)
|
|
43
|
+
: { uri: placeholderImage };
|
|
48
44
|
|
|
49
45
|
return (
|
|
50
|
-
// @ts-ignore
|
|
51
46
|
<MemoizedImage
|
|
52
47
|
style={style as ImageStyle}
|
|
53
48
|
onError={React.useCallback(() => setErrorState(true), [])}
|
|
54
|
-
source
|
|
55
|
-
|
|
56
|
-
}
|
|
49
|
+
// as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
|
|
50
|
+
source={_source?.uri ? _source : undefined}
|
|
57
51
|
{...R.omit(["source"], otherProps)}
|
|
58
52
|
/>
|
|
59
53
|
);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ImageBorderContainer } from "../index";
|
|
2
|
+
import { getImageContainerMarginStyles } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
3
|
+
|
|
4
|
+
const mockValue = (key) => {
|
|
5
|
+
const values = {
|
|
6
|
+
cell_padding_top: 1,
|
|
7
|
+
cell_padding_left: 2,
|
|
8
|
+
cell_padding_right: 3,
|
|
9
|
+
cell_padding_bottom: 4,
|
|
10
|
+
image_border_size: 5,
|
|
11
|
+
image_focused_border_color: "red",
|
|
12
|
+
image_selected_border_color: "blue",
|
|
13
|
+
image_focused_selected_border_color: "green",
|
|
14
|
+
image_border_color: "black",
|
|
15
|
+
image_corner_radius: 10,
|
|
16
|
+
image_border_position: "outside",
|
|
17
|
+
image_border_padding_top: 6,
|
|
18
|
+
image_border_padding_right: 7,
|
|
19
|
+
image_border_padding_bottom: 8,
|
|
20
|
+
image_border_padding_left: 9,
|
|
21
|
+
image_margin_top: 11,
|
|
22
|
+
image_margin_left: 12,
|
|
23
|
+
image_margin_right: 13,
|
|
24
|
+
image_margin_bottom: 14,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return values[key] || 0;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe("ImageBorderContainer", () => {
|
|
31
|
+
it("calculates style properties correctly", () => {
|
|
32
|
+
const marginStyles = getImageContainerMarginStyles({ value: mockValue });
|
|
33
|
+
|
|
34
|
+
expect(marginStyles.marginTop).toBe(11);
|
|
35
|
+
expect(marginStyles.marginLeft).toBe(12);
|
|
36
|
+
expect(marginStyles.marginRight).toBe(13);
|
|
37
|
+
expect(marginStyles.marginBottom).toBe(14);
|
|
38
|
+
|
|
39
|
+
const props = {
|
|
40
|
+
value: mockValue,
|
|
41
|
+
state: "default",
|
|
42
|
+
imageStyles: {},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const result = ImageBorderContainer(props);
|
|
46
|
+
|
|
47
|
+
expect(result.style.marginTop).toBe(12); // 11 + 1
|
|
48
|
+
expect(result.style.marginLeft).toBe(14); // 12 + 2
|
|
49
|
+
expect(result.style.marginRight).toBe(16); // 13 + 3
|
|
50
|
+
expect(result.style.marginBottom).toBe(18); // 14 + 4
|
|
51
|
+
expect(result.style.borderWidth).toBe(5);
|
|
52
|
+
expect(result.style.borderColor).toBe("black");
|
|
53
|
+
expect(result.style.borderRadius).toBe(10);
|
|
54
|
+
expect(result.additionalProps.borderPosition).toBe("outside");
|
|
55
|
+
expect(result.additionalProps.borderPaddingTop).toBe(6);
|
|
56
|
+
expect(result.additionalProps.borderPaddingRight).toBe(7);
|
|
57
|
+
expect(result.additionalProps.borderPaddingBottom).toBe(8);
|
|
58
|
+
expect(result.additionalProps.borderPaddingLeft).toBe(9);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("handles focused state correctly", () => {
|
|
62
|
+
const props = {
|
|
63
|
+
value: mockValue,
|
|
64
|
+
state: "focused",
|
|
65
|
+
imageStyles: {},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = ImageBorderContainer(props);
|
|
69
|
+
expect(result.style.borderColor).toBe("red");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("handles selected state correctly", () => {
|
|
73
|
+
const props = {
|
|
74
|
+
value: mockValue,
|
|
75
|
+
state: "selected",
|
|
76
|
+
imageStyles: {},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const result = ImageBorderContainer(props);
|
|
80
|
+
expect(result.style.borderColor).toBe("blue");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("handles focused and selected state correctly", () => {
|
|
84
|
+
const props = {
|
|
85
|
+
value: mockValue,
|
|
86
|
+
state: "focused_selected",
|
|
87
|
+
imageStyles: {},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const result = ImageBorderContainer(props);
|
|
91
|
+
expect(result.style.borderColor).toBe("green");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -244,7 +244,7 @@ const LiveImageComponent = (props: LiveImageProps) => {
|
|
|
244
244
|
return (
|
|
245
245
|
<>
|
|
246
246
|
<Image {...props} applyMaxSize />
|
|
247
|
-
{isShouldRender
|
|
247
|
+
{isShouldRender ? (
|
|
248
248
|
<View style={[style, positionAbsolute]}>
|
|
249
249
|
<PlayerLiveImage
|
|
250
250
|
uri={props.uri}
|
|
@@ -257,7 +257,7 @@ const LiveImageComponent = (props: LiveImageProps) => {
|
|
|
257
257
|
audioMutedByDefault={audio_muted_by_default}
|
|
258
258
|
/>
|
|
259
259
|
</View>
|
|
260
|
-
)}
|
|
260
|
+
) : null}
|
|
261
261
|
</>
|
|
262
262
|
);
|
|
263
263
|
};
|
|
@@ -17,7 +17,7 @@ const SECONDARY_IMAGE_PREFIX = "secondary_image";
|
|
|
17
17
|
|
|
18
18
|
type ImageSizing = typeof IMAGE_SIZING_FIT | typeof IMAGE_SIZING_FILL;
|
|
19
19
|
|
|
20
|
-
type ImagePosition = typeof IMAGE_POSITION[keyof typeof IMAGE_POSITION];
|
|
20
|
+
type ImagePosition = (typeof IMAGE_POSITION)[keyof typeof IMAGE_POSITION];
|
|
21
21
|
|
|
22
22
|
export type DisplayMode =
|
|
23
23
|
| typeof DISPLAY_MODE_FIXED
|