Skip to content

Instantly share code, notes, and snippets.

@burdiuz
Last active December 29, 2019 19:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burdiuz/c6d425f16b5069c86a5d92fab88cd248 to your computer and use it in GitHub Desktop.
Save burdiuz/c6d425f16b5069c86a5d92fab88cd248 to your computer and use it in GitHub Desktop.
@actualwave/react-native-props-layout -- Provide style to component with it's props

@actualwave/react-native-props-layout

Provide style to component with it's props

export * from './Layout';
export * from './withLayoutProps';
export { addStyleProp, addStyle, buildStyleFromProps } from './utils';
import { View } from 'react-native';
import withLayoutProps from './withLayoutProps';
export const Layout = withLayoutProps(View, true, true, 'Layout');
{
"name": "@actualwave/react-native-props-layout",
"description": "Provide style to component with it's props",
"version": "0.0.1",
"main": "index.js",
"keywords": [
"js",
"javascript",
"react",
"react-native",
"layout",
"style"
],
"homepage": "https://github.com/burdiuz/c6d425f16b5069c86a5d92fab88cd248",
"bugs": {
"url": "https://github.com/burdiuz/c6d425f16b5069c86a5d92fab88cd248",
"email": "burdiuz@gmail.com"
},
"author": {
"name": "Oleg Galaburda",
"email": "burdiuz@gmail.com",
"url": "http://actualwave.com/"
},
"dependencies": {
"@actualwave/react-component-name": "^0.0.1"
},
"peerDependencies": {
"prop-types": "*",
"react": "*",
"react-native": "*"
},
"license": "MIT"
}
export const STYLE_PROPS = {
flex1: { flex: 1 },
widthFull: { width: '100%' },
heightFull: { height: '100%' },
shrink0: { flexShrink: 0 },
wrap: { flexWrap: 'wrap' },
row: { flexDirection: 'row' },
rowReverse: { flexDirection: 'row-reverse' },
columnReverse: { flexDirection: 'column-reverse' },
justifyStart: { justifyContent: 'flex-start' },
justifyEnd: { justifyContent: 'flex-end' },
justifySpaceBetween: { justifyContent: 'flex-start' },
justifySpaceAround: { justifyContent: 'flex-end' },
alignStart: { alignItems: 'flex-start' },
alignEnd: { alignItems: 'flex-end' },
alignCenter: { alignItems: 'center' },
alignStretch: { alignItems: 'stretch' },
alignSelfStart: { alignSelf: 'flex-start' },
alignSelfEnd: { alignSelf: 'flex-end' },
alignSelfCenter: { alignSelf: 'center' },
alignSelfStretch: { alignSelf: 'stretch' },
marginAuto: { margin: 'auto' },
marginLeftAuto: { marginLeft: 'auto' },
marginBottomAuto: { marginBottom: 'auto' },
marginEndAuto: { marginEnd: 'auto' },
marginHorizontalAuto: { marginHorizontal: 'auto' },
marginRightAuto: { marginRight: 'auto' },
marginStartAuto: { marginStart: 'auto' },
marginTopAuto: { marginTop: 'auto' },
marginVerticalAuto: { marginVertical: 'auto' },
margin5: { margin: 5 },
marginBottom5: { marginBottom: 5 },
marginEnd5: { marginEnd: 5 },
marginHorizontal5: { marginHorizontal: 5 },
marginLeft5: { marginLeft: 5 },
marginRight5: { marginRight: 5 },
marginStart5: { marginStart: 5 },
marginTop5: { marginTop: 5 },
marginVertical5: { marginVertical: 5 },
margin10: { margin: 10 },
marginBottom10: { marginBottom: 10 },
marginEnd10: { marginEnd: 10 },
marginHorizontal10: { marginHorizontal: 10 },
marginLeft10: { marginLeft: 10 },
marginRight10: { marginRight: 10 },
marginStart10: { marginStart: 10 },
marginTop10: { marginTop: 10 },
marginVertical10: { marginVertical: 10 },
padding5: { padding: 5 },
paddingBottom5: { paddingBottom: 5 },
paddingEnd5: { paddingEnd: 5 },
paddingHorizontal5: { paddingHorizontal: 5 },
paddingLeft5: { paddingLeft: 5 },
paddingRight5: { paddingRight: 5 },
paddingStart5: { paddingStart: 5 },
paddingTop5: { paddingTop: 5 },
paddingVertical5: { paddingVertical: 5 },
padding10: { padding: 10 },
paddingBottom10: { paddingBottom: 10 },
paddingEnd10: { paddingEnd: 10 },
paddingHorizontal10: { paddingHorizontal: 10 },
paddingLeft10: { paddingLeft: 10 },
paddingRight10: { paddingRight: 10 },
paddingStart10: { paddingStart: 10 },
paddingTop10: { paddingTop: 10 },
paddingVertical10: { paddingVertical: 10 },
};
// eslint-disable-next-line no-param-reassign
export const STYLE_PROPS_UNSET = Object.keys(STYLE_PROPS).reduce((result, name) => {
result[name] = undefined;
return result;
}, {});
export const addStyleProp = (propName, styleName, styleValue) => {
STYLE_PROPS[propName] = { [styleName]: styleValue };
STYLE_PROPS_UNSET[propName] = undefined;
};
export const addStyle = (propName, style) => {
STYLE_PROPS[propName] = style;
STYLE_PROPS_UNSET[propName] = undefined;
};
export const buildStyleFromProps = (props) => {
const style = {};
Object.keys(props).forEach((name) => {
const styleProps = STYLE_PROPS[name];
if (styleProps) {
Object.assign(style, styleProps);
}
});
return style;
};
import React, { useEffect, useState, useMemo } from 'react';
import { StyleSheet } from 'react-native';
import getComponentName from '@actualwave/react-component-name';
import { buildStyleFromProps } from './utils';
const createComponentStyleFactory = (hasOwnStyle, staticStyles) => (props) => {
const { style } = props;
let layoutStyle = buildStyleFromProps(props);
if (staticStyles) {
if (hasOwnStyle && style) {
layoutStyle = StyleSheet.create({ self: StyleSheet.flatten([layoutStyle, style]) }).self;
} else {
layoutStyle = StyleSheet.create({ self: layoutStyle }).self;
}
} else if (hasOwnStyle && style) {
layoutStyle = [layoutStyle, style];
}
return layoutStyle;
};
export const withLayoutProps = (
ContentComponent,
hasOwnStyle = true,
staticStyles = true,
displayName = undefined,
) => {
let Wrapper;
const styleFactory = createComponentStyleFactory(hasOwnStyle, staticStyles);
if (staticStyles) {
Wrapper = (props) => {
const combinedStyle = useMemo(() => styleFactory(props), []);
// {...STYLE_PROPS_UNSET}
return <ContentComponent {...props} style={combinedStyle} />;
};
} else {
Wrapper = (props) => {
/*
I use useMemo() here to call styleFactory() once,
otherwise it will be called on each render be wasted.
*/
const [combinedStyle, setStyle] = useState(useMemo(() => styleFactory(props), []));
useEffect(() => {
setStyle(styleFactory(props));
});
// {...STYLE_PROPS_UNSET}
return <ContentComponent {...props} style={combinedStyle} />;
};
}
Wrapper.displayName = displayName || `withLayoutProps(${getComponentName(ContentComponent)})`;
Wrapper.propTypes = ContentComponent.propTypes;
Wrapper.defaultProps = ContentComponent.defaultProps;
return Wrapper;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment