GithubHelp home page GithubHelp logo

vitalets / react-native-extended-stylesheet Goto Github PK

View Code? Open in Web Editor NEW
2.9K 38.0 138.0 1.77 MB

Extended StyleSheets for React Native

License: MIT License

JavaScript 98.06% TypeScript 1.94%
react react-native stylesheets theme theming style styling

react-native-extended-stylesheet's Introduction

React Native Extended StyleSheet

Build Status Coverage Status npm version license

Drop-in replacement of React Native StyleSheet with media-queries, variables, dynamic themes, relative units, percents, math operations, scaling and other styling stuff.

Demo

Use this Expo snack to play with Extended StyleSheets right in the browser or in Expo app.

Installation

npm i react-native-extended-stylesheet --save

Usage

  1. Define styles using EStyleSheet.create() instead of StyleSheet.create():
/* component.js */
import EStyleSheet from 'react-native-extended-stylesheet';

// define extended styles 
const styles = EStyleSheet.create({
  column: {
    width: '80%'                                    // 80% of screen width
  },
  text: {
    color: '$textColor',                            // global variable $textColor
    fontSize: '1.5rem'                              // relative REM unit
  },
  '@media (min-width: 350) and (max-width: 500)': { // media queries
    text: {
      fontSize: '2rem',
    }
  }
});

// use styles as usual
class MyComponent extends React.Component {
  render() {
    return (
      <View style={styles.column}>
        <Text style={styles.text}>Hello</Text>
      </View>
    );
  }
}  
  1. In app entry point call EStyleSheet.build() to actually calculate styles:
/* app.js */
import EStyleSheet from 'react-native-extended-stylesheet';

EStyleSheet.build({ // always call EStyleSheet.build() even if you don't use global variables!
  $textColor: '#0275d8'
});

[top]

Features

Global variables

Global variables are passed to EStyleSheet.build() and available in all stylesheets.

// app entry: set global variables and calc styles
EStyleSheet.build({
  $textColor: '#0275d8'
});

// component: use global variables
const styles = EStyleSheet.create({
  text: {
    color: '$textColor'
  }
});

// global variable as inline style or as props to components
<View style = {{
  backgroundColor: EStyleSheet.value('$textColor')
}}>
...
</View>

[top]

Local variables

Local variables can be defined directly in sylesheet and have priority over global variables. To define local variable just start it with $:

const styles = EStyleSheet.create({
  $textColor: '#0275d8',
  text: {
    color: '$textColor'
  },
  icon: {
    color: '$textColor'
  },
});

Local variables are also available in result style: styles.$textColor.
[top]

Theming

Changing app theme contains two steps:

  1. re-build app styles
  2. re-render components tree with new styles

To re-build app styles you can call EStyleSheet.build() with new set of global variables:

EStyleSheet.build({
  $theme: 'light',  // required variable for caching!
  $bgColor: 'white',
});

Please note that special variable $theme is required for proper caching of calculated styles.

Re-rendering whole component tree is currently a bit tricky in React.
One option is to wrap app into component and re-mount it on theme change:

  toggleTheme() {
    const theme = EStyleSheet.value('$theme') === 'light' ? darkTheme : lightTheme;
    EStyleSheet.build(theme);
    this.setState({render: false}, () => this.setState({render: true}));
  }
  render() {
    return this.state.render ? <App/> : null;
  }

The caveat is that all components loss their state. In the future it may be possible with forceDeepUpdate() method (see facebook/react#7759).
The approach is open for discusison, feel free to share your ideas in #22, #47.

You can check out full theming code in examples/theming or in Expo snack.
[top]

Media queries

Media queries allows to have different styles for different screens, platform, direction and orientation. They are supported as properties with @media prefix (thanks for idea to @grabbou, #5).

Media queries can operate with the following values:

  • media type: ios|android
  • width, min-width, max-width
  • height, min-height, max-height
  • orientation (landscape|portrait)
  • aspect-ratio
  • direction (ltr|rtl)

You can use media queries on:

  • global level
  • sheet level
  • style level

Examples:

// global level
EStyleSheet.build({
  '@media ios': {
    $fontSize: 12,
  },
  '@media android': {
    $fontSize: 16,
  },
});

// sheet level
const styles = EStyleSheet.create({
  column: {
    width: '80%',
  },
  '@media (min-width: 350) and (max-width: 500)': {
    column: {
      width: '90%',
    }
  }
});

// style level
const styles = EStyleSheet.create({
  header: {
    '@media ios': {
      color: 'green',
    },
    '@media android': {
      color: 'blue',
    },
  }
});

You can check out full example code in examples/media-queries or in Expo snack.
[top]

Math operations

Any value can contain one of following math operations: *, /, +, -. Operands can be numbers, variables and percents.
For example, to render circle you may create style:

const styles = EStyleSheet.create({
  $size: 20,
  circle: {
    width: '$size',
    height: '$size',
    borderRadius: '0.5 * $size'
  }
});

[top]

REM units

Similar to CSS3 rem unit it allows to define any integer value as relative to the root element. In our case root value is special rem global variable that can be set in EStyleSheet.build(). It makes easy to scale app depending on screen size and other conditions. Default rem is 16.

// component
const styles = EStyleSheet.create({
  text: {
    fontSize: '1.5rem',
    marginHorizontal: '2rem'
  }
});
// app entry
let {height, width} = Dimensions.get('window');
EStyleSheet.build({
  $rem: width > 340 ? 18 : 16
});

You can check out full example code in examples/rem or in Expo snack.
[top]

Percents

Percent values are supported natively since React Native 0.43. EStyleSheet passes them through to original StyleSheet except cases, when you use calculations with percents, e.g. "100% - 20". Percents are calculated relative to screen width/height on application launch.

const styles = EStyleSheet.create({
  column: {
    width: '100% - 20'
  }
});

Percents in nested components
If you need sub-component with percent operations relative to parent component - you can achieve that with variables.
For example, to render 2 sub-columns with 30%/70% width of parent column:

render() {
  return (
    <View style={styles.column}>
      <View style={styles.subColumnLeft}></View>
      <View style={styles.subColumnRight}></View>
    </View>
  );
}

...

const styles = EStyleSheet.create({
  $columnWidth: '80%',
  column: {
    width: '$columnWidth',
    flexDirection: 'row'
  },
  subColumnLeft: {
    width: '0.3 * $columnWidth'
  },
  subColumnRight: {
    width: '0.7 * $columnWidth'
  }
});

[top]

Scaling

You can apply scale to components by setting special $scale variable.

const styles = EStyleSheet.create({
  $scale: 1.5,
  button: {
    width: 100,
    height: 20,
    marginLeft: 10
  }
});

This helps to create reusable components that could be scaled depending on prop:

class Button extends React.Component {
  static propTypes = {
    scale: React.PropTypes.number
  };
  render() {
    let style = getStyle(this.props.scale)
    return (
      <View style={style.button}>
      </View>
    );
  }
}

let getStyle = function (scale = 1) {
  return EStyleSheet.create({
    $scale: scale,
    button: {
      width: 100,
      height: 20,
      marginLeft: 10
    }
  });
}

To cache calculated styles please have a look on caching section.
[top]

Underscored styles

Original react-native stylesheets are calculated to integer numbers and original values are unavailable. But sometimes they are needed. Let's take an example:
You want to render text and icon with the same size and color. You can take this awesome icon library and see that <Icon> component has size and color props. It would be convenient to define style for text and keep icon's size/color in sync.

const styles = EStyleSheet.create({
  text: {
    fontSize: '1rem',
    color: 'gray'
  }
});

In runtime styles created with original react's StyleSheet will look like:

styles = {
  text: 0
}

But extended stylesheet saves calculated values under _text property:

styles = {
  text: 0,
  _text: {
    fontSize: 16,
    color: 'gray'
  }
}

To render icon we just take styles from _text:

return (
  <View>
    <Icon name="rocket" size={styles._text.fontSize} color={styles._text.color} />
    <Text style={styles.text}>Hello</Text>
  </View>
);

[top]

Pseudo classes (:nth-child)

Extended stylesheet supports 4 pseudo classes: :first-child, :nth-child-even, :nth-child-odd, :last-child. As well as in traditional CSS it allows to apply special styling for first/last items or render stripped rows.
To get style for appropriate index you should use EStyleSheet.child() method. It's signature: EStyleSheet.child(stylesObj, styleName, index, count).

const styles = EStyleSheet.create({
  row: {
    fontSize: '1.5rem',
    borderTopWidth: 1
  },
  'row:nth-child-even': {
    backgroundColor: 'gray' // make stripped
  },
  'row:last-child': {
    borderBottomWidth: 1 // render bottom edge for last row
  }
});
...
render() {
  return (
    <View>
      {items.map((item, index) => {
        return (
          <View key={index} style={EStyleSheet.child(styles, 'row', index, items.length)}></View>
        );
      })}
    </View>
  );
}

[top]

Value as a function

For the deepest customization you can specify any value as a function that will be executed on EStyleSheet build. For example, you may darken or lighten color of variable via npm color package:

import Color from 'color';
import EStyleSheet from 'react-native-extended-stylesheet';

const styles = EStyleSheet.create({
  button: {
    backgroundColor: () => Color('green').darken(0.1).hexString() // <-- value as a function
  }
});

render() {
  return (
    <TouchableHighlight style={styles.button}>
      ...
    </TouchableHighlight>
  );
}

The common pattern is to use EStyleSheet.value() inside the function to get access to global variables:

EStyleSheet.build({
  $prmaryColor: 'green'
});

const styles = EStyleSheet.create({
  button: {
    backgroundColor: () => Color(EStyleSheet.value('$prmaryColor')).darken(0.1).hexString()
  }
});

[top]

Caching

If you use dynamic styles depending on runtime prop or you are making reusable component with dynamic styling you may need stylesheet creation in every render() call. Let's take example from scaling section:

class Button extends React.Component {
  static propTypes = {
    scale: React.PropTypes.number
  };
  render() {
    let style = getStyle(this.props.scale)
    return (
      <View style={style.button}>
      </View>
    );
  }
}

let getStyle = function (scale = 1) {
  return EStyleSheet.create({
    $scale: scale,
    button: {
      width: 100,
      height: 20,
      marginLeft: 10
    }
  });
}

To avoid creating styles on every render you can use lodash.memoize: store result for particular parameters and returns it from cache when called with the same parameters. Updated example:

import memoize from 'lodash.memoize';

let getStyle = memoize(function (scale = 1) {
  return EStyleSheet.create({
    $scale: scale,
    button: {
      width: 100,
      height: 20,
      marginLeft: 10
    }
  });
});

Now if you call getStyle(1.5) 3 times actually style will be created on the first call and two other calls will get it from cache.
[top]

Outline for debug

It is possible to outline all components that are using EStyleSheet. For that set global $outline variable:

EStyleSheet.build({$outline: 1});

Note that components without styles will not be outlined, because RN does not support default component styling yet.

To outline particular component set local $outline variable:

const styles = EStyleSheet.create({
  $outline: 1,
  column: {
    width: '80%',
    flexDirection: 'row'
  },
  ...
});

[top]

Hot module reload

Hot module reload (HMR) allows you to change code and see live updates without loosing app state. It is very handy for tuning styles. EStyleSheet supports HMR with the following options:

  1. When you change style of component - the component is updated by HMR automatically without any effort from your side.
  2. When you change global variable or theme - you should use HMR API to force style re-calculation:
    // app.js
    EStyleSheet.build({
      $fontColor: 'black'
    });
    
    ...
    
    module.hot.accept(() => {
      EStyleSheet.clearCache();
      EStyleSheet.build(); // force style re-calculation
    });

See full example of HMR here.
[top]

EStyleSheet API

.create()

/**
 * Creates extended stylesheet object
 *
 * @param {Object} source style
 * @returns {Object} extended stylesheet object
 */
 create (source) {...}

[top]

.build()

/**
 * Calculates all stylesheets
 *
 * @param {Object} [globalVars] global variables for all stylesheets
 */
 build (globalVars) {...}

[top]

.value()

/**
 * Calculates particular expression.
 *
 * @param {*} value
 * @param {String} [prop] property for which value is calculated. For example, to calculate percent values 
 * the function should know is it 'width' or 'height' to use proper reference value.
 * @returns {*} calculated result
 */
 value (value, prop) {...}

Please note that in most cases EStyleSheet.value() should be used inside function, not directly:

const styles = EStyleSheet.create({
    button1: {
        width: () => EStyleSheet.value('$contentWidth') + 10 // <-- Correct!
    },
    button2: {
        width: EStyleSheet.value('$contentWidth') + 10 // <-- Incorrect. Because EStyleSheet.build() may occur later and $contentWidth will be undefined at this moment.
    }
});

[top]

.child()

/**
 * Returns styles with pseudo classes :first-child, :nth-child-even, :last-child according to index and count
 *
 * @param {Object} stylesheet
 * @param {String} styleName
 * @param {Number} index index of item for style
 * @param {Number} count total count of items
 * @returns {Object|Array} styles
 */
 child (styles, styleName, index, count) {...}

[top]

.subscribe()

/**
 * Subscribe to event. Currently only 'build' event is supported.
 *
 * @param {String} event
 * @param {Function} listener
 */
 subscribe (event, listener) {...}

This method is useful when you want to pre-render some component on init. As extended style is calculated after call of EStyleSheet.build(), it is not available instantly after creation so you should wrap pre-render info listener to build event:

const styles = EStyleSheet.create({
  button: {
    width: '80%',
  }
});

// this will NOT work as styles.button is not calculated yet
let Button = <View style={styles.button}></View>;

// but this will work
let Button;
EStyleSheet.subscribe('build', () => {
  Button = <View style={styles.button}></View>;
});

[top]

.unsubscribe()

/**
 * Unsubscribe from event. Currently only 'build' event is supported.
 *
 * @param {String} event
 * @param {Function} listener
 */
 unsubscribe (event, listener) {...}

Unsubscribe from event. [top]

Caveats

  1. Dynamic theme change is possible only with loosing components local state
    When theme styles are re-calculated - all components should be re-rendered. Currently it can be done via re-mounting components tree, please see #47.

    Note: it is not issue if you are using state container like Redux and can easily re-render app in the same state

  2. Dynamic orientation change is not supported
    Please see #9 for more details.

  3. Old RN versions (< 0.43) can crash the app with percent values
    RN >= 0.43 supports percent values natively (#32) and EStyleSheet since 0.5.0 just proxy percent values to RN as is (#77) to keep things simple. Older RN versions (< 0.43) can't process percents and EStyleSheet process such values. So if you are using RN < 0.43, you should stick to [email protected].

FAQ

  1. I'm getting error: "Unresolved variable: ..."
    • Ensure that you call EStyleSheet.build() in entry point of your app.
    • Ensure that $variable name without typos.
    • Ensure that you are not using EStyleSheet.value() before the styles are built. See #50 for details.

Changelog

Please see CHANGELOG.md

Feedback

If you have any ideas or something goes wrong feel free to open new issue.

License

MIT @ Vitaliy Potapov

[top]

* * *
If you love ❤️ JavaScript and would like to track new trending repositories,
have a look on vitalets/github-trending-repos.

react-native-extended-stylesheet's People

Contributors

achipa avatar artsra avatar esthor avatar gbhasha avatar grantbi avatar joemckie avatar kerumen avatar mitramejia avatar tlvenn avatar vikrantnegi avatar vitalets avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-extended-stylesheet's Issues

[suggestion]Do we need different style for iOS and android version?

Thanks for this repo! Help me a lot.

I just read a post which introduce a interesting idea(chinese post), I do not know it is worth to embedded here or not, I just post the code here.

Because iOS and android display different in same style. So they wrap things like this:

import { StyleSheet as RNStyleSheet, Platform } from 'react-native'

class StyleSheet {
  static create(styles: Object): {[name: string]: number} {
    const platformStyles = {}
    Object.keys(styles).forEach((name) => {
      const { ios, android, ...style } = { ...styles[name] }
      let outputStyle = style
      if (ios && Platform.OS === 'ios') outputStyle = { ...style, ...ios }
      if (android && Platform.OS === 'android') outputStyle = { ...style, ...android }
      platformStyles[name] = outputStyle
    })
    return RNStyleSheet.create(platformStyles)
  }
}

export default StyleSheet

Then we can use style like this:

export default StyleSheet.create({
  container: {
    flex: 1,
    paddingLeft: 20,
    paddingRight: 20,
    ios: {
      paddingTop: 15,
      paddingBottom: 15,
    },
    android: {
      paddingTop: 10,
      paddingBottom: 10,
    },
    backgroundColor: 'white',
  },
)}

Interesting?

Global styles

It is possible to have global styles, like we have in CSS?

Nested global variables

EStyleSheet.build({
    dashboard: {
         $valueFontSize: 26 * fontScale,
    }
});

Currently, this is not possible because the check is against the first letter (charAt(0)).
Say I want to use:

EStyleSheet.create({
    text: {
         fontSize: '16 * dashboard.$valueFontSize',
    }
});

Could we have this support?

Aspect-ratio

How to use aspect-ratio media query. Need example. Thanks!

Using static theme (change theme without app reload)

1- Is it possible to use static theme and no app reload to theme change? for example when I want to change theme , Just call EStyleSheet.build and forceUpdate again

2- Is dynamic theme need cashing ? IS dynamic theme need stylesheet creation in every render() call?

Variables don't support division

Is there currently any way to implement division with a variable? Take the following example which creates a label with rounded sides:

const styles = EStyleSheet.create({
  label: {
    $height: 30,
    borderRadius: '$height / 2',
    height: '$height',
  }
});

This is throwing an error that says $height / 2 is an unresolved variable. The docs also suggest that division isn't implemented.

Is there a reason for that or is it just unimplemented? I could take a look into it if there's nothing blocking it.

Multiple math operators

Currently only 1 operator is supported, so if I have to do the following I can't

{
  height: '$deviceHeight/2-100'
}

Instead I have to do

{
  $halfDeviceHeight: '$deviceHeight/2',
  height: '$halfDeviceHeight-100'
}

So for many operators this becomes unnecessary & this happens for quite a few use cases that I've encountered in the past few weeks or so

Ideas for orientation change support

After implementing media queries in #5 I'm thinking about supporting orientation change somehow.
As it will allow to get full power of media queries.

Technically I see these steps:

  1. catch orientation change
  2. re-calculate styles
  3. re-render components

I quickly searched for that topic but did not found ready to use concept how it can be implemented in RN.
If you have some ideas or experience, please feel free to share it here and we will think how to add it.

Thanks!

App Crashes When Percentage is used [Expo]

Hi, thanks for this package.
I just that my app crashes whenever i declare a percentage value. Example code below.

 import EStyleSheet from "react-native-extended-stylesheet";

const styles = EStyleSheet.create({
  root: {
    flex: 1
  },
  meetupCard: {
    height: 200,
    width: 175,
    marginLeft: '1.5%',
        backgroundColor: "#f56d79"
      }
    });

    export default styles;

When ever I comment out the percentage line, Everything works find.

Edit

Seems this only happens when I use it on any margin value
Is this a bug? Thakns

Styles returns empty Object

I have a styles.js file and themes/default.js theme.

in styles.js:

import { Platform } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import theme from './themes/default';

const styles = EStyleSheet.create({
  PrimaryButton: {
    backgroundColor: 'lightblue',
    borderColor: 'lightblue',
    borderRadius: 0,
  },
  Badge: {
    borderRadius: 5,
    backgroundColor: '#ffc900',
    paddingHorizontal: 5,
    paddingVertical: 2,
    alignSelf: 'center'
  },
  LabelWithBadgeSpaceBetween: {
    justifyContent: 'space-between',
    flexDirection: 'row',
    paddingVertical: 5,
    paddingHorizontal: 10,
    backgroundColor: '#eee'
  },
  AlertButton: {
    backgroundColor: '$alertColor',
    borderColor: '$alertColor',
    borderRadius: 0,
    marginTop: 4,
    marginBottom: 0,
  },
});
EStyleSheet.build(theme);

export default styles;

this returns an empty Object {}.
react-native: 0.42.3

Unexpected Token 'import'

Getting this error when running my project after adding this dependency. We're running babel (stage-2). Any idea why this is happening?

Get value in other theme

Hi, i have define a lightTheme how default, how could i get a value of the another theme?
something like:

import lightTheme from './lightTheme'
import darkTheme from './darkTheme'

EStyleSheet.build(lightTheme) // set light theme

const font = EStyleSheet.value('$font', darkTheme) // get value of dark theme

is there any way to do this?

thanks :-)

Global styles 'Unresolved variable' error

Hi,

I'm trying to get all my style values in EStyleSheet.build({...}); but I'm experiencing some troubles with the error "Unresolved variable: $<VAR_NAME>".

Here's my code:

// style.js
const COLORS = {
    $ORANGE: '#D57C4C',
    $PURPLE: '#B36892',
    $WHITE: '#FFFFFF',
    $BLACK: '#000000',
    $GREY: '#C1C1C1',
    $LIGHT_GREY: '#EAEBED',
    $DEFAULT_IOS_BLUE: '#0e7afe',
};

const FONTS = {
    $FONT_XL: 20,
    $FONT_L: 17,
    $FONT_M: 14,
    $FONT_S: 12,
    $FONT_XS: 10,
};

const ICONS = {
    $ICON_XL: 30,
    $ICON_L: 25,
    $ICON_M: 20,
    $ICON_S: 15,
};

const VALUES = {
    $RAD: 4,
};

export default {
    ...COLORS,
    ...FONTS,
    ...ICONS,
    ...VALUES
};
// app.js, entry file

EStyleSheet.build({
    ...globalStyleVars
});

// my component code style
const styles = EStyleSheet.create({
    $padding: 10,

    container: {
        justifyContent: 'flex-start',
        alignItems: 'center',
        paddingLeft: '$padding',
        paddingRight: '$padding',

        borderStyle: 'solid',
        borderBottomColor: '$ORANGE',
        borderBottomWidth: 4,

    },

    inputContainer: {
        flex: 1,
        flexDirection: 'row',
        marginRight: 10
    },

    inputWrapper: {
        $padding: 5,
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'flex-start',
        alignItems: 'center',
        alignSelf: 'stretch',

        paddingLeft: '$padding',
        paddingRight: '$padding',

        backgroundColor: '$LIGHT_GREY',
        borderRadius: '$RAD',
        height: 25,
    },

    input: {
        flex: 1,
        paddingLeft: 8,
        fontSize: 14,
        padding: 0,
    },

    icon: {
        width: 15,
        height: 15
    },

    buttonContainer: {
        justifyContent: 'center',
        alignItems: 'center',
    },

    text: {
        color: '$DEFAULT_IOS_BLUE',
        alignSelf: 'stretch',
        paddingTop: 10,
        paddingBottom: 10
    },
});

And, the weird thing is that If I remove $RAD, it works with the others values ($ORANGE etc...)

Thank you for your help !

get style value directly

Hi

Is it possible to get style value directly to pass it to props?
for example I want to count it from rem or use global variable

for example
<SomeComponent height={EStyleSheet.get('$globalHeight - 10rem')} />
or something like this

Common styles ?

Is there any way to create Common styles since I'm repeating a lot of code.

Currently, my approach is

<View style={[styles.commonStyle, styles.A]} />
<View style={[styles.commonStyle, styles.B]} />

But, I think the following approach would be much better

EStylesheet.create({
	$commonStyles: {
		margin: 10,
		padding: 10,
	},
	A: {
		...$commonStyles,
		color: 'red',
	},
	B: {
		...$commonStyles,
		color: 'green',
	},
})

So that in my component I will only do this -

<View style={styles.A} />
<View style={styles.B} />

Someway the Component would be much more readable. What do u think @vitalets

Universal support?

Hey vitalets!

Awesome library man. It would be super cool if this could compile on web too. Do you think that would be much effort? If not, I might look into trying to do that. I'm looking for something that works in native and progressively enhances if it can (eg. inside browser).

Cheers

Using with livereload

If livereload is on, I get error on every update Unhandled JS Exception: No need to call EStyleSheet.build() more than once

And thanks for your work!!!

Variables are included in computed styles

Variables declared with $<var-name> are included in the computed styles _style and are thus "applied" to elements. They don't seem to be removed correctly because warnings are being logged reminding that the variable is an invalid style prop key.

Questions about theming

  • How to change theme at runtime?
    For example, the app loaded EStyleSheet.build(DarkTheme) in the index.js. How to change to Light Theme? Calling build again does not seem to work.
  • How to use a different theme per component? For example:
<View>
    <Button theme='dark'>Dark Button</Button>
    <Button theme='light'>Light Button</Button>
<View>

media queries for global variables

Hi

Is it possible to use medai queries while setting global variables?
I want to set different values depending on IOS/android while EStyleSheet.build but it doesn't work

PS I know that I can do it with native Platform, but probably I'll use other media queries

and thanks for great extension

Problem with create

Hi,

I tried to use this module without success, I always got an empty object as a result, even with the simple example on the readme.
I looked at the code and I was able to make it work by changing (in api.js) : if (this.builded) to if (!this.builded) since in my test this.builded was always false and it looks like it needs to go through sheet.calc()

Maybe i'm missing something...

EStyleSheet.memoize does not work for Object params

If you pass objects to a memoized function, it considers that the value is the same, due to use of Object.toString (indirectly called, when it uses Array.join) when creating the cache key.

Code to reproduce the error:

import EStyleSheet from 'react-native-extended-stylesheet';

const memoized = EStyleSheet.memoize((data) => console.log(data));

// These two work as expected:
memoized({id: 1}); // should log
memoized({id: 1}); // should not log

// This one won't
memoized({id: 2}); // should log

See src/memoize.js#L7

EStyleSheet.value

My case

EStyleSheet.value('2.3rem')

returns value for default rem value but I had set other build option

EStyleSheet.build({rem: 20});

Global styles

I have tried something like this but I got an error. I think this is needed. Thanks.

EStyleSheet.build (
  container: {
    flex: 1,
    backgroundColor:'white'
  }
)

const styles = EStyleSheet.create({
  container: '$container'
})

Forward core StyleSheet properties

Brilliant extension, thanks.

It'd be nice to be able to magically do:

// But really get EStyleSheet
import {StyleSheet} from "react-native";

I'm currently settling on this (until I figure out a nice way to do the above):

import StyleSheet from "react-native-extended-stylesheet";

The problem is EStyleSheet is not a drop-in replacement for the core StyleSheet.

It'd be neat if flatten, harilineWidth, etc. were exposed on EStyleSheet.

Question: When to use underscored styles ❓

I have read the docs about underscored styles but don't know what to use & why ❓

Currently, I'm using styles._text styles everywhere bcz once styles.text was not working.

So @vitalets if u can explain when to use underscored styles

Media queries always assume initial device orientation on Android

There is a known issue with Dimensions in Android that cause it to report wrong values. I guess it might be different on different devices, in my Galaxy S5 Mini running Android 5 it always gets stuck with the values app had on launch (e.g. if you start in Portrait, dimensions will be stating narrow screen width forever, even if you rotate the device). Naturally media queries relying on Dimensions do not work properly then. I think I've heard of some similar issues on iOS, but as for Android they are present for sure.

The proper way for fetching the screen size seems to use Android's native DisplayMetrics, there is even an npm module doing it - https://www.npmjs.com/package/react-native-extra-dimensions-android (maybe react-native-extended-stylesheet could depend on this one?).

Another option for tracking the real screen size (that I am using in my app at the moment) is to have one View that takes the whole screen and watch for its onLayout event - its parameters seem to deliver real view size quite reliably. That is useless for react-native-extended-stylesheet at the moment, but possibly you could allow overriding the default dimensions with whatever clients wants e.g. via .build(forcedCurrentDimensions)?

P.S.
Sorry if I am producing too many issues, @vitalets You made an awesome module that simplifies styling for the different devices a lot, so I am reporting what I discover when getting it into use.

build failed

uncaught error Error: SyntaxError: Unexpected token ...
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:387:25)
    at Module._extensions..js (module.js:422:10)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/samliu/Projects/weather/node_modules/babel-register/lib/node.js:138:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at OptionManager.mergePresets (/Users/samliu/Projects/weather/node_modules/babel-core/lib/transformation/file/options/option-manager.js:324:28)
TransformError: /Users/samliu/Projects/weather/node_modules/react-native-extended-stylesheet/src/index.js: Unexpected token ...
See logs /var/folders/qh/1pg8d2s57k52gqxszrwf6f940000gn/T/react-packager.log
    at SocketClient._handleMessage (SocketClient.js:139:23)
    at BunserBuf.<anonymous> (SocketClient.js:53:42)
    at emitOne (events.js:90:13)
    at BunserBuf.emit (events.js:182:7)
    at BunserBuf.process (/Users/samliu/Projects/weather/node_modules/bser/index.js:289:10)
    at /Users/samliu/Projects/weather/node_modules/bser/index.js:244:12
    at nextTickCallbackWith0Args (node.js:452:9)
    at process._tickCallback (node.js:381:13)
Command /bin/sh failed with exit code 1

Unexpected token

[ios] maxFontSize style property.

On ios it's possible to change font scale in accessibility settings. Right now you can control if to allow the font scaling at all in the specific text component. anyway you can't set the max scale value for that text. Hopefully there's pixel ratio api which seems to allow query for current font scale.

That said, I think there should be an Api to set the max font size in the specific text field:

{
  fontSize: '1rem',
  maxFontSize: '2rem',
}

Which should be equivalent of

{
  fontSize: `1rem * {Math.min(2, PixelRatio.getFontScale())}`,
}

Thanks.

first-child not working?

Not sure if i'm making a mistake but, :first-child pseudo class doesn't seem to be working for me, last-child, even, and odd all seem to work fine?

It still takes the 'left: 50' for first child

In my styles:

event_guest: {
    position: "absolute",
    height: 40,
    borderColor: "white",
    width: 40,
    marginTop: 10,
    left: 30,
    borderRadius: 20,
    borderWidth: 2,
    borderColor: "#FFF"
},
'event_guest:nth-child-even': {
    left:50,
},
'event_guest:first-child': {
    left:10,
},

media-queries.js file throws error when ran on Android

So the library works great on iOS, but when I try to run the same library on Android, I receive the following error on startup.

screen shot 2016-06-07 at 4 58 15 pm

It's on this line: const res = Object.keys(obj).reduce((res, key) => {

I've read up on the other issues and it looks like Android is not setting these properties correctly. Can you please advise?

My code:

screen shot 2016-06-07 at 5 01 49 pm

auto?

I was led to this project because someone said you could do something to the effect of width='100%' height='auto'.

I can't get it to work. Does this functionality exist?

EStyleSheet.create returned number instead of object

Hi, thanks for this great library for styling,

I've used the old version of EStyleSheet, and it works :)
but now i'm in a new project with RN 0.41 and the EStyleSheet 0.3.2,
i got plenty warning that invalid property type of style, it

here's where i declare the build in my app.js:

'use` strict';

import React,{ Component } from 'react';
import { StyleSheet, Dimensions, Image, Alert, BackAndroid } from 'react-native';
import { Container, Content, Text, View } from 'native-base';
import EStyleSheet from 'react-native-extended-stylesheet';
import AppNavigator from './AppNavigator';

let {height, width} = Dimensions.get('window');
let styles = StyleSheet.create({
  container: {
    flex: 1,
    width: null,
    height: null,
  },
  box: {
    padding: 10,
    backgroundColor: 'transparent',
    flex: 1,
    height: height-70
  },
  space: {
    marginTop: 10,
    marginBottom: 10,
    justifyContent: 'center'
  },
  modal: {
    justifyContent: 'center',
    alignItems: 'center'
  },
  modal1: {
    height: 300

  },
  modal2: {
    height: height-78,
    position: 'relative',
    justifyContent: 'center',
  },
});

class App extends Component {

  constructor(props) {
    super(props);
    
  }


  render() {
     //some render
  }
}

EStyleSheet.build({
  rem: width > 500 ? 2 : 1,
  $scale: width > 500 ? 1 : 1
});

export default App

and my class

import React, { Component } from 'react';
import { Image, Platform, StyleSheet } from 'react-native';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import { Container, Content, Text, Item, Input, Button, Icon, View, Form, Header } from 'native-base';

import styles from './styles';

const backgroundImage = require('../../../../images/login.png');

class Login extends Component {

  constructor(props) {
    super(props);
    this.state = {
      email: '',
      password: '',
      scroll: false,
    };
  }

  render() {
    return (
      <Container>

        <Content scrollEnabled={true} bounces={false}>
          <Image source={backgroundImage} style={styles.container}>
            <View style={styles.bg}>
              <Button style={styles.buttonLoginFacebook} onPress={() => Actions.main()}>
                <Text style={styles.buttonTextLogin}>
                  Login with facebook
                </Text>
              </Button>
              <Button style={styles.buttonRegisterFacebook} onPress={() => Actions.signUp()}>
                <Text style={styles.buttonTextLogin}>
                  Register with facebook
                </Text>
              </Button>
            </View>
          </Image>
        </Content>
      </Container>
    );
  }
}

export default connect()(Login);`

and finally, my style.js:

'use strict';
const React = require('react-native');
import EStyleSheet from 'react-native-extended-stylesheet';
const { StyleSheet, Dimensions, Platform } = React;

const deviceHeight = Dimensions.get('window').height;

module.exports = EStyleSheet.create({
  $outline: 1,
  container: {
    flex: 1,
    width: null,
    height: '100%',
    resizeMode: 'cover',
    alignItems: 'center',
  },
  buttonTextLogin: {
    color: '#000',
    width: '90%',
    textAlign: 'center'
  },
  buttonRegisterFacebook: {
    backgroundColor: '#cf4965',
    width: '90%'
  },
  shadow: {
    flex: 1,
    marginTop: (deviceHeight < 600) ? -40 : -10,
    width: null,
    height: null,
    backgroundColor: 'transparent',
  },
  bg: {
    backgroundColor: 'rgba(255,0,0,0)',
  },
  buttonLoginFacebook: {
    backgroundColor: '#454190',
    width: '90%'
  },

});

But the style doesn't make any effect on my layout, and i keep getting lots of warning,
Warning: Failed prop type: Invalid prop 'style' of type 'number' supplied to 'Styled(Text)', expected 'object' Warning: Failed prop type: Invalid prop 'style' of type 'number' supplied to 'Styled(Button)', expected 'object' Warning: Failed prop type: Invalid prop 'style' of type 'number' supplied to 'Styled(Content)', expected 'object' Warning: Failed prop type: Invalid prop 'style' of type 'number' supplied to 'Styled(Button)', expected 'object'

Fyi, i did make sure the path is correct, so it's not import problem.
and my package.json

{
  "name": "xxx",
  "version": "6.0.0",
  "private": true,
  "scripts": {
    "postinstall": "remotedev-debugger",
    "start": "node_modules/react-native/packager/packager.sh",
    "eslint": "eslint"
  },
  "dependencies": {
    "@remobile/react-native-cordova": "^1.1.1",
    "@remobile/react-native-file-transfer": "^1.0.7",
    "bugsnag-react-native": "^2.2.0",
    "color": "^0.11.3",
    "lodash": "^4.13.1",
    "moment": "^2.13.0",
    "native-base": "2.1.0-rc.2",
    "react": "15.4.2",
    "react-native": "0.41.0",
    "react-native-button": "^1.6.0",
    "react-native-code-push": "^1.17.0-beta",
    "react-native-extended-stylesheet": "^0.3.2",
    "react-native-fcm": "^6.2.0",
    "react-native-gifted-messenger": "^0.1.4",
    "react-native-gifted-spinner": "0.0.5",
    "react-native-image-picker": "^0.26.2",
    "react-native-loading-spinner-overlay": "^0.4.2",
    "react-native-modalbox": "^1.3.7",
    "react-native-navigation-redux-helpers": "^0.5.0",
    "react-native-router-flux": "^3.38.0",
    "react-native-scrollable-tab-view": "^0.7.2",
    "react-native-storage": "^0.1.5",
    "react-redux": "^4.4.5",
    "redux": "^3.5.2",
    "redux-persist": "^3.2.2",
    "redux-thunk": "^2.1.0",
    "remote-redux-devtools": "^0.3.3",
    "remote-redux-devtools-on-debugger": "^0.4.6"
  },
  "devDependencies": {
    "chai": "^3.5.0",
    "babel-eslint": "^6.1.2",
    "eslint": "^3.5.0",
    "eslint-config-airbnb": "^11.1.0",
    "eslint-plugin-import": "^1.14.0",
    "eslint-plugin-jsx-a11y": "^2.2.1",
    "eslint-plugin-react": "^6.2.0",
    "eslint-plugin-react-native": "^2.0.0",
    "mocha": "^2.5.3",
    "babel-jest": "19.0.0",
    "jest": "19.0.2"
  },
  "jest": {
    "preset": "react-native"
  }
}

*updated:

render() {
    console.log(StyleSheet.flatten(styles));
    return (
      <Container>
        <Content scrollEnabled={true} bounces={false}>
          <Image source={backgroundImage} style={StyleSheet.flatten(styles.container)}>
            <View style={StyleSheet.flatten(styles.bg)}>
              <Button style={StyleSheet.flatten(styles.buttonLoginFacebook)} onPress={() => Actions.main()}>
                <Text style={StyleSheet.flatten(styles.buttonTextLogin)}>
                  Login with facebook
                </Text>
              </Button>
              <Button style={StyleSheet.flatten(styles.buttonRegisterFacebook)} onPress={() => Actions.signUp()}>
                <Text style={StyleSheet.flatten(styles.buttonTextLogin)}>
                  Register with facebook
                </Text>
              </Button>
            </View>
          </Image>
        </Content>
      </Container>
    );
  }

if i use the flatten method in react-native Stylesheet, it worked, it rendered the outline correctly (for $outline: 1), everything works, but it's kinda absurd to write Stylesheet.flatten() everytime, right?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.