@applicaster/zapp-react-native-utils 13.0.0-rc.12 → 13.0.0-rc.120

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 (183) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +196 -11
  4. package/actionsExecutor/consts.ts +4 -0
  5. package/alertUtils/alert.ts +148 -0
  6. package/alertUtils/index.ts +1 -148
  7. package/analyticsUtils/AnalyticPlayerListener.ts +18 -1
  8. package/analyticsUtils/__tests__/__snapshots__/analyticsManagerNoModule.test.js.snap +9 -9
  9. package/analyticsUtils/currentScreenProperities.ts +6 -4
  10. package/analyticsUtils/helpers/hooks.ts +1 -1
  11. package/appUtils/HooksManager/{Hook.js → Hook.ts} +39 -23
  12. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +10 -8
  13. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  14. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  15. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  16. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  17. package/appUtils/HooksManager/{index.js → index.ts} +124 -113
  18. package/appUtils/HooksManager/types.ts +119 -0
  19. package/appUtils/RiverFocusManager/index.js +17 -12
  20. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  21. package/appUtils/__tests__/allZappLocales.ts +79 -0
  22. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  23. package/appUtils/accessibilityManager/index.ts +42 -1
  24. package/appUtils/contextKeysManager/contextResolver.ts +66 -0
  25. package/appUtils/contextKeysManager/index.ts +2 -2
  26. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  27. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +9 -6
  28. package/appUtils/focusManager/index.ios.ts +14 -4
  29. package/appUtils/focusManager/index.ts +108 -69
  30. package/appUtils/focusManager/treeDataStructure/Tree/index.js +25 -3
  31. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  32. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  33. package/appUtils/focusManager/utils/enums.ts +4 -0
  34. package/appUtils/focusManager/utils/index.ts +5 -0
  35. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  36. package/appUtils/{index.js → index.ts} +1 -1
  37. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
  38. package/appUtils/keyCodes/__tests__/keyCodes.test.js +4 -4
  39. package/appUtils/keyCodes/{index.js → index.ts} +13 -7
  40. package/appUtils/keyCodes/keys/index.ts +3 -0
  41. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  42. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  43. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  44. package/appUtils/keyCodes/keys/keys.ts +15 -0
  45. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +4 -0
  46. package/appUtils/keyCodes/keysByPlatform.ts +8 -0
  47. package/appUtils/keyInputHandler/KeyInputHandler.ts +68 -0
  48. package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +31 -0
  49. package/appUtils/orientationHelper.ts +11 -13
  50. package/appUtils/platform/const.ts +14 -0
  51. package/appUtils/platform/platformUtils.ts +47 -18
  52. package/appUtils/playerManager/index.ts +1 -1
  53. package/appUtils/playerManager/player.ts +42 -18
  54. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  55. package/appUtils/playerManager/playerNative.ts +18 -2
  56. package/appUtils/playerManager/usePlayerControllerSetup.tsx +3 -3
  57. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  58. package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
  59. package/cellUtils/index.ts +9 -5
  60. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  61. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  62. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  63. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  64. package/componentsUtils/index.ts +39 -0
  65. package/dateUtils/index.ts +19 -0
  66. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  67. package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
  68. package/equalUtils/index.ts +49 -30
  69. package/focusManager/FocusManager.ts +14 -2
  70. package/focusManager/index.ts +23 -4
  71. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +4 -4
  72. package/functionUtils/index.ts +61 -19
  73. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  74. package/idleUtils/index.ts +1 -1
  75. package/idleUtils/withTimeout.ts +15 -2
  76. package/index.d.ts +0 -12
  77. package/localizationUtils/index.ts +8 -13
  78. package/logger/const.ts +9 -67
  79. package/manifestUtils/__tests__/createConfig.test.js +16 -16
  80. package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
  81. package/manifestUtils/defaultManifestConfigurations/player.js +9 -3
  82. package/manifestUtils/fonts/index.js +5 -6
  83. package/manifestUtils/keys.js +27 -2
  84. package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
  85. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +875 -0
  86. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
  87. package/modalState/__tests__/index.test.ts +51 -0
  88. package/modalState/index.ts +33 -7
  89. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +7 -6
  90. package/navigationUtils/__tests__/itemTypes.test.js +2 -2
  91. package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
  92. package/navigationUtils/index.ts +20 -9
  93. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  94. package/numberUtils/index.ts +11 -5
  95. package/package.json +5 -10
  96. package/playerUtils/configurationGenerator.ts +9 -11
  97. package/reactHooks/advertising/index.ts +5 -5
  98. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  99. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +6 -8
  100. package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
  101. package/reactHooks/cell-click/__tests__/index.test.js +10 -2
  102. package/reactHooks/cell-click/index.ts +7 -1
  103. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +4 -4
  104. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -11
  105. package/reactHooks/feed/useBatchLoading.ts +10 -12
  106. package/reactHooks/feed/useFeedLoader.tsx +18 -9
  107. package/reactHooks/feed/usePipesCacheReset.ts +5 -5
  108. package/reactHooks/flatList/__tests__/index.test.tsx +30 -21
  109. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  110. package/reactHooks/layout/__tests__/index.test.tsx +10 -10
  111. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +14 -28
  112. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  113. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  114. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  115. package/reactHooks/navigation/__tests__/index.test.tsx +6 -21
  116. package/reactHooks/navigation/index.ts +41 -240
  117. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +23 -0
  118. package/reactHooks/navigation/useGetNavBarTopBorderWidth.ts +14 -0
  119. package/reactHooks/navigation/useGetTabBarHeight.ts +10 -0
  120. package/reactHooks/navigation/useIsScreenActive.ts +17 -0
  121. package/reactHooks/navigation/useNavigationPluginData.ts +15 -0
  122. package/reactHooks/navigation/useNavigationType.ts +15 -0
  123. package/reactHooks/navigation/usePathname.ts +4 -0
  124. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  125. package/reactHooks/navigation/useRoute.ts +98 -0
  126. package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
  127. package/reactHooks/player/TVSeekControlller/ISeekController.ts +32 -0
  128. package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +71 -0
  129. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +258 -0
  130. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +53 -0
  131. package/reactHooks/player/__tests__/{useAutoSeek.test.tsx → useAutoSeek._test.tsx} +2 -3
  132. package/reactHooks/player/const.ts +0 -4
  133. package/reactHooks/player/index.ts +0 -6
  134. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  135. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  136. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  137. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  138. package/reactHooks/useListenEventBusEvent.ts +1 -1
  139. package/reactHooks/usePluginConfiguration.ts +1 -1
  140. package/reactHooks/useSubscriberFor.ts +4 -3
  141. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  142. package/reactUtils/__tests__/reactUtils.test.js +1 -37
  143. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  144. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +13 -79
  145. package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +2 -2
  146. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  147. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  148. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  149. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  150. package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
  151. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  152. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  153. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  154. package/reactUtils/createContext/helpers.ts +6 -1
  155. package/reactUtils/createContext/index.ts +11 -25
  156. package/reactUtils/index.ts +9 -25
  157. package/screenState/index.ts +24 -10
  158. package/services/js2native.ts +673 -0
  159. package/testUtils/index.tsx +0 -10
  160. package/theme/__mocks__/index.ts +4 -0
  161. package/theme/index.ts +1 -1
  162. package/time/BackgroundTimer.ts +55 -0
  163. package/time/Timer.ts +9 -6
  164. package/types.ts +1 -0
  165. package/utils/README.md +30 -0
  166. package/utils/chunk.ts +5 -0
  167. package/utils/index.ts +5 -0
  168. package/utils/times.ts +5 -0
  169. package/zappFrameworkUtils/localStorageHelper.ts +6 -0
  170. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  171. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  172. package/zappFrameworkUtils/types.ts +11 -0
  173. package/appUtils/keyCodes/keys.ios.js +0 -46
  174. package/reactHooks/player/useAutoSeek.tsx +0 -87
  175. package/reactHooks/player/useSeek.tsx +0 -66
  176. package/reactHooks/player/useTapSeek.tsx +0 -58
  177. package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
  178. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  179. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  180. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  181. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  182. /package/domUtils/{logger.js → logger.ts} +0 -0
  183. /package/reactHooks/player/__tests__/{useTapSeek.test.ts → useTapSeek._test.ts} +0 -0
@@ -0,0 +1,119 @@
1
+ import { SubscriberObj } from "../../functionUtils";
2
+ import { HOOKS_EVENTS } from "./constants";
3
+
4
+ export interface HookConfiguration {}
5
+
6
+ /* existing Hook Plugn props: sample */
7
+
8
+ /*
9
+ interface _HookModulePlugin {
10
+ Component:
11
+ | React.FC<HookPluginProps>
12
+ | React.Component<HookPluginProps, any>
13
+ | React.ReactNode;
14
+ ModalContainer?: React.FC<ModalProps> | React.Component<ModalProps, any>;
15
+ skipHook?: (payload: ZappRiver | ZappEntry) => boolean;
16
+ presentFullScreen: boolean;
17
+ showNavBar?: boolean;
18
+ isFlowBlocker: (() => boolean) | boolean; // narrow this
19
+ hasPlayerHook?: boolean;
20
+ name: string;
21
+ runInBackground?: (
22
+ item: HookPluginProps["payload"],
23
+ callback: hookCallback,
24
+ hookPlugin: HookScreenData,
25
+ presentUI: (payload?: HookPluginProps["payload"]) => void
26
+ ) => any;
27
+ }
28
+ */
29
+
30
+ //* Derived from usage */
31
+ export interface HookModule {
32
+ ModalContainer?: React.ComponentType<any>;
33
+ Component: React.ComponentType<any>;
34
+ presentFullScreen: boolean;
35
+ run?: (
36
+ arg0: unknown,
37
+ callback: () => void,
38
+ configuration: HookConfiguration
39
+ ) => void; // not sure about optional parameter
40
+ hasPlayerHook?: boolean;
41
+ configuration?: HookConfiguration;
42
+ isFlowBlocker: () => boolean;
43
+ skipHook?: (payload?: ZappRiver | ZappEntry) => boolean;
44
+ runInBackground?: (
45
+ arg0: unknown,
46
+ callback: () => void,
47
+ hookPlugin: Hook,
48
+ presentUI: (payload?: HookPluginProps["payload"]) => void
49
+ ) => void;
50
+ name: string;
51
+ showNavBar?: boolean; // unsure
52
+ }
53
+
54
+ export type HookManagerArgs = {
55
+ rivers: Record<string, ZappRiver>;
56
+ plugins: ZappPlugin[];
57
+ targetScreen: ZappRiver;
58
+ startUpHooksData?: {
59
+ startUpHooks?: unknown[] | "in_process";
60
+ setStartUpHooks?: (arg0: string) => void;
61
+ };
62
+ };
63
+
64
+ export interface HookManager {
65
+ subscriber: SubscriberObj;
66
+ presentScreenHook: (
67
+ hook: Hook,
68
+ payload: unknown,
69
+ callback: (...any) => void
70
+ ) => void;
71
+ executeHook: (
72
+ hook: Hook,
73
+ payload: unknown,
74
+ callback: (...any) => void
75
+ ) => void;
76
+ handleHooks: (payload: unknown) => void;
77
+ runInBackground: (
78
+ hook: Hook,
79
+ payload: unknown,
80
+ callback: (...any) => void,
81
+ presentUI: (payload?: HookPluginProps["payload"]) => void
82
+ ) => void;
83
+ }
84
+
85
+ export type HookIniObj = {
86
+ hook: HookModule & {
87
+ module: HookModule;
88
+ general: unknown;
89
+ screen_id?: string;
90
+ identifier?: string;
91
+ weight?: number | string;
92
+ };
93
+ hooks: Hook<any>[];
94
+ manager: HookManager;
95
+ };
96
+
97
+ export interface Hook<T extends HookModule = HookModule> {
98
+ manager: HookManager;
99
+ lastHook: boolean;
100
+ state: number;
101
+ module: T;
102
+ screen_id: string;
103
+ identifier: string;
104
+ configuration: T["configuration"];
105
+ setStateAndNotify(
106
+ event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
107
+ opts: {
108
+ error?: typeof Error;
109
+ route?: string;
110
+ hookPlugin: Hook<T>;
111
+ payload: unknown;
112
+ }
113
+ );
114
+ general?: {
115
+ transition_type: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS];
116
+ allow_screen_plugin_presentation: boolean;
117
+ is_flow_blocker: boolean;
118
+ };
119
+ }
@@ -26,7 +26,7 @@ export const riverFocusManager = (function () {
26
26
  /**
27
27
  * Retrieve screen focus data by id
28
28
  *
29
- * @param {String} screenFocusableGroupId Id that was used to save screen data.
29
+ * @param {{screenFocusableGroupId: string}} screenFocusableGroupId Unique Id of the screen from layout.json
30
30
  *
31
31
  */
32
32
  function screenFocusableData({ screenFocusableGroupId }) {
@@ -36,8 +36,9 @@ export const riverFocusManager = (function () {
36
36
  /**
37
37
  * Clear screen data for specific screen
38
38
  *
39
- * @param {String} screenId Unique Id of the screen from layout.json
40
- * @param {boolean} isInsideContainer If this screen a screen picker child
39
+ * @param {{ screenId: string, isInsideContainer: boolean }}
40
+ * screenId Unique Id of the screen from layout.json
41
+ * isInsideContainer If this screen a screen picker child
41
42
  *
42
43
  */
43
44
  function clearScreenData({ screenId, isInsideContainer }) {
@@ -60,9 +61,13 @@ export const riverFocusManager = (function () {
60
61
  /**
61
62
  * Focus on selected items
62
63
  *
63
- * @param {String} screenFocusableGroupId Top group id that was saved as screenn
64
- * @param {String} screenFocusedOnItem focusable item to focus
65
- * @param {object} history navigator history object
64
+ * @param {{
65
+ * screenFocusableGroupId: string,
66
+ * screenFocusedOnItem: () => void,
67
+ * previousAction: QuickBrickNavigationActionType,
68
+ * isDeepLink: boolean }} object contains data for focus
69
+ * - `screenFocusedOnItem` focusable item to focus
70
+ * - `previousActionhistory` navigator history object
66
71
  *
67
72
  */
68
73
  function focusOnSelectedItem({
@@ -115,15 +120,15 @@ export const riverFocusManager = (function () {
115
120
 
116
121
  /**
117
122
  * Create unique key that will be used for save focused group data inside specific screen
118
- *
119
- * @param {String} screenId Unique Id of the screen from layout.json
120
- * @param {boolean} isInsideContainer If this screen a screen picker child
123
+ * @param {{ screenId: string, isInsideContainer: boolean }}
124
+ * screenId Unique Id of the screen from layout.json
125
+ * isInsideContainer If this screen a screen picker child
121
126
  *
122
127
  */
123
128
  function screenFocusableGroupId({ screenId, isInsideContainer }) {
124
- return R.isNil(isInsideContainer)
125
- ? `RiverFocusableGroup-${screenId}`
126
- : `RiverFocusableGroup-${screenId}-isInsideContainer`;
129
+ return `RiverFocusableGroup-${screenId}${
130
+ R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
131
+ }`;
127
132
  }
128
133
 
129
134
  return {
@@ -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
+ });
@@ -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,
@@ -0,0 +1,66 @@
1
+ import { ContextKeysManager } from "./index";
2
+ import * as R from "ramda";
3
+
4
+ interface IResolver {
5
+ resolve: (string) => Promise<string | number | object>;
6
+ }
7
+
8
+ export class EntryResolver implements IResolver {
9
+ entry: ZappEntry;
10
+
11
+ constructor(entry: ZappEntry) {
12
+ this.entry = entry;
13
+ }
14
+
15
+ async resolve(key: string) {
16
+ if (!key || key.length === 0) {
17
+ return this.entry;
18
+ }
19
+
20
+ return R.view(R.lensPath(key.split(".")), this.entry);
21
+ }
22
+ }
23
+
24
+ export class ContextResolver implements IResolver {
25
+ resolve = async (compositeKey: string) =>
26
+ ContextKeysManager.instance.getKey(compositeKey);
27
+ }
28
+
29
+ export const resolveObjectValues = async (
30
+ data: Record<string, any>,
31
+ resolvers: Record<string, IResolver> = null
32
+ ) => {
33
+ const entries = Object.entries(data);
34
+
35
+ const exResolvers = { ctx: new ContextResolver(), ...resolvers };
36
+
37
+ const resolvedEntries = await Promise.all(
38
+ entries.map(async ([key, value]) => {
39
+ if (typeof value !== "string") {
40
+ return [key, value];
41
+ }
42
+
43
+ if (!value.startsWith("@")) {
44
+ return [key, value];
45
+ }
46
+
47
+ const regex = /@{([^/]+)\/([^}]*)}/;
48
+
49
+ const match = (value as string).match(regex);
50
+
51
+ if (match) {
52
+ const contextResolverName = match[1];
53
+ const compositeKey = match[2];
54
+
55
+ const resolver = exResolvers[contextResolverName] || exResolvers.ctx;
56
+ const resolvedValue = await resolver.resolve(compositeKey);
57
+
58
+ return [key, resolvedValue];
59
+ }
60
+
61
+ return [key, value];
62
+ })
63
+ );
64
+
65
+ return Object.fromEntries(resolvedEntries);
66
+ };
@@ -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(".")
@@ -1,14 +1,15 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`focusManager should be defined 1`] = `
4
- Object {
4
+ {
5
5
  "blur": [Function],
6
6
  "disableFocus": [Function],
7
7
  "enableFocus": [Function],
8
+ "findPreferredFocusChild": [Function],
8
9
  "focusableTree": Tree {
9
10
  "loadingCounter": 0,
10
- "root": Object {
11
- "children": Array [],
11
+ "root": {
12
+ "children": [],
12
13
  "component": null,
13
14
  "id": "root",
14
15
  "lastFocusedItem": null,
@@ -28,6 +29,7 @@ Object {
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],
@@ -39,12 +41,12 @@ Object {
39
41
  `;
40
42
 
41
43
  exports[`focusManagerIOS should be defined 1`] = `
42
- Object {
44
+ {
43
45
  "focus": [Function],
44
46
  "focusableTree": Tree {
45
47
  "loadingCounter": 0,
46
- "root": Object {
47
- "children": Array [],
48
+ "root": {
49
+ "children": [],
48
50
  "component": null,
49
51
  "id": "root",
50
52
  "lastFocusedItem": null,
@@ -59,6 +61,7 @@ Object {
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
  })();