Skip to content

Commit

Permalink
[RNMobile] add RangeControl mobile implementation (slider) (#17282)
Browse files Browse the repository at this point in the history
* add RangeCell
  • Loading branch information
jbinda authored and hypest committed Nov 4, 2019
1 parent 426bf65 commit 5a5672e
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/components/src/mobile/bottom-sheet/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Button from './button';
import Cell from './cell';
import PickerCell from './picker-cell';
import SwitchCell from './switch-cell';
import RangeCell from './range-cell';
import KeyboardAvoidingView from './keyboard-avoiding-view';

class BottomSheet extends Component {
Expand Down Expand Up @@ -173,5 +174,6 @@ ThemedBottomSheet.Button = Button;
ThemedBottomSheet.Cell = Cell;
ThemedBottomSheet.PickerCell = PickerCell;
ThemedBottomSheet.SwitchCell = SwitchCell;
ThemedBottomSheet.RangeCell = RangeCell;

export default ThemedBottomSheet;
46 changes: 46 additions & 0 deletions packages/components/src/mobile/bottom-sheet/range-cell.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* External dependencies
*/
import { Platform } from 'react-native';

/**
* Internal dependencies
*/
import Cell from './cell';
import Slider from '../slider';

export default function BottomSheetRangeCell( props ) {
const {
value,
defaultValue,
onChangeValue,
minimumValue = 0,
maximumValue = 10,
disabled,
step = 1,
minimumTrackTintColor = '#00669b',
maximumTrackTintColor = Platform.OS === 'ios' ? '#e9eff3' : '#909090',
thumbTintColor = Platform.OS === 'ios' ? '#fff' : '#00669b',
...cellProps
} = props;

return (
<Cell
editable={ false }
{ ...cellProps }
>
<Slider
value={ value }
defaultValue={ defaultValue }
disabled={ disabled }
step={ step }
minimumValue={ minimumValue }
maximumValue={ maximumValue }
minimumTrackTintColor={ minimumTrackTintColor }
maximumTrackTintColor={ maximumTrackTintColor }
thumbTintColor={ thumbTintColor }
onChangeValue={ onChangeValue }
/>
</Cell>
);
}
118 changes: 118 additions & 0 deletions packages/components/src/mobile/slider/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* External dependencies
*/
import { Slider as RNSlider, TextInput, View } from 'react-native';

/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';

/**
* Internal dependencies
*/
import styles from './styles.scss';

class Slider extends Component {
constructor( props ) {
super( props );
this.handleToggleFocus = this.handleToggleFocus.bind( this );
this.handleChange = this.handleChange.bind( this );
this.handleValueSave = this.handleValueSave.bind( this );
this.handleReset = this.handleReset.bind( this );

const initialValue = this.validateInput( props.value || props.defaultValue || props.minimumValue );

this.state = { hasFocus: false, initialValue, sliderValue: initialValue };
}

componentDidUpdate( ) {
const reset = this.props.value === null;
if ( reset ) {
this.handleReset();
}
}

handleToggleFocus( validateInput = true ) {
const newState = { hasFocus: ! this.state.hasFocus };

if ( validateInput ) {
const sliderValue = this.validateInput( this.state.sliderValue );
this.handleValueSave( sliderValue );
}

this.setState( newState );
}

validateInput( text ) {
const { minimumValue, maximumValue } = this.props;
if ( ! text ) {
return minimumValue;
}
if ( typeof text === 'number' ) {
return Math.min( Math.max( text, minimumValue ), maximumValue );
}
return Math.min( Math.max( text.replace( /[^0-9]/g, '' ).replace( /^0+(?=\d)/, '' ), minimumValue ), maximumValue );
}

handleChange( text ) {
if ( ! isNaN( Number( text ) ) ) {
this.setState( { sliderValue: text } );
}
}

handleValueSave( text ) {
if ( ! isNaN( Number( text ) ) ) {
if ( this.props.onChangeValue ) {
this.props.onChangeValue( text );
}
this.setState( { sliderValue: text } );
}
}

handleReset() {
this.handleValueSave( this.props.defaultValue || this.state.initialValue );
}

render() {
const {
minimumValue,
maximumValue,
disabled,
step,
minimumTrackTintColor,
maximumTrackTintColor,
thumbTintColor,
} = this.props;

const { hasFocus, sliderValue } = this.state;

return (
<View style={ styles.sliderContainer }>
<RNSlider
value={ this.validateInput( sliderValue ) }
disabled={ disabled }
style={ styles.slider }
step={ step }
minimumValue={ minimumValue }
maximumValue={ maximumValue }
minimumTrackTintColor={ minimumTrackTintColor }
maximumTrackTintColor={ maximumTrackTintColor }
thumbTintColor={ thumbTintColor }
onValueChange={ this.handleChange }
onSlidingComplete={ this.handleValueSave }
/>
<TextInput
style={ [ styles.sliderTextInput, hasFocus ? styles.isSelected : {} ] }
onChangeText={ this.handleChange }
onFocus={ this.handleToggleFocus }
onBlur={ this.handleToggleFocus }
keyboardType="numeric"
value={ `${ sliderValue }` }
/>
</View>
);
}
}

export default Slider;
27 changes: 27 additions & 0 deletions packages/components/src/mobile/slider/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.sliderContainer {
flex: 1;
flex-direction: row;
align-content: center;
justify-content: space-evenly;
}

.slider {
flex-grow: 1;
}

.sliderTextInput {
width: 40px;
height: 25px;
align-self: center;
margin-left: 10px;
border-width: 1px;
border-radius: 4px;
border-color: $dark-gray-150;
padding-top: 0;
padding-bottom: 0;
}

.isSelected {
border-width: 2px;
border-color: $blue-wordpress;
}

0 comments on commit 5a5672e

Please sign in to comment.