Compare commits

..

159 Commits
0.3.0 ... 0.7.2

Author SHA1 Message Date
Nicolas Gallagher
eb0e0b8771 0.7.2 2018-05-19 08:46:55 -07:00
Nicolas Gallagher
15d5e57e92 [fix] convert VirtualizedList vendor code to ES modules
Webpack has trouble bundling a mix of CommonJS and ES modules in the
same package.

Fix #957
2018-05-19 08:45:21 -07:00
Nicolas Gallagher
def873e9e3 0.7.1 2018-05-18 18:16:51 -07:00
Nicolas Gallagher
9e9b40f155 [fix] ResponderEventPlugin injection for tree-shaking bundler
Previously this depended on a side-effecting `import` statement which
would be removed under tree-shaking.
2018-05-18 18:13:30 -07:00
Nicolas Gallagher
4a45595b7a 0.7.0 2018-05-18 17:29:47 -07:00
Nicolas Gallagher
45095fd300 Documentation updates 2018-05-18 17:27:39 -07:00
Nicolas Gallagher
004c7ce478 [change] export ES modules by default
ES modules are the default package export. Commonjs modules are exported
from 'dist/cjs'. Modern bundlers like webpack can consume ES modules.
The addition of the `sideEffects:false` to the `package.json` helps
webpack tree-shaking modules.
2018-05-18 17:27:36 -07:00
Nicolas Gallagher
96c3f09fac [fix] Firefox UI for numeric TextInput
Fix #900
2018-05-18 13:40:15 -07:00
Nicolas Gallagher
edc99e79eb [change] ResponderEventPlugin filters browser emulated mouse events
Browsers dispatch mouse events after touch events:
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent

There have been several attempts to avoid this behaviour affecting the
ResponderEvent system. The previous approach of cancelling the event in
the `onResponderRelease` event handler can end up cancelling other
events that are expected, e.g., `focus`.

Instead, this patch changes the `ResponderEventPlugin.extractEvents`
function to filter the mouse events that occur a short time after a
touch event. (It's assumed that people will not be clicking a mouse
within a few hundred ms of performing a touch.) This allows the
ResponderEvent system to function as expected and leaves other callbacks
to fire as they would be expected to in React DOM, i.e., both
`onTouchStart` and `onMouseDown` will be called following a touch start.

Fix #835
Fix #888
Fix #932
Close #938
Ref #802
2018-05-18 13:39:25 -07:00
Nicolas Gallagher
e8f2c98786 [add] mark focusable DOM nodes with 'data-focusable'
Focus-based UIs can use out-of-tree focus algorithms to manage focus
using remote control devices. This patch marks DOM nodes that React
Native considers "focusable".

Close #827
2018-05-18 11:56:56 -07:00
Nicolas Gallagher
dcdf1468f9 [fix] onLayout timing without ResizeObserver
onLayout is called after the component is mounted to the DOM. This makes
both the fallback and ResizeObserver code path behave the same as React
Native.

Fix #911
Fix #941
Close #939
2018-05-18 11:44:30 -07:00
Nicolas Gallagher
ee5e80064f [add] support for CSP policy requiring 'nonce' on <style>
CSP policy may prevent writing to `<style>` unless a `nonce` attribute
is set. This change makes that possible by moving the modality-related
styles into the main style sheet, and allowing additional props to be
provided to the `<style>` element when rendering on the server. For
example:

```
const { element, getStyleElement } = AppRegistry.getApplication('App');
const html = renderToString(element);
const css = renderToStaticMarkup(getStyleElement({ nonce }));
```
2018-05-18 11:44:24 -07:00
Philipp Spiess
3e4d8d6b2f Upgrade React and all transitive dependencies
Close #942
2018-05-16 15:01:19 -07:00
Nicolas Gallagher
d3a8270d55 Add a development sandbox to storybook 2018-05-09 10:38:34 -07:00
Nicolas Gallagher
18933724d6 Remove @providesModule from all modules
Ref: d5e9e55fa3
2018-05-08 10:28:25 -07:00
Nicolas Gallagher
e7f84a9228 Add GitHub issue templates
Close #931
2018-05-08 10:11:27 -07:00
Scott Kyle
8b1e6f816f [change] remove NetInfo.isConnected.getConnectionInfo()
React Native doesn't have `NetInfo.isConnected.getConnectionInfo()`.
This was incorrectly added to the API while updating the main `NetInfo`
API.

Close #937
2018-05-08 10:01:41 -07:00
Scott Kyle
02b6f3ff3c [fix] findNodeHandle import in VirtualizedList
Close #936
2018-05-08 09:53:50 -07:00
odalay
6f52007cc8 Fix CheckboxScreen link on website
Close #926
2018-05-08 09:53:16 -07:00
Nicolas Gallagher
1e59e53e66 Update jest 2018-05-08 09:49:02 -07:00
Nicolas Gallagher
f6a65210ca Update formatter and linter 2018-05-08 09:24:08 -07:00
Nicolas Gallagher
2e9071eb0e Update benchmarks dependencies 2018-05-08 09:15:51 -07:00
Nicolas Gallagher
8f25fcc05b Update storybook dependencies 2018-05-07 15:00:22 -07:00
Nicolas Gallagher
1e8577fc9e [fix] setting flex styles as inline styles
Reverts #648 as browsers are inconsistent in how they handle
'flex-basis', so this hack isn't effective. And React has no support for
using '!important' in inline styles.

Fix #798
2018-04-30 11:51:18 -07:00
Nicolas Gallagher
c51f567d19 Simplify tests for several exported modules 2018-04-24 15:54:40 -07:00
Nicolas Gallagher
bce5957991 0.6.1 2018-04-21 12:16:05 -07:00
Nicolas Gallagher
34d8409d43 Update yarn.lock 2018-04-21 12:15:18 -07:00
Sébastien Lorber
8442f13e96 Add Gatsby integration to README
Close #868
2018-04-21 12:12:50 -07:00
Nicolas Gallagher
c6e2b584af [fix] AppRegistry.getApplication shouldn't throw if missing options
Fix #899
2018-04-21 12:05:42 -07:00
Philipp Spiess
38affa9bae Fix Game2048 on desktop browsers
The React Native example only listens for touch events but on web we can
listen to mouse events to improve support.

Close #909
2018-04-21 11:56:14 -07:00
Nicolas Gallagher
f9ebdb6327 Documentation layout fixes 2018-04-21 11:50:39 -07:00
Nicolas Gallagher
83a8758f68 0.6.0 2018-04-15 15:56:10 -07:00
MoOx
e022d166dd Update Phenomic integration link to official example 2018-04-15 15:26:24 -07:00
Nicolas Gallagher
1a225bc449 [fix] Text onPress event propagation
The press event should not propagate.

Fix #897
2018-04-15 15:23:32 -07:00
Nicolas Gallagher
cf2612663b [fix] createElement uses provided function component
If the component provided to 'createElement' is not a string alias for a
DOM component, it will no longer attempt to replace that component with
a DOM component inferred from the 'accessibility{Component,Role,Traits}'
prop.

Fix #895
2018-04-15 15:03:34 -07:00
Nicolas Gallagher
1aec803086 [fix] Picker.Item support for 'color' prop
Not well supported by browsers.

Fix #810
2018-04-08 11:43:20 -07:00
Nicolas Gallagher
2050730b77 [fix] consistency of nativeEvent.location{X,Y} between touch and mouse
Calculate `location{X,Y}` in the same way for both touch and mouse
events. Also defer the call to `getBoundingClientRect` to avoid
unnecessary DOM queries when the data is not used.
2018-04-08 11:05:12 -07:00
Nicolas Gallagher
a67bf0f490 [change] synchronous layout measurement 2018-04-08 10:38:31 -07:00
Nicolas Gallagher
4529a4ac0a Update benchmarks dependencies 2018-04-07 17:20:01 -07:00
Giuseppe Gurgone
5a04d07a35 [change] call 'onLayout' when elements are resized
Uses ResizeObserver to monitor layout changes. Falls back to
window.onresize (with initial firing).

Fix #60
Close #848
2018-04-07 17:03:17 -07:00
Nicolas Gallagher
9427eea293 [add] VirtualizedList support
Make changes needed to run VirtualizedList using React Native for Web.

Close #659
2018-04-07 10:25:15 -07:00
Nicolas Gallagher
b9803e1e07 Add snapshot of VirtualizedList from React Native
Exact source code of the module and its dependencies, for the given SHA.
2018-04-07 10:25:15 -07:00
slorber
7a3a9a5c3f [add] AppRegistry support for React render callback
Close #858

Co-authored-by: Nicolas Gallagher <nicolasgallagher@gmail.com>
2018-04-07 10:15:17 -07:00
Nicolas Gallagher
4c59343fd3 [fix] SafeAreaView inset padding for Safari
See https://webkit.org/blog/7929/designing-websites-for-iphone-x/

Fix #859
2018-04-02 14:32:15 -07:00
Nicolas Gallagher
ce89b7e3ec [change] move 'react-art' to peerDependencies 2018-04-02 14:31:26 -07:00
Nicolas Gallagher
23fa663a6e [fix] Text font styling
Don't use 'font' shorthand internally to reset font styles, as the
framework's internal styles may be injected after application styles,
causing 'font' to override 'font-*' properties.

Fix #881
2018-04-02 11:37:59 -07:00
Nicolas Gallagher
b96dd668d3 [add] AppRegistry provider methods
Adds support for the following methods in React Native:
- setComponentProviderInstrumentationHook
- setWrapperComponentProvider
2018-04-01 10:29:27 -07:00
Nicolas Gallagher
a9cacb2ef5 [change] AppRegistry container is not absolutely positioned
Aligned with latest layout of AppContainer in React Native.

Fix #871
2018-04-01 09:47:02 -07:00
Nicolas Gallagher
c122814591 0.5.4 2018-04-01 09:34:51 -07:00
Bruno Lemos
efe18f1b7e [fix] Linking.openURL on Firefox
Fix #883
Close #884
2018-04-01 09:25:16 -07:00
Nicolas Gallagher
e1b576e427 [add] StyleSheet support for 'System' in font stack
Allow 'System' to be used in a font-family stack, e.g., "Noto, System".

Update the 'System' font stack to include "system-ui", which is the
latest keyword for system fonts.
2018-03-31 14:57:29 -07:00
Nicolas Gallagher
5d77d6e30f [fix] TextInput focus management
Defer to the browser's native handling of 'blur' and 'focus'; directly
update the internal state of TextInputState. Fixes an issue with
preserving focus when the tab is backgrounded.

Also ensure the TextInputState is correctly set when a component mounts.
When 'autoFocus' is true, 'onFocus' can be called before the internal
ref is set.

Fix #880
2018-03-31 14:01:19 -07:00
Jesús Darío
8fb9a88ee6 Add webpack-cli to getting started guide 2018-03-29 15:49:43 -07:00
Kyle Goggin
a7cda988ef [fix] ignore 'tvParallaxProperties' prop
Close #867
2018-03-29 15:47:39 -07:00
Nicolas Gallagher
b239cfb04d [fix] update InteractionManager stub
Fix #875
2018-03-29 15:32:38 -07:00
Nicolas Gallagher
8e94d858b2 [fix] Picker prop types
Fix #879
2018-03-29 15:11:16 -07:00
Nicolas Gallagher
aa22b06359 0.5.3 2018-03-15 13:32:24 -07:00
Paul Armstrong
2aa565c7c3 [fix] Picker default fontFamily
Close #860
2018-03-15 13:08:23 -07:00
Sakamoto, Kazunori
7b9b57960d Update getting-started.md
Fix __DEV__ value in example web/webpack.config.js

Close #862
2018-03-15 13:06:58 -07:00
Nicolas Gallagher
eae3ee9dca 0.5.2 2018-03-07 19:56:46 -08:00
Nicolas Gallagher
74e1a196b6 [fix] Linking.openURL works with nonce use
`Linking` no longer uses an iframe hack to add 'noopener' support to
older Safari. Instead it relies on browsers having support for
'noopener'.

Fix #837
Close #846
2018-03-05 11:50:08 -08:00
Nicolas Gallagher
48da9814e7 Update benchmark libraries 2018-03-05 10:40:02 -08:00
Nicolas Gallagher
4d391ef57c Link to example integrations in README 2018-03-05 10:22:26 -08:00
Nicolas Gallagher
780df69a80 Update link to Glitch starter 2018-03-01 19:37:12 -08:00
Nicolas Gallagher
6c229da01f Minor improvement to AppRegistry console.log message 2018-02-26 15:20:35 -08:00
Nicolas Gallagher
ae7aa818fb 0.5.1 2018-02-20 17:48:12 -08:00
Nicolas Gallagher
306cf67932 [add] Image style support for animations, interactions, and filters 2018-02-20 17:45:19 -08:00
Nicolas Gallagher
619c2048be [add] support for 'transformStyle' style prop 2018-02-20 17:44:22 -08:00
Nicolas Gallagher
b9f9a4f8d7 Move some View style propTypes to InteractionPropTypes 2018-02-20 17:43:22 -08:00
Nicolas Gallagher
58bc18c2f5 Group 'transition' style propTypes with animations 2018-02-20 17:42:19 -08:00
Nicolas Gallagher
073940fc4e Group 'perspective' style propType with transforms 2018-02-20 17:40:57 -08:00
Nicolas Gallagher
5c462303de Inline some values in TextStylePropTypes 2018-02-20 17:32:45 -08:00
Nicolas Gallagher
5fb92da317 [fix] Switch layout when left/right do not flip
The I18nManager can now disable the automatic BiDi flipping of
left/right, which caused the Switch layout to break in RTL mode. Change
the styles to use start/end.
2018-02-20 16:44:46 -08:00
Nicolas Gallagher
cafe10d851 Improve View 'pointerEvents' example 2018-02-19 18:48:31 -08:00
Nicolas Gallagher
b28581f44e [fix] Touchable 'touchAction' value 2018-02-19 18:27:49 -08:00
Nicolas Gallagher
9333e7e887 0.5.0 2018-02-19 15:48:05 -08:00
Nicolas Gallagher
b28cbbb37e [fix] TextInput default font styles
Match React Native (and web) expected defaults.
2018-02-19 15:29:05 -08:00
Nicolas Gallagher
a53372ceb3 [fix] babel-plugin only rewrites paths for known modules
Don't rewrite import paths for non-existent modules or types. They will
attempt to be imported from the package's main export. This change
currently requires a module map to be generated for the babel-plugin to
use. The map is automatically regenerated for any commit that alters the
entry file of react-native-web.

Fix #822
2018-02-19 13:05:42 -08:00
Nicolas Gallagher
239a43978f Update yarn.lock 2018-02-18 17:43:22 -08:00
Nicolas Gallagher
b4e4bfbb3c Fix the event handlers with event normalization
Events are now normalized within the responder system, so those handlers
don't need to be listed anymore. Recently added events (blur,
contextmenu, focus) are now also normalized.
2018-02-18 17:42:02 -08:00
Nicolas Gallagher
893963a799 [fix] PanResponder grant firing twice on touch devices
Touch events can produce trailing mouse events, which cause unwanted
events to fire in the responder event system.  This issue is avoided in
`Touchable` by cancelling the event in the responder release callback.
To fix the issue in other areas, like the PaneResponder, this hack is
moved into `createElement` and applied to event `onResponderRelease`
callback.

Fix #802
2018-02-18 17:41:48 -08:00
Nicolas Gallagher
e5adc5a37c Add 'coveragePathIgnorePatterns' to jest config 2018-02-17 18:03:36 -08:00
Nicolas Gallagher
6d908189a7 [fix] Text support for 'fontVariant' style
Fix #824
Close #825
2018-02-17 18:03:31 -08:00
Nicolas Gallagher
31db333ba3 [fix] Image support for SVG base64 data
The previous fix to support inline SVG data in utf-8 format broke images
that were rendering base64 SVGs.
2018-02-17 15:55:45 -08:00
Nicolas Gallagher
9fe089ca21 [add] development warning about using '!important' in styles
React Native for Web may use '!important' as part of the internal
resolving of styles. But user styles should never be allowed to include
'!important' in the value. Print a warning to the console when they do.
2018-02-17 14:46:31 -08:00
Nicolas Gallagher
a314d5b2e4 [change] MIT license
Now possible to license under MIT following the change to React Native's
license.

26684cf3ad

Fix #828
2018-02-17 12:23:45 -08:00
Nicolas Gallagher
fb845ebf44 Update benchmarks dependencies 2018-02-16 19:08:19 -08:00
Nicolas Gallagher
0d0c7e6e27 Document 'onBlur', 'onFocus', and 'onContextMenu' props 2018-02-16 18:53:33 -08:00
Nicolas Gallagher
f37003a079 Add end/start to BorderPropTypes 2018-02-15 19:08:34 -08:00
Nicolas Gallagher
f1fc2a9e37 Rewrite I18nManager and i18nStyle unit tests 2018-02-15 18:46:08 -08:00
Nicolas Gallagher
92794cdc9f [add] I18nManager and StyleSheet support for RTL without left/right flip
I18nManager supports `doLeftAndRightSwapInRTL` and
`swapLeftAndRightInRTL` to query and control the BiDi-flipping of
left/right properties and values. For example, you may choose to use
`end`/`start` for positioning that flips with writing direction, and
then disable `left`/`right` swapping in RTL so that `left` will always
be `left`.

The StyleSheet resolver cache must also account for the third "direction"
variant: RTL with no swapping of left/right.
2018-02-15 18:45:45 -08:00
Nicolas Gallagher
b754776373 [add] StyleSheet support for start/end properties and values
Add support for new style properties and values that automatically
account for the writing direction (as introduced in React Native
0.51.0). The start/end variants are automatically resolved to match the
global writing direction, as defined by I18nManager.isRTL. Start/End
take precedence over Left/Right.

Adds support for the following properties:

* `borderTop{End,Start}Radius`
* `borderBottom{End,Start}Radius`
* `border{End,Start}Color`
* `border{End,Start}Style`
* `border{End,Start}Width`
* `end`
* `margin{End,Start}`
* `padding{End,Start}`
* `start`

And values:

* `clear: "end" | "start"`
* `float: "end" | "start"`
* `textAlign: "end" | "start"`
2018-02-15 18:43:09 -08:00
Nicolas Gallagher
155b34e495 Fix unit test timeouts on Travis CI
Jest recommends using 'runInBand' for Travis CI. It runs all tests
serially in the current process, rather than creating a worker pool of
child processes that run tests.
2018-02-14 14:26:03 -08:00
Nicolas Gallagher
00c9dc4236 [fix] setNativeProps can apply flex styles
Updates the 'setValueForStyle' implementation to support style values
that contain "!important". This allows the 'flex{Basis,Grow,Shrink}'
values created by the style resolver to be applied. They currently use
the important priority as a work-around for browser-inconsistencies in
the 'flex' shorthand.

Upstream fix: https://github.com/facebook/react/pull/12181

Ref #798
Close #813
2018-02-14 13:51:00 -08:00
Nicolas Gallagher
b66aba1a06 website: fix ImageBackground source code link
Close #820
2018-02-14 13:39:14 -08:00
Nicolas Gallagher
17f8a674b8 [fix] ResponderEventPlugin skips 'mouseup' when no touch is active
Prevent the responder system recording 'mouseup' events if there is no
active 'touch'.

Fix #816
2018-02-13 15:02:09 -08:00
Nicolas Gallagher
b8080ba775 [fix] Touchable press events regression in 9ee89bc
Fix a regression introduced by "ResponderEvent event filtering"
9ee89bc7f7. Touchable press events were
firing twice after the event normalization was moved up into
'extractEvents'. The reason is:

1) events were previously not normalized throughout the responder system
2) once they were normalized, the fix introduced by a535c558d8 stopped working
3) because normalized nativeEvent did not include event data like 'cancelable'.

This patch adds more of the original nativeEvent fields to the
normalized event, so that React's synthetic event can return the correct
information for 'bubbles', 'cancelable', 'isDefaultPrevented()', etc.
2018-02-13 13:34:17 -08:00
Nicolas Gallagher
7265736545 [fix] StyleSheet accepts 'space-evenly' value for 'justifyContent' 2018-02-12 10:35:30 -08:00
Bulat Kidasov
399f465e59 [fix] NativeMethodsMixin measure/measureInWindow with scroll
Account for scroll offsets when calculating measurements.

Fix #702
Fix #805
Close #806
2018-02-12 10:27:47 -08:00
Nicolas Gallagher
9ee89bc7f7 [fix] ResponderEventPlugin event filtering
Exclude middle, wheel, and right click mouse events from the responder
system. This fixes the Touchables incorrectly triggering 'onPress' in
response to these events.

Filter mousemove events in the 'extractEvents' methods, and check for
active touches rather than the length of the touch bank. This fixes the
PanResponder not functioning after the first touch in Firefox.

Fix #719
Fix #729
Close #804
2018-02-12 10:08:44 -08:00
Jakub Rimal
748b2d0f3f [fix] Image 'source' prop update when missing in initial render
Close #811
2018-02-12 08:27:48 -08:00
Nicolas Gallagher
fb4635e013 Update README's 2018-02-08 16:09:56 -08:00
Nicolas Gallagher
73b459e770 [add] TextInput onKeyPress support for arrow keys
Close #791
Close #792
2018-02-08 10:57:32 -08:00
Nicolas Gallagher
a41af0f65f 0.4.0 2018-02-06 16:35:20 -08:00
Nicolas Gallagher
96eecc0da3 Replace lerna with custom script
Each package version is now updated with each release.

Fix #783
2018-02-06 16:30:03 -08:00
Nicolas Gallagher
69d5373222 [fix] Firefox rendering of TextInput
Removes UA controls from numeric inputs in Firefox, and makes the
default border solid in all browsers.

Fix #789
2018-02-06 11:17:38 -08:00
Nicolas Gallagher
538ab88eda Separate modules for StyleSheet and related side-effects 2018-02-05 12:18:43 -08:00
Nicolas Gallagher
21b3f39c0b [fix] babel-plugin require call for compiled modules
require('module') => require('module').default

Fix #786
2018-02-04 10:42:21 -08:00
Nicolas Gallagher
998e275e65 [add] CSS keyframes support via 'animationName' style
Keyframes can be defined using an array of objects as the value of
'animationName'. Each keyframe is transformed into a CSS keyframe rule.
2018-02-03 11:48:57 -08:00
Nicolas Gallagher
31d428a649 [fix] add support for TextInput placeholderTextColor prop
This change also ensures that potential object-styles (user-provided or
placeholderTextColor) are group together at the end of the style array.

Fix #560
2018-01-31 10:55:45 -08:00
Nicolas Gallagher
240cf7e05f [change] AppRegistry and StyleSheet APIs to fix SSR
SSR was not working correctly. Styles would accumulate in the style
cache and the styles returned for each 'getApplication' call would not
represent the styles needed to render a given tree, but rather all the
styles needed to render every tree that has been rendered by that server
instance.

This is now fixed by reinitializing the style resolver after a call to
'getStyleSheet' on the server. The return type of
'AppRegistry.getApplication' is changed – { element, getStyleElement }.
The 'getStyleElement' function must be called after the component tree
has been rendered.  Note that if 'getStyleElement' is not called for a
response, then its styles may leak into the next response's styles (but
will not affect the UX).

This patch also removes the 'StyleSheet.getStyleSheets' (web-only) API
and requires SSR to be done using 'AppRegistry.getApplication'.

Fix #778
2018-01-31 10:55:45 -08:00
Nicolas Gallagher
2ad710d83a [change] StyleSheet does not eagerly resolve and inject styles
Resolving styles at the same time as they are registered is problematic.
This work doesn't need to be complete until the moment a component is
rendered, rather than being done at startup.
2018-01-31 10:55:45 -08:00
Nicolas Gallagher
dcce72b66e Reorganize style resolver
The style resolver is reorganized to remove React Native style
registration, and contain all the stateful resolver logic (previously
partially found in NativeMethodsMixin).

Style registration is done in 'StyleSheet.create', and will subsequently
be decoupled from eager style resolution.

The stateful resolver is fully contained in the
ReactNativeStyleResolver. The options are removed from the resolver as
they aren't needed to implement the correct i18n-ified styles. This
functionality is also covered by unit tests now.
2018-01-31 10:55:44 -08:00
Nicolas Gallagher
083769d642 [fix] resolve inline-style pointerEvents to classNames
pointerEvents styles are now always resolved to classNames, even if
working with dynamic styles. In practice, inline-style pointerEvents
have always resolved to classNames as an accident of 'createElement'
registering each pointerEvent style. However, this patch ensures that
the style resolver produces correct output, and introduces the basic
mechanism by which 'placeholderTextColor' (for which classNames cannot
be precomputed) could function similarly.
2018-01-31 10:55:44 -08:00
Nicolas Gallagher
a53dba8c62 [change] simplify CSS rule injection
WebStyleSheet handles injecting CSS rules and returning the style
sheet's text content.

All CSS, including the reset, is now added using WebStyleSheet and the DOM API 'insertRule'.
Browsers will throw a parse error on unrecognized vendor-prefixes in
selectors, so rules with unsafe selectors are wrapped in '@media all {}'
before being passed to 'insertRule'. (This will be relevant when
attempting to support 'placeholderTextColor'. And it is a way to
batch-insert rules with a single call to 'insertRule'.)

The html tag 'font-family' CSS reset is removed as it's not needed.
2018-01-31 10:55:44 -08:00
Nicolas Gallagher
670d43ba04 Refactor how pointerEvents styles are managed 2018-01-31 10:55:44 -08:00
Nicolas Gallagher
73a731f2da Rename StyleManager and StyleRegistry 2018-01-31 10:55:44 -08:00
Nicolas Gallagher
1542f1f369 0.3.4 2018-01-31 10:31:50 -08:00
Nicolas Gallagher
6f58d7abe7 [fix] TextInput support for spellCheck prop
Fix #501
2018-01-31 10:27:08 -08:00
Nicolas Gallagher
7e0fbf9691 Fix yarn.lock
Yarn didn't make these changes to yarn.lock after updating packages.
2018-01-29 12:46:12 -08:00
Maximilian Stoiber
865034e8f7 Update benchmark instructions 2018-01-29 12:40:37 -08:00
Nicolas Gallagher
6e96ee4f3c Update benchmarked libraries 2018-01-29 08:59:18 -08:00
Maxime Thirouin
16d98b49f0 [fix] ignore native-only Image props
Close #788
2018-01-26 14:59:59 -08:00
Nicolas Gallagher
d04721c75a Update yarn.lock 2018-01-23 13:01:48 -08:00
Nicolas Gallagher
8512709251 Fix benchmark picker touch target size in Safari 2018-01-23 12:24:56 -08:00
Nicolas Gallagher
efeaea70a9 Benchmarks include forced layout time
This change to 'benchmarks' reports the time taken to perform a forced
layout after mounting the tree. Adding a forced layout to the stress
tests can surface how different approaches to styling may affect browser
render timings.

The total time displayed is now the sum of "scripting time" (previously
total time) and "layout time". The layout time is a reflection of the
time the browser takes to perform a style recalculation and relayout of
the document.

The Benchmark component now has a 'forceLayout' prop. When it is 'true'
a forced layout is triggered on componentDidUpdate. The time taken is
added to the sample's timing data.
2018-01-23 12:24:18 -08:00
Nicolas Gallagher
a403244e67 Update benchmarks library dependencies 2018-01-23 09:49:48 -08:00
Oleg Slobodskoi
985c1d63b6 Add benchmarks update test for react-jss
Close #785
2018-01-23 09:11:38 -08:00
Nicolas Gallagher
9d8d4057f6 Benchmark app component optimizations 2018-01-22 15:52:37 -08:00
Nicolas Gallagher
ec8843fe90 Compute benchmark props before each iteration
Fix a bug in the logic that was meant to perform component prop
computation in-between cycles.
2018-01-22 13:24:41 -08:00
Nicolas Gallagher
935970156c Benchmarks report total run time 2018-01-21 17:02:21 -08:00
Nicolas Gallagher
e4e6147081 0.3.3 2018-01-19 14:05:46 -08:00
Nicolas Gallagher
3e1b68d801 Add Moto G4 example benchmark results 2018-01-19 13:59:13 -08:00
Giuseppe Gurgone
1b493c9914 Add styled-jsx to benchmarks
Close #782
2018-01-19 12:51:21 -08:00
hushicai
6ecdc1a517 [fix] babel-plugin VariableDeclaration case
Convert VariableDeclarations, e.g.,

var ReactNative = require('react-native');

Close #781
2018-01-19 00:09:43 -08:00
Nicolas Gallagher
619079cedf Move babel-plugin npm badge to correct README 2018-01-18 10:24:02 -08:00
Javi Velasco
bbf7674b43 Add react-fela to benchmarks
Close #779
2018-01-18 10:03:13 -08:00
Nicolas Gallagher
f163e4f16f Use full URLs for README links 2018-01-18 09:50:14 -08:00
Nicolas Gallagher
bd8c2d6f24 Add npm badge to babel-plugin-react-native-web README 2018-01-18 09:49:54 -08:00
Nicolas Gallagher
3906b6b41b Add benchmarks app link to README 2018-01-17 19:38:58 -08:00
Nicolas Gallagher
753ef963f6 0.3.2 2018-01-17 19:18:50 -08:00
Nicolas Gallagher
0721245b3e Patch release script
Disable husky on version commit. Current publish script doesn't account
for attempts to republish the same version.
2018-01-17 19:15:23 -08:00
Nicolas Gallagher
b7adfd5f32 [fix] Picker.Item label text
Render the label as a child of 'option' rather than using the 'label'
attribute.

Fix #774
2018-01-17 17:59:05 -08:00
Nicolas Gallagher
a9342daee2 Add release script for benchmarks 2018-01-17 17:40:13 -08:00
Nicolas Gallagher
ed0cafac7c Rewrite benchmarks app
Reorganizes and rewrites the benchmarks. Each implementation is now
self-contained and the benchmarks can be run using a GUI. The benchmarks
themselves have been changed so that individual tests render over a
shorter time frame and more samples are taken.
2018-01-17 17:21:53 -08:00
Nicolas Gallagher
6e6fd4b5d0 Add note about Object.assign polyfill to docs 2018-01-16 17:14:17 -08:00
Nicolas Gallagher
5cd533e6cc 0.3.1 2018-01-16 11:15:45 -08:00
Nicolas Gallagher
d5e8d85ce9 Fix example in babel plugin README 2018-01-16 11:11:50 -08:00
Nicolas Gallagher
e234568a34 Fix source links in documentation 2018-01-11 12:59:44 -08:00
Nicolas Gallagher
19cf0711bc [add] StyleSheet support for 'overscrollBehavior'
An experimental CSS property to control the behavior when the scroll
position of a scroll container reaches the edge of the scrollport. This
allows web apps to get closer to native scrolling behaviour and
performance.

https://wicg.github.io/overscroll-behavior/
https://developers.google.com/web/updates/2017/11/overscroll-behavior

Fix #765
2018-01-11 12:58:43 -08:00
Johannes
067e3f346f [fix] KeyboardAvoidingView missing 'this' binding
Close #762
2018-01-11 12:53:54 -08:00
Nicolas Gallagher
2117e44e9d [fix] limit Image loader deferral to 1000ms
This patch introduces a limit on how long image loading is deferred, and
mitigates an issue with lengthy delays to 'requestIdleCallback' in the
Chrome browser.

Fix #759
2018-01-11 12:08:30 -08:00
Nicolas Gallagher
902ba22877 Update to flow-bin@0.63.1 2018-01-09 17:49:52 -08:00
Nicolas Gallagher
60c2cd65df Update to lint-staged@6.0.0 2018-01-09 17:36:19 -08:00
Nicolas Gallagher
fde29326f1 Update to lerna@2.6.0 2018-01-09 17:35:53 -08:00
Nicolas Gallagher
44d795437e Update to storybook@3.3.6 2018-01-09 17:34:28 -08:00
Nicolas Gallagher
03598d869b Update to babel-plugin-tester@5.0.0 2018-01-09 17:31:52 -08:00
Nicolas Gallagher
a3e44a5c60 Update to enzyme@3.3.0 2018-01-09 17:27:38 -08:00
Nicolas Gallagher
02b124eceb Update yarn.lock 2018-01-08 18:53:05 -08:00
345 changed files with 13136 additions and 6537 deletions

View File

@@ -1,9 +1,8 @@
[version]
^0.61.0
^0.63.0
[ignore]
<PROJECT_ROOT>/.*/__tests__/.*
<PROJECT_ROOT>/packages/benchmarks/.*
<PROJECT_ROOT>/packages/.*/dist/.*
<PROJECT_ROOT>/website/.*
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
@@ -14,4 +13,4 @@
<PROJECT_ROOT>/types
[options]
unsafe.enable_getters_and_setters=true

View File

@@ -74,7 +74,7 @@ yarn compile --watch
To run the interactive storybook:
```
yarn docs:start
yarn website
```
When you're also making changes to the 'react-native-web' source files, run this command in another process:
@@ -85,10 +85,18 @@ yarn compile --watch
## Benchmarks
To run the performance benchmarks in a browser (opening `./packages/benchmarks/index.html`):
To run the benchmarks locally:
```
yarn benchmark
yarn benchmarks
open ./packages/benchmarks/dist/index.html
```
To develop against these benchmarks:
```
yarn compile --watch
yarn benchmarks --watch
```
### New Features

View File

@@ -1,20 +0,0 @@
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce and
if a minimal demo of the problem via Glitch or similar (template:
https://glitch.com/edit/#!/react-native-web-playground).**
1.
2.
**What is the expected behavior?**
**Environment (include versions). Did this work in previous versions?**
* OS:
* Device:
* Browser:
* React Native for Web (version):
* React (version):

32
.github/ISSUE_TEMPLATE/bug.md vendored Normal file
View File

@@ -0,0 +1,32 @@
---
name: "\U0001F41B Bug report"
about: "If something isn't working as expected \U0001F914"
---
**The problem**
A clear and concise description of the bug or problem.
**How to reproduce**
Test case: <!-- FORK THIS TEMPLATE: https://codesandbox.io/s/6lx6ql1w5r -->
Steps to reproduce:
1.
2.
3.
<!-- If applicable, add screenshots to help explain your problem. -->
**Expected behavior**
A clear and concise description of what you expected to happen.
**Environment (include versions). Did this work in previous versions?**
* OS:
* Device:
* Browser:
* React Native for Web (version):
* React (version):
**Additional context**
Add any other context about the problem here.

17
.github/ISSUE_TEMPLATE/feature.md vendored Normal file
View File

@@ -0,0 +1,17 @@
---
name: "\U0001F680 Feature request"
about: If you have a suggestion
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is, e.g., I have an issue when [...]
**Describe a solution you'd like**
A clear and concise description of what you want to happen. Add any considered drawbacks.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1 +0,0 @@
**Before submitting a pull request,** please make sure you have followed the steps the CONTRIBUTING guide.

45
LICENSE
View File

@@ -1,31 +1,22 @@
BSD License
MIT License
For React Native software
Copyright (c) 2015-present, Nicolas Gallagher.
Copyright (c) 2015-present, Facebook, Inc.
Copyright (c) 2015-present, Nicolas Gallagher. All rights reserved.
Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -6,10 +6,11 @@
[React Native][react-native-url] to the Web.
* **High-quality user interfaces**: React Native for Web makes it easy to
create [fast](packages/benchmarks/README.md), adaptive web UIs in JavaScript.
It provides native-like interactions, support for multiple input modes (touch,
mouse, keyboard), optimized vendor-prefixed styles, built-in support for RTL
layout, built-in accessibility, and integrates with React Dev Tools.
create [fast](https://github.com/necolas/react-native-web/blob/master/packages/benchmarks/README.md),
adaptive web UIs in JavaScript. It provides native-like interactions, support
for multiple input modes (touch, mouse, keyboard), optimized vendor-prefixed
styles, built-in support for RTL layout, built-in accessibility, and integrates
with React Dev Tools.
* **Write once, render anywhere**: React Native for Web interoperates with
existing React DOM components and is compatible with the majority of the
@@ -18,20 +19,19 @@ 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? [Twitter](https://mobile.twitter.com),
[Major League Soccer](https://matchcenter.mlssoccer.com), [The
[Major League Soccer](https://matchcenter.mlssoccer.com),
[Flipkart](https://www.flipkart.com/), Playstation, Uber, [The
Times](https://github.com/newsuk/times-components), [React Native's
documentation](http://facebook.github.io/react-native/).
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
## Quick start
The easiest way to get started with React Native for Web is to use this
[ready-to-go project on Glitch](https://glitch.com/edit/#!/react-native-web-playground).
You dont need to install anything to try it out.
If you are unfamiliar with setting up a React web project, please follow the
recommendations in the [React documentation](https://reactjs.org/).
[CodeSandbox](https://codesandbox.io/s/q4qymyp2l6) template (or
[Glitch](https://glitch.com/edit/#!/react-native)). You dont need to install
anything to try it out.
## Documentation
@@ -43,28 +43,20 @@ design details, and for 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).
### Installation
Install using `yarn` or `npm`:
```
yarn add react react-dom react-native-web
yarn add --dev babel-plugin-react-native-web
```
### Guides
* [Getting started](website/guides/getting-started.md)
* [Style](website/guides/style.md)
* [Accessibility](website/guides/accessibility.md)
* [Internationalization](website/guides/internationalization.md)
* [Direct manipulation](website/guides/direct-manipulation.md)
* [Advanced use](website/guides/advanced.md)
* [Getting started](https://github.com/necolas/react-native-web/blob/master/website/guides/getting-started.md)
* [Style](https://github.com/necolas/react-native-web/blob/master/website/guides/style.md)
* [Accessibility](https://github.com/necolas/react-native-web/blob/master/website/guides/accessibility.md)
* [Internationalization](https://github.com/necolas/react-native-web/blob/master/website/guides/internationalization.md)
* [Direct manipulation](https://github.com/necolas/react-native-web/blob/master/website/guides/direct-manipulation.md)
* [Advanced use](https://github.com/necolas/react-native-web/blob/master/website/guides/advanced.md)
## Examples
There are several examples [on the website][website-url] and in the [website's
source code](./website). Here is an example to get you started:
source code](https://github.com/necolas/react-native-web/blob/master/website).
Here is an example to get you started:
```js
import React from 'react';
@@ -95,6 +87,17 @@ You'll notice that there is no reference to `react-dom`; the `App` component is
defined using the platform-agnostic APIs and Components introduced by React
Native. This allows the app to be rendered to web and native platforms.
## Integrations
Examples of using React Native for Web with other web tools:
* [Gatsby](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-react-native-web)
* [Next.js](https://github.com/zeit/next.js/tree/master/examples/with-react-native-web)
* [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/website/storybook/.storybook)
* [Styleguidist](https://github.com/styleguidist/react-styleguidist/tree/master/examples/react-native)
## Contributing
The main purpose of this repository is to help evolve React web and native
@@ -124,7 +127,9 @@ relatively limited scope. This is a great place to get started.
## License
React Native for Web is [BSD licensed](./LICENSE).
React Native for Web is [MIT licensed](./LICENSE). By contributing to React
Native for Web, you agree that your contributions will be licensed under its
MIT license.
[package-badge]: https://img.shields.io/npm/v/react-native-web.svg?style=flat
[package-url]: https://yarnpkg.com/en/package/react-native-web
@@ -132,6 +137,6 @@ React Native for Web is [BSD licensed](./LICENSE).
[ci-url]: https://travis-ci.org/necolas/react-native-web
[website-url]: https://necolas.github.io/react-native-web/storybook/
[react-native-url]: https://facebook.github.io/react-native/
[contributing-url]: ./.github/CONTRIBUTING.md
[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
[code-of-conduct]: https://code.facebook.com/codeofconduct

View File

@@ -1,10 +0,0 @@
{
"lerna": "2.5.1",
"version": "0.3.0",
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*",
"website"
]
}

View File

@@ -1,28 +1,31 @@
{
"private": true,
"version": "0.7.2",
"name": "react-native-web-monorepo",
"scripts": {
"benchmark": "cd packages/benchmarks && yarn benchmark",
"clean": "del ./packages/*/dist",
"compile": "yarn clean && cd packages/react-native-web && babel src --out-dir dist --ignore \"**/__tests__\"",
"docs:start": "cd website && yarn start",
"docs:release": "cd website && yarn release",
"compile:commonjs": "cd packages/react-native-web && MODULES=commonjs babel src --out-dir dist/cjs --ignore \"**/__tests__\"",
"benchmarks": "cd packages/benchmarks && yarn build",
"benchmarks:release": "cd packages/benchmarks && yarn release",
"website": "cd website && yarn start",
"website:release": "cd website && yarn release",
"flow": "flow",
"fmt": "find packages scripts types website -name '*.js' | grep -v -E '(node_modules|dist|vendor)' | xargs yarn fmt:cmd",
"fmt:cmd": "prettier --write",
"jest": "jest --config ./scripts/jest/config.js",
"jest": "MODULES=commonjs jest --config ./scripts/jest/config.js",
"lint": "yarn lint:check --fix",
"lint:check": "eslint packages scripts website",
"precommit": "lint-staged",
"prerelease": "yarn test && yarn compile",
"prerelease": "yarn test && yarn compile && yarn compile:commonjs",
"release": "node ./scripts/release/publish.js",
"postrelease": "yarn docs:release",
"test": "yarn flow && yarn lint:check && yarn jest"
"postrelease": "yarn website:release && yarn benchmarks:release",
"test": "yarn flow && yarn lint:check && yarn jest --runInBand"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.3",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.2",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
@@ -33,23 +36,24 @@
"babel-preset-react-native": "^4.0.0",
"caniuse-api": "^2.0.0",
"del-cli": "^1.1.0",
"enzyme": "^3.2.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.0",
"enzyme-to-json": "^3.2.2",
"eslint": "^4.12.1",
"enzyme-to-json": "^3.3.3",
"eslint": "^4.19.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-react": "^7.5.1",
"flow-bin": "^0.61.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",
"jest": "^21.2.1",
"lerna": "^2.5.1",
"lint-staged": "^4.1.3",
"prettier": "^1.8.2",
"raf": "^3.4.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-test-renderer": "^16.2.0"
"jest": "^22.4.3",
"jest-canvas-mock": "^1.0.2",
"lint-staged": "^7.1.0",
"prettier": "^1.12.1",
"react": "^16.3.2",
"react-art": "^16.3.2",
"react-dom": "^16.3.2",
"react-test-renderer": "^16.3.2"
},
"workspaces": [
"packages/*",
@@ -57,9 +61,12 @@
],
"lint-staged": {
"**/*.js": [
"fmt:cmd",
"prettier --write",
"git update-index --again",
"eslint"
],
"packages/react-native-web/src/index.js": [
"node ./scripts/babel/createModuleMap.js"
]
},
"prettier": {
@@ -67,5 +74,5 @@
"singleQuote": true
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause"
"license": "MIT"
}

View File

@@ -1,5 +1,7 @@
# babel-plugin-react-native-web
[![npm version][package-badge]][package-url] [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
A Babel plugin that will alias `react-native` to `react-native-web` and exclude
any modules not required by your app (keeping bundle size down).
@@ -34,6 +36,9 @@ import { StyleSheet, View } from 'react-native';
**After**
```js
import StyleSheet from 'react-native-web/dist/apis/StyleSheet';
import View from 'react-native-web/dist/components/View';
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
import View from 'react-native-web/dist/exports/View';
```
[package-badge]: https://img.shields.io/npm/v/babel-plugin-react-native-web.svg?style=flat
[package-url]: https://yarnpkg.com/en/package/babel-plugin-react-native-web

View File

@@ -1,10 +1,10 @@
{
"name": "babel-plugin-react-native-web",
"version": "0.3.0",
"version": "0.7.2",
"description": "Babel plugin for React Native for Web",
"main": "index.js",
"devDependencies": {
"babel-plugin-tester": "^4.0.0"
"babel-plugin-tester": "^5.0.0"
},
"author": "Nicolas Gallagher",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`export from "react-native" 1`] = `
exports[`Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = `
"
export { View } from 'react-native';
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';
@@ -15,7 +15,7 @@ export { default as createElement } from 'react-native-web/dist/exports/createEl
"
`;
exports[`export from "react-native-web" 1`] = `
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 { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';
@@ -30,7 +30,7 @@ export { default as createElement } from 'react-native-web/dist/exports/createEl
"
`;
exports[`import from "native-native" 1`] = `
exports[`Rewrite react-native to react-native-web import from "native-native": import from "native-native" 1`] = `
"
import ReactNative from 'react-native';
import { View } from 'react-native';
@@ -41,14 +41,14 @@ import * as ReactNativeModules from 'react-native';
import ReactNative from 'react-native-web/dist/index';
import View from 'react-native-web/dist/exports/View';
import Invalid from 'react-native-web/dist/exports/Invalid';
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';
"
`;
exports[`import from "react-native-web" 1`] = `
exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = `
"
import { createElement } from 'react-native-web';
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
@@ -66,7 +66,25 @@ import * as ReactNativeModules from 'react-native-web/dist/index';
"
`;
exports[`require "react-native-web" 1`] = `
exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = `
"
const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
↓ ↓ ↓ ↓ ↓ ↓
const ReactNative = require('react-native-web/dist/index').default;
const View = require('react-native-web/dist/exports/View').default;
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity').default;
"
`;
exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = `
"
const ReactNative = require('react-native-web');
const { createElement } = require('react-native-web');
@@ -74,18 +92,18 @@ const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = requ
↓ ↓ ↓ ↓ ↓ ↓
const ReactNative = require('react-native-web');
const ReactNative = require('react-native-web/dist/index').default;
const createElement = require('react-native-web/dist/exports/createElement');
const createElement = require('react-native-web/dist/exports/createElement').default;
const ColorPropType = require('react-native-web/dist/exports/ColorPropType');
const ColorPropType = require('react-native-web/dist/exports/ColorPropType').default;
const StyleSheet = require('react-native-web/dist/exports/StyleSheet');
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
const View = require('react-native-web/dist/exports/View');
const View = require('react-native-web/dist/exports/View').default;
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity');
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity').default;
const processColor = require('react-native-web/dist/exports/processColor');
const processColor = require('react-native-web/dist/exports/processColor').default;
"
`;

View File

@@ -30,6 +30,13 @@ export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';`,
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';`,
snapshot: true
},
{
title: 'require "react-native"',
code: `const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');`,
snapshot: true
},
{
title: 'require "react-native-web"',
code: `const ReactNative = require('react-native-web');

View File

@@ -1,5 +1,7 @@
const moduleMap = require('./moduleMap');
const getDistLocation = importName =>
importName ? `react-native-web/dist/exports/${importName}` : undefined;
importName && moduleMap[importName] ? `react-native-web/dist/exports/${importName}` : undefined;
const isReactNativeRequire = (t, node) => {
const { declarations } = node;
@@ -8,7 +10,7 @@ const isReactNativeRequire = (t, node) => {
}
const { id, init } = declarations[0];
return (
t.isObjectPattern(id) &&
(t.isObjectPattern(id) || t.isIdentifier(id)) &&
t.isCallExpression(init) &&
t.isIdentifier(init.callee) &&
init.callee.name === 'require' &&
@@ -84,21 +86,41 @@ module.exports = function({ types: t }) {
VariableDeclaration(path, state) {
if (isReactNativeRequire(t, path.node)) {
const { id } = path.node.declarations[0];
const imports = id.properties
.map(identifier => {
const distLocation = getDistLocation(identifier.key.name);
if (distLocation) {
return t.variableDeclaration(path.node.kind, [
t.variableDeclarator(
t.identifier(identifier.value.name),
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)])
)
]);
}
})
.filter(Boolean);
if (t.isObjectPattern(id)) {
const imports = id.properties
.map(identifier => {
const distLocation = getDistLocation(identifier.key.name);
if (distLocation) {
return t.variableDeclaration(path.node.kind, [
t.variableDeclarator(
t.identifier(identifier.value.name),
t.memberExpression(
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)]),
t.identifier('default')
)
)
]);
}
})
.filter(Boolean);
path.replaceWithMultiple(imports);
path.replaceWithMultiple(imports);
} else if (t.isIdentifier(id)) {
const name = id.name;
const importIndex = t.variableDeclaration(path.node.kind, [
t.variableDeclarator(
t.identifier(name),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral('react-native-web/dist/index')
]),
t.identifier('default')
)
)
]);
path.replaceWith(importIndex);
}
}
}
}

View File

@@ -0,0 +1,61 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
module.exports = {
ART: true,
ActivityIndicator: true,
Animated: true,
AppRegistry: true,
AppState: true,
AsyncStorage: true,
BackHandler: true,
Button: true,
CheckBox: true,
Clipboard: true,
ColorPropType: true,
Dimensions: true,
Easing: true,
EdgeInsetsPropType: true,
FlatList: true,
I18nManager: true,
Image: true,
ImageBackground: true,
InteractionManager: true,
Keyboard: true,
KeyboardAvoidingView: true,
Linking: true,
ListView: true,
Modal: true,
NativeModules: true,
NetInfo: true,
PanResponder: true,
Picker: true,
PixelRatio: true,
Platform: true,
PointPropType: true,
ProgressBar: true,
RefreshControl: true,
SafeAreaView: true,
ScrollView: true,
SectionList: true,
Slider: true,
StatusBar: true,
StyleSheet: true,
Switch: true,
Text: true,
TextInput: true,
TextPropTypes: true,
Touchable: true,
TouchableHighlight: true,
TouchableNativeFeedback: true,
TouchableOpacity: true,
TouchableWithoutFeedback: true,
UIManager: true,
Vibration: true,
View: true,
ViewPropTypes: true,
VirtualizedList: true,
createElement: true,
findNodeHandle: true,
processColor: true,
render: true,
unmountComponentAtNode: true
};

View File

@@ -1,56 +1,70 @@
# benchmarks
To run these benchmarks:
Try the [benchmarks app](https://necolas.github.io/react-native-web/benchmarks) online.
To run the benchmarks locally:
```
yarn benchmark
yarn benchmarks
open ./packages/benchmarks/dist/index.html
```
To run benchmarks for individual implementations append `?<name>,<name>` to the
URL, e.g., `?css-modules,react-native-web`.
Develop against these benchmarks:
```
yarn compile --watch
yarn benchmarks --watch
```
## Notes
These benchmarks are crude approximations of extreme cases that libraries may
encounter. The deep and wide tree cases look at the performance of mounting and
rendering large trees of styled elements. The Triangle case looks at the
performance of repeated style updates to a large mounted tree. Some libraries
must inject new styles for each "dynamic style", whereas others may not.
Libraries without support for dynamic styles (i.e., they rely on user-authored
inline styles) do not include the `SierpinskiTriangle` benchmark.
These benchmarks are approximations of extreme cases that libraries may
encounter. Their purpose is to provide an early-warning signal for performance
regressions. Each test report includes the mean and standard deviation of the
timings, and approximations of the time spent in scripting (S) and layout (L).
The components used in the render benchmarks are simple enough to be
implemented by multiple UI or style libraries. The benchmark implementations
and the features of the style libraries are _only approximately equivalent in
functionality_.
## Results
No benchmark will run for more than 20 seconds.
Typical render timings*: mean ± two standard deviations.
### Mount deep/wide tree
| Implementation | Deep tree (ms) | Wide tree (ms) | Triangle (ms) |
These cases look at the performance of mounting and rendering large trees of
elements that use static styles.
### Update dynamic styles
This case looks at the performance of repeated style updates to a large mounted
tree. Some libraries choose to inject new styles for each "dynamic style",
whereas others choose to use inline styles. Libraries without built-in support
for dynamic styles (i.e., they rely on user-authored inline styles) are not
included.
## Example results
### MacBook Pro (2011)
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) |
| :--- | ---: | ---: | ---: |
| `react-native-web@0.2.2` | `89.67` `±28.51` | `167.46` `±27.03` | `65.40` `±19.50` |
| `css-modules` | `77.42` 45.50` | `141.44` 33.96` | - |
| `inline-styles` | `236.25` `±95.57` | `477.01` 88.30` | `40.95` 23.53` |
| `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` |
Other libraries
### Moto G4
| Implementation | Deep tree (ms) | Wide tree (ms) | Triangle (ms) |
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) |
| :--- | ---: | ---: | ---: |
| `styletron@3.0.0-rc.5` | `83.53` 33.55` | `153.12` 39.13` | `56.47` `±24.22` |
| `aphrodite@1.2.5` | `88.23` 31.22` | `164.03` 34.70` | - |
| `glamor@2.20.40` | `110.09` 34.20` | `182.06` `±50.39` | ‡ |
| `emotion@8.0.12` | `103.44` `±32.12` | `204.45` `±41.00` | `110.28` `±26.94` |
| `react-jss@8.2.0` | `136.17` `±59.23` | `270.51` `±69.20` | - |
| `styled-components@2.3.2` | `217.57` `±51.90` | `437.57` `±65.74` | `76.99` `±41.79` |
| `reactxp@0.46.6` | `240.88` `±79.82` | `467.32` `±74.42` | `70.95` `±32.90`|
| `radium@0.19.6` | `400.19` `±94.58` | `816.59` `±91.10` | `71.13` `±27.22` |
These results indicate that render times when using `react-native-web`,
`css-modules`, `aphrodite`, and `styletron` are roughly equivalent and
significantly faster than alternatives.
*MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3. Google Chrome 62.
‡Glamor essentially crashes the browser tab.
| `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` |

View File

@@ -3,9 +3,14 @@
<head>
<meta charset="UTF-8">
<title>Performance tests</title>
<meta name="viewport" content="width=device-width">
<style>
html, body { height: 100%; width: 100%; overflow: hidden; }
.root { height: 100%; overflow: hidden; }
</style>
</head>
<body>
<div class="root"></div>
<script src="dist/performance.bundle.js"></script>
<script src="./bundle.js"></script>
</body>
</html>

View File

@@ -1,33 +1,37 @@
{
"private": true,
"name": "benchmarks",
"version": "0.3.0",
"version": "0.7.2",
"scripts": {
"benchmark": "webpack --config ./webpack.config.js && open index.html"
"build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
"release": "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": "^1.2.5",
"babel-polyfill": "^6.26.0",
"aphrodite": "^2.2.0",
"classnames": "^2.2.5",
"d3-scale-chromatic": "^1.1.1",
"emotion": "^8.0.12",
"glamor": "^2.20.40",
"marky": "^1.2.0",
"radium": "^0.19.6",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-jss": "^8.2.0",
"react-native-web": "^0.3.0",
"reactxp": "^0.46.6",
"styled-components": "^2.3.2",
"styletron-client": "^3.0.0-rc.5",
"styletron-utils": "^3.0.0-rc.3"
"d3-scale-chromatic": "^1.2.0",
"emotion": "^9.1.3",
"fela": "^6.1.7",
"glamor": "2.20.40",
"radium": "^0.24.0",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-fela": "^7.2.0",
"react-jss": "^8.4.0",
"react-native-web": "0.7.2",
"reactxp": "^1.1.1",
"styled-components": "^3.2.6",
"styled-jsx": "^2.2.6",
"styletron-engine-atomic": "^1.0.5",
"styletron-react": "^4.2.1"
},
"devDependencies": {
"babel-plugin-react-native-web": "^0.3.0",
"css-loader": "^0.28.7",
"style-loader": "^0.19.1",
"webpack": "^3.10.0",
"webpack-bundle-analyzer": "^2.9.1"
"babel-plugin-react-native-web": "0.7.2",
"css-loader": "^0.28.11",
"style-loader": "^0.21.0",
"url-loader": "^1.0.1",
"webpack": "^4.8.1",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.1.3"
}
}

View File

@@ -0,0 +1,297 @@
/* eslint-disable react/prop-types */
import Benchmark from './Benchmark';
import { Picker, StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
import React, { Component } from 'react';
import Button from './Button';
import { IconClear, IconEye } from './Icons';
import ReportCard from './ReportCard';
import Text from './Text';
import Layout from './Layout';
import { colors } from './theme';
const Overlay = () => <View style={[StyleSheet.absoluteFill, { zIndex: 2 }]} />;
export default class App extends Component {
static displayName = '@app/App';
constructor(props, context) {
super(props, context);
const currentBenchmarkName = Object.keys(props.tests)[0];
this.state = {
currentBenchmarkName,
currentLibraryName: 'react-native-web',
status: 'idle',
results: []
};
}
render() {
const { tests } = this.props;
const { currentBenchmarkName, status, currentLibraryName, results } = this.state;
const currentImplementation = tests[currentBenchmarkName][currentLibraryName];
const { Component, Provider, getComponentProps, sampleCount } = currentImplementation;
return (
<Layout
actionPanel={
<View>
<View style={styles.pickers}>
<View style={styles.pickerContainer}>
<Text style={styles.pickerTitle}>Library</Text>
<Text style={{ fontWeight: 'bold' }}>{currentLibraryName}</Text>
<Picker
enabled={status !== 'running'}
onValueChange={this._handleChangeLibrary}
selectedValue={currentLibraryName}
style={styles.picker}
>
{Object.keys(tests[currentBenchmarkName]).map(libraryName => (
<Picker.Item key={libraryName} label={libraryName} value={libraryName} />
))}
</Picker>
</View>
<View style={{ width: 1, backgroundColor: colors.fadedGray }} />
<View style={styles.pickerContainer}>
<Text style={styles.pickerTitle}>Benchmark</Text>
<Text>{currentBenchmarkName}</Text>
<Picker
enabled={status !== 'running'}
onValueChange={this._handleChangeBenchmark}
selectedValue={currentBenchmarkName}
style={styles.picker}
>
{Object.keys(tests).map(test => (
<Picker.Item key={test} label={test} value={test} />
))}
</Picker>
</View>
</View>
<View style={{ flexDirection: 'row', height: 50 }}>
<View style={styles.grow}>
<Button
onPress={this._handleStart}
style={styles.button}
title={status === 'running' ? 'Running…' : 'Run'}
/>
</View>
</View>
{status === 'running' ? <Overlay /> : null}
</View>
}
listPanel={
<View style={styles.listPanel}>
<View style={styles.grow}>
<View style={styles.listBar}>
<View style={styles.iconClearContainer}>
<TouchableOpacity onPress={this._handleClear}>
<IconClear />
</TouchableOpacity>
</View>
</View>
<ScrollView ref={this._setScrollRef} style={styles.grow}>
{results.map((r, i) => (
<ReportCard
benchmarkName={r.benchmarkName}
key={i}
libraryName={r.libraryName}
libraryVersion={r.libraryVersion}
mean={r.mean}
meanLayout={r.meanLayout}
meanScripting={r.meanScripting}
runTime={r.runTime}
sampleCount={r.sampleCount}
stdDev={r.stdDev}
/>
))}
{status === 'running' ? (
<ReportCard
benchmarkName={currentBenchmarkName}
libraryName={currentLibraryName}
/>
) : null}
</ScrollView>
</View>
{status === 'running' ? <Overlay /> : null}
</View>
}
viewPanel={
<View style={styles.viewPanel}>
<View style={styles.iconEyeContainer}>
<TouchableOpacity onPress={this._handleVisuallyHideBenchmark}>
<IconEye style={styles.iconEye} />
</TouchableOpacity>
</View>
<Provider>
{status === 'running' ? (
<React.Fragment>
<View ref={this._setBenchWrapperRef}>
<Benchmark
component={Component}
forceLayout={true}
getComponentProps={getComponentProps}
onComplete={this._createHandleComplete({
sampleCount,
benchmarkName: currentBenchmarkName,
libraryName: currentLibraryName
})}
ref={this._setBenchRef}
sampleCount={sampleCount}
timeout={20000}
type={Component.benchmarkType}
/>
</View>
</React.Fragment>
) : (
<Component {...getComponentProps({ cycle: 10 })} />
)}
</Provider>
{status === 'running' ? <Overlay /> : null}
</View>
}
/>
);
}
_handleChangeBenchmark = value => {
this.setState(() => ({ currentBenchmarkName: value }));
};
_handleChangeLibrary = value => {
this.setState(() => ({ currentLibraryName: value }));
};
_handleStart = () => {
this.setState(
() => ({ status: 'running' }),
() => {
if (this._shouldHideBenchmark && this._benchWrapperRef) {
this._benchWrapperRef.setNativeProps({ style: { opacity: 0 } });
}
this._benchmarkRef.start();
this._scrollToEnd();
}
);
};
// hide the benchmark as it is performed (no flashing on screen)
_handleVisuallyHideBenchmark = () => {
this._shouldHideBenchmark = !this._shouldHideBenchmark;
if (this._benchWrapperRef) {
this._benchWrapperRef.setNativeProps({
style: { opacity: this._shouldHideBenchmark ? 0 : 1 }
});
}
};
_createHandleComplete = ({ benchmarkName, libraryName, sampleCount }) => results => {
this.setState(
state => ({
results: state.results.concat([
{
...results,
benchmarkName,
libraryName,
libraryVersion: this.props.tests[benchmarkName][libraryName].version
}
]),
status: 'complete'
}),
this._scrollToEnd
);
// console.log(results);
// console.log(results.samples.map(sample => sample.elapsed.toFixed(1)).join('\n'));
};
_handleClear = () => {
this.setState(() => ({ results: [] }));
};
_setBenchRef = ref => {
this._benchmarkRef = ref;
};
_setBenchWrapperRef = ref => {
this._benchWrapperRef = ref;
};
_setScrollRef = ref => {
this._scrollRef = ref;
};
// scroll the most recent result into view
_scrollToEnd = () => {
window.requestAnimationFrame(() => {
if (this._scrollRef) {
this._scrollRef.scrollToEnd();
}
});
};
}
const styles = StyleSheet.create({
viewPanel: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden',
backgroundColor: 'black'
},
iconEye: {
color: 'white',
height: 32
},
iconEyeContainer: {
position: 'absolute',
top: 10,
right: 10,
zIndex: 1
},
iconClearContainer: {
height: '100%',
marginLeft: 5
},
grow: {
flex: 1
},
listPanel: {
flex: 1,
width: '100%',
marginHorizontal: 'auto'
},
listBar: {
padding: 5,
alignItems: 'center',
flexDirection: 'row',
backgroundColor: colors.fadedGray,
borderBottomWidth: 1,
borderBottomColor: colors.mediumGray,
justifyContent: 'flex-end'
},
pickers: {
flexDirection: 'row'
},
pickerContainer: {
flex: 1,
padding: 5
},
pickerTitle: {
fontSize: 12,
color: colors.deepGray
},
picker: {
...StyleSheet.absoluteFillObject,
appearance: 'none',
opacity: 0,
width: '100%'
},
button: {
borderRadius: 0,
flex: 1
}
});

View File

@@ -0,0 +1,253 @@
/**
* The MIT License (MIT)
* Copyright (c) 2017 Paul Armstrong
* https://github.com/paularmstrong/react-component-benchmark
*/
/* global $Values */
/**
* @flow
*/
import * as Timing from './timing';
import React, { Component } from 'react';
import { getMean, getMedian, getStdDev } from './math';
import type { BenchResultsType, FullSampleTimingType, SampleTimingType } from './types';
export const BenchmarkType = {
MOUNT: 'mount',
UPDATE: 'update',
UNMOUNT: 'unmount'
};
const shouldRender = (cycle: number, type: $Values<typeof BenchmarkType>): boolean => {
switch (type) {
// Render every odd iteration (first, third, etc)
// Mounts and unmounts the component
case BenchmarkType.MOUNT:
case BenchmarkType.UNMOUNT:
return !((cycle + 1) % 2);
// Render every iteration (updates previously rendered module)
case BenchmarkType.UPDATE:
return true;
default:
return false;
}
};
const shouldRecord = (cycle: number, type: $Values<typeof BenchmarkType>): boolean => {
switch (type) {
// Record every odd iteration (when mounted: first, third, etc)
case BenchmarkType.MOUNT:
return !((cycle + 1) % 2);
// Record every iteration
case BenchmarkType.UPDATE:
return true;
// Record every even iteration (when unmounted)
case BenchmarkType.UNMOUNT:
return !(cycle % 2);
default:
return false;
}
};
const isDone = (
cycle: number,
sampleCount: number,
type: $Values<typeof BenchmarkType>
): boolean => {
switch (type) {
case BenchmarkType.MOUNT:
return cycle >= sampleCount * 2 - 1;
case BenchmarkType.UPDATE:
return cycle >= sampleCount - 1;
case BenchmarkType.UNMOUNT:
return cycle >= sampleCount * 2;
default:
return true;
}
};
const sortNumbers = (a: number, b: number): number => a - b;
type BenchmarkPropsType = {
component: typeof React.Component,
forceLayout?: boolean,
getComponentProps: Function,
onComplete: (x: BenchResultsType) => void,
sampleCount: number,
timeout: number,
type: $Values<typeof BenchmarkType>
};
type BenchmarkStateType = {
componentProps: Object,
cycle: number,
running: boolean
};
/**
* Benchmark
* TODO: documentation
*/
export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkStateType> {
_raf: ?Function;
_startTime: number;
_samples: Array<SampleTimingType>;
static displayName = 'Benchmark';
static defaultProps = {
sampleCount: 50,
timeout: 10000, // 10 seconds
type: BenchmarkType.MOUNT
};
static Type = BenchmarkType;
constructor(props: BenchmarkPropsType, context?: {}) {
super(props, context);
const cycle = 0;
const componentProps = props.getComponentProps({ cycle });
this.state = {
componentProps,
cycle,
running: false
};
this._startTime = 0;
this._samples = [];
}
componentWillReceiveProps(nextProps: BenchmarkPropsType) {
if (nextProps) {
this.setState(state => ({ componentProps: nextProps.getComponentProps(state.cycle) }));
}
}
componentWillUpdate(nextProps: BenchmarkPropsType, nextState: BenchmarkStateType) {
if (nextState.running && !this.state.running) {
this._startTime = Timing.now();
}
}
componentDidUpdate() {
const { forceLayout, sampleCount, timeout, type } = this.props;
const { cycle, running } = this.state;
if (running && shouldRecord(cycle, type)) {
this._samples[cycle].scriptingEnd = Timing.now();
// force style recalc that would otherwise happen before the next frame
if (forceLayout) {
this._samples[cycle].layoutStart = Timing.now();
if (document.body) {
document.body.offsetWidth;
}
this._samples[cycle].layoutEnd = Timing.now();
}
}
if (running) {
const now = Timing.now();
if (!isDone(cycle, sampleCount, type) && now - this._startTime < timeout) {
this._handleCycleComplete();
} else {
this._handleComplete(now);
}
}
}
componentWillUnmount() {
if (this._raf) {
window.cancelAnimationFrame(this._raf);
}
}
render() {
const { component: Component, type } = this.props;
const { componentProps, cycle, running } = this.state;
if (running && shouldRecord(cycle, type)) {
this._samples[cycle] = { scriptingStart: Timing.now() };
}
return running && shouldRender(cycle, type) ? <Component {...componentProps} /> : null;
}
start() {
this._samples = [];
this.setState(() => ({ running: true, cycle: 0 }));
}
_handleCycleComplete() {
const { getComponentProps, type } = this.props;
const { cycle } = this.state;
let componentProps;
if (getComponentProps) {
// Calculate the component props outside of the time recording (render)
// so that it doesn't skew results
componentProps = getComponentProps({ cycle });
// make sure props always change for update tests
if (type === BenchmarkType.UPDATE) {
componentProps['data-test'] = cycle;
}
}
this._raf = window.requestAnimationFrame(() => {
this.setState((state: BenchmarkStateType) => ({
cycle: state.cycle + 1,
componentProps
}));
});
}
getSamples(): Array<FullSampleTimingType> {
return this._samples.reduce(
(
memo: Array<FullSampleTimingType>,
{ scriptingStart, scriptingEnd, layoutStart, layoutEnd }: SampleTimingType
): Array<FullSampleTimingType> => {
memo.push({
start: scriptingStart,
end: layoutEnd || scriptingEnd || 0,
scriptingStart,
scriptingEnd: scriptingEnd || 0,
layoutStart,
layoutEnd
});
return memo;
},
[]
);
}
_handleComplete(endTime: number) {
const { onComplete } = this.props;
const samples = this.getSamples();
this.setState(() => ({ running: false, cycle: 0 }));
const runTime = endTime - this._startTime;
const sortedElapsedTimes = samples.map(({ start, end }) => end - start).sort(sortNumbers);
const sortedScriptingElapsedTimes = samples
.map(({ scriptingStart, scriptingEnd }) => scriptingEnd - scriptingStart)
.sort(sortNumbers);
const sortedLayoutElapsedTimes = samples
.map(({ layoutStart, layoutEnd }) => (layoutEnd || 0) - (layoutStart || 0))
.sort(sortNumbers);
onComplete({
startTime: this._startTime,
endTime,
runTime,
sampleCount: samples.length,
samples: samples,
max: sortedElapsedTimes[sortedElapsedTimes.length - 1],
min: sortedElapsedTimes[0],
median: getMedian(sortedElapsedTimes),
mean: getMean(sortedElapsedTimes),
stdDev: getStdDev(sortedElapsedTimes),
meanLayout: getMean(sortedLayoutElapsedTimes),
meanScripting: getMean(sortedScriptingElapsedTimes)
});
}
}

View File

@@ -0,0 +1,27 @@
// @flow
type ValuesType = Array<number>;
export const getStdDev = (values: ValuesType): number => {
const avg = getMean(values);
const squareDiffs = values.map((value: number) => {
const diff = value - avg;
return diff * diff;
});
return Math.sqrt(getMean(squareDiffs));
};
export const getMean = (values: ValuesType): number => {
const sum = values.reduce((sum: number, value: number) => sum + value, 0);
return sum / values.length;
};
export const getMedian = (values: ValuesType): number => {
if (values.length === 1) {
return values[0];
}
const numbers = values.sort((a: number, b: number) => a - b);
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
};

View File

@@ -0,0 +1,18 @@
// @flow
const NS_PER_MS = 1e6;
const MS_PER_S = 1e3;
// Returns a high resolution time (if possible) in milliseconds
export function now(): number {
if (window && window.performance) {
return window.performance.now();
} else if (process && process.hrtime) {
const [seconds, nanoseconds] = process.hrtime();
const secInMS = seconds * MS_PER_S;
const nSecInMS = nanoseconds / NS_PER_MS;
return secInMS + nSecInMS;
} else {
return Date.now();
}
}

View File

@@ -0,0 +1,31 @@
/**
* @flow
*/
export type BenchResultsType = {
startTime: number,
endTime: number,
runTime: number,
sampleCount: number,
samples: Array<FullSampleTimingType>,
max: number,
min: number,
median: number,
mean: number,
stdDev: number
};
export type SampleTimingType = {
scriptingStart: number,
scriptingEnd?: number,
layoutStart?: number,
layoutEnd?: number
};
export type FullSampleTimingType = {
start: number,
end: number,
scriptingStart: number,
scriptingEnd: number,
layoutStart?: number,
layoutEnd?: number
};

View File

@@ -0,0 +1,71 @@
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,
color,
disabled,
onPress,
style,
textStyle,
testID,
title
} = this.props;
return (
<TouchableHighlight
accessibilityLabel={accessibilityLabel}
accessibilityRole="button"
disabled={disabled}
onPress={onPress}
style={[
styles.button,
style,
color && { backgroundColor: color },
disabled && styles.buttonDisabled
]}
testID={testID}
>
<Text style={[styles.text, textStyle, disabled && styles.textDisabled]}>{title}</Text>
</TouchableHighlight>
);
}
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#2196F3',
borderRadius: 0,
justifyContent: 'center'
},
text: {
color: '#fff',
fontSize: 20,
fontWeight: '500',
padding: 8,
textAlign: 'center',
textTransform: 'uppercase'
},
buttonDisabled: {
backgroundColor: '#dfdfdf'
},
textDisabled: {
color: '#a1a1a1'
}
});

View File

@@ -0,0 +1,55 @@
import React, { Fragment } from 'react';
import { createElement, StyleSheet, Text } from 'react-native';
const styles = StyleSheet.create({
root: {
display: 'inline-block',
fill: 'currentcolor',
height: '1.25em',
maxWidth: '100%',
position: 'relative',
userSelect: 'none',
textAlignVertical: 'text-bottom'
}
});
const createIcon = children => {
const Icon = props =>
createElement(
'svg',
{
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;
};
export const IconClear = createIcon(
<Fragment>
<path d="M0 0h24v24H0z" id="bounds" opacity="0" />
<path d="M12 1.25C6.072 1.25 1.25 6.072 1.25 12S6.072 22.75 12 22.75 22.75 17.928 22.75 12 17.928 1.25 12 1.25zm0 1.5c2.28 0 4.368.834 5.982 2.207L4.957 17.982C3.584 16.368 2.75 14.282 2.75 12c0-5.1 4.15-9.25 9.25-9.25zm0 18.5c-2.28 0-4.368-.834-5.982-2.207L19.043 6.018c1.373 1.614 2.207 3.7 2.207 5.982 0 5.1-4.15 9.25-9.25 9.25z" />
</Fragment>
);
export const IconEye = createIcon(
<Fragment>
<path d="M0 0h24v24H0z" id="bounds" opacity="0" />
<path d="M14.548 11.634c-1.207 0-2.188-.98-2.188-2.188 0-.664.302-1.25.77-1.653-.363-.097-.736-.165-1.13-.165-2.416 0-4.375 1.96-4.375 4.376S9.585 16.38 12 16.38c2.418 0 4.377-1.96 4.377-4.376 0-.4-.07-.78-.17-1.146-.402.47-.992.776-1.66.776z" />
<path d="M12 19.79c-7.228 0-10.12-6.724-10.24-7.01-.254-.466-.254-1.105.035-1.642C1.88 10.923 4.772 4.2 12 4.2s10.12 6.723 10.24 7.01c.254.465.254 1.104-.035 1.64-.085.216-2.977 6.94-10.205 6.94zm0-14c-6.154 0-8.668 5.787-8.772 6.033-.068.135-.068.208-.033.273.137.316 2.65 6.104 8.805 6.104 6.18 0 8.747-5.973 8.772-6.033.07-.136.07-.21.034-.274-.138-.316-2.652-6.103-8.806-6.103z" />
</Fragment>
);
export const IconCopy = createIcon(
<Fragment>
<path d="M0 0h24v24H0z" id="bounds" opacity="0" />
<path d="M11.47 14.53c.146.146.338.22.53.22s.384-.073.53-.22l5-5c.293-.293.293-.768 0-1.06s-.768-.294-1.06 0l-3.72 3.72V2c0-.414-.337-.75-.75-.75s-.75.336-.75.75v10.19L7.53 8.47c-.293-.293-.768-.293-1.06 0s-.294.768 0 1.06l5 5z" />
<path d="M21.25 13.25c-.414 0-.75.336-.75.75v5.652c0 .437-.355.792-.792.792H4.292c-.437 0-.792-.355-.792-.792V14c0-.414-.336-.75-.75-.75S2 13.586 2 14v5.652c0 1.264 1.028 2.292 2.292 2.292h15.416c1.264 0 2.292-1.028 2.292-2.292V14c0-.414-.336-.75-.75-.75z" />
</Fragment>
);

View File

@@ -0,0 +1,68 @@
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
};
render() {
const { viewPanel, actionPanel, listPanel } = this.props;
const { widescreen } = this.state;
return (
<View onLayout={this._handleLayout} style={[styles.root, widescreen && styles.row]}>
<View style={[widescreen ? styles.grow : styles.stackPanel, styles.layer]}>
{viewPanel}
</View>
<View style={styles.grow}>
<View style={[styles.grow, styles.layer]}>{listPanel}</View>
<View style={styles.divider} />
<View style={styles.layer}>{actionPanel}</View>
</View>
</View>
);
}
_handleLayout = ({ nativeEvent }) => {
const { layout } = nativeEvent;
const { width } = layout;
if (width >= 740) {
this.setState(() => ({ widescreen: true }));
} else {
this.setState(() => ({ widescreen: false }));
}
};
}
const styles = StyleSheet.create({
root: {
height: '100%'
},
row: {
flexDirection: 'row'
},
divider: {
height: 10,
backgroundColor: colors.fadedGray,
borderBottomWidth: 1,
borderTopWidth: 1,
borderColor: colors.mediumGray
},
grow: {
flex: 1
},
stackPanel: {
height: '33.33%'
},
layer: {
transform: [{ translateZ: '0' }]
}
});

View File

@@ -0,0 +1,83 @@
/* eslint-disable react/prop-types */
import Text from './Text';
import { StyleSheet, View } from 'react-native';
import React, { Fragment } from 'react';
const fmt = (time: number) => {
const i = Number(Math.round(time + 'e2') + 'e-2').toFixed(2);
return 10 / i > 1 ? `0${i}` : i;
};
class ReportCard extends React.PureComponent {
render() {
const {
benchmarkName,
libraryName,
sampleCount,
mean,
meanLayout,
meanScripting,
stdDev,
libraryVersion
} = this.props;
const sampleCountText = sampleCount != null ? `(${sampleCount})` : '';
return (
<View style={styles.root}>
<View style={styles.left}>
<Text numberOfLines={1} style={styles.bold}>
{`${libraryName}${libraryVersion ? '@' + libraryVersion : ''}`}
</Text>
<Text numberOfLines={1}>
{benchmarkName} {sampleCountText}
</Text>
</View>
<View style={styles.right}>
{mean ? (
<Fragment>
<Text style={[styles.bold, styles.monoFont]}>
{fmt(mean)} ±{fmt(stdDev)} ms
</Text>
<Text style={[styles.smallText, styles.monoFont]}>
(S/L) {fmt(meanScripting)}/{fmt(meanLayout)} ms
</Text>
</Fragment>
) : (
<Text style={styles.bold}>In progress</Text>
)}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
root: {
flexDirection: 'row',
alignItems: 'center',
padding: 5,
borderBottomWidth: 1,
borderBottomColor: '#eee'
},
bold: {
fontWeight: 'bold'
},
smallText: { fontSize: 12 },
monoFont: {
fontFamily: 'monospace'
},
centerText: {
display: 'flex',
alignItems: 'center'
},
left: {
width: '50%'
},
right: {
flex: 1,
alignItems: 'flex-end'
}
});
export default ReportCard;

View File

@@ -0,0 +1,30 @@
/* eslint-disable react/prop-types */
import { bool } from 'prop-types';
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import { colors } from './theme';
class AppText extends React.Component {
static displayName = '@app/Text';
static contextTypes = {
isInAParentText: bool
};
render() {
const { style, ...rest } = this.props;
const { isInAParentText } = this.context;
return <Text {...rest} style={[!isInAParentText && styles.baseText, style]} />;
}
}
const styles = StyleSheet.create({
baseText: {
color: colors.textBlack,
fontSize: '1rem',
lineHeight: '1.3125em'
}
});
export default AppText;

View File

@@ -0,0 +1,101 @@
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import { Dimensions, Platform } from 'react-native';
const baseFontSize = 14;
const baseUnit = 1.3125;
const createPlatformLength = multiplier =>
Platform.select({ web: `${multiplier}rem`, default: multiplier * baseFontSize });
/**
* Exported variables
*/
export const borderRadii = {
normal: Platform.select({ web: '0.35rem', default: 5 }),
infinite: '9999px'
};
export const breakpoints = {
small: 360,
medium: 600,
large: 800,
xLarge: 1100
};
/**
* Color palette
* DO NOT add new colors unless they are part of @design's color palette.
* DO NOT use colors that are not specified here.
* source: go/uicolors
*/
export const colors = {
// Primary
blue: '#1DA1F2',
purple: '#794BC4',
green: '#17BF63',
yellow: '#FFAD1F',
orange: '#F45D22',
red: '#E0245E',
// Text and interface grays
textBlack: '#14171A',
deepGray: '#657786',
mediumGray: '#AAB8C2',
lightGray: '#CCD6DD',
fadedGray: '#E6ECF0',
faintGray: '#F5F8FA',
white: '#FFF',
textBlue: '#1B95E0'
};
export const fontFamilies = {
normal: 'System',
japan: Platform.select({
web:
'Arial, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka, "メイリオ", Meiryo, " Pゴシック", "MS PGothic", sans-serif',
default: 'System'
}),
rtl: Platform.select({ web: 'Tahoma, Arial, sans-serif', default: 'System' })
};
export const fontSizes = {
// font scale
small: createPlatformLength(0.85),
normal: createPlatformLength(1),
large: createPlatformLength(1.25),
xLarge: createPlatformLength(1.5),
jumbo: createPlatformLength(2)
};
export const lineHeight = Platform.select({ web: `${baseUnit}` });
export const spaces = {
// This set of space variables should be used for margin, padding
micro: createPlatformLength(baseUnit * 0.125),
xxSmall: createPlatformLength(baseUnit * 0.25),
xSmall: createPlatformLength(baseUnit * 0.5),
small: createPlatformLength(baseUnit * 0.75),
medium: createPlatformLength(baseUnit),
large: createPlatformLength(baseUnit * 1.5),
xLarge: createPlatformLength(baseUnit * 2),
xxLarge: createPlatformLength(baseUnit * 2.5),
jumbo: createPlatformLength(baseUnit * 3)
};
// On web, change the root font-size at specific breakpoints to scale the UI
// for larger viewports.
if (Platform.OS === 'web' && canUseDOM) {
const { medium, large } = breakpoints;
const htmlElement = document.documentElement;
const setFontSize = width => {
const fontSize = width > medium ? (width > large ? '18px' : '17px') : '16px';
if (htmlElement) {
htmlElement.style.fontSize = fontSize;
}
};
setFontSize(Dimensions.get('window').width);
Dimensions.addEventListener('change', dimensions => {
setFontSize(dimensions.window.width);
});
}

View File

@@ -1,98 +0,0 @@
import * as marky from 'marky';
const fmt = time => `${Math.round(time * 100) / 100}ms`;
const measure = (name, fn) => {
marky.mark(name);
fn();
const performanceMeasure = marky.stop(name);
return performanceMeasure.duration;
};
const mean = values => {
const sum = values.reduce((sum, value) => sum + value, 0);
return sum / values.length;
};
const median = values => {
if (!Array.isArray(values)) {
return 0;
}
if (values.length === 1) {
return values[0];
}
const numbers = [...values].sort((a, b) => a - b);
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
};
const standardDeviation = values => {
const avg = mean(values);
const squareDiffs = values.map(value => {
const diff = value - avg;
return diff * diff;
});
const meanSquareDiff = mean(squareDiffs);
return Math.sqrt(meanSquareDiff);
};
export const log = (name, description, durations) => {
const stdDev = standardDeviation(durations);
const formattedMean = fmt(mean(durations));
const formattedMedian = fmt(median(durations));
const formattedStdDev = fmt(stdDev);
console.groupCollapsed(`${name}\n${formattedMean} ±${fmt(2 * stdDev)}`);
description && console.log(description);
console.log(`Median: ${formattedMedian}`);
console.log(`Mean: ${formattedMean}`);
console.log(`Standard deviation: ${formattedStdDev}`);
console.log(durations);
console.groupEnd();
};
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
return new Promise(resolve => {
const durations = [];
let i = 0;
setup();
teardown();
const done = () => {
log(name, description, durations);
resolve();
};
const a = () => {
setup();
window.requestAnimationFrame(b);
};
const b = () => {
const duration = measure('mean', task);
durations.push(duration);
window.requestAnimationFrame(c);
};
const c = () => {
teardown();
window.requestAnimationFrame(d);
};
const d = () => {
i += 1;
if (i < runs) {
window.requestAnimationFrame(a);
} else {
window.requestAnimationFrame(done);
}
};
window.requestAnimationFrame(a);
});
};
export default benchmark;

View File

@@ -1,58 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
class DeepTree extends Component {
static propTypes = {
breadth: PropTypes.number.isRequired,
components: PropTypes.object,
depth: PropTypes.number.isRequired,
id: PropTypes.number.isRequired,
wrap: PropTypes.number.isRequired
};
/* necessary for reactxp to work without errors */
static childContextTypes = {
focusManager: PropTypes.object
};
getChildContext() {
return {
focusManager: {
addFocusableComponent() {},
removeFocusableComponent() {},
restrictFocusWithin() {},
removeFocusRestriction() {},
limitFocusWithin() {},
removeFocusLimitation() {}
}
};
}
render() {
const { breadth, components, depth, id, wrap } = this.props;
const { Box } = components;
let result = (
<Box color={id % 3} components={components} layout={depth % 2 === 0 ? 'column' : 'row'} outer>
{depth === 0 && <Box color={id % 3 + 3} components={components} fixed />}
{depth !== 0 &&
Array.from({ length: breadth }).map((el, i) => (
<DeepTree
breadth={breadth}
components={components}
depth={depth - 1}
id={i}
key={i}
wrap={wrap}
/>
))}
</Box>
);
for (let i = 0; i < wrap; i++) {
result = <Box components={components}>{result}</Box>;
}
return result;
}
}
export default DeepTree;

View File

@@ -1,17 +1,22 @@
import PropTypes from 'prop-types';
import { BenchmarkType } from '../app/Benchmark';
import { number, object } from 'prop-types';
import React from 'react';
import { interpolatePurples, interpolateBuPu, interpolateRdPu } from 'd3-scale-chromatic';
const targetSize = 25;
const targetSize = 10;
class SierpinskiTriangle extends React.Component {
static displayName = 'SierpinskiTriangle';
static benchmarkType = BenchmarkType.UPDATE;
static propTypes = {
Dot: PropTypes.node,
depth: PropTypes.number,
renderCount: PropTypes.number,
s: PropTypes.number,
x: PropTypes.number,
y: PropTypes.number
components: object,
depth: number,
renderCount: number,
s: number,
x: number,
y: number
};
static defaultProps = {
@@ -20,64 +25,65 @@ class SierpinskiTriangle extends React.Component {
};
render() {
const { x, y, depth, renderCount, Dot } = this.props;
const { components, x, y, depth, renderCount } = this.props;
let { s } = this.props;
const { Dot } = components;
if (s <= targetSize) {
let fn;
switch (depth) {
case 1:
fn = interpolatePurples;
break;
case 2:
fn = interpolateBuPu;
break;
case 3:
default:
fn = interpolateRdPu;
if (Dot) {
if (s <= targetSize) {
let fn;
switch (depth) {
case 1:
fn = interpolatePurples;
break;
case 2:
fn = interpolateBuPu;
break;
case 3:
default:
fn = interpolateRdPu;
}
// introduce randomness to ensure that repeated runs don't produce the same colors
const color = fn(renderCount * Math.random() / 20);
return (
<Dot color={color} size={targetSize} x={x - targetSize / 2} y={y - targetSize / 2} />
);
}
s /= 2;
return (
<Dot
color={fn(renderCount / 20)}
size={targetSize}
x={x - targetSize / 2}
y={y - targetSize / 2}
/>
<React.Fragment>
<SierpinskiTriangle
components={components}
depth={1}
renderCount={renderCount}
s={s}
x={x}
y={y - s / 2}
/>
<SierpinskiTriangle
components={components}
depth={2}
renderCount={renderCount}
s={s}
x={x - s}
y={y + s / 2}
/>
<SierpinskiTriangle
components={components}
depth={3}
renderCount={renderCount}
s={s}
x={x + s}
y={y + s / 2}
/>
</React.Fragment>
);
} else {
return <span style={{ color: 'white' }}>No implementation available</span>;
}
s /= 2;
return [
<SierpinskiTriangle
Dot={Dot}
depth={1}
key={1}
renderCount={renderCount}
s={s}
x={x}
y={y - s / 2}
/>,
<SierpinskiTriangle
Dot={Dot}
depth={2}
key={2}
renderCount={renderCount}
s={s}
x={x - s}
y={y + s / 2}
/>,
<SierpinskiTriangle
Dot={Dot}
depth={3}
key={3}
renderCount={renderCount}
s={s}
x={x + s}
y={y + s / 2}
/>
];
}
}

View File

@@ -0,0 +1,45 @@
import { BenchmarkType } from '../app/Benchmark';
import { number, object } from 'prop-types';
import React, { Component } from 'react';
class Tree extends Component {
static displayName = 'Tree';
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 &&
Array.from({ length: breadth }).map((el, i) => (
<Tree
breadth={breadth}
components={components}
depth={depth - 1}
id={i}
key={i}
wrap={wrap}
/>
))}
</Box>
);
for (let i = 0; i < wrap; i++) {
result = <Box>{result}</Box>;
}
return result;
}
}
export default Tree;

View File

@@ -1,14 +0,0 @@
import createRenderBenchmark from '../createRenderBenchmark';
import NestedTree from './NestedTree';
import React from 'react';
const renderDeepTree = (label, components) =>
createRenderBenchmark({
name: `[${label}] Deep tree`,
runs: 20,
getElement() {
return <NestedTree breadth={3} components={components} depth={6} id={0} wrap={1} />;
}
});
export default renderDeepTree;

View File

@@ -1,112 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import SierpinskiTriangle from './SierpinskiTriangle';
import { log } from '../benchmark';
const node = document.querySelector('.root');
let runs = 20;
class Speedometer extends React.Component {
/* necessary for reactxp to work without errors */
static childContextTypes = {
focusManager: PropTypes.object
};
getChildContext() {
return {
focusManager: {
addFocusableComponent() {},
removeFocusableComponent() {},
restrictFocusWithin() {},
removeFocusRestriction() {},
limitFocusWithin() {},
removeFocusLimitation() {}
}
};
}
static propTypes = {
Dot: PropTypes.node.isRequired,
description: PropTypes.string,
name: PropTypes.string.isRequired,
onComplete: PropTypes.node.isRequired
};
state = { renderCount: -1 };
async componentDidMount() {
const durations = [];
while ((runs -= 1)) {
const prev = window.performance.now();
await new Promise(resolve => {
this.raf = window.requestAnimationFrame(() => {
this.setState({ renderCount: this.state.renderCount + 1 }, () => {
const now = window.performance.now();
durations.push(now - prev);
resolve();
});
});
});
}
const { description, name } = this.props;
log(name, description, durations);
runs = 20;
this.props.onComplete();
}
componentWillUnmount() {
window.cancelAnimationFrame(this.raf);
}
render() {
return (
<div style={styles.wrapper}>
<SierpinskiTriangle
Dot={this.props.Dot}
renderCount={this.state.renderCount}
s={1000}
x={0}
y={0}
/>
</div>
);
}
}
const styles = {
wrapper: {
position: 'absolute',
transformOrigin: '0 0',
left: '50%',
top: '50%',
width: '10px',
height: '10px',
backgroundColor: '#eee',
transform: 'scale(0.33)'
}
};
const renderSierpinskiTriangle = (name, { Dot }) => () => {
return new Promise(resolve => {
/* eslint-disable react/jsx-no-bind */
ReactDOM.render(
<Speedometer
Dot={Dot}
description="Dynamic styles"
name={`[${name}] Triangle`}
onComplete={() => {
ReactDOM.unmountComponentAtNode(node);
resolve();
}}
/>,
node
);
/* eslint-enable react/jsx-no-bind */
});
};
export default renderSierpinskiTriangle;

View File

@@ -1,112 +0,0 @@
import createRenderBenchmark from '../createRenderBenchmark';
import React from 'react';
const tweet1 = {
favorite_count: 30,
favorited: true,
id: '834889712556875776',
lang: 'en',
retweet_count: 6,
retweeted: false,
textParts: [
{
prefix: '',
text: 'Living burrito to burrito '
},
{
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
isEmoji: true,
prefix: '',
text: '🌯'
},
{
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
isEmoji: true,
prefix: '',
text: '🌯'
},
{
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
isEmoji: true,
prefix: '',
text: '🌯'
}
],
timestamp: 'Feb 23',
user: {
fullName: 'Nicolas',
screenName: 'necolas',
profileImageUrl: 'https://pbs.twimg.com/profile_images/804365942360719360/dQnPejph_normal.jpg'
}
};
const tweet2 = {
favorite_count: 84,
favorited: false,
id: '730896800060579840',
lang: 'en',
media: {
source: {
uri: 'https://pbs.twimg.com/media/CiSqvsJVEAAtLZ1.jpg',
width: 600,
height: 338
}
},
retweet_count: 4,
retweeted: true,
textParts: [
{
prefix: '',
text: 'Presenting '
},
{
displayUrl: 'mobile.twitter.com',
expandedUrl: 'https://mobile.twitter.com',
isEntity: true,
isUrl: true,
linkRelation: 'nofollow',
prefix: '',
text: '',
textDirection: 'ltr',
url: 'https://t.co/4hRCAxiUUG'
},
{
prefix: '',
text: ' with '
},
{
isEntity: true,
isMention: true,
prefix: '@',
text: 'davidbellona',
textDirection: 'ltr',
url: '/davidbellona'
},
{
prefix: '',
text: " at Twitter's all hands meeting "
}
],
timestamp: 'May 12',
user: {
fullName: 'Nicolas',
screenName: 'necolas',
profileImageUrl: 'https://pbs.twimg.com/profile_images/804365942360719360/dQnPejph_normal.jpg'
}
};
const renderTweet = (label, { Tweet }) =>
createRenderBenchmark({
name: `[${label}] Tweet`,
runs: 10,
getElement() {
return (
<div style={{ width: 500 }}>
<Tweet tweet={tweet1} />
<Tweet tweet={tweet2} />
</div>
);
}
});
export default renderTweet;

View File

@@ -1,14 +0,0 @@
import createRenderBenchmark from '../createRenderBenchmark';
import NestedTree from './NestedTree';
import React from 'react';
const renderWideTree = (label, components) =>
createRenderBenchmark({
name: `[${label}] Wide tree`,
runs: 20,
getElement() {
return <NestedTree breadth={10} components={components} depth={3} id={0} wrap={4} />;
}
});
export default renderWideTree;

View File

@@ -1,24 +0,0 @@
import benchmark from './benchmark';
import ReactDOM from 'react-dom';
const node = document.querySelector('.root');
const createRenderBenchmark = ({ description, getElement, name, runs }) => () => {
const setup = () => {};
const teardown = () => {
ReactDOM.unmountComponentAtNode(node);
};
return benchmark({
name,
description,
runs,
setup,
teardown,
task: () => {
ReactDOM.render(getElement(), node);
}
});
};
export default createRenderBenchmark;

View File

@@ -0,0 +1,36 @@
import { type Component } from 'react';
import packageJson from '../package.json';
const context = require.context('./implementations/', true, /index\.js$/);
const { dependencies } = packageJson;
type ComponentsType = {
Box: Component,
Dot: Component,
Provider: Component,
View: Component
};
type ImplementationType = {
components: ComponentsType,
name: string,
version: string
};
const toImplementations = (context: Object): Array<ImplementationType> =>
context.keys().map(path => {
const components = context(path).default;
const name = path.split('/')[1];
const version = dependencies[name] || '';
return { components, name, version };
});
const toObject = (impls: Array<ImplementationType>): Object =>
impls.reduce((acc, impl) => {
acc[impl.name] = impl;
return acc;
}, {});
const map = toObject(toImplementations(context));
export default map;

View File

@@ -17,32 +17,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = StyleSheet.create({
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
});

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,7 +1,9 @@
import Box from './Box';
import Provider from './Provider';
import View from './View';
export default {
Box,
Provider,
View
};

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,4 +1,5 @@
.outer {
align-self: flex-start;
padding: 4px;
}
@@ -7,30 +8,30 @@
}
.color0 {
background-color: #222;
background-color: #14171A;
}
.color1 {
background-color: #666;
background-color: #AAB8C2;
}
.color2 {
background-color: #999;
background-color: #E6ECF0;
}
.color3 {
background-color: blue;
background-color: #FFAD1F;
}
.color4 {
background-color: orange;
background-color: #F45D22;
}
.color5 {
background-color: red;
background-color: #E0245E;
}
.fixed {
width: 20px;
height: 20px;
width: 6px;
height: 6px;
}

View File

@@ -1,7 +1,9 @@
import Box from './Box';
import Provider from './Provider';
import View from './View';
export default {
Box,
Provider,
View
};

View File

@@ -16,32 +16,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = {
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
};

View File

@@ -9,8 +9,8 @@ const Dot = ({ size, x, y, children, color }) => (
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
marginLeft: `${x}px`,
marginTop: `${y}px`
})}
>
{children}
@@ -25,7 +25,8 @@ const styles = {
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
}
};

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -16,32 +16,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = {
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
};

View File

@@ -9,8 +9,8 @@ const Dot = ({ size, x, y, children, color }) => (
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
marginLeft: `${x}px`,
marginTop: `${y}px`
})}
>
{children}
@@ -25,7 +25,8 @@ const styles = {
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
}
};

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -16,32 +16,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = {
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
};

View File

@@ -10,8 +10,8 @@ const Dot = ({ size, x, y, children, color }) => (
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
marginLeft: `${x}px`,
marginTop: `${y}px`
}
}}
>
@@ -27,7 +27,8 @@ const styles = {
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
}
};

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -17,32 +17,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = {
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
};

View File

@@ -11,8 +11,8 @@ const Dot = ({ size, x, y, children, color }) => (
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
marginLeft: `${x}px`,
marginTop: `${y}px`
}
]}
>
@@ -28,7 +28,8 @@ const styles = {
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
}
};

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -0,0 +1,46 @@
import { createComponent } from 'react-fela';
import View from './View';
const Box = createComponent(
({ color, fixed = false, layout = 'column', outer = false }) => ({
...styles[`color${color}`],
...(fixed && styles.fixed),
...(layout === 'row' && styles.row),
...(outer && styles.outer)
}),
View
);
const styles = {
outer: {
alignSelf: 'flex-start',
padding: '4px'
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: '#E0245E'
},
fixed: {
width: '6px',
height: '6px'
}
};
export default Box;

View File

@@ -0,0 +1,28 @@
/* eslint-disable react/prop-types */
import { createComponent } from 'react-fela';
const Dot = createComponent(
({ size, x, y, children, color }) => ({
...staticStyle,
borderBottomColor: color,
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
marginLeft: `${x}px`,
marginTop: `${y}px`
}),
'div'
);
const staticStyle = {
position: 'absolute',
cursor: 'pointer',
width: 0,
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
};
export default Dot;

View File

@@ -0,0 +1,19 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { createRenderer } from 'fela';
import { Provider as FelaProvider } from 'react-fela';
import View from './View';
const renderer = createRenderer();
class Provider extends React.Component {
render() {
return (
<FelaProvider renderer={renderer}>
<View>{this.props.children}</View>
</FelaProvider>
);
}
}
export default Provider;

View File

@@ -0,0 +1,24 @@
/* eslint-disable react/prop-types */
import { createComponent } from 'react-fela';
const View = createComponent(
() => ({
alignItems: 'stretch',
borderWidth: '0px',
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: '0',
margin: '0px',
padding: '0px',
position: 'relative',
// fix flexbox bugs
minHeight: '0px',
minWidth: '0px'
}),
'div'
);
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -18,32 +18,33 @@ const Box = ({ classes, color, fixed = false, layout = 'column', outer = false,
const styles = {
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
};

View File

@@ -0,0 +1,26 @@
/* eslint-disable react/prop-types */
import injectSheet from 'react-jss';
import React from 'react';
const Dot = ({ classes, children }) => <div className={classes.root}>{children}</div>;
const styles = {
root: {
position: 'absolute',
cursor: 'pointer',
width: 0,
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0,
transform: 'translate(50%, 50%)',
borderBottomColor: ({ color }) => color,
borderRightWidth: ({ size }) => size / 2,
borderBottomWidth: ({ size }) => size / 2,
borderLeftWidth: ({ size }) => size / 2,
marginLeft: ({ x }) => x,
marginTop: ({ y }) => y
}
};
export default injectSheet(styles)(Dot);

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,7 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -16,32 +16,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = StyleSheet.create({
outer: {
alignSelf: 'flex-start',
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: 'orange'
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: 'red'
backgroundColor: '#E0245E'
},
fixed: {
width: 20,
height: 20
width: 6,
height: 6
}
});

View File

@@ -11,8 +11,8 @@ const Dot = ({ size, x, y, children, color }) =>
borderRightWidth: size / 2,
borderBottomWidth: size / 2,
borderLeftWidth: size / 2,
left: x,
top: y
marginLeft: x,
marginTop: y
}
]
});
@@ -25,7 +25,8 @@ const styles = StyleSheet.create({
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: [{ translateX: '50%' }, { translateY: '50%' }]
}
});

View File

@@ -0,0 +1,2 @@
import { View } from 'react-native';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import { View } from 'react-native';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -16,32 +16,33 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
const styles = {
outer: Styles.createViewStyle({
alignSelf: 'flex-start',
padding: 4
}),
row: Styles.createViewStyle({
flexDirection: 'row'
}),
color0: Styles.createViewStyle({
backgroundColor: '#222'
backgroundColor: '#14171A'
}),
color1: Styles.createViewStyle({
backgroundColor: '#666'
backgroundColor: '#AAB8C2'
}),
color2: Styles.createViewStyle({
backgroundColor: '#999'
backgroundColor: '#E6ECF0'
}),
color3: Styles.createViewStyle({
backgroundColor: 'blue'
backgroundColor: '#FFAD1F'
}),
color4: Styles.createViewStyle({
backgroundColor: 'orange'
backgroundColor: '#F45D22'
}),
color5: Styles.createViewStyle({
backgroundColor: 'red'
backgroundColor: '#E0245E'
}),
fixed: Styles.createViewStyle({
width: 20,
height: 20
width: 6,
height: 6
})
};

View File

@@ -12,8 +12,8 @@ const Dot = ({ size, x, y, children, color }) => (
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
marginLeft: `${x}px`,
marginTop: `${y}px`
}
]}
/>
@@ -27,7 +27,8 @@ const styles = {
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
})
};

View File

@@ -0,0 +1,31 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { object } from 'prop-types';
import { View } from 'reactxp';
class Provider extends React.Component {
/* this mock context is necessary for reactxp to work without errors… ¯\_(ツ)_/¯ */
static childContextTypes = {
focusManager: object
};
getChildContext() {
return {
focusManager: {
addFocusableComponent() {},
removeFocusableComponent() {},
restrictFocusWithin() {},
removeFocusRestriction() {},
limitFocusWithin() {},
removeFocusLimitation() {}
}
};
}
render() {
return <View style={{ overflow: 'visible' }}>{this.props.children}</View>;
}
}
export default Provider;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import { View } from 'reactxp';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -4,28 +4,28 @@ import View from './View';
const getColor = color => {
switch (color) {
case 0:
return '#222';
return '#14171A';
case 1:
return '#666';
return '#AAB8C2';
case 2:
return '#999';
return '#E6ECF0';
case 3:
return 'blue';
return '#FFAD1F';
case 4:
return 'orange';
return '#F45D22';
case 5:
return 'red';
return '#E0245E';
default:
return 'transparent';
}
};
const Box = styled(View)`
align-self: flex-start;
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
padding: ${props => (props.outer ? '4px' : '0')};
height: ${props => (props.fixed ? '20px' : 'auto')};
width: ${props => (props.fixed ? '20px' : 'auto')};
background-color: ${props => getColor(props.color)};
${props => props.fixed && 'height:6px;'} ${props =>
props.fixed && 'width:6px;'} background-color: ${props => getColor(props.color)};
`;
export default Box;

View File

@@ -4,8 +4,8 @@ import View from './View';
const Dot = styled(View).attrs({
style: props => ({
left: `${props.x}px`,
top: `${props.y}px`,
marginLeft: `${props.x}px`,
marginTop: `${props.y}px`,
borderRightWidth: `${props.size / 2}px`,
borderBottomWidth: `${props.size / 2}px`,
borderLeftWidth: `${props.size / 2}px`,
@@ -19,6 +19,7 @@ const Dot = styled(View).attrs({
border-color: transparent;
border-style: solid;
border-top-width: 0;
transform: translate(50%, 50%);
`;
export default Dot;

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -1,9 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -0,0 +1,46 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import React from 'react';
import View from './View';
const getColor = color => {
switch (color) {
case 0:
return '#14171A';
case 1:
return '#AAB8C2';
case 2:
return '#E6ECF0';
case 3:
return '#FFAD1F';
case 4:
return '#F45D22';
case 5:
return '#E0245E';
default:
return 'transparent';
}
};
const Box = props => {
const { className, children: styles } = (
<scope className={classnames('Box', props.fixed && 'fixed')}>
<style jsx>{`
.Box {
align-self: flex-start;
flex-direction: ${props.layout === 'column' ? 'column' : 'row'};
padding: ${props.outer ? '4px' : '0'};
background-color: ${getColor(props.color)};
}
.fixed {
height: 6px;
width: 6px;
}
`}</style>
</scope>
).props;
return <View className={className}>{[props.children, styles]}</View>;
};
export default Box;

View File

@@ -0,0 +1,36 @@
/* eslint-disable react/prop-types */
import React from 'react';
import View from './View';
const Dot = props => {
const { className, children: styles } = (
<scope className="Dot">
<style jsx>{`
.Dot {
position: absolute;
cursor: pointer;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-top-width: 0;
transform: translate(50%, 50%);
}
`}</style>
<style jsx>{`
.Dot {
margin-left: ${props.x}px;
margin-top: ${props.y}px;
border-right-width: ${props.size / 2}px;
border-bottom-width: ${props.size / 2}px;
border-left-width: ${props.size / 2}px;
border-bottom-color: ${props.color};
}
`}</style>
</scope>
).props;
return <View className={className}>{[props.children, styles]}</View>;
};
export default Dot;

View File

@@ -0,0 +1,2 @@
import View from './View';
export default View;

View File

@@ -0,0 +1,32 @@
/* eslint-disable react/prop-types */
import React from 'react';
class View extends React.Component {
render() {
const { children, className, ...props } = this.props;
return (
<div {...props} className={`initial ${className}`}>
{children}
<style jsx>{`
.initial {
align-items: stretch;
border-width: 0;
border-style: solid;
box-sizing: border-box;
display: flex;
flex-basis: auto;
flex-direction: column;
flex-shrink: 0;
margin: 0;
padding: 0;
position: relative;
min-height: 0;
min-width: 0;
}
`}</style>
</div>
);
}
}
export default View;

View File

@@ -0,0 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -0,0 +1,47 @@
/* eslint-disable react/prop-types */
import { withStyle } from 'styletron-react';
import View from './View';
const Box = withStyle(
View,
({ color, fixed = false, layout = 'column', outer = false, ...other }) => ({
...styles[`color${color}`],
...(fixed && styles.fixed),
...(layout === 'row' && styles.row),
...(outer && styles.outer)
})
);
const styles = {
outer: {
alignSelf: 'flex-start',
padding: '4px'
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#14171A'
},
color1: {
backgroundColor: '#AAB8C2'
},
color2: {
backgroundColor: '#E6ECF0'
},
color3: {
backgroundColor: '#FFAD1F'
},
color4: {
backgroundColor: '#F45D22'
},
color5: {
backgroundColor: '#E0245E'
},
fixed: {
width: '6px',
height: '6px'
}
};
export default Box;

View File

@@ -0,0 +1,25 @@
/* eslint-disable react/prop-types */
import { styled } from 'styletron-react';
const Dot = styled('div', ({ size, x, y, children, color }) => ({
...staticStyle,
borderBottomColor: color,
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
marginLeft: `${x}px`,
marginTop: `${y}px`
}));
const staticStyle = {
position: 'absolute',
cursor: 'pointer',
width: 0,
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0,
transform: 'translate(50%, 50%)'
};
export default Dot;

View File

@@ -0,0 +1,19 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { Client as Styletron } from 'styletron-engine-atomic';
import { Provider as StyletronProvider } from 'styletron-react';
import View from './View';
const styletron = new Styletron();
class Provider extends React.Component {
render() {
return (
<StyletronProvider value={styletron}>
<View>{this.props.children}</View>
</StyletronProvider>
);
}
}
export default Provider;

View File

@@ -0,0 +1,26 @@
/* eslint-disable react/prop-types */
import { styled } from 'styletron-react';
const View = styled('div', ({ style }) => ({
...viewStyle,
style
}));
const viewStyle = {
alignItems: 'stretch',
borderWidth: '0px',
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: '0',
margin: '0px',
padding: '0px',
position: 'relative',
// fix flexbox bugs
minHeight: '0px',
minWidth: '0px'
};
export default View;

View File

@@ -0,0 +1,11 @@
import Box from './Box';
import Dot from './Dot';
import Provider from './Provider';
import View from './View';
export default {
Box,
Dot,
Provider,
View
};

View File

@@ -1,49 +0,0 @@
/* eslint-disable react/prop-types */
import { injectStylePrefixed } from 'styletron-utils';
import React from 'react';
import View, { styletron } from './View';
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
<View
{...other}
style={[
styles[`color${color}`],
fixed && styles.fixed,
layout === 'row' && styles.row,
outer && styles.outer
]}
/>
);
const styles = {
outer: injectStylePrefixed(styletron, {
padding: '4px'
}),
row: injectStylePrefixed(styletron, {
flexDirection: 'row'
}),
color0: injectStylePrefixed(styletron, {
backgroundColor: '#222'
}),
color1: injectStylePrefixed(styletron, {
backgroundColor: '#666'
}),
color2: injectStylePrefixed(styletron, {
backgroundColor: '#999'
}),
color3: injectStylePrefixed(styletron, {
backgroundColor: 'blue'
}),
color4: injectStylePrefixed(styletron, {
backgroundColor: 'orange'
}),
color5: injectStylePrefixed(styletron, {
backgroundColor: 'red'
}),
fixed: injectStylePrefixed(styletron, {
width: '20px',
height: '20px'
})
};
export default Box;

View File

@@ -1,37 +0,0 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import React from 'react';
import { injectStylePrefixed } from 'styletron-utils';
import { styletron } from './View';
const Dot = ({ size, x, y, children, color }) => (
<div
className={classnames(
styles.root,
injectStylePrefixed(styletron, {
borderBottomColor: color,
borderRightWidth: `${size / 2}px`,
borderBottomWidth: `${size / 2}px`,
borderLeftWidth: `${size / 2}px`,
left: `${x}px`,
top: `${y}px`
})
)}
>
{children}
</div>
);
const styles = {
root: injectStylePrefixed(styletron, {
position: 'absolute',
cursor: 'pointer',
width: 0,
height: 0,
borderColor: 'transparent',
borderStyle: 'solid',
borderTopWidth: 0
})
};
export default Dot;

View File

@@ -1,33 +0,0 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import Styletron from 'styletron-client';
import { injectStylePrefixed } from 'styletron-utils';
import React from 'react';
export const styletron = new Styletron();
class View extends React.Component {
render() {
const { style, ...other } = this.props;
return <div {...other} className={classnames(viewStyle, ...style)} />;
}
}
const viewStyle = injectStylePrefixed(styletron, {
alignItems: 'stretch',
borderWidth: '0px',
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: '0',
margin: '0px',
padding: '0px',
position: 'relative',
// fix flexbox bugs
minHeight: '0px',
minWidth: '0px'
});
export default View;

View File

@@ -1,97 +1,56 @@
import aphrodite from './implementations/aphrodite';
import cssModules from './implementations/css-modules';
import emotion from './implementations/emotion';
import jss from './implementations/jss';
import glamor from './implementations/glamor';
import inlineStyles from './implementations/inline-styles';
import radium from './implementations/radium';
import reactNativeWeb from './implementations/react-native-web';
import reactxp from './implementations/reactxp';
import styledComponents from './implementations/styled-components';
import styletron from './implementations/styletron';
import App from './app/App';
import impl from './impl';
import Tree from './cases/Tree';
import SierpinskiTriangle from './cases/SierpinskiTriangle';
import renderDeepTree from './cases/renderDeepTree';
import renderSierpinskiTriangle from './cases/renderSierpinskiTriangle';
import renderWideTree from './cases/renderWideTree';
import React from 'react';
import ReactDOM from 'react-dom';
const testMatrix = {
'inline-styles': [
() => renderDeepTree('inline-styles', inlineStyles),
() => renderWideTree('inline-styles', inlineStyles),
() => renderSierpinskiTriangle('inline-styles', inlineStyles)
],
'css-modules': [
() => renderDeepTree('css-modules', cssModules),
() => renderWideTree('css-modules', cssModules)
],
'react-native-web': [
() => renderDeepTree('react-native-web', reactNativeWeb),
() => renderWideTree('react-native-web', reactNativeWeb),
() => renderSierpinskiTriangle('react-native-web', reactNativeWeb)
],
const implementations = impl;
const packageNames = Object.keys(implementations);
aphrodite: [
() => renderDeepTree('aphrodite', aphrodite),
() => renderWideTree('aphrodite', aphrodite)
],
emotion: [
() => renderDeepTree('emotion', emotion),
() => renderWideTree('emotion', emotion),
() => renderSierpinskiTriangle('emotion', emotion)
],
glamor: [
() => renderDeepTree('glamor', glamor),
() => renderWideTree('glamor', glamor)
// disabled: glamor starts to lock up the browser
// () => renderSierpinskiTriangle('glamor', glamor)
],
jss: [() => renderDeepTree('jss', jss), () => renderWideTree('jss', jss)],
radium: [
() => renderDeepTree('radium', radium),
() => renderWideTree('radium', radium),
() => renderSierpinskiTriangle('radium', radium)
],
reactxp: [
() => renderDeepTree('reactxp', reactxp),
() => renderWideTree('reactxp', reactxp),
() => renderSierpinskiTriangle('reactxp', reactxp)
],
'styled-components': [
() => renderDeepTree('styled-components', styledComponents),
() => renderWideTree('styled-components', styledComponents),
() => renderSierpinskiTriangle('styled-components', styledComponents)
],
styletron: [
() => renderDeepTree('styletron', styletron),
() => renderWideTree('styletron', styletron),
() => renderSierpinskiTriangle('styletron', styletron)
]
const createTestBlock = fn => {
return packageNames.reduce((testSetups, packageName) => {
const { name, components, version } = implementations[packageName];
const { Component, getComponentProps, sampleCount, Provider, benchmarkType } = fn(components);
testSetups[packageName] = {
Component,
getComponentProps,
sampleCount,
Provider,
benchmarkType,
version,
name
};
return testSetups;
}, {});
};
const allTests = Object.keys(testMatrix).reduce((acc, curr) => {
testMatrix[curr].forEach(test => {
acc.push(test);
});
return acc;
}, []);
const tests = {
'Mount deep tree': createTestBlock(components => ({
benchmarkType: 'mount',
Component: Tree,
getComponentProps: () => ({ breadth: 2, components, depth: 7, id: 0, wrap: 1 }),
Provider: components.Provider,
sampleCount: 50
})),
'Mount wide tree': createTestBlock(components => ({
benchmarkType: 'mount',
Component: Tree,
getComponentProps: () => ({ breadth: 6, components, depth: 3, id: 0, wrap: 2 }),
Provider: components.Provider,
sampleCount: 50
})),
'Update dynamic styles': createTestBlock(components => ({
benchmarkType: 'update',
Component: SierpinskiTriangle,
getComponentProps: ({ cycle }) => {
return { components, s: 200, renderCount: cycle, x: 0, y: 0 };
},
Provider: components.Provider,
sampleCount: 100
}))
};
const tests = [];
if (window.location.search) {
window.location.search
.slice(1)
.split(',')
.forEach(implementation => {
if (Array.isArray(testMatrix[implementation])) {
tests.push(...testMatrix[implementation]);
} else {
throw new Error(`Benchmark for ${implementation} not found`);
}
});
} else {
tests.push(...allTests);
}
tests.push(() => () => Promise.resolve(console.log('Done')));
tests.reduce((promise, test) => promise.then(test()), Promise.resolve());
ReactDOM.render(<App tests={tests} />, document.querySelector('.root'));

View File

@@ -1,16 +1,16 @@
const babelPreset = require('../../scripts/babel/preset');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path');
const webpack = require('webpack');
const appDirectory = path.resolve(__dirname);
module.exports = {
mode: 'production',
context: __dirname,
entry: ['babel-polyfill', './src/index'],
entry: './src/index',
output: {
path: path.resolve(appDirectory, 'dist'),
filename: 'performance.bundle.js'
filename: 'bundle.js'
},
module: {
rules: [
@@ -30,9 +30,9 @@ module.exports = {
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheDirectory: false,
presets: babelPreset,
plugins: ['react-native-web']
plugins: ['styled-jsx/babel']
}
}
}
@@ -42,16 +42,6 @@ module.exports = {
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
dead_code: true,
screw_ie8: true,
warnings: false
}
})
],
resolve: {

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`enzyme.mount complex 1`] = `
exports[`enzyme complex: enzyme.mount complex 1`] = `
<Box
element={
<View>
@@ -26,7 +26,7 @@ exports[`enzyme.mount complex 1`] = `
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<Title>
<Text
@@ -39,7 +39,7 @@ exports[`enzyme.mount complex 1`] = `
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -48,7 +48,7 @@ exports[`enzyme.mount complex 1`] = `
</Title>
<View>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<View
style={
@@ -58,12 +58,12 @@ exports[`enzyme.mount complex 1`] = `
}
>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
<Text>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -76,85 +76,24 @@ exports[`enzyme.mount complex 1`] = `
</Box>
`;
exports[`enzyme.mount composite 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
</Box>
`;
exports[`enzyme.mount nested 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<Title>
<Text
style={
Object {
"color": "black",
"fontSize": 16,
"textAlignVertical": "center",
}
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</Text>
</Title>
</div>
</View>
</Box>
`;
exports[`enzyme.mount noop 1`] = `
<View>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
`;
exports[`enzyme.render complex 1`] = `
exports[`enzyme complex: enzyme.render complex 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -163,32 +102,7 @@ exports[`enzyme.render complex 1`] = `
</div>
`;
exports[`enzyme.render composite 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme.render nested 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</div>
`;
exports[`enzyme.render noop 1`] = `
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme.shallow complex 1`] = `
exports[`enzyme complex: enzyme.shallow complex 1`] = `
<View
style={
Object {
@@ -215,7 +129,30 @@ exports[`enzyme.shallow complex 1`] = `
</View>
`;
exports[`enzyme.shallow composite 1`] = `
exports[`enzyme composite: enzyme.mount composite 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
</Box>
`;
exports[`enzyme composite: enzyme.render composite 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme composite: enzyme.shallow composite 1`] = `
<View
style={
Object {
@@ -226,7 +163,56 @@ exports[`enzyme.shallow composite 1`] = `
/>
`;
exports[`enzyme.shallow nested 1`] = `
exports[`enzyme nested: enzyme.mount nested 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<Title>
<Text
style={
Object {
"color": "black",
"fontSize": 16,
"textAlignVertical": "center",
}
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</Text>
</Title>
</div>
</View>
</Box>
`;
exports[`enzyme nested: enzyme.render nested 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</div>
`;
exports[`enzyme nested: enzyme.shallow nested 1`] = `
<View
style={
Object {
@@ -241,30 +227,44 @@ exports[`enzyme.shallow nested 1`] = `
</View>
`;
exports[`enzyme.shallow noop 1`] = `
exports[`enzyme noop: enzyme.mount noop 1`] = `
<View>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
`;
exports[`enzyme noop: enzyme.render noop 1`] = `
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme noop: enzyme.shallow noop 1`] = `
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`react-test-renderer complex 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -275,16 +275,16 @@ exports[`react-test-renderer complex 1`] = `
exports[`react-test-renderer composite 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`react-test-renderer nested 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-fontStyle-o11vmf rn-fontVariant-ebii48 rn-fontWeight-gul640 rn-lineHeight-t9a87b rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -294,6 +294,6 @@ exports[`react-test-renderer nested 1`] = `
exports[`react-test-renderer noop 1`] = `
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;

Some files were not shown because too many files have changed in this diff Show More