mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-31 10:11:38 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c482ef3be | ||
|
|
f51592f96e | ||
|
|
6bffe1775f | ||
|
|
7e75d037f2 | ||
|
|
7536508fe3 | ||
|
|
945fff0015 | ||
|
|
5032ed6fe1 | ||
|
|
8c7cdbf4be | ||
|
|
e5d8857bcc | ||
|
|
cda8d05bb7 | ||
|
|
049edc4611 | ||
|
|
e76d5a4e6c | ||
|
|
f71dae7d93 | ||
|
|
94d31beaf4 | ||
|
|
f5f9389728 | ||
|
|
fdbd19a4af |
@@ -5,5 +5,4 @@ before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
|
||||
@@ -57,7 +57,7 @@ To continuously watch and run tests, run the following:
|
||||
npm run test:watch
|
||||
```
|
||||
|
||||
To perform linting, run the following:
|
||||
To perform only linting, run the following:
|
||||
|
||||
```
|
||||
npm run lint
|
||||
|
||||
@@ -142,6 +142,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||
* [react-web](https://github.com/taobaofed/react-web)
|
||||
* [react-native-for-web](https://github.com/KodersLab/react-native-for-web)
|
||||
* [rhinos-app](https://github.com/rhinos-app/rhinos-app-dev)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
`AppRegistry` is the control point for registering, running, prerendering, and
|
||||
unmounting all apps. App root components should register themselves with
|
||||
`AppRegistry.registerComponent`. Apps can be run by invoking
|
||||
`AppRegistry.runApplication`, and prerendered by invoking
|
||||
`AppRegistry.prerenderApplication` (see the [client and server rendering
|
||||
`AppRegistry.runApplication` (see the [client and server rendering
|
||||
guide](../guides/rendering.md) for more details).
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
|
||||
@@ -62,16 +62,13 @@ AppRegistry.runApplication('App', {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-app')
|
||||
})
|
||||
|
||||
// prerender the app
|
||||
const { html, styleElement } = AppRegistry.prerenderApplication('App', { initialProps })
|
||||
```
|
||||
|
||||
## Server-side rendering
|
||||
|
||||
Rendering using the `AppRegistry`:
|
||||
|
||||
```
|
||||
```js
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import ReactNative, { AppRegistry } from 'react-native'
|
||||
|
||||
@@ -84,4 +81,4 @@ AppRegistry.registerComponent('App', () => AppContainer)
|
||||
// prerender the app
|
||||
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
|
||||
const initialHTML = ReactDOMServer.renderToString(element);
|
||||
```
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ const examples = [
|
||||
title: 'Wrap',
|
||||
render: function() {
|
||||
return (
|
||||
<Text>
|
||||
<Text style={{ WebkitFontSmoothing: 'antialiased' }}>
|
||||
The text should wrap if it goes on multiple lines. See, this is going to
|
||||
the next line.
|
||||
</Text>
|
||||
|
||||
11
package.json
11
package.json
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.52",
|
||||
"version": "0.0.56",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"src",
|
||||
"!**/__tests__"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
|
||||
@@ -14,8 +16,9 @@
|
||||
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
|
||||
"lint": "eslint src",
|
||||
"prepublish": "npm run build && npm run build:umd",
|
||||
"test": "jest",
|
||||
"test:watch": "npm run test -- --watch"
|
||||
"test": "npm run lint && npm run test:jest",
|
||||
"test:jest": "jest",
|
||||
"test:watch": "npm run test:jest -- --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"animated": "^0.1.3",
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('apis/StyleSheet', () => {
|
||||
|
||||
test('renders a style sheet in the browser', () => {
|
||||
StyleSheet.create({ root: { color: 'red' } });
|
||||
expect(document.getElementById('__react-native-style').textContent).toEqual(getDefaultStyleSheet());
|
||||
expect(document.getElementById('react-native-style__').textContent).toEqual(getDefaultStyleSheet());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
||||
let styleElement;
|
||||
let shouldInsertStyleSheet = ExecutionEnvironment.canUseDOM;
|
||||
|
||||
const STYLE_SHEET_ID = '__react-native-style';
|
||||
const STYLE_SHEET_ID = 'react-native-style__';
|
||||
|
||||
const absoluteFillObject = { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 };
|
||||
|
||||
|
||||
@@ -1,3 +1,60 @@
|
||||
exports[`components/Image passes other props through to underlying View 1`] = `
|
||||
<div
|
||||
className=" __style_df"
|
||||
onResponderGrant={[Function]}
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"MozBoxSizing": "border-box",
|
||||
"WebkitAlignItems": "stretch",
|
||||
"WebkitBoxAlign": "stretch",
|
||||
"WebkitBoxDirection": "normal",
|
||||
"WebkitBoxOrient": "vertical",
|
||||
"WebkitFlexBasis": "auto",
|
||||
"WebkitFlexDirection": "column",
|
||||
"WebkitFlexShrink": 0,
|
||||
"alignItems": "stretch",
|
||||
"backgroundColor": "transparent",
|
||||
"backgroundPosition": "center",
|
||||
"backgroundRepeat": "no-repeat",
|
||||
"backgroundSize": "cover",
|
||||
"borderBottomStyle": "solid",
|
||||
"borderBottomWidth": "0px",
|
||||
"borderLeftStyle": "solid",
|
||||
"borderLeftWidth": "0px",
|
||||
"borderRightStyle": "solid",
|
||||
"borderRightWidth": "0px",
|
||||
"borderTopStyle": "solid",
|
||||
"borderTopWidth": "0px",
|
||||
"boxSizing": "border-box",
|
||||
"color": "inherit",
|
||||
"display": null,
|
||||
"flexBasis": "auto",
|
||||
"flexDirection": "column",
|
||||
"flexShrink": 0,
|
||||
"font": "inherit",
|
||||
"listStyle": "none",
|
||||
"marginBottom": "0px",
|
||||
"marginLeft": "0px",
|
||||
"marginRight": "0px",
|
||||
"marginTop": "0px",
|
||||
"minHeight": "0px",
|
||||
"minWidth": "0px",
|
||||
"msFlexAlign": "stretch",
|
||||
"msFlexDirection": "column",
|
||||
"msFlexNegative": 0,
|
||||
"msPreferredSize": "auto",
|
||||
"paddingBottom": "0px",
|
||||
"paddingLeft": "0px",
|
||||
"paddingRight": "0px",
|
||||
"paddingTop": "0px",
|
||||
"position": "relative",
|
||||
"textAlign": "inherit",
|
||||
"textDecoration": "none",
|
||||
}
|
||||
} />
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "accessibilityLabel" 1`] = `
|
||||
<div
|
||||
aria-label="accessibilityLabel"
|
||||
|
||||
@@ -91,4 +91,10 @@ describe('components/Image', () => {
|
||||
const component = renderer.create(<Image testID='testID' />);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('passes other props through to underlying View', () => {
|
||||
const fn = () => {};
|
||||
const component = renderer.create(<Image onResponderGrant={fn} />);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* global window */
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
|
||||
import ImageResizeMode from './ImageResizeMode';
|
||||
import ImageStylePropTypes from './ImageStylePropTypes';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
@@ -38,7 +37,7 @@ class Image extends Component {
|
||||
static displayName = 'Image';
|
||||
|
||||
static propTypes = {
|
||||
...BaseComponentPropTypes,
|
||||
...View.propTypes,
|
||||
children: PropTypes.any,
|
||||
defaultSource: ImageSourcePropType,
|
||||
onError: PropTypes.func,
|
||||
@@ -99,27 +98,32 @@ class Image extends Component {
|
||||
defaultSource,
|
||||
onLayout,
|
||||
source,
|
||||
testID
|
||||
testID,
|
||||
/* eslint-disable */
|
||||
resizeMode,
|
||||
/* eslint-enable */
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
const displayImage = resolveAssetSource(!isLoaded ? defaultSource : source);
|
||||
const imageSizeStyle = resolveAssetDimensions(!isLoaded ? defaultSource : source);
|
||||
const backgroundImage = displayImage ? `url("${displayImage}")` : null;
|
||||
const originalStyle = StyleSheet.flatten(this.props.style);
|
||||
const resizeMode = this.props.resizeMode || originalStyle.resizeMode || ImageResizeMode.cover;
|
||||
const finalResizeMode = resizeMode || originalStyle.resizeMode || ImageResizeMode.cover;
|
||||
|
||||
const style = StyleSheet.flatten([
|
||||
styles.initial,
|
||||
imageSizeStyle,
|
||||
originalStyle,
|
||||
backgroundImage && { backgroundImage },
|
||||
resizeModeStyles[resizeMode]
|
||||
resizeModeStyles[finalResizeMode]
|
||||
]);
|
||||
// View doesn't support 'resizeMode' as a style
|
||||
delete style.resizeMode;
|
||||
|
||||
return (
|
||||
<View
|
||||
{...other}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole='img'
|
||||
accessible={accessible}
|
||||
|
||||
@@ -21,7 +21,6 @@ import React, { Component, PropTypes } from 'react';
|
||||
const ScrollView = React.createClass({
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
children: View.propTypes.children,
|
||||
contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
|
||||
horizontal: PropTypes.bool,
|
||||
keyboardDismissMode: PropTypes.oneOf([ 'none', 'interactive', 'on-drag' ]),
|
||||
|
||||
@@ -29,10 +29,17 @@ class Text extends Component {
|
||||
render() {
|
||||
const {
|
||||
numberOfLines,
|
||||
onLayout, // eslint-disable-line
|
||||
onPress, // eslint-disable-line
|
||||
selectable,
|
||||
style,
|
||||
/* eslint-disable */
|
||||
adjustsFontSizeToFit,
|
||||
allowFontScaling,
|
||||
ellipsizeMode,
|
||||
minimumFontScale,
|
||||
onLayout,
|
||||
onPress,
|
||||
suppressHighlighting,
|
||||
/* eslint-enable */
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@ var ColorPropType = require('../../propTypes/ColorPropType');
|
||||
var NativeMethodsMixin = require('../../modules/NativeMethodsMixin');
|
||||
var React = require('react');
|
||||
var StyleSheet = require('../../apis/StyleSheet');
|
||||
var StyleSheetPropType = require('../../propTypes/StyleSheetPropType');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var Touchable = require('./Touchable');
|
||||
var TouchableWithoutFeedback = require('./TouchableWithoutFeedback');
|
||||
var View = require('../View');
|
||||
var ViewStylePropTypes = require('../View/ViewStylePropTypes');
|
||||
|
||||
var ensureComponentIsNative = require('./ensureComponentIsNative');
|
||||
var ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
|
||||
@@ -77,7 +79,7 @@ var TouchableHighlight = React.createClass({
|
||||
* active.
|
||||
*/
|
||||
underlayColor: ColorPropType,
|
||||
style: View.propTypes.style,
|
||||
style: StyleSheetPropType(ViewStylePropTypes),
|
||||
/**
|
||||
* Called immediately after the underlay is shown
|
||||
*/
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
// Note (avik): add @flow when Flow supports spread properties in propTypes
|
||||
|
||||
var Animated = require('../../apis/Animated');
|
||||
var NativeMethodsMixin = require('../../modules/NativeMethodsMixin');
|
||||
var React = require('react');
|
||||
var StyleSheet = require('../../apis/StyleSheet');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var Touchable = require('./Touchable');
|
||||
var TouchableWithoutFeedback = require('./TouchableWithoutFeedback');
|
||||
var View = require('../View');
|
||||
|
||||
var ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
|
||||
var flattenStyle = StyleSheet.flatten
|
||||
@@ -70,10 +70,7 @@ var TouchableOpacity = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
...this.touchableGetInitialState(),
|
||||
anim: new Animated.Value(1),
|
||||
};
|
||||
return this.touchableGetInitialState();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
@@ -85,10 +82,11 @@ var TouchableOpacity = React.createClass({
|
||||
},
|
||||
|
||||
setOpacityTo: function(value) {
|
||||
Animated.timing(
|
||||
this.state.anim,
|
||||
{toValue: value, duration: 150}
|
||||
).start();
|
||||
this.setNativeProps({
|
||||
style: {
|
||||
opacity: value
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -166,7 +164,7 @@ var TouchableOpacity = React.createClass({
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<Animated.View
|
||||
<View
|
||||
accessible={this.props.accessible !== false}
|
||||
accessibilityLabel={this.props.accessibilityLabel}
|
||||
accessibilityRole={this.props.accessibilityRole}
|
||||
@@ -174,8 +172,7 @@ var TouchableOpacity = React.createClass({
|
||||
style={[
|
||||
styles.root,
|
||||
this.props.disabled && styles.disabled,
|
||||
this.props.style,
|
||||
{opacity: this.state.anim}
|
||||
this.props.style
|
||||
]}
|
||||
testID={this.props.testID}
|
||||
onLayout={this.props.onLayout}
|
||||
@@ -192,7 +189,7 @@ var TouchableOpacity = React.createClass({
|
||||
tabIndex={this.props.disabled ? null : '0'}
|
||||
>
|
||||
{this.props.children}
|
||||
</Animated.View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -200,6 +197,7 @@ var TouchableOpacity = React.createClass({
|
||||
var styles = StyleSheet.create({
|
||||
root: {
|
||||
cursor: 'pointer',
|
||||
transition: 'opacity 0.15s',
|
||||
userSelect: 'none'
|
||||
},
|
||||
disabled: {
|
||||
|
||||
@@ -16,7 +16,6 @@ var EdgeInsetsPropType = require('../../propTypes/EdgeInsetsPropType');
|
||||
var React = require('react');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var Touchable = require('./Touchable');
|
||||
var View = require('../View');
|
||||
var ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var StyleSheet = require('../../apis/StyleSheet');
|
||||
@@ -38,9 +37,9 @@ const TouchableWithoutFeedback = React.createClass({
|
||||
mixins: [TimerMixin, Touchable.Mixin],
|
||||
|
||||
propTypes: {
|
||||
accessible: View.propTypes.accessible,
|
||||
accessibilityLabel: View.propTypes.accessibilityLabel,
|
||||
accessibilityRole: View.propTypes.accessibilityRole,
|
||||
accessible: React.PropTypes.bool,
|
||||
accessibilityLabel: React.PropTypes.string,
|
||||
accessibilityRole: React.PropTypes.string,
|
||||
/**
|
||||
* If true, disable all interactions for this component.
|
||||
*/
|
||||
|
||||
@@ -87,11 +87,18 @@ class View extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
collapsable, // eslint-disable-line
|
||||
hitSlop, // eslint-disable-line
|
||||
onLayout, // eslint-disable-line
|
||||
pointerEvents,
|
||||
style,
|
||||
/* eslint-disable */
|
||||
accessibilityComponentType,
|
||||
accessibilityTraits,
|
||||
collapsable,
|
||||
hitSlop,
|
||||
onAccessibilityTap,
|
||||
onLayout,
|
||||
onMagicTap,
|
||||
removeClippedSubviews,
|
||||
/* eslint-enable */
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import findNodeHandle from './modules/findNodeHandle';
|
||||
import ReactDefaultInjection from 'react/lib/ReactDefaultInjection';
|
||||
import { render, unmountComponentAtNode } from 'react/lib/ReactMount';
|
||||
|
||||
ReactDefaultInjection.inject();
|
||||
|
||||
// APIs
|
||||
import I18nManager from './apis/I18nManager';
|
||||
import StyleSheet from './apis/StyleSheet';
|
||||
@@ -11,7 +14,11 @@ import Text from './components/Text';
|
||||
import TextInput from './components/TextInput';
|
||||
import View from './components/View';
|
||||
|
||||
// modules
|
||||
import createDOMElement from './modules/createDOMElement';
|
||||
|
||||
const ReactNativeCore = {
|
||||
createDOMElement,
|
||||
findNodeHandle,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import findNodeHandle from './modules/findNodeHandle';
|
||||
import ReactDefaultInjection from 'react/lib/ReactDefaultInjection';
|
||||
import { render, unmountComponentAtNode } from 'react/lib/ReactMount';
|
||||
|
||||
ReactDefaultInjection.inject();
|
||||
|
||||
// APIs
|
||||
import Animated from './apis/Animated';
|
||||
import AppRegistry from './apis/AppRegistry';
|
||||
@@ -34,10 +37,10 @@ import TouchableWithoutFeedback from './components/Touchable/TouchableWithoutFee
|
||||
import View from './components/View';
|
||||
|
||||
// modules
|
||||
import createDOMElement from './modules/createDOMElement';
|
||||
import NativeModules from './modules/NativeModules';
|
||||
|
||||
// propTypes
|
||||
|
||||
import ColorPropType from './propTypes/ColorPropType';
|
||||
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
|
||||
import PointPropType from './propTypes/PointPropType';
|
||||
@@ -81,6 +84,7 @@ const ReactNative = {
|
||||
View,
|
||||
|
||||
// modules
|
||||
createDOMElement,
|
||||
NativeModules,
|
||||
|
||||
// propTypes
|
||||
|
||||
@@ -20,22 +20,19 @@ const TextPropTypes = process.env.NODE_ENV !== 'production' ? {
|
||||
textAlign: TextAlignPropType,
|
||||
textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
|
||||
textDecorationLine: string,
|
||||
/* @platform web */
|
||||
textOverflow: string,
|
||||
/* @platform web */
|
||||
textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
|
||||
textShadowColor: ColorPropType,
|
||||
textShadowOffset: ShadowOffsetPropType,
|
||||
textShadowRadius: number,
|
||||
/* @platform web */
|
||||
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
|
||||
/* @platform web */
|
||||
unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
|
||||
/* @platform web */
|
||||
whiteSpace: string,
|
||||
/* @platform web */
|
||||
wordWrap: string,
|
||||
writingDirection: WritingDirectionPropType,
|
||||
/* @platform web */
|
||||
textOverflow: string,
|
||||
textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
|
||||
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
|
||||
unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
|
||||
whiteSpace: string,
|
||||
wordWrap: string,
|
||||
MozOsxFontSmoothing: string,
|
||||
WebkitFontSmoothing: string,
|
||||
// opt-out of RTL flipping
|
||||
textAlign$noI18n: TextAlignPropType,
|
||||
textShadowOffset$noI18n: ShadowOffsetPropType,
|
||||
|
||||
@@ -34,7 +34,7 @@ module.exports = {
|
||||
// https://github.com/animatedjs/animated/issues/40
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/es6-set/,
|
||||
path.join(__dirname, 'src/modules/polyfills/Set.js')
|
||||
path.join(__dirname, 'dist/modules/polyfills/Set.js')
|
||||
),
|
||||
new webpack.optimize.OccurenceOrderPlugin(),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
|
||||
Reference in New Issue
Block a user