mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-26 09:14:15 +08:00
[add] StyleSheet API
Initial StyleSheet implementation for Web. Converts style object declarations to "atomic" CSS rules. Close gh-25
This commit is contained in:
@@ -68,7 +68,7 @@ not want to merge into the project.
|
||||
Development commands:
|
||||
|
||||
* `npm run build` – build the library
|
||||
* `npm run dev` – start the dev server and develop against live examples
|
||||
* `npm run examples` – start the dev server and develop against live examples
|
||||
* `npm run lint` – run the linter
|
||||
* `npm run test` – run the linter and unit tests
|
||||
|
||||
|
||||
186
README.md
186
README.md
@@ -3,8 +3,8 @@
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![npm version][npm-image]][npm-url]
|
||||
|
||||
The core [React Native][react-native-url] components adapted and expanded upon
|
||||
for the web, backed by a precomputed CSS library. ~21KB minified and gzipped.
|
||||
[React Native][react-native-url] components and APIs for the Web.
|
||||
~19 KB minified and gzipped.
|
||||
|
||||
* [Slack: reactiflux channel #react-native-web][slack-url]
|
||||
* [Gitter: react-native-web][gitter-url]
|
||||
@@ -12,7 +12,8 @@ for the web, backed by a precomputed CSS library. ~21KB minified and gzipped.
|
||||
## Table of contents
|
||||
|
||||
* [Install](#install)
|
||||
* [Use](#use)
|
||||
* [Example](#example)
|
||||
* [APIs](#APIs)
|
||||
* [Components](#components)
|
||||
* [Styling](#styling)
|
||||
* [Contributing](#contributing)
|
||||
@@ -25,32 +26,107 @@ for the web, backed by a precomputed CSS library. ~21KB minified and gzipped.
|
||||
npm install --save react react-native-web
|
||||
```
|
||||
|
||||
## Use
|
||||
## Example
|
||||
|
||||
React Native for Web exports its components and a reference to the `React`
|
||||
installation. Styles are authored in JavaScript as plain objects.
|
||||
installation. Styles are defined with, and used as JavaScript objects.
|
||||
|
||||
Component:
|
||||
|
||||
```js
|
||||
import React, { View } from 'react-native-web'
|
||||
import React, { Image, StyleSheet, Text, View } from 'react-native-web'
|
||||
|
||||
class MyComponent extends React.Component {
|
||||
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
|
||||
|
||||
const Summary = ({ children }) => (
|
||||
<View style={styles.text}>
|
||||
<Text style={styles.subtitle}>{children}</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.root} />
|
||||
<View style={styles.row}>
|
||||
<Image
|
||||
source={{ uri: 'http://facebook.github.io/react/img/logo_og.png' }}
|
||||
style={styles.image}
|
||||
/>
|
||||
<Title>React Native Web</Title>
|
||||
<Summary>Build high quality web apps using React</Summary>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
borderColor: 'currentcolor'
|
||||
borderWidth: '5px',
|
||||
flexDirection: 'row'
|
||||
height: '5em'
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
margin: 40
|
||||
},
|
||||
image: {
|
||||
height: 40,
|
||||
marginRight: 10,
|
||||
width: 40,
|
||||
},
|
||||
text: {
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
title: {
|
||||
fontSize: '1.25rem',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: '1rem'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Pre-render styles on the server:
|
||||
|
||||
```js
|
||||
// server.js
|
||||
import App from './components/App'
|
||||
import React, { StyleSheet } from 'react-native-web'
|
||||
|
||||
const html = React.renderToString(<App />);
|
||||
const css = StyleSheet.renderToString();
|
||||
|
||||
const Html = () => (
|
||||
<html>
|
||||
<head>
|
||||
<style id="react-stylesheet">{css}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="react-root" dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
```
|
||||
|
||||
Render styles on the client:
|
||||
|
||||
```js
|
||||
// client.js
|
||||
import App from './components/App'
|
||||
import React, { StyleSheet } from 'react-native-web'
|
||||
|
||||
React.render(
|
||||
<App />,
|
||||
document.getElementById('react-root')
|
||||
)
|
||||
|
||||
document.getElementById('stylesheet').textContent = StyleSheet.renderToString()
|
||||
```
|
||||
|
||||
## APIs
|
||||
|
||||
### [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||
|
||||
StyleSheet is a style abstraction that transforms inline styles to CSS on the
|
||||
client or the server. It provides a minimal CSS reset.
|
||||
|
||||
## Components
|
||||
|
||||
### [`Image`](docs/components/Image.md)
|
||||
@@ -88,78 +164,14 @@ The fundamental UI building block using flexbox for layout.
|
||||
|
||||
## Styling
|
||||
|
||||
React Native for Web provides a mechanism to declare all your styles in
|
||||
JavaScript within your components. The `View` component makes it easy to build
|
||||
common layouts with flexbox, such as stacked and nested boxes with margin
|
||||
and padding. See this [guide to flexbox][flexbox-guide-url].
|
||||
React Native for Web relies on styles being defined in JavaScript.
|
||||
|
||||
Authoring `style` is no different to the existing use of inline styles in
|
||||
React, but most inline styles are converted to single-purpose class names. The
|
||||
current implementation includes 300+ precomputed CSS declarations (~4.5KB
|
||||
gzipped) that covers many common property-value pairs. A more sophisticated
|
||||
build-time implementation may produce a slightly larger CSS file for large
|
||||
apps, and fall back to fewer inline styles. Read more about the [styling
|
||||
strategy](docs/style.md).
|
||||
The `View` component makes it easy to build common layouts with flexbox, such
|
||||
as stacked and nested boxes with margin and padding. See this [guide to
|
||||
flexbox][flexbox-guide-url].
|
||||
|
||||
```js
|
||||
import React, { Image, Text, View } from 'react-native-web'
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<Image
|
||||
source={{ uri: 'http://facebook.github.io/react/img/logo_og.png' }}
|
||||
style={styles.image}
|
||||
/>
|
||||
<View style={styles.text}>
|
||||
<Text style={styles.title}>
|
||||
React Native Web
|
||||
</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Build high quality web apps using React
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const styles = {
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
margin: 40
|
||||
},
|
||||
image: {
|
||||
height: 40,
|
||||
marginRight: 10,
|
||||
width: 40,
|
||||
},
|
||||
text: {
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
title: {
|
||||
fontSize: '1.25rem',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: '1rem'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Combine and override style objects:
|
||||
|
||||
```js
|
||||
import baseStyle from './baseStyle'
|
||||
|
||||
const buttonStyle = {
|
||||
...baseStyle,
|
||||
backgroundColor: '#333',
|
||||
color: '#fff'
|
||||
}
|
||||
```
|
||||
Styling components can be achieved with inline styles or the use of
|
||||
[StyleSheet](docs/apis/StyleSheet.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -25,14 +25,6 @@ if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = {
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: [
|
||||
'style-loader',
|
||||
'css-loader?module&localIdentName=[hash:base64:5]',
|
||||
'autoprefixer-loader'
|
||||
].join('!')
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
|
||||
117
docs/apis/StyleSheet.md
Normal file
117
docs/apis/StyleSheet.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# StyleSheet
|
||||
|
||||
React Native for Web will automatically vendor-prefix styles applied to the
|
||||
libraries components. The `StyleSheet` abstraction converts predefined styles
|
||||
to CSS without a compile-time step. Some styles cannot be resolved outside of
|
||||
the render loop and are applied as inline styles.
|
||||
|
||||
The `style`-to-`className` conversion strategy is optimized to minimize the
|
||||
amount of CSS required. Unique declarations are defined using "atomic" CSS – a
|
||||
unique class name for a unique declaration.
|
||||
|
||||
React Native for Web includes a CSS reset to remove unwanted user agent styles
|
||||
from elements and pseudo-elements beyond the reach of React (e.g., `html` and
|
||||
`body`).
|
||||
|
||||
Create a new StyleSheet:
|
||||
|
||||
```
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: 4,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#d6d7da',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
activeTitle: {
|
||||
color: 'red',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Use styles:
|
||||
|
||||
```js
|
||||
<View style={styles.container}>
|
||||
<Text
|
||||
style={{
|
||||
...styles.title,
|
||||
...(this.props.isActive && styles.activeTitle)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
```
|
||||
|
||||
Render styles on the server or in the browser:
|
||||
|
||||
```js
|
||||
StyleSheet.renderToString()
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
**create**(obj: {[key: string]: any})
|
||||
|
||||
**renderToString**()
|
||||
|
||||
## Strategy
|
||||
|
||||
Mapping entire `style` objects to CSS rules can lead to increasingly large CSS
|
||||
files. Each new component adds new rules to the stylesheet.
|
||||
|
||||

|
||||
|
||||
React Native for Web uses an alternative strategy: mapping declarations to
|
||||
declarations.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
<View style={styles.root}>...</View>
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Yields (in development):
|
||||
|
||||
```html
|
||||
<div className="background:transparent display:flex flexGrow:1 justifyContent:center">...</div>
|
||||
```
|
||||
|
||||
And is backed by the following CSS:
|
||||
|
||||
```css
|
||||
.background\:transparent {background:transparent;}
|
||||
.display\:flex {display:flex;}
|
||||
.flexGrow\:1 {flex-grow:1;}
|
||||
.justifyContext\:center {justify-content:center;}
|
||||
```
|
||||
|
||||
In production the class names are obfuscated.
|
||||
|
||||
(CSS libraries like [Atomic CSS](http://acss.io/),
|
||||
[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
|
||||
[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
|
||||
stylesheet growth in a similar way. But they're CSS utility libraries, each with a
|
||||
particular set of classes and features to learn. All of them require developers
|
||||
to manually connect CSS classes for given styles.)
|
||||
|
||||
## Media Queries, pseudo-classes, and pseudo-elements
|
||||
|
||||
Media Queries in JavaScript can be used to modify the render tree and styles.
|
||||
This has the benefit of co-locating breakpoint-specific DOM and style changes.
|
||||
|
||||
Pseudo-classes like `:hover` and `:focus` can be replaced with JavaScript
|
||||
events.
|
||||
|
||||
Pseudo-elements are not supported.
|
||||
123
docs/style.md
123
docs/style.md
@@ -1,123 +0,0 @@
|
||||
# Styling strategy
|
||||
|
||||
Using the `style` attribute would normally produce inline styles. There are
|
||||
several existing approaches to using the `style` attribute, some of which
|
||||
convert inline styles to static CSS:
|
||||
[jsxstyle](https://github.com/petehunt/jsxstyle),
|
||||
[react-free-style](https://github.com/blakeembrey/react-free-style/),
|
||||
[react-inline](https://github.com/martinandert/react-inline),
|
||||
[react-native](https://facebook.github.io/react-native/),
|
||||
[react-style](https://github.com/js-next/react-style),
|
||||
[stilr](https://github.com/kodyl/stilr).
|
||||
|
||||
## Style syntax: native vs proprietary data structure
|
||||
|
||||
React Native for Web diverges from React Native by using plain JS objects for
|
||||
styles:
|
||||
|
||||
```js
|
||||
<Text style={styles.root}>...</Text>
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Most approaches to managing style in React introduce a proprietary data
|
||||
structure, often via an implementation of `Stylesheet.create`.
|
||||
|
||||
```js
|
||||
<Text style={styles.root}>...</Text>
|
||||
|
||||
const styles = Stylesheet.create({
|
||||
root: {
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## JS-to-CSS: conversion strategies
|
||||
|
||||
Mapping entire `style` objects to CSS rules can lead to increasingly large CSS
|
||||
files. Each new component adds new rules to the stylesheet.
|
||||
|
||||

|
||||
|
||||
One strategy for converting styles from JS to CSS is to map style objects to
|
||||
CSS rules. Another strategy is to map declarations to declarations.
|
||||
|
||||
React Native for Web currently includes a proof-of-concept implementation of
|
||||
the latter strategy. This results in smaller CSS files because all applications
|
||||
has fewer unique declarations than total declarations. Creating a new component
|
||||
with no new unique declarations results in no change to the CSS file.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
<Text style={styles.root}>...</Text>
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```html
|
||||
<span className="_abcde _fghij _klmno _pqrst">...</span>
|
||||
```
|
||||
|
||||
And is backed by:
|
||||
|
||||
```css
|
||||
._abcde { background: transparent }
|
||||
._fghij { display: flex }
|
||||
._klmno { flex-grow: 1 }
|
||||
._pqrst { justify-content: center }
|
||||
```
|
||||
|
||||
The current implementation uses a precomputed CSS library of single-declaration
|
||||
rules, with obfuscated selectors. This handles a signficant portion of possible
|
||||
declarations. A build-time implementation would produce more accurate CSS
|
||||
files and fall through to inline styles significantly less often.
|
||||
|
||||
(CSS libraries like [Atomic CSS](http://acss.io/),
|
||||
[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
|
||||
[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
|
||||
stylesheet growth in a similar way. But they're CSS utility libraries, each with a
|
||||
particular set of classes and features to learn. All of them require developers
|
||||
to manually connect CSS classes for given styles.)
|
||||
|
||||
## Dynamic styles: use inline styles
|
||||
|
||||
Some styles cannot be resolved ahead of time and continue to rely on inline
|
||||
styles:
|
||||
|
||||
```js
|
||||
<View style={{ backgroundColor: (Math.random() > 0.5 ? 'red' : 'black') }}>...</Text>
|
||||
```
|
||||
|
||||
## Media Queries, pseudo-classes, and pseudo-elements
|
||||
|
||||
Media Queries could be replaced with `mediaMatch`. This would have the added
|
||||
benefit of co-locating breakpoint-specific DOM and style changes. Perhaps Media
|
||||
Query data could be accessed on `this.content`?
|
||||
|
||||
Pseudo-classes like `:hover` and `:focus` can be handled with JavaScript.
|
||||
|
||||
Pseudo-elements should be avoided in general, but for particular cases like
|
||||
`::placeholder` it might be necessary to reimplement it in the `TextInput`
|
||||
component (see React Native's API).
|
||||
18
package.json
18
package.json
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rm -rf ./dist && webpack --config config/webpack.config.publish.js --sort-assets-by --progress",
|
||||
"dev": "webpack-dev-server --config config/webpack.config.example.js --inline --colors --quiet",
|
||||
"examples": "webpack-dev-server --config config/webpack.config.example.js --inline --hot --colors --quiet",
|
||||
"lint": "eslint config src",
|
||||
"prepublish": "NODE_ENV=publish npm run build",
|
||||
"test": "npm run lint && npm run test:unit",
|
||||
@@ -16,24 +16,22 @@
|
||||
"test:watch": "npm run test:unit -- --no-single-run"
|
||||
},
|
||||
"dependencies": {
|
||||
"inline-style-prefixer": "^0.3.3",
|
||||
"react": ">=0.13.3",
|
||||
"react-swipeable": "^3.0.2",
|
||||
"react-tappable": "^0.6.0",
|
||||
"react-textarea-autosize": "^2.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer-loader": "^3.1.0",
|
||||
"babel-core": "^5.8.23",
|
||||
"babel-eslint": "^4.1.1",
|
||||
"babel-loader": "^5.3.2",
|
||||
"babel-runtime": "^5.8.20",
|
||||
"css-loader": "^0.18.0",
|
||||
"eslint": "^1.3.1",
|
||||
"eslint-config-standard": "^4.3.1",
|
||||
"eslint-config-standard-react": "^1.0.4",
|
||||
"eslint-plugin-react": "^3.3.1",
|
||||
"eslint-plugin-standard": "^1.3.0",
|
||||
"extract-text-webpack-plugin": "^0.8.2",
|
||||
"karma": "^0.13.9",
|
||||
"karma-browserstack-launcher": "^0.1.5",
|
||||
"karma-chrome-launcher": "^0.2.0",
|
||||
@@ -45,7 +43,6 @@
|
||||
"mocha": "^2.3.0",
|
||||
"node-libs-browser": "^0.5.2",
|
||||
"object-assign": "^4.0.1",
|
||||
"style-loader": "^0.12.3",
|
||||
"webpack": "^1.12.1",
|
||||
"webpack-dev-server": "^1.10.1"
|
||||
},
|
||||
@@ -54,5 +51,14 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/necolas/react-native-web.git"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"react"
|
||||
],
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-component",
|
||||
"react-native",
|
||||
"web"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import restyle from './modules/restyle'
|
||||
import stylePropTypes from './modules/stylePropTypes'
|
||||
import StylePropTypes from '../../modules/StylePropTypes'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
|
||||
class CoreComponent extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -13,18 +13,15 @@ class CoreComponent extends React.Component {
|
||||
testID: PropTypes.string
|
||||
}
|
||||
|
||||
static stylePropTypes = stylePropTypes;
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
component: 'div'
|
||||
}
|
||||
|
||||
static stylePropTypes = StylePropTypes;
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
component: Component,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
@@ -32,7 +29,7 @@ class CoreComponent extends React.Component {
|
||||
return (
|
||||
<Component
|
||||
{...other}
|
||||
{...restyle({ className, style })}
|
||||
{...StyleSheet.resolve(other)}
|
||||
data-testid={testID}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
export default function prefixStyles(style) {
|
||||
if (style.hasOwnProperty('flexBasis')) {
|
||||
style = {
|
||||
WebkitFlexBasis: style.flexBasis,
|
||||
msFlexBasis: style.flexBasis,
|
||||
...style
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('flexGrow')) {
|
||||
style = {
|
||||
WebkitBoxFlex: style.flexGrow,
|
||||
WebkitFlexGrow: style.flexGrow,
|
||||
msFlexPositive: style.flexGrow,
|
||||
...style
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('flexShrink')) {
|
||||
style = {
|
||||
WebkitFlexShrink: style.flexShrink,
|
||||
msFlexNegative: style.flexShrink,
|
||||
...style
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: adding `;` to the string value prevents React from automatically
|
||||
// adding a `px` suffix to the unitless value
|
||||
if (style.hasOwnProperty('order')) {
|
||||
style = {
|
||||
WebkitBoxOrdinalGroup: `${parseInt(style.order, 10) + 1};`,
|
||||
WebkitOrder: `${style.order}`,
|
||||
msFlexOrder: `${style.order}`,
|
||||
...style
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('transform')) {
|
||||
style = {
|
||||
WebkitTransform: style.transform,
|
||||
msTransform: style.transform,
|
||||
...style
|
||||
}
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import autoprefix from './autoprefix'
|
||||
import styles from '../../../modules/styles'
|
||||
|
||||
/**
|
||||
* Get the HTML class that corresponds to a style declaration
|
||||
* @param prop {string} prop name
|
||||
* @param style {Object} style
|
||||
* @return {string} class name
|
||||
*/
|
||||
function getSinglePurposeClassName(prop, style) {
|
||||
const className = `${prop}-${style[prop]}`
|
||||
if (style.hasOwnProperty(prop) && styles[className]) {
|
||||
return styles[className]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace inline styles with single purpose classes where possible
|
||||
* @param props {Object} React Element properties
|
||||
* @return {Object}
|
||||
*/
|
||||
export default function stylingStrategy(props) {
|
||||
let className
|
||||
let style = {}
|
||||
|
||||
const classList = [ props.className ]
|
||||
for (const prop in props.style) {
|
||||
const styleClass = getSinglePurposeClassName(prop, props.style)
|
||||
if (styleClass) {
|
||||
classList.push(styleClass)
|
||||
} else {
|
||||
style[prop] = props.style[prop]
|
||||
}
|
||||
}
|
||||
|
||||
className = classList.join(' ')
|
||||
style = autoprefix(style)
|
||||
|
||||
return { className, style }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/* global window */
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import ImageStylePropTypes from './ImageStylePropTypes'
|
||||
import React, { PropTypes } from 'react'
|
||||
@@ -13,7 +14,7 @@ const STATUS_IDLE = 'IDLE'
|
||||
|
||||
const imageStyleKeys = Object.keys(ImageStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
alignSelf: 'flex-start',
|
||||
backgroundColor: 'lightgray',
|
||||
@@ -49,7 +50,7 @@ const styles = {
|
||||
backgroundSize: '100% 100%'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class Image extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -195,10 +196,10 @@ class Image extends React.Component {
|
||||
accessible={accessible}
|
||||
component='div'
|
||||
style={{
|
||||
...(styles.initial),
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
...(backgroundImage && { backgroundImage }),
|
||||
...(styles.resizeMode[resizeMode])
|
||||
...styles.resizeMode[resizeMode]
|
||||
}}
|
||||
testID={testID}
|
||||
>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
import TextStylePropTypes from './TextStylePropTypes'
|
||||
|
||||
const textStyleKeys = Object.keys(TextStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
color: 'inherit',
|
||||
display: 'inline-block',
|
||||
@@ -20,7 +21,7 @@ const styles = {
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class Text extends React.Component {
|
||||
static propTypes = {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInputStylePropTypes from './TextInputStylePropTypes'
|
||||
|
||||
const textInputStyleKeys = Object.keys(TextInputStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
appearance: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
@@ -17,7 +18,7 @@ const styles = {
|
||||
font: 'inherit',
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class TextInput extends React.Component {
|
||||
static propTypes = {
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import Tappable from 'react-tappable'
|
||||
import View from '../View'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
...View.defaultProps.style,
|
||||
cursor: 'pointer',
|
||||
userSelect: undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class Touchable extends React.Component {
|
||||
constructor(props, context) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
import ViewStylePropTypes from './ViewStylePropTypes'
|
||||
|
||||
const viewStyleKeys = Object.keys(ViewStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
// https://github.com/facebook/css-layout#default-values
|
||||
initial: {
|
||||
alignItems: 'stretch',
|
||||
@@ -26,7 +27,7 @@ const styles = {
|
||||
font: 'inherit',
|
||||
textAlign: 'inherit'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class View extends React.Component {
|
||||
static propTypes = {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { Image, Swipeable, Text, TextInput, Touchable, View } from '.'
|
||||
import React, { Image, StyleSheet, Swipeable, Text, TextInput, Touchable, View } from '.'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class Heading extends Component {
|
||||
class Heading extends React.Component {
|
||||
static propTypes = {
|
||||
children: Text.propTypes.children,
|
||||
level: PropTypes.oneOf(['1', '2', '3']),
|
||||
size: PropTypes.oneOf(['xlarge', 'large', 'normal'])
|
||||
children: PropTypes.any,
|
||||
level: PropTypes.string,
|
||||
size: PropTypes.string
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
@@ -27,7 +27,7 @@ class Heading extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const headingStyles = {
|
||||
const headingStyles = StyleSheet.create({
|
||||
size: {
|
||||
xlarge: {
|
||||
fontSize: '2rem',
|
||||
@@ -44,7 +44,7 @@ const headingStyles = {
|
||||
marginTop: '0.5em'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
@@ -205,7 +205,7 @@ class Example extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
maxWidth: '600px',
|
||||
margin: '0 auto'
|
||||
@@ -226,7 +226,7 @@ const styles = {
|
||||
pointerEventsBox: {
|
||||
alignItems: 'center',
|
||||
borderWidth: '1px',
|
||||
flexGrow: '1',
|
||||
flexGrow: 1,
|
||||
height: '100px',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
@@ -236,6 +236,8 @@ const styles = {
|
||||
height: '200px',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
React.render(<Example />, document.getElementById('react-root'))
|
||||
|
||||
document.getElementById('react-stylesheet').textContent = StyleSheet.renderToString()
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="The core React Native components adapted and expanded upon for the web">
|
||||
<style>html { font-family: sans-serif; }</style>
|
||||
<style id="react-stylesheet"></style>
|
||||
<div id="react-root"></div>
|
||||
<script src="/example.js"></script>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
import StyleSheet from './modules/StyleSheet'
|
||||
|
||||
// components
|
||||
import Image from './components/Image'
|
||||
import ListView from './components/ListView'
|
||||
@@ -13,6 +15,9 @@ import View from './components/View'
|
||||
export default React
|
||||
|
||||
export {
|
||||
StyleSheet,
|
||||
|
||||
// components
|
||||
Image,
|
||||
ListView,
|
||||
ScrollView,
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { PropTypes } from 'react'
|
||||
|
||||
const numberOrString = PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string
|
||||
])
|
||||
|
||||
const { string } = PropTypes
|
||||
const { number, string } = PropTypes
|
||||
const numberOrString = PropTypes.oneOfType([ number, string ])
|
||||
|
||||
export default {
|
||||
alignContent: string,
|
||||
@@ -20,21 +16,22 @@ export default {
|
||||
backgroundPosition: string,
|
||||
backgroundRepeat: string,
|
||||
backgroundSize: string,
|
||||
borderColor: numberOrString,
|
||||
borderBottomColor: numberOrString,
|
||||
borderLeftColor: numberOrString,
|
||||
borderRightColor: numberOrString,
|
||||
borderTopColor: numberOrString,
|
||||
border: string,
|
||||
borderColor: string,
|
||||
borderBottomColor: string,
|
||||
borderLeftColor: string,
|
||||
borderRightColor: string,
|
||||
borderTopColor: string,
|
||||
borderRadius: numberOrString,
|
||||
borderTopLeftRadius: numberOrString,
|
||||
borderTopRightRadius: numberOrString,
|
||||
borderBottomLeftRadius: numberOrString,
|
||||
borderBottomRightRadius: numberOrString,
|
||||
borderStyle: numberOrString,
|
||||
borderBottomStyle: numberOrString,
|
||||
borderLeftStyle: numberOrString,
|
||||
borderRightStyle: numberOrString,
|
||||
borderTopStyle: numberOrString,
|
||||
borderStyle: string,
|
||||
borderBottomStyle: string,
|
||||
borderLeftStyle: string,
|
||||
borderRightStyle: string,
|
||||
borderTopStyle: string,
|
||||
borderWidth: numberOrString,
|
||||
borderBottomWidth: numberOrString,
|
||||
borderLeftWidth: numberOrString,
|
||||
@@ -47,6 +44,7 @@ export default {
|
||||
cursor: string,
|
||||
direction: string,
|
||||
display: string,
|
||||
flex: string,
|
||||
flexBasis: string,
|
||||
flexDirection: string,
|
||||
flexGrow: numberOrString,
|
||||
99
src/modules/StyleSheet/Store.js
Normal file
99
src/modules/StyleSheet/Store.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import hyphenate from './hyphenate'
|
||||
import normalizeValue from './normalizeValue'
|
||||
import prefixer from './prefixer'
|
||||
|
||||
export default class Store {
|
||||
constructor(
|
||||
initialState:Object = {},
|
||||
options:Object = { obfuscateClassNames: false }
|
||||
) {
|
||||
this._counter = 0
|
||||
this._classNames = { ...initialState.classNames }
|
||||
this._declarations = { ...initialState.declarations }
|
||||
this._options = options
|
||||
}
|
||||
|
||||
get(property, value) {
|
||||
const normalizedValue = normalizeValue(property, value)
|
||||
const key = this._getDeclarationKey(property, normalizedValue)
|
||||
return this._classNames[key]
|
||||
}
|
||||
|
||||
set(property, value) {
|
||||
if (value != null) {
|
||||
const normalizedValue = normalizeValue(property, value)
|
||||
const values = this._getPropertyValues(property) || []
|
||||
if (values.indexOf(normalizedValue) === -1) {
|
||||
values.push(normalizedValue)
|
||||
this._setClassName(property, normalizedValue)
|
||||
this._setPropertyValues(property, values)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
const obfuscate = this._options.obfuscateClassNames
|
||||
|
||||
// sort the properties to ensure shorthands are first in the cascade
|
||||
const properties = Object.keys(this._declarations).sort()
|
||||
|
||||
// transform the class name to a valid CSS selector
|
||||
const getCssSelector = (property, value) => {
|
||||
let className = this.get(property, value)
|
||||
if (!obfuscate && className) {
|
||||
className = className.replace(/[:?.%\\$#]/g, '\\$&')
|
||||
}
|
||||
return className
|
||||
}
|
||||
|
||||
// transform the declarations into CSS rules with vendor-prefixes
|
||||
const buildCSSRules = (property, values) => {
|
||||
return values.reduce((cssRules, value) => {
|
||||
const declarations = prefixer.prefix({ [property]: value })
|
||||
const cssDeclarations = Object.keys(declarations).reduce((str, prop) => {
|
||||
str += `${hyphenate(prop)}:${value};`
|
||||
return str
|
||||
}, '')
|
||||
const selector = getCssSelector(property, value)
|
||||
|
||||
cssRules += `\n.${selector}{${cssDeclarations}}`
|
||||
|
||||
return cssRules
|
||||
}, '')
|
||||
}
|
||||
|
||||
const css = properties.reduce((css, property) => {
|
||||
const values = this._declarations[property]
|
||||
css += buildCSSRules(property, values)
|
||||
return css
|
||||
}, '')
|
||||
|
||||
return (`/* ${this._counter} unique declarations */${css}`)
|
||||
}
|
||||
|
||||
_getDeclarationKey(property, value) {
|
||||
return `${property}:${value}`
|
||||
}
|
||||
|
||||
_getPropertyValues(property) {
|
||||
return this._declarations[property]
|
||||
}
|
||||
|
||||
_setPropertyValues(property, values) {
|
||||
this._declarations[property] = values.map(value => normalizeValue(property, value))
|
||||
}
|
||||
|
||||
_setClassName(property, value) {
|
||||
const key = this._getDeclarationKey(property, value)
|
||||
const exists = !!this._classNames[key]
|
||||
if (!exists) {
|
||||
this._counter += 1
|
||||
if (this._options.obfuscateClassNames) {
|
||||
this._classNames[key] = `_rn_${this._counter}`
|
||||
} else {
|
||||
const val = `${value}`.replace(/\s/g, '-')
|
||||
this._classNames[key] = `${property}:${val}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/modules/StyleSheet/__tests__/getStyleObjects-test.js
Normal file
33
src/modules/StyleSheet/__tests__/getStyleObjects-test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import getStyleObjects from '../getStyleObjects'
|
||||
|
||||
const fixture = {
|
||||
rule: {
|
||||
margin: 0,
|
||||
padding: 0
|
||||
},
|
||||
nested: {
|
||||
auto: {
|
||||
backgroundSize: 'auto'
|
||||
},
|
||||
contain: {
|
||||
backgroundSize: 'contain'
|
||||
}
|
||||
},
|
||||
ignored: {
|
||||
pading: 0
|
||||
}
|
||||
}
|
||||
|
||||
suite('modules/StyleSheet/getStyleObjects', () => {
|
||||
test('returns only style objects', () => {
|
||||
const actual = getStyleObjects(fixture)
|
||||
assert.deepEqual(actual, [
|
||||
{ margin: 0, padding: 0 },
|
||||
{ backgroundSize: 'auto' },
|
||||
{ backgroundSize: 'contain' }
|
||||
])
|
||||
})
|
||||
})
|
||||
13
src/modules/StyleSheet/__tests__/hyphenate-test.js
Normal file
13
src/modules/StyleSheet/__tests__/hyphenate-test.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import hyphenate from '../hyphenate'
|
||||
|
||||
suite('modules/StyleSheet/hyphenate', () => {
|
||||
test('style property', () => {
|
||||
assert.equal(hyphenate('alignItems'), 'align-items')
|
||||
})
|
||||
test('vendor prefixed style property', () => {
|
||||
assert.equal(hyphenate('WebkitAppearance'), '-webkit-appearance')
|
||||
})
|
||||
})
|
||||
34
src/modules/StyleSheet/__tests__/index-test.js
Normal file
34
src/modules/StyleSheet/__tests__/index-test.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import { resetCSS, predefinedCSS } from '../predefs'
|
||||
import assert from 'assert'
|
||||
import StyleSheet from '..'
|
||||
|
||||
const styles = { root: { border: 0 } }
|
||||
|
||||
suite('modules/StyleSheet', () => {
|
||||
setup(() => {
|
||||
StyleSheet.destroy()
|
||||
})
|
||||
|
||||
test('create', () => {
|
||||
assert.equal(StyleSheet.create(styles), styles)
|
||||
})
|
||||
|
||||
test('renderToString', () => {
|
||||
StyleSheet.create(styles)
|
||||
assert.equal(
|
||||
StyleSheet.renderToString(),
|
||||
`${resetCSS}\n${predefinedCSS}\n` +
|
||||
`/* 1 unique declarations */\n` +
|
||||
`.border\\:0px{border:0px;}`
|
||||
)
|
||||
})
|
||||
|
||||
test('resolve', () => {
|
||||
const props = { className: 'className', style: styles.root }
|
||||
const expected = { className: 'className border:0px', style: {} }
|
||||
StyleSheet.create(styles)
|
||||
assert.deepEqual(StyleSheet.resolve(props), expected)
|
||||
})
|
||||
})
|
||||
15
src/modules/StyleSheet/__tests__/isObject-test.js
Normal file
15
src/modules/StyleSheet/__tests__/isObject-test.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import isObject from '../isObject'
|
||||
|
||||
suite('modules/StyleSheet/isObject', () => {
|
||||
test('returns "true" for objects', () => {
|
||||
assert.ok(isObject({}) === true)
|
||||
})
|
||||
test('returns "false" for non-objects', () => {
|
||||
assert.ok(isObject(function () {}) === false)
|
||||
assert.ok(isObject([]) === false)
|
||||
assert.ok(isObject('') === false)
|
||||
})
|
||||
})
|
||||
16
src/modules/StyleSheet/__tests__/isStyleObject-test.js
Normal file
16
src/modules/StyleSheet/__tests__/isStyleObject-test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import isStyleObject from '../isStyleObject'
|
||||
|
||||
const style = { margin: 0 }
|
||||
const notStyle = { root: style }
|
||||
|
||||
suite('modules/StyleSheet/isStyleObject', () => {
|
||||
test('returns "true" for style objects', () => {
|
||||
assert.ok(isStyleObject(style) === true)
|
||||
})
|
||||
test('returns "false" for non-style objects', () => {
|
||||
assert.ok(isStyleObject(notStyle) === false)
|
||||
})
|
||||
})
|
||||
13
src/modules/StyleSheet/__tests__/normalizeValue-test.js
Normal file
13
src/modules/StyleSheet/__tests__/normalizeValue-test.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import normalizeValue from '../normalizeValue'
|
||||
|
||||
suite('modules/StyleSheet/normalizeValue', () => {
|
||||
test('normalizes property values requiring units', () => {
|
||||
assert.deepEqual(normalizeValue('margin', 0), '0px')
|
||||
})
|
||||
test('ignores unitless property values', () => {
|
||||
assert.deepEqual(normalizeValue('flexGrow', 1), 1)
|
||||
})
|
||||
})
|
||||
127
src/modules/StyleSheet/__tests__/store-test.js
Normal file
127
src/modules/StyleSheet/__tests__/store-test.js
Normal file
@@ -0,0 +1,127 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import Store from '../Store'
|
||||
|
||||
suite('modules/StyleSheet/Store', () => {
|
||||
suite('the constructor', () => {
|
||||
test('initialState', () => {
|
||||
const initialState = { classNames: { 'alignItems:center': '__classname__' } }
|
||||
const store = new Store(initialState)
|
||||
assert.deepEqual(store._classNames['alignItems:center'], '__classname__')
|
||||
})
|
||||
})
|
||||
|
||||
suite('#get', () => {
|
||||
test('returns a declaration-specific className', () => {
|
||||
const initialState = {
|
||||
classNames: {
|
||||
'alignItems:center': '__expected__',
|
||||
'alignItems:flex-start': '__error__'
|
||||
}
|
||||
}
|
||||
const store = new Store(initialState)
|
||||
assert.deepEqual(store.get('alignItems', 'center'), '__expected__')
|
||||
})
|
||||
})
|
||||
|
||||
suite('#set', () => {
|
||||
test('stores declarations', () => {
|
||||
const store = new Store()
|
||||
store.set('alignItems', 'center')
|
||||
store.set('flexGrow', 0)
|
||||
store.set('flexGrow', 1)
|
||||
store.set('flexGrow', 2)
|
||||
assert.deepEqual(store._declarations, {
|
||||
alignItems: [ 'center' ],
|
||||
flexGrow: [ 0, 1, 2 ]
|
||||
})
|
||||
})
|
||||
|
||||
test('human-readable classNames', () => {
|
||||
const store = new Store()
|
||||
store.set('alignItems', 'center')
|
||||
store.set('flexGrow', 0)
|
||||
store.set('flexGrow', 1)
|
||||
store.set('flexGrow', 2)
|
||||
assert.deepEqual(store._classNames, {
|
||||
'alignItems:center': 'alignItems:center',
|
||||
'flexGrow:0': 'flexGrow:0',
|
||||
'flexGrow:1': 'flexGrow:1',
|
||||
'flexGrow:2': 'flexGrow:2'
|
||||
})
|
||||
})
|
||||
|
||||
test('obfuscated classNames', () => {
|
||||
const store = new Store({}, { obfuscateClassNames: true })
|
||||
store.set('alignItems', 'center')
|
||||
store.set('flexGrow', 0)
|
||||
store.set('flexGrow', 1)
|
||||
store.set('flexGrow', 2)
|
||||
assert.deepEqual(store._classNames, {
|
||||
'alignItems:center': '_rn_1',
|
||||
'flexGrow:0': '_rn_2',
|
||||
'flexGrow:1': '_rn_3',
|
||||
'flexGrow:2': '_rn_4'
|
||||
})
|
||||
})
|
||||
|
||||
test('value normalization', () => {
|
||||
const store = new Store()
|
||||
store.set('flexGrow', 0)
|
||||
store.set('margin', 0)
|
||||
assert.deepEqual(store._declarations, {
|
||||
flexGrow: [ 0 ],
|
||||
margin: [ '0px' ]
|
||||
})
|
||||
assert.deepEqual(store._classNames, {
|
||||
'flexGrow:0': 'flexGrow:0',
|
||||
'margin:0px': 'margin:0px'
|
||||
})
|
||||
})
|
||||
|
||||
test('replaces space characters', () => {
|
||||
const store = new Store()
|
||||
store.set('margin', '0 auto')
|
||||
assert.deepEqual(store.get('margin', '0 auto'), 'margin:0-auto')
|
||||
})
|
||||
})
|
||||
|
||||
suite('#toString', () => {
|
||||
test('human-readable style sheet', () => {
|
||||
const store = new Store()
|
||||
store.set('alignItems', 'center')
|
||||
store.set('marginBottom', 0)
|
||||
store.set('margin', 1)
|
||||
store.set('margin', 2)
|
||||
store.set('margin', 3)
|
||||
|
||||
const expected = '/* 5 unique declarations */\n' +
|
||||
'.alignItems\\:center{align-items:center;}\n' +
|
||||
'.margin\\:1px{margin:1px;}\n' +
|
||||
'.margin\\:2px{margin:2px;}\n' +
|
||||
'.margin\\:3px{margin:3px;}\n' +
|
||||
'.marginBottom\\:0px{margin-bottom:0px;}'
|
||||
|
||||
assert.equal(store.toString(), expected)
|
||||
})
|
||||
|
||||
test('obfuscated style sheet', () => {
|
||||
const store = new Store({}, { obfuscateClassNames: true })
|
||||
store.set('alignItems', 'center')
|
||||
store.set('marginBottom', 0)
|
||||
store.set('margin', 1)
|
||||
store.set('margin', 2)
|
||||
store.set('margin', 3)
|
||||
|
||||
const expected = '/* 5 unique declarations */\n' +
|
||||
'._rn_1{align-items:center;}\n' +
|
||||
'._rn_3{margin:1px;}\n' +
|
||||
'._rn_4{margin:2px;}\n' +
|
||||
'._rn_5{margin:3px;}\n' +
|
||||
'._rn_2{margin-bottom:0px;}'
|
||||
|
||||
assert.equal(store.toString(), expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
22
src/modules/StyleSheet/getStyleObjects.js
Normal file
22
src/modules/StyleSheet/getStyleObjects.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import isObject from './isObject'
|
||||
import isStyleObject from './isStyleObject'
|
||||
|
||||
/**
|
||||
* Recursively check for objects that are style rules.
|
||||
*/
|
||||
const getStyleObjects = (styles: Object): Array => {
|
||||
const keys = Object.keys(styles)
|
||||
return keys.reduce((rules, key) => {
|
||||
const possibleRule = styles[key]
|
||||
if (isObject(possibleRule)) {
|
||||
if (isStyleObject(possibleRule)) {
|
||||
rules.push(possibleRule)
|
||||
} else {
|
||||
rules = rules.concat(getStyleObjects(possibleRule))
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}, [])
|
||||
}
|
||||
|
||||
export default getStyleObjects
|
||||
1
src/modules/StyleSheet/hyphenate.js
Normal file
1
src/modules/StyleSheet/hyphenate.js
Normal file
@@ -0,0 +1 @@
|
||||
export default (string) => string.replace(/([A-Z])/g, '-$1').toLowerCase()
|
||||
75
src/modules/StyleSheet/index.js
Normal file
75
src/modules/StyleSheet/index.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { resetCSS, predefinedCSS, predefinedClassNames } from './predefs'
|
||||
import getStyleObjects from './getStyleObjects'
|
||||
import prefixer from './prefixer'
|
||||
import Store from './Store'
|
||||
|
||||
/**
|
||||
* Initialize the store with pointer-event styles mapping to our custom pointer
|
||||
* event classes
|
||||
*/
|
||||
const initialState = { classNames: predefinedClassNames }
|
||||
const options = { obfuscateClassNames: process.env.NODE_ENV === 'production' }
|
||||
const createStore = () => new Store(initialState, options)
|
||||
let store = createStore()
|
||||
|
||||
/**
|
||||
* Process all unique declarations
|
||||
*/
|
||||
const create = (styles: Object): Object => {
|
||||
const rules = getStyleObjects(styles)
|
||||
rules.forEach((rule) => {
|
||||
Object.keys(rule).forEach(property => {
|
||||
const value = rule[property]
|
||||
// add each declaration to the store
|
||||
store.set(property, value)
|
||||
})
|
||||
})
|
||||
return styles
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy existing styles
|
||||
*/
|
||||
const destroy = () => {
|
||||
store = createStore()
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the styles as a CSS style sheet
|
||||
*/
|
||||
const renderToString = () => {
|
||||
const css = store.toString()
|
||||
return `${resetCSS}\n${predefinedCSS}\n${css}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts React props and converts inline styles to single purpose classes
|
||||
* where possible.
|
||||
*/
|
||||
const resolve = ({ className = '', style = {} }) => {
|
||||
let _className
|
||||
let _style = {}
|
||||
|
||||
const classList = [ className ]
|
||||
for (const prop in style) {
|
||||
let styleClass = store.get(prop, style[prop])
|
||||
|
||||
if (styleClass) {
|
||||
classList.push(styleClass)
|
||||
} else {
|
||||
_style[prop] = style[prop]
|
||||
}
|
||||
}
|
||||
|
||||
_className = classList.join(' ')
|
||||
_style = prefixer.prefix(_style)
|
||||
|
||||
return { className: _className, style: _style }
|
||||
}
|
||||
|
||||
export default {
|
||||
create,
|
||||
destroy,
|
||||
renderToString,
|
||||
resolve
|
||||
}
|
||||
5
src/modules/StyleSheet/isObject.js
Normal file
5
src/modules/StyleSheet/isObject.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const isObject = (obj) => {
|
||||
return Object.prototype.toString.call(obj) === '[object Object]'
|
||||
}
|
||||
|
||||
export default isObject
|
||||
9
src/modules/StyleSheet/isStyleObject.js
Normal file
9
src/modules/StyleSheet/isStyleObject.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { pickProps } from '../filterObjectProps'
|
||||
import StylePropTypes from '../StylePropTypes'
|
||||
|
||||
const isStyleObject = (obj) => {
|
||||
const declarations = pickProps(obj, Object.keys(StylePropTypes))
|
||||
return Object.keys(declarations).length > 0
|
||||
}
|
||||
|
||||
export default isStyleObject
|
||||
33
src/modules/StyleSheet/normalizeValue.js
Normal file
33
src/modules/StyleSheet/normalizeValue.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const unitlessNumbers = {
|
||||
boxFlex: true,
|
||||
boxFlexGroup: true,
|
||||
columnCount: true,
|
||||
flex: true,
|
||||
flexGrow: true,
|
||||
flexPositive: true,
|
||||
flexShrink: true,
|
||||
flexNegative: true,
|
||||
fontWeight: true,
|
||||
lineClamp: true,
|
||||
lineHeight: true,
|
||||
opacity: true,
|
||||
order: true,
|
||||
orphans: true,
|
||||
widows: true,
|
||||
zIndex: true,
|
||||
zoom: true,
|
||||
// SVG-related
|
||||
fillOpacity: true,
|
||||
strokeDashoffset: true,
|
||||
strokeOpacity: true,
|
||||
strokeWidth: true
|
||||
}
|
||||
|
||||
const normalizeValues = (property, value) => {
|
||||
if (!unitlessNumbers[property] && typeof value === 'number') {
|
||||
value = `${value}px`
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export default normalizeValues
|
||||
28
src/modules/StyleSheet/predefs.js
Normal file
28
src/modules/StyleSheet/predefs.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Reset unwanted styles beyond the control of React inline styles
|
||||
*/
|
||||
export const resetCSS =
|
||||
`/* React Native Web */
|
||||
html {font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
|
||||
body {margin:0}
|
||||
button::-moz-focus-inner, input::-moz-focus-inner {border:0;padding:0}
|
||||
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {-webkit-appearance:none}`
|
||||
|
||||
/**
|
||||
* Custom pointer event styles
|
||||
*/
|
||||
export const predefinedCSS =
|
||||
`/* pointer-events */
|
||||
._rn_pe-a {pointer-events:auto}
|
||||
._rn_pe-bn {pointer-events:none}
|
||||
._rn_pe-bn * {pointer-events:auto}
|
||||
._rn_pe-bo {pointer-events:auto}
|
||||
._rn_pe-bo * {pointer-events:none}
|
||||
._rn_pe-n {pointer-events:none}`
|
||||
|
||||
export const predefinedClassNames = {
|
||||
'pointerEvents:auto': '_rn_pe-a',
|
||||
'pointerEvents:box-none': '_rn_pe-bn',
|
||||
'pointerEvents:box-only': '_rn_pe-bo',
|
||||
'pointerEvents:none': '_rn_pe-n'
|
||||
}
|
||||
3
src/modules/StyleSheet/prefixer.js
Normal file
3
src/modules/StyleSheet/prefixer.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Prefixer from 'inline-style-prefixer'
|
||||
const prefixer = new Prefixer()
|
||||
export default prefixer
|
||||
@@ -1,2 +0,0 @@
|
||||
import styles from './styles.css'
|
||||
export default styles
|
||||
@@ -1,688 +0,0 @@
|
||||
/* align-content */
|
||||
|
||||
.alignContent-center { align-content: center; }
|
||||
.alignContent-flex-end { align-content: flex-end; }
|
||||
.alignContent-flex-start { align-content: flex-start; }
|
||||
.alignContent-stretch { align-content: stretch; }
|
||||
.alignContent-space-around { align-content: space-around; }
|
||||
.alignContent-space-between { align-content: space-between; }
|
||||
|
||||
/* align-items */
|
||||
|
||||
.alignItems-center { align-items: center; }
|
||||
.alignItems-flex-end { align-items: flex-end; }
|
||||
.alignItems-flex-start { align-items: flex-start; }
|
||||
.alignItems-stretch { align-items: stretch; }
|
||||
.alignItems-space-around { align-items: space-around; }
|
||||
.alignItems-space-between { align-items: space-between; }
|
||||
|
||||
/* align-self */
|
||||
|
||||
.alignSelf-auto { align-self: auto; }
|
||||
.alignSelf-baseline { align-self: baseline; }
|
||||
.alignSelf-center { align-self: center; }
|
||||
.alignSelf-flex-end { align-self: flex-end; }
|
||||
.alignSelf-flex-start { align-self: flex-start; }
|
||||
.alignSelf-stretch { align-self: stretch; }
|
||||
|
||||
/* appearance */
|
||||
|
||||
.appearance-none { appearance: none; }
|
||||
|
||||
/* background-attachment */
|
||||
|
||||
.backgroundAttachment-fixed { background-attachment: fixed; }
|
||||
.backgroundAttachment-inherit { background-attachment: inherit; }
|
||||
.backgroundAttachment-local { background-attachment: local; }
|
||||
.backgroundAttachment-scroll { background-attachment: scroll; }
|
||||
|
||||
/* background-clip */
|
||||
|
||||
.backgroundClip-border-box { background-clip: border-box; }
|
||||
.backgroundClip-content-box { background-clip: content-box; }
|
||||
.backgroundClip-inherit { background-clip: inherit; }
|
||||
.backgroundClip-padding-box { background-clip: padding-box; }
|
||||
|
||||
/* background-color */
|
||||
|
||||
.backgroundColor-\#000,
|
||||
.backgroundColor-black { background-color: black; }
|
||||
.backgroundColor-\#fff,
|
||||
.backgroundColor-white { background-color: white; }
|
||||
.backgroundColor-currentcolor,
|
||||
.backgroundColor-currentColor { background-color: currentcolor; }
|
||||
.backgroundColor-inherit { background-color: inherit; }
|
||||
.backgroundColor-transparent { background-color: transparent; }
|
||||
|
||||
/* background-image */
|
||||
|
||||
.backgroundImage { background-image: none; }
|
||||
|
||||
/* background-origin */
|
||||
|
||||
.backgroundOrigin-border-box { background-clip: border-box; }
|
||||
.backgroundOrigin-content-box { background-clip: content-box; }
|
||||
.backgroundOrigin-inherit { background-clip: inherit; }
|
||||
.backgroundOrigin-padding-box { background-clip: padding-box; }
|
||||
|
||||
/* background-position */
|
||||
|
||||
.backgroundPosition-bottom { background-position: bottom; }
|
||||
.backgroundPosition-center { background-position: center; }
|
||||
.backgroundPosition-left { background-position: left; }
|
||||
.backgroundPosition-right { background-position: right; }
|
||||
.backgroundPosition-top { background-position: top; }
|
||||
|
||||
/* background-repeat */
|
||||
|
||||
.backgroundRepeat-inherit { background-repeat: inherit; }
|
||||
.backgroundRepeat-no-repeat { background-repeat: no-repeat; }
|
||||
.backgroundRepeat-repeat { background-repeat: repeat; }
|
||||
.backgroundRepeat-repeat-x { background-repeat: repeat-x; }
|
||||
.backgroundRepeat-repeat-y { background-repeat: repeat-y; }
|
||||
.backgroundRepeat-round { background-repeat: round; }
|
||||
.backgroundRepeat-space { background-repeat: space; }
|
||||
|
||||
/* background-size */
|
||||
|
||||
.backgroundSize-auto { background-size: auto; }
|
||||
.backgroundSize-contain { background-size: contain; }
|
||||
.backgroundSize-cover { background-size: cover; }
|
||||
.backgroundSize-inherit { background-size: inherit; }
|
||||
|
||||
/* border-color */
|
||||
|
||||
.borderColor-\#fff,
|
||||
.borderColor-white { border-color: white; }
|
||||
.borderColor-currentcolor { border-color: currentcolor; }
|
||||
.borderColor-inherit { border-color: inherit; }
|
||||
.borderColor-transparent { border-color: transparent; }
|
||||
|
||||
/* border-bottom-color */
|
||||
|
||||
.borderBottomColor-\#fff,
|
||||
.borderBottomColor-white { border-bottom-color: white; }
|
||||
.borderBottomColor-currentcolor { border-bottom-color: currentcolor; }
|
||||
.borderBottomColor-inherit { border-bottom-color: inherit; }
|
||||
.borderBottomColor-transparent { border-bottom-color: transparent; }
|
||||
|
||||
/* border-left-color */
|
||||
|
||||
.borderLeftColor-\#fff,
|
||||
.borderLeftColor-white { border-left-color: white; }
|
||||
.borderLeftColor-currentcolor { border-left-color: currentcolor; }
|
||||
.borderLeftColor-inherit { border-left-color: inherit; }
|
||||
.borderLeftColor-transparent { border-left-color: transparent; }
|
||||
|
||||
/* border-right-color */
|
||||
|
||||
.borderRightColor-\#fff,
|
||||
.borderRightColor-white { border-right-color: white; }
|
||||
.borderRightColor-currentcolor { border-right-color: currentcolor; }
|
||||
.borderRightColor-inherit { border-right-color: inherit; }
|
||||
.borderRightColor-transparent { border-right-color: transparent; }
|
||||
|
||||
/* border-top-color */
|
||||
|
||||
.borderTopColor-\#fff,
|
||||
.borderTopColor-white { border-top-color: white; }
|
||||
.borderTopColor-currentcolor { border-top-color: currentcolor; }
|
||||
.borderTopColor-inherit { border-top-color: inherit; }
|
||||
.borderTopColor-transparent { border-top-color: transparent; }
|
||||
|
||||
/* border-style */
|
||||
|
||||
.borderStyle-dashed { border-style: dashed; }
|
||||
.borderStyle-dotted { border-style: dotted; }
|
||||
.borderStyle-inherit { border-style: inherit; }
|
||||
.borderStyle-none { border-style: none; }
|
||||
.borderStyle-solid { border-style: solid; }
|
||||
|
||||
/* border-bottom-style */
|
||||
|
||||
.borderBottomStyle-dashed { border-bottom-style: dashed; }
|
||||
.borderBottomStyle-dotted { border-bottom-style: dotted; }
|
||||
.borderBottomStyle-inherit { border-bottom-style: inherit; }
|
||||
.borderBottomStyle-none { border-bottom-style: none; }
|
||||
.borderBottomStyle-solid { border-bottom-style: solid; }
|
||||
|
||||
/* border-left-style */
|
||||
|
||||
.borderLeftStyle-dashed { border-left-style: dashed; }
|
||||
.borderLeftStyle-dotted { border-left-style: dotted; }
|
||||
.borderLeftStyle-inherit { border-left-style: inherit; }
|
||||
.borderLeftStyle-none { border-left-style: none; }
|
||||
.borderLeftStyle-solid { border-left-style: solid; }
|
||||
|
||||
/* border-right-style */
|
||||
|
||||
.borderRightStyle-dashed { border-right-style: dashed; }
|
||||
.borderRightStyle-dotted { border-right-style: dotted; }
|
||||
.borderRightStyle-inherit { border-right-style: inherit; }
|
||||
.borderRightStyle-none { border-right-style: none; }
|
||||
.borderRightStyle-solid { border-right-style: solid; }
|
||||
|
||||
/* border-top-style */
|
||||
|
||||
.borderTopStyle-dashed { border-top-style: dashed; }
|
||||
.borderTopStyle-dotted { border-top-style: dotted; }
|
||||
.borderTopStyle-inherit { border-top-style: inherit; }
|
||||
.borderTopStyle-none { border-top-style: none; }
|
||||
.borderTopStyle-solid { border-top-style: solid; }
|
||||
|
||||
/* border-width */
|
||||
|
||||
.borderWidth-0 { border-width: 0; }
|
||||
.borderWidth-1px { border-width: 1px; }
|
||||
.borderWidth-2px { border-width: 2px; }
|
||||
.borderWidth-3px { border-width: 3px; }
|
||||
.borderWidth-4px { border-width: 4px; }
|
||||
.borderWidth-5px { border-width: 5px; }
|
||||
|
||||
/* border-bottom-width */
|
||||
|
||||
.borderBottomWidth-0 { border-bottom-width: 0; }
|
||||
.borderBottomWidth-1px { border-bottom-width: 1px; }
|
||||
.borderBottomWidth-2px { border-bottom-width: 2px; }
|
||||
.borderBottomWidth-3px { border-bottom-width: 3px; }
|
||||
.borderBottomWidth-4px { border-bottom-width: 4px; }
|
||||
.borderBottomWidth-5px { border-bottom-width: 5px; }
|
||||
|
||||
/* border-left-width */
|
||||
|
||||
.borderLeftWidth-0 { border-left-width: 0; }
|
||||
.borderLeftWidth-1px { border-left-width: 1px; }
|
||||
.borderLeftWidth-2px { border-left-width: 2px; }
|
||||
.borderLeftWidth-3px { border-left-width: 3px; }
|
||||
.borderLeftWidth-4px { border-left-width: 4px; }
|
||||
.borderLeftWidth-5px { border-left-width: 5px; }
|
||||
|
||||
/* border-right-width */
|
||||
|
||||
.borderRightWidth-0 { border-right-width: 0; }
|
||||
.borderRightWidth-1px { border-right-width: 1px; }
|
||||
.borderRightWidth-2px { border-right-width: 2px; }
|
||||
.borderRightWidth-3px { border-right-width: 3px; }
|
||||
.borderRightWidth-4px { border-right-width: 4px; }
|
||||
.borderRightWidth-5px { border-right-width: 5px; }
|
||||
|
||||
/* border-top-width */
|
||||
|
||||
.borderTopWidth-0 { border-top-width: 0; }
|
||||
.borderTopWidth-1px { border-top-width: 1px; }
|
||||
.borderTopWidth-2px { border-top-width: 2px; }
|
||||
.borderTopWidth-3px { border-top-width: 3px; }
|
||||
.borderTopWidth-4px { border-top-width: 4px; }
|
||||
.borderTopWidth-5px { border-top-width: 5px; }
|
||||
|
||||
/* bottom */
|
||||
|
||||
.bottom-0 { bottom: 0; }
|
||||
.bottom-50% { bottom: 50%; }
|
||||
.bottom-100% { bottom: 100%; }
|
||||
|
||||
/* box-sizing */
|
||||
|
||||
.boxSizing-border-box { box-sizing: border-box; }
|
||||
.boxSizing-content-box { box-sizing: content-box; }
|
||||
.boxSizing-inherit { box-sizing: inherit; }
|
||||
.boxSizing-padding-box { box-sizing: padding-box; }
|
||||
|
||||
/* clear */
|
||||
|
||||
.clear-both { clear: both; }
|
||||
.clear-inherit { clear: inherit; }
|
||||
.clear-left { clear: left; }
|
||||
.clear-none { clear: none; }
|
||||
.clear-right { clear: right; }
|
||||
|
||||
/* color */
|
||||
|
||||
.color-#000,
|
||||
.color-black { color: black; }
|
||||
.color-\#fff,
|
||||
.color-white { color: white; }
|
||||
.color-inherit { color: inherit; }
|
||||
.color-transparent { color: transparent; }
|
||||
|
||||
/* cursor */
|
||||
|
||||
.cursor-default { cursor: default; }
|
||||
.cursor-pointer { cursor: pointer; }
|
||||
|
||||
/* direction */
|
||||
|
||||
.direction-inherit { direction: inherit; }
|
||||
.direction-ltr { direction: ltr; }
|
||||
.direction-rtl { direction: rtl; }
|
||||
|
||||
/* display */
|
||||
|
||||
.display-block { display: block; }
|
||||
.display-contents { display: contents; }
|
||||
.display-flex { display: flex; }
|
||||
.display-grid { display: grid; }
|
||||
.display-inherit { display: inherit; }
|
||||
.display-initial { display: initial; }
|
||||
.display-inline { display: inline; }
|
||||
.display-inline-block { display: inline-block; }
|
||||
.display-inline-flex { display: inline-flex; }
|
||||
.display-inline-grid { display: inline-grid; }
|
||||
.display-inline-table { display: inline-table; }
|
||||
.display-list-item { display: list-item; }
|
||||
.display-none { display: none; }
|
||||
.display-table { display: table; }
|
||||
.display-table-cell { display: table-cell; }
|
||||
.display-table-column { display: table-column; }
|
||||
.display-table-column-group { display: table-column-group; }
|
||||
.display-table-footer-group { display: table-footer-group; }
|
||||
.display-table-header-group { display: table-header-group; }
|
||||
.display-table-row { display: table-row; }
|
||||
.display-table-row-group { display: table-row-group; }
|
||||
.display-unset { display: unset; }
|
||||
|
||||
/* flex-basis */
|
||||
|
||||
.flexBasis-0 { flex-basis: 0%; }
|
||||
.flexBasis-auto { flex-basis: auto; }
|
||||
|
||||
/* flex-direction */
|
||||
|
||||
.flexDirection-column { flex-direction: column; }
|
||||
.flexDirection-column-reverse { flex-direction: column-reverse; }
|
||||
.flexDirection-row { flex-direction: row; }
|
||||
.flexDirection-row-reverse { flex-direction: row-reverse; }
|
||||
|
||||
/* flex-grow */
|
||||
|
||||
.flexGrow-0 { flex-grow: 0; }
|
||||
.flexGrow-1 { flex-grow: 1; }
|
||||
.flexGrow-2 { flex-grow: 2; }
|
||||
.flexGrow-3 { flex-grow: 3; }
|
||||
.flexGrow-4 { flex-grow: 4; }
|
||||
.flexGrow-5 { flex-grow: 5; }
|
||||
.flexGrow-6 { flex-grow: 6; }
|
||||
.flexGrow-7 { flex-grow: 7; }
|
||||
.flexGrow-8 { flex-grow: 8; }
|
||||
.flexGrow-9 { flex-grow: 9; }
|
||||
.flexGrow-10 { flex-grow: 10; }
|
||||
.flexGrow-11 { flex-grow: 11; }
|
||||
|
||||
/* flex-shrink */
|
||||
|
||||
.flexShrink-0 { flex-shrink: 0; }
|
||||
.flexShrink-1 { flex-shrink: 1; }
|
||||
.flexShrink-2 { flex-shrink: 2; }
|
||||
.flexShrink-3 { flex-shrink: 3; }
|
||||
.flexShrink-4 { flex-shrink: 4; }
|
||||
.flexShrink-5 { flex-shrink: 5; }
|
||||
.flexShrink-6 { flex-shrink: 6; }
|
||||
.flexShrink-7 { flex-shrink: 7; }
|
||||
.flexShrink-8 { flex-shrink: 8; }
|
||||
.flexShrink-9 { flex-shrink: 9; }
|
||||
.flexShrink-10 { flex-shrink: 10; }
|
||||
.flexShrink-11 { flex-shrink: 11; }
|
||||
|
||||
/* flex-wrap */
|
||||
|
||||
.flexWrap-nowrap { flex-wrap: nowrap; }
|
||||
.flexWrap-wrap { flex-wrap: wrap; }
|
||||
.flexWrap-wrap-reverse { flex-wrap: wrap-reverse; }
|
||||
|
||||
/* float */
|
||||
|
||||
.float-left { float: left; }
|
||||
.float-none { float: none; }
|
||||
.float-right { float: right; }
|
||||
|
||||
/* font */
|
||||
|
||||
.font-inherit { font: inherit; }
|
||||
|
||||
/* font-family */
|
||||
|
||||
.fontFamily-inherit { font-family: inherit; }
|
||||
.fontFamily-monospace { font-family: monospace; }
|
||||
.fontFamily-sans-serif { font-family: sans-serif; }
|
||||
.fontFamily-serif { font-family: serif; }
|
||||
|
||||
/* font-size */
|
||||
|
||||
.fontSize-100\% { font-size: 100%; }
|
||||
.fontSize-inherit { font-size: inherit; }
|
||||
|
||||
/* font-style */
|
||||
|
||||
.fontStyle-inherit { font-style: inherit; }
|
||||
.fontStyle-italic { font-style: italic; }
|
||||
.fontStyle-normal { font-style: normal; }
|
||||
.fontStyle-oblique { font-style: oblique; }
|
||||
|
||||
/* font-weight */
|
||||
|
||||
.fontWeight-100 { font-weight: 100; }
|
||||
.fontWeight-200 { font-weight: 200; }
|
||||
.fontWeight-300 { font-weight: 300; }
|
||||
.fontWeight-400 { font-weight: 400; }
|
||||
.fontWeight-500 { font-weight: 500; }
|
||||
.fontWeight-600 { font-weight: 600; }
|
||||
.fontWeight-700 { font-weight: 700; }
|
||||
.fontWeight-800 { font-weight: 800; }
|
||||
.fontWeight-900 { font-weight: 900; }
|
||||
.fontWeight-bold { font-weight: bold; }
|
||||
.fontWeight-bolder { font-weight: bolder; }
|
||||
.fontWeight-inherit { font-weight: inherit; }
|
||||
.fontWeight-lighter { font-weight: lighter; }
|
||||
.fontWeight-normal { font-weight: normal; }
|
||||
|
||||
/* height */
|
||||
|
||||
.height-0 { height: 0; }
|
||||
.height-10\% { height: 10%; }
|
||||
.height-12\.5\% { height: 12.5%; }
|
||||
.height-20\% { height: 20%; }
|
||||
.height-25\% { height: 25%; }
|
||||
.height-30\% { height: 30%; }
|
||||
.height-37\.5\% { height: 37.5%; }
|
||||
.height-40\% { height: 40%; }
|
||||
.height-50\% { height: 50%; }
|
||||
.height-60\% { height: 60%; }
|
||||
.height-62\.5\% { height: 62.5%; }
|
||||
.height-70\% { height: 70%; }
|
||||
.height-75\% { height: 75%; }
|
||||
.height-80\% { height: 80%; }
|
||||
.height-87\.5\% { height: 87.5%; }
|
||||
.height-90\% { height: 90%; }
|
||||
.height-100\% { height: 100%; }
|
||||
|
||||
/* justify-content */
|
||||
|
||||
.justifyContent-center { justify-content: center; }
|
||||
.justifyContent-flex-end { justify-content: flex-end; }
|
||||
.justifyContent-flex-start { justify-content: flex-start; }
|
||||
.justifyContent-space-around { justify-content: space-around; }
|
||||
.justifyContent-space-between { justify-content: space-between; }
|
||||
|
||||
/* left */
|
||||
|
||||
.left-0 { left: 0; }
|
||||
.left-50% { left: 50%; }
|
||||
.left-100% { left: 100%; }
|
||||
|
||||
/* line-height */
|
||||
|
||||
.lineHeight-inherit { line-height: inherit; }
|
||||
.lineHeight-normal { line-height: normal; }
|
||||
|
||||
/* list-style */
|
||||
|
||||
.listStyle-none { list-style: none; }
|
||||
|
||||
/* margin */
|
||||
|
||||
.margin-0 { margin: 0; }
|
||||
.margin-auto { margin: auto; }
|
||||
|
||||
/* margin-bottom */
|
||||
|
||||
.marginBottom-auto { margin-bottom: auto; }
|
||||
.marginBottom-0 { margin-bottom: 0; }
|
||||
.marginBottom-1em { margin-bottom: 1em; }
|
||||
.marginBottom-1rem { margin-bottom: 1rem; }
|
||||
|
||||
/* margin-left */
|
||||
|
||||
.marginLeft-auto { margin-left: auto; }
|
||||
.marginLeft-0 { margin-left: 0; }
|
||||
.marginLeft-1em { margin-left: 1em; }
|
||||
.marginLeft-1rem { margin-left: 1rem; }
|
||||
|
||||
/* margin-right */
|
||||
|
||||
.marginRight-auto { margin-right: auto; }
|
||||
.marginRight-0 { margin-right: 0; }
|
||||
.marginRight-1em { margin-right: 1em; }
|
||||
.marginRight-1rem { margin-right: 1rem; }
|
||||
|
||||
/* margin-top */
|
||||
|
||||
.marginTop-auto { margin-top: auto; }
|
||||
.marginTop-0 { margin-top: 0; }
|
||||
.marginTop-1em { margin-top: 1em; }
|
||||
.marginTop-1rem { margin-top: 1rem; }
|
||||
|
||||
/* max-height */
|
||||
|
||||
.maxHeight-100\% { max-height: 100%; }
|
||||
|
||||
/* max-width */
|
||||
|
||||
.maxWidth-100\% { max-width: 100%; }
|
||||
|
||||
/* min-height */
|
||||
|
||||
.minHeight-100\% { min-height: 100%; }
|
||||
|
||||
/* min-width */
|
||||
|
||||
.minWidth-100\% { min-width: 100%; }
|
||||
|
||||
/* opacity */
|
||||
|
||||
.opacity-0 { opacity: 0; }
|
||||
.opacity-0\.1 { opacity: 0.1; }
|
||||
.opacity-0\.2 { opacity: 0.2; }
|
||||
.opacity-0\.25 { opacity: 0.25; }
|
||||
.opacity-0\.3 { opacity: 0.3; }
|
||||
.opacity-0\.4 { opacity: 0.4; }
|
||||
.opacity-0\.5 { opacity: 0.5; }
|
||||
.opacity-0\.6 { opacity: 0.6; }
|
||||
.opacity-0\.7 { opacity: 0.7; }
|
||||
.opacity-0\.75 { opacity: 0.75; }
|
||||
.opacity-0\.8 { opacity: 0.8; }
|
||||
.opacity-0\.9 { opacity: 0.9; }
|
||||
.opacity-1 { opacity: 1; }
|
||||
|
||||
/* order */
|
||||
|
||||
.order--1 { order: -1; }
|
||||
.order-1 { order: 1; }
|
||||
.order-2 { order: 2; }
|
||||
.order-3 { order: 3; }
|
||||
.order-4 { order: 4; }
|
||||
.order-5 { order: 5; }
|
||||
.order-6 { order: 6; }
|
||||
.order-7 { order: 7; }
|
||||
.order-8 { order: 8; }
|
||||
.order-9 { order: 9; }
|
||||
.order-10 { order: 10; }
|
||||
.order-11 { order: 11; }
|
||||
|
||||
/* overflow */
|
||||
|
||||
.overflow-auto { overflow: auto; }
|
||||
.overflow-hidden { overflow: hidden; }
|
||||
.overflow-inherit { overflow: inherit; }
|
||||
.overflow-scroll { overflow: scroll; }
|
||||
.overflow-visible { overflow: visible; }
|
||||
|
||||
/* overflow-x */
|
||||
|
||||
.overflowX-auto { overflow-x: auto; }
|
||||
.overflowX-hidden { overflow-x: hidden; }
|
||||
.overflowX-inherit { overflow-x: inherit; }
|
||||
.overflowX-scroll { overflow-x: scroll; }
|
||||
.overflowX-visible { overflow-x: visible; }
|
||||
|
||||
/* overflow-y */
|
||||
|
||||
.overflowY-auto { overflow-y: auto; }
|
||||
.overflowY-hidden { overflow-y: hidden; }
|
||||
.overflowY-inherit { overflow-y: inherit; }
|
||||
.overflowY-scroll { overflow-y: scroll; }
|
||||
.overflowY-visible { overflow-y: visible; }
|
||||
|
||||
/* padding */
|
||||
|
||||
.padding-0 { padding: 0; }
|
||||
.padding-1em { padding: 1em; }
|
||||
.padding-1rem { padding: 1rem; }
|
||||
|
||||
/* padding-bottom */
|
||||
|
||||
.paddingBottom-0 { padding-bottom: 0; }
|
||||
.paddingBottom-1em { padding-bottom: 1em; }
|
||||
.paddingBottom-1rem { padding-bottom: 1rem; }
|
||||
|
||||
/* padding-left */
|
||||
|
||||
.paddingLeft-0 { padding-left: 0; }
|
||||
.paddingLeft-1em { padding-left: 1em; }
|
||||
.paddingLeft-1rem { padding-left: 1rem; }
|
||||
|
||||
/* padding-right */
|
||||
|
||||
.paddingRight-0 { padding-right: 0; }
|
||||
.paddingRight-1em { padding-right: 1em; }
|
||||
.paddingRight-1rem { padding-right: 1rem; }
|
||||
|
||||
/* padding-top */
|
||||
|
||||
.paddingTop-0 { padding-top: 0; }
|
||||
.paddingTop-1em { padding-top: 1em; }
|
||||
.paddingTop-1rem { padding-top: 1rem; }
|
||||
|
||||
/* pointer-events */
|
||||
|
||||
.pointerEvents-auto { pointer-events: auto; }
|
||||
.pointerEvents-none { pointer-events: none; }
|
||||
.pointerEvents-box-none { pointer-events: none; }
|
||||
.pointerEvents-box-none * { pointer-events: auto;}
|
||||
.pointerEvents-box-only { pointer-events: auto; }
|
||||
.pointerEvents-box-only * { pointer-events: none; }
|
||||
|
||||
/* position */
|
||||
|
||||
.position-absolute { position: absolute; }
|
||||
.position-fixed { position: fixed; }
|
||||
.position-relative { position: relative; }
|
||||
|
||||
/* right */
|
||||
|
||||
.right-0 { right: 0; }
|
||||
.right-50% { right: 50%; }
|
||||
.right-100% { right: 100%; }
|
||||
|
||||
/* text-align */
|
||||
|
||||
.textAlign-center { text-align: center; }
|
||||
.textAlign-end { text-align: end; }
|
||||
.textAlign-inherit { text-align: inherit; }
|
||||
.textAlign-left { text-align: left; }
|
||||
.textAlign-right { text-align: right; }
|
||||
.textAlign-justify { text-align: justify; }
|
||||
.textAlign-start { text-align: start; }
|
||||
|
||||
/* text-decoration */
|
||||
|
||||
.textDecoration-inherit { text-decoration: inherit; }
|
||||
.textDecoration-none { text-decoration: none; }
|
||||
.textDecoration-underline { text-decoration: underline; }
|
||||
|
||||
/* text-overflow */
|
||||
|
||||
.textOverflow-clip { text-overflow: clip; }
|
||||
.textOverflow-ellipsis { text-overflow: ellipsis; }
|
||||
|
||||
/* text-rendering */
|
||||
|
||||
.textRendering-auto { text-rendering: auto; }
|
||||
.textRendering-geometricPrecision { text-rendering: geometricPrecision; }
|
||||
.textRendering-inherit { text-rendering: inherit; }
|
||||
.textRendering-optimizeLegibility { text-rendering: optimizeLegibility; }
|
||||
.textRendering-optimizeSpeed { text-rendering: optimizeSpeed; }
|
||||
|
||||
/* text-transform */
|
||||
|
||||
.textTransform-capitalize { text-transform: capitalize; }
|
||||
.textTransform-lowercase { text-transform: lowercase; }
|
||||
.textTransform-none { text-transform: none; }
|
||||
.textTransform-uppercase { text-transform: uppercase; }
|
||||
|
||||
/* top */
|
||||
|
||||
.top-0 { top: 0; }
|
||||
.top-50% { top: 50%; }
|
||||
.top-100% { top: 100%; }
|
||||
|
||||
/* unicode-bidi */
|
||||
|
||||
.unicodeBidi-bidi-override { unicode-bidi: bidi-override; }
|
||||
.unicodeBidi-embed { unicode-bidi: embed; }
|
||||
.unicodeBidi-inherit { unicode-bidi: inherit; }
|
||||
.unicodeBidi-isolate { unicode-bidi: isolate; }
|
||||
.unicodeBidi-isolate-override { unicode-bidi: isolate-override; }
|
||||
.unicodeBidi-normal { unicode-bidi: normal; }
|
||||
.unicodeBidi-plaintext { unicode-bidi: plaintext; }
|
||||
|
||||
/* user-select */
|
||||
|
||||
.userSelect-all { user-select: all; }
|
||||
.userSelect-inherit { user-select: inherit; }
|
||||
.userSelect-none { user-select: none; }
|
||||
.userSelect-text { user-select: text; }
|
||||
|
||||
/* visibility */
|
||||
|
||||
.visibility-collapse { visibility: collapse; }
|
||||
.visibility-hidden { visibility: hidden; }
|
||||
.visibility-inherit { visibility: inherit; }
|
||||
.visibility-visible { visibility: visible; }
|
||||
|
||||
/* white-space */
|
||||
|
||||
.whiteSpace-normal { white-space: normal; }
|
||||
.whiteSpace-nowrap { white-space: nowrap; }
|
||||
.whiteSpace-pre { white-space: pre; }
|
||||
.whiteSpace-pre-line { white-space: pre-line; }
|
||||
.whiteSpace-pre-wrap { white-space: pre-wrap; }
|
||||
|
||||
/* width */
|
||||
|
||||
.width-0 { width: 0; }
|
||||
.width-10\% { width: 10%; }
|
||||
.width-12\.5\% { width: 12.5%; }
|
||||
.width-20\% { width: 20%; }
|
||||
.width-25\% { width: 25%; }
|
||||
.width-30\% { width: 30%; }
|
||||
.width-37\.5\% { width: 37.5%; }
|
||||
.width-40\% { width: 40%; }
|
||||
.width-50\% { width: 50%; }
|
||||
.width-60\% { width: 60%; }
|
||||
.width-62\.5\% { width: 62.5%; }
|
||||
.width-70\% { width: 70%; }
|
||||
.width-75\% { width: 75%; }
|
||||
.width-80\% { width: 80%; }
|
||||
.width-87\.5\% { width: 87.5%; }
|
||||
.width-90\% { width: 90%; }
|
||||
.width-100\% { width: 100%; }
|
||||
|
||||
/* word-wrap */
|
||||
|
||||
.wordWrap-break-word { word-wrap: break-word; }
|
||||
.wordWrap-normal { word-wrap: normal; }
|
||||
|
||||
/* z-index */
|
||||
|
||||
.zIndex--1 { z-index: -1; }
|
||||
.zIndex-0 { z-index: 0; }
|
||||
.zIndex-1 { z-index: 1; }
|
||||
.zIndex-2 { z-index: 2; }
|
||||
.zIndex-3 { z-index: 3; }
|
||||
.zIndex-4 { z-index: 4; }
|
||||
.zIndex-5 { z-index: 5; }
|
||||
.zIndex-6 { z-index: 6; }
|
||||
.zIndex-7 { z-index: 7; }
|
||||
.zIndex-8 { z-index: 8; }
|
||||
.zIndex-9 { z-index: 9; }
|
||||
.zIndex-10 { z-index: 10; }
|
||||
Reference in New Issue
Block a user