@applicaster/zapp-react-native-utils 13.0.0-alpha.4244205068 → 13.0.0-alpha.4302300656

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.
Files changed (132) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +202 -15
  4. package/actionsExecutor/consts.ts +4 -0
  5. package/analyticsUtils/currentScreenProperities.ts +6 -4
  6. package/appUtils/HooksManager/Hook.ts +6 -2
  7. package/appUtils/HooksManager/index.ts +3 -1
  8. package/appUtils/HooksManager/types.ts +5 -2
  9. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  10. package/appUtils/__tests__/allZappLocales.ts +79 -0
  11. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  12. package/appUtils/accessibilityManager/const.ts +18 -0
  13. package/appUtils/accessibilityManager/index.ts +42 -1
  14. package/appUtils/contextKeysManager/contextResolver.ts +7 -14
  15. package/appUtils/contextKeysManager/index.ts +2 -2
  16. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  17. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  18. package/appUtils/focusManager/index.ios.ts +14 -4
  19. package/appUtils/focusManager/index.ts +24 -12
  20. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  21. package/appUtils/focusManager/utils/index.ts +5 -0
  22. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  23. package/appUtils/keyCodes/index.ts +11 -7
  24. package/appUtils/localizationsHelper.ts +31 -0
  25. package/appUtils/orientationHelper.ts +11 -13
  26. package/appUtils/platform/const.ts +14 -0
  27. package/appUtils/platform/platformUtils.ts +47 -4
  28. package/appUtils/playerManager/index.ts +1 -1
  29. package/appUtils/playerManager/player.ts +26 -14
  30. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  31. package/appUtils/playerManager/playerNative.ts +18 -3
  32. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  33. package/cellUtils/index.ts +9 -5
  34. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  35. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  36. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  37. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  38. package/componentsUtils/index.ts +39 -0
  39. package/dateUtils/index.ts +19 -0
  40. package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
  41. package/equalUtils/index.ts +49 -30
  42. package/focusManager/FocusManager.ts +14 -2
  43. package/focusManager/index.ts +23 -4
  44. package/functionUtils/index.ts +46 -8
  45. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  46. package/idleUtils/index.ts +1 -1
  47. package/idleUtils/withTimeout.ts +15 -2
  48. package/index.d.ts +0 -12
  49. package/localizationUtils/index.ts +8 -13
  50. package/logger/const.ts +9 -67
  51. package/manifestUtils/__tests__/createConfig.test.js +0 -2
  52. package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
  53. package/manifestUtils/defaultManifestConfigurations/player.js +9 -3
  54. package/manifestUtils/fonts/index.js +5 -6
  55. package/manifestUtils/index.js +2 -0
  56. package/manifestUtils/keys.js +27 -2
  57. package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
  58. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +874 -0
  59. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
  60. package/modalState/__tests__/index.test.ts +51 -0
  61. package/modalState/index.ts +32 -2
  62. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
  63. package/navigationUtils/index.ts +6 -4
  64. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  65. package/numberUtils/index.ts +11 -5
  66. package/package.json +4 -10
  67. package/playerUtils/configurationGenerator.ts +9 -11
  68. package/playerUtils/index.ts +23 -0
  69. package/reactHooks/advertising/index.ts +5 -5
  70. package/reactHooks/app/useAppState.ts +2 -2
  71. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +5 -7
  72. package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
  73. package/reactHooks/cell-click/__tests__/index.test.js +5 -0
  74. package/reactHooks/cell-click/index.ts +7 -1
  75. package/reactHooks/feed/useBatchLoading.ts +10 -12
  76. package/reactHooks/feed/useFeedLoader.tsx +18 -9
  77. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  78. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  79. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  80. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  81. package/reactHooks/navigation/__tests__/index.test.tsx +6 -17
  82. package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +2 -4
  83. package/reactHooks/navigation/index.ts +13 -23
  84. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +10 -3
  85. package/reactHooks/navigation/useNavigationPluginData.ts +8 -4
  86. package/reactHooks/navigation/useNavigationType.ts +4 -2
  87. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  88. package/reactHooks/navigation/useRoute.ts +4 -6
  89. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  90. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  91. package/reactHooks/state/README.md +79 -0
  92. package/reactHooks/state/ZStoreProvider.tsx +71 -0
  93. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
  94. package/reactHooks/state/index.ts +2 -0
  95. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  96. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  97. package/reactHooks/useListenEventBusEvent.ts +1 -1
  98. package/reactHooks/usePluginConfiguration.ts +1 -1
  99. package/reactHooks/useSubscriberFor.ts +4 -3
  100. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  101. package/reactUtils/__tests__/reactUtils.test.js +1 -19
  102. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  103. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +6 -72
  104. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  105. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  106. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  107. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  108. package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
  109. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  110. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  111. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  112. package/reactUtils/createContext/helpers.ts +6 -1
  113. package/reactUtils/createContext/index.ts +11 -25
  114. package/reactUtils/index.ts +9 -11
  115. package/screenState/index.ts +24 -10
  116. package/services/js2native.ts +673 -0
  117. package/testUtils/index.tsx +0 -10
  118. package/theme/index.ts +1 -1
  119. package/time/BackgroundTimer.ts +55 -0
  120. package/time/Timer.ts +9 -6
  121. package/typeGuards/index.ts +3 -0
  122. package/types.ts +1 -0
  123. package/utils/README.md +30 -0
  124. package/utils/chunk.ts +5 -0
  125. package/utils/index.ts +5 -0
  126. package/utils/times.ts +5 -0
  127. package/zappFrameworkUtils/localStorageHelper.ts +38 -10
  128. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  129. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  130. package/zappFrameworkUtils/types.ts +11 -0
  131. package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
  132. /package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
@@ -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
+ });
@@ -47,4 +47,22 @@ export const BUTTON_ACCESSIBILITY_KEYS = {
47
47
  label: "accessibility_fullscreen_label",
48
48
  hint: "accessibility_fullscreen_hint",
49
49
  },
50
+ // EPG-specific buttons
51
+ now: {
52
+ label: "accessibility_now_label",
53
+ hint: "accessibility_now_hint",
54
+ },
55
+ day: {
56
+ label: "accessibility_day_label",
57
+ hint: "accessibility_day_hint",
58
+ },
59
+ program: {
60
+ label: "accessibility_program_label",
61
+ hint: "accessibility_program_hint",
62
+ },
63
+ // Menu-specific buttons
64
+ menu_item: {
65
+ label: "accessibility_menu_item_label",
66
+ hint: "accessibility_menu_item_hint",
67
+ },
50
68
  } as const;
@@ -6,6 +6,9 @@ import { AccessibilityRole } from "react-native";
6
6
 
7
7
  export class AccessibilityManager {
8
8
  private static _instance: AccessibilityManager | null = null;
9
+ private headingTimeout: NodeJS.Timeout | null = null;
10
+ private WORDS_PER_MINUTE = 160;
11
+ private MINIMUM_PAUSE = 500;
9
12
  private state$ = new BehaviorSubject<AccessibilityState>({
10
13
  screenReaderEnabled: false,
11
14
  reduceMotionEnabled: false,
@@ -20,6 +23,7 @@ export class AccessibilityManager {
20
23
 
21
24
  private ttsManager = TTSManager.getInstance();
22
25
  private localizations: { [key: string]: string } = {};
26
+ private headingQueue: string[] = [];
23
27
 
24
28
  private constructor() {}
25
29
 
@@ -52,6 +56,28 @@ export class AccessibilityManager {
52
56
  return this.state$.asObservable();
53
57
  }
54
58
 
59
+ /** Calculates the reading time for a given text
60
+ * This method is a bit of a hack because we don't have a callback, or promise from VIZIO API
61
+ * @param text - The text to calculate the reading time for
62
+ * @returns The reading time in milliseconds
63
+ */
64
+ private calculateReadingTime(text: string): number {
65
+ const words = text.trim().split(/\s+/).length;
66
+
67
+ return Math.max(
68
+ this.MINIMUM_PAUSE,
69
+ (words / this.WORDS_PER_MINUTE) * 60 * 1000
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Adds a heading to the queue, headings will be read before the next text
75
+ * Each heading will be read once and removed from the queue
76
+ */
77
+ public addHeading(heading: string) {
78
+ this.headingQueue.push(heading);
79
+ }
80
+
55
81
  /**
56
82
  * text you want to be read, if you want to use localized text pass keyOfLocalizedText instead
57
83
  * keyOfLocalizedText is the key to the localized text
@@ -85,7 +111,22 @@ export class AccessibilityManager {
85
111
  textToRead = localizedMessage;
86
112
  }
87
113
 
88
- this.ttsManager && this.ttsManager.readText(textToRead);
114
+ if (this.headingQueue.length > 0) {
115
+ const heading = this.headingQueue.shift()!;
116
+ this.ttsManager?.readText(heading);
117
+
118
+ if (this.headingTimeout) {
119
+ clearTimeout(this.headingTimeout);
120
+ }
121
+
122
+ const pauseTime = this.calculateReadingTime(heading);
123
+
124
+ this.headingTimeout = setTimeout(() => {
125
+ this.ttsManager?.readText(textToRead);
126
+ }, pauseTime);
127
+ } else {
128
+ this.ttsManager?.readText(textToRead);
129
+ }
89
130
 
90
131
  this.announcements$.next({
91
132
  message: textToRead,
@@ -1,12 +1,6 @@
1
- import { createLogger } from "../../logger";
2
1
  import { ContextKeysManager } from "./index";
3
2
  import * as R from "ramda";
4
3
 
5
- const { log_error } = createLogger({
6
- subsystem: "contextResolver",
7
- category: "General",
8
- });
9
-
10
4
  interface IResolver {
11
5
  resolve: (string) => Promise<string | number | object>;
12
6
  }
@@ -42,12 +36,16 @@ export const resolveObjectValues = async (
42
36
 
43
37
  const resolvedEntries = await Promise.all(
44
38
  entries.map(async ([key, value]) => {
45
- const regex = /@{([^/]+)\/([^}]*)}/;
46
-
47
39
  if (typeof value !== "string") {
48
40
  return [key, value];
49
41
  }
50
42
 
43
+ if (!value.startsWith("@")) {
44
+ return [key, value];
45
+ }
46
+
47
+ const regex = /@{([^/]+)\/([^}]*)}/;
48
+
51
49
  const match = (value as string).match(regex);
52
50
 
53
51
  if (match) {
@@ -60,12 +58,7 @@ export const resolveObjectValues = async (
60
58
  return [key, resolvedValue];
61
59
  }
62
60
 
63
- log_error("resolveObjectValues: invalid context string", {
64
- key,
65
- value,
66
- });
67
-
68
- return [key, null];
61
+ return [key, value];
69
62
  })
70
63
  );
71
64
 
@@ -16,12 +16,12 @@ import {
16
16
 
17
17
  export { StorageLevel };
18
18
 
19
- type KeyNameObj = {
19
+ export type KeyNameObj = {
20
20
  namespace: string;
21
21
  key: string;
22
22
  };
23
23
 
24
- type KeyName = string | KeyNameObj;
24
+ export type KeyName = string | KeyNameObj;
25
25
 
26
26
  type ParsedKeyAndNamespace = {
27
27
  namespace?: string;
@@ -1,10 +1,11 @@
1
1
  import * as R from "ramda";
2
2
  import { DEFAULT_NAMESPACE } from "../consts";
3
+ import { KeyName, KeyNameObj } from "../index";
3
4
 
4
5
  const lastDotRegex = /\.([^.]+)$/;
5
6
  const splitByLastDot = R.compose(R.init, R.split(lastDotRegex));
6
7
 
7
- export function getNamespaceAndKey(namespacedKey) {
8
+ export function getNamespaceAndKey(namespacedKey: KeyName): KeyNameObj {
8
9
  if (typeof namespacedKey !== "string") return namespacedKey;
9
10
 
10
11
  const namespacedKeyProps = namespacedKey.includes(".")
@@ -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": {
@@ -28,6 +29,7 @@ exports[`focusManager should be defined 1`] = `
28
29
  "moveFocus": [Function],
29
30
  "on": [Function],
30
31
  "press": [Function],
32
+ "pressIn": [Function],
31
33
  "pressOut": [Function],
32
34
  "recoverFocus": [Function],
33
35
  "register": [Function],
@@ -59,6 +61,7 @@ exports[`focusManagerIOS should be defined 1`] = `
59
61
  "getCurrentGroup": [Function],
60
62
  "getGroupById": [Function],
61
63
  "getGroupRootById": [Function],
64
+ "getPreferredFocusChild": [Function],
62
65
  "invokeHandler": [Function],
63
66
  "isGroupItemFocused": [Function],
64
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 = R.compose(
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
  })();
@@ -13,6 +13,7 @@ import {
13
13
  import { subscriber } from "../../functionUtils";
14
14
  import { coreLogger } from "../../logger";
15
15
  import { ACTION } from "./utils/enums";
16
+
16
17
  const logger = coreLogger.addSubsystem("focusManager");
17
18
 
18
19
  const isFocusEnabled = (focusableItem): boolean => {
@@ -325,8 +326,6 @@ export const focusManager = (function () {
325
326
  },
326
327
  });
327
328
 
328
- currentFocusNode = focusCandidate;
329
-
330
329
  focusableItem && setFocus(focusCandidate.id, null);
331
330
 
332
331
  return { success: true };
@@ -335,15 +334,14 @@ export const focusManager = (function () {
335
334
  return { success: false };
336
335
  }
337
336
 
338
- function treeLoaded(val, node) {
339
- logger.log({
340
- message: "treeLoaded",
341
- data: {
342
- val,
343
- node,
344
- currentFocusNode,
345
- },
346
- });
337
+ function treeLoaded(_val, _node) {}
338
+
339
+ function pressIn() {
340
+ const currentFocusable = getCurrentFocus();
341
+
342
+ if (currentFocusable) {
343
+ currentFocusable.pressIn(null);
344
+ }
347
345
  }
348
346
 
349
347
  /**
@@ -477,7 +475,7 @@ export const focusManager = (function () {
477
475
  function isCurrentFocusOnTheTopScreen() {
478
476
  const routes = R.pathOr([], ["root", "children"], focusableTree);
479
477
 
480
- if (routes.length <= 1) {
478
+ if (currentFocusNode && routes.length <= 1) {
481
479
  // there is only one or zero routes
482
480
  return true;
483
481
  }
@@ -536,6 +534,18 @@ export const focusManager = (function () {
536
534
 
537
535
  const { on, invokeHandler, removeHandler } = eventHandler;
538
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
+
539
549
  /**
540
550
  * this is the list of the functions available externally
541
551
  * when importing the focus manager
@@ -553,6 +563,7 @@ export const focusManager = (function () {
553
563
  invokeHandler,
554
564
  removeHandler,
555
565
  longPress,
566
+ pressIn,
556
567
  pressOut,
557
568
  enableFocus,
558
569
  setInitialFocus,
@@ -564,5 +575,6 @@ export const focusManager = (function () {
564
575
  isGroupItemFocused,
565
576
  recoverFocus,
566
577
  isCurrentFocusOnTheTopScreen,
578
+ findPreferredFocusChild,
567
579
  };
568
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
+ );
@@ -1,8 +1,8 @@
1
1
  import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
2
- import { find, last, startsWith, pathOr } from "ramda";
2
+ import { find, last, pathOr, startsWith } from "ramda";
3
3
  import {
4
- QUICK_BRICK_NAVBAR,
5
4
  QUICK_BRICK_CONTENT,
5
+ QUICK_BRICK_NAVBAR,
6
6
  } from "@applicaster/quick-brick-core/const";
7
7
 
8
8
  // run check each 300 ms
@@ -66,7 +66,8 @@ export const getContentNode = (focusableTree) => {
66
66
  const content = find(
67
67
  (child) =>
68
68
  startsWith(QUICK_BRICK_CONTENT, child.id) ||
69
- startsWith("player", child.id),
69
+ startsWith("player", child.id) ||
70
+ startsWith("/hooks", child?.parent?.id), // For startup hooks case
70
71
  getActiveScreenChildren(focusableTree)
71
72
  );
72
73
 
@@ -1,5 +1,3 @@
1
- import * as R from "ramda";
2
-
3
1
  // more keys can be added here. Simply make sure
4
2
  // the key matches the code value
5
3
 
@@ -34,12 +32,18 @@ export function keyCode(key) {
34
32
  keyCode(keyEvent).matchesAny("Enter", "Backspace", KEYS.ArrowLeft, ...)
35
33
  */
36
34
 
37
- const matches = R.compose(
38
- R.either(R.eqProps("code", key), R.eqProps("keyCode", key)),
39
- R.when(R.is(String), R.prop(R.__, KEYS))
40
- );
35
+ const matches = (compareKey) => {
36
+ // If compareKey is a string, look it up in KEYS object
37
+ const keyToCompare =
38
+ typeof compareKey === "string" ? KEYS[compareKey] : compareKey;
39
+
40
+ // Compare either code or keyCode properties
41
+ return (
42
+ keyToCompare?.code === key.code || keyToCompare?.keyCode === key.keyCode
43
+ );
44
+ };
41
45
 
42
- const matchesAny = (...args) => R.any(matches, args);
46
+ const matchesAny = (...args) => args.some(matches);
43
47
 
44
48
  const direction = () =>
45
49
  matchesAny(...ARROW_KEYS) ? directionHelper(key) : null;
@@ -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,
@@ -1,8 +1,8 @@
1
- /// <reference types="@types/react-native" />
2
1
  import * as ReactNative from "react-native";
3
- import { isTV, platformSelect } from "../reactUtils";
4
2
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
3
+
4
+ import { isTV, platformSelect } from "../reactUtils";
5
+ import { useIsTablet } from "../reactHooks";
6
6
 
7
7
  import {
8
8
  QUICK_BRICK_EVENTS,
@@ -121,8 +121,15 @@ export const removeOrientationChangeListener = (listener: any): void => {
121
121
  */
122
122
  export const isOrientationCompatible = ({
123
123
  orientation,
124
- layoutData: { width, height },
124
+ layoutData: { width, height, isTablet, isTabletPortrait },
125
125
  }) => {
126
+ // We count portrait as compatible, because if default in zapp for mobile layout
127
+ // We count landscape as compatible, because if isTabletPortrait is false,
128
+ // it defaults for device
129
+ if (isTablet && !isTabletPortrait) {
130
+ return true;
131
+ }
132
+
126
133
  const isLandscape = width > height;
127
134
 
128
135
  if (
@@ -146,15 +153,6 @@ export const isOrientationCompatible = ({
146
153
  return true;
147
154
  };
148
155
 
149
- export const useIsOrientationCompatible = (orientation) => {
150
- const { height, width } = ReactNative.useWindowDimensions();
151
-
152
- return isOrientationCompatible({
153
- orientation,
154
- layoutData: { width, height },
155
- });
156
- };
157
-
158
156
  /**
159
157
  * Determine final screen orientation based on device type,
160
158
  * settings and orientation value provided by screen data settings
@@ -23,3 +23,17 @@ export const PLATFORMS = {
23
23
  export const PLATFORM_KEYS = {
24
24
  deviceClosedCaptioningEnabled: "device_closed_captioning_enabled",
25
25
  };
26
+
27
+ export enum ZappPlatform {
28
+ Android = "android",
29
+ AndroidTV = "android_tv",
30
+ AmazonFireTV = "amazon",
31
+ iOS = "ios",
32
+ tvOS = "tvos",
33
+ Roku = "roku",
34
+ Tizen = "tizen",
35
+ Web = "web",
36
+ WebOS = "webos",
37
+ Vizio = "vizio",
38
+ Unknown = "unknown",
39
+ }