@applicaster/zapp-react-native-utils 14.0.0-alpha.4385101226 → 14.0.0-alpha.4520122433
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 +1 -1
- package/analyticsUtils/__tests__/analyticsUtils.test.js +0 -11
- package/analyticsUtils/playerAnalyticsTracker.ts +2 -1
- package/appUtils/accessibilityManager/const.ts +13 -0
- package/appUtils/accessibilityManager/hooks.ts +35 -1
- package/appUtils/accessibilityManager/index.ts +151 -30
- package/appUtils/accessibilityManager/utils.ts +24 -0
- package/appUtils/contextKeysManager/contextResolver.ts +42 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +7 -0
- package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
- package/appUtils/focusManager/events.ts +2 -0
- package/appUtils/focusManager/index.ios.ts +10 -0
- package/appUtils/focusManager/index.ts +86 -11
- package/appUtils/focusManagerAux/utils/index.ts +94 -3
- package/appUtils/platform/platformUtils.ts +31 -1
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +0 -1
- package/configurationUtils/index.ts +1 -1
- package/focusManager/FocusManager.ts +78 -4
- package/focusManager/aux/index.ts +98 -0
- package/focusManager/utils.ts +12 -6
- package/index.d.ts +1 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +188 -2
- package/manifestUtils/index.js +4 -0
- package/manifestUtils/keys.js +12 -0
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +6 -0
- package/navigationUtils/index.ts +1 -1
- package/package.json +2 -2
- package/playerUtils/PlayerTTS/PlayerTTS.ts +359 -0
- package/playerUtils/PlayerTTS/index.ts +1 -0
- package/playerUtils/getPlayerActionButtons.ts +1 -1
- package/playerUtils/usePlayerTTS.ts +21 -0
- 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 +14 -9
- package/reactHooks/feed/useFeedLoader.tsx +36 -38
- package/reactHooks/feed/useLoadPipesDataDispatch.ts +63 -0
- package/reactHooks/navigation/useRoute.ts +7 -2
- package/reactHooks/navigation/useScreenStateStore.ts +8 -0
- package/reactHooks/state/index.ts +1 -1
- package/reactHooks/state/useHomeRiver.ts +4 -2
- package/screenPickerUtils/index.ts +13 -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/utils/__tests__/endsWith.test.ts +30 -0
- package/utils/__tests__/find.test.ts +36 -0
- package/utils/__tests__/omit.test.ts +19 -0
- package/utils/__tests__/path.test.ts +33 -0
- package/utils/__tests__/pathOr.test.ts +37 -0
- package/utils/__tests__/startsWith.test.ts +30 -0
- package/utils/__tests__/take.test.ts +40 -0
- package/utils/endsWith.ts +9 -0
- package/utils/find.ts +3 -0
- package/utils/index.ts +17 -1
- package/utils/omit.ts +5 -0
- package/utils/path.ts +5 -0
- package/utils/pathOr.ts +5 -0
- package/utils/startsWith.ts +9 -0
- package/utils/take.ts +5 -0
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
isNil,
|
|
3
|
+
last,
|
|
4
|
+
startsWith,
|
|
5
|
+
find,
|
|
6
|
+
pathOr,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/utils";
|
|
8
|
+
|
|
3
9
|
import {
|
|
4
10
|
QUICK_BRICK_CONTENT,
|
|
5
11
|
QUICK_BRICK_NAVBAR,
|
|
6
12
|
} from "@applicaster/quick-brick-core/const";
|
|
7
13
|
|
|
14
|
+
import {
|
|
15
|
+
getFocusableId,
|
|
16
|
+
SCREEN_PICKER_CONTAINER,
|
|
17
|
+
} from "@applicaster/zapp-react-native-utils/screenPickerUtils";
|
|
18
|
+
|
|
8
19
|
// run check each 300 ms
|
|
9
20
|
// run this check too often could lead to performance penalty on low-end devices
|
|
10
21
|
const HOW_OFTEN_TO_CHECK_CONDITION = 300; // ms
|
|
11
22
|
|
|
23
|
+
const isTopMenu = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
24
|
+
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
25
|
+
const isRoot = (node) => node?.id === "root";
|
|
26
|
+
|
|
27
|
+
const isScrenPicker = (node) => startsWith(SCREEN_PICKER_CONTAINER, node?.id);
|
|
28
|
+
|
|
12
29
|
type Props = {
|
|
13
30
|
maxTimeout: number;
|
|
14
31
|
conditionFn: () => boolean;
|
|
@@ -49,7 +66,7 @@ export const waitForActiveScreen = (currentRoute: string, focusableTree) => {
|
|
|
49
66
|
|
|
50
67
|
const route = find((route) => route.id === currentRoute, routes);
|
|
51
68
|
|
|
52
|
-
return
|
|
69
|
+
return !isNil(route);
|
|
53
70
|
};
|
|
54
71
|
|
|
55
72
|
return waitUntil({
|
|
@@ -99,3 +116,77 @@ export const waitForContent = (focusableTree) => {
|
|
|
99
116
|
conditionFn: contentHasAnyChildren,
|
|
100
117
|
});
|
|
101
118
|
};
|
|
119
|
+
|
|
120
|
+
export const findSelectedTabId = (item: ZappEntry): string => {
|
|
121
|
+
const selectedTabId = getFocusableId(item.id);
|
|
122
|
+
|
|
123
|
+
return selectedTabId;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const isTabsScreenOnContentFocused = (node) => {
|
|
127
|
+
if (isRoot(node)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (isTopMenu(node)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (isContent(node)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (isScrenPicker(node)) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return isTabsScreenOnContentFocused(node.parent);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const isCurrentFocusOnMenu = (node) => {
|
|
147
|
+
if (isRoot(node)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (isTopMenu(node)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (isContent(node)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return isCurrentFocusOnMenu(node.parent);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const isCurrentFocusOnContent = (node) => {
|
|
163
|
+
if (isRoot(node)) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (isTopMenu(node)) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (isContent(node)) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return isCurrentFocusOnContent(node.parent);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const isCurrentFocusOn = (id, node) => {
|
|
179
|
+
if (!node) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (isRoot(node)) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (node?.id === id) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return isCurrentFocusOn(id, node.parent);
|
|
192
|
+
};
|
|
@@ -10,6 +10,7 @@ import { PLATFORM_KEYS, PLATFORMS, ZappPlatform } from "./const";
|
|
|
10
10
|
import { createLogger, utilsLogger } from "../../logger";
|
|
11
11
|
import { getPlatform } from "../../reactUtils";
|
|
12
12
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
13
|
+
import { calculateReadingTime } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/utils";
|
|
13
14
|
|
|
14
15
|
const { log_debug } = createLogger({
|
|
15
16
|
category: "General",
|
|
@@ -212,9 +213,16 @@ export class TTSManager {
|
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
readText(text: string) {
|
|
216
|
+
this.ttsState$.next(true);
|
|
217
|
+
|
|
215
218
|
if (isSamsungPlatform() && window.speechSynthesis) {
|
|
216
219
|
const utterance = new SpeechSynthesisUtterance(text);
|
|
220
|
+
|
|
221
|
+
window.speechSynthesis.cancel(); // Cancel previous speech before speaking new text
|
|
217
222
|
window.speechSynthesis.speak(utterance);
|
|
223
|
+
|
|
224
|
+
// Estimate reading time and set inactive when done
|
|
225
|
+
this.scheduleTTSComplete(text);
|
|
218
226
|
}
|
|
219
227
|
|
|
220
228
|
if (isLgPlatform() && window.webOS?.service) {
|
|
@@ -225,23 +233,45 @@ export class TTSManager {
|
|
|
225
233
|
log_debug("There was a failure setting up webOS TTS service", {
|
|
226
234
|
error,
|
|
227
235
|
});
|
|
236
|
+
|
|
237
|
+
this.ttsState$.next(false);
|
|
228
238
|
},
|
|
229
239
|
onSuccess(response: any) {
|
|
230
240
|
log_debug("webOS TTS service is configured successfully", {
|
|
231
241
|
response,
|
|
232
242
|
});
|
|
243
|
+
|
|
244
|
+
// Estimate reading time and set inactive when done
|
|
245
|
+
this.scheduleTTSComplete(text);
|
|
233
246
|
},
|
|
234
247
|
parameters: {
|
|
235
248
|
text,
|
|
249
|
+
clear: true, // Clear any previous speech before speaking new text
|
|
236
250
|
},
|
|
237
251
|
});
|
|
238
252
|
} catch (error) {
|
|
239
253
|
log_debug("webOS TTS service error", { error });
|
|
254
|
+
this.ttsState$.next(false);
|
|
240
255
|
}
|
|
241
256
|
}
|
|
242
257
|
|
|
243
|
-
if (!window.VIZIO?.Chromevox)
|
|
258
|
+
if (!window.VIZIO?.Chromevox) {
|
|
259
|
+
// For platforms without TTS, estimate reading time
|
|
260
|
+
this.scheduleTTSComplete(text);
|
|
261
|
+
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
244
264
|
|
|
245
265
|
window.VIZIO.Chromevox.play(text);
|
|
266
|
+
// Estimate reading time and set inactive when done
|
|
267
|
+
this.scheduleTTSComplete(text);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private scheduleTTSComplete(text: string) {
|
|
271
|
+
const readingTime = calculateReadingTime(text);
|
|
272
|
+
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
this.ttsState$.next(false);
|
|
275
|
+
}, readingTime);
|
|
246
276
|
}
|
|
247
277
|
}
|
|
@@ -399,7 +399,7 @@ export const populateConfigurationValues =
|
|
|
399
399
|
flattenAndPopulateFields(fields, configuration, skipDefaults)
|
|
400
400
|
);
|
|
401
401
|
|
|
402
|
-
export const
|
|
402
|
+
export const getAccessibilityProps = (item: ZappEntry) => ({
|
|
403
403
|
accessible: item?.extensions?.accessibility,
|
|
404
404
|
accessibilityLabel: item?.extensions?.accessibility?.label || item?.title,
|
|
405
405
|
accessibilityHint: item?.extensions?.accessibility?.hint,
|
|
@@ -2,11 +2,24 @@ import { path } from "ramda";
|
|
|
2
2
|
import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
3
3
|
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
4
4
|
|
|
5
|
+
import {
|
|
6
|
+
QUICK_BRICK_CONTENT,
|
|
7
|
+
QUICK_BRICK_NAVBAR,
|
|
8
|
+
} from "@applicaster/quick-brick-core/const";
|
|
9
|
+
|
|
5
10
|
import { logger } from "./logger";
|
|
6
11
|
import { TreeNode } from "./TreeNode";
|
|
7
12
|
import { Tree } from "./Tree";
|
|
8
13
|
import { subscriber } from "../functionUtils";
|
|
9
14
|
import { getFocusableId, toFocusDirection } from "./utils";
|
|
15
|
+
import {
|
|
16
|
+
findSelectedMenuId,
|
|
17
|
+
isTabsScreenContentFocused,
|
|
18
|
+
findSelectedTabId,
|
|
19
|
+
contextWithoutScrolling,
|
|
20
|
+
} from "./aux";
|
|
21
|
+
|
|
22
|
+
export { contextWithoutScrolling } from "./aux";
|
|
10
23
|
|
|
11
24
|
export {
|
|
12
25
|
toFocusDirection,
|
|
@@ -221,7 +234,8 @@ class FocusManager {
|
|
|
221
234
|
|
|
222
235
|
private setNextFocus(
|
|
223
236
|
nextFocus: FocusManager.TouchableReactRef,
|
|
224
|
-
options?: FocusManager.Android.CallbackOptions
|
|
237
|
+
options?: FocusManager.Android.CallbackOptions,
|
|
238
|
+
context?: FocusManager.FocusContext
|
|
225
239
|
) {
|
|
226
240
|
if (nextFocus?.current?.props?.blockFocus) {
|
|
227
241
|
return;
|
|
@@ -250,7 +264,7 @@ class FocusManager {
|
|
|
250
264
|
|
|
251
265
|
FocusManager.instance.setPreviousNavigationDirection(options ?? null);
|
|
252
266
|
|
|
253
|
-
nextFocus?.current?.onFocus?.(nextFocus.current, options ?? {});
|
|
267
|
+
nextFocus?.current?.onFocus?.(nextFocus.current, options ?? {}, context);
|
|
254
268
|
}
|
|
255
269
|
}
|
|
256
270
|
|
|
@@ -291,7 +305,8 @@ class FocusManager {
|
|
|
291
305
|
|
|
292
306
|
setFocus(
|
|
293
307
|
newFocus: FocusManager.TouchableReactRef | string,
|
|
294
|
-
options?: FocusManager.Android.CallbackOptions
|
|
308
|
+
options?: FocusManager.Android.CallbackOptions,
|
|
309
|
+
context?: FocusManager.FocusContext
|
|
295
310
|
) {
|
|
296
311
|
// Checks if element is focusable
|
|
297
312
|
const { isFocusable, error } = FocusManager.isFocusable(newFocus);
|
|
@@ -316,7 +331,7 @@ class FocusManager {
|
|
|
316
331
|
}
|
|
317
332
|
|
|
318
333
|
if (newFocusRef) {
|
|
319
|
-
FocusManager.instance.setNextFocus(newFocusRef, options);
|
|
334
|
+
FocusManager.instance.setNextFocus(newFocusRef, options, context);
|
|
320
335
|
}
|
|
321
336
|
}
|
|
322
337
|
}
|
|
@@ -351,6 +366,11 @@ class FocusManager {
|
|
|
351
366
|
FocusManager.instance.focused.onBlur(FocusManager.instance.focused, {});
|
|
352
367
|
}
|
|
353
368
|
|
|
369
|
+
// send reset event to some handler to reset their internal state, before real reset happens
|
|
370
|
+
this.eventHandler?.invokeHandler?.(FOCUS_EVENTS.RESET, {
|
|
371
|
+
focusedId: FocusManager.instance.focusedId,
|
|
372
|
+
});
|
|
373
|
+
|
|
354
374
|
FocusManager.instance.setFocusLocal({ current: null });
|
|
355
375
|
}
|
|
356
376
|
|
|
@@ -417,6 +437,60 @@ class FocusManager {
|
|
|
417
437
|
throw new Error(`Group with id ${id} not found`);
|
|
418
438
|
}
|
|
419
439
|
}
|
|
440
|
+
|
|
441
|
+
isFocusOnMenu(): boolean {
|
|
442
|
+
return this.isFocusableChildOf(
|
|
443
|
+
FocusManager.instance.focusedId,
|
|
444
|
+
QUICK_BRICK_NAVBAR
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
isFocusOnContent(): boolean {
|
|
449
|
+
return this.isFocusableChildOf(
|
|
450
|
+
FocusManager.instance.focusedId,
|
|
451
|
+
QUICK_BRICK_CONTENT
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private landFocusToWithoutScrolling = (id) => {
|
|
456
|
+
if (id) {
|
|
457
|
+
// set focus on selected menu item
|
|
458
|
+
const direction = undefined;
|
|
459
|
+
|
|
460
|
+
const context: FocusManager.FocusContext =
|
|
461
|
+
contextWithoutScrolling("back");
|
|
462
|
+
|
|
463
|
+
logger.log({ message: "landFocusToWithoutScrolling", data: { id } });
|
|
464
|
+
|
|
465
|
+
this.setFocus(id, direction, context);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// Move focus to appropriate top navigation tab with context
|
|
470
|
+
focusOnSelectedTab(index: number): void {
|
|
471
|
+
const selectedTabId = findSelectedTabId(this.tree, index);
|
|
472
|
+
|
|
473
|
+
// Set focus with back button context to tabs-menu
|
|
474
|
+
this.landFocusToWithoutScrolling(selectedTabId);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Move focus to appropriate top navigation tab with context
|
|
478
|
+
focusOnSelectedTopMenuItem(index: number, sectionKey: string): void {
|
|
479
|
+
const selectedMenuItemId = findSelectedMenuId(this.tree, {
|
|
480
|
+
index,
|
|
481
|
+
sectionKey,
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Set focus with back button context to top-menu
|
|
485
|
+
this.landFocusToWithoutScrolling(selectedMenuItemId);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
isTabsScreenContentFocused(): boolean {
|
|
489
|
+
return isTabsScreenContentFocused(
|
|
490
|
+
this.tree,
|
|
491
|
+
FocusManager.instance.focusedId
|
|
492
|
+
);
|
|
493
|
+
}
|
|
420
494
|
}
|
|
421
495
|
|
|
422
496
|
export const focusManager = FocusManager.getInstance();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isNil, pathOr } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
QUICK_BRICK_CONTENT,
|
|
5
|
+
QUICK_BRICK_NAVBAR,
|
|
6
|
+
QUICK_BRICK_NAVBAR_SECTIONS,
|
|
7
|
+
} from "@applicaster/quick-brick-core/const";
|
|
8
|
+
|
|
9
|
+
const isNavBar = (node) => QUICK_BRICK_NAVBAR === node?.id;
|
|
10
|
+
const isContent = (node) => QUICK_BRICK_CONTENT === node?.id;
|
|
11
|
+
|
|
12
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER(we assume there is only one SCREEN_PICKER)
|
|
13
|
+
let screenPickerSelectorContainerId;
|
|
14
|
+
|
|
15
|
+
export const onRegisterScreenPickerSelectorContainer = (id) => {
|
|
16
|
+
screenPickerSelectorContainerId = id;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const onUnregisterScreenPickerSelectorContainer = (id) => {
|
|
20
|
+
// reset screenSelectorId on unregistration
|
|
21
|
+
if (screenPickerSelectorContainerId === id) {
|
|
22
|
+
screenPickerSelectorContainerId = undefined;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER
|
|
26
|
+
|
|
27
|
+
// SCREEN_PICKER_CONTENT_CONTAINER(we assume there is only one SCREEN_PICKER)
|
|
28
|
+
let screenPickerContentContainerId;
|
|
29
|
+
|
|
30
|
+
export const onRegisterScreenPickerContentContainer = (id) => {
|
|
31
|
+
screenPickerContentContainerId = id;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const onUnregisterScreenPickerContentContainer = (id) => {
|
|
35
|
+
// reset screenSelectorId on unregistration
|
|
36
|
+
if (screenPickerContentContainerId === id) {
|
|
37
|
+
screenPickerContentContainerId = undefined;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const isScreenPickerContentContainer = (node) =>
|
|
42
|
+
screenPickerContentContainerId === node?.id;
|
|
43
|
+
|
|
44
|
+
// SCREEN_PICKER_CONTENT_CONTAINER
|
|
45
|
+
|
|
46
|
+
export const findSelectedMenuId = (
|
|
47
|
+
focusableTree,
|
|
48
|
+
{ index, sectionKey }: { index: number; sectionKey: string }
|
|
49
|
+
) => {
|
|
50
|
+
const sectionName = QUICK_BRICK_NAVBAR_SECTIONS[sectionKey];
|
|
51
|
+
|
|
52
|
+
return pathOr(
|
|
53
|
+
undefined,
|
|
54
|
+
["children", index, "id"],
|
|
55
|
+
focusableTree.find(sectionName)
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const findSelectedTabId = (focusableTree, index: number): string => {
|
|
60
|
+
const screenSelectorContainerNode = focusableTree.find(
|
|
61
|
+
screenPickerSelectorContainerId
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const selectedTabId = screenSelectorContainerNode.children[index]?.id;
|
|
65
|
+
|
|
66
|
+
return selectedTabId;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const isTabsScreenContentFocused = (focusableTree, id) => {
|
|
70
|
+
const node = focusableTree.find(id);
|
|
71
|
+
|
|
72
|
+
if (isNil(node)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (isNavBar(node)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (isContent(node)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isScreenPickerContentContainer(node)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return isTabsScreenContentFocused(focusableTree, node.parentId);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const contextWithoutScrolling = (
|
|
92
|
+
source: FocusManager.FocusContext["source"]
|
|
93
|
+
): FocusManager.FocusContext => {
|
|
94
|
+
return {
|
|
95
|
+
source,
|
|
96
|
+
preserveScroll: true,
|
|
97
|
+
};
|
|
98
|
+
};
|
package/focusManager/utils.ts
CHANGED
|
@@ -4,11 +4,11 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
4
4
|
|
|
5
5
|
export const getFocusableId = (ref) => ref?.current?.props.id;
|
|
6
6
|
|
|
7
|
-
type Direction = "up" | "down" | "left" | "right";
|
|
8
|
-
|
|
9
7
|
const normalizeDirection = (direction) => direction.toLowerCase();
|
|
10
8
|
|
|
11
|
-
const checkDirection = (
|
|
9
|
+
const checkDirection = (
|
|
10
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
11
|
+
) => {
|
|
12
12
|
invariant(!isNilOrEmpty(direction), "direction should not be empty");
|
|
13
13
|
|
|
14
14
|
invariant(
|
|
@@ -17,19 +17,25 @@ const checkDirection = (direction: Direction) => {
|
|
|
17
17
|
);
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export const toFocusDirection = (
|
|
20
|
+
export const toFocusDirection = (
|
|
21
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
22
|
+
) => {
|
|
21
23
|
checkDirection(direction);
|
|
22
24
|
|
|
23
25
|
return `nextFocus${capitalize(normalizeDirection(direction))}`;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
export const isHorizontalDirection = (
|
|
28
|
+
export const isHorizontalDirection = (
|
|
29
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
30
|
+
) => {
|
|
27
31
|
checkDirection(direction);
|
|
28
32
|
|
|
29
33
|
return ["left", "right"].includes(normalizeDirection(direction));
|
|
30
34
|
};
|
|
31
35
|
|
|
32
|
-
export const isVerticalDirection = (
|
|
36
|
+
export const isVerticalDirection = (
|
|
37
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
38
|
+
) => {
|
|
33
39
|
checkDirection(direction);
|
|
34
40
|
|
|
35
41
|
return ["up", "down"].includes(normalizeDirection(direction));
|