/* eslint-disable react/jsx-no-bind */ /** * 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 */ import React from 'react'; import { storiesOf } from '@kadira/storybook'; import UIExplorer from '../../UIExplorer'; import { any, bool, string } from 'prop-types'; import { StyleSheet, Text, TextInput, TextPropTypes, View } from 'react-native'; class WithLabel extends React.Component { static propTypes = { children: any, label: string }; 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('onBlur')} onChange={event => this.updateText('onChange text: ' + event.nativeEvent.text)} onEndEditing={event => this.updateText('onEndEditing text: ' + event.nativeEvent.text)} onFocus={() => this.updateText('onFocus')} onKeyPress={event => { this.updateText('onKeyPress key: ' + event.nativeEvent.key); }} onSelectionChange={event => this.updateText( 'onSelectionChange range: ' + event.nativeEvent.selection.start + ',' + event.nativeEvent.selection.end )} onSubmitEditing={event => this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)} placeholder="Enter text to see events" style={[styles.default, { maxWidth: 200 }]} /> {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() { const limit = 20; const remainder = limit - this.state.text.length; const 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 const delimiter = /\s+/; //split string let _text = this.state.text; let token, index; const 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 ( { this.setState({ text }); }} style={styles.multiline} value={parts.join('')} /> ); } } class BlurOnSubmitExample extends React.Component { constructor(props) { super(props); this._nodes = {}; } focusNextField = nextField => { this._nodes[nextField].focus(); }; render() { return ( this.focusNextField('2')} placeholder="blurOnSubmit = false" ref={c => { this._nodes['1'] = c; }} returnKeyType="next" style={styles.default} /> this.focusNextField('3')} placeholder="blurOnSubmit = false" ref={c => { this._nodes['2'] = c; }} returnKeyType="next" style={styles.default} /> this.focusNextField('4')} placeholder="blurOnSubmit = false" ref={c => { this._nodes['3'] = c; }} returnKeyType="next" style={styles.default} /> this.focusNextField('5')} placeholder="blurOnSubmit = false" ref={c => { this._nodes['4'] = c; }} style={styles.default} /> { this._nodes['5'] = c; }} returnKeyType="done" style={styles.default} /> ); } } type SelectionExampleState = { selection: { start: number, end?: number }, value: string }; class SelectionExample extends React.Component { state: SelectionExampleState; _textInput: any; static propTypes = { multiline: bool, style: TextPropTypes.style, value: string }; constructor(props) { super(props); this.state = { selection: { start: 0, end: 0 }, value: props.value }; } onSelectionChange({ nativeEvent: { selection } }) { this.setState({ selection }); } getRandomPosition() { const length = this.state.value.length; return Math.round(Math.random() * length); } select(start, end) { this._textInput.focus(); this.setState({ selection: { start, end } }); } selectRandom() { const positions = [this.getRandomPosition(), this.getRandomPosition()].sort(); this.select(...positions); } placeAt(position) { this.select(position, position); } placeAtRandom() { this.placeAt(this.getRandomPosition()); } render() { const 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 ); } } const 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() { return ( ); } }, { title: "Live Re-Write ( -> '_') + maxLength", render() { return ; } }, { title: 'Live Re-Write (no spaces allowed)', render() { return ; } }, { title: 'Auto-capitalize', render() { return ( ); } }, { title: 'Auto-correct', render() { return ( ); } }, { title: 'Keyboard types', render() { const keyboardTypes = [ 'default', //'ascii-capable', //'numbers-and-punctuation', 'url', 'number-pad', 'phone-pad', //'name-phone-pad', 'email-address', //'decimal-pad', //'twitter', 'web-search', 'numeric' ]; const examples = keyboardTypes.map(type => { return ( ); }); return {examples}; } }, { title: 'Keyboard appearance', render() { const keyboardAppearance = ['default', 'light', 'dark']; const examples = keyboardAppearance.map(type => { return ( ); }); return {examples}; } }, { title: 'Return key types', render() { const returnKeyTypes = [ 'default', 'go', 'google', 'join', 'next', 'route', 'search', 'send', 'yahoo', 'done', 'emergency-call' ]; const examples = returnKeyTypes.map(type => { return ( ); }); return {examples}; } }, { title: 'Enable return key automatically', render() { return ( ); } }, { title: 'Secure text entry', render() { return ( ); } }, { title: 'Event handling', render(): React.Element { return ; } }, { title: 'Colored input text', render() { return ( ); } }, { title: 'Colored highlight/cursor for text input', render() { return ( ); } }, { title: 'Clear button mode', render() { return ( ); } }, { title: 'Clear and select', render() { return ( ); } }, { title: 'Blur on submit', render(): React.Element { return ; } }, { title: 'Multiline blur on submit', render() { return ( { console.log(event.nativeEvent.text); }} placeholder="blurOnSubmit = true" returnKeyType="next" style={styles.multiline} /> ); } }, { title: 'Multiline', render() { return ( ); } }, { title: 'Number of lines', render() { return ( ); } }, { title: 'Auto-expanding', render() { return ( ); } }, { title: 'Attributed text', render() { return ; } }, { title: 'Text selection & cursor placement', render() { return ( ); } }, { title: 'TextInput maxLength', render() { return ( ); } } ]; storiesOf('Components', module).add('TextInput', () => );