@applicaster/zapp-react-native-utils 15.1.0-rc.1 → 16.0.0-alpha.6593152532

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 (144) hide show
  1. package/README.md +0 -6
  2. package/actionUtils/index.ts +7 -0
  3. package/actionsExecutor/ActionExecutorContext.tsx +43 -12
  4. package/actionsExecutor/feedDecorator.ts +6 -6
  5. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  6. package/adsUtils/index.ts +2 -2
  7. package/analyticsUtils/README.md +1 -1
  8. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  10. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  11. package/appUtils/HooksManager/index.ts +13 -19
  12. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  13. package/appUtils/accessibilityManager/const.ts +4 -0
  14. package/appUtils/accessibilityManager/utils.ts +0 -1
  15. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  16. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  17. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  18. package/appUtils/contextKeysManager/index.ts +65 -10
  19. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  20. package/appUtils/focusManager/index.ios.ts +43 -4
  21. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  22. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  23. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  24. package/appUtils/focusManagerAux/utils/index.ts +11 -3
  25. package/appUtils/focusManagerAux/utils/utils.ios.ts +202 -3
  26. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  27. package/appUtils/orientationHelper.ts +2 -4
  28. package/appUtils/platform/platformUtils.ts +12 -1
  29. package/appUtils/playerManager/player.ts +4 -0
  30. package/appUtils/playerManager/playerNative.ts +30 -21
  31. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  32. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  33. package/cloudEventsUtils/index.ts +65 -1
  34. package/componentsUtils/index.ts +8 -0
  35. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  36. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  37. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  38. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  39. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  40. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  41. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  42. package/errorUtils/__tests__/invariant.test.ts +112 -0
  43. package/focusManager/aux/index.ts +1 -1
  44. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  45. package/headersUtils/index.ts +2 -1
  46. package/manifestUtils/_internals/__tests__/index.test.js +41 -0
  47. package/manifestUtils/_internals/index.js +33 -0
  48. package/manifestUtils/defaultManifestConfigurations/player.js +59 -1
  49. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
  50. package/manifestUtils/fieldUtils/index.js +54 -0
  51. package/manifestUtils/index.js +3 -1
  52. package/manifestUtils/keys.js +228 -0
  53. package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
  54. package/manifestUtils/mobileAction/button/index.js +140 -0
  55. package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
  56. package/manifestUtils/mobileAction/container/index.js +73 -0
  57. package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
  58. package/manifestUtils/mobileAction/groups/defaults.js +76 -0
  59. package/manifestUtils/mobileAction/groups/index.js +80 -0
  60. package/manifestUtils/tvAction/container/index.js +1 -1
  61. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  62. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  63. package/numberUtils/index.ts +23 -1
  64. package/package.json +4 -4
  65. package/pluginUtils/index.ts +4 -0
  66. package/reactHooks/advertising/index.ts +2 -2
  67. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  68. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  69. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  70. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  71. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  72. package/reactHooks/cell-click/index.ts +2 -1
  73. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  74. package/reactHooks/connection/__tests__/index.test.js +1 -1
  75. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  76. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  77. package/reactHooks/device/useIsTablet.tsx +14 -19
  78. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  79. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  80. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  81. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  82. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  83. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  84. package/reactHooks/feed/index.ts +0 -2
  85. package/reactHooks/feed/useBatchLoading.ts +7 -1
  86. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  87. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  88. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  89. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  90. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  91. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  92. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  93. package/reactHooks/navigation/__tests__/index.test.tsx +2 -4
  94. package/reactHooks/navigation/index.ts +7 -6
  95. package/reactHooks/navigation/useRoute.ts +8 -6
  96. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  97. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  98. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  99. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  100. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  101. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  102. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  103. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  104. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  105. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  106. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  107. package/reactHooks/screen/index.ts +0 -2
  108. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  109. package/reactHooks/state/useRivers.ts +1 -1
  110. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  111. package/reactHooks/usePluginConfiguration.ts +2 -2
  112. package/reactHooks/utils/__tests__/index.test.js +1 -1
  113. package/rectUtils/__tests__/index.test.ts +549 -0
  114. package/rectUtils/index.ts +2 -2
  115. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +206 -0
  116. package/refreshUtils/RefreshCoordinator/index.ts +245 -0
  117. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  118. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  119. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  120. package/screenState/__tests__/index.test.ts +1 -1
  121. package/screenUtils/index.ts +3 -0
  122. package/searchUtils/const.ts +7 -0
  123. package/searchUtils/index.ts +3 -0
  124. package/stringUtils/index.ts +1 -1
  125. package/testUtils/index.tsx +30 -21
  126. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  127. package/time/__tests__/Timer.test.ts +236 -0
  128. package/typeGuards/__tests__/isString.test.ts +21 -0
  129. package/typeGuards/index.ts +4 -0
  130. package/utils/__tests__/mergeRight.test.ts +48 -0
  131. package/utils/__tests__/path.test.ts +7 -0
  132. package/utils/__tests__/selectors.test.ts +124 -0
  133. package/utils/index.ts +13 -0
  134. package/utils/mergeRight.ts +5 -0
  135. package/utils/path.ts +6 -3
  136. package/utils/pathOr.ts +5 -1
  137. package/utils/selectors.ts +46 -0
  138. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +1 -1
  139. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  140. package/zappFrameworkUtils/loginPluginUtils.ts +1 -1
  141. package/reactHooks/componentsMap/index.ts +0 -55
  142. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  143. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
  144. package/reactHooks/screen/useIsStandaloneFullscreen.ts +0 -12
