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

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 (86) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +60 -84
  2. package/actionsExecutor/ScreenActions.ts +164 -0
  3. package/actionsExecutor/StorageActions.ts +110 -0
  4. package/actionsExecutor/feedDecorator.ts +171 -0
  5. package/actionsExecutor/screenResolver.ts +11 -0
  6. package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
  7. package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
  8. package/analyticsUtils/__tests__/analyticsUtils.test.js +3 -0
  9. package/analyticsUtils/events.ts +8 -0
  10. package/appUtils/HooksManager/Hook.ts +4 -4
  11. package/appUtils/HooksManager/index.ts +11 -1
  12. package/appUtils/accessibilityManager/const.ts +13 -0
  13. package/appUtils/accessibilityManager/hooks.ts +35 -1
  14. package/appUtils/accessibilityManager/index.ts +152 -31
  15. package/appUtils/accessibilityManager/utils.ts +24 -0
  16. package/appUtils/contextKeysManager/contextResolver.ts +42 -1
  17. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +5 -0
  18. package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
  19. package/appUtils/focusManager/index.ios.ts +10 -0
  20. package/appUtils/focusManager/index.ts +82 -11
  21. package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
  22. package/appUtils/focusManagerAux/utils/index.ts +106 -3
  23. package/appUtils/platform/platformUtils.ts +31 -1
  24. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +0 -15
  25. package/appUtils/playerManager/useChapterMarker.tsx +0 -1
  26. package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
  27. package/arrayUtils/index.ts +1 -1
  28. package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
  29. package/componentsUtils/index.ts +4 -1
  30. package/configurationUtils/__tests__/manifestKeyParser.test.ts +546 -0
  31. package/configurationUtils/manifestKeyParser.ts +57 -32
  32. package/focusManager/FocusManager.ts +26 -16
  33. package/focusManager/Tree.ts +25 -21
  34. package/focusManager/__tests__/FocusManager.test.ts +50 -8
  35. package/index.d.ts +0 -9
  36. package/manifestUtils/defaultManifestConfigurations/player.js +24 -2
  37. package/navigationUtils/__tests__/mapContentTypesToRivers.test.ts +130 -0
  38. package/navigationUtils/index.ts +6 -4
  39. package/package.json +2 -3
  40. package/playerUtils/PlayerTTS/PlayerTTS.ts +359 -0
  41. package/playerUtils/PlayerTTS/index.ts +1 -0
  42. package/playerUtils/getPlayerActionButtons.ts +1 -1
  43. package/playerUtils/index.ts +51 -0
  44. package/playerUtils/usePlayerTTS.ts +21 -0
  45. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +3 -1
  46. package/reactHooks/cell-click/__tests__/index.test.js +3 -0
  47. package/reactHooks/cell-click/index.ts +8 -1
  48. package/reactHooks/debugging/__tests__/index.test.js +0 -1
  49. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +8 -2
  50. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
  51. package/reactHooks/feed/index.ts +2 -0
  52. package/reactHooks/feed/useBatchLoading.ts +16 -9
  53. package/reactHooks/feed/useFeedLoader.tsx +36 -34
  54. package/reactHooks/feed/useLoadPipesDataDispatch.ts +57 -0
  55. package/reactHooks/feed/usePipesCacheReset.ts +3 -3
  56. package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
  57. package/reactHooks/layout/__tests__/index.test.tsx +3 -1
  58. package/reactHooks/layout/isTablet/index.ts +12 -5
  59. package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +34 -36
  60. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -3
  61. package/reactHooks/layout/useLayoutVersion.ts +5 -5
  62. package/reactHooks/navigation/index.ts +7 -5
  63. package/reactHooks/navigation/useIsScreenActive.ts +9 -5
  64. package/reactHooks/navigation/useRoute.ts +7 -2
  65. package/reactHooks/navigation/useScreenStateStore.ts +8 -0
  66. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +4 -0
  67. package/reactHooks/screen/useScreenContext.ts +1 -1
  68. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
  69. package/reactHooks/state/index.ts +1 -1
  70. package/reactHooks/state/useHomeRiver.ts +4 -2
  71. package/reactHooks/state/useRivers.ts +7 -8
  72. package/riverComponetsMeasurementProvider/index.tsx +1 -1
  73. package/screenPickerUtils/index.ts +7 -0
  74. package/services/js2native.ts +1 -0
  75. package/storage/ScreenSingleValueProvider.ts +204 -0
  76. package/storage/ScreenStateMultiSelectProvider.ts +293 -0
  77. package/storage/StorageMultiSelectProvider.ts +192 -0
  78. package/storage/StorageSingleSelectProvider.ts +108 -0
  79. package/time/BackgroundTimer.ts +6 -4
  80. package/utils/__tests__/find.test.ts +36 -0
  81. package/utils/__tests__/pathOr.test.ts +37 -0
  82. package/utils/__tests__/startsWith.test.ts +30 -0
  83. package/utils/find.ts +3 -0
  84. package/utils/index.ts +12 -0
  85. package/utils/pathOr.ts +5 -0
  86. package/utils/startsWith.ts +9 -0
