@applicaster/zapp-react-native-utils 14.0.0-alpha.3514550494 → 14.0.0-alpha.3652810444

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.
@@ -0,0 +1,167 @@
1
+ import {
2
+ isNil,
3
+ startsWith,
4
+ find,
5
+ pathOr,
6
+ } from "@applicaster/zapp-react-native-utils/utils";
7
+
8
+ import {
9
+ QUICK_BRICK_CONTENT,
10
+ QUICK_BRICK_NAVBAR,
11
+ QUICK_BRICK_NAVBAR_SECTIONS,
12
+ } from "@applicaster/quick-brick-core/const";
13
+
14
+ const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
15
+ const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
16
+
17
+ // SCREEN_PICKER_SELECTOR_CONTAINER(we assume there is only one SCREEN_PICKER)
18
+ let screenPickerSelectorContainerId;
19
+
20
+ export const onRegisterScreenPickerSelectorContainer = (id) => {
21
+ screenPickerSelectorContainerId = id;
22
+ };
23
+
24
+ export const onUnregisterScreenPickerSelectorContainer = (id) => {
25
+ // reset screenSelectorId on unregistration
26
+ if (screenPickerSelectorContainerId === id) {
27
+ screenPickerSelectorContainerId = undefined;
28
+ }
29
+ };
30
+ // SCREEN_PICKER_SELECTOR_CONTAINER
31
+
32
+ // SCREEN_PICKER_CONTENT_CONTAINER(we assume there is only one SCREEN_PICKER)
33
+ let screenPickerContentContainerId;
34
+
35
+ export const onRegisterScreenPickerContentContainer = (id) => {
36
+ screenPickerContentContainerId = id;
37
+ };
38
+
39
+ export const onUnregisterScreenPickerContentContainer = (id) => {
40
+ // reset screenSelectorId on unregistration
41
+ if (screenPickerContentContainerId === id) {
42
+ screenPickerContentContainerId = undefined;
43
+ }
44
+ };
45
+
46
+ const isScreenPickerContentContainer = (node) =>
47
+ screenPickerContentContainerId === node?.id;
48
+
49
+ // SCREEN_PICKER_CONTENT_CONTAINER
50
+
51
+ const findSelectedMenuIdInSection = (focusableTree, section) => {
52
+ const children = pathOr([], ["children"], focusableTree.find(section));
53
+
54
+ return find((child) => child.component.current.props.isSelected(), children)
55
+ ?.id;
56
+ };
57
+
58
+ export const findSelectedMenuId = (focusableTree) => {
59
+ const selectedMenuItemIdInLeftSection = findSelectedMenuIdInSection(
60
+ focusableTree,
61
+ QUICK_BRICK_NAVBAR_SECTIONS.left
62
+ );
63
+
64
+ if (selectedMenuItemIdInLeftSection) {
65
+ return selectedMenuItemIdInLeftSection;
66
+ }
67
+
68
+ const selectedMenuItemIdInMenuSection = findSelectedMenuIdInSection(
69
+ focusableTree,
70
+ QUICK_BRICK_NAVBAR_SECTIONS.menu
71
+ );
72
+
73
+ if (selectedMenuItemIdInMenuSection) {
74
+ return selectedMenuItemIdInMenuSection;
75
+ }
76
+
77
+ const selectedMenuItemIdInRightSection = findSelectedMenuIdInSection(
78
+ focusableTree,
79
+ QUICK_BRICK_NAVBAR_SECTIONS.right
80
+ );
81
+
82
+ if (selectedMenuItemIdInRightSection) {
83
+ return selectedMenuItemIdInRightSection;
84
+ }
85
+
86
+ return undefined;
87
+ };
88
+
89
+ export const findSelectedTabId = (focusableTree, item: ZappEntry): string => {
90
+ const screenSelectorContainerNode = focusableTree.find(
91
+ screenPickerSelectorContainerId
92
+ );
93
+
94
+ const selectedTabId = find(
95
+ (child) => child.component.current.props.isSelected(item.id),
96
+ screenSelectorContainerNode.children
97
+ )?.id;
98
+
99
+ return selectedTabId;
100
+ };
101
+
102
+ export const isTabsScreenContentFocused = (focusableTree, id) => {
103
+ const node = focusableTree.find(id);
104
+
105
+ if (isNil(node)) {
106
+ return false;
107
+ }
108
+
109
+ if (isNavBar(node)) {
110
+ return false;
111
+ }
112
+
113
+ if (isContent(node)) {
114
+ return false;
115
+ }
116
+
117
+ if (isScreenPickerContentContainer(node)) {
118
+ return true;
119
+ }
120
+
121
+ return isTabsScreenContentFocused(focusableTree, node.parentId);
122
+ };
123
+
124
+ export const isCurrentFocusOnMenu = (focusableTree, id): boolean => {
125
+ const node = focusableTree.find(id);
126
+
127
+ if (isNil(node)) {
128
+ return false;
129
+ }
130
+
131
+ if (isNavBar(node)) {
132
+ return true;
133
+ }
134
+
135
+ if (isContent(node)) {
136
+ return false;
137
+ }
138
+
139
+ return isCurrentFocusOnMenu(focusableTree, node.parentId);
140
+ };
141
+
142
+ export const isCurrentFocusOnContent = (focusableTree, id) => {
143
+ const node = focusableTree.find(id);
144
+
145
+ if (isNil(node)) {
146
+ return false;
147
+ }
148
+
149
+ if (isNavBar(node)) {
150
+ return false;
151
+ }
152
+
153
+ if (isContent(node)) {
154
+ return true;
155
+ }
156
+
157
+ return isCurrentFocusOnContent(focusableTree, node.parentId);
158
+ };
159
+
160
+ export const contextWithoutScrolling = (
161
+ source: FocusManager.FocusContext["source"]
162
+ ): FocusManager.FocusContext => {
163
+ return {
164
+ source,
165
+ preserveScroll: true,
166
+ };
167
+ };
@@ -4,11 +4,11 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
4
4
 
5
5
  export const getFocusableId = (ref) => ref?.current?.props.id;
6
6
 
7
- type Direction = "up" | "down" | "left" | "right";
8
-
9
7
  const normalizeDirection = (direction) => direction.toLowerCase();
10
8
 
11
- const checkDirection = (direction: Direction) => {
9
+ const checkDirection = (
10
+ direction: FocusManager.Android.FocusNavigationDirections
11
+ ) => {
12
12
  invariant(!isNilOrEmpty(direction), "direction should not be empty");
13
13
 
14
14
  invariant(
@@ -17,19 +17,25 @@ const checkDirection = (direction: Direction) => {
17
17
  );
18
18
  };
19
19
 
20
- export const toFocusDirection = (direction: Direction) => {
20
+ export const toFocusDirection = (
21
+ direction: FocusManager.Android.FocusNavigationDirections
22
+ ) => {
21
23
  checkDirection(direction);
22
24
 
23
25
  return `nextFocus${capitalize(normalizeDirection(direction))}`;
24
26
  };
25
27
 
26
- export const isHorizontalDirection = (direction: Direction) => {
28
+ export const isHorizontalDirection = (
29
+ direction: FocusManager.Android.FocusNavigationDirections
30
+ ) => {
27
31
  checkDirection(direction);
28
32
 
29
33
  return ["left", "right"].includes(normalizeDirection(direction));
30
34
  };
31
35
 
32
- export const isVerticalDirection = (direction: Direction) => {
36
+ export const isVerticalDirection = (
37
+ direction: FocusManager.Android.FocusNavigationDirections
38
+ ) => {
33
39
  checkDirection(direction);
34
40
 
35
41
  return ["up", "down"].includes(normalizeDirection(direction));
@@ -208,7 +208,7 @@ function getPlayerConfiguration({ platform, version }) {
208
208
  {
209
209
  key: "accessibility_forward_label",
210
210
  label: "Accessibility forward label",
211
- initial_value: "Fast forward button",
211
+ initial_value: "Forward button",
212
212
  label_tooltip: "Label for forward button accessibility",
213
213
  type: "text_input",
214
214
  },
@@ -292,7 +292,7 @@ function getPlayerConfiguration({ platform, version }) {
292
292
  {
293
293
  key: "accessibility_back_label",
294
294
  label: "Accessibility back label",
295
- initial_value: "Exit player button",
295
+ initial_value: "Back button",
296
296
  label_tooltip: "Label for back button accessibility",
297
297
  type: "text_input",
298
298
  },
@@ -317,20 +317,6 @@ function getPlayerConfiguration({ platform, version }) {
317
317
  label_tooltip: "Hint for fullscreen button accessibility",
318
318
  type: "text_input",
319
319
  },
320
- {
321
- key: "accessibility_skip_intro_label",
322
- label: "Accessibility skip intro label",
323
- initial_value: "Skip intro - button",
324
- label_tooltip: "Label for skip intro button accessibility",
325
- type: "text_input",
326
- },
327
- {
328
- key: "accessibility_skip_intro_hint",
329
- label: "Accessibility skip intro hint",
330
- initial_value: "Press to skip intro",
331
- label_tooltip: "Hint for skip intro button accessibility",
332
- type: "text_input",
333
- },
334
320
  ],
335
321
  };
336
322
 
@@ -42,7 +42,7 @@ export function getNavigationType(
42
42
  R.unless(R.isNil, R.prop("navigation_type")),
43
43
  R.defaultTo(undefined),
44
44
  R.find(R.propEq("category", category))
45
- )(navigations);
45
+ )(navigations || []);
46
46
  }
47
47
 
48
48
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "14.0.0-alpha.3514550494",
3
+ "version": "14.0.0-alpha.3652810444",
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": "14.0.0-alpha.3514550494",
30
+ "@applicaster/applicaster-types": "14.0.0-alpha.3652810444",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -13,5 +13,5 @@ export const getPlayerActionButtons = (configuration: any) => {
13
13
  return [];
14
14
  }
15
15
 
16
- return take(map(buttonsString.split(","), trim), 2);
16
+ return take(2, map(buttonsString.split(","), trim));
17
17
  };
@@ -30,7 +30,13 @@ export const useLoadPipesDataDispatch = () => {
30
30
  return React.useCallback(
31
31
  (
32
32
  url: string,
33
- options = {},
33
+ options: {
34
+ callback?: (data: unknown, error?: Error | null | undefined) => void;
35
+ riverId?: string;
36
+ clearCache?: boolean;
37
+ silentRefresh?: boolean;
38
+ parentFeed?: string;
39
+ } = {},
34
40
  {
35
41
  withResolvers = false,
36
42
  withScreenRouteMapping = false,
@@ -5,3 +5,9 @@ export const getPickerSelectorId = (id) => `PickerSelector.${id}`;
5
5
  export const SCREEN_PICKER_CONTAINER = "ScreenPickerContainer";
6
6
 
7
7
  export const getScreenPickerId = (id) => `${SCREEN_PICKER_CONTAINER}.${id}`;
8
+
9
+ export const getScreenPickerSelectorContainerId = (id) =>
10
+ `${SCREEN_PICKER_CONTAINER}.${id}-screen-selector`;
11
+
12
+ export const getScreenPickerContentContainerId = (id) =>
13
+ `${SCREEN_PICKER_CONTAINER}.${id}-screen-container`;
@@ -0,0 +1,30 @@
1
+ import { endsWith } from "../endsWith";
2
+
3
+ describe("endsWith", () => {
4
+ it("returns false when str is null", () => {
5
+ expect(endsWith("a", null)).toBe(false);
6
+ });
7
+
8
+ it("returns false when str is undefined", () => {
9
+ expect(endsWith("a", undefined)).toBe(false);
10
+ });
11
+
12
+ it("returns true when string ends with target", () => {
13
+ expect(endsWith("lo", "hello")).toBe(true);
14
+ expect(endsWith("", "hello")).toBe(true); // empty target always matches
15
+ });
16
+
17
+ it("returns false when string does not end with target", () => {
18
+ expect(endsWith("yo", "hello")).toBe(false);
19
+ });
20
+
21
+ it("works with single character target", () => {
22
+ expect(endsWith("o", "hello")).toBe(true);
23
+ expect(endsWith("x", "hello")).toBe(false);
24
+ });
25
+
26
+ it("is case-sensitive", () => {
27
+ expect(endsWith("Lo", "hello")).toBe(false);
28
+ expect(endsWith("lo", "hello")).toBe(true);
29
+ });
30
+ });
@@ -0,0 +1,65 @@
1
+ import { equals } from "../equals";
2
+
3
+ describe("equals", () => {
4
+ it("returns true for two identical primitive values", () => {
5
+ expect(equals(5, 5)).toBe(true);
6
+ expect(equals("hello", "hello")).toBe(true);
7
+ expect(equals(true, true)).toBe(true);
8
+ });
9
+
10
+ it("returns false for two different primitive values", () => {
11
+ expect(equals(5, 10)).toBe(false);
12
+ expect(equals("hello", "world")).toBe(false);
13
+ expect(equals(true, false)).toBe(false);
14
+ });
15
+
16
+ it("returns true for deeply equal objects", () => {
17
+ const a = { x: 1, y: { z: 2 } };
18
+ const b = { x: 1, y: { z: 2 } };
19
+ expect(equals(a, b)).toBe(true);
20
+ });
21
+
22
+ it("returns false for objects with different values", () => {
23
+ const a = { x: 1, y: { z: 2 } };
24
+ const b = { x: 1, y: { z: 3 } };
25
+ expect(equals(a, b)).toBe(false);
26
+ });
27
+
28
+ it("returns true for arrays with same elements", () => {
29
+ expect(equals([1, 2, 3], [1, 2, 3])).toBe(true);
30
+ });
31
+
32
+ it("returns false for arrays with different elements", () => {
33
+ expect(equals([1, 2, 3], [1, 2, 4])).toBe(false);
34
+ });
35
+
36
+ it("returns true for nested arrays/objects", () => {
37
+ const a = [{ id: 1, data: [1, 2, 3] }];
38
+ const b = [{ id: 1, data: [1, 2, 3] }];
39
+ expect(equals(a, b)).toBe(true);
40
+ });
41
+
42
+ it("returns false for arrays with different order", () => {
43
+ expect(equals([1, 2, 3], [3, 2, 1])).toBe(false);
44
+ });
45
+
46
+ it("handles null and undefined correctly", () => {
47
+ expect(equals(null, null)).toBe(true);
48
+ expect(equals(undefined, undefined)).toBe(true);
49
+ expect(equals(null, undefined)).toBe(false);
50
+ });
51
+
52
+ it("handles dates correctly", () => {
53
+ const d1 = new Date("2020-01-01");
54
+ const d2 = new Date("2020-01-01");
55
+ const d3 = new Date("2021-01-01");
56
+
57
+ expect(equals(d1, d2)).toBe(true);
58
+ expect(equals(d1, d3)).toBe(false);
59
+ });
60
+
61
+ it("handles regex correctly", () => {
62
+ expect(equals(/abc/, /abc/)).toBe(true);
63
+ expect(equals(/abc/i, /abc/)).toBe(false);
64
+ });
65
+ });
@@ -0,0 +1,36 @@
1
+ import { max } from "../max";
2
+
3
+ describe("max", () => {
4
+ describe("for numbers", () => {
5
+ it("returns the first argument when it is greater", () => {
6
+ expect(max(10, 5)).toBe(10);
7
+ });
8
+
9
+ it("returns the second argument when it is greater", () => {
10
+ expect(max(3, 7)).toBe(7);
11
+ });
12
+
13
+ it("returns the same value when both arguments are equal", () => {
14
+ expect(max(4, 4)).toBe(4);
15
+ });
16
+
17
+ it("works with negative numbers", () => {
18
+ expect(max(-2, -5)).toBe(-2);
19
+ });
20
+
21
+ it("works when one argument is negative and the other is positive", () => {
22
+ expect(max(-10, 20)).toBe(20);
23
+ });
24
+
25
+ it("works with zeros", () => {
26
+ expect(max(0, 0)).toBe(0);
27
+ expect(max(0, -1)).toBe(0);
28
+ });
29
+ });
30
+
31
+ describe("for letters", () => {
32
+ it("returns the second argument when it is greater", () => {
33
+ expect(max("a", "b")).toBe("b");
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,19 @@
1
+ import { omit } from "../omit";
2
+
3
+ test("example 1", () => {
4
+ const path = ["a", "b", "c"];
5
+ const record = { a: 1, b: 2, c: 3 };
6
+
7
+ const output = {};
8
+
9
+ expect(omit(path, record)).toEqual(output);
10
+ });
11
+
12
+ test("example 2", () => {
13
+ const path = ["a", "b"];
14
+ const record = { a: 1, b: 2, c: 3 };
15
+
16
+ const output = { c: 3 };
17
+
18
+ expect(omit(path, record)).toEqual(output);
19
+ });
@@ -0,0 +1,33 @@
1
+ import { path } from "../path";
2
+
3
+ test("example 1", () => {
4
+ const route = ["a", "b", "c"];
5
+ const xs = { a: { b: { c: 1 } } };
6
+
7
+ const output = 1;
8
+
9
+ expect(path(route, xs)).toEqual(output);
10
+ });
11
+
12
+ test("example 2", () => {
13
+ const route = ["a", "b"];
14
+ const xs = { a: { b: { c: 1 } } };
15
+
16
+ const output = { c: 1 };
17
+
18
+ expect(path(route, xs)).toEqual(output);
19
+ });
20
+
21
+ test("example 3", () => {
22
+ const route = ["a", "b", "x"];
23
+ const xs = { a: { b: { c: 1 } } };
24
+
25
+ expect(path(route, xs)).toBeUndefined();
26
+ });
27
+
28
+ test("example 4", () => {
29
+ const route = ["a", "b", "c"];
30
+ const xs = undefined;
31
+
32
+ expect(path(route, xs)).toBeUndefined();
33
+ });
@@ -0,0 +1,40 @@
1
+ import { take } from "../take";
2
+
3
+ describe("take", () => {
4
+ it("takes n elements from the beginning", () => {
5
+ expect(take(2, [1, 2, 3])).toEqual([1, 2]);
6
+ });
7
+
8
+ it("returns the whole array if n is larger than length", () => {
9
+ expect(take(5, [1, 2, 3])).toEqual([1, 2, 3]);
10
+ });
11
+
12
+ it("returns empty array if n is 0", () => {
13
+ expect(take(0, [1, 2, 3])).toEqual([]);
14
+ });
15
+
16
+ it("returns empty array for empty input array", () => {
17
+ expect(take(2, [])).toEqual([]);
18
+ });
19
+
20
+ it("returns empty array if n is negative", () => {
21
+ expect(take(-1, [1, 2, 3])).toEqual([]);
22
+ });
23
+
24
+ it("works with strings in array", () => {
25
+ expect(take(2, ["a", "b", "c"])).toEqual(["a", "b"]);
26
+ });
27
+
28
+ it("works with objects in array", () => {
29
+ const arr = [{ id: 1 }, { id: 2 }];
30
+ expect(take(1, arr)).toEqual([{ id: 1 }]);
31
+ });
32
+
33
+ it("returns empty array if input is not an array", () => {
34
+ // @ts-expect-error testing non-array input
35
+ expect(take(2, null)).toEqual([]);
36
+
37
+ // @ts-expect-error testing non-array input
38
+ expect(take(2, undefined)).toEqual([]);
39
+ });
40
+ });
@@ -0,0 +1,39 @@
1
+ import { toLower } from "../toLower";
2
+
3
+ describe("toLower", () => {
4
+ it("converts mixed case string to lowercase", () => {
5
+ expect(toLower("--Foo-Bar--")).toBe("--foo-bar--");
6
+ expect(toLower("fooBar")).toBe("foobar");
7
+ expect(toLower("__FOO_BAR__")).toBe("__foo_bar__");
8
+ });
9
+
10
+ it("returns the same string if already lowercase", () => {
11
+ expect(toLower("hello")).toBe("hello");
12
+ });
13
+
14
+ it("converts uppercase string to lowercase", () => {
15
+ expect(toLower("HELLO")).toBe("hello");
16
+ });
17
+
18
+ it("handles empty string", () => {
19
+ expect(toLower("")).toBe("");
20
+ });
21
+
22
+ it("converts string with numbers and symbols", () => {
23
+ expect(toLower("123-ABC-xyz")).toBe("123-abc-xyz");
24
+ });
25
+
26
+ it("handles null and undefined gracefully", () => {
27
+ // @ts-expect-error testing null input
28
+ expect(toLower(null)).toBe("");
29
+ // @ts-expect-error testing undefined input
30
+ expect(toLower(undefined)).toBe("");
31
+ });
32
+
33
+ it("coerces non-string values to string before lowercasing", () => {
34
+ // @ts-expect-error testing number input
35
+ expect(toLower(12345)).toBe("12345");
36
+ // @ts-expect-error testing boolean input
37
+ expect(toLower(true)).toBe("true");
38
+ });
39
+ });
@@ -0,0 +1,9 @@
1
+ import { isNil } from "lodash";
2
+
3
+ export const endsWith = (target, str) => {
4
+ if (isNil(str)) {
5
+ return false;
6
+ }
7
+
8
+ return str.endsWith(target);
9
+ };
@@ -0,0 +1,5 @@
1
+ import { isEqual } from "lodash";
2
+
3
+ export function equals(a: any, b: any): boolean {
4
+ return isEqual(a, b);
5
+ }
package/utils/index.ts CHANGED
@@ -8,6 +8,20 @@ export { find } from "./find";
8
8
 
9
9
  export { pathOr } from "./pathOr";
10
10
 
11
+ export { path } from "./path";
12
+
13
+ export { omit } from "./omit";
14
+
15
+ export { endsWith } from "./endsWith";
16
+
17
+ export { max } from "./max";
18
+
19
+ export { equals } from "./equals";
20
+
21
+ export { take } from "./take";
22
+
23
+ export { toLower } from "./toLower";
24
+
11
25
  export {
12
26
  cloneDeep as clone,
13
27
  flatten,
@@ -19,7 +33,6 @@ export {
19
33
  has,
20
34
  flatMap,
21
35
  difference,
22
- take,
23
36
  pick,
24
37
  map,
25
38
  trim,
package/utils/max.ts ADDED
@@ -0,0 +1,5 @@
1
+ type Value = number | string;
2
+
3
+ export function max(a: Value, b: Value): Value {
4
+ return a > b ? a : b;
5
+ }
package/utils/omit.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { omit as Lodash_omit } from "lodash";
2
+
3
+ export const omit = (path, record) => {
4
+ return Lodash_omit(record, path);
5
+ };
package/utils/path.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { get } from "lodash";
2
+
3
+ export const path = (route, record) => {
4
+ return get(record, route, undefined);
5
+ };
package/utils/take.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { take as Ltake } from "lodash";
2
+
3
+ export function take<T>(n: number, xs: T[]): T[] {
4
+ return Ltake(xs, n);
5
+ }
@@ -0,0 +1,5 @@
1
+ import { toLower as L_toLower } from "lodash";
2
+
3
+ export function toLower(value: Option<string>): string {
4
+ return L_toLower(value);
5
+ }