@@ -1,193 +1,5 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`HooksManager when target route is playable executes the player hook 1`] = `
4
- [
5
- {
6
- "callback": [Function],
7
- "hookPlugin": Hook {
8
- "configuration": {
9
- "config_field": "bar",
10
- },
11
- "identifier": "headless_player_hook",
12
- "lastHook": true,
13
- "manager": {
14
- "executeHook": [Function],
15
- "handleHooks": [Function],
16
- "presentScreenHook": [Function],
17
- "runInBackground": [Function],
18
- "subscriber": {
19
- "handlers": {
20
- "complete": [
21
- [MockFunction] {
22
- "calls": [
23
- [
24
- {
25
- "callback": [Function],
26
- "hookPlugin": [Circular],
27
- "payload": {
28
- "foo": "bar",
29
- },
30
- },
31
- [Function],
32
- ],
33
- ],
34
- "results": [
35
- {
36
- "type": "return",
37
- "value": undefined,
38
- },
39
- ],
40
- },
41
- ],
42
- "presentScreenHook": [
43
- [MockFunction],
44
- ],
45
- "success": [
46
- [MockFunction] {
47
- "calls": [
48
- [Circular],
49
- ],
50
- "results": [
51
- {
52
- "type": "return",
53
- "value": undefined,
54
- },
55
- ],
56
- },
57
- ],
58
- },
59
- "invokeHandler": [Function],
60
- "on": [Function],
61
- "removeHandler": [Function],
62
- },
63
- },
64
- "module": {
65
- "hasPlayerHook": true,
66
- "run": [MockFunction] {
67
- "calls": [
68
- [
69
- {
70
- "foo": "bar",
71
- },
72
- [Function],
73
- {
74
- "config_field": "bar",
75
- },
76
- ],
77
- ],
78
- "results": [
79
- {
80
- "type": "return",
81
- "value": undefined,
82
- },
83
- ],
84
- },
85
- },
86
- "state": 7,
87
- "weight": 1,
88
- },
89
- "payload": {
90
- "foo": "bar",
91
- },
92
- },
93
- [Function],
94
- ]
95
- `;
96
-
97
- exports[`HooksManager when target route is playable executes the player hook 2`] = `
98
- [
99
- {
100
- "callback": [Function],
101
- "hookPlugin": Hook {
102
- "configuration": {
103
- "config_field": "bar",
104
- },
105
- "identifier": "headless_player_hook",
106
- "lastHook": true,
107
- "manager": {
108
- "executeHook": [Function],
109
- "handleHooks": [Function],
110
- "presentScreenHook": [Function],
111
- "runInBackground": [Function],
112
- "subscriber": {
113
- "handlers": {
114
- "complete": [
115
- [MockFunction] {
116
- "calls": [
117
- [Circular],
118
- ],
119
- "results": [
120
- {
121
- "type": "return",
122
- "value": undefined,
123
- },
124
- ],
125
- },
126
- ],
127
- "presentScreenHook": [
128
- [MockFunction],
129
- ],
130
- "success": [
131
- [MockFunction] {
132
- "calls": [
133
- [
134
- {
135
- "callback": [Function],
136
- "hookPlugin": [Circular],
137
- "payload": {
138
- "foo": "bar",
139
- },
140
- },
141
- [Function],
142
- ],
143
- ],
144
- "results": [
145
- {
146
- "type": "return",
147
- "value": undefined,
148
- },
149
- ],
150
- },
151
- ],
152
- },
153
- "invokeHandler": [Function],
154
- "on": [Function],
155
- "removeHandler": [Function],
156
- },
157
- },
158
- "module": {
159
- "hasPlayerHook": true,
160
- "run": [MockFunction] {
161
- "calls": [
162
- [
163
- {
164
- "foo": "bar",
165
- },
166
- [Function],
167
- {
168
- "config_field": "bar",
169
- },
170
- ],
171
- ],
172
- "results": [
173
- {
174
- "type": "return",
175
- "value": undefined,
176
- },
177
- ],
178
- },
179
- },
180
- "state": 7,
181
- "weight": 1,
182
- },
183
- "payload": {
184
- "foo": "bar",
185
- },
186
- },
187
- [Function],
188
- ]
189
- `;
190
-
191
3
  exports[`HooksManager when there are preload hooks hook with screen: executes 1`] = `
192
4
  [
193
5
  {
@@ -116,9 +116,23 @@ describe("HooksManager", () => {
116
116
  headlessPlayerHook.configuration
117
117
  );
118
118
 
119
- expect(successHandler.mock.calls[0]).toMatchSnapshot();
119
+ expect(successHandler).toHaveBeenCalledTimes(1);
120
+ expect(successHandler.mock.calls[0][0].payload).toEqual(payload);
120
121
 
121
- expect(completeHandler.mock.calls[0]).toMatchSnapshot();
122
+ expect(successHandler.mock.calls[0][0].hookPlugin.identifier).toBe(
123
+ "headless_player_hook"
124
+ );
125
+
126
+ expect(typeof successHandler.mock.calls[0][1]).toBe("function");
127
+
128
+ expect(completeHandler).toHaveBeenCalledTimes(1);
129
+ expect(completeHandler.mock.calls[0][0].payload).toEqual(payload);
130
+
131
+ expect(completeHandler.mock.calls[0][0].hookPlugin.identifier).toBe(
132
+ "headless_player_hook"
133
+ );
134
+
135
+ expect(typeof completeHandler.mock.calls[0][1]).toBe("function");
122
136
  });
123
137
  });
124
138
 
@@ -1,14 +1,11 @@
1
1
  import * as R from "ramda";
2
2
 
3
3
  import { subscriber } from "@applicaster/zapp-react-native-utils/functionUtils";
4
- import {
5
- QUICK_BRICK_EVENTS,
6
- sendQuickBrickEvent,
7
- } from "@applicaster/zapp-react-native-bridge/QuickBrick";
8
-
9
4
  import { Hook } from "./Hook";
10
5
  import { HOOKS_EVENTS, HOOKS_TYPE } from "./constants";
11
6
 
7
+ import { platformToBackground } from "../platform";
8
+
12
9
  import { hooksManagerLogger } from "./logger";
13
10
  import { HookManager, HookManagerArgs } from "./types";
14
11
  import {
@@ -234,7 +231,7 @@ export function HooksManager({
234
231
  function completeHook(hookPlugin, payload, callback) {
235
232
  logHookEvent(
236
233
  hooksManagerLogger.info,
237
- `completeHook: hook sequence completed successfully: ${hookPlugin["identifier"]}`,
234
+ `completeHook: hook sequence completed successfully: ${hookPlugin.identifier}`,
238
235
  {
239
236
  payload,
240
237
  hook: hookPlugin,
@@ -280,7 +277,7 @@ export function HooksManager({
280
277
  if (hookPlugin.isCancelled()) {
281
278
  logHookEvent(
282
279
  hooksManagerLogger.info,
283
- `hookCallback: hook was cancelled: ${hookPlugin["identifier"]}`,
280
+ `hookCallback: hook was cancelled: ${hookPlugin.identifier}`,
284
281
  {}
285
282
  );
286
283
 
@@ -313,7 +310,7 @@ export function HooksManager({
313
310
  if (!success) {
314
311
  logHookEvent(
315
312
  hooksManagerLogger.info,
316
- `hookCallback: hook was cancelled: ${hookPlugin["identifier"]}`,
313
+ `hookCallback: hook was cancelled: ${hookPlugin.identifier}`,
317
314
  {
318
315
  payload,
319
316
  hook: hookPlugin,
@@ -344,22 +341,19 @@ export function HooksManager({
344
341
  if (isHookInHomescreen && isHookFlowBlocker && cancelled) {
345
342
  logHookEvent(
346
343
  hooksManagerLogger.info,
347
- `hookCallback: send app to background, cancelled flow blocker hook ${hookPlugin["identifier"]} on home screen`,
344
+ `hookCallback: send app to background, cancelled flow blocker hook ${hookPlugin.identifier} on home screen`,
348
345
  {
349
346
  payload,
350
347
  hook: hookPlugin,
351
348
  }
352
349
  );
353
350
 
354
- // TODO: Add this logic to platformBack and rename platformBack to platformToBackground for all platforms
355
- sendQuickBrickEvent(QUICK_BRICK_EVENTS.MOVE_APP_TO_BACKGROUND, {
356
- MOVE_APP_TO_BACKGROUND: true,
357
- });
351
+ platformToBackground();
358
352
  }
359
353
  } else {
360
354
  logHookEvent(
361
355
  hooksManagerLogger.info,
362
- `hookCallback: hook successfully finished: ${hookPlugin["identifier"]}`,
356
+ `hookCallback: hook successfully finished: ${hookPlugin.identifier}`,
363
357
  {
364
358
  payload,
365
359
  hook: hookPlugin,
@@ -369,7 +363,7 @@ export function HooksManager({
369
363
  if (!callback) {
370
364
  logHookEvent(
371
365
  hooksManagerLogger.warn,
372
- `hookCallback: ${hookPlugin["identifier"]} is missing \`callback\`, using hookCallback(default one)`,
366
+ `hookCallback: ${hookPlugin.identifier} is missing \`callback\`, using hookCallback(default one)`,
373
367
  {
374
368
  hookPlugin,
375
369
  }
