Skip to content

Commit

Permalink
Merge pull request #8 from vitalets/media-queries
Browse files Browse the repository at this point in the history
Media queries
  • Loading branch information
vitalets committed Apr 25, 2016
2 parents 8616d19 + 7babe54 commit 3da89ec
Show file tree
Hide file tree
Showing 28 changed files with 630 additions and 194 deletions.
121 changes: 83 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
[![Build Status](https://travis-ci.org/vitalets/react-native-extended-stylesheet.svg?branch=master)](https://travis-ci.org/vitalets/react-native-extended-stylesheet)
[![Coverage Status](https://coveralls.io/repos/github/vitalets/react-native-extended-stylesheet/badge.svg?branch=master)](https://coveralls.io/github/vitalets/react-native-extended-stylesheet?branch=master)

Extend [React Native](https://facebook.github.io/react-native/) stylesheets with variables, relative units, percents,
math operations, scaling and other stuff to control app styling.
Extend [React Native](https://facebook.github.io/react-native/) stylesheets with media-queries, variables, themes,
relative units, percents, math operations, scaling and other styling stuff.

<img align="right" src="https://raw.githubusercontent.com/vitalets/react-native-extended-stylesheet/master/example/screenshot.png">

Expand All @@ -17,10 +17,10 @@ math operations, scaling and other stuff to control app styling.
- [math operations](#math-operations)
- [rem units](#rem-units)
- [percents](#percents)
- [media queries](#media-queries)
- [scaling](#scaling)
- [_underscored styles](#underscored-styles)
- [pseudo classes (:nth-child)](#pseudo-classes-nth-child)
- [OS specific props](#os-specific-props)
- [value as a function](#value-as-a-function)
- [caching](#caching)
- [outline for debug](#outline-for-debug)
Expand Down Expand Up @@ -68,20 +68,16 @@ npm i react-native-extended-stylesheet --save
}
```

2. Call `EStyleSheet.build()` in entry point of your app:
2. Call `EStyleSheet.build()` in entry point of your app to actually calculate styles:

```js
// app.js
import EStyleSheet from 'react-native-extended-stylesheet';
// build styles
// calculate styles
EStyleSheet.build();
// build styles with passed variables
EStyleSheet.build({
textColor: '#0275d8'
});
```

\[[top](#)\]

## Features
Expand Down Expand Up @@ -112,13 +108,32 @@ export default {
}
// app entry
import theme from '.theme';
import theme from './theme';
EStyleSheet.build(theme);
```
You can define nested variables and access them via dot path:
```js
// entry
EStyleSheet.build({
button: {
size: 10
}
});
// component
const styles = EStyleSheet.create({
text: {
color: '$button.size'
}
});
```
\[[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 `$`:
```js
const styles = EStyleSheet.create({
$textColor: '#0275d8',
Expand Down Expand Up @@ -167,8 +182,8 @@ EStyleSheet.build({
\[[top](#)\]
### Percents
Percents are useful only for **single-orientation apps** as calculation performed once on start using screen dimensions.
You can apply it to top-level components to render layout.
Percent values are useful for **single-orientation apps** because calculation is performed on app start only.
They are calculated relative to **screen width/height** (not parent component!).
```js
const styles = EStyleSheet.create({
column: {
Expand All @@ -178,11 +193,11 @@ const styles = EStyleSheet.create({
}
});
```
Supporting orientation change is always design-decision but sometimes it's really unneeded and makes life much easier.
Note: supporting orientation change is always design-decision but sometimes it's really unneeded and makes life much easier.
How to lock orientaion for [IOS](http://stackoverflow.com/a/24205653/740245), [Android](http://stackoverflow.com/a/4675801/740245).

**Percents in nested components**
If you need sub-components with percentage props based on parent, you can easily achieve it with variables.
If you need sub-components with percentage props based on parent, you can achieve it with variables.
For example, to render 2 sub-columns with 30%/70% width of parent:
```js
const styles = EStyleSheet.create({
Expand Down Expand Up @@ -213,8 +228,46 @@ render() {
```
\[[top](#)\]

### Media queries
Media queries are supported in standard format (thanks for idea to [@grabbou](https://github.com/grabbou),
[#5](https://github.com/vitalets/react-native-extended-stylesheet/issues/5)).
They allows to have different styles for different screens, platform, orienation etc.

Supported values are:

* media type: `ios|android`
* `width`, `min-width`, `max-width`
* `height`, `min-height`, `max-height`
* `orientation` (`landscape|portrait`)
* `aspect-ratio`

You can define media queries on sheet level or style level:
```js
const styles = EStyleSheet.create({
column: {
width: '80%',
},
'@media (min-width: 350) and (max-width: 500)': { // media query on sheet level
column: {
width: '90%',
}
},
header: {
fontSize: 18,
'@media ios': { // media query on style level
color: 'green',
},
'@media android': {
color: 'blue',
},
}
});
```
See full example [here](examples/media-queries).
\[[top](#)\]

### Scaling
You can easily scale your components by setting special `$scale` variable.
You can apply scale to components by setting special `$scale` variable.
```js
const styles = EStyleSheet.create({
$scale: 1.5,
Expand All @@ -225,7 +278,7 @@ const styles = EStyleSheet.create({
}
});
```
This also helps to create reusable components that could be scaled depending on prop.
This helps to create reusable components that could be scaled depending on prop:
```js
class Button extends React.Component {
static propTypes = {
Expand All @@ -251,12 +304,16 @@ let getStyle = function (scale = 1) {
});
}
```
To cache calculated styles please have a look on [caching](#caching) section.
\[[top](#)\]

### Underscored styles
Usual 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](https:/oblador/react-native-vector-icons) and see that `<Icon>` component has `size` and `color` props.
It would be convenient to define style for text and keep icon's size and color in sync.
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](https:/oblador/react-native-vector-icons)
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.
```js
const styles = EStyleSheet.create({
text: {
Expand All @@ -271,7 +328,7 @@ styles = {
text: 0
}
```
But extended stylesheet saves original values under `_text` property:
But extended stylesheet saves calculated values under `_text` property:
```js
styles = {
text: 0,
Expand Down Expand Up @@ -324,22 +381,8 @@ render() {
```
\[[top](#)\]

### OS specific props
If you want different values of the same prop for IOS / Android, just name prop with appropriate suffix:
```js
const styles = EStyleSheet.create({
container: {
marginTopIOS: 10,
marginTopAndroid: 0
}
});
```
The output style will have only one property `marginTop` depending on OS.
\[[top](#)\]

### Value as a function
For the deepest customization you can specify any value as a function that will be executed on EStyleSheet build.
It is practically useful if you need to calculate value depending on some global variable.
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](https://www.npmjs.com/package/color):
```js
import Color from 'color';
Expand All @@ -364,7 +407,8 @@ render() {
\[[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](#scaling) section:
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](#scaling) section:
```js
class Button extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -403,7 +447,8 @@ let getStyle = EStyleSheet.memoize(function (scale = 1) {
});
});
```
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.
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
Expand Down
Binary file removed example/screenshot.png
Binary file not shown.
5 changes: 0 additions & 5 deletions example/theme.js

This file was deleted.

6 changes: 3 additions & 3 deletions example/README.md → examples/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## How to run this example
## How to run examples

1. Create new react-native project

Expand All @@ -17,7 +17,7 @@

```js
import {AppRegistry} from 'react-native';
import App from 'react-native-extended-stylesheet/example/app';
import App from 'react-native-extended-stylesheet/examples/simple/app';
AppRegistry.registerComponent('ExtendedStyleSheetExample', () => App);
```


14 changes: 14 additions & 0 deletions examples/media-queries/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react-native';
import EStyleSheet from '../../src';
import MyComponent from './component';

// calc styles
EStyleSheet.build();

export default class extends React.Component {
render() {
return (
<MyComponent/>
);
}
}
50 changes: 50 additions & 0 deletions examples/media-queries/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, {View, Text} from 'react-native';
import EStyleSheet from '../../src';

export default class extends React.Component {
render() {
return (
<View style={styles.column}>
<Text style={styles.header}>
Width: <Text>{styles._column.width}</Text>,
margin: <Text>{styles._column.marginHorizontal}</Text>
</Text>
</View>
);
}
}

const styles = EStyleSheet.create({
column: {
alignItems: 'center',
borderWidth: 1,
marginTop: '10%',
},
'@media (max-width: 350)': { // media query on sheet level
column: {
width: '70%',
marginHorizontal: '15%',
}
},
'@media (min-width: 350) and (max-width: 500)': { // media query on sheet level
column: {
width: '80%',
marginHorizontal: '10%',
}
},
'@media (min-width: 500)': { // media query on sheet level
column: {
width: '90%',
marginHorizontal: '5%',
}
},
header: {
fontSize: 18,
'@media ios': { // media query on style level
color: 'green',
},
'@media android': { // media query on style level
color: 'blue',
},
}
});
18 changes: 18 additions & 0 deletions examples/readme/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react-native';
import EStyleSheet from '../../src';
import MyComponent from './component';

EStyleSheet.build({
textColor: 'black',
buttonColor: '#679267',
outline: 0,
rem: 18,
});

export default class extends React.Component {
render() {
return (
<MyComponent/>
);
}
}
15 changes: 10 additions & 5 deletions example/component.js → examples/readme/component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {View, Text, TouchableHighlight} from 'react-native';
import EStyleSheet from '../src';
import EStyleSheet from '../../src';

const items = [
'first-child',
Expand All @@ -16,9 +16,13 @@ export default class extends React.Component {
return (
<View style={styles.column}>
<Text style={styles.header}>Extended StyleSheets</Text>
<Text style={styles.label}>Container: width=<Text style={styles.bold}>80%</Text>, margin=<Text style={styles.bold}>10%</Text></Text>
<Text style={styles.label}>
<Text style={styles.bold}>Percent</Text> values:
width=<Text style={styles.bold}>80%</Text>,
margin=<Text style={styles.bold}>10%</Text>
</Text>

<Text style={styles.label}><Text style={styles.bold}>Stripped</Text> rows:</Text>
<Text style={styles.label}>Stripped rows via <Text style={styles.bold}>pseudo-classes</Text></Text>
{items.map((item, index) => {
return (
<View key={index} style={EStyleSheet.child(styles, 'row', index, items.length)}>
Expand All @@ -27,13 +31,14 @@ export default class extends React.Component {
);
})}

<Text style={styles.label}>Button: width=<Text style={styles.bold}>$size</Text>,
<Text style={styles.label}>Circle button via <Text style={styles.bold}>variables{'\n'}</Text>
width=<Text style={styles.bold}>$size</Text>,
height=<Text style={styles.bold}>$size</Text>,
borderRadius=<Text style={styles.bold}>0.5*$size</Text></Text>
<TouchableHighlight style={btnStyles.button} underlayColor={btnStyles._button.$underlayColor}>
<Text style={btnStyles.buttonText}>Like it!</Text>
</TouchableHighlight>
<Text style={styles.label}>Circle button scaled to <Text style={styles.bold}>1.4x</Text></Text>
<Text style={styles.label}>Scaled to <Text style={styles.bold}>1.4x</Text></Text>
<TouchableHighlight style={btnStylesScaled.button} underlayColor={btnStylesScaled._button.$underlayColor}>
<Text style={btnStylesScaled.buttonText}>Like it!</Text>
</TouchableHighlight>
Expand Down
Loading

0 comments on commit 3da89ec

Please sign in to comment.