mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-07 22:41:39 +08:00
Compare commits
1 Commits
feat/logbo
...
react-nati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc46c1d1a8 |
43
.eslintrc
43
.eslintrc
@@ -1,11 +1,4 @@
|
||||
{
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React",
|
||||
"version": "16.6",
|
||||
"flowVersion": "0.109.0" // Flow version
|
||||
}
|
||||
},
|
||||
// babel parser to support ES6/7 features
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
@@ -17,24 +10,31 @@
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": [
|
||||
"plugin:flowtype/recommended",
|
||||
"prettier",
|
||||
"prettier/react"
|
||||
],
|
||||
"plugins": [
|
||||
"flowtype",
|
||||
"promise",
|
||||
"react",
|
||||
"react-hooks"
|
||||
"react"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"jest": true,
|
||||
"node": true
|
||||
},
|
||||
"globals": {
|
||||
|
||||
"document": false,
|
||||
"navigator": false,
|
||||
"window": false,
|
||||
// Flow global types,
|
||||
"$Enum": false,
|
||||
"HTMLInputElement": false,
|
||||
"ReactClass": false,
|
||||
"ReactComponent": false,
|
||||
"ReactElement": false,
|
||||
"ReactPropsChainableTypeChecker": false,
|
||||
"ReactPropsCheckType": false,
|
||||
"ReactPropTypes": false,
|
||||
"SyntheticEvent": false
|
||||
},
|
||||
"rules": {
|
||||
"camelcase": 0,
|
||||
@@ -57,6 +57,7 @@
|
||||
"no-dupe-class-members": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-duplicate-imports": 2,
|
||||
"no-empty-character-class": 2,
|
||||
"no-empty-pattern": 2,
|
||||
"no-eval": 2,
|
||||
@@ -124,16 +125,12 @@
|
||||
"valid-typeof": 2,
|
||||
"yoda": [2, "never"],
|
||||
|
||||
// flow
|
||||
"flowtype/generic-spacing": 0,
|
||||
"flowtype/space-after-type-colon": 0,
|
||||
|
||||
// promise
|
||||
"promise/param-names": 2,
|
||||
|
||||
// react
|
||||
"react/display-name": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"react/jsx-no-bind": 2,
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
"react/jsx-no-undef": 2,
|
||||
"react/jsx-pascal-case": 2,
|
||||
@@ -147,15 +144,11 @@
|
||||
"react/no-string-refs": 2,
|
||||
"react/no-unknown-property": 2,
|
||||
"react/prefer-es6-class": 2,
|
||||
"react/prop-types": 0,
|
||||
"react/prop-types": 2,
|
||||
"react/react-in-jsx-scope": 0,
|
||||
"react/self-closing-comp": 2,
|
||||
"react/sort-comp": 0,
|
||||
"react/sort-prop-types": 2,
|
||||
"react/wrap-multilines": 0,
|
||||
|
||||
// react-hooks
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn"
|
||||
"react/wrap-multilines": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
[version]
|
||||
^0.109.0
|
||||
^0.63.0
|
||||
|
||||
[ignore]
|
||||
<PROJECT_ROOT>/.*/__tests__/.*
|
||||
<PROJECT_ROOT>/packages/.*/dist/.*
|
||||
<PROJECT_ROOT>/packages/docs/.*
|
||||
<PROJECT_ROOT>/packages/examples/.*
|
||||
<PROJECT_ROOT>/packages/website/.*
|
||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||
|
||||
[include]
|
||||
@@ -14,7 +15,3 @@
|
||||
|
||||
[options]
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
7
.github/CONTRIBUTING.md
vendored
7
.github/CONTRIBUTING.md
vendored
@@ -70,16 +70,15 @@ yarn compile
|
||||
yarn compile --watch
|
||||
```
|
||||
|
||||
## Documentation and visual tests
|
||||
## Website and visual tests
|
||||
|
||||
To run the interactive storybook:
|
||||
|
||||
```
|
||||
yarn docs
|
||||
yarn website
|
||||
```
|
||||
|
||||
When you're also making changes to the 'react-native-web' source files, run this
|
||||
command in another process:
|
||||
When you're also making changes to the 'react-native-web' source files, run this command in another process:
|
||||
|
||||
```
|
||||
yarn compile --watch
|
||||
|
||||
13
.github/workflows/compressed-size.yml
vendored
13
.github/workflows/compressed-size.yml
vendored
@@ -1,13 +0,0 @@
|
||||
name: compressed-size
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: necolas/compressed-size-action@master
|
||||
with:
|
||||
build-script: "compile"
|
||||
exclude: "./packages/react-native-web/dist/cjs/{index.js,**/*.js}"
|
||||
pattern: "./packages/react-native-web/dist/{index.js,**/*.js}"
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
@@ -1,7 +1,7 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "10"
|
||||
- "8"
|
||||
|
||||
before_install:
|
||||
# Install Yarn
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
102
README.md
102
README.md
@@ -2,10 +2,12 @@
|
||||
|
||||
[![npm version][package-badge]][package-url] [![Build Status][ci-badge]][ci-url] [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
||||
|
||||
**Compatibility: React Native >= 0.63**.
|
||||
**Compatibility: React Native 0.55**.
|
||||
|
||||
"React Native for Web" makes it possible to run [React
|
||||
Native][react-native-url] components and APIs on the web using React DOM.
|
||||
Native][react-native-url] components and APIs on the web using React DOM. Check
|
||||
out the live demo of the [React Native examples][examples-url] running on the
|
||||
web.
|
||||
|
||||
* **High-quality web interfaces**: makes it easy to
|
||||
create [fast](https://github.com/necolas/react-native-web/blob/master/packages/benchmarks/README.md),
|
||||
@@ -20,59 +22,73 @@ develop new components for native and web without rewriting existing code.
|
||||
React Native for Web can also render to HTML and critical CSS on the server
|
||||
using Node.js.
|
||||
|
||||
Who is using React Native for Web in production?
|
||||
Who is using React Native in production web apps?
|
||||
[Twitter](https://mobile.twitter.com),
|
||||
[Expo](https://docs.expo.io/workflow/web/),
|
||||
[Major League Soccer](https://matchcenter.mlssoccer.com),
|
||||
[Flipkart](https://twitter.com/naqvitalha/status/969577892991549440),
|
||||
[Uber](https://www.youtube.com/watch?v=RV9rxrNIxnY),
|
||||
[The Times](https://github.com/newsuk/times-components),
|
||||
[DataCamp](https://www.datacamp.com/community/tech/porting-practice-to-web-part1).
|
||||
[The Times](https://github.com/newsuk/times-components), [DataCamp](https://www.datacamp.com/community/tech/porting-practice-to-web-part1).
|
||||
|
||||
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
|
||||
|
||||
Components and APIs deprecated in React Native are not supported by React Native for Web.
|
||||
|
||||
## Quick start
|
||||
|
||||
The easiest way to get started is to edit this
|
||||
[CodeSandbox](https://codesandbox.io/s/q4qymyp2l6) template. You don’t need to
|
||||
install anything to try it out.
|
||||
[CodeSandbox](https://codesandbox.io/s/q4qymyp2l6) template (or
|
||||
[Glitch](https://glitch.com/edit/#!/react-native)). You don’t need to install
|
||||
anything to try it out.
|
||||
|
||||
For installation and configuration details please read the [getting
|
||||
started](https://github.com/necolas/react-native-web/blob/master/docs/guides/getting-started.md)
|
||||
guide.
|
||||
|
||||
## Documentation
|
||||
|
||||
The [documentation app](https://necolas.github.com/react-native-web/docs) covers
|
||||
installation, configuration, APIs, and guides.
|
||||
Please refer to the [React Native documentation][react-native-url] for the
|
||||
overall API, design details, and information about the [Gesture Responder
|
||||
system](https://facebook.github.io/react-native/docs/gesture-responder-system.html)
|
||||
and [animations](https://facebook.github.io/react-native/docs/animations.html).
|
||||
|
||||
The [React Native documentation][react-native-url] contains more information
|
||||
about the [Gesture Responder
|
||||
system](https://facebook.github.io/react-native/docs/gesture-responder-system.html),
|
||||
[animations](https://facebook.github.io/react-native/docs/animations.html), and
|
||||
other design details.
|
||||
Some components and APIs are extended with additional features for the web. And
|
||||
in a few cases, features present for Android or iOS are missing on the web.
|
||||
These differences are documented [on the website][website-url].
|
||||
|
||||
## Libraries and integrations
|
||||
### Guides
|
||||
|
||||
List of React Native packages with known web compatibility:
|
||||
These guides provide a detailed look at using React Native to create accessible
|
||||
web experiences. Certain web-specific patterns are documented in the "web
|
||||
recipes" guide.
|
||||
|
||||
* [React Native Directory](https://reactnative.directory/?web=true)
|
||||
* [Getting started](https://github.com/necolas/react-native-web/blob/master/docs/guides/getting-started.md)
|
||||
* [Client-side rendering](https://github.com/necolas/react-native-web/blob/master/docs/guides/client-side-rendering.md)
|
||||
* [Server-side rendering](https://github.com/necolas/react-native-web/blob/master/docs/guides/server-side-rendering.md)
|
||||
* [Style](https://github.com/necolas/react-native-web/blob/master/docs/guides/style.md)
|
||||
* [Accessibility](https://github.com/necolas/react-native-web/blob/master/docs/guides/accessibility.md)
|
||||
* [Internationalization](https://github.com/necolas/react-native-web/blob/master/docs/guides/internationalization.md)
|
||||
* [Direct manipulation](https://github.com/necolas/react-native-web/blob/master/docs/guides/direct-manipulation.md)
|
||||
* [Web recipes](https://github.com/necolas/react-native-web/blob/master/docs/guides/web-recipes.md)
|
||||
* [Multi-platform apps](https://github.com/necolas/react-native-web/blob/master/docs/guides/multi-platform-apps.md)
|
||||
* [Experimental / unstable use](https://github.com/necolas/react-native-web/blob/master/docs/guides/advanced.md)
|
||||
|
||||
## Integrations
|
||||
|
||||
Examples of using React Native for Web with other web tools:
|
||||
|
||||
* [Docz](https://github.com/doczjs/docz/tree/master/examples/react-native)
|
||||
* [Docz](https://github.com/pedronauck/docz-plugin-react-native)
|
||||
* [Gatsby](https://github.com/slorber/gatsby-plugin-react-native-web)
|
||||
* [Next.js](https://github.com/zeit/next.js/tree/master/examples/with-react-native-web)
|
||||
(and [example recipes](https://gist.github.com/necolas/f9034091723f1b279be86c7429eb0c96))
|
||||
* [Next.js](https://github.com/zeit/next.js/tree/master/examples/with-react-native-web) (and [example recipes](https://gist.github.com/necolas/f9034091723f1b279be86c7429eb0c96))
|
||||
* [Phenomic](https://github.com/phenomic/phenomic/tree/master/examples/react-native-web-app)
|
||||
* [Razzle](https://github.com/jaredpalmer/razzle/tree/master/examples/with-react-native-web)
|
||||
* [Storybook](https://github.com/necolas/react-native-web/tree/master/packages/docs/)
|
||||
* [Storybook](https://github.com/necolas/react-native-web/tree/master/packages/website/storybook/.storybook)
|
||||
* [Styleguidist](https://github.com/styleguidist/react-styleguidist/tree/master/examples/react-native)
|
||||
|
||||
## Examples
|
||||
|
||||
And here is a simple example to get you started. The documentation includes
|
||||
interactive examples and the [source
|
||||
code](https://github.com/necolas/react-native-web/blob/master/packages/docs) is
|
||||
also available.
|
||||
Check out all the [React Native examples][examples-url] ([source
|
||||
code](https://github.com/necolas/react-native-web/blob/master/packages/examples)).
|
||||
There are more examples [on the website][website-url] ([source
|
||||
code](https://github.com/necolas/react-native-web/blob/master/packages/website)).
|
||||
And here is a simple example to get you started:
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
@@ -105,30 +121,34 @@ Native. This allows the app to be rendered to web and native platforms.
|
||||
|
||||
## Compatibility with React Native
|
||||
|
||||
React Native v0.60
|
||||
React Native v0.55
|
||||
|
||||
### Components
|
||||
|
||||
| Name | Status | Notes |
|
||||
| :----------------------- | :----- | :---- |
|
||||
| ActivityIndicator | ✓ | |
|
||||
| ART | ✓ | |
|
||||
| Button | ✓ | |
|
||||
| CheckBox | ✓ | |
|
||||
| FlatList | ✓ | |
|
||||
| Image | ✓ | Missing multiple sources ([#515](https://github.com/necolas/react-native-web/issues/515)) and HTTP headers ([#1019](https://github.com/necolas/react-native-web/issues/1019)). |
|
||||
| ImageBackground | ✓ | |
|
||||
| KeyboardAvoidingView | (✓) | Mock. No equivalent web APIs. |
|
||||
| Modal | ✓ | |
|
||||
| ListView | ✓ | |
|
||||
| Modal | ✘ | Not started ([#1020](https://github.com/necolas/react-native-web/issues/1020)). |
|
||||
| Picker | ✓ | |
|
||||
| Pressable | ✓ | |
|
||||
| RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). |
|
||||
| SafeAreaView | ✓ | |
|
||||
| ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)). |
|
||||
| SectionList | ✓ | |
|
||||
| Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). |
|
||||
| StatusBar | (✓) | Mock. No equivalent web APIs. |
|
||||
| SwipeableFlatList | ✓ | |
|
||||
| SwipeableListView | ✓ | |
|
||||
| Switch | ✓ | |
|
||||
| Text | ✓ | Missing `onLongPress` ([#1011](https://github.com/necolas/react-native-web/issues/1011)) support. |
|
||||
| TextInput | ✓ | Missing rich text features ([#1023](https://github.com/necolas/react-native-web/issues/1023)), and auto-expanding behaviour ([#795](https://github.com/necolas/react-native-web/issues/795)). |
|
||||
| Text | ✓ | Missing `onLongPress` ([#1011](https://github.com/necolas/react-native-web/issues/1011)) and `numberOfLines` ([#13](https://github.com/necolas/react-native-web/issues/13)) support. |
|
||||
| TextInput | ✓ | Missing `onContentSizeChange` ([#793](https://github.com/necolas/react-native-web/issues/793)), rich text features ([#1023](https://github.com/necolas/react-native-web/issues/1023)), and auto-expanding behaviour ([#795](https://github.com/necolas/react-native-web/issues/795)). |
|
||||
| Touchable | ✓ | Includes additional support for mouse and keyboard interactions. |
|
||||
| TouchableHighlight | ✓ | |
|
||||
| TouchableNativeFeedback | ✘ | Not started ([#1024](https://github.com/necolas/react-native-web/issues/1024)). |
|
||||
@@ -136,6 +156,7 @@ React Native v0.60
|
||||
| TouchableWithoutFeedback | ✓ | |
|
||||
| View | ✓ | |
|
||||
| VirtualizedList | ✓ | |
|
||||
| WebView | ✘ | Not started ([1025](https://github.com/necolas/react-native-web/issues/1025)). |
|
||||
| YellowBox | (✓) | Mock. No YellowBox functionality. |
|
||||
|
||||
### Modules
|
||||
@@ -145,16 +166,21 @@ React Native v0.60
|
||||
| AccessibilityInfo | (✓) | Mock. No equivalent web APIs. |
|
||||
| Alert | ✘ | Not started ([#1026](https://github.com/necolas/react-native-web/issues/1026)). |
|
||||
| Animated | ✓ | Missing `useNativeDriver` support. |
|
||||
| Appearance | ✓ | |
|
||||
| AppRegistry | ✓ | Includes additional support for server rendering with `getApplication`. |
|
||||
| AppState | ✓ | |
|
||||
| AsyncStorage | ✓ | |
|
||||
| BackHandler | (✓) | Mock. No equivalent web APIs. |
|
||||
| CameraRoll | ✘ | No equivalent web APIs. |
|
||||
| Clipboard | ✓ | |
|
||||
| ColorPropType | ✓ | |
|
||||
| DeviceInfo | (✓) | Limited information. |
|
||||
| Dimensions | ✓ | |
|
||||
| Easing | ✓ | |
|
||||
| EdgeInsetsPropType | ✓ | |
|
||||
| Geolocation | ✓ | |
|
||||
| I18nManager | ✓ | Includes additional support for runtime switch to RTL. |
|
||||
| ImageEditor | ✘ | No equivalent web APIs. |
|
||||
| ImageStore | ✘ | No equivalent web APIs. |
|
||||
| InteractionManager | (✓) | |
|
||||
| Keyboard | (✓) | Mock. |
|
||||
| LayoutAnimation | (✓) | Missing translation to web animations. |
|
||||
@@ -162,16 +188,18 @@ React Native v0.60
|
||||
| NativeEventEmitter | ✓ | |
|
||||
| NativeMethodsMixin | ✓ | |
|
||||
| NativeModules | (✓) | Mocked. Missing ability to load native modules. |
|
||||
| NetInfo | ✓ | Missing functionality to detect expensive connections as there are no equivalent web APIs. |
|
||||
| PanResponder | ✓ | |
|
||||
| PixelRatio | ✓ | |
|
||||
| Platform | ✓ | |
|
||||
| PointPropType | ✓ | |
|
||||
| Settings | ✘ | No equivalent web APIs. |
|
||||
| Share | ✓ | Only available over HTTPS. Read about the [Web Share API](https://wicg.github.io/web-share/). |
|
||||
| StyleSheet | ✓ | |
|
||||
| TextPropTypes | ✓ | |
|
||||
| UIManager | ✓ | |
|
||||
| Vibration | ✓ | |
|
||||
| useColorScheme | ✓ | |
|
||||
| useWindowDimensions | ✓ | |
|
||||
| ViewPropTypes | ✓ | |
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -210,6 +238,8 @@ MIT license.
|
||||
[package-url]: https://yarnpkg.com/en/package/react-native-web
|
||||
[ci-badge]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||
[ci-url]: https://travis-ci.org/necolas/react-native-web
|
||||
[examples-url]: https://necolas.github.io/react-native-web/examples/
|
||||
[website-url]: https://necolas.github.io/react-native-web/storybook/
|
||||
[react-native-url]: https://facebook.github.io/react-native/
|
||||
[contributing-url]: https://github.com/necolas/react-native-web/blob/master/.github/CONTRIBUTING.md
|
||||
[good-first-issue-url]: https://github.com/necolas/react-native-web/labels/good%20first%20issue
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
|
||||
return {
|
||||
presets: ['./scripts/babel/preset']
|
||||
};
|
||||
};
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Accessibility" />
|
||||
|
||||
# Accessibility
|
||||
|
||||
On the Web, assistive technologies (e.g., VoiceOver, TalkBack screen readers)
|
||||
@@ -15,43 +11,38 @@ props: `accessible`, `accessibilityLabel`, `accessibilityLiveRegion`,
|
||||
|
||||
## Accessibility properties
|
||||
|
||||
### accessible
|
||||
|
||||
When `true`, indicates that the view is an accessibility element. When a view
|
||||
is an accessibility element, it groups its children into a single focusable
|
||||
component. By default, all touchable elements, buttons, and links are
|
||||
"accessible". Prefer using `accessibilityRole` (e.g., `button`, `link`) to
|
||||
create focusable HTML elements wherever possible. On web, `accessible={true}`
|
||||
is implemented using `tabIndex`.
|
||||
|
||||
### accessibilityLabel
|
||||
|
||||
Overrides the text that's read by a screen reader when a person interacts with
|
||||
the element. (This is implemented using `aria-label`.)
|
||||
When a view is marked as `accessible`, it is a good practice to set an
|
||||
`accessibilityLabel` on the view, so that people who use screen readers know
|
||||
what element they have selected. On web, `accessibilityLabel` is implemented
|
||||
using `aria-label`.
|
||||
|
||||
```js
|
||||
<View accessibilityLabel="Timeline: trending topics">
|
||||
<View>...</View>
|
||||
</View>
|
||||
```
|
||||
<TouchableOpacity accessibilityLabel={'Tap me!'} accessible={true} onPress={this._onPress}>
|
||||
<View style={styles.button}>
|
||||
<Text style={styles.buttonText}>Press me!</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
```
|
||||
|
||||
### accessibilityLiveRegion: 'assertive' | 'none' | 'polite'
|
||||
### accessibilityRole
|
||||
|
||||
Allows assistive technologies to announce dynamic changes to a view. 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
|
||||
announce the change. (This is implemented using `aria-live`.)
|
||||
|
||||
* `none`: Accessibility services should not announce changes to this view.
|
||||
* `polite`: Accessibility services should announce changes to this view.
|
||||
* `assertive`: Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
|
||||
|
||||
```js
|
||||
<Text accessibilityLiveRegion="polite">
|
||||
Clicked {count} times
|
||||
</Text>
|
||||
```
|
||||
|
||||
### accessibilityRole: ?string
|
||||
|
||||
Indicates to assistive technologies how to describe the view, e.g., that it is a "button".
|
||||
|
||||
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.)
|
||||
In some cases, we also want to alert the end user of the type of selected
|
||||
component (i.e., that it is a “button”). To provide more context to screen
|
||||
readers on the web, you should use the `accessibilityRole` property. (Note that
|
||||
React Native for Web also provides a compatibility mapping of equivalent
|
||||
`accessibilityTraits` and `accessibilityComponentType` values to
|
||||
`accessibilityRole`).
|
||||
|
||||
The `accessibilityRole` prop is used to infer an [analogous HTML
|
||||
element][html-aria-url] and ARIA `role`, where possible. In most cases, both
|
||||
@@ -74,36 +65,53 @@ The `heading` role can be combined with `aria-level`:
|
||||
* `<Text accessibilityRole="heading" aria-level="3" />` => `<h3 />`.
|
||||
|
||||
The `button` role renders an accessible button but is not implemented using the
|
||||
native `button` element due to some browsers limiting the use of flexbox layout
|
||||
on its children.
|
||||
native `button` element due to some browsers limiting the use of flexbox layout on
|
||||
its children.
|
||||
|
||||
* `<View accessibilityRole="button" />` => `<div role="button" tabIndex="0" />`.
|
||||
|
||||
In the example below, the `TouchableHighlight` is announced by screen readers
|
||||
as a button and it responds to touch, mouse, and keyboard interactions.
|
||||
|
||||
```js
|
||||
<TouchableHighlight accessibilityRole="button" onPress={this._handlePress}>
|
||||
<View style={styles.button}>
|
||||
<Text style={styles.buttonText}>Press me!</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### accessibilityState: ?object
|
||||
### accessibilityLiveRegion
|
||||
|
||||
...
|
||||
When components dynamically change we may need to inform the user. The
|
||||
`accessibilityLiveRegion` property serves this purpose and can be set to
|
||||
`none`, `polite` and `assertive`. On web, `accessibilityLiveRegion` is
|
||||
implemented using `aria-live`.
|
||||
|
||||
### accessibilityValue: ?object
|
||||
* `none`: Accessibility services should not announce changes to this view.
|
||||
* `polite`: Accessibility services should announce changes to this view.
|
||||
* `assertive`: Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
|
||||
|
||||
...
|
||||
```
|
||||
<TouchableWithoutFeedback onPress={this._addOne}>
|
||||
<View style={styles.embedded}>
|
||||
<Text>Click me</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
|
||||
### accessible
|
||||
<Text accessibilityLiveRegion="polite">
|
||||
Clicked {this.state.count} times
|
||||
</Text>
|
||||
```
|
||||
|
||||
When `true`, indicates that the view is an accessibility element. When a view
|
||||
is an accessibility element, it groups its children into a single focusable
|
||||
component. By default, all touchable elements, buttons, and links are
|
||||
"accessible". Prefer using `accessibilityRole` (e.g., `button`, `link`) to
|
||||
create focusable HTML elements wherever possible. On web, `accessible={true}`
|
||||
is implemented using `tabIndex`.
|
||||
|
||||
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
In the above example, method `_addOne` changes the `state.count` variable. As
|
||||
soon as an end user clicks the `TouchableWithoutFeedback`, screen readers
|
||||
announce text in the `Text` view because of its
|
||||
`accessibilityLiveRegion="polite"` property.
|
||||
|
||||
### importantForAccessibility
|
||||
|
||||
@@ -111,14 +119,7 @@ The `importantForAccessibility` property controls if a view appears in the
|
||||
accessibility tree and if it is reported to accessibility services. On web, a
|
||||
value of `no` will remove a focusable element from the tab flow, and a value of
|
||||
`no-hide-descendants` will also hide the entire subtree from assistive
|
||||
technologies. (This is implemented using `aria-hidden`).
|
||||
|
||||
### nativeID
|
||||
|
||||
Used to locate this view from any native DOM code, or to define accessibility
|
||||
relationships. This is rendered to the native `id` DOM attribute.
|
||||
|
||||
## Additional topics
|
||||
technologies (this is implemented using `aria-hidden`).
|
||||
|
||||
### Spatial navigation
|
||||
|
||||
@@ -132,7 +133,7 @@ that React Native considers focusable can be matched by the attribute
|
||||
const focusableElements = document.querySelectorAll('[data-focusable="true"]');
|
||||
```
|
||||
|
||||
### Other ARIA properties
|
||||
### Other
|
||||
|
||||
Other ARIA properties can be set via [direct
|
||||
manipulation](./direct-manipulation.md) or props (this may change in the
|
||||
@@ -1,12 +1,8 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Unstable uses" />
|
||||
|
||||
# Unstable APIs
|
||||
# Experimental / unstable uses
|
||||
|
||||
## Use with existing React DOM components
|
||||
|
||||
React Native for Web exports a web-specific module called `unstable_createElement`,
|
||||
React Native for Web exports a web-specific module called `createElement`,
|
||||
which can be used to wrap React DOM components. This allows you to use React
|
||||
Native's accessibility and style optimizations.
|
||||
|
||||
@@ -15,8 +11,8 @@ In the example below, `Video` will now accept common React Native props such as
|
||||
props.
|
||||
|
||||
```js
|
||||
import { unstable_createElement } from 'react-native-web';
|
||||
const Video = (props) => unstable_createElement('video', props);
|
||||
import { createElement } from 'react-native-web';
|
||||
const Video = (props) => createElement('video', props);
|
||||
```
|
||||
|
||||
This also works with composite components defined in your existing component
|
||||
@@ -24,10 +20,10 @@ gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw
|
||||
|
||||
```js
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
import { unstable_createElement } from 'react-native-web';
|
||||
import { createElement } from 'react-native-web';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const CustomButton = (props) => unstable_createElement(RaisedButton, {
|
||||
const CustomButton = (props) => createElement(RaisedButton, {
|
||||
...props,
|
||||
style: [ styles.button, props.style ]
|
||||
});
|
||||
@@ -39,11 +35,11 @@ const styles = StyleSheet.create({
|
||||
});
|
||||
```
|
||||
|
||||
And `unstable_createElement` can be used as drop-in replacement for `React.createElement`:
|
||||
And `createElement` can be used as drop-in replacement for `React.createElement`:
|
||||
|
||||
```js
|
||||
/* @jsx unstable_createElement */
|
||||
import { unstable_createElement } from 'react-native-web';
|
||||
/* @jsx createElement */
|
||||
import { createElement } from 'react-native-web';
|
||||
const Video = (props) => <video {...props} style={[ { marginVertical: 10 }, props.style ]} />
|
||||
```
|
||||
|
||||
@@ -59,7 +55,7 @@ an API inspired by styled-components ([live
|
||||
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
|
||||
|
||||
```js
|
||||
import { unstable_createElement } from 'react-native-web';
|
||||
import { createElement } from 'react-native-web';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
/**
|
||||
@@ -82,7 +78,7 @@ const styled = (Component, styler) => {
|
||||
|
||||
return (
|
||||
isDOMComponent
|
||||
? unstable_createElement(Component, nextProps)
|
||||
? createElement(Component, nextProps)
|
||||
: <Component {...nextProps} />
|
||||
);
|
||||
}
|
||||
@@ -101,3 +97,17 @@ const styles = StyleSheet.create({
|
||||
|
||||
const StyledView = styled(View, styles.container);
|
||||
```
|
||||
|
||||
## Use with react-sketchapp
|
||||
|
||||
Use with [react-sketchapp](http://airbnb.io/react-sketchapp/) requires that you
|
||||
alias `react-native` to `react-sketchapp`. This will allow you to render simple
|
||||
React Native components in Sketch. Sketch-specific components like `Artboard`
|
||||
should be imported from `react-sketchapp`.
|
||||
|
||||
If you're using `skpm`, you can rely on an [undocumented
|
||||
feature](https://github.com/sketch-pm/skpm/blob/master/lib/utils/webpackConfig.js)
|
||||
which will merge your `webpack.config.js`, `.babelrc`, or `package.json` Babel
|
||||
config into its internal webpack config. The simplest option may be to use the
|
||||
[babel-plugin-module-alias](https://www.npmjs.com/package/babel-plugin-module-alias)
|
||||
and configure it in your `package.json`.
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Client-side" />
|
||||
|
||||
# Client-side rendering
|
||||
|
||||
Render apps using `AppRegistry`:
|
||||
@@ -32,6 +28,10 @@ import { render } from 'react-native';
|
||||
render(<AppHeader />, document.getElementById('react-app-header'))
|
||||
```
|
||||
|
||||
(Components will also be rendered within a tree produced by calling
|
||||
`ReactDOM.render` (i.e., an existing web app), but
|
||||
otherwise it is not recommended.)
|
||||
|
||||
You might need to adjust the styles of the HTML document's root elements for
|
||||
your app to fill the viewport.
|
||||
|
||||
@@ -40,6 +40,3 @@ your app to fill the viewport.
|
||||
<body style="height:100%">
|
||||
<div id="react-root" style="display:flex;height:100%"></div>
|
||||
```
|
||||
|
||||
NOTE: Components will also be rendered within a tree produced by calling
|
||||
`ReactDOM.render` (i.e., an existing web app), but it is not recommended.
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Direct manipulation" />
|
||||
|
||||
# Direct manipulation
|
||||
|
||||
React Native provides several methods to directly access the underlying host
|
||||
@@ -1,57 +1,37 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Overview|Getting started" />
|
||||
|
||||
# Getting started
|
||||
|
||||
This guide will help you render components and applications with React Native
|
||||
for Web.
|
||||
|
||||
If you're not familiar with setting up a new React web project, please refer to
|
||||
the [React documentation](https://reactjs.org/).
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install react react-dom react-native-web
|
||||
```
|
||||
|
||||
Your application may need to polyfill `Promise`, `Object.assign`, `Array.from`,
|
||||
and [`ResizeObserver`](https://github.com/que-etc/resize-observer-polyfill) as
|
||||
necessary for your desired browser support.
|
||||
|
||||
## Recommended starter kits
|
||||
If you're not familiar with setting up a new React web project, please follow
|
||||
the recommendations in the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Expo
|
||||
|
||||
[Expo](https://expo.io) is a framework and a platform for universal React
|
||||
applications. [Expo for Web](https://docs.expo.io/workflow/web/) uses React
|
||||
Native for Web and provides dozens of additional cross-platform APIs.
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install expo-cli --global
|
||||
expo init my-app
|
||||
cd my-app
|
||||
expo start
|
||||
yarn add react react-dom react-native-web
|
||||
```
|
||||
|
||||
### Create React App
|
||||
|
||||
[Create React App](https://github.com/facebook/create-react-app) is a basic way
|
||||
to setup a simple, web-only React app with built-in support for aliasing
|
||||
`react-native-web` to `react-native`. However, it's generally recommended that
|
||||
you use Expo.
|
||||
And if you need to use `ART`:
|
||||
|
||||
```
|
||||
npx create-react-app my-app
|
||||
cd my-app
|
||||
npm install react-native-web
|
||||
npm start
|
||||
yarn add react-art
|
||||
```
|
||||
|
||||
## Standalone configurations
|
||||
## Starter kits
|
||||
|
||||
### Configuring a module bundler
|
||||
[create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||
includes built-in support for aliasing `react-native-web` to `react-native`.
|
||||
|
||||
```
|
||||
create-react-app my-app
|
||||
```
|
||||
|
||||
## Configuring a module bundler
|
||||
|
||||
If you have a custom setup, you may choose to configure your module bundler to
|
||||
alias the package to `react-native`.
|
||||
@@ -72,9 +52,11 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
### Configuring Babel
|
||||
Now you can create your components and applications with the React Native API.
|
||||
|
||||
[Babel](https://babeljs.io/) supports module aliasing using
|
||||
## Configuring Babel
|
||||
|
||||
If you need to do the aliasing with Babel you can use
|
||||
[babel-plugin-module-resolver](https://www.npmjs.com/package/babel-plugin-module-resolver)
|
||||
|
||||
```
|
||||
@@ -89,7 +71,7 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
### Configuring Jest
|
||||
## Configuring Jest
|
||||
|
||||
[Jest](https://facebook.github.io/jest/) can be configured using the provided
|
||||
preset. This will map `react-native` to `react-native-web` and provide
|
||||
@@ -103,7 +85,7 @@ appropriate mocks:
|
||||
|
||||
Please refer to the Jest documentation for more information.
|
||||
|
||||
### Configuring Flow
|
||||
## Configuring Flow
|
||||
|
||||
[Flow](https://flow.org) can be configured to understand the aliased module:
|
||||
|
||||
@@ -116,22 +98,6 @@ You may also need to include a custom libdef
|
||||
([example](https://gist.github.com/paularmstrong/f60b40d16fc83e1e8e532d483336f9bb))
|
||||
in your config.
|
||||
|
||||
### Configuring Node.js
|
||||
|
||||
Node.js can alias `react-native` to `react-native-web` using
|
||||
[`module-alias`](https://www.npmjs.com/package/module-alias). This is useful if
|
||||
you want to pre-render the app (e.g., server-side rendering or build-time
|
||||
rendering).
|
||||
|
||||
```js
|
||||
// Install the `module-alias` package as a dependency first
|
||||
const moduleAlias = require("module-alias");
|
||||
moduleAlias.addAliases({
|
||||
"react-native": require.resolve("react-native-web"),
|
||||
});
|
||||
moduleAlias();
|
||||
```
|
||||
|
||||
## Other notes
|
||||
|
||||
### Safari flexbox performance
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Internationalization" />
|
||||
|
||||
# Internationalization
|
||||
|
||||
To support right-to-left languages, application layout can be automatically
|
||||
@@ -1,14 +1,5 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Multi-platform" />
|
||||
|
||||
# Multi-platform applications
|
||||
|
||||
If you are interested in making a multi-platform app it is strongly recommended
|
||||
that you use Expo. Recent Expo releases include [web
|
||||
support](https://docs.expo.io/versions/v35.0.0/guides/running-in-the-browser/)
|
||||
and take care of all the configuration work required.
|
||||
|
||||
## Web-specific code
|
||||
|
||||
Minor platform differences can use the `Platform` module.
|
||||
@@ -45,9 +36,8 @@ target platform.
|
||||
|
||||
What follows is merely an _example_ of one basic way to package a web app using
|
||||
[Webpack](https://webpack.js.org) and [Babel](https://babeljs.io/). (You can
|
||||
also use the React Native bundler, [Metro](https://github.com/facebook/metro),
|
||||
to build web apps although it is not officially supported: see
|
||||
[#1257](https://github.com/necolas/react-native-web/issues/1257#issuecomment-541443684).)
|
||||
also use the React Native bundler, [Metro](https://github.com/facebook/metro), to
|
||||
build web apps.)
|
||||
|
||||
Packaging web apps is subtly different to packaging React Native apps and is
|
||||
complicated by the need to tree-shake and code-split non-trivial apps.
|
||||
@@ -94,8 +84,8 @@ const babelLoaderConfiguration = {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
// The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
// The 'react-native' preset is recommended to match React Native's packager
|
||||
presets: ['react-native'],
|
||||
// Re-write paths to import only the modules needed by the app
|
||||
plugins: ['react-native-web']
|
||||
}
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Server-side" />
|
||||
|
||||
# Server-side rendering
|
||||
|
||||
Server-side rendering to HTML is supported using `AppRegistry`:
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Style" />
|
||||
|
||||
# Style
|
||||
|
||||
React Native relies on JavaScript to define and resolve the styles of your
|
||||
@@ -62,7 +58,7 @@ registered object, a plain object, or an array.
|
||||
<View style={{ transform: [ { translateX } ] }} />
|
||||
|
||||
// array of registered or plain objects
|
||||
<View style={[ styles.container, props.style ]} />
|
||||
<View style={[ styles.container, this.props.style ]} />
|
||||
```
|
||||
|
||||
The array syntax will merge styles from left-to-right as normal JavaScript
|
||||
@@ -71,7 +67,7 @@ objects, and can be used to conditionally apply styles:
|
||||
```js
|
||||
<View style={[
|
||||
styles.container,
|
||||
state.active && styles.active
|
||||
this.state.active && styles.active
|
||||
]} />
|
||||
```
|
||||
|
||||
@@ -87,30 +83,28 @@ To let other components customize the style of a component's children you can
|
||||
expose a prop so styles can be explicitly passed into the component.
|
||||
|
||||
```js
|
||||
import { View } from 'react-native';
|
||||
class List extends React.Component {
|
||||
static propTypes = {
|
||||
style: ViewPropTypes.style,
|
||||
elementStyle: ViewPropTypes.style,
|
||||
}
|
||||
|
||||
type ViewProps = $PropertyType<View, 'props'>;
|
||||
type ViewStyle = $PropertyType<ViewProps, 'style'>;
|
||||
type Props = {
|
||||
elementStyle: ViewStyle,
|
||||
style: ViewStyle,
|
||||
};
|
||||
|
||||
export default function List(props: Props) {
|
||||
return (
|
||||
<View style={props.style}>
|
||||
{elements.map((element) =>
|
||||
<View style={[ styles.element, props.elementStyle ]} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
render() {
|
||||
return (
|
||||
<View style={this.props.style}>
|
||||
{elements.map((element) =>
|
||||
<View style={[ styles.element, this.props.elementStyle ]} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In another file:
|
||||
|
||||
```js
|
||||
<List elementStyle={styles.listElement} style={styles.list} />
|
||||
<List style={styles.list} elementStyle={styles.listElement} />
|
||||
```
|
||||
|
||||
You also have much greater control over how styles are composed when compared
|
||||
@@ -127,11 +121,10 @@ the CSS and takes precedence over the previous rules, resulting in a margin of
|
||||
|
||||
```html
|
||||
<style>
|
||||
.marginTop { margin-top: 10px; }
|
||||
.marginBottom { margin-bottom: 20px; }
|
||||
.margin { margin: 0; }
|
||||
.marginTop { margin-top: 10px; }
|
||||
.marginBottom { margin-bottom: 20px; }
|
||||
.margin { margin: 0; }
|
||||
</style>
|
||||
|
||||
<div class="marginTop marginBottom margin"></div>
|
||||
```
|
||||
|
||||
@@ -174,10 +167,10 @@ Output:
|
||||
|
||||
```html
|
||||
<style>
|
||||
.rn-1mnahxq { margin-top: 0px; }
|
||||
.rn-61z16t { margin-right: 0px; }
|
||||
.rn-p1pxzi { margin-bottom: 0px; }
|
||||
.rn-11wrixw { margin-left: 0px; }
|
||||
.rn-1mnahxq { margin-top: 0px; }
|
||||
.rn-61z16t { margin-right: 0px; }
|
||||
.rn-p1pxzi { margin-bottom: 0px; }
|
||||
.rn-11wrixw { margin-left: 0px; }
|
||||
</style>
|
||||
|
||||
<div class="rn-156q2ks rn-61z16t rn-p1pxzi rn-11wrixw"></div>
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Guides|Web recipes" />
|
||||
|
||||
# Web recipes
|
||||
|
||||
Examples of how to implement web patterns with React Native.
|
||||
89
package.json
89
package.json
@@ -1,65 +1,64 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "0.14.7",
|
||||
"name": "monorepo",
|
||||
"version": "0.9.13",
|
||||
"name": "react-native-web-monorepo",
|
||||
"scripts": {
|
||||
"clean": "del-cli ./packages/*/dist",
|
||||
"clean": "del ./packages/*/dist",
|
||||
"compile": "npm-run-all clean -p \"compile:* -- {@}\" --",
|
||||
"compile:commonjs": "cd packages/react-native-web && cross-env BABEL_ENV=commonjs babel --root-mode upward src --out-dir dist/cjs --ignore \"**/__tests__\"",
|
||||
"compile:es": "cd packages/react-native-web && babel --root-mode upward src --out-dir dist --ignore \"**/__tests__\"",
|
||||
"compile:commonjs": "cd packages/react-native-web && BABEL_ENV=commonjs babel src --out-dir dist/cjs --ignore \"**/__tests__\"",
|
||||
"compile:es": "cd packages/react-native-web && babel src --out-dir dist --ignore \"**/__tests__\"",
|
||||
"benchmarks": "cd packages/benchmarks && yarn build",
|
||||
"benchmarks:release": "cd packages/benchmarks && yarn release",
|
||||
"docs": "cd packages/docs && yarn start",
|
||||
"docs:release": "cd packages/docs && yarn release",
|
||||
"examples": "cd packages/examples && yarn build",
|
||||
"examples:release": "cd packages/examples && yarn release",
|
||||
"website": "cd packages/website && yarn start",
|
||||
"website:release": "cd packages/website && yarn release",
|
||||
"flow": "flow",
|
||||
"fmt": "prettier --write \"**/*.js\"",
|
||||
"jest": "jest --config ./scripts/jest/config.js",
|
||||
"jest": "BABEL_ENV=commonjs jest --config ./scripts/jest/config.js",
|
||||
"lint": "yarn lint:check --fix",
|
||||
"lint:check": "eslint packages scripts",
|
||||
"precommit": "lint-staged",
|
||||
"prerelease": "yarn test && yarn compile && yarn compile:commonjs",
|
||||
"release": "node ./scripts/release/publish.js",
|
||||
"postrelease": "yarn benchmarks:release && yarn docs:release",
|
||||
"postrelease": "yarn benchmarks:release && yarn examples:release && yarn website:release",
|
||||
"test": "yarn flow && yarn lint:check && yarn jest --runInBand"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.8.4",
|
||||
"@babel/core": "^7.8.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-runtime": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@babel/preset-flow": "^7.8.3",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"@testing-library/react": "^9.3.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^25.1.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-add-module-exports": "^1.0.2",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||
"caniuse-api": "^3.0.0",
|
||||
"cross-env": "^6.0.3",
|
||||
"del-cli": "^3.0.0",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-prettier": "^6.4.0",
|
||||
"eslint-plugin-flowtype": "^4.7.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.16.0",
|
||||
"eslint-plugin-react-hooks": "^2.3.0",
|
||||
"flow-bin": "^0.109.0",
|
||||
"glob": "^7.1.4",
|
||||
"husky": "^3.0.8",
|
||||
"inline-style-prefixer": "^5.1.0",
|
||||
"jest": "^25.1.0",
|
||||
"jest-canvas-mock": "^2.2.0",
|
||||
"lint-staged": "^9.4.2",
|
||||
"metro-react-native-babel-preset": "^0.56.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-flow": "^6.23.0",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-react-native": "^4.0.0",
|
||||
"caniuse-api": "^2.0.0",
|
||||
"del-cli": "^1.1.0",
|
||||
"enzyme": "^3.6.0",
|
||||
"enzyme-adapter-react-16": "^1.5.0",
|
||||
"enzyme-to-json": "^3.3.3",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-promise": "^3.7.0",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"flow-bin": "^0.63.1",
|
||||
"glob": "^7.1.2",
|
||||
"husky": "^0.14.3",
|
||||
"inline-style-prefixer": "^5.0.3",
|
||||
"jest": "^22.4.3",
|
||||
"jest-canvas-mock": "^1.0.2",
|
||||
"lint-staged": "^7.1.0",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"prettier": "^1.18.2",
|
||||
"react": "^16.10.2",
|
||||
"react-dom": "^16.10.2",
|
||||
"react-test-renderer": "^16.10.2"
|
||||
"prettier": "^1.12.1",
|
||||
"react": "^16.7.0",
|
||||
"react-art": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-test-renderer": "^16.7.0"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
{
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"name": "babel-plugin-react-native-web",
|
||||
"version": "0.14.7",
|
||||
"version": "0.9.13",
|
||||
"description": "Babel plugin for React Native for Web",
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-plugin-tester": "^7.0.4"
|
||||
"babel-plugin-tester": "^5.0.0"
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -3,28 +3,30 @@
|
||||
exports[`Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = `
|
||||
"
|
||||
export { View } from 'react-native';
|
||||
export { StyleSheet, Text, unstable_createElement } from 'react-native';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as View } from 'react-native-web/dist/exports/View';
|
||||
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||
export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement';
|
||||
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = `
|
||||
"
|
||||
export { View } from 'react-native-web';
|
||||
export { StyleSheet, Text, unstable_createElement } from 'react-native-web';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as View } from 'react-native-web/dist/exports/View';
|
||||
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||
export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement';
|
||||
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -32,7 +34,7 @@ exports[`Rewrite react-native to react-native-web import from "native-native": i
|
||||
"
|
||||
import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
@@ -41,6 +43,7 @@ import ReactNative from 'react-native-web/dist/index';
|
||||
import View from 'react-native-web/dist/exports/View';
|
||||
import { Invalid } from 'react-native-web/dist/index';
|
||||
import MyView from 'react-native-web/dist/exports/View';
|
||||
import ViewPropTypes from 'react-native-web/dist/exports/ViewPropTypes';
|
||||
import * as ReactNativeModules from 'react-native-web/dist/index';
|
||||
"
|
||||
`;
|
||||
@@ -49,7 +52,7 @@ exports[`Rewrite react-native to react-native-web import from "native-native": i
|
||||
"
|
||||
import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
@@ -58,19 +61,21 @@ import ReactNative from 'react-native-web/dist/cjs/index';
|
||||
import View from 'react-native-web/dist/cjs/exports/View';
|
||||
import { Invalid } from 'react-native-web/dist/cjs/index';
|
||||
import MyView from 'react-native-web/dist/cjs/exports/View';
|
||||
import ViewPropTypes from 'react-native-web/dist/cjs/exports/ViewPropTypes';
|
||||
import * as ReactNativeModules from 'react-native-web/dist/cjs/index';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = `
|
||||
"
|
||||
import { unstable_createElement } from 'react-native-web';
|
||||
import { StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
import { createElement } from 'react-native-web';
|
||||
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
import * as ReactNativeModules from 'react-native-web';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
import unstable_createElement from 'react-native-web/dist/exports/createElement';
|
||||
import createElement from 'react-native-web/dist/exports/createElement';
|
||||
import ColorPropType from 'react-native-web/dist/exports/ColorPropType';
|
||||
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
|
||||
import View from 'react-native-web/dist/exports/View';
|
||||
import TouchableOpacity from 'react-native-web/dist/exports/TouchableOpacity';
|
||||
@@ -87,7 +92,7 @@ const { StyleSheet, TouchableOpacity } = require('react-native');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/index');
|
||||
const ReactNative = require('react-native-web/dist/index').default;
|
||||
|
||||
const View = require('react-native-web/dist/exports/View').default;
|
||||
|
||||
@@ -105,7 +110,7 @@ const { StyleSheet, TouchableOpacity } = require('react-native');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/cjs/index');
|
||||
const ReactNative = require('react-native-web/dist/cjs/index').default;
|
||||
|
||||
const View = require('react-native-web/dist/cjs/exports/View').default;
|
||||
|
||||
@@ -118,14 +123,16 @@ const TouchableOpacity = require('react-native-web/dist/cjs/exports/TouchableOpa
|
||||
exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = `
|
||||
"
|
||||
const ReactNative = require('react-native-web');
|
||||
const { unstable_createElement } = require('react-native-web');
|
||||
const { StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');
|
||||
const { createElement } = require('react-native-web');
|
||||
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/index');
|
||||
const ReactNative = require('react-native-web/dist/index').default;
|
||||
|
||||
const unstable_createElement = require('react-native-web/dist/exports/createElement').default;
|
||||
const createElement = require('react-native-web/dist/exports/createElement').default;
|
||||
|
||||
const ColorPropType = require('react-native-web/dist/exports/ColorPropType').default;
|
||||
|
||||
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const tests = [
|
||||
title: 'import from "native-native"',
|
||||
code: `import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';`,
|
||||
snapshot: true
|
||||
},
|
||||
@@ -15,28 +15,28 @@ import * as ReactNativeModules from 'react-native';`,
|
||||
title: 'import from "native-native"',
|
||||
code: `import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';`,
|
||||
snapshot: true,
|
||||
pluginOptions: { commonjs: true }
|
||||
},
|
||||
{
|
||||
title: 'import from "react-native-web"',
|
||||
code: `import { unstable_createElement } from 'react-native-web';
|
||||
import { StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
code: `import { createElement } from 'react-native-web';
|
||||
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
import * as ReactNativeModules from 'react-native-web';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'export from "react-native"',
|
||||
code: `export { View } from 'react-native';
|
||||
export { StyleSheet, Text, unstable_createElement } from 'react-native';`,
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'export from "react-native-web"',
|
||||
code: `export { View } from 'react-native-web';
|
||||
export { StyleSheet, Text, unstable_createElement } from 'react-native-web';`,
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
@@ -57,20 +57,13 @@ const { StyleSheet, TouchableOpacity } = require('react-native');`,
|
||||
{
|
||||
title: 'require "react-native-web"',
|
||||
code: `const ReactNative = require('react-native-web');
|
||||
const { unstable_createElement } = require('react-native-web');
|
||||
const { StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');`,
|
||||
const { createElement } = require('react-native-web');
|
||||
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');`,
|
||||
snapshot: true
|
||||
}
|
||||
];
|
||||
|
||||
pluginTester({
|
||||
babelOptions: {
|
||||
generatorOpts: {
|
||||
jsescOption: {
|
||||
quotes: 'single'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugin,
|
||||
tests
|
||||
});
|
||||
|
||||
@@ -4,11 +4,10 @@ const isCommonJS = opts => opts.commonjs === true;
|
||||
|
||||
const getDistLocation = (importName, opts) => {
|
||||
const format = isCommonJS(opts) ? 'cjs/' : '';
|
||||
const internalName = importName === 'unstable_createElement' ? 'createElement' : importName;
|
||||
if (internalName === 'index') {
|
||||
if (importName === 'index') {
|
||||
return `react-native-web/dist/${format}index`;
|
||||
} else if (internalName && moduleMap[internalName]) {
|
||||
return `react-native-web/dist/${format}exports/${internalName}`;
|
||||
} else if (importName && moduleMap[importName]) {
|
||||
return `react-native-web/dist/${format}exports/${importName}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -119,9 +118,12 @@ module.exports = function({ types: t }) {
|
||||
const importIndex = t.variableDeclaration(path.node.kind, [
|
||||
t.variableDeclarator(
|
||||
t.identifier(name),
|
||||
t.callExpression(t.identifier('require'), [
|
||||
t.stringLiteral(getDistLocation('index', state.opts))
|
||||
])
|
||||
t.memberExpression(
|
||||
t.callExpression(t.identifier('require'), [
|
||||
t.stringLiteral(getDistLocation('index', state.opts))
|
||||
]),
|
||||
t.identifier('default')
|
||||
)
|
||||
)
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
module.exports = {
|
||||
ART: true,
|
||||
AccessibilityInfo: true,
|
||||
ActivityIndicator: true,
|
||||
Alert: true,
|
||||
Animated: true,
|
||||
AppRegistry: true,
|
||||
AppState: true,
|
||||
Appearance: true,
|
||||
AsyncStorage: true,
|
||||
BackHandler: true,
|
||||
Button: true,
|
||||
CheckBox: true,
|
||||
Clipboard: true,
|
||||
DeviceEventEmitter: true,
|
||||
ColorPropType: true,
|
||||
DeviceInfo: true,
|
||||
Dimensions: true,
|
||||
DrawerLayoutAndroid: true,
|
||||
Easing: true,
|
||||
EdgeInsetsPropType: true,
|
||||
FlatList: true,
|
||||
I18nManager: true,
|
||||
Image: true,
|
||||
ImageBackground: true,
|
||||
InputAccessoryView: true,
|
||||
InteractionManager: true,
|
||||
Keyboard: true,
|
||||
KeyboardAvoidingView: true,
|
||||
LayoutAnimation: true,
|
||||
Linking: true,
|
||||
LogBox: true,
|
||||
ListView: true,
|
||||
Modal: true,
|
||||
NativeEventEmitter: true,
|
||||
NativeModules: true,
|
||||
NetInfo: true,
|
||||
PanResponder: true,
|
||||
PermissionsAndroid: true,
|
||||
Picker: true,
|
||||
PixelRatio: true,
|
||||
Platform: true,
|
||||
Pressable: true,
|
||||
PointPropType: true,
|
||||
ProgressBar: true,
|
||||
RefreshControl: true,
|
||||
SafeAreaView: true,
|
||||
ScrollView: true,
|
||||
SectionList: true,
|
||||
Settings: true,
|
||||
Share: true,
|
||||
Slider: true,
|
||||
StatusBar: true,
|
||||
StyleSheet: true,
|
||||
SwipeableFlatList: true,
|
||||
SwipeableListView: true,
|
||||
Switch: true,
|
||||
Systrace: true,
|
||||
TVEventHandler: true,
|
||||
Text: true,
|
||||
TextInput: true,
|
||||
ToastAndroid: true,
|
||||
TextPropTypes: true,
|
||||
Touchable: true,
|
||||
TouchableHighlight: true,
|
||||
TouchableNativeFeedback: true,
|
||||
@@ -59,13 +59,12 @@ module.exports = {
|
||||
UIManager: true,
|
||||
Vibration: true,
|
||||
View: true,
|
||||
ViewPropTypes: true,
|
||||
VirtualizedList: true,
|
||||
YellowBox: true,
|
||||
createElement: true,
|
||||
findNodeHandle: true,
|
||||
processColor: true,
|
||||
render: true,
|
||||
unmountComponentAtNode: true,
|
||||
useColorScheme: true,
|
||||
useWindowDimensions: true
|
||||
unmountComponentAtNode: true
|
||||
};
|
||||
|
||||
@@ -47,24 +47,24 @@ included.
|
||||
|
||||
### MacBook Pro (2011)
|
||||
|
||||
MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 72.
|
||||
MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 63.
|
||||
|
||||
Typical render timings: mean ± standard deviations.
|
||||
|
||||
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
||||
| :--- | ---: | ---: | ---: |
|
||||
| `css-modules` | `23.41` `±03.06` | `35.38` `±06.41` | - |
|
||||
| `react-native-web@0.11.0` | `28.37` `±04.39` | `41.50` `±05.75` | `23.13` `±03.51` |
|
||||
| `inline-styles` | `66.19` `±06.31` | `104.22` `±10.22` | `09.96` `±02.76` |
|
||||
| `css-modules` | `30.19` `±04.84` | `38.25` `±04.85` | - |
|
||||
| `react-native-web@0.4.0` | `36.40` `±04.98` | `51.28` `±05.58` | `19.36` `±02.56` |
|
||||
| `inline-styles` | `64.12` `±07.69` | `94.49` `±11.34` | `09.84` `±02.36` |
|
||||
|
||||
### Moto G4
|
||||
|
||||
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 72.
|
||||
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63.
|
||||
|
||||
Typical render timings: mean ± standard deviations.
|
||||
|
||||
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
||||
| :--- | ---: | ---: | ---: |
|
||||
| `css-modules` | `71.33` `±09.68` | `101.36` `±12.36` | - |
|
||||
| `react-native-web@0.11.0` | `83.65` `±12.40` | `123.59` `±14.40` | `75.41` `±07.74` |
|
||||
| `inline-styles` | `188.35` `±17.69` | `282.35` `±22.48` | `28.10` `±06.87` |
|
||||
| `css-modules` | `98.24` `±20.26` | `143.75` `±25.50` | - |
|
||||
| `react-native-web@0.4.0` | `131.46` `±18.96` | `174.70` `±14.88` | `60.87` `±06.32` |
|
||||
| `inline-styles` | `184.58` `±26.23` | `273.86` `±26.23` | `30.28` `±07.44` |
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "benchmarks",
|
||||
"version": "0.14.7",
|
||||
"version": "0.9.13",
|
||||
"scripts": {
|
||||
"build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
|
||||
"release": "NODE_ENV=production yarn build && git checkout gh-pages && rm -rf ../../benchmarks && mv dist ../../benchmarks && git add -A && git commit -m \"Benchmarks deploy\" && git push origin gh-pages && git checkout -"
|
||||
},
|
||||
"dependencies": {
|
||||
"aphrodite": "^2.4.0",
|
||||
"aphrodite": "^2.2.3",
|
||||
"classnames": "^2.2.6",
|
||||
"d3-scale-chromatic": "^1.5.0",
|
||||
"emotion": "^10.0.27",
|
||||
"fela": "^11.0.2",
|
||||
"react-fela": "^11.0.2",
|
||||
"react-jss": "^10.0.4",
|
||||
"react-native-web": "0.14.7",
|
||||
"reactxp": "^2.0.0",
|
||||
"styled-components": "^5.0.0",
|
||||
"styled-jsx": "^3.2.4",
|
||||
"styletron-engine-atomic": "^1.4.4",
|
||||
"styletron-react": "^5.2.6"
|
||||
"d3-scale-chromatic": "^1.3.3",
|
||||
"emotion": "^10.0.5",
|
||||
"fela": "^10.0.2",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-fela": "^10.0.2",
|
||||
"react-jss": "^8.6.1",
|
||||
"react-native-web": "0.9.13",
|
||||
"reactxp": "^1.5.0",
|
||||
"styled-components": "^4.1.3",
|
||||
"styled-jsx": "^3.1.2",
|
||||
"styletron-engine-atomic": "^1.0.13",
|
||||
"styletron-react": "^4.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-react-native-web": "0.14.7",
|
||||
"css-loader": "^3.4.2",
|
||||
"style-loader": "^1.1.3",
|
||||
"url-loader": "^3.0.0",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.10"
|
||||
"babel-plugin-react-native-web": "0.9.13",
|
||||
"css-loader": "^2.0.2",
|
||||
"style-loader": "^0.23.1",
|
||||
"url-loader": "^1.1.2",
|
||||
"webpack": "^4.28.1",
|
||||
"webpack-bundle-analyzer": "^3.0.3",
|
||||
"webpack-cli": "^3.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
import Benchmark from './Benchmark';
|
||||
import { Picker, StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2017 Paul Armstrong
|
||||
* https://github.com/paularmstrong/react-component-benchmark
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/* global $Values */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
import * as Timing from './timing';
|
||||
import React, { Component } from 'react';
|
||||
import { getMean, getMedian, getStdDev } from './math';
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { StyleSheet, TouchableHighlight, Text } from 'react-native';
|
||||
import { ColorPropType, StyleSheet, TouchableHighlight, Text } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import { bool, func, string } from 'prop-types';
|
||||
|
||||
export default class Button extends Component<*> {
|
||||
static displayName = '@app/Button';
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: string,
|
||||
color: ColorPropType,
|
||||
disabled: bool,
|
||||
onPress: func.isRequired,
|
||||
style: TouchableHighlight.propTypes.style,
|
||||
testID: string,
|
||||
textStyle: Text.propTypes.style,
|
||||
title: string.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { unstable_createElement as createElement, StyleSheet } from 'react-native';
|
||||
import { createElement, StyleSheet, Text } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
@@ -18,16 +18,16 @@ const createIcon = children => {
|
||||
createElement(
|
||||
'svg',
|
||||
{
|
||||
style: StyleSheet.compose(
|
||||
styles.root,
|
||||
props.style
|
||||
),
|
||||
style: StyleSheet.compose(styles.root, props.style),
|
||||
width: 24,
|
||||
height: 24,
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
children
|
||||
);
|
||||
Icon.propTypes = {
|
||||
style: Text.propTypes.style
|
||||
};
|
||||
return Icon;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { colors } from './theme';
|
||||
import { element } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
export default class Layout extends Component {
|
||||
static propTypes = {
|
||||
actionPanel: element,
|
||||
listPanel: element,
|
||||
viewPanel: element
|
||||
};
|
||||
|
||||
state = {
|
||||
widescreen: false
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* @noflow */
|
||||
|
||||
/* eslint-disable react/prop-types */
|
||||
import Text from './Text';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
import { bool } from 'prop-types';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
import { bool } from 'prop-types';
|
||||
import { colors } from './theme';
|
||||
|
||||
class AppText extends React.Component {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BenchmarkType } from '../app/Benchmark';
|
||||
import { number, object } from 'prop-types';
|
||||
import React from 'react';
|
||||
import { interpolatePurples, interpolateBuPu, interpolateRdPu } from 'd3-scale-chromatic';
|
||||
|
||||
@@ -9,6 +10,15 @@ class SierpinskiTriangle extends React.Component {
|
||||
|
||||
static benchmarkType = BenchmarkType.UPDATE;
|
||||
|
||||
static propTypes = {
|
||||
components: object,
|
||||
depth: number,
|
||||
renderCount: number,
|
||||
s: number,
|
||||
x: number,
|
||||
y: number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
depth: 0,
|
||||
renderCount: 0
|
||||
@@ -35,7 +45,7 @@ class SierpinskiTriangle extends React.Component {
|
||||
}
|
||||
|
||||
// introduce randomness to ensure that repeated runs don't produce the same colors
|
||||
const color = fn((renderCount * Math.random()) / 20);
|
||||
const color = fn(renderCount * Math.random() / 20);
|
||||
return (
|
||||
<Dot color={color} size={targetSize} x={x - targetSize / 2} y={y - targetSize / 2} />
|
||||
);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { BenchmarkType } from '../app/Benchmark';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class TextTree extends Component {
|
||||
static displayName = 'TextTree';
|
||||
|
||||
static benchmarkType = BenchmarkType.MOUNT;
|
||||
|
||||
render() {
|
||||
const { breadth, components, depth, id, wrap } = this.props;
|
||||
const { TextBox } = components;
|
||||
|
||||
let result = (
|
||||
<TextBox children={'TextBox ${id % 3}'} color={id % 3} outer>
|
||||
{depth === 0 && <TextBox children={'Depth 0'} color={(id % 3) + 3} />}
|
||||
{depth !== 0 &&
|
||||
Array.from({ length: breadth }).map((el, i) => (
|
||||
<TextTree
|
||||
breadth={breadth}
|
||||
components={components}
|
||||
depth={depth - 1}
|
||||
id={i}
|
||||
key={i}
|
||||
wrap={wrap}
|
||||
/>
|
||||
))}
|
||||
</TextBox>
|
||||
);
|
||||
for (let i = 0; i < wrap; i++) {
|
||||
result = <TextBox>{result}</TextBox>;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default TextTree;
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BenchmarkType } from '../app/Benchmark';
|
||||
import { number, object } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class Tree extends Component {
|
||||
@@ -6,13 +7,21 @@ class Tree extends Component {
|
||||
|
||||
static benchmarkType = BenchmarkType.MOUNT;
|
||||
|
||||
static propTypes = {
|
||||
breadth: number.isRequired,
|
||||
components: object,
|
||||
depth: number.isRequired,
|
||||
id: number.isRequired,
|
||||
wrap: number.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const { breadth, components, depth, id, wrap } = this.props;
|
||||
const { Box } = components;
|
||||
|
||||
let result = (
|
||||
<Box color={id % 3} layout={depth % 2 === 0 ? 'column' : 'row'} outer>
|
||||
{depth === 0 && <Box color={(id % 3) + 3} fixed />}
|
||||
{depth === 0 && <Box color={id % 3 + 3} fixed />}
|
||||
{depth !== 0 &&
|
||||
Array.from({ length: breadth }).map((el, i) => (
|
||||
<Tree
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* @noflow */
|
||||
|
||||
import { type Component } from 'react';
|
||||
import packageJson from '../package.json';
|
||||
|
||||
@@ -10,7 +8,6 @@ type ComponentsType = {
|
||||
Box: Component,
|
||||
Dot: Component,
|
||||
Provider: Component,
|
||||
TextBox: Component,
|
||||
View: Component
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
import { StyleSheet } from 'aphrodite';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { css, StyleSheet } from 'aphrodite';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import styles from './view-styles.css';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { css } from 'emotion';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { css } from 'emotion';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
|
||||
const Dot = ({ size, x, y, children, color }) => (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
|
||||
const compose = (s1, s2) => {
|
||||
@@ -11,15 +12,7 @@ const compose = (s1, s2) => {
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
return (
|
||||
<div
|
||||
{...other}
|
||||
style={compose(
|
||||
viewStyle,
|
||||
style
|
||||
)}
|
||||
/>
|
||||
);
|
||||
return <div {...other} style={compose(viewStyle, style)} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createComponent } from 'react-fela';
|
||||
|
||||
const Dot = createComponent(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { createRenderer } from 'fela';
|
||||
import { Provider as FelaProvider } from 'react-fela';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createComponent } from 'react-fela';
|
||||
|
||||
const View = createComponent(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import injectSheet from 'react-jss';
|
||||
import React from 'react';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import injectSheet from 'react-jss';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import injectSheet from 'react-jss';
|
||||
import React from 'react';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { unstable_createElement as createElement, StyleSheet } from 'react-native';
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createElement, StyleSheet } from 'react-native';
|
||||
|
||||
const Dot = ({ size, x, y, children, color }) =>
|
||||
createElement('div', {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
|
||||
const TextBox = ({ color, outer = false, ...other }) => (
|
||||
<Text {...other} style={[styles.root, styles[`color${color}`], outer && styles.outer]} />
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
color: 'white'
|
||||
},
|
||||
outer: {
|
||||
fontStyle: 'italic'
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
color0: {
|
||||
color: '#14171A'
|
||||
},
|
||||
color1: {
|
||||
color: '#AAB8C2'
|
||||
},
|
||||
color2: {
|
||||
color: '#E6ECF0'
|
||||
},
|
||||
color3: {
|
||||
color: '#FFAD1F'
|
||||
},
|
||||
color4: {
|
||||
color: '#F45D22'
|
||||
},
|
||||
color5: {
|
||||
color: '#E0245E'
|
||||
}
|
||||
});
|
||||
|
||||
export default TextBox;
|
||||
108
packages/benchmarks/src/implementations/react-native-web/Tweet/AppText.js
vendored
Normal file
108
packages/benchmarks/src/implementations/react-native-web/Tweet/AppText.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import theme from './theme';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
|
||||
class AppText extends PureComponent {
|
||||
static displayName = 'AppText';
|
||||
|
||||
static propTypes = {
|
||||
align: PropTypes.oneOf(['center', 'left', 'right']),
|
||||
color: PropTypes.oneOf(['blue', 'deepGray', 'normal', 'red', 'white']),
|
||||
fontStyle: PropTypes.oneOf(['normal', 'italic']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
uppercase: PropTypes.bool,
|
||||
weight: PropTypes.oneOf(['normal', 'bold'])
|
||||
};
|
||||
|
||||
render() {
|
||||
const { align, color, fontStyle, size, uppercase, weight, ...other } = this.props;
|
||||
|
||||
const style = [
|
||||
styles.root,
|
||||
align && alignStyles[align],
|
||||
color && colorStyles[color],
|
||||
fontStyle && fontStyles[fontStyle],
|
||||
size && sizeStyles[size],
|
||||
weight && weightStyles[weight],
|
||||
uppercase === true && styles.uppercase
|
||||
];
|
||||
|
||||
return <Text {...other} style={style} />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
fontFamily: theme.fontFamily,
|
||||
fontSize: theme.fontSize.normal,
|
||||
fontWeight: 'normal',
|
||||
lineHeight: theme.createLength(theme.lineHeight),
|
||||
wordWrap: 'break-word'
|
||||
},
|
||||
uppercase: {
|
||||
textTransform: 'uppercase'
|
||||
}
|
||||
});
|
||||
|
||||
const alignStyles = StyleSheet.create({
|
||||
center: {
|
||||
textAlign: 'center'
|
||||
},
|
||||
left: {
|
||||
textAlign: 'left'
|
||||
},
|
||||
right: {
|
||||
textAlign: 'right'
|
||||
}
|
||||
});
|
||||
|
||||
const colorStyles = StyleSheet.create({
|
||||
blue: {
|
||||
color: theme.colors.blue
|
||||
},
|
||||
deepGray: {
|
||||
color: theme.colors.deepGray
|
||||
},
|
||||
normal: {
|
||||
color: theme.colors.textBlack
|
||||
},
|
||||
red: {
|
||||
color: theme.colors.red
|
||||
},
|
||||
white: {
|
||||
color: theme.colors.white
|
||||
}
|
||||
});
|
||||
|
||||
const fontStyles = StyleSheet.create({
|
||||
normal: {
|
||||
fontStyle: 'normal'
|
||||
},
|
||||
italic: {
|
||||
fontStyle: 'italic'
|
||||
}
|
||||
});
|
||||
|
||||
const sizeStyles = StyleSheet.create({
|
||||
small: {
|
||||
fontSize: theme.fontSize.small
|
||||
},
|
||||
normal: {
|
||||
fontSize: theme.fontSize.normal
|
||||
},
|
||||
large: {
|
||||
fontSize: theme.fontSize.large
|
||||
}
|
||||
});
|
||||
|
||||
const weightStyles = StyleSheet.create({
|
||||
normal: {
|
||||
fontWeight: '400'
|
||||
},
|
||||
bold: {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
||||
export default AppText;
|
||||
41
packages/benchmarks/src/implementations/react-native-web/Tweet/AspectRatio.js
vendored
Normal file
41
packages/benchmarks/src/implementations/react-native-web/Tweet/AspectRatio.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { StyleSheet, View, ViewPropTypes } from 'react-native';
|
||||
|
||||
class AspectRatio extends PureComponent {
|
||||
static displayName = 'AspectRatio';
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
ratio: PropTypes.number,
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
ratio: 1
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, ratio, style } = this.props;
|
||||
const percentage = 100 / ratio;
|
||||
|
||||
return (
|
||||
<View style={[styles.root, style]}>
|
||||
<View style={[styles.shim, { paddingBottom: `${percentage}%` }]} />
|
||||
<View style={StyleSheet.absoluteFill}>{children}</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
overflow: 'hidden'
|
||||
},
|
||||
shim: {
|
||||
display: 'block',
|
||||
width: '100%'
|
||||
}
|
||||
});
|
||||
|
||||
export default AspectRatio;
|
||||
53
packages/benchmarks/src/implementations/react-native-web/Tweet/GridView.js
vendored
Normal file
53
packages/benchmarks/src/implementations/react-native-web/Tweet/GridView.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, View, ViewPropTypes } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import theme from './theme';
|
||||
|
||||
class GridView extends Component {
|
||||
static displayName = 'GridView';
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
hasGap: PropTypes.bool,
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, hasGap, style, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<View {...other} style={[style, styles.root, hasGap && styles.hasGap]}>
|
||||
{React.Children.map(children, child => {
|
||||
return (
|
||||
child &&
|
||||
React.cloneElement(child, {
|
||||
style: [child.props.style, styles.column, hasGap && styles.hasGapColumn]
|
||||
})
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
/**
|
||||
* 1. Distribute all space (rather than extra space)
|
||||
* 2. Prevent wide content from forcing wider flex columns
|
||||
*/
|
||||
column: {
|
||||
flexBasis: 0, // 1
|
||||
minWidth: 0 // 2
|
||||
},
|
||||
hasGap: {
|
||||
marginHorizontal: theme.createLength(theme.spaceX * -0.5, 'rem')
|
||||
},
|
||||
hasGapColumn: {
|
||||
marginHorizontal: theme.createLength(theme.spaceX * 0.5, 'rem')
|
||||
}
|
||||
});
|
||||
|
||||
export default GridView;
|
||||
20
packages/benchmarks/src/implementations/react-native-web/Tweet/IconDirectMessage.js
vendored
Normal file
20
packages/benchmarks/src/implementations/react-native-web/Tweet/IconDirectMessage.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createElement } from 'react-native';
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
const IconDirectMessage = props =>
|
||||
createElement('svg', {
|
||||
children: (
|
||||
<g>
|
||||
<path d="M43.34 14H12.66L28 27.946z" />
|
||||
<path d="M51.392 14.789L30.018 34.22c-.009.008-.028.006-.039.012-.563.5-1.266.768-1.98.768-.72 0-1.442-.258-2.017-.78L4.609 14.79A3.957 3.957 0 0 0 3 18v37a1.998 1.998 0 0 0 2 2c.464 0 .924-.162 1.292-.473L19 46h30c2.243 0 4-1.757 4-4V18a3.96 3.96 0 0 0-1.608-3.211z" />
|
||||
</g>
|
||||
),
|
||||
style: [styles.icon, props.style],
|
||||
viewBox: '0 0 56 72'
|
||||
});
|
||||
|
||||
IconDirectMessage.metadata = { height: 72, width: 56 };
|
||||
|
||||
export default IconDirectMessage;
|
||||
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconHeart.js
vendored
Normal file
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconHeart.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createElement } from 'react-native';
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
const IconHeart = props =>
|
||||
createElement('svg', {
|
||||
children: (
|
||||
<g>
|
||||
<path d="M38.723 12c-7.187 0-11.16 7.306-11.723 8.131C26.437 19.306 22.504 12 15.277 12 8.791 12 3.533 18.163 3.533 24.647 3.533 39.964 21.891 55.907 27 56c5.109-.093 23.467-16.036 23.467-31.353C50.467 18.163 45.209 12 38.723 12z" />
|
||||
</g>
|
||||
),
|
||||
style: [styles.icon, props.style],
|
||||
viewBox: '0 0 54 72'
|
||||
});
|
||||
|
||||
IconHeart.metadata = { height: 72, width: 54 };
|
||||
|
||||
export default IconHeart;
|
||||
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconReply.js
vendored
Normal file
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconReply.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createElement } from 'react-native';
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
const IconReply = props =>
|
||||
createElement('svg', {
|
||||
children: (
|
||||
<g>
|
||||
<path d="M41 31h-9V19a2.999 2.999 0 0 0-4.817-2.386l-21 16a3 3 0 0 0-.001 4.773l21 16a3.006 3.006 0 0 0 3.15.301A2.997 2.997 0 0 0 32 51V39h9c5.514 0 10 4.486 10 10a4 4 0 0 0 8 0c0-9.925-8.075-18-18-18z" />
|
||||
</g>
|
||||
),
|
||||
style: [styles.icon, props.style],
|
||||
viewBox: '0 0 62 72'
|
||||
});
|
||||
|
||||
IconReply.metadata = { height: 72, width: 62 };
|
||||
|
||||
export default IconReply;
|
||||
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconRetweet.js
vendored
Normal file
19
packages/benchmarks/src/implementations/react-native-web/Tweet/IconRetweet.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { createElement } from 'react-native';
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
const IconRetweet = props =>
|
||||
createElement('svg', {
|
||||
children: (
|
||||
<g>
|
||||
<path d="M70.676 36.644A3 3 0 0 0 68 35h-7V19a4 4 0 0 0-4-4H34a4 4 0 0 0 0 8h18a1 1 0 0 1 1 .998V35h-7a3.001 3.001 0 0 0-2.419 4.775l11 15a3.003 3.003 0 0 0 4.839-.001l11-15a3.001 3.001 0 0 0 .256-3.13zM40.001 48H22a.995.995 0 0 1-.992-.96L21.001 36h7a3.001 3.001 0 0 0 2.419-4.775l-11-15a3.003 3.003 0 0 0-4.839.001l-11 15A3 3 0 0 0 6.001 36h7l.011 16.003a4 4 0 0 0 4 3.997h22.989a4 4 0 0 0 0-8z" />
|
||||
</g>
|
||||
),
|
||||
style: [styles.icon, props.style],
|
||||
viewBox: '0 0 74 72'
|
||||
});
|
||||
|
||||
IconRetweet.metadata = { height: 72, width: 74 };
|
||||
|
||||
export default IconRetweet;
|
||||
78
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetAction.js
vendored
Normal file
78
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetAction.js
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import IconReply from './IconReply';
|
||||
import IconHeart from './IconHeart';
|
||||
import IconRetweet from './IconRetweet';
|
||||
import IconDirectMessage from './IconDirectMessage';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import theme from './theme';
|
||||
import { Text, View, ViewPropTypes, StyleSheet } from 'react-native';
|
||||
|
||||
const getIcon = (icon, highlighted) => {
|
||||
switch (icon) {
|
||||
case 'like':
|
||||
return <IconHeart />;
|
||||
case 'reply':
|
||||
return <IconReply />;
|
||||
case 'retweet':
|
||||
return <IconRetweet />;
|
||||
case 'directMessage':
|
||||
return <IconDirectMessage />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default class TweetAction extends React.Component {
|
||||
static displayName = 'TweetAction';
|
||||
|
||||
static propTypes = {
|
||||
count: PropTypes.number,
|
||||
displayMode: PropTypes.oneOf(['like', 'reply', 'retweet', 'directMessage']),
|
||||
highlighted: PropTypes.bool,
|
||||
onPress: PropTypes.func,
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
render() {
|
||||
const { count, displayMode, highlighted, onPress, style } = this.props;
|
||||
|
||||
return (
|
||||
<View accessibilityRole="button" onPress={onPress} style={[styles.root, style]}>
|
||||
<Text
|
||||
style={[
|
||||
styles.inner,
|
||||
displayMode === 'like' && highlighted && styles.likedColor,
|
||||
displayMode === 'retweet' && highlighted && styles.retweetedColor
|
||||
]}
|
||||
>
|
||||
{getIcon(displayMode, highlighted)}
|
||||
{count > 0 ? <Text style={styles.count}>{count}</Text> : null}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
minHeight: theme.createLength(theme.lineHeight, 'rem'),
|
||||
overflow: 'visible',
|
||||
userSelect: 'none',
|
||||
whiteSpace: 'nowrap'
|
||||
},
|
||||
inner: {
|
||||
alignItems: 'center',
|
||||
color: theme.colors.deepGray,
|
||||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
count: {
|
||||
marginLeft: '0.25em'
|
||||
},
|
||||
retweetedColor: {
|
||||
color: theme.colors.green
|
||||
},
|
||||
likedColor: {
|
||||
color: theme.colors.red
|
||||
}
|
||||
});
|
||||
52
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetActionsBar.js
vendored
Normal file
52
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetActionsBar.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import TweetAction from './TweetAction';
|
||||
import { View, ViewPropTypes, StyleSheet } from 'react-native';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
const actionNames = ['reply', 'retweet', 'like', 'directMessage'];
|
||||
|
||||
export default class TweetActionsBar extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
count: PropTypes.number,
|
||||
label: PropTypes.string,
|
||||
highlighted: PropTypes.bool,
|
||||
name: PropTypes.oneOf(actionNames).isRequired,
|
||||
onPress: PropTypes.func
|
||||
})
|
||||
),
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
render() {
|
||||
const { actions, style } = this.props;
|
||||
|
||||
/* eslint-disable react/jsx-handler-names */
|
||||
return (
|
||||
<View style={[styles.root, style]}>
|
||||
{actions.map((action, i) => (
|
||||
<TweetAction
|
||||
accessibilityLabel={actions.label}
|
||||
count={action.count}
|
||||
displayMode={action.name}
|
||||
highlighted={action.highlighted}
|
||||
key={i}
|
||||
onPress={action.onPress}
|
||||
style={styles.action}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
action: {
|
||||
display: 'block',
|
||||
marginRight: '10%'
|
||||
}
|
||||
});
|
||||
29
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetText.js
vendored
Normal file
29
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetText.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import AppText from './AppText';
|
||||
import React from 'react';
|
||||
import TweetTextPart from './TweetTextPart';
|
||||
import { array, number, string } from 'prop-types';
|
||||
|
||||
class TweetText extends React.Component {
|
||||
static displayName = 'TweetText';
|
||||
|
||||
static propTypes = {
|
||||
displayMode: TweetTextPart.propTypes.displayMode,
|
||||
lang: string,
|
||||
numberOfLines: number,
|
||||
textParts: array.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const { displayMode, lang, numberOfLines, textParts, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<AppText {...other} lang={lang} numberOfLines={numberOfLines}>
|
||||
{textParts.map((part, i) => (
|
||||
<TweetTextPart displayMode={displayMode} key={i} part={part} />
|
||||
))}
|
||||
</AppText>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TweetText;
|
||||
113
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetTextPart.js
vendored
Normal file
113
packages/benchmarks/src/implementations/react-native-web/Tweet/TweetTextPart.js
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { Image, StyleSheet, Text } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import theme from './theme';
|
||||
|
||||
const createTextEntity = ({ part }) => <Text>{`${part.prefix}${part.text}`}</Text>;
|
||||
|
||||
const createTwemojiEntity = ({ part }) => (
|
||||
<Image
|
||||
accessibilityLabel={part.text}
|
||||
draggable={false}
|
||||
source={{ uri: part.emoji }}
|
||||
style={styles.twemoji}
|
||||
/>
|
||||
);
|
||||
|
||||
// @mention, #hashtag, $cashtag
|
||||
const createSymbolEntity = ({ displayMode, part }) => {
|
||||
const links = displayMode === 'links';
|
||||
return (
|
||||
<Text accessibilityRole={links ? 'link' : null} href={part.url} style={[links && styles.link]}>
|
||||
{`${part.prefix}${part.text}`}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
// internal links
|
||||
const createLinkEntity = ({ displayMode, part }) => {
|
||||
const { displayUrl, linkRelation, url } = part;
|
||||
const links = displayMode === 'links';
|
||||
|
||||
return (
|
||||
<Text
|
||||
accessibilityRole={links ? 'link' : null}
|
||||
href={url}
|
||||
rel={links ? linkRelation : null}
|
||||
style={[links && styles.link]}
|
||||
>
|
||||
{displayUrl}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
// external links
|
||||
const createExternalLinkEntity = ({ displayMode, part }) => {
|
||||
const { displayUrl, linkRelation, url } = part;
|
||||
const links = displayMode === 'links';
|
||||
|
||||
return (
|
||||
<Text
|
||||
accessibilityRole={links ? 'link' : null}
|
||||
href={url}
|
||||
rel={links ? linkRelation : null}
|
||||
style={[links && styles.link]}
|
||||
target="_blank"
|
||||
>
|
||||
{displayUrl}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
class TweetTextPart extends React.Component {
|
||||
static displayName = 'TweetTextPart';
|
||||
|
||||
static propTypes = {
|
||||
displayMode: PropTypes.oneOf(['links', 'no-links']),
|
||||
part: PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
displayMode: 'links'
|
||||
};
|
||||
|
||||
render() {
|
||||
let renderer;
|
||||
const { isEmoji, isEntity, isHashtag, isMention, isMedia, isUrl } = this.props.part;
|
||||
|
||||
if (isEmoji || isEntity || isUrl || isMedia) {
|
||||
if (isUrl) {
|
||||
renderer = createExternalLinkEntity;
|
||||
} else if (isHashtag || isMention) {
|
||||
renderer = createSymbolEntity;
|
||||
} else if (isEmoji) {
|
||||
renderer = createTwemojiEntity;
|
||||
} else {
|
||||
renderer = createLinkEntity;
|
||||
}
|
||||
} else {
|
||||
renderer = createTextEntity;
|
||||
}
|
||||
|
||||
return renderer(this.props);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
link: {
|
||||
color: theme.colors.blue,
|
||||
textDecorationLine: 'none',
|
||||
unicodeBidi: 'embed'
|
||||
},
|
||||
twemoji: {
|
||||
display: 'inline-block',
|
||||
height: '1.25em',
|
||||
width: '1.25em',
|
||||
paddingRight: '0.05em',
|
||||
paddingLeft: '0.1em',
|
||||
textAlignVertical: '-0.2em'
|
||||
}
|
||||
});
|
||||
|
||||
export default TweetTextPart;
|
||||
65
packages/benchmarks/src/implementations/react-native-web/Tweet/UserAvatar.js
vendored
Normal file
65
packages/benchmarks/src/implementations/react-native-web/Tweet/UserAvatar.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import AspectRatio from './AspectRatio';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Image, StyleSheet, ViewPropTypes } from 'react-native';
|
||||
import React, { PureComponent } from 'react';
|
||||
import theme from './theme';
|
||||
|
||||
class UserAvatar extends PureComponent {
|
||||
static displayName = 'UserAvatar';
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
circle: PropTypes.bool,
|
||||
style: ViewPropTypes.style,
|
||||
uri: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
circle: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const { accessibilityLabel, circle, style, uri } = this.props;
|
||||
|
||||
return (
|
||||
<AspectRatio ratio={1} style={[styles.root, style]}>
|
||||
{uri ? (
|
||||
<Image
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onLoad={this._handleLoad}
|
||||
ref={this._setImageRef}
|
||||
source={{ uri }}
|
||||
style={[styles.image, circle && styles.circle]}
|
||||
/>
|
||||
) : null}
|
||||
</AspectRatio>
|
||||
);
|
||||
}
|
||||
|
||||
_handleLoad = () => {
|
||||
this._imageRef && this._imageRef.setNativeProps(nativeProps);
|
||||
};
|
||||
|
||||
_setImageRef = component => {
|
||||
this._imageRef = component;
|
||||
};
|
||||
}
|
||||
|
||||
const nativeProps = { style: { backgroundColor: '#fff' } };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
borderRadius: '0.35rem'
|
||||
},
|
||||
circle: {
|
||||
borderRadius: '9999px'
|
||||
},
|
||||
image: {
|
||||
backgroundColor: theme.colors.fadedGray,
|
||||
display: 'block',
|
||||
height: '100%',
|
||||
width: '100%'
|
||||
}
|
||||
});
|
||||
|
||||
export default UserAvatar;
|
||||
52
packages/benchmarks/src/implementations/react-native-web/Tweet/UserNames.js
vendored
Normal file
52
packages/benchmarks/src/implementations/react-native-web/Tweet/UserNames.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import AppText from './AppText';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, ViewPropTypes } from 'react-native';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
class UserNames extends PureComponent {
|
||||
static displayName = 'UserNames';
|
||||
|
||||
static propTypes = {
|
||||
fullName: PropTypes.string,
|
||||
layout: PropTypes.oneOf(['nowrap', 'stack']),
|
||||
onPress: PropTypes.func,
|
||||
screenName: PropTypes.string,
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
layout: 'nowrap'
|
||||
};
|
||||
|
||||
render() {
|
||||
const { fullName, layout, onPress, screenName, style, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<AppText
|
||||
{...other}
|
||||
color="deepGray"
|
||||
numberOfLines={layout === 'nowrap' ? 1 : null}
|
||||
onPress={onPress}
|
||||
style={[styles.root, style]}
|
||||
>
|
||||
<AppText color="normal" weight="bold">
|
||||
{fullName}
|
||||
</AppText>
|
||||
{layout === 'stack' ? ' \u000A' : ' '}
|
||||
<AppText color="deepGray" style={styles.screenName}>{`@${screenName}`}</AppText>
|
||||
</AppText>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
display: 'inline-block'
|
||||
},
|
||||
screenName: {
|
||||
unicodeBidi: 'embed',
|
||||
writingDirection: 'ltr'
|
||||
}
|
||||
});
|
||||
|
||||
export default UserNames;
|
||||
144
packages/benchmarks/src/implementations/react-native-web/Tweet/index.js
vendored
Normal file
144
packages/benchmarks/src/implementations/react-native-web/Tweet/index.js
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
import AspectRatio from './AspectRatio';
|
||||
import GridView from './GridView';
|
||||
import PropTypes from 'prop-types';
|
||||
import TweetActionsBar from './TweetActionsBar';
|
||||
import TweetText from './TweetText';
|
||||
import UserAvatar from './UserAvatar';
|
||||
import UserNames from './UserNames';
|
||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import theme from './theme';
|
||||
|
||||
export class Tweet extends Component {
|
||||
static displayName = 'Tweet';
|
||||
|
||||
static propTypes = {
|
||||
tweet: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const { tweet } = this.props;
|
||||
const { id, lang, media, textParts, timestamp, user } = tweet;
|
||||
const { fullName, profileImageUrl, screenName } = user;
|
||||
|
||||
return (
|
||||
<View accessibilityRole="article" accessible style={styles.root}>
|
||||
<GridView hasGap>
|
||||
<View style={styles.avatarColumn}>
|
||||
<View
|
||||
accessibilityRole="link"
|
||||
accessible
|
||||
href={`/${screenName}`}
|
||||
style={styles.avatarLink}
|
||||
>
|
||||
<UserAvatar style={styles.avatar} uri={profileImageUrl} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.bodyColumn}>
|
||||
<View style={styles.body}>
|
||||
<View style={styles.row}>
|
||||
<Text
|
||||
accessibilityRole="link"
|
||||
children={timestamp}
|
||||
href={`/${screenName}/status/${id}`}
|
||||
style={styles.timestamp}
|
||||
/>
|
||||
<UserNames fullName={fullName} screenName={screenName} />
|
||||
</View>
|
||||
|
||||
<View accessibilityRole="heading" aria-level="4">
|
||||
<TweetText displayMode={'links'} lang={lang} textParts={textParts} />
|
||||
</View>
|
||||
|
||||
{media ? (
|
||||
<View style={styles.richContent}>
|
||||
<AspectRatio ratio={16 / 9}>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.cover}
|
||||
source={media.source}
|
||||
style={styles.media}
|
||||
/>
|
||||
</AspectRatio>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<TweetActionsBar
|
||||
actions={[
|
||||
{ name: 'reply', label: 'Reply' },
|
||||
{
|
||||
name: 'retweet',
|
||||
label: 'Retweet',
|
||||
count: tweet.retweet_count,
|
||||
highlighted: tweet.retweeted
|
||||
},
|
||||
{
|
||||
name: 'like',
|
||||
label: 'Like',
|
||||
count: tweet.favorite_count,
|
||||
highlighted: tweet.favorited
|
||||
},
|
||||
{ name: 'directMessage', label: 'Direct Message' }
|
||||
]}
|
||||
style={styles.actionBar}
|
||||
/>
|
||||
</View>
|
||||
</GridView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
paddingVertical: theme.createLength(theme.spaceY * 0.75, 'rem'),
|
||||
paddingHorizontal: theme.createLength(theme.spaceX, 'rem')
|
||||
},
|
||||
avatarColumn: {
|
||||
flexGrow: 1,
|
||||
minWidth: 32
|
||||
},
|
||||
bodyColumn: {
|
||||
flexGrow: 7
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
avatarLink: {
|
||||
display: 'block',
|
||||
flexShrink: 1,
|
||||
flexGrow: 0,
|
||||
width: '100%'
|
||||
},
|
||||
avatar: {
|
||||
width: '100%'
|
||||
},
|
||||
body: {
|
||||
marginTop: '-0.15rem'
|
||||
},
|
||||
timestamp: {
|
||||
color: theme.colors.deepGray,
|
||||
marginLeft: theme.createLength(theme.spaceX, 'rem'),
|
||||
order: 1,
|
||||
textDecorationLine: 'none',
|
||||
whiteSpace: 'nowrap'
|
||||
},
|
||||
actionBar: {
|
||||
marginTop: theme.createLength(theme.spaceY * 0.5, 'rem')
|
||||
},
|
||||
richContent: {
|
||||
borderRadius: '0.35rem',
|
||||
marginTop: theme.createLength(theme.spaceY * 0.5, 'rem'),
|
||||
overflow: 'hidden'
|
||||
},
|
||||
media: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
margin: 'auto',
|
||||
width: 'auto',
|
||||
height: 'auto'
|
||||
}
|
||||
});
|
||||
|
||||
export default Tweet;
|
||||
15
packages/benchmarks/src/implementations/react-native-web/Tweet/styles.js
vendored
Normal file
15
packages/benchmarks/src/implementations/react-native-web/Tweet/styles.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
icon: {
|
||||
display: 'inline-block',
|
||||
fill: 'currentcolor',
|
||||
height: '1.25em',
|
||||
maxWidth: '100%',
|
||||
position: 'relative',
|
||||
userSelect: 'none',
|
||||
textAlignVertical: 'text-bottom'
|
||||
}
|
||||
});
|
||||
|
||||
export default styles;
|
||||
40
packages/benchmarks/src/implementations/react-native-web/Tweet/theme.js
vendored
Normal file
40
packages/benchmarks/src/implementations/react-native-web/Tweet/theme.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
const colors = {
|
||||
blue: '#1B95E0',
|
||||
lightBlue: '#71C9F8',
|
||||
green: '#17BF63',
|
||||
orange: '#F45D22',
|
||||
purple: '#794BC4',
|
||||
red: '#E0245E',
|
||||
white: '#FFFFFF',
|
||||
yellow: '#FFAD1F',
|
||||
deepGray: '#657786',
|
||||
fadedGray: '#E6ECF0',
|
||||
faintGray: '#F5F8FA',
|
||||
gray: '#AAB8C2',
|
||||
lightGray: '#CCD6DD',
|
||||
textBlack: '#14171A'
|
||||
};
|
||||
|
||||
const fontSize = {
|
||||
root: '14px',
|
||||
// font scale
|
||||
small: '0.85rem',
|
||||
normal: '1rem',
|
||||
large: '1.25rem'
|
||||
};
|
||||
|
||||
const theme = {
|
||||
colors,
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||
fontSize,
|
||||
lineHeight: 1.3125,
|
||||
spaceX: 0.6,
|
||||
spaceY: 1.3125,
|
||||
createLength(num, unit) {
|
||||
return `${num}${unit}`;
|
||||
}
|
||||
};
|
||||
|
||||
export default theme;
|
||||
@@ -1,13 +1,11 @@
|
||||
import Box from './Box';
|
||||
import Dot from './Dot';
|
||||
import Provider from './Provider';
|
||||
import TextBox from './TextBox';
|
||||
import { View } from 'react-native';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
Dot,
|
||||
Provider,
|
||||
TextBox,
|
||||
View
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { Styles, View } from 'reactxp';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { Styles, View } from 'reactxp';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { object } from 'prop-types';
|
||||
import { View } from 'reactxp';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import styled from 'styled-components';
|
||||
import View from './View';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
|
||||
class View extends React.Component {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { withStyle } from 'styletron-react';
|
||||
import View from './View';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { styled } from 'styletron-react';
|
||||
|
||||
const Dot = styled('div', ({ size, x, y, children, color }) => ({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { Client as Styletron } from 'styletron-engine-atomic';
|
||||
import { Provider as StyletronProvider } from 'styletron-react';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import { styled } from 'styletron-react';
|
||||
|
||||
const View = styled('div', ({ style }) => ({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import App from './app/App';
|
||||
import impl from './impl';
|
||||
import TextTree from './cases/TextTree';
|
||||
import Tree from './cases/Tree';
|
||||
import SierpinskiTriangle from './cases/SierpinskiTriangle';
|
||||
|
||||
@@ -51,13 +50,6 @@ const tests = {
|
||||
},
|
||||
Provider: components.Provider,
|
||||
sampleCount: 100
|
||||
})),
|
||||
'Mount text tree': createTestBlock(components => ({
|
||||
benchmarkType: 'mount',
|
||||
Component: TextTree,
|
||||
getComponentProps: () => ({ breadth: 6, components, depth: 3, id: 0, wrap: 2 }),
|
||||
Provider: components.Provider,
|
||||
sampleCount: 50
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
@@ -23,11 +23,7 @@ module.exports = {
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[hash:base64:8]'
|
||||
}
|
||||
}
|
||||
options: { modules: true, localIdentName: '[hash:base64:8]' }
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -38,7 +34,7 @@ module.exports = {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: false,
|
||||
presets: [babelPreset],
|
||||
presets: babelPreset,
|
||||
plugins: ['styled-jsx/babel']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = async ({ config, mode }) => {
|
||||
config.module.rules.push({
|
||||
test: /\.(gif|jpe?g|png|svg)$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: { name: '[name].[ext]' }
|
||||
}
|
||||
});
|
||||
|
||||
config.resolve.extensions = ['.web.js', '.js', '.json', '.web.jsx', '.jsx'];
|
||||
|
||||
config.resolve.alias = {
|
||||
'react-native': 'react-native-web'
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
// import '@storybook/addon-options/register';
|
||||
@@ -1,48 +0,0 @@
|
||||
import { create } from '@storybook/theming';
|
||||
|
||||
// import centered from './decorator-centered';
|
||||
import { addParameters, configure, addDecorator } from '@storybook/react';
|
||||
|
||||
// Option defaults:
|
||||
addParameters({
|
||||
options: {
|
||||
storySort: (a, b) => {
|
||||
const sectionA = a[1].id.split('-')[0];
|
||||
const sectionB = b[1].id.split('-')[0];
|
||||
|
||||
return sectionB.localeCompare(sectionA);
|
||||
},
|
||||
theme: create({
|
||||
base: 'light',
|
||||
brandTitle: 'React Native for Web',
|
||||
brandUrl: 'https://necolas.github.io/react-native-web'
|
||||
// To control appearance:
|
||||
// brandImage: 'http://url.of/some.svg',
|
||||
}),
|
||||
/**
|
||||
* regex for finding the hierarchy separator
|
||||
* @example:
|
||||
* null - turn off hierarchy
|
||||
* /\// - split by `/`
|
||||
* /\./ - split by `.`
|
||||
* /\/|\./ - split by `/` or `.`
|
||||
* @type {Regex}
|
||||
*/
|
||||
hierarchySeparator: /\/|\./,
|
||||
/**
|
||||
* regex for finding the hierarchy root separator
|
||||
* @example:
|
||||
* null - turn off multiple hierarchy roots
|
||||
* /\|/ - split by `|`
|
||||
* @type {Regex}
|
||||
*/
|
||||
hierarchyRootSeparator: /\|/,
|
||||
panelPosition: 'bottom'
|
||||
}
|
||||
});
|
||||
|
||||
// addDecorator(centered);
|
||||
|
||||
const context = require.context('../src', true, /\.stories\.(js|mdx)$/);
|
||||
|
||||
configure(context, module);
|
||||
@@ -1,10 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: '@storybook/addon-docs/preset',
|
||||
options: {
|
||||
configureJSX: true,
|
||||
babelOptions: {},
|
||||
sourceLoaderOptions: null
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
plugins: ['react-native-web']
|
||||
};
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "docs",
|
||||
"version": "0.14.7",
|
||||
"scripts": {
|
||||
"build": "build-storybook --docs -o ./dist -c ./.storybook",
|
||||
"start": "start-storybook --docs -p 9001 -c ./.storybook",
|
||||
"release": "yarn build && git checkout gh-pages && rm -rf ../../docs && mv dist ../../docs && git add -A && git commit -m \"Deploy documentation\" && git push origin gh-pages && git checkout -"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addon-docs": "^5.3.9",
|
||||
"@storybook/addon-options": "^5.3.9",
|
||||
"@storybook/cli": "^5.3.9",
|
||||
"@storybook/react": "^5.3.9",
|
||||
"@storybook/theming": "^5.3.9",
|
||||
"react-native-web": "0.14.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-react-native-web": "0.14.7",
|
||||
"url-loader": "^3.0.0",
|
||||
"webpack": "^4.41.5"
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import { Meta, Props } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="APIs|AppRegistry" />
|
||||
|
||||
# AppRegistry
|
||||
|
||||
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`.
|
||||
|
||||
## Methods
|
||||
|
||||
### getAppKeys()
|
||||
|
||||
Returns an array of all registered app keys
|
||||
|
||||
```js
|
||||
const appKeys = AppRegistry.getAppKeys();
|
||||
```
|
||||
|
||||
### getApplication(appKey, appParams)
|
||||
|
||||
A web-only method for server-side rendering to HTML and CSS. It returns an
|
||||
object containing the given application's element and a function to get styles
|
||||
once the element is rendered.
|
||||
|
||||
Additional props can be passed to the `getStyleElement` function, e.g., your CSP
|
||||
policy may require a `nonce` to be set on style elements.
|
||||
|
||||
```js
|
||||
const appKey = 'MyApp';
|
||||
const appParams = { ... };
|
||||
const { element, getStyleElement } = AppRegistry.getApplication(appKey, appParams);
|
||||
```
|
||||
|
||||
### registerComponent(appKey, getComponent)
|
||||
|
||||
Register a component provider under the given appKey.
|
||||
|
||||
```js
|
||||
const appKey = 'MyApp';
|
||||
const getComponent = () => App;
|
||||
AppRegistry.registerComponent(appKey, getComponent)
|
||||
```
|
||||
|
||||
### registerConfig(config)
|
||||
|
||||
Register multiple applications. AppConfig type is:
|
||||
|
||||
```js
|
||||
type AppConfig = {
|
||||
appKey: string;
|
||||
component: ComponentProvider;
|
||||
run?: function
|
||||
}
|
||||
|
||||
const config = [{
|
||||
appKey: 'FirstApp',
|
||||
component: () => FirstApp
|
||||
}, {
|
||||
appKey: 'SecondApp',
|
||||
component: () => SecondApp
|
||||
}];
|
||||
AppRegistry.registerConfig(config)
|
||||
```
|
||||
|
||||
### registerRunnable(appKey, run)
|
||||
|
||||
Register a custom render function for an application. The function will receive
|
||||
the `appParameters` passed to `runApplication`.
|
||||
|
||||
```js
|
||||
AppRegistry.registerRunnable('MyApp', (appParams) => { ... });
|
||||
```
|
||||
|
||||
### runApplication(appKey, appParams)
|
||||
|
||||
Runs the application that was registered under `appKey`. The `appParameters`
|
||||
must include the `rootTag` into which the application is rendered, and
|
||||
optionally any `initialProps` or render callback. If the client should hydrate
|
||||
server-rendered HTML, set `hydrate` to `true`.
|
||||
|
||||
```js
|
||||
AppRegistry.runApplication('MyApp', {
|
||||
callback: () => { console.log('React rendering has finished') },
|
||||
hydrate: true,
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-root'),
|
||||
})
|
||||
```
|
||||
|
||||
### setComponentProviderInstrumentationHook(componentProvider)
|
||||
|
||||
```js
|
||||
type setComponentProviderInstrumentationHook = (componentProvider: func) => Component;
|
||||
```
|
||||
|
||||
### setWrapperComponentProvider(appParams)
|
||||
|
||||
```js
|
||||
type setWrapperComponentProvider = (appParameters: object) => Component;
|
||||
```
|
||||
|
||||
### unmountApplicationComponentAtRootTag(rootTag)
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the `rootTag` that was passed
|
||||
into `runApplication`.
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
title: 'APIs|AppState',
|
||||
includeStories: []
|
||||
};
|
||||
|
||||
export { default as stateChanges } from './examples/StateChanges';
|
||||
@@ -1,46 +0,0 @@
|
||||
import { Meta, Props, Preview, Story } from '@storybook/addon-docs/blocks';
|
||||
import * as Stories from './AppState.stories.js';
|
||||
|
||||
<Meta title="APIs|AppState" />
|
||||
|
||||
# AppState
|
||||
|
||||
AppState can tell you if the app is in the foreground or background, and notify
|
||||
you when the state changes. States: `active` (the app is running in the
|
||||
foreground), `background` (the app is running in the background, i.e., the user
|
||||
has not focused the app's tab).
|
||||
|
||||
## Properties
|
||||
|
||||
### isAvailable
|
||||
|
||||
Determines whether the browser environment supports `AppState`.
|
||||
|
||||
### currentState
|
||||
|
||||
Returns the current state of the app: "active" or "background".
|
||||
|
||||
## Methods
|
||||
|
||||
### addEventListener(type, handler)
|
||||
|
||||
Add a handler to AppState changes by listening to the `change` event type and
|
||||
providing the handler. The handler is called with the app state value.
|
||||
|
||||
```js
|
||||
AppState.addEventListener('change', (currentState) => {});
|
||||
```
|
||||
|
||||
### removeEventListener(type, handler)
|
||||
|
||||
Remove a handler by passing the `change` event type and the handler.
|
||||
|
||||
AppState.removeEventListener('change', handler);
|
||||
|
||||
## Example
|
||||
|
||||
<Preview withSource='none'>
|
||||
<Story name="stateChanges">
|
||||
<Stories.stateChanges />
|
||||
</Story>
|
||||
</Preview>
|
||||
@@ -1,32 +0,0 @@
|
||||
import React from 'react';
|
||||
import { AppState, Text, View } from 'react-native';
|
||||
|
||||
export default function StateChanges() {
|
||||
const [state, updateState] = React.useState({
|
||||
active: 0,
|
||||
background: 0,
|
||||
currentState: AppState.currentState
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleChange = nextState => {
|
||||
updateState(previousState => ({
|
||||
...previousState,
|
||||
[nextState]: previousState[nextState] + 1
|
||||
}));
|
||||
};
|
||||
|
||||
AppState.addEventListener('change', handleChange);
|
||||
return () => {
|
||||
AppState.removeEventListener('change', handleChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text>Active count: {state.active}</Text>
|
||||
<Text>Background count: {state.background}</Text>
|
||||
<Text>Current state is: {state.currentState}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import { Meta, Preview } from '@storybook/addon-docs/blocks';
|
||||
import * as Stories from './examples';
|
||||
|
||||
<Meta title="APIs|Appearance" />
|
||||
|
||||
# Appearance
|
||||
|
||||
The Appearance module exposes information about the user's appearance
|
||||
preferences, such as their preferred color scheme (light or dark). In
|
||||
`react-native-web` this is achieved using the `prefers-color-scheme` media query.
|
||||
|
||||
## Methods
|
||||
|
||||
### getColorScheme()
|
||||
|
||||
You can use the Appearance module to determine if the user prefers a dark color
|
||||
scheme:
|
||||
|
||||
```js
|
||||
const colorScheme = Appearance.getColorScheme();
|
||||
if (colorScheme === 'dark') {
|
||||
// Use dark color scheme
|
||||
}
|
||||
```
|
||||
|
||||
Although the color scheme is available immediately, this may change (e.g.
|
||||
scheduled color scheme change at sunrise or sunset). Any rendering logic or
|
||||
styles that depend on the user preferred color scheme should try to call this
|
||||
function on every render, rather than caching the value.
|
||||
|
||||
## Hooks
|
||||
|
||||
### useColorScheme
|
||||
|
||||
The `useColorScheme` React hook provides and subscribes to color scheme updates
|
||||
from the Appearance module. The return value indicates the current user
|
||||
preferred color scheme. The value may be updated later, either through direct
|
||||
user action (e.g. theme selection in device settings) or on a schedule (e.g.
|
||||
light and dark themes that follow the day/night cycle).
|
||||
|
||||
Supported color schemes:
|
||||
|
||||
- `'light'`: The user prefers a light color theme.
|
||||
- `'dark'`: The user prefers a dark color theme.
|
||||
- `null`: The user has not indicated a preferred color theme.
|
||||
|
||||
```js
|
||||
import * as React from 'react';
|
||||
import { Text, useColorScheme } from 'react-native';
|
||||
|
||||
const MyComponent = () => {
|
||||
const colorScheme = useColorScheme();
|
||||
return <Text>Your color scheme is: {colorScheme}</Text>;
|
||||
};
|
||||
```
|
||||
|
||||
This produces:
|
||||
|
||||
<Preview withSource="none">
|
||||
<Story name="colorScheme">
|
||||
<Stories.colorSchemeText />
|
||||
</Story>
|
||||
</Preview>
|
||||
@@ -1,7 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Text, useColorScheme } from 'react-native';
|
||||
|
||||
export default function ColorSchemeText() {
|
||||
const colorScheme = useColorScheme();
|
||||
return <Text>Your color scheme is: {colorScheme}</Text>;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default as colorSchemeText } from './ColorSchemeText';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user