@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5974411329 → 14.0.0-alpha.6000342231
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/AnimatedInOut/index.tsx +69 -26
- package/Components/BaseFocusable/index.tsx +23 -12
- package/Components/Cell/Cell.tsx +91 -64
- package/Components/Cell/CellWithFocusable.tsx +3 -0
- package/Components/Cell/FocusableWrapper.tsx +44 -0
- package/Components/Cell/TvOSCellComponent.tsx +80 -14
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
- package/Components/FeedLoader/FeedLoader.tsx +7 -16
- package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
- package/Components/FeedLoader/index.js +2 -8
- package/Components/Focusable/Focusable.tsx +10 -3
- package/Components/Focusable/FocusableTvOS.tsx +2 -2
- package/Components/Focusable/Touchable.tsx +5 -3
- package/Components/Focusable/index.android.tsx +8 -4
- package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
- package/Components/FocusableList/FocusableItem.tsx +4 -3
- package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
- package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
- package/Components/FocusableList/index.tsx +16 -9
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +14 -17
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -65
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +74 -0
- package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +0 -12
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +65 -17
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +21 -3
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +6 -3
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +26 -6
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
- package/Components/MasterCell/utils/behaviorProvider.ts +2 -2
- package/Components/MasterCell/utils/index.ts +1 -19
- package/Components/OfflineHandler/__tests__/index.test.tsx +6 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +5 -17
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/River/ComponentsMap/ComponentsMap.tsx +49 -42
- package/Components/River/ComponentsMap/ContextProviders/ComponentsMapHeightContext.ts +8 -0
- package/Components/River/ComponentsMap/ContextProviders/ComponentsMapRefContext.ts +8 -0
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +0 -1
- package/Components/River/RefreshControl.tsx +11 -19
- package/Components/River/__tests__/river.test.js +12 -26
- package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
- package/Components/Screen/__tests__/Screen.test.tsx +5 -17
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
- package/Components/Screen/index.tsx +22 -5
- package/Components/Screen/navigationHandler.ts +20 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +2 -2
- package/Components/ScreenRevealManager/utils/index.ts +23 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
- package/Components/Tabs/TV/Tabs.android.tsx +1 -1
- package/Components/Tabs/Tabs.tsx +2 -3
- package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +13 -0
- package/Components/TextInputTv/index.tsx +11 -0
- package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +117 -157
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerDetails.tsx +5 -5
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +9 -1
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +40 -15
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +2 -2
- package/Components/VideoModal/hooks/utils/index.ts +4 -0
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Contexts/CellFocusedStateContext/index.tsx +27 -0
- package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
- package/Contexts/ScreenContext/index.tsx +28 -32
- package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
- package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
- package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
- package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
- package/Decorators/RiverFeedLoader/index.tsx +21 -13
- package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
- package/Decorators/RiverFeedLoader/utils/index.ts +0 -35
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +27 -27
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +3 -5
- package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +68 -76
- package/events/index.ts +3 -0
- package/package.json +5 -5
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -421
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
|
-
import {
|
|
4
|
-
findPluginByType,
|
|
5
|
-
findPluginByIdentifier,
|
|
6
|
-
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
7
2
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
3
|
import {
|
|
9
4
|
useDimensions,
|
|
@@ -16,6 +11,7 @@ import { PlayerContainer } from "../PlayerContainer";
|
|
|
16
11
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
12
|
import { ViewStyle } from "react-native";
|
|
18
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import { findCastPlugin, getPlayer } from "./utils";
|
|
19
15
|
|
|
20
16
|
type Props = {
|
|
21
17
|
item: ZappEntry;
|
|
@@ -26,62 +22,6 @@ type Props = {
|
|
|
26
22
|
groupId?: string;
|
|
27
23
|
};
|
|
28
24
|
|
|
29
|
-
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
30
|
-
const CHROMECAST_PLUGIN_ID = "chromecast_qb";
|
|
31
|
-
|
|
32
|
-
const getPlayerWithModuleProperties = (
|
|
33
|
-
PlayerModule: ZappPlugin
|
|
34
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
35
|
-
const getPlayerModuleProperties = R.ifElse(
|
|
36
|
-
R.is(Object) && R.has("Component"),
|
|
37
|
-
R.omit(["Component"]),
|
|
38
|
-
() => ({})
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
return [
|
|
42
|
-
PlayerModule?.Component || PlayerModule,
|
|
43
|
-
getPlayerModuleProperties(PlayerModule),
|
|
44
|
-
];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const getPlayer = (
|
|
48
|
-
item: ZappEntry,
|
|
49
|
-
state
|
|
50
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
51
|
-
const {
|
|
52
|
-
plugins,
|
|
53
|
-
contentTypes,
|
|
54
|
-
rivers,
|
|
55
|
-
appData: { layoutVersion },
|
|
56
|
-
} = state;
|
|
57
|
-
|
|
58
|
-
let PlayerModule;
|
|
59
|
-
|
|
60
|
-
if (layoutVersion === "v2") {
|
|
61
|
-
const { screen_id } = contentTypes?.[item?.type?.value] || {};
|
|
62
|
-
const { type } = rivers?.[screen_id] || {};
|
|
63
|
-
|
|
64
|
-
if (type) {
|
|
65
|
-
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
66
|
-
|
|
67
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (item?.content?.type === "youtube-id") {
|
|
72
|
-
PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;
|
|
73
|
-
|
|
74
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
PlayerModule = findPluginByType(
|
|
78
|
-
"playable",
|
|
79
|
-
plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
25
|
type PlayableComponent = {
|
|
86
26
|
Component: React.ComponentType<any>;
|
|
87
27
|
};
|
|
@@ -99,14 +39,23 @@ export function HandlePlayable({
|
|
|
99
39
|
mode,
|
|
100
40
|
groupId,
|
|
101
41
|
}: Props): React.ReactElement | null {
|
|
102
|
-
const
|
|
42
|
+
const { plugins, contentTypes, rivers, appData } = usePickFromState([
|
|
43
|
+
"plugins",
|
|
44
|
+
"contentTypes",
|
|
45
|
+
"rivers",
|
|
46
|
+
"appData",
|
|
47
|
+
]);
|
|
103
48
|
|
|
104
49
|
const { closeVideoModal } = useNavigation();
|
|
105
50
|
|
|
106
|
-
const [Player, playerModuleProperties] = getPlayer(item,
|
|
51
|
+
const [Player, playerModuleProperties] = getPlayer(item, {
|
|
52
|
+
plugins,
|
|
53
|
+
contentTypes,
|
|
54
|
+
rivers,
|
|
55
|
+
appData,
|
|
56
|
+
});
|
|
107
57
|
|
|
108
|
-
const { module: CastPlugin } =
|
|
109
|
-
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
|
|
58
|
+
const { module: CastPlugin } = findCastPlugin(plugins);
|
|
110
59
|
|
|
111
60
|
const [playable, setPlayable] =
|
|
112
61
|
React.useState<Nullable<PlayableComponent>>(null);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findPluginByIdentifier,
|
|
3
|
+
findPluginByType,
|
|
4
|
+
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
|
+
|
|
6
|
+
import { CHROMECAST_PLUGIN_ID, YOUTUBE_PLUGIN_ID } from "./const";
|
|
7
|
+
import { omit } from "@applicaster/zapp-react-native-utils/utils";
|
|
8
|
+
|
|
9
|
+
const getPlayerModuleProperties = (PlayerModule: ZappPlugin) => {
|
|
10
|
+
if (PlayerModule?.Component && typeof PlayerModule.Component === "object") {
|
|
11
|
+
return omit(["Component"], PlayerModule);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getPlayerWithModuleProperties = (
|
|
18
|
+
PlayerModule: ZappPlugin
|
|
19
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
20
|
+
return [
|
|
21
|
+
PlayerModule?.Component || PlayerModule,
|
|
22
|
+
getPlayerModuleProperties(PlayerModule),
|
|
23
|
+
];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const findCastPlugin = (plugins: ZappPlugin[]) =>
|
|
27
|
+
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, plugins, true) || {};
|
|
28
|
+
|
|
29
|
+
export const findYoutubePlugin = (plugins: ZappPlugin[]) =>
|
|
30
|
+
findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins, true) || {};
|
|
31
|
+
|
|
32
|
+
export const getPlayer = (
|
|
33
|
+
item: ZappEntry,
|
|
34
|
+
{
|
|
35
|
+
plugins,
|
|
36
|
+
contentTypes,
|
|
37
|
+
rivers,
|
|
38
|
+
appData: { layoutVersion },
|
|
39
|
+
}: {
|
|
40
|
+
plugins: ZappPlugin[];
|
|
41
|
+
contentTypes: Record<string, any>;
|
|
42
|
+
rivers: Record<string, any>;
|
|
43
|
+
appData: { layoutVersion: string };
|
|
44
|
+
}
|
|
45
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
46
|
+
let PlayerModule;
|
|
47
|
+
|
|
48
|
+
if (layoutVersion === "v2") {
|
|
49
|
+
const screen_id = contentTypes?.[item?.type?.value]?.screen_id;
|
|
50
|
+
const type = rivers?.[screen_id]?.type;
|
|
51
|
+
|
|
52
|
+
if (type) {
|
|
53
|
+
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
54
|
+
|
|
55
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (item?.content?.type === "youtube-id") {
|
|
60
|
+
PlayerModule = findYoutubePlugin(plugins)?.module;
|
|
61
|
+
|
|
62
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
PlayerModule = findPluginByType(
|
|
66
|
+
"playable",
|
|
67
|
+
(plugins as any[]).filter(
|
|
68
|
+
({ identifier }: { identifier: string }) =>
|
|
69
|
+
identifier !== YOUTUBE_PLUGIN_ID
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
74
|
+
};
|
|
@@ -7,7 +7,6 @@ import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/
|
|
|
7
7
|
import configureStore from "redux-mock-store";
|
|
8
8
|
import Layout from "../index.web";
|
|
9
9
|
|
|
10
|
-
// mock useTheme to provide app_background_color
|
|
11
10
|
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
12
11
|
useTheme: () => ({
|
|
13
12
|
app_background_color: "#000000",
|
|
@@ -23,6 +23,7 @@ type Props = {
|
|
|
23
23
|
style: ViewStyle;
|
|
24
24
|
testID?: string;
|
|
25
25
|
accessibilityLabel?: string;
|
|
26
|
+
accessibilityHint?: string;
|
|
26
27
|
cellUUID?: string;
|
|
27
28
|
extraProps?: Record<string, any>;
|
|
28
29
|
};
|
|
@@ -48,7 +49,9 @@ function getAssetValue(asset, flavour, fallbackAsset = null) {
|
|
|
48
49
|
return asset.src || fallbackAsset;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
export
|
|
52
|
+
export const ActionButton = React.memo(function ActionButtonComponent(
|
|
53
|
+
props: Props
|
|
54
|
+
) {
|
|
52
55
|
const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
|
|
53
56
|
const actionContext = useActions(action?.identifier);
|
|
54
57
|
|
|
@@ -98,6 +101,7 @@ export function ActionButton(props: Props) {
|
|
|
98
101
|
onPress={onPress}
|
|
99
102
|
testID={props?.testID || `${item?.id}`}
|
|
100
103
|
accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
|
|
104
|
+
accessibilityHint={props?.accessibilityHint}
|
|
101
105
|
accessible={!!(props?.testID || props?.accessibilityLabel)}
|
|
102
106
|
style={props?.style}
|
|
103
107
|
>
|
|
@@ -118,4 +122,4 @@ export function ActionButton(props: Props) {
|
|
|
118
122
|
)}
|
|
119
123
|
</TouchableOpacity>
|
|
120
124
|
);
|
|
121
|
-
}
|
|
125
|
+
});
|
|
@@ -4,7 +4,6 @@ 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 { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
6
6
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
-
import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
|
|
8
7
|
|
|
9
8
|
const { Logger } = getXray();
|
|
10
9
|
|
|
@@ -44,11 +43,6 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
44
43
|
|
|
45
44
|
const actionContext = useActions(pluginIdentifier);
|
|
46
45
|
|
|
47
|
-
const accessibilityManager = useAccessibilityManager({});
|
|
48
|
-
|
|
49
|
-
const { ttsLabel = "" } =
|
|
50
|
-
actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
|
|
51
|
-
|
|
52
46
|
const onPress = (event) => {
|
|
53
47
|
event?.preventDefault?.();
|
|
54
48
|
|
|
@@ -71,12 +65,6 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
71
65
|
focusedButtonId,
|
|
72
66
|
mouse: focusable.mouse,
|
|
73
67
|
});
|
|
74
|
-
|
|
75
|
-
if (ttsLabel) {
|
|
76
|
-
accessibilityManager.readText({
|
|
77
|
-
text: ttsLabel,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
68
|
};
|
|
81
69
|
|
|
82
70
|
const handleBlur = (_focusable, _direction) => {
|
|
@@ -28,17 +28,10 @@ interface Props {
|
|
|
28
28
|
onAsyncRender: () => void;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
displayMode,
|
|
36
|
-
imageSizing,
|
|
37
|
-
fitPosition,
|
|
38
|
-
fixedHeight,
|
|
39
|
-
fixedWidth,
|
|
40
|
-
onAsyncRender,
|
|
41
|
-
} = props;
|
|
31
|
+
/** Secondary Image Dynamic does not render until the image is loaded */
|
|
32
|
+
const SecondaryImageDynamic = (props: Props) => {
|
|
33
|
+
const { uri, style, displayMode, imageSizing, fitPosition, onAsyncRender } =
|
|
34
|
+
props;
|
|
42
35
|
|
|
43
36
|
const imageDimension = useGetImageDimensions(
|
|
44
37
|
uri,
|
|
@@ -46,13 +39,9 @@ const SecondaryImageComponent = (props: Props) => {
|
|
|
46
39
|
isImageSizingFit(imageSizing) ? undefined : (style.height as number)
|
|
47
40
|
);
|
|
48
41
|
|
|
49
|
-
const containerHeight =
|
|
50
|
-
? fixedHeight
|
|
51
|
-
: imageDimension?.height;
|
|
42
|
+
const containerHeight = imageDimension?.height;
|
|
52
43
|
|
|
53
|
-
const containerWidth =
|
|
54
|
-
? fixedWidth
|
|
55
|
-
: style?.width;
|
|
44
|
+
const containerWidth = style?.width;
|
|
56
45
|
|
|
57
46
|
if (isNil(imageDimension?.aspectRatio)) {
|
|
58
47
|
return null;
|
|
@@ -80,4 +69,63 @@ const SecondaryImageComponent = (props: Props) => {
|
|
|
80
69
|
);
|
|
81
70
|
};
|
|
82
71
|
|
|
72
|
+
/** Secondary Image Fixed does not render the image until the image is loaded, but keep container rendered */
|
|
73
|
+
const SecondaryImageFixed = (props: Props) => {
|
|
74
|
+
const {
|
|
75
|
+
uri,
|
|
76
|
+
style,
|
|
77
|
+
displayMode,
|
|
78
|
+
imageSizing,
|
|
79
|
+
fitPosition,
|
|
80
|
+
fixedHeight,
|
|
81
|
+
fixedWidth,
|
|
82
|
+
onAsyncRender,
|
|
83
|
+
} = props;
|
|
84
|
+
|
|
85
|
+
const imageDimension = useGetImageDimensions(
|
|
86
|
+
uri,
|
|
87
|
+
style.width as number,
|
|
88
|
+
isImageSizingFit(imageSizing) ? undefined : (style.height as number)
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View style={style} onLayout={onAsyncRender}>
|
|
93
|
+
{isNil(imageDimension?.aspectRatio) ? null : (
|
|
94
|
+
<Image
|
|
95
|
+
{...props}
|
|
96
|
+
source={{ uri }}
|
|
97
|
+
style={{
|
|
98
|
+
...getStyle({
|
|
99
|
+
imageSizing,
|
|
100
|
+
fitPosition,
|
|
101
|
+
displayMode,
|
|
102
|
+
imageDimension,
|
|
103
|
+
containerHeight: fixedHeight,
|
|
104
|
+
containerWidth: fixedWidth,
|
|
105
|
+
}),
|
|
106
|
+
borderRadius: style.borderRadius,
|
|
107
|
+
aspectRatio: imageDimension.aspectRatio,
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
</View>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const SecondaryImageComponent = (props: Props) => {
|
|
116
|
+
const { uri, displayMode } = props;
|
|
117
|
+
|
|
118
|
+
if (!uri) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const isFixed = isDisplayModeFixed(displayMode);
|
|
123
|
+
|
|
124
|
+
return isFixed ? (
|
|
125
|
+
<SecondaryImageFixed {...props} />
|
|
126
|
+
) : (
|
|
127
|
+
<SecondaryImageDynamic {...props} />
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
83
131
|
export const SecondaryImage = withAsyncRenderHOC(SecondaryImageComponent);
|
|
@@ -4,9 +4,26 @@ import { render } from "@testing-library/react-native";
|
|
|
4
4
|
import { SecondaryImage } from "../Image";
|
|
5
5
|
|
|
6
6
|
describe("SecondaryImage - Image", () => {
|
|
7
|
-
it("SecondaryImage should not render if no
|
|
7
|
+
it("SecondaryImage should not render if no uri", async () => {
|
|
8
8
|
const wrapper = await render(
|
|
9
|
-
<SecondaryImage
|
|
9
|
+
<SecondaryImage
|
|
10
|
+
displayMode="dynamic"
|
|
11
|
+
uri={undefined}
|
|
12
|
+
style={{ width: 100 }}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(wrapper.toJSON()).toEqual(null);
|
|
17
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("SecondaryImage should not render if no aspect ratio (dynamic)", async () => {
|
|
21
|
+
const wrapper = await render(
|
|
22
|
+
<SecondaryImage
|
|
23
|
+
displayMode="dynamic"
|
|
24
|
+
uri="someurl"
|
|
25
|
+
style={{ width: 100 }}
|
|
26
|
+
/>
|
|
10
27
|
);
|
|
11
28
|
|
|
12
29
|
expect(wrapper.toJSON()).toEqual(null);
|
|
@@ -16,7 +33,8 @@ describe("SecondaryImage - Image", () => {
|
|
|
16
33
|
it("SecondaryImage should render if known dimensions", async () => {
|
|
17
34
|
const wrapper = await render(
|
|
18
35
|
<SecondaryImage
|
|
19
|
-
uri=""
|
|
36
|
+
uri="someUrl"
|
|
37
|
+
displayMode="dynamic"
|
|
20
38
|
style={{ width: 100, height: 100, borderRadius: 10 }}
|
|
21
39
|
/>
|
|
22
40
|
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio 1`] = `null`;
|
|
3
|
+
exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio (dynamic) 1`] = `null`;
|
|
4
|
+
|
|
5
|
+
exports[`SecondaryImage - Image SecondaryImage should not render if no uri 1`] = `null`;
|
|
4
6
|
|
|
5
7
|
exports[`SecondaryImage - Image SecondaryImage should render if known dimensions 1`] = `
|
|
6
8
|
<View
|
|
@@ -14,10 +16,11 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
|
|
|
14
16
|
}
|
|
15
17
|
>
|
|
16
18
|
<Image
|
|
19
|
+
displayMode="dynamic"
|
|
17
20
|
onAsyncRender={[Function]}
|
|
18
21
|
source={
|
|
19
22
|
{
|
|
20
|
-
"uri": "",
|
|
23
|
+
"uri": "someUrl",
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
style={
|
|
@@ -28,7 +31,7 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
|
|
|
28
31
|
"width": 100,
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
|
-
uri=""
|
|
34
|
+
uri="someUrl"
|
|
32
35
|
/>
|
|
33
36
|
</View>
|
|
34
37
|
`;
|
|
@@ -11,6 +11,8 @@ import { withScaledLineHeight } from "./utils";
|
|
|
11
11
|
import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
12
12
|
import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
|
|
13
13
|
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
14
|
+
import { CellFocusedStateContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellFocusedStateContext";
|
|
15
|
+
import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
|
|
14
16
|
|
|
15
17
|
type Props = {
|
|
16
18
|
style: any;
|
|
@@ -35,10 +37,9 @@ const _Text = ({
|
|
|
35
37
|
}: Props) => {
|
|
36
38
|
const _label = useTextLabel({ label, entry });
|
|
37
39
|
const isMeasurement = React.useContext(MeasurementPortalContext);
|
|
40
|
+
const cellFocused = React.useContext(CellFocusedStateContext);
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
+
const accessibilityManager = useAccessibilityManager({});
|
|
42
43
|
|
|
43
44
|
// set maximum possible height for the text in case of measurement
|
|
44
45
|
const height =
|
|
@@ -46,6 +47,27 @@ const _Text = ({
|
|
|
46
47
|
? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
|
|
47
48
|
: undefined;
|
|
48
49
|
|
|
50
|
+
const textLabel = dateTransformEnabled
|
|
51
|
+
? dateFormat(dateTransform, label)
|
|
52
|
+
: textTransform(transformText, _label);
|
|
53
|
+
|
|
54
|
+
React.useLayoutEffect(() => {
|
|
55
|
+
// For FocusableCells with action buttons
|
|
56
|
+
if (otherProps.state) {
|
|
57
|
+
if (otherProps.state === "focused" && cellFocused === true) {
|
|
58
|
+
accessibilityManager.addHeading(textLabel);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
if (cellFocused === true) {
|
|
62
|
+
accessibilityManager.addHeading(textLabel);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, [cellFocused, otherProps.state, textLabel]);
|
|
66
|
+
|
|
67
|
+
if (isNilOrEmpty(_label)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
49
71
|
return (
|
|
50
72
|
<Text
|
|
51
73
|
style={[
|
|
@@ -55,9 +77,7 @@ const _Text = ({
|
|
|
55
77
|
allowFontScaling={false}
|
|
56
78
|
{...withoutLabel(otherProps)}
|
|
57
79
|
>
|
|
58
|
-
{
|
|
59
|
-
? dateFormat(dateTransform, label)
|
|
60
|
-
: textTransform(transformText, _label)}
|
|
80
|
+
{textLabel}
|
|
61
81
|
</Text>
|
|
62
82
|
);
|
|
63
83
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
3
|
import { Image } from "react-native";
|
|
4
4
|
|
|
5
5
|
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
@@ -10,35 +10,35 @@ const CustomImage = require("../Image").default;
|
|
|
10
10
|
|
|
11
11
|
describe("image with no source", () => {
|
|
12
12
|
it("Uses provided placeholder image string", () => {
|
|
13
|
-
const
|
|
13
|
+
const { UNSAFE_getByType } = render(
|
|
14
14
|
<CustomImage placeholderImage={"foo"} />
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const imageComponent = UNSAFE_getByType(Image);
|
|
18
18
|
|
|
19
|
-
expect(
|
|
19
|
+
expect(imageComponent.props.source).toEqual({
|
|
20
20
|
uri: "foo",
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
it("Uses provided placeholder image object", () => {
|
|
25
|
-
const
|
|
25
|
+
const { UNSAFE_getByType } = render(
|
|
26
26
|
<CustomImage placeholderImage={"foo"} />
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const imageComponent = UNSAFE_getByType(Image);
|
|
30
30
|
|
|
31
|
-
expect(
|
|
31
|
+
expect(imageComponent.props.source).toEqual({
|
|
32
32
|
uri: "foo",
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it("Returns empty string if no image or placeholder defined", () => {
|
|
37
|
-
const
|
|
37
|
+
const { UNSAFE_getByType } = render(
|
|
38
38
|
<CustomImage placeholderImage={null} />
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
expect(
|
|
41
|
+
const imageComponent = UNSAFE_getByType(Image);
|
|
42
|
+
expect(imageComponent.props.source).toBeUndefined();
|
|
43
43
|
});
|
|
44
44
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import RN from "react-native";
|
|
3
|
-
import {
|
|
4
|
-
import TestRenderer from "react-test-renderer";
|
|
5
|
-
import configureStoreFn from "redux-mock-store";
|
|
3
|
+
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
6
4
|
|
|
7
5
|
const mockUseIsRTL = jest.fn(() => true);
|
|
8
6
|
const mockGetIsRTL = jest.fn(() => true);
|
|
@@ -17,7 +15,6 @@ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
|
17
15
|
}));
|
|
18
16
|
|
|
19
17
|
const CustomText = require("../Text").default;
|
|
20
|
-
const mockStore = configureStoreFn();
|
|
21
18
|
|
|
22
19
|
const defaultProps = {
|
|
23
20
|
entry: {},
|
|
@@ -25,16 +22,15 @@ const defaultProps = {
|
|
|
25
22
|
transformText: "default",
|
|
26
23
|
};
|
|
27
24
|
|
|
28
|
-
const getRenderedText = (label: string,
|
|
25
|
+
const getRenderedText = (label: string, storeConfig: any) => {
|
|
29
26
|
const props = { ...{ ...defaultProps, label } };
|
|
30
27
|
|
|
31
|
-
const
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
</Provider>
|
|
28
|
+
const { UNSAFE_getByType } = renderWithProviders(
|
|
29
|
+
<CustomText {...props} />,
|
|
30
|
+
storeConfig
|
|
35
31
|
);
|
|
36
32
|
|
|
37
|
-
return
|
|
33
|
+
return UNSAFE_getByType(RN.Text).props.children;
|
|
38
34
|
};
|
|
39
35
|
|
|
40
36
|
describe("RTL app: Hebrew text contains english word", () => {
|
|
@@ -42,28 +38,32 @@ describe("RTL app: Hebrew text contains english word", () => {
|
|
|
42
38
|
const textWithNotFirstEnglishWord = "השיר של נועה נועה קירל באירוויזיון Word";
|
|
43
39
|
const textWithoutEnglishWord = "השיר של נועה נועה קירל באירוויזיון";
|
|
44
40
|
|
|
45
|
-
const
|
|
41
|
+
const storeConfig = {
|
|
46
42
|
remoteConfigurations: { localizations: { he: {} } },
|
|
47
43
|
appData: {
|
|
48
44
|
languageCode: "he",
|
|
49
45
|
countryCode: "IL",
|
|
50
46
|
},
|
|
51
|
-
}
|
|
47
|
+
};
|
|
52
48
|
|
|
53
49
|
it("Hebrew text contains first english word", () => {
|
|
54
|
-
const renderedText = getRenderedText(textWithFirstEnglishWord,
|
|
50
|
+
const renderedText = getRenderedText(textWithFirstEnglishWord, storeConfig);
|
|
55
51
|
const desiredText = "\u200fWord\u202c השיר של נועה נועה קירל באירוויזיון";
|
|
56
52
|
|
|
57
53
|
expect(renderedText).toEqual(desiredText);
|
|
58
54
|
});
|
|
59
55
|
|
|
60
56
|
it("Hebrew text contains not first english word", () => {
|
|
61
|
-
const renderedText = getRenderedText(
|
|
57
|
+
const renderedText = getRenderedText(
|
|
58
|
+
textWithNotFirstEnglishWord,
|
|
59
|
+
storeConfig
|
|
60
|
+
);
|
|
61
|
+
|
|
62
62
|
expect(renderedText).toEqual(textWithNotFirstEnglishWord);
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
it("Hebrew text doesn't contain english word", () => {
|
|
66
|
-
const renderedText = getRenderedText(textWithoutEnglishWord,
|
|
66
|
+
const renderedText = getRenderedText(textWithoutEnglishWord, storeConfig);
|
|
67
67
|
expect(renderedText).toEqual(textWithoutEnglishWord);
|
|
68
68
|
});
|
|
69
69
|
});
|
|
@@ -77,16 +77,16 @@ describe("LTR app: English text", () => {
|
|
|
77
77
|
|
|
78
78
|
const englishText = "Test sentence";
|
|
79
79
|
|
|
80
|
-
const
|
|
80
|
+
const storeConfig = {
|
|
81
81
|
remoteConfigurations: { localizations: { en: {} } },
|
|
82
82
|
appData: {
|
|
83
83
|
languageCode: "en",
|
|
84
84
|
countryCode: "US",
|
|
85
85
|
},
|
|
86
|
-
}
|
|
86
|
+
};
|
|
87
87
|
|
|
88
88
|
it("English text", () => {
|
|
89
|
-
const renderedText = getRenderedText(englishText,
|
|
89
|
+
const renderedText = getRenderedText(englishText, storeConfig);
|
|
90
90
|
expect(renderedText).toEqual(englishText);
|
|
91
91
|
});
|
|
92
92
|
});
|