diff --git a/packages/components/src/mobile/bottom-sheet/index.native.js b/packages/components/src/mobile/bottom-sheet/index.native.js index f17284b49e730..56265a9f18ee6 100644 --- a/packages/components/src/mobile/bottom-sheet/index.native.js +++ b/packages/components/src/mobile/bottom-sheet/index.native.js @@ -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 { @@ -171,5 +172,6 @@ ThemedBottomSheet.Button = Button; ThemedBottomSheet.Cell = Cell; ThemedBottomSheet.PickerCell = PickerCell; ThemedBottomSheet.SwitchCell = SwitchCell; +ThemedBottomSheet.RangeCell = RangeCell; export default ThemedBottomSheet; diff --git a/packages/components/src/mobile/bottom-sheet/range-cell.native.js b/packages/components/src/mobile/bottom-sheet/range-cell.native.js new file mode 100644 index 0000000000000..07b343e9ec078 --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/range-cell.native.js @@ -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 ( + + + + ); +} diff --git a/packages/components/src/mobile/slider/index.native.js b/packages/components/src/mobile/slider/index.native.js new file mode 100644 index 0000000000000..111d9987e973d --- /dev/null +++ b/packages/components/src/mobile/slider/index.native.js @@ -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 ( + + + + + ); + } +} + +export default Slider; diff --git a/packages/components/src/mobile/slider/styles.scss b/packages/components/src/mobile/slider/styles.scss new file mode 100644 index 0000000000000..326880b621807 --- /dev/null +++ b/packages/components/src/mobile/slider/styles.scss @@ -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; +}