@applicaster/zapp-react-native-ui-components 15.0.0-alpha.7809066324 → 15.0.0-alpha.8111467956

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,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { renderHook } from "@testing-library/react-hooks";
2
+ import { renderHook } from "@testing-library/react-native";
3
3
 
4
4
  import {
5
5
  getTransformedPreset,
@@ -9,10 +9,9 @@ import {
9
9
  import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
10
10
  import { Categories } from "./logger";
11
11
  import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
12
- import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
12
+ import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
13
13
 
14
14
  import {
15
- ZappPipesEntryContext,
16
15
  ZappPipesScreenContext,
17
16
  ZappPipesSearchContext,
18
17
  } from "@applicaster/zapp-react-native-ui-components/Contexts";
@@ -136,7 +135,6 @@ export const useCurationAPI = (
136
135
  [components]
137
136
  );
138
137
 
139
- const { pathname } = useRoute();
140
138
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
141
139
  const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
142
140
 
@@ -146,10 +144,12 @@ export const useCurationAPI = (
146
144
  screenContextType === TABS_SCREEN_TYPE ||
147
145
  screenContextType === QB_TABS_SCREEN_TYPE;
148
146
 
149
- const [entryContext] = ZappPipesEntryContext.useZappPipesContext(
150
- pathname,
151
- isNestedScreen
152
- );
147
+ const screenContextData = useScreenContext();
148
+
149
+ const entryContext = ((isNestedScreen && screenContextData?.nested?.entry
150
+ ? screenContextData?.nested?.entry
151
+ : (screenContextData?.entry?.payload ?? screenContextData?.entry)) ||
152
+ {}) as ZappEntry;
153
153
 
154
154
  const urlsMap = useMemo<{ [key: string]: string }>(() => {
155
155
  const map = {};
@@ -3,8 +3,8 @@ import { isNil } from "ramda";
3
3
  import { ImageStyle, View } from "react-native";
4
4
  import {
5
5
  FIT_POSITION,
6
- IMAGE_SIZING_FIT,
7
6
  IMAGE_SIZING_FILL,
7
+ IMAGE_SIZING_FIT,
8
8
  } from "@applicaster/zapp-react-native-utils/manifestUtils/secondaryImage";
9
9
  import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
10
10
 
@@ -25,49 +25,51 @@ interface Props {
25
25
  fitPosition: typeof FIT_POSITION;
26
26
  fixedWidth: number;
27
27
  fixedHeight: number;
28
- onAsyncRender: () => void;
28
+ onAsyncRender?: () => void;
29
29
  }
30
30
 
31
31
  /** Secondary Image Dynamic does not render until the image is loaded */
32
- const SecondaryImageDynamic = (props: Props) => {
33
- const { uri, style, displayMode, imageSizing, fitPosition, onAsyncRender } =
34
- props;
32
+ const SecondaryImageDynamic = withAsyncRenderHOC(
33
+ (props: Props & { onAsyncRender: () => void }) => {
34
+ const { uri, style, displayMode, imageSizing, fitPosition, onAsyncRender } =
35
+ props;
35
36
 
36
- const imageDimension = useGetImageDimensions(
37
- uri,
38
- style.width as number,
39
- isImageSizingFit(imageSizing) ? undefined : (style.height as number)
40
- );
37
+ const imageDimension = useGetImageDimensions(
38
+ uri,
39
+ style.width as number,
40
+ isImageSizingFit(imageSizing) ? undefined : (style.height as number)
41
+ );
41
42
 
42
- const containerHeight = imageDimension?.height;
43
+ const containerHeight = imageDimension?.height;
43
44
 
44
- const containerWidth = style?.width;
45
+ const containerWidth = style?.width;
45
46
 
46
- if (isNil(imageDimension?.aspectRatio)) {
47
- return null;
48
- }
47
+ if (isNil(imageDimension?.aspectRatio)) {
48
+ return null;
49
+ }
49
50
 
50
- return (
51
- <View style={style} onLayout={onAsyncRender}>
52
- <Image
53
- {...props}
54
- source={{ uri }}
55
- style={{
56
- ...getStyle({
57
- imageSizing,
58
- fitPosition,
59
- displayMode,
60
- imageDimension,
61
- containerHeight,
62
- containerWidth,
63
- }),
64
- borderRadius: style.borderRadius,
65
- aspectRatio: imageDimension.aspectRatio,
66
- }}
67
- />
68
- </View>
69
- );
70
- };
51
+ return (
52
+ <View style={style} onLayout={onAsyncRender}>
53
+ <Image
54
+ {...props}
55
+ source={{ uri }}
56
+ style={{
57
+ ...getStyle({
58
+ imageSizing,
59
+ fitPosition,
60
+ displayMode,
61
+ imageDimension,
62
+ containerHeight,
63
+ containerWidth,
64
+ }),
65
+ borderRadius: style.borderRadius,
66
+ aspectRatio: imageDimension.aspectRatio,
67
+ }}
68
+ />
69
+ </View>
70
+ );
71
+ }
72
+ );
71
73
 
72
74
  /** Secondary Image Fixed does not render the image until the image is loaded, but keep container rendered */
73
75
  const SecondaryImageFixed = (props: Props) => {
@@ -79,7 +81,6 @@ const SecondaryImageFixed = (props: Props) => {
79
81
  fitPosition,
80
82
  fixedHeight,
81
83
  fixedWidth,
82
- onAsyncRender,
83
84
  } = props;
84
85
 
85
86
  const imageDimension = useGetImageDimensions(
@@ -89,7 +90,7 @@ const SecondaryImageFixed = (props: Props) => {
89
90
  );
90
91
 
91
92
  return (
92
- <View style={style} onLayout={onAsyncRender}>
93
+ <View style={style}>
93
94
  {isNil(imageDimension?.aspectRatio) ? null : (
94
95
  <Image
95
96
  {...props}
@@ -128,4 +129,4 @@ const SecondaryImageComponent = (props: Props) => {
128
129
  );
129
130
  };
130
131
 
131
- export const SecondaryImage = withAsyncRenderHOC(SecondaryImageComponent);
132
+ export const SecondaryImage = SecondaryImageComponent;
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook, waitFor } from "@testing-library/react-native";
2
2
  import { Image } from "react-native";
3
3
 
4
4
  import { useGetImageDimensions } from "../useGetImageDimensions";
@@ -13,15 +13,16 @@ jest.spyOn(Image, "getSize").mockImplementation((_uri, success) => {
13
13
 
14
14
  describe("useGetImageDimensions", () => {
15
15
  it("should return aspect ration initially when known dimensions", async () => {
16
- const { result, waitForNextUpdate } = renderHook(() =>
16
+ const { result } = renderHook(() =>
17
17
  useGetImageDimensions("https://some_url.com", WIDTH, undefined)
18
18
  );
19
19
 
20
20
  expect(result.current).toBeUndefined();
21
- await waitForNextUpdate();
22
21
 
23
- expect(result.current).toEqual(
24
- getDimension({ width: WIDTH, height: HEIGTH })
25
- );
22
+ await waitFor(() => {
23
+ expect(result.current).toEqual(
24
+ getDimension({ width: WIDTH, height: HEIGTH })
25
+ );
26
+ });
26
27
  });
27
28
  });
@@ -103,7 +103,7 @@ export const SecondaryImage = ({ value, currentPosition, state }: Props) => {
103
103
  data: [
104
104
  {
105
105
  func: "image_src_from_media_item",
106
- args: [imageKey],
106
+ args: [imageKey, false],
107
107
  propName: "uri",
108
108
  },
109
109
  ],
@@ -4,7 +4,7 @@ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/nu
4
4
  import { Button } from "./Button";
5
5
  import {
6
6
  getButtonsCount,
7
- getPluginIdentifier,
7
+ memoizedGetPluginIdentifier,
8
8
  mapSelfAlignment,
9
9
  } from "./utils";
10
10
 
@@ -80,7 +80,11 @@ export const TvActionButtons = ({
80
80
  prefix: independentStyles ? prefixSpecificButton : buttonId(1),
81
81
  value,
82
82
  platformValue,
83
- pluginIdentifier: getPluginIdentifier(configuration, PREFIX, index),
83
+ pluginIdentifier: memoizedGetPluginIdentifier(
84
+ configuration,
85
+ PREFIX,
86
+ index
87
+ ),
84
88
  suffixId: prefixSpecificButton,
85
89
  preferredFocus: index === 0,
86
90
  });
@@ -3,7 +3,7 @@ import { getPluginIdentifier } from "..";
3
3
  describe("getPluginIdentifier", () => {
4
4
  const prefix = "tv_buttons";
5
5
 
6
- it("get first plugin identifier", () => {
6
+ it("returns the first valid plugin identifier", () => {
7
7
  const configuration = {
8
8
  tv_buttons_button_1_other: "value",
9
9
  tv_buttons_button_1_assign_action:
@@ -13,13 +13,12 @@ describe("getPluginIdentifier", () => {
13
13
  };
14
14
 
15
15
  const index = 0;
16
-
17
16
  const result = getPluginIdentifier(configuration, prefix, index);
18
17
 
19
18
  expect(result).toEqual(configuration.tv_buttons_button_1_assign_action);
20
19
  });
21
20
 
22
- it("get second plugin identifier", () => {
21
+ it("returns the second valid plugin identifier", () => {
23
22
  const configuration = {
24
23
  tv_buttons_button_1_other: "value_1",
25
24
  tv_buttons_button_1_assign_action:
@@ -30,24 +29,123 @@ describe("getPluginIdentifier", () => {
30
29
  };
31
30
 
32
31
  const index = 1;
33
-
34
32
  const result = getPluginIdentifier(configuration, prefix, index);
35
33
 
36
34
  expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
37
35
  });
38
36
 
39
- it("get undefined if no assign_actions at all", () => {
37
+ it("returns undefined when there are no assign_action keys", () => {
40
38
  const configuration = {};
39
+ const index = 0;
40
+
41
+ const result = getPluginIdentifier(configuration, prefix, index);
42
+
43
+ expect(result).toBeUndefined();
44
+ });
45
+
46
+ it("skips undefined values and returns the correct plugin identifier", () => {
47
+ const configuration = {
48
+ tv_buttons_button_1_assign_action: "tv_buttons_button_1_assign_action",
49
+ tv_buttons_button_2_assign_action: undefined,
50
+ tv_buttons_button_3_assign_action: "tv_buttons_button_3_assign_action",
51
+ };
52
+
53
+ const index = 1;
54
+ const result = getPluginIdentifier(configuration, prefix, index);
55
+
56
+ expect(result).toEqual(configuration.tv_buttons_button_3_assign_action);
57
+ });
58
+
59
+ it("handles missing intermediate keys and returns the correct plugin identifier", () => {
60
+ const configuration = {
61
+ tv_buttons_button_1_assign_action: "tv_buttons_button_1_assign_action",
62
+ tv_buttons_button_3_assign_action: "tv_buttons_button_3_assign_action",
63
+ };
64
+
65
+ const index = 1;
66
+ const result = getPluginIdentifier(configuration, prefix, index);
67
+
68
+ expect(result).toEqual(configuration.tv_buttons_button_3_assign_action);
69
+ });
70
+
71
+ it("skips empty string values and returns the first non-empty assign_action", () => {
72
+ const configuration = {
73
+ tv_buttons_button_1_assign_action: "",
74
+ tv_buttons_button_2_assign_action: "tv_buttons_button_2_assign_action",
75
+ };
41
76
 
42
77
  const index = 0;
78
+ const result = getPluginIdentifier(configuration, prefix, index);
79
+
80
+ expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
81
+ });
82
+
83
+ it("returns undefined for negative index", () => {
84
+ const configuration = {
85
+ tv_buttons_button_1_assign_action: "a",
86
+ tv_buttons_button_2_assign_action: "b",
87
+ };
43
88
 
89
+ const index = -1;
44
90
  const result = getPluginIdentifier(configuration, prefix, index);
45
91
 
46
92
  expect(result).toBeUndefined();
47
93
  });
94
+
95
+ it("returns undefined for out-of-bounds index", () => {
96
+ const configuration = {
97
+ tv_buttons_button_1_assign_action: "a",
98
+ tv_buttons_button_2_assign_action: "b",
99
+ };
100
+
101
+ const index = 5;
102
+ const result = getPluginIdentifier(configuration, prefix, index);
103
+
104
+ expect(result).toBeUndefined();
105
+ });
106
+
107
+ it("ignores keys with wrong prefix or format", () => {
108
+ const configuration = {
109
+ tv_buttons_button_1_assign_action: "a",
110
+ tv_buttons_wrongprefix_2_assign_action: "b",
111
+ tv_buttons_button_x_assign_action: "c",
112
+ };
113
+
114
+ const index = 1;
115
+ const result = getPluginIdentifier(configuration, prefix, index);
116
+
117
+ expect(result).toBeUndefined();
118
+ });
119
+
120
+ it("returns undefined if all assign_actions are null or empty", () => {
121
+ const configuration = {
122
+ tv_buttons_button_1_assign_action: null,
123
+ tv_buttons_button_2_assign_action: undefined,
124
+ tv_buttons_button_3_assign_action: "",
125
+ };
126
+
127
+ const index = 0;
128
+ const result = getPluginIdentifier(configuration, prefix, index);
129
+
130
+ expect(result).toBeUndefined();
131
+ });
132
+
133
+ it("handles non-string values correctly", () => {
134
+ const configuration = {
135
+ tv_buttons_button_1_assign_action: 123,
136
+ tv_buttons_button_2_assign_action: true,
137
+ tv_buttons_button_3_assign_action: { nested: "value" },
138
+ };
139
+
140
+ expect(getPluginIdentifier(configuration, prefix, 0)).toEqual(123);
141
+ expect(getPluginIdentifier(configuration, prefix, 1)).toEqual(true);
142
+ expect(getPluginIdentifier(configuration, prefix, 2)).toEqual({
143
+ nested: "value",
144
+ });
145
+ });
48
146
  });
49
147
 
50
- describe("getPluginIdentifier - when configuration has same values for different keys", () => {
148
+ describe("getPluginIdentifier - when configuration has duplicate values", () => {
51
149
  const prefix = "tv_buttons";
52
150
 
53
151
  const configuration = {
@@ -55,17 +153,15 @@ describe("getPluginIdentifier - when configuration has same values for different
55
153
  tv_buttons_button_2_assign_action: "navigation_action",
56
154
  };
57
155
 
58
- it("get first plugin identifier", () => {
156
+ it("returns the first plugin identifier when values are identical", () => {
59
157
  const index = 0;
60
-
61
158
  const result = getPluginIdentifier(configuration, prefix, index);
62
159
 
63
160
  expect(result).toEqual(configuration.tv_buttons_button_1_assign_action);
64
161
  });
65
162
 
66
- it("get second plugin identifier", () => {
163
+ it("returns the second plugin identifier when values are identical", () => {
67
164
  const index = 1;
68
-
69
165
  const result = getPluginIdentifier(configuration, prefix, index);
70
166
 
71
167
  expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
@@ -1,7 +1,7 @@
1
1
  import * as R from "ramda";
2
+ import memoizee from "memoizee";
2
3
 
3
4
  import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
4
- import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
5
5
 
6
6
  export const getButtonsCount = (
7
7
  configuration: Record<string, unknown>,
@@ -21,23 +21,29 @@ export const getPluginIdentifier = (
21
21
  configuration: Record<string, unknown>,
22
22
  prefix: string,
23
23
  index: number
24
- ): string => {
25
- const match = `${prefix}_button_\\d_assign_action`;
26
- const re = new RegExp(match);
27
-
28
- const rejectNils = R.compose(R.path([index]), R.filter(isNotNil));
29
-
30
- return rejectNils(
31
- R.toPairs(configuration)
32
- .filter(([key]) => R.startsWith(`${prefix}_button`, key))
33
- .map(([key, value]) => {
34
- const matched = key.match(re);
24
+ ): string | undefined => {
25
+ const re = new RegExp(`${prefix}_button_\\d_assign_action`);
26
+ let count = 0;
27
+
28
+ for (const [key, value] of Object.entries(configuration)) {
29
+ if (
30
+ key.startsWith(`${prefix}_button`) &&
31
+ re.test(key) &&
32
+ value != null &&
33
+ value !== ""
34
+ ) {
35
+ if (count === index) return value as string;
36
+ count++;
37
+ }
38
+ }
35
39
 
36
- return matched ? value : undefined;
37
- })
38
- );
40
+ return undefined;
39
41
  };
40
42
 
43
+ export const memoizedGetPluginIdentifier = memoizee(getPluginIdentifier, {
44
+ primitive: true,
45
+ });
46
+
41
47
  type Label = {
42
48
  name: string;
43
49
  };
@@ -6,12 +6,12 @@ type withAsyncRenderHOCProps = {
6
6
  emitAsyncElementLayout?: () => void;
7
7
  };
8
8
 
9
- type withAsyncRenderHOCT = (
10
- Component: React.ComponentType<{ onAsyncRender: () => void }>
11
- ) => React.FC<withAsyncRenderHOCProps>;
12
-
13
- export const withAsyncRenderHOC: withAsyncRenderHOCT = (Component) => {
14
- const WithAsyncRender = (props: withAsyncRenderHOCProps) => {
9
+ export const withAsyncRenderHOC = <P extends { onAsyncRender: () => void }>(
10
+ Component: React.ComponentType<P>
11
+ ): React.FC<Omit<P, "onAsyncRender"> & withAsyncRenderHOCProps> => {
12
+ const WithAsyncRender = (
13
+ props: Omit<P, "onAsyncRender"> & withAsyncRenderHOCProps
14
+ ) => {
15
15
  const { emitAsyncElementRegistrate = noop, emitAsyncElementLayout = noop } =
16
16
  props;
17
17
 
@@ -27,7 +27,9 @@ export const withAsyncRenderHOC: withAsyncRenderHOCT = (Component) => {
27
27
  }
28
28
  }, [emitAsyncElementLayout]);
29
29
 
30
- return <Component {...props} onAsyncRender={onAsyncRender} />;
30
+ return (
31
+ <Component {...(props as unknown as P)} onAsyncRender={onAsyncRender} />
32
+ );
31
33
  };
32
34
 
33
35
  return WithAsyncRender;
@@ -1,4 +1,4 @@
1
- import { renderHook, act } from "@testing-library/react-hooks";
1
+ import { renderHook, act } from "@testing-library/react-native";
2
2
  import { BehaviorSubject } from "rxjs";
3
3
  import { useLoadingState } from "../useLoadingState";
4
4
 
@@ -1,18 +1,16 @@
1
- import React, { useLayoutEffect } from "react";
1
+ import { useLayoutEffect } from "react";
2
2
 
3
3
  import {
4
4
  allowedOrientationsForScreen,
5
- ORIENTATIONS,
6
5
  getOrientation,
6
+ ORIENTATIONS,
7
7
  useGetScreenOrientation,
8
8
  } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
9
9
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
10
10
  import { usePlugins, useAppData } from "@applicaster/zapp-react-native-redux";
11
11
  import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
12
12
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
13
-
14
- import { ZappHookModalContext } from "../../Contexts";
15
- import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
13
+ import { zappHookModalStore } from "../../Contexts/ZappHookModalContext";
16
14
 
17
15
  /**
18
16
  * This function calls the native module needed to set orientation
@@ -89,10 +87,6 @@ type Props = {
89
87
  };
90
88
 
91
89
  export function useScreenOrientationHandler({ screenData, isActive }: Props) {
92
- const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
93
- ZappHookModalContext.ReactContext
94
- );
95
-
96
90
  const prevIsActive = usePrevious(isActive);
97
91
 
98
92
  const newOrientation = useNewOrientationForScreenData({
@@ -105,6 +99,9 @@ export function useScreenOrientationHandler({ screenData, isActive }: Props) {
105
99
  return;
106
100
  }
107
101
 
102
+ // TODO: make sure it can be static getter and subscription is not needed
103
+ const { isHooksExecutionInProgress } = zappHookModalStore.getState();
104
+
108
105
  // If modal hook presented we need to skip
109
106
  // Change orientation for presenter screen
110
107
  if (isHooksExecutionInProgress) {
@@ -116,7 +113,7 @@ export function useScreenOrientationHandler({ screenData, isActive }: Props) {
116
113
 
117
114
  setOrientation(newOrientation);
118
115
  }
119
- }, [newOrientation, isHooksExecutionInProgress, prevIsActive, isActive]);
116
+ }, [newOrientation, prevIsActive, isActive]);
120
117
  }
121
118
 
122
119
  export function useOrientationHandler({ screenData }: OrientationHookArgs) {
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { act, renderHook, waitFor } from "@testing-library/react-native";
2
2
  import { useDelayedPlayerDetails } from "../useDelayedPlayerDetails";
3
3
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
4
4
 
@@ -13,16 +13,20 @@ describe("useDelayedPlayerDetails", () => {
13
13
  jest.clearAllMocks();
14
14
  });
15
15
 
16
- it("should return false initially, that changes after 1 second", () => {
16
+ it("should return false initially, that changes after 1 second", async () => {
17
17
  const { result } = renderHook(() =>
18
18
  useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
19
19
  );
20
20
 
21
21
  expect(result.current).toBe(false);
22
22
 
23
- jest.advanceTimersByTime(1000);
23
+ act(() => {
24
+ jest.advanceTimersByTime(1000);
25
+ });
24
26
 
25
- expect(result.current).toBe(true);
27
+ await waitFor(() => {
28
+ expect(result.current).toBe(true);
29
+ });
26
30
  });
27
31
 
28
32
  it("should return false when isPip is true", () => {
@@ -41,7 +45,7 @@ describe("useDelayedPlayerDetails", () => {
41
45
  expect(result.current).toBe(false);
42
46
  });
43
47
 
44
- it("should return true for tablet regardless of other flags", () => {
48
+ it("should return true for tablet regardless of other flags", async () => {
45
49
  (useIsTablet as jest.Mock).mockReturnValue(true);
46
50
 
47
51
  const { result } = renderHook(() =>
@@ -52,8 +56,12 @@ describe("useDelayedPlayerDetails", () => {
52
56
  })
53
57
  );
54
58
 
55
- jest.advanceTimersByTime(1000);
59
+ act(() => {
60
+ jest.advanceTimersByTime(1000);
61
+ });
56
62
 
57
- expect(result.current).toBe(true);
63
+ await waitFor(() => {
64
+ expect(result.current).toBe(true);
65
+ });
58
66
  });
59
67
  });
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { renderHook } from "@testing-library/react-hooks";
2
+ import { renderHook } from "@testing-library/react-native";
3
3
  import {
4
4
  ViewportEvents,
5
5
  useViewportEventsContext,
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import {
3
3
  useScreenTrackedViewPositionsContext,
4
4
  ScreenTrackedViewPositionsContext,
@@ -1,4 +1,4 @@
1
- import React, { useCallback } from "react";
1
+ import { create } from "zustand";
2
2
 
3
3
  type HookModalState = {
4
4
  path: string;
@@ -10,11 +10,12 @@ export type HookModalContextT = {
10
10
  setIsHooksExecutionInProgress: (hookExecutionState?: boolean) => void;
11
11
  isRunningInBackground: boolean;
12
12
  isPresentationFullScreen: boolean;
13
- setIsRunningInBackground: (hookBackgroundProcessState?: boolean) => void;
14
- setIsPresentingFullScreen: (hookBackgroundProcessState?: boolean) => void;
13
+ setIsRunningInBackground: () => void;
14
+ setIsPresentingFullScreen: () => void;
15
15
  state: HookModalState;
16
16
  setState: (state: HookModalState) => void;
17
17
  resetState: () => void;
18
+ hookPresentationMode: HookPresentationMode;
18
19
  };
19
20
 
20
21
  const initialState = {
@@ -24,68 +25,43 @@ const initialState = {
24
25
 
25
26
  type HookPresentationMode = "background" | "fullScreen";
26
27
 
27
- const ReactContext = React.createContext<HookModalContextT>({
28
- isHooksExecutionInProgress: false,
29
- setIsHooksExecutionInProgress: () => {},
30
- isRunningInBackground: null,
31
- setIsRunningInBackground: () => {},
32
- setIsPresentingFullScreen: () => {},
33
- isPresentationFullScreen: null,
28
+ // Use useZappHookModalStore() in React components (hooks)
29
+ // Use zappHookModalStore.getState() in non-React functions (utility functions, etc.)
30
+ export const useZappHookModalStore = create<HookModalContextT>()((set) => ({
34
31
  state: initialState,
35
- setState: () => null,
36
- resetState: () => null,
37
- });
38
-
39
- const Provider = ({ children }: { children: React.ReactNode }) => {
40
- const [state, setState] = React.useState<HookModalState>(initialState);
41
-
42
- const [hookPresentationMode, setHookPresentationMode] =
43
- React.useState<HookPresentationMode>(null);
44
-
45
- const resetState = useCallback(() => {
46
- setState(initialState);
47
- }, [setState]);
48
-
49
- const [isHooksExecutionInProgress, setIsHooksExecutionInProgress] =
50
- React.useState(false);
32
+ isHooksExecutionInProgress: false,
33
+ hookPresentationMode: null as HookPresentationMode,
34
+ isRunningInBackground: false,
35
+ isPresentationFullScreen: false,
51
36
 
52
- const setIsRunningInBackground = () => {
53
- setHookPresentationMode("background");
54
- };
37
+ setState: (newState: HookModalState) => {
38
+ set({ state: newState });
39
+ },
55
40
 
56
- const setIsPresentingFullScreen = () => {
57
- setHookPresentationMode("fullScreen");
58
- };
41
+ setIsHooksExecutionInProgress: (hookExecutionState?: boolean) => {
42
+ set({ isHooksExecutionInProgress: hookExecutionState ?? false });
43
+ },
59
44
 
60
- return (
61
- <ReactContext.Provider
62
- value={{
63
- isRunningInBackground: hookPresentationMode === "background",
64
- setIsRunningInBackground,
65
- setIsPresentingFullScreen,
66
- isPresentationFullScreen: hookPresentationMode === "fullScreen",
67
- isHooksExecutionInProgress,
68
- setIsHooksExecutionInProgress,
69
- state,
70
- setState,
71
- resetState,
72
- }}
73
- >
74
- {children}
75
- </ReactContext.Provider>
76
- );
77
- };
45
+ setIsRunningInBackground: () => {
46
+ set({
47
+ hookPresentationMode: "background",
48
+ isRunningInBackground: true,
49
+ isPresentationFullScreen: false,
50
+ });
51
+ },
78
52
 
79
- const withProvider = (Component) => {
80
- const WithProvider = (props) => {
81
- return (
82
- <Provider>
83
- <Component {...props} />
84
- </Provider>
85
- );
86
- };
53
+ setIsPresentingFullScreen: () => {
54
+ set({
55
+ hookPresentationMode: "fullScreen",
56
+ isRunningInBackground: false,
57
+ isPresentationFullScreen: true,
58
+ });
59
+ },
87
60
 
88
- return WithProvider;
89
- };
61
+ resetState: () => {
62
+ set({ state: initialState });
63
+ },
64
+ }));
90
65
 
91
- export const ZappHookModalContext = { withProvider, ReactContext };
66
+ // Export an alias for clearer non-React usage (utility functions, etc.)
67
+ export const zappHookModalStore = useZappHookModalStore;
package/Contexts/index.ts CHANGED
@@ -12,8 +12,6 @@ export { HorizontalScrollContext } from "./HorizontalScrollContext";
12
12
 
13
13
  export { RiverOffsetContext } from "./RiverOffsetContext";
14
14
 
15
- export { ZappHookModalContext } from "./ZappHookModalContext";
16
-
17
15
  export { MeasurementContext } from "./MeasurementContext";
18
16
 
19
17
  export * from "./ZappPipesContext";
package/events/index.ts CHANGED
@@ -5,4 +5,5 @@ export enum QBUIComponentEvents {
5
5
  scrollVerticallyToInitialOffset = "scrollVerticallyToInitialOffset",
6
6
  focusOnSelectedTab = "focusOnSelectedTab",
7
7
  focusOnSelectedTopMenuItem = "focusOnSelectedTopMenuItem",
8
+ scrollToTopForScreenWrappedInContainer = "scrollToTopForScreenWrappedInContainer",
8
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "15.0.0-alpha.7809066324",
3
+ "version": "15.0.0-alpha.8111467956",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,10 +28,10 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "15.0.0-alpha.7809066324",
32
- "@applicaster/zapp-react-native-bridge": "15.0.0-alpha.7809066324",
33
- "@applicaster/zapp-react-native-redux": "15.0.0-alpha.7809066324",
34
- "@applicaster/zapp-react-native-utils": "15.0.0-alpha.7809066324",
31
+ "@applicaster/applicaster-types": "15.0.0-alpha.8111467956",
32
+ "@applicaster/zapp-react-native-bridge": "15.0.0-alpha.8111467956",
33
+ "@applicaster/zapp-react-native-redux": "15.0.0-alpha.8111467956",
34
+ "@applicaster/zapp-react-native-utils": "15.0.0-alpha.8111467956",
35
35
  "fast-json-stable-stringify": "^2.1.0",
36
36
  "promise": "^8.3.0",
37
37
  "url": "^0.11.0",