mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-31 10:11:38 +08:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec9985a3b3 | ||
|
|
0aa29d8816 | ||
|
|
45777e0405 | ||
|
|
84e06564d4 | ||
|
|
1d1b633317 | ||
|
|
565ec2fee8 | ||
|
|
33082f988e | ||
|
|
a2fb65a79c | ||
|
|
e727193809 | ||
|
|
d6db206ec4 | ||
|
|
b3beea9bb3 | ||
|
|
ef4de789ae | ||
|
|
86037ab740 | ||
|
|
6c20646f10 | ||
|
|
b5aa68dc7a | ||
|
|
5668c40ee6 | ||
|
|
be86250ac6 | ||
|
|
1e04dfc306 | ||
|
|
283ab2fa2e | ||
|
|
09dd9a224a | ||
|
|
c7524b7b6f | ||
|
|
5453c8843a | ||
|
|
e0f836ccb5 | ||
|
|
eada8e7fc7 | ||
|
|
114fb5f8c7 | ||
|
|
4aa87c79fa | ||
|
|
9107fd3de9 | ||
|
|
c72173ff88 | ||
|
|
edf0fda75a | ||
|
|
3b848fe378 | ||
|
|
7eff1a644e | ||
|
|
2750d70a93 | ||
|
|
65559f50e6 | ||
|
|
77fd21ea44 | ||
|
|
38e4de76cd | ||
|
|
0f42cd83e1 | ||
|
|
e6cbea82c4 | ||
|
|
6d4c9e881f | ||
|
|
b9c8a560a0 | ||
|
|
357201e843 | ||
|
|
0ab345a490 | ||
|
|
2e087c10ad | ||
|
|
a7c1e105c6 | ||
|
|
969b57de53 | ||
|
|
50771fc5cd | ||
|
|
cd215a916d | ||
|
|
1668dc4635 | ||
|
|
f0b6576e80 | ||
|
|
7551596fa5 | ||
|
|
90e015112a | ||
|
|
cfdbd351f0 | ||
|
|
08013daa23 | ||
|
|
e7a5d56058 | ||
|
|
abf2c0307f | ||
|
|
6bb6a17046 | ||
|
|
b5c8af2694 | ||
|
|
17d993261b | ||
|
|
ef4064d966 | ||
|
|
b9e2007b59 | ||
|
|
247f489fdd | ||
|
|
d5b3b60c04 | ||
|
|
6b55032e49 | ||
|
|
77f73a8929 | ||
|
|
f951de43a2 | ||
|
|
fb7a997256 | ||
|
|
1417dd2e6a | ||
|
|
ff5c8f64cc | ||
|
|
653cfd71ce | ||
|
|
95d6b98e9d | ||
|
|
92dbadacb5 | ||
|
|
d3dce675df | ||
|
|
000bbf9f93 | ||
|
|
9d424fa529 | ||
|
|
344239bd8a | ||
|
|
8ec27cefab | ||
|
|
ecc23f46d4 | ||
|
|
39088affbc | ||
|
|
5494a8e191 | ||
|
|
95b1af9f1f | ||
|
|
1f3ac7a7b8 | ||
|
|
d86c2f4840 | ||
|
|
89202e51f6 | ||
|
|
36b6bd05af |
6
.babelrc
6
.babelrc
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": [ "typecheck" ]
|
||||
}
|
||||
},
|
||||
"optional": [
|
||||
"es7.classProperties",
|
||||
"runtime"
|
||||
],
|
||||
"stage": 1
|
||||
|
||||
17
.eslintrc
Normal file
17
.eslintrc
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
// babel parser to support ES features
|
||||
"parser": "babel-eslint",
|
||||
// based on https://github.com/feross/standard
|
||||
"extends": [ "standard", "standard-react" ],
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
// overrides of the standard style
|
||||
"space-before-function-paren": [ 2, { "anonymous": "always", "named": "never" } ],
|
||||
"wrap-iife": [ 2, "outside" ],
|
||||
// overrides of the standard-react style
|
||||
"react/jsx-sort-props": 2,
|
||||
"react/jsx-sort-prop-types": 2
|
||||
}
|
||||
}
|
||||
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
125
CONTRIBUTING.md
Normal file
125
CONTRIBUTING.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Contributing to this project
|
||||
|
||||
The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||
[features requests](#features) and [submitting pull
|
||||
requests](#pull-requests).
|
||||
|
||||
<a name="bugs"></a>
|
||||
## Bug reports
|
||||
|
||||
A bug is a _demonstrable problem_ that is caused by the code in the repository.
|
||||
Good bug reports are extremely helpful - thank you!
|
||||
|
||||
Guidelines for bug reports:
|
||||
|
||||
1. **Use the GitHub issue search** — check if the issue has already been
|
||||
reported.
|
||||
|
||||
2. **Check if the issue has been fixed** — try to reproduce it using the
|
||||
latest `master` or development branch in the repository.
|
||||
|
||||
3. **Isolate the problem** — create a [reduced test
|
||||
case](http://css-tricks.com/reduced-test-cases/) and a live example.
|
||||
|
||||
A good bug report contains as much detail as possible. What is your
|
||||
environment? What steps will reproduce the issue? What browser(s) and OS
|
||||
experience the problem? What would you expect to be the outcome? All these
|
||||
details really help!
|
||||
|
||||
Example:
|
||||
|
||||
> Short and descriptive example bug report title
|
||||
>
|
||||
> A summary of the issue and the browser/OS environment in which it occurs. If
|
||||
> suitable, include the steps required to reproduce the bug.
|
||||
>
|
||||
> 1. This is the first step
|
||||
> 2. This is the second step
|
||||
> 3. Further steps, etc.
|
||||
>
|
||||
> `<url>` - a link to the reduced test case
|
||||
>
|
||||
> Any other information you want to share that is relevant to the issue being
|
||||
> reported. This might include the lines of code that you have identified as
|
||||
> causing the bug, and potential solutions (and your opinions on their
|
||||
> merits).
|
||||
|
||||
|
||||
<a name="features"></a>
|
||||
## Feature requests
|
||||
|
||||
Feature requests are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature. Please
|
||||
provide as much detail and context as possible.
|
||||
|
||||
|
||||
<a name="pull-requests"></a>
|
||||
## Pull requests
|
||||
|
||||
Good pull requests - patches, improvements, new features - are a fantastic
|
||||
help. Please keep them focused in scope and avoid containing unrelated commits.
|
||||
|
||||
**Please ask first** before embarking on any significant pull request (e.g.
|
||||
implementing new features or components, refactoring code), otherwise you risk
|
||||
spending a lot of time working on something that the project's developers might
|
||||
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 lint` – run the linter
|
||||
* `npm run test:specs` – run and watch the unit tests
|
||||
|
||||
Please follow this process for submitting a patch:
|
||||
|
||||
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
|
||||
and configure the remotes:
|
||||
|
||||
```bash
|
||||
# Clone your fork of the repo into the current directory
|
||||
git clone https://github.com/<your-username>/react-native-web
|
||||
# Navigate to the newly cloned directory
|
||||
cd react-native-web
|
||||
# Assign the original repo to a remote called "upstream"
|
||||
git remote add upstream https://github.com/necolas/react-native-web
|
||||
```
|
||||
|
||||
2. If you cloned a while ago, get the latest changes from upstream:
|
||||
|
||||
```bash
|
||||
git checkout master
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
3. Create a new topic branch (off the main project development branch) to
|
||||
contain your feature, change, or fix:
|
||||
|
||||
```bash
|
||||
git checkout -b <topic-branch-name>
|
||||
```
|
||||
|
||||
4. Commit your changes in logical chunks. Please adhere to these [git commit
|
||||
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||
or your code is unlikely be merged into the main project. Use Git's
|
||||
[interactive rebase](https://help.github.com/articles/interactive-rebase)
|
||||
feature to tidy up your commits before making them public.
|
||||
|
||||
5. Locally merge (or rebase) the upstream development branch into your topic branch:
|
||||
|
||||
```bash
|
||||
git pull [--rebase] upstream master
|
||||
```
|
||||
|
||||
6. Push your topic branch up to your fork:
|
||||
|
||||
```bash
|
||||
git push origin <topic-branch-name>
|
||||
```
|
||||
|
||||
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
|
||||
with a clear title and description.
|
||||
|
||||
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
|
||||
license your work under the same license as that used by the project.
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Nicolas Gallagher
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
221
README.md
221
README.md
@@ -1,102 +1,150 @@
|
||||
# react-web-sdk
|
||||
# React Native for Web
|
||||
|
||||
**Experimental / Proof of concept**
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![npm version][npm-image]][npm-url]
|
||||
|
||||
A React SDK (~9KB gzipped) for creating web applications and toolkits. Inspired by `react-native`.
|
||||
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.
|
||||
|
||||
It includes the following components:
|
||||
* [Slack: reactiflux channel #react-native-web][slack-url]
|
||||
* [Gitter: react-native-web][gitter-url]
|
||||
|
||||
* `View`: a flexbox primitive
|
||||
* `Text`: a text primitive
|
||||
* `Image`: an image primitive
|
||||
* (`Component`: base / implementation)
|
||||
## Table of contents
|
||||
|
||||
And uses a [styling strategy](docs/styling-strategy.md) that maps inline styles
|
||||
to single-purpose CSS rules.
|
||||
* [Install](#install)
|
||||
* [Use](#use)
|
||||
* [Components](#components)
|
||||
* [Styling](#styling)
|
||||
* [Contributing](#contributing)
|
||||
* [Thanks](#thanks)
|
||||
* [License](#license)
|
||||
|
||||
This proof of concept uses a CSS bundle (~4.5KB gzipped) of 300+ precomputed
|
||||
declarations. A more sophisticated implementation is likely to produce a
|
||||
slightly larger CSS file and fewer inline styles.
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install --save react react-native-web
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
React Native for Web exports its components and a reference to the `React`
|
||||
installation. Styles are authored in JavaScript as plain objects.
|
||||
|
||||
```js
|
||||
import React, { View } from 'react-native-web'
|
||||
|
||||
class MyComponent extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.root} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
borderColor: 'currentcolor'
|
||||
borderWidth: '5px',
|
||||
flexDirection: 'row'
|
||||
height: '5em'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
All components define explicit `style` PropTypes according to the [`StyleProp`
|
||||
spec](docs/StyleProp.spec.md).
|
||||
### [`Image`](docs/components/Image.md)
|
||||
|
||||
### Component
|
||||
An accessibile image component with support for image resizing, default image,
|
||||
and child content.
|
||||
|
||||
TODO
|
||||
### [`ListView`](docs/components/ListView.md)
|
||||
|
||||
[`Component`](docs/Component.md)
|
||||
(TODO)
|
||||
|
||||
### View
|
||||
### [`ScrollView`](docs/components/ListView.md)
|
||||
|
||||
TODO
|
||||
(TODO)
|
||||
|
||||
A flexbox container; foundational layout building block.
|
||||
### [`Swipeable`](docs/components/Swipeable.md)
|
||||
|
||||
[`View` spec](docs/View.spec.md)
|
||||
Touch bindings for swipe gestures.
|
||||
|
||||
See this [guide to flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).
|
||||
### [`Text`](docs/components/Text.md)
|
||||
|
||||
### Text
|
||||
Displays text as an inline block and supports basic press handling.
|
||||
|
||||
TODO
|
||||
### [`TextInput`](docs/components/TextInput.md)
|
||||
|
||||
[`Text` spec](docs/View.spec.md)
|
||||
Accessible single- and multi-line text input via a keyboard.
|
||||
|
||||
### Image
|
||||
### [`Touchable`](docs/components/Touchable.md)
|
||||
|
||||
TODO
|
||||
Touch bindings for press and long press.
|
||||
|
||||
[`Image` spec](docs/View.spec.md)
|
||||
### [`View`](docs/components/View.md)
|
||||
|
||||
The fundamental UI building block using flexbox for layout.
|
||||
|
||||
## Styling
|
||||
|
||||
Styling is identical to using inline styles in React, but most inline styles
|
||||
are converted to unique CSS classes. **This is only true for the SDK
|
||||
components**.
|
||||
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].
|
||||
|
||||
The companion stylesheet can be referenced as an external resource, inlined, or
|
||||
injected by JS.
|
||||
|
||||
See the [styling strategy docs](docs/styling-strategy.md) for more details.
|
||||
|
||||
### Use plain JavaScript objects
|
||||
|
||||
Use JavaScript to write style definitions in React components:
|
||||
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).
|
||||
|
||||
```js
|
||||
const style = {
|
||||
common: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '1em'
|
||||
},
|
||||
root: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
image: {
|
||||
opacity: 0.5
|
||||
},
|
||||
text: {
|
||||
fontWeight: '300'
|
||||
}
|
||||
};
|
||||
```
|
||||
import React, { Image, Text, View } from 'react-native-web'
|
||||
|
||||
### Use the `style` attribute
|
||||
|
||||
The `style` attribute is a simple API for creating element-scoped styles.
|
||||
|
||||
```js
|
||||
import {View} from 'react-web-sdk';
|
||||
|
||||
class Example extends React.Component {
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={style.root}>...</View>
|
||||
);
|
||||
<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'
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -104,7 +152,7 @@ class Example extends React.Component {
|
||||
Combine and override style objects:
|
||||
|
||||
```js
|
||||
import baseStyle from './baseStyle';
|
||||
import baseStyle from './baseStyle'
|
||||
|
||||
const buttonStyle = {
|
||||
...baseStyle,
|
||||
@@ -113,25 +161,32 @@ const buttonStyle = {
|
||||
}
|
||||
```
|
||||
|
||||
## Utilities
|
||||
## Contributing
|
||||
|
||||
#### `getOtherProps(reactComponentInstance)`
|
||||
Please read the [contribution guidelines][contributing-url]. Contributions are
|
||||
welcome!
|
||||
|
||||
Returns an object containing all the props from `this.props` that are not
|
||||
defined in `propTypes`.
|
||||
## Thanks
|
||||
|
||||
#### `omitProps(obj, arrayOfExcludedProps)`
|
||||
Thanks to current and past members of the React and React Native teams (in
|
||||
particular Vjeux and Pete Hunt), and Tobias Koppers for Webpack and CSS loader.
|
||||
|
||||
Returns an object with the specified props excluded.
|
||||
Thanks to [react-swipeable](https://github.com/dogfessional/react-swipeable/)
|
||||
for the current implementation of `Swipeable`, and to
|
||||
[react-tappable](https://github.com/JedWatson/react-tappable) for backing the
|
||||
current implementation of `Touchable`.
|
||||
|
||||
#### `pickProps(obj, arrayOfIncludedProps)`
|
||||
## License
|
||||
|
||||
Returns an object with the specified props included.
|
||||
Copyright (c) 2015 Nicolas Gallagher. Released under the [MIT
|
||||
license](http://www.opensource.org/licenses/mit-license.php).
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
npm install
|
||||
npm run build:example:watch
|
||||
open example/index.html
|
||||
```
|
||||
[contributing-url]: https://github.com/necolas/react-native-web/blob/master/CONTRIBUTING.md
|
||||
[flexbox-guide-url]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
|
||||
[gitter-url]: https://gitter.im/necolas/react-native-web
|
||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
||||
[npm-url]: https://npmjs.org/package/react-native-web
|
||||
[react-native-url]: https://facebook.github.io/react-native/
|
||||
[slack-url]: https://reactiflux.slack.com/messages/react-native-web/
|
||||
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/necolas/react-native-web
|
||||
|
||||
9
config/constants.js
Normal file
9
config/constants.js
Normal file
@@ -0,0 +1,9 @@
|
||||
var path = require('path')
|
||||
|
||||
var ROOT = path.join(__dirname, '..')
|
||||
|
||||
module.exports = {
|
||||
DIST_DIRECTORY: path.join(ROOT, 'dist'),
|
||||
SRC_DIRECTORY: path.join(ROOT, 'src'),
|
||||
ROOT_DIRECTORY: ROOT
|
||||
}
|
||||
46
config/karma.config.js
Normal file
46
config/karma.config.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var assign = require('object-assign')
|
||||
var constants = require('./constants')
|
||||
var webpackConfig = require('./webpack.config.base')
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: constants.ROOT_DIRECTORY,
|
||||
browsers: process.env.TRAVIS ? [ 'Firefox' ] : [ 'Chrome' ],
|
||||
browserNoActivityTimeout: 60000,
|
||||
client: {
|
||||
captureConsole: true,
|
||||
mocha: {
|
||||
ui: 'tdd'
|
||||
},
|
||||
useIframe: true
|
||||
},
|
||||
files: [
|
||||
'src/specs.context.js'
|
||||
],
|
||||
frameworks: [
|
||||
'mocha'
|
||||
],
|
||||
plugins: [
|
||||
'karma-chrome-launcher',
|
||||
'karma-firefox-launcher',
|
||||
'karma-mocha',
|
||||
'karma-sourcemap-loader',
|
||||
'karma-webpack'
|
||||
],
|
||||
preprocessors: {
|
||||
'src/specs.context.js': [ 'webpack', 'sourcemap' ]
|
||||
},
|
||||
reporters: [ 'dots' ],
|
||||
singleRun: true,
|
||||
webpack: assign({}, webpackConfig, { devtool: 'inline' }),
|
||||
webpackMiddleware: {
|
||||
stats: {
|
||||
assetsSort: 'name',
|
||||
colors: true,
|
||||
children: false,
|
||||
chunks: false,
|
||||
modules: false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
45
config/webpack.config.base.js
Normal file
45
config/webpack.config.base.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var webpack = require('webpack')
|
||||
|
||||
var DedupePlugin = webpack.optimize.DedupePlugin
|
||||
var OccurenceOrderPlugin = webpack.optimize.OccurenceOrderPlugin
|
||||
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
|
||||
|
||||
var plugins = [
|
||||
new DedupePlugin(),
|
||||
new OccurenceOrderPlugin()
|
||||
]
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
plugins.push(
|
||||
new UglifyJsPlugin({
|
||||
compress: {
|
||||
dead_code: true,
|
||||
drop_console: true,
|
||||
screw_ie8: true,
|
||||
warnings: true
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: [
|
||||
'style-loader',
|
||||
'css-loader?module&localIdentName=[hash:base64:5]',
|
||||
'autoprefixer-loader'
|
||||
].join('!')
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: { cacheDirectory: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: plugins
|
||||
}
|
||||
17
config/webpack.config.example.js
Normal file
17
config/webpack.config.example.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var assign = require('object-assign')
|
||||
var base = require('./webpack.config.base')
|
||||
var constants = require('./constants')
|
||||
var path = require('path')
|
||||
|
||||
module.exports = assign({}, base, {
|
||||
devServer: {
|
||||
contentBase: constants.SRC_DIRECTORY
|
||||
},
|
||||
entry: {
|
||||
example: path.join(constants.SRC_DIRECTORY, 'example')
|
||||
},
|
||||
output: {
|
||||
filename: 'example.js',
|
||||
path: constants.DIST_DIRECTORY
|
||||
}
|
||||
})
|
||||
18
config/webpack.config.publish.js
Normal file
18
config/webpack.config.publish.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var assign = require('object-assign')
|
||||
var base = require('./webpack.config.base')
|
||||
var constants = require('./constants')
|
||||
|
||||
module.exports = assign({}, base, {
|
||||
entry: {
|
||||
main: constants.SRC_DIRECTORY
|
||||
},
|
||||
externals: [{
|
||||
react: true
|
||||
}],
|
||||
output: {
|
||||
filename: 'react-native-web.js',
|
||||
library: 'ReactNativeWeb',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: constants.DIST_DIRECTORY
|
||||
}
|
||||
})
|
||||
@@ -1,44 +0,0 @@
|
||||
# `Component`
|
||||
|
||||
This component is part of the implementation for managing styles across the
|
||||
`className` and `style` properties. It is the building block upon which all
|
||||
other components in `react-web-sdk` are built.
|
||||
|
||||
## PropTypes
|
||||
|
||||
All other props are transferred directly to the `element`.
|
||||
|
||||
+ `element`: `func` or `string`
|
||||
+ `style`: `object`
|
||||
|
||||
#### Examples
|
||||
|
||||
```js
|
||||
import {Component, pickProps} from 'react-web-sdk';
|
||||
import React, {PropTypes} from 'react';
|
||||
|
||||
const ExampleStylePropTypes = { opacity: PropTypes.number };
|
||||
const ExampleStyleDefaultProps = { opacity: 1 };
|
||||
|
||||
class Example extends React.Component {
|
||||
static propTypes = {
|
||||
style: PropTypes.shape(ExampleStylePropTypes)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
// only apply supported styles
|
||||
const supportedStyle = pickProps(style, ExampleStylePropTypes);
|
||||
// merge with default styles
|
||||
const mergedStyle = { ...ExampleStyleDefaultProps, ...supportedStyle }
|
||||
|
||||
return (
|
||||
<Component
|
||||
...other
|
||||
element="main"
|
||||
style={mergedStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,66 +0,0 @@
|
||||
# Image spec
|
||||
|
||||
#### PropTypes
|
||||
|
||||
All other props are transferred directly to the `element`.
|
||||
|
||||
+ `accessibilityLabel`: `string`
|
||||
+ `async`: `bool` (TODO)
|
||||
+ `className`: `string`
|
||||
+ `source`: `string`
|
||||
+ `style`: `ImageStylePropTypes`
|
||||
|
||||
#### ImageStylePropTypes
|
||||
|
||||
+ `BackgroundPropTypes`
|
||||
+ `BorderThemePropTypes`
|
||||
+ `LayoutPropTypes`
|
||||
+ `opacity`: `string`
|
||||
|
||||
#### Examples
|
||||
|
||||
```js
|
||||
import {Image} from 'react-web-sdk';
|
||||
import React, {PropTypes} from 'react';
|
||||
|
||||
class Avatar extends React.Component {
|
||||
static propTypes = {
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
size: 'normal'
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Image
|
||||
accessibilityLabel={`${user.name}'s profile picture`}
|
||||
source={user.avatarUrl}
|
||||
style={ ...style.base, ...style[this.props.size] }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const style = {
|
||||
base: {
|
||||
borderColor: 'white',
|
||||
borderRadius: '5px',
|
||||
borderWidth: '5px'
|
||||
},
|
||||
small: {
|
||||
height: '32px',
|
||||
width: '32px'
|
||||
},
|
||||
normal: {
|
||||
height: '48px',
|
||||
width: '48px'
|
||||
},
|
||||
large: {
|
||||
height: '64px',
|
||||
width: '32px'
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,89 +0,0 @@
|
||||
## StyleProp spec
|
||||
|
||||
### Background
|
||||
|
||||
+ `backgroundColor`: `string`
|
||||
+ `backgroundImage`: `string`
|
||||
+ `backgroundPosition`: `string`
|
||||
+ `backgroundRepeat`: `string`
|
||||
+ `backgroundSize`: `string`
|
||||
|
||||
### BorderTheme
|
||||
|
||||
+ `borderColor`: `string`
|
||||
+ `borderTopColor`: `string`
|
||||
+ `borderRightColor`: `string`
|
||||
+ `borderBottomColor`: `string`
|
||||
+ `borderLeftColor`: `string`
|
||||
+ `borderStyle`: `string`
|
||||
+ `borderRadius`: `number` or `string`
|
||||
+ `borderTopLeftRadius`: `number` or `string`
|
||||
+ `borderTopRightRadius`: `number` or `string`
|
||||
+ `borderBottomLeftRadius`: `number` or `string`
|
||||
+ `borderBottomRightRadius`: `number` or `string`
|
||||
|
||||
### BoxModel
|
||||
|
||||
+ `borderWidth`: `number` or `string`
|
||||
+ `borderTopWidth`: `number` or `string`
|
||||
+ `borderRightWidth`: `number` or `string`
|
||||
+ `borderBottomWidth`: `number` or `string`
|
||||
+ `borderLeftWidth`: `number` or `string`
|
||||
+ `boxSizing`: `oneOf('border-box', 'content-box')`
|
||||
+ `display`: `oneOf('block', 'flex', 'inline', 'inline-block', 'inline-flex')`
|
||||
+ `height`: `number` or `string`
|
||||
+ `margin`: `number` or `string`
|
||||
+ `marginTop`: `number` or `string`
|
||||
+ `marginRight`: `number` or `string`
|
||||
+ `marginBottom`: `number` or `string`
|
||||
+ `marginLeft`: `number` or `string`
|
||||
+ `padding`: `number` or `string`
|
||||
+ `paddingTop`: `number` or `string`
|
||||
+ `paddingRight`: `number` or `string`
|
||||
+ `paddingBottom`: `number` or `string`
|
||||
+ `paddingLeft`: `number` or `string`
|
||||
+ `width`: `number` or `string`
|
||||
|
||||
### Flexbox
|
||||
|
||||
* `alignContent`: `oneOf('center', 'flex-end', 'flex-start', 'stretch', 'space-around', 'space-between')`
|
||||
* `alignItems`: `oneOf('baseline', 'center', 'flex-end', 'flex-start', 'stretch')`
|
||||
* `alignSelf`: `oneOf('auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch')`
|
||||
* `flex`: `string`
|
||||
* `flexBasis`: `string`
|
||||
* `flexDirection`: `oneOf('column', 'column-reverse', 'row', 'row-reverse')`
|
||||
* `flexGrow`: `number`
|
||||
* `flexShrink`: `number`
|
||||
* `flexWrap`: `oneOf('nowrap', 'wrap', 'wrap-reverse')`
|
||||
* `justifyContent`: `oneOf('center', 'flex-end', 'flex-start', 'space-around', 'space-between')`
|
||||
* `order`: `number`
|
||||
|
||||
### Layout
|
||||
|
||||
* BoxModel
|
||||
* Flexbox
|
||||
* Position
|
||||
|
||||
### Position
|
||||
|
||||
* `position`: `oneOf('absolute', 'fixed', 'relative')`
|
||||
* `bottom`: `number` or `string`
|
||||
* `left`: `number` or `string`
|
||||
* `right`: `number` or `string`
|
||||
* `top`: `number` or `string`
|
||||
* `zIndex`: `number`
|
||||
|
||||
### Typographic
|
||||
|
||||
* `direction`: `oneOf('auto', 'ltr', 'rtl')`
|
||||
* `fontFamily`: `string`
|
||||
* `fontSize`: `string`
|
||||
* `fontWeight`: `oneOf('100', '200', '300', '400', '500', '600', '700', '800', '900', 'bold', 'normal')`
|
||||
* `fontStyle`: `oneOf('normal', 'italic')`
|
||||
* `letterSpacing`: `string`
|
||||
* `lineHeight`: `number` or `string`
|
||||
* `textAlign`: `oneOf('auto', 'left', 'right', 'center')`
|
||||
* `textDecoration`: `oneOf('none', 'underline')`
|
||||
* `textTransform`: `oneOf('capitalize', 'lowercase', 'none', 'uppercase')`
|
||||
* `wordWrap`: `oneOf('break-word', 'normal')`
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# Text spec
|
||||
|
||||
Text layout and styles.
|
||||
|
||||
#### PropTypes
|
||||
|
||||
All other props are transferred directly to the `element`.
|
||||
|
||||
+ `element`: `func` or `string` (default `"div"`)
|
||||
+ `style`: `TextStylePropTypes`
|
||||
|
||||
#### TextStylePropTypes
|
||||
|
||||
+ ViewStylePropTypes
|
||||
+ TypographicPropTypes
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import {Text} from 'react-web-sdk';
|
||||
import React, {PropTypes} from 'react';
|
||||
|
||||
class PrettyText extends React.Component {
|
||||
static propTypes = {
|
||||
color: PropTypes.oneOf(['white', 'gray', 'red']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
color: 'gray',
|
||||
size: 'normal',
|
||||
weight: 'normal'
|
||||
}
|
||||
|
||||
render() {
|
||||
const { color, size, style, weight, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<Text
|
||||
...other
|
||||
style={{
|
||||
...style,
|
||||
...localStyle.color[color],
|
||||
...localStyle.size[size],
|
||||
...localStyle.weight[weight]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = {
|
||||
color: {
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
red: { color: 'red' }
|
||||
},
|
||||
size: {
|
||||
small: { fontSize: '0.85rem', padding: '0.5rem' },
|
||||
normal: { fontSize: '1rem', padding: '0.75rem' },
|
||||
large: { fontSize: '1.5rem', padding: '1rem' }
|
||||
},
|
||||
weight: {
|
||||
light: { fontWeight: '300' },
|
||||
normal: { fontWeight: '400' },
|
||||
bold: { fontWeight: '700' }
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,66 +0,0 @@
|
||||
# View spec
|
||||
|
||||
`View` is a flexbox container and the fundamental building block for UI. It is
|
||||
designed to be nested inside other `View`'s and to have 0-to-many children of
|
||||
any type.
|
||||
|
||||
## PropTypes
|
||||
|
||||
All other props are transferred directly to the `element`.
|
||||
|
||||
+ `element`: `func` or `string` (default `"div"`)
|
||||
+ `pointerEvents`: `oneOf('all', 'box-only', 'box-none', 'none')`
|
||||
+ `style`: `ViewStylePropTypes`
|
||||
|
||||
## ViewStylePropTypes
|
||||
|
||||
+ BackgroundPropTypes
|
||||
+ BorderThemePropTypes
|
||||
+ LayoutPropTypes
|
||||
+ `boxShadow`: `string`
|
||||
+ `color`: `string`
|
||||
+ `opacity`: `number`
|
||||
|
||||
## ViewStyleDefaultProps
|
||||
|
||||
Implements the default styles from
|
||||
[facebook/css-layout](https://github.com/facebook/css-layout).
|
||||
|
||||
1. All the flex elements are oriented from top-to-bottom, left-to-right and do
|
||||
not shrink. This is how things are laid out using the default CSS settings
|
||||
and what you'd expect.
|
||||
|
||||
2. The most convenient way to express the relation between width and other
|
||||
box-model properties.
|
||||
|
||||
3. Everything is `display:flex` by default. All the behaviors of `block` and
|
||||
`inline-block` can be expressed in term of flex but not the opposite.
|
||||
|
||||
4. Everything is `position:relative`. This makes `position:absolute` target the
|
||||
direct parent and not some parent which is either relative or absolute. If
|
||||
you want to position an element relative to something else, you should move
|
||||
it in the DOM instead of relying of CSS. It also makes `top`, `left`,
|
||||
`right`, `bottom` do something when not specifying `position:absolute`.
|
||||
|
||||
```js
|
||||
const ViewStyleDefaultProps = {
|
||||
alignItems: 'stretch', // 1
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box', // 2
|
||||
display: 'flex', // 3
|
||||
flexBasis: 'auto', // 1
|
||||
flexDirection: 'column', // 1
|
||||
flexShrink: 0, // 1
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative' // 4
|
||||
};
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
// TODO
|
||||
```
|
||||
143
docs/components/Image.md
Normal file
143
docs/components/Image.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Image
|
||||
|
||||
An accessibile image component with support for image resizing, default image,
|
||||
and child content.
|
||||
|
||||
Unsupported React Native props:
|
||||
`capInsets` (ios),
|
||||
`onProgress` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: string
|
||||
|
||||
The text that's read by a screenreader when someone interacts with the image.
|
||||
|
||||
**accessible**: bool
|
||||
|
||||
When `false`, the view is hidden from screenreaders. Default: `true`.
|
||||
|
||||
**children**: any
|
||||
|
||||
Content to display over the image.
|
||||
|
||||
**defaultSource**: { uri: string }
|
||||
|
||||
An image to display as a placeholder while downloading the final image off the network.
|
||||
|
||||
**onError**: function
|
||||
|
||||
Invoked on load error with `{nativeEvent: {error}}`.
|
||||
|
||||
**onLayout**: function
|
||||
|
||||
TODO
|
||||
|
||||
**onLoad**: function
|
||||
|
||||
Invoked when load completes successfully.
|
||||
|
||||
**onLoadEnd**: function
|
||||
|
||||
Invoked when load either succeeds or fails,
|
||||
|
||||
**onLoadStart**: function
|
||||
|
||||
Invoked on load start.
|
||||
|
||||
**resizeMode**: oneOf('contain', 'cover', 'none', 'stretch') = 'stretch'
|
||||
|
||||
Determines how to resize the image when the frame doesn't match the raw image
|
||||
dimensions.
|
||||
|
||||
**source**: { uri: string }
|
||||
|
||||
`uri` is a string representing the resource identifier for the image, which
|
||||
could be an http address or a base64 encoded image.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
Defaults:
|
||||
|
||||
```js
|
||||
{
|
||||
alignSelf: 'flex-start',
|
||||
backgroundColor: 'lightGray'
|
||||
}
|
||||
```
|
||||
|
||||
**testID**: string
|
||||
|
||||
Used to locate a view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import placeholderAvatar from './placeholderAvatar.png'
|
||||
import React, { Image } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
class Avatar extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { loading: true }
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
testID: Image.propTypes.testID,
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
size: 'normal'
|
||||
}
|
||||
|
||||
_onLoad(e) {
|
||||
console.log('Avatar.onLoad', e)
|
||||
this.setState({ loading: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { size, testID, user } = this.props
|
||||
const loadingStyle = this.state.loading ? { styles.loading } : { }
|
||||
|
||||
return (
|
||||
<Image
|
||||
accessibilityLabel={`${user.name}'s profile picture`}
|
||||
defaultSource={{ uri: placeholderAvatar }}
|
||||
onLoad={this._onLoad.bind(this)}
|
||||
resizeMode='cover'
|
||||
source={{ uri: user.avatarUrl }}
|
||||
style={{ ...styles.base, ...styles[size], ...loadingStyle }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
base: {
|
||||
borderColor: 'white',
|
||||
borderRadius: '5px',
|
||||
borderWidth: '5px'
|
||||
},
|
||||
loading: {
|
||||
opacity: 0.5
|
||||
},
|
||||
small: {
|
||||
height: '32px',
|
||||
width: '32px'
|
||||
},
|
||||
normal: {
|
||||
height: '48px',
|
||||
width: '48px'
|
||||
},
|
||||
large: {
|
||||
height: '64px',
|
||||
width: '64px'
|
||||
}
|
||||
}
|
||||
```
|
||||
42
docs/components/ListView.md
Normal file
42
docs/components/ListView.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# ListView
|
||||
|
||||
TODO
|
||||
|
||||
## Props
|
||||
|
||||
**children**: any
|
||||
|
||||
Content to display over the image.
|
||||
|
||||
**style**: style
|
||||
|
||||
+ `property` type
|
||||
|
||||
Defaults:
|
||||
|
||||
```js
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { ListView } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ListView />
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
59
docs/components/ScrollView.md
Normal file
59
docs/components/ScrollView.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# ScrollView
|
||||
|
||||
TODO
|
||||
|
||||
## Props
|
||||
|
||||
**children**: any
|
||||
|
||||
Child content.
|
||||
|
||||
**contentContainerStyle**: style
|
||||
|
||||
These styles will be applied to the scroll view content container which wraps
|
||||
all of the child views. Example:
|
||||
|
||||
**horizontal**: bool = false
|
||||
|
||||
When true, the scroll view's children are arranged horizontally in a row instead of vertically in a column. Default: `false`.
|
||||
|
||||
**onScroll**: function
|
||||
|
||||
Fires at most once per frame during scrolling. The frequency of the events can be contolled using the `scrollEventThrottle` prop.
|
||||
|
||||
**scrollEnabled**: bool
|
||||
|
||||
When false, the content does not scroll. Default: `true`.
|
||||
|
||||
**scrollEventThrottle**: number
|
||||
|
||||
This controls how often the scroll event will be fired while scrolling (in
|
||||
events per seconds). A higher number yields better accuracy for code that is
|
||||
tracking the scroll position, but can lead to scroll performance problems.
|
||||
Default: `0` (the scroll event will be sent only once each time the view is
|
||||
scrolled.)
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { ScrollView } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
95
docs/components/Swipeable.md
Normal file
95
docs/components/Swipeable.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Swipeable
|
||||
|
||||
Unique to web.
|
||||
|
||||
## Props
|
||||
|
||||
**delta**: number = 10
|
||||
|
||||
Number of pixels that must be swiped before events are dispatched.
|
||||
|
||||
**flickThreshold**: number = 0.6
|
||||
|
||||
The velocity threshold at which a swipe is considered a flick.
|
||||
|
||||
**onSwiped**: function
|
||||
|
||||
(SyntheticTouchEvent, deltaX, deltaY, isFlick) => swipeHandler
|
||||
|
||||
Called once a swipe has ended.
|
||||
|
||||
**onSwipedDown**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called once a swipe-down has ended.
|
||||
|
||||
**onSwipedLeft**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called once a swipe-left has ended.
|
||||
|
||||
**onSwipedUp**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called once a swipe-up has ended.
|
||||
|
||||
**onSwipedRight**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called once a swipe-right has ended.
|
||||
|
||||
**onSwipingDown**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called while a swipe-down is in progress.
|
||||
|
||||
**onSwipingLeft**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called while a swipe-left is in progress.
|
||||
|
||||
**onSwipingRight**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called while a swipe-right is in progress.
|
||||
|
||||
**onSwipingUp**: function
|
||||
|
||||
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
|
||||
|
||||
Called while a swipe-up is in progress.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Swipeable } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
|
||||
_onSwiped(event, x, y, isFlick) {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Swipeable
|
||||
onSwiped={this._onSwiped.bind(this)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
124
docs/components/Text.md
Normal file
124
docs/components/Text.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Text
|
||||
|
||||
`Text` is component for displaying text. It supports style, basic touch
|
||||
handling, and inherits typographic styles from ancestor elements. In a
|
||||
divergence from React Native, components other than `Text` can be children of a
|
||||
`Text` component.
|
||||
|
||||
The `Text` is unique relative to layout: child elements use text layout
|
||||
(`inline-block`) rather than flexbox layout. This means that elements inside of
|
||||
a `Text` are not rectangles, as they wrap when reaching the edge of their
|
||||
container.
|
||||
|
||||
Unsupported React Native props:
|
||||
`allowFontScaling` (ios),
|
||||
`suppressHighlighting` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `Text` will transfer all other props to the rendered HTML element.
|
||||
|
||||
(web) **accessibilityLabel**: string
|
||||
|
||||
Defines the text available to assistive technologies upon interaction with the
|
||||
element. (This is implemented using `aria-label`.)
|
||||
|
||||
(web) **accessible**: bool = true
|
||||
|
||||
When `false`, the text is hidden from assistive technologies. (This is
|
||||
implemented using `aria-hidden`.)
|
||||
|
||||
**children**: any
|
||||
|
||||
Child content.
|
||||
|
||||
(web) **component**: function | string = 'span'
|
||||
|
||||
Backing component.
|
||||
|
||||
**numberOfLines**: number
|
||||
|
||||
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
|
||||
|
||||
**onPress**: function
|
||||
|
||||
This function is called on press.
|
||||
|
||||
**style**: style
|
||||
|
||||
+ `backgroundColor`
|
||||
+ `color`
|
||||
+ `direction`
|
||||
+ `fontFamily`
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `margin`
|
||||
+ `padding`
|
||||
+ `textAlign`
|
||||
+ `textDecoration`
|
||||
+ `textTransform`
|
||||
+ `whiteSpace`
|
||||
+ `wordWrap`
|
||||
|
||||
**testID**: string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Text } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class PrettyText extends Component {
|
||||
static propTypes = {
|
||||
color: PropTypes.oneOf(['white', 'gray', 'red']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
color: 'gray',
|
||||
size: 'normal',
|
||||
weight: 'normal'
|
||||
}
|
||||
|
||||
render() {
|
||||
const { color, size, style, weight, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<Text
|
||||
...other
|
||||
style={{
|
||||
...style,
|
||||
...localStyle.color[color],
|
||||
...localStyle.size[size],
|
||||
...localStyle.weight[weight]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = {
|
||||
color: {
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
red: { color: 'red' }
|
||||
},
|
||||
size: {
|
||||
small: { fontSize: '0.85rem', padding: '0.5rem' },
|
||||
normal: { fontSize: '1rem', padding: '0.75rem' },
|
||||
large: { fontSize: '1.5rem', padding: '1rem' }
|
||||
},
|
||||
weight: {
|
||||
light: { fontWeight: '300' },
|
||||
normal: { fontWeight: '400' },
|
||||
bold: { fontWeight: '700' }
|
||||
}
|
||||
}
|
||||
```
|
||||
203
docs/components/TextInput.md
Normal file
203
docs/components/TextInput.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# TextInput
|
||||
|
||||
Accessible single- and multi-line text input via a keyboard. Supports features
|
||||
such as auto-complete, auto-focus, placeholder text, and event callbacks.
|
||||
|
||||
Note: some props are exclusive to or excluded from `multiline`.
|
||||
|
||||
Unsupported React Native props:
|
||||
`autoCapitalize`,
|
||||
`autoCorrect`,
|
||||
`onEndEditing`,
|
||||
`onSubmitEditing`,
|
||||
`clearButtonMode` (ios),
|
||||
`enablesReturnKeyAutomatically` (ios),
|
||||
`returnKeyType` (ios),
|
||||
`selectionState` (ios),
|
||||
`textAlign` (android),
|
||||
`textAlignVertical` (android),
|
||||
`underlineColorAndroid` (android)
|
||||
|
||||
## Props
|
||||
|
||||
(web) **accessibilityLabel**: string
|
||||
|
||||
Defines the text label available to assistive technologies upon interaction
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
(web) **autoComplete**: bool = false
|
||||
|
||||
Indicates whether the value of the control can be automatically completed by the browser.
|
||||
|
||||
**autoFocus**: bool = false
|
||||
|
||||
If true, focuses the input on `componentDidMount`. Only the first form element
|
||||
in a document with `autofocus` is focused.
|
||||
|
||||
**clearTextOnFocus**: bool = false
|
||||
|
||||
If `true`, clears the text field automatically when focused.
|
||||
|
||||
**defaultValue**: string
|
||||
|
||||
Provides an initial value that will change when the user starts typing. Useful
|
||||
for simple use-cases where you don't want to deal with listening to events and
|
||||
updating the `value` prop to keep the controlled state in sync.
|
||||
|
||||
**editable**: bool = true
|
||||
|
||||
If `false`, text is not editable (i.e., read-only).
|
||||
|
||||
**keyboardType**: oneOf('default', 'email-address', 'numeric', 'phone-pad', 'url') = 'default'
|
||||
|
||||
Determines which keyboard to open.
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**maxLength**: number
|
||||
|
||||
Limits the maximum number of characters that can be entered.
|
||||
|
||||
(web) **maxNumberOfLines**: number = numberOfLines
|
||||
|
||||
Limits the maximum number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**multiline**: bool = false
|
||||
|
||||
If true, the text input can be multiple lines.
|
||||
|
||||
**numberOfLines**: number = 2
|
||||
|
||||
Sets the initial number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**onBlur**: function
|
||||
|
||||
Callback that is called when the text input is blurred.
|
||||
|
||||
**onChange**: function
|
||||
|
||||
Callback that is called when the text input's text changes.
|
||||
|
||||
**onChangeText**: function
|
||||
|
||||
Callback that is called when the text input's text changes. The text is passed
|
||||
as an argument to the callback handler.
|
||||
|
||||
**onFocus**: function
|
||||
|
||||
Callback that is called when the text input is focused.
|
||||
|
||||
**onLayout**: function
|
||||
|
||||
TODO
|
||||
|
||||
(web) **onSelectionChange**: function
|
||||
|
||||
Callback that is called when the text input's selection changes. The following
|
||||
object is passed as an argument to the callback handler.
|
||||
|
||||
```js
|
||||
{
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent
|
||||
}
|
||||
```
|
||||
|
||||
**placeholder**: string
|
||||
|
||||
The string that will be rendered before text input has been entered.
|
||||
|
||||
**placeholderTextColor**: string
|
||||
|
||||
TODO. The text color of the placeholder string.
|
||||
|
||||
**secureTextEntry**: bool = false
|
||||
|
||||
If true, the text input obscures the text entered so that sensitive text like
|
||||
passwords stay secure.
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**selectTextOnFocus**: bool = false
|
||||
|
||||
If `true`, all text will automatically be selected on focus.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
+ `color`
|
||||
+ `direction`
|
||||
+ `fontFamily`
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `textAlign`
|
||||
+ `textDecoration`
|
||||
+ `textTransform`
|
||||
|
||||
**testID**: string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**value**: string
|
||||
|
||||
The value to show for the text input. `TextInput` is a controlled component,
|
||||
which means the native `value` will be forced to match this prop if provided.
|
||||
Read about how [React form
|
||||
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
|
||||
user edits to the value set `editable={false}`.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { TextInput } from 'react-native-web'
|
||||
|
||||
const { Component } = React
|
||||
|
||||
class AppTextInput extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { isFocused: false }
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
this.setState({ isFocused: true })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
accessibilityLabel='Write a status update'
|
||||
maxNumberOfLines={5}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
placeholder={`What's happening?`}
|
||||
style={
|
||||
...styles.default
|
||||
...(this.state.isFocused && styles.focused)
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
default: {
|
||||
borderColor: 'gray',
|
||||
borderWidth: '0 0 2px 0'
|
||||
},
|
||||
focused: {
|
||||
borderColor: 'blue'
|
||||
}
|
||||
}
|
||||
```
|
||||
104
docs/components/Touchable.md
Normal file
104
docs/components/Touchable.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Touchable
|
||||
|
||||
A wrapper for making views respond to mouse, keyboard, and touch presses. On
|
||||
press in, the touchable area can display a highlight color, and the opacity of
|
||||
the wrapped view can be decreased.
|
||||
|
||||
This component combines the various `Touchable*` components from React Native.
|
||||
|
||||
Unsupported React Native props:
|
||||
`accessibilityComponentType` (android) – use `accessibilityRole`,
|
||||
`accessibilityTraits` (ios) – use `accessibilityRole`,
|
||||
`onHideUnderlay` – use `onPressOut`,
|
||||
`onShowUnderlay` – use `onPressIn`,
|
||||
`underlayColor` – use `activeUnderlayColor`
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: string
|
||||
|
||||
Overrides the text that's read by the screen reader when the user interacts
|
||||
with the element.
|
||||
|
||||
(web) **accessibilityRole**: oneOf(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
||||
actions. Generally, accessibility APIs do not provide a means of notifying
|
||||
assistive technologies of a `role` value change.
|
||||
|
||||
**accessible**: bool = true
|
||||
|
||||
When `false`, the view is hidden from screenreaders.
|
||||
|
||||
**activeOpacity**: number = 1
|
||||
|
||||
Sets the opacity of the child view when `onPressIn` is called. The opacity is
|
||||
reset when `onPressOut` is called.
|
||||
|
||||
(web) **activeUnderlayColor**: string = 'transparent'
|
||||
|
||||
Sets the color of the background highlight when `onPressIn` is called. The
|
||||
highlight is removed when `onPressOut` is called.
|
||||
|
||||
**children**: element
|
||||
|
||||
A single child element.
|
||||
|
||||
**delayLongPress**: number = 1000
|
||||
|
||||
Delay in ms, from `onPressIn`, before `onLongPress` is called.
|
||||
|
||||
**delayPressIn**: number = 0
|
||||
|
||||
(TODO)
|
||||
|
||||
Delay in ms, from the start of the touch, before `onPressIn` is called.
|
||||
|
||||
**delayPressOut**: number = 0
|
||||
|
||||
(TODO)
|
||||
|
||||
Delay in ms, from the release of the touch, before `onPressOut` is called.
|
||||
|
||||
**onLayout**: function
|
||||
|
||||
(TODO)
|
||||
|
||||
**onLongPress**: function
|
||||
|
||||
**onPress**: function
|
||||
|
||||
**onPressIn**: function
|
||||
|
||||
**onPressOut**: function
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Touchable } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Touchable />
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
190
docs/components/View.md
Normal file
190
docs/components/View.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# View
|
||||
|
||||
`View` is the fundamental UI building block. It is a component that supports
|
||||
style, layout with flexbox, and accessibility controls. It can be nested
|
||||
inside another `View` and has 0-to-many children of any type.
|
||||
|
||||
Unsupported React Native props:
|
||||
`accessibilityComponentType` (android) – use `accessibilityRole`,
|
||||
`accessibilityTraits` (ios) – use `accessibilityRole`,
|
||||
`collapsable` (android),
|
||||
`importantForAccessibility` (android),
|
||||
`needsOffscreenAlphaCompositing` (android),
|
||||
`onAccessibilityTap`,
|
||||
`onMagicTap`,
|
||||
`onMoveShouldSetResponder`,
|
||||
`onResponder*`,
|
||||
`onStartShouldSetResponder`,
|
||||
`onStartShouldSetResponderCapture`
|
||||
`removeClippedSubviews` (ios),
|
||||
`renderToHardwareTextureAndroid` (android),
|
||||
`shouldRasterizeIOS` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `View` will transfer all other props to the rendered HTML element.
|
||||
|
||||
**accessibilityLabel**: string
|
||||
|
||||
Defines the text available to assistive technologies upon interaction with the
|
||||
element. (This is implemented using `aria-label`.)
|
||||
|
||||
**accessibilityLiveRegion**: oneOf('assertive', 'off', 'polite') = 'off'
|
||||
|
||||
Indicates to assistive technologies whether to notify the user when the view
|
||||
changes. The values of this attribute are expressed in degrees of importance.
|
||||
When regions are specified as `polite` (recommended), updates take low
|
||||
priority. When regions are specified as `assertive`, assistive technologies
|
||||
will interrupt and immediately notify the user. (This is implemented using
|
||||
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
||||
|
||||
(web) **accessibilityRole**: oneOf(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
||||
actions. Generally, accessibility APIs do not provide a means of notifying
|
||||
assistive technologies of a `role` value change.
|
||||
|
||||
**accessible**: bool = true
|
||||
|
||||
When `false`, the view is hidden from assistive technologies. (This is
|
||||
implemented using `aria-hidden`.)
|
||||
|
||||
(web) **component**: function | string = 'div'
|
||||
|
||||
The React Component for this view.
|
||||
|
||||
**onLayout**: function
|
||||
|
||||
(TODO)
|
||||
|
||||
**pointerEvents**: oneOf('auto', 'box-only', 'box-none', 'none') = 'auto'
|
||||
|
||||
Configure the `pointerEvents` of the view. The enhanced `pointerEvents` modes
|
||||
provided are not part of the CSS spec, therefore, `pointerEvents` is excluded
|
||||
from `style`.
|
||||
|
||||
`box-none` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-none { pointer-events: none }
|
||||
.box-none * { pointer-events: auto }
|
||||
```
|
||||
|
||||
`box-only` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-only { pointer-events: auto }
|
||||
.box-only * { pointer-events: none }
|
||||
```
|
||||
|
||||
**style**: style
|
||||
|
||||
+ `alignContent`
|
||||
+ `alignItems`
|
||||
+ `alignSelf`
|
||||
+ `backfaceVisibility`
|
||||
+ `backgroundAttachment`
|
||||
+ `backgroundClip`
|
||||
+ `backgroundColor`
|
||||
+ `backgroundImage`
|
||||
+ `backgroundOrigin`
|
||||
+ `backgroundPosition`
|
||||
+ `backgroundRepeat`
|
||||
+ `backgroundSize`
|
||||
+ `borderColor`
|
||||
+ `borderRadius`
|
||||
+ `borderStyle`
|
||||
+ `borderWidth`
|
||||
+ `bottom`
|
||||
+ `boxShadow`
|
||||
+ `boxSizing`
|
||||
+ `cursor`
|
||||
+ `flexBasis`
|
||||
+ `flexDirection`
|
||||
+ `flexGrow`
|
||||
+ `flexShrink`
|
||||
+ `flexWrap`
|
||||
+ `height`
|
||||
+ `justifyContent`
|
||||
+ `left`
|
||||
+ `margin`
|
||||
+ `maxHeight`
|
||||
+ `maxWidth`
|
||||
+ `minHeight`
|
||||
+ `minWidth`
|
||||
+ `opacity`
|
||||
+ `order`
|
||||
+ `overflow`
|
||||
+ `overflowX`
|
||||
+ `overflowY`
|
||||
+ `padding`
|
||||
+ `position`
|
||||
+ `right`
|
||||
+ `top`
|
||||
+ `transform`
|
||||
+ `userSelect`
|
||||
+ `visibility`
|
||||
+ `width`
|
||||
+ `zIndex`
|
||||
|
||||
Default:
|
||||
|
||||
```js
|
||||
{
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative'
|
||||
};
|
||||
```
|
||||
|
||||
(See [facebook/css-layout](https://github.com/facebook/css-layout)).
|
||||
|
||||
**testID**: string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { View } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class Example extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
{
|
||||
['1', '2', '3', '4', '5'].map((value, i) => {
|
||||
return <View children={value} key={i} style={styles.cell} />
|
||||
})
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
cell: {
|
||||
flexGrow: 1
|
||||
}
|
||||
}
|
||||
|
||||
export default Example
|
||||
```
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
@@ -12,8 +12,8 @@ convert inline styles to static CSS:
|
||||
|
||||
## Style syntax: native vs proprietary data structure
|
||||
|
||||
React Web SDK (in a divergence from React Native) represents style using plain
|
||||
JS objects:
|
||||
React Native for Web diverges from React Native by using plain JS objects for
|
||||
styles:
|
||||
|
||||
```js
|
||||
<Text style={styles.root}>...</Text>
|
||||
@@ -46,19 +46,18 @@ const styles = Stylesheet.create({
|
||||
|
||||
## JS-to-CSS: conversion strategies
|
||||
|
||||
One strategy for converting styles from JS to CSS is to map style objects to
|
||||
CSS rules. Another strategy is to map declarations to declarataions.
|
||||
|
||||

|
||||
|
||||
Mapping entire `style` objects to CSS rules can lead to increasingly large CSS
|
||||
files. Each new component adds new rules to the stylesheet.
|
||||
|
||||
React Web SDK includes a proof-of-concept for the strategy of automatically
|
||||
mapping unique declarations to declarations, via a unique selector for each
|
||||
declaration. This strategy results in smaller CSS files because an application
|
||||
has fewer unique declarations than total declarations. Creating a new
|
||||
component with no new unique declarations results in no change to the CSS file.
|
||||

|
||||
|
||||
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:
|
||||
|
||||
@@ -92,10 +91,9 @@ And is backed by:
|
||||
|
||||
The current implementation uses a precomputed CSS library of single-declaration
|
||||
rules, with obfuscated selectors. This handles a signficant portion of possible
|
||||
declarations. But a build-time implementation would produce more accurate CSS
|
||||
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
|
||||
@@ -121,5 +119,5 @@ 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 SDK's
|
||||
`TextInput` component (see React Native's API).
|
||||
`::placeholder` it might be necessary to reimplement it in the `TextInput`
|
||||
component (see React Native's API).
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Image, Text, View } from '../dist/main';
|
||||
|
||||
class Example extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.grid}>
|
||||
{[1,2,3,4,5,6].map((item, i) => {
|
||||
return (
|
||||
<View key={i} style={{ ...styles.box, ...(item === 6 && styles.boxFull) }}>
|
||||
<Text style={{ fontSize: '2rem' }}>{item}</Text>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
|
||||
<View style={{
|
||||
alignItems: 'center',
|
||||
borderWidth: '1px',
|
||||
justifyContent: 'center',
|
||||
marginTop: '10px',
|
||||
height: '200px'
|
||||
}}>
|
||||
<Text>This should be centered</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
grid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
box: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'lightblue',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderColor: 'blue',
|
||||
borderWidth: '5px'
|
||||
},
|
||||
boxFull: {
|
||||
width: '100%'
|
||||
}
|
||||
}
|
||||
|
||||
React.render(<Example />, document.getElementById('react-root'));
|
||||
@@ -1,6 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../dist/react-web-sdk.css">
|
||||
<div id="react-root"></div>
|
||||
<script src="../dist/example.js"></script>
|
||||
@@ -1,19 +0,0 @@
|
||||
module.exports = {
|
||||
entry: {
|
||||
example: './example.js'
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: { cacheDirectory: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
output: {
|
||||
filename: 'example.js',
|
||||
path: '../dist'
|
||||
}
|
||||
};
|
||||
58
package.json
58
package.json
@@ -1,37 +1,57 @@
|
||||
{
|
||||
"name": "react-web-sdk",
|
||||
"version": "0.0.2",
|
||||
"description": "UI SDK based on react-native",
|
||||
"main": "dist/main.js",
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.6",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/react-native-web.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf ./dist && npm install",
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"build:watch": "npm run build -- --watch",
|
||||
"build:example": "npm run build && cd example && webpack --config ./webpack.config.js",
|
||||
"build:example:watch": "npm run build:example -- --watch"
|
||||
"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",
|
||||
"lint": "eslint config src",
|
||||
"prepublish": "NODE_ENV=publish npm run build",
|
||||
"test:specs": "NODE_ENV=test karma start config/karma.config.js",
|
||||
"test:specs:watch": "npm run test:specs -- --no-single-run",
|
||||
"test": "npm run test:specs && npm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^0.13.3"
|
||||
"react": ">=0.13.3",
|
||||
"react-swipeable": "^3.0.2",
|
||||
"react-tappable": "^0.6.0",
|
||||
"react-textarea-autosize": "^2.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer-core": "^5.2.0",
|
||||
"babel-core": "^5.5.6",
|
||||
"babel-loader": "^5.1.4",
|
||||
"babel-runtime": "^5.5.6",
|
||||
"css-loader": "^0.15.1",
|
||||
"extract-text-webpack-plugin": "^0.8.1",
|
||||
"autoprefixer-loader": "^3.1.0",
|
||||
"babel-core": "^5.8.23",
|
||||
"babel-eslint": "^4.1.1",
|
||||
"babel-loader": "^5.3.2",
|
||||
"babel-plugin-typecheck": "^1.2.0",
|
||||
"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-chrome-launcher": "^0.2.0",
|
||||
"karma-firefox-launcher": "^0.1.6",
|
||||
"karma-mocha": "^0.2.0",
|
||||
"karma-sourcemap-loader": "^0.3.5",
|
||||
"karma-webpack": "^1.7.0",
|
||||
"mocha": "^2.3.0",
|
||||
"node-libs-browser": "^0.5.2",
|
||||
"postcss-loader": "^0.4.4",
|
||||
"object-assign": "^4.0.1",
|
||||
"style-loader": "^0.12.3",
|
||||
"webpack": "^1.9.10"
|
||||
"webpack": "^1.12.1",
|
||||
"webpack-dev-server": "^1.10.1"
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/necolas/react-web-sdk.git"
|
||||
"url": "git://github.com/necolas/react-native-web.git"
|
||||
}
|
||||
}
|
||||
|
||||
42
src/components/CoreComponent/index.js
Normal file
42
src/components/CoreComponent/index.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import restyle from './modules/restyle'
|
||||
import stylePropTypes from './modules/stylePropTypes'
|
||||
|
||||
class CoreComponent extends React.Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
component: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.string
|
||||
]),
|
||||
style: PropTypes.object,
|
||||
testID: PropTypes.string
|
||||
}
|
||||
|
||||
static stylePropTypes = stylePropTypes;
|
||||
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
component: 'div'
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
component: Component,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...other}
|
||||
{...restyle({ className, style })}
|
||||
data-testid={testID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CoreComponent
|
||||
@@ -4,7 +4,7 @@ export default function prefixStyles(style) {
|
||||
WebkitFlexBasis: style.flexBasis,
|
||||
msFlexBasis: style.flexBasis,
|
||||
...style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('flexGrow')) {
|
||||
@@ -13,7 +13,7 @@ export default function prefixStyles(style) {
|
||||
WebkitFlexGrow: style.flexGrow,
|
||||
msFlexPositive: style.flexGrow,
|
||||
...style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('flexShrink')) {
|
||||
@@ -21,7 +21,7 @@ export default function prefixStyles(style) {
|
||||
WebkitFlexShrink: style.flexShrink,
|
||||
msFlexNegative: style.flexShrink,
|
||||
...style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: adding `;` to the string value prevents React from automatically
|
||||
@@ -30,9 +30,9 @@ export default function prefixStyles(style) {
|
||||
style = {
|
||||
WebkitBoxOrdinalGroup: `${parseInt(style.order, 10) + 1};`,
|
||||
WebkitOrder: `${style.order}`,
|
||||
msFlexOrder: `${style.order};`,
|
||||
msFlexOrder: `${style.order}`,
|
||||
...style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (style.hasOwnProperty('transform')) {
|
||||
@@ -40,8 +40,8 @@ export default function prefixStyles(style) {
|
||||
WebkitTransform: style.transform,
|
||||
msTransform: style.transform,
|
||||
...style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
return style
|
||||
}
|
||||
40
src/components/CoreComponent/modules/restyle.js
Normal file
40
src/components/CoreComponent/modules/restyle.js
Normal file
@@ -0,0 +1,40 @@
|
||||
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 }
|
||||
}
|
||||
97
src/components/CoreComponent/modules/stylePropTypes.js
Normal file
97
src/components/CoreComponent/modules/stylePropTypes.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import { PropTypes } from 'react'
|
||||
|
||||
const numberOrString = PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string
|
||||
])
|
||||
|
||||
const { string } = PropTypes
|
||||
|
||||
export default {
|
||||
alignContent: string,
|
||||
alignItems: string,
|
||||
alignSelf: string,
|
||||
backfaceVisibility: string,
|
||||
backgroundAttachment: string,
|
||||
backgroundClip: string,
|
||||
backgroundColor: string,
|
||||
backgroundImage: string,
|
||||
backgroundOrigin: string,
|
||||
backgroundPosition: string,
|
||||
backgroundRepeat: string,
|
||||
backgroundSize: string,
|
||||
borderColor: numberOrString,
|
||||
borderBottomColor: numberOrString,
|
||||
borderLeftColor: numberOrString,
|
||||
borderRightColor: numberOrString,
|
||||
borderTopColor: numberOrString,
|
||||
borderRadius: numberOrString,
|
||||
borderTopLeftRadius: numberOrString,
|
||||
borderTopRightRadius: numberOrString,
|
||||
borderBottomLeftRadius: numberOrString,
|
||||
borderBottomRightRadius: numberOrString,
|
||||
borderStyle: numberOrString,
|
||||
borderBottomStyle: numberOrString,
|
||||
borderLeftStyle: numberOrString,
|
||||
borderRightStyle: numberOrString,
|
||||
borderTopStyle: numberOrString,
|
||||
borderWidth: numberOrString,
|
||||
borderBottomWidth: numberOrString,
|
||||
borderLeftWidth: numberOrString,
|
||||
borderRightWidth: numberOrString,
|
||||
borderTopWidth: numberOrString,
|
||||
bottom: numberOrString,
|
||||
boxSizing: string,
|
||||
clear: string,
|
||||
color: string,
|
||||
cursor: string,
|
||||
direction: string,
|
||||
display: string,
|
||||
flexBasis: string,
|
||||
flexDirection: string,
|
||||
flexGrow: numberOrString,
|
||||
flexShrink: numberOrString,
|
||||
flexWrap: string,
|
||||
float: string,
|
||||
font: string,
|
||||
fontFamily: string,
|
||||
fontSize: numberOrString,
|
||||
fontStyle: string,
|
||||
fontWeight: string,
|
||||
height: numberOrString,
|
||||
justifyContent: string,
|
||||
left: numberOrString,
|
||||
letterSpacing: string,
|
||||
lineHeight: numberOrString,
|
||||
margin: numberOrString,
|
||||
marginBottom: numberOrString,
|
||||
marginLeft: numberOrString,
|
||||
marginRight: numberOrString,
|
||||
marginTop: numberOrString,
|
||||
maxHeight: numberOrString,
|
||||
maxWidth: numberOrString,
|
||||
minHeight: numberOrString,
|
||||
minWidth: numberOrString,
|
||||
opacity: numberOrString,
|
||||
order: numberOrString,
|
||||
overflow: string,
|
||||
overflowX: string,
|
||||
overflowY: string,
|
||||
padding: numberOrString,
|
||||
paddingBottom: numberOrString,
|
||||
paddingLeft: numberOrString,
|
||||
paddingRight: numberOrString,
|
||||
paddingTop: numberOrString,
|
||||
position: string,
|
||||
right: numberOrString,
|
||||
textAlign: string,
|
||||
textDecoration: string,
|
||||
textTransform: string,
|
||||
top: numberOrString,
|
||||
userSelect: string,
|
||||
visibility: string,
|
||||
whiteSpace: string,
|
||||
width: numberOrString,
|
||||
wordWrap: string,
|
||||
zIndex: numberOrString
|
||||
}
|
||||
4
src/components/Image/ImageStylePropTypes.js
Normal file
4
src/components/Image/ImageStylePropTypes.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import View from '../View'
|
||||
export default {
|
||||
...(View.stylePropTypes)
|
||||
}
|
||||
217
src/components/Image/index.js
Normal file
217
src/components/Image/index.js
Normal file
@@ -0,0 +1,217 @@
|
||||
/* global window */
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import ImageStylePropTypes from './ImageStylePropTypes'
|
||||
import React, { PropTypes } from 'react'
|
||||
import View from '../View'
|
||||
|
||||
const STATUS_ERRORED = 'ERRORED'
|
||||
const STATUS_LOADED = 'LOADED'
|
||||
const STATUS_LOADING = 'LOADING'
|
||||
const STATUS_PENDING = 'PENDING'
|
||||
const STATUS_IDLE = 'IDLE'
|
||||
|
||||
const imageStyleKeys = Object.keys(ImageStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
initial: {
|
||||
alignSelf: 'flex-start',
|
||||
backgroundColor: 'lightgray',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: '100% 100%'
|
||||
},
|
||||
img: {
|
||||
borderWidth: 0,
|
||||
height: 'auto',
|
||||
maxHeight: '100%',
|
||||
maxWidth: '100%',
|
||||
opacity: 0
|
||||
},
|
||||
children: {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0
|
||||
},
|
||||
resizeMode: {
|
||||
contain: {
|
||||
backgroundSize: 'contain'
|
||||
},
|
||||
cover: {
|
||||
backgroundSize: 'cover'
|
||||
},
|
||||
none: {
|
||||
backgroundSize: 'auto'
|
||||
},
|
||||
stretch: {
|
||||
backgroundSize: '100% 100%'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Image extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
// state
|
||||
this.state = { status: props.source.uri ? STATUS_PENDING : STATUS_IDLE }
|
||||
|
||||
// autobinding
|
||||
this._onError = this._onError.bind(this)
|
||||
this._onLoad = this._onLoad.bind(this)
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
children: PropTypes.any,
|
||||
defaultSource: PropTypes.object,
|
||||
onError: PropTypes.func,
|
||||
onLoad: PropTypes.func,
|
||||
onLoadEnd: PropTypes.func,
|
||||
onLoadStart: PropTypes.func,
|
||||
resizeMode: PropTypes.oneOf(['contain', 'cover', 'none', 'stretch']),
|
||||
source: PropTypes.object,
|
||||
style: PropTypes.shape(ImageStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
}
|
||||
|
||||
static stylePropTypes = ImageStylePropTypes
|
||||
|
||||
static defaultProps = {
|
||||
accessible: true,
|
||||
defaultSource: {},
|
||||
resizeMode: 'stretch',
|
||||
source: {},
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
_createImageLoader() {
|
||||
const { source } = this.props
|
||||
|
||||
this._destroyImageLoader()
|
||||
this.image = new window.Image()
|
||||
this.image.onerror = this._onError
|
||||
this.image.onload = this._onLoad
|
||||
this.image.src = source.uri
|
||||
this._onLoadStart()
|
||||
}
|
||||
|
||||
_destroyImageLoader() {
|
||||
if (this.image) {
|
||||
this.image.onload = null
|
||||
this.image.onerror = null
|
||||
this.image = null
|
||||
}
|
||||
}
|
||||
|
||||
_onError(e) {
|
||||
const { onError } = this.props
|
||||
const event = { nativeEvent: e }
|
||||
|
||||
this._destroyImageLoader()
|
||||
this.setState({ status: STATUS_ERRORED })
|
||||
this._onLoadEnd()
|
||||
if (onError) onError(event)
|
||||
}
|
||||
|
||||
_onLoad(e) {
|
||||
const { onLoad } = this.props
|
||||
const event = { nativeEvent: e }
|
||||
|
||||
this._destroyImageLoader()
|
||||
this.setState({ status: STATUS_LOADED })
|
||||
this._onLoadEnd()
|
||||
if (onLoad) onLoad(event)
|
||||
}
|
||||
|
||||
_onLoadEnd() {
|
||||
const { onLoadEnd } = this.props
|
||||
if (onLoadEnd) onLoadEnd()
|
||||
}
|
||||
|
||||
_onLoadStart() {
|
||||
const { onLoadStart } = this.props
|
||||
this.setState({ status: STATUS_LOADING })
|
||||
if (onLoadStart) onLoadStart()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.state.status === STATUS_PENDING) {
|
||||
this._createImageLoader()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.status === STATUS_PENDING && !this.image) {
|
||||
this._createImageLoader()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.source.uri !== nextProps.source.uri) {
|
||||
this.setState({
|
||||
status: nextProps.source.uri ? STATUS_PENDING : STATUS_IDLE
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._destroyImageLoader()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessible,
|
||||
children,
|
||||
defaultSource,
|
||||
resizeMode,
|
||||
source,
|
||||
style,
|
||||
testID
|
||||
} = this.props
|
||||
|
||||
const isLoaded = this.state.status === STATUS_LOADED
|
||||
const defaultImage = defaultSource.uri || null
|
||||
const displayImage = !isLoaded ? defaultImage : source.uri
|
||||
const resolvedStyle = pickProps(style, imageStyleKeys)
|
||||
const backgroundImage = displayImage ? `url("${displayImage}")` : null
|
||||
|
||||
/**
|
||||
* Image is a non-stretching View. The image is displayed as a background
|
||||
* image to support `resizeMode`. The HTML image is hidden but used to
|
||||
* provide the correct responsive image dimensions, and to support the
|
||||
* image context menu. Child content is rendered into an element absolutely
|
||||
* positioned over the image.
|
||||
*/
|
||||
return (
|
||||
<View
|
||||
_className='Image'
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole='img'
|
||||
accessible={accessible}
|
||||
component='div'
|
||||
style={{
|
||||
...(styles.initial),
|
||||
...resolvedStyle,
|
||||
...(backgroundImage && { backgroundImage }),
|
||||
...(styles.resizeMode[resizeMode])
|
||||
}}
|
||||
testID={testID}
|
||||
>
|
||||
<img
|
||||
src={displayImage}
|
||||
style={styles.img}
|
||||
/>
|
||||
{children ? (
|
||||
<View children={children} pointerEvents='box-none' style={styles.children} />
|
||||
) : null}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Image
|
||||
73
src/components/Image/index.spec.js
Normal file
73
src/components/Image/index.spec.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { assertProps, render, renderToDOM } from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import Image from '.'
|
||||
|
||||
suite('Image', () => {
|
||||
test('default accessibility', () => {
|
||||
const dom = renderToDOM(<Image />)
|
||||
assert.equal(dom.getAttribute('role'), 'img')
|
||||
})
|
||||
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Image)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Image)
|
||||
})
|
||||
|
||||
test.skip('prop "children"', () => { })
|
||||
|
||||
test('prop "defaultSource"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' }
|
||||
const dom = renderToDOM(<Image defaultSource={defaultSource} />)
|
||||
const backgroundImage = dom.style.backgroundImage
|
||||
assert(backgroundImage.indexOf(defaultSource.uri) > -1)
|
||||
})
|
||||
|
||||
test('prop "onError"', function (done) {
|
||||
this.timeout(5000)
|
||||
|
||||
function onError(e) {
|
||||
assert.equal(e.nativeEvent.type, 'error')
|
||||
done()
|
||||
}
|
||||
|
||||
render(<Image
|
||||
onError={onError}
|
||||
source={{ uri: 'https://google.com/favicon.icox' }}
|
||||
/>)
|
||||
})
|
||||
|
||||
test('prop "onLoad"', function (done) {
|
||||
this.timeout(5000)
|
||||
|
||||
function onLoad(e) {
|
||||
assert.equal(e.nativeEvent.type, 'load')
|
||||
done()
|
||||
}
|
||||
|
||||
render(<Image
|
||||
onLoad={onLoad}
|
||||
source={{ uri: 'https://google.com/favicon.ico' }}
|
||||
/>)
|
||||
})
|
||||
|
||||
test.skip('prop "onLoadEnd"', () => { })
|
||||
|
||||
test.skip('prop "onLoadStart"', () => { })
|
||||
|
||||
test.skip('prop "resizeMode"', () => { })
|
||||
|
||||
test.skip('prop "source"', () => { })
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(Image)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(Image)
|
||||
})
|
||||
})
|
||||
20
src/components/ListView/index.js
Normal file
20
src/components/ListView/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ScrollView from '../ScrollView'
|
||||
|
||||
class ListView extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
className: ''
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView {...this.props} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ListView
|
||||
18
src/components/ListView/index.spec.js
Normal file
18
src/components/ListView/index.spec.js
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import ListView from '.'
|
||||
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
function shallowRender(component, context = {}) {
|
||||
const shallowRenderer = React.addons.TestUtils.createRenderer()
|
||||
shallowRenderer.render(component, context)
|
||||
return shallowRenderer.getRenderOutput()
|
||||
}
|
||||
|
||||
suite.skip('ListView', () => {
|
||||
test('prop "children"', () => {})
|
||||
})
|
||||
*/
|
||||
20
src/components/ScrollView/index.js
Normal file
20
src/components/ScrollView/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import View from '../View'
|
||||
|
||||
class ScrollView extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
className: ''
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View {...this.props} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ScrollView
|
||||
13
src/components/ScrollView/index.spec.js
Normal file
13
src/components/ScrollView/index.spec.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
import { assertProps, renderToDOM, shallowRender } from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import ScrollView from '.'
|
||||
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
suite.skip('ScrollView', () => {
|
||||
test('prop "children"', () => {})
|
||||
})
|
||||
*/
|
||||
2
src/components/Swipeable/index.js
Normal file
2
src/components/Swipeable/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import Swipeable from 'react-swipeable'
|
||||
export default Swipeable
|
||||
31
src/components/Text/TextStylePropTypes.js
Normal file
31
src/components/Text/TextStylePropTypes.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
|
||||
export default {
|
||||
...pickProps(CoreComponent.stylePropTypes, [
|
||||
'backgroundColor',
|
||||
'color',
|
||||
'direction',
|
||||
'font',
|
||||
'fontFamily',
|
||||
'fontSize',
|
||||
'fontWeight',
|
||||
'letterSpacing',
|
||||
'lineHeight',
|
||||
'margin',
|
||||
'marginBottom',
|
||||
'marginLeft',
|
||||
'marginRight',
|
||||
'marginTop',
|
||||
'padding',
|
||||
'paddingBottom',
|
||||
'paddingLeft',
|
||||
'paddingRight',
|
||||
'paddingTop',
|
||||
'textAlign',
|
||||
'textDecoration',
|
||||
'textTransform',
|
||||
'whiteSpace',
|
||||
'wordWrap'
|
||||
])
|
||||
}
|
||||
88
src/components/Text/index.js
Normal file
88
src/components/Text/index.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import TextStylePropTypes from './TextStylePropTypes'
|
||||
|
||||
const textStyleKeys = Object.keys(TextStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
initial: {
|
||||
color: 'inherit',
|
||||
display: 'inline-block',
|
||||
font: 'inherit',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
wordWrap: 'break-word'
|
||||
},
|
||||
singleLineStyle: {
|
||||
maxWidth: '100%',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends React.Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
children: PropTypes.any,
|
||||
component: CoreComponent.propTypes.component,
|
||||
numberOfLines: PropTypes.number,
|
||||
onPress: PropTypes.func,
|
||||
style: PropTypes.shape(TextStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
}
|
||||
|
||||
static stylePropTypes = TextStylePropTypes
|
||||
|
||||
static defaultProps = {
|
||||
_className: '',
|
||||
accessible: true,
|
||||
component: 'span',
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
_onPress(e) {
|
||||
if (this.props.onPress) this.props.onPress(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
_className,
|
||||
accessibilityLabel,
|
||||
accessible,
|
||||
children,
|
||||
component,
|
||||
numberOfLines,
|
||||
onPress,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
const className = `Text ${_className}`.trim()
|
||||
const resolvedStyle = pickProps(style, textStyleKeys)
|
||||
|
||||
return (
|
||||
<CoreComponent
|
||||
{...other}
|
||||
aria-hidden={accessible ? null : true}
|
||||
aria-label={accessibilityLabel}
|
||||
children={children}
|
||||
className={className}
|
||||
component={component}
|
||||
onClick={this._onPress.bind(this)}
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
...(numberOfLines === 1 && styles.singleLineStyle)
|
||||
}}
|
||||
testID={testID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Text
|
||||
49
src/components/Text/index.spec.js
Normal file
49
src/components/Text/index.spec.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { assertProps, renderToDOM, shallowRender } from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import Text from '.'
|
||||
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
suite('Text', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Text)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Text)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = 'children'
|
||||
const result = shallowRender(<Text>{children}</Text>)
|
||||
|
||||
assert.equal(result.props.children, children)
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
assertProps.component(Text, 'span')
|
||||
})
|
||||
|
||||
test.skip('prop "numberOfLines"', () => {})
|
||||
|
||||
test('prop "onPress"', (done) => {
|
||||
const dom = renderToDOM(<Text onPress={onPress} />)
|
||||
ReactTestUtils.Simulate.click(dom)
|
||||
|
||||
function onPress(e) {
|
||||
assert(true, 'the "onPress" callback was never called')
|
||||
assert.ok(e.nativeEvent)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(Text)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(Text)
|
||||
})
|
||||
})
|
||||
20
src/components/TextInput/TextInputStylePropTypes.js
Normal file
20
src/components/TextInput/TextInputStylePropTypes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import View from '../View'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
|
||||
export default {
|
||||
...(View.stylePropTypes),
|
||||
...pickProps(CoreComponent.stylePropTypes, [
|
||||
'color',
|
||||
'direction',
|
||||
'fontFamily',
|
||||
'fontSize',
|
||||
'fontStyle',
|
||||
'fontWeight',
|
||||
'letterSpacing',
|
||||
'lineHeight',
|
||||
'textAlign',
|
||||
'textDecoration',
|
||||
'textTransform'
|
||||
])
|
||||
}
|
||||
177
src/components/TextInput/index.js
Normal file
177
src/components/TextInput/index.js
Normal file
@@ -0,0 +1,177 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInputStylePropTypes from './TextInputStylePropTypes'
|
||||
|
||||
const textInputStyleKeys = Object.keys(TextInputStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
initial: {
|
||||
appearance: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: 'black',
|
||||
borderWidth: '1px',
|
||||
boxSizing: 'border-box',
|
||||
color: 'inherit',
|
||||
font: 'inherit',
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
class TextInput extends React.Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
autoComplete: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
clearTextOnFocus: PropTypes.bool,
|
||||
defaultValue: PropTypes.string,
|
||||
editable: PropTypes.bool,
|
||||
keyboardType: PropTypes.oneOf(['default', 'email-address', 'numeric', 'phone-pad', 'url']),
|
||||
maxLength: PropTypes.number,
|
||||
maxNumberOfLines: PropTypes.number,
|
||||
multiline: PropTypes.bool,
|
||||
numberOfLines: PropTypes.number,
|
||||
onBlur: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
onChangeText: PropTypes.func,
|
||||
onFocus: PropTypes.func,
|
||||
onSelectionChange: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
placeholderTextColor: PropTypes.string,
|
||||
secureTextEntry: PropTypes.bool,
|
||||
selectTextOnFocus: PropTypes.bool,
|
||||
style: PropTypes.shape(TextInputStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID,
|
||||
value: PropTypes.string
|
||||
}
|
||||
|
||||
static stylePropTypes = TextInputStylePropTypes
|
||||
|
||||
static defaultProps = {
|
||||
editable: true,
|
||||
keyboardType: 'default',
|
||||
multiline: false,
|
||||
numberOfLines: 2,
|
||||
secureTextEntry: false,
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
const { onBlur } = this.props
|
||||
if (onBlur) onBlur(e)
|
||||
}
|
||||
|
||||
_onChange(e) {
|
||||
const { onChange, onChangeText } = this.props
|
||||
if (onChangeText) onChangeText(e.target.value)
|
||||
if (onChange) onChange(e)
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props
|
||||
const node = React.findDOMNode(this)
|
||||
if (clearTextOnFocus) node.value = ''
|
||||
if (selectTextOnFocus) node.select()
|
||||
if (onFocus) onFocus(e)
|
||||
}
|
||||
|
||||
_onSelectionChange(e) {
|
||||
const { onSelectionChange } = this.props
|
||||
const { selectionDirection, selectionEnd, selectionStart } = e.target
|
||||
const event = {
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent: e.nativeEvent
|
||||
}
|
||||
if (onSelectionChange) onSelectionChange(event)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
autoComplete,
|
||||
autoFocus,
|
||||
defaultValue,
|
||||
editable,
|
||||
keyboardType,
|
||||
maxLength,
|
||||
maxNumberOfLines,
|
||||
multiline,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onChange,
|
||||
onChangeText,
|
||||
onSelectionChange,
|
||||
placeholder,
|
||||
secureTextEntry,
|
||||
style,
|
||||
testID,
|
||||
value
|
||||
} = this.props
|
||||
|
||||
const resolvedStyle = pickProps(style, textInputStyleKeys)
|
||||
let type
|
||||
|
||||
switch (keyboardType) {
|
||||
case 'email-address':
|
||||
type = 'email'
|
||||
break
|
||||
case 'numeric':
|
||||
type = 'number'
|
||||
break
|
||||
case 'phone-pad':
|
||||
type = 'tel'
|
||||
break
|
||||
case 'url':
|
||||
type = 'url'
|
||||
break
|
||||
}
|
||||
|
||||
if (secureTextEntry) {
|
||||
type = 'password'
|
||||
}
|
||||
|
||||
const propsCommon = {
|
||||
'aria-label': accessibilityLabel,
|
||||
autoComplete: autoComplete && 'on',
|
||||
autoFocus,
|
||||
className: 'TextInput',
|
||||
defaultValue,
|
||||
maxLength,
|
||||
onBlur: onBlur && this._onBlur.bind(this),
|
||||
onChange: (onChange || onChangeText) && this._onChange.bind(this),
|
||||
onFocus: this._onFocus.bind(this),
|
||||
onSelect: onSelectionChange && this._onSelectionChange.bind(this),
|
||||
placeholder,
|
||||
readOnly: !editable,
|
||||
style: {
|
||||
...styles.initial,
|
||||
...resolvedStyle
|
||||
},
|
||||
testID,
|
||||
value
|
||||
}
|
||||
|
||||
const propsMultiline = {
|
||||
...propsCommon,
|
||||
component: TextareaAutosize,
|
||||
maxRows: maxNumberOfLines || numberOfLines,
|
||||
minRows: numberOfLines
|
||||
}
|
||||
|
||||
const propsSingleline = {
|
||||
...propsCommon,
|
||||
component: 'input',
|
||||
type
|
||||
}
|
||||
|
||||
return (multiline
|
||||
? <CoreComponent {...propsMultiline} />
|
||||
: <CoreComponent {...propsSingleline} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TextInput
|
||||
222
src/components/TextInput/index.spec.js
Normal file
222
src/components/TextInput/index.spec.js
Normal file
@@ -0,0 +1,222 @@
|
||||
import * as utils from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import TextInput from '.'
|
||||
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
suite('TextInput', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
utils.assertProps.accessibilityLabel(TextInput)
|
||||
})
|
||||
|
||||
test('prop "autoComplete"', () => {
|
||||
// off
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), undefined)
|
||||
// on
|
||||
dom = utils.renderToDOM(<TextInput autoComplete />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), 'on')
|
||||
})
|
||||
|
||||
test('prop "autoFocus"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.deepEqual(document.activeElement, document.body)
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput autoFocus />)
|
||||
assert.deepEqual(document.activeElement, dom)
|
||||
})
|
||||
|
||||
test('prop "clearTextOnFocus"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
utils.requiresFocus(() => {
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, defaultValue)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput clearTextOnFocus defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, '')
|
||||
})
|
||||
})
|
||||
|
||||
test('prop "defaultValue"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
const result = utils.shallowRender(<TextInput defaultValue={defaultValue} />)
|
||||
assert.equal(result.props.defaultValue, defaultValue)
|
||||
})
|
||||
|
||||
test('prop "editable"', () => {
|
||||
// true
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('readonly'), undefined)
|
||||
// false
|
||||
dom = utils.renderToDOM(<TextInput editable={false} />)
|
||||
assert.equal(dom.getAttribute('readonly'), '')
|
||||
})
|
||||
|
||||
test('prop "keyboardType"', () => {
|
||||
// default
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='default' />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
// email-address
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='email-address' />)
|
||||
assert.equal(dom.getAttribute('type'), 'email')
|
||||
// numeric
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='numeric' />)
|
||||
assert.equal(dom.getAttribute('type'), 'number')
|
||||
// phone-pad
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='phone-pad' />)
|
||||
assert.equal(dom.getAttribute('type'), 'tel')
|
||||
// url
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='url' />)
|
||||
assert.equal(dom.getAttribute('type'), 'url')
|
||||
})
|
||||
|
||||
test('prop "maxLength"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('maxlength'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput maxLength={10} />)
|
||||
assert.equal(dom.getAttribute('maxlength'), '10')
|
||||
})
|
||||
|
||||
test('prop "maxNumberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
const value = (() => {
|
||||
let str = ''
|
||||
while (str.length < 100) str += 'x'
|
||||
return str
|
||||
}())
|
||||
let dom = utils.renderAndInject(
|
||||
<TextInput
|
||||
maxNumberOfLines={3}
|
||||
multiline
|
||||
style={style}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
const height = dom.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 60, height)
|
||||
assert.ok(height <= 66, height)
|
||||
})
|
||||
|
||||
test('prop "multiline"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput multiline />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
// missing multiline
|
||||
let dom = utils.renderToDOM(<TextInput numberOfLines={2} />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
// with multiline
|
||||
dom = utils.renderAndInject(<TextInput multiline numberOfLines={2} style={style} />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
const height = dom.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 40)
|
||||
assert.ok(height <= 45)
|
||||
})
|
||||
|
||||
test('prop "onBlur"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onBlur={onBlur} />)
|
||||
ReactTestUtils.Simulate.blur(input)
|
||||
function onBlur(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onChange"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onChange={onChange} />)
|
||||
ReactTestUtils.Simulate.change(input)
|
||||
function onChange(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onChangeText"', (done) => {
|
||||
const newText = 'newText'
|
||||
const input = utils.renderToDOM(<TextInput onChangeText={onChangeText} />)
|
||||
ReactTestUtils.Simulate.change(input, { target: { value: newText } })
|
||||
function onChangeText(text) {
|
||||
assert.equal(text, newText)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onFocus"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onFocus={onFocus} />)
|
||||
ReactTestUtils.Simulate.focus(input)
|
||||
function onFocus(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test.skip('prop "onLayout"', () => {})
|
||||
|
||||
test('prop "onSelectionChange"', (done) => {
|
||||
const input = utils.renderAndInject(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />)
|
||||
ReactTestUtils.Simulate.select(input, { target: { selectionStart: 0, selectionEnd: 3 } })
|
||||
function onSelectionChange(e) {
|
||||
assert.equal(e.selectionEnd, 3)
|
||||
assert.equal(e.selectionStart, 0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test.skip('prop "placeholder"', () => {})
|
||||
|
||||
test.skip('prop "placeholderTextColor"', () => {})
|
||||
|
||||
test('prop "secureTextEntry"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), 'password')
|
||||
// ignored for multiline
|
||||
dom = utils.renderToDOM(<TextInput multiline secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
})
|
||||
|
||||
test('prop "selectTextOnFocus"', () => {
|
||||
const text = 'Text'
|
||||
utils.requiresFocus(() => {
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={text} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 0)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput defaultValue={text} selectTextOnFocus />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 4)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
})
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
utils.assertProps.style(TextInput)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
utils.assertProps.testID(TextInput)
|
||||
})
|
||||
|
||||
test('prop "value"', () => {
|
||||
const value = 'value'
|
||||
const result = utils.shallowRender(<TextInput value={value} />)
|
||||
assert.equal(result.props.value, value)
|
||||
})
|
||||
})
|
||||
134
src/components/Touchable/index.js
Normal file
134
src/components/Touchable/index.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import Tappable from 'react-tappable'
|
||||
import View from '../View'
|
||||
|
||||
const styles = {
|
||||
initial: {
|
||||
...View.defaultProps.style,
|
||||
cursor: 'pointer',
|
||||
userSelect: undefined
|
||||
}
|
||||
}
|
||||
|
||||
class Touchable extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
isActive: false
|
||||
}
|
||||
|
||||
this._onLongPress = this._onLongPress.bind(this)
|
||||
this._onPress = this._onPress.bind(this)
|
||||
this._onPressIn = this._onPressIn.bind(this)
|
||||
this._onPressOut = this._onPressOut.bind(this)
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityRole: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
activeOpacity: PropTypes.number,
|
||||
activeUnderlayColor: PropTypes.string,
|
||||
children: PropTypes.element,
|
||||
delayLongPress: PropTypes.number,
|
||||
delayPressIn: PropTypes.number,
|
||||
delayPressOut: PropTypes.number,
|
||||
onLongPress: PropTypes.func,
|
||||
onPress: PropTypes.func,
|
||||
onPressIn: PropTypes.func,
|
||||
onPressOut: PropTypes.func,
|
||||
style: View.propTypes.style
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
accessibilityRole: 'button',
|
||||
activeOpacity: 1,
|
||||
activeUnderlayColor: 'transparent',
|
||||
component: 'div',
|
||||
delayLongPress: 1000,
|
||||
delayPressIn: 0,
|
||||
delayPressOut: 0,
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
_getChildren() {
|
||||
const { activeOpacity, children } = this.props
|
||||
return React.cloneElement(React.Children.only(children), {
|
||||
style: {
|
||||
...children.props.style,
|
||||
...(this.state.isActive && { opacity: activeOpacity })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_onKeyEnter(e, callback) {
|
||||
var ENTER = 13
|
||||
if (e.keyCode === ENTER) {
|
||||
callback(e)
|
||||
}
|
||||
}
|
||||
|
||||
_onLongPress(e) {
|
||||
if (this.props.onLongPress) this.props.onLongPress(e)
|
||||
}
|
||||
|
||||
_onPress(e) {
|
||||
if (this.props.onPress) this.props.onPress(e)
|
||||
}
|
||||
|
||||
_onPressIn(e) {
|
||||
this.setState({ isActive: true })
|
||||
if (this.props.onPressIn) this.props.onPressIn(e)
|
||||
}
|
||||
|
||||
_onPressOut(e) {
|
||||
this.setState({ isActive: false })
|
||||
if (this.props.onPressOut) this.props.onPressOut(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessibilityRole,
|
||||
accessible,
|
||||
activeUnderlayColor,
|
||||
delayLongPress,
|
||||
style
|
||||
} = this.props
|
||||
|
||||
/**
|
||||
* Creates a wrapping element that can receive beyboard focus. The
|
||||
* highlight is applied as a background color on this wrapper. The opacity
|
||||
* is set on the child element, allowing it to have its own background
|
||||
* color.
|
||||
*/
|
||||
return (
|
||||
<Tappable
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole={accessibilityRole}
|
||||
accessible={accessible}
|
||||
children={this._getChildren()}
|
||||
component={View}
|
||||
onKeyDown={(e) => { this._onKeyEnter(e, this._onPressIn) }}
|
||||
onKeyPress={this._onPress}
|
||||
onKeyUp={(e) => { this._onKeyEnter(e, this._onPressOut) }}
|
||||
onMouseDown={this._onPressIn}
|
||||
onMouseUp={this._onPressOut}
|
||||
onPress={this._onLongPress}
|
||||
onTap={this._onPress}
|
||||
onTouchEnd={this._onPressOut}
|
||||
onTouchStart={this._onPressIn}
|
||||
pressDelay={delayLongPress}
|
||||
pressMoveThreshold={5}
|
||||
style={{
|
||||
...styles.initial,
|
||||
...style,
|
||||
backgroundColor: this.state.isActive ? activeUnderlayColor : style.backgroundColor
|
||||
}}
|
||||
tabIndex='0'
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Touchable
|
||||
27
src/components/Touchable/index.spec.js
Normal file
27
src/components/Touchable/index.spec.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { assertProps, shallowRender } from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import Touchable from '.'
|
||||
|
||||
const children = <span style={{}}>children</span>
|
||||
const requiredProps = { children }
|
||||
|
||||
suite('Touchable', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Touchable, requiredProps)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
assertProps.accessibilityRole(Touchable, requiredProps)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Touchable, requiredProps)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const result = shallowRender(<Touchable {...requiredProps} />)
|
||||
assert.deepEqual(result.props.children, children)
|
||||
})
|
||||
})
|
||||
86
src/components/View/ViewStylePropTypes.js
Normal file
86
src/components/View/ViewStylePropTypes.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
|
||||
export default {
|
||||
...pickProps(CoreComponent.stylePropTypes, [
|
||||
'alignContent',
|
||||
'alignItems',
|
||||
'alignSelf',
|
||||
'backfaceVisibility',
|
||||
// background
|
||||
'backgroundAttachment',
|
||||
'backgroundClip',
|
||||
'backgroundColor',
|
||||
'backgroundImage',
|
||||
'backgroundPosition',
|
||||
'backgroundOrigin',
|
||||
'backgroundRepeat',
|
||||
'backgroundSize',
|
||||
// border-color
|
||||
'borderColor',
|
||||
'borderTopColor',
|
||||
'borderRightColor',
|
||||
'borderBottomColor',
|
||||
'borderLeftColor',
|
||||
// border-radius
|
||||
'borderRadius',
|
||||
'borderTopLeftRadius',
|
||||
'borderTopRightRadius',
|
||||
'borderBottomLeftRadius',
|
||||
'borderBottomRightRadius',
|
||||
// border style
|
||||
'borderStyle',
|
||||
'borderBottomStyle',
|
||||
'borderLeftStyle',
|
||||
'borderRightStyle',
|
||||
'borderTopStyle',
|
||||
// border width
|
||||
'borderWidth',
|
||||
'borderBottomWidth',
|
||||
'borderLeftWidth',
|
||||
'borderRightWidth',
|
||||
'borderTopWidth',
|
||||
'bottom',
|
||||
'boxShadow',
|
||||
'boxSizing',
|
||||
'cursor',
|
||||
'flexBasis',
|
||||
'flexDirection',
|
||||
'flexGrow',
|
||||
'flexShrink',
|
||||
'flexWrap',
|
||||
'height',
|
||||
'justifyContent',
|
||||
'left',
|
||||
// margin
|
||||
'margin',
|
||||
'marginBottom',
|
||||
'marginLeft',
|
||||
'marginRight',
|
||||
'marginTop',
|
||||
// max/min
|
||||
'maxHeight',
|
||||
'maxWidth',
|
||||
'minHeight',
|
||||
'minWidth',
|
||||
'opacity',
|
||||
'order',
|
||||
'overflow',
|
||||
'overflowX',
|
||||
'overflowY',
|
||||
// padding
|
||||
'padding',
|
||||
'paddingBottom',
|
||||
'paddingLeft',
|
||||
'paddingRight',
|
||||
'paddingTop',
|
||||
'position',
|
||||
'right',
|
||||
'top',
|
||||
'transform',
|
||||
'userSelect',
|
||||
'visibility',
|
||||
'width',
|
||||
'zIndex'
|
||||
])
|
||||
}
|
||||
90
src/components/View/index.js
Normal file
90
src/components/View/index.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import ViewStylePropTypes from './ViewStylePropTypes'
|
||||
|
||||
const viewStyleKeys = Object.keys(ViewStylePropTypes)
|
||||
|
||||
const styles = {
|
||||
// https://github.com/facebook/css-layout#default-values
|
||||
initial: {
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative',
|
||||
// button reset
|
||||
backgroundColor: 'transparent',
|
||||
color: 'inherit',
|
||||
font: 'inherit',
|
||||
textAlign: 'inherit'
|
||||
}
|
||||
}
|
||||
|
||||
class View extends React.Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLiveRegion: PropTypes.oneOf(['assertive', 'off', 'polite']),
|
||||
accessibilityRole: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
children: PropTypes.any,
|
||||
component: CoreComponent.propTypes.component,
|
||||
pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']),
|
||||
style: PropTypes.shape(ViewStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
}
|
||||
|
||||
static stylePropTypes = ViewStylePropTypes
|
||||
|
||||
static defaultProps = {
|
||||
_className: '',
|
||||
accessible: true,
|
||||
component: 'div',
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
_className,
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRole,
|
||||
accessible,
|
||||
pointerEvents,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
const className = `View ${_className}`.trim()
|
||||
const pointerEventsStyle = pointerEvents && { pointerEvents }
|
||||
const resolvedStyle = pickProps(style, viewStyleKeys)
|
||||
|
||||
return (
|
||||
<CoreComponent
|
||||
{...other}
|
||||
aria-hidden={accessible ? null : true}
|
||||
aria-label={accessibilityLabel}
|
||||
aria-live={accessibilityLiveRegion}
|
||||
className={className}
|
||||
role={accessibilityRole}
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
...pointerEventsStyle
|
||||
}}
|
||||
testID={testID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default View
|
||||
46
src/components/View/index.spec.js
Normal file
46
src/components/View/index.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { assertProps, shallowRender } from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
import View from '.'
|
||||
|
||||
suite('View', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(View)
|
||||
})
|
||||
|
||||
test('prop "accessibilityLiveRegion"', () => {
|
||||
assertProps.accessibilityLiveRegion(View)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
assertProps.accessibilityRole(View)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(View)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = 'children'
|
||||
const result = shallowRender(<View>{children}</View>)
|
||||
assert.equal(result.props.children, children)
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
assertProps.component(View)
|
||||
})
|
||||
|
||||
test('prop "pointerEvents"', () => {
|
||||
const result = shallowRender(<View pointerEvents='box-only' />)
|
||||
assert.equal(result.props.style.pointerEvents, 'box-only')
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(View)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(View)
|
||||
})
|
||||
})
|
||||
241
src/example.js
Normal file
241
src/example.js
Normal file
@@ -0,0 +1,241 @@
|
||||
import React, { Image, Swipeable, Text, TextInput, Touchable, View } from '.'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class Heading extends Component {
|
||||
static propTypes = {
|
||||
children: Text.propTypes.children,
|
||||
level: PropTypes.oneOf(['1', '2', '3']),
|
||||
size: PropTypes.oneOf(['xlarge', 'large', 'normal'])
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
level: '1',
|
||||
size: 'normal'
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, level, size } = this.props
|
||||
|
||||
return (
|
||||
<Text
|
||||
children={children}
|
||||
component={`h${level}`}
|
||||
style={headingStyles.size[size]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const headingStyles = {
|
||||
size: {
|
||||
xlarge: {
|
||||
fontSize: '2rem',
|
||||
marginBottom: '1em'
|
||||
},
|
||||
large: {
|
||||
fontSize: '1.5rem',
|
||||
marginBottom: '1em',
|
||||
marginTop: '1em'
|
||||
},
|
||||
normal: {
|
||||
fontSize: '1.25rem',
|
||||
marginBottom: '0.5em',
|
||||
marginTop: '0.5em'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
style: View.propTypes.style
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View accessibilityRole='main' style={styles.root}>
|
||||
<Heading level='1' size='xlarge'>React Native Web</Heading>
|
||||
<Text>React Native Web takes the core components from <Text
|
||||
component='a' href='https://facebook.github.io/react-native/'>React
|
||||
Native</Text> and brings them to the web. These components provide
|
||||
simple building blocks – touch and swipe handling, flexbox layout,
|
||||
scroll views – from which more complex components and apps can be
|
||||
constructed.</Text>
|
||||
|
||||
<Heading level='2' size='large'>Image</Heading>
|
||||
<Image
|
||||
accessibilityLabel='accessible image'
|
||||
children={<Text>Inner content</Text>}
|
||||
defaultSource={{
|
||||
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wkGESkdPWMDggAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5UlEQVR42u3UMQ0AAAgEMcC/x7eCCgaSVsIN10kK4IORADAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAkAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAALi04UQW9HF910gAAAABJRU5ErkJggg=='
|
||||
}}
|
||||
onError={(e) => { console.log('Image.onError', e) }}
|
||||
onLoad={(e) => { console.log('Image.onLoad', e) }}
|
||||
onLoadEnd={() => { console.log('Image.onLoadEnd') }}
|
||||
onLoadStart={() => { console.log('Image.onLoadStart') }}
|
||||
resizeMode={'contain'}
|
||||
source={{
|
||||
height: 400,
|
||||
uri: 'http://facebook.github.io/react/img/logo_og.png',
|
||||
width: 400
|
||||
}}
|
||||
style={{
|
||||
borderWidth: '5px'
|
||||
}}
|
||||
testID='Example.image'
|
||||
/>
|
||||
|
||||
<Heading level='2' size='large'>Swipeable</Heading>
|
||||
<Swipeable
|
||||
onSwiped={(e) => { console.log('Swipeable.onSwiped', e) }}
|
||||
testID={'Example.swipeable'}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: 'black',
|
||||
alignSelf: 'center',
|
||||
width: '200px',
|
||||
height: '200px'
|
||||
}}
|
||||
/>
|
||||
</Swipeable>
|
||||
|
||||
<Heading level='2' size='large'>Text</Heading>
|
||||
<Text
|
||||
onPress={(e) => { console.log('Text.onPress', e) }}
|
||||
testID={'Example.text'}
|
||||
>
|
||||
PRESS ME.
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
|
||||
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
|
||||
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
|
||||
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
|
||||
hendrerit consequat. Aliquam lorem quam, elementum eget ex nec,
|
||||
ultrices porttitor nibh. Nulla pellentesque urna leo, a aliquet elit
|
||||
rhoncus a. Aenean ultricies, nunc a interdum dictum, dui odio
|
||||
scelerisque mauris, a fringilla elit ligula vel sem. Sed vel aliquet
|
||||
ipsum, sed rhoncus velit. Vivamus commodo pretium libero id placerat.
|
||||
</Text>
|
||||
<Text numberOfLines={1}>
|
||||
TRUNCATED after 1 line.
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
|
||||
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
|
||||
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
|
||||
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
|
||||
hendrerit consequat.
|
||||
</Text>
|
||||
|
||||
<Heading level='2' size='large'>TextInput</Heading>
|
||||
<TextInput
|
||||
keyboardType='default'
|
||||
onBlur={(e) => { console.log('TextInput.onBlur', e) }}
|
||||
onChange={(e) => { console.log('TextInput.onChange', e) }}
|
||||
onChangeText={(e) => { console.log('TextInput.onChangeText', e) }}
|
||||
onFocus={(e) => { console.log('TextInput.onFocus', e) }}
|
||||
onSelectionChange={(e) => { console.log('TextInput.onSelectionChange', e) }}
|
||||
/>
|
||||
<TextInput secureTextEntry />
|
||||
<TextInput defaultValue='read only' editable={false} />
|
||||
<TextInput keyboardType='email-address' />
|
||||
<TextInput keyboardType='numeric' />
|
||||
<TextInput keyboardType='phone-pad' />
|
||||
<TextInput keyboardType='url' />
|
||||
<TextInput
|
||||
defaultValue='default value'
|
||||
maxNumberOfLines={10}
|
||||
multiline
|
||||
numberOfLines={5}
|
||||
/>
|
||||
|
||||
<Heading level='2' size='large'>Touchable</Heading>
|
||||
<Touchable
|
||||
accessibilityLabel={'Touchable element'}
|
||||
activeHighlight='lightblue'
|
||||
activeOpacity={0.8}
|
||||
onLongPress={(e) => { console.log('Touchable.onLongPress', e) }}
|
||||
onPress={(e) => { console.log('Touchable.onPress', e) }}
|
||||
onPressIn={(e) => { console.log('Touchable.onPressIn', e) }}
|
||||
onPressOut={(e) => { console.log('Touchable.onPressOut', e) }}
|
||||
>
|
||||
<View style={styles.touchableArea}>
|
||||
<Text>Touchable area (press, long press)</Text>
|
||||
</View>
|
||||
</Touchable>
|
||||
|
||||
<Heading level='2' size='large'>View</Heading>
|
||||
<Heading level='3'>Default layout</Heading>
|
||||
<View>
|
||||
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
|
||||
return (
|
||||
<View key={i} style={styles.box}>
|
||||
<Text>{item}</Text>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
|
||||
<Heading level='3'>Row layout</Heading>
|
||||
<View style={styles.row}>
|
||||
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
|
||||
return (
|
||||
<View key={i} style={styles.box}>
|
||||
<Text>{item}</Text>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
|
||||
<Heading level='3'>pointerEvents</Heading>
|
||||
<View style={styles.row}>
|
||||
{['box-none', 'box-only', 'none'].map((value, i) => {
|
||||
return (
|
||||
<View
|
||||
children={value}
|
||||
component='a'
|
||||
href='https://google.com'
|
||||
key={i}
|
||||
pointerEvents={value}
|
||||
style={styles.pointerEventsBox}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
maxWidth: '600px',
|
||||
margin: '0 auto'
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
box: {
|
||||
alignItems: 'center',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderWidth: '1px'
|
||||
},
|
||||
boxFull: {
|
||||
width: '100%'
|
||||
},
|
||||
pointerEventsBox: {
|
||||
alignItems: 'center',
|
||||
borderWidth: '1px',
|
||||
flexGrow: '1',
|
||||
height: '100px',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
touchableArea: {
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
height: '200px',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
}
|
||||
|
||||
React.render(<Example />, document.getElementById('react-root'))
|
||||
8
src/index.html
Normal file
8
src/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>React Native for Web</title>
|
||||
<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>
|
||||
<div id="react-root"></div>
|
||||
<script src="/example.js"></script>
|
||||
33
src/index.js
33
src/index.js
@@ -1,17 +1,24 @@
|
||||
import { getOtherProps, omitProps, pickProps } from './modules/filterObjectProps';
|
||||
import WebStyleComponent from './modules/WebStyleComponent';
|
||||
import StylePropTypes from './modules/StylePropTypes';
|
||||
import Image from './modules/Image';
|
||||
import Text from './modules/Text';
|
||||
import View from './modules/View';
|
||||
import React from 'react'
|
||||
|
||||
export default {
|
||||
getOtherProps,
|
||||
omitProps,
|
||||
pickProps,
|
||||
StylePropTypes,
|
||||
WebStyleComponent,
|
||||
// components
|
||||
import Image from './components/Image'
|
||||
import ListView from './components/ListView'
|
||||
import ScrollView from './components/ScrollView'
|
||||
import Swipeable from './components/Swipeable'
|
||||
import Text from './components/Text'
|
||||
import TextInput from './components/TextInput'
|
||||
import Touchable from './components/Touchable'
|
||||
import View from './components/View'
|
||||
|
||||
export default React
|
||||
|
||||
export {
|
||||
Image,
|
||||
ListView,
|
||||
ScrollView,
|
||||
Swipeable,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
View
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { pickProps } from '../filterObjectProps';
|
||||
import StylePropTypes from '../StylePropTypes';
|
||||
import React, { PropTypes } from 'react';
|
||||
import WebStyleComponent from '../WebStyleComponent';
|
||||
|
||||
const ImageStyleDefaultProps = {
|
||||
backgroundColor: 'lightGray',
|
||||
borderWidth: 0,
|
||||
maxWidth: '100%'
|
||||
};
|
||||
|
||||
const ImageStylePropTypes = {
|
||||
...StylePropTypes.BorderThemePropTypes,
|
||||
...StylePropTypes.LayoutPropTypes,
|
||||
backgroundColor: PropTypes.string,
|
||||
opacity: PropTypes.string
|
||||
};
|
||||
|
||||
class Image extends React.Component {
|
||||
static _getPropTypes() {
|
||||
return {
|
||||
alt: PropTypes.string,
|
||||
async: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
src: PropTypes.string,
|
||||
style: PropTypes.shape(ImageStylePropTypes)
|
||||
};
|
||||
}
|
||||
|
||||
static _getDefaultProps() {
|
||||
return {
|
||||
async: true,
|
||||
className: '',
|
||||
src: 'data:image/gif;base64,' +
|
||||
'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
||||
style: {}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { alt, className, src, style, ...other } = this.props;
|
||||
const filteredStyle = pickProps(style, Object.keys(ImageStylePropTypes));
|
||||
const mergedStyle = { ...ImageStyleDefaultProps, ...filteredStyle };
|
||||
|
||||
return (
|
||||
<WebStyleComponent
|
||||
{...other}
|
||||
alt={alt}
|
||||
className={`Image ${className}`}
|
||||
element="img"
|
||||
src={src}
|
||||
style={mergedStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Image.propTypes = Image._getPropTypes();
|
||||
Image.defaultProps = Image._getDefaultProps();
|
||||
|
||||
export default Image;
|
||||
@@ -1,9 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
export default {
|
||||
backgroundColor: PropTypes.string,
|
||||
backgroundImage: PropTypes.string,
|
||||
backgroundPosition: PropTypes.string,
|
||||
backgroundRepeat: PropTypes.string,
|
||||
backgroundSize: PropTypes.string
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
const numberOrString = PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string,
|
||||
]);
|
||||
|
||||
export default {
|
||||
// border-color
|
||||
borderColor: PropTypes.string,
|
||||
borderTopColor: PropTypes.string,
|
||||
borderRightColor: PropTypes.string,
|
||||
borderBottomColor: PropTypes.string,
|
||||
borderLeftColor: PropTypes.string,
|
||||
// border-style
|
||||
borderStyle: PropTypes.string,
|
||||
// border-radius
|
||||
borderRadius: numberOrString,
|
||||
borderTopLeftRadius: numberOrString,
|
||||
borderTopRightRadius: numberOrString,
|
||||
borderBottomLeftRadius: numberOrString,
|
||||
borderBottomRightRadius: numberOrString
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
const numberOrString = PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string,
|
||||
]);
|
||||
|
||||
export default {
|
||||
boxSizing: PropTypes.oneOf([
|
||||
'border-box',
|
||||
'content-box'
|
||||
]),
|
||||
// display
|
||||
display: PropTypes.oneOf([
|
||||
'block',
|
||||
'flex',
|
||||
'inline',
|
||||
'inline-block',
|
||||
'inline-flex'
|
||||
]),
|
||||
// dimensions
|
||||
height: numberOrString,
|
||||
width: numberOrString,
|
||||
// border width
|
||||
borderWidth: numberOrString,
|
||||
borderTopWidth: numberOrString,
|
||||
borderRightWidth: numberOrString,
|
||||
borderBottomWidth: numberOrString,
|
||||
borderLeftWidth: numberOrString,
|
||||
// margin
|
||||
margin: numberOrString,
|
||||
marginTop: numberOrString,
|
||||
marginBottom: numberOrString,
|
||||
marginLeft: numberOrString,
|
||||
marginRight: numberOrString,
|
||||
// padding
|
||||
padding: numberOrString,
|
||||
paddingTop: numberOrString,
|
||||
paddingBottom: numberOrString,
|
||||
paddingLeft: numberOrString,
|
||||
paddingRight: numberOrString
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
export default {
|
||||
alignContent: PropTypes.oneOf([
|
||||
'center',
|
||||
'flex-end',
|
||||
'flex-start',
|
||||
'stretch',
|
||||
'space-around',
|
||||
'space-between'
|
||||
]),
|
||||
alignItems: PropTypes.oneOf([
|
||||
'baseline',
|
||||
'center',
|
||||
'flex-end',
|
||||
'flex-start',
|
||||
'stretch'
|
||||
]),
|
||||
alignSelf: PropTypes.oneOf([
|
||||
'auto',
|
||||
'baseline',
|
||||
'center',
|
||||
'flex-end',
|
||||
'flex-start',
|
||||
'stretch'
|
||||
]),
|
||||
flexBasis: PropTypes.string,
|
||||
flexDirection: PropTypes.oneOf([
|
||||
'column',
|
||||
'column-reverse',
|
||||
'row',
|
||||
'row-reverse'
|
||||
]),
|
||||
flexGrow: PropTypes.number,
|
||||
flexShrink: PropTypes.number,
|
||||
flexWrap: PropTypes.oneOf([
|
||||
'nowrap',
|
||||
'wrap',
|
||||
'wrap-reverse'
|
||||
]),
|
||||
justifyContent: PropTypes.oneOf([
|
||||
'center',
|
||||
'flex-end',
|
||||
'flex-start',
|
||||
'space-around',
|
||||
'space-between'
|
||||
]),
|
||||
order: PropTypes.number
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import BoxModel from './BoxModel';
|
||||
import Flexbox from './Flexbox';
|
||||
import Position from './Position';
|
||||
|
||||
export default {
|
||||
...BoxModel,
|
||||
...Flexbox,
|
||||
...Position
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
const numberOrString = PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string,
|
||||
]);
|
||||
|
||||
export default {
|
||||
position: PropTypes.oneOf([
|
||||
'absolute',
|
||||
'fixed',
|
||||
'relative'
|
||||
]),
|
||||
bottom: numberOrString,
|
||||
left: numberOrString,
|
||||
right: numberOrString,
|
||||
top: numberOrString,
|
||||
zIndex: PropTypes.number
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
import {PropTypes} from 'react';
|
||||
|
||||
export default {
|
||||
direction: PropTypes.oneOf([
|
||||
'auto', 'ltr', 'rtl'
|
||||
]),
|
||||
fontFamily: PropTypes.string,
|
||||
fontSize: PropTypes.string,
|
||||
fontWeight: PropTypes.oneOf([
|
||||
'100', '200', '300', '400', '500', '600', '700', '800', '900',
|
||||
'bold', 'normal'
|
||||
]),
|
||||
fontStyle: PropTypes.oneOf([
|
||||
'normal', 'italic'
|
||||
]),
|
||||
letterSpacing: PropTypes.string,
|
||||
lineHeight: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
|
||||
textAlign: PropTypes.oneOf([
|
||||
'auto', 'left', 'right', 'center'
|
||||
]),
|
||||
textDecoration: PropTypes.oneOf([
|
||||
'none', 'underline'
|
||||
]),
|
||||
textTransform: PropTypes.oneOf([
|
||||
'capitalize', 'lowercase', 'none', 'uppercase'
|
||||
]),
|
||||
wordWrap: PropTypes.oneOf([
|
||||
'break-word', 'normal'
|
||||
])
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import BackgroundPropTypes from './Background';
|
||||
import BorderThemePropTypes from './BorderTheme';
|
||||
import FlexboxPropTypes from './Flexbox';
|
||||
import LayoutPropTypes from './Layout';
|
||||
import TypographicPropTypes from './Typographic';
|
||||
|
||||
export default {
|
||||
BackgroundPropTypes,
|
||||
BorderThemePropTypes,
|
||||
FlexboxPropTypes,
|
||||
LayoutPropTypes,
|
||||
TypographicPropTypes
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
import { pickProps } from '../filterObjectProps';
|
||||
import { ViewStylePropTypes } from '../View';
|
||||
import StylePropTypes from '../StylePropTypes';
|
||||
import React, { PropTypes } from 'react';
|
||||
import WebStyleComponent from '../WebStyleComponent';
|
||||
|
||||
const TextStyleDefaultProps = {
|
||||
alignItems: 'stretch', /* 1 */
|
||||
borderWidth: '0',
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box', /* 2 */
|
||||
display: 'flex', /* 3 */
|
||||
flexBasis: 'auto', /* 1 */
|
||||
flexDirection: 'column', /* 1 */
|
||||
flexShrink: 0, /* 1 */
|
||||
listStyle: 'none',
|
||||
margin: '0',
|
||||
padding: '0',
|
||||
position: 'relative' /* 4 */
|
||||
};
|
||||
|
||||
const TextStylePropTypes = {
|
||||
...ViewStylePropTypes,
|
||||
...StylePropTypes.TypographicPropTypes
|
||||
};
|
||||
|
||||
class Text extends React.Component {
|
||||
static _getPropTypes() {
|
||||
return {
|
||||
className: PropTypes.string,
|
||||
element: PropTypes.oneOfType([
|
||||
PropTypes.string, PropTypes.func
|
||||
]),
|
||||
style: PropTypes.shape(TextStylePropTypes)
|
||||
};
|
||||
}
|
||||
|
||||
static _getDefaultProps() {
|
||||
return {
|
||||
className: '',
|
||||
element: 'div',
|
||||
style: {}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, style, ...other } = this.props;
|
||||
const filteredStyle = pickProps(style, Object.keys(TextStylePropTypes));
|
||||
const mergedStyle = { ...TextStyleDefaultProps, ...filteredStyle };
|
||||
|
||||
return (
|
||||
<WebStyleComponent
|
||||
{...other}
|
||||
className={`Text ${className}`}
|
||||
style={mergedStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Text.propTypes = Text._getPropTypes();
|
||||
Text.defaultProps = Text._getDefaultProps();
|
||||
|
||||
export default Text;
|
||||
export { TextStylePropTypes };
|
||||
@@ -1,81 +0,0 @@
|
||||
import { pickProps } from '../filterObjectProps';
|
||||
import StylePropTypes from '../StylePropTypes';
|
||||
import React, { PropTypes } from 'react';
|
||||
import WebStyleComponent from '../WebStyleComponent';
|
||||
|
||||
// https://github.com/facebook/css-layout#default-values
|
||||
const ViewStyleDefaultProps = {
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative'
|
||||
};
|
||||
|
||||
const ViewStylePropTypes = {
|
||||
...StylePropTypes.BackgroundPropTypes,
|
||||
...StylePropTypes.BorderThemePropTypes,
|
||||
...StylePropTypes.LayoutPropTypes,
|
||||
boxShadow: PropTypes.string,
|
||||
opacity: PropTypes.number,
|
||||
transform: PropTypes.string
|
||||
};
|
||||
|
||||
class View extends React.Component {
|
||||
static _getPropTypes() {
|
||||
return {
|
||||
className: PropTypes.string,
|
||||
element: PropTypes.oneOfType([
|
||||
PropTypes.string, PropTypes.func
|
||||
]),
|
||||
pointerEvents: PropTypes.oneOf([
|
||||
'auto',
|
||||
'box-none',
|
||||
'box-only',
|
||||
'none'
|
||||
]),
|
||||
style: PropTypes.shape(ViewStylePropTypes)
|
||||
};
|
||||
}
|
||||
|
||||
static _getDefaultProps() {
|
||||
return {
|
||||
className: '',
|
||||
element: 'div',
|
||||
style: {}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, element, pointerEvents, style, ...other } = this.props;
|
||||
const filteredStyle = pickProps(style, Object.keys(ViewStylePropTypes));
|
||||
const pointerEventsStyle = pointerEvents && { pointerEvents };
|
||||
const mergedStyle = {
|
||||
...ViewStyleDefaultProps,
|
||||
...filteredStyle,
|
||||
...pointerEventsStyle
|
||||
};
|
||||
|
||||
return (
|
||||
<WebStyleComponent
|
||||
{...other}
|
||||
className={`View ${className}`}
|
||||
element={element}
|
||||
style={mergedStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
View.propTypes = View._getPropTypes();
|
||||
View.defaultProps = View._getDefaultProps();
|
||||
|
||||
export default View;
|
||||
export { ViewStylePropTypes };
|
||||
@@ -1,70 +0,0 @@
|
||||
import autoprefix from './lib/autoprefix';
|
||||
import React, {PropTypes} from 'react';
|
||||
import styleMap from './lib/styleMap';
|
||||
|
||||
class WebStyleComponent extends React.Component {
|
||||
static _getPropTypes() {
|
||||
return {
|
||||
className: PropTypes.string,
|
||||
element: PropTypes.oneOfType([
|
||||
PropTypes.string, PropTypes.func
|
||||
]),
|
||||
style: PropTypes.object
|
||||
};
|
||||
}
|
||||
|
||||
static _getDefaultProps() {
|
||||
return {
|
||||
className: '',
|
||||
element: 'div',
|
||||
style: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { element: Element, ...other } = this.props;
|
||||
const { classNames, inlineStyles } = this._separateClassNamesAndStyles();
|
||||
|
||||
return (
|
||||
<Element
|
||||
{...other}
|
||||
className={classNames.join(' ')}
|
||||
style={autoprefix(inlineStyles)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_getSinglePurposeClassName(prop, style) {
|
||||
const uniqueClassName = `${prop}-${style[prop]}`;
|
||||
if (
|
||||
style.hasOwnProperty(prop) &&
|
||||
styleMap[uniqueClassName]
|
||||
) {
|
||||
return styleMap[uniqueClassName];
|
||||
}
|
||||
}
|
||||
|
||||
_separateClassNamesAndStyles() {
|
||||
const styleProp = this.props.style;
|
||||
let classNames = [ this.props.className ];
|
||||
let inlineStyles = {};
|
||||
|
||||
for (let prop in styleProp) {
|
||||
let singlePurposeClassName =
|
||||
this._getSinglePurposeClassName(prop, styleProp);
|
||||
if (singlePurposeClassName) {
|
||||
classNames.push(singlePurposeClassName);
|
||||
} else {
|
||||
inlineStyles[prop] = styleProp[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return { classNames, inlineStyles };
|
||||
}
|
||||
}
|
||||
|
||||
WebStyleComponent.propTypes = WebStyleComponent._getPropTypes();
|
||||
WebStyleComponent.defaultProps = WebStyleComponent._getDefaultProps();
|
||||
|
||||
export default WebStyleComponent;
|
||||
@@ -1 +0,0 @@
|
||||
.appearance-none { appearance: none; }
|
||||
@@ -1,44 +0,0 @@
|
||||
.backgroundAttachment-fixed { background-attachment: fixed; }
|
||||
.backgroundAttachment-inherit { background-attachment: inherit; }
|
||||
.backgroundAttachment-local { background-attachment: local; }
|
||||
.backgroundAttachment-scroll { background-attachment: scroll; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.backgroundImage { background-image: none; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.backgroundSize-auto { background-size: auto; }
|
||||
.backgroundSize-contain { background-size: contain; }
|
||||
.backgroundSize-cover { background-size: cover; }
|
||||
.backgroundSize-inherit { background-size: inherit; }
|
||||
@@ -1,100 +0,0 @@
|
||||
/* border-color */
|
||||
|
||||
.borderColor-\#fff,
|
||||
.borderColor-white { border-color: white; }
|
||||
.borderColor-currentcolor { border-color: currentcolor; }
|
||||
.borderColor-inherit { border-color: inherit; }
|
||||
.borderColor-transparent { border-color: transparent; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
@@ -1,4 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,5 +0,0 @@
|
||||
.clear-both { clear: both; }
|
||||
.clear-inherit { clear: inherit; }
|
||||
.clear-left { clear: left; }
|
||||
.clear-none { clear: none; }
|
||||
.clear-right { clear: right; }
|
||||
@@ -1,6 +0,0 @@
|
||||
.color-#000,
|
||||
.color-black { color: black; }
|
||||
.color-\#fff,
|
||||
.color-white { color: white; }
|
||||
.color-inherit { color: inherit; }
|
||||
.color-transparent { color: transparent; }
|
||||
@@ -1,3 +0,0 @@
|
||||
.direction-inherit { direction: inherit; }
|
||||
.direction-ltr { direction: ltr; }
|
||||
.direction-rtl { direction: rtl; }
|
||||
@@ -1,22 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,74 +0,0 @@
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.flexBasis-0 { flex-basis: 0%; }
|
||||
.flexBasis-auto { flex-basis: auto; }
|
||||
|
||||
.flexDirection-column { flex-direction: column; }
|
||||
.flexDirection-column-reverse { flex-direction: column-reverse; }
|
||||
.flexDirection-row { flex-direction: row; }
|
||||
.flexDirection-row-reverse { flex-direction: row-reverse; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
|
||||
.flexWrap-nowrap { flex-wrap: nowrap; }
|
||||
.flexWrap-wrap { flex-wrap: wrap; }
|
||||
.flexWrap-wrap-reverse { flex-wrap: wrap-reverse; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
@@ -1,3 +0,0 @@
|
||||
.float-left { float: left; }
|
||||
.float-none { float: none; }
|
||||
.float-right { float: right; }
|
||||
@@ -1,37 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,20 +0,0 @@
|
||||
.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%; }
|
||||
|
||||
.maxHeight-100\% { max-height: 100%; }
|
||||
.minHeight-100\% { min-height: 100%; }
|
||||
@@ -1,2 +0,0 @@
|
||||
.lineHeight-inherit { line-height: inherit; }
|
||||
.lineHeight-normal { line-height: normal; }
|
||||
@@ -1 +0,0 @@
|
||||
.listStyle-none { list-style: none; }
|
||||
@@ -1,22 +0,0 @@
|
||||
.margin-0 { margin: 0; }
|
||||
.margin-auto { margin: auto; }
|
||||
|
||||
.marginBottom-auto { margin-bottom: auto; }
|
||||
.marginLeft-auto { margin-left: auto; }
|
||||
.marginRight-auto { margin-right: auto; }
|
||||
.marginTop-auto { margin-top: auto; }
|
||||
|
||||
.marginBottom-0 { margin-bottom: 0; }
|
||||
.marginLeft-0 { margin-left: 0; }
|
||||
.marginRight-0 { margin-right: 0; }
|
||||
.marginTop-0 { margin-top: 0; }
|
||||
|
||||
.marginBottom-1em { margin-bottom: 1em; }
|
||||
.marginLeft-1em { margin-left: 1em; }
|
||||
.marginRight-1em { margin-right: 1em; }
|
||||
.marginTop-1em { margin-top: 1em; }
|
||||
|
||||
.marginBottom-1rem { margin-bottom: 1rem; }
|
||||
.marginLeft-1rem { margin-left: 1rem; }
|
||||
.marginRight-1rem { margin-right: 1rem; }
|
||||
.marginTop-1rem { margin-top: 1rem; }
|
||||
@@ -1,2 +0,0 @@
|
||||
.opacity-0 { opacity: 0; }
|
||||
.opacity-1 { opacity: 1; }
|
||||
@@ -1,17 +0,0 @@
|
||||
.overflow-auto { overflow: auto; }
|
||||
.overflow-hidden { overflow: hidden; }
|
||||
.overflow-inherit { overflow: inherit; }
|
||||
.overflow-scroll { overflow: scroll; }
|
||||
.overflow-visible { overflow: visible; }
|
||||
|
||||
.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; }
|
||||
|
||||
.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; }
|
||||
@@ -1,17 +0,0 @@
|
||||
.padding-0 { padding: 0; }
|
||||
.paddingTop-0 { padding-top: 0; }
|
||||
.paddingRight-0 { padding-right: 0; }
|
||||
.paddingBottom-0 { padding-bottom: 0; }
|
||||
.paddingLeft-0 { padding-left: 0; }
|
||||
|
||||
.padding-1em { padding: 1em; }
|
||||
.paddingTop-1em { padding-top: 1em; }
|
||||
.paddingRight-1em { padding-right: 1em; }
|
||||
.paddingBottom-1em { padding-bottom: 1em; }
|
||||
.paddingLeft-1em { padding-left: 1em; }
|
||||
|
||||
.padding-1rem { padding: 1rem; }
|
||||
.paddingTop-1rem { padding-top: 1rem; }
|
||||
.paddingRight-1rem { padding-right: 1rem; }
|
||||
.paddingBottom-1rem { padding-bottom: 1rem; }
|
||||
.paddingLeft-1rem { padding-left: 1rem; }
|
||||
@@ -1,6 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,18 +0,0 @@
|
||||
.position-absolute { position: absolute; }
|
||||
.position-fixed { position: fixed; }
|
||||
.position-relative { position: relative; }
|
||||
|
||||
.bottom-0 { bottom: 0; }
|
||||
.left-0 { left: 0; }
|
||||
.right-0 { right: 0; }
|
||||
.top-0 { top: 0; }
|
||||
|
||||
.bottom-50% { bottom: 50%; }
|
||||
.left-50% { left: 50%; }
|
||||
.right-50% { right: 50%; }
|
||||
.top-50% { top: 50%; }
|
||||
|
||||
.bottom-100% { bottom: 100%; }
|
||||
.left-100% { left: 100%; }
|
||||
.right-100% { right: 100%; }
|
||||
.top-100% { top: 100%; }
|
||||
@@ -1,25 +0,0 @@
|
||||
.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; }
|
||||
|
||||
.textDecoration-inherit { text-decoration: inherit; }
|
||||
.textDecoration-none { text-decoration: none; }
|
||||
.textDecoration-underline { text-decoration: underline; }
|
||||
|
||||
.textOverflow-clip { text-overflow: clip; }
|
||||
.textOverflow-ellipsis { text-overflow: ellipsis; }
|
||||
|
||||
.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; }
|
||||
|
||||
.textTransform-capitalize { text-transform: capitalize; }
|
||||
.textTransform-lowercase { text-transform: lowercase; }
|
||||
.textTransform-none { text-transform: none; }
|
||||
.textTransform-uppercase { text-transform: uppercase; }
|
||||
@@ -1,7 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,4 +0,0 @@
|
||||
.userSelect-all { user-select: all; }
|
||||
.userSelect-inherit { user-select: inherit; }
|
||||
.userSelect-none { user-select: none; }
|
||||
.userSelect-text { user-select: text; }
|
||||
@@ -1,4 +0,0 @@
|
||||
.visibility-collapse { visibility: collapse; }
|
||||
.visibility-hidden { visibility: hidden; }
|
||||
.visibility-inherit { visibility: inherit; }
|
||||
.visibility-visible { visibility: visible; }
|
||||
@@ -1,5 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,20 +0,0 @@
|
||||
.maxWidth-100\% { max-width: 100%; }
|
||||
.minWidth-100\% { min-width: 100%; }
|
||||
|
||||
.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%; }
|
||||
@@ -1,2 +0,0 @@
|
||||
.wordWrap-break-word { word-wrap: break-word; }
|
||||
.wordWrap-normal { word-wrap: normal; }
|
||||
@@ -1,12 +0,0 @@
|
||||
.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; }
|
||||
@@ -1,60 +0,0 @@
|
||||
import appearance from './css/appearance.css';
|
||||
import background from './css/background.css';
|
||||
import border from './css/border.css';
|
||||
import boxSizing from './css/boxSizing.css';
|
||||
import clear from './css/clear.css';
|
||||
import color from './css/color.css';
|
||||
import cssFloat from './css/float.css';
|
||||
import direction from './css/direction.css';
|
||||
import display from './css/display.css';
|
||||
import flexbox from './css/flexbox.css';
|
||||
import font from './css/font.css';
|
||||
import height from './css/height.css';
|
||||
import lineHeight from './css/lineHeight.css';
|
||||
import list from './css/list.css';
|
||||
import margin from './css/margin.css';
|
||||
import opacity from './css/opacity.css';
|
||||
import overflow from './css/overflow.css';
|
||||
import padding from './css/padding.css';
|
||||
import pointerEvents from './css/pointerEvents.css';
|
||||
import position from './css/position.css';
|
||||
import text from './css/text.css';
|
||||
import unicodeBidi from './css/unicodeBidi.css';
|
||||
import userSelect from './css/userSelect.css';
|
||||
import visibility from './css/visibility.css';
|
||||
import whiteSpace from './css/whiteSpace.css';
|
||||
import width from './css/width.css';
|
||||
import word from './css/word.css';
|
||||
import zIndex from './css/zIndex.css';
|
||||
|
||||
const map = Object.assign({},
|
||||
appearance,
|
||||
background,
|
||||
border,
|
||||
boxSizing,
|
||||
clear,
|
||||
color,
|
||||
cssFloat,
|
||||
direction,
|
||||
display,
|
||||
flexbox,
|
||||
font,
|
||||
height,
|
||||
list,
|
||||
margin,
|
||||
opacity,
|
||||
overflow,
|
||||
padding,
|
||||
pointerEvents,
|
||||
position,
|
||||
text,
|
||||
unicodeBidi,
|
||||
userSelect,
|
||||
visibility,
|
||||
whiteSpace,
|
||||
width,
|
||||
word,
|
||||
zIndex
|
||||
);
|
||||
|
||||
export default map;
|
||||
@@ -1,35 +1,25 @@
|
||||
function filterProps(obj, props, excluded=false) {
|
||||
if (!Array.isArray(props)) {
|
||||
throw new TypeError('props is not an Array');
|
||||
}
|
||||
|
||||
let filtered = {};
|
||||
for (let prop in obj) {
|
||||
function filterProps(obj, propKeys: Array, excluded = false) {
|
||||
const filtered = {}
|
||||
for (const prop in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
|
||||
let isMatch = props.indexOf(prop) > -1;
|
||||
const isMatch = propKeys.indexOf(prop) > -1
|
||||
if (excluded && isMatch) {
|
||||
continue;
|
||||
continue
|
||||
} else if (!excluded && !isMatch) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
filtered[prop] = obj[prop];
|
||||
filtered[prop] = obj[prop]
|
||||
}
|
||||
}
|
||||
|
||||
return filtered;
|
||||
return filtered
|
||||
}
|
||||
|
||||
// Extract all props that are not part of the React Component's 'propTypes'
|
||||
export function getOtherProps(componentInstance) {
|
||||
const excludedProps = Object.keys(componentInstance.constructor.propTypes);
|
||||
return omitProps(componentInstance.props, excludedProps);
|
||||
export function pickProps(obj, propKeys) {
|
||||
return filterProps(obj, propKeys)
|
||||
}
|
||||
|
||||
export function pickProps(obj, props) {
|
||||
return filterProps(obj, props);
|
||||
}
|
||||
|
||||
export function omitProps(obj, props) {
|
||||
return filterProps(obj, props, true);
|
||||
export function omitProps(obj, propKeys) {
|
||||
return filterProps(obj, propKeys, true)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user