@hero-design/rn 8.41.1 → 8.41.3-rc.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.
- package/.turbo/turbo-build.log +1 -1
- package/es/index.js +681 -577
- package/lib/index.js +685 -579
- package/package.json +8 -7
- package/rollup.config.js +1 -0
- package/src/components/Error/StyledError.tsx +1 -2
- package/src/components/Error/__tests__/__snapshots__/index.spec.tsx.snap +97 -115
- package/src/components/Error/__tests__/index.spec.tsx +6 -9
- package/src/components/Modal/ModalContentWrapper.tsx +112 -0
- package/src/components/Modal/ModalPresenter/ModalPresenter.tsx +135 -0
- package/src/components/Modal/ModalPresenter/index.tsx +9 -0
- package/src/components/Modal/ModalProvider.tsx +8 -0
- package/src/components/Modal/index.tsx +82 -178
- package/src/components/Success/StyledSuccess.tsx +1 -2
- package/src/components/Success/__tests__/__snapshots__/index.spec.tsx.snap +95 -115
- package/src/components/Success/__tests__/index.spec.tsx +6 -9
- package/src/index.ts +2 -0
- package/testUtils/setup.tsx +18 -0
- package/types/components/Error/StyledError.d.ts +5 -3
- package/types/components/Modal/ModalContentWrapper.d.ts +16 -0
- package/types/components/Modal/ModalPresenter/ModalPresenter.d.ts +34 -0
- package/types/components/Modal/ModalPresenter/index.d.ts +3 -0
- package/types/components/Modal/ModalProvider.d.ts +5 -0
- package/types/components/Modal/index.d.ts +8 -12
- package/types/components/Success/StyledSuccess.d.ts +5 -3
- package/types/index.d.ts +2 -1
- package/src/components/Modal/__tests__/__snapshots__/index.spec.tsx.snap +0 -117
- package/src/components/Modal/__tests__/index.spec.tsx +0 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/rn",
|
|
3
|
-
"version": "8.41.
|
|
3
|
+
"version": "8.41.3-rc.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@emotion/native": "^11.9.3",
|
|
23
23
|
"@emotion/react": "^11.9.3",
|
|
24
|
-
"@hero-design/colors": "8.41.
|
|
24
|
+
"@hero-design/colors": "8.41.3-rc.0",
|
|
25
25
|
"date-fns": "^2.16.1",
|
|
26
26
|
"events": "^3.2.0",
|
|
27
27
|
"hero-editor": "^1.9.21",
|
|
28
28
|
"nanoid": "^4.0.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@hero-design/react-native-month-year-picker": "^8.41.
|
|
31
|
+
"@hero-design/react-native-month-year-picker": "^8.41.3-rc.0",
|
|
32
32
|
"@react-native-community/datetimepicker": "^3.5.2",
|
|
33
33
|
"@react-native-community/slider": "4.1.12",
|
|
34
34
|
"react": "18.0.0",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"react-native-gesture-handler": "^1.10.3 | ~2.5.0",
|
|
37
37
|
"react-native-linear-gradient": "^2.6.2",
|
|
38
38
|
"react-native-pager-view": "^5.4.25",
|
|
39
|
+
"react-native-root-siblings": "^4.1.1",
|
|
39
40
|
"react-native-safe-area-context": "^3.0.2",
|
|
40
41
|
"react-native-vector-icons": "^9.1.0",
|
|
41
42
|
"react-native-webview": "^11.2.5"
|
|
@@ -47,8 +48,8 @@
|
|
|
47
48
|
"@babel/preset-typescript": "^7.17.12",
|
|
48
49
|
"@babel/runtime": "^7.18.9",
|
|
49
50
|
"@emotion/jest": "^11.11.0",
|
|
50
|
-
"@hero-design/eslint-plugin": "8.41.
|
|
51
|
-
"@hero-design/react-native-month-year-picker": "^8.41.
|
|
51
|
+
"@hero-design/eslint-plugin": "8.41.3-rc.0",
|
|
52
|
+
"@hero-design/react-native-month-year-picker": "^8.41.3-rc.0",
|
|
52
53
|
"@react-native-community/datetimepicker": "^3.5.2",
|
|
53
54
|
"@react-native-community/slider": "4.1.12",
|
|
54
55
|
"@rollup/plugin-babel": "^5.3.1",
|
|
@@ -64,12 +65,12 @@
|
|
|
64
65
|
"@types/react-native": "^0.67.7",
|
|
65
66
|
"@types/react-native-vector-icons": "^6.4.10",
|
|
66
67
|
"babel-plugin-inline-import": "^3.0.0",
|
|
67
|
-
"eslint-config-hd": "8.41.
|
|
68
|
+
"eslint-config-hd": "8.41.3-rc.0",
|
|
68
69
|
"eslint-plugin-import": "^2.27.5",
|
|
69
70
|
"jest": "^29.6.2",
|
|
70
71
|
"jest-environment-jsdom": "^29.6.2",
|
|
71
72
|
"jest-junit": "^16.0.0",
|
|
72
|
-
"prettier-config-hd": "8.41.
|
|
73
|
+
"prettier-config-hd": "8.41.3-rc.0",
|
|
73
74
|
"react": "18.0.0",
|
|
74
75
|
"react-native": "0.69.7",
|
|
75
76
|
"react-native-gesture-handler": "~2.5.0",
|
package/rollup.config.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import styled from '@emotion/native';
|
|
2
|
-
import { View } from 'react-native';
|
|
2
|
+
import { Modal, View } from 'react-native';
|
|
3
3
|
import Image from '../Image';
|
|
4
4
|
import Typography from '../Typography';
|
|
5
5
|
import Button from '../Button';
|
|
6
|
-
import Modal from '../Modal';
|
|
7
6
|
|
|
8
7
|
type ErrorVariant = 'full-screen' | 'in-page';
|
|
9
8
|
|
|
@@ -245,164 +245,146 @@ exports[`Error renders error screen with image correctly 1`] = `
|
|
|
245
245
|
`;
|
|
246
246
|
|
|
247
247
|
exports[`Error renders full screen error page correctly 1`] = `
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
<Modal
|
|
249
|
+
animationType="slide"
|
|
250
|
+
hardwareAccelerated={false}
|
|
251
|
+
onDismiss={[Function]}
|
|
252
|
+
onRequestClose={[Function]}
|
|
253
|
+
style={
|
|
254
|
+
[
|
|
252
255
|
{
|
|
253
|
-
"
|
|
254
|
-
"
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
/>,
|
|
256
|
+
"height": "100%",
|
|
257
|
+
"width": "100%",
|
|
258
|
+
},
|
|
259
|
+
undefined,
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
visible={true}
|
|
263
|
+
>
|
|
263
264
|
<View
|
|
264
|
-
collapsable={false}
|
|
265
265
|
style={
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
"translateY": 1334,
|
|
276
|
-
},
|
|
277
|
-
],
|
|
278
|
-
}
|
|
266
|
+
[
|
|
267
|
+
{
|
|
268
|
+
"backgroundColor": "#ccd2d3",
|
|
269
|
+
"display": "flex",
|
|
270
|
+
"flex": 1,
|
|
271
|
+
"flexDirection": "column",
|
|
272
|
+
},
|
|
273
|
+
undefined,
|
|
274
|
+
]
|
|
279
275
|
}
|
|
276
|
+
themeVariant="full-screen"
|
|
280
277
|
>
|
|
281
278
|
<View
|
|
282
279
|
style={
|
|
283
280
|
[
|
|
284
281
|
{
|
|
285
|
-
"
|
|
282
|
+
"alignItems": "center",
|
|
286
283
|
"display": "flex",
|
|
287
284
|
"flex": 1,
|
|
288
285
|
"flexDirection": "column",
|
|
286
|
+
"justifyContent": "center",
|
|
287
|
+
"padding": 24,
|
|
289
288
|
},
|
|
290
289
|
undefined,
|
|
291
290
|
]
|
|
292
291
|
}
|
|
293
|
-
themeVariant="full-screen"
|
|
294
292
|
>
|
|
295
293
|
<View
|
|
296
294
|
style={
|
|
297
295
|
[
|
|
298
296
|
{
|
|
299
|
-
"
|
|
300
|
-
"
|
|
301
|
-
"
|
|
302
|
-
"flexDirection": "column",
|
|
303
|
-
"justifyContent": "center",
|
|
304
|
-
"padding": 24,
|
|
297
|
+
"height": 176,
|
|
298
|
+
"marginBottom": 24,
|
|
299
|
+
"width": 176,
|
|
305
300
|
},
|
|
306
301
|
undefined,
|
|
307
302
|
]
|
|
308
303
|
}
|
|
309
304
|
>
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
"height": 176,
|
|
315
|
-
"marginBottom": 24,
|
|
316
|
-
"width": 176,
|
|
317
|
-
},
|
|
318
|
-
undefined,
|
|
319
|
-
]
|
|
320
|
-
}
|
|
321
|
-
>
|
|
322
|
-
<Image
|
|
323
|
-
source={
|
|
324
|
-
{
|
|
325
|
-
"uri": "path_to_image",
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
style={
|
|
329
|
-
[
|
|
330
|
-
{
|
|
331
|
-
"borderRadius": 0,
|
|
332
|
-
"height": 72,
|
|
333
|
-
"width": 72,
|
|
334
|
-
},
|
|
335
|
-
[
|
|
336
|
-
{
|
|
337
|
-
"height": 176,
|
|
338
|
-
"marginBottom": 24,
|
|
339
|
-
"resizeMode": "contain",
|
|
340
|
-
"width": 176,
|
|
341
|
-
},
|
|
342
|
-
undefined,
|
|
343
|
-
],
|
|
344
|
-
]
|
|
305
|
+
<Image
|
|
306
|
+
source={
|
|
307
|
+
{
|
|
308
|
+
"uri": "path_to_image",
|
|
345
309
|
}
|
|
346
|
-
|
|
347
|
-
/>
|
|
348
|
-
</View>
|
|
349
|
-
<Text
|
|
350
|
-
allowFontScaling={false}
|
|
310
|
+
}
|
|
351
311
|
style={
|
|
352
312
|
[
|
|
353
313
|
{
|
|
354
|
-
"
|
|
355
|
-
"
|
|
356
|
-
"
|
|
357
|
-
"letterSpacing": 0.24,
|
|
358
|
-
"lineHeight": 32,
|
|
314
|
+
"borderRadius": 0,
|
|
315
|
+
"height": 72,
|
|
316
|
+
"width": 72,
|
|
359
317
|
},
|
|
360
318
|
[
|
|
361
319
|
{
|
|
362
|
-
"
|
|
363
|
-
"marginBottom":
|
|
364
|
-
"
|
|
320
|
+
"height": 176,
|
|
321
|
+
"marginBottom": 24,
|
|
322
|
+
"resizeMode": "contain",
|
|
323
|
+
"width": 176,
|
|
365
324
|
},
|
|
366
325
|
undefined,
|
|
367
326
|
],
|
|
368
327
|
]
|
|
369
328
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
329
|
+
testID="error-image"
|
|
330
|
+
/>
|
|
331
|
+
</View>
|
|
332
|
+
<Text
|
|
333
|
+
allowFontScaling={false}
|
|
334
|
+
style={
|
|
335
|
+
[
|
|
336
|
+
{
|
|
337
|
+
"color": "#001f23",
|
|
338
|
+
"fontFamily": "RebondGrotesque-SemiBold",
|
|
339
|
+
"fontSize": 24,
|
|
340
|
+
"letterSpacing": 0.24,
|
|
341
|
+
"lineHeight": 32,
|
|
342
|
+
},
|
|
379
343
|
[
|
|
380
344
|
{
|
|
381
345
|
"color": "#001f23",
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"letterSpacing": 0.54,
|
|
385
|
-
"lineHeight": 26,
|
|
346
|
+
"marginBottom": 8,
|
|
347
|
+
"textAlign": "center",
|
|
386
348
|
},
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
349
|
+
undefined,
|
|
350
|
+
],
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
themeIntent="body"
|
|
354
|
+
themeLevel="h4"
|
|
355
|
+
themeTypeface="playful"
|
|
356
|
+
>
|
|
357
|
+
We’re sorry, something went wrong
|
|
358
|
+
</Text>
|
|
359
|
+
<Text
|
|
360
|
+
allowFontScaling={false}
|
|
361
|
+
style={
|
|
362
|
+
[
|
|
363
|
+
{
|
|
364
|
+
"color": "#001f23",
|
|
365
|
+
"fontFamily": "BeVietnamPro-Regular",
|
|
366
|
+
"fontSize": 18,
|
|
367
|
+
"letterSpacing": 0.54,
|
|
368
|
+
"lineHeight": 26,
|
|
369
|
+
},
|
|
370
|
+
[
|
|
371
|
+
{
|
|
372
|
+
"color": "#4d6265",
|
|
373
|
+
"textAlign": "center",
|
|
374
|
+
},
|
|
375
|
+
undefined,
|
|
376
|
+
],
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
themeIntent="body"
|
|
380
|
+
themeTypeface="playful"
|
|
381
|
+
themeVariant="regular"
|
|
382
|
+
>
|
|
383
|
+
Please try again later
|
|
384
|
+
</Text>
|
|
403
385
|
</View>
|
|
404
|
-
</View
|
|
405
|
-
|
|
386
|
+
</View>
|
|
387
|
+
</Modal>
|
|
406
388
|
`;
|
|
407
389
|
|
|
408
390
|
exports[`Error renders title only correctly 1`] = `
|
|
@@ -3,7 +3,6 @@ import { fireEvent } from '@testing-library/react-native';
|
|
|
3
3
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
4
4
|
import Error from '..';
|
|
5
5
|
import Image from '../../Image';
|
|
6
|
-
import Portal from '../../Portal';
|
|
7
6
|
|
|
8
7
|
const title = `We’re sorry, something went wrong`;
|
|
9
8
|
const description = 'Please try again later';
|
|
@@ -47,14 +46,12 @@ describe('Error', () => {
|
|
|
47
46
|
});
|
|
48
47
|
it('renders full screen error page correctly', () => {
|
|
49
48
|
const { toJSON, getByText, getByTestId } = renderWithTheme(
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
/>
|
|
57
|
-
</Portal.Provider>
|
|
49
|
+
<Error
|
|
50
|
+
variant="full-screen"
|
|
51
|
+
title={title}
|
|
52
|
+
description={description}
|
|
53
|
+
image="path_to_image"
|
|
54
|
+
/>
|
|
58
55
|
);
|
|
59
56
|
|
|
60
57
|
expect(getByText(title)).toBeTruthy();
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Animated,
|
|
4
|
+
Dimensions,
|
|
5
|
+
Easing,
|
|
6
|
+
Platform,
|
|
7
|
+
StyleProp,
|
|
8
|
+
ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
|
|
11
|
+
type ModalContentWrapperProps = {
|
|
12
|
+
children: React.ReactElement;
|
|
13
|
+
visible?: boolean;
|
|
14
|
+
onShow?: () => void;
|
|
15
|
+
testID?: string;
|
|
16
|
+
animationType?: 'none' | 'slide' | 'fade';
|
|
17
|
+
style?: StyleProp<ViewStyle>;
|
|
18
|
+
animated?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ModalContentWrapperHandler = {
|
|
22
|
+
hide: (callback?: () => void) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const windowHeight = Dimensions.get('window').height;
|
|
26
|
+
const defaultAnimationConfig = {
|
|
27
|
+
easing: Easing.inOut(Easing.cubic),
|
|
28
|
+
duration: 400,
|
|
29
|
+
useNativeDriver: Platform.OS !== 'web',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const ModalContentWrapper = forwardRef<
|
|
33
|
+
ModalContentWrapperHandler,
|
|
34
|
+
ModalContentWrapperProps
|
|
35
|
+
>(
|
|
36
|
+
(
|
|
37
|
+
{
|
|
38
|
+
animationType,
|
|
39
|
+
children,
|
|
40
|
+
testID,
|
|
41
|
+
onShow,
|
|
42
|
+
style,
|
|
43
|
+
visible,
|
|
44
|
+
animated = true,
|
|
45
|
+
},
|
|
46
|
+
ref
|
|
47
|
+
) => {
|
|
48
|
+
const animatedValue = React.useRef(new Animated.Value(0)).current;
|
|
49
|
+
|
|
50
|
+
const modalAnimation = animatedValue.interpolate(
|
|
51
|
+
animationType === 'fade'
|
|
52
|
+
? {
|
|
53
|
+
inputRange: [0, 1],
|
|
54
|
+
outputRange: [0, 1],
|
|
55
|
+
}
|
|
56
|
+
: {
|
|
57
|
+
inputRange: [0, 1],
|
|
58
|
+
outputRange: [windowHeight, 0],
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
React.useImperativeHandle(
|
|
63
|
+
ref,
|
|
64
|
+
() => ({
|
|
65
|
+
hide: (callback) => {
|
|
66
|
+
Animated.timing(animatedValue, {
|
|
67
|
+
toValue: 0,
|
|
68
|
+
...defaultAnimationConfig,
|
|
69
|
+
}).start(callback);
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
[animatedValue]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
React.useEffect(() => {
|
|
76
|
+
// Hiding animation will be called from the modal component
|
|
77
|
+
if (visible) {
|
|
78
|
+
Animated.timing(animatedValue, {
|
|
79
|
+
toValue: 1,
|
|
80
|
+
...defaultAnimationConfig,
|
|
81
|
+
// Prevent animation when updating the modal content
|
|
82
|
+
duration: animated ? defaultAnimationConfig.duration : 0,
|
|
83
|
+
}).start(() => {
|
|
84
|
+
onShow?.();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}, [visible, animatedValue, onShow, animated]);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Animated.View
|
|
91
|
+
testID={testID}
|
|
92
|
+
style={[
|
|
93
|
+
style,
|
|
94
|
+
{
|
|
95
|
+
...(animationType === 'fade' ? { opacity: modalAnimation } : {}),
|
|
96
|
+
...(animationType === 'slide'
|
|
97
|
+
? {
|
|
98
|
+
transform: [{ translateY: modalAnimation }],
|
|
99
|
+
}
|
|
100
|
+
: {}),
|
|
101
|
+
},
|
|
102
|
+
]}
|
|
103
|
+
>
|
|
104
|
+
{children}
|
|
105
|
+
</Animated.View>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
ModalContentWrapper.displayName = 'ModalContentWrapper';
|
|
111
|
+
|
|
112
|
+
export default ModalContentWrapper;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React, { forwardRef, useRef } from 'react';
|
|
2
|
+
import { Animated, StyleSheet, ViewProps } from 'react-native';
|
|
3
|
+
import RootSiblings from 'react-native-root-siblings';
|
|
4
|
+
import { useTheme } from '../../../theme';
|
|
5
|
+
import Box from '../../Box';
|
|
6
|
+
|
|
7
|
+
export type ModalPresenterHandles = {
|
|
8
|
+
animatedOut: (completion?: () => void) => void;
|
|
9
|
+
};
|
|
10
|
+
export type ModalDismissFunc = (onDismiss?: () => void) => void;
|
|
11
|
+
export type ModalUpdateFunc = (content: React.ReactNode) => void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Modal handler is returned by `showModal` function.
|
|
15
|
+
*/
|
|
16
|
+
export type ModalHandler = {
|
|
17
|
+
/**
|
|
18
|
+
* Same `dismiss` function as in `ModalContentProps`.
|
|
19
|
+
*/
|
|
20
|
+
dismiss: ModalDismissFunc;
|
|
21
|
+
/**
|
|
22
|
+
* Same `update` function as in `ModalContentProps`.
|
|
23
|
+
*/
|
|
24
|
+
update: ModalUpdateFunc;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const ModalPresenter = forwardRef<ModalPresenterHandles, ViewProps>(
|
|
28
|
+
({ style, children, ...props }, ref) => {
|
|
29
|
+
const animatedOpacity = useRef(new Animated.Value(0));
|
|
30
|
+
const theme = useTheme();
|
|
31
|
+
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
Animated.spring(animatedOpacity.current, {
|
|
34
|
+
toValue: 1,
|
|
35
|
+
useNativeDriver: true,
|
|
36
|
+
}).start();
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
React.useImperativeHandle(ref, () => ({
|
|
40
|
+
animatedOut: (completion?: () => void) => {
|
|
41
|
+
Animated.spring(animatedOpacity.current, {
|
|
42
|
+
toValue: 0,
|
|
43
|
+
useNativeDriver: true,
|
|
44
|
+
}).start(() => {
|
|
45
|
+
completion?.();
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Box style={StyleSheet.absoluteFill}>
|
|
52
|
+
<Animated.View
|
|
53
|
+
style={[
|
|
54
|
+
{
|
|
55
|
+
width: '100%',
|
|
56
|
+
height: '100%',
|
|
57
|
+
backgroundColor: `${theme.colors.overlayGlobalSurface}66`, // 66 = 40% opacity as suggested by the mobile color guidelines
|
|
58
|
+
justifyContent: 'center',
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
opacity: animatedOpacity.current,
|
|
61
|
+
},
|
|
62
|
+
style,
|
|
63
|
+
]}
|
|
64
|
+
{...props}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</Animated.View>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Present a modal on screen immediately.
|
|
75
|
+
*
|
|
76
|
+
* The new presented modal will be on top of existing modals if there are any.
|
|
77
|
+
*
|
|
78
|
+
* @param Content A component to be presented as a modal on screen.
|
|
79
|
+
* This component will be centered horizontally and vertically on screen with
|
|
80
|
+
* a semitransparent black overlay underneath.
|
|
81
|
+
* @param contentProps Props for this modal component.
|
|
82
|
+
* @returns A `ModalHandler` you can use to dismiss the modal.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
export const showModal = (content: React.ReactNode): ModalHandler => {
|
|
86
|
+
let ref: ModalPresenterHandles | null = null;
|
|
87
|
+
let rootSiblings: RootSiblings | null = null;
|
|
88
|
+
|
|
89
|
+
const dismiss: ModalDismissFunc = (onDismiss) => {
|
|
90
|
+
if (rootSiblings) {
|
|
91
|
+
const cleanup = () => {
|
|
92
|
+
rootSiblings?.destroy();
|
|
93
|
+
rootSiblings = null;
|
|
94
|
+
ref = null;
|
|
95
|
+
onDismiss?.();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (ref) {
|
|
99
|
+
ref.animatedOut(cleanup);
|
|
100
|
+
} else {
|
|
101
|
+
cleanup();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const update: ModalUpdateFunc = (newContent) => {
|
|
107
|
+
rootSiblings?.update(
|
|
108
|
+
<ModalPresenter
|
|
109
|
+
ref={(_ref) => {
|
|
110
|
+
ref = _ref;
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
{newContent}
|
|
114
|
+
</ModalPresenter>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
rootSiblings = new RootSiblings(
|
|
119
|
+
(
|
|
120
|
+
<ModalPresenter
|
|
121
|
+
ref={(_ref) => {
|
|
122
|
+
ref = _ref;
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
{content}
|
|
126
|
+
</ModalPresenter>
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return { dismiss, update };
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
ModalPresenter.displayName = 'ModalPresenter';
|
|
134
|
+
|
|
135
|
+
export default ModalPresenter;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { RootSiblingParent } from 'react-native-root-siblings';
|
|
3
|
+
|
|
4
|
+
const ModalProvider = ({ children }: { children: ReactNode }) => {
|
|
5
|
+
return <RootSiblingParent>{children}</RootSiblingParent>;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default ModalProvider;
|