Skip to content

Commit

Permalink
Merge pull request #1 from monkvision/feature-loader
Browse files Browse the repository at this point in the history
Add a beautiful Loader component
  • Loading branch information
natsukiai authored Aug 27, 2021
2 parents eb31535 + e31f02f commit bada7dd
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 20 deletions.
23 changes: 19 additions & 4 deletions App.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import React, { useState } from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { StyleSheet, Text, View, Pressable } from 'react-native';

import { Provider as PaperProvider } from 'react-native-paper';
import { Provider as StoreProvider } from 'react-redux';

import { store } from 'Controllers';

import Logo from 'Components/Logo';
import Loader from 'Components/Loader';

const styles = StyleSheet.create({
container: {
Expand All @@ -16,14 +16,29 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
loader: {
height: 100,
width: 100,
},
});

export default function App() {
const [isLoading, setLoading] = useState(false);

function handlePress() {
setLoading((prevState) => !prevState);
}

return (
<StoreProvider store={store}>
<PaperProvider theme={store.getState().theme}>
<View style={styles.container}>
<Logo height={100} width={100} />
<Pressable onPress={handlePress}>
<Loader
isLoading={isLoading}
style={styles.loader}
/>
</Pressable>
<Text style={{ marginTop: 16 }}>
Welcome to Monk Software Development Kit!
</Text>
Expand Down
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function babelConfig(api) {
},
plugins: [
['module-resolver', { root: ['./src'] }],
'react-native-reanimated/plugin',
],
};
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz",
"react-native-paper": "^4.9.2",
"react-native-reanimated": "~2.2.0",
"react-native-svg": "12.1.1",
"react-native-web": "~0.13.12",
"react-redux": "^7.2.4"
Expand Down
21 changes: 21 additions & 0 deletions src/Components/CustomPropTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import PropTypes from 'prop-types';

export function progress(props, propName, componentName) {
const value = props[propName];

const notANumber = typeof value !== 'number';
const notInTheRange = !notANumber && (value < 0 || value > 99);

if (notANumber || notInTheRange) {
return new Error(
`
Invalid prop \`${propName}\` supplied to\`${componentName}\`.
It must be a number between 0 and 99 included.
`,
);
}

return null;
}

export const nodeEnv = PropTypes.oneOf(['development', 'test', 'production']);
24 changes: 24 additions & 0 deletions src/Components/Loader/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import Logo from 'Components/Logo';

/**
* Display a loader built with the Monk Logo
* @param isLoading
* @param logoProps {object} passed through <Logo />
* @returns {JSX.Element}
* @constructor
*/
function Loader({ isLoading, ...logoProps }) {
return <Logo animated={isLoading} {...logoProps} />;
}

Loader.propTypes = {
isLoading: PropTypes.bool,
};

Loader.defaultProps = {
isLoading: false,
};

export default Loader;
126 changes: 113 additions & 13 deletions src/Components/Logo/index.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,120 @@
import React, { useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { Platform, StyleSheet } from 'react-native';
import { useTheme } from 'react-native-paper';
import Svg, { Circle, G } from 'react-native-svg';
import Svg, { Circle, G, Path } from 'react-native-svg';
import isEmpty from 'Functions/isEmpty';

import Animated, {
cancelAnimation,
Easing,
withRepeat,
withTiming,
useSharedValue,
useAnimatedProps,
} from 'react-native-reanimated';

const AnimatedPath = Animated.createAnimatedComponent(Path);

const NativeInnerCircle = ({ animated }) => {
const radius = useSharedValue(10);

const animatedProps = useAnimatedProps(() => {
// draw a circle
const path = `
M 50, 50
m -${radius.value}, 0
a ${radius.value},${radius.value} 0 1,0 ${radius.value * 2},0
a ${radius.value},${radius.value} 0 1,0 ${-radius.value * 2},0
`;
return {
d: path,
};
});

useEffect(() => {
if (animated) {
radius.value = withRepeat(withTiming(30, {
duration: 700,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}), -1, true);
} else {
cancelAnimation(radius);
radius.value = 10;
}
}, [animated, radius]);

return (
<AnimatedPath
animatedProps={animatedProps}
fill="black"
/>
);
};

NativeInnerCircle.propTypes = {
animated: PropTypes.bool,
};

NativeInnerCircle.defaultProps = {
animated: false,
};

const DefaultInnerCircle = ({ animated }) => (
<Circle
fill="#000"
cx="0"
cy="0"
r="10"
transform="translate(50 50)"
>
<animateTransform
attributeName="transform"
type="scale"
additive="sum"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.2 1; 0.4 0 0.2 1"
values={`1; ${animated ? 3 : 1}; 1`}
/>
</Circle>
);

DefaultInnerCircle.propTypes = {
animated: PropTypes.bool,
};

DefaultInnerCircle.defaultProps = {
animated: false,
};

const InnerCircle = Platform.select({
native: () => NativeInnerCircle,
default: () => DefaultInnerCircle,
})();

const styles = StyleSheet.create({
root: {
height: 75,
width: 75,
},
});

/**
* Display Monk's SVG logo
* @param animated {bool}
* @param color {string}
* @param height {number}
* @param theme
* @param width {number}
* @param passThroughProps {object}
* @returns {JSX.Element}
* @constructor
*/
function Logo({ color, height, width }) {
function Logo({
animated,
color,
...passThroughProps
}) {
const { colors } = useTheme();

const stroke = useMemo(
Expand All @@ -24,9 +125,10 @@ function Logo({ color, height, width }) {
return (
<Svg
viewBox="0 0 100 100"
style={{ height, width }}
style={styles}
{...passThroughProps}
>
<G id="logo">
<G>
<Circle
stroke={stroke}
fill="transparent"
Expand All @@ -35,22 +137,20 @@ function Logo({ color, height, width }) {
cy="50"
r="38"
/>
<Circle fill="#000" cx="50" cy="50" r="11" />
<InnerCircle animated={animated} />
</G>
</Svg>
);
}

Logo.propTypes = {
animated: PropTypes.bool,
color: PropTypes.string,
height: PropTypes.number,
width: PropTypes.number,
};

Logo.defaultProps = {
animated: false,
color: '',
height: 75,
width: 75,
};

export default Logo;
8 changes: 6 additions & 2 deletions src/Components/NodeEnv/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Badge } from 'react-native-paper';
import CustomPropTypes from 'Components/CustomPropTypes';

/**
* Display NODE_ENV value by default.
Expand All @@ -12,15 +13,18 @@ import { Badge } from 'react-native-paper';
*/
function NodeEnv({ title, value, ...passThroughProps }) {
return (
<Badge title={title} {...passThroughProps}>
<Badge
title={title}
{...passThroughProps}
>
{value}
</Badge>
);
}

NodeEnv.propTypes = {
title: PropTypes.string,
value: PropTypes.oneOf(['development', 'test', 'production']),
value: CustomPropTypes.nodeEnv,
};

NodeEnv.defaultProps = {
Expand Down
1 change: 1 addition & 0 deletions src/Components/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as Logo } from './Logo';
export { default as Loader } from './Loader';
export { default as NodeEnv } from './NodeEnv';
22 changes: 21 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"

"@babel/plugin-transform-object-assign@^7.0.0":
"@babel/plugin-transform-object-assign@^7.0.0", "@babel/plugin-transform-object-assign@^7.10.4":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.14.5.tgz#62537d54b6d85de04f4df48bfdba2eebff17b760"
integrity sha512-lvhjk4UN9xJJYB1mI5KC0/o1D5EcJXdbhVe+4fSk08D6ZN+iuAIs7LJC+71h8av9Ew4+uRq9452v9R93SFmQlQ==
Expand Down Expand Up @@ -8302,6 +8302,11 @@ mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==

mockdate@^3.0.2:
version "3.0.5"
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb"
integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==

module-alias@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
Expand Down Expand Up @@ -9799,6 +9804,16 @@ react-native-paper@^4.9.2:
color "^3.1.2"
react-native-iphone-x-helper "^1.3.1"

react-native-reanimated@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz#a6412c56b4e591d1f00fac949f62d0c72c357c78"
integrity sha512-lOJDd+5w1gY6DHGXG2jD1dsjzQmXQ2699HUc3IztvI2WP4zUT+UAA+zSG+5JiBS5DUnTL8YhhkmUQmr1KNGO5w==
dependencies:
"@babel/plugin-transform-object-assign" "^7.10.4"
fbjs "^3.0.0"
mockdate "^3.0.2"
string-hash-64 "^1.0.3"

react-native-safe-area-context@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.2.0.tgz#06113c6b208f982d68ab5c3cebd199ca93db6941"
Expand Down Expand Up @@ -10995,6 +11010,11 @@ stream-buffers@~2.2.0:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=

string-hash-64@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string-hash-64/-/string-hash-64-1.0.3.tgz#0deb56df58678640db5c479ccbbb597aaa0de322"
integrity sha512-D5OKWKvDhyVWWn2x5Y9b+37NUllks34q1dCDhk/vYcso9fmhs+Tl3KR/gE4v5UNj2UA35cnX4KdVVGkG1deKqw==

string-width@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
Expand Down

0 comments on commit bada7dd

Please sign in to comment.