@applicaster/zapp-react-native-utils 14.0.0-alpha.2247415563 → 14.0.0-alpha.2292190333
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 +60 -84
- package/actionsExecutor/ScreenActions.ts +164 -0
- package/actionsExecutor/StorageActions.ts +110 -0
- package/actionsExecutor/feedDecorator.ts +171 -0
- package/actionsExecutor/screenResolver.ts +11 -0
- package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
- package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
- package/analyticsUtils/__tests__/analyticsUtils.test.js +3 -0
- package/analyticsUtils/events.ts +8 -0
- package/appUtils/HooksManager/Hook.ts +4 -4
- package/appUtils/HooksManager/index.ts +11 -1
- package/appUtils/accessibilityManager/index.ts +5 -5
- package/appUtils/contextKeysManager/contextResolver.ts +42 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +5 -0
- package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
- package/appUtils/focusManager/index.ios.ts +10 -0
- package/appUtils/focusManager/index.ts +82 -11
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
- package/appUtils/focusManagerAux/utils/index.ts +106 -3
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +0 -15
- package/appUtils/playerManager/useChapterMarker.tsx +0 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
- package/arrayUtils/index.ts +1 -1
- package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
- package/componentsUtils/index.ts +4 -1
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +546 -0
- package/configurationUtils/manifestKeyParser.ts +57 -32
- package/focusManager/FocusManager.ts +95 -20
- package/focusManager/Tree.ts +25 -21
- package/focusManager/__tests__/FocusManager.test.ts +50 -8
- package/focusManager/aux/index.ts +170 -0
- package/index.d.ts +0 -9
- package/manifestUtils/defaultManifestConfigurations/player.js +8 -0
- package/navigationUtils/__tests__/mapContentTypesToRivers.test.ts +130 -0
- package/navigationUtils/index.ts +6 -4
- package/package.json +2 -3
- package/playerUtils/getPlayerActionButtons.ts +1 -1
- package/playerUtils/index.ts +51 -0
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +3 -1
- package/reactHooks/cell-click/__tests__/index.test.js +3 -0
- package/reactHooks/cell-click/index.ts +8 -1
- package/reactHooks/debugging/__tests__/index.test.js +0 -1
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +8 -2
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
- package/reactHooks/feed/index.ts +2 -0
- package/reactHooks/feed/useBatchLoading.ts +16 -9
- package/reactHooks/feed/useFeedLoader.tsx +36 -34
- package/reactHooks/feed/useLoadPipesDataDispatch.ts +57 -0
- package/reactHooks/feed/usePipesCacheReset.ts +3 -3
- package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
- package/reactHooks/layout/__tests__/index.test.tsx +3 -1
- package/reactHooks/layout/isTablet/index.ts +12 -5
- package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +34 -36
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -3
- package/reactHooks/layout/useLayoutVersion.ts +5 -5
- package/reactHooks/navigation/index.ts +7 -5
- package/reactHooks/navigation/useIsScreenActive.ts +9 -5
- package/reactHooks/navigation/useRoute.ts +7 -2
- package/reactHooks/navigation/useScreenStateStore.ts +8 -0
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +4 -0
- package/reactHooks/screen/useScreenContext.ts +1 -1
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
- package/reactHooks/state/index.ts +1 -1
- package/reactHooks/state/useHomeRiver.ts +4 -2
- package/reactHooks/state/useRivers.ts +7 -8
- package/riverComponetsMeasurementProvider/index.tsx +1 -1
- package/screenPickerUtils/index.ts +13 -0
- package/services/js2native.ts +1 -0
- package/storage/ScreenSingleValueProvider.ts +204 -0
- package/storage/ScreenStateMultiSelectProvider.ts +293 -0
- package/storage/StorageMultiSelectProvider.ts +192 -0
- package/storage/StorageSingleSelectProvider.ts +108 -0
- package/time/BackgroundTimer.ts +6 -4
- package/utils/__tests__/find.test.ts +36 -0
- package/utils/__tests__/omit.test.ts +19 -0
- package/utils/__tests__/pathOr.test.ts +37 -0
- package/utils/__tests__/startsWith.test.ts +30 -0
- package/utils/endsWith.ts +9 -0
- package/utils/find.ts +3 -0
- package/utils/index.ts +16 -0
- package/utils/omit.ts +5 -0
- package/utils/pathOr.ts +5 -0
- package/utils/startsWith.ts +9 -0
|
@@ -7,6 +7,13 @@ import { TreeNode } from "./TreeNode";
|
|
|
7
7
|
import { Tree } from "./Tree";
|
|
8
8
|
import { subscriber } from "../functionUtils";
|
|
9
9
|
import { getFocusableId, toFocusDirection } from "./utils";
|
|
10
|
+
import {
|
|
11
|
+
isCurrentFocusOnMenu,
|
|
12
|
+
isCurrentFocusOnContent,
|
|
13
|
+
findSelectedMenuId,
|
|
14
|
+
isTabsScreenContentFocused,
|
|
15
|
+
findSelectedTabId,
|
|
16
|
+
} from "./aux";
|
|
10
17
|
|
|
11
18
|
export {
|
|
12
19
|
toFocusDirection,
|
|
@@ -176,18 +183,30 @@ class FocusManager {
|
|
|
176
183
|
}
|
|
177
184
|
}
|
|
178
185
|
|
|
179
|
-
registerFocusable(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
isFocusableCell
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
registerFocusable({
|
|
187
|
+
touchableRef,
|
|
188
|
+
parentFocusableRef,
|
|
189
|
+
isFocusableCell,
|
|
190
|
+
parentFocusableId,
|
|
191
|
+
}: {
|
|
192
|
+
touchableRef: FocusManager.TouchableReactRef;
|
|
193
|
+
parentFocusableRef: FocusManager.TouchableReactRef;
|
|
194
|
+
isFocusableCell: boolean;
|
|
195
|
+
parentFocusableId: string;
|
|
196
|
+
}) {
|
|
197
|
+
const focusableId = getFocusableId(touchableRef);
|
|
198
|
+
|
|
185
199
|
const focusableComponent = FocusManager.findFocusable(focusableId);
|
|
186
200
|
|
|
187
|
-
if (!focusableComponent &&
|
|
188
|
-
this.focusableComponents.push(
|
|
201
|
+
if (!focusableComponent && touchableRef) {
|
|
202
|
+
this.focusableComponents.push(touchableRef);
|
|
189
203
|
|
|
190
|
-
this.tree.add(
|
|
204
|
+
this.tree.add(
|
|
205
|
+
touchableRef,
|
|
206
|
+
parentFocusableRef,
|
|
207
|
+
isFocusableCell,
|
|
208
|
+
parentFocusableId
|
|
209
|
+
);
|
|
191
210
|
} else {
|
|
192
211
|
logger.warning("Focusable component already registered", {
|
|
193
212
|
id: focusableId,
|
|
@@ -209,7 +228,8 @@ class FocusManager {
|
|
|
209
228
|
|
|
210
229
|
private setNextFocus(
|
|
211
230
|
nextFocus: FocusManager.TouchableReactRef,
|
|
212
|
-
options?: FocusManager.Android.CallbackOptions
|
|
231
|
+
options?: FocusManager.Android.CallbackOptions,
|
|
232
|
+
context?: FocusManager.FocusContext
|
|
213
233
|
) {
|
|
214
234
|
if (nextFocus?.current?.props?.blockFocus) {
|
|
215
235
|
return;
|
|
@@ -238,17 +258,15 @@ class FocusManager {
|
|
|
238
258
|
|
|
239
259
|
FocusManager.instance.setPreviousNavigationDirection(options ?? null);
|
|
240
260
|
|
|
241
|
-
nextFocus?.current?.onFocus?.(nextFocus.current, options ?? {});
|
|
261
|
+
nextFocus?.current?.onFocus?.(nextFocus.current, options ?? {}, context);
|
|
242
262
|
}
|
|
243
263
|
}
|
|
244
264
|
|
|
245
265
|
blurPrevious(options?: FocusManager.Android.CallbackOptions) {
|
|
246
|
-
|
|
247
|
-
FocusManager.instance.prevFocused
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
);
|
|
251
|
-
}
|
|
266
|
+
FocusManager.instance.prevFocused?.onBlur?.(
|
|
267
|
+
FocusManager.instance.prevFocused,
|
|
268
|
+
options ?? {} // Adding fallback to avoid potential regression caused by #7509
|
|
269
|
+
);
|
|
252
270
|
}
|
|
253
271
|
|
|
254
272
|
onDisableFocusChange = (id) => {
|
|
@@ -269,7 +287,7 @@ class FocusManager {
|
|
|
269
287
|
|
|
270
288
|
if (nextFocus) {
|
|
271
289
|
// HACK: hack to fix the hack below
|
|
272
|
-
// HACK: putting call to the end of the event loop so the next component has a
|
|
290
|
+
// HACK: putting call to the end of the event loop so the next component has a chance to be registered
|
|
273
291
|
setTimeout(() => {
|
|
274
292
|
FocusManager.instance.setFocus(nextFocus, {
|
|
275
293
|
direction: "down",
|
|
@@ -281,7 +299,8 @@ class FocusManager {
|
|
|
281
299
|
|
|
282
300
|
setFocus(
|
|
283
301
|
newFocus: FocusManager.TouchableReactRef | string,
|
|
284
|
-
options?: FocusManager.Android.CallbackOptions
|
|
302
|
+
options?: FocusManager.Android.CallbackOptions,
|
|
303
|
+
context?: FocusManager.FocusContext
|
|
285
304
|
) {
|
|
286
305
|
// Checks if element is focusable
|
|
287
306
|
const { isFocusable, error } = FocusManager.isFocusable(newFocus);
|
|
@@ -306,7 +325,7 @@ class FocusManager {
|
|
|
306
325
|
}
|
|
307
326
|
|
|
308
327
|
if (newFocusRef) {
|
|
309
|
-
FocusManager.instance.setNextFocus(newFocusRef, options);
|
|
328
|
+
FocusManager.instance.setNextFocus(newFocusRef, options, context);
|
|
310
329
|
}
|
|
311
330
|
}
|
|
312
331
|
}
|
|
@@ -407,6 +426,62 @@ class FocusManager {
|
|
|
407
426
|
throw new Error(`Group with id ${id} not found`);
|
|
408
427
|
}
|
|
409
428
|
}
|
|
429
|
+
|
|
430
|
+
isFocusOnMenu(): boolean {
|
|
431
|
+
// FIXME
|
|
432
|
+
return isCurrentFocusOnMenu(this.tree, FocusManager.instance.focusedId);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
isFocusOnContent(): boolean {
|
|
436
|
+
// FIXME
|
|
437
|
+
return isCurrentFocusOnContent(this.tree, FocusManager.instance.focusedId);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Move focus to appropriate top navigation tab with context
|
|
441
|
+
focusTopNavigation(isTabsScreen: boolean, item: ZappEntry): void {
|
|
442
|
+
const landFocusTo = (id) => {
|
|
443
|
+
console.log("debug_2", "FM - landFocusTo", { id });
|
|
444
|
+
|
|
445
|
+
if (id) {
|
|
446
|
+
// set focus on selected menu item
|
|
447
|
+
const direction = undefined;
|
|
448
|
+
|
|
449
|
+
const context: FocusManager.FocusContext = {
|
|
450
|
+
source: "back",
|
|
451
|
+
preserveScroll: true,
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
logger.log({ message: "landFocusTo", data: { id } });
|
|
455
|
+
|
|
456
|
+
// blur(direction); ???
|
|
457
|
+
this.setFocus(id, direction, context);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
if (
|
|
462
|
+
isTabsScreen &&
|
|
463
|
+
isTabsScreenContentFocused(this.tree, FocusManager.instance.focusedId)
|
|
464
|
+
) {
|
|
465
|
+
const selectedTabId = findSelectedTabId(this.tree, item);
|
|
466
|
+
|
|
467
|
+
// Set focus with back button context to tabs-menu
|
|
468
|
+
landFocusTo(selectedTabId);
|
|
469
|
+
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const selectedMenuItemId = findSelectedMenuId(this.tree);
|
|
474
|
+
|
|
475
|
+
console.log("debug_2", "FM - focusTopNavigation", {
|
|
476
|
+
isTabsScreen,
|
|
477
|
+
item,
|
|
478
|
+
tree: this.tree,
|
|
479
|
+
selectedMenuItemId,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Set focus with back button context to top-menu
|
|
483
|
+
landFocusTo(selectedMenuItemId);
|
|
484
|
+
}
|
|
410
485
|
}
|
|
411
486
|
|
|
412
487
|
export const focusManager = FocusManager.getInstance();
|
package/focusManager/Tree.ts
CHANGED
|
@@ -8,37 +8,41 @@ export class Tree {
|
|
|
8
8
|
this.tree = focusManagerTree;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
add(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
add(
|
|
12
|
+
touchableRef: FocusManager.TouchableReactRef,
|
|
13
|
+
parentFocusableRef: FocusManager.TouchableReactRef,
|
|
14
|
+
isFocusableCell: boolean,
|
|
15
|
+
parentFocusableId: string
|
|
16
|
+
) {
|
|
17
|
+
const focusableId = getFocusableId(touchableRef);
|
|
18
|
+
const parentId = getFocusableId(parentFocusableRef) || parentFocusableId;
|
|
14
19
|
const focusableComponentInTree = this.find(focusableId);
|
|
15
20
|
|
|
16
21
|
// update node if it already exists
|
|
17
22
|
if (focusableComponentInTree) {
|
|
18
|
-
focusableComponentInTree.updateNode(
|
|
23
|
+
focusableComponentInTree.updateNode(touchableRef);
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
if (!this.find(parentId)) {
|
|
27
|
+
// create temporary node to the root of the tree
|
|
28
|
+
this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
|
|
29
|
+
}
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
const parentNode = this.find(parentId);
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
if (parentNode) {
|
|
34
|
+
if (focusableComponentInTree) {
|
|
35
|
+
focusableComponentInTree.isFocusableCell = isFocusableCell;
|
|
36
|
+
focusableComponentInTree.parentId = parentNode.id;
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
parentNode.addChild(focusableComponentInTree);
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
40
|
+
// remove root object from the list
|
|
41
|
+
this.tree = this.tree.filter(
|
|
42
|
+
(node) => node !== focusableComponentInTree
|
|
43
|
+
);
|
|
44
|
+
} else {
|
|
45
|
+
parentNode.addChild(touchableRef, focusableId, isFocusableCell);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { focusManager } from "../FocusManager";
|
|
2
2
|
|
|
3
|
+
const isFocusableCell = true;
|
|
4
|
+
const parentFocusableId = "parentFocusableId";
|
|
5
|
+
|
|
3
6
|
const group = {
|
|
4
7
|
current: {
|
|
5
8
|
props: {
|
|
@@ -62,13 +65,47 @@ jest.useFakeTimers();
|
|
|
62
65
|
|
|
63
66
|
describe("FocusManager", () => {
|
|
64
67
|
beforeAll(() => {
|
|
65
|
-
focusManager.registerFocusable(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
focusManager.registerFocusable({
|
|
69
|
+
touchableRef: group,
|
|
70
|
+
parentFocusableRef: { current: null },
|
|
71
|
+
isFocusableCell,
|
|
72
|
+
parentFocusableId,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
focusManager.registerFocusable({
|
|
76
|
+
touchableRef: child1,
|
|
77
|
+
parentFocusableRef: group,
|
|
78
|
+
isFocusableCell,
|
|
79
|
+
parentFocusableId,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
focusManager.registerFocusable({
|
|
83
|
+
touchableRef: child2,
|
|
84
|
+
parentFocusableRef: group,
|
|
85
|
+
isFocusableCell,
|
|
86
|
+
parentFocusableId,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
focusManager.registerFocusable({
|
|
90
|
+
touchableRef: child3,
|
|
91
|
+
parentFocusableRef: child2,
|
|
92
|
+
isFocusableCell,
|
|
93
|
+
parentFocusableId,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
focusManager.registerFocusable({
|
|
97
|
+
touchableRef: child4,
|
|
98
|
+
parentFocusableRef: child2,
|
|
99
|
+
isFocusableCell,
|
|
100
|
+
parentFocusableId,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
focusManager.registerFocusable({
|
|
104
|
+
touchableRef: child5,
|
|
105
|
+
parentFocusableRef: child2,
|
|
106
|
+
isFocusableCell,
|
|
107
|
+
parentFocusableId,
|
|
108
|
+
});
|
|
72
109
|
});
|
|
73
110
|
|
|
74
111
|
it("focusManager should be defined", () => {
|
|
@@ -199,7 +236,12 @@ describe("FocusManager", () => {
|
|
|
199
236
|
});
|
|
200
237
|
|
|
201
238
|
it("focusManager registerFocusable should register", () => {
|
|
202
|
-
focusManager.registerFocusable(
|
|
239
|
+
focusManager.registerFocusable({
|
|
240
|
+
touchableRef: child5,
|
|
241
|
+
parentFocusableRef: child2,
|
|
242
|
+
isFocusableCell,
|
|
243
|
+
parentFocusableId,
|
|
244
|
+
});
|
|
203
245
|
|
|
204
246
|
expect(
|
|
205
247
|
focusManager.isFocusableChildOf(child5.current.props.id, child2)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isNil,
|
|
3
|
+
startsWith,
|
|
4
|
+
find,
|
|
5
|
+
pathOr,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/utils";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
QUICK_BRICK_CONTENT,
|
|
10
|
+
QUICK_BRICK_NAVBAR,
|
|
11
|
+
} from "@applicaster/quick-brick-core/const";
|
|
12
|
+
|
|
13
|
+
const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
14
|
+
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
15
|
+
|
|
16
|
+
// FIXME
|
|
17
|
+
const sectionIds = {
|
|
18
|
+
right: "nav-bar-right",
|
|
19
|
+
menu: "navbar-items",
|
|
20
|
+
left: "nav-bar-left",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER
|
|
24
|
+
let screenPickerSelectorContainerId;
|
|
25
|
+
|
|
26
|
+
export const onRegisterScreenPickerSelectorContainer = (id) => {
|
|
27
|
+
screenPickerSelectorContainerId = id;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const onUnRegisterScreenPickerSelectorContainer = (id) => {
|
|
31
|
+
// reset screenSelectorId on unregistration
|
|
32
|
+
if (screenPickerSelectorContainerId === id) {
|
|
33
|
+
screenPickerSelectorContainerId = undefined;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER
|
|
37
|
+
|
|
38
|
+
// SCREEN_PICKER_CONTENT_CONTAINER
|
|
39
|
+
let screenPickerContentContainerId;
|
|
40
|
+
|
|
41
|
+
export const onRegisterScreenPickerContentContainer = (id) => {
|
|
42
|
+
screenPickerContentContainerId = id;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const onUnRegisterScreenPickerContentContainer = (id) => {
|
|
46
|
+
// reset screenSelectorId on unregistration
|
|
47
|
+
if (screenPickerContentContainerId === id) {
|
|
48
|
+
screenPickerContentContainerId = undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const isScreenPickerContentContainer = (node) =>
|
|
53
|
+
screenPickerContentContainerId === node?.id;
|
|
54
|
+
|
|
55
|
+
// SCREEN_PICKER_CONTENT_CONTAINER
|
|
56
|
+
|
|
57
|
+
const findSelectedMenuIdInSection = (focusableTree, section) => {
|
|
58
|
+
const children = pathOr([], ["children"], focusableTree.find(section));
|
|
59
|
+
|
|
60
|
+
return find((child) => child.component.current.props.isSelected(), children)
|
|
61
|
+
?.id;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const findSelectedMenuId = (focusableTree) => {
|
|
65
|
+
const selectedMenuItemIdInLeftSection = findSelectedMenuIdInSection(
|
|
66
|
+
focusableTree,
|
|
67
|
+
sectionIds.left
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
if (selectedMenuItemIdInLeftSection) {
|
|
71
|
+
return selectedMenuItemIdInLeftSection;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const selectedMenuItemIdInMenuSection = findSelectedMenuIdInSection(
|
|
75
|
+
focusableTree,
|
|
76
|
+
sectionIds.menu
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if (selectedMenuItemIdInMenuSection) {
|
|
80
|
+
return selectedMenuItemIdInMenuSection;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const selectedMenuItemIdInRightSection = findSelectedMenuIdInSection(
|
|
84
|
+
focusableTree,
|
|
85
|
+
sectionIds.right
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (selectedMenuItemIdInRightSection) {
|
|
89
|
+
return selectedMenuItemIdInRightSection;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return undefined;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const findSelectedTabId = (focusableTree, item: ZappEntry): string => {
|
|
96
|
+
const screenSelectorContainerNode = focusableTree.find(
|
|
97
|
+
screenPickerSelectorContainerId
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// console.log("debug_2", "findSelectedTabId", {
|
|
101
|
+
// focusableTree,
|
|
102
|
+
// item,
|
|
103
|
+
// screenSelectorContainerNode,
|
|
104
|
+
// });
|
|
105
|
+
|
|
106
|
+
const selectedTabId = find(
|
|
107
|
+
(child) => child.component.current.props.isSelected(item.id),
|
|
108
|
+
screenSelectorContainerNode.children
|
|
109
|
+
)?.id;
|
|
110
|
+
|
|
111
|
+
return selectedTabId;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const isTabsScreenContentFocused = (focusableTree, id) => {
|
|
115
|
+
const node = focusableTree.find(id);
|
|
116
|
+
|
|
117
|
+
if (isNil(node)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (isNavBar(node)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (isContent(node)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (isScreenPickerContentContainer(node)) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return isTabsScreenContentFocused(focusableTree, node.parentId);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const isCurrentFocusOnMenu = (focusableTree, id): boolean => {
|
|
137
|
+
const node = focusableTree.find(id);
|
|
138
|
+
|
|
139
|
+
if (isNil(node)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (isNavBar(node)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (isContent(node)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return isCurrentFocusOnMenu(focusableTree, node.parentId);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const isCurrentFocusOnContent = (focusableTree, id) => {
|
|
155
|
+
const node = focusableTree.find(id);
|
|
156
|
+
|
|
157
|
+
if (isNil(node)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (isNavBar(node)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (isContent(node)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return isCurrentFocusOnContent(focusableTree, node.parentId);
|
|
170
|
+
};
|
package/index.d.ts
CHANGED
|
@@ -137,12 +137,3 @@ declare type AccessibilityState = {
|
|
|
137
137
|
reduceMotionEnabled: boolean;
|
|
138
138
|
boldTextEnabled: boolean;
|
|
139
139
|
};
|
|
140
|
-
|
|
141
|
-
declare type AccessibilityProps = {
|
|
142
|
-
accessibilityLabel?: string;
|
|
143
|
-
accessibilityHint?: string;
|
|
144
|
-
"aria-label"?: string;
|
|
145
|
-
"aria-description"?: string;
|
|
146
|
-
accessibilityRole?: string;
|
|
147
|
-
"aria-role"?: string;
|
|
148
|
-
};
|
|
@@ -2985,6 +2985,14 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
2985
2985
|
type: "uploader",
|
|
2986
2986
|
default: "",
|
|
2987
2987
|
},
|
|
2988
|
+
{
|
|
2989
|
+
key: "audio_player_background_image_overlay",
|
|
2990
|
+
label: "Background Image Overlay",
|
|
2991
|
+
label_tooltip:
|
|
2992
|
+
"Add a semi-transparent color overlay to improve text readability over the background image.",
|
|
2993
|
+
type: "color_picker_rgba",
|
|
2994
|
+
initial_value: "rgba(17, 17, 17, 0.5)",
|
|
2995
|
+
},
|
|
2988
2996
|
{
|
|
2989
2997
|
type: "text_input",
|
|
2990
2998
|
label: "Item Image Key",
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { mapContentTypesToRivers } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("mapContentTypesToRivers", () => {
|
|
4
|
+
it("should return the correct content types mapped to rivers", () => {
|
|
5
|
+
const state = {
|
|
6
|
+
rivers: {
|
|
7
|
+
"river-1": {
|
|
8
|
+
plugin_type: "river",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
contentTypes: {
|
|
12
|
+
"content-type-1": {
|
|
13
|
+
screen_id: "river-1",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const result = mapContentTypesToRivers(state);
|
|
19
|
+
|
|
20
|
+
expect(result).toEqual({
|
|
21
|
+
"content-type-1": {
|
|
22
|
+
screenType: "river",
|
|
23
|
+
screen_id: "river-1",
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return null if contentTypes is undefined", () => {
|
|
29
|
+
const state = {
|
|
30
|
+
rivers: {
|
|
31
|
+
"river-1": {
|
|
32
|
+
plugin_type: "river",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
// contentTypes is missing
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const result = mapContentTypesToRivers(state);
|
|
39
|
+
|
|
40
|
+
expect(result).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should skip content types whose screen does not exist in rivers", () => {
|
|
44
|
+
const state = {
|
|
45
|
+
rivers: {
|
|
46
|
+
"river-1": {
|
|
47
|
+
plugin_type: "river",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
contentTypes: {
|
|
51
|
+
"content-type-1": {
|
|
52
|
+
screen_id: "river-1",
|
|
53
|
+
},
|
|
54
|
+
"content-type-2": {
|
|
55
|
+
screen_id: "river-2", // river-2 does not exist
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const result = mapContentTypesToRivers(state);
|
|
61
|
+
|
|
62
|
+
expect(result).toEqual({
|
|
63
|
+
"content-type-1": {
|
|
64
|
+
screenType: "river",
|
|
65
|
+
screen_id: "river-1",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// result is not null, but may be undefined for missing keys
|
|
70
|
+
expect(result && result["content-type-2"]).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should use 'type' if 'plugin_type' is not present in river", () => {
|
|
74
|
+
const state = {
|
|
75
|
+
rivers: {
|
|
76
|
+
"river-1": {
|
|
77
|
+
type: "custom-type",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
contentTypes: {
|
|
81
|
+
"content-type-1": {
|
|
82
|
+
screen_id: "river-1",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const result = mapContentTypesToRivers(state);
|
|
88
|
+
|
|
89
|
+
expect(result).toEqual({
|
|
90
|
+
"content-type-1": {
|
|
91
|
+
screenType: "custom-type",
|
|
92
|
+
screen_id: "river-1",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should skip content types if neither plugin_type nor type is present in river", () => {
|
|
98
|
+
const state = {
|
|
99
|
+
rivers: {
|
|
100
|
+
"river-1": {
|
|
101
|
+
// no plugin_type or type
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
contentTypes: {
|
|
105
|
+
"content-type-1": {
|
|
106
|
+
screen_id: "river-1",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const result = mapContentTypesToRivers(state);
|
|
112
|
+
|
|
113
|
+
expect(result).toEqual({});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should handle empty contentTypes object", () => {
|
|
117
|
+
const state = {
|
|
118
|
+
rivers: {
|
|
119
|
+
"river-1": {
|
|
120
|
+
plugin_type: "river",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
contentTypes: {},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = mapContentTypesToRivers(state);
|
|
127
|
+
|
|
128
|
+
expect(result).toEqual({});
|
|
129
|
+
});
|
|
130
|
+
});
|
package/navigationUtils/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isPlayable,
|
|
14
14
|
isV2River,
|
|
15
15
|
} from "./itemTypeMatchers";
|
|
16
|
+
import { RootState } from "@applicaster/zapp-react-native-redux/store";
|
|
16
17
|
|
|
17
18
|
type PathAttribute = {
|
|
18
19
|
screenType: string;
|
|
@@ -377,10 +378,11 @@ export const usesVideoModal = (
|
|
|
377
378
|
return targetScreenConfiguration?.styles?.use_video_modal;
|
|
378
379
|
};
|
|
379
380
|
|
|
380
|
-
export const mapContentTypesToRivers = (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
381
|
+
export const mapContentTypesToRivers = (
|
|
382
|
+
state: Partial<RootState>
|
|
383
|
+
): ZappContentTypesMapped | null => {
|
|
384
|
+
const { rivers, contentTypes } = state;
|
|
385
|
+
|
|
384
386
|
if (!contentTypes) {
|
|
385
387
|
return null;
|
|
386
388
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "14.0.0-alpha.
|
|
3
|
+
"version": "14.0.0-alpha.2292190333",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "14.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.2292190333",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@applicaster/zapp-pipes-v2-client": "*",
|
|
40
40
|
"@react-native-community/netinfo": "*",
|
|
41
|
-
"immer": "*",
|
|
42
41
|
"react": "*",
|
|
43
42
|
"react-native": "*",
|
|
44
43
|
"uglify-js": "*",
|