Skip to content

Commit f9ccdf3

Browse files
committed
feat(*): refactor animations and modal
1 parent f0cc45a commit f9ccdf3

15 files changed

Lines changed: 176 additions & 134 deletions

File tree

jest.config.snapshot.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ module.exports = {
1919
'tsx',
2020
...defaults.moduleFileExtensions,
2121
],
22-
transformIgnorePatterns: ['/node_modules/(?!@expo/vector-icons).+\\.js$'],
2322
testRegex: './tests/snapshot.test.js',
2423
setupFiles: ['jest-canvas-mock'],
2524
};

src/components/Dialog/Dialog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export interface DialogProps {
2020
useHistory?: boolean;
2121
/** To show dialog or not */
2222
isVisible?: boolean;
23+
/** WWhether body can scroll while dialog is opened */
24+
isBackgroundScrollable?: boolean;
2325
/** Called when clicking on overlay or pressing Esc, or using back button (requires useHistory to be true) */
2426
onRequestClose?: () => void;
2527
/** In ConfirmDialog, you can pass null to render nothing. If it is undefined, it will use default value */
@@ -37,6 +39,7 @@ export const Dialog = (props: DialogProps) => {
3739
children,
3840
footer,
3941
header,
42+
isBackgroundScrollable = false,
4043
isVisible,
4144
onRequestClose = () => null,
4245
getStyles,
@@ -55,6 +58,7 @@ export const Dialog = (props: DialogProps) => {
5558
visible={isVisible}
5659
transparent
5760
onRequestClose={onRequestClose}
61+
isBackgroundScrollable={isBackgroundScrollable}
5862
>
5963
<View style={modalContainerStyle}>
6064
<View style={containerStyle}>

src/components/Drawer/Drawer.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
2-
import { Animated, View } from 'react-native';
2+
import { View } from 'react-native';
3+
import { animated, useSpring } from 'react-spring/native.cjs';
34
import { DeepPartial } from 'ts-essentials';
45

56
import { useTheme } from '../../theme';
@@ -13,6 +14,7 @@ import {
1314
} from './Drawer.styles';
1415

1516
type Position = 'bottom' | 'top' | 'right' | 'left';
17+
const AnimatedView = animated(View);
1618

1719
export interface DrawerProps {
1820
children: React.ReactNode;
@@ -47,23 +49,21 @@ export const Drawer = (props: DrawerProps) => {
4749
getStyles,
4850
)(theme);
4951

50-
if (!isVisible) return null;
51-
52-
const value = new Animated.Value(-500);
53-
54-
Animated.spring(value, {
55-
bounciness: 0,
56-
speed: 70,
57-
toValue: offset,
58-
}).start();
52+
const animation = useSpring({
53+
[position]: offset,
54+
from: { [position]: -600 },
55+
reset: true,
56+
});
5957

6058
return (
61-
<Modal visible transparent onRequestClose={onClose}>
59+
<Modal visible={isVisible} transparent onRequestClose={onClose}>
6260
<View style={modalContainerStyle}>
63-
<Animated.View
61+
{/*
62+
// @ts-ignore */}
63+
<AnimatedView
6464
style={{
6565
...containerStyle,
66-
[position]: value,
66+
[position]: animation[position],
6767
...((position === 'left' || position === 'right') &&
6868
space && {
6969
height: '100%',
@@ -77,7 +77,7 @@ export const Drawer = (props: DrawerProps) => {
7777
}}
7878
>
7979
{children}
80-
</Animated.View>
80+
</AnimatedView>
8181
<Overlay onPress={onClose} />
8282
</View>
8383
</Modal>

src/components/Helpers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export * from './ViewMeasure';
22
export * from './Responsive';
33
export * from './useMeasure';
4+
export * from './useElement';
5+
export * from './useFreezeBody';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as React from 'react';
2+
3+
// ported from https://www.jayfreestone.com/writing/react-portals-with-hooks/
4+
5+
const createRootElement = (id: string) => {
6+
const rootContainer = document.createElement('div');
7+
rootContainer.setAttribute('id', id);
8+
return rootContainer;
9+
};
10+
11+
const addRootElement = (rootElem: Element) => {
12+
if (document.body.lastElementChild) {
13+
document.body.insertBefore(
14+
rootElem,
15+
document.body.lastElementChild.nextElementSibling,
16+
);
17+
}
18+
};
19+
20+
export const useElement = (id: string) => {
21+
const rootElemRef = React.useRef<Element>(null);
22+
23+
React.useEffect(() => {
24+
const existingParent = document.querySelector(`#${id}`);
25+
const parentElem = existingParent || createRootElement(id);
26+
27+
// If there is no existing DOM element, add a new one.
28+
if (!existingParent) {
29+
addRootElement(parentElem);
30+
}
31+
32+
if (rootElemRef.current) {
33+
parentElem.appendChild(rootElemRef.current);
34+
}
35+
36+
return () => {
37+
if (rootElemRef.current) rootElemRef.current.remove();
38+
if (parentElem.childNodes.length === -1) {
39+
parentElem.remove();
40+
}
41+
};
42+
}, []);
43+
44+
const getRootElem = () => {
45+
if (!rootElemRef.current) {
46+
// @ts-ignore
47+
rootElemRef.current = document.createElement('div');
48+
}
49+
return rootElemRef.current;
50+
};
51+
52+
return getRootElem();
53+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react';
2+
3+
export const useFreezeBody = ({ isFrozen }: { isFrozen: boolean }) => {
4+
React.useEffect(() => {
5+
const freeze = () => {
6+
document.body.style.overflow = 'hidden';
7+
document.body.style.height = '100vh';
8+
};
9+
10+
const unfreeze = () => {
11+
document.body.style.overflow = '';
12+
document.body.style.height = '';
13+
};
14+
15+
if (isFrozen) freeze();
16+
else unfreeze();
17+
18+
return () => unfreeze();
19+
}, [isFrozen]);
20+
};

src/components/Loading/LoadingDots.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { View } from 'react-native';
3-
import { animated, useTrail } from 'react-spring/native';
3+
import { animated, useTrail } from 'react-spring/native.cjs';
44

55
const AnimatedView = animated(View);
66

src/components/Modal/HistoryModal.web.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ let modalId = 0;
1212
* 3. Manually closed from within the modal (e.g. Close button)
1313
* Each of them should properly restore the page user was at
1414
*/
15-
class HistoryModalBase extends React.PureComponent<HistoryModalProps> {
15+
class HistoryModalBase extends React.Component<HistoryModalProps> {
1616
public modalId = ++modalId;
1717

1818
public componentDidUpdate = (previousProps: HistoryModalProps) => {

src/components/Modal/ModalBase.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Modal, ModalProps } from 'react-native';
44
export interface ModalBaseProps extends ModalProps {
55
/** (Web) Whether should scroll when user initiates non-touch scroll (mouse wheel, keyboard down/up) */
66
isBackgroundScrollable?: boolean;
7+
children?: React.ReactNode;
78
}
89

910
export const ModalBase = (props: ModalBaseProps) => <Modal {...props} />;

0 commit comments

Comments
 (0)