@applicaster/zapp-react-native-utils 15.0.0-alpha.3564377339 → 15.0.0-alpha.3642255793

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 (71) hide show
  1. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  2. package/analyticsUtils/analyticsMapper.ts +10 -2
  3. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  4. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  5. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  6. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  7. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  8. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  9. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  10. package/appUtils/contextKeysManager/index.ts +65 -10
  11. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  12. package/appUtils/focusManager/index.ios.ts +37 -4
  13. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  14. package/appUtils/focusManagerAux/utils/utils.ios.ts +150 -11
  15. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  16. package/cloudEventsUtils/index.ts +65 -1
  17. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
  18. package/configurationUtils/index.ts +17 -11
  19. package/dateUtils/__tests__/dayjs.test.ts +330 -0
  20. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  21. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  22. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  23. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  24. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  25. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  26. package/errorUtils/__tests__/invariant.test.ts +112 -0
  27. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  28. package/headersUtils/index.ts +2 -1
  29. package/manifestUtils/defaultManifestConfigurations/player.js +50 -10
  30. package/navigationUtils/index.ts +15 -5
  31. package/numberUtils/__tests__/toNumber.test.ts +12 -0
  32. package/numberUtils/__tests__/toPositiveNumber.test.ts +165 -0
  33. package/numberUtils/index.ts +19 -1
  34. package/package.json +4 -4
  35. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  36. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  37. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  38. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  39. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  40. package/reactHooks/connection/__tests__/index.test.js +1 -1
  41. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  42. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  43. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +1 -1
  44. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  45. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +1 -1
  46. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  47. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  48. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  49. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  50. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  51. package/reactHooks/navigation/index.ts +19 -4
  52. package/reactHooks/navigation/useRoute.ts +3 -1
  53. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  54. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  55. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  56. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  57. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  58. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  59. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  60. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +2 -2
  61. package/reactHooks/state/useRefWithInitialValue.ts +10 -0
  62. package/reactHooks/utils/__tests__/index.test.js +1 -1
  63. package/screenState/__tests__/index.test.ts +1 -1
  64. package/searchUtils/const.ts +7 -0
  65. package/searchUtils/index.ts +3 -0
  66. package/services/storageServiceSync.web.ts +1 -1
  67. package/stringUtils/index.ts +1 -1
  68. package/testUtils/index.tsx +1 -1
  69. package/utils/__tests__/mergeRight.test.ts +48 -0
  70. package/utils/index.ts +3 -0
  71. package/utils/mergeRight.ts +5 -0
@@ -4,7 +4,11 @@ import * as R from "ramda";
4
4
  import {
5
5
  isCurrentFocusOn,
6
6
  isChildOf as isChildOfUtils,
7
- } from "../focusManagerAux/utils";
7
+ isPartOfMenu,
8
+ isPartOfContent,
9
+ isPartOfTabsScreenContent,
10
+ } from "../focusManagerAux/utils/index.ios";
11
+
8
12
  import { Tree } from "./treeDataStructure/Tree";
9
13
  import { findFocusableNode } from "./treeDataStructure/Utils";
10
14
  import { subscriber } from "../../functionUtils";
@@ -194,9 +198,9 @@ export const focusManager = (function () {
194
198
  registerItem(id, component);
195
199
  }
196
200
 
197
- const parentId = component?.props?.groupId;
201
+ const groupId = component?.props?.groupId;
198
202
 
199
- emitRegistered({ id, parentId, isGroup });
203
+ emitRegistered({ id, groupId, isGroup });
200
204
  }
201
205
 
202
206
  function unregister(id, { group = false } = {}) {
@@ -279,7 +283,9 @@ export const focusManager = (function () {
279
283
  function setFocus(
280
284
  id: string,
281
285
  direction?: FocusManager.IOS.Direction,
282
- options?: Partial<{ groupFocusedChanged: boolean }>,
286
+ options?: Partial<{
287
+ groupFocusedChanged: boolean;
288
+ }>,
283
289
  callback?: any
284
290
  ) {
285
291
  blur(direction);
@@ -418,6 +424,30 @@ export const focusManager = (function () {
418
424
  return id && isCurrentFocusOn(id, currentFocusNode);
419
425
  }
420
426
 
427
+ function isFocusOnMenu(): boolean {
428
+ const currentFocusable = getCurrentFocus();
429
+
430
+ return isPartOfMenu(focusableTree, currentFocusable?.props?.id);
431
+ }
432
+
433
+ function isFocusOnContent(): boolean {
434
+ const currentFocusable = getCurrentFocus();
435
+
436
+ return isPartOfContent(focusableTree, currentFocusable?.props?.id);
437
+ }
438
+
439
+ function isFocusOnTabsScreenContent(
440
+ screenPickerContentContainerId: string
441
+ ): boolean {
442
+ const currentFocusable = getCurrentFocus();
443
+
444
+ return isPartOfTabsScreenContent(
445
+ focusableTree,
446
+ screenPickerContentContainerId,
447
+ currentFocusable?.props?.id
448
+ );
449
+ }
450
+
421
451
  function isChildOf(childId, parentId): boolean {
422
452
  return isChildOfUtils(focusableTree, childId, parentId);
423
453
  }
@@ -444,6 +474,9 @@ export const focusManager = (function () {
444
474
  isGroupItemFocused,
445
475
  getPreferredFocusChild,
446
476
  isFocusOn,
477
+ isFocusOnMenu,
478
+ isFocusOnContent,
479
+ isFocusOnTabsScreenContent,
447
480
  isChildOf,
448
481
  };
449
482
  })();
@@ -0,0 +1,122 @@
1
+ import { isNil, startsWith } from "@applicaster/zapp-react-native-utils/utils";
2
+
3
+ import {
4
+ QUICK_BRICK_CONTENT,
5
+ QUICK_BRICK_NAVBAR,
6
+ } from "@applicaster/quick-brick-core/const";
7
+
8
+ const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
9
+ const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
10
+ const isRoot = (node) => node?.id === "root";
11
+
12
+ export const isPartOfTabsScreenContent = (
13
+ focusableTree,
14
+ screenPickerContentContainerId,
15
+ id
16
+ ) => {
17
+ const node = focusableTree.findInTree(id);
18
+
19
+ if (isNil(node)) {
20
+ return false;
21
+ }
22
+
23
+ if (isRoot(node)) {
24
+ return false;
25
+ }
26
+
27
+ if (isNavBar(node)) {
28
+ return false;
29
+ }
30
+
31
+ if (isContent(node)) {
32
+ return false;
33
+ }
34
+
35
+ if (node?.id === screenPickerContentContainerId) {
36
+ return true;
37
+ }
38
+
39
+ return isPartOfTabsScreenContent(
40
+ focusableTree,
41
+ screenPickerContentContainerId,
42
+ node.parent?.id
43
+ );
44
+ };
45
+
46
+ export const isPartOfMenu = (focusableTree, id): boolean => {
47
+ const node = focusableTree.findInTree(id);
48
+
49
+ if (isNil(node)) {
50
+ return false;
51
+ }
52
+
53
+ if (isRoot(node)) {
54
+ return false;
55
+ }
56
+
57
+ if (isNavBar(node)) {
58
+ return true;
59
+ }
60
+
61
+ if (isContent(node)) {
62
+ return false;
63
+ }
64
+
65
+ return isPartOfMenu(focusableTree, node.parent?.id);
66
+ };
67
+
68
+ export const isPartOfContent = (focusableTree, id) => {
69
+ const node = focusableTree.findInTree(id);
70
+
71
+ if (isNil(node)) {
72
+ return false;
73
+ }
74
+
75
+ if (isRoot(node)) {
76
+ return false;
77
+ }
78
+
79
+ if (isNavBar(node)) {
80
+ return false;
81
+ }
82
+
83
+ if (isContent(node)) {
84
+ return true;
85
+ }
86
+
87
+ return isPartOfContent(focusableTree, node.parent?.id);
88
+ };
89
+
90
+ export const isCurrentFocusOn = (id, node) => {
91
+ if (!node) {
92
+ return false;
93
+ }
94
+
95
+ if (isRoot(node)) {
96
+ return false;
97
+ }
98
+
99
+ if (node?.id === id) {
100
+ return true;
101
+ }
102
+
103
+ return isCurrentFocusOn(id, node.parent);
104
+ };
105
+
106
+ export const isChildOf = (focusableTree, childId, parentId) => {
107
+ if (isNil(childId) || isNil(parentId)) {
108
+ return false;
109
+ }
110
+
111
+ const childNode = focusableTree.findInTree(childId);
112
+
113
+ if (isNil(childNode)) {
114
+ return false;
115
+ }
116
+
117
+ if (childNode.parent?.id === parentId) {
118
+ return true;
119
+ }
120
+
121
+ return isChildOf(focusableTree, childNode.parent?.id, parentId);
122
+ };
@@ -1,7 +1,9 @@
1
1
  import { ReplaySubject, Subject } from "rxjs";
2
- import { filter, switchMap, take } from "rxjs/operators";
2
+ import { filter, switchMap, take, withLatestFrom, map } from "rxjs/operators";
3
+
3
4
  import { BUTTON_PREFIX } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const";
4
5
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
6
+ import { isPartOfMenu, isPartOfContent } from "./index.ios";
5
7
 
6
8
  type FocusableID = string;
7
9
  type RegistrationEvent = {
@@ -11,13 +13,23 @@ type RegistrationEvent = {
11
13
 
12
14
  let focusableViewRegistrationSubject$ = new Subject<{
13
15
  id: FocusableID;
14
- parentId: FocusableID;
16
+ groupId: FocusableID;
15
17
  }>();
16
18
 
17
19
  let focusableGroupRegistrationSubject$ = new ReplaySubject<{
18
20
  id: FocusableID;
19
21
  }>();
20
22
 
23
+ let focusableNativeViewRegistrationSubject$ = new Subject<{
24
+ id: FocusableID;
25
+ groupId: FocusableID;
26
+ }>();
27
+
28
+ let focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
29
+ id: FocusableID;
30
+ groupId: FocusableID;
31
+ }>();
32
+
21
33
  const isFocusableButton = (id: Option<FocusableID>): boolean =>
22
34
  id && id.includes?.(BUTTON_PREFIX);
23
35
 
@@ -41,35 +53,90 @@ export const resetFocusableRegistration = () => {
41
53
  focusableGroupRegistrationSubject$.complete();
42
54
  }
43
55
 
56
+ if (!focusableNativeViewRegistrationSubject$.closed) {
57
+ focusableNativeViewRegistrationSubject$.complete();
58
+ }
59
+
60
+ if (!focusableNativeGroupRegistrationSubject$.closed) {
61
+ focusableNativeGroupRegistrationSubject$.complete();
62
+ }
63
+
44
64
  focusableViewRegistrationSubject$ = new Subject<{
45
65
  id: FocusableID;
46
- parentId: FocusableID;
66
+ groupId: FocusableID;
47
67
  }>();
48
68
 
49
69
  focusableGroupRegistrationSubject$ = new ReplaySubject<{
50
70
  id: FocusableID;
51
71
  }>();
72
+
73
+ focusableNativeViewRegistrationSubject$ = new Subject<{
74
+ id: FocusableID;
75
+ groupId: FocusableID;
76
+ }>();
77
+
78
+ focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
79
+ id: FocusableID;
80
+ groupId: FocusableID;
81
+ }>();
82
+ };
83
+
84
+ const focusableNativeViewRegistration = ({ focusableView, focusableGroup }) => {
85
+ return focusableNativeViewRegistrationSubject$.pipe(
86
+ filter(
87
+ (focusableNativeView) => focusableNativeView.id === focusableView.id
88
+ ),
89
+ take(1),
90
+ switchMap((focusableNativeView) =>
91
+ // start waiting registration of its parent FocusableNativeGroup
92
+ focusableNativeGroupRegistrationSubject$.pipe(
93
+ filter(
94
+ (focusableNativeGroup) =>
95
+ focusableNativeGroup.id === focusableNativeView.groupId
96
+ ),
97
+ take(1),
98
+ map((focusableNativeGroup) => ({
99
+ focusableNativeGroup,
100
+ focusableNativeView,
101
+ focusableView,
102
+ focusableGroup,
103
+ }))
104
+ )
105
+ )
106
+ );
52
107
  };
53
108
 
54
109
  export const firstFocusableViewRegistrationFactory = () =>
55
110
  focusableViewRegistrationSubject$.pipe(
56
111
  take(1), // we care about only first FocusableView registration
57
- switchMap(({ parentId }) =>
58
- // start waiting registration of its parent
112
+ switchMap((focusableView) =>
113
+ // start waiting registration of its parent FocusableGroup
59
114
  focusableGroupRegistrationSubject$.pipe(
60
- filter(({ id }) => id === parentId)
115
+ filter((focusableGroup) => focusableGroup.id === focusableView.groupId),
116
+ take(1),
117
+ map((focusableGroup) => ({
118
+ focusableView,
119
+ focusableGroup,
120
+ }))
61
121
  )
62
122
  ),
63
- take(1)
123
+ // start waiting registration for FocusableNativeView and its parent FocusableNativeGroup
124
+ switchMap(({ focusableView, focusableGroup }) =>
125
+ focusableNativeViewRegistration({
126
+ focusableView,
127
+ focusableGroup,
128
+ })
129
+ )
64
130
  );
65
131
 
132
+ // registration on RN level(into RN focusManager)
66
133
  export const emitRegistered = ({
67
134
  id,
68
- parentId,
135
+ groupId,
69
136
  isGroup,
70
137
  }: {
71
138
  id: Option<FocusableID>;
72
- parentId: Option<FocusableID>;
139
+ groupId: Option<FocusableID>;
73
140
  isGroup: boolean;
74
141
  }): void => {
75
142
  if (isFocusableButton(id)) {
@@ -80,13 +147,85 @@ export const emitRegistered = ({
80
147
  focusableGroupRegistrationSubject$.next({ id });
81
148
  }
82
149
 
83
- if (!isGroup && id && parentId) {
84
- focusableViewRegistrationSubject$.next({ id, parentId });
150
+ if (!isGroup && id && groupId) {
151
+ focusableViewRegistrationSubject$.next({ id, groupId });
85
152
  }
86
153
  };
87
154
 
155
+ // unregistration on RN level(into RN focusManager)
88
156
  export const emitUnregistered = (id: Option<FocusableID>): void => {
89
157
  if (isFocusableButton(id)) {
90
158
  registeredSubject$.next({ id, registered: false });
91
159
  }
92
160
  };
161
+
162
+ // registration focusableNativeView and focusableNativeGroup
163
+ export const emitNativeRegistered = ({
164
+ id,
165
+ groupId,
166
+ isGroup,
167
+ }: {
168
+ id: Option<FocusableID>;
169
+ groupId: Option<FocusableID>;
170
+ isGroup: boolean;
171
+ }): void => {
172
+ if (!isGroup && id && groupId) {
173
+ focusableNativeViewRegistrationSubject$.next({ id, groupId });
174
+ }
175
+
176
+ if (isGroup && id && groupId) {
177
+ focusableNativeGroupRegistrationSubject$.next({ id, groupId });
178
+ }
179
+ };
180
+
181
+ // /////
182
+
183
+ const focusedSubject$ = new Subject<FocusableID>();
184
+
185
+ const focused$ = focusedSubject$.asObservable();
186
+
187
+ export const emitFocused = (id: FocusableID): void => {
188
+ focusedSubject$.next(id);
189
+ };
190
+
191
+ export const topMenuItemFocused$ = focused$.pipe(
192
+ filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
193
+ );
194
+
195
+ export const contentFocused$ = focused$.pipe(
196
+ filter((id) => {
197
+ const isContent = isPartOfContent(focusManager.focusableTree, id);
198
+
199
+ return id && isContent;
200
+ })
201
+ );
202
+
203
+ const createFocusableRegistry = () => {
204
+ const subject$ = new ReplaySubject<FocusableID | undefined>(1);
205
+
206
+ return {
207
+ observable$: subject$.asObservable(),
208
+ register: (id: FocusableID) => {
209
+ // save focusable_id on registration
210
+ subject$.next(id);
211
+ },
212
+ unregister: () => {
213
+ // reset focusable_id on unregistration
214
+ subject$.next(undefined);
215
+ },
216
+ };
217
+ };
218
+
219
+ /// HOME_TOP_MENU_ITEM
220
+ export const HomeTopMenuItemRegistry = createFocusableRegistry();
221
+
222
+ export const homeTopMenuItemFocused$ = topMenuItemFocused$.pipe(
223
+ withLatestFrom(HomeTopMenuItemRegistry.observable$),
224
+ filter(([id, homeId]) => id === homeId)
225
+ );
226
+
227
+ /// SCREEN_PICKER
228
+ export const ScreenPickerContentContainerRegistry = createFocusableRegistry();
229
+
230
+ /// SEARCH_INPUT
231
+ export const SearchInputRegistry = createFocusableRegistry();