@applicaster/zapp-react-native-utils 13.0.0-alpha.8357105823 → 13.0.0-alpha.8432878190

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 (45) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutorContext.tsx +5 -2
  3. package/appUtils/HooksManager/Hook.ts +2 -2
  4. package/appUtils/HooksManager/types.ts +2 -2
  5. package/appUtils/contextKeysManager/contextResolver.ts +6 -2
  6. package/appUtils/contextKeysManager/index.ts +2 -2
  7. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  8. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -0
  9. package/appUtils/focusManager/index.ts +11 -3
  10. package/appUtils/platform/platformUtils.ts +30 -3
  11. package/appUtils/playerManager/player.ts +2 -2
  12. package/equalUtils/index.ts +10 -3
  13. package/focusManager/FocusManager.ts +11 -1
  14. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  15. package/idleUtils/index.ts +1 -1
  16. package/idleUtils/withTimeout.ts +15 -2
  17. package/manifestUtils/__tests__/createConfig.test.js +0 -2
  18. package/navigationUtils/index.ts +3 -3
  19. package/package.json +2 -2
  20. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  21. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  22. package/reactHooks/navigation/index.ts +7 -19
  23. package/reactHooks/navigation/useGetTabBarHeight.ts +1 -3
  24. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  25. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +5 -0
  26. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +1 -1
  27. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  28. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  29. package/reactHooks/usePluginConfiguration.ts +1 -1
  30. package/reactHooks/useSubscriberFor.ts +4 -3
  31. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  32. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  33. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +6 -72
  34. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  35. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  36. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  37. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  38. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  39. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  40. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  41. package/screenState/index.ts +24 -10
  42. package/testUtils/index.tsx +0 -10
  43. package/theme/index.ts +1 -1
  44. package/time/Timer.ts +4 -1
  45. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
package/README.md CHANGED
@@ -376,16 +376,6 @@ useEffect(() => {
376
376
  }, []);
377
377
  ```
378
378
 
379
- ### testUtils
380
-
381
- `@applicaster/zapp-react-native-utils/testUtils`
382
-
383
- - `testIDEquals: (testId: any) => boolean | { width: number, height: number }` - Function to be used in tandem with enzyme findWhere
384
-
385
- ```javascript
386
- wrapper.findWhere(testIDEquals("text"));
387
- ```
388
-
389
379
  ### appUtils - contextKeysManager
390
380
 
391
381
  `@applicaster/zapp-react-native-utils/appUtils/contextKeyManager`
@@ -165,9 +165,12 @@ const prepareDefaultActions = (actionExecutor) => {
165
165
 
166
166
  actionExecutor.registerAction(
167
167
  "localStorageToggleFlag",
168
- async (action: ActionType, entry?: ZappEntry): Promise<ActionResult> => {
168
+ async (
169
+ action: ActionType,
170
+ context?: Record<string, any>
171
+ ): Promise<ActionResult> => {
169
172
  const keyNamespace = action.options?.key;
170
- const tag = entry?.extensions?.tag;
173
+ const tag = context?.entry?.extensions?.tag;
171
174
 
172
175
  if (keyNamespace && tag) {
173
176
  const multiSelectProvider =
@@ -16,7 +16,7 @@ const BASE_HOOK_PROPERTIES = ["screen_id", "identifier", "weight"];
16
16
  * @returns {number} index
17
17
  */
18
18
  const hookState: (
19
- arg0: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS]
19
+ arg0: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS]
20
20
  ) => number = R.indexOf(R.__, R.values(HOOKS_EVENTS));
21
21
 
22
22
  /**
@@ -62,7 +62,7 @@ export class Hook implements HookInterface {
62
62
  * @param {Array<Any>} args variadic arguments to invoke the handler with
63
63
  */
64
64
  setStateAndNotify(
65
- event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
65
+ event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
66
66
  ...args
67
67
  ) {
68
68
  this.state = hookState(event);
@@ -103,7 +103,7 @@ export interface Hook<T extends HookModule = HookModule> {
103
103
  identifier: string;
104
104
  configuration: T["configuration"];
105
105
  setStateAndNotify(
106
- event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
106
+ event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
107
107
  opts: {
108
108
  error?: typeof Error;
109
109
  route?: string;
@@ -112,7 +112,7 @@ export interface Hook<T extends HookModule = HookModule> {
112
112
  }
113
113
  );
114
114
  general?: {
115
- transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
115
+ transition_type: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS];
116
116
  allow_screen_plugin_presentation: boolean;
117
117
  is_flow_blocker: boolean;
118
118
  };
@@ -42,12 +42,16 @@ export const resolveObjectValues = async (
42
42
 
43
43
  const resolvedEntries = await Promise.all(
44
44
  entries.map(async ([key, value]) => {
45
- const regex = /@{([^/]+)\/([^}]*)}/;
46
-
47
45
  if (typeof value !== "string") {
48
46
  return [key, value];
49
47
  }
50
48
 
49
+ if (!value.startsWith("@")) {
50
+ return [key, value];
51
+ }
52
+
53
+ const regex = /@{([^/]+)\/([^}]*)}/;
54
+
51
55
  const match = (value as string).match(regex);
52
56
 
53
57
  if (match) {
@@ -16,12 +16,12 @@ import {
16
16
 
17
17
  export { StorageLevel };
18
18
 
19
- type KeyNameObj = {
19
+ export type KeyNameObj = {
20
20
  namespace: string;
21
21
  key: string;
22
22
  };
23
23
 
24
- type KeyName = string | KeyNameObj;
24
+ export type KeyName = string | KeyNameObj;
25
25
 
26
26
  type ParsedKeyAndNamespace = {
27
27
  namespace?: string;
@@ -1,10 +1,11 @@
1
1
  import * as R from "ramda";
2
2
  import { DEFAULT_NAMESPACE } from "../consts";
3
+ import { KeyName, KeyNameObj } from "../index";
3
4
 
4
5
  const lastDotRegex = /\.([^.]+)$/;
5
6
  const splitByLastDot = R.compose(R.init, R.split(lastDotRegex));
6
7
 
7
- export function getNamespaceAndKey(namespacedKey) {
8
+ export function getNamespaceAndKey(namespacedKey: KeyName): KeyNameObj {
8
9
  if (typeof namespacedKey !== "string") return namespacedKey;
9
10
 
10
11
  const namespacedKeyProps = namespacedKey.includes(".")
@@ -28,6 +28,7 @@ exports[`focusManager should be defined 1`] = `
28
28
  "moveFocus": [Function],
29
29
  "on": [Function],
30
30
  "press": [Function],
31
+ "pressIn": [Function],
31
32
  "pressOut": [Function],
32
33
  "recoverFocus": [Function],
33
34
  "register": [Function],
@@ -13,6 +13,7 @@ import {
13
13
  import { subscriber } from "../../functionUtils";
14
14
  import { coreLogger } from "../../logger";
15
15
  import { ACTION } from "./utils/enums";
16
+
16
17
  const logger = coreLogger.addSubsystem("focusManager");
17
18
 
18
19
  const isFocusEnabled = (focusableItem): boolean => {
@@ -325,8 +326,6 @@ export const focusManager = (function () {
325
326
  },
326
327
  });
327
328
 
328
- currentFocusNode = focusCandidate;
329
-
330
329
  focusableItem && setFocus(focusCandidate.id, null);
331
330
 
332
331
  return { success: true };
@@ -346,6 +345,14 @@ export const focusManager = (function () {
346
345
  });
347
346
  }
348
347
 
348
+ function pressIn() {
349
+ const currentFocusable = getCurrentFocus();
350
+
351
+ if (currentFocusable) {
352
+ currentFocusable.pressIn(null);
353
+ }
354
+ }
355
+
349
356
  /**
350
357
  * calls the `press` method on the current focus component
351
358
  * @public
@@ -477,7 +484,7 @@ export const focusManager = (function () {
477
484
  function isCurrentFocusOnTheTopScreen() {
478
485
  const routes = R.pathOr([], ["root", "children"], focusableTree);
479
486
 
480
- if (routes.length <= 1) {
487
+ if (currentFocusNode && routes.length <= 1) {
481
488
  // there is only one or zero routes
482
489
  return true;
483
490
  }
@@ -553,6 +560,7 @@ export const focusManager = (function () {
553
560
  invokeHandler,
554
561
  removeHandler,
555
562
  longPress,
563
+ pressIn,
556
564
  pressOut,
557
565
  enableFocus,
558
566
  setInitialFocus,
@@ -77,13 +77,22 @@ export class ClosedCaptioningManager {
77
77
 
78
78
  private constructor() {
79
79
  this.initialize();
80
+
81
+ window["vizioDebug"] = {
82
+ setCCEnabled: (isCCEnabled: boolean) => {
83
+ this.ccState$.next(isCCEnabled);
84
+ },
85
+ };
80
86
  }
81
87
 
82
88
  static getInstance(): ClosedCaptioningManager {
83
89
  if (!ClosedCaptioningManager.ccManagerInstance) {
90
+ log_debug("ClosedCaptioningManager: Creating new instance");
84
91
  ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
85
92
  }
86
93
 
94
+ log_debug("ClosedCaptioningManager: Returning existing instance");
95
+
87
96
  return ClosedCaptioningManager.ccManagerInstance;
88
97
  }
89
98
 
@@ -92,23 +101,41 @@ export class ClosedCaptioningManager {
92
101
  PLATFORM_KEYS.deviceClosedCaptioningEnabled
93
102
  );
94
103
 
95
- log_debug("Initializing closed captioning manager", { existingState });
96
-
97
104
  if (existingState !== null) {
105
+ log_debug(
106
+ `ClosedCaptioningManager: Setting initial state to ${existingState}`
107
+ );
108
+
98
109
  this.ccState$.next(existingState === "true" || existingState === true);
110
+ } else {
111
+ log_debug("ClosedCaptioningManager: No existing state found");
99
112
  }
100
113
 
101
114
  if (hasVizioAPIs()) {
115
+ log_debug("ClosedCaptioningManager: Setting closed captioning handler");
116
+
102
117
  window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
103
- log_debug("CC state changed", { isCCEnabled });
118
+ log_debug(
119
+ "ClosedCaptioningManager: There was a change in the CC state",
120
+ { isCCEnabled }
121
+ );
104
122
 
105
123
  sessionStorage.setItem(
106
124
  PLATFORM_KEYS.deviceClosedCaptioningEnabled,
107
125
  isCCEnabled
108
126
  );
109
127
 
128
+ log_debug(
129
+ "ClosedCaptioningManager: Saved CC state to session storage",
130
+ { isCCEnabled }
131
+ );
132
+
110
133
  this.ccState$.next(isCCEnabled);
111
134
  });
135
+ } else {
136
+ log_debug(
137
+ "ClosedCaptioningManager: Vizio APIs are not available, skipping setup"
138
+ );
112
139
  }
113
140
  }
114
141
 
@@ -154,8 +154,8 @@ export class Player {
154
154
  this.isSeeking()
155
155
  ? this.playerState.seekPosition
156
156
  : this.playerState.adState
157
- ? this.playerState.adState.adPosition
158
- : this.playerState.contentPosition;
157
+ ? this.playerState.adState.adPosition
158
+ : this.playerState.contentPosition;
159
159
 
160
160
  getEntry = (): ZappEntry | null => this.entry;
161
161
 
@@ -49,9 +49,16 @@ export const isEqual =
49
49
  }
50
50
 
51
51
  if (compareRemainingKeysBySameValue) {
52
- const undeclaredKeys = R.difference(
53
- [...byValue, ...byReference, byComparator.keys],
54
- Object.keys(prev)
52
+ const allKeys = new Set([...Object.keys(prev), ...Object.keys(next)]);
53
+
54
+ const declaredKeys = new Set([
55
+ ...byValue,
56
+ ...byReference,
57
+ ...byComparator.keys,
58
+ ]);
59
+
60
+ const undeclaredKeys = Array.from(allKeys).filter(
61
+ (key) => !declaredKeys.has(key)
55
62
  );
56
63
 
57
64
  const isRestKeysEqualAllBySameValue = undeclaredKeys.every((key) =>
@@ -250,7 +250,17 @@ class FocusManager {
250
250
  }
251
251
 
252
252
  onDisableFocusChange = (id) => {
253
- if (FocusManager.instance.isFocused(id)) {
253
+ const isFocused = FocusManager.instance.isFocused(id);
254
+
255
+ const isDescendantFocused = (() => {
256
+ try {
257
+ return FocusManager.instance.isAnyDescendantFocused(id);
258
+ } catch (_e) {
259
+ return false;
260
+ }
261
+ })();
262
+
263
+ if (isFocused || isDescendantFocused) {
254
264
  // Move focus to next one
255
265
  const nextFocus = FocusManager.instance.focused?.props
256
266
  ?.nextFocusDown as string;
@@ -0,0 +1,37 @@
1
+ import { TestScheduler } from "rxjs/testing";
2
+
3
+ import { withTimeout$ } from "..";
4
+
5
+ describe("withTimeout$", () => {
6
+ let testScheduler: TestScheduler;
7
+
8
+ beforeEach(() => {
9
+ testScheduler = new TestScheduler((actual, expected) => {
10
+ expect(actual).toEqual(expected);
11
+ });
12
+ });
13
+
14
+ it("should emit undefined after the specified timeout", () => {
15
+ testScheduler.run(({ expectObservable }) => {
16
+ const timeout = 1000;
17
+ const expectedMarble = "1s (a|)";
18
+ const expectedValues = { a: undefined };
19
+
20
+ const result$ = withTimeout$(timeout);
21
+
22
+ expectObservable(result$).toBe(expectedMarble, expectedValues);
23
+ });
24
+ });
25
+
26
+ it("should complete after emitting undefined", () => {
27
+ testScheduler.run(({ expectObservable }) => {
28
+ const timeout = 500;
29
+ const expectedMarble = "500ms (a|)";
30
+ const expectedValues = { a: undefined };
31
+
32
+ const result$ = withTimeout$(timeout);
33
+
34
+ expectObservable(result$).toBe(expectedMarble, expectedValues);
35
+ });
36
+ });
37
+ });
@@ -1,4 +1,4 @@
1
- export { withTimeout } from "./withTimeout";
1
+ export { withTimeout, withTimeout$ } from "./withTimeout";
2
2
 
3
3
  export { onIdle } from "./onIdle";
4
4
 
@@ -1,7 +1,20 @@
1
- export const withTimeout = (timeout: number) => {
2
- return new Promise((resolve) => {
1
+ import { of, Observable } from "rxjs";
2
+ import { delay } from "rxjs/operators";
3
+
4
+ export const withTimeout = (timeout: number): Promise<void> => {
5
+ return new Promise<void>((resolve) => {
3
6
  setTimeout(() => {
4
7
  resolve(undefined);
5
8
  }, timeout);
6
9
  });
7
10
  };
11
+
12
+ /**
13
+ * Creates an observable that emits a single value after a specified timeout.
14
+ *
15
+ * @param timeout - The delay duration in milliseconds before emitting the value.
16
+ * @returns An observable that emits `undefined` after the specified timeout.
17
+ */
18
+ export const withTimeout$ = (timeout: number): Observable<void> => {
19
+ return of(undefined).pipe(delay(timeout));
20
+ };
@@ -78,8 +78,6 @@ describe("createConfig", () => {
78
78
  extend: "styles",
79
79
  })(props);
80
80
 
81
- console.log(mockGenerators.styles.mock.calls);
82
-
83
81
  expect(mockGenerators.styles).toBeCalledWith(props);
84
82
  });
85
83
 
@@ -644,8 +644,8 @@ export const getScreenId = (
644
644
  fallbackRiver: ZappRiver
645
645
  ) => {
646
646
  return screenData?.targetScreen
647
- ? screenData?.targetScreen?.id ?? fallbackRiver.id
647
+ ? (screenData?.targetScreen?.id ?? fallbackRiver.id)
648
648
  : "screen_id" in screenData
649
- ? screenData.screen_id
650
- : fallbackRiver.id;
649
+ ? screenData.screen_id
650
+ : fallbackRiver.id;
651
651
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "13.0.0-alpha.8357105823",
3
+ "version": "13.0.0-alpha.8432878190",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "13.0.0-alpha.8357105823",
31
+ "@applicaster/applicaster-types": "13.0.0-alpha.8432878190",
32
32
  "buffer": "^5.2.1",
33
33
  "camelize": "^1.0.0",
34
34
  "create-react-context": "^0.2.3",
@@ -5,7 +5,7 @@ const mockDimensionsGet = jest.fn(
5
5
  ({
6
6
  window: { width: 1, height: 1 },
7
7
  screen: { width: 360, height: 540 },
8
- }[type])
8
+ })[type]
9
9
  );
10
10
 
11
11
  ReactNative.Dimensions.get = mockDimensionsGet;
@@ -52,6 +52,14 @@ export const useDimensions: UseDimensions = (
52
52
  ? { fullDimensions }
53
53
  : { ...fullDimensions };
54
54
 
55
+ if (options.updateForInactiveScreens === undefined) {
56
+ options.updateForInactiveScreens = true;
57
+ }
58
+
59
+ if (options.fullDimensions === undefined) {
60
+ options.fullDimensions = false;
61
+ }
62
+
55
63
  const [dimensions, setDimensions] = useState(getInitialDimensions(context));
56
64
  const deviceInfo = useRef(getDeviceInfo(dimensions, appData));
57
65
 
@@ -1,5 +1,5 @@
1
- import React, { useEffect, useMemo } from "react";
2
- import { BackHandler, InteractionManager, NativeModules } from "react-native";
1
+ import { useContext, useEffect, useMemo, useRef } from "react";
2
+ import { BackHandler } from "react-native";
3
3
 
4
4
  import {
5
5
  useContentTypes,
@@ -31,6 +31,8 @@ export { useGetBottomTabBarHeight } from "./useGetBottomTabBarHeight";
31
31
 
32
32
  export { useIsScreenActive } from "./useIsScreenActive";
33
33
 
34
+ export { useProfilerLogging } from "./useProfilerLogging";
35
+
34
36
  export {
35
37
  useUniqueRouteSuffix,
36
38
  useNavbarId,
@@ -121,10 +123,8 @@ export function isNavBarVisible(
121
123
  return true;
122
124
  }
123
125
 
124
- const { ProfilerBridge } = NativeModules;
125
-
126
126
  export const useBackHandler = (cb: () => boolean) => {
127
- React.useEffect(() => {
127
+ useEffect(() => {
128
128
  BackHandler.addEventListener("hardwareBackPress", cb);
129
129
 
130
130
  return () => {
@@ -158,7 +158,7 @@ export const useZappHooksForEntry = (
158
158
  setIsHooksExecutionInProgress,
159
159
  setIsPresentingFullScreen,
160
160
  setIsRunningInBackground,
161
- }: HookModalContextT = React.useContext(ZappHookModalContext.ReactContext);
161
+ }: HookModalContextT = useContext(ZappHookModalContext.ReactContext);
162
162
 
163
163
  const {
164
164
  appData: { layoutVersion },
@@ -256,22 +256,10 @@ export const useZappHooksForEntry = (
256
256
  }, [entry.id]);
257
257
  };
258
258
 
259
- export const useProfilerLogging = () => {
260
- const logTimestamp = (data: string) =>
261
- InteractionManager.runAfterInteractions(() => {
262
- if (ProfilerBridge && data) {
263
- ProfilerBridge.updateTimer("navigation", data, Date.now());
264
- }
265
- });
266
-
267
- return logTimestamp;
268
- };
269
-
270
259
  export const useRunIfLongPress = (
271
260
  options = { timeout: LONG_KEY_PRESS_TIMEOUT }
272
261
  ) => {
273
- const pressTimeout =
274
- React.useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
262
+ const pressTimeout = useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
275
263
 
276
264
  const resetTimeout = () => {
277
265
  clearTimeout(pressTimeout.current as ReturnType<typeof setTimeout>);
@@ -1,5 +1,3 @@
1
- import { useSafeAreaInsets } from "react-native-safe-area-context";
2
-
3
1
  import { platformSelect } from "../../reactUtils";
4
2
 
5
3
  const TAB_BAR_HEIGHT_IOS = 49;
@@ -7,6 +5,6 @@ const TAB_BAR_HEIGHT_ANDROID = 56;
7
5
 
8
6
  export const useGetTabBarHeight = () =>
9
7
  platformSelect({
10
- ios: TAB_BAR_HEIGHT_IOS + (useSafeAreaInsets().bottom ?? 0),
8
+ ios: TAB_BAR_HEIGHT_IOS,
11
9
  android: TAB_BAR_HEIGHT_ANDROID,
12
10
  }) as number;
@@ -0,0 +1,15 @@
1
+ import { useCallback } from "react";
2
+ import { InteractionManager, NativeModules } from "react-native";
3
+
4
+ const { ProfilerBridge } = NativeModules;
5
+
6
+ export const useProfilerLogging = () =>
7
+ useCallback(
8
+ (data: string) =>
9
+ InteractionManager.runAfterInteractions(() => {
10
+ if (ProfilerBridge && data) {
11
+ ProfilerBridge.updateTimer("navigation", data, Date.now());
12
+ }
13
+ }),
14
+ []
15
+ );
@@ -93,6 +93,8 @@ export class TVSeekController
93
93
  this.isPlayerInitiallyPaused = this.playerController.isPaused();
94
94
  }
95
95
 
96
+ log_debug(`handleStartSeek: seekType: ${seekType}, initiallyPaused: ${this.isPlayerInitiallyPaused}`);
97
+
96
98
  this.clearLongPressThresholdTimeout();
97
99
  this.clearSeekCompleteTimeout();
98
100
  this.setStrategy(SEEK_STRATEGY.TAP_SEEK);
@@ -117,6 +119,7 @@ export class TVSeekController
117
119
  };
118
120
 
119
121
  onSeekEnd = () => {
122
+ log_debug("onSeekEnd: Seek ended");
120
123
  this.clearLongPressThresholdTimeout();
121
124
  this.currentSeekController.onSeekEnd();
122
125
  };
@@ -174,6 +177,8 @@ export class TVSeekController
174
177
  }
175
178
  }
176
179
 
180
+ log_debug(`handleDelayedSeek: currentPos: ${currentPos} targetPos:${targetPos}, initiallyPaused: ${this.isPlayerInitiallyPaused}`);
181
+
177
182
  this.delayedSeekPosition = targetPos;
178
183
  this.delayedSeekProgressSubject.next(targetPos);
179
184
  };
@@ -46,7 +46,7 @@ export class TapSeekController implements ISeekController {
46
46
  };
47
47
 
48
48
  reset = () => {
49
- log_debug("{this.title}: Reset states");
49
+ log_debug(`${this.title}: Reset states`);
50
50
 
51
51
  this.seekIncrementalStrategy.reset();
52
52
  };
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+
3
+ /**
4
+ * returns a ref with an initial value that is lazily evaluated once
5
+ * */
6
+ export const useRefWithInitialValue = <T>(initialValueGetter: () => T) => {
7
+ const ref = React.useRef<T>(null);
8
+
9
+ if (ref.current === null) {
10
+ ref.current = initialValueGetter();
11
+ }
12
+
13
+ return ref;
14
+ };
@@ -0,0 +1,23 @@
1
+ import { useEffect, useState } from "react";
2
+ import type { Subject } from "rxjs";
3
+
4
+ export const useStateFromSubscribe = <T, U>(
5
+ subject: Subject<T>,
6
+ onUpdate: (
7
+ observerValue: T,
8
+ next: React.Dispatch<React.SetStateAction<U>>
9
+ ) => void,
10
+ initialValue: U
11
+ ) => {
12
+ const [state, setState] = useState<U>(initialValue);
13
+
14
+ useEffect(() => {
15
+ const subscription = subject.subscribe((observer) =>
16
+ onUpdate(observer, setState)
17
+ );
18
+
19
+ return () => subscription.unsubscribe();
20
+ }, [subject]);
21
+
22
+ return state;
23
+ };
@@ -91,7 +91,7 @@ export function useLayoutConfiguration<
91
91
  S extends unknown,
92
92
  G extends unknown,
93
93
  R extends unknown,
94
- L extends unknown
94
+ L extends unknown,
95
95
  >(layoutData, manifest, options: Options = {}) {
96
96
  const keys = options.keys || [
97
97
  "assets",
@@ -4,9 +4,10 @@ import { subscriber } from "@applicaster/zapp-react-native-utils/functionUtils";
4
4
  const subscriberObjects = Object.create({});
5
5
 
6
6
  interface UseSubscriberFor {
7
- (eventName: string, handler?: (...args: unknown[]) => void): (
8
- ...args: unknown[]
9
- ) => ReturnType<typeof subscriber>;
7
+ (
8
+ eventName: string,
9
+ handler?: (...args: unknown[]) => void
10
+ ): (...args: unknown[]) => ReturnType<typeof subscriber>;
10
11
  }
11
12
 
12
13
  /**
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`addLifeCycleMethods attaches the lifecycle method to the component 1`] = `
3
+ exports[`reactUtils helpers addLifeCycleMethods attaches the lifecycle method to the component 1`] = `
4
4
  <View>
5
5
  <Text>
6
6
  I'm a class component
@@ -8,7 +8,7 @@ exports[`addLifeCycleMethods attaches the lifecycle method to the component 1`]
8
8
  </View>
9
9
  `;
10
10
 
11
- exports[`attachMethodToPrototype attaches a lifecycle method to the component's prototype 1`] = `
11
+ exports[`reactUtils helpers attachMethodToPrototype attaches a lifecycle method to the component's prototype 1`] = `
12
12
  <View>
13
13
  <Text>
14
14
  I'm a class component
@@ -16,6 +16,18 @@ exports[`attachMethodToPrototype attaches a lifecycle method to the component's
16
16
  </View>
17
17
  `;
18
18
 
19
- exports[`attachMethodToPrototype preserves any existing lifecycle method 1`] = `<StatelessComponent />`;
19
+ exports[`reactUtils helpers attachMethodToPrototype preserves any existing lifecycle method 1`] = `
20
+ <View>
21
+ <Text>
22
+ I'm a stateless component
23
+ </Text>
24
+ </View>
25
+ `;
20
26
 
21
- exports[`wrapInClass wraps the stateless component in a class 1`] = `<StatelessComponent />`;
27
+ exports[`reactUtils helpers wrapInClass wraps the stateless component in a class 1`] = `
28
+ <View>
29
+ <Text>
30
+ I'm a stateless component
31
+ </Text>
32
+ </View>
33
+ `;