@applicaster/zapp-react-native-utils 13.0.0-alpha.1918049654 → 13.0.0-alpha.1952415373

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.
@@ -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) {
@@ -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,
@@ -81,9 +81,12 @@ export class ClosedCaptioningManager {
81
81
 
82
82
  static getInstance(): ClosedCaptioningManager {
83
83
  if (!ClosedCaptioningManager.ccManagerInstance) {
84
+ log_debug("ClosedCaptioningManager: Creating new instance");
84
85
  ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
85
86
  }
86
87
 
88
+ log_debug("ClosedCaptioningManager: Returning existing instance");
89
+
87
90
  return ClosedCaptioningManager.ccManagerInstance;
88
91
  }
89
92
 
@@ -92,23 +95,41 @@ export class ClosedCaptioningManager {
92
95
  PLATFORM_KEYS.deviceClosedCaptioningEnabled
93
96
  );
94
97
 
95
- log_debug("Initializing closed captioning manager", { existingState });
96
-
97
98
  if (existingState !== null) {
99
+ log_debug(
100
+ `ClosedCaptioningManager: Setting initial state to ${existingState}`
101
+ );
102
+
98
103
  this.ccState$.next(existingState === "true" || existingState === true);
104
+ } else {
105
+ log_debug("ClosedCaptioningManager: No existing state found");
99
106
  }
100
107
 
101
108
  if (hasVizioAPIs()) {
109
+ log_debug("ClosedCaptioningManager: Setting closed captioning handler");
110
+
102
111
  window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
103
- log_debug("CC state changed", { isCCEnabled });
112
+ log_debug(
113
+ "ClosedCaptioningManager: There was a change in the CC state",
114
+ { isCCEnabled }
115
+ );
104
116
 
105
117
  sessionStorage.setItem(
106
118
  PLATFORM_KEYS.deviceClosedCaptioningEnabled,
107
119
  isCCEnabled
108
120
  );
109
121
 
122
+ log_debug(
123
+ "ClosedCaptioningManager: Saved CC state to session storage",
124
+ { isCCEnabled }
125
+ );
126
+
110
127
  this.ccState$.next(isCCEnabled);
111
128
  });
129
+ } else {
130
+ log_debug(
131
+ "ClosedCaptioningManager: Vizio APIs are not available, skipping setup"
132
+ );
112
133
  }
113
134
  }
114
135
 
@@ -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
 
@@ -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
 
@@ -5,7 +5,6 @@ exports[`getNavigationProps returns the props otherwise 1`] = `
5
5
  "assets": {
6
6
  "appLogo": "appLogo.png",
7
7
  },
8
- "data": undefined,
9
8
  "home": false,
10
9
  "nav_items": [
11
10
  {
@@ -111,7 +111,6 @@ export function getNavigationProps({
111
111
  assets: ZappNavBarAssets;
112
112
  rules: ZappNavBarRules;
113
113
  nav_items: NavBarItem[];
114
- data: MenuItemDataProperties;
115
114
  } | null {
116
115
  const { activeRiver } = navigator;
117
116
  const { navigations, id: selected, home } = activeRiver; // use useRiver hook instead
@@ -125,7 +124,7 @@ export function getNavigationProps({
125
124
  return null;
126
125
  }
127
126
 
128
- const { styles, assets, nav_items, rules, data } = navigation;
127
+ const { styles, assets, nav_items, rules } = navigation;
129
128
 
130
129
  return {
131
130
  selected,
@@ -135,7 +134,6 @@ export function getNavigationProps({
135
134
  assets: assets as ZappNavBarAssets,
136
135
  nav_items: nav_items as any as NavBarItem[],
137
136
  rules: rules as any as ZappNavBarRules,
138
- data: data as MenuItemDataProperties,
139
137
  };
140
138
  }
141
139
 
@@ -646,8 +644,8 @@ export const getScreenId = (
646
644
  fallbackRiver: ZappRiver
647
645
  ) => {
648
646
  return screenData?.targetScreen
649
- ? screenData?.targetScreen?.id ?? fallbackRiver.id
647
+ ? (screenData?.targetScreen?.id ?? fallbackRiver.id)
650
648
  : "screen_id" in screenData
651
- ? screenData.screen_id
652
- : fallbackRiver.id;
649
+ ? screenData.screen_id
650
+ : fallbackRiver.id;
653
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.1918049654",
3
+ "version": "13.0.0-alpha.1952415373",
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.1918049654",
31
+ "@applicaster/applicaster-types": "13.0.0-alpha.1952415373",
32
32
  "buffer": "^5.2.1",
33
33
  "camelize": "^1.0.0",
34
34
  "create-react-context": "^0.2.3",
@@ -20,7 +20,6 @@ type Props = {
20
20
  silentRefresh?: boolean;
21
21
  method?: "get" | "post";
22
22
  bodyParams?: Record<string, unknown>;
23
- skipLoading?: boolean;
24
23
  };
25
24
  };
26
25
 
@@ -94,7 +93,7 @@ export const useFeedLoader = ({
94
93
  if (
95
94
  shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
96
95
  ) {
97
- if (callableFeedUrl && !pipesOptions.skipLoading) {
96
+ if (callableFeedUrl) {
98
97
  dispatch(
99
98
  loadPipesData(callableFeedUrl, {
100
99
  ...pipesOptions,
@@ -102,33 +101,26 @@ export const useFeedLoader = ({
102
101
  riverId,
103
102
  })
104
103
  );
105
- } else if (!callableFeedUrl) {
106
- logger.info({
107
- message:
108
- "Feed is not defined or not inflated, skipping loading. \nMake sure you have correct feedUrl and mapping.",
109
- jsOnly: true,
110
- });
111
104
  } else {
112
105
  logger.info({
113
106
  message:
114
- "Loading skipped as per pipesOptions.skipLoading configuration.",
115
- data: { url: callableFeedUrl },
107
+ "Feed is not defined or not inflated, skipping loading. \nMake sure you have correct feedUrl and mapping.",
116
108
  jsOnly: true,
117
109
  });
118
110
  }
119
111
  } else {
120
112
  logger.info({
121
113
  message:
122
- "Feed already exists, skipping loading. \nCall reloadData() if you want to refresh data.",
114
+ "Feed already exist, skipping loading. \nCall reloadData() if you want to refresh data.",
123
115
  data: { url: callableFeedUrl },
124
116
  jsOnly: true,
125
117
  });
126
118
  }
127
119
  }, []);
128
120
 
129
- // Reload feed when feedUrl changes, unless skipLoading is true
121
+ // Reload feed when feedUrl changes
130
122
  useEffect(() => {
131
- if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
123
+ if (!isInitialRender && callableFeedUrl) {
132
124
  dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
133
125
  }
134
126
  }, [callableFeedUrl]);
@@ -164,6 +156,7 @@ export const useFeedLoader = ({
164
156
  currentFeed?.data,
165
157
  currentFeed?.error,
166
158
  currentFeed?.loading,
159
+
167
160
  reloadData,
168
161
  loadNext,
169
162
  ]);
@@ -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,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,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,8 @@
1
1
  import { create } from "zustand";
2
2
  import { produce } from "immer";
3
3
  import { path } from "ramda";
4
+ import React from "react";
5
+ import { useShallow } from "zustand/react/shallow";
4
6
 
5
7
  type ScreenState = {
6
8
  selectedEntry: {
@@ -18,6 +20,8 @@ type ScreenStore = {
18
20
  setSelectedEntry: (screenId: string, entryId: string) => void;
19
21
  };
20
22
 
23
+ type SetSelectedEntry = (screenId: string, entryId: string) => void;
24
+
21
25
  const useScreenStore = create<ScreenStore>((set) => ({
22
26
  screens: screensInitialState,
23
27
  setSelectedEntry: (screenId, entryId) =>
@@ -35,17 +39,27 @@ const useScreenStore = create<ScreenStore>((set) => ({
35
39
  export function useScreenState(
36
40
  screenId: ScreenId
37
41
  ): null | { screen: ScreenState; setSelectedEntry: (entryId: string) => void } {
38
- // const state = useState(screenState);
39
- const screenState = useScreenStore(
40
- path(["screens", screenId])
41
- ) as ScreenState;
42
+ const screenState = useScreenStore<ScreenState>(
43
+ useShallow(path(["screens", screenId]))
44
+ );
42
45
 
43
- const setSelectedEntry = useScreenStore((state) => state.setSelectedEntry);
46
+ const setSelectedEntry = useScreenStore<SetSelectedEntry>(
47
+ useShallow(path(["setSelectedEntry"]))
48
+ );
44
49
 
45
- if (!screenId) return null;
50
+ const memoizedSetSelectedEntry = React.useCallback(
51
+ (entryId) => setSelectedEntry(screenId, entryId),
52
+ [screenId, setSelectedEntry]
53
+ );
46
54
 
47
- return {
48
- screen: screenState,
49
- setSelectedEntry: (entryId) => setSelectedEntry(screenId, entryId),
50
- };
55
+ return React.useMemo(
56
+ () =>
57
+ !screenId
58
+ ? null
59
+ : {
60
+ screen: screenState,
61
+ setSelectedEntry: memoizedSetSelectedEntry,
62
+ },
63
+ [screenId, screenState]
64
+ );
51
65
  }
package/theme/index.ts CHANGED
@@ -14,7 +14,7 @@ export const ThemeContext = React.createContext({
14
14
  export function useTheme<
15
15
  T extends Record<string, any> =
16
16
  | BaseThemePropertiesTV
17
- | BaseThemePropertiesMobile
17
+ | BaseThemePropertiesMobile,
18
18
  >(): T {
19
19
  const { themes, selectedThemeId } = React.useContext(ThemeContext);
20
20
 
package/time/Timer.ts CHANGED
@@ -3,7 +3,10 @@ export class Timer {
3
3
  private remaining: number;
4
4
  private timeoutId: NodeJS.Timeout | null;
5
5
 
6
- constructor(private callback: () => void, private duration: number) {
6
+ constructor(
7
+ private callback: () => void,
8
+ private duration: number
9
+ ) {
7
10
  this.remaining = this.duration;
8
11
  this.timeoutId = null;
9
12
  }
@@ -92,9 +92,8 @@ export const PresentHookPluginOneTime = (
92
92
  const presentOneTimeVersionName =
93
93
  await getLatestWatchedVersionNumberFromStorage(storageKey, namespace);
94
94
 
95
- const applicationVersionName = await sessionStorage.getItem(
96
- versionNameKey
97
- );
95
+ const applicationVersionName =
96
+ await sessionStorage.getItem(versionNameKey);
98
97
 
99
98
  if (!presentOneTimeVersionName || !applicationVersionName) {
100
99
  log_info(