@@ -432,7 +426,7 @@ export function HooksManager({
432
426
 
433
427
  logHookEvent(
434
428
  hooksManagerLogger.info,
435
- `presentScreenHook: Presenting screen hook: ${hookPlugin["identifier"]}`,
429
+ `presentScreenHook: Presenting screen hook: ${hookPlugin.identifier}`,
436
430
  {
437
431
  hook: hookPlugin,
438
432
  payload,
@@ -454,7 +448,7 @@ export function HooksManager({
454
448
  hooksManager.executeHook = function (hookPlugin, payload, callback) {
455
449
  logHookEvent(
456
450
  hooksManagerLogger.info,
457
- `executeHook: ${hookPlugin["identifier"]}`,
451
+ `executeHook: ${hookPlugin.identifier}`,
458
452
  {
459
453
  hook: hookPlugin,
460
454
  payload,
@@ -466,7 +460,7 @@ export function HooksManager({
466
460
  } catch (error) {
467
461
  logHookEvent(
468
462
  hooksManagerLogger.error,
469
- `executeHook: error executing hook: ${hookPlugin["identifier"]} error: ${error.message}`,
463
+ `executeHook: error executing hook: ${hookPlugin.identifier} error: ${error.message}`,
470
464
  {
471
465
  hook: hookPlugin,
472
466
  payload,
@@ -493,7 +487,7 @@ export function HooksManager({
493
487
  try {
494
488
  logHookEvent(
495
489
  hooksManagerLogger.info,
496
- `runInBackground: Executing hook: ${hookPlugin["identifier"]}`,
490
+ `runInBackground: Executing hook: ${hookPlugin.identifier}`,
497
491
  {
498
492
  hook: hookPlugin,
499
493
  payload,
@@ -1,11 +1,31 @@
1
- import * as R from "ramda";
2
-
3
- import { focusManager } from "../focusManager";
1
+ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
2
+ import { QUICK_BRICK_CONTENT } from "@applicaster/quick-brick-core/const";
3
+ import { isNil, isEmpty } from "@applicaster/zapp-react-native-utils/utils";
4
+ import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
4
5
 
5
6
  let riverFocusData = {};
6
7
  let initialyPresentedScreenFocused = false;
7
8
 
8
9
  export const riverFocusManager = (function () {
10
+ /**
11
+ * Create unique key that will be used for save focused group data inside specific screen
12
+ * @param {{ screenId: string, isInsideContainer: boolean }}
13
+ * screenId Unique Id of the screen from layout.json
14
+ * isInsideContainer If this screen a screen picker child
15
+ *
16
+ */
17
+ function screenFocusableGroupId({
18
+ screenId,
19
+ isInsideContainer,
20
+ }: {
21
+ screenId: string;
22
+ isInsideContainer: Option<boolean>;
23
+ }) {
24
+ return `${QUICK_BRICK_CONTENT}-${screenId}${
25
+ isNil(isInsideContainer) ? "" : "-isInsideContainer"
26
+ }`;
27
+ }
28
+
9
29
  function setScreenFocusableData({
10
30
  screenFocusableGroupId,
11
31
  groupId,
@@ -78,8 +98,8 @@ export const riverFocusManager = (function () {
78
98
  }) {
79
99
  // Check if screen should be focused
80
100
  const shouldFocus =
81
- (initialyPresentedScreenFocused === false && R.isEmpty(riverFocusData)) ||
82
- R.compose(R.not, R.isNil)(riverFocusData[screenFocusableGroupId]) ||
101
+ (initialyPresentedScreenFocused === false && isEmpty(riverFocusData)) ||
102
+ isNotNil(riverFocusData[screenFocusableGroupId]) ||
83
103
  isDeepLink;
84
104
 
85
105
  // TODO: Uncommit it to start fixing bug where selection wrong item
@@ -118,19 +138,6 @@ export const riverFocusManager = (function () {
118
138
  }
119
139
  }
120
140
 
121
- /**
122
- * Create unique key that will be used for save focused group data inside specific screen
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
126
- *
127
- */
128
- function screenFocusableGroupId({ screenId, isInsideContainer }) {
129
- return `RiverFocusableGroup-${screenId}${
130
- R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
131
- }`;
132
- }
133
-
134
141
  return {
135
142
  setScreenFocusableData,
136
143
  clearAllScreensData,
@@ -31,6 +31,10 @@ export const BUTTON_ACCESSIBILITY_KEYS = {
31
31
  hint: "accessibility_close_mini_hint",
32
32
  },
33
33
  },
34
+ back_to_live: {
35
+ label: "back_to_live_label",
36
+ hint: "",
37
+ },
34
38
  maximize: {
35
39
  label: "accessibility_maximize_label",
36
40
  hint: "accessibility_maximize_hint",
@@ -35,7 +35,6 @@ export function calculateReadingTime(
35
35
  return 0;
36
36
  }
37
37
 
38
- // Count words (split on whitespace and punctuation, keep alnum boundaries)
39
38
  const words = trimmed
40
39
  .split(/(?<=\d)(?=[a-zA-Z])|(?<=[a-zA-Z])(?=\d)|[^\w\s]+|\s+/)
41
40
  .filter(Boolean).length;
@@ -1,7 +1,12 @@
1
+ import { NativeModules } from "react-native";
1
2
  import { ContextKeysManager } from "../..";
2
3
 
3
4
  describe("Context Keys Manager - getKeys", () => {
4
- it("returns null if all keys are invalid", async () => {
5
+ beforeEach(() => {
6
+ delete NativeModules.ContextResolverBridge;
7
+ });
8
+
9
+ it("returns null if all keys are invalid 1", async () => {
5
10
  // setup
6
11
  const keys = [null];
7
12
 
@@ -24,7 +29,7 @@ describe("Context Keys Manager - getKeys", () => {
24
29
  expect(getKey.mock.calls).toEqual([[null]]);
25
30
  });
26
31
 
27
- it("returns null if all keys are invalid", async () => {
32
+ it("returns null if all keys are invalid 2", async () => {
28
33
  // setup
29
34
  const keys = [null, undefined];
30
35
 
@@ -1,6 +1,11 @@
1
+ import { NativeModules } from "react-native";
1
2
  import { ContextKeysManager } from "../..";
2
3
 
3
4
  describe("Context Keys Manager - getKeys", () => {
5
+ beforeEach(() => {
6
+ delete NativeModules.ContextResolverBridge;
7
+ });
8
+
4
9
  it("returns value if found by getKey", async () => {
5
10
  // setup
6
11
  const keys = ["namespace.key"];
@@ -165,4 +170,47 @@ describe("Context Keys Manager - getKeys", () => {
165
170
  expect(getKey).toHaveBeenCalledTimes(2);
166
171
  expect(getKey.mock.calls).toEqual([[keys[0]], [keys[1]]]);
167
172
  });
173
+
174
+ it("returns values from native bridge when available", async () => {
175
+ // setup
176
+ const keys = ["namespace.key1", "namespace.key2"];
177
+
178
+ const contextObj = [
179
+ { key: keys[0], required: true },
180
+ { key: keys[1], required: false },
181
+ ];
182
+
183
+ const resolved = {
184
+ [keys[0]]: "value1",
185
+ [keys[1]]: "value2",
186
+ };
187
+
188
+ const reactNative = require("react-native");
189
+
190
+ const bridgeMock = {
191
+ resolveContextKeys: jest.fn().mockResolvedValue(resolved),
192
+ };
193
+
194
+ reactNative.__setContextResolverBridgeMock(bridgeMock);
195
+
196
+ const contextManager = new ContextKeysManager({});
197
+ const getKey = jest.spyOn(contextManager, "getKey");
198
+
199
+ // run
200
+ const result = await contextManager.getKeys(keys, contextObj);
201
+
202
+ // verify
203
+ const map = new Map();
204
+ map.set(keys[0], "value1");
205
+ map.set(keys[1], "value2");
206
+
207
+ expect(result).toEqual(map);
208
+
209
+ expect(bridgeMock.resolveContextKeys).toHaveBeenCalledWith({
210
+ [keys[0]]: true,
211
+ [keys[1]]: false,
212
+ });
213
+
214
+ expect(getKey).not.toHaveBeenCalled();
215
+ });
168
216
  });
@@ -1,8 +1,10 @@
1
1
  import { ContextKeysManager } from "./index";
2
- import * as R from "ramda";
3
- import * as _ from "lodash";
2
+ import { get, values } from "@applicaster/zapp-react-native-utils/utils";
4
3
  import { useScreenStateStore } from "../../reactHooks/navigation/useScreenStateStore";
5
4
 
5
+ const contextKeyPattern = /@{([^/]+)\/([^}]*)}/;
6
+ const contextVariablePattern = /@\{([^}]*)\}/g;
7
+
6
8
  export interface IResolver {
7
9
  resolve: (string) => Promise<string | number | object>;
8
10
  }
@@ -20,7 +22,7 @@ export class EntryResolver implements IResolver {
20
22
  return this.entry;
21
23
  }
22
24
 
23
- return R.view(R.lensPath(key.split(".")), this.entry);
25
+ return get(this.entry, key.split("."));
24
26
  }
25
27
  }
26
28
 
@@ -39,7 +41,7 @@ export class ScreenStateResolver implements IResolver {
39
41
  }
40
42
 
41
43
  if (key.includes(".")) {
42
- return R.view(R.lensPath(key.split(".")), screenState);
44
+ return get(screenState, key.split("."));
43
45
  }
44
46
 
45
47
  return screenState?.[key];
@@ -61,21 +63,16 @@ export const resolveObjectValues = async (
61
63
 
62
64
  const resolvedEntries = await Promise.all(
63
65
  entries.map(async ([key, value]) => {
64
- if (typeof value !== "string") {
66
+ if (typeof value !== "string" || !value.startsWith("@")) {
65
67
  return [key, value];
66
68
  }
67
69
 
68
- if (!value.startsWith("@")) {
69
- return [key, value];
70
- }
71
-
72
- const regex = /@{([^/]+)\/([^}]*)}/;
70
+ const regex = contextKeyPattern;
73
71
 
74
72
  const match = (value as string).match(regex);
75
73
 
76
74
  if (match) {
77
- const contextResolverName = match[1];
78
- const compositeKey = match[2];
75
+ const [_, contextResolverName, compositeKey] = match;
79
76
 
80
77
  const resolver = exResolvers[contextResolverName] || exResolvers.ctx;
81
78
  const resolvedValue = await resolver.resolve(compositeKey);
@@ -90,18 +87,50 @@ export const resolveObjectValues = async (
90
87
  return Object.fromEntries(resolvedEntries);
91
88
  };
92
89
 
93
- export const extractAtValues = _.memoize((input: any): string[] => {
94
- return _.flatMapDeep(input, (value: any) => {
95
- if (_.isString(value)) {
96
- const matches = value.match(/@\{([^}]*)\}/g);
90
+ // Simple memoization cache
91
+ const extractAtValuesCache = new Map<any, string[]>();
92
+
93
+ const flatMapDeep = <T, U>(arr: T[], fn: (value: T) => U | U[]): U[] => {
94
+ const result: U[] = [];
97
95
 
98
- return matches ? matches.map((match) => match.slice(2, -1)) : [];
96
+ const flatten = (items: any) => {
97
+ for (const item of items) {
98
+ if (Array.isArray(item)) {
99
+ flatten(item);
100
+ } else {
101
+ result.push(item);
102
+ }
99
103
  }
104
+ };
105
+
106
+ flatten(arr.map(fn));
100
107
 
101
- if (_.isObject(value)) {
102
- return extractAtValues(_.values(value));
108
+ return result;
109
+ };
110
+
111
+ export const extractAtValues = (input: any): string[] => {
112
+ if (extractAtValuesCache.has(input)) {
113
+ return extractAtValuesCache.get(input)!;
114
+ }
115
+
116
+ const result = flatMapDeep(
117
+ Array.isArray(input) ? input : [input],
118
+ (value: any) => {
119
+ if (typeof value === "string") {
120
+ const matches = value.match(contextVariablePattern);
121
+
122
+ return matches ? matches.map((match) => match.slice(2, -1)) : [];
123
+ }
124
+
125
+ if (typeof value === "object" && value !== null) {
126
+ return extractAtValues(values(value));
127
+ }
128
+
129
+ return [];
103
130
  }
131
+ );
104
132
 
105
- return [];
106
- });
107
- });
133
+ extractAtValuesCache.set(input, result);
134
+
135
+ return result;
136
+ };