UNPKG

react-native-styled-px2dp

Version:

Write CSS px in react-native using styled-components and adapt multi resolution screens automatically.

104 lines (85 loc) 3.88 kB
const { Dimensions } = require('react-native') const styled = require('styled-components/native').default; import { ReactNativeStyledInterface, DefaultTheme} from "styled-components/native" type IOrientation = 'portrait'|'landscape' // current deisgn width and height which are affected by orientation // they will switch value with each other after orientation changed let currentDesignWidth, currentDesignHeight // device orientation, 'protrait' by default let orientation: IOrientation = 'portrait' // always re-get current screen width(becuz of oritation changes) const currentScreenWidth = () => Dimensions.get('screen').width const relativeCaculator = (px: number) => { return Number( ((px / currentDesignWidth) * currentScreenWidth()).toFixed(2) ) } const stringToRelativePX = (cssStr: string) => { // calling cssStr.replace on non-string will trigger error if(typeof cssStr !== 'string') return cssStr return cssStr.replace(/([\d|.]+)px/gm, (matched, pxNumber) => { // you have to write px in styled components // and css-to-react-native(a dependency of Styled Components) will translate it to RN unit, which is dp return relativeCaculator(pxNumber) + "px"; }); } const interpolationToRelativePX = (interpolation) => { if (typeof interpolation === 'string') { return stringToRelativePX(interpolation) } else { // deal with non-string interpolations like functions if (typeof interpolation === 'function') { // wrap the original function with stringToRelativePX and rewrite it const originFunction = interpolation const wrappedInterpolation = (...args) => stringToRelativePX(originFunction(...args)) return wrappedInterpolation } // just return if it is non-function interpolation return interpolation; } } //for extending styles like styled(SomeComponent)`blahblah` const extendingStyled = tag => (strings, ...interpolations) => { const transformedStrings = strings.map(stringToRelativePX) const transformedInterpolations = interpolations.map(interpolationToRelativePX) return styled(tag)(transformedStrings, ...transformedInterpolations) } //for using primitives directly like styled.View`blahblah` const flexibleStyled = new Proxy(extendingStyled, { get: (target, prop) => // return Tagged Template Literal to pretend styled component (strings, ...interpolations) => { const transformedStrings = strings.map(stringToRelativePX) const transformedInterpolations = interpolations.map(interpolationToRelativePX) return styled[prop](transformedStrings, ...transformedInterpolations) } }) const updateOrientation = (newOrientation: IOrientation) => { if(newOrientation !== orientation) { let temp = currentDesignWidth currentDesignWidth = currentDesignHeight currentDesignHeight = temp orientation = newOrientation } } interface IFlexibleInitProps { designWidth: number, designHeight?: number, orientation?: IOrientation } const getFlexibleStyled = (props: IFlexibleInitProps) => { currentDesignWidth = props.designWidth if(props.designHeight) { currentDesignHeight = props.designHeight } if(props.orientation) { orientation = props.orientation // throws warns if it is not a typical 'portrait' or 'landscape' if(orientation === 'portrait' && props.designWidth > props.designHeight) { console.warn("You are setting orientation to 'portrait' while you passed a designWidth greater than designHeight") } else if (orientation === 'landscape' && props.designWidth < props.designHeight) { console.warn("You are setting orientation to 'landscape' while you passed a designWidth less than designHeight") } } return { styled: flexibleStyled as ReactNativeStyledInterface<DefaultTheme>, px2dp: relativeCaculator, updateOrientation} } export default getFlexibleStyled