Compare commits

...

601 Commits

Author SHA1 Message Date
Nicolas Gallagher
03769f7d45 0.0.93 2017-04-29 19:53:45 -07:00
Nicolas Gallagher
eb43a8f3e7 [fix] setNativeProps with RTL layout
Ensure that 'setNativeProps' doesn't try to i18n flip styles that have
already been flipped. This is hacked into the current design.
Registering both RTL and LTR styles is not implemented yet either.
2017-04-29 19:49:59 -07:00
Nicolas Gallagher
cdf13b880d Reorganize 'createReactDOMStyle'
1. Rename 'expandStyle' to 'createReactDOMStyle'
2. Move use of 'i18nStyle' out of 'createReactDOMStyle' to decouple the
   two transformations.
3. Move the style property resolvers into 'createReactDOMStyle'
2017-04-29 19:03:48 -07:00
Nicolas Gallagher
47fad1ef58 [fix] setNativeProps 2017-04-29 18:58:15 -07:00
Nicolas Gallagher
5f69c8e8b8 0.0.92 2017-04-29 12:19:16 -07:00
Nicolas Gallagher
21550db5f2 [fix] stop propagation of ScrollView 'onScroll' event
Fix #440
2017-04-29 12:15:19 -07:00
Nicolas Gallagher
1cae5d55a1 [fix] setNativeProps DOM style copying
The 'style' object of an HTML node is a 'CSSStyleDeclaration'. Use the
'CSSStyleDeclaration' API to copy the inline styles, rather than
treating it like a plain object. This avoids errors that were resulting
from indices and property names being used a key-value pairs in the
resulting style copy.

Fix #460
Ref #454
2017-04-29 11:09:43 -07:00
Nicolas Gallagher
11d23f850a 0.0.91 2017-04-28 15:40:12 -07:00
Nicolas Gallagher
d994a25017 0.0.90 2017-04-28 15:17:44 -07:00
Nicolas Gallagher
756df70154 [fix] check 'transform' style is array before mapping 2017-04-28 15:15:57 -07:00
Nicolas Gallagher
f0b06419f9 Move prefixStyles module 2017-04-27 16:27:45 -07:00
Nicolas Gallagher
60ff75705e [fix] remove stray 'length' property from style object
Fix #454
2017-04-27 15:10:03 -07:00
Nicolas Gallagher
5e8ad67296 0.0.89 2017-04-26 15:12:19 -07:00
Nathan Broadbent
ba24a882be Link to another starter kit example 2017-04-26 15:11:16 -07:00
Nicolas Gallagher
c7686209cd Update prettier 2017-04-26 15:07:44 -07:00
Nicolas Gallagher
f1b281ae32 Update debounce dependency 2017-04-26 15:06:41 -07:00
Nicolas Gallagher
b676fbd5e0 [fix] propTypes removal in production builds
Updates the relevant babel plugin, which now replaces component
propTypes with an empty object, avoiding the majority of potential
runtime errors related to this transform.

Fix #423
2017-04-26 11:05:33 -07:00
Nicolas Gallagher
51aef6c791 0.0.88 2017-04-24 13:28:38 -07:00
Nathan Leung
ae9a9cde5f Fix example webpack config in documentation 2017-04-24 13:21:46 -07:00
Nicolas Gallagher
beb907b180 Rename some variables in StyleRegistry 2017-04-24 13:21:27 -07:00
Nicolas Gallagher
a3362e1f38 [fix] setNativeProps inline styles
Inline styles are preserved when using 'setNativeProps'. Adds unit tests
for the resolution logic required by 'setNativeProps'/'resolveStateful'
in a DOM context.

Fix #439
2017-04-23 21:24:27 -07:00
Nicolas Gallagher
64d2d34367 0.0.87 2017-04-23 13:39:27 -07:00
Nicolas Gallagher
d83cd45b6f [fix] Clipboard browser support
Safari 10.3 supports copying (but apparently not from inputs)
2017-04-23 13:38:51 -07:00
Nicolas Gallagher
227971d22c [add] support for CSS grid properties (experimental)
Allow people to experiment with using CSS grid in react-native. (No
support for shorthand properties.)
2017-04-22 10:34:43 -07:00
Nicolas Gallagher
4822cf4620 [add] support for 'clip' and 'textIndent' styles 2017-04-22 10:06:27 -07:00
Nathan Broadbent
91e4528eac Allow filter property in CSS 2017-04-22 22:56:07 +07:00
Nicolas Gallagher
1ee64d8285 0.0.86 2017-04-21 19:04:23 -07:00
Nicolas Gallagher
66a4c13bf3 [fix] AppState.isSupported -> AppState.isAvailable
React Native exposes AppState support via 'isAvailable'.
2017-04-21 18:47:29 -07:00
Nicolas Gallagher
9012e98ba7 [fix] support 'mailto:' URLs in 'Linking' 2017-04-21 18:29:29 -07:00
Nicolas Gallagher
046e01dfa9 [fix] add AsyncStorage callbacks and tests
Add support for the callback interface and add test coverage.

Fix #399
Close #400
2017-04-21 18:13:14 -07:00
Nicolas Gallagher
6e71e1e058 [fix] attempt to avoid need for 'Array.from' polyfill
Fix #409
2017-04-20 18:04:09 -07:00
Nicolas Gallagher
d5a9f3e779 Add ES module export
Preparation for publishing an ES module build.
Move 'modality' into 'createDOMElement' to ensure it is always initialized.
2017-04-20 17:16:05 -07:00
Nicolas Gallagher
f16f5f21ce [add] WebkitMaskImage style prop
Undocumented supported. Commonly used in border-radius hacks.

Close #326
2017-04-20 15:12:07 -07:00
Nicolas Gallagher
0bb7e67e63 0.0.85 2017-04-20 15:07:56 -07:00
Nicolas Gallagher
c6b54930b6 [add] StatusBar stub component
Fix #425
2017-04-20 15:07:34 -07:00
Nicolas Gallagher
599f1fcaf5 Filter unsupported TextInput props
Fix #385
2017-04-20 14:58:48 -07:00
Nicolas Gallagher
3f7a4e455f [add] support 'outlineColor' style prop
Fix #435
2017-04-20 14:50:14 -07:00
Nicolas Gallagher
1f3e9cc6ee [change] ScrollView as new surface
Fix #405
2017-04-20 13:36:00 -07:00
Nicolas Gallagher
17ed63129f Add a note about accessibilityRole compat 2017-04-20 10:39:34 -07:00
Nicolas Gallagher
769334d04e Update benchmark results 2017-04-20 10:04:33 -07:00
Nicolas Gallagher
dad80d5718 0.0.84 2017-04-20 10:00:49 -07:00
Nicolas Gallagher
d8e93058da Fix publish step 2017-04-20 10:00:39 -07:00
Nicolas Gallagher
4ae894313f Add 'styletron' to benchmarks 2017-04-20 09:16:02 -07:00
Nicolas Gallagher
438f398022 Standardize styles for benchmark View implementations 2017-04-20 09:14:41 -07:00
Nicolas Gallagher
630ee24fdd 0.0.83 2017-04-19 16:53:15 -07:00
Nicolas Gallagher
ae13873c2c [change] move 'a', 'button', 'ul' style resets to createDOMProps
Custom styles resets for the 'a', 'button', and 'ul' DOM elements are
now conditionally applied by 'createDOMProps'. This reduces the number
of classes on most Views and ensures that 'createDOMElement' (not just
'View' or 'Text') generates views with their styles reset.
2017-04-19 16:41:07 -07:00
Nicolas Gallagher
7705f521c8 [change] new accessibility features and docs
* Change 'accessible' to align with React Native.
* Add support for 'importantForAccessibility'.
* Stop event propagation for keyboard-activated Touchables (nested
  Touchables now respond the same as when touch-activated).
* Fix whitespace layout of nested Text elements.
* Use 'div' for Text to improve TalkBack grouping.
* Rewrite accessibility docs.

Close #382
Fix #408
2017-04-19 16:41:01 -07:00
Nicolas Gallagher
cbd98a8bd7 [fix] accessibilityLiveRegion values 2017-04-18 21:11:34 -07:00
Nicolas Gallagher
1f80e4c105 [change] render Image 'source' immediately if previously loaded
Maintain a record of loaded images. If an image has already been loaded,
bypass the JS loading logic and render it immediately. This prevents
flashes of placeholder state when moving between screens or items in a
virtualized list.
2017-04-18 20:50:48 -07:00
Nicolas Gallagher
dbc8f31be6 Update benchmark dependencies 2017-04-18 14:59:00 -07:00
Nicolas Gallagher
ed994dc670 Update 'getting-started' docs 2017-04-15 09:12:08 -07:00
Joe Cortopassi
a57e58607a Change to using 'prepare' npm-script
Avoids excessive rebuilding of modules during development tasks

Close #429
2017-04-14 13:34:24 -07:00
Nicolas Gallagher
03ea259d70 Update documentation
Close #417
2017-04-14 09:03:38 -07:00
Nicolas Gallagher
e39b58fd04 Update LayoutPropTypes
* Consolidates certain style props under LayoutPropTypes.
* Adds 'direction' style prop.
* Adds 'scroll' to 'overflow' style prop.
* Filter out 'aspectRatio' for now.

Ref #420
2017-04-14 08:28:06 -07:00
Nicolas Gallagher
ab45211401 [change] remove TextInput autogrow behaviour
This is non-standard. Removes 'maxNumberOfLines' too.

Ref #287
2017-04-13 20:46:28 -07:00
Nicolas Gallagher
32183bb92a Update performance dependencies 2017-04-13 20:37:08 -07:00
Nicolas Gallagher
761c42301d Update prettier 2017-04-13 19:26:01 -07:00
Nicolas Gallagher
0863894f40 [change] make react-dom a peer dependency 2017-04-13 19:24:43 -07:00
Nicolas Gallagher
8f736ddefe Update enzyme and don't use react-test-renderer 2017-04-13 19:22:47 -07:00
Nicolas Gallagher
ab686e2a07 Update webpack 2017-04-13 18:30:37 -07:00
Nicolas Gallagher
2c14bdab2e Update inline-style-prefixer 2017-04-13 17:33:54 -07:00
Nicolas Gallagher
0b8b064757 Update babel packages 2017-04-13 17:32:37 -07:00
Nicolas Gallagher
93eadb734b Update eslint plugins 2017-04-13 17:24:57 -07:00
Nicolas Gallagher
8d561d7309 Update prettier and eslint 2017-04-13 17:18:54 -07:00
Nicolas Gallagher
cdca9e1e2b Update 'modality' implementation 2017-04-13 15:57:58 -07:00
Nicolas Gallagher
170bab659d [change] use 'prop-types' and 'create-react-class'
Preparation for React 15.5
2017-04-11 22:20:39 -07:00
Nicolas Gallagher
941c628445 Remove dependency on most react-dom internals 2017-04-09 19:20:08 -07:00
Nicolas Gallagher
547c375bd6 Add more comparative benchmarks
Add "aphrodite", "react-jss", and "reactxp" renderers.

"react-addons-perf" is required due to:
https://github.com/Microsoft/reactxp/issues/11
2017-04-08 18:52:15 -07:00
Sunil Pai
aa85876eb2 Improve performance of glamor benchmark renderer 2017-04-08 18:48:16 -07:00
Nicolas Gallagher
50b168cc41 Add note about Safari flexbox performance 2017-04-05 14:48:11 -07:00
Nicolas Gallagher
25a11e673d 0.0.81 2017-04-05 14:03:07 -07:00
Nicolas Gallagher
e846054f4e Add 'Tweet' to performance benchmarks 2017-04-05 14:02:17 -07:00
Nicolas Gallagher
d6854abd7d [fix] accessibilityLiveRegion values 2017-04-02 16:16:41 -07:00
Nicolas Gallagher
1b172319b9 [change] use 'aria-level' to determine DOM heading tag
Fix #401
Close #402
2017-03-30 09:25:13 -07:00
Nicolas Gallagher
e81394c26e Add 'platform' benchmark
The "platform" benchmark relies on no intermediate layer. All the static
CSS it requires is inlined in the HTML page.
2017-03-25 09:11:23 -07:00
Nicolas Gallagher
d33aa3eee2 [change] Touchable no default 'accessibilityRole' 2017-03-23 15:42:20 -07:00
Nicolas Gallagher
5d78c73e8c [add] export 'ViewPropTypes'
See https://github.com/reactjs/react-codemod/pull/99
2017-03-23 12:06:24 -07:00
Nicolas Gallagher
7735d304ef [fix] export 'processColor' 2017-03-23 11:57:14 -07:00
Nicolas Gallagher
b7c72308ea 0.0.80 2017-03-22 23:43:37 -07:00
Nicolas Gallagher
5fee075774 Add 'processColor' tests 2017-03-22 23:40:40 -07:00
Nicolas Gallagher
25204eeff0 [fix] convert color values to CSS color
Convert all hex and numeric colors to rgba. Assume non-hex strings are
valid CSS colors.
2017-03-22 23:15:42 -07:00
Nicolas Gallagher
9c61fe58d3 [add] View 'hitSlop' shim
Shim the 'hitSlop' prop using a positioned element to extend the size of
a View's touch target without changing layout. Unlike the native
implementation, the touch target may extend past the parent view bounds.
2017-03-22 23:01:53 -07:00
Nicolas Gallagher
782125d169 Remove pointerEvents code from View 2017-03-20 22:53:57 -07:00
Nicolas Gallagher
af805d67e6 0.0.79 2017-03-20 22:42:00 -07:00
Nicolas Gallagher
68068f8cb6 [fix] support React Native props in 'setNativeProps'
React Native allows props like 'pointerEvents' to be set using
'setNativeProps'.

Fix #392
2017-03-20 22:33:59 -07:00
Nicolas Gallagher
e05e2122d7 [fix] avoid setting empty style objects 2017-03-20 22:33:59 -07:00
Nicolas Gallagher
47dac44120 [fix] filter 'lineBreakMode' from Text props 2017-03-20 22:33:53 -07:00
Nicolas Gallagher
22af6894c2 Update jest 2017-03-20 22:18:50 -07:00
Nicolas Gallagher
458c534200 [change] improve button accessibility and styling
1. If no 'accessibilityRole' is set, fallback to looking for 'button'
role in the equivalent native props. This helps improve accessibility of
button-like components authored without the web platform in mind.

2. Ensure button context is properly inherited.

3. Add 'appearance:none' to DOM button elements to enable better styling
support in Safari

Fix #378
2017-03-20 14:50:01 -07:00
Nicolas Gallagher
ec2db3e2a3 0.0.78 2017-03-19 18:45:21 -07:00
Bruno Lemos
e6f00f7592 [add] default option for Platform.select
See: f30ab35e92
2017-03-19 15:27:07 -07:00
Nicolas Gallagher
976320916e [change] move bridge code into createDOMElement
Moves event normalization and the ResponderEventPlugin injection from
'View' to 'createDOMElement'.

The 'react-native-web/lite' variant is removed from the performance
directory as the implementation is not substantially different.
Micro-optimizations to marginally narrow the performance gap to
css-modules.
2017-03-19 15:19:26 -07:00
Nicolas Gallagher
808790505e [change] onLayout improvements
1. Fires when window resizes
2. Guards against nodes being unmounted

Fix #397
Ref #60
2017-03-19 13:29:47 -07:00
Nicolas Gallagher
89ad493ce5 Update benchmark results 2017-03-14 17:23:16 -07:00
Nicolas Gallagher
c4f2869ad8 0.0.77 2017-03-09 18:20:07 -08:00
Nicolas Gallagher
3ae1e5b786 [fix] don't run 'modality' without a DOM
Fix #387
2017-03-09 18:13:00 -08:00
Nicolas Gallagher
e929fb572d [change] add 'testID' prop to 'Button'
Close #386
2017-03-09 18:09:27 -08:00
Nicolas Gallagher
5af9d537c2 Fix stylesheet snapshots 2017-03-06 12:56:50 -08:00
Nicolas Gallagher
b7d3f0d099 0.0.76 2017-03-06 12:31:41 -08:00
Nicolas Gallagher
f1ca00a13a [fix] ProgressBar animation styles
Fix #384
2017-03-06 12:30:34 -08:00
Aaron Craig
9451c0f85e [fix] avoid passing ListView props to ScrollView
The 'onChangeVisibleRows' and 'onEndReachedThreshold' props should not
be passed to 'ScrollView', as it results in React warnings about unknown
props on the underlying DOM node.

Close #383
2017-03-05 09:21:10 -08:00
Nicolas Gallagher
b408bc5537 Use a package for style name hyphenation
The 'hyphenate-style-name' packages is already a dependency of
'inline-style-prefixer', so we don't need our own implementation.
2017-03-02 19:10:05 -08:00
Nicolas Gallagher
a2f25a46c4 Reformat 'performance' and 'src' code 2017-03-02 18:59:33 -08:00
Nicolas Gallagher
29d52f5b31 Remove formatting rules from eslint config 2017-03-02 18:59:32 -08:00
Nicolas Gallagher
ba6be1f64a Install prettier code formatter 2017-03-02 18:59:32 -08:00
Nicolas Gallagher
43f78828a5 Update benchmarks to use styled-components@2.0.0-5
No significant change in the benchmark results
2017-03-02 18:57:57 -08:00
Nicolas Gallagher
26bc8173f0 0.0.75 2017-02-27 23:11:30 -08:00
Nicolas Gallagher
ecae52ccc5 [change] Touchable pass through props
Add support for web-specific props to improve accessibility, e.g., ARIA
properties (and declarative links).

Fix #65
2017-02-27 17:05:38 -08:00
Nicolas Gallagher
997653863f [fix] ignore unsupported style prop types
Fix #347
Close #371
2017-02-27 16:40:54 -08:00
Nicolas Gallagher
5dc692719f Update snapshots after StyleSheet refactor 2017-02-27 15:59:18 -08:00
Nicolas Gallagher
0361845537 [change] StyleSheet refactor
* HTML class names are now hashes of the corresponding declaration
* Simplifies 'setNativeProps' logic
* Fixes use of server-rendered style sheet
* Fixes duplicate insertion of style sheets with hot-reloading

No significant change to the benchmark results
2017-02-27 15:59:18 -08:00
Nicolas Gallagher
f391031fb1 0.0.74 2017-02-27 14:55:34 -08:00
Matthias Le Brun
77799abf9b [fix] Touchable support for 'Enter' keypress event
Close #375
2017-02-27 14:53:27 -08:00
Nicolas Gallagher
2cfd09ecdb [fix] server-side rendering
e1fc253 added deferred image loading but didn't guard the
'requestIdleFallback' shim for use in Node.js

Fix #376
2017-02-27 14:50:29 -08:00
Nicolas Gallagher
89eea2b366 Remove unused style in 'View' 2017-02-27 14:41:47 -08:00
Nicolas Gallagher
18440158b3 Add comparative performance benchmarks
Includes a 'css-modules' implementation of the nested trees to act as a
baseline for comparison.
2017-02-26 17:19:43 -08:00
Nicolas Gallagher
24eda7c4ad 0.0.73 2017-02-24 12:35:18 -08:00
Nicolas Gallagher
44ebd8f5a3 [change] modality-specific focus styles
Remove the default focus ring when the keyboard is not being used. This
provides a superior UX when using touch or mouse.

Fix #310
2017-02-18 13:39:25 -08:00
Matthias Le Brun
a3ed8f05e6 [add] resize 'TextInput' style
Fix #363
2017-02-18 12:49:25 -08:00
Nicolas Gallagher
b653fe0bd3 [add] fontFeatureSettings 'Text' style
Fix #331
2017-02-18 12:18:28 -08:00
Nicolas Gallagher
30da226e4d Update component style docs 2017-02-18 12:07:30 -08:00
Nicolas Gallagher
f1f39bfabd 0.0.72 2017-02-18 11:34:33 -08:00
Nicolas Gallagher
267c5aab7e Allow benchmark to run in Safari
Performing teardown in a new frame was causing Safari to hang on the 2nd
benchmark run.
2017-02-18 11:34:33 -08:00
Nicolas Gallagher
fe71c7efe5 [fix] Image browser context menu
Fix #368
2017-02-18 11:34:28 -08:00
Nicolas Gallagher
eb59875bed [change] defer Image loading
x4 faster render benchmark
2017-02-18 09:46:10 -08:00
Nicolas Gallagher
e1fc253277 Add image benchmark 2017-02-18 09:46:10 -08:00
Nicolas Gallagher
40b03aca52 [change] improve 'View' render performance
1. Register the 'pointerEvents' styles to enable memoization
2. Don't flatten styles in render; move flex reset to 'expandStyle'

Reduces benchmark render times by ~10% on early 2011 MacBook Pro
2017-02-18 09:46:04 -08:00
Nicolas Gallagher
418a1a9516 [change] depend on animated@0.2.0 2017-02-17 13:28:51 -08:00
Nicolas Gallagher
8762f8e9c8 [change] depend on inline-style-prefixer@3.0.0 2017-02-17 13:28:49 -08:00
Nicolas Gallagher
10ef2bfe20 [fix] i18n styles
1. Fix auto-flipping of styles

The StyleRegistry didn't account for LTR/RTL when caching the results of
style resolution. The 'writingDirection' style is no longer flipped; no
clear use case for it.

2. Remove experimental '$noI18n' style prop suffix

This feature is essentially unused, and less likely to be used with the
introduction of 'dir=auto' on 'Text'. Removing also marginally improves
render performance.
2017-02-17 13:25:54 -08:00
Nicolas Gallagher
6d2ae4597e Update babel packages 2017-02-17 12:04:30 -08:00
Nicolas Gallagher
a34b8b149f [fix] V8 deopt in compiled 'createDOMElement'
Fixes V8 "deopt" warning: "Bad value context for arguments value".

This deopt was caused by the babel-compiled output of the ES6 argument
default value for 'rnProps':

    var t = arguments.length > 1 && void 0 !== arguments[1]
      ? arguments[1]
      : l

Not relying on ES6 default arguments avoids the function 'deopt'.
2017-02-17 10:23:59 -08:00
Nicolas Gallagher
6166024d15 [fix] NODE_ENV check in 'flattenStyle' 2017-02-17 09:59:56 -08:00
Nicolas Gallagher
701ecb7c52 0.0.71 2017-02-17 08:54:33 -08:00
Li Hau Tan
75042093c2 [fix] add 'State' static to 'TextInput'
Fix #365
Close #366
2017-02-17 08:51:22 -08:00
Nathan Tran
bb417900a9 [add] willChange style prop type
Close #367
2017-02-17 08:44:12 -08:00
Nicolas Gallagher
89e0a15d1b [fix] add 'timeStamp' to scroll and layout events 2017-02-16 08:18:56 -08:00
Nicolas Gallagher
b2e0a3702f [fix] Linking methods return promises 2017-02-11 14:13:25 -08:00
Rodrigo Moyle
a4644c204d [fix] add shadow style props to Image styles
Fix #357
Close #358
2017-02-11 11:21:45 -08:00
Nicolas Gallagher
1e9536b611 0.0.70 2017-02-06 17:15:43 -08:00
Nicolas Gallagher
d15dafc108 Build UMD bundle from source 2017-02-06 13:14:48 -08:00
Nicolas Gallagher
c9c1aab97e Rearrange propType imports 2017-02-05 16:50:06 -08:00
Nicolas Gallagher
a2903f9d30 Move TextPropTypes to TextStylePropTypes 2017-02-05 16:37:54 -08:00
Nicolas Gallagher
c7771ac64f [change] avoid 'react-dom/lib/*' where possible 2017-02-05 16:36:26 -08:00
Nicolas Gallagher
c8129c2a99 Remove NODE_ENV wrappers 2017-02-05 16:35:04 -08:00
Matthias Le Brun
b793737393 [fix] onLayout calculation
The 0.0.69 release introduced a regression in UIManager's measurement
calculations.

Using `offset` properties returns the offset relative to the closest
positioned ancestor. Make `getRect` iterate over the ancestor chain.

Fix #341
Close #345
2017-02-05 12:09:42 -08:00
Nicolas Gallagher
2a4d1c81d8 0.0.69 2017-01-28 11:01:23 -08:00
Nicolas Gallagher
a8a25d66ea [fix] measure CSS layout independent of transforms
Fix #332
2017-01-28 10:37:49 -08:00
Gethin Webster
e06d7a9650 [fix] Prevent props warnings from ScrollView in ListView 2017-01-28 10:01:16 -08:00
Nicolas Gallagher
c2501f2bc2 Add documentation for webpack@2 *.web.js resolving
Fix #334
2017-01-28 09:57:14 -08:00
Nicolas Gallagher
c51e7f1965 [fix] Linking method names
Fix #339
2017-01-28 09:50:15 -08:00
Nicolas Gallagher
dfff6b3780 [fix] StyleSheet resolving for 'number' style 2017-01-16 14:36:20 -08:00
Nicolas Gallagher
5f6b4a746a Update webpack-bundler-analyzer 2017-01-13 13:21:23 -08:00
Nicolas Gallagher
f077907dd4 Fix AppRegistry/renderApplication snapshot 2017-01-11 13:15:07 -08:00
Nicolas Gallagher
a94367bdcb 0.0.68 2017-01-11 13:12:25 -08:00
Nicolas Gallagher
65febbbc52 [fix] error in setNativeProps when no style
Close #325
Close #327
2017-01-11 13:08:10 -08:00
Nicolas Gallagher
b14d2e5bd8 [fix] CSS pointer event selectors 2017-01-11 12:47:24 -08:00
Nicolas Gallagher
7c83ba162d 0.0.67 2017-01-08 18:40:02 -08:00
Nicolas Gallagher
3ffc005a7b [fix] setNativeProps resolving logic
Since styles are set using both class names and inline styles,
'setNativeProps' needs an additional resolving step that accounts for
the pre-existing state of RN-managed styles on the DOM node.

Fix #321
2017-01-08 18:25:39 -08:00
Nicolas Gallagher
50a70ad02f 0.0.66 2017-01-07 19:05:54 -08:00
Nicolas Gallagher
768e895701 [fix] View transforms; add perspective styles
Fixes a regression introduced by
5db300df35

The `perspective` function is distinct from the `perspective` property.
This patch reverts the regression and adds support for `perspective`,
`perspectiveOrigin`, and `transformOrigin`.

Fix #208
2017-01-07 19:02:57 -08:00
Nicolas Gallagher
af5fde994d Fix yarn.lock 2017-01-07 18:25:54 -08:00
Paul Le Cam
c3d0763944 [fix] ListView imports and 'getRowAndSectionCount'
Close #316
2017-01-07 18:22:47 -08:00
Nicolas Gallagher
0aba506725 Fix UIManager tests 2017-01-07 18:18:56 -08:00
Nicolas Gallagher
91032d8565 [change] allow 'display' in ViewStylePropTypes
Fix #296
2017-01-07 18:15:16 -08:00
Nicolas Gallagher
0696721488 Document transition and animation View styles 2017-01-07 18:12:26 -08:00
Nicolas Gallagher
fe18830ce6 [change] use classList in UIManager
Prevent setting the same class multiple times
2017-01-07 18:03:51 -08:00
Nicolas Gallagher
1b86d02300 [change] wrap layout measurement in 'asap' 2017-01-07 18:03:03 -08:00
Nicolas Gallagher
c56b472258 [change] depend on normalize-css-color
Fix #308
2017-01-07 18:00:17 -08:00
Nicolas Gallagher
b00132f007 [fix] TouchableOpacity transition duration 2017-01-07 17:50:59 -08:00
Nicolas Gallagher
8b8f8f0374 [fix] CSS properties that support unitless numbers 2017-01-05 14:47:10 -08:00
Nicolas Gallagher
8e94af34e1 Remove use of 'keyOf' 2017-01-05 14:47:10 -08:00
Nicolas Gallagher
7ffaf592d5 [fix] Text automatic writing direction detection 2017-01-05 14:47:08 -08:00
Nicolas Gallagher
a1017fa785 0.0.65 2017-01-04 18:25:39 -08:00
Nicolas Gallagher
5db300df35 [fix] transform perspective resolution 2017-01-04 18:04:15 -08:00
Nicolas Gallagher
214d862e61 [add] ScrollView to Animated 2017-01-04 18:04:05 -08:00
Nicolas Gallagher
4ef5453b33 0.0.64 2017-01-04 10:58:15 -08:00
Nicolas Gallagher
a27671d7cf [fix] passing on RN style props in createDOMElement
The 'createDOMElement' function wasn't pulling 'style' out of the
props. A change to the logic that sets DOM props meant that if
'StyleRegistry.resolve' didn't return a 'style' object, the React Native
styles would be passed through to the underlying DOM node.

Fix #315
2017-01-04 10:43:19 -08:00
Nicolas Gallagher
8d2a650670 [fix] StyleSheet selector escaping
Values that contain '*' (e.g. 'calc(2 * 2)') were not properly escaped,
resulting in broken selectors.
2017-01-03 14:25:39 -08:00
Nicolas Gallagher
4cc1c983e8 0.0.63 2017-01-02 23:44:10 -08:00
Nicolas Gallagher
37413fd55f Update Text snapshot 2017-01-02 23:43:39 -08:00
Nicolas Gallagher
07ff0ea104 Use setNativeProps to update ProgressBar 2017-01-02 23:28:14 -08:00
Nicolas Gallagher
1a87657500 [fix] Switch thumb positioning 2017-01-02 23:25:15 -08:00
Nicolas Gallagher
5e4c8e520a [fix] StyleSheet registry key check 2017-01-02 23:24:24 -08:00
Nicolas Gallagher
236121e32c Add unregistered styles benchmark 2017-01-02 22:46:38 -08:00
Nicolas Gallagher
39c76ca50c Minor StyleSheet/injector refactor; small fixes 2017-01-02 15:07:05 -08:00
Nicolas Gallagher
e65f91d849 [change] simplify CSS generation 2017-01-02 13:15:38 -08:00
Nicolas Gallagher
a535c558d8 [change] Move 'onResponderRelease' cancel to 'Touchable'
Moves a fix for double-firing Touchables into 'Touchable'
2017-01-02 13:12:13 -08:00
Nicolas Gallagher
a74be91b7c Minor documentation changes 2017-01-02 11:27:46 -08:00
Nicolas Gallagher
8eaaf28a32 0.0.62 2017-01-01 20:45:45 -08:00
Nicolas Gallagher
16d448dc5b Update various dependencies 2017-01-01 20:45:14 -08:00
Nicolas Gallagher
ea75cced13 [change] ProgressBar using CSS animations
Fix #299
2017-01-01 20:22:42 -08:00
Nicolas Gallagher
cfc56a1354 [change] ActivityIndicator using CSS animations
Ref #299
2017-01-01 19:48:50 -08:00
Nicolas Gallagher
b1cd92a65d [change] update Animated
Fix #309
2017-01-01 18:35:18 -08:00
Nicolas Gallagher
d87f71ebc1 [change] StyleSheet performance rewrite
Improves StyleSheet benchmark performance by 13x. Removes undocumented
`StyleSheet.resolve` API.

Typical mean (and first) task duration.

[benchmark] DeepTree: depth=3, breadth=10, wrap=4)
  -master  2809.76ms (3117.64ms)
  -patch     211.2ms  (364.28ms)

[benchmark] DeepTree: depth=5, breadth=3, wrap=1)
  -master   421.25ms (428.15ms)
  -patch     32.46ms  (47.36ms)

This patch adds memoization of DOM prop resolution (~3-4x faster), and
re-introduces a `className`-based styling strategy (~3-4x faster).
Styles map to "atomic css" rules.

Fix #307
2017-01-01 17:42:25 -08:00
Nicolas Gallagher
a2cafe56fc Add initial performance benchmarks
Simple render tree benchmarks originally developed by @lelandrichardson

Fix #306
2017-01-01 14:43:47 -08:00
Nicolas Gallagher
351c0ac3d4 Minor changes 2016-12-30 22:19:51 -08:00
Nicolas Gallagher
877c0d2818 Simplify StyleSheet's expandStyle 2016-12-30 22:14:39 -08:00
Nicolas Gallagher
3afc5d5de6 Rename style processors to resolvers 2016-12-29 19:17:12 -08:00
Nicolas Gallagher
edf3b9b7ff Move 'flattenStyle' into 'StyleSheet' 2016-12-29 16:31:14 -08:00
Nicolas Gallagher
518a85bf1b Rename 'createReactStyleObject' to 'createReactDOMStyle' 2016-12-29 16:26:31 -08:00
vaukalak
ba75acb66a [add] BackAndroid API stub 2016-12-27 18:14:31 +00:00
Nicolas Gallagher
bc68b0b6f4 0.0.61 2016-12-27 18:09:11 +00:00
Nicolas Gallagher
44ecbc072e [change] update React and Touchables
Update to React@15.4. The 'EventConstants' module no longer exports a
key-mirror, which was preventing the 'ResponderEventPlugin' from working
as it did with React@15.3.

Close #255
2016-12-27 17:57:27 +00:00
Nicolas Gallagher
4cf4905fc2 [change] add support for ShadowPropTypes
Fix #44
2016-12-26 13:57:19 +00:00
Nicolas Gallagher
509920be4b [add] Image 'prefetch' and 'getSize' statics
Fix #160
2016-12-26 13:31:40 +00:00
Gethin Webster
04e3c23e67 [fix] ListView updates rows when dataSource changes
Close #295
2016-12-23 12:51:40 +00:00
Nicolas Gallagher
32f454de66 [change] add Platform and Touchable to 'core' module 2016-12-23 12:45:54 +00:00
Nicolas Gallagher
1273bfc7cf Address avoidable object creation 2016-12-23 12:22:32 +00:00
Nicolas Gallagher
dc7f526f6b [fix] TextInput props
- Add missing 'onSubmitEditing' propType and test
- Add 'dir=auto' DOM attribute to allow browser to switch writing
  direction for RTL languages
2016-12-17 23:38:36 +00:00
Nicolas Gallagher
7cda89c5ce 0.0.60 2016-12-16 12:15:23 +00:00
Nicolas Gallagher
695eba45af [add] Clipboard API
Close #125
Fix #122
2016-12-16 11:59:22 +00:00
Nicolas Gallagher
92a2cb274a [fix] remove TextInput default flex value 2016-12-16 11:39:12 +00:00
Nicolas Gallagher
b1ca04d11e Rename I18nManager example 2016-12-16 11:35:11 +00:00
Nicolas Gallagher
22ab70ea6f 0.0.59 2016-12-14 17:42:15 +00:00
Gethin Webster
49f36d8eb1 Update to ListView functionality
Re-build ListView from the core react-native component, to get better
feature parity

Ensure lists with small initialListSize render correctly

Changes as requested via PR
2016-12-14 09:39:05 -08:00
Nicolas Gallagher
80ba119b83 Update install command
Close #285
Close #286
2016-12-14 17:05:15 +00:00
Nicolas Gallagher
c30b67f6db 0.0.57 2016-12-12 15:10:39 +00:00
Nicolas Gallagher
4580f93199 Use fbjs requestAnimationFrame in Image 2016-12-12 14:26:07 +00:00
Nicolas Gallagher
4c46126ffe [change] ScrollView event normalization 2016-12-12 14:21:33 +00:00
Calvin Chan
f8d5c15405 [add] Button component 2016-12-12 13:02:16 +00:00
Nicolas Gallagher
dc54e03625 [add] Linking API
Adds support for opening external URLs in a new tab/window. Includes
patches to 'Text' to improve accessibility and 'createDOMElement' to
improve external link security.

Fix #198
2016-12-12 11:45:30 +00:00
Nicolas Gallagher
4d5819ae28 [fix] RTL translateX; Switch transition 2016-12-08 19:40:34 -08:00
Nicolas Gallagher
5c482ef3be 0.0.56 2016-12-08 18:29:38 -08:00
Nicolas Gallagher
f51592f96e [change] TouchableOpacity without Animated
Fix #259
2016-12-08 18:22:25 -08:00
Nicolas Gallagher
6bffe1775f Fix lint error 2016-12-07 16:49:53 -08:00
Nicolas Gallagher
7e75d037f2 [fix] Image passes unknown props to underlying View
Fix #267
2016-12-07 16:37:24 -08:00
Nicolas Gallagher
7536508fe3 Update docs 2016-12-07 16:22:39 -08:00
Maxime Thirouin
945fff0015 Add source files to published package 2016-11-25 12:38:29 -08:00
Nicolas Gallagher
5032ed6fe1 Update AppRegistry docs 2016-11-25 12:36:05 -08:00
Nicolas Gallagher
8c7cdbf4be 0.0.55 2016-11-24 10:24:19 -08:00
Nicolas Gallagher
e5d8857bcc [fix] inject ReactDefaultInjection
Fixes a regression introduced in the following commit to avoid directly
depending on the 'react-dom' entry file:

d65c92eea9

Injecting ReactDefaultInjection adds ~25 KB back to the UMD build.

Fix #263
2016-11-24 10:21:40 -08:00
Nicolas Gallagher
cda8d05bb7 0.0.54 2016-11-24 08:42:53 -08:00
Nicolas Gallagher
049edc4611 [change] don't prefix HTML id's with underscore 2016-11-23 10:28:20 -08:00
Nicolas Gallagher
e76d5a4e6c [change] export createDOMElement helper
Fix #184
2016-11-23 10:25:00 -08:00
Nicolas Gallagher
f71dae7d93 [add] support for vendor-prefixed font-smoothing styles
Fix #240
2016-11-23 09:58:18 -08:00
Nicolas Gallagher
94d31beaf4 [change] ignore unsupported React Native props
Ignores RN props that RN packages commonly applied to elements without
scoping them to supported platforms.

Fix #252
2016-11-23 09:27:27 -08:00
Nicolas Gallagher
f5f9389728 0.0.53 2016-11-22 17:46:57 -08:00
Nicolas Gallagher
fdbd19a4af [fix] PropTypes production error
See: https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types/issues/68
2016-11-22 17:44:48 -08:00
Nicolas Gallagher
36eafbc2f5 0.0.52 2016-11-22 17:10:14 -08:00
Nicolas Gallagher
bca3398c1c Correct devDependencies 2016-11-22 17:08:04 -08:00
Nicolas Gallagher
722d77e8e5 Smaller production builds
Builds on the exclusion of PropTypes from production builds:

- Remove 'lodash' and use smaller modules for equivalent functions.
- Remove use of some unnecessary Facebook utilities.
- Remove 'TouchableBounce'; it isn't part of React Native anymore.
- Remove stray import of 'react-dom/server'.
- Exclude 'StyleSheetValidation' from production.

Measuring the UMD build (gzip)…

Before: ~100KB
After: ~60KB
2016-11-22 16:59:20 -08:00
Nicolas Gallagher
d65c92eea9 [change] prepare for react-dom@15.4.0
Don't depend directly on the 'react-dom' module as it will be prebuilt
in 15.4. Leave server-side rendering to 'react-dom/server'.
2016-11-22 16:57:28 -08:00
Nicolas Gallagher
8dd39c681c [change] allow propTypes to be removed in production builds
Fix #254
2016-11-22 16:57:22 -08:00
Nicolas Gallagher
0b1759363d [add] promote ScrollView content to new layer 2016-11-22 13:08:11 -08:00
Nicolas Gallagher
abd1227a94 [change] ScrollView props and event handling
- Update 'scrollEventThrottle' prop
- Filter non-DOM props
- Persist debounced scroll events.

Fix #209
2016-11-21 21:39:08 -08:00
Nicolas Gallagher
8352c7cbda Use yarn for dependency management 2016-11-21 17:10:50 -08:00
Nicolas Gallagher
89f5a13891 [change] TextInput uses DOM elements
This patch changes TextInput to use DOM inputs directly, rather than
trying to reimplement 'placeholder'. Removes support for
'placeholderTextColor'.

Fix #54
Fix #224
Fix #229
Fix #235
Fix #253
2016-11-21 16:52:40 -08:00
Nicolas Gallagher
4005f9ddde 0.0.51 2016-11-21 12:42:58 -08:00
Nicolas Gallagher
f192a9ba26 [fix] Depend on React@15.3
React@15.4 includes changes that prevent the ResponderEventPlugin from
being properly injected, which breaks Touchables and PanResponder.

Fix #257
2016-11-21 12:38:37 -08:00
Nicolas Gallagher
e688a949fb 0.0.50 2016-11-20 14:00:42 -08:00
Nicolas Gallagher
77605cb27c [add] Text accessibility roles
Fix #199
2016-11-20 13:56:49 -08:00
Nicolas Gallagher
4f71833aec [fix] Image rendering in Safari
The use of 'max-height:100%' on the inner image can cause extremely poor
render performance in Safari. Remove the inner image and simplify
`Image` to use a single view. This fixes the following additional bugs:

Fix #202
Fix #226
2016-11-20 13:51:16 -08:00
Nicolas Gallagher
fa14995a35 Use jest for testing
Thanks to @paularmstrong:
https://github.com/necolas/react-native-web/pull/249
2016-11-09 10:00:49 -08:00
Paul Armstrong
4beae0dd78 [fix] NetInfo event handler registration 2016-11-04 10:20:19 -07:00
Nicolas Gallagher
5598961d2c Move ResponderEventPlugin injection to View 2016-11-04 10:09:55 -07:00
Nicolas Gallagher
4613baf0e8 [fix] StyleSheet check 'transform' is an array 2016-11-04 10:09:27 -07:00
Nicolas Gallagher
3b661d8d6d 0.0.49 2016-11-03 09:16:00 -07:00
Nicolas Gallagher
22d20706e3 Add React Native TextInput examples 2016-11-03 08:56:26 -07:00
Nicolas Gallagher
0b2813b186 [fix] View when 'style' is not defined 2016-11-03 08:52:25 -07:00
Nicolas Gallagher
b248de552d Fix tests 2016-11-03 08:51:51 -07:00
Nicolas Gallagher
2b826dc7f4 [add] TextInput support for selection 2016-10-28 23:37:19 -07:00
Nicolas Gallagher
b46acd4f50 [fix] TextInputState focus management 2016-10-28 22:12:20 -07:00
Nicolas Gallagher
5a03cb25cb [add] TextInput support for blurOnSubmit and onSubmitEditing 2016-10-28 21:15:35 -07:00
Nicolas Gallagher
44e60d12e3 [change] TextInput support for autoCorrect and autoComplete 2016-10-28 10:51:05 -07:00
Nicolas Gallagher
fc60f8d332 [add] TextInput support for autoCapitalize 2016-10-28 10:36:06 -07:00
Nicolas Gallagher
2a65ca6fc0 [add] TextInput support for isFocused 2016-10-27 22:31:43 -07:00
Nicolas Gallagher
9db3bd7e67 [add] TextInput support for onKeyPress
Fix #215
2016-10-27 22:17:59 -07:00
Nicolas Gallagher
1963e9109a 0.0.48 2016-10-27 21:12:04 -07:00
Nicolas Gallagher
14072c7471 [fix] View event handling
Fix #238
2016-10-27 21:00:17 -07:00
Nicolas Gallagher
0af6dc00fc [change] Image 'source' dimensions and RN layout
Adds support for 'width' and 'height' set via the 'source' property.
Emulates RN image layout (i.e., no dimensions by default).

Fix #10
2016-10-23 19:19:52 -07:00
Nicolas Gallagher
c9d401f09a [fix] Image resizeMode style
Fixes an issue in production where 'resizeMode' is deleted from style
simple objects, preventing it from being applied at render time.

Fix #233
2016-10-23 14:50:25 -07:00
Nicolas Gallagher
8aeeed0ef7 [fix] accept number or string for flexBasis style
Fix #230
2016-10-20 10:36:40 -07:00
Nicolas Gallagher
f5d0f73b4f 0.0.47 2016-10-13 10:30:49 -07:00
Xiaohan Zhang
ee7d367062 [fix] AsyncStorage.mergeItem to support deep merge
Mirrors behaviour of react-native
2016-10-13 10:27:51 -07:00
Nicolas Gallagher
dbd607ce47 0.0.46 2016-10-10 17:12:28 -07:00
Nicolas Gallagher
373cb38ca9 Fix lint error 2016-10-10 09:19:20 -07:00
Nicolas Gallagher
4576b42365 Correct the Image docs 2016-10-09 16:53:41 -07:00
Nicolas Gallagher
5a5707855b [fix] CSS reset 2016-10-04 16:26:03 -07:00
Paul Le Cam
0c76cc5d80 [fix] how ListView uses ScrollView
* Bind `_setScrollViewRef` to instance
* Fix getting ScrollView props for ListView
2016-09-19 16:24:25 -07:00
Nicolas Gallagher
d64df129b2 [fix] remove default 'input' border-radius 2016-09-12 11:46:47 -07:00
Nicolas Gallagher
763c5444ce Add 'ProgressBar' to README 2016-09-06 12:51:59 -07:00
Nicolas Gallagher
88d13f06f8 0.0.45 2016-09-06 12:42:36 -07:00
Nicolas Gallagher
3dd94880e0 [fix] ActivtyIndicator accessibility props
Markup the 'ActivityIndicator' as an indeterminate ARIA 'progressbar'
2016-09-06 12:41:07 -07:00
Nicolas Gallagher
e1080d72d7 [fix] ScrollView style issues
* Fix contentContainer not expanding to contain all child elements
* Add momentum scrolling on iOS

Fix #197
2016-09-06 12:33:53 -07:00
Nicolas Gallagher
55849cdd0d Add display names 2016-09-06 12:33:14 -07:00
Nicolas Gallagher
0aef117733 [add] ProgressBar component
Ref #91
2016-09-01 16:49:42 -07:00
Nicolas Gallagher
977d8729f5 Fix style prop validation in development 2016-09-01 16:37:45 -07:00
Nicolas Gallagher
9222cbf4bd [add] support numeric ActivityIndicator size value 2016-09-01 16:36:49 -07:00
Nicolas Gallagher
103560fc11 Add i18n docs and update README 2016-08-31 15:19:49 -07:00
Nicolas Gallagher
3a2daf386d [change] Hide more 'input' pseudo-elements
Removes the webkit spin-buttons from numeric inputs.

Fix #194
2016-08-31 14:07:08 -07:00
Nicolas Gallagher
6640b61b3e Change appearance of ActivityIndicator
This looks more like a traditional OS-level activity indicator.

The design of the Android activity indicator hasn't worked very well for
us on Web. The main problem is that if the main thread is locked, the
indicator (even if it's a gif) will stop animating and can look really
bad. This implementation looks like an activity indicator even when it
isn't animating.
2016-08-31 13:54:00 -07:00
Nicolas Gallagher
07d1124d60 Update runtime dependencies 2016-08-26 11:30:45 -07:00
Nicolas Gallagher
c7b3a8e60b Update react-storybook dependency 2016-08-26 11:30:44 -07:00
Nicolas Gallagher
d32eec7239 Update build and test dependencies 2016-08-26 11:30:38 -07:00
Nicolas Gallagher
f8f2898095 Use Twitter JavaScript style 2016-08-26 11:29:11 -07:00
Nicolas Gallagher
201bfd2e4d [change] remove 'label' element from Switch 2016-08-22 16:32:18 -07:00
Nicolas Gallagher
496839d19a Add tests for Switch 2016-08-20 20:33:55 -07:00
Nicolas Gallagher
6fe3f1f533 Don't persist RTL across examples 2016-08-19 16:46:07 -07:00
Nicolas Gallagher
aa53d931d5 Add I18nManager example 2016-08-19 14:04:10 -07:00
Nicolas Gallagher
88b184d540 Reorganize examples 2016-08-19 14:03:55 -07:00
Nicolas Gallagher
011affb110 0.0.44 2016-08-18 16:27:39 -07:00
Nicolas Gallagher
87a4f56a89 [add] Switch component
'Switch' on Web can support custom sizes and colors. To do so,
Web-specific propTypes are introduced: `trackColor`, `thumbColor`,
`activeTrackColor`, and `activeThumbColor`.
2016-08-18 16:25:16 -07:00
Nathan Tran
2f94295739 [fix] TextInput 'keyboardType' propType 2016-08-17 15:51:55 -07:00
Nicolas Gallagher
fdf4a88251 Refactor DOM element helper 2016-08-17 15:46:10 -07:00
Nicolas Gallagher
acc7032d60 0.0.43 2016-08-16 14:05:48 -07:00
Nicolas Gallagher
0fc5644959 Add more details to README
Fix #57
2016-08-16 14:04:22 -07:00
Nicolas Gallagher
be923ec453 [fix] disabled Touchable 2016-08-16 10:29:26 -07:00
Nicolas Gallagher
248c2e1258 [fix] ActivityIndicator animation
Use 'Animated' to animate the 'ActivityIndicator'

Fix #182
2016-08-15 16:58:20 -07:00
Nicolas Gallagher
2e822c068d [fix] Image render thrashing
This patch removes several avoidable uses of `setState`, only
re-rendering the `Image` when necessary.

It also fixes a style prop warning for `resizeMode`, which was not being
removed in development due to the use of `Object.freeze` when styles are
registered.

Close #116
2016-08-15 15:00:47 -07:00
Nicolas Gallagher
fb5406e4ec [change] I18nManager manages global writing direction 2016-08-15 11:36:59 -07:00
Vitor Balocco
638479991e Fix broken link and typo in StyleSheet API docs (#189) 2016-08-14 19:42:42 -07:00
Nicolas Gallagher
fb41be1bf7 0.0.42 2016-08-12 14:59:59 -07:00
Nicolas Gallagher
2291544373 [fix] React@15.3 propType warnings 2016-08-12 14:59:28 -07:00
Nicolas Gallagher
6416166bc3 [add] support for RTL layout
Add `I18nManager` API from React Native. This can be used to control
when the app displays in RTL mode.

Add `$noI18n` property suffix for properties that StyleSheet will
automatically flip. This can be used to opt-out of automatic flipping on
a per-declaration basis.
2016-08-12 14:58:53 -07:00
Nicolas Gallagher
f1e221e51e Add Github issue and pull request templates
Fix #180
Close #185
2016-08-05 10:59:00 -07:00
Nicolas Gallagher
27edfd9d88 Update guide for styling 2016-08-03 15:56:04 -07:00
Nicolas Gallagher
6cadc22ad5 0.0.41 2016-08-03 13:16:50 -07:00
Nicolas Gallagher
5c8cdd7742 [add] export a 'core' module 2016-08-03 13:16:09 -07:00
Nicolas Gallagher
e3450ed26c 0.0.40 2016-07-29 14:06:21 -07:00
Nicolas Gallagher
d54a84701a [fix] ScrollView scrolling
Scrolling is broken by the patch that adds ResponderEvent support for
multi-input devices: 6a9212df40

By calling 'preventDefault' on every touch event, scroll events were
cancelled. This patch shifts the responsibility for calling
'preventDefault' to the 'View' event handler normalizer, and only on
touch events within the Responder system.

Fix #175
2016-07-29 14:05:52 -07:00
Nicolas Gallagher
8201906703 Fix lint error 2016-07-27 15:08:10 -07:00
Nicolas Gallagher
10f88670ed [add] support for textShadow* and transition style props
Close #170
2016-07-23 19:16:48 -07:00
Nicolas Gallagher
1be2c810d1 Minor refactor of StyleSheet helpers 2016-07-23 18:54:41 -07:00
Nicolas Gallagher
6f75fb3e0d Fix gh-pages build 2016-07-22 16:10:14 -07:00
Nicolas Gallagher
424e6b5994 0.0.39 2016-07-22 15:54:02 -07:00
Nicolas Gallagher
769931061a Fix lint issue 2016-07-22 11:35:27 -07:00
Nicolas Gallagher
7aa760506a [fix] improve event normalization coverage 2016-07-22 11:28:08 -07:00
Nicolas Gallagher
9401eb9b47 Move webpack test entry 2016-07-20 14:30:20 -07:00
Nicolas Gallagher
6a9212df40 [change] ResponderEvent support for multi-input devices
Certain devices support both mouse and touch inputs. The Responder
plugin needs to support this. Previously it would specific touch-only
dependencies if touch support was detected.

The recommended way to prevent browsers firing mouse events after touch
events is to call `preventDefault` on the touch event. This may be
problematic if/when `View` and `Touchable` support URLs/hrefs.

Fix #169
2016-07-20 14:26:42 -07:00
Nicolas Gallagher
f2772b89bf [add] support for 'currentcolor' color 2016-07-16 19:31:10 -07:00
Nicolas Gallagher
9e970b3c34 Better layout for Text examples 2016-07-16 19:26:59 -07:00
Nicolas Gallagher
9677e9da0a Use React's 'TouchHistoryMath' module 2016-07-16 19:25:32 -07:00
Nicolas Gallagher
2440e74e99 [add] new Image resize modes 2016-07-16 19:24:25 -07:00
Nicolas Gallagher
66b0387023 add a script to deploy storybook to gh-pages 2016-07-14 00:04:15 -07:00
Nicolas Gallagher
94f37740af use react-storybook to display examples
Initial setup of react-storybook. Includes examples copied from the
React Native repository.

Close #148
2016-07-13 22:19:39 -07:00
Nicolas Gallagher
e1991f8f6b [change] remove maxWidth from default View styles
View's default styles include `maxWidth:"100%"` to fix a specific
flexbox bug in Internet Explorer. But it's not needed for the default View
layout and it limits the width of absolutely positioned elements (a
bug).
2016-07-13 21:56:35 -07:00
Nicolas Gallagher
21eeafabd5 0.0.38 2016-07-12 21:19:28 -07:00
Nicolas Gallagher
249f157ed9 [fix] ListView child layout
Fix #166
2016-07-12 21:18:18 -07:00
Nicolas Gallagher
0f8cff6124 0.0.37 2016-07-12 17:47:40 -07:00
Nicolas Gallagher
30bf00a3bc [fix] TextInput styles
Ref #166
2016-07-12 17:47:10 -07:00
Nicolas Gallagher
f4515a3995 0.0.36 2016-07-12 13:56:34 -07:00
Nicolas Gallagher
17b30aceb2 [fix] default DOM element for 'View' (part 2)
First patch: 41159bcb10

@chriskjaer mentioned that changing from 'div' to 'span' introduces
different validation errors, e.g., <span><form>a</form></span>.

This patch uses 'context' to switch to a 'span' element if a 'View' is
being rendered within a 'button' element.
2016-07-12 11:03:31 -07:00
Nicolas Gallagher
5f3f4db7a6 [fix] iOS Touchable click handling 2016-07-12 10:26:00 -07:00
Nicolas Gallagher
eb8aa0a9db [add] 'selectable' prop to Text 2016-07-12 10:23:40 -07:00
Nicolas Gallagher
af60504ca4 [add] Vibration API 2016-07-11 21:51:00 -07:00
Nicolas Gallagher
41159bcb10 [fix] default DOM element for 'View'
There are certain contexts where using a `div` is invalid HTML and may
cause rendering issues. Change the default element created by
`createReactDOMComponent` to a `span`.

**Appendix**

The following HTML results a validator error.

  <!DOCTYPE html>
  <head>
  <meta charset="utf-8">
  <title>test</title>
  <button><div>a</div></button>

Error: Element `div` not allowed as child of element `button` in this
context.

Source: https://validator.w3.org/nu/#textarea
2016-07-11 20:25:05 -07:00
Nicolas Gallagher
640e41dc34 0.0.35 2016-07-11 19:03:33 -07:00
Andrew Palm
c609a6ff2b Fix TouchableWithoutFeedback propTypes (#164) 2016-07-11 19:02:39 -07:00
Nicolas Gallagher
294d94d869 0.0.34 2016-07-11 00:02:15 -07:00
Nicolas Gallagher
179d624917 [change] don't use invariant in StyleSheet validation 2016-07-11 00:01:29 -07:00
Nicolas Gallagher
61860b6d49 0.0.33 2016-07-10 22:20:03 -07:00
Nicolas Gallagher
597fcc65e8 [add] initial 'onLayout' support
Add initial support for 'onLayout' when components mount and update.

Ref #60
2016-07-10 22:15:51 -07:00
Nicolas Gallagher
5e1e0ec8e5 [fix] update Touchables 2016-07-10 22:15:24 -07:00
Nicolas Gallagher
0ac243038f remove Portal docs 2016-07-10 22:13:14 -07:00
Nicolas Gallagher
c9d68fe93e Resolve React@15.2.0 unknown props warnings 2016-07-10 18:32:02 -07:00
Nicolas Gallagher
77f72aa129 [change] StyleSheet: news APIs and refactor
This fixes several issues with 'StyleSheet' and simplifies the
implementation.

1. The generated style sheet could render after an apps existing style
sheets, potentially overwriting certain 'html' and 'body' styles. To fix
this, the style sheet is now rendered first in the document head.

2. 'StyleSheet' didn't make it easy to render app shells on the server.
The prerendered style sheet would contain classnames that didn't apply
to the client-generated style sheet (in part because the class names
were not generated as a hash of the declaration). When the client
initialized, server-rendered parts of the page could become unstyled. To
fix this 'StyleSheet' uses inline styles by default and a few predefined
CSS rules where inline styles are not possible.

3. Even with the strategy of mapping declarations to unique CSS rules,
very large apps can produce very large style sheets. For example,
twitter.com would produce a gzipped style sheet ~30 KB. Issues related
to this are also alleviated by using inline styles.

4. 'StyleSheet' didn't really work unless you rendered an app using
'AppRegistry'. To fix this, 'StyleSheet' now handles injection of the
DOM style sheet.

Using inline styles doesn't appear to have any serious performance
problems compared to using single classes (ref #110).

Fix #90
Fix #106
2016-07-10 18:31:12 -07:00
Nicolas Gallagher
216885406f [fix] TouchableHighlight inactive styles 2016-07-10 17:42:23 -07:00
Nicolas Gallagher
f15bf2664a fix View propTypes 2016-07-10 14:23:05 -07:00
Nicolas Gallagher
79998e0acc move 'normalizeNativeEvent' and 'injectResponderEventPlugin' 2016-07-09 11:17:05 -07:00
Nicolas Gallagher
44fc48f7a0 use 'normalizeValue' in 'processTransform' 2016-07-07 22:24:05 -07:00
Nicolas Gallagher
37f2d78f34 Minor tweaks 2016-07-07 22:22:37 -07:00
Nicolas Gallagher
1dc769bfb1 move propTypes and normalizeColor 2016-07-07 22:14:08 -07:00
Nicolas Gallagher
4b3cb41107 rename createNativeComponent to createReactDOMComponent 2016-07-07 21:21:45 -07:00
Nicolas Gallagher
ed2cbfd5d3 [fix] React Native styles -> React DOM styles
Add 'createReactStyleObject' to transform a React Native style object
into a React DOM-compatible style object. This is also needed to ensure
that 'setNativeProps' works as expected.
2016-07-06 19:49:55 -07:00
Nicolas Gallagher
8c4b5b68c3 Fix eslint error 2016-07-06 18:57:51 -07:00
Nicolas Gallagher
3564bbf840 0.0.32 2016-07-06 18:50:25 -07:00
Nicolas Gallagher
297b2e5afb [fix] support for Animated transform styles (part 2)
Only add 'px' to numeric translate values
2016-07-06 18:48:53 -07:00
Nicolas Gallagher
215697234e 0.0.31 2016-07-06 18:33:12 -07:00
Nicolas Gallagher
9efa7e94bd [fix] support for Animated transform styles
Animated uses 'setNativeProps' to update styles. This mutates the DOM
without using React. But the code path was not adding 'px' units to
transform values and browsers were ignoring the style.

Fix #129
2016-07-06 17:16:55 -07:00
Nicolas Gallagher
c44da41497 0.0.30 2016-07-06 15:30:40 -07:00
Nicolas Gallagher
331c92fb3a Use enzyme for all React component tests 2016-07-06 15:26:32 -07:00
Nicolas Gallagher
26758e905c [fix] TextInput alignment of small inner 'input'
Fix #139
2016-07-06 15:25:00 -07:00
Nicolas Gallagher
a15b15c55d Use babel-preset-react-native 2016-07-06 10:27:43 -07:00
Nicolas Gallagher
f0202dbe61 Remove use of decorator syntax 2016-07-06 10:11:03 -07:00
Nicolas Gallagher
d4d67dafc0 [fix] StyleSheet expansion of shortform properties
The previous implementation relied on a buggy sorting strategy. It could
result in shortform properties replacing the values set for longform
properties. This patch avoids expanding shorthand values to a longform
property if it declared in the original style object.

Fix #141
2016-07-05 19:18:11 -07:00
Nicolas Gallagher
579bdeb8a5 [fix] setNativeProps on TextInput 2016-07-05 18:52:44 -07:00
Nicolas Gallagher
7132a18440 Remove unused import 2016-07-05 18:48:49 -07:00
Nicolas Gallagher
18881b1edb [fix] support border styles on Image
Fix #128
2016-07-05 13:57:42 -07:00
Nicolas Gallagher
4d1e7d8c0b 0.0.29 2016-07-05 13:50:25 -07:00
Nicolas Gallagher
a7158aeb6f [change] remove Portal component
Portal was undocumented and has been removed from React Native.

Fix #149
2016-07-05 13:49:37 -07:00
Nicolas Gallagher
03d413bca4 0.0.28 2016-07-05 11:33:29 -07:00
IjzerenHein
aef5efbad3 [add] basic ListView component
Close #87
2016-07-05 11:33:02 -07:00
Nicolas Gallagher
8fb8645723 Use 'enzyme' for 'View' tests 2016-07-05 11:33:02 -07:00
Cesar Andreu
d69406b4b1 Add an API to wrap and initialize animated (#159) 2016-07-03 11:00:50 -07:00
Nicolas Gallagher
2c2a96a183 update rendering docs 2016-06-29 17:42:06 -07:00
Nicolas Gallagher
b4a3053b5b fix README install command 2016-06-29 17:00:50 -07:00
Nicolas Gallagher
24836afd6a 0.0.26 2016-06-28 16:38:31 -07:00
Nicolas Gallagher
c46f242f6b [add] ReactDOM server API to ReactNative API 2016-06-28 16:38:21 -07:00
Nicolas Gallagher
1940868065 [fix] TextInput support for Text styles
Fix #81
Fix #133
2016-06-28 15:55:27 -07:00
Nicolas Gallagher
65a9317756 [fix] TextInput placeholder layout and focus
Fix the layout of placeholder text and shift focus to the DOM input when
`TextInput` is clicked or pressed.

Thanks to @tuckerconnelly and @Dremora.

Fix #138
Fix #119
Close #137
2016-06-28 15:04:38 -07:00
Nicolas Gallagher
3da05c48b0 [fix] support 'onClick' prop in 'View' 2016-06-28 15:04:17 -07:00
Nicolas Gallagher
f33312a4dd [change] Use animatedjs/animated
Depend on 'animatedjs/animated' for the Animation implementation. This
patch also replaces 'es6-set' with a small shim to reduce impact on
production bundle size.

Fix #95
2016-06-23 15:10:43 -07:00
Nicolas Gallagher
4516c72296 Use enzyme for Image tests 2016-06-23 13:52:08 -07:00
Nicolas Gallagher
7f94c4bf06 Install enzyme
Fix #83
2016-06-23 13:50:06 -07:00
Nicolas Gallagher
37781171aa [add] more ReactNative exports 2016-06-23 10:16:45 -07:00
Nicolas Gallagher
22f45e350b [fix] React@15: remove inline-style fallback values
React 15 has no way to handle fallback CSS values (for example, vendor
prefixed 'display:flex' values) in inline styles. This patch drops all
fallback values for inline styles at the cost of regressing browser
support (those without standard flexbox support will not layout React
Native components correctly).

Fix #131
2016-06-22 16:13:48 -07:00
Nicolas Gallagher
af40f98f23 [fix] AppState event handler registration
Fix #151
2016-06-22 15:41:35 -07:00
Nicolas Gallagher
eca2f69593 Remove a React error from test report 2016-06-21 14:59:45 -07:00
Nicolas Gallagher
d03d89ac71 [fix] CoreComponent -> createNativeComponent
'CoreComponent' creates new component instances and clutters the React
component tree during debugging. This patch converts 'CoreComponent' to
a simple function that creates a native web element.

This patch also includes a fix for use of the 'flexShrink' style on
'View'.

Fix #140
2016-06-21 14:59:38 -07:00
Nicolas Gallagher
393a6ef835 [fix] don't use 'bind' in JSX props 2016-06-20 11:31:38 -07:00
Nicolas Gallagher
36e89d5275 [fix] installation on Windows
Fix #114
2016-06-20 11:22:42 -07:00
Nicolas Gallagher
d53d1e6e56 Add link to react-native-web-starter 2016-06-20 11:09:50 -07:00
Nicolas Gallagher
2cb68a45be [add] Platform.select 2016-06-18 16:43:22 -07:00
Nicolas Gallagher
b56b8e494a Update various packages (inc. babel and eslint) 2016-06-14 16:05:30 -07:00
Nicolas Gallagher
60ad0e9ec5 Further fixes to examples following react@15 update 2016-06-14 15:56:10 -07:00
Nicolas Gallagher
f2ea7c089c [change] separate the React and React Native APIs
Fix #136
2016-06-14 13:47:47 -07:00
Nicolas Gallagher
a3b59ed2b4 [fix] Touchable with React@15
Fix #123
2016-06-14 13:47:39 -07:00
Nicolas Gallagher
a378d3cce2 [change] update to React@15 2016-06-14 13:04:30 -07:00
Nicolas Gallagher
462f9793ea Fix code style issue 2016-06-13 15:05:03 -07:00
Monir Abu Hilal
ae38bb538c Do not treat lineHeight as a unitless numbers
Match the behavior of react-native for iOS and Android

The browser treats the 'line-height' CSS property as an 'em' value,
while react-native treats it as pixel unit (or device unit, which should
be 'px' for the web), this issue is causing the 'TextInput' component to
be sized incorrectly.

Close #142
2016-06-13 12:04:53 -07:00
Nicolas Gallagher
93d1488cc7 Fix README link to View 2016-06-13 11:59:24 -07:00
Nicolas Gallagher
a16e542bd8 [fix] don't replace 'className' value 2016-06-13 11:58:05 -07:00
Nicolas Gallagher
62cd335788 [fix] TouchableHighlight default underlay style 2016-06-13 11:57:02 -07:00
Nicolas Gallagher
288e14cd70 Remove MediaQueryWidget from examples 2016-06-13 11:56:15 -07:00
Nicolas Gallagher
71cfd23624 0.0.25 2016-04-29 12:49:13 -07:00
Nicolas Gallagher
77b8e4a1fc [fix] pin inline-style-prefix-all
Version 1.1.0 contains a breaking change
2016-04-29 12:48:40 -07:00
Nicolas Gallagher
9543a79c3f 0.0.24 2016-04-20 11:38:38 -07:00
Nicolas Gallagher
e3eea6e132 [fix] TouchableHighlight
The fix in 97c0a31ce6 was incomplete due
to state key not being renamed.
2016-04-20 11:37:15 -07:00
Nicolas Gallagher
4d3418a968 0.0.23 2016-04-19 17:11:26 -07:00
Nicolas Gallagher
ea9bc734f1 [fix] TouchableWithoutFeedback
Fix #127
2016-04-19 17:10:50 -07:00
Nicolas Gallagher
e03af435ac 0.0.22 2016-04-18 16:55:57 -07:00
Nicolas Gallagher
97c0a31ce6 [fix] TouchableHighlight default underlayColor 2016-04-18 16:46:09 -07:00
Nicolas Gallagher
25d11ded46 [fix] NetInfo event handlers 2016-04-18 16:38:09 -07:00
Nicolas Gallagher
6a73d77030 Fix build 2016-03-24 17:01:38 -07:00
Nicolas Gallagher
0b63ba4e89 0.0.21 2016-03-24 11:50:01 -07:00
Nicolas Gallagher
51109d0768 [fix] update inline-style-prefix-all
inline-style-prefix-all@1.0.4 doesn't depend on `Set` anymore
2016-03-24 11:49:22 -07:00
Nicolas Gallagher
ac04ecd69e Update Dimensions when window resizes 2016-03-24 11:44:02 -07:00
Nicolas Gallagher
1a670ba6a7 Fix UMD bundle
Include React and ReactDOM in the UMD bundle. The library occupies the
`React` global.

Fix #105
2016-03-22 18:39:24 -07:00
Nicolas Gallagher
7a16d5711c 0.0.20 2016-03-20 12:19:40 -07:00
Nicolas Gallagher
9dde70fff5 Update documentation 2016-03-20 12:19:29 -07:00
Nicolas Gallagher
203980ab66 [fix] fbjs version compatible with React Native
React Native 0.21 currently uses fbjs@0.6.x, and React Native 0.22 will
use fbjs@0.7.x.

Fix #103
2016-03-20 12:11:31 -07:00
Nicolas Gallagher
924dc36d4a [fix] refactor StyleSheet
**Problem**

StyleSheet's implementation was overly complex. It required
`flattenStyle` to use `expandStyle`, and couldn't support mapping React
Native style props to CSS properties without also exposing those CSS
properties in the API.

**Response**

- `flattenStyle` is concerned only with flattening style objects.

- `StyleSheetRegistry` is responsible for registering styles, mapping
  the React Native style prop to DOM props, and generating the CSS for
  the backing style element.

- `StyleSheetRegistry` uses a simpler approach to caching styles and
  generating style sheet strings. It also drops the unobfuscated class
  names from development mode, as the React Dev Tools can provide a
  better debugging experience (pending a fix to allow props/styles to be
  changed from the dev tools).

- `StyleSheet` will fall back to inline styles if it doesn't think a
  style sheet has been rendered into the document. The relationship is
  currently only implicit. This should be revisited.

- `StyleSheet` exports `renderToString` as part of the documented API.

- Fix processing of `transformMatrix` and add tests for
  `processTransform`.

- Fix `input[type=search]` rendering in Safari by using `display:none`
  on its pseudo-elements.

- Add support for `textDecorationLine` and `textAlignVertical`.

- Note the `View` hack to conditionally apply the `flex-shrink:0` reset
  from css-layout. This is required because React Native's approach to
  resolving `style` is to give precendence to long-hand styles
  (e.g., `flexShrink`) over short-hand styles (e.g., `flex`). This means
  the `View` reset overrides any `flex:1` declaration. To get around
  this, `flexShrink` is only set in `View` if `flex` is not set.
2016-03-20 12:09:04 -07:00
Nicolas Gallagher
9b2421cdfa [fix] Server-side rendering
`AppRegistry.prerenderApplication` now returns a style element for use
in app shells.

Guard use of `window` in APIs and Event plugin.

Fix #107
Fix #108
2016-03-20 11:43:13 -07:00
Nicolas Gallagher
36ea662402 0.0.19 2016-03-16 10:19:17 -07:00
Nicolas Gallagher
69962ae815 [fix] StyleSheet: add hairlineWidth
Fix #99
2016-03-16 10:03:37 -07:00
Nicolas Gallagher
62d1a0f83d Add Game2048 example 2016-03-16 00:55:04 -07:00
Nicolas Gallagher
910286303a Add TicTacToe example 2016-03-16 00:48:41 -07:00
Nicolas Gallagher
706fa887e6 [fix] remove invariant error from Portal 2016-03-16 00:48:41 -07:00
Nicolas Gallagher
c589d79035 Reorganize karma and webpack configs 2016-03-16 00:48:37 -07:00
Nicolas Gallagher
83e4c68461 [fix] TouchableHighlight inactive state
TouchableHighlight didn't preserve its original 'backgroundColor' after
pressOut. This was caused by the inactive background style (transparent)
being applied as an inline style, and so not merging with the original
prop style. The patch sets inactive 'backgroundColor' to 'null' so as to
remove the inline style and render the backgroundColor from props.

Fix #98
2016-03-16 00:36:06 -07:00
Nicolas Gallagher
54597edbaf 0.0.18 2016-03-15 17:27:42 -07:00
Nicolas Gallagher
fc31287566 [fix] remove -webkit-tap-highlight-color 2016-03-15 17:26:29 -07:00
Nicolas Gallagher
21cc8f47ba Update documentation 2016-03-15 17:14:44 -07:00
Nicolas Gallagher
bf7beb4102 Update dependencies 2016-03-15 14:25:27 -07:00
Nicolas Gallagher
127d103c0a Fix lint issues 2016-03-15 14:19:46 -07:00
Nicolas Gallagher
ae6132af56 Update library exports 2016-03-15 14:19:29 -07:00
Nicolas Gallagher
3c4d7655db [fix] Touchable: adapt RN touchables for Web 2016-03-15 14:18:08 -07:00
Nicolas Gallagher
190966f411 [fix] ScrollView: based on ScrollResponder 2016-03-15 14:07:45 -07:00
Nicolas Gallagher
8d5ecb84d5 [add] ScrollResponder: adjust to work on Web 2016-03-15 13:49:03 -07:00
Nicolas Gallagher
b4a9177ce3 [add] dismissKeyboard module 2016-03-15 13:44:50 -07:00
Nicolas Gallagher
ad4a6c5be7 [fix] View: guard against browser flexbox bugs
There are various flexbox bugs that can cause views to grow beyond the
vertical or horizontal bounds of their container. The width and height
styles avoid most of them manifesting.
2016-03-15 13:43:25 -07:00
Nicolas Gallagher
5f795dfc6c Clean up View's event normalization code 2016-03-15 13:43:11 -07:00
Nicolas Gallagher
949cb75894 [add] TextInput: 'clear' method on instance 2016-03-15 13:38:54 -07:00
Nicolas Gallagher
2e1914080f [add] TextInputState 2016-03-15 13:38:28 -07:00
Nicolas Gallagher
49e9e0ab5b [add] StyleSheet: new prop types 2016-03-15 13:32:52 -07:00
Nicolas Gallagher
ee4c544957 [fix] StyleSheet: support for 'transform' and 'transformMatrix'
Fix #46
2016-03-15 13:32:02 -07:00
Nicolas Gallagher
56549cf794 [add] NativeMethodsMixin: 'measureInWindow' support 2016-03-15 13:24:36 -07:00
Nicolas Gallagher
e6811b2134 [fix] ResponderEventPlugin: touch or mouse dependencies
**Problem**

Browsers tend to fire both touch and mouse events when touch is
supported. This causes touchables to fire responder callbacks twice.
For example, 'TouchableOpacity' will animate the opacity twice in
response to a touch.

**Response**

If a browser supports touch, don't include the mouse events as
dependencies of the responder events. This is not ideal, as some devices
support both touch and mouse interactions. This will need to be
revisited.
2016-03-15 13:19:43 -07:00
Nicolas Gallagher
d8b7dcc60f Add 'locationX/Y' to recorded Responder events 2016-03-15 13:19:24 -07:00
Nicolas Gallagher
62a08f09ab [fix] ResponderEventPlugin: add missing 'responderRelease' dependencies 2016-03-15 13:17:25 -07:00
Nicolas Gallagher
3e7cd1a001 [add] UIManager: 'blur', 'focus' and 'measureInWindow' 2016-03-15 13:14:06 -07:00
Nicolas Gallagher
8441755d61 [fix] 'window' value in 'Dimension' 2016-03-15 11:35:36 -07:00
Nicolas Gallagher
ba9fa2a7a0 [add] upstream 'merge' module 2016-03-15 11:34:09 -07:00
Nicolas Gallagher
e26edfb9ea Move NativeMethodsDecorator 2016-03-14 23:25:58 -07:00
Nicolas Gallagher
9a8a9ad209 Use 'module.exports' over 'export default'
The use of CommonJS require in RN modules makes it simpler to use
CommonJS exports everywhere.
2016-03-14 23:21:12 -07:00
Nicolas Gallagher
efccbe41bb 0.0.17 2016-03-12 08:00:02 -08:00
IjzerenHein
f6f8d30aba [fix] PanResponder improvements + mouse support
- Adds `locationX` and `locationY` to touch events
- Adds `timestamp` to the `touches` and `touchesChanged` data
- Add mouse event support

Close #94
2016-03-12 07:53:24 -08:00
Nicolas Gallagher
6d7d98c149 [add] support directly requiring image assets
Thanks to IjzerenHein <hrutjes@gmail.com>. See #84
2016-03-08 18:03:45 -08:00
IjzerenHein
77d201988d Add .editorconfig 2016-03-08 09:40:28 -08:00
Nicolas Gallagher
b3d7332ddd Update 'known issues' guide 2016-03-08 09:33:56 -08:00
IjzerenHein
651d519500 [add] NativeModules shim
The `NativeModules` namespace is import by some libraries, which will
throw an error if missing.

Close #86
2016-03-08 09:32:14 -08:00
Hein Rutjes
06d8614519 Merge pull request #1 from necolas/master
Update from original master
2016-03-08 10:57:42 +01:00
Nicolas Gallagher
3eced7e842 Update documentation 2016-03-08 00:52:13 -08:00
rofrischmann
e627e0cd77 Use inline-style-prefix-all for vendor prefixes
Fix #74
Close #82
2016-03-08 00:31:43 -08:00
Nicolas Gallagher
7ab33727c4 Minor test clean up 2016-03-08 00:21:47 -08:00
Nicolas Gallagher
7295a8fee8 Add tests for Image resizeMode 2016-03-08 00:21:35 -08:00
IjzerenHein
9a09456532 [add] Image: support resizeMode style 2016-03-08 00:19:56 -08:00
Nicolas Gallagher
4cd38552cd Fix the 'test:watch' npm-script 2016-03-07 21:18:30 -08:00
Neil Kistner
b0f35f6c66 Add syntax highlighting to docs where missing 2016-03-07 20:43:56 -08:00
Nicolas Gallagher
2dff45b561 Add link to Game2048 example 2016-03-07 20:43:22 -08:00
Nicolas Gallagher
fd9232201d 0.0.16 2016-02-22 19:39:12 -08:00
Nicolas Gallagher
29f6bd363c Fix linting error and check-in test patch 2016-02-22 19:23:05 -08:00
Nicolas Gallagher
4845de5cb5 [add] Update components with native methods
Hack in touch event normalization within `View` to produce events that
contain `pageX`, `pageY` for React Native compatibility.
2016-02-22 16:41:50 -08:00
Nicolas Gallagher
267a9b55bf [add] inject ResponderEventPlugin 2016-02-22 16:40:18 -08:00
Nicolas Gallagher
7add5c524a [add] mirror various React Native APIs
Copy over API code that requires no DOM modifications:

- Animated
- Easing
- Interaction Manager (stub)
- PanResponder
- Touchable
2016-02-22 16:37:42 -08:00
Nicolas Gallagher
8e0d94e092 Use 'fbjs' instead of separate packages 2016-02-22 14:00:43 -08:00
Nicolas Gallagher
25f96ba8ae [fix] StyleSheet prefixing on client and server
A small error from referencing the wrong value caused prefixed values to
be dropped. The patch also updated inline-style-prefixer and turns all
vendor prefixes on by default. This provides the option to drop all the
caniuse and bowser data that inline-style-prefixer uses (probably by
forking the project and removing those dependencies).

Fix #51
2016-02-22 13:55:09 -08:00
Nicolas Gallagher
2b90bd736f Minor docs update 2016-02-19 13:17:39 -08:00
Nicolas Gallagher
791ede06dd 0.0.15 2016-02-18 23:04:35 -08:00
Nicolas Gallagher
0567232942 [fix] NetInfo export 2016-02-18 23:03:59 -08:00
Nicolas Gallagher
e5ecc26d21 0.0.14 2016-02-18 21:32:08 -08:00
Nicolas Gallagher
715c71b215 Refactor StyleSheet to support arrays 2016-02-18 16:45:23 -08:00
Nicolas Gallagher
f8554ecc1e Update README; add guides to docs 2016-02-17 00:49:18 -08:00
Nicolas Gallagher
3292ced765 Add new components
- ActivityIndicator
- Portal
- StaticContainer
- StaticRenderer
2016-02-17 00:20:02 -08:00
Nicolas Gallagher
1c7fb4cb45 Add APIs
- AppRegistry
- AppState
- AsyncStorage
- Dimensions
- NativeMethods
- NetInfo
- PixelRatio
- Platform
- UIManager
2016-02-16 23:54:06 -08:00
Nicolas Gallagher
60409bea18 BSD License; CONTRIBUTING.md 2016-02-16 23:43:41 -08:00
Nicolas Gallagher
5c74c0efb7 Move StyleSheet into 'apis' directory 2016-02-16 23:40:50 -08:00
Ben Alpert
a0187f9b1a Add semicolons to property initializers
According to the current proposal, semicolons are required. Babel 6.4
was updated to require them (see github.com/babel/babel/pull/3225). This
is required in order to fix the build -- master will be red on Travis as
soon as the build is rerun because it will pick up the latest Babel
parser.
2016-01-29 10:16:58 -08:00
Nicolas Gallagher
74ef265d83 [chore] update documentation 2015-12-30 14:10:22 -08:00
Nicolas Gallagher
97b3a91c0e [add] StyleSheet: immutable style in development
Fix #66
2015-12-30 14:10:15 -08:00
Nicolas Gallagher
c65aa8a943 0.0.13 2015-12-27 12:05:35 +00:00
Nicolas Gallagher
0aa60a3c29 [fix] umd bundle 2015-12-27 12:04:40 +00:00
Nicolas Gallagher
8ac84f6da5 [change] StyleSheet: support code-splitting / export smaller API
Quick-fix for code-splitting support by updating the rendered style
sheet in place. Reduce the API to `create`, as the rest is now internal
to the framework.

Fix #34
2015-12-27 11:54:53 +00:00
Nicolas Gallagher
69166b1502 [fix] StyleSheet: support textAlign 'inherit' 2015-12-27 11:46:03 +00:00
Nicolas Gallagher
cc10de43eb [change] export or replace react-dom methods
This change adds the react-dom methods to the main export, since this is
a Web-only environment (React Native does something similar). It
augments the default render methods in order to move style sheet
management under the control of the library (necessary for
code-splitting support).

Relates to #52
2015-12-27 11:45:49 +00:00
Nicolas Gallagher
c850a5fa8c [add] CSS textShadow and reintroduce enums 2015-12-26 17:54:56 +00:00
Nicolas Gallagher
1efe5a533f [add] StyleSheet: support 'flex' style prop
Fix #63
2015-12-26 17:54:13 +00:00
Nicolas Gallagher
804132ce36 [fix] 'process.env.NODE_ENV' check
Use babel to transpile the source code without bundling it.
Use webpack to create a standalone, productionized UMD bundle.

Fix #50
2015-12-26 14:22:36 +00:00
Nicolas Gallagher
5335bcfd48 [chore] docs and formatting 2015-12-26 10:40:36 +00:00
Nicolas Gallagher
c0e7afc495 [change] Touchable: default prop values from RN Touchables 2015-12-22 00:15:48 +00:00
Nicolas Gallagher
fa88548c3c Update CONTRIBUTING and README with CodePen link 2015-12-21 23:50:58 +00:00
Nicolas Gallagher
39b2b2f979 Fix unreliable TextInput tests 2015-12-20 04:26:59 -08:00
Nicolas Gallagher
fd04d65b03 0.0.12 2015-12-20 03:24:57 -08:00
Nicolas Gallagher
0ab984f507 [change] TextInput: implement placeholder and placeholderTextColor
Without access to the Shadow DOM pseudo-elements, the placeholder
behaviour needs to be reimplemented.

Update to match React Native's modification to `TextInput` to include
all `View` props and use the `Text` style props.

Fix #12
Fix #48
2015-12-20 03:11:39 -08:00
Nicolas Gallagher
3d1ad50a58 Update documentation and examples 2015-12-19 10:59:22 -08:00
Nicolas Gallagher
92554321df [add] Text: support all ViewStylePropTypes 2015-12-19 10:51:29 -08:00
Nicolas Gallagher
1c9270c4ea [fix] ReactNative export pattern 2015-12-19 10:49:49 -08:00
Nicolas Gallagher
8a5f9cd7d9 0.0.11 2015-12-19 06:04:03 -08:00
Nicolas Gallagher
aac6b796b2 Replace 'EnvironmentPlugin' with 'DefinePlugin' 2015-12-19 05:47:20 -08:00
Nicolas Gallagher
c77ce19f1b [fix] StyleSheet: escaping of class names in CSS
Fix #47
2015-12-19 04:22:00 -08:00
Nicolas Gallagher
25b74d30c4 [fix] Text: style props 2015-12-19 03:57:04 -08:00
Nicolas Gallagher
4191d58694 Fix styles in 'GridView' example 2015-12-19 03:27:44 -08:00
Nicolas Gallagher
11b861ae64 [add] support for 'list' and 'listitem' accessibilityRole mapping
Fix #49
2015-12-19 03:25:40 -08:00
Nicolas Gallagher
68bf08112a [fix] StylePropTypes: add support for 'verticalAlign'
Fix #45
2015-12-19 03:11:55 -08:00
Nicolas Gallagher
b277b3e509 [fix] StylePropTypes: add support for 'boxShadow'
Fix #44
2015-12-19 03:11:12 -08:00
Nicolas Gallagher
c135dddbd1 [fix] StyleSheet: isStyleObject check 2015-12-14 15:28:40 -08:00
Nicolas Gallagher
ffc6368162 0.0.10 2015-12-13 12:49:48 -08:00
Nicolas Gallagher
501c19fe9b [fix] StyleSheet: shorthand properties
Expand shorthand properties to preserve the one-rule-to-one-style
isolation. Resolve styles like React Native - most specific comes last.
Add support for the hz and vt properties for margin and padding.

Fix #40
2015-12-13 12:48:26 -08:00
Kirill Korolyov
e1da11fa1d [change] transparent default Image backgroundColor 2015-12-07 13:33:16 -08:00
Nicolas Gallagher
b2a4d742a9 [chore] update dependencies 2015-12-01 16:01:51 -08:00
Nicolas Gallagher
8b965fdfa0 [chore] update development dependencies 2015-12-01 15:58:04 -08:00
Nicolas Gallagher
8cfef85934 [fix] Image tests 2015-12-01 15:50:38 -08:00
Nicolas Gallagher
6db24e9358 [fix] Image: default 'resizeMode' is 'cover'
Fix #41
2015-12-01 14:44:17 -08:00
Nicolas Gallagher
13e36bee65 0.0.9 2015-10-24 12:06:37 -07:00
Nicolas Gallagher
93e8e90a1a [fix] README docs 2015-10-24 11:54:31 -07:00
Tom Ashworth
894fd0362d [add] initial ScrollView
Supports the following props: `children`, `contentContainerStyle`,
`horizontal`, `onScroll`, `scrollEnabled`, `scrollEventThrottle`, and
`style`.

Fix #6
2015-10-24 11:35:30 -07:00
Nicolas Gallagher
a1664927ce [change] initial example with media queries 2015-10-21 18:00:10 -07:00
Nicolas Gallagher
ae2abc578a [change] update dependencies 2015-10-19 18:45:33 -07:00
Nicolas Gallagher
5f7b3f5fef [change] move examples 2015-10-19 18:32:38 -07:00
Nicolas Gallagher
75f653818a [change] move tests.webpack.js 2015-10-19 18:31:27 -07:00
Nicolas Gallagher
2c52d41b75 [fix] -ms- CSS vendor prefix 2015-10-19 16:02:41 -07:00
Nicolas Gallagher
83f749d983 [change] docs on MQs and a11y 2015-10-19 10:35:42 -07:00
Nicolas Gallagher
bf5046415c [fix] doc examples 2015-10-19 09:42:30 -07:00
Nicolas Gallagher
885d4586a9 [change] obfuscated selector prefix 2015-10-18 22:15:03 -07:00
Nicolas Gallagher
ea0a778ba3 [change] add more about accessibility to docs 2015-10-18 22:11:20 -07:00
Nicolas Gallagher
0a7eda2505 [fix] remove default link styles 2015-10-18 22:09:27 -07:00
Nicolas Gallagher
35385e7b69 [change] pointerEvents CSS 2015-10-18 22:08:36 -07:00
Nicolas Gallagher
3fd29697c0 [fix] initial 'display' value of 'Text'
Using `inline-block` breaks text overflow truncation in nested `Text`
components.

Fix gh-19
2015-10-18 18:08:39 -07:00
Nicolas Gallagher
a26033be2d 0.0.8 2015-10-18 17:56:05 -07:00
Nicolas Gallagher
fdb4ee4aae [change] StyleSheet docs 2015-10-18 17:49:35 -07:00
Nicolas Gallagher
08300f624f [change] remove 'component' prop; accessibility docs
- infer underlying HTML tag from 'accessibilityRole'
- move accessibility props to 'CoreComponent'
- remove the 'component' prop from exported Components

Fix gh-23
2015-10-18 15:24:59 -07:00
Nicolas Gallagher
7f5a2807e2 [fix] avoid eslint-plugin-react@3.6.0 bug 2015-10-18 11:23:29 -07:00
Nicolas Gallagher
292f045c52 [fix] README examples 2015-10-18 11:02:36 -07:00
Nicolas Gallagher
a19b57df4d 0.0.7 2015-10-18 09:11:38 -07:00
Nicolas Gallagher
1c444569ae [change] React 0.14 support 2015-10-18 08:54:09 -07:00
Nicolas Gallagher
0b8c4b8746 [fix] link to API docs 2015-10-17 18:51:01 -07:00
Nicolas Gallagher
6772233837 [remove] Swipeable 2015-10-17 18:49:21 -07:00
Nicolas Gallagher
cd89f88d96 [add] StyleSheet API
Initial StyleSheet implementation for Web. Converts style object
declarations to "atomic" CSS rules.

Close gh-25
2015-10-17 17:52:01 -07:00
Nicolas Gallagher
b59bdb17b2 [change] Unit test setup and reporter 2015-10-17 17:51:54 -07:00
Nicolas Gallagher
2bfa579fe4 [remove] babel-plugin-typecheck 2015-10-17 17:51:30 -07:00
Nicolas Gallagher
f4c6e33b2f Fix #26 2015-10-01 15:18:28 -07:00
Nicolas Gallagher
39b273f9d8 Moves 2015-09-20 21:00:15 -07:00
Nicolas Gallagher
ec9985a3b3 0.0.6 2015-09-20 19:52:18 -07:00
Nicolas Gallagher
0aa29d8816 Image: add test for 'role=img' 2015-09-20 19:41:13 -07:00
Nicolas Gallagher
45777e0405 Add '_className' escape-hatch to Text and View 2015-09-20 19:31:59 -07:00
Nicolas Gallagher
84e06564d4 Accessibility fixes for Image and Text 2015-09-20 19:21:01 -07:00
Nicolas Gallagher
1d1b633317 npm-script: fix 'test' 2015-09-20 16:40:46 -07:00
Nicolas Gallagher
565ec2fee8 Docs: minor update 2015-09-20 15:50:22 -07:00
Nicolas Gallagher
33082f988e Text: add props 'accessibilityLabel' and 'accessible'
These properties are missing in React Native but important for
accessible web interfaces.
2015-09-20 15:48:09 -07:00
Nicolas Gallagher
a2fb65a79c Touchable: activeHighlight -> activeUnderlayColor 2015-09-20 15:47:35 -07:00
Nicolas Gallagher
e727193809 TextInput: props and tests 2015-09-20 15:43:52 -07:00
Nicolas Gallagher
d6db206ec4 Fix type of 'fontSize' style 2015-09-20 15:29:00 -07:00
Nicolas Gallagher
b3beea9bb3 Fix npm scripts 2015-09-20 15:25:03 -07:00
Nicolas Gallagher
ef4de789ae ScrollView: initial docs 2015-09-14 17:28:20 -07:00
Nicolas Gallagher
86037ab740 Add links to slack and gitter rooms 2015-09-14 11:51:44 -07:00
Nicolas Gallagher
6c20646f10 Touchable: add 'accessibilityRole' prop 2015-09-13 22:59:45 -07:00
Nicolas Gallagher
b5aa68dc7a specHelpers: accept props 2015-09-13 22:59:04 -07:00
Nicolas Gallagher
5668c40ee6 Don't strip testID's in production 2015-09-13 21:43:25 -07:00
Nicolas Gallagher
be86250ac6 Image: fix example code 2015-09-12 18:08:58 -07:00
Nicolas Gallagher
1e04dfc306 filterObjectProps: props -> propKeys 2015-09-12 18:08:21 -07:00
Nicolas Gallagher
283ab2fa2e Update dependencies 2015-09-12 18:07:22 -07:00
Nicolas Gallagher
09dd9a224a Remove type tests; fix code style 2015-09-11 21:28:03 -07:00
Nicolas Gallagher
c7524b7b6f Add Flow type checking; React >= 0.13 2015-09-11 21:17:48 -07:00
Nicolas Gallagher
5453c8843a Trivial edits 2015-09-09 00:48:18 -07:00
Nicolas Gallagher
e0f836ccb5 Minor example page update 2015-09-09 00:31:32 -07:00
Nicolas Gallagher
eada8e7fc7 Refactor dev workflow 2015-09-08 23:29:31 -07:00
Nicolas Gallagher
114fb5f8c7 LICENCE -> LICENSE 2015-09-08 22:44:27 -07:00
Nicolas Gallagher
4aa87c79fa Fix tests and code style 2015-09-08 14:21:17 -07:00
Nicolas Gallagher
9107fd3de9 Use more reliable npm badge host 2015-09-08 09:26:16 -07:00
Nicolas Gallagher
c72173ff88 Image: set 'resizeMode' default to 'stretch'
Fix #8
2015-09-08 00:29:53 -07:00
Nicolas Gallagher
edf0fda75a Docs: minor adjustments 2015-09-08 00:24:12 -07:00
Nicolas Gallagher
3b848fe378 View: additional accessibility props
* Add `accessibilityLiveRegion` for `aria-live` support.
* Add `accessibilityRole` for `role` support.

Fix #11
2015-09-08 00:09:09 -07:00
Nicolas Gallagher
7eff1a644e Spec helpers 2015-09-07 23:37:36 -07:00
Nicolas Gallagher
2750d70a93 Add support for 'accessible' prop 2015-09-07 22:09:16 -07:00
Nicolas Gallagher
65559f50e6 Image: fix ARIA role 2015-09-07 19:16:58 -07:00
Nicolas Gallagher
77fd21ea44 Touchable: add support for 'style' and keyboard 2015-09-07 14:40:37 -07:00
Nicolas Gallagher
38e4de76cd Documentation edits; transfer props 2015-09-07 13:14:09 -07:00
Nicolas Gallagher
0f42cd83e1 Component stylePropTypes keys as constants 2015-09-07 13:00:59 -07:00
Nicolas Gallagher
e6cbea82c4 Don't optimize published package 2015-09-07 12:59:16 -07:00
Nicolas Gallagher
6d4c9e881f Move CoreComponent module 2015-09-07 12:58:48 -07:00
311 changed files with 29338 additions and 3122 deletions

View File

@@ -1,7 +1,8 @@
{
"optional": [
"es7.classProperties",
"runtime"
"presets": [
"react-native"
],
"stage": 1
"plugins": [
[ "transform-react-remove-prop-types", { "mode": "wrap" } ]
]
}

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
# EditorConfig: http://editorconfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

View File

@@ -1,2 +0,0 @@
dist
docs

148
.eslintrc
View File

@@ -1,17 +1,147 @@
{
// babel parser to support ES features
// babel parser to support ES6/7 features
"parser": "babel-eslint",
// based on https://github.com/feross/standard
"extends": [ "standard", "standard-react" ],
"parserOptions": {
"ecmaVersion": 7,
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
},
"extends": [
"prettier",
"prettier/react"
],
"plugins": [
"promise",
"react"
],
"env": {
"mocha": true
"es6": true,
"node": true
},
"globals": {
"document": false,
"navigator": false,
"window": false
},
"rules": {
// overrides of the standard style
"space-before-function-paren": [ 2, { "anonymous": "always", "named": "never" } ],
"wrap-iife": [ 2, "outside" ],
// overrides of the standard-react style
"camelcase": 0,
"constructor-super": 2,
"default-case": [2, { commentPattern: '^no default$' }],
"eqeqeq": [2, "allow-null"],
"handle-callback-err": [2, "^(err|error)$" ],
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
"no-alert": 1,
"no-array-constructor": 2,
"no-caller": 2,
"no-case-declarations": 2,
"no-class-assign": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-duplicate-imports": 2,
"no-empty-character-class": 2,
"no-empty-pattern": 2,
"no-eval": 2,
"no-ex-assign": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-extra-boolean-cast": 2,
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-func-assign": 2,
"no-implied-eval": 2,
"no-inner-declarations": [2, "functions"],
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
"no-lone-blocks": 2,
"no-loop-func": 2,
"no-multi-str": 2,
"no-native-reassign": 2,
"no-negated-in-lhs": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-new-require": 2,
"no-new-symbol": 2,
"no-new-wrappers": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-path-concat": 2,
"no-proto": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-return-assign": [2, "except-parens"],
"no-script-url": 2,
"no-self-assign": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-shadow-restricted-names": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-throw-literal": 2,
"no-undef": 2,
"no-undef-init": 2,
"no-unexpected-multiline": 2,
"no-unmodified-loop-condition": 2,
"no-unneeded-ternary": [2, { "defaultAssignment": false }],
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
"no-useless-call": 2,
"no-useless-computed-key": 2,
"no-useless-concat": 2,
"no-useless-constructor": 2,
"no-useless-escape": 2,
"no-var": 2,
"no-with": 2,
"prefer-const": 2,
"prefer-rest-params": 2,
"quotes": [2, "single", "avoid-escape"],
"radix": 2,
"use-isnan": 2,
"valid-typeof": 2,
"yoda": [2, "never"],
// promise
"promise/param-names": 2,
// react
"react/display-name": 0,
"react/jsx-handler-names": [2, {
"eventHandlerPrefix": "_handle"
}],
"react/jsx-no-bind": 2,
"react/jsx-no-duplicate-props": 2,
"react/jsx-no-undef": 2,
"react/jsx-pascal-case": 2,
"react/jsx-sort-props": 2,
"react/jsx-sort-prop-types": 2
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 2,
"react/no-direct-mutation-state": 2,
"react/no-multi-comp": 0,
"react/no-string-refs": 2,
"react/no-unknown-property": 2,
"react/prefer-es6-class": 2,
"react/prop-types": 2,
"react/react-in-jsx-scope": 0,
"react/self-closing-comp": 2,
"react/sort-comp": 0,
"react/sort-prop-types": 2,
"react/wrap-multilines": 0
}
}

30
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,30 @@
<!--
React Native for Web is an implementation of React Native. If you have feature
requests, you should post them to https://productpains.com/product/react-native/.
GitHub issues should only be used for bugs or Web-specific features you believe
React Native requires.
Make sure to add ALL the information needed to understand the bug so that
someone can help. If the info is missing we'll add the 'needs more information'
label and close the issue until there is enough information.
-->
**What is the current behavior?**
Link to minimal test case: (template: [codepen](https://codepen.io/necolas/pen/PZzwBR?editors=0010))
**What is the expected behaviour?**
**Steps to reproduce**
1.
2.
**Environment (include versions)**
OS:
Device:
Browser:
React Native for Web (version):
React (version):

18
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,18 @@
<!--
Thanks for submitting a pull request! Make sure the PR does only one thing.
Please provide enough information so that others can review your pull
request. Make sure you have read the Contributing Guidelines -
https://github.com/necolas/react-native-web/CONTRIBUTING.md
-->
**This patch solves the following problem**
**Test plan**
**This pull request**
- [ ] includes documentation
- [ ] includes tests
- [ ] includes benchmark reports
- [ ] includes an interactive example
- [ ] includes screenshots/videos

5
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/dist
/node_modules
node_modules
dist
dist-examples

View File

@@ -1,6 +1,8 @@
language: node_js
node_js:
- "0.12"
- "6"
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script:
- npm test

View File

@@ -1,125 +1,88 @@
# Contributing to this project
# Contributing
The issue tracker is the preferred channel for [bug reports](#bugs),
[features requests](#features) and [submitting pull
requests](#pull-requests).
## Reporting Issues and Asking Questions
<a name="bugs"></a>
## Bug reports
Before opening an issue, please search the [issue
tracker](https://github.com/necolas/react-native-web/issues) to make sure your
issue hasn't already been reported.
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!
## Development
Guidelines for bug reports:
Visit the [Issue tracker](https://github.com/necolas/react-native-web/issues)
to find a list of open issues that need attention.
1. **Use the GitHub issue search** &mdash; check if the issue has already been
reported.
Fork, then clone the repo:
2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
latest `master` or development branch in the repository.
```
git clone https://github.com/your-username/react-native-web.git
```
3. **Isolate the problem** &mdash; create a [reduced test
case](http://css-tricks.com/reduced-test-cases/) and a live example.
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
A good bug report contains as much detail as possible. What is your
environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? What would you expect to be the outcome? All these
details really help!
```
yarn
```
Example:
Run the examples:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
```
npm run examples
```
Run the benchmarks in a browser by opening `./performance/index.html` after running:
<a name="features"></a>
## Feature requests
```
npm run build:performance
```
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.
### Building
```
npm run build
```
<a name="pull-requests"></a>
## Pull requests
To create a UMD build:
Good pull requests - patches, improvements, new features - are a fantastic
help. Please keep them focused in scope and avoid containing unrelated commits.
```
npm run build:umd
```
**Please ask first** before embarking on any significant pull request (e.g.
implementing new features or components, refactoring code), otherwise you risk
spending a lot of time working on something that the project's developers might
not want to merge into the project.
### Testing and Linting
Development commands:
To run the tests:
* `npm start` start the dev server and develop against live examples
* `npm run lint` run the linter
* `npm run specs` run the unit tests
* `npm run build` generate a build
```
npm run test
```
Please follow this process for submitting a patch:
To continuously watch and run tests, run the following:
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
and configure the remotes:
```
npm run test:watch
```
```bash
# Clone your fork of the repo into the current directory
git clone https://github.com/<your-username>/react-native-web
# Navigate to the newly cloned directory
cd react-native-web
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/necolas/react-native-web
```
To perform only linting, run the following:
2. If you cloned a while ago, get the latest changes from upstream:
```
npm run lint
```
```bash
git checkout master
git pull upstream master
```
### New Features
3. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
Please open an issue with a proposal for a new feature or refactoring before
starting on the work. We don't want you to waste your efforts on a pull request
that we won't want to accept.
```bash
git checkout -b <topic-branch-name>
```
## Submitting Changes
4. Commit your changes in logical chunks. Please adhere to these [git commit
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
or your code is unlikely be merged into the main project. Use Git's
[interactive rebase](https://help.github.com/articles/interactive-rebase)
feature to tidy up your commits before making them public.
* Open a new issue in the [Issue tracker](https://github.com/necolas/react-native-web/issues).
* Fork the repo.
* Create a new feature branch based off the `master` branch.
* Make sure all tests pass and there are no linting errors.
* Submit a pull request, referencing any issues it addresses.
5. Locally merge (or rebase) the upstream development branch into your topic branch:
Please try to keep your pull request focused in scope and avoid including unrelated commits.
```bash
git pull [--rebase] upstream master
```
After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements.
6. Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
with a clear title and description.
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the same license as that used by the project.
Thank you for contributing!

21
LICENCE
View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Nicolas Gallagher
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

31
LICENSE Normal file
View File

@@ -0,0 +1,31 @@
BSD License
For React Native software
Copyright (c) 2015-present, Nicolas Gallagher. All rights reserved.
Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* 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.

281
README.md
View File

@@ -3,188 +3,149 @@
[![Build Status][travis-image]][travis-url]
[![npm version][npm-image]][npm-url]
The core [React Native][react-native-url] components adapted and expanded upon
for the web, backed by a precomputed CSS library. ~19KB minified and gzipped.
[React Native][react-native-url] components and APIs for the Web.
## Table of contents
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
* [Install](#install)
* [Use](#use)
* [Components](#components)
* [Styling](#styling)
* [Contributing](#contributing)
* [Thanks](#thanks)
* [License](#license)
[npm-image]: https://badge.fury.io/js/react-native-web.svg
[npm-url]: https://npmjs.org/package/react-native-web
[react-native-url]: https://facebook.github.io/react-native/
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
[travis-url]: https://travis-ci.org/necolas/react-native-web
## Install
## Overview
"React Native for Web" is a project to bring React Native's building blocks and
touch handling to the Web. [Read more](#why).
Browse the UI Explorer to see React Native [examples running on
Web](https://necolas.github.io/react-native-web/storybook/). Or try it out
online with [React Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc).
## Quick start
To install in your app:
```
npm install --save react react-native-web
npm install --save react@15.4 react-dom@15.4 react-native-web
```
## Use
Read the [Getting Started](docs/guides/getting-started.md) guide.
React Native for Web exports its components and a reference to the `React`
installation. Styles are authored in JavaScript as plain objects.
Alternatively, you can quickly setup a local project
using [create-react-app](https://github.com/facebookincubator/create-react-app)
(which supports `react-native-web` out-of-the-box once installed) and
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter).
## Documentation
Guides:
* [Getting started](docs/guides/getting-started.md)
* [Accessibility](docs/guides/accessibility.md)
* [Direct manipulation](docs/guides/direct-manipulation.md)
* [Internationalization](docs/guides/internationalization.md)
* [Known issues](docs/guides/known-issues.md)
* [Style](docs/guides/style.md)
Exported modules:
* Components
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
* [`Button`](docs/components/Button.md)
* [`Image`](docs/components/Image.md)
* [`ListView`](docs/components/ListView.md)
* [`ProgressBar`](docs/components/ProgressBar.md)
* [`ScrollView`](docs/components/ScrollView.md)
* [`Switch`](docs/components/Switch.md)
* [`Text`](docs/components/Text.md)
* [`TextInput`](docs/components/TextInput.md)
* [`TouchableHighlight`](http://facebook.github.io/react-native/releases/0.22/docs/touchablehighlight.html) (mirrors React Native)
* [`TouchableOpacity`](http://facebook.github.io/react-native/releases/0.22/docs/touchableopacity.html) (mirrors React Native)
* [`TouchableWithoutFeedback`](docs/components/TouchableWithoutFeedback.md)
* [`View`](docs/components/View.md)
* APIs
* [`Animated`](http://facebook.github.io/react-native/releases/0.20/docs/animated.html) (mirrors React Native)
* [`AppRegistry`](docs/apis/AppRegistry.md)
* [`AppState`](docs/apis/AppState.md)
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
* [`Clipboard`](docs/apis/Clipboard.md)
* [`Dimensions`](docs/apis/Dimensions.md)
* [`I18nManager`](docs/apis/I18nManager.md)
* [`NativeMethods`](docs/apis/NativeMethods.md)
* [`NetInfo`](docs/apis/NetInfo.md)
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
* [`PixelRatio`](docs/apis/PixelRatio.md)
* [`Platform`](docs/apis/Platform.md)
* [`StyleSheet`](docs/apis/StyleSheet.md)
* [`Vibration`](docs/apis/Vibration.md)
<span id="#why"></span>
## Why?
There are many different teams at Twitter building web applications with React.
We want to share React components, libraries, and APIs between teams…much like
the OSS community tries to do. At our scale, this involves dealing with
multiple, inter-related problems including: a common way to handle style,
animation, touch, viewport adaptation, accessibility, themes, RTL layout, and
server-rendering.
This is hard to do with React DOM, as the components are essentially the same
low-level building blocks that the browser provides. However, React Native
avoids, solves, or can solve almost all these problems facing Web teams.
Central to this is React Native's JavaScript style API (not strictly
"CSS-in-JS") which avoids the key [problems with
CSS](https://speakerdeck.com/vjeux/react-css-in-js) by giving up some of the
complexity of CSS.
## Example code
```js
import React, { View } from 'react-native-web'
import React from 'react'
import { AppRegistry, Image, StyleSheet, Text, View } from 'react-native'
class MyComponent extends React.Component {
render() {
return (
<View style={styles.root} />
)
}
}
// Components
const Card = ({ children }) => <View style={styles.card}>{children}</View>
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
const Photo = ({ uri }) => <Image source={{ uri }} style={styles.image} />
const App = () => (
<Card>
<Title>App Card</Title>
<Photo uri="/some-photo.jpg" />
</Card>
)
const styles = {
root: {
borderColor: 'currentcolor'
borderWidth: '5px',
flexDirection: 'row'
height: '5em'
}
}
```
## Components
### [`Image`](docs/components/Image.md)
An accessibile image component with support for image resizing, default image,
and child content.
### [`ListView`](docs/components/ListView.md)
(TODO)
### [`ScrollView`](docs/components/ListView.md)
(TODO)
### [`Swipeable`](docs/components/Swipeable.md)
Touch bindings for swipe gestures.
### [`Text`](docs/components/Text.md)
Displays text as an inline block and supports basic press handling.
### [`TextInput`](docs/components/TextInput.md)
Accessible single- and multi-line text input via a keyboard. Supports features
### [`Touchable`](docs/components/Touchable.md)
Touch bindings for press and long press.
### [`View`](docs/components/View.md)
The fundamental UI building block: layout with flexbox, layout and positioning
styles, and accessibility controls.
## Styling
React Native for Web provides a mechanism to declare all your styles and layout
inline with the components that use them. The `View` component makes it easy to
build common layouts with flexbox, such as stacked and nested boxes with margin
and padding.
Styling is identical to using inline styles in React, but most inline styles
are converted to single-purpose classes. The current implementation includes
300+ precomputed CSS declarations (~4.5KB gzipped) that cover a large
proportion of common styles. A more sophisticated build-time implementation may
produce a slightly larger CSS file for large apps, and fall back to fewer
inline styles. Read more about the [styling
strategy](docs/style.md).
See this [guide to flexbox][flexbox-guide-url].
```js
import React, { Image, Text, View } from 'react-native-web'
class App extends React.Component {
render() {
return (
<View style={styles.row}>
<Image
source={{ uri: 'http://facebook.github.io/react/img/logo_og.png' }}
style={styles.image}
/>
<View style={styles.text}>
<Text style={styles.title}>
React Native Web
</Text>
<Text style={styles.subtitle}>
Build high quality web apps using React
</Text>
</View>
</View>
)
},
})
const styles = {
row: {
flexDirection: 'row',
margin: 40
},
image: {
height: 40,
marginRight: 10,
width: 40,
},
text: {
flex: 1,
// Styles
const styles = StyleSheet.create({
card: {
flexGrow: 1,
justifyContent: 'center'
},
title: {
fontSize: '1.25rem',
fontWeight: 'bold'
},
subtitle: {
fontSize: '1rem'
image: {
height: 40,
marginVertical: 10,
width: 40
}
}
})
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => App)
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
```
Combine and override style objects:
## Related projects
```js
import baseStyle from './baseStyle'
const buttonStyle = {
...baseStyle,
backgroundColor: '#333',
color: '#fff'
}
```
## Contributing
Please read the [contribution guidelines][contributing-url]. Contributions are
welcome!
## Thanks
Thanks to current and past members of the React and React Native teams (in
particular Vjeux and Pete Hunt), and Tobias Koppers for Webpack and CSS loader.
Thanks to [react-swipeable](https://github.com/dogfessional/react-swipeable/)
for the current implementation of `Swipeable`, and to
[react-tappable](https://github.com/JedWatson/react-tappable) for backing the
current implementation of `Touchable`.
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
* [reactxp](https://github.com/microsoft/reactxp)
* [react-web](https://github.com/taobaofed/react-web)
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
## License
Copyright (c) 2015 Nicolas Gallagher. Released under the [MIT
license](http://www.opensource.org/licenses/mit-license.php).
[contributing-url]: https://github.com/necolas/react-native-web/blob/master/CONTRIBUTING.md
[flexbox-guide-url]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
[npm-image]: https://img.shields.io/npm/v/react-native-web.svg
[npm-url]: https://npmjs.org/package/react-native-web
[react-native-url]: https://facebook.github.io/react-native/
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
[travis-url]: https://travis-ci.org/necolas/react-native-web
React Native for Web is [BSD licensed](LICENSE).

View File

@@ -1,46 +0,0 @@
var assign = require('object-assign')
var path = require('path')
var webpackConfig = require('./webpack-base.config.js')
module.exports = function (config) {
config.set({
basePath: path.resolve(__dirname, '..'),
browsers: [ process.env.TRAVIS ? 'Firefox' : 'Chrome' ],
browserNoActivityTimeout: 60000,
client: {
captureConsole: true,
mocha: {
ui: 'tdd'
},
useIframe: true
},
files: [
'src/specs.bundle.js'
],
frameworks: [
'mocha'
],
plugins: [
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-mocha',
'karma-sourcemap-loader',
'karma-webpack'
],
preprocessors: {
'src/specs.bundle.js': [ 'webpack', 'sourcemap' ]
},
reporters: [ 'dots' ],
singleRun: true,
webpack: assign({}, webpackConfig, { devtool: 'inline' }),
webpackMiddleware: {
stats: {
assetsSort: 'name',
colors: true,
children: false,
chunks: false,
modules: false
}
}
})
}

View File

@@ -1,23 +0,0 @@
var autoprefixer = require('autoprefixer-core')
module.exports = {
module: {
loaders: [
{
test: /\.css$/,
loader: [
'style-loader',
'css-loader?module&localIdentName=[hash:base64:5]',
'!postcss-loader'
].join('!')
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
}
]
},
postcss: [ autoprefixer ]
}

View File

@@ -1,34 +0,0 @@
var assign = require('object-assign')
var base = require('./webpack-base.config.js')
var webpack = require('webpack')
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
var plugins = []
if (process.env.NODE_ENV === 'production') {
plugins.push(
new UglifyJsPlugin({
compress: {
dead_code: true,
drop_console: true,
screw_ie8: true,
warnings: true
}
})
)
}
module.exports = assign({}, base, {
entry: {
main: './src/index'
},
externals: [{
react: true
}],
output: {
filename: 'react-native-web.js',
library: 'ReactNativeWeb',
libraryTarget: 'commonjs2',
path: './dist'
},
plugins: plugins
})

1
core.js Normal file
View File

@@ -0,0 +1 @@
module.exports = require('./dist/core')

59
docs/apis/AppRegistry.md Normal file
View File

@@ -0,0 +1,59 @@
# AppRegistry
`AppRegistry` is the control point for registering, running, prerendering, and
unmounting all apps. App root components should register themselves with
`AppRegistry.registerComponent`. Apps can be run by invoking
`AppRegistry.runApplication` (see the [client and server rendering
guide](../guides/rendering.md) for more details).
To "stop" an application when a view should be destroyed, call
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
into `runApplication`. These should always be used as a pair.
## Methods
(web) static **getApplication**(appKey:string, appParameters: object)
Returns the given application element. Use this for server-side rendering.
Return object is of type `{ element: ReactElement; stylesheet: ReactElement }`.
It's recommended that you use `sheetsheet` to render the style sheet in an app
static **registerConfig**(config: Array<AppConfig>)
Registry multiple applications. `AppConfig` is of type `{ appKey: string;
component: ComponentProvider; run?: Function }`.
static **registerComponent**(appKey: string, getComponentFunc: ComponentProvider)
Register a component provider under the given `appKey`.
static **registerRunnable**(appKey: string, run: Function)
Register a custom render function for an application. The function will receive
the `appParameters` passed to `runApplication`.
static **getAppKeys**()
Returns all registered app keys.
static **runApplication**(appKey: string, appParameters?: object)
Runs the application that was registered under `appKey`. The `appParameters`
must include the `rootTag` into which the application is rendered, and
optionally any `initialProps`.
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
To "stop" an application when a view should be destroyed, call
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
into `runApplication`
## Example
```js
AppRegistry.registerComponent('MyApp', () => AppComponent)
AppRegistry.runApplication('MyApp', {
initialProps: {},
rootTag: document.getElementById('react-root')
})
```

60
docs/apis/AppState.md Normal file
View File

@@ -0,0 +1,60 @@
## AppState
`AppState` can tell you if the app is in the foreground or background, and
notify you when the state changes.
States
* `active` - The app is running in the foreground
* `background` - The app is running in the background (i.e., the user has not focused the app's tab).
## Properties
static **currentState**
Returns the current state of the app: `active` or `background`.
## Methods
static **addEventListener**(type: string, handler: Function)
Add a handler to `AppState` changes by listening to the `change` event type and
providing the `handler`. The handler is called with the app state value.
static **removeEventListener**(type: string, handler: Function)
Remove a handler by passing the change event `type` and the `handler`.
## Examples
To see the current state, you can check `AppState.currentState`, which will be
kept up-to-date. This example will only ever appear to say "Current state is:
active" because the app is only visible to the user when in the `active` state,
and the null state will happen only momentarily.
```js
class Example extends React.Component {
constructor(props) {
super(props)
this.state = { currentAppState: AppState.currentState }
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (currentAppState) => {
this.setState({ currentAppState });
}
render() {
return (
<Text>Current state is: {this.state.currentAppState}</Text>
)
}
}
```

71
docs/apis/AsyncStorage.md Normal file
View File

@@ -0,0 +1,71 @@
# AsyncStorage
`AsyncStorage` is a simple, asynchronous, persistent, key-value storage system
that is global to the domain. It's a facade over, and should be used instead of
`window.localStorage` to provide an asynchronous API and multi functions. Each
method returns a `Promise` object.
It is recommended that you use an abstraction on top of `AsyncStorage` instead
of `AsyncStorage` directly for anything more than light usage since it operates
globally.
The batched functions are useful for executing a lot of operations at once,
allowing for optimizations to provide the convenience of a single promise after
all operations are complete.
## Methods
static **clear**()
Erases all AsyncStorage. You probably don't want to call this - use
`removeItem` or `multiRemove` to clear only your own keys instead. Returns a
Promise object.
static **getAllKeys**()
Gets all known keys. Returns a Promise object.
static **getItem**(key: string)
Fetches the value of the given key. Returns a Promise object.
static **mergeItem**(key: string, value: string)
Merges existing value with input value, assuming they are stringified JSON.
Returns a Promise object.
static **multiGet**(keys: Array<string>)
`multiGet` results in an array of key-value pair arrays that matches the input
format of `multiSet`. Returns a Promise object.
```js
multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
```
static **multiMerge**(keyValuePairs: Array<Array<string>>)
multiMerge takes an array of key-value array pairs that match the output of
`multiGet`. It merges existing values with input values, assuming they are
stringified JSON. Returns a Promise object.
static **multiRemove**(keys: Array<string>)
Delete all the keys in the keys array. Returns a Promise object.
static **multiSet**(keyValuePairs: Array<Array<string>>)
`multiSet` takes an array of key-value array pairs that match the output of
`multiGet`. Returns a Promise object.
```js
multiSet([['k1', 'val1'], ['k2', 'val2']]);
```
static **removeItem**(key: string)
Removes the value of the given key. Returns a Promise object.
static **setItem**(key: string, value: string)
Sets the value of the given key. Returns a Promise object.

16
docs/apis/Clipboard.md Normal file
View File

@@ -0,0 +1,16 @@
# Clipboard
Clipboard gives you an interface for setting to the clipboard. (Getting
clipboard content is not supported on web.)
## Methods
static **getString**()
Returns a `Promise` of an empty string.
static **setString**(content: string): boolean
Copies a string to the clipboard. On web, some browsers may not support copying
to the clipboard, therefore, this function returns a boolean to indicate if the
copy was successful.

13
docs/apis/Dimensions.md Normal file
View File

@@ -0,0 +1,13 @@
# Dimensions
Note: dimensions may change (e.g due to device rotation) so any rendering logic
or styles that depend on these constants should try to call this function on
every render, rather than caching the value.
## Methods
static **get**(dimension: string)
Get a dimension (e.g., `"window"` or `"screen"`).
Example: `const { height, width } = Dimensions.get('window')`

25
docs/apis/I18nManager.md Normal file
View File

@@ -0,0 +1,25 @@
# I18nManager
Control and set the layout and writing direction of the application.
## Properties
**isRTL**: bool = false
Whether the application is currently in RTL mode.
## Methods
static **allowRTL**(allowRTL: bool)
Allow the application to display in RTL mode.
static **forceRTL**(forceRTL: bool)
Force the application to display in RTL mode.
static **setPreferredLanguageRTL**(isRTL: bool)
Set the application's preferred writing direction to RTL. You will need to
determine the user's preferred locale server-side (from HTTP headers) and
decide whether it's an RTL language.

View File

@@ -0,0 +1,42 @@
# NativeMethods
React Native for Web provides several methods to directly access the underlying
DOM node. This can be useful in cases when you want to focus a view or measure
its on-screen dimensions, for example.
The methods described are available on most of the default components provided
by React Native for Web. Note, however, that they are *not* available on the
composite components that you define in your own app. For more information, see
[Direct Manipulation](../guides/direct-manipulation.md).
## Methods
**blur**()
Removes focus from an input or view. This is the opposite of `focus()`.
**focus**()
Requests focus for the given input or view. The exact behavior triggered will
depend the type of view.
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
For a given view, `measure` determines the offset relative to the parent view,
width, height, and the offset relative to the viewport. Returns the values via
an async callback.
Note that these measurements are not available until after the rendering has
been completed.
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
Like `measure`, but measures the view relative to another view, specified as
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
the origin `x`, `y` of the ancestor view.
**setNativeProps**(nativeProps: Object)
This function sends props straight to the underlying DOM node. See the [direct
manipulation](../guides/direct-manipulation.md) guide for cases where
`setNativeProps` should be used.

77
docs/apis/NetInfo.md Normal file
View File

@@ -0,0 +1,77 @@
# NetInfo
`NetInfo` asynchronously determines the online/offline status of the
application.
Connection types:
* `bluetooth` - The user agent is using a Bluetooth connection.
* `cellular` - The user agent is using a cellular connection (e.g., EDGE, HSPA, LTE, etc.).
* `ethernet` - The user agent is using an Ethernet connection.
* `mixed` - The user agent is using multiple connection types.
* `none` - The user agent will not contact the network (offline).
* `other` - The user agent is using a connection type that is not one of enumerated connection types.
* `unknown` - The user agent has established a network connection, but is unable to determine what is the underlying connection technology.
* `wifi` - The user agent is using a Wi-Fi connection.
* `wimax` - The user agent is using a WiMAX connection.
## Methods
Note that support for retrieving the connection type depends upon browswer
support (and is limited to mobile browsers). It will default to `unknown` when
support is missing.
static **addEventListener**(eventName: ChangeEventName, handler: Function)
static **fetch**(): Promise
static **removeEventListener**(eventName: ChangeEventName, handler: Function)
## Properties
**isConnected**: bool = true
Available on all user agents. Asynchronously fetch a boolean to determine
internet connectivity.
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
**isConnected.fetch**(): Promise
**isConnected.removeEventListener**(eventName: ChangeEventName, handler: Function)
## Examples
Fetching the connection type:
```js
NetInfo.fetch().then((connectionType) => {
console.log('Connection type:', connectionType);
});
```
Subscribing to changes in the connection type:
```js
const handleConnectivityTypeChange = (connectionType) => {
console.log('Current connection type:', connectionType);
}
NetInfo.addEventListener('change', handleConnectivityTypeChange);
```
Fetching the connection status:
```js
NetInfo.isConnected.fetch().then((isConnected) => {
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
});
```
Subscribing to changes in the connection status:
```js
const handleConnectivityStatusChange = (isConnected) => {
console.log('Current connection status:', (isConnected ? 'online' : 'offline'));
}
NetInfo.isConnected.addEventListener('change', handleConnectivityStatusChange);
```

51
docs/apis/PixelRatio.md Normal file
View File

@@ -0,0 +1,51 @@
# PixelRatio
`PixelRatio` gives access to the device pixel density.
## Methods
static **get**()
Returns the device pixel density. Some examples:
* PixelRatio.get() === 1
* mdpi Android devices (160 dpi)
* PixelRatio.get() === 1.5
* hdpi Android devices (240 dpi)
* PixelRatio.get() === 2
* iPhone 4, 4S
* iPhone 5, 5c, 5s
* iPhone 6
* xhdpi Android devices (320 dpi)
* PixelRatio.get() === 3
* iPhone 6 plus
* xxhdpi Android devices (480 dpi)
* PixelRatio.get() === 3.5
* Nexus 6
static **getPixelSizeForLayoutSize**(layoutSize: number)
Converts a layout size (dp) to pixel size (px). Guaranteed to return an integer
number.
static **roundToNearestPixel**(layoutSize: number)
Rounds a layout size (dp) to the nearest layout size that corresponds to an
integer number of pixels. For example, on a device with a PixelRatio of 3,
`PixelRatio.roundToNearestPixel(8.4)` = `8.33`, which corresponds to exactly
`(8.33 * 3)` = `25` pixels.
## Examples
Fetching a correctly sized image. You should get a higher resolution image if
you are on a high pixel density device. A good rule of thumb is to multiply the
size of the image you display by the pixel ratio.
```js
const image = getImage({
width: PixelRatio.getPixelSizeForLayoutSize(200),
height: PixelRatio.getPixelSizeForLayoutSize(100),
});
<Image source={image} style={{ width: 200, height: 100 }} />
```

45
docs/apis/Platform.md Normal file
View File

@@ -0,0 +1,45 @@
# Platform
Detect what is the platform in which the app is running. This piece of
functionality can be useful when only small parts of a component are platform
specific.
## Properties
**OS**: string
`Platform.OS` will be `web` when running in a Web browser.
```js
import { Platform } from 'react-native';
const styles = StyleSheet.create({
height: (Platform.OS === 'web') ? 200 : 100,
});
```
## Methods
**select**(object): any
`Platform.select` takes an object containing `Platform.OS` as keys and returns
the value for the platform you are currently running on.
```js
import { Platform } from 'react-native';
const containerStyles = {
flex: 1,
...Platform.select({
android: {
backgroundColor: 'blue'
},
ios: {
backgroundColor: 'red'
},
web: {
backgroundColor: 'green'
}
})
});
```

78
docs/apis/StyleSheet.md Normal file
View File

@@ -0,0 +1,78 @@
# StyleSheet
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
CSS without requiring a compile-time step. Some styles cannot be resolved
outside of the render loop and are applied as inline styles. Read more about
[how to style your application](../guides/style.md).
## Methods
**create**(obj: {[key: string]: any})
Each key of the object passed to `create` must define a style object.
**flatten**: function
Flattens an array of styles into a single style object.
**renderToString**: function
Returns a string of the stylesheet for use in server-side rendering.
## Properties
**absoluteFill**: number
A very common pattern is to create overlays with position absolute and zero positioning,
so `absoluteFill` can be used for convenience and to reduce duplication of these repeated
styles.
```js
<View style={StyleSheet.absoluteFill} />
```
**absoluteFillObject**: object
Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be
used to create a customized entry in a `StyleSheet`, e.g.:
```js
const styles = StyleSheet.create({
wrapper: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'transparent',
top: 10
}
})
```
**hairlineWidth**: number
## Example
```js
<View style={styles.container}>
<Text
children={'Title text'}
style={[
styles.title,
this.props.isActive && styles.activeTitle
]}
/>
</View>
const styles = StyleSheet.create({
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
},
title: {
fontSize: 19,
fontWeight: 'bold',
},
activeTitle: {
color: 'red',
}
})
```

35
docs/apis/Vibration.md Normal file
View File

@@ -0,0 +1,35 @@
# Vibration
Vibration is described as a pattern of on-off pulses, which may be of varying
lengths. The pattern may consist of either a single integer, describing the
number of milliseconds to vibrate, or an array of integers describing a pattern
of vibrations and pauses. Vibration is controlled with a single method:
`Vibration.vibrate()`.
The vibration is asynchronous so this method will return immediately. There
will be no effect on devices that do not support vibration.
## Methods
static **cancel**()
Stop the vibration.
static **vibrate**(pattern)
Start the vibration pattern.
## Examples
Vibrate once for 200ms:
```js
Vibration.vibrate(200);
Vibration.vibrate([200]);
```
Vibrate for 200ms, pause for 100ms, vibrate for 200ms:
```js
Vibration.vibrate([200, 100, 200]);
```

View File

@@ -0,0 +1,70 @@
# ActivityIndicator
## Props
[...View props](./View.md)
**animating**: boolean = true
Whether to show the indicator or hide it.
**color**: ?color = '#1976D2'
The foreground color of the spinner.
**hidesWhenStopped**: ?boolean = true
Whether the indicator should hide when not animating.
**size**: ?enum('small, 'large') | number = 'small'
Size of the indicator. Small has a height of `20`, large has a height of `36`.
## Examples
```js
import React, { Component } from 'react'
import { ActivityIndicator, StyleSheet, View } from 'react-native'
class ToggleAnimatingActivityIndicator extends Component {
constructor(props) {
super(props)
this.state = { animating: true }
}
componentDidMount: function() {
this.setToggleTimeout();
}
render() {
return (
<ActivityIndicator
animating={this.state.animating}
size="large"
style={[styles.centering, { height: 80 }]}
/>
);
}
_setToggleTimeout() {
setTimeout(() => {
this.setState({ animating: !this.state.animating })
this._setToggleTimeout()
}, 1200)
}
})
const styles = StyleSheet.create({
centering: {
alignItems: 'center',
justifyContent: 'center'
},
gray: {
backgroundColor: '#cccccc'
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around'
}
})
```

43
docs/components/Button.md Normal file
View File

@@ -0,0 +1,43 @@
# Button
A basic button component. Supports a minimal level of customization. You can
build your own custom button using `TouchableOpacity` or
`TouchableNativeFeedback`.
## Props
**accessibilityLabel**: ?string
Overrides the text that's read by a screen reader when the user interacts
with the element.
**color**: ?string
Background color of the button.
**disabled**: ?boolean
If `true`, disable all interactions for this element.
**onPress**: function
This function is called on press.
testID: ?string
Used to locate this view in end-to-end tests.
**title**: string
Text to display inside the button.
## Examples
```js
<Button
accessibilityLabel="Learn more about this purple button"
color="#841584"
onPress={onPressLearnMore}
title="Learn More"
/>
```

View File

@@ -3,75 +3,107 @@
An accessibile image component with support for image resizing, default image,
and child content.
Unsupported React Native props:
`capInsets` (ios),
`onProgress` (ios)
## Props
**accessibilityLabel** string
**accessibilityLabel**: ?string
The text that's read by the screen reader when the user interacts with the image.
The text that's read by a screenreader when someone interacts with the image.
**children** any
**accessible**: ?boolean
When `true`, indicates the image is an accessibility element.
**children**: ?any
Content to display over the image.
**defaultSource** { uri: string }
**defaultSource**: ?object
An image to display as a placeholder while downloading the final image off the network.
An image to display as a placeholder while downloading the final image off the
network. `{ uri: string, width, height }`
**onError** function
**onError**: ?function
Invoked on load error with `{nativeEvent: {error}}`.
**onLoad** function
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onLoad**: ?function
Invoked when load completes successfully.
**onLoadEnd** function
**onLoadEnd**: ?function
Invoked when load either succeeds or fails,
**onLoadStart** function
**onLoadStart**: ?function
Invoked on load start.
**resizeMode** oneOf('clip', 'contain', 'cover', 'stretch')
**resizeMode**: ?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
Determines how to resize the image when the frame doesn't match the raw image
dimensions. Default: `cover`.
dimensions.
**source** { uri: string }
**source**: ?object
`uri` is a string representing the resource identifier for the image, which
could be an http address or a base64 encoded image.
could be an http address or a base64 encoded image. `{ uri: string, width, height }`
**style** style
**style**: ?style
[View](View.md) style
+ ...[View#style](./View.md)
+ `resizeMode`
Defaults:
```js
{
alignSelf: 'flex-start',
backgroundColor: 'lightGray'
}
```
**testID** string
**testID**: ?string
Used to locate a view in end-to-end tests.
## Properties
static **resizeMode**: object
Example usage:
```
<Image resizeMode={Image.resizeMode.contain} />
```
## Methods
static **getSize**(uri: string, success: (width, height) => {}, failure: function)
Retrieve the width and height (in pixels) of an image prior to displaying it.
This method can fail if the image cannot be found, or fails to download.
(In order to retrieve the image dimensions, the image may first need to be
loaded or downloaded, after which it will be cached. This means that in
principle you could use this method to preload images, however it is not
optimized for that purpose, and may in future be implemented in a way that does
not fully load/download the image data.)
static **prefetch**(url: string): Promise
Prefetches a remote image for later use by downloading it.
## Examples
```js
import placeholderAvatar from './placeholderAvatar.png'
import React, { Image } from 'react-native-web'
import React, { Component } from 'react'
import { Image, PropTypes, StyleSheet } from 'react-native'
const { Component, PropTypes } = React;
class Avatar extends Component {
export default class ImageExample extends Component {
constructor(props, context) {
super(props, context)
this.state = { isLoaded: false }
this.state = { loading: true }
}
static propTypes = {
@@ -86,12 +118,12 @@ class Avatar extends Component {
_onLoad(e) {
console.log('Avatar.onLoad', e)
this.setState({ isLoaded: true })
this.setState({ loading: false })
}
render() {
const { size, testID, user } = this.props
const { isLoaded } = this.state
const loadingStyle = this.state.loading ? { styles.loading } : { }
return (
<Image
@@ -100,33 +132,36 @@ class Avatar extends Component {
onLoad={this._onLoad.bind(this)}
resizeMode='cover'
source={{ uri: user.avatarUrl }}
style={ ...style.base, ...style[size], ...style[isLoaded] }
style={[
styles.base,
styles[size],
loadingStyle
]}
/>
)
}
}
const style = {
const styles = StyleSheet.create({
base: {
borderColor: 'white',
borderRadius: '5px',
borderWidth: '5px',
opacity: 0.5,
borderRadius: 5,
borderWidth: 5
},
loading: {
opacity: 0.5
},
small: {
height: '32px',
width: '32px'
height: 32,
width: 32
},
normal: {
height: '48px',
width: '48px'
height: 48,
width: 48
},
large: {
height: '64px',
width: '64px'
height: 64,
width: 64
}
isLoaded: {
opacity: 1
}
}
})
```

View File

@@ -1,36 +1,29 @@
# ListView
TODO
## Props
**children** any
[...ScrollView props](./ScrollView.md)
**children**: any
Content to display over the image.
**style** style
+ `property` type
Defaults:
```js
{
}
```
**style**: style
+ ...[View#style](View.md)
## Examples
```js
import React, { ListView } from 'react-native-web'
import React, { Component, PropTypes } from 'react'
import { ListView } from 'react-native'
const { Component, PropTypes } = React;
export default class ListViewExample extends Component {
static propTypes = {}
class Example extends Component {
static propTypes = {
}
static defaultProps = {
}
static defaultProps = {}
render() {
return (

View File

@@ -0,0 +1,27 @@
# ProgressBar
Display an activity progress bar.
## Props
[...View props](./View.md)
**color**: ?string = '#1976D2'
Color of the progress bar.
**indeterminate**: ?boolean = true
Whether the progress bar will show indeterminate progress.
**progress**: ?number
The progress value (between 0 and 1).
**testID**: ?string
Used to locate this view in end-to-end tests.
(web) **trackColor**: ?string = 'transparent'
Color of the track bar.

View File

@@ -1,40 +1,134 @@
# ScrollView
A scrollable `View` that provides itegration with the touch-locking "responder"
system. `ScrollView`'s must have a bounded height: either set the height of the
view directly (discouraged) or make sure all parent views have bounded height
(e.g., transfer `{ flex: 1}` down the view stack).
## Props
**children** any
[...View props](./View.md)
Content to display over the image.
**contentContainerStyle**: ?style
**style** style
These styles will be applied to the scroll view content container which wraps
all of the child views.
+ `property` type
**horizontal**: ?boolean = false
Defaults:
When `true`, the scroll view's children are arranged horizontally in a row
instead of vertically in a column.
**keyboardDismissMode**: ?enum('none', 'on-drag') = 'none'
Determines whether the keyboard gets dismissed in response to a scroll drag.
* `none` (the default), drags do not dismiss the keyboard.
* `on-drag`, the keyboard is dismissed when a drag begins.
* `interactive` (not supported on web; same as `none`)
**onContentSizeChange**: ?function
Called when scrollable content view of the `ScrollView` changes. It's
implemented using the `onLayout` handler attached to the content container
which this `ScrollView` renders.
**onScroll**: ?function
Fires at most once per frame during scrolling. The frequency of the events can
be contolled using the `scrollEventThrottle` prop.
Invoked on scroll with the following event:
```js
{
nativeEvent: {
contentOffset: { x, y },
contentSize: { height, width },
layoutMeasurement: { height, width }
}
}
```
**refreshControl**: ?element
TODO
A [RefreshControl](../RefreshControl) component, used to provide
pull-to-refresh functionality for the `ScrollView`.
**scrollEnabled**: ?boolean = true
When false, the content does not scroll.
**scrollEventThrottle**: ?number = 0
This controls how often the scroll event will be fired while scrolling (as a
time interval in ms). A lower number yields better accuracy for code that is
tracking the scroll position, but can lead to scroll performance problems. The
default value is `0`, which means the scroll event will be sent only once each
time the view is scrolled.
## Instance methods
**getInnerViewNode()**: any
Returns a reference to the underlying content container DOM node within the `ScrollView`.
**getScrollableNode()**: any
Returns a reference to the underlying scrollable DOM node.
**getScrollResponder()**: Component
Returns a reference to the underlying scroll responder, which supports
operations like `scrollTo`. All `ScrollView`-like components should implement
this method so that they can be composed while providing access to the
underlying scroll responder's methods.
**scrollTo(options: { x: number = 0; y: number = 0; animated: boolean = true })**
Scrolls to a given `x`, `y` offset (animation is not currently supported).
## Examples
```js
import React, { ScrollView } from 'react-native-web'
import React, { Component } from 'react'
import { ScrollView, StyleSheet } from 'react-native'
import Item from './Item'
const { Component, PropTypes } = React;
class Example extends Component {
static propTypes = {
export default class ScrollViewExample extends Component {
constructor(props, context) {
super(props, context)
this.state = {
items: Array.from(new Array(20)).map((_, i) => ({ id: i }))
}
}
static defaultProps = {
onScroll(e) {
console.log(e)
}
render() {
return (
<ScrollView
children={this.state.items.map((item) => <Item {...item} />)}
contentContainerStyle={styles.container}
horizontal
onScroll={(e) => this.onScroll(e)}
scrollEventThrottle={100}
style={styles.root}
/>
)
}
}
const styles = StyleSheet.create({
root: {
borderWidth: 1
},
container: {
padding: 10
}
})
```

View File

@@ -1,93 +0,0 @@
# Swipeable
## Props
**delta** number
Number of pixels that must be swiped before events are dispatched. Default: `10`.
**flickThreshold** number
The velocity threshold at which a swipe is considered a flick. Default: `0.6`.
**onSwiped** function
(SyntheticTouchEvent, deltaX, deltaY, isFlick) => swipeHandler
Called once a swipe has ended.
**onSwipedDown** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called once a swipe-down has ended.
**onSwipedLeft** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called once a swipe-left has ended.
**onSwipedUp** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called once a swipe-up has ended.
**onSwipedRight** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called once a swipe-right has ended.
**onSwipingDown** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called while a swipe-down is in progress.
**onSwipingLeft** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called while a swipe-left is in progress.
**onSwipingRight** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called while a swipe-right is in progress.
**onSwipingUp** function
(SyntheticTouchEvent, delta, isFlick) => swipeHandler
Called while a swipe-up is in progress.
## Examples
```js
import React, { Swipeable } from 'react-native-web'
const { Component, PropTypes } = React;
class Example extends Component {
static propTypes = {
}
static defaultProps = {
}
_onSwiped(event, x, y, isFlick) {
}
render() {
return (
<Swipeable
onSwiped={this._onSwiped.bind(this)}
/>
)
}
}
```

76
docs/components/Switch.md Normal file
View File

@@ -0,0 +1,76 @@
# Switch
This is a controlled component that requires an `onValueChange` callback that
updates the value prop in order for the component to reflect user actions. If
the `value` prop is not updated, the component will continue to render the
supplied `value` prop instead of the expected result of any user actions.
## Props
[...View props](./View.md)
**disabled**: ?boolean = false
If `true` the user won't be able to interact with the switch.
**onValueChange**: ?function
Invoked with the new value when the value changes.
**value**: ?boolean = false
The value of the switch. If `true` the switch will be turned on.
(web) **activeThumbColor**: ?color = #009688
The color of the thumb grip when the switch is turned on.
(web) **activeTrackColor**: ?color = #A3D3CF
The color of the track when the switch is turned on.
(web) **thumbColor**: ?color = #FAFAFA
The color of the thumb grip when the switch is turned off.
(web) **trackColor**: ?color = #939393
The color of the track when the switch is turned off.
## Examples
```js
import React, { Component } from 'react'
import { Switch, View } from 'react-native'
class ColorSwitchExample extends Component {
constructor(props) {
super(props)
this.state = {
colorTrueSwitchIsOn: true,
colorFalseSwitchIsOn: false
}
}
render() {
return (
<View>
<Switch
activeThumbColor='#428BCA'
activeTrackColor='#A0C4E3'
onValueChange={(value) => this.setState({ colorFalseSwitchIsOn: value })}
value={this.state.colorFalseSwitchIsOn}
/>
<Switch
activeThumbColor='#5CB85C'
activeTrackColor='#ADDAAD'
onValueChange={(value) => this.setState({ colorTrueSwitchIsOn: value })}
thumbColor='#EBA9A7'
trackColor='#D9534F'
value={this.state.colorTrueSwitchIsOn}
/>
</View>
)
}
}
```

View File

@@ -1,75 +1,128 @@
# Text
`Text` is component for displaying text. It supports style, basic touch
handling, and inherits typographic styles from ancestor elements. In a
divergence from React Native, components other than `Text` can be children of a
`Text` component.
handling, and inherits typographic styles from ancestor elements.
The `Text` is unique relative to layout: child elements use text layout
(`inline-block`) rather than flexbox layout. This means that elements inside of
a `Text` are not rectangles, as they wrap when reaching the edge of their
(`inline`) rather than flexbox layout. This means that elements inside of a
`Text` are not rectangles, as they wrap when reaching the edge of their
container.
Unsupported React Native props:
`allowFontScaling` (ios),
`suppressHighlighting` (ios)
## Props
**children** any
NOTE: `Text` will transfer all other props to the rendered HTML element.
Child content
(web) **accessibilityLabel**: ?string
**component** function, string
Overrides the text that's read by a screen reader when the user interacts
with the element. (This is implemented using `aria-label`.)
Default is `span`.
See the [Accessibility guide](../guides/accessibility) for more information.
**numberOfLines** number
(web) **accessibilityRole**: ?oneOf(roles)
Truncates the text with an ellipsis after this many lines.
Allows assistive technologies to present and support interaction with the view
in a manner that is consistent with user expectations for similar views of that
type. For example, marking a touchable view with an `accessibilityRole` of
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
**onPress** function
See the [Accessibility guide](../guides/accessibility) for more information.
**accessible**: ?boolean
When `true`, indicates that the view is an accessibility element (i.e.,
focusable) and groups its child content. By default, all the touchable elements
and elements with `accessibilityRole` of `button` and `link` are accessible.
(This is implemented using `tabindex`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**children**: ?any
Child content.
**importantForAccessibility**: ?enum('auto', 'no-hide-descendants', 'yes')
A value of `no` will remove the element from the tab flow.
A value of `no-hide-descendants` will hide the element and its children from
assistive technologies. (This is implemented using `aria-hidden`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**numberOfLines**: ?number
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onPress**: ?function
This function is called on press.
**style** style
**selectable**: ?boolean
+ `backgroundColor`
When `false`, the text is not selectable.
**style**: ?style
+ ...[View#style](View.md)
+ `color`
+ `direction`
+ `fontFamily`
+ `fontFeatureSettings`
+ `fontSize`
+ `fontStyle`
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
+ `margin`
+ `padding`
+ `textAlign`
+ `textDecoration`
+ `textTransform`
+ `textAlignVertical`
+ `textDecorationLine`
+ `textIndent`
+ `textOverflow`
+ `textRendering`
+ `textShadowColor`
+ `textShadowOffset`
+ `textShadowRadius`
+ `textTransform`
+ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
+ `wordWrap`
+ `writingDirection`
**testID** string
‡ web only.
**testID**: ?string
Used to locate this view in end-to-end tests.
## Examples
```js
import React, { Text } from 'react-native-web'
import React, { Component, PropTypes } from 'react'
import { StyleSheet, Text } from 'react-native'
const { Component, PropTypes } = React
class PrettyText extends Component {
export default class PrettyText extends Component {
static propTypes = {
...Text.propTypes,
color: PropTypes.oneOf(['white', 'gray', 'red']),
size: PropTypes.oneOf(['small', 'normal', 'large']),
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
}
};
static defaultProps = {
...Text.defaultProps,
color: 'gray',
size: 'normal',
weight: 'normal'
}
};
render() {
const { color, size, style, weight, ...other } = this.props;
@@ -77,32 +130,32 @@ class PrettyText extends Component {
return (
<Text
...other
style={{
...style,
...localStyle.color[color],
...localStyle.size[size],
...localStyle.weight[weight]
}}
style={[
style,
colorStyles[color],
sizeStyles[size],
weightStyles[weight]
]}
/>
);
}
}
const localStyle = {
color: {
white: { color: 'white' },
gray: { color: 'gray' },
red: { color: 'red' }
},
size: {
small: { fontSize: '0.85rem', padding: '0.5rem' },
normal: { fontSize: '1rem', padding: '0.75rem' },
large: { fontSize: '1.5rem', padding: '1rem' }
},
weight: {
light: { fontWeight: '300' },
normal: { fontWeight: '400' },
bold: { fontWeight: '700' }
}
}
const colorStyles = StyleSheet.create({
white: { color: 'white' },
gray: { color: 'gray' },
red: { color: 'red' }
})
const sizeStyles = StyleSheet.create({
small: { fontSize: '0.85rem', padding: '0.5rem' },
normal: { fontSize: '1rem', padding: '0.75rem' },
large: { fontSize: '1.5rem', padding: '1rem' }
})
const weightStyles = StyleSheet.create({
light: { fontWeight: '300' },
normal: { fontWeight: '400' },
bold: { fontWeight: '700' }
})
```

View File

@@ -5,107 +5,219 @@ such as auto-complete, auto-focus, placeholder text, and event callbacks.
Note: some props are exclusive to or excluded from `multiline`.
Unsupported React Native props:
`onEndEditing`,
`clearButtonMode` (ios),
`enablesReturnKeyAutomatically` (ios),
`placeholderTextColor`,
`returnKeyType` (ios),
`selectionState` (ios),
`underlineColorAndroid` (android)
## Props
**autoComplete** bool
[...View props](./View.md)
Indicates whether the value of the control can be automatically completed by the browser.
**autoCapitalize**: ?enum('characters', 'none', 'sentences', 'words') = 'sentences'
**autoFocus** bool
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
If true, focuses the input on `componentDidMount`. Only the first form element
in a document with `autofocus` is focused. Default: `false`.
* `characters`: Automatically capitalize all characters.
* `none`: Completely disables automatic capitalization
* `sentences`: Automatically capitalize the first letter of sentences.
* `words`: Automatically capitalize the first letter of words.
**defaultValue** string
(web) **autoComplete**: ?string
Indicates whether the value of the control can be automatically completed by
the browser. [Accepted values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
**autoCorrect**: ?boolean = true
Automatically correct spelling mistakes (only available in iOS Safari).
**autoFocus**: ?boolean = false
If `true`, focuses the input on `componentDidMount`. Only the first form element
in a document with `autofocus` is focused.
**blurOnSubmit**: ?boolean
If `true`, the text field will blur when submitted. The default value is `true`
for single-line fields and `false` for multiline fields. Note, for multiline
fields setting `blurOnSubmit` to `true` means that pressing return will blur
the field and trigger the `onSubmitEditing` event instead of inserting a
newline into the field.
**clearTextOnFocus**: ?boolean = false
If `true`, clears the text field automatically when focused.
**defaultValue**: ?string
Provides an initial value that will change when the user starts typing. Useful
for simple use-cases where you don't want to deal with listening to events and
updating the `value` prop to keep the controlled state in sync.
**editable** bool
**editable**: ?boolean = true
If false, text is not editable. Default: `true`.
If `false`, text is not editable (i.e., read-only).
**keyboardType** oneOf('default', 'email', 'numeric', 'search', 'tel', 'url')
**keyboardType**: enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
Determines which keyboard to open, e.g. `email`. Default: `default`. (Not
available when `multiline` is `true`.)
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
`<form action>` element to display the `search` keyboard).
**multiline** bool
(Not available when `multiline` is `true`.)
If true, the text input can be multiple lines. Default: `false`.
**maxLength**: ?number
**onBlur** function
Limits the maximum number of characters that can be entered.
**multiline**: ?boolean = false
If true, the text input can be multiple lines.
**numberOfLines**: ?number = 2
Sets the number of lines for a multiline `TextInput`.
(Requires `multiline` to be `true`.)
**onBlur**: ?function
Callback that is called when the text input is blurred.
**onChange** function
**onChange**: ?function
Callback that is called when the text input's text changes.
**onChangeText** function
**onChangeText**: ?function
Callback that is called when the text input's text changes. Changed text is
passed as an argument to the callback handler.
Callback that is called when the text input's text changes. The text is passed
as an argument to the callback handler.
**onFocus** function
**onFocus**: ?function
Callback that is called when the text input is focused.
**placeholder** string
**onKeyPress**: ?function
The string that will be rendered before text input has been entered.
Callback that is called when a key is pressed. Pressed key value is passed as
an argument to the callback handler. Fires before `onChange` callbacks.
**placeholderTextColor** string
**onSelectionChange**: ?function
The text color of the placeholder string.
Callback that is called when the text input's selection changes. This will be called with
`{ nativeEvent: { selection: { start, end } } }`.
**secureTextEntry** bool
**onSubmitEditing**: ?function
Callback that is called when the keyboard's submit button is pressed.
**placeholder**: ?string
The string that will be rendered in an empty `TextInput` before text has been
entered.
**secureTextEntry**: ?boolean = false
If true, the text input obscures the text entered so that sensitive text like
passwords stay secure. Default: `false`. (Not available when `multiline` is `true`.)
passwords stay secure.
**style** style
(Not available when `multiline` is `true`.)
[View](View.md) style
**selection**: ?{ start: number, end: ?number }
+ `color`
+ `direction`
+ `fontFamily`
+ `fontSize`
+ `fontStyle`
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
+ `textAlign`
+ `textDecoration`
+ `textTransform`
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
**testID** string
**selectTextOnFocus**: ?boolean = false
If `true`, all text will automatically be selected on focus.
**style**: ?style
+ ...[Text#style](./Text.md)
+ `resize`
‡ web only.
**testID**: ?string
Used to locate this view in end-to-end tests.
**value**: ?string
The value to show for the text input. `TextInput` is a controlled component,
which means the native `value` will be forced to match this prop if provided.
Read about how [React form
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
user edits to the value set `editable={false}`.
## Instance methods
**blur()**
Blur the underlying DOM input.
**clear()**
Clear the text from the underlying DOM input.
**focus()**
Focus the underlying DOM input.
**isFocused()**
Returns `true` if the input is currently focused; `false` otherwise.
## Examples
```js
import React, { TextInput } from 'react-native-web'
import React, { Component } from 'react'
import { StyleSheet, TextInput } from 'react-native'
const { Component, PropTypes } = React
class AppTextInput extends Component {
static propTypes = {
export default class TextInputExample extends Component {
constructor(props, context) {
super(props, context)
this.state = { isFocused: false }
}
static defaultProps = {
_onBlur(e) {
this.setState({ isFocused: false })
}
_onFocus(e) {
this.setState({ isFocused: true })
}
render() {
return (
<TextInput />
<TextInput
accessibilityLabel='Write a status update'
maxNumberOfLines={5}
multiline
numberOfLines={2}
onBlur={this._onBlur.bind(this)}
onFocus={this._onFocus.bind(this)}
placeholder={`What's happening?`}
style={[
styles.default
this.state.isFocused && styles.focused
]}
/>
);
}
}
const styles = {
}
const styles = StyleSheet.create({
default: {
borderColor: 'gray',
borderBottomWidth: 2
},
focused: {
borderColor: 'blue'
}
})
```

View File

@@ -1,59 +0,0 @@
# Touchable
## Props
**activeHighlight** string
Sets the color of the background highlight when `onPressIn` is called. The
highlight is removed when `onPressOut` is called. Default: `transparent`.
**activeOpacity** number
Sets the opacity of the child view when `onPressIn` is called. The opacity is
reset when `onPressOut` is called. Default: `1`.
**component** function or string
The backing component. Default: `div`.
**delayLongPress** number
Delay in ms, from `onPressIn`, before `onLongPress` is called. Default: `1000`.
**delayPressIn** number (TODO)
Delay in ms, from the start of the touch, before `onPressIn` is called. Default: `0`.
**delayPressOut** number (TODO)
Delay in ms, from the release of the touch, before `onPressOut` is called. Default: `0`.
**onLongPress** function
**onPress** function
**onPressIn** function
**onPressOut** function
## Examples
```js
import React, { Touchable } from 'react-native-web'
const { Component, PropTypes } = React;
class Example extends Component {
static propTypes = {
}
static defaultProps = {
}
render() {
return (
<Touchable />
)
}
}
```

View File

@@ -0,0 +1,46 @@
# TouchableWithoutFeedback
Do not use unless you have a very good reason. All the elements that respond to
press should have a visual feedback when touched. This is one of the primary
reason a "web" app doesn't feel "native".
**NOTE: `TouchableWithoutFeedback` supports only one child**. If you wish to have
several child components, wrap them in a View.
## Props
[...View props](./View.md)
**delayLongPress**: ?number
Delay in ms, from `onPressIn`, before `onLongPress` is called.
**delayPressIn**: ?number
Delay in ms, from the start of the touch, before `onPressIn` is called.
**delayPressOut**: ?number
Delay in ms, from the release of the touch, before `onPressOut` is called.
**disabled**: ?boolean
If `true`, disable all interactions for this component.
**onLongPress**: ?function
**onPress**: ?function
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
**onPressIn**: ?function
**onPressOut**: ?function
**pressRetentionOffset**: ?`{top: number, left: number, bottom: number, right: number}`
When the scroll view is disabled, this defines how far your touch may move off
of the button, before deactivating the button. Once deactivated, try moving it
back and you'll see that the button is once again reactivated! Move it back and
forth several times while the scroll view is disabled. Ensure you pass in a
constant to reduce memory allocations.

View File

@@ -1,24 +1,133 @@
# View
`View` is the fundamental UI building block. It is a component that supports
style, layout with flexbox, and accessibility controls. It can be nested
style, layout with flexbox, and accessibility controls. It can be nested
inside another `View` and has 0-to-many children of any type.
Also, refer to React Native's documentation about the [Gesture Responder
System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html).
Unsupported React Native props: `collapsable`, `onAccessibilityTap`, `onMagicTap`.
## Props
**accessibilityLabel** string
NOTE: `View` will transfer all other props to the rendered HTML element.
Overrides the text that's read by the screen reader when the user interacts
with the element. This is implemented using `aria-label`.
**accessibilityLabel**: ?string
**component** function, string
Overrides the text that's read by a screen reader when the user interacts
with the element. (This is implemented using `aria-label`.)
Default is `div`.
See the [Accessibility guide](../guides/accessibility) for more information.
**pointerEvents** oneOf('auto', 'box-only', 'box-none', 'none')
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
We deviate from the CSS spec by supporting additional `pointerEvents` modes,
therefore `pointerEvents` is excluded from `style`.
Indicates to assistive technologies whether to notify the user when the view
changes. The values of this attribute are expressed in degrees of importance.
When regions are specified as `polite` (recommended), updates take low
priority. When regions are specified as `assertive`, assistive technologies
will interrupt and immediately notify the user. (This is implemented using
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
See the [Accessibility guide](../guides/accessibility) for more information.
(web) **accessibilityRole**: ?enum(roles)
Allows assistive technologies to present and support interaction with the view
in a manner that is consistent with user expectations for similar views of that
type. For example, marking a touchable view with an `accessibilityRole` of
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
See the [Accessibility guide](../guides/accessibility) for more information.
**accessible**: ?boolean
When `true`, indicates that the view is an accessibility element (i.e.,
focusable) and groups its child content. By default, all the touchable elements
and elements with `accessibilityRole` of `button` and `link` are accessible.
(This is implemented using `tabindex`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**children**: ?element
Child content.
**hitSlop**: ?object
This defines how far a touch event can start away from the view (in pixels).
Typical interface guidelines recommend touch targets that are at least 30 - 40
points/density-independent pixels.
For example, if a touchable view has a height of `20` the touchable height can
be extended to `40` with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`.
**importantForAccessibility**: ?enum('auto', 'no', 'no-hide-descendants', 'yes')
A value of `no` will remove the element from the tab flow.
A value of `no-hide-descendants` will hide the element and its children from
assistive technologies. (This is implemented using `aria-hidden`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onMoveShouldSetResponder**: ?function => boolean
Does this view want to "claim" touch responsiveness? This is called for every
touch move on the `View` when it is not the responder.
**onMoveShouldSetResponderCapture**: ?function => boolean
If a parent `View` wants to prevent a child `View` from becoming responder on a
move, it should have this handler return `true`.
**onResponderGrant**: ?function
The `View` is now responding to touch events. This is the time to highlight and
show the user what is happening. For most touch interactions, you'll simply
want to wrap your component in `TouchableHighlight` or `TouchableOpacity`.
**onResponderMove**: ?function
The user is moving their finger.
**onResponderReject**: ?function
Another responder is already active and will not release it to the `View`
asking to be the responder.
**onResponderRelease**: ?function
Fired at the end of the touch.
**onResponderTerminate**: ?function
The responder has been taken from the `View`.
**onResponderTerminationRequest**: ?function
Some other `View` wants to become responder and is asking this `View` to
release its responder. Returning `true` allows its release.
**onStartShouldSetResponder**: ?function => boolean
Does this view want to become responder on the start of a touch?
**onStartShouldSetResponderCapture**: ?function => boolean
If a parent `View` wants to prevent a child `View` from becoming the responder
on a touch start, it should have this handler return `true`.
**pointerEvents**: ?enum('auto', 'box-only', 'box-none', 'none') = 'auto'
Controls whether the View can be the target of touch events. The enhanced
`pointerEvents` modes provided are not part of the CSS spec, therefore,
`pointerEvents` is excluded from `style`.
`box-none` is the equivalent of:
@@ -34,55 +143,124 @@ therefore `pointerEvents` is excluded from `style`.
.box-only * { pointer-events: none }
```
**style** style
**style**: ?style
+ `alignContent`
+ `alignItems`
+ `alignSelf`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `backfaceVisibility`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundColor`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `borderColor`
+ `borderRadius`
+ `borderStyle`
+ `borderWidth`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `borderColor` (single value)
+ `borderTopColor`
+ `borderBottomColor`
+ `borderRightColor`
+ `borderLeftColor`
+ `borderRadius` (single value)
+ `borderTopLeftRadius`
+ `borderTopRightRadius`
+ `borderBottomLeftRadius`
+ `borderBottomRightRadius`
+ `borderStyle` (single value)
+ `borderTopStyle`
+ `borderRightStyle`
+ `borderBottomStyle`
+ `borderLeftStyle`
+ `borderWidth` (single value)
+ `borderBottomWidth`
+ `borderLeftWidth`
+ `borderRightWidth`
+ `borderTopWidth`
+ `bottom`
+ `boxShadow`
+ `boxShadow`
+ `boxSizing`
+ `clip`
+ `cursor`
+ `display`
+ `filter`
+ `flex` (number)
+ `flexBasis`
+ `flexDirection`
+ `flexGrow`
+ `flexShrink`
+ `flexWrap`
+ `gridAutoColumns`
+ `gridAutoFlow`
+ `gridAutoRows`
+ `gridColumnEnd`
+ `gridColumnGap`
+ `gridColumnStart`
+ `gridRowEnd`
+ `gridRowGap`
+ `gridRowStart`
+ `gridTemplateColumns`
+ `gridTemplateRows`
+ `gridTemplateAreas`
+ `height`
+ `justifyContent`
+ `left`
+ `margin`
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
+ `marginLeft`
+ `marginRight`
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
+ `maxWidth`
+ `minHeight`
+ `minWidth`
+ `opacity`
+ `order`
+ `outline`
+ `outlineColor`
+ `overflow`
+ `overflowX`
+ `overflowY`
+ `padding`
+ `overflowX`
+ `overflowY`
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
+ `paddingLeft`
+ `paddingRight`
+ `paddingTop`
+ `paddingVertical`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
+ `right`
+ `shadowColor`
+ `shadowOffset`
+ `shadowOpacity`
+ `shadowRadius`
+ `top`
+ `transform`
+ `userSelect`
+ `visibility`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `userSelect`
+ `visibility`
+ `width`
+ `willChange`
+ `zIndex`
‡ web only.
Default:
```js
@@ -103,18 +281,17 @@ Default:
(See [facebook/css-layout](https://github.com/facebook/css-layout)).
**testID** string
**testID**: ?string
Used to locate this view in end-to-end tests.
## Examples
```js
import React, { View } from 'react-native-web'
import React, { Component, PropTypes } from 'react'
import { StyleSheet, View } from 'react-native'
const { Component, PropTypes } = React
class Example extends Component {
export default class ViewExample extends Component {
render() {
return (
<View style={styles.row}>
@@ -128,14 +305,12 @@ class Example extends Component {
}
}
const styles = {
const styles = StyleSheet.create({
row: {
flexDirection: 'row'
},
cell: {
flexGrow: 1
}
}
export default Example
})
```

View File

@@ -0,0 +1,120 @@
# Accessibility
On the Web, assistive technologies (e.g., VoiceOver, TalkBack screen readers)
derive useful information about the structure, purpose, and interactivity of
apps from their [HTML elements][html-accessibility-url], attributes, and [ARIA
in HTML][aria-in-html-url]. React Native for Web includes APIs designed to
provide developers with support for making apps more accessible. The most
common and best supported accessibility features of the Web are exposed as the
props: `accessible`, `accessibilityLabel`, `accessibilityLiveRegion`,
`accessibilityRole`, and `importantForAccessibility`.
## Accessibility properties
### accessible
When `true`, indicates that the view is an accessibility element. When a view
is an accessibility element, it groups its children into a single focusable
component. By default, all touchable elements, buttons, and links are
"accessible". Prefer using `accessibilityRole` (e.g., `button`, `link`) to
create focusable HTML elements wherever possible. On web, `accessible={true}`
is implemented using `tabIndex`.
### accessibilityLabel
When a view is marked as `accessible`, it is a good practice to set an
`accessibilityLabel` on the view, so that people who use screen readers know
what element they have selected. On web, `accessibilityLabel` is implemented
using `aria-label`.
```
<TouchableOpacity accessibilityLabel={'Tap me!'} accessible={true} onPress={this._onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>
```
### accessibilityRole
In some cases, we also want to alert the end user of the type of selected
component (i.e., that it is a “button”). To provide more context to screen
readers, you should specify the `accessibilityRole` property. (Note that React
Native for Web provides a compatibility mapping of equivalent
`accessibilityTraits` and `accessibilityComponentType` values to
`accessibilityRole`).
The `accessibilityRole` prop is used to infer an [analogous HTML
element][html-aria-url] to use in addition to the resulting ARIA `role`, where
possible. While this may contradict some ARIA recommendations, it also helps
avoid certain HTML5 conformance errors and accessibility anti-patterns (e.g.,
giving a `heading` role to a `button` element).
For example:
* `<View accessibilityRole='article' />` => `<article role='article' />`.
* `<View accessibilityRole='banner' />` => `<header role='banner' />`.
* `<View accessibilityRole='button' />` => `<button type='button' role='button' />`.
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
* `<View accessibilityRole='main' />` => `<main role='main' />`.
In the example below, the `TouchableWithoutFeedback` is announced by screen
readers as a native Button.
```
<TouchableWithoutFeedback accessibilityRole="button" onPress={this._onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableWithoutFeedback>
```
Note: Avoid changing `accessibilityRole` values over time or after user
actions. Generally, accessibility APIs do not provide a means of notifying
assistive technologies of a `role` value change.
### accessibilityLiveRegion
When components dynamically change we may need to inform the user. The
`accessibilityLiveRegion` property serves this purpose and can be set to
`none`, `polite` and `assertive`. On web, `accessibilityLiveRegion` is
implemented using `aria-live`.
* `none`: Accessibility services should not announce changes to this view.
* `polite`: Accessibility services should announce changes to this view.
* `assertive`: Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
```
<TouchableWithoutFeedback onPress={this._addOne}>
<View style={styles.embedded}>
<Text>Click me</Text>
</View>
</TouchableWithoutFeedback>
<Text accessibilityLiveRegion="polite">
Clicked {this.state.count} times
</Text>
```
In the above example, method `_addOne` changes the `state.count` variable. As
soon as an end user clicks the `TouchableWithoutFeedback`, screen readers
announce text in the `Text` view because of its
`accessibilityLiveRegion="polite"` property.
### importantForAccessibility
The `importantForAccessibility` property controls if a view appears in the
accessibility tree and if it is reported to accessibility services. On web, a
value of `no` will remove a focusable element from the tab flow, and a value of
`no-hide-descendants` will also hide the entire subtree from assistive
technologies (this is implemented using `aria-hidden`).
### Other
Other ARIA properties can be set via [direct
manipulation](./direct-manipulation.md) or props (this may change in the
future).
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
[html-accessibility-url]: http://www.html5accessibility.com/
[html-aria-url]: http://www.w3.org/TR/html-aria/

View File

@@ -0,0 +1,115 @@
# Direct manipulation
It is sometimes necessary to make changes directly to a component without using
state/props to trigger a re-render of the entire subtree in the browser, this
is done by directly modifying a DOM node. `setNativeProps` is the React Native
equivalent to setting properties directly on a DOM node. Use direct
manipulation when frequent re-rendering creates a performance bottleneck. Direct
manipulation will not be a tool that you reach for frequently.
## `setNativeProps` and `shouldComponentUpdate`
`setNativeProps` is imperative and stores state in the native layer (DOM,
UIView, etc.) and not within your React components, which makes your code more
difficult to reason about. Before you use it, try to solve your problem with
`setState` and `shouldComponentUpdate`.
## Avoiding conflicts with the render function
If you update a property that is also managed by the render function, you might
end up with some unpredictable and confusing bugs because anytime the component
re-renders and that property changes, whatever value was previously set from
`setNativeProps` will be completely ignored and overridden.
## Why use `setNativeProps` on Web?
Using `setNativeProps` in web-specific code is required when making changes to
`className` or `style`, as these properties are controlled by React Native for
Web and setting them directly may cause unintended rendering issues.
```js
setOpacityTo(value) {
this._childElement.setNativeProps({
style: { opacity: value }
})
}
```
## Composite components and `setNativeProps`
Composite components are not backed by a DOM node, so you cannot call
`setNativeProps` on them. Consider this example:
```js
const MyButton = (props) => (
<View>
<Text>{props.label}</Text>
</View>
)
const App = () => (
<TouchableOpacity>
<MyButton label="Press me!" />
</TouchableOpacity>
)
```
If you run this you will immediately see this error: `Touchable` child must
either be native or forward `setNativeProps` to a native component. This occurs
because `MyButton` isn't directly backed by a native view whose opacity should
be set. You can think about it like this: if you define a component with
`React.Component/createClass` you would not expect to be able to set a style
prop on it and have that work - you would need to pass the style prop down to a
child, unless you are wrapping a native component. Similarly, we are going to
forward `setNativeProps` to a native-backed child component.
## Forward `setNativeProps` to a child
All we need to do is provide a `setNativeProps` method on our component that
calls `setNativeProps` on the appropriate child with the given arguments.
```js
class MyButton extends React.Component {
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps)
}
render() {
return (
<View ref={component => this._root = component}>
<Text>{this.props.label}</Text>
</View>
)
}
}
```
You can now use `MyButton` inside of `TouchableOpacity`!
## `setNativeProps` to clear `TextInput` value
Another very common use case of `setNativeProps` is to clear the value of a
`TextInput`. For example, the following code demonstrates clearing the input
when you tap a button:
```js
class App extends React.Component {
_handlePress() {
this._textInput.setNativeProps({ text: '' })
}
render() {
return (
<View style={styles.container}>
<TextInput
ref={component => this._textInput = component}
style={styles.textInput}
/>
<TouchableOpacity onPress={this._handlePress.bind(this)}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
)
}
}
```

View File

@@ -0,0 +1,167 @@
# Getting started
It is recommended that your application provide a `Promise` and `Array.from`
polyfill.
## Webpack and Babel
[Webpack](webpack.js.org) is a popular build tool for web apps. Below is an
example of how to configure a build that uses [Babel](https://babeljs.io/) to
compile your JavaScript for the web.
```js
// webpack.config.js
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-native-uncompiled')
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'react-native' preset is recommended
presets: ['react-native']
}
}
};
// This is needed for webpack to import static images in JavaScript files
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]'
}
}
};
module.exports = {
// ...the rest of your config
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration
]
},
plugins: [
// `process.env.NODE_ENV === 'production'` must be `true` for production
// builds to eliminate development checks and reduce build size.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
],
resolve: {
// Maps the 'react-native' import to 'react-native-web'.
alias: {
'react-native': 'react-native-web'
},
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: [ '.web.js', '.js' ]
}
}
```
A more complex example setup for web apps can be found in various starter kits
(e.g., create-react-app and
[react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack))
Please refer to the Webpack documentation for more information.
## Jest
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
```
"jest": {
"moduleNameMapper": {
"react-native": "<rootDir>/node_modules/react-native-web"
}
}
```
Please refer to the Jest documentation for more information.
## Web-specific code
Minor platform differences can use the `Platform` module.
```js
import { AppRegistry, Platform } from 'react-native'
AppRegistry.registerComponent('MyApp', () => MyApp)
if (Platform.OS === 'web') {
AppRegistry.runApplication('MyApp', {
rootTag: document.getElementById('react-root')
});
}
```
## Client-side rendering
Rendering using `ReactNative`:
```js
import React from 'react'
import ReactNative from 'react-native'
// component that renders the app
const AppHeaderContainer = (props) => { /* ... */ }
ReactNative.render(<AppHeaderContainer />, document.getElementById('react-app-header'))
```
Rendering using `AppRegistry`:
```js
import React from 'react'
import ReactNative, { AppRegistry } from 'react-native'
// component that renders the app
const AppContainer = (props) => { /* ... */ }
// register the app
AppRegistry.registerComponent('App', () => AppContainer)
AppRegistry.runApplication('App', {
initialProps: {},
rootTag: document.getElementById('react-app')
})
```
Rendering within `ReactDOM.render` also works when introduce `react-native-web`
to an existing web app, but it is not recommended oherwise.
## Server-side rendering
Rendering using the `AppRegistry`:
```js
import ReactDOMServer from 'react-dom/server'
import ReactNative, { AppRegistry } from 'react-native'
// component that renders the app
const AppContainer = (props) => { /* ... */ }
// register the app
AppRegistry.registerComponent('App', () => AppContainer)
// prerender the app
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
const initialHTML = ReactDOMServer.renderToString(element);
```

View File

@@ -0,0 +1,29 @@
# Internationalization
To support right-to-left languages, application layout can be automatically
flipped from LTR to RTL. The `I18nManager` API can be used to help with more
fine-grained control and testing of RTL layouts.
## Working with icons and images
Icons and images that must match the LTR or RTL layout of the app need to be manually flipped.
Either use a transform style:
```js
<Image
source={...}
style={{ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }] }}
/>
```
Or replace the source asset:
```js
import imageSourceLTR from './back.png';
import imageSourceRTL from './forward.png';
<Image
source={I18nManager.isRTL ? imageSourceRTL : imageSourceLTR}
/>
```

View File

@@ -0,0 +1,31 @@
# Known issues
## Safari flexbox performance
Safari version prior to 10.1 can suffer from extremely [poor flexbox
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
way to work around this issue (as used on mobile.twitter.com) is to set
`display:block` on Views in your element hierarchy that you know don't need
flexbox layout.
## Missing modules and components
Not all of the views present on iOS/Android are currently available on Web. We
are very much interested in the community's feedback on the next set of modules
and views.
Not all the modules or views for iOS/Android can be implemented on Web. In some
cases it will be necessary to use a Web counterpart or to guard the use of a
module with `Platform.OS` (e.g. `NativeModules`)
## Missing component props
There are properties that do not work across all platforms. All web-specific
props are annotated with `(web)` in the documentation.
## Platform parity
There are some known issues in React Native where APIs could be made more
consistent between platforms. For example, React Native for Web includes
`ActivityIndicator` and a horizontal `ProgressBar` for Web use, in anticipation
of the convergence between the iOS and Android components in React Native.

145
docs/guides/style.md Normal file
View File

@@ -0,0 +1,145 @@
# Style
React Native for Web relies on JavaScript to define styles for your
application. This allows you to avoid issues arising from the [7 deadly sins of
CSS](https://speakerdeck.com/vjeux/react-css-in-js):
1. Global namespace
2. Dependency hell
3. No dead code elimination
4. No code minification
5. No sharing of constants
6. Non-deterministic resolution
7. Lack of isolation
## Defining styles
Styles should be defined outside of the component:
```js
class Example extends React.Component {}
const styles = StyleSheet.create({
heading: {
color: 'gray',
fontSize: '2rem'
},
text: {
color: 'gray',
fontSize: '1.25rem'
}
})
```
Using `StyleSheet.create` is optional but provides the best performance
(`style` is resolved to CSS stylesheets). Avoid creating unregistered style
objects.
The attribute names and values are a subset of CSS. See the `style`
documentation of individual components.
## Using styles
All the React Native components accept a `style` attribute.
```js
<Text style={styles.text} />
<View style={styles.view} />
```
A common pattern is to conditionally add style based on a condition:
```js
// either
<View style={[
styles.base,
this.state.active && styles.active
]} />
```
## Composing styles
In order to let a call site customize the style of your component children, you
can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in
order to make sure only valid styles are being passed.
```js
class List extends React.Component {
static propTypes = {
style: View.propTypes.style,
elementStyle: View.propTypes.style,
}
render() {
return (
<View style={this.props.style}>
{elements.map((element) =>
<View style={[ styles.element, this.props.elementStyle ]} />
)}
</View>
);
}
}
```
In another file:
```js
<List style={styles.list} elementStyle={styles.listElement} />
```
You also have much greater control over how styles are composed when compared
to using class names. For example, you may choose to accept a limited subset
of style props in the component's API, and control when they are applied:
```js
class List extends React.Component {
static propTypes = {
children: React.PropTypes.any,
// limit which styles are accepted
style: React.PropTypes.shape({
borderColor: View.propTypes.borderColor,
borderWidth: View.propTypes.borderWidth
})
}
render() {
return (
<View
children={children}
style={[
this.props.style,
// override border-color when scrolling
isScrolling && { borderColor: 'transparent' }
]}
/>
)
}
}
```
## Media Queries
`StyleSheet.create` is a way of defining the styles your application requires;
it does not concern itself with _where_ or _when_ those styles are applied to
elements.
There are various React libraries wrapping JavaScript Media Query API's, e.g.,
[react-media-queries](https://github.com/bloodyowl/react-media-queries),
[media-query-fascade](https://github.com/tanem/media-query-facade), or
[react-responsive](https://github.com/contra/react-responsive). This has the
benefit of co-locating breakpoint-specific DOM and style changes.
## Pseudo-classes and pseudo-elements
Pseudo-classes like `:hover` and `:focus` can be implemented with events (e.g.
`onFocus`). Pseudo-elements are not supported; elements should be used instead.
### Reset
You **do not** need to include a CSS reset or
[normalize.css](https://necolas.github.io/normalize.css/).
React Native for Web includes a very small CSS reset taken from normalize.css.
It removes unwanted User Agent styles from (pseudo-)elements beyond the reach
of React (e.g., `html`, `body`) or inline styles (e.g., `::-moz-focus-inner`).

View File

@@ -1,123 +0,0 @@
# Styling strategy
Using the `style` attribute would normally produce inline styles. There are
several existing approaches to using the `style` attribute, some of which
convert inline styles to static CSS:
[jsxstyle](https://github.com/petehunt/jsxstyle),
[react-free-style](https://github.com/blakeembrey/react-free-style/),
[react-inline](https://github.com/martinandert/react-inline),
[react-native](https://facebook.github.io/react-native/),
[react-style](https://github.com/js-next/react-style),
[stilr](https://github.com/kodyl/stilr).
## Style syntax: native vs proprietary data structure
React Native for Web diverges from React Native by using plain JS objects for
styles:
```js
<Text style={styles.root}>...</Text>
const styles = {
root: {
background: 'transparent',
display: 'flex',
flexGrow: 1,
justifyContent: 'center'
}
};
```
Most approaches to managing style in React introduce a proprietary data
structure, often via an implementation of `Stylesheet.create`.
```js
<Text style={styles.root}>...</Text>
const styles = Stylesheet.create({
root: {
background: 'transparent',
display: 'flex',
flexGrow: 1,
justifyContent: 'center'
}
});
```
## JS-to-CSS: conversion strategies
Mapping entire `style` objects to CSS rules can lead to increasingly large CSS
files. Each new component adds new rules to the stylesheet.
![](../static/styling-strategy.png)
One strategy for converting styles from JS to CSS is to map style objects to
CSS rules. Another strategy is to map declarations to declarations.
React Native for Web currently includes a proof-of-concept implementation of
the latter strategy. This results in smaller CSS files because all applications
has fewer unique declarations than total declarations. Creating a new component
with no new unique declarations results in no change to the CSS file.
For example:
```js
<Text style={styles.root}>...</Text>
const styles = {
root: {
background: 'transparent',
display: 'flex',
flexGrow: 1,
justifyContent: 'center'
}
};
```
Yields:
```html
<span className="_abcde _fghij _klmno _pqrst">...</span>
```
And is backed by:
```css
._abcde { background: transparent }
._fghij { display: flex }
._klmno { flex-grow: 1 }
._pqrst { justify-content: center }
```
The current implementation uses a precomputed CSS library of single-declaration
rules, with obfuscated selectors. This handles a signficant portion of possible
declarations. A build-time implementation would produce more accurate CSS
files and fall through to inline styles significantly less often.
(CSS libraries like [Atomic CSS](http://acss.io/),
[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
stylesheet growth in a similar way. But they're CSS utility libraries, each with a
particular set of classes and features to learn. All of them require developers
to manually connect CSS classes for given styles.)
## Dynamic styles: use inline styles
Some styles cannot be resolved ahead of time and continue to rely on inline
styles:
```js
<View style={{ backgroundColor: (Math.random() > 0.5 ? 'red' : 'black') }}>...</Text>
```
## Media Queries, pseudo-classes, and pseudo-elements
Media Queries could be replaced with `mediaMatch`. This would have the added
benefit of co-locating breakpoint-specific DOM and style changes. Perhaps Media
Query data could be accessed on `this.content`?
Pseudo-classes like `:hover` and `:focus` can be handled with JavaScript.
Pseudo-elements should be avoided in general, but for particular cases like
`::placeholder` it might be necessary to reimplement it in the `TextInput`
component (see React Native's API).

View File

@@ -1,228 +0,0 @@
import React, { Image, Swipeable, Text, TextInput, Touchable, View } from '../dist/react-native-web'
const { Component, PropTypes } = React
class Heading extends Component {
static propTypes = {
children: Text.propTypes.children,
level: PropTypes.oneOf(['1', '2', '3']),
size: PropTypes.oneOf(['xlarge', 'large', 'normal'])
}
static defaultProps = {
level: '1',
size: 'normal'
}
render() {
const { children, level, size } = this.props
return (
<Text
children={children}
component={`h${level}`}
style={headingStyles.size[size]}
/>
)
}
}
const headingStyles = {
size: {
xlarge: {
fontSize: '2rem',
marginBottom: '1em'
},
large: {
fontSize: '1.5rem',
marginBottom: '1em',
marginTop: '1em'
},
normal: {
fontSize: '1.25rem',
marginBottom: '0.5em',
marginTop: '0.5em'
}
}
}
class Example extends Component {
static propTypes = {
style: View.propTypes.style
}
render() {
return (
<View style={styles.root}>
<Heading level='1' size='xlarge'>React Native for Web: examples</Heading>
<Heading level='2' size='large'>Image</Heading>
<Image
accessibilityLabel='accessible image'
children={<Text>Inner content</Text>}
defaultSource={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wkGESkdPWMDggAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5UlEQVR42u3UMQ0AAAgEMcC/x7eCCgaSVsIN10kK4IORADAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAkAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAALi04UQW9HF910gAAAABJRU5ErkJggg=='
}}
onError={(e) => { console.log('Image.onError', e) }}
onLoad={(e) => { console.log('Image.onLoad', e) }}
onLoadEnd={() => { console.log('Image.onLoadEnd') }}
onLoadStart={() => { console.log('Image.onLoadStart') }}
resizeMode={'contain'}
source={{
height: 400,
uri: 'http://facebook.github.io/react/img/logo_og.png',
width: 400
}}
style={{
borderWidth: '5px'
}}
testID='Example.image'
/>
<Heading level='2' size='large'>Swipeable</Heading>
<Swipeable
onSwiped={(e) => { console.log('Swipeable.onSwiped', e) }}
testID={'Example.swipeable'}
>
<View
style={{
backgroundColor: 'black',
alignSelf: 'center',
width: '200px',
height: '200px'
}}
/>
</Swipeable>
<Heading level='2' size='large'>Text</Heading>
<Text
onPress={(e) => { console.log('Text.onPress', e) }}
testID={'Example.text'}
>
PRESS ME.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat. Aliquam lorem quam, elementum eget ex nec,
ultrices porttitor nibh. Nulla pellentesque urna leo, a aliquet elit
rhoncus a. Aenean ultricies, nunc a interdum dictum, dui odio
scelerisque mauris, a fringilla elit ligula vel sem. Sed vel aliquet
ipsum, sed rhoncus velit. Vivamus commodo pretium libero id placerat.
</Text>
<Text numberOfLines={1}>
TRUNCATED after 1 line.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat.
</Text>
<Heading level='2' size='large'>TextInput</Heading>
<TextInput
keyboardType='default'
onBlur={(e) => { console.log('TextInput.onBlur', e) }}
onChange={(e) => { console.log('TextInput.onChange', e) }}
onChangeText={(e) => { console.log('TextInput.onChangeText', e) }}
onFocus={(e) => { console.log('TextInput.onFocus', e) }}
/>
<TextInput secureTextEntry={true} />
<TextInput keyboardType='numeric' />
<TextInput keyboardType='tel' />
<TextInput keyboardType='url' />
<TextInput keyboardType='search' />
<TextInput defaultValue='default value' multiline />
<Heading level='2' size='large'>Touchable</Heading>
<Touchable
activeHighlight='lightblue'
activeOpacity={0.8}
onLongPress={(e) => { console.log('Touchable.onLongPress', e) }}
onPress={(e) => { console.log('Touchable.onPress', e) }}
onPressIn={(e) => { console.log('Touchable.onPressIn', e) }}
onPressOut={(e) => { console.log('Touchable.onPressOut', e) }}
>
<View style={styles.touchableArea}>
<Text>Touchable area (press, long press)</Text>
</View>
</Touchable>
<Heading level='2' size='large'>View</Heading>
<Heading level='3'>Default layout</Heading>
<View>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading level='3'>Row layout</Heading>
<View style={styles.row}>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading level='3'>pointerEvents</Heading>
<View style={styles.row}>
{['box-none', 'box-only', 'none'].map((value, i) => {
return (
<View
children={value}
component='a'
href='https://google.com'
key={i}
pointerEvents={value}
style={styles.pointerEventsBox}
/>
)
})}
</View>
</View>
)
}
}
const styles = {
root: {
fontFamily: 'sans-serif',
maxWidth: '600px',
margin: '0 auto'
},
row: {
flexDirection: 'row',
flexWrap: 'wrap'
},
box: {
alignItems: 'center',
flexGrow: 1,
justifyContent: 'center',
borderWidth: '1px'
},
boxFull: {
width: '100%'
},
pointerEventsBox: {
alignItems: 'center',
borderWidth: '1px',
flexGrow: '1',
height: '100px',
justifyContent: 'center'
},
touchableArea: {
alignItems: 'center',
borderWidth: 1,
height: '200px',
justifyContent: 'center'
}
}
React.render(<Example />, document.getElementById('react-root'))

View File

@@ -1,5 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div id="react-root"></div>
<script src="../dist/example.js"></script>

View File

@@ -1,19 +0,0 @@
module.exports = {
entry: {
example: './example.js'
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
}
]
},
output: {
filename: 'example.js',
path: '../dist'
}
}

View File

@@ -0,0 +1,12 @@
import { configure, addDecorator } from '@kadira/storybook'
import centered from './decorator-centered'
const context = require.context('../', true, /Example\.js$/)
addDecorator(centered)
function loadStories() {
context.keys().forEach(context)
}
configure(loadStories, module)

View File

@@ -0,0 +1,18 @@
import React from 'react';
import { StyleSheet, View } from 'react-native'
const styles = StyleSheet.create({
root: {
alignItems: 'center',
height: '100vh',
justifyContent: 'center'
}
});
export default function (renderStory) {
return (
<View style={[ StyleSheet.absoluteFill, styles.root ]}>
{renderStory()}
</View>
);
}

View File

@@ -0,0 +1,33 @@
const path = require('path')
const webpack = require('webpack')
const DEV = process.env.NODE_ENV !== 'production';
module.exports = {
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
},
{
test: /\.(gif|jpe?g|png|svg)$/,
loader: 'url-loader',
query: { name: '[name].[ext]' }
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
})
],
resolve: {
alias: {
'react-native': path.join(__dirname, '../../src/module')
}
}
}

View File

@@ -0,0 +1,33 @@
import { Clipboard, Text, TextInput, View } from 'react-native'
import React, { Component } from 'react';
import { action, storiesOf } from '@kadira/storybook';
class ClipboardExample extends Component {
render() {
return (
<View style={{ minWidth: 300 }}>
<Text onPress={this._handleSet}>Copy to clipboard</Text>
<TextInput
multiline={true}
placeholder={'Try pasting here afterwards'}
style={{ borderWidth: 1, height: 200, marginVertical: 20 }}
/>
<Text onPress={this._handleGet}>(Clipboard.getString returns a Promise that always resolves to an empty string on web)</Text>
</View>
)
}
_handleGet() {
Clipboard.getString().then((value) => { console.log(`Clipboard value: ${value}`) });
}
_handleSet() {
const success = Clipboard.setString('This text was copied to the clipboard by React Native');
console.log(`Clipboard.setString success? ${success}`);
}
}
storiesOf('api: Clipboard', module)
.add('setString', () => (
<ClipboardExample />
));

View File

@@ -0,0 +1,90 @@
import { storiesOf } from '@kadira/storybook';
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native'
import React, { Component } from 'react';
class I18nManagerExample extends Component {
componentWillUnmount() {
I18nManager.setPreferredLanguageRTL(false)
}
render() {
return (
<View style={styles.container}>
<Text accessibilityRole='heading' style={styles.welcome}>
LTR/RTL layout example!
</Text>
<Text style={styles.text}>
The writing direction of text is automatically determined by the browser, independent of the global writing direction of the app.
</Text>
<Text style={[ styles.text, styles.rtlText ]}>
أحب اللغة العربية
</Text>
<Text style={[ styles.text, styles.textAlign ]}>
textAlign toggles
</Text>
<View style={styles.horizontal}>
<View style={[ styles.box, { backgroundColor: 'lightblue' } ]}>
<Text>One</Text>
</View>
<View style={[ styles.box ]}>
<Text>Two</Text>
</View>
</View>
<TouchableHighlight
onPress={this._handleToggle}
style={styles.toggle}
underlayColor='rgba(0,0,0,0.25)'
>
<Text>Toggle LTR/RTL</Text>
</TouchableHighlight>
</View>
)
}
_handleToggle = () => {
I18nManager.setPreferredLanguageRTL(!I18nManager.isRTL)
this.forceUpdate();
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
justifyContent: 'center',
padding: 10
},
welcome: {
fontSize: 28,
marginVertical: 10
},
text: {
color: '#333333',
fontSize: 18,
marginBottom: 5
},
textAlign: {
textAlign: 'left'
},
horizontal: {
flexDirection: 'row',
marginVertical: 10
},
box: {
borderWidth: 1,
flex: 1
},
toggle: {
alignSelf: 'center',
borderColor: 'black',
borderStyle: 'solid',
borderWidth: 1,
marginTop: 10,
padding: 10
}
})
storiesOf('api: I18nManager', module)
.add('RTL layout', () => (
<I18nManagerExample />
))

View File

@@ -0,0 +1,37 @@
import { Linking, StyleSheet, Text, View } from 'react-native'
import React, { Component } from 'react';
import { storiesOf, action } from '@kadira/storybook';
const url = 'https://mathiasbynens.github.io/rel-noopener/malicious.html';
class LinkingExample extends Component {
handlePress() {
Linking.canOpenURL(url).then((supported) => {
return Linking.openURL(url);
});
}
render() {
return (
<View>
<Text onPress={this.handlePress} style={styles.text}>
Linking.openURL (Expect: "The previous tab is safe and intact")
</Text>
<Text accessibilityRole='link' href='https://mathiasbynens.github.io/rel-noopener/malicious.html' style={styles.text} target='_blank'>
target="_blank" (Expect: "The previous tab is safe and intact")
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
text: {
marginVertical: 10
}
});
storiesOf('api: Linking', module)
.add('Safe linking', () => (
<LinkingExample />
));

View File

@@ -0,0 +1,118 @@
'use strict';
import createReactClass from 'create-react-class';
import { storiesOf, action } from '@kadira/storybook';
var React = require('react');
var ReactNative = require('react-native');
var {
PanResponder,
StyleSheet,
View
} = ReactNative;
var CIRCLE_SIZE = 80;
var PanResponderExample = createReactClass({
_panResponder: {},
_previousLeft: 0,
_previousTop: 0,
_circleStyles: {},
circle: (null : ?{ setNativeProps(props: Object): void }),
componentWillMount: function() {
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
onPanResponderGrant: this._handlePanResponderGrant,
onPanResponderMove: this._handlePanResponderMove,
onPanResponderRelease: this._handlePanResponderEnd,
onPanResponderTerminate: this._handlePanResponderEnd,
});
this._previousLeft = 20;
this._previousTop = 84;
this._circleStyles = {
style: {
left: this._previousLeft,
top: this._previousTop,
backgroundColor: 'green',
}
};
},
componentDidMount: function() {
this._updateNativeStyles();
},
render: function() {
return (
<View
style={styles.container}>
<View
ref={(circle) => {
this.circle = circle;
}}
style={styles.circle}
{...this._panResponder.panHandlers}
/>
</View>
);
},
_highlight: function() {
this._circleStyles.style.backgroundColor = 'blue';
this._updateNativeStyles();
},
_unHighlight: function() {
this._circleStyles.style.backgroundColor = 'green';
this._updateNativeStyles();
},
_updateNativeStyles: function() {
this.circle && this.circle.setNativeProps(this._circleStyles);
},
_handleStartShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
// Should we become active when the user presses down on the circle?
return true;
},
_handleMoveShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
// Should we become active when the user moves a touch over the circle?
return false;
},
_handlePanResponderGrant: function(e: Object, gestureState: Object) {
this._highlight();
},
_handlePanResponderMove: function(e: Object, gestureState: Object) {
this._circleStyles.style.left = this._previousLeft + gestureState.dx;
this._circleStyles.style.top = this._previousTop + gestureState.dy;
this._updateNativeStyles();
},
_handlePanResponderEnd: function(e: Object, gestureState: Object) {
this._unHighlight();
this._previousLeft += gestureState.dx;
this._previousTop += gestureState.dy;
},
});
var styles = StyleSheet.create({
circle: {
width: CIRCLE_SIZE,
height: CIRCLE_SIZE,
borderRadius: CIRCLE_SIZE / 2,
position: 'absolute',
left: 0,
top: 0,
},
container: {
flex: 1,
paddingTop: 64,
},
});
storiesOf('api: PanResponder', module)
.add('example', () => <PanResponderExample />)

View File

@@ -0,0 +1,169 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { ActivityIndicator, StyleSheet, View } from 'react-native'
import TimerMixin from 'react-timer-mixin';
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
const ToggleAnimatingActivityIndicator = createReactClass({
mixins: [TimerMixin],
getInitialState() {
return {
animating: true,
};
},
setToggleTimeout() {
this.setTimeout(() => {
this.setState({animating: !this.state.animating});
this.setToggleTimeout();
}, 2000);
},
componentDidMount() {
this.setToggleTimeout();
},
render() {
return (
<ActivityIndicator
animating={this.state.animating}
style={styles.centering}
hidesWhenStopped={this.props.hidesWhenStopped}
size="large"
/>
);
}
});
const examples = [
{
title: 'Default',
render() {
return (
<ActivityIndicator
style={[styles.centering]}
/>
);
}
},
{
title: 'Custom colors',
render() {
return (
<View style={styles.horizontal}>
<ActivityIndicator color="#0000ff" />
<ActivityIndicator color="#aa00aa" />
<ActivityIndicator color="#aa3300" />
<ActivityIndicator color="#00aa00" />
</View>
);
}
},
{
title: 'Large',
render() {
return (
<ActivityIndicator
style={[styles.centering, styles.gray]}
color="white"
size="large"
/>
);
}
},
{
title: 'Large, custom colors',
render() {
return (
<View style={styles.horizontal}>
<ActivityIndicator
size="large"
color="#0000ff"
/>
<ActivityIndicator
size="large"
color="#aa00aa"
/>
<ActivityIndicator
size="large"
color="#aa3300"
/>
<ActivityIndicator
size="large"
color="#00aa00"
/>
</View>
);
}
},
{
title: 'Start/stop',
render() {
return (
<View style={[styles.horizontal, styles.centering]}>
<ToggleAnimatingActivityIndicator />
<ToggleAnimatingActivityIndicator hidesWhenStopped={false} />
</View>
);
}
},
{
title: 'Custom size',
render() {
return (
<View style={[styles.horizontal, styles.centering]}>
<ActivityIndicator size={40} />
<ActivityIndicator
style={{ marginLeft: 20, transform: [ {scale: 1.5} ] }}
size="large"
/>
</View>
);
}
},
];
const styles = StyleSheet.create({
centering: {
alignItems: 'center',
justifyContent: 'center',
padding: 8,
},
gray: {
backgroundColor: '#cccccc',
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around',
padding: 8,
},
});
examples.forEach((example) => {
storiesOf('component: ActivityIndicator', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,80 @@
import React from 'react';
import { action, storiesOf } from '@kadira/storybook';
import { Button, StyleSheet, View } from 'react-native';
const onButtonPress = action('Button has been pressed!');
const examples = [
{
title: 'Simple Button',
description: 'The title and onPress handler are required. It is ' +
'recommended to set accessibilityLabel to help make your app usable by ' +
'everyone.',
render: function() {
return (
<Button
onPress={onButtonPress}
title="Press Me"
accessibilityLabel="See an informative alert"
/>
);
},
},
{
title: 'Adjusted color',
description: 'Adjusts the color in a way that looks standard on each ' +
'platform. On iOS, the color prop controls the color of the text. On ' +
'Android, the color adjusts the background color of the button.',
render: function() {
return (
<Button
onPress={onButtonPress}
title="Press Purple"
color="#841584"
accessibilityLabel="Learn more about purple"
/>
);
},
},
{
title: 'Fit to text layout',
description: 'This layout strategy lets the title define the width of ' +
'the button',
render: function() {
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Button
onPress={onButtonPress}
title="This looks great!"
accessibilityLabel="This sounds great!"
/>
<Button
onPress={onButtonPress}
title="Ok!"
color="#841584"
accessibilityLabel="Ok, Great!"
/>
</View>
);
},
},
{
title: 'Disabled Button',
description: 'All interactions for the component are disabled.',
render: function() {
return (
<Button
disabled
onPress={onButtonPress}
title="I Am Disabled"
accessibilityLabel="See an informative alert"
/>
);
},
},
];
examples.forEach((example) => {
storiesOf('component: Button', module)
.add(example.title, () => example.render());
});

View File

@@ -0,0 +1,654 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action, addDecorator } from '@kadira/storybook';
import { ActivityIndicator, Image, Platform, StyleSheet, Text, View } from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
//var ImageCapInsetsExample = require('./ImageCapInsetsExample');
const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
var NetworkImageCallbackExample = createReactClass({
getInitialState: function() {
return {
events: [],
startLoadPrefetched: false,
mountTime: new Date(),
};
},
componentWillMount() {
this.setState({mountTime: new Date()});
},
render: function() {
var { mountTime } = this.state;
return (
<View>
<Image
source={this.props.source}
style={[styles.base, {overflow: 'visible'}]}
onLoadStart={() => this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
onLoad={() => this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`)}
onLoadEnd={() => {
this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`);
this.setState({startLoadPrefetched: true}, () => {
prefetchTask.then(() => {
this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
}, error => {
this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
});
});
}}
/>
{this.state.startLoadPrefetched ?
<Image
source={this.props.prefetchedSource}
style={[styles.base, {overflow: 'visible'}]}
onLoadStart={() => this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
onLoad={() => this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`)}
onLoadEnd={() => this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
/>
: null}
<Text style={{marginTop: 20}}>
{this.state.events.join('\n')}
</Text>
</View>
);
},
_loadEventFired(event) {
this.setState((state) => {
return state.events = [...state.events, event];
});
}
});
var NetworkImageExample = createReactClass({
getInitialState: function() {
return {
error: false,
loading: false,
progress: 0
};
},
render: function() {
var loader = this.state.loading ?
<View style={styles.progress}>
<Text>{this.state.progress}%</Text>
<ActivityIndicator style={{marginLeft:5}} />
</View> : null;
return this.state.error ?
<Text>{this.state.error}</Text> :
<Image
source={this.props.source}
style={[styles.base, {overflow: 'visible'}]}
onLoadStart={(e) => this.setState({loading: true})}
onError={(e) => this.setState({error: e.nativeEvent.error, loading: false})}
onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})}
onLoad={() => this.setState({loading: false, error: false})}>
{loader}
</Image>;
}
});
var ImageSizeExample = createReactClass({
getInitialState: function() {
return {
width: 0,
height: 0,
};
},
componentDidMount: function() {
Image.getSize(this.props.source.uri, (width, height) => {
this.setState({width, height});
});
},
render: function() {
return (
<View>
<Text>
Actual dimensions:{'\n'}
width: {this.state.width}, height: {this.state.height}
</Text>
<Image
source={this.props.source}
style={{
backgroundColor: '#eee',
height: 227,
marginTop: 10,
width: 323
}}
/>
</View>
);
},
});
/*
var MultipleSourcesExample = createReactClass({
getInitialState: function() {
return {
width: 30,
height: 30,
};
},
render: function() {
return (
<View style={styles.container}>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Text
style={styles.touchableText}
onPress={this.decreaseImageSize} >
Decrease image size
</Text>
<Text
style={styles.touchableText}
onPress={this.increaseImageSize} >
Increase image size
</Text>
</View>
<Text>Container image size: {this.state.width}x{this.state.height} </Text>
<View
style={[styles.imageContainer, {height: this.state.height, width: this.state.width}]} >
<Image
style={{flex: 1}}
source={[
{uri: 'http://facebook.github.io/react/img/logo_small.png', width: 38, height: 38},
{uri: 'http://facebook.github.io/react/img/logo_small_2x.png', width: 76, height: 76},
{uri: 'http://facebook.github.io/react/img/logo_og.png', width: 400, height: 400}
]}
/>
</View>
</View>
);
},
increaseImageSize: function() {
if (this.state.width >= 100) {
return;
}
this.setState({
width: this.state.width + 10,
height: this.state.height + 10,
});
},
decreaseImageSize: function() {
if (this.state.width <= 10) {
return;
}
this.setState({
width: this.state.width - 10,
height: this.state.height - 10,
});
},
});
*/
const examples = [
{
title: 'Plain Network Image',
description: 'If the `source` prop `uri` property is prefixed with ' +
'"http", then it will be downloaded from the network.',
render: function() {
return (
<Image
source={{ uri: 'http://facebook.github.io/react/img/logo_og.png', width: 1200, height: 630 }}
style={styles.base}
/>
);
},
},
{
title: 'Plain Static Image',
description: 'Static assets should be placed in the source code tree, and ' +
'required in the same way as JavaScript modules.',
render: function() {
return (
<View style={styles.horizontal}>
<Image source={require('./uie_thumb_normal@2x.png')} style={styles.icon} />
<Image source={require('./uie_thumb_selected@2x.png')} style={styles.icon} />
{/*<Image source={require('./uie_comment_normal.png')} style={styles.icon} />*/}
{/*<Image source={require('./uie_comment_highlighted.png')} style={styles.icon} />*/}
</View>
);
},
},
{
title: 'Image Loading Events',
render: function() {
return (
<NetworkImageCallbackExample
source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now()}}
prefetchedSource={{uri: IMAGE_PREFETCH_URL}}
/>
);
},
},
{
title: 'Error Handler',
render: function() {
return (
<NetworkImageExample source={{uri: 'http://TYPO_ERROR_facebook.github.io/react/img/logo_og.png'}} />
);
},
platform: 'ios',
},
{
title: 'Image Download Progress',
render: function() {
return (
<NetworkImageExample source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1'}}/>
);
},
platform: 'ios',
},
{
title: 'defaultSource',
description: 'Show a placeholder image when a network image is loading',
render: function() {
return (
<Image
defaultSource={require('./bunny.png')}
source={{uri: 'http://facebook.github.io/origami/public/images/birds.jpg'}}
style={styles.base}
/>
);
},
platform: 'ios',
},
{
title: 'Border Color',
render: function() {
return (
<View style={styles.horizontal}>
<Image
source={smallImage}
style={[
styles.base,
styles.background,
{borderWidth: 3, borderColor: '#f099f0'}
]}
/>
</View>
);
},
},
{
title: 'Border Width',
render: function() {
return (
<View style={styles.horizontal}>
<Image
source={smallImage}
style={[
styles.base,
styles.background,
{borderWidth: 5, borderColor: '#f099f0'}
]}
/>
</View>
);
},
},
{
title: 'Border Radius',
render: function() {
return (
<View style={styles.horizontal}>
<Image
style={[styles.base, {borderRadius: 5}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {borderRadius: 19}]}
source={fullImage}
/>
</View>
);
},
},
{
title: 'Background Color',
render: function() {
return (
<View style={styles.horizontal}>
<Image source={smallImage} style={styles.base} />
<Image
style={[
styles.base,
styles.leftMargin,
{backgroundColor: 'rgba(0, 0, 100, 0.25)'}
]}
source={smallImage}
/>
<Image
style={[styles.base, styles.leftMargin, {backgroundColor: 'red'}]}
source={smallImage}
/>
<Image
style={[styles.base, styles.leftMargin, {backgroundColor: 'black'}]}
source={smallImage}
/>
</View>
);
},
},
{
title: 'Opacity',
render: function() {
return (
<View style={styles.horizontal}>
<Image
style={[styles.base, {opacity: 1}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {opacity: 0.8}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {opacity: 0.6}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {opacity: 0.4}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {opacity: 0.2}]}
source={fullImage}
/>
<Image
style={[styles.base, styles.leftMargin, {opacity: 0}]}
source={fullImage}
/>
</View>
);
},
},
{
title: 'Nesting',
render: function() {
return (
<Image
style={{width: 60, height: 60, backgroundColor: 'transparent'}}
source={fullImage}>
<Text style={styles.nestedText}>
React
</Text>
</Image>
);
},
},
/*
{
title: 'Tint Color',
description: 'The `tintColor` style prop changes all the non-alpha ' +
'pixels to the tint color.',
render: function() {
return (
<View>
<View style={styles.horizontal}>
<Image
source={require('./uie_thumb_normal@2x.png')}
style={[styles.icon, {borderRadius: 5, tintColor: '#5ac8fa' }]}
/>
<Image
source={require('./uie_thumb_normal@2x.png')}
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#4cd964' }]}
/>
<Image
source={require('./uie_thumb_normal@2x.png')}
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#ff2d55' }]}
/>
<Image
source={require('./uie_thumb_normal@2x.png')}
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#8e8e93' }]}
/>
</View>
<Text style={styles.sectionText}>
It also works with downloaded images:
</Text>
<View style={styles.horizontal}>
<Image
source={smallImage}
style={[styles.base, {borderRadius: 5, tintColor: '#5ac8fa' }]}
/>
<Image
source={smallImage}
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#4cd964' }]}
/>
<Image
source={smallImage}
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#ff2d55' }]}
/>
<Image
source={smallImage}
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#8e8e93' }]}
/>
</View>
</View>
);
},
},
*/
{
title: 'Resize Mode',
description: 'The `resizeMode` style prop controls how the image is ' +
'rendered within the frame.',
render: function() {
return (
<View>
{[smallImage, fullImage].map((image, index) => {
return (
<View key={index}>
<View style={styles.horizontal}>
<View>
<Text style={[styles.resizeModeText]}>
Contain
</Text>
<Image
style={styles.resizeMode}
resizeMode={Image.resizeMode.contain}
source={image}
/>
</View>
<View style={styles.leftMargin}>
<Text style={[styles.resizeModeText]}>
Cover
</Text>
<Image
style={styles.resizeMode}
resizeMode={Image.resizeMode.cover}
source={image}
/>
</View>
</View>
<View style={styles.horizontal}>
<View>
<Text style={[styles.resizeModeText]}>
Stretch
</Text>
<Image
style={styles.resizeMode}
resizeMode={Image.resizeMode.stretch}
source={image}
/>
</View>
<View style={styles.leftMargin}>
<Text style={[styles.resizeModeText]}>
Repeat
</Text>
<Image
style={styles.resizeMode}
resizeMode={'repeat'}
source={image}
/>
</View>
<View style={styles.leftMargin}>
<Text style={[styles.resizeModeText]}>
Center
</Text>
<Image
style={styles.resizeMode}
resizeMode={'center'}
source={image}
/>
</View>
</View>
</View>
);
})}
</View>
);
},
},
{
title: 'Animated GIF',
render: function() {
return (
<Image
style={styles.gif}
source={{uri: 'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'}}
/>
);
},
platform: 'ios',
},
{
title: 'Base64 image',
render: function() {
return (
<Image
style={styles.base64}
source={{uri: base64Icon, scale: 3}}
/>
);
},
platform: 'ios',
},
/*
{
title: 'Cap Insets',
description:
'When the image is resized, the corners of the size specified ' +
'by capInsets will stay a fixed size, but the center content and ' +
'borders of the image will be stretched. This is useful for creating ' +
'resizable rounded buttons, shadows, and other resizable assets.',
render: function() {
return <ImageCapInsetsExample />;
},
platform: 'ios',
},
*/
{
title: 'Image Size',
render: function() {
return <ImageSizeExample source={{ uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg' }} />;
},
},
/*
{
title: 'MultipleSourcesExample',
description:
'The `source` prop allows passing in an array of uris, so that native to choose which image ' +
'to diplay based on the size of the of the target image',
render: function() {
return <MultipleSourcesExample />;
},
platform: 'android',
},
*/
];
var fullImage = {uri: 'http://facebook.github.io/react/img/logo_og.png'};
var smallImage = {uri: 'http://facebook.github.io/react/img/logo_small_2x.png'};
var styles = StyleSheet.create({
base: {
width: 38,
height: 38,
},
progress: {
flex: 1,
alignItems: 'center',
flexDirection: 'row',
width: 100
},
leftMargin: {
marginLeft: 10,
},
background: {
backgroundColor: '#222222'
},
sectionText: {
marginVertical: 6,
},
nestedText: {
marginLeft: 12,
marginTop: 20,
backgroundColor: 'transparent',
color: 'white'
},
resizeMode: {
width: 90,
height: 60,
borderWidth: 0.5,
borderColor: 'black'
},
resizeModeText: {
fontSize: 11,
marginBottom: 3,
},
icon: {
width: 15,
height: 15,
},
horizontal: {
flexDirection: 'row',
},
gif: {
flex: 1,
height: 200,
},
base64: {
flex: 1,
height: 50,
resizeMode: 'contain',
},
touchableText: {
fontWeight: '500',
color: 'blue',
},
});
examples.forEach((example) => {
storiesOf('component: Image', module)
.addDecorator((renderStory) => <View style={{ width: '100%' }}>{renderStory()}</View>)
.add(example.title, () => example.render())
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,80 @@
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import { ListView, StyleSheet, Text, View } from 'react-native';
const generateData = (length) => Array.from({ length }).map((item, i) => i);
const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
storiesOf('component: ListView', module)
.add('vertical', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(100))}
initialListSize={100}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
))
.add('incremental rendering - large pageSize', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(5000))}
initialListSize={100}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
pageSize={50}
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
))
.add('incremental rendering - small pageSize', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(5000))}
initialListSize={5}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
pageSize={1}
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
));
const styles = StyleSheet.create({
box: {
flexGrow: 1,
justifyContent: 'center',
borderWidth: 1
},
scrollViewContainer: {
height: '200px',
width: 300
},
scrollViewStyle: {
borderWidth: '1px'
},
scrollViewContentContainerStyle: {
backgroundColor: '#eee',
padding: '10px'
}
});

View File

@@ -0,0 +1,97 @@
import createReactClass from 'create-react-class';
import { ProgressBar, StyleSheet, View } from 'react-native'
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import TimerMixin from 'react-timer-mixin';
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
var ProgressBarExample = createReactClass({
mixins: [TimerMixin],
getInitialState() {
return {
progress: 0,
};
},
componentDidMount() {
this.updateProgress();
},
updateProgress() {
var progress = this.state.progress + 0.01;
this.setState({ progress });
this.requestAnimationFrame(() => this.updateProgress());
},
getProgress(offset) {
var progress = this.state.progress + offset;
return Math.sin(progress % Math.PI) % 1;
},
render() {
return (
<View style={styles.container}>
<ProgressBar style={styles.progressView} color="purple" progress={this.getProgress(0.2)} />
<ProgressBar style={styles.progressView} color="red" progress={this.getProgress(0.4)} />
<ProgressBar style={styles.progressView} color="orange" progress={this.getProgress(0.6)} />
<ProgressBar style={styles.progressView} color="yellow" progress={this.getProgress(0.8)} />
</View>
);
},
});
const examples = [{
title: 'progress',
render() {
return (
<ProgressBarExample />
);
},
}, {
title: 'indeterminate',
render() {
return (
<ProgressBar indeterminate style={styles.progressView} trackColor='#D1E3F6' />
);
}
}];
var styles = StyleSheet.create({
container: {
minWidth: 200,
marginTop: -20,
backgroundColor: 'transparent',
},
progressView: {
marginTop: 20,
minWidth: 200
}
});
examples.forEach((example) => {
storiesOf('component: ProgressBar', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,59 @@
import React from 'react';
import { action, storiesOf } from '@kadira/storybook';
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native'
const onScroll = action('ScrollView.onScroll');
storiesOf('component: ScrollView', module)
.add('vertical', () => (
<View style={styles.scrollViewContainer}>
<ScrollView
contentContainerStyle={styles.scrollViewContentContainerStyle}
onScroll={onScroll}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
>
{Array.from({ length: 50 }).map((item, i) => (
<View key={i} style={styles.box}>
<TouchableHighlight onPress={() => {}}><Text>{i}</Text></TouchableHighlight>
</View>
))}
</ScrollView>
</View>
))
.add('horizontal', () => (
<View style={styles.scrollViewContainer}>
<ScrollView
contentContainerStyle={styles.scrollViewContentContainerStyle}
horizontal
onScroll={onScroll}
scrollEventThrottle={16} // ~60 events per second
style={styles.scrollViewStyle}
>
{Array.from({ length: 50 }).map((item, i) => (
<View key={i} style={[ styles.box, styles.horizontalBox ]}>
<Text>{i}</Text>
</View>
))}
</ScrollView>
</View>
))
const styles = StyleSheet.create({
box: {
flexGrow: 1,
justifyContent: 'center',
borderWidth: 1
},
scrollViewContainer: {
height: '200px',
width: 300
},
scrollViewStyle: {
borderWidth: 1
},
scrollViewContentContainerStyle: {
backgroundColor: '#eee',
padding: 10
}
})

View File

@@ -0,0 +1,191 @@
import createReactClass from 'create-react-class';
import { Platform, Switch, Text, View } from 'react-native'
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
var BasicSwitchExample = createReactClass({
getInitialState() {
return {
trueSwitchIsOn: true,
falseSwitchIsOn: false,
};
},
render() {
return (
<View>
<Switch
onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
style={{marginBottom: 10}}
value={this.state.falseSwitchIsOn}
/>
<Switch
onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
value={this.state.trueSwitchIsOn}
/>
</View>
);
}
});
var DisabledSwitchExample = createReactClass({
render() {
return (
<View>
<Switch
disabled={true}
style={{marginBottom: 10}}
value={true} />
<Switch
disabled={true}
value={false} />
</View>
);
},
});
var ColorSwitchExample = createReactClass({
getInitialState() {
return {
colorTrueSwitchIsOn: true,
colorFalseSwitchIsOn: false,
};
},
render() {
return (
<View>
<Switch
activeThumbColor="#428bca"
activeTrackColor="#A0C4E3"
onValueChange={(value) => this.setState({colorFalseSwitchIsOn: value})}
style={{marginBottom: 10}}
value={this.state.colorFalseSwitchIsOn}
/>
<Switch
activeThumbColor="#5CB85C"
activeTrackColor="#ADDAAD"
onValueChange={(value) => this.setState({colorTrueSwitchIsOn: value})}
thumbColor="#EBA9A7"
trackColor="#D9534F"
value={this.state.colorTrueSwitchIsOn}
/>
</View>
);
},
});
var EventSwitchExample = createReactClass({
getInitialState() {
return {
eventSwitchIsOn: false,
eventSwitchRegressionIsOn: true,
};
},
render() {
return (
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
<View>
<Switch
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventSwitchIsOn} />
<Switch
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventSwitchIsOn} />
<Text>{this.state.eventSwitchIsOn ? 'On' : 'Off'}</Text>
</View>
<View>
<Switch
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventSwitchRegressionIsOn} />
<Switch
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventSwitchRegressionIsOn} />
<Text>{this.state.eventSwitchRegressionIsOn ? 'On' : 'Off'}</Text>
</View>
</View>
);
}
});
var SizeSwitchExample = createReactClass({
getInitialState() {
return {
trueSwitchIsOn: true,
falseSwitchIsOn: false,
};
},
render() {
return (
<View>
<Switch
onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
style={{marginBottom: 10, height: '3rem' }}
value={this.state.falseSwitchIsOn}
/>
<Switch
onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
style={{marginBottom: 10, width: 150 }}
value={this.state.trueSwitchIsOn}
/>
</View>
);
}
});
var examples = [
{
title: 'set to true or false',
render(): ReactElement<any> { return <BasicSwitchExample />; }
},
{
title: 'disabled',
render(): ReactElement<any> { return <DisabledSwitchExample />; }
},
{
title: 'change events',
render(): ReactElement<any> { return <EventSwitchExample />; }
},
{
title: 'custom colors',
render(): ReactElement<any> { return <ColorSwitchExample />; }
},
{
title: 'custom size',
render(): ReactElement<any> { return <SizeSwitchExample />; }
},
{
title: 'controlled component',
render(): ReactElement<any> { return <Switch />; }
}
];
examples.forEach((example) => {
storiesOf('component: Switch', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,473 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { Image, StyleSheet, Text, View } from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
var Entity = createReactClass({
render: function() {
return (
<Text style={{fontWeight: '500', color: '#527fe4'}}>
{this.props.children}
</Text>
);
}
});
var AttributeToggler = createReactClass({
getInitialState: function() {
return {fontWeight: 'bold', fontSize: 15};
},
toggleWeight: function() {
this.setState({
fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
});
},
increaseSize: function() {
this.setState({
fontSize: this.state.fontSize + 1
});
},
render: function() {
var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
return (
<View>
<Text style={curStyle}>
Tap the controls below to change attributes.
</Text>
<Text>
<Text>See how it will even work on <Text style={curStyle}>this nested text</Text></Text>
</Text>
<Text
style={{backgroundColor: '#ffaaaa', marginTop: 5}}
onPress={this.toggleWeight}>
Toggle Weight
</Text>
<Text
style={{backgroundColor: '#aaaaff', marginTop: 5}}
onPress={this.increaseSize}>
Increase Size
</Text>
</View>
);
}
});
const examples = [
{
title: 'Wrap',
render: function() {
return (
<Text style={{ WebkitFontSmoothing: 'antialiased' }}>
The text should wrap if it goes on multiple lines. See, this is going to
the next line.
</Text>
);
},
}, {
title: 'Padding',
render: function() {
return (
<Text style={{padding: 10}}>
This text is indented by 10px padding on all sides.
</Text>
);
},
}, {
title: 'Font Family',
render: function() {
return (
<View>
<Text style={{fontFamily: 'Cochin'}}>
Cochin
</Text>
<Text style={{fontFamily: 'Cochin', fontWeight: 'bold'}}>
Cochin bold
</Text>
<Text style={{fontFamily: 'Helvetica'}}>
Helvetica
</Text>
<Text style={{fontFamily: 'Helvetica', fontWeight: 'bold'}}>
Helvetica bold
</Text>
<Text style={{fontFamily: 'Verdana'}}>
Verdana
</Text>
<Text style={{fontFamily: 'Verdana', fontWeight: 'bold'}}>
Verdana bold
</Text>
</View>
);
},
}, {
title: 'Font Size',
render: function() {
return (
<View>
<Text style={{fontSize: 23}}>
Size 23
</Text>
<Text style={{fontSize: 8}}>
Size 8
</Text>
</View>
);
},
}, {
title: 'Color',
render: function() {
return (
<View>
<Text style={{color: 'red'}}>
Red color
</Text>
<Text style={{color: 'blue'}}>
Blue color
</Text>
</View>
);
},
}, {
title: 'Font Weight',
render: function() {
return (
<View>
<Text style={{fontSize: 20, fontWeight: '100'}}>
Move fast and be ultralight
</Text>
<Text style={{fontSize: 20, fontWeight: '200'}}>
Move fast and be light
</Text>
<Text style={{fontSize: 20, fontWeight: 'normal'}}>
Move fast and be normal
</Text>
<Text style={{fontSize: 20, fontWeight: 'bold'}}>
Move fast and be bold
</Text>
<Text style={{fontSize: 20, fontWeight: '900'}}>
Move fast and be ultrabold
</Text>
</View>
);
},
}, {
title: 'Font Style',
render: function() {
return (
<View>
<Text style={{fontStyle: 'normal'}}>
Normal text
</Text>
<Text style={{fontStyle: 'italic'}}>
Italic text
</Text>
</View>
);
},
}, {
title: 'Text Decoration',
render: function() {
return (
<View>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'solid'}}>
Solid underline
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'double', textDecorationColor: '#ff0000'}}>
Double underline with custom color
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'dashed', textDecorationColor: '#9CDC40'}}>
Dashed underline with custom color
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'dotted', textDecorationColor: 'blue'}}>
Dotted underline with custom color
</Text>
<Text style={{textDecorationLine: 'none'}}>
None textDecoration
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'solid'}}>
Solid line-through
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'double', textDecorationColor: '#ff0000'}}>
Double line-through with custom color
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'dashed', textDecorationColor: '#9CDC40'}}>
Dashed line-through with custom color
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'dotted', textDecorationColor: 'blue'}}>
Dotted line-through with custom color
</Text>
<Text style={{textDecorationLine: 'underline line-through'}}>
Both underline and line-through
</Text>
</View>
);
},
}, {
title: 'Nested',
description: 'Nested text components will inherit the styles of their ' +
'parents (only backgroundColor is inherited from non-Text parents). ' +
'<Text> only supports other <Text> and raw text (strings) as children.',
render: function() {
return (
<View>
<Text>
(Normal text,
<Text style={{fontWeight: 'bold'}}>
(and bold
<Text style={{fontSize: 11, color: '#527fe4'}}>
(and tiny inherited bold blue)
</Text>
)
</Text>
)
</Text>
<Text style={{opacity:0.7}}>
(opacity
<Text>
(is inherited
<Text style={{opacity:0.7}}>
(and accumulated
<Text style={{backgroundColor:'#ffaaaa'}}>
(and also applies to the background)
</Text>
)
</Text>
)
</Text>
)
</Text>
<Text style={{fontSize: 12}}>
<Entity>Entity Name</Entity>
</Text>
</View>
);
},
}, {
title: 'Text Align',
render: function() {
return (
<View>
<Text>
auto (default) - english LTR
</Text>
<Text>
أحب اللغة العربية auto (default) - arabic RTL
</Text>
<Text style={{textAlign: 'left'}}>
left left left left left left left left left left left left left left left
</Text>
<Text style={{textAlign: 'center'}}>
center center center center center center center center center center center
</Text>
<Text style={{textAlign: 'right'}}>
right right right right right right right right right right right right right
</Text>
<Text style={{textAlign: 'justify'}}>
justify: this text component{"'"}s contents are laid out with "textAlign: justify"
and as you can see all of the lines except the last one span the
available width of the parent container.
</Text>
</View>
);
},
}, {
title: 'Letter Spacing',
render: function() {
return (
<View>
<Text style={{letterSpacing: 0}}>
letterSpacing = 0
</Text>
<Text style={{letterSpacing: 2, marginTop: 5}}>
letterSpacing = 2
</Text>
<Text style={{letterSpacing: 9, marginTop: 5}}>
letterSpacing = 9
</Text>
<Text style={{letterSpacing: -1, marginTop: 5}}>
letterSpacing = -1
</Text>
</View>
);
},
}, {
title: 'Spaces',
render: function() {
return (
<Text>
A {'generated'} {' '} {'string'} and some &nbsp;&nbsp;&nbsp; spaces
</Text>
);
},
}, {
title: 'Line Height',
render: function() {
return (
<Text>
<Text style={{lineHeight: 35}}>
A lot of space between the lines of this long passage that should
wrap once.
</Text>
</Text>
);
},
}, {
title: 'Empty Text',
description: 'It\'s ok to have Text with zero or null children.',
render: function() {
return (
<Text />
);
},
}, {
title: 'Toggling Attributes',
render: function(): ReactElement<any> {
return <AttributeToggler />;
},
}, {
title: 'backgroundColor attribute',
description: 'backgroundColor is inherited from all types of views.',
render: function() {
return (
<Text style={{backgroundColor: 'yellow'}}>
Yellow container background,
<Text style={{backgroundColor: '#ffaaaa'}}>
{' '}red background,
<Text style={{backgroundColor: '#aaaaff'}}>
{' '}blue background,
<Text>
{' '}inherited blue background,
<Text style={{backgroundColor: '#aaffaa'}}>
{' '}nested green background.
</Text>
</Text>
</Text>
</Text>
</Text>
);
},
}, {
title: 'numberOfLines attribute',
render: function() {
return (
<View>
<Text numberOfLines={1}>
Maximum of one line, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after one line.
</Text>
<Text numberOfLines={2} style={{marginTop: 20}}>
Maximum of two lines, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after two lines.
</Text>
<Text style={{marginTop: 20}}>
No maximum lines specified, no matter how much I write here. If I keep writing, it{"'"}ll just keep going and going.
</Text>
</View>
);
},
}, {
title: 'Text highlighting (tap the link to see highlight)',
render: function() {
return (
<View>
<Text>Lorem ipsum dolor sit amet, <Text suppressHighlighting={false} style={{backgroundColor: 'white', textDecorationLine: 'underline', color: 'blue'}} onPress={() => null}>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud</Text> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</Text>
</View>
);
},
}, {
title: 'allowFontScaling attribute',
render: function() {
return (
<View>
<Text>
By default, text will respect Text Size accessibility setting on iOS.
It means that all font sizes will be increased or descreased depending on the value of Text Size setting in
{" "}<Text style={{fontWeight: 'bold'}}>Settings.app - Display & Brightness - Text Size</Text>
</Text>
<Text style={{marginTop: 10}}>
You can disable scaling for your Text component by passing {"\""}allowFontScaling={"{"}false{"}\""} prop.
</Text>
<Text allowFontScaling={false} style={{marginTop: 20}}>
This text will not scale.
</Text>
</View>
);
},
}, {
title: 'Inline views',
render: function() {
return (
<View>
<Text>
This text contains an inline blue view <View style={{width: 25, height: 25, backgroundColor: 'steelblue'}} /> and
an inline image <Image source={{ uri: 'http://lorempixel.com/30/11' }} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
</Text>
</View>
);
},
}, {
title: 'Text shadow',
render: function() {
return (
<View>
<Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
Demo text shadow
</Text>
</View>
);
},
}, {
title: 'Line break mode',
render: function() {
return (
<View>
<Text numberOfLines={1}>
This very long text should be truncated with dots in the end.
</Text>
<Text lineBreakMode="middle" numberOfLines={1}>
This very long text should be truncated with dots in the middle.
</Text>
<Text lineBreakMode="head" numberOfLines={1}>
This very long text should be truncated with dots in the beginning.
</Text>
<Text lineBreakMode="clip" numberOfLines={1}>
This very looooooooooooooooooooooooooooong text should be clipped.
</Text>
</View>
);
},
}];
var styles = StyleSheet.create({
backgroundColorText: {
margin: 5,
marginBottom: 0,
backgroundColor: 'rgba(100, 100, 100, 0.3)'
},
});
examples.forEach((example) => {
storiesOf('component: Text', module)
.addDecorator((renderStory) => <View style={{ width: 320 }}>{renderStory()}</View>)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,867 @@
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { StyleSheet, Text, TextInput, View } from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
class WithLabel extends React.Component {
render() {
return (
<View style={styles.labelContainer}>
<View style={styles.label}>
<Text>{this.props.label}</Text>
</View>
{this.props.children}
</View>
);
}
}
class TextEventsExample extends React.Component {
state = {
curText: '<No Event>',
prevText: '<No Event>',
prev2Text: '<No Event>',
prev3Text: '<No Event>',
};
updateText = (text) => {
this.setState((state) => {
return {
curText: text,
prevText: state.curText,
prev2Text: state.prevText,
prev3Text: state.prev2Text,
};
});
};
render() {
return (
<View style={{ alignItems: 'center' }}>
<TextInput
autoCapitalize="none"
placeholder="Enter text to see events"
autoCorrect={false}
onFocus={() => this.updateText('onFocus')}
onBlur={() => this.updateText('onBlur')}
onChange={(event) => this.updateText(
'onChange text: ' + event.nativeEvent.text
)}
onEndEditing={(event) => this.updateText(
'onEndEditing text: ' + event.nativeEvent.text
)}
onSubmitEditing={(event) => this.updateText(
'onSubmitEditing text: ' + event.nativeEvent.text
)}
onSelectionChange={(event) => this.updateText(
'onSelectionChange range: ' +
event.nativeEvent.selection.start + ',' +
event.nativeEvent.selection.end
)}
onKeyPress={(event) => {
this.updateText('onKeyPress key: ' + event.nativeEvent.key);
}}
style={[ styles.default, { maxWidth: 200 } ]}
/>
<Text style={styles.eventLabel}>
{this.state.curText}{'\n'}
(prev: {this.state.prevText}){'\n'}
(prev2: {this.state.prev2Text}){'\n'}
(prev3: {this.state.prev3Text})
</Text>
</View>
);
}
}
class AutoExpandingTextInput extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {
text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
height: 0,
};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChangeText={(text) => {
this.setState({text});
}}
onContentSizeChange={(event) => {
this.setState({height: event.nativeEvent.contentSize.height});
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
class RewriteExample extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
var limit = 20;
var remainder = limit - this.state.text.length;
var remainderColor = remainder > 5 ? 'blue' : 'red';
return (
<View style={styles.rewriteContainer}>
<TextInput
multiline={false}
maxLength={limit}
onChangeText={(text) => {
text = text.replace(/ /g, '_');
this.setState({text});
}}
style={styles.default}
value={this.state.text}
/>
<Text style={[styles.remainder, {color: remainderColor}]}>
{remainder}
</Text>
</View>
);
}
}
class RewriteExampleInvalidCharacters extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={styles.rewriteContainer}>
<TextInput
multiline={false}
onChangeText={(text) => {
this.setState({text: text.replace(/\s/g, '')});
}}
style={styles.default}
value={this.state.text}
/>
</View>
);
}
}
class TokenizedTextExample extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: 'Hello #World'};
}
render() {
//define delimiter
let delimiter = /\s+/;
//split string
let _text = this.state.text;
let token, index, parts = [];
while (_text) {
delimiter.lastIndex = 0;
token = delimiter.exec(_text);
if (token === null) {
break;
}
index = token.index;
if (token[0].length === 0) {
index = 1;
}
parts.push(_text.substr(0, index));
parts.push(token[0]);
index = index + token[0].length;
_text = _text.slice(index);
}
parts.push(_text);
return (
<View>
<TextInput
value={parts.join('')}
multiline={true}
style={styles.multiline}
onChangeText={(text) => {
this.setState({text});
}}
/>
</View>
);
}
}
class BlurOnSubmitExample extends React.Component {
focusNextField = (nextField) => {
this.refs[nextField].focus();
};
render() {
return (
<View>
<TextInput
ref="1"
style={styles.default}
placeholder="blurOnSubmit = false"
returnKeyType="next"
blurOnSubmit={false}
onSubmitEditing={() => this.focusNextField('2')}
/>
<TextInput
ref="2"
style={styles.default}
keyboardType="email-address"
placeholder="blurOnSubmit = false"
returnKeyType="next"
blurOnSubmit={false}
onSubmitEditing={() => this.focusNextField('3')}
/>
<TextInput
ref="3"
style={styles.default}
keyboardType="url"
placeholder="blurOnSubmit = false"
returnKeyType="next"
blurOnSubmit={false}
onSubmitEditing={() => this.focusNextField('4')}
/>
<TextInput
ref="4"
style={styles.default}
keyboardType="numeric"
placeholder="blurOnSubmit = false"
blurOnSubmit={false}
onSubmitEditing={() => this.focusNextField('5')}
/>
<TextInput
ref="5"
style={styles.default}
keyboardType="numeric"
placeholder="blurOnSubmit = true"
returnKeyType="done"
/>
</View>
);
}
}
type SelectionExampleState = {
selection: {
start: number;
end?: number;
};
value: string;
};
class SelectionExample extends React.Component {
state: SelectionExampleState;
_textInput: any;
constructor(props) {
super(props);
this.state = {
selection: {start: 0, end: 0},
value: props.value
};
}
onSelectionChange({nativeEvent: {selection}}) {
this.setState({selection});
}
getRandomPosition() {
var length = this.state.value.length;
return Math.round(Math.random() * length);
}
select(start, end) {
this._textInput.focus();
this.setState({selection: {start, end}});
}
selectRandom() {
var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
this.select(...positions);
}
placeAt(position) {
this.select(position, position);
}
placeAtRandom() {
this.placeAt(this.getRandomPosition());
}
render() {
var length = this.state.value.length;
return (
<View>
<TextInput
multiline={this.props.multiline}
onChangeText={(value) => this.setState({value})}
onSelectionChange={this.onSelectionChange.bind(this)}
ref={textInput => (this._textInput = textInput)}
selection={this.state.selection}
style={this.props.style}
value={this.state.value}
/>
<View>
<Text>
selection = {JSON.stringify(this.state.selection)}
</Text>
<Text onPress={this.placeAt.bind(this, 0)}>
Place at Start (0, 0)
</Text>
<Text onPress={this.placeAt.bind(this, length)}>
Place at End ({length}, {length})
</Text>
<Text onPress={this.placeAtRandom.bind(this)}>
Place at Random
</Text>
<Text onPress={this.select.bind(this, 0, length)}>
Select All
</Text>
<Text onPress={this.selectRandom.bind(this)}>
Select Random
</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
page: {
paddingBottom: 300,
},
default: {
height: 26,
borderWidth: 0.5,
borderColor: '#0f0f0f',
flex: 1,
fontSize: 13,
padding: 4,
},
multiline: {
borderWidth: 0.5,
borderColor: '#0f0f0f',
flex: 1,
fontSize: 13,
height: 50,
padding: 4,
marginBottom: 4,
},
multilineWithFontStyles: {
color: 'blue',
fontWeight: 'bold',
fontSize: 18,
fontFamily: 'Cochin',
height: 60,
},
multilineChild: {
width: 50,
height: 40,
position: 'absolute',
right: 5,
backgroundColor: 'red',
},
eventLabel: {
margin: 3,
fontSize: 12,
},
labelContainer: {
flexDirection: 'row',
marginVertical: 2,
flex: 1,
},
label: {
width: 115,
alignItems: 'flex-end',
marginRight: 10,
paddingTop: 2,
},
rewriteContainer: {
flexDirection: 'row',
alignItems: 'center',
},
remainder: {
textAlign: 'right',
width: 24,
},
hashtag: {
color: 'blue',
fontWeight: 'bold',
},
});
const examples = [
{
title: 'Auto-focus',
render: function() {
return (
<View>
<TextInput
autoFocus={true}
style={styles.default}
accessibilityLabel="I am the accessibility label for text input"
/>
</View>
);
}
},
{
title: "Live Re-Write (<sp> -> '_') + maxLength",
render: function() {
return <RewriteExample />;
}
},
{
title: 'Live Re-Write (no spaces allowed)',
render: function() {
return <RewriteExampleInvalidCharacters />;
}
},
{
title: 'Auto-capitalize',
render: function() {
return (
<View>
<WithLabel label="none">
<TextInput
autoCapitalize="none"
style={styles.default}
/>
</WithLabel>
<WithLabel label="sentences">
<TextInput
autoCapitalize="sentences"
style={styles.default}
/>
</WithLabel>
<WithLabel label="words">
<TextInput
autoCapitalize="words"
style={styles.default}
/>
</WithLabel>
<WithLabel label="characters">
<TextInput
autoCapitalize="characters"
style={styles.default}
/>
</WithLabel>
</View>
);
}
},
{
title: 'Auto-correct',
render: function() {
return (
<View>
<WithLabel label="true">
<TextInput autoCorrect={true} style={styles.default} />
</WithLabel>
<WithLabel label="false">
<TextInput autoCorrect={false} style={styles.default} />
</WithLabel>
</View>
);
}
},
{
title: 'Keyboard types',
render: function() {
var keyboardTypes = [
'default',
//'ascii-capable',
//'numbers-and-punctuation',
'url',
'number-pad',
'phone-pad',
//'name-phone-pad',
'email-address',
//'decimal-pad',
//'twitter',
'web-search',
'numeric',
];
var examples = keyboardTypes.map((type) => {
return (
<WithLabel key={type} label={type}>
<TextInput
keyboardType={type}
style={styles.default}
/>
</WithLabel>
);
});
return <View>{examples}</View>;
}
},
{
title: 'Keyboard appearance',
render: function() {
var keyboardAppearance = [
'default',
'light',
'dark',
];
var examples = keyboardAppearance.map((type) => {
return (
<WithLabel key={type} label={type}>
<TextInput
keyboardAppearance={type}
style={styles.default}
/>
</WithLabel>
);
});
return <View>{examples}</View>;
}
},
{
title: 'Return key types',
render: function() {
var returnKeyTypes = [
'default',
'go',
'google',
'join',
'next',
'route',
'search',
'send',
'yahoo',
'done',
'emergency-call',
];
var examples = returnKeyTypes.map((type) => {
return (
<WithLabel key={type} label={type}>
<TextInput
returnKeyType={type}
style={styles.default}
/>
</WithLabel>
);
});
return <View>{examples}</View>;
}
},
{
title: 'Enable return key automatically',
render: function() {
return (
<View>
<WithLabel label="true">
<TextInput enablesReturnKeyAutomatically={true} style={styles.default} />
</WithLabel>
</View>
);
}
},
{
title: 'Secure text entry',
render: function() {
return (
<View>
<WithLabel label="true">
<TextInput secureTextEntry={true} style={styles.default} defaultValue="abc" />
</WithLabel>
</View>
);
}
},
{
title: 'Event handling',
render: function(): React.Element<any> { return <TextEventsExample />; },
},
{
title: 'Colored input text',
render: function() {
return (
<View>
<TextInput
style={[styles.default, {color: 'blue'}]}
defaultValue="Blue"
/>
<TextInput
style={[styles.default, {color: 'green'}]}
defaultValue="Green"
/>
</View>
);
}
},
{
title: 'Colored highlight/cursor for text input',
render: function() {
return (
<View>
<TextInput
style={styles.default}
selectionColor={"green"}
defaultValue="Highlight me"
/>
<TextInput
style={styles.default}
selectionColor={"rgba(86, 76, 205, 1)"}
defaultValue="Highlight me"
/>
</View>
);
}
},
{
title: 'Clear button mode',
render: function () {
return (
<View>
<WithLabel label="never">
<TextInput
style={styles.default}
clearButtonMode="never"
/>
</WithLabel>
<WithLabel label="while editing">
<TextInput
style={styles.default}
clearButtonMode="while-editing"
/>
</WithLabel>
<WithLabel label="unless editing">
<TextInput
style={styles.default}
clearButtonMode="unless-editing"
/>
</WithLabel>
<WithLabel label="always">
<TextInput
style={styles.default}
clearButtonMode="always"
/>
</WithLabel>
</View>
);
}
},
{
title: 'Clear and select',
render: function() {
return (
<View>
<WithLabel label="clearTextOnFocus">
<TextInput
placeholder="text is cleared on focus"
defaultValue="text is cleared on focus"
style={styles.default}
clearTextOnFocus={true}
/>
</WithLabel>
<WithLabel label="selectTextOnFocus">
<TextInput
placeholder="text is selected on focus"
defaultValue="text is selected on focus"
style={styles.default}
selectTextOnFocus={true}
/>
</WithLabel>
</View>
);
}
},
{
title: 'Blur on submit',
render: function(): React.Element<any> { return <BlurOnSubmitExample />; },
},
{
title: 'Multiline blur on submit',
render: function() {
return (
<View>
<TextInput
style={styles.multiline}
placeholder="blurOnSubmit = true"
returnKeyType="next"
blurOnSubmit={true}
multiline={true}
onSubmitEditing={event => alert(event.nativeEvent.text)}
/>
</View>
);
}
},
{
title: 'Multiline',
render: function() {
return (
<View>
<TextInput
placeholder="multiline text input"
multiline={true}
style={styles.multiline}
/>
<TextInput
placeholder="multiline text input with font styles and placeholder"
multiline={true}
clearTextOnFocus={true}
autoCorrect={true}
autoCapitalize="words"
placeholderTextColor="red"
keyboardType="url"
style={[styles.multiline, styles.multilineWithFontStyles]}
/>
<TextInput
placeholder="multiline text input with max length"
maxLength={5}
multiline={true}
style={styles.multiline}
/>
<TextInput
placeholder="uneditable multiline text input"
editable={false}
multiline={true}
style={styles.multiline}
/>
<TextInput
defaultValue="uneditable multiline text input with phone number detection: 88888888."
editable={false}
multiline={true}
style={styles.multiline}
dataDetectorTypes="phoneNumber"
/>
</View>
);
}
},
{
title: 'Number of lines',
render: function() {
return (
<View>
<TextInput
multiline={true}
numberOfLines={4}
style={[ styles.multiline, { height: 'auto' } ]}
/>
</View>
);
}
},
{
title: 'Auto-expanding',
render: function() {
return (
<View>
<AutoExpandingTextInput
placeholder="height increases with content"
enablesReturnKeyAutomatically={true}
returnKeyType="default"
/>
</View>
);
}
},
{
title: 'Attributed text',
render: function() {
return <TokenizedTextExample />;
}
},
{
title: 'Text selection & cursor placement',
render: function() {
return (
<View>
<SelectionExample
style={styles.default}
value="text selection can be changed"
/>
<SelectionExample
multiline
style={styles.multiline}
value={"multiline text selection\ncan also be changed"}
/>
</View>
);
}
},
{
title: 'TextInput maxLength',
render: function() {
return (
<View>
<WithLabel label="maxLength: 5">
<TextInput
maxLength={5}
style={styles.default}
/>
</WithLabel>
<WithLabel label="maxLength: 5 with placeholder">
<TextInput
maxLength={5}
placeholder="ZIP code entry"
style={styles.default}
/>
</WithLabel>
<WithLabel label="maxLength: 5 with default value already set">
<TextInput
maxLength={5}
defaultValue="94025"
style={styles.default}
/>
</WithLabel>
<WithLabel label="maxLength: 5 with very long default value already set">
<TextInput
maxLength={5}
defaultValue="9402512345"
style={styles.default}
/>
</WithLabel>
</View>
);
}
}
];
examples.forEach((example) => {
storiesOf('component: TextInput', module)
.add(example.title, () => example.render())
});

View File

@@ -0,0 +1,448 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import {
Image,
StyleSheet,
Text,
TouchableHighlight,
TouchableOpacity,
Platform,
TouchableNativeFeedback,
View,
} from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
const examples = [
{
title: '<TouchableHighlight>',
description: 'TouchableHighlight works by adding an extra view with a ' +
'black background under the single child view. This works best when the ' +
'child view is fully opaque, although it can be made to work as a simple ' +
'background color change as well with the activeOpacity and ' +
'underlayColor props.',
render: function() {
return (
<View>
<View style={styles.row}>
<TouchableHighlight
style={styles.wrapper}
onPress={() => console.log('stock THW image - highlight')}>
<Image
source={heartImage}
style={styles.image}
/>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
activeOpacity={1}
underlayColor="rgb(210, 230, 255)"
onPress={() => console.log('custom THW text - highlight')}>
<View style={styles.wrapperCustom}>
<Text style={styles.text}>
Tap Here For Custom Highlight!
</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
},
}, {
title: '<Text onPress={fn}> with highlight',
render: function(): ReactElement<any> {
return <TextOnPressBox />;
},
}, {
title: 'Touchable feedback events',
description: '<Touchable*> components accept onPress, onPressIn, ' +
'onPressOut, and onLongPress as props.',
render: function(): ReactElement<any> {
return <TouchableFeedbackEvents />;
},
}, {
title: 'Touchable delay for events',
description: '<Touchable*> components also accept delayPressIn, ' +
'delayPressOut, and delayLongPress as props. These props impact the ' +
'timing of feedback events.',
render: function(): ReactElement<any> {
return <TouchableDelayEvents />;
},
}, {
title: '3D Touch / Force Touch',
description: 'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
render: function(): ReactElement<any> {
return <ForceTouchExample />;
},
platform: 'ios',
}, {
title: 'Touchable Hit Slop',
description: '<Touchable*> components accept hitSlop prop which extends the touch area ' +
'without changing the view bounds.',
render: function(): ReactElement<any> {
return <TouchableHitSlop />;
},
}, {
title: 'Disabled Touchable*',
description: '<Touchable*> components accept disabled prop which prevents ' +
'any interaction with component',
render: function(): ReactElement<any> {
return <TouchableDisabled />;
},
}];
var TextOnPressBox = createReactClass({
getInitialState: function() {
return {
timesPressed: 0,
};
},
textOnPress: function() {
this.setState({
timesPressed: this.state.timesPressed + 1,
});
},
render: function() {
var textLog = '';
if (this.state.timesPressed > 1) {
textLog = this.state.timesPressed + 'x text onPress';
} else if (this.state.timesPressed > 0) {
textLog = 'text onPress';
}
return (
<View>
<Text
style={styles.textBlock}
onPress={this.textOnPress}>
Text has built-in onPress handling
</Text>
<View style={styles.logBox}>
<Text>
{textLog}
</Text>
</View>
</View>
);
}
});
var TouchableFeedbackEvents = createReactClass({
getInitialState: function() {
return {
eventLog: [],
};
},
render: function() {
return (
<View testID="touchable_feedback_events">
<View style={[styles.row, {justifyContent: 'center'}]}>
<TouchableOpacity
style={styles.wrapper}
testID="touchable_feedback_events_button"
accessibilityLabel="touchable feedback events"
accessibilityTraits="button"
accessibilityComponentType="button"
onPress={() => this._appendEvent('press')}
onPressIn={() => this._appendEvent('pressIn')}
onPressOut={() => this._appendEvent('pressOut')}
onLongPress={() => this._appendEvent('longPress')}>
<Text style={styles.button}>
Press Me
</Text>
</TouchableOpacity>
</View>
<View testID="touchable_feedback_events_console" style={styles.eventLogBox}>
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
</View>
</View>
);
},
_appendEvent: function(eventName) {
var limit = 6;
var eventLog = this.state.eventLog.slice(0, limit - 1);
eventLog.unshift(eventName);
this.setState({eventLog});
},
});
var TouchableDelayEvents = createReactClass({
getInitialState: function() {
return {
eventLog: [],
};
},
render: function() {
return (
<View testID="touchable_delay_events">
<View style={[styles.row, {justifyContent: 'center'}]}>
<TouchableOpacity
style={styles.wrapper}
testID="touchable_delay_events_button"
onPress={() => this._appendEvent('press')}
delayPressIn={400}
onPressIn={() => this._appendEvent('pressIn - 400ms delay')}
delayPressOut={1000}
onPressOut={() => this._appendEvent('pressOut - 1000ms delay')}
delayLongPress={800}
onLongPress={() => this._appendEvent('longPress - 800ms delay')}>
<Text style={styles.button}>
Press Me
</Text>
</TouchableOpacity>
</View>
<View style={styles.eventLogBox} testID="touchable_delay_events_console">
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
</View>
</View>
);
},
_appendEvent: function(eventName) {
var limit = 6;
var eventLog = this.state.eventLog.slice(0, limit - 1);
eventLog.unshift(eventName);
this.setState({eventLog});
},
});
var ForceTouchExample = createReactClass({
getInitialState: function() {
return {
force: 0,
};
},
_renderConsoleText: function() {
return View.forceTouchAvailable ?
'Force: ' + this.state.force.toFixed(3) :
'3D Touch is not available on this device';
},
render: function() {
return (
<View testID="touchable_3dtouch_event">
<View style={styles.forceTouchBox} testID="touchable_3dtouch_output">
<Text>{this._renderConsoleText()}</Text>
</View>
<View style={[styles.row, {justifyContent: 'center'}]}>
<View
style={styles.wrapper}
testID="touchable_3dtouch_button"
onStartShouldSetResponder={() => true}
onResponderMove={(event) => this.setState({force: event.nativeEvent.force})}
onResponderRelease={(event) => this.setState({force: 0})}>
<Text style={styles.button}>
Press Me
</Text>
</View>
</View>
</View>
);
},
});
var TouchableHitSlop = createReactClass({
getInitialState: function() {
return {
timesPressed: 0,
};
},
onPress: function() {
this.setState({
timesPressed: this.state.timesPressed + 1,
});
},
render: function() {
var log = '';
if (this.state.timesPressed > 1) {
log = this.state.timesPressed + 'x onPress';
} else if (this.state.timesPressed > 0) {
log = 'onPress';
}
return (
<View testID="touchable_hit_slop">
<View style={[styles.row, {justifyContent: 'center'}]}>
<TouchableOpacity
onPress={this.onPress}
style={styles.hitSlopWrapper}
hitSlop={{top: 30, bottom: 30, left: 60, right: 60}}
testID="touchable_hit_slop_button">
<Text style={styles.hitSlopButton}>
Press Outside This View
</Text>
</TouchableOpacity>
</View>
<View style={styles.logBox}>
<Text>
{log}
</Text>
</View>
</View>
);
}
});
var TouchableDisabled = createReactClass({
render: function() {
return (
<View>
<TouchableOpacity disabled={true} style={[styles.row, styles.block]} onPress={action('TouchableOpacity')}>
<Text style={styles.disabledButton}>Disabled TouchableOpacity</Text>
</TouchableOpacity>
<TouchableOpacity disabled={false} style={[styles.row, styles.block]} onPress={action('TouchableOpacity')}>
<Text style={styles.button}>Enabled TouchableOpacity</Text>
</TouchableOpacity>
<TouchableHighlight
activeOpacity={1}
disabled={true}
underlayColor="rgb(210, 230, 255)"
style={[styles.row, styles.block]}
onPress={action('TouchableHighlight')}>
<Text style={styles.disabledButton}>
Disabled TouchableHighlight
</Text>
</TouchableHighlight>
<TouchableHighlight
activeOpacity={1}
underlayColor="rgb(210, 230, 255)"
style={[styles.row, styles.block]}
onPress={action('TouchableHighlight')}>
<Text style={styles.button}>
Enabled TouchableHighlight
</Text>
</TouchableHighlight>
{Platform.OS === 'android' &&
<TouchableNativeFeedback
style={[styles.row, styles.block]}
onPress={() => console.log('custom TNF has been clicked')}
background={TouchableNativeFeedback.SelectableBackground()}>
<View>
<Text style={[styles.button, styles.nativeFeedbackButton]}>
Enabled TouchableNativeFeedback
</Text>
</View>
</TouchableNativeFeedback>
}
{Platform.OS === 'android' &&
<TouchableNativeFeedback
disabled={true}
style={[styles.row, styles.block]}
onPress={() => console.log('custom TNF has been clicked')}
background={TouchableNativeFeedback.SelectableBackground()}>
<View>
<Text style={[styles.disabledButton, styles.nativeFeedbackButton]}>
Disabled TouchableNativeFeedback
</Text>
</View>
</TouchableNativeFeedback>
}
</View>
);
}
});
var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
var styles = StyleSheet.create({
row: {
justifyContent: 'center',
flexDirection: 'row',
},
icon: {
width: 24,
height: 24,
},
image: {
width: 50,
height: 50,
},
text: {
fontSize: 16,
},
block: {
padding: 10,
},
button: {
color: '#007AFF',
},
disabledButton: {
color: '#007AFF',
opacity: 0.5,
},
nativeFeedbackButton: {
textAlign: 'center',
margin: 10,
},
hitSlopButton: {
color: 'white',
},
wrapper: {
borderRadius: 8,
},
wrapperCustom: {
borderRadius: 8,
padding: 6,
},
hitSlopWrapper: {
backgroundColor: 'red',
marginVertical: 30,
},
logBox: {
padding: 20,
margin: 10,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#f0f0f0',
backgroundColor: '#f9f9f9',
},
eventLogBox: {
padding: 10,
margin: 10,
height: 120,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#f0f0f0',
backgroundColor: '#f9f9f9',
},
forceTouchBox: {
padding: 10,
margin: 10,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#f0f0f0',
backgroundColor: '#f9f9f9',
alignItems: 'center',
},
textBlock: {
fontWeight: '500',
color: 'blue',
},
});
examples.forEach((example) => {
storiesOf('component: Touchable*', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,275 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @flow
*/
var styles = StyleSheet.create({
box: {
backgroundColor: '#527FE4',
borderColor: '#000033',
borderWidth: 1,
},
shadowBox: {
width: 100,
height: 100,
borderWidth: 2,
},
shadow: {
shadowOpacity: 0.5,
shadowColor: 'red',
shadowRadius: 3,
shadowOffset: { width: 3, height: 3 },
},
zIndex: {
justifyContent: 'space-around',
width: 100,
height: 50,
marginTop: -10,
},
});
var ViewBorderStyleExample = createReactClass({
getInitialState() {
return {
showBorder: true
};
},
render() {
return (
<TouchableWithoutFeedback onPress={this._handlePress}>
<View>
<View style={{
borderWidth: 1,
borderStyle: this.state.showBorder ? 'dashed' : null,
padding: 5
}}>
<Text style={{fontSize: 11}}>
Dashed border style
</Text>
</View>
<View style={{
marginTop: 5,
borderWidth: 1,
borderRadius: 5,
borderStyle: this.state.showBorder ? 'dotted' : null,
padding: 5
}}>
<Text style={{fontSize: 11}}>
Dotted border style
</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
},
_handlePress() {
this.setState({showBorder: !this.state.showBorder});
}
});
var ZIndexExample = createReactClass({
getInitialState() {
return {
flipped: false
};
},
render() {
const indices = this.state.flipped ? [-1, 0, 1, 2] : [2, 1, 0, -1];
return (
<TouchableWithoutFeedback onPress={this._handlePress}>
<View>
<Text style={{paddingBottom: 10}}>Tap to flip sorting order</Text>
<View style={[
styles.zIndex,
{marginTop: 0, backgroundColor: '#E57373', zIndex: indices[0]}
]}>
<Text>ZIndex {indices[0]}</Text>
</View>
<View style={[
styles.zIndex,
{marginLeft: 50, backgroundColor: '#FFF176', zIndex: indices[1]}
]}>
<Text>ZIndex {indices[1]}</Text>
</View>
<View style={[
styles.zIndex,
{marginLeft: 100, backgroundColor: '#81C784', zIndex: indices[2]}
]}>
<Text>ZIndex {indices[2]}</Text>
</View>
<View style={[
styles.zIndex,
{marginLeft: 150, backgroundColor: '#64B5F6', zIndex: indices[3]}
]}>
<Text>ZIndex {indices[3]}</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
},
_handlePress() {
this.setState({flipped: !this.state.flipped});
}
});
const examples = [
{
title: 'Background Color',
render: function() {
return (
<View style={{backgroundColor: '#527FE4', padding: 5}}>
<Text style={{fontSize: 11}}>
Blue background
</Text>
</View>
);
},
}, {
title: 'Border',
render: function() {
return (
<View style={{borderColor: '#527FE4', borderWidth: 5, padding: 10}}>
<Text style={{fontSize: 11}}>5px blue border</Text>
</View>
);
},
}, {
title: 'Padding/Margin',
render: function() {
return (
<View style={{borderColor: '#bb0000', borderWidth: 0.5}}>
<View style={[styles.box, {padding: 5}]}>
<Text style={{fontSize: 11}}>5px padding</Text>
</View>
<View style={[styles.box, {margin: 5}]}>
<Text style={{fontSize: 11}}>5px margin</Text>
</View>
<View style={[styles.box, {margin: 5, padding: 5, alignSelf: 'flex-start'}]}>
<Text style={{fontSize: 11}}>
5px margin and padding,
</Text>
<Text style={{fontSize: 11}}>
widthAutonomous=true
</Text>
</View>
</View>
);
},
}, {
title: 'Border Radius',
render: function() {
return (
<View style={{borderWidth: 0.5, borderRadius: 5, padding: 5}}>
<Text style={{fontSize: 11}}>
Too much use of `borderRadius` (especially large radii) on
anything which is scrolling may result in dropped frames.
Use sparingly.
</Text>
</View>
);
},
}, {
title: 'Border Style',
render: function() {
return <ViewBorderStyleExample />;
},
}, {
title: 'Circle with Border Radius',
render: function() {
return (
<View style={{borderRadius: 10, borderWidth: 1, width: 20, height: 20}} />
);
},
}, {
title: 'Overflow',
render: function() {
return (
<View style={{flexDirection: 'row'}}>
<View
style={{
width: 95,
height: 10,
marginRight: 10,
marginBottom: 5,
overflow: 'hidden',
borderWidth: 0.5,
}}>
<View style={{width: 200, height: 20}}>
<Text>Overflow hidden</Text>
</View>
</View>
<View style={{width: 95, height: 10, marginBottom: 5, borderWidth: 0.5}}>
<View style={{width: 200, height: 20}}>
<Text>Overflow visible</Text>
</View>
</View>
</View>
);
},
}, {
title: 'Opacity',
render: function() {
return (
<View>
<View style={{opacity: 0}}><Text>Opacity 0</Text></View>
<View style={{opacity: 0.1}}><Text>Opacity 0.1</Text></View>
<View style={{opacity: 0.3}}><Text>Opacity 0.3</Text></View>
<View style={{opacity: 0.5}}><Text>Opacity 0.5</Text></View>
<View style={{opacity: 0.7}}><Text>Opacity 0.7</Text></View>
<View style={{opacity: 0.9}}><Text>Opacity 0.9</Text></View>
<View style={{opacity: 1}}><Text>Opacity 1</Text></View>
</View>
);
},
}, {
title: 'ZIndex',
render: function() {
return <ZIndexExample />;
},
},
{
title: 'Basic shadow',
render() {
return <View style={[ styles.shadowBox, styles.shadow ]} />;
}
},
{
title: 'Shaped shadow',
description: 'borderRadius: 50',
render() {
return <View style={[ styles.shadowBox, styles.shadow, {borderRadius: 50} ]} />;
}
}
];
examples.forEach((example) => {
storiesOf('component: View', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,287 @@
import createReactClass from 'create-react-class';
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { Animated, StyleSheet, Text, View } from 'react-native'
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
* @flow
*/
var Flip = createReactClass({
getInitialState() {
return {
theta: new Animated.Value(45),
};
},
componentDidMount() {
this._animate();
},
_animate() {
this.state.theta.setValue(0);
Animated.timing(this.state.theta, {
toValue: 360,
duration: 5000,
}).start(this._animate);
},
render() {
return (
<View style={styles.flipCardContainer}>
<Animated.View style={[
styles.flipCard,
{transform: [
{perspective: 850},
{rotateX: this.state.theta.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg']
})},
]}]}>
<Text style={styles.flipText}>
This text is flipping great.
</Text>
</Animated.View>
<Animated.View style={[styles.flipCard, {
position: 'absolute',
top: 0,
backgroundColor: 'red',
transform: [
{perspective: 850},
{rotateX: this.state.theta.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg']
})},
]}]}>
<Text style={styles.flipText}>
On the flip side...
</Text>
</Animated.View>
</View>
);
}
});
var styles = StyleSheet.create({
box1: {
left: 0,
backgroundColor: 'green',
height: 50,
top: 0,
transform: [
{translateX: 100},
{translateY: 50},
{rotate: '30deg'},
{scaleX: 2},
{scaleY: 2},
],
width: 50,
},
box2: {
left: 0,
backgroundColor: 'purple',
height: 50,
top: 0,
transform: [
{scaleX: 2},
{scaleY: 2},
{translateX: 100},
{translateY: 50},
{rotate: '30deg'},
],
width: 50,
},
box3step1: {
left: 0,
backgroundColor: 'lightpink',
height: 50,
top: 0,
transform: [
{rotate: '30deg'},
],
width: 50,
},
box3step2: {
left: 0,
backgroundColor: 'hotpink',
height: 50,
opacity: 0.5,
top: 0,
transform: [
{rotate: '30deg'},
{scaleX: 2},
{scaleY: 2},
],
width: 50,
},
box3step3: {
left: 0,
backgroundColor: 'deeppink',
height: 50,
opacity: 0.5,
top: 0,
transform: [
{rotate: '30deg'},
{scaleX: 2},
{scaleY: 2},
{translateX: 10},
{translateY: 50},
],
width: 50,
},
box4: {
left: 0,
backgroundColor: 'darkorange',
height: 50,
top: 0,
transform: [
{translateX: 20},
{translateY: 35},
{scale: 2.5},
{rotate: '-0.2rad'},
],
width: 100,
},
box5: {
backgroundColor: 'maroon',
height: 50,
right: 0,
top: 0,
width: 50,
},
box5Transform: {
transform: [
{translateX: -50},
{translateY: 35},
{rotate: '50deg'},
{scale: 2},
],
},
flipCardContainer: {
marginVertical: 40,
flex: 1,
alignSelf: 'center',
},
flipCard: {
width: 200,
height: 200,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'blue',
backfaceVisibility: 'hidden',
},
flipText: {
width: 90,
fontSize: 20,
color: 'white',
fontWeight: 'bold',
}
});
const examples = [
{
title: 'Perspective',
description: 'perspective: 850, rotateX: Animated.timing(0 -> 360)',
render(): ReactElement<any> { return <Flip />; }
},
{
title: 'Translate, Rotate, Scale',
description: "translateX: 100, translateY: 50, rotate: '30deg', scaleX: 2, scaleY: 2",
render() {
return (
<View style={styles.box1} />
);
}
},
{
title: 'Scale, Translate, Rotate, ',
description: "scaleX: 2, scaleY: 2, translateX: 100, translateY: 50, rotate: '30deg'",
render() {
return (
<View style={styles.box2} />
);
}
},
{
title: 'Rotate',
description: "rotate: '30deg'",
render() {
return (
<View style={styles.box3step1} />
);
}
},
{
title: 'Rotate, Scale',
description: "rotate: '30deg', scaleX: 2, scaleY: 2",
render() {
return (
<View style={styles.box3step2} />
);
}
},
{
title: 'Rotate, Scale, Translate ',
description: "rotate: '30deg', scaleX: 2, scaleY: 2, translateX: 100, translateY: 50",
render() {
return (
<View style={styles.box3step3} />
);
}
},
{
title: 'Translate, Scale, Rotate',
description: "translate: [200, 350], scale: 2.5, rotate: '-0.2rad'",
render() {
return (
<View style={styles.box4} />
);
}
},
{
title: 'Translate, Rotate, Scale',
description: "translate: [-50, 35], rotate: '50deg', scale: 2",
render() {
return (
<View style={[styles.box5, styles.box5Transform]} />
);
}
}
];
examples.forEach((example) => {
storiesOf('component: View (transforms)', module)
.add(example.title, () => example.render())
})

View File

@@ -0,0 +1,325 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @providesModule Game2048
* @flow
*/
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var {
Animated,
AppRegistry,
StyleSheet,
Text,
TouchableOpacity,
View,
} = ReactNative;
var GameBoard = require('./GameBoard');
var BOARD_PADDING = 3;
var CELL_MARGIN = 4;
var CELL_SIZE = 60;
class Cell extends React.Component {
render() {
return <View style={styles.cell} />;
}
}
class Board extends React.Component {
render() {
return (
<View style={styles.board}>
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
{this.props.children}
</View>
);
}
}
class Tile extends React.Component {
state: any;
static _getPosition(index): number {
return BOARD_PADDING + (index * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN);
}
constructor(props: {}) {
super(props);
var tile = this.props.tile;
this.state = {
opacity: new Animated.Value(0),
top: new Animated.Value(Tile._getPosition(tile.toRow())),
left: new Animated.Value(Tile._getPosition(tile.toColumn())),
};
}
calculateOffset(): {top: number; left: number; opacity: number} {
var tile = this.props.tile;
var offset = {
top: this.state.top,
left: this.state.left,
opacity: this.state.opacity,
};
if (tile.isNew()) {
Animated.timing(this.state.opacity, {
duration: 100,
toValue: 1,
}).start();
} else {
Animated.parallel([
Animated.timing(offset.top, {
duration: 100,
toValue: Tile._getPosition(tile.toRow()),
}),
Animated.timing(offset.left, {
duration: 100,
toValue: Tile._getPosition(tile.toColumn()),
}),
]).start();
}
return offset;
}
render() {
var tile = this.props.tile;
var tileStyles = [
styles.tile,
styles['tile' + tile.value],
this.calculateOffset(),
];
var textStyles = [
styles.value,
tile.value > 4 && styles.whiteText,
tile.value > 100 && styles.threeDigits,
tile.value > 1000 && styles.fourDigits,
];
return (
<Animated.View style={tileStyles}>
<Text style={textStyles}>{tile.value}</Text>
</Animated.View>
);
}
}
class GameEndOverlay extends React.Component {
render() {
var board = this.props.board;
if (!board.hasWon() && !board.hasLost()) {
return <View/>;
}
var message = board.hasWon() ?
'Good Job!' : 'Game Over';
return (
<View style={styles.overlay}>
<Text style={styles.overlayMessage}>{message}</Text>
<TouchableOpacity onPress={this.props.onRestart} style={styles.tryAgain}>
<Text style={styles.tryAgainText}>Try Again?</Text>
</TouchableOpacity>
</View>
);
}
}
class Game2048 extends React.Component {
startX: number;
startY: number;
state: any;
constructor(props: {}) {
super(props);
this.state = {
board: new GameBoard(),
};
this.startX = 0;
this.startY = 0;
}
restartGame() {
this.setState({board: new GameBoard()});
}
handleTouchStart(event: Object) {
if (this.state.board.hasWon()) {
return;
}
this.startX = event.nativeEvent.pageX;
this.startY = event.nativeEvent.pageY;
}
handleTouchEnd(event: Object) {
if (this.state.board.hasWon()) {
return;
}
var deltaX = event.nativeEvent.pageX - this.startX;
var deltaY = event.nativeEvent.pageY - this.startY;
var direction = -1;
if (Math.abs(deltaX) > 3 * Math.abs(deltaY) && Math.abs(deltaX) > 30) {
direction = deltaX > 0 ? 2 : 0;
} else if (Math.abs(deltaY) > 3 * Math.abs(deltaX) && Math.abs(deltaY) > 30) {
direction = deltaY > 0 ? 3 : 1;
}
if (direction !== -1) {
this.setState({board: this.state.board.move(direction)});
}
}
render() {
var tiles = this.state.board.tiles
.filter((tile) => tile.value)
.map((tile) => <Tile ref={tile.id} key={tile.id} tile={tile} />);
return (
<View
style={styles.container}
onTouchStart={(event) => this.handleTouchStart(event)}
onTouchEnd={(event) => this.handleTouchEnd(event)}>
<Board>
{tiles}
</Board>
<GameEndOverlay board={this.state.board} onRestart={() => this.restartGame()} />
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
board: {
padding: BOARD_PADDING,
backgroundColor: '#bbaaaa',
borderRadius: 5,
},
overlay: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(221, 221, 221, 0.5)',
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
overlayMessage: {
fontSize: 40,
marginBottom: 20,
},
tryAgain: {
backgroundColor: '#887761',
padding: 20,
borderRadius: 5,
},
tryAgainText: {
color: '#ffffff',
fontSize: 20,
fontWeight: '500',
},
cell: {
width: CELL_SIZE,
height: CELL_SIZE,
borderRadius: 5,
backgroundColor: '#ddccbb',
margin: CELL_MARGIN,
},
row: {
flexDirection: 'row',
},
tile: {
position: 'absolute',
width: CELL_SIZE,
height: CELL_SIZE,
backgroundColor: '#ddccbb',
borderRadius: 5,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
value: {
fontSize: 24,
color: '#776666',
fontFamily: 'Verdana',
fontWeight: '500',
},
tile2: {
backgroundColor: '#eeeeee',
},
tile4: {
backgroundColor: '#eeeecc',
},
tile8: {
backgroundColor: '#ffbb87',
},
tile16: {
backgroundColor: '#ff9966',
},
tile32: {
backgroundColor: '#ff7755',
},
tile64: {
backgroundColor: '#ff5533',
},
tile128: {
backgroundColor: '#eecc77',
},
tile256: {
backgroundColor: '#eecc66',
},
tile512: {
backgroundColor: '#eecc55',
},
tile1024: {
backgroundColor: '#eecc33',
},
tile2048: {
backgroundColor: '#eecc22',
},
whiteText: {
color: '#ffffff',
},
threeDigits: {
fontSize: 20,
},
fourDigits: {
fontSize: 18,
},
});
AppRegistry.registerComponent('Game2048', () => Game2048);
module.exports = Game2048;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import Game2048 from './Game2048'
storiesOf('demo: Game2048', module)
.add('the game', () => (
<Game2048 />
))

View File

@@ -0,0 +1,201 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @providesModule GameBoard
* @flow
*/
'use strict';
// NB: Taken straight from: https://github.com/IvanVergiliev/2048-react/blob/master/src/board.js
// with no modification except to format it for CommonJS and fix lint/flow errors
var rotateLeft = function (matrix) {
var rows = matrix.length;
var columns = matrix[0].length;
var res = [];
for (var row = 0; row < rows; ++row) {
res.push([]);
for (var column = 0; column < columns; ++column) {
res[row][column] = matrix[column][columns - row - 1];
}
}
return res;
};
var Tile = function (value?: number, row?: number, column?: number) {
this.value = value || 0;
this.row = row || -1;
this.column = column || -1;
this.oldRow = -1;
this.oldColumn = -1;
this.markForDeletion = false;
this.mergedInto = null;
this.id = Tile.id++;
};
Tile.id = 0;
Tile.prototype.moveTo = function (row, column) {
this.oldRow = this.row;
this.oldColumn = this.column;
this.row = row;
this.column = column;
};
Tile.prototype.isNew = function () {
return this.oldRow === -1 && !this.mergedInto;
};
Tile.prototype.hasMoved = function () {
return (this.fromRow() !== -1 && (this.fromRow() !== this.toRow() || this.fromColumn() !== this.toColumn())) ||
this.mergedInto;
};
Tile.prototype.fromRow = function () {
return this.mergedInto ? this.row : this.oldRow;
};
Tile.prototype.fromColumn = function () {
return this.mergedInto ? this.column : this.oldColumn;
};
Tile.prototype.toRow = function () {
return this.mergedInto ? this.mergedInto.row : this.row;
};
Tile.prototype.toColumn = function () {
return this.mergedInto ? this.mergedInto.column : this.column;
};
var Board = function () {
this.tiles = [];
this.cells = [];
for (var i = 0; i < Board.size; ++i) {
this.cells[i] = [this.addTile(), this.addTile(), this.addTile(), this.addTile()];
}
this.addRandomTile();
this.setPositions();
this.won = false;
};
Board.prototype.addTile = function () {
var res = new Tile();
Tile.apply(res, arguments);
this.tiles.push(res);
return res;
};
Board.size = 4;
Board.prototype.moveLeft = function () {
var hasChanged = false;
for (var row = 0; row < Board.size; ++row) {
var currentRow = this.cells[row].filter(function (tile) { return tile.value !== 0; });
var resultRow = [];
for (var target = 0; target < Board.size; ++target) {
var targetTile = currentRow.length ? currentRow.shift() : this.addTile();
if (currentRow.length > 0 && currentRow[0].value === targetTile.value) {
var tile1 = targetTile;
targetTile = this.addTile(targetTile.value);
tile1.mergedInto = targetTile;
var tile2 = currentRow.shift();
tile2.mergedInto = targetTile;
targetTile.value += tile2.value;
}
resultRow[target] = targetTile;
this.won = this.won || (targetTile.value === 2048);
hasChanged = hasChanged || (targetTile.value !== this.cells[row][target].value);
}
this.cells[row] = resultRow;
}
return hasChanged;
};
Board.prototype.setPositions = function () {
this.cells.forEach(function (row, rowIndex) {
row.forEach(function (tile, columnIndex) {
tile.oldRow = tile.row;
tile.oldColumn = tile.column;
tile.row = rowIndex;
tile.column = columnIndex;
tile.markForDeletion = false;
});
});
};
Board.fourProbability = 0.1;
Board.prototype.addRandomTile = function () {
var emptyCells = [];
for (var r = 0; r < Board.size; ++r) {
for (var c = 0; c < Board.size; ++c) {
if (this.cells[r][c].value === 0) {
emptyCells.push({r: r, c: c});
}
}
}
var index = Math.floor(Math.random() * emptyCells.length);
var cell = emptyCells[index];
var newValue = Math.random() < Board.fourProbability ? 4 : 2;
this.cells[cell.r][cell.c] = this.addTile(newValue);
};
Board.prototype.move = function (direction) {
// 0 -> left, 1 -> up, 2 -> right, 3 -> down
this.clearOldTiles();
for (var i = 0; i < direction; ++i) {
this.cells = rotateLeft(this.cells);
}
var hasChanged = this.moveLeft();
for (var i = direction; i < 4; ++i) {
this.cells = rotateLeft(this.cells);
}
if (hasChanged) {
this.addRandomTile();
}
this.setPositions();
return this;
};
Board.prototype.clearOldTiles = function () {
this.tiles = this.tiles.filter(function (tile) { return tile.markForDeletion === false; });
this.tiles.forEach(function (tile) { tile.markForDeletion = true; });
};
Board.prototype.hasWon = function () {
return this.won;
};
Board.deltaX = [-1, 0, 1, 0];
Board.deltaY = [0, -1, 0, 1];
Board.prototype.hasLost = function () {
var canMove = false;
for (var row = 0; row < Board.size; ++row) {
for (var column = 0; column < Board.size; ++column) {
canMove = canMove || (this.cells[row][column].value === 0);
for (var dir = 0; dir < 4; ++dir) {
var newRow = row + Board.deltaX[dir];
var newColumn = column + Board.deltaY[dir];
if (newRow < 0 || newRow >= Board.size || newColumn < 0 || newColumn >= Board.size) {
continue;
}
canMove = canMove || (this.cells[row][column].value === this.cells[newRow][newColumn].value);
}
}
}
return !canMove;
};
module.exports = Board;

View File

@@ -0,0 +1,323 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* 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 NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK 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.
*
* @providesModule TicTacToeApp
* @flow
*/
'use strict';
import createReactClass from 'create-react-class';
var React = require('react');
var ReactNative = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
TouchableHighlight,
View,
} = ReactNative;
class Board {
grid: Array<Array<number>>;
turn: number;
constructor() {
var size = 3;
var grid = Array(size);
for (var i = 0; i < size; i++) {
var row = Array(size);
for (var j = 0; j < size; j++) {
row[j] = 0;
}
grid[i] = row;
}
this.grid = grid;
this.turn = 1;
}
mark(row: number, col: number, player: number): Board {
this.grid[row][col] = player;
return this;
}
hasMark(row: number, col: number): boolean {
return this.grid[row][col] !== 0;
}
winner(): ?number {
for (var i = 0; i < 3; i++) {
if (this.grid[i][0] !== 0 && this.grid[i][0] === this.grid[i][1] &&
this.grid[i][0] === this.grid[i][2]) {
return this.grid[i][0];
}
}
for (var i = 0; i < 3; i++) {
if (this.grid[0][i] !== 0 && this.grid[0][i] === this.grid[1][i] &&
this.grid[0][i] === this.grid[2][i]) {
return this.grid[0][i];
}
}
if (this.grid[0][0] !== 0 && this.grid[0][0] === this.grid[1][1] &&
this.grid[0][0] === this.grid[2][2]) {
return this.grid[0][0];
}
if (this.grid[0][2] !== 0 && this.grid[0][2] === this.grid[1][1] &&
this.grid[0][2] === this.grid[2][0]) {
return this.grid[0][2];
}
return null;
}
tie(): boolean {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (this.grid[i][j] === 0) {
return false;
}
}
}
return this.winner() === null;
}
}
var Cell = createReactClass({
cellStyle() {
switch (this.props.player) {
case 1:
return styles.cellX;
case 2:
return styles.cellO;
default:
return null;
}
},
textStyle() {
switch (this.props.player) {
case 1:
return styles.cellTextX;
case 2:
return styles.cellTextO;
default:
return null;
}
},
textContents() {
switch (this.props.player) {
case 1:
return 'X';
case 2:
return 'O';
default:
return '';
}
},
render() {
return (
<TouchableHighlight
onPress={this.props.onPress}
underlayColor="transparent"
activeOpacity={0.5}>
<View style={[styles.cell, this.cellStyle()]}>
<Text style={[styles.cellText, this.textStyle()]}>
{this.textContents()}
</Text>
</View>
</TouchableHighlight>
);
}
});
var GameEndOverlay = createReactClass({
render() {
var board = this.props.board;
var tie = board.tie();
var winner = board.winner();
if (!winner && !tie) {
return <View />;
}
var message;
if (tie) {
message = 'It\'s a tie!';
} else {
message = (winner === 1 ? 'X' : 'O') + ' wins!';
}
return (
<View style={styles.overlay}>
<Text style={styles.overlayMessage}>{message}</Text>
<TouchableHighlight
onPress={this.props.onRestart}
underlayColor="transparent"
activeOpacity={0.5}>
<View style={styles.newGame}>
<Text style={styles.newGameText}>New Game</Text>
</View>
</TouchableHighlight>
</View>
);
}
});
var TicTacToeApp = createReactClass({
getInitialState() {
return { board: new Board(), player: 1 };
},
restartGame() {
this.setState(this.getInitialState());
},
nextPlayer(): number {
return this.state.player === 1 ? 2 : 1;
},
handleCellPress(row: number, col: number) {
if (this.state.board.hasMark(row, col)) {
return;
}
this.setState({
board: this.state.board.mark(row, col, this.state.player),
player: this.nextPlayer(),
});
},
render() {
var rows = this.state.board.grid.map((cells, row) =>
<View key={'row' + row} style={styles.row}>
{cells.map((player, col) =>
<Cell
key={'cell' + col}
player={player}
onPress={this.handleCellPress.bind(this, row, col)}
/>
)}
</View>
);
return (
<View style={styles.container}>
<Text style={styles.title}>EXTREME T3</Text>
<View style={styles.board}>
{rows}
</View>
<GameEndOverlay
board={this.state.board}
onRestart={this.restartGame}
/>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
},
title: {
fontFamily: 'Chalkduster',
fontSize: 39,
marginBottom: 20,
},
board: {
padding: 5,
backgroundColor: '#47525d',
borderRadius: 10,
},
row: {
flexDirection: 'row',
},
// CELL
cell: {
width: 80,
height: 80,
borderRadius: 5,
backgroundColor: '#7b8994',
margin: 5,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
cellX: {
backgroundColor: '#72d0eb',
},
cellO: {
backgroundColor: '#7ebd26',
},
// CELL TEXT
cellText: {
borderRadius: 5,
fontSize: 50,
fontFamily: 'AvenirNext-Bold',
},
cellTextX: {
color: '#19a9e5',
},
cellTextO: {
color: '#b9dc2f',
},
// GAME OVER
overlay: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(221, 221, 221, 0.5)',
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
overlayMessage: {
fontSize: 40,
marginBottom: 20,
marginLeft: 20,
marginRight: 20,
fontFamily: 'AvenirNext-DemiBold',
textAlign: 'center',
},
newGame: {
backgroundColor: '#887765',
padding: 20,
borderRadius: 5,
},
newGameText: {
color: 'white',
fontSize: 20,
fontFamily: 'AvenirNext-DemiBold',
},
});
AppRegistry.registerComponent('TicTacToeApp', () => TicTacToeApp);
module.exports = TicTacToeApp;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import TicTacToe from './TicTacToe'
storiesOf('demo: TicTacToe', module)
.add('the game', () => (
<TicTacToe />
))

View File

@@ -1,57 +1,92 @@
{
"name": "react-native-web",
"version": "0.0.5",
"version": "0.0.93",
"description": "React Native for Web",
"main": "dist/react-native-web.js",
"main": "dist/index.js",
"files": [
"dist"
"dist",
"src",
"!**/__tests__"
],
"scripts": {
"prepublish": "NODE_ENV=production npm run build",
"build": "rm -rf ./dist && webpack --config config/webpack.config.js --sort-assets-by --progress",
"example": "cd example && webpack --config webpack.config.js",
"lint": "eslint .",
"specs": "NODE_ENV=test karma start config/karma.config.js",
"specs:watch": "npm run specs -- --no-single-run",
"start": "webpack-dev-server --config config/webpack.config.js --inline --hot --colors --quiet",
"test": "npm run specs && npm run lint"
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
"build:examples": "build-storybook -o dist-examples -c ./examples/.storybook",
"build:performance": "cd performance && yarn && webpack",
"build:umd": "webpack --config webpack.config.js --sort-assets-by --progress",
"deploy:examples": "git checkout gh-pages && rm -rf ./storybook && mv dist-examples storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
"fmt": "find performance src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs prettier --print-width=100 --single-quote --write",
"lint": "eslint performance src --ignore-path .gitignore",
"release": "npm run build && npm run build:umd && npm publish",
"test": "npm run lint && npm run test:jest",
"test:jest": "jest",
"test:watch": "npm run test:jest -- --watch"
},
"dependencies": {
"react": "^0.13.3",
"react-swipeable": "^3.0.2",
"react-tappable": "^0.6.0"
"animated": "^0.2.0",
"array-find-index": "^1.0.2",
"babel-runtime": "^6.23.0",
"create-react-class": "^15.5.2",
"debounce": "1.0.2",
"deep-assign": "^2.0.0",
"fbjs": "^0.8.8",
"hyphenate-style-name": "^1.0.2",
"inline-style-prefixer": "^3.0.2",
"normalize-css-color": "^1.0.2",
"prop-types": "^15.5.8",
"react-timer-mixin": "^0.13.3"
},
"devDependencies": {
"autoprefixer-core": "^5.2.1",
"babel-core": "^5.8.23",
"babel-eslint": "^4.1.1",
"babel-loader": "^5.3.2",
"babel-runtime": "^5.8.20",
"css-loader": "^0.17.0",
"eslint": "^1.3.1",
"eslint-config-standard": "^4.3.1",
"eslint-config-standard-react": "^1.0.4",
"eslint-plugin-react": "^3.3.1",
"eslint-plugin-standard": "^1.3.0",
"extract-text-webpack-plugin": "^0.8.2",
"karma": "^0.13.9",
"karma-chrome-launcher": "^0.2.0",
"karma-firefox-launcher": "^0.1.6",
"karma-mocha": "^0.2.0",
"karma-sourcemap-loader": "^0.3.5",
"karma-webpack": "^1.7.0",
"mocha": "^2.3.0",
"node-libs-browser": "^0.5.2",
"object-assign": "^4.0.1",
"postcss-loader": "^0.4.4",
"style-loader": "^0.12.3",
"webpack": "^1.12.1",
"webpack-dev-server": "^1.10.1"
"@kadira/storybook": "^2.5.1",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-eslint": "^7.2.2",
"babel-loader": "^6.4.1",
"babel-plugin-transform-react-remove-prop-types": "^0.4.2",
"babel-preset-react-native": "^1.9.1",
"del-cli": "^0.2.1",
"enzyme": "^2.8.2",
"enzyme-to-json": "^1.5.1",
"eslint": "^3.19.0",
"eslint-config-prettier": "^1.7.0",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^6.10.3",
"file-loader": "^0.11.1",
"jest": "^19.0.2",
"node-libs-browser": "^0.5.3",
"prettier": "^1.2.2",
"react": "~15.4.1",
"react-addons-test-utils": "~15.4.1",
"react-dom": "~15.4.1",
"react-test-renderer": "^15.5.4",
"url-loader": "^0.5.8",
"webpack": "^2.3.3",
"webpack-bundle-analyzer": "^2.4.0"
},
"peerDependencies": {
"react": "15.4.x || 15.5.x",
"react-dom": "15.4.x || 15.5.x"
},
"author": "Nicolas Gallagher",
"license": "MIT",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "git://github.com/necolas/react-native-web.git"
},
"tags": [
"react"
],
"keywords": [
"react",
"react-component",
"react-native",
"web"
],
"jest": {
"testEnvironment": "jsdom",
"timers": "fake",
"snapshotSerializers": [
"<rootDir>/node_modules/enzyme-to-json/serializer"
]
}
}

40
performance/README.md Normal file
View File

@@ -0,0 +1,40 @@
# Performance
To run these benchmarks:
```
npm run build:performance
open ./performance/index.html
```
## Notes
The components used in the render benchmarks are simple enough to be
implemented by multiple UI or style libraries. The implementations are not
equivalent in functionality.
`react-native-web/stylesheet` is a comparative baseline that implements a
simple `View` without much of React Native's functionality.
## Benchmark results
Typical render timings*: mean ± two standard deviations
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `87.67` `±15.22` | `170.85` `±16.87` | |
| `react-native-web/stylesheet@0.0.84` | `90.02` `±13.16` | `186.66` `±19.23` | |
| `react-native-web@0.0.84` | `102.72` `±19.26` | `222.35` `±18.95` | `12.81` `±5.45ms` |
Other libraries
| Implementation | Deep tree (ms) | Wide tree (ms) |
| :--- | ---: | ---: |
| `styletron@2.5.1` | `88.48` `±12.00` | `171.89` `±13.28` |
| `aphrodite@1.2.0` | `101.32` `±20.33` | `220.33` `±31.41` |
| `glamor@3.0.0-1` | `129.00` `±14.92` | `264.57` `±28.54` |
| `react-jss@5.4.1` | `137.33` `±21.55` | `314.91` `±29.03` |
| `reactxp@0.34.3` | `223.82` `±32.77` | `461.56` `±34.43` |
| `styled-components@2.0.0-11` | `277.53` `±28.83` | `627.91` `±43.13` |
*MacBook Pro (13-inch, Early 2011); 2.7 GHz Intel Core i7; 16 GB 1600 MHz DDR3. Google Chrome 56.

97
performance/benchmark.js Normal file
View File

@@ -0,0 +1,97 @@
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);
};
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
return new Promise(resolve => {
const durations = [];
let i = 0;
setup();
const first = measure('first', task);
teardown();
const done = () => {
const stdDev = standardDeviation(durations);
const formattedFirst = fmt(first);
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(`First: ${formattedFirst}`);
console.log(`Median: ${formattedMedian}`);
console.log(`Mean: ${formattedMean}`);
console.log(`Standard deviation: ${formattedStdDev}`);
console.log(durations);
console.groupEnd();
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

@@ -0,0 +1,20 @@
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;

11
performance/index.html Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Performance tests</title>
</head>
<body>
<div class="root"></div>
<script src="dist/performance.bundle.js"></script>
</body>
</html>

49
performance/index.js Normal file
View File

@@ -0,0 +1,49 @@
import aphrodite from './src/aphrodite';
import cssModules from './src/css-modules';
import glamor from './src/glamor';
import jss from './src/jss';
import reactNative from './src/react-native';
import reactNativeStyleSheet from './src/react-native-stylesheet';
import styledComponents from './src/styled-components';
import styletron from './src/styletron';
import xp from './src/reactxp';
import renderDeepTree from './tests/renderDeepTree';
import renderTweet from './tests/renderTweet';
import renderWideTree from './tests/renderWideTree';
const testAll = window.location.search === '?all';
const coreTests = [
() => renderTweet('react-native-web', reactNative),
() => renderDeepTree('css-modules', cssModules),
() => renderWideTree('css-modules', cssModules),
() => renderDeepTree('react-native-web/stylesheet', reactNativeStyleSheet),
() => renderWideTree('react-native-web/stylesheet', reactNativeStyleSheet),
() => renderDeepTree('react-native-web', reactNative),
() => renderWideTree('react-native-web', reactNative)
];
/**
* Optionally run tests using other libraries
*/
const extraTests = [
() => renderDeepTree('styletron', styletron),
() => renderWideTree('styletron', styletron),
() => renderDeepTree('aphrodite', aphrodite),
() => renderWideTree('aphrodite', aphrodite),
() => renderDeepTree('glamor', glamor),
() => renderWideTree('glamor', glamor),
() => renderDeepTree('react-jss', jss),
() => renderWideTree('react-jss', jss),
() => renderDeepTree('reactxp', xp),
() => renderWideTree('reactxp', xp),
() => renderDeepTree('styled-components', styledComponents),
() => renderWideTree('styled-components', styledComponents)
];
const tests = testAll ? coreTests.concat(extraTests) : coreTests;
// run benchmarks
tests.reduce((promise, test) => promise.then(test()), Promise.resolve());

20
performance/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "performance",
"private": true,
"dependencies": {
"aphrodite": "^1.2.0",
"classnames": "^2.2.5",
"glamor": "3.0.0-1",
"marky": "^1.2.0",
"react-jss": "^6.1.1",
"reactxp": "^0.34.3",
"styled-components": "2.0.0-15",
"styletron-client": "^2.5.1",
"styletron-utils": "^2.5.4"
},
"devDependencies": {
"css-loader": "^0.28.0",
"react-addons-perf": "^15.4.2",
"style-loader": "^0.16.1"
}
}

View File

@@ -0,0 +1,7 @@
import Box from './components/Box/aphrodite';
import View from './components/View/aphrodite';
export default {
Box,
View
};

View File

@@ -0,0 +1,107 @@
import theme from '../theme';
import React, { PropTypes, PureComponent } from 'react';
import { StyleSheet, Text } from 'react-native';
class AppText extends PureComponent {
static displayName = 'AppText';
static propTypes = {
align: PropTypes.oneOf(['center', 'left', 'right']),
color: PropTypes.oneOf(['blue', 'deepGray', 'normal', 'red', 'white']),
fontStyle: PropTypes.oneOf(['normal', 'italic']),
size: PropTypes.oneOf(['small', 'normal', 'large']),
uppercase: PropTypes.bool,
weight: PropTypes.oneOf(['normal', 'bold'])
};
render() {
const { align, color, fontStyle, size, uppercase, weight, ...other } = this.props;
const style = [
styles.root,
align && alignStyles[align],
color && colorStyles[color],
fontStyle && fontStyles[fontStyle],
size && sizeStyles[size],
weight && weightStyles[weight],
uppercase === true && styles.uppercase
];
return <Text {...other} style={style} />;
}
}
const styles = StyleSheet.create({
root: {
fontFamily: theme.fontFamily,
fontSize: theme.fontSize.normal,
fontWeight: 'normal',
lineHeight: theme.createLength(theme.lineHeight),
wordWrap: 'break-word'
},
uppercase: {
textTransform: 'uppercase'
}
});
const alignStyles = StyleSheet.create({
center: {
textAlign: 'center'
},
left: {
textAlign: 'left'
},
right: {
textAlign: 'right'
}
});
const colorStyles = StyleSheet.create({
blue: {
color: theme.colors.blue
},
deepGray: {
color: theme.colors.deepGray
},
normal: {
color: theme.colors.textBlack
},
red: {
color: theme.colors.red
},
white: {
color: theme.colors.white
}
});
const fontStyles = StyleSheet.create({
normal: {
fontStyle: 'normal'
},
italic: {
fontStyle: 'italic'
}
});
const sizeStyles = StyleSheet.create({
small: {
fontSize: theme.fontSize.small
},
normal: {
fontSize: theme.fontSize.normal
},
large: {
fontSize: theme.fontSize.large
}
});
const weightStyles = StyleSheet.create({
normal: {
fontWeight: '400'
},
bold: {
fontWeight: 'bold'
}
});
export default AppText;

View File

@@ -0,0 +1,40 @@
import React, { PureComponent, PropTypes } from 'react';
import { StyleSheet, View } from 'react-native';
class AspectRatio extends PureComponent {
static displayName = 'AspectRatio';
static propTypes = {
children: PropTypes.any,
ratio: PropTypes.number,
style: PropTypes.object
};
static defaultProps = {
ratio: 1
};
render() {
const { children, ratio, style } = this.props;
const percentage = 100 / ratio;
return (
<View style={[styles.root, style]}>
<View style={[styles.shim, { paddingBottom: `${percentage}%` }]} />
<View style={StyleSheet.absoluteFill}>{children}</View>
</View>
);
}
}
const styles = StyleSheet.create({
root: {
overflow: 'hidden'
},
shim: {
display: 'block',
width: '100%'
}
});
export default AspectRatio;

View File

@@ -0,0 +1,49 @@
/* eslint-disable react/prop-types */
import React from 'react';
import View from '../View/aphrodite';
import { StyleSheet } from 'aphrodite';
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 = StyleSheet.create({
outer: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
});
module.exports = Box;

View File

@@ -0,0 +1,18 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import React from 'react';
import View from '../View/css-modules';
import styles from './styles.css';
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
<View
{...other}
className={classnames(styles[`color${color}`], {
[styles.fixed]: fixed,
[styles.outer]: outer,
[styles.row]: layout === 'row'
})}
/>
);
module.exports = Box;

View File

@@ -0,0 +1,48 @@
/* eslint-disable react/prop-types */
import React from 'react';
import View from '../View/glamor';
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: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
};
module.exports = Box;

View File

@@ -0,0 +1,50 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import injectSheet from 'react-jss';
import React from 'react';
import View from '../View/jss';
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => (
<View
{...other}
className={classnames({
[classes[`color${color}`]]: true,
[classes.fixed]: fixed,
[classes.row]: layout === 'row',
[classes.outer]: outer
})}
/>
);
const styles = {
outer: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
};
module.exports = injectSheet(styles)(Box);

View File

@@ -0,0 +1,49 @@
/* eslint-disable react/prop-types */
import React from 'react';
import StyleSheet from 'react-native/apis/StyleSheet';
import View from '../View/react-native-stylesheet';
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 = StyleSheet.create({
outer: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
});
module.exports = Box;

View File

@@ -0,0 +1,48 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { StyleSheet, View } from 'react-native';
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 = StyleSheet.create({
outer: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
});
module.exports = Box;

View File

@@ -0,0 +1,48 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { Styles, View } from 'reactxp';
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: Styles.createViewStyle({
padding: 4
}),
row: Styles.createViewStyle({
flexDirection: 'row'
}),
color0: Styles.createViewStyle({
backgroundColor: '#222'
}),
color1: Styles.createViewStyle({
backgroundColor: '#666'
}),
color2: Styles.createViewStyle({
backgroundColor: '#999'
}),
color3: Styles.createViewStyle({
backgroundColor: 'blue'
}),
color4: Styles.createViewStyle({
backgroundColor: 'orange'
}),
color5: Styles.createViewStyle({
backgroundColor: 'red'
}),
fixed: Styles.createViewStyle({
width: 20,
height: 20
})
};
module.exports = Box;

View File

@@ -0,0 +1,31 @@
import styled from 'styled-components';
import View from '../View/styled-components';
const getColor = color => {
switch (color) {
case 0:
return '#222';
case 1:
return '#666';
case 2:
return '#999';
case 3:
return 'blue';
case 4:
return 'orange';
case 5:
return 'red';
default:
return 'transparent';
}
};
const Box = styled(View)`
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)};
`;
module.exports = Box;

View File

@@ -0,0 +1,36 @@
.outer {
padding: 4px;
}
.row {
flex-direction: row;
}
.color0 {
background-color: #222;
}
.color1 {
background-color: #666;
}
.color2 {
background-color: #999;
}
.color3 {
background-color: blue;
}
.color4 {
background-color: orange;
}
.color5 {
background-color: red;
}
.fixed {
width: 20px;
height: 20px;
}

View File

@@ -0,0 +1,49 @@
/* eslint-disable react/prop-types */
import { injectStylePrefixed } from 'styletron-utils';
import React from 'react';
import View, { styletron } from '../View/styletron';
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'
})
};
module.exports = Box;

View File

@@ -0,0 +1,52 @@
import { StyleSheet, View } from 'react-native';
import React, { Component, PropTypes } from 'react';
import theme from '../theme';
class GridView extends Component {
static displayName = 'GridView';
static propTypes = {
children: PropTypes.node,
hasGap: PropTypes.bool,
style: PropTypes.object
};
render() {
const { children, hasGap, style, ...other } = this.props;
return (
<View {...other} style={[style, styles.root, hasGap && styles.hasGap]}>
{React.Children.map(children, child => {
return (
child &&
React.cloneElement(child, {
style: [child.props.style, styles.column, hasGap && styles.hasGapColumn]
})
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
root: {
flexDirection: 'row'
},
/**
* 1. Distribute all space (rather than extra space)
* 2. Prevent wide content from forcing wider flex columns
*/
column: {
flexBasis: 0, // 1
minWidth: 0 // 2
},
hasGap: {
marginHorizontal: theme.createLength(theme.spaceX * -0.5, 'rem')
},
hasGapColumn: {
marginHorizontal: theme.createLength(theme.spaceX * 0.5, 'rem')
}
});
export default GridView;

View File

@@ -0,0 +1,19 @@
import { createDOMElement } from 'react-native';
import React from 'react';
import styles from './styles';
const IconDirectMessage = props =>
createDOMElement('svg', {
children: (
<g>
<path d="M43.34 14H12.66L28 27.946z" />
<path d="M51.392 14.789L30.018 34.22c-.009.008-.028.006-.039.012-.563.5-1.266.768-1.98.768-.72 0-1.442-.258-2.017-.78L4.609 14.79A3.957 3.957 0 0 0 3 18v37a1.998 1.998 0 0 0 2 2c.464 0 .924-.162 1.292-.473L19 46h30c2.243 0 4-1.757 4-4V18a3.96 3.96 0 0 0-1.608-3.211z" />
</g>
),
style: [styles.icon, props.style],
viewBox: '0 0 56 72'
});
IconDirectMessage.metadata = { height: 72, width: 56 };
export default IconDirectMessage;

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