@@ -176,18 +176,30 @@ class FocusManager {
176
176
  }
177
177
  }
178
178
 
179
- registerFocusable(
180
- component: FocusManager.TouchableReactRef,
181
- parentFocusable: FocusManager.TouchableReactRef,
182
- isFocusableCell: boolean
183
- ) {
184
- const focusableId = getFocusableId(component);
179
+ registerFocusable({
180
+ touchableRef,
181
+ parentFocusableRef,
182
+ isFocusableCell,
183
+ parentFocusableId,
184
+ }: {
185
+ touchableRef: FocusManager.TouchableReactRef;
186
+ parentFocusableRef: FocusManager.TouchableReactRef;
187
+ isFocusableCell: boolean;
188
+ parentFocusableId: string;
189
+ }) {
190
+ const focusableId = getFocusableId(touchableRef);
191
+
185
192
  const focusableComponent = FocusManager.findFocusable(focusableId);
186
193
 
187
- if (!focusableComponent && component) {
188
- this.focusableComponents.push(component);
194
+ if (!focusableComponent && touchableRef) {
195
+ this.focusableComponents.push(touchableRef);
189
196
 
190
- this.tree.add(component, parentFocusable, isFocusableCell);
197
+ this.tree.add(
198
+ touchableRef,
199
+ parentFocusableRef,
200
+ isFocusableCell,
201
+ parentFocusableId
202
+ );
191
203
  } else {
192
204
  logger.warning("Focusable component already registered", {
193
205
  id: focusableId,
@@ -243,12 +255,10 @@ class FocusManager {
243
255
  }
244
256
 
245
257
  blurPrevious(options?: FocusManager.Android.CallbackOptions) {
246
- if (options) {
247
- FocusManager.instance.prevFocused?.onBlur?.(
248
- FocusManager.instance.prevFocused,
249
- options
250
- );
251
- }
258
+ FocusManager.instance.prevFocused?.onBlur?.(
259
+ FocusManager.instance.prevFocused,
260
+ options ?? {} // Adding fallback to avoid potential regression caused by #7509
261
+ );
252
262
  }
253
263
 
254
264
  onDisableFocusChange = (id) => {
@@ -269,7 +279,7 @@ class FocusManager {
269
279
 
270
280
  if (nextFocus) {
271
281
  // HACK: hack to fix the hack below
272
- // HACK: putting call to the end of the event loop so the next component has a chane to be registered
282
+ // HACK: putting call to the end of the event loop so the next component has a chance to be registered
273
283
  setTimeout(() => {
274
284
  FocusManager.instance.setFocus(nextFocus, {
275
285
  direction: "down",
@@ -8,37 +8,41 @@ export class Tree {
8
8
  this.tree = focusManagerTree;
9
9
  }
10
10
 
11
- add(component, parentFocusable, isFocusableCell) {
12
- const focusableId = getFocusableId(component);
13
- const parentId = getFocusableId(parentFocusable);
11
+ add(
12
+ touchableRef: FocusManager.TouchableReactRef,
13
+ parentFocusableRef: FocusManager.TouchableReactRef,
14
+ isFocusableCell: boolean,
15
+ parentFocusableId: string
16
+ ) {
17
+ const focusableId = getFocusableId(touchableRef);
18
+ const parentId = getFocusableId(parentFocusableRef) || parentFocusableId;
14
19
  const focusableComponentInTree = this.find(focusableId);
15
20
 
16
21
  // update node if it already exists
17
22
  if (focusableComponentInTree) {
18
- focusableComponentInTree.updateNode(component);
23
+ focusableComponentInTree.updateNode(touchableRef);
19
24
  }
20
25
 
21
- if (parentFocusable?.current) {
22
- if (!this.find(parentId)) {
23
- this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
24
- }
26
+ if (!this.find(parentId)) {
27
+ // create temporary node to the root of the tree
28
+ this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
29
+ }
25
30
 
26
- const parentNode = this.find(parentId);
31
+ const parentNode = this.find(parentId);
27
32
 
28
- if (parentNode) {
29
- if (focusableComponentInTree) {
30
- focusableComponentInTree.isFocusableCell = isFocusableCell;
31
- focusableComponentInTree.parentId = parentNode.id;
33
+ if (parentNode) {
34
+ if (focusableComponentInTree) {
35
+ focusableComponentInTree.isFocusableCell = isFocusableCell;
36
+ focusableComponentInTree.parentId = parentNode.id;
32
37
 
33
- parentNode.addChild(focusableComponentInTree);
38
+ parentNode.addChild(focusableComponentInTree);
34
39
 
35
- // remove root object from the list
36
- this.tree = this.tree.filter(
37
- (node) => node !== focusableComponentInTree
38
- );
39
- } else {
40
- parentNode.addChild(component, focusableId, isFocusableCell);
41
- }
40
+ // remove root object from the list
41
+ this.tree = this.tree.filter(
42
+ (node) => node !== focusableComponentInTree
43
+ );
44
+ } else {
45
+ parentNode.addChild(touchableRef, focusableId, isFocusableCell);
42
46
  }
43
47
  }
44
48
  }
@@ -1,5 +1,8 @@
1
1
  import { focusManager } from "../FocusManager";
2
2
 
3
+ const isFocusableCell = true;
4
+ const parentFocusableId = "parentFocusableId";
5
+
3
6
  const group = {
4
7
  current: {
5
8
  props: {
@@ -62,13 +65,47 @@ jest.useFakeTimers();
62
65
 
63
66
  describe("FocusManager", () => {
64
67
  beforeAll(() => {
65
- focusManager.registerFocusable(group, { current: null });
66
- focusManager.registerFocusable(child1, group);
67
- focusManager.registerFocusable(child2, group);
68
- focusManager.registerFocusable(child3, child2);
69
-
70
- focusManager.registerFocusable(child4, child2);
71
- focusManager.registerFocusable(child5, child2);
68
+ focusManager.registerFocusable({
69
+ touchableRef: group,
70
+ parentFocusableRef: { current: null },
71
+ isFocusableCell,
72
+ parentFocusableId,
73
+ });
74
+
75
+ focusManager.registerFocusable({
76
+ touchableRef: child1,
77
+ parentFocusableRef: group,
78
+ isFocusableCell,
79
+ parentFocusableId,
80
+ });
81
+
82
+ focusManager.registerFocusable({
83
+ touchableRef: child2,
84
+ parentFocusableRef: group,
85
+ isFocusableCell,
86
+ parentFocusableId,
87
+ });
88
+
89
+ focusManager.registerFocusable({
90
+ touchableRef: child3,
91
+ parentFocusableRef: child2,
92
+ isFocusableCell,
93
+ parentFocusableId,
94
+ });
95
+
96
+ focusManager.registerFocusable({
97
+ touchableRef: child4,
98
+ parentFocusableRef: child2,
99
+ isFocusableCell,
100
+ parentFocusableId,
101
+ });
102
+
103
+ focusManager.registerFocusable({
104
+ touchableRef: child5,
105
+ parentFocusableRef: child2,
106
+ isFocusableCell,
107
+ parentFocusableId,
108
+ });
72
109
  });
73
110
 
74
111
  it("focusManager should be defined", () => {
@@ -199,7 +236,12 @@ describe("FocusManager", () => {
199
236
  });
200
237
 
201
238
  it("focusManager registerFocusable should register", () => {
202
- focusManager.registerFocusable(child5, child2);
239
+ focusManager.registerFocusable({
240
+ touchableRef: child5,
241
+ parentFocusableRef: child2,
242
+ isFocusableCell,
243
+ parentFocusableId,
244
+ });
203
245
 
204
246
  expect(
205
247
  focusManager.isFocusableChildOf(child5.current.props.id, child2)
package/index.d.ts CHANGED
@@ -137,12 +137,3 @@ declare type AccessibilityState = {
137
137
  reduceMotionEnabled: boolean;
138
138
  boldTextEnabled: boolean;
139
139
  };
140
-
141
- declare type AccessibilityProps = {
142
- accessibilityLabel?: string;
143
- accessibilityHint?: string;
144
- "aria-label"?: string;
145
- "aria-description"?: string;
146
- accessibilityRole?: string;
147
- "aria-role"?: string;
148
- };
@@ -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: "Forward button",
211
+ initial_value: "Fast 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: "Back button",
295
+ initial_value: "Exit player button",
296
296
  label_tooltip: "Label for back button accessibility",
297
297
  type: "text_input",
298
298
  },
@@ -317,6 +317,20 @@ 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
+ },
320
334
  ],
321
335
  };
322
336
 
@@ -2985,6 +2999,14 @@ function getPlayerConfiguration({ platform, version }) {
2985
2999
  type: "uploader",
2986
3000
  default: "",
2987
3001
  },
3002
+ {
3003
+ key: "audio_player_background_image_overlay",
3004
+ label: "Background Image Overlay",
3005
+ label_tooltip:
3006
+ "Add a semi-transparent color overlay to improve text readability over the background image.",
3007
+ type: "color_picker_rgba",
3008
+ initial_value: "rgba(17, 17, 17, 0.5)",
3009
+ },
2988
3010
  {
2989
3011
  type: "text_input",
2990
3012
  label: "Item Image Key",
@@ -0,0 +1,130 @@
1
+ import { mapContentTypesToRivers } from "../index";
2
+
3
+ describe("mapContentTypesToRivers", () => {
4
+ it("should return the correct content types mapped to rivers", () => {
5
+ const state = {
6
+ rivers: {
7
+ "river-1": {
8
+ plugin_type: "river",
9
+ },
10
+ },
11
+ contentTypes: {
12
+ "content-type-1": {
13
+ screen_id: "river-1",
14
+ },
15
+ },
16
+ };
17
+
18
+ const result = mapContentTypesToRivers(state);
19
+
20
+ expect(result).toEqual({
21
+ "content-type-1": {
22
+ screenType: "river",
23
+ screen_id: "river-1",
24
+ },
25
+ });
26
+ });
27
+
28
+ it("should return null if contentTypes is undefined", () => {
29
+ const state = {
30
+ rivers: {
31
+ "river-1": {
32
+ plugin_type: "river",
33
+ },
34
+ },
35
+ // contentTypes is missing
36
+ };
37
+
38
+ const result = mapContentTypesToRivers(state);
39
+
40
+ expect(result).toBeNull();
41
+ });
42
+
43
+ it("should skip content types whose screen does not exist in rivers", () => {
44
+ const state = {
45
+ rivers: {
46
+ "river-1": {
47
+ plugin_type: "river",
48
+ },
49
+ },
50
+ contentTypes: {
51
+ "content-type-1": {
52
+ screen_id: "river-1",
53
+ },
54
+ "content-type-2": {
55
+ screen_id: "river-2", // river-2 does not exist
56
+ },
57
+ },
58
+ };
59
+
60
+ const result = mapContentTypesToRivers(state);
61
+
62
+ expect(result).toEqual({
63
+ "content-type-1": {
64
+ screenType: "river",
65
+ screen_id: "river-1",
66
+ },
67
+ });
68
+
69
+ // result is not null, but may be undefined for missing keys
70
+ expect(result && result["content-type-2"]).toBeUndefined();
71
+ });
72
+
73
+ it("should use 'type' if 'plugin_type' is not present in river", () => {
74
+ const state = {
75
+ rivers: {
76
+ "river-1": {
77
+ type: "custom-type",
78
+ },
79
+ },
80
+ contentTypes: {
81
+ "content-type-1": {
82
+ screen_id: "river-1",
83
+ },
84
+ },
85
+ };
86
+
87
+ const result = mapContentTypesToRivers(state);
88
+
89
+ expect(result).toEqual({
90
+ "content-type-1": {
91
+ screenType: "custom-type",
92
+ screen_id: "river-1",
93
+ },
94
+ });
95
+ });
96
+
97
+ it("should skip content types if neither plugin_type nor type is present in river", () => {
98
+ const state = {
99
+ rivers: {
100
+ "river-1": {
101
+ // no plugin_type or type
102
+ },
103
+ },
104
+ contentTypes: {
105
+ "content-type-1": {
106
+ screen_id: "river-1",
107
+ },
108
+ },
109
+ };
110
+
111
+ const result = mapContentTypesToRivers(state);
112
+
113
+ expect(result).toEqual({});
114
+ });
115
+
116
+ it("should handle empty contentTypes object", () => {
117
+ const state = {
118
+ rivers: {
119
+ "river-1": {
120
+ plugin_type: "river",
121
+ },
122
+ },
123
+ contentTypes: {},
124
+ };
125
+
126
+ const result = mapContentTypesToRivers(state);
127
+
128
+ expect(result).toEqual({});
129
+ });
130
+ });
@@ -13,6 +13,7 @@ import {
13
13
  isPlayable,
14
14
  isV2River,
15
15
  } from "./itemTypeMatchers";
16
+ import { RootState } from "@applicaster/zapp-react-native-redux/store";
16
17
 
17
18
  type PathAttribute = {
18
19
  screenType: string;
@@ -377,10 +378,11 @@ export const usesVideoModal = (
377
378
  return targetScreenConfiguration?.styles?.use_video_modal;
378
379
  };
379
380
 
380
- export const mapContentTypesToRivers = ({
381
- rivers,
382
- contentTypes,
383
- }): ZappContentTypesMapped | null => {
381
+ export const mapContentTypesToRivers = (
382
+ state: Partial<RootState>
383
+ ): ZappContentTypesMapped | null => {
384
+ const { rivers, contentTypes } = state;
385
+
384
386
  if (!contentTypes) {
385
387
  return null;
386
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "14.0.0-alpha.3259144304",
3
+ "version": "14.0.0-alpha.3514550494",
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.3259144304",
30
+ "@applicaster/applicaster-types": "14.0.0-alpha.3514550494",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -38,7 +38,6 @@
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
40
40
  "@react-native-community/netinfo": "*",
41
- "immer": "*",
42
41
  "react": "*",
43
42
  "react-native": "*",
44
43
  "uglify-js": "*",