@applicaster/zapp-react-native-ui-components 14.0.7 → 14.0.8

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.
@@ -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;
@@ -10,6 +10,10 @@ describe("SecondaryImage - Image", () => {
10
10
  displayMode="dynamic"
11
11
  uri={undefined}
12
12
  style={{ width: 100 }}
13
+ imageSizing="fit"
14
+ fitPosition="center"
15
+ fixedWidth={0}
16
+ fixedHeight={0}
13
17
  />
14
18
  );
15
19
 
@@ -23,6 +27,10 @@ describe("SecondaryImage - Image", () => {
23
27
  displayMode="dynamic"
24
28
  uri="someurl"
25
29
  style={{ width: 100 }}
30
+ imageSizing="fit"
31
+ fitPosition="center"
32
+ fixedWidth={0}
33
+ fixedHeight={0}
26
34
  />
27
35
  );
28
36
 
@@ -36,6 +44,93 @@ describe("SecondaryImage - Image", () => {
36
44
  uri="someUrl"
37
45
  displayMode="dynamic"
38
46
  style={{ width: 100, height: 100, borderRadius: 10 }}
47
+ imageSizing="fill"
48
+ fitPosition="center"
49
+ fixedWidth={0}
50
+ fixedHeight={0}
51
+ />
52
+ );
53
+
54
+ expect(wrapper.toJSON()).not.toEqual(null);
55
+ expect(wrapper.toJSON()).toMatchSnapshot();
56
+ });
57
+
58
+ it("SecondaryImage should render in fixed mode without image until loaded", async () => {
59
+ const wrapper = await render(
60
+ <SecondaryImage
61
+ displayMode="fixed"
62
+ uri="someurl"
63
+ style={{ width: 100, height: 100, borderRadius: 5 }}
64
+ imageSizing="fit"
65
+ fitPosition="center"
66
+ fixedWidth={100}
67
+ fixedHeight={100}
68
+ />
69
+ );
70
+
71
+ expect(wrapper.toJSON()).toMatchSnapshot();
72
+ });
73
+
74
+ it("SecondaryImage should not render in dynamic mode without image", async () => {
75
+ const wrapper = await render(
76
+ <SecondaryImage
77
+ displayMode="dynamic"
78
+ uri={null}
79
+ style={{ width: 100, height: 100 }}
80
+ imageSizing="fit"
81
+ fitPosition="center"
82
+ fixedWidth={0}
83
+ fixedHeight={0}
84
+ />
85
+ );
86
+
87
+ expect(wrapper.toJSON()).toEqual(null);
88
+ expect(wrapper.toJSON()).toMatchSnapshot();
89
+ });
90
+
91
+ it("SecondaryImage should render in fixed mode with known dimensions", async () => {
92
+ const wrapper = await render(
93
+ <SecondaryImage
94
+ uri="someUrl"
95
+ displayMode="fixed"
96
+ style={{ width: 100, height: 100, borderRadius: 10 }}
97
+ imageSizing="fill"
98
+ fitPosition="center"
99
+ fixedWidth={100}
100
+ fixedHeight={100}
101
+ />
102
+ );
103
+
104
+ expect(wrapper.toJSON()).not.toEqual(null);
105
+ expect(wrapper.toJSON()).toMatchSnapshot();
106
+ });
107
+
108
+ it("SecondaryImage dynamic mode should call onAsyncRender when provided", async () => {
109
+ const wrapper = await render(
110
+ <SecondaryImage
111
+ uri="someUrl"
112
+ displayMode="dynamic"
113
+ style={{ width: 100, height: 100, borderRadius: 10 }}
114
+ imageSizing="fill"
115
+ fitPosition="center"
116
+ fixedWidth={0}
117
+ fixedHeight={0}
118
+ />
119
+ );
120
+
121
+ expect(wrapper.toJSON()).not.toEqual(null);
122
+ });
123
+
124
+ it("SecondaryImage fixed mode should not use async render props", async () => {
125
+ const wrapper = await render(
126
+ <SecondaryImage
127
+ uri="someUrl"
128
+ displayMode="fixed"
129
+ style={{ width: 100, height: 100, borderRadius: 10 }}
130
+ imageSizing="fill"
131
+ fitPosition="center"
132
+ fixedWidth={100}
133
+ fixedHeight={100}
39
134
  />
40
135
  );
41
136
 
@@ -1,9 +1,45 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`SecondaryImage - Image SecondaryImage fixed mode should not use async render props 1`] = `
4
+ <View
5
+ style={
6
+ {
7
+ "borderRadius": 10,
8
+ "height": 100,
9
+ "width": 100,
10
+ }
11
+ }
12
+ >
13
+ <Image
14
+ displayMode="fixed"
15
+ fitPosition="center"
16
+ fixedHeight={100}
17
+ fixedWidth={100}
18
+ imageSizing="fill"
19
+ source={
20
+ {
21
+ "uri": "someUrl",
22
+ }
23
+ }
24
+ style={
25
+ {
26
+ "aspectRatio": 1,
27
+ "borderRadius": 10,
28
+ "height": 100,
29
+ "width": 100,
30
+ }
31
+ }
32
+ uri="someUrl"
33
+ />
34
+ </View>
35
+ `;
36
+
3
37
  exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio (dynamic) 1`] = `null`;
4
38
 
5
39
  exports[`SecondaryImage - Image SecondaryImage should not render if no uri 1`] = `null`;
6
40
 
41
+ exports[`SecondaryImage - Image SecondaryImage should not render in dynamic mode without image 1`] = `null`;
42
+
7
43
  exports[`SecondaryImage - Image SecondaryImage should render if known dimensions 1`] = `
8
44
  <View
9
45
  onLayout={[Function]}
@@ -17,6 +53,10 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
17
53
  >
18
54
  <Image
19
55
  displayMode="dynamic"
56
+ fitPosition="center"
57
+ fixedHeight={0}
58
+ fixedWidth={0}
59
+ imageSizing="fill"
20
60
  onAsyncRender={[Function]}
21
61
  source={
22
62
  {
@@ -35,3 +75,49 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
35
75
  />
36
76
  </View>
37
77
  `;
78
+
79
+ exports[`SecondaryImage - Image SecondaryImage should render in fixed mode with known dimensions 1`] = `
80
+ <View
81
+ style={
82
+ {
83
+ "borderRadius": 10,
84
+ "height": 100,
85
+ "width": 100,
86
+ }
87
+ }
88
+ >
89
+ <Image
90
+ displayMode="fixed"
91
+ fitPosition="center"
92
+ fixedHeight={100}
93
+ fixedWidth={100}
94
+ imageSizing="fill"
95
+ source={
96
+ {
97
+ "uri": "someUrl",
98
+ }
99
+ }
100
+ style={
101
+ {
102
+ "aspectRatio": 1,
103
+ "borderRadius": 10,
104
+ "height": 100,
105
+ "width": 100,
106
+ }
107
+ }
108
+ uri="someUrl"
109
+ />
110
+ </View>
111
+ `;
112
+
113
+ exports[`SecondaryImage - Image SecondaryImage should render in fixed mode without image until loaded 1`] = `
114
+ <View
115
+ style={
116
+ {
117
+ "borderRadius": 5,
118
+ "height": 100,
119
+ "width": 100,
120
+ }
121
+ }
122
+ />
123
+ `;
@@ -0,0 +1,141 @@
1
+ import { SecondaryImage } from "../index";
2
+
3
+ describe("SecondaryImage - Configuration Builder", () => {
4
+ const mockValue = (config: any) => (key: string, transformer?: Function) => {
5
+ const value = config[key];
6
+
7
+ return transformer ? transformer(value) : value;
8
+ };
9
+
10
+ it("should pass false as second argument to image_src_from_media_item", () => {
11
+ const config = {
12
+ secondary_image_switch: true,
13
+ secondary_image_position: "over_image",
14
+ secondary_image_visibility: "always",
15
+ secondary_image_image_key: "custom_image",
16
+ secondary_image_display_mode: "dynamic",
17
+ secondary_image_dynamic_width: 100,
18
+ };
19
+
20
+ const result = SecondaryImage({
21
+ value: mockValue(config),
22
+ currentPosition: "over_image",
23
+ state: "default",
24
+ });
25
+
26
+ expect(result).not.toBeNull();
27
+ expect(result?.elements).toBeDefined();
28
+ expect(result?.elements[0].data).toBeDefined();
29
+
30
+ const imageData = result?.elements[0].data[0];
31
+ expect(imageData.func).toBe("image_src_from_media_item");
32
+ expect(imageData.args).toEqual(["custom_image", false]);
33
+ expect(imageData.propName).toBe("uri");
34
+ });
35
+
36
+ it("should return null when secondary image is disabled", () => {
37
+ const config = {
38
+ secondary_image_switch: false,
39
+ };
40
+
41
+ const result = SecondaryImage({
42
+ value: mockValue(config),
43
+ currentPosition: "over_image",
44
+ state: "default",
45
+ });
46
+
47
+ expect(result).toBeNull();
48
+ });
49
+
50
+ it("should return null when position does not match currentPosition", () => {
51
+ const config = {
52
+ secondary_image_switch: true,
53
+ secondary_image_position: "above_text_label_1",
54
+ secondary_image_visibility: "always",
55
+ };
56
+
57
+ const result = SecondaryImage({
58
+ value: mockValue(config),
59
+ currentPosition: "over_image",
60
+ state: "default",
61
+ });
62
+
63
+ expect(result).toBeNull();
64
+ });
65
+
66
+ it("should return null when visibility does not match state", () => {
67
+ const config = {
68
+ secondary_image_switch: true,
69
+ secondary_image_position: "over_image",
70
+ secondary_image_visibility: "focused",
71
+ };
72
+
73
+ const result = SecondaryImage({
74
+ value: mockValue(config),
75
+ currentPosition: "over_image",
76
+ state: "default",
77
+ });
78
+
79
+ expect(result).toBeNull();
80
+ });
81
+
82
+ it("should include display mode and image sizing in additionalProps", () => {
83
+ const config = {
84
+ secondary_image_switch: true,
85
+ secondary_image_position: "over_image",
86
+ secondary_image_visibility: "always",
87
+ secondary_image_image_key: "logo",
88
+ secondary_image_display_mode: "fixed",
89
+ secondary_image_image_sizing: "fill",
90
+ secondary_image_fit_position: "center",
91
+ secondary_image_fixed_width: 200,
92
+ secondary_image_fixed_height: 150,
93
+ };
94
+
95
+ const result = SecondaryImage({
96
+ value: mockValue(config),
97
+ currentPosition: "over_image",
98
+ state: "default",
99
+ });
100
+
101
+ expect(result?.elements[0].additionalProps).toMatchObject({
102
+ displayMode: "fixed",
103
+ imageSizing: "fill",
104
+ fitPosition: "center",
105
+ fixedWidth: 200,
106
+ fixedHeight: 150,
107
+ });
108
+ });
109
+
110
+ it("should apply correct styles including margins and border radius", () => {
111
+ const config = {
112
+ secondary_image_switch: true,
113
+ secondary_image_position: "over_image",
114
+ secondary_image_visibility: "always",
115
+ secondary_image_display_mode: "fixed",
116
+ secondary_image_fixed_width: 100,
117
+ secondary_image_fixed_height: 100,
118
+ secondary_image_corner_radius: 12,
119
+ secondary_image_margin_top: 10,
120
+ secondary_image_margin_left: 5,
121
+ secondary_image_margin_right: 5,
122
+ secondary_image_margin_bottom: 10,
123
+ };
124
+
125
+ const result = SecondaryImage({
126
+ value: mockValue(config),
127
+ currentPosition: "over_image",
128
+ state: "default",
129
+ });
130
+
131
+ expect(result?.elements[0].style).toMatchObject({
132
+ width: 100,
133
+ height: 100,
134
+ borderRadius: 12,
135
+ marginTop: 10,
136
+ marginLeft: 5,
137
+ marginRight: 5,
138
+ marginBottom: 10,
139
+ });
140
+ });
141
+ });
@@ -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
  ],
@@ -0,0 +1,219 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { Text, View } from "react-native";
4
+ import { withAsyncRenderHOC } from "../withAsyncRender";
5
+
6
+ describe("withAsyncRenderHOC", () => {
7
+ // Test component that requires onAsyncRender
8
+ const TestComponent = ({
9
+ onAsyncRender,
10
+ text,
11
+ }: {
12
+ onAsyncRender: () => void;
13
+ text?: string;
14
+ }) => {
15
+ React.useEffect(() => {
16
+ onAsyncRender();
17
+ }, [onAsyncRender]);
18
+
19
+ return (
20
+ <View>
21
+ <Text>{text || "Test"}</Text>
22
+ </View>
23
+ );
24
+ };
25
+
26
+ it("should wrap component and provide onAsyncRender callback", () => {
27
+ const WrappedComponent = withAsyncRenderHOC(TestComponent);
28
+
29
+ const wrapper = render(<WrappedComponent text="Hello" />);
30
+
31
+ expect(wrapper.toJSON()).not.toBeNull();
32
+ expect(wrapper.getByText("Hello")).toBeDefined();
33
+ });
34
+
35
+ it("should call emitAsyncElementRegistrate on mount", () => {
36
+ const mockRegistrate = jest.fn();
37
+ const WrappedComponent = withAsyncRenderHOC(TestComponent);
38
+
39
+ render(<WrappedComponent emitAsyncElementRegistrate={mockRegistrate} />);
40
+
41
+ expect(mockRegistrate).toHaveBeenCalledTimes(1);
42
+ });
43
+
44
+ it("should call emitAsyncElementLayout when onAsyncRender is called", () => {
45
+ const mockLayout = jest.fn();
46
+
47
+ const ComponentWithAsyncCall = ({
48
+ onAsyncRender,
49
+ }: {
50
+ onAsyncRender: () => void;
51
+ }) => {
52
+ return (
53
+ <View onLayout={onAsyncRender}>
54
+ <Text>Async Component</Text>
55
+ </View>
56
+ );
57
+ };
58
+
59
+ const WrappedComponent = withAsyncRenderHOC(ComponentWithAsyncCall);
60
+
61
+ const wrapper = render(
62
+ <WrappedComponent emitAsyncElementLayout={mockLayout} />
63
+ );
64
+
65
+ // Trigger onLayout
66
+ const view = wrapper.UNSAFE_getByType(View);
67
+ view.props.onLayout();
68
+
69
+ expect(mockLayout).toHaveBeenCalled();
70
+ });
71
+
72
+ it("should return unsubscribe function from emitAsyncElementRegistrate", () => {
73
+ const mockUnsubscribe = jest.fn();
74
+ const mockRegistrate = jest.fn(() => mockUnsubscribe);
75
+ const WrappedComponent = withAsyncRenderHOC(TestComponent);
76
+
77
+ const { unmount } = render(
78
+ <WrappedComponent emitAsyncElementRegistrate={mockRegistrate} />
79
+ );
80
+
81
+ expect(mockRegistrate).toHaveBeenCalledTimes(1);
82
+
83
+ // Unmount should trigger cleanup
84
+ unmount();
85
+
86
+ expect(mockUnsubscribe).toHaveBeenCalled();
87
+ });
88
+
89
+ it("should work without emitAsyncElementRegistrate prop", () => {
90
+ const WrappedComponent = withAsyncRenderHOC(TestComponent);
91
+
92
+ const wrapper = render(<WrappedComponent text="No Registration" />);
93
+
94
+ expect(wrapper.toJSON()).not.toBeNull();
95
+ expect(wrapper.getByText("No Registration")).toBeDefined();
96
+ });
97
+
98
+ it("should work without emitAsyncElementLayout prop", () => {
99
+ const ComponentWithLayout = ({
100
+ onAsyncRender,
101
+ }: {
102
+ onAsyncRender: () => void;
103
+ }) => {
104
+ return (
105
+ <View onLayout={onAsyncRender}>
106
+ <Text>Test Layout</Text>
107
+ </View>
108
+ );
109
+ };
110
+
111
+ const WrappedComponent = withAsyncRenderHOC(ComponentWithLayout);
112
+
113
+ const wrapper = render(<WrappedComponent />);
114
+
115
+ // Should not throw when calling onLayout without emitAsyncElementLayout
116
+ const view = wrapper.UNSAFE_getByType(View);
117
+ expect(() => view.props.onLayout()).not.toThrow();
118
+ });
119
+
120
+ it("should pass through all other props to wrapped component", () => {
121
+ const ComponentWithProps = ({
122
+ customProp,
123
+ anotherProp,
124
+ }: {
125
+ onAsyncRender: () => void;
126
+ customProp: string;
127
+ anotherProp: number;
128
+ }) => {
129
+ return (
130
+ <View>
131
+ <Text>{customProp}</Text>
132
+ <Text>{anotherProp}</Text>
133
+ </View>
134
+ );
135
+ };
136
+
137
+ const WrappedComponent = withAsyncRenderHOC(ComponentWithProps);
138
+
139
+ const wrapper = render(
140
+ <WrappedComponent customProp="custom value" anotherProp={42} />
141
+ );
142
+
143
+ expect(wrapper.getByText("custom value")).toBeDefined();
144
+ expect(wrapper.getByText("42")).toBeDefined();
145
+ });
146
+
147
+ it("should call emitAsyncElementLayout multiple times if onAsyncRender is called multiple times", () => {
148
+ const mockLayout = jest.fn();
149
+
150
+ const ComponentWithMultipleCalls = ({
151
+ onAsyncRender,
152
+ }: {
153
+ onAsyncRender: () => void;
154
+ }) => {
155
+ return (
156
+ <View>
157
+ <View onLayout={onAsyncRender} testID="view1">
158
+ <Text>First</Text>
159
+ </View>
160
+ <View onLayout={onAsyncRender} testID="view2">
161
+ <Text>Second</Text>
162
+ </View>
163
+ </View>
164
+ );
165
+ };
166
+
167
+ const WrappedComponent = withAsyncRenderHOC(ComponentWithMultipleCalls);
168
+
169
+ const wrapper = render(
170
+ <WrappedComponent emitAsyncElementLayout={mockLayout} />
171
+ );
172
+
173
+ // Trigger both onLayout callbacks
174
+ const view1 = wrapper.getByTestId("view1");
175
+ const view2 = wrapper.getByTestId("view2");
176
+
177
+ view1.props.onLayout();
178
+ view2.props.onLayout();
179
+
180
+ expect(mockLayout).toHaveBeenCalledTimes(2);
181
+ });
182
+
183
+ it("should handle components that use onAsyncRender in effects", () => {
184
+ const mockLayout = jest.fn();
185
+
186
+ const ComponentWithEffect = ({
187
+ onAsyncRender,
188
+ }: {
189
+ onAsyncRender: () => void;
190
+ }) => {
191
+ React.useEffect(() => {
192
+ // Simulate async operation completing
193
+ const timer = setTimeout(() => {
194
+ onAsyncRender();
195
+ }, 0);
196
+
197
+ return () => clearTimeout(timer);
198
+ }, [onAsyncRender]);
199
+
200
+ return (
201
+ <View>
202
+ <Text>Effect Component</Text>
203
+ </View>
204
+ );
205
+ };
206
+
207
+ const WrappedComponent = withAsyncRenderHOC(ComponentWithEffect);
208
+
209
+ render(<WrappedComponent emitAsyncElementLayout={mockLayout} />);
210
+
211
+ // The effect should have been triggered
212
+ return new Promise((resolve) => {
213
+ setTimeout(() => {
214
+ expect(mockLayout).toHaveBeenCalled();
215
+ resolve(true);
216
+ }, 10);
217
+ });
218
+ });
219
+ });
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "14.0.7",
3
+ "version": "14.0.8",
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": "14.0.7",
32
- "@applicaster/zapp-react-native-bridge": "14.0.7",
33
- "@applicaster/zapp-react-native-redux": "14.0.7",
34
- "@applicaster/zapp-react-native-utils": "14.0.7",
31
+ "@applicaster/applicaster-types": "14.0.8",
32
+ "@applicaster/zapp-react-native-bridge": "14.0.8",
33
+ "@applicaster/zapp-react-native-redux": "14.0.8",
34
+ "@applicaster/zapp-react-native-utils": "14.0.8",
35
35
  "fast-json-stable-stringify": "^2.1.0",
36
36
  "promise": "^8.3.0",
37
37
  "url": "^0.11.0",