Skip to content

Instantly share code, notes, and snippets.

@eightyfive
Last active December 15, 2020 14:25
Show Gist options
  • Save eightyfive/f34d6ac11fff5169b2b4fa6b894730fd to your computer and use it in GitHub Desktop.
Save eightyfive/f34d6ac11fff5169b2b4fa6b894730fd to your computer and use it in GitHub Desktop.
A collection of React Native atoms (atomic design)
import React from 'react';
import { ActivityIndicator as RNActivityIndicator } from 'react-native';
export default function ActivityIndicator({
color = 'white',
large = false,
...rest
}) {
const size = large ? 'large' : 'small';
return <RNActivityIndicator {...{ color, size, ...rest }} />;
}
import React from 'react';
import { Platform, Pressable, StyleSheet } from 'react-native';
import { mr } from '../spacing';
import Theme from '../theme';
import ActivityIndicator from './activity-indicator';
import Icon from './icon';
import Text from './text';
const isAndroid = Platform.OS === 'android';
// Container styles
const $c = StyleSheet.create({
default: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: Theme.roundness,
backgroundColor: 'accent',
elevation: isAndroid ? 3 : 0,
},
pressed: {
backgroundColor: 'primary',
},
compact: {
paddingVertical: 8,
paddingHorizontal: 12,
},
link: {
backgroundColor: 'transparent',
},
disabled: {
opacity: 0.8,
// backgroundColor: 'disabled',
},
});
// Text styles
const $t = StyleSheet.create({
default: {
textAlign: 'center',
color: 'white',
fontSize: isAndroid ? 14 : 17,
fontWeight: isAndroid ? 'bold' : '600', // Semibold
},
compact: {
fontSize: 13,
fontWeight: '600', // Semibold
},
link: {
color: 'white',
},
disabled: {
color: 'disabled',
},
});
export default function Button({
color,
compact = false,
children: title,
disabled = false,
icon,
loading = false,
mode = 'contained',
onPress,
style,
}) {
const $container = [
$c.default,
compact && $c.compact,
disabled && $c.disabled,
mode === 'text' && $c.link,
color && { backgroundColor: color },
style,
];
const $text = [
$t.default,
compact && $t.compact,
mode === 'text' && $t.link,
disabled && $t.disabled,
];
let left = null;
if (loading) {
left = <ActivityIndicator style={mr[2]} />;
} else if (icon) {
left = <Icon style={mr[1]} name={icon} color="white" />;
}
return (
<Pressable
{...{
onPress,
disabled: disabled || loading,
style: ({ pressed }) => [$container, pressed && $c.pressed],
}}>
{left}
<Text style={$text}>
{isAndroid || compact ? title.toUpperCase() : title}
</Text>
</Pressable>
);
}
import React from 'react';
import Text from './text';
export default function Caption(props) {
return <Text {...props} type="caption" />;
}
import React from 'react';
import { SafeAreaView, View } from 'react-native';
import { p } from '../spacing';
export default function Content({ style, children }) {
return (
<SafeAreaView style={ss.f1}>
<View style={[p[3], style]}>{children}</View>
</SafeAreaView>
);
}
import React from 'react';
import { Image, StyleSheet } from 'react-native';
import Theme from '../theme';
import * as sources from '../images/icons';
const $ = StyleSheet.create({
container: {
width: 24,
height: 24,
},
medium: {
width: 36,
height: 36,
},
large: {
width: 48,
height: 48,
},
});
export default function Icon({ large, medium, name, color = 'accent', style }) {
const source = sources[name];
if (!source) {
throw new Error(`Icon "${name}" does not exist`);
}
const tintColor = Theme.colors[color] || color;
return (
<Image
{...{
source,
style: [
$.container,
medium && $.medium,
large && $.large,
{ tintColor },
style,
],
}}
/>
);
}
@@ -0 +0 @@
+// f34d6ac11fff5169b2b4fa6b894730fd
+export { default as ActivityIndicator } from './activity-indicator';
+export { default as Button } from './button';
+export { default as Content } from './content';
+export { default as Caption } from './caption';
+export { default as Icon } from './icon';
+export { default as Link } from './link';
+export { default as Text } from './text';
+export { default as TextInput } from './text-input';
+export { default as Title } from './title';
+
import React from 'react';
import {
TextInput as RNTextInput,
View,
Pressable,
StyleSheet,
} from 'react-native';
import Theme from '../theme';
const $ = StyleSheet.create({
textInput: {
padding: 3,
fontSize: 17,
borderRadius: Theme.roundness,
backgroundColor: 'white',
color: 'black',
},
});
const f1 = { flex: 1 };
export default function TextInput({
onPress,
onSubmit,
onSubmitEditing,
style,
...rest
}) {
const handleSubmit = (ev) => {
if (onSubmitEditing) {
onSubmitEditing(ev);
} else if (onSubmit) {
onSubmit(ev.nativeEvent.text);
}
};
const textInput = (
<RNTextInput
{...rest}
editable={!onPress}
placeholderTextColor={Theme.colors.disabled}
style={[$.textInput, style]}
onSubmitEditing={handleSubmit}
/>
);
if (onPress) {
return (
<Pressable {...{ onPress, style: f1 }}>
<View pointerEvents="none">{textInput}</View>
</Pressable>
);
}
return textInput;
}
import React from 'react';
import { Platform, Text as RNText } from 'react-native';
import { iOSUIKit, material } from 'react-native-typography';
import { trans, transChoice } from '../i18n';
const isAndroid = Platform.OS === 'android';
const types = isAndroid ? material : iOSUIKit;
const iOSTypes = {
title: 'title3',
subheading: 'subhead',
body1: 'body',
caption: 'footnote',
display1: 'largeTitle',
};
export default function Text({
children: content,
choice,
em = false,
style,
type = 'body1',
data,
s: sProp,
...rest
}) {
let name = isAndroid ? type : iOSTypes[type];
// <em> Android
if (em && isAndroid) {
name = name === 'body1' ? 'body2' : name;
}
// <em> iOS
if (em && !isAndroid) {
name += 'Emphasized';
}
if (colorName === 'white') {
name += 'White';
}
let translation;
if (typeof choice !== 'undefined') {
translation = transChoice(content, choice, data);
} else {
translation = trans(content, data);
}
const styles = [types[name], style];
return (
<RNText {...rest} style={styles}>
{translation}
</RNText>
);
}
import React from 'react';
import Text from './text';
export default function Title({ large = false, em, ...rest }) {
return <Text {...rest} em type={large ? 'display1' : 'title'} />;
}
{
"dir": "app/views/atoms",
"keywords": ["rnna", "react-native"]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment