@hero-design/rn 8.12.5 → 8.13.0

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.
@@ -0,0 +1,343 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Error renders error screen with image correctly 1`] = `
4
+ <View
5
+ style={
6
+ Array [
7
+ Object {
8
+ "backgroundColor": "#f6f6f7",
9
+ "display": "flex",
10
+ "flex": 1,
11
+ "flexDirection": "column",
12
+ },
13
+ undefined,
14
+ ]
15
+ }
16
+ themeVariant="in-page"
17
+ >
18
+ <View
19
+ style={
20
+ Array [
21
+ Object {
22
+ "alignItems": "center",
23
+ "display": "flex",
24
+ "flex": 1,
25
+ "flexDirection": "column",
26
+ "justifyContent": "center",
27
+ "padding": 24,
28
+ },
29
+ undefined,
30
+ ]
31
+ }
32
+ >
33
+ <Image
34
+ source={
35
+ Object {
36
+ "uri": "path_to_image",
37
+ }
38
+ }
39
+ style={
40
+ Array [
41
+ Object {
42
+ "borderRadius": 0,
43
+ "height": 72,
44
+ "width": 72,
45
+ },
46
+ Array [
47
+ Object {
48
+ "height": 176,
49
+ "marginBottom": 32,
50
+ "resizeMode": "contain",
51
+ "width": 176,
52
+ },
53
+ undefined,
54
+ ],
55
+ ]
56
+ }
57
+ testID="error-image"
58
+ />
59
+ <Text
60
+ style={
61
+ Array [
62
+ Object {
63
+ "color": "#001f23",
64
+ "fontFamily": "BeVietnamPro-Regular",
65
+ "fontSize": 14,
66
+ "letterSpacing": 0.42,
67
+ "lineHeight": 22,
68
+ },
69
+ Array [
70
+ Object {
71
+ "color": "#001f23",
72
+ "fontFamily": "RebondGrotesque-SemiBold",
73
+ "fontSize": 24,
74
+ "marginBottom": 8,
75
+ "textAlign": "center",
76
+ },
77
+ undefined,
78
+ ],
79
+ ]
80
+ }
81
+ themeFontSize="medium"
82
+ themeFontWeight="regular"
83
+ themeIntent="body"
84
+ themeTypeface="neutral"
85
+ >
86
+ We’re sorry, something went wrong
87
+ </Text>
88
+ <Text
89
+ style={
90
+ Array [
91
+ Object {
92
+ "color": "#001f23",
93
+ "fontFamily": "BeVietnamPro-Regular",
94
+ "fontSize": 14,
95
+ "letterSpacing": 0.42,
96
+ "lineHeight": 22,
97
+ },
98
+ Array [
99
+ Object {
100
+ "color": "#4d6265",
101
+ "fontFamily": "RebondGrotesque",
102
+ "fontSize": 18,
103
+ "textAlign": "center",
104
+ },
105
+ undefined,
106
+ ],
107
+ ]
108
+ }
109
+ themeFontSize="medium"
110
+ themeFontWeight="regular"
111
+ themeIntent="body"
112
+ themeTypeface="neutral"
113
+ >
114
+ Please try again later
115
+ </Text>
116
+ </View>
117
+ </View>
118
+ `;
119
+
120
+ exports[`Error renders full screen error page correctly 1`] = `
121
+ <Modal
122
+ animationType="slide"
123
+ hardwareAccelerated={false}
124
+ onDismiss={[Function]}
125
+ onRequestClose={[Function]}
126
+ style={
127
+ Array [
128
+ Object {
129
+ "height": "100%",
130
+ "width": "100%",
131
+ },
132
+ undefined,
133
+ ]
134
+ }
135
+ visible={true}
136
+ >
137
+ <View
138
+ style={
139
+ Array [
140
+ Object {
141
+ "backgroundColor": "#ccd2d3",
142
+ "display": "flex",
143
+ "flex": 1,
144
+ "flexDirection": "column",
145
+ },
146
+ undefined,
147
+ ]
148
+ }
149
+ themeVariant="full-screen"
150
+ >
151
+ <View
152
+ style={
153
+ Array [
154
+ Object {
155
+ "alignItems": "center",
156
+ "display": "flex",
157
+ "flex": 1,
158
+ "flexDirection": "column",
159
+ "justifyContent": "center",
160
+ "padding": 24,
161
+ },
162
+ undefined,
163
+ ]
164
+ }
165
+ >
166
+ <Image
167
+ source={
168
+ Object {
169
+ "uri": "path_to_image",
170
+ }
171
+ }
172
+ style={
173
+ Array [
174
+ Object {
175
+ "borderRadius": 0,
176
+ "height": 72,
177
+ "width": 72,
178
+ },
179
+ Array [
180
+ Object {
181
+ "height": 176,
182
+ "marginBottom": 32,
183
+ "resizeMode": "contain",
184
+ "width": 176,
185
+ },
186
+ undefined,
187
+ ],
188
+ ]
189
+ }
190
+ testID="error-image"
191
+ />
192
+ <Text
193
+ style={
194
+ Array [
195
+ Object {
196
+ "color": "#001f23",
197
+ "fontFamily": "BeVietnamPro-Regular",
198
+ "fontSize": 14,
199
+ "letterSpacing": 0.42,
200
+ "lineHeight": 22,
201
+ },
202
+ Array [
203
+ Object {
204
+ "color": "#001f23",
205
+ "fontFamily": "RebondGrotesque-SemiBold",
206
+ "fontSize": 24,
207
+ "marginBottom": 8,
208
+ "textAlign": "center",
209
+ },
210
+ undefined,
211
+ ],
212
+ ]
213
+ }
214
+ themeFontSize="medium"
215
+ themeFontWeight="regular"
216
+ themeIntent="body"
217
+ themeTypeface="neutral"
218
+ >
219
+ We’re sorry, something went wrong
220
+ </Text>
221
+ <Text
222
+ style={
223
+ Array [
224
+ Object {
225
+ "color": "#001f23",
226
+ "fontFamily": "BeVietnamPro-Regular",
227
+ "fontSize": 14,
228
+ "letterSpacing": 0.42,
229
+ "lineHeight": 22,
230
+ },
231
+ Array [
232
+ Object {
233
+ "color": "#4d6265",
234
+ "fontFamily": "RebondGrotesque",
235
+ "fontSize": 18,
236
+ "textAlign": "center",
237
+ },
238
+ undefined,
239
+ ],
240
+ ]
241
+ }
242
+ themeFontSize="medium"
243
+ themeFontWeight="regular"
244
+ themeIntent="body"
245
+ themeTypeface="neutral"
246
+ >
247
+ Please try again later
248
+ </Text>
249
+ </View>
250
+ </View>
251
+ </Modal>
252
+ `;
253
+
254
+ exports[`Error renders title only correctly 1`] = `
255
+ <View
256
+ style={
257
+ Array [
258
+ Object {
259
+ "backgroundColor": "#f6f6f7",
260
+ "display": "flex",
261
+ "flex": 1,
262
+ "flexDirection": "column",
263
+ },
264
+ undefined,
265
+ ]
266
+ }
267
+ themeVariant="in-page"
268
+ >
269
+ <View
270
+ style={
271
+ Array [
272
+ Object {
273
+ "alignItems": "center",
274
+ "display": "flex",
275
+ "flex": 1,
276
+ "flexDirection": "column",
277
+ "justifyContent": "center",
278
+ "padding": 24,
279
+ },
280
+ undefined,
281
+ ]
282
+ }
283
+ >
284
+ <Text
285
+ style={
286
+ Array [
287
+ Object {
288
+ "color": "#001f23",
289
+ "fontFamily": "BeVietnamPro-Regular",
290
+ "fontSize": 14,
291
+ "letterSpacing": 0.42,
292
+ "lineHeight": 22,
293
+ },
294
+ Array [
295
+ Object {
296
+ "color": "#001f23",
297
+ "fontFamily": "RebondGrotesque-SemiBold",
298
+ "fontSize": 24,
299
+ "marginBottom": 8,
300
+ "textAlign": "center",
301
+ },
302
+ undefined,
303
+ ],
304
+ ]
305
+ }
306
+ themeFontSize="medium"
307
+ themeFontWeight="regular"
308
+ themeIntent="body"
309
+ themeTypeface="neutral"
310
+ >
311
+ We’re sorry, something went wrong
312
+ </Text>
313
+ <Text
314
+ style={
315
+ Array [
316
+ Object {
317
+ "color": "#001f23",
318
+ "fontFamily": "BeVietnamPro-Regular",
319
+ "fontSize": 14,
320
+ "letterSpacing": 0.42,
321
+ "lineHeight": 22,
322
+ },
323
+ Array [
324
+ Object {
325
+ "color": "#4d6265",
326
+ "fontFamily": "RebondGrotesque",
327
+ "fontSize": 18,
328
+ "textAlign": "center",
329
+ },
330
+ undefined,
331
+ ],
332
+ ]
333
+ }
334
+ themeFontSize="medium"
335
+ themeFontWeight="regular"
336
+ themeIntent="body"
337
+ themeTypeface="neutral"
338
+ >
339
+ Please try again later
340
+ </Text>
341
+ </View>
342
+ </View>
343
+ `;
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+ import { fireEvent } from '@testing-library/react-native';
3
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
4
+ import Error from '..';
5
+
6
+ const title = `We’re sorry, something went wrong`;
7
+ const description = 'Please try again later';
8
+
9
+ describe('Error', () => {
10
+ it('renders title only correctly', () => {
11
+ const { toJSON, getByText } = renderWithTheme(
12
+ <Error visible title={title} description={description} />
13
+ );
14
+
15
+ expect(getByText(title)).toBeTruthy();
16
+ expect(getByText(description)).toBeTruthy();
17
+ expect(toJSON()).toMatchSnapshot();
18
+ });
19
+ it('renders error screen with image correctly', () => {
20
+ const { toJSON, getByText, getByTestId } = renderWithTheme(
21
+ <Error
22
+ visible
23
+ title={title}
24
+ description={description}
25
+ image="path_to_image"
26
+ />
27
+ );
28
+
29
+ expect(getByText(title)).toBeTruthy();
30
+ expect(getByText(description)).toBeTruthy();
31
+ expect(getByTestId('error-image')).toBeTruthy();
32
+ expect(toJSON()).toMatchSnapshot();
33
+ });
34
+ it('renders full screen error page correctly', () => {
35
+ const { toJSON, getByText, getByTestId } = renderWithTheme(
36
+ <Error
37
+ visible
38
+ variant="full-screen"
39
+ title={title}
40
+ description={description}
41
+ image="path_to_image"
42
+ />
43
+ );
44
+
45
+ expect(getByText(title)).toBeTruthy();
46
+ expect(getByText(description)).toBeTruthy();
47
+ expect(getByTestId('error-image')).toBeTruthy();
48
+ expect(toJSON()).toMatchSnapshot();
49
+ });
50
+ it('handles CTA press correctly', () => {
51
+ const onCtaPress = jest.fn();
52
+ const onSecondaryCtaPress = jest.fn();
53
+ const { getByText } = renderWithTheme(
54
+ <Error
55
+ visible
56
+ title={title}
57
+ description={description}
58
+ image="path_to_image"
59
+ ctaText="CTA Text"
60
+ onCtaPress={onCtaPress}
61
+ secondaryCtaText="Secondary CTA Text"
62
+ onSecondaryCtaPress={onSecondaryCtaPress}
63
+ />
64
+ );
65
+
66
+ const CTA = getByText('CTA Text');
67
+ fireEvent.press(CTA);
68
+ expect(onCtaPress).toBeCalledTimes(1);
69
+
70
+ const secondaryCTA = getByText('Secondary CTA Text');
71
+ fireEvent.press(secondaryCTA);
72
+ expect(onSecondaryCtaPress).toBeCalledTimes(1);
73
+ });
74
+ });
@@ -0,0 +1,215 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import type { ReactElement } from 'react';
3
+ import type { ImageSourcePropType, ViewProps } from 'react-native';
4
+ import {
5
+ ErrorVariant,
6
+ StyledErrorButtonContainer,
7
+ StyledErrorButtonPrimary,
8
+ StyledErrorButtonSecondary,
9
+ StyledErrorContainer,
10
+ StyledErrorContent,
11
+ StyledErrorDescription,
12
+ StyledErrorImage,
13
+ StyledErrorModal,
14
+ StyledErrorTitle,
15
+ } from './StyledError';
16
+
17
+ interface ErrorPageProps extends ViewProps {
18
+ /**
19
+ * Variant of the error
20
+ */
21
+ variant?: ErrorVariant;
22
+ /**
23
+ * Title of the error
24
+ */
25
+ title: string;
26
+ /**
27
+ * Description of the error
28
+ */
29
+ description?: string;
30
+ /**
31
+ * Image of the error
32
+ */
33
+ image?: ImageSourcePropType | string;
34
+ /**
35
+ * Testing id of the component.
36
+ */
37
+ testID?: string;
38
+ /**
39
+ * Action button text
40
+ */
41
+ ctaText?: string;
42
+ /**
43
+ * Callback when the action button is pressed.
44
+ */
45
+ onCtaPress?: () => void;
46
+ /**
47
+ * Secondary button text
48
+ */
49
+ secondaryCtaText?: string;
50
+ /**
51
+ * Callback when the secondary button is pressed.
52
+ */
53
+ onSecondaryCtaPress?: () => void;
54
+ }
55
+
56
+ type ErrorProps = ErrorPageProps & {
57
+ /**
58
+ * Visibility of the error
59
+ */
60
+ visible: boolean;
61
+ };
62
+
63
+ type onCloseCallbackType = 'cta' | 'secondaryCta' | null;
64
+
65
+ const ErrorPage = ({
66
+ variant = 'in-page',
67
+ title,
68
+ description,
69
+ image,
70
+ testID,
71
+ ctaText,
72
+ onCtaPress,
73
+ secondaryCtaText,
74
+ onSecondaryCtaPress,
75
+ ...nativeProps
76
+ }: ErrorPageProps): ReactElement => {
77
+ const showCta = ctaText && onCtaPress !== undefined;
78
+ const showSecondaryCta =
79
+ secondaryCtaText && onSecondaryCtaPress !== undefined;
80
+ const showButtonContainer = showCta || showSecondaryCta;
81
+ return (
82
+ <StyledErrorContainer testID={testID} themeVariant={variant}>
83
+ <StyledErrorContent {...nativeProps}>
84
+ {image && (
85
+ <StyledErrorImage
86
+ source={typeof image === 'string' ? { uri: image } : image}
87
+ testID="error-image"
88
+ />
89
+ )}
90
+
91
+ <StyledErrorTitle>{title}</StyledErrorTitle>
92
+
93
+ {description && (
94
+ <StyledErrorDescription>{description}</StyledErrorDescription>
95
+ )}
96
+ </StyledErrorContent>
97
+
98
+ {showButtonContainer && (
99
+ <StyledErrorButtonContainer>
100
+ {showCta && (
101
+ <StyledErrorButtonPrimary
102
+ variant="filled"
103
+ text={ctaText}
104
+ onPress={onCtaPress}
105
+ />
106
+ )}
107
+ {showSecondaryCta && (
108
+ <StyledErrorButtonSecondary
109
+ variant="text"
110
+ text={secondaryCtaText}
111
+ onPress={onSecondaryCtaPress}
112
+ />
113
+ )}
114
+ </StyledErrorButtonContainer>
115
+ )}
116
+ </StyledErrorContainer>
117
+ );
118
+ };
119
+ /**
120
+ * Renders error page
121
+ *
122
+ * @param {ErrorProps}
123
+ * @return {*} {ReactElement}
124
+ */
125
+ const Error = ({
126
+ visible = true,
127
+ variant = 'in-page',
128
+ title,
129
+ description,
130
+ testID,
131
+ ctaText,
132
+ onCtaPress,
133
+ secondaryCtaText,
134
+ onSecondaryCtaPress,
135
+ ...nativeProps
136
+ }: ErrorProps): ReactElement => {
137
+ const [isVisible, setIsVisible] = useState(visible);
138
+ const [ctaPressed, setCtaPressed] = useState<onCloseCallbackType>(null);
139
+
140
+ const onCloseModal = useCallback(() => {
141
+ if (ctaPressed === 'cta' && onCtaPress) {
142
+ onCtaPress();
143
+ }
144
+ if (ctaPressed === 'secondaryCta' && onSecondaryCtaPress) {
145
+ onSecondaryCtaPress();
146
+ }
147
+ setCtaPressed(null);
148
+ }, [ctaPressed, onCtaPress, onSecondaryCtaPress]);
149
+
150
+ useEffect(() => {
151
+ setIsVisible(visible);
152
+ }, [visible]);
153
+
154
+ // These useEffect lines prevents race condition error when callback contains navigation logic
155
+ useEffect(() => {
156
+ if (ctaPressed) {
157
+ setIsVisible(false);
158
+ }
159
+ }, [ctaPressed]);
160
+
161
+ useEffect(() => {
162
+ if (!isVisible) {
163
+ onCloseModal();
164
+ }
165
+ }, [isVisible, onCloseModal]);
166
+
167
+ if (variant === 'full-screen') {
168
+ return (
169
+ <StyledErrorModal
170
+ visible={isVisible}
171
+ onRequestClose={() => setIsVisible(false)}
172
+ onDismiss={() => setIsVisible(false)}
173
+ animationType="slide"
174
+ >
175
+ <ErrorPage
176
+ variant={variant}
177
+ title={title}
178
+ description={description}
179
+ testID={testID}
180
+ ctaText={ctaText}
181
+ onCtaPress={
182
+ onCtaPress &&
183
+ (() => {
184
+ setCtaPressed('cta');
185
+ })
186
+ }
187
+ secondaryCtaText={secondaryCtaText}
188
+ onSecondaryCtaPress={
189
+ onSecondaryCtaPress &&
190
+ (() => {
191
+ setCtaPressed('secondaryCta');
192
+ })
193
+ }
194
+ {...nativeProps}
195
+ />
196
+ </StyledErrorModal>
197
+ );
198
+ }
199
+
200
+ return (
201
+ <ErrorPage
202
+ variant={variant}
203
+ title={title}
204
+ description={description}
205
+ testID={testID}
206
+ ctaText={ctaText}
207
+ onCtaPress={onCtaPress}
208
+ secondaryCtaText={secondaryCtaText}
209
+ onSecondaryCtaPress={onSecondaryCtaPress}
210
+ {...nativeProps}
211
+ />
212
+ );
213
+ };
214
+
215
+ export default Error;
package/src/index.ts CHANGED
@@ -32,6 +32,7 @@ import DatePicker from './components/DatePicker';
32
32
  import Divider from './components/Divider';
33
33
  import Drawer from './components/Drawer';
34
34
  import Empty from './components/Empty';
35
+ import Error from './components/Error';
35
36
  import FAB from './components/FAB';
36
37
  import Icon from './components/Icon';
37
38
  import Image from './components/Image';
@@ -90,6 +91,7 @@ export {
90
91
  Divider,
91
92
  Drawer,
92
93
  Empty,
94
+ Error,
93
95
  FAB,
94
96
  Icon,
95
97
  Image,
@@ -420,6 +420,36 @@ Object {
420
420
  "wrapperPadding": 16,
421
421
  },
422
422
  },
423
+ "error": Object {
424
+ "colors": Object {
425
+ "description": "#4d6265",
426
+ "fullScreenBackground": "#ccd2d3",
427
+ "inPageBackground": "#f6f6f7",
428
+ "title": "#001f23",
429
+ },
430
+ "fontSizes": Object {
431
+ "description": 18,
432
+ "title": 24,
433
+ },
434
+ "fonts": Object {
435
+ "description": "RebondGrotesque",
436
+ "title": "RebondGrotesque-SemiBold",
437
+ },
438
+ "sizes": Object {
439
+ "image": 176,
440
+ },
441
+ "space": Object {
442
+ "button": Object {
443
+ "margin": 16,
444
+ "padding": 16,
445
+ "wrapperHorizontalPadding": 16,
446
+ "wrapperVerticalPadding": 48,
447
+ },
448
+ "imageMarginBottom": 32,
449
+ "titleMarginBottom": 8,
450
+ "wrapperPadding": 24,
451
+ },
452
+ },
423
453
  "fab": Object {
424
454
  "colors": Object {
425
455
  "actionItemBackground": "#401960",