@applicaster/zapp-react-native-utils 13.0.0-alpha.2510266138 → 13.0.0-alpha.2535725541
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 +32 -0
- package/actionsExecutor/consts.ts +4 -0
- package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
- package/appUtils/__tests__/allZappLocales.ts +79 -0
- package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -0
- package/appUtils/focusManager/index.ios.ts +14 -4
- package/appUtils/focusManager/index.ts +13 -0
- package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
- package/appUtils/focusManager/utils/index.ts +5 -0
- package/appUtils/localizationsHelper.ts +31 -0
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
- package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
- package/componentsUtils/__tests__/isGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
- package/componentsUtils/index.ts +32 -0
- package/dateUtils/index.ts +17 -0
- package/focusManager/FocusManager.ts +3 -1
- package/focusManager/index.ts +4 -30
- package/functionUtils/index.ts +25 -0
- package/index.d.ts +0 -12
- package/localizationUtils/index.ts +5 -10
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +6 -0
- package/manifestUtils/keys.js +27 -2
- package/modalState/__tests__/index.test.ts +51 -0
- package/modalState/index.ts +32 -2
- package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
- package/navigationUtils/index.ts +3 -1
- package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
- package/numberUtils/index.ts +4 -0
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +6 -0
- package/reactHooks/advertising/index.ts +5 -5
- package/reactHooks/feed/useFeedLoader.tsx +13 -6
- package/reactHooks/navigation/useRoute.ts +2 -2
- package/reactHooks/useListenEventBusEvent.ts +1 -1
- package/zappFrameworkUtils/localStorageHelper.ts +6 -0
- package/zappFrameworkUtils/types.ts +11 -0
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
useContentTypes,
|
|
27
27
|
usePickFromState,
|
|
28
28
|
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
29
|
+
import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
|
|
30
|
+
import { postEvent } from "../reactHooks/useSubscriberFor";
|
|
29
31
|
|
|
30
32
|
export const { log_error, log_info, log_debug } = createLogger({
|
|
31
33
|
subsystem: "ActionExecutorContext",
|
|
@@ -74,6 +76,19 @@ function findParentComponent(
|
|
|
74
76
|
return null;
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
// send all data just in case (like for message string formatting)
|
|
80
|
+
// Type is not exported for now
|
|
81
|
+
type MaxTagsReachedEvent = {
|
|
82
|
+
selectedItems: string[];
|
|
83
|
+
maxItems: number;
|
|
84
|
+
tag: string;
|
|
85
|
+
keyNamespace: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
async function onMaxTagsReached(data: MaxTagsReachedEvent) {
|
|
89
|
+
postEvent(TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT, [data]);
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
const prepareDefaultActions = (actionExecutor) => {
|
|
78
93
|
actionExecutor.registerAction("localStorageSet", async (action) => {
|
|
79
94
|
const namespaces = action.options.content;
|
|
@@ -234,6 +249,23 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
234
249
|
if (selectedItems.includes(tag)) {
|
|
235
250
|
await multiSelectProvider.removeItem(tag);
|
|
236
251
|
} else {
|
|
252
|
+
const maxItems = action.options?.max_items;
|
|
253
|
+
|
|
254
|
+
if (maxItems && selectedItems.length >= maxItems) {
|
|
255
|
+
log_info(
|
|
256
|
+
`handleAction: localStorageToggleFlag event reached max items limit: ${maxItems}, cannot add tag: ${tag}`
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
await onMaxTagsReached({
|
|
260
|
+
selectedItems,
|
|
261
|
+
maxItems,
|
|
262
|
+
tag,
|
|
263
|
+
keyNamespace,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return ActionResult.Cancel;
|
|
267
|
+
}
|
|
268
|
+
|
|
237
269
|
await multiSelectProvider.addItem(tag);
|
|
238
270
|
}
|
|
239
271
|
} else {
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`toDayJSLocaleMap [af] returns a valid dayjs locale 1`] = `"af"`;
|
|
4
|
+
|
|
5
|
+
exports[`toDayJSLocaleMap [ar] returns a valid dayjs locale 1`] = `"ar"`;
|
|
6
|
+
|
|
7
|
+
exports[`toDayJSLocaleMap [bg] returns a valid dayjs locale 1`] = `"bg"`;
|
|
8
|
+
|
|
9
|
+
exports[`toDayJSLocaleMap [bn] returns a valid dayjs locale 1`] = `"bn"`;
|
|
10
|
+
|
|
11
|
+
exports[`toDayJSLocaleMap [bo] returns a valid dayjs locale 1`] = `"bo"`;
|
|
12
|
+
|
|
13
|
+
exports[`toDayJSLocaleMap [ca] returns a valid dayjs locale 1`] = `"ca"`;
|
|
14
|
+
|
|
15
|
+
exports[`toDayJSLocaleMap [cs] returns a valid dayjs locale 1`] = `"cs"`;
|
|
16
|
+
|
|
17
|
+
exports[`toDayJSLocaleMap [da] returns a valid dayjs locale 1`] = `"da"`;
|
|
18
|
+
|
|
19
|
+
exports[`toDayJSLocaleMap [de] returns a valid dayjs locale 1`] = `"de"`;
|
|
20
|
+
|
|
21
|
+
exports[`toDayJSLocaleMap [el] returns a valid dayjs locale 1`] = `"el"`;
|
|
22
|
+
|
|
23
|
+
exports[`toDayJSLocaleMap [en] returns a valid dayjs locale 1`] = `"en"`;
|
|
24
|
+
|
|
25
|
+
exports[`toDayJSLocaleMap [en-GB] returns a valid dayjs locale 1`] = `"en-gb"`;
|
|
26
|
+
|
|
27
|
+
exports[`toDayJSLocaleMap [en-UK] returns a valid dayjs locale 1`] = `"en-gb"`;
|
|
28
|
+
|
|
29
|
+
exports[`toDayJSLocaleMap [es] returns a valid dayjs locale 1`] = `"es"`;
|
|
30
|
+
|
|
31
|
+
exports[`toDayJSLocaleMap [es-LA] returns a valid dayjs locale 1`] = `"es"`;
|
|
32
|
+
|
|
33
|
+
exports[`toDayJSLocaleMap [es-MX] returns a valid dayjs locale 1`] = `"es-mx"`;
|
|
34
|
+
|
|
35
|
+
exports[`toDayJSLocaleMap [es-US] returns a valid dayjs locale 1`] = `"es-us"`;
|
|
36
|
+
|
|
37
|
+
exports[`toDayJSLocaleMap [et] returns a valid dayjs locale 1`] = `"et"`;
|
|
38
|
+
|
|
39
|
+
exports[`toDayJSLocaleMap [eu] returns a valid dayjs locale 1`] = `"eu"`;
|
|
40
|
+
|
|
41
|
+
exports[`toDayJSLocaleMap [fa] returns a valid dayjs locale 1`] = `"fa"`;
|
|
42
|
+
|
|
43
|
+
exports[`toDayJSLocaleMap [fi] returns a valid dayjs locale 1`] = `"fi"`;
|
|
44
|
+
|
|
45
|
+
exports[`toDayJSLocaleMap [fj] returns a valid dayjs locale 1`] = `"en"`;
|
|
46
|
+
|
|
47
|
+
exports[`toDayJSLocaleMap [fr] returns a valid dayjs locale 1`] = `"fr"`;
|
|
48
|
+
|
|
49
|
+
exports[`toDayJSLocaleMap [ga] returns a valid dayjs locale 1`] = `"ga"`;
|
|
50
|
+
|
|
51
|
+
exports[`toDayJSLocaleMap [gu] returns a valid dayjs locale 1`] = `"gu"`;
|
|
52
|
+
|
|
53
|
+
exports[`toDayJSLocaleMap [he] returns a valid dayjs locale 1`] = `"he"`;
|
|
54
|
+
|
|
55
|
+
exports[`toDayJSLocaleMap [hi] returns a valid dayjs locale 1`] = `"hi"`;
|
|
56
|
+
|
|
57
|
+
exports[`toDayJSLocaleMap [hr] returns a valid dayjs locale 1`] = `"hr"`;
|
|
58
|
+
|
|
59
|
+
exports[`toDayJSLocaleMap [hu] returns a valid dayjs locale 1`] = `"hu"`;
|
|
60
|
+
|
|
61
|
+
exports[`toDayJSLocaleMap [hy] returns a valid dayjs locale 1`] = `"hy-am"`;
|
|
62
|
+
|
|
63
|
+
exports[`toDayJSLocaleMap [id] returns a valid dayjs locale 1`] = `"id"`;
|
|
64
|
+
|
|
65
|
+
exports[`toDayJSLocaleMap [is] returns a valid dayjs locale 1`] = `"is"`;
|
|
66
|
+
|
|
67
|
+
exports[`toDayJSLocaleMap [it] returns a valid dayjs locale 1`] = `"it"`;
|
|
68
|
+
|
|
69
|
+
exports[`toDayJSLocaleMap [ja] returns a valid dayjs locale 1`] = `"ja"`;
|
|
70
|
+
|
|
71
|
+
exports[`toDayJSLocaleMap [ka] returns a valid dayjs locale 1`] = `"ka"`;
|
|
72
|
+
|
|
73
|
+
exports[`toDayJSLocaleMap [km] returns a valid dayjs locale 1`] = `"km"`;
|
|
74
|
+
|
|
75
|
+
exports[`toDayJSLocaleMap [ko] returns a valid dayjs locale 1`] = `"ko"`;
|
|
76
|
+
|
|
77
|
+
exports[`toDayJSLocaleMap [la] returns a valid dayjs locale 1`] = `"en"`;
|
|
78
|
+
|
|
79
|
+
exports[`toDayJSLocaleMap [lt] returns a valid dayjs locale 1`] = `"lt"`;
|
|
80
|
+
|
|
81
|
+
exports[`toDayJSLocaleMap [lv] returns a valid dayjs locale 1`] = `"lv"`;
|
|
82
|
+
|
|
83
|
+
exports[`toDayJSLocaleMap [mi] returns a valid dayjs locale 1`] = `"mi"`;
|
|
84
|
+
|
|
85
|
+
exports[`toDayJSLocaleMap [mk] returns a valid dayjs locale 1`] = `"mk"`;
|
|
86
|
+
|
|
87
|
+
exports[`toDayJSLocaleMap [ml] returns a valid dayjs locale 1`] = `"ml"`;
|
|
88
|
+
|
|
89
|
+
exports[`toDayJSLocaleMap [mn] returns a valid dayjs locale 1`] = `"mn"`;
|
|
90
|
+
|
|
91
|
+
exports[`toDayJSLocaleMap [mr] returns a valid dayjs locale 1`] = `"mr"`;
|
|
92
|
+
|
|
93
|
+
exports[`toDayJSLocaleMap [ms] returns a valid dayjs locale 1`] = `"ms"`;
|
|
94
|
+
|
|
95
|
+
exports[`toDayJSLocaleMap [mt] returns a valid dayjs locale 1`] = `"mt"`;
|
|
96
|
+
|
|
97
|
+
exports[`toDayJSLocaleMap [ne] returns a valid dayjs locale 1`] = `"ne"`;
|
|
98
|
+
|
|
99
|
+
exports[`toDayJSLocaleMap [nl] returns a valid dayjs locale 1`] = `"nl"`;
|
|
100
|
+
|
|
101
|
+
exports[`toDayJSLocaleMap [no] returns a valid dayjs locale 1`] = `"en"`;
|
|
102
|
+
|
|
103
|
+
exports[`toDayJSLocaleMap [pa] returns a valid dayjs locale 1`] = `"pa-in"`;
|
|
104
|
+
|
|
105
|
+
exports[`toDayJSLocaleMap [pl] returns a valid dayjs locale 1`] = `"pl"`;
|
|
106
|
+
|
|
107
|
+
exports[`toDayJSLocaleMap [pt] returns a valid dayjs locale 1`] = `"pt"`;
|
|
108
|
+
|
|
109
|
+
exports[`toDayJSLocaleMap [pt-BR] returns a valid dayjs locale 1`] = `"pt-br"`;
|
|
110
|
+
|
|
111
|
+
exports[`toDayJSLocaleMap [qu] returns a valid dayjs locale 1`] = `"en"`;
|
|
112
|
+
|
|
113
|
+
exports[`toDayJSLocaleMap [ro] returns a valid dayjs locale 1`] = `"ro"`;
|
|
114
|
+
|
|
115
|
+
exports[`toDayJSLocaleMap [ru] returns a valid dayjs locale 1`] = `"ru"`;
|
|
116
|
+
|
|
117
|
+
exports[`toDayJSLocaleMap [sk] returns a valid dayjs locale 1`] = `"sk"`;
|
|
118
|
+
|
|
119
|
+
exports[`toDayJSLocaleMap [sl] returns a valid dayjs locale 1`] = `"sl"`;
|
|
120
|
+
|
|
121
|
+
exports[`toDayJSLocaleMap [sm] returns a valid dayjs locale 1`] = `"en"`;
|
|
122
|
+
|
|
123
|
+
exports[`toDayJSLocaleMap [sq] returns a valid dayjs locale 1`] = `"sq"`;
|
|
124
|
+
|
|
125
|
+
exports[`toDayJSLocaleMap [sr] returns a valid dayjs locale 1`] = `"sr"`;
|
|
126
|
+
|
|
127
|
+
exports[`toDayJSLocaleMap [sv] returns a valid dayjs locale 1`] = `"sv"`;
|
|
128
|
+
|
|
129
|
+
exports[`toDayJSLocaleMap [sw] returns a valid dayjs locale 1`] = `"sw"`;
|
|
130
|
+
|
|
131
|
+
exports[`toDayJSLocaleMap [ta] returns a valid dayjs locale 1`] = `"ta"`;
|
|
132
|
+
|
|
133
|
+
exports[`toDayJSLocaleMap [te] returns a valid dayjs locale 1`] = `"te"`;
|
|
134
|
+
|
|
135
|
+
exports[`toDayJSLocaleMap [th] returns a valid dayjs locale 1`] = `"th"`;
|
|
136
|
+
|
|
137
|
+
exports[`toDayJSLocaleMap [to] returns a valid dayjs locale 1`] = `"en"`;
|
|
138
|
+
|
|
139
|
+
exports[`toDayJSLocaleMap [tr] returns a valid dayjs locale 1`] = `"tr"`;
|
|
140
|
+
|
|
141
|
+
exports[`toDayJSLocaleMap [tt] returns a valid dayjs locale 1`] = `"en"`;
|
|
142
|
+
|
|
143
|
+
exports[`toDayJSLocaleMap [uk] returns a valid dayjs locale 1`] = `"uk"`;
|
|
144
|
+
|
|
145
|
+
exports[`toDayJSLocaleMap [ur] returns a valid dayjs locale 1`] = `"ur"`;
|
|
146
|
+
|
|
147
|
+
exports[`toDayJSLocaleMap [uz] returns a valid dayjs locale 1`] = `"uz"`;
|
|
148
|
+
|
|
149
|
+
exports[`toDayJSLocaleMap [vi] returns a valid dayjs locale 1`] = `"vi"`;
|
|
150
|
+
|
|
151
|
+
exports[`toDayJSLocaleMap [zh] returns a valid dayjs locale 1`] = `"zh"`;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
// common locales from https://rubygems.org/gems/language_list
|
|
3
|
+
"en",
|
|
4
|
+
"fr",
|
|
5
|
+
"de",
|
|
6
|
+
"nl",
|
|
7
|
+
"ru",
|
|
8
|
+
"es",
|
|
9
|
+
"he",
|
|
10
|
+
"hy",
|
|
11
|
+
"sq",
|
|
12
|
+
"af",
|
|
13
|
+
"ar",
|
|
14
|
+
"eu",
|
|
15
|
+
"bn",
|
|
16
|
+
"bg",
|
|
17
|
+
"zh",
|
|
18
|
+
"cs",
|
|
19
|
+
"km",
|
|
20
|
+
"ca",
|
|
21
|
+
"hr",
|
|
22
|
+
"da",
|
|
23
|
+
"et",
|
|
24
|
+
"fj",
|
|
25
|
+
"fi",
|
|
26
|
+
"gu",
|
|
27
|
+
"ka",
|
|
28
|
+
"hu",
|
|
29
|
+
"hi",
|
|
30
|
+
"it",
|
|
31
|
+
"is",
|
|
32
|
+
"id",
|
|
33
|
+
"ga",
|
|
34
|
+
"ja",
|
|
35
|
+
"ko",
|
|
36
|
+
"la",
|
|
37
|
+
"lv",
|
|
38
|
+
"lt",
|
|
39
|
+
"ms",
|
|
40
|
+
"mi",
|
|
41
|
+
"mn",
|
|
42
|
+
"mt",
|
|
43
|
+
"mk",
|
|
44
|
+
"el",
|
|
45
|
+
"mr",
|
|
46
|
+
"ml",
|
|
47
|
+
"ne",
|
|
48
|
+
"no",
|
|
49
|
+
"pa",
|
|
50
|
+
"pl",
|
|
51
|
+
"pt",
|
|
52
|
+
"fa",
|
|
53
|
+
"qu",
|
|
54
|
+
"ro",
|
|
55
|
+
"sk",
|
|
56
|
+
"sm",
|
|
57
|
+
"sr",
|
|
58
|
+
"sw",
|
|
59
|
+
"sv",
|
|
60
|
+
"sl",
|
|
61
|
+
"to",
|
|
62
|
+
"tr",
|
|
63
|
+
"th",
|
|
64
|
+
"te",
|
|
65
|
+
"bo",
|
|
66
|
+
"tt",
|
|
67
|
+
"ta",
|
|
68
|
+
"uk",
|
|
69
|
+
"ur",
|
|
70
|
+
"uz",
|
|
71
|
+
"vi",
|
|
72
|
+
// Extra locales https://github.com/applicaster/zapp/blob/5604794f15cfd270ae494b0db85e542de4cebfaa/config/additional_languages.yml
|
|
73
|
+
"en-UK",
|
|
74
|
+
"en-GB",
|
|
75
|
+
"es-LA",
|
|
76
|
+
"pt-BR",
|
|
77
|
+
"es-MX",
|
|
78
|
+
"es-US",
|
|
79
|
+
];
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
getLocale,
|
|
9
9
|
getLanguageCode,
|
|
10
10
|
getCountryCode,
|
|
11
|
+
toDayJSLocaleMap,
|
|
11
12
|
} = require("../localizationsHelper");
|
|
12
13
|
|
|
13
14
|
describe("getLocale", () => {
|
|
@@ -69,3 +70,13 @@ describe("getCountryCode", () => {
|
|
|
69
70
|
expect(currentValue).toEqual(expectedValue);
|
|
70
71
|
});
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
describe("toDayJSLocaleMap", () => {
|
|
75
|
+
const allZappLocales: string[] = require("./allZappLocales").default;
|
|
76
|
+
|
|
77
|
+
it.each(allZappLocales)("[%s] returns a valid dayjs locale", (locale) => {
|
|
78
|
+
const dayJSLocale = toDayJSLocaleMap(locale);
|
|
79
|
+
expect(dayJSLocale).toBeDefined();
|
|
80
|
+
expect(dayJSLocale).toMatchSnapshot();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -5,6 +5,7 @@ exports[`focusManager should be defined 1`] = `
|
|
|
5
5
|
"blur": [Function],
|
|
6
6
|
"disableFocus": [Function],
|
|
7
7
|
"enableFocus": [Function],
|
|
8
|
+
"findPreferredFocusChild": [Function],
|
|
8
9
|
"focusableTree": Tree {
|
|
9
10
|
"loadingCounter": 0,
|
|
10
11
|
"root": {
|
|
@@ -60,6 +61,7 @@ exports[`focusManagerIOS should be defined 1`] = `
|
|
|
60
61
|
"getCurrentGroup": [Function],
|
|
61
62
|
"getGroupById": [Function],
|
|
62
63
|
"getGroupRootById": [Function],
|
|
64
|
+
"getPreferredFocusChild": [Function],
|
|
63
65
|
"invokeHandler": [Function],
|
|
64
66
|
"isGroupItemFocused": [Function],
|
|
65
67
|
"moveFocus": [Function],
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { NativeModules } from "react-native";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
|
|
3
4
|
import { Tree } from "./treeDataStructure/Tree";
|
|
4
5
|
import { findFocusableNode } from "./treeDataStructure/Utils";
|
|
5
6
|
import { subscriber } from "../../functionUtils";
|
|
7
|
+
import { findChild } from "./utils";
|
|
6
8
|
|
|
7
9
|
const { FocusableManagerModule } = NativeModules;
|
|
8
10
|
|
|
@@ -52,10 +54,7 @@ export const focusManager = (function () {
|
|
|
52
54
|
const node = focusableTree.findInTree(groupId);
|
|
53
55
|
|
|
54
56
|
if (node?.children?.length > 0) {
|
|
55
|
-
const preferredFocus =
|
|
56
|
-
R.find(R.pathEq(["component", "props", "preferredFocus"], true)),
|
|
57
|
-
R.prop("children")
|
|
58
|
-
)(node);
|
|
57
|
+
const preferredFocus = findChild(true, node);
|
|
59
58
|
|
|
60
59
|
if (preferredFocus?.component?.isGroup) {
|
|
61
60
|
return getPreferredFocusInGroup({ groupId: preferredFocus?.id });
|
|
@@ -382,6 +381,16 @@ export const focusManager = (function () {
|
|
|
382
381
|
forceFocusOnItem({ focusableItem, callback });
|
|
383
382
|
}
|
|
384
383
|
|
|
384
|
+
function getPreferredFocusChild(id) {
|
|
385
|
+
const node = focusableTree.findInTree(id);
|
|
386
|
+
|
|
387
|
+
if (node?.children?.length > 0) {
|
|
388
|
+
return findChild(true, node) || findChild(false, node);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return node;
|
|
392
|
+
}
|
|
393
|
+
|
|
385
394
|
return {
|
|
386
395
|
on,
|
|
387
396
|
invokeHandler,
|
|
@@ -402,5 +411,6 @@ export const focusManager = (function () {
|
|
|
402
411
|
getCurrentGroup,
|
|
403
412
|
getGroupRootById,
|
|
404
413
|
isGroupItemFocused,
|
|
414
|
+
getPreferredFocusChild,
|
|
405
415
|
};
|
|
406
416
|
})();
|
|
@@ -534,6 +534,18 @@ export const focusManager = (function () {
|
|
|
534
534
|
|
|
535
535
|
const { on, invokeHandler, removeHandler } = eventHandler;
|
|
536
536
|
|
|
537
|
+
function findPreferredFocusChild(id) {
|
|
538
|
+
const node = getCurrentFocusNode(id);
|
|
539
|
+
|
|
540
|
+
const preferredFocus = findPriorityItem([node]);
|
|
541
|
+
|
|
542
|
+
if (isNilOrEmpty(preferredFocus)) {
|
|
543
|
+
return undefined;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return preferredFocus[0];
|
|
547
|
+
}
|
|
548
|
+
|
|
537
549
|
/**
|
|
538
550
|
* this is the list of the functions available externally
|
|
539
551
|
* when importing the focus manager
|
|
@@ -563,5 +575,6 @@ export const focusManager = (function () {
|
|
|
563
575
|
isGroupItemFocused,
|
|
564
576
|
recoverFocus,
|
|
565
577
|
isCurrentFocusOnTheTopScreen,
|
|
578
|
+
findPreferredFocusChild,
|
|
566
579
|
};
|
|
567
580
|
})();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { findChild } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("findChild", () => {
|
|
4
|
+
const makeNode = (children = []) => ({ children });
|
|
5
|
+
|
|
6
|
+
const child = (preferredFocus: boolean) => ({
|
|
7
|
+
component: { props: { preferredFocus } },
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns the child with preferredFocus=true", () => {
|
|
11
|
+
const node = makeNode([child(false), child(true), child(false)]);
|
|
12
|
+
expect(findChild(true, node)).toBe(node.children[1]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("returns the child with preferredFocus=false", () => {
|
|
16
|
+
const node = makeNode([child(false), child(true), child(false)]);
|
|
17
|
+
expect(findChild(false, node)).toBe(node.children[0]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns undefined if no child matches preferredFocus", () => {
|
|
21
|
+
const node = makeNode([child(false), child(false)]);
|
|
22
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns undefined if node has no children", () => {
|
|
26
|
+
const node = makeNode();
|
|
27
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
28
|
+
expect(findChild(false, node)).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns undefined if children is not an array", () => {
|
|
32
|
+
const node = { children: null };
|
|
33
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -98,3 +98,8 @@ export const waitForContent = (focusableTree) => {
|
|
|
98
98
|
conditionFn: contentHasAnyChildren,
|
|
99
99
|
});
|
|
100
100
|
};
|
|
101
|
+
|
|
102
|
+
export const findChild = (preferredFocus: boolean, node) =>
|
|
103
|
+
(node?.children || []).find(
|
|
104
|
+
(child) => child?.component?.props?.preferredFocus === preferredFocus
|
|
105
|
+
);
|
|
@@ -65,6 +65,37 @@ export function getUILanguage() {
|
|
|
65
65
|
return getLanguageCode();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* fallback to en for missing dayjslocalization
|
|
70
|
+
* converts the locale code to a dayjs compatible locale code
|
|
71
|
+
* lowercase input code is expected, e.g. "en-GB" => "en-gb"
|
|
72
|
+
* @param {string} code - locale code, e.g. "en", "fr", "es-LA"
|
|
73
|
+
* */
|
|
74
|
+
export const toDayJSLocaleMap = (code) => {
|
|
75
|
+
const map = {
|
|
76
|
+
hy: "hy-am",
|
|
77
|
+
fj: null,
|
|
78
|
+
la: null,
|
|
79
|
+
no: null,
|
|
80
|
+
pa: "pa-in",
|
|
81
|
+
qu: null,
|
|
82
|
+
sm: null,
|
|
83
|
+
to: null,
|
|
84
|
+
xh: null,
|
|
85
|
+
tt: null,
|
|
86
|
+
"es-LA": "es",
|
|
87
|
+
"en-UK": "en-gb",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (map[code] === null) {
|
|
91
|
+
return "en";
|
|
92
|
+
} else if (map[code]) {
|
|
93
|
+
return map[code];
|
|
94
|
+
} else {
|
|
95
|
+
return code.toLowerCase();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
68
99
|
/**
|
|
69
100
|
* returns the localization for the app based on the locale. If the locale is null
|
|
70
101
|
* or undefined, or if the given locale doesn't exist in the localizations,
|
|
@@ -3,12 +3,18 @@ import { OverlaysObserver } from "./OverlayObserver/OverlaysObserver";
|
|
|
3
3
|
import { useFeedLoader } from "../../reactHooks";
|
|
4
4
|
import { usePlayer } from "./usePlayer";
|
|
5
5
|
|
|
6
|
+
const getLiveUrl = (url: string) => {
|
|
7
|
+
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
8
|
+
return url.replace(new RegExp("subClass", "g"), "livePage");
|
|
9
|
+
};
|
|
10
|
+
|
|
6
11
|
export const useTitleSummaryOverlay = (
|
|
7
|
-
feedUrl,
|
|
8
12
|
entry,
|
|
9
13
|
isLive = false,
|
|
10
14
|
interval: number
|
|
11
15
|
) => {
|
|
16
|
+
// TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
|
|
17
|
+
const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
|
|
12
18
|
const player = usePlayer();
|
|
13
19
|
const [title, setTitle] = useState<string | number>(entry?.title || "");
|
|
14
20
|
const [summary, setSummary] = useState<string | number>(entry?.summary || "");
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentGallery } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentGallery", () => {
|
|
4
|
+
it("should return true if the first component is a gallery", () => {
|
|
5
|
+
const components = [
|
|
6
|
+
{ component_type: "gallery-qb" },
|
|
7
|
+
{ component_type: "other-component" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
expect(isFirstComponentGallery(components)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should return false if the first component is not a gallery", () => {
|
|
14
|
+
const components = [
|
|
15
|
+
{ component_type: "other-component" },
|
|
16
|
+
{ component_type: "gallery-qb" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return false if the components array is empty", () => {
|
|
23
|
+
const components = [];
|
|
24
|
+
|
|
25
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return false if the components array is undefined", () => {
|
|
29
|
+
const components = undefined;
|
|
30
|
+
|
|
31
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentScreenPicker", () => {
|
|
4
|
+
it("should return true if the first component screen-picker", () => {
|
|
5
|
+
const items = [{ component_type: "screen-picker-qb-tv" }];
|
|
6
|
+
expect(isFirstComponentScreenPicker(items)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the first component type is not screen-picker", () => {
|
|
10
|
+
const items = [{ component_type: "other-component" }];
|
|
11
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const items = [{ component_type: undefined }];
|
|
16
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const items = null;
|
|
21
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const items = undefined;
|
|
26
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const items = {};
|
|
31
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isGallery } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isGallery", () => {
|
|
4
|
+
it("should return true if the component type is 'gallery-qb'", () => {
|
|
5
|
+
const item = { component_type: "gallery-qb" };
|
|
6
|
+
expect(isGallery(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'gallery-qb'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isGallery(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isGallery(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isGallery(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isGallery(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isGallery(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isScreenPicker", () => {
|
|
4
|
+
it("should return true if the component type is 'screen-picker-qb-tv'", () => {
|
|
5
|
+
const item = { component_type: "screen-picker-qb-tv" };
|
|
6
|
+
expect(isScreenPicker(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'screen-picker-qb-tv'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const GROUP = "group-qb";
|
|
2
|
+
const GROUP_INFO = "group-info-qb";
|
|
3
|
+
const EMPTY_GROUP_COMPONENT = "empty_group_component";
|
|
4
|
+
|
|
5
|
+
const GALLERY = "gallery-qb";
|
|
6
|
+
|
|
7
|
+
const SCREEN_PICKER = "screen-picker-qb-tv";
|
|
8
|
+
|
|
9
|
+
export const isGallery = (item): boolean => item?.component_type === GALLERY;
|
|
10
|
+
|
|
11
|
+
export const isScreenPicker = (item): boolean =>
|
|
12
|
+
item?.component_type === SCREEN_PICKER;
|
|
13
|
+
|
|
14
|
+
export const isFirstComponentScreenPicker = (
|
|
15
|
+
components: ZappUIComponent[]
|
|
16
|
+
): boolean => {
|
|
17
|
+
return isScreenPicker(components?.[0]);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const isFirstComponentGallery = (
|
|
21
|
+
components: ZappUIComponent[]
|
|
22
|
+
): boolean => {
|
|
23
|
+
return isGallery(components?.[0]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const isGroup = (item): boolean => item?.component_type === GROUP;
|
|
27
|
+
|
|
28
|
+
export const isEmptyGroup = (item): boolean =>
|
|
29
|
+
item?.component_type === EMPTY_GROUP_COMPONENT;
|
|
30
|
+
|
|
31
|
+
export const isGroupInfo = (item): boolean =>
|
|
32
|
+
item?.component_type === GROUP_INFO;
|