Skip to content

Instantly share code, notes, and snippets.

@GGrassiant
Created September 5, 2020 23:07
Show Gist options
  • Select an option

  • Save GGrassiant/22b727e57d695bf73229237bb5d54682 to your computer and use it in GitHub Desktop.

Select an option

Save GGrassiant/22b727e57d695bf73229237bb5d54682 to your computer and use it in GitHub Desktop.
React Native Helpers
// Libs
import { Dimensions, PixelRatio } from 'react-native';
const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height;
const pixelRatio = PixelRatio.get();
const fontScale = PixelRatio.getFontScale();
// utils from https://github.com/marudy/react-native-responsive-screen
// Emulate vw
export const widthPercentageToDP = (widthPercent: number) => {
return PixelRatio.roundToNearestPixel((screenWidth * widthPercent) / 100);
};
// Emulate vh
export const heightPercentageToDP = (heightPercent: number) => {
return PixelRatio.roundToNearestPixel((screenHeight * heightPercent) / 100);
};
// Normalize size in pixel to dp based on device pixel ratio
// Tweaked from from react-native-elements
// https://github.com/react-native-elements/react-native-elements/blob/next/src/helpers/normalizeText.js
export const normalizeSize = (size: number) => {
if (pixelRatio >= 2 && pixelRatio < 3) {
// iphone 5s and older Androids
if (screenWidth < 360) {
return PixelRatio.roundToNearestPixel(size * 0.95 * fontScale);
}
// iphone 5
if (screenHeight < 667) {
return PixelRatio.roundToNearestPixel(size * fontScale);
// iphone 6-6s
}
if (screenHeight >= 667 && screenHeight <= 735) {
return PixelRatio.roundToNearestPixel(size * 1.15 * fontScale);
}
// older phablets
return PixelRatio.roundToNearestPixel(size * 1.25 * fontScale);
}
if (pixelRatio >= 3 && pixelRatio < 3.5) {
// catch Android font scaling on small machines
// where pixel ratio / font scale ratio => 3:3
if (screenWidth <= 360) {
return PixelRatio.roundToNearestPixel(size * fontScale);
}
// Catch other weird android width sizings
if (screenHeight < 667) {
return PixelRatio.roundToNearestPixel(size * 1.15 * fontScale);
// catch in-between size Androids and scale font up
// a tad but not too much
}
if (screenHeight >= 667 && screenHeight <= 735) {
return PixelRatio.roundToNearestPixel(size * 1.2 * fontScale);
}
// catch larger devices
// ie iphone 6s plus / 7 plus / mi note 等等
return PixelRatio.roundToNearestPixel(size * 1.27 * fontScale);
}
if (pixelRatio >= 3.5) {
// catch Android font scaling on small machines
// where pixel ratio / font scale ratio => 3:3
if (screenWidth <= 360) {
return PixelRatio.roundToNearestPixel(size * fontScale);
// Catch other smaller android height sizings
}
if (screenHeight < 667) {
return PixelRatio.roundToNearestPixel(size * 1.2 * fontScale);
// catch in-between size Androids and scale font up
// a tad but not too much
}
if (screenHeight >= 667 && screenHeight <= 735) {
return PixelRatio.roundToNearestPixel(size * 1.25 * fontScale);
}
// catch larger phablet devices
return PixelRatio.roundToNearestPixel(size * 1.4 * fontScale);
}
return size * fontScale;
};
export const defaultTimeOut: number = 3000;
export const layoutGridPadding: number = widthPercentageToDP(10);
export const defaultAvatarUri: string = 'https://placedog.net/180/180?random';
export const defaultViewWrapper: { [key: string]: number } = {
flexGrow: 1,
// react-navigation SafeAreaView padding top for portrait is 44
// and padding bottom is 34
flexBasis: heightPercentageToDP(100) - normalizeSize(44) - normalizeSize(34),
};
export const defaultContainer: { [key: string]: number } = {
...defaultViewWrapper,
width: Dimensions.get('window').width,
paddingHorizontal: layoutGridPadding,
};
export const defaultButton: {
[key: string]: number | string | { [key: string]: number };
} = {
alignSelf: 'stretch',
justifyContent: 'center',
alignItems: 'center',
height: normalizeSize(48),
borderRadius: normalizeSize(16),
};
export const defaultBoxShadow: {
[key: string]: number | string | { [key: string]: number };
} = {
shadowColor: colors.shadow,
shadowOffset: { width: 0, height: normalizeSize(2) },
shadowRadius: normalizeSize(4),
shadowOpacity: 0.9,
elevation: 3,
};
export const defaultInstructions: {
[key: string]: { [key: string]: number | string | { [key: string]: number } };
} = {
instructionsWrapper: {
flex: 1,
justifyContent: 'center',
},
instructionItemTitle: {
fontFamily: defaultFontFamily,
fontSize: caption3,
lineHeight: normalizeSize(14),
color: colors.grey4,
marginBottom: normalizeSize(2),
},
instructionItemWrapper: {
flexDirection: 'row',
},
instructionItem: {
flex: 1,
paddingLeft: normalizeSize(5),
fontFamily: defaultFontFamily,
fontSize: caption3,
lineHeight: normalizeSize(14),
color: colors.grey3,
},
};
export const renderNode = (
ComponentElement: typeof Text | typeof IconButton,
content: any,
defaultProps?: any,
): React.ReactNode | null => {
if (content == null || content === false) {
return null;
}
if (React.isValidElement(content)) {
return content;
}
if (typeof content === 'function') {
return content();
}
// Just in case
if (content === true) {
return <ComponentElement {...defaultProps} />;
}
if (typeof content === 'string' || typeof content === 'number') {
return <ComponentElement {...defaultProps}>{content}</ComponentElement>;
}
return <ComponentElement {...defaultProps} {...content} />;
};
export const renderText = (
content: string,
style: ViewStyle | TextStyle | ImageStyle,
): React.ReactNode | null =>
renderNode(Text, content, {
style: StyleSheet.flatten(style),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment