From 22d20706e36f58e019db9a7bf7b845ee9cc8041f Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Thu, 3 Nov 2016 08:56:26 -0700 Subject: [PATCH] Add React Native TextInput examples --- .../components/TextInput/TextInputExample.js | 915 +++++++++++++++++- 1 file changed, 879 insertions(+), 36 deletions(-) diff --git a/examples/components/TextInput/TextInputExample.js b/examples/components/TextInput/TextInputExample.js index 3f1e62c1..df7f813f 100644 --- a/examples/components/TextInput/TextInputExample.js +++ b/examples/components/TextInput/TextInputExample.js @@ -1,41 +1,884 @@ import React from 'react'; import { storiesOf, action } from '@kadira/storybook'; -import { StyleSheet, TextInput, View } from 'react-native' +import { StyleSheet, Text, TextInput, View } from 'react-native' -storiesOf('component: TextInput', module) - .add('tbd', () => ( - - { console.log('TextInput.onBlur', e) }} - onChange={(e) => { console.log('TextInput.onChange', e) }} - onChangeText={(e) => { console.log('TextInput.onChangeText', e) }} - onFocus={(e) => { console.log('TextInput.onFocus', e) }} - onSelectionChange={(e) => { console.log('TextInput.onSelectionChange', e) }} - /> - - - - - - - - - - )) +/** + * 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 styles = StyleSheet.create({ - textInput: { - borderWidth: 1 +class WithLabel extends React.Component { + render() { + return ( + + + {this.props.label} + + {this.props.children} + + ); } -}) +} + +class TextEventsExample extends React.Component { + state = { + curText: '', + prevText: '', + prev2Text: '', + prev3Text: '', + }; + + updateText = (text) => { + this.setState((state) => { + return { + curText: text, + prevText: state.curText, + prev2Text: state.prevText, + prev3Text: state.prev2Text, + }; + }); + }; + + render() { + return ( + + 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} + /> + + {this.state.curText}{'\n'} + (prev: {this.state.prevText}){'\n'} + (prev2: {this.state.prev2Text}){'\n'} + (prev3: {this.state.prev3Text}) + + + ); + } +} + +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 ( + { + 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 ( + + { + text = text.replace(/ /g, '_'); + this.setState({text}); + }} + style={styles.default} + value={this.state.text} + /> + + {remainder} + + + ); + } +} + +class RewriteExampleInvalidCharacters extends React.Component { + state: any; + + constructor(props) { + super(props); + this.state = {text: ''}; + } + render() { + return ( + + { + this.setState({text: text.replace(/\s/g, '')}); + }} + style={styles.default} + value={this.state.text} + /> + + ); + } +} + +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); + + //highlight hashtags + parts = parts.map((text) => { + if (/^#/.test(text)) { + return {text}; + } else { + return text; + } + }); + + return ( + + { + this.setState({text}); + }}> + {parts} + + + ); + } +} + +class BlurOnSubmitExample extends React.Component { + focusNextField = (nextField) => { + this.refs[nextField].focus(); + }; + + render() { + return ( + + this.focusNextField('2')} + /> + this.focusNextField('3')} + /> + this.focusNextField('4')} + /> + this.focusNextField('5')} + /> + + + ); + } +} + +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 ( + + 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} + /> + + + selection = {JSON.stringify(this.state.selection)} + + + Place at Start (0, 0) + + + Place at End ({length}, {length}) + + + Place at Random + + + Select All + + + Select Random + + + + ); + } +} + +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 ( + + + + ); + } + }, + { + title: "Live Re-Write ( -> '_') + maxLength", + render: function() { + return ; + } + }, + { + title: 'Live Re-Write (no spaces allowed)', + render: function() { + return ; + } + }, + { + title: 'Auto-capitalize', + render: function() { + return ( + + + + + + + + + + + + + + + ); + } + }, + { + title: 'Auto-correct', + render: function() { + return ( + + + + + + + + + ); + } + }, + { + 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 ( + + + + ); + }); + return {examples}; + } + }, + { + title: 'Keyboard appearance', + render: function() { + var keyboardAppearance = [ + 'default', + 'light', + 'dark', + ]; + var examples = keyboardAppearance.map((type) => { + return ( + + + + ); + }); + return {examples}; + } + }, + { + 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 ( + + + + ); + }); + return {examples}; + } + }, + { + title: 'Enable return key automatically', + render: function() { + return ( + + + + + + ); + } + }, + { + title: 'Secure text entry', + render: function() { + return ( + + + + + + ); + } + }, + { + title: 'Event handling', + render: function(): React.Element { return ; }, + }, + { + title: 'Colored input text', + render: function() { + return ( + + + + + ); + } + }, + { + title: 'Colored highlight/cursor for text input', + render: function() { + return ( + + + + + ); + } + }, + { + title: 'Clear button mode', + render: function () { + return ( + + + + + + + + + + + + + + + ); + } + }, + { + title: 'Clear and select', + render: function() { + return ( + + + + + + + + + ); + } + }, + { + title: 'Blur on submit', + render: function(): React.Element { return ; }, + }, + { + title: 'Multiline blur on submit', + render: function() { + return ( + + alert(event.nativeEvent.text)} + /> + + ); + } + }, + { + title: 'Multiline', + render: function() { + return ( + + + + + + + + + + + ); + } + }, + { + title: 'Number of lines', + render: function() { + return ( + + + + ); + } + }, + { + title: 'Auto-expanding', + render: function() { + return ( + + + + ); + } + }, + { + title: 'Attributed text', + render: function() { + return ; + } + }, + { + title: 'Text selection & cursor placement', + render: function() { + return ( + + + + + ); + } + }, + { + title: 'TextInput maxLength', + render: function() { + return ( + + + + + + + + + + + + + + + ); + } + } +]; + +examples.forEach((example) => { + storiesOf('component: TextInput', module) + .add(example.title, () => example.render()) +});