@applicaster/zapp-react-native-utils 15.0.0-alpha.1456157166 → 15.0.0-alpha.2239032089

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.
@@ -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,
@@ -70,6 +70,9 @@ exports[`focusManagerIOS should be defined 1`] = `
70
70
  "getPreferredFocusChild": [Function],
71
71
  "invokeHandler": [Function],
72
72
  "isFocusOn": [Function],
73
+ "isFocusOnContent": [Function],
74
+ "isFocusOnMenu": [Function],
75
+ "isFocusOnTabsScreenContent": [Function],
73
76
  "isGroupItemFocused": [Function],
74
77
  "moveFocus": [Function],
75
78
  "on": [Function],
@@ -1,12 +1,18 @@
1
1
  import { NativeModules } from "react-native";
2
2
  import * as R from "ramda";
3
3
 
4
- import { isCurrentFocusOn } from "../focusManagerAux/utils";
5
4
  import { Tree } from "./treeDataStructure/Tree";
6
5
  import { findFocusableNode } from "./treeDataStructure/Utils";
7
6
  import { subscriber } from "../../functionUtils";
8
7
  import { findChild } from "./utils";
9
8
 
9
+ import {
10
+ isCurrentFocusOn,
11
+ isPartOfMenu,
12
+ isPartOfContent,
13
+ isPartOfTabsScreenContent,
14
+ } from "../focusManagerAux/utils/index.ios";
15
+
10
16
  const { FocusableManagerModule } = NativeModules;
11
17
 
12
18
  /**
@@ -261,7 +267,9 @@ export const focusManager = (function () {
261
267
  function setFocus(
262
268
  id: string,
263
269
  direction?: FocusManager.IOS.Direction,
264
- options?: Partial<{ groupFocusedChanged: boolean }>,
270
+ options?: Partial<{
271
+ groupFocusedChanged: boolean;
272
+ }>,
265
273
  callback?: any
266
274
  ) {
267
275
  blur(direction);
@@ -400,6 +408,30 @@ export const focusManager = (function () {
400
408
  return id && isCurrentFocusOn(id, currentFocusNode);
401
409
  }
402
410
 
411
+ function isFocusOnMenu(): boolean {
412
+ const currentFocusable = getCurrentFocus();
413
+
414
+ return isPartOfMenu(focusableTree, currentFocusable?.props?.id);
415
+ }
416
+
417
+ function isFocusOnContent(): boolean {
418
+ const currentFocusable = getCurrentFocus();
419
+
420
+ return isPartOfContent(focusableTree, currentFocusable?.props?.id);
421
+ }
422
+
423
+ function isFocusOnTabsScreenContent(
424
+ screenPickerContentContainerId: string
425
+ ): boolean {
426
+ const currentFocusable = getCurrentFocus();
427
+
428
+ return isPartOfTabsScreenContent(
429
+ focusableTree,
430
+ screenPickerContentContainerId,
431
+ currentFocusable?.props?.id
432
+ );
433
+ }
434
+
403
435
  return {
404
436
  on,
405
437
  invokeHandler,
@@ -422,5 +454,8 @@ export const focusManager = (function () {
422
454
  isGroupItemFocused,
423
455
  getPreferredFocusChild,
424
456
  isFocusOn,
457
+ isFocusOnMenu,
458
+ isFocusOnContent,
459
+ isFocusOnTabsScreenContent,
425
460
  };
426
461
  })();
@@ -0,0 +1,104 @@
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
+ };
@@ -0,0 +1,63 @@
1
+ import { Subject, ReplaySubject, withLatestFrom } from "rxjs";
2
+ import { filter } from "rxjs/operators";
3
+
4
+ import { isPartOfMenu, isPartOfContent } from "./index.ios";
5
+
6
+ import { focusManager } from "../../focusManager/index.ios";
7
+
8
+ type FocusableID = string;
9
+ const focusedSubject$ = new Subject<FocusableID>();
10
+
11
+ const focused$ = focusedSubject$.asObservable();
12
+
13
+ export const emitFocused = (id: FocusableID): void => {
14
+ focusedSubject$.next(id);
15
+ };
16
+
17
+ export const topMenuItemFocused$ = focused$.pipe(
18
+ filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
19
+ );
20
+
21
+ export const contentFocused$ = focused$.pipe(
22
+ filter((id) => {
23
+ const isContent = isPartOfContent(focusManager.focusableTree, id);
24
+
25
+ return id && isContent;
26
+ })
27
+ );
28
+
29
+ const registeredHomeTopMenuItemSubject$ = new ReplaySubject<FocusableID>(1);
30
+
31
+ export const registeredHomeTopMenuItem$ =
32
+ registeredHomeTopMenuItemSubject$.asObservable();
33
+
34
+ export const homeTopMenuItemFocused$ = topMenuItemFocused$.pipe(
35
+ withLatestFrom(registeredHomeTopMenuItem$),
36
+ filter(([id, homeId]) => id === homeId)
37
+ );
38
+
39
+ export const emitHomeTopMenuItemRegistered = (id) => {
40
+ // save homeId on registration
41
+ registeredHomeTopMenuItemSubject$.next(id);
42
+ };
43
+
44
+ export const emitHomeTopMenuItemUnregistered = () => {
45
+ // reset homeId on unregistration
46
+ registeredHomeTopMenuItemSubject$.next(undefined);
47
+ };
48
+
49
+ const registeredScreenPickerContentContainerSubject$ =
50
+ new ReplaySubject<FocusableID>(1);
51
+
52
+ export const registeredScreenPickerContentContainer$ =
53
+ registeredScreenPickerContentContainerSubject$.asObservable();
54
+
55
+ export const emitScreenPickerContentContainerRegistered = (id) => {
56
+ // save screenPickerContentContainerId on registration
57
+ registeredScreenPickerContentContainerSubject$.next(id);
58
+ };
59
+
60
+ export const emitScreenPickerContentContainerUnregistered = () => {
61
+ // reset screenPickerContentContainerId on unregistration
62
+ registeredScreenPickerContentContainerSubject$.next(undefined);
63
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.0.0-alpha.1456157166",
3
+ "version": "15.0.0-alpha.2239032089",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.0.0-alpha.1456157166",
30
+ "@applicaster/applicaster-types": "15.0.0-alpha.2239032089",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -37,6 +37,15 @@ export const useFeedLoader = ({
37
37
  mapping,
38
38
  pipesOptions = {},
39
39
  }: Props): FeedLoaderResponse => {
40
+ useEffect(() => {
41
+ if (!feedUrl) {
42
+ logger.warning({
43
+ message: "Required parameter feedUrl is missing",
44
+ data: { feedUrl },
45
+ });
46
+ }
47
+ }, []);
48
+
40
49
  const isInitialRender = useIsInitialRender();
41
50
 
42
51
  const callableFeedUrl = useInflatedUrl({ feedUrl, mapping });
@@ -18,7 +18,6 @@ import {
18
18
  } from "@applicaster/zapp-pipes-v2-client";
19
19
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
20
20
  import { ENDPOINT_TAGS } from "../../types";
21
- import { isNilOrEmpty } from "../../reactUtils/helpers";
22
21
 
23
22
  /**
24
23
  * will match any occurrence in a string of one or more word characters
@@ -76,19 +75,15 @@ export const getInflatedDataSourceUrl: GetInflatedDataSourceUrl = ({
76
75
  * https://foo.com/shows/A1234
77
76
  */
78
77
 
79
- if (!isNilOrEmpty(mapping)) {
80
- if (!source) {
81
- if (__DEV__) {
82
- // eslint-disable-next-line no-console
83
- throw new Error(
84
- "getInflatedDataSourceUrl: source is empty while mapping is provided"
85
- );
86
- }
78
+ if (!source) {
79
+ // eslint-disable-next-line no-console
80
+ console.error("source is empty", {
81
+ source,
82
+ contexts,
83
+ mapping,
84
+ });
87
85
 
88
- return null;
89
- }
90
- } else {
91
- return source || null;
86
+ return null;
92
87
  }
93
88
 
94
89
  // Hack because in tv we expect to get key names instead of values from the fake entry
@@ -198,17 +193,28 @@ export function useInflatedUrl({
198
193
 
199
194
  const url = useMemo(
200
195
  () =>
201
- getInflatedDataSourceUrl({
202
- source: feedUrl,
203
- contexts: {
204
- entry: entryContext,
205
- screen: screenContext,
206
- search: getSearchContext(searchContext, mapping),
207
- },
208
- mapping,
209
- }),
210
- [entryContext, feedUrl, mapping, screenContext, searchContext]
196
+ mapping
197
+ ? getInflatedDataSourceUrl({
198
+ source: feedUrl,
199
+ contexts: {
200
+ entry: entryContext,
201
+ screen: screenContext,
202
+ search: getSearchContext(searchContext, mapping),
203
+ },
204
+ mapping,
205
+ })
206
+ : feedUrl,
207
+ [feedUrl, mapping]
211
208
  );
212
209
 
210
+ if (!feedUrl) {
211
+ logger.warning({
212
+ message: "Required parameter feedUrl is missing",
213
+ data: { feedUrl },
214
+ });
215
+
216
+ return null;
217
+ }
218
+
213
219
  return url;
214
220
  }
package/utils/index.ts CHANGED
@@ -34,4 +34,5 @@ export {
34
34
  last,
35
35
  toLower,
36
36
  isEqual as equals,
37
+ flowRight as compose,
37
38
  } from "lodash";