@applicaster/zapp-react-native-utils 12.0.0-alpha.9151207838 → 12.0.0-alpha.9233494544
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/actionsExecutor/ActionExecutorContext.tsx +11 -3
- package/analyticsUtils/__tests__/analyticsManager.test.js +75 -73
- package/analyticsUtils/helpers/hooks.ts +1 -1
- package/appUtils/HooksManager/index.js +3 -1
- package/appUtils/focusManager/index.ts +147 -25
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +83 -33
- package/appUtils/focusManager/utils/index.ts +77 -0
- package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +1 -1
- package/appUtils/keyCodes/__tests__/keyCodes.test.js +80 -85
- package/appUtils/keyCodes/keys.web.js +1 -0
- package/appUtils/orientationHelper.ts +1 -1
- package/appUtils/playerManager/conts.ts +5 -0
- package/appUtils/playerManager/player.ts +35 -0
- package/appUtils/playerManager/playerFactory.ts +15 -1
- package/appUtils/playerManager/playerNative.ts +9 -0
- package/cellUtils/__tests__/cellUtils.test.ts +59 -0
- package/cellUtils/__tests__/fixtures.ts +13 -0
- package/cellUtils/index.ts +46 -2
- package/focusManager/index.ts +1 -1
- package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +2 -2
- package/functionUtils/__tests__/functionUtils.test.js +244 -248
- package/headersUtils/index.ts +1 -0
- package/localizationUtils/__tests__/localizationUtils.test.ts +17 -13
- package/localizationUtils/index.ts +6 -3
- package/logger/index.ts +1 -1
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +2 -1
- package/manifestUtils/index.js +5 -1
- package/manifestUtils/secondaryImage/index.js +18 -15
- package/navigationUtils/index.ts +56 -7
- package/package.json +3 -2
- package/playerUtils/configurationGenerator.ts +3 -1
- package/pluginUtils/index.ts +11 -7
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
- package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
- package/reactHooks/cell-click/__tests__/index.test.js +6 -2
- package/reactHooks/cell-click/index.ts +2 -2
- package/reactHooks/device/index.ts +0 -1
- package/reactHooks/device/useIsTablet.tsx +28 -3
- package/reactHooks/device/useMemoizedIsTablet.ts +1 -1
- package/reactHooks/device/useOrientation.tsx +3 -1
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +16 -9
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +66 -59
- package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
- package/reactHooks/layout/index.ts +2 -1
- package/reactHooks/layout/types/index.ts +2 -0
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +11 -16
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +12 -14
- package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
- package/reactHooks/navigation/__mocks__/index.ts +15 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +234 -78
- package/reactHooks/navigation/index.ts +262 -81
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
- package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
- package/reactHooks/screen/index.ts +2 -0
- package/reactHooks/screen/useScreenContext.ts +5 -4
- package/reactHooks/screen/useScreenData.ts +1 -1
- package/reactHooks/screen/useTargetScreenData.ts +7 -0
- package/reactHooks/state/useRivers.ts +3 -1
- package/reactHooks/useListenEventBusEvent.ts +1 -4
- package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +10 -9
- package/reactUtils/helpers.tsx +1 -1
- package/riverComponetsMeasurementProvider/index.tsx +2 -2
- package/stringUtils/index.ts +5 -0
- package/testUtils/getByTestId.ts +14 -0
- package/testUtils/index.tsx +38 -23
- package/reactHooks/device/useIsTablet.android.tsx +0 -14
- package/reactHooks/device/useIsTablet.ios.tsx +0 -7
- package/reactHooks/device/useIsTablet.web.tsx +0 -3
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
2
|
+
import { find, last, startsWith, pathOr } from "ramda";
|
|
3
|
+
|
|
4
|
+
// run check each 300 ms
|
|
5
|
+
// run this check too often could lead to performance penalty on low-end devices
|
|
6
|
+
const HOW_OFTEN_TO_CHECK_CONDITION = 300; //ms
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
maxTimeout: number;
|
|
10
|
+
conditionFn: () => boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const waitUntil = ({ maxTimeout, conditionFn }: Props) => {
|
|
14
|
+
let interval;
|
|
15
|
+
let timeout;
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
interval = setInterval(() => {
|
|
18
|
+
if (conditionFn()) {
|
|
19
|
+
clearInterval(interval);
|
|
20
|
+
clearTimeout(timeout);
|
|
21
|
+
|
|
22
|
+
resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
}, HOW_OFTEN_TO_CHECK_CONDITION);
|
|
25
|
+
|
|
26
|
+
timeout = setTimeout(() => {
|
|
27
|
+
clearInterval(interval);
|
|
28
|
+
clearTimeout(timeout);
|
|
29
|
+
|
|
30
|
+
reject();
|
|
31
|
+
}, maxTimeout);
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const waitForActiveScreen = (currentRoute: string, focusableTree) => {
|
|
36
|
+
const isActiveScreenAvailableToFocus = (): boolean => {
|
|
37
|
+
const routes = focusableTree.root.children;
|
|
38
|
+
|
|
39
|
+
const route = find((route) => route.id === currentRoute, routes);
|
|
40
|
+
return isNotNil(route);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return waitUntil({
|
|
44
|
+
maxTimeout: 2500, //ms
|
|
45
|
+
conditionFn: isActiveScreenAvailableToFocus,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getActiveScreen = (focusableTree) => {
|
|
50
|
+
return last(focusableTree.root.children);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const getContentNode = (focusableTree) => {
|
|
54
|
+
const content = find(
|
|
55
|
+
(child) => startsWith("content", child.id),
|
|
56
|
+
getActiveScreen(focusableTree)?.children
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return content;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const waitForContent = (focusableTree) => {
|
|
63
|
+
const contentHasAnyChildren = (): boolean => {
|
|
64
|
+
const countOfChildren = pathOr(
|
|
65
|
+
0,
|
|
66
|
+
["children", "length"],
|
|
67
|
+
getContentNode(focusableTree)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return countOfChildren > 0;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return waitUntil({
|
|
74
|
+
maxTimeout: 2500, //ms
|
|
75
|
+
conditionFn: contentHasAnyChildren,
|
|
76
|
+
});
|
|
77
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const { Platform } = require("react-native");
|
|
2
|
+
|
|
3
|
+
Platform.OS = "web";
|
|
4
|
+
|
|
1
5
|
import { directionHelper } from "../../directionHelper";
|
|
2
6
|
|
|
3
7
|
const globalTizen = {
|
|
@@ -6,105 +10,96 @@ const globalTizen = {
|
|
|
6
10
|
},
|
|
7
11
|
};
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe("keyCode", () => {
|
|
14
|
-
const { keyCode } = require("../index");
|
|
15
|
-
const { KEYS } = require("../keys.web");
|
|
16
|
-
|
|
17
|
-
it("returns an object for a given key event", () => {
|
|
18
|
-
expect(keyCode(KEYS.Enter)).toMatchSnapshot();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("has a matcher method for a single key", () => {
|
|
22
|
-
expect(keyCode(KEYS.Enter).matches("Enter")).toBeTruthy();
|
|
23
|
-
expect(keyCode(KEYS.Enter).matches(KEYS.Enter)).toBeTruthy();
|
|
24
|
-
expect(keyCode(KEYS.Back).matches("Enter")).toBeFalsy();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("has matcher for multiple keys", () => {
|
|
28
|
-
expect(
|
|
29
|
-
keyCode(KEYS.Enter).matchesAny("Enter", "Back", "ArrowUp")
|
|
30
|
-
).toBeTruthy();
|
|
13
|
+
describe("keyCodes", () => {
|
|
14
|
+
describe("keyCode", () => {
|
|
15
|
+
const { keyCode } = require("..");
|
|
16
|
+
const { KEYS } = require("../keys.web");
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
keyCode(KEYS.Enter).
|
|
34
|
-
)
|
|
35
|
-
});
|
|
18
|
+
it("returns an object for a given key event", () => {
|
|
19
|
+
expect(keyCode(KEYS.Enter)).toMatchSnapshot();
|
|
20
|
+
});
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
it("has a matcher method for a single key", () => {
|
|
23
|
+
expect(keyCode(KEYS.Enter).matches("Enter")).toBeTruthy();
|
|
24
|
+
expect(keyCode(KEYS.Enter).matches(KEYS.Enter)).toBeTruthy();
|
|
25
|
+
expect(keyCode(KEYS.Back).matches("Enter")).toBeFalsy();
|
|
26
|
+
});
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
it("has matcher for multiple keys", () => {
|
|
29
|
+
expect(
|
|
30
|
+
keyCode(KEYS.Enter).matchesAny("Enter", "Back", "ArrowUp")
|
|
31
|
+
).toBeTruthy();
|
|
44
32
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
expect(
|
|
34
|
+
keyCode(KEYS.Enter).matchesAny("Back", "ArrowUp", "ArrowDown")
|
|
35
|
+
).toBeFalsy();
|
|
48
36
|
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return { Platform: { OS: "samsung_tv" } };
|
|
55
|
-
});
|
|
38
|
+
it("returns the direction if it matches an arrow key", () => {
|
|
39
|
+
expect(keyCode(KEYS.Enter).direction()).toBe(null);
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
41
|
+
expect(keyCode(KEYS.ArrowDown).direction()).toEqual(
|
|
42
|
+
directionHelper(KEYS.ArrowDown)
|
|
43
|
+
);
|
|
44
|
+
});
|
|
61
45
|
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
describe("in web env", () => {
|
|
47
|
+
it("uses the proper keyCode for the environment", () => {
|
|
48
|
+
expect(keyCode({ keyCode: 13 }).matches(KEYS.Enter)).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
64
51
|
});
|
|
65
52
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
describe("in Tizen Env", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
jest.resetModules();
|
|
56
|
+
global.tizen = globalTizen;
|
|
57
|
+
});
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"MediaPlayPause",
|
|
74
|
-
"MediaPause",
|
|
75
|
-
"MediaFastForward",
|
|
76
|
-
"MediaRewind",
|
|
77
|
-
"MediaStop",
|
|
78
|
-
"Exit",
|
|
79
|
-
"0",
|
|
80
|
-
"1",
|
|
81
|
-
"2",
|
|
82
|
-
"3",
|
|
83
|
-
"4",
|
|
84
|
-
"5",
|
|
85
|
-
"6",
|
|
86
|
-
"7",
|
|
87
|
-
"8",
|
|
88
|
-
"9",
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
expect(keyCode({ keyCode: 10009 }).matches(KEYS.Back)).toBeTruthy();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
global.tizen = undefined;
|
|
61
|
+
});
|
|
94
62
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
63
|
+
it("uses the proper keyCode for the environment", () => {
|
|
64
|
+
Platform.OS = "samsung_tv";
|
|
65
|
+
const { keyCode } = require("../");
|
|
66
|
+
const { KEYS } = require("../keys.web");
|
|
67
|
+
|
|
68
|
+
expect(globalTizen.tvinputdevice.registerKeyBatch).toHaveBeenCalledWith([
|
|
69
|
+
"MediaPlay",
|
|
70
|
+
"MediaPlayPause",
|
|
71
|
+
"MediaPause",
|
|
72
|
+
"MediaFastForward",
|
|
73
|
+
"MediaRewind",
|
|
74
|
+
"MediaStop",
|
|
75
|
+
"Exit",
|
|
76
|
+
"0",
|
|
77
|
+
"1",
|
|
78
|
+
"2",
|
|
79
|
+
"3",
|
|
80
|
+
"4",
|
|
81
|
+
"5",
|
|
82
|
+
"6",
|
|
83
|
+
"7",
|
|
84
|
+
"8",
|
|
85
|
+
"9",
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
expect(keyCode({ keyCode: 10009 }).matches(KEYS.Back)).toBeTruthy();
|
|
89
|
+
});
|
|
98
90
|
});
|
|
99
91
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
describe("in WebOS Env", () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
jest.resetModules();
|
|
95
|
+
});
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
it("uses the proper keyCode for the environment", () => {
|
|
98
|
+
Platform.OS = "lg_tv";
|
|
99
|
+
const { keyCode } = require("..");
|
|
100
|
+
const { KEYS } = require("../keys.web");
|
|
101
|
+
// Back is reserved on LG
|
|
102
|
+
expect(keyCode({ keyCode: 417 }).matches(KEYS.Forward)).toBeTruthy();
|
|
103
|
+
});
|
|
109
104
|
});
|
|
110
105
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as ReactNative from "react-native";
|
|
3
3
|
import { isTV, platformSelect } from "../reactUtils";
|
|
4
4
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
|
+
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
QUICK_BRICK_EVENTS,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
sendQuickBrickEvent,
|
|
10
11
|
} from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
11
12
|
import { utilsLogger } from "../logger";
|
|
12
|
-
import { useIsTablet } from "../reactHooks/device/useIsTablet";
|
|
13
13
|
|
|
14
14
|
const { DeviceEventEmitter, NativeModules, NativeEventEmitter } = ReactNative;
|
|
15
15
|
|
|
@@ -20,6 +20,11 @@ export enum SharedPlayerCallBacksKeys {
|
|
|
20
20
|
OnPlayerMute = "onPlayerMute",
|
|
21
21
|
OnPlayerUnmute = "onPlayerUnmute",
|
|
22
22
|
|
|
23
|
+
onVideoFullscreenPlayerDidDismiss = "onVideoFullscreenPlayerDidDismiss",
|
|
24
|
+
onVideoFullscreenPlayerDidPresent = "onVideoFullscreenPlayerDidPresent",
|
|
25
|
+
onVideoFullscreenPlayerWillDismiss = "onVideoFullscreenPlayerWillDismiss",
|
|
26
|
+
onVideoFullscreenPlayerWillPresent = "onVideoFullscreenPlayerWillPresent",
|
|
27
|
+
|
|
23
28
|
OnAdBegin = "onAdBegin",
|
|
24
29
|
OnAdBreakBegin = "onAdBreakBegin",
|
|
25
30
|
OnAdBreakEnd = "onAdBreakEnd",
|
|
@@ -414,6 +414,32 @@ export class Player {
|
|
|
414
414
|
});
|
|
415
415
|
};
|
|
416
416
|
|
|
417
|
+
onVideoFullscreenPlayerWillDismiss = () => {
|
|
418
|
+
this.invokeListenersUpdate({
|
|
419
|
+
callbackName:
|
|
420
|
+
SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillDismiss,
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
onVideoFullscreenPlayerDidDismiss = () => {
|
|
425
|
+
this.invokeListenersUpdate({
|
|
426
|
+
callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidDismiss,
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
onVideoFullscreenPlayerWillPresent = () => {
|
|
431
|
+
this.invokeListenersUpdate({
|
|
432
|
+
callbackName:
|
|
433
|
+
SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillPresent,
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
onVideoFullscreenPlayerDidPresent = () => {
|
|
438
|
+
this.invokeListenersUpdate({
|
|
439
|
+
callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidPresent,
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
|
|
417
443
|
public invokeListenersUpdate = ({
|
|
418
444
|
callbackName,
|
|
419
445
|
event = {},
|
|
@@ -634,6 +660,12 @@ export class Player {
|
|
|
634
660
|
onBufferStart: this.onBufferStart,
|
|
635
661
|
onBufferComplete: this.onBufferComplete,
|
|
636
662
|
|
|
663
|
+
onPlayerClose: this.onPlayerClose,
|
|
664
|
+
onVideoFullscreenPlayerWillPresent: this.onVideoFullscreenPlayerWillPresent,
|
|
665
|
+
onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
|
|
666
|
+
onVideoFullscreenPlayerWillDismiss: this.onVideoFullscreenPlayerWillDismiss,
|
|
667
|
+
onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
|
|
668
|
+
|
|
637
669
|
// Ads Callbacks:
|
|
638
670
|
onAdBegin: this.onAdBegin,
|
|
639
671
|
onAdBreakBegin: this.onAdBreakBegin,
|
|
@@ -693,4 +725,7 @@ export class Player {
|
|
|
693
725
|
isFullScreenSupported(): boolean {
|
|
694
726
|
return true;
|
|
695
727
|
}
|
|
728
|
+
|
|
729
|
+
public supportsNativeControls = (): boolean => false;
|
|
730
|
+
public supportNativeCast = (): boolean => false;
|
|
696
731
|
}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
2
2
|
import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
3
3
|
import { Player } from "./player";
|
|
4
|
+
import { PlayerRole } from "./conts";
|
|
4
5
|
|
|
5
6
|
type PlayerFactoryItem = {
|
|
6
7
|
Component: any;
|
|
7
8
|
controller: Player;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
type PlayerFactoryProps = {
|
|
12
|
+
player: any;
|
|
13
|
+
playerId: string;
|
|
14
|
+
autoplay: boolean;
|
|
15
|
+
entry: ZappEntry;
|
|
16
|
+
muted: boolean;
|
|
17
|
+
playerPluginId: string;
|
|
18
|
+
screenConfig: Record<string, any>;
|
|
19
|
+
playerRole: PlayerRole;
|
|
20
|
+
};
|
|
21
|
+
|
|
10
22
|
interface PlayerConstructor {
|
|
11
23
|
new (params: any): Player;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
|
-
export const playerFactory = (
|
|
26
|
+
export const playerFactory = (
|
|
27
|
+
config: PlayerFactoryProps
|
|
28
|
+
): PlayerFactoryItem | null => {
|
|
15
29
|
const IDENTIFIER = config?.playerPluginId;
|
|
16
30
|
|
|
17
31
|
if (!IDENTIFIER) {
|
|
@@ -5,6 +5,7 @@ import { Player } from "./player";
|
|
|
5
5
|
import { findNodeHandle, NativeModules } from "react-native";
|
|
6
6
|
import { isApplePlatform } from "../../reactUtils";
|
|
7
7
|
import { PlayerRole } from "./conts";
|
|
8
|
+
import { toBooleanWithDefaultFalse } from "../../booleanUtils";
|
|
8
9
|
|
|
9
10
|
const RNPlayerManager = {
|
|
10
11
|
QuickBrickPlayerPlugin: isApplePlatform()
|
|
@@ -291,4 +292,12 @@ export class PlayerNative extends Player {
|
|
|
291
292
|
|
|
292
293
|
return !(isFullScreenAudioPlayer && this.isAudioItem());
|
|
293
294
|
};
|
|
295
|
+
|
|
296
|
+
supportsNativeControls = (): boolean =>
|
|
297
|
+
toBooleanWithDefaultFalse(this.getConfig()?.["supports_native_controls"]);
|
|
298
|
+
|
|
299
|
+
supportNativeCast = (): boolean =>
|
|
300
|
+
toBooleanWithDefaultFalse(
|
|
301
|
+
this.playerPluginId === "quick-brick-player-brightcove"
|
|
302
|
+
);
|
|
294
303
|
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
castAndFallbackColor,
|
|
15
15
|
compact,
|
|
16
16
|
getValue,
|
|
17
|
+
getColorFromData,
|
|
17
18
|
} from "../";
|
|
18
19
|
|
|
19
20
|
import {
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
EMPTY,
|
|
24
25
|
FALLBACK,
|
|
25
26
|
TRANSFORM,
|
|
27
|
+
defaultColor,
|
|
26
28
|
} from "./fixtures";
|
|
27
29
|
|
|
28
30
|
describe("getKeyForLabel", () => {
|
|
@@ -388,3 +390,60 @@ describe("getValue", () => {
|
|
|
388
390
|
expect(getValue({ value })(value)).toBeNull();
|
|
389
391
|
});
|
|
390
392
|
});
|
|
393
|
+
|
|
394
|
+
describe("getColorFromData", () => {
|
|
395
|
+
it("should return value directly if valid color", () => {
|
|
396
|
+
const result = getColorFromData({
|
|
397
|
+
data: entry,
|
|
398
|
+
key: "background_color",
|
|
399
|
+
getValue: getValue(componentStyle),
|
|
400
|
+
defaultColor,
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
expect(result).toBe("#123456");
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it("should return valid rgba color name", () => {
|
|
407
|
+
const result = getColorFromData({
|
|
408
|
+
data: entry,
|
|
409
|
+
key: "component_background_color",
|
|
410
|
+
getValue: getValue(componentStyle),
|
|
411
|
+
defaultColor,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
expect(result).toBe("rgba(255, 255, 255, 0)");
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("should return path value if path value is set and is valid color", () => {
|
|
418
|
+
const result = getColorFromData({
|
|
419
|
+
data: entry,
|
|
420
|
+
key: VAL.colorKeyPath,
|
|
421
|
+
getValue: getValue(componentStyle),
|
|
422
|
+
defaultColor,
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
expect(result).toBe("#123456");
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it("should return defaultColor if key value and path value are invalid", () => {
|
|
429
|
+
const result = getColorFromData({
|
|
430
|
+
data: entry,
|
|
431
|
+
key: VAL.invalidColorKey,
|
|
432
|
+
getValue: getValue(componentStyle),
|
|
433
|
+
defaultColor,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
expect(result).toBe(defaultColor);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("should return defaultColor if path does not exist", () => {
|
|
440
|
+
const result = getColorFromData({
|
|
441
|
+
data: entry,
|
|
442
|
+
key: VAL.invalidColorKeyPath,
|
|
443
|
+
getValue: getValue(componentStyle),
|
|
444
|
+
defaultColor,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
expect(result).toBe(defaultColor);
|
|
448
|
+
});
|
|
449
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
2
|
|
|
3
|
+
export const defaultColor = "#ffffff";
|
|
4
|
+
|
|
3
5
|
export const entry = {
|
|
4
6
|
type: {
|
|
5
7
|
value: "video",
|
|
@@ -26,7 +28,9 @@ export const entry = {
|
|
|
26
28
|
type: "video/mp4",
|
|
27
29
|
src: "https://wino-feed.s3.amazonaws.com/movieFeed/Ford+v+Ferrari.mp4",
|
|
28
30
|
},
|
|
31
|
+
background_color: "#123456",
|
|
29
32
|
extensions: {
|
|
33
|
+
background_color: "#123456",
|
|
30
34
|
free: false,
|
|
31
35
|
duration: 9000,
|
|
32
36
|
section: "New Releases",
|
|
@@ -46,7 +50,11 @@ export const componentStyle = {
|
|
|
46
50
|
horizontal_list_cell_width: "400",
|
|
47
51
|
cell_plugin_configuration_id: "267bd05a-08bd-4675-bdd3-9b73899773f0",
|
|
48
52
|
horizontal_list_scaled_switch: false,
|
|
53
|
+
background_color: "#123456",
|
|
49
54
|
component_background_color: "rgba(255, 255, 255, 0)",
|
|
55
|
+
background_color_1: "extensions.background_color",
|
|
56
|
+
background_color_2: "invalidColorKey",
|
|
57
|
+
background_color_3: "extensions.invalidColorKeyPath",
|
|
50
58
|
component_padding_left: "",
|
|
51
59
|
horizontal_list_next_offset: 20,
|
|
52
60
|
component_margin_bottom: "",
|
|
@@ -93,6 +101,11 @@ export const VAL = {
|
|
|
93
101
|
upper: "STRING",
|
|
94
102
|
width: 400,
|
|
95
103
|
height: 225,
|
|
104
|
+
colorKey: "background_color",
|
|
105
|
+
colorKeyRgba: "component_background_color",
|
|
106
|
+
colorKeyPath: "background_color_1",
|
|
107
|
+
invalidColorKey: "background_color_2",
|
|
108
|
+
invalidColorKeyPath: "background_color_3",
|
|
96
109
|
};
|
|
97
110
|
|
|
98
111
|
export const TRANSFORM = {
|
package/cellUtils/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
|
+
import validateColor from "validate-color";
|
|
3
4
|
|
|
4
5
|
import { toNumberWithDefault, toNumberWithDefaultZero } from "../numberUtils";
|
|
5
6
|
import { transformColorCode as fixColorHexCode } from "../transform";
|
|
@@ -181,8 +182,8 @@ export const getHeight = (width, aspectRatio) => {
|
|
|
181
182
|
* @returns {string} duration
|
|
182
183
|
*/
|
|
183
184
|
|
|
184
|
-
export const getDurationInMinutes = (seconds
|
|
185
|
-
if (seconds
|
|
185
|
+
export const getDurationInMinutes = (seconds?: number): string => {
|
|
186
|
+
if (!seconds) return "00:00";
|
|
186
187
|
const minutes = Math.floor(Number(seconds) / 60);
|
|
187
188
|
const secondsReminder = Math.floor(Number(seconds)) % 60;
|
|
188
189
|
const pad = (num: number): string => `${num < 10 ? "0" : ""}${num}`;
|
|
@@ -343,6 +344,19 @@ export const ifElseFocused = R.curry(
|
|
|
343
344
|
state === "focused" ? focusedValue : defaultValue
|
|
344
345
|
);
|
|
345
346
|
|
|
347
|
+
export const ifElseSelected = R.curry(
|
|
348
|
+
(state: string, selectedValue, defaultValue) => {
|
|
349
|
+
switch (state) {
|
|
350
|
+
case "selected":
|
|
351
|
+
return selectedValue;
|
|
352
|
+
case "focused_selected":
|
|
353
|
+
return selectedValue;
|
|
354
|
+
default:
|
|
355
|
+
return defaultValue;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
|
|
346
360
|
/**
|
|
347
361
|
* Map textAlign values to their corresponding alignSelf values
|
|
348
362
|
* This is so that we could use the same field for both properties
|
|
@@ -430,3 +444,33 @@ export const toResizeMode = (
|
|
|
430
444
|
resizeMode: "contain",
|
|
431
445
|
};
|
|
432
446
|
};
|
|
447
|
+
|
|
448
|
+
type GetColorFromData = {
|
|
449
|
+
data: Record<string, any>;
|
|
450
|
+
key: string;
|
|
451
|
+
getValue: Function;
|
|
452
|
+
defaultColor: string;
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
export const getColorFromData = ({
|
|
456
|
+
data,
|
|
457
|
+
key,
|
|
458
|
+
getValue,
|
|
459
|
+
defaultColor,
|
|
460
|
+
}: GetColorFromData): string => {
|
|
461
|
+
const value = getValue(key);
|
|
462
|
+
|
|
463
|
+
// Temporary hack to fix color validation when alpha is floating point number
|
|
464
|
+
// https://github.com/dreamyguy/validate-color/issues/44
|
|
465
|
+
if (validateColor(value.replace(".00", ""))) {
|
|
466
|
+
return value;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const pathValue = R.path(value.split("."), data);
|
|
470
|
+
|
|
471
|
+
if (pathValue && validateColor(pathValue)) {
|
|
472
|
+
return pathValue;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return defaultColor;
|
|
476
|
+
};
|
package/focusManager/index.ts
CHANGED
|
@@ -86,7 +86,7 @@ export const isFocusable = (component: ZappEntry | ZappUIComponent | any) =>
|
|
|
86
86
|
|
|
87
87
|
type Props = {
|
|
88
88
|
component: ZappUIComponent;
|
|
89
|
-
zappPipesData
|
|
89
|
+
zappPipesData?: ZappPipesData;
|
|
90
90
|
} & Record<string, any>;
|
|
91
91
|
|
|
92
92
|
export const useIsFocusable = (props: Props): void => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`subscriber can be invoked without args 1`] = `
|
|
3
|
+
exports[`functionUtils subscriber can be invoked without args 1`] = `
|
|
4
4
|
Object {
|
|
5
5
|
"handlers": Object {},
|
|
6
6
|
"invokeHandler": [Function],
|
|
@@ -9,7 +9,7 @@ Object {
|
|
|
9
9
|
}
|
|
10
10
|
`;
|
|
11
11
|
|
|
12
|
-
exports[`subscriber returns the original object with additional methods 1`] = `
|
|
12
|
+
exports[`functionUtils subscriber returns the original object with additional methods 1`] = `
|
|
13
13
|
Object {
|
|
14
14
|
"foo": "bar",
|
|
15
15
|
"handlers": Object {},
|