UNPKG

citong-react-web

Version:

A framework for building web apps with React

241 lines (231 loc) 7.49 kB
/** * Copyright (c) 2015-present, Alibaba Group Holding Limited. * All rights reserved. * * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * @providesModule ReactSlider */ 'use strict'; import React, { PropTypes, Component } from 'react'; import ReactDOM from 'react-dom'; import StyleSheet from 'ReactStyleSheet'; import View from 'ReactView'; import Image from 'ReactImage'; import PanResponder from 'ReactPanResponder'; const TRACK_SIZE = 4; const THUMB_SIZE = 20; function noop() {} class Slider extends Component { constructor(props) { super(props); this.state = { value: props.value, }; } componentWillMount() { this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder.bind(this), onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder.bind(this), onPanResponderGrant: this._handlePanResponderGrant.bind(this), onPanResponderMove: this._handlePanResponderMove.bind(this), onPanResponderRelease: this._handlePanResponderEnd.bind(this), onPanResponderTerminate: this._handlePanResponderEnd.bind(this), }); } render() { let { minimumTrackTintColor, maximumTrackTintColor, styles, style, trackStyle, thumbStyle, thumbTintColor, thumbImage, disabled, ...other, } = this.props; let mainStyles = styles || defaultStyles; let trackHeight = (trackStyle && trackStyle.height) || defaultStyles.track.height; let thumbHeight = (thumbStyle && thumbStyle.height) || defaultStyles.thumb.height; let minTrackWidth = this._getMinTrackWidth(); let minimumTrackStyle = { width: minTrackWidth, marginTop: -trackHeight, backgroundColor: minimumTrackTintColor, }; return ( <View style={[mainStyles.container, style]}> <View ref="totalTrack" style={[ {backgroundColor: maximumTrackTintColor}, mainStyles.track, trackStyle, disabled && {backgroundColor: mainStyles.disabled.backgroundColor}, ]} /> <View ref="minTrack" style={[mainStyles.track, trackStyle, minimumTrackStyle]} /> { thumbImage && thumbImage.uri && <Image ref="thumb" source={thumbImage} style={[ {width: mainStyles.thumb.width, height: mainStyles.thumb.height}, thumbStyle, {left: minTrackWidth, position: 'relative', display: 'block'}, {marginLeft: - thumbHeight / 2, marginTop: -(thumbHeight + trackHeight) / 2}, ]} {...this._panResponder.panHandlers} /> || <View ref="thumb" style={[ {backgroundColor: thumbTintColor, left: minTrackWidth}, mainStyles.thumb, thumbStyle, {marginLeft: - thumbHeight / 2, marginTop: -(thumbHeight + trackHeight) / 2}, disabled && {boxShadow: mainStyles.disabled.boxShadow}, ]} {...this._panResponder.panHandlers} /> } </View>); } _handleStartShouldSetPanResponder() { return !this.props.disabled; } _handleMoveShouldSetPanResponder() { return false; } _handlePanResponderGrant(e, gestureState) { this.previousLeft = this._getWidth('minTrack'); this.previousValue = this.state.value; this._fireProcessEvent('onSlidingStart'); } _handlePanResponderMove(e, gestureState) { this.setState({value: this._getValue(gestureState)}); this._fireProcessEvent('onValueChange'); } _handlePanResponderEnd(e, gestureState) { this.setState({value: this._getValue(gestureState)}); this._fireProcessEvent('onSlidingComplete'); } _fireProcessEvent(event) { if (this.props[event]) { this.props[event](this.state.value); } } _getValue(gestureState) { const {step, maximumValue, minimumValue} = this.props; let totalWidth = this._getWidth('totalTrack'); let thumbLeft = Math.min(totalWidth, Math.max(0, this.previousLeft + gestureState.dx)), ratio = thumbLeft / totalWidth, newValue = ratio * (maximumValue - minimumValue) + minimumValue; if (step > 0) { return Math.round(newValue / step) * step; } else { return newValue; } } _getWidth(ref) { if (this.refs[ref]) { let node = ReactDOM.findDOMNode(this.refs[ref]), rect = node.getBoundingClientRect(); return rect.width; } } _getMinTrackWidth() { let value = this.state.value; return 100 * (value - this.props.minimumValue) / (this.props.maximumValue - this.props.minimumValue) + '%'; } } Slider.propTypes = { /** * Used to style and layout the `Slider`. See `StyleSheet.js` and * `ViewStylePropTypes.js` for more info. */ style: View.propTypes.style, /** * Initial value of the slider. The value should be between minimumValue * and maximumValue, which default to 0 and 1 respectively. * Default value is 0. * * *This is not a controlled component*, e.g. if you don't update * the value, the component won't be reset to its inital value. */ value: PropTypes.number, /** * Step value of the slider. The value should be * between 0 and (maximumValue - minimumValue). * Default value is 0. */ step: PropTypes.number, /** * Initial minimum value of the slider. Default value is 0. */ minimumValue: PropTypes.number, /** * Initial maximum value of the slider. Default value is 1. */ maximumValue: PropTypes.number, /** * The color used for the track to the left of the button. Overrides the * default blue gradient image. */ minimumTrackTintColor: PropTypes.string, /** * The color used for the track to the right of the button. Overrides the * default blue gradient image. */ maximumTrackTintColor: PropTypes.string, /** * If true the user won't be able to move the slider. * Default value is false. */ disabled: PropTypes.bool, /** * Sets an image for the track. It only supports images that are included as assets */ trackImage: PropTypes.any, /** * Sets an image for the thumb. It only supports static images. */ thumbImage: PropTypes.any, /** * Callback continuously called while the user is dragging the slider. */ onValueChange: PropTypes.func, /** * Callback called when the user finishes changing the value (e.g. when * the slider is released). */ onSlidingComplete: PropTypes.func, }; Slider.defaultProps = { value: 0, step: 0, minimumValue: 0, maximumValue: 1, minimumTrackTintColor: '#0f85fb', maximumTrackTintColor: '#b3b3b3', thumbTintColor: '#fff', disabled: false, onValueChange: noop, onSlidingComplete: noop, }; let defaultStyles = StyleSheet.create({ container: { height: 40, justifyContent: 'center', position: 'relative', }, track: { height: TRACK_SIZE, borderRadius: TRACK_SIZE / 2, }, thumb: { width: THUMB_SIZE, height: THUMB_SIZE, borderRadius: THUMB_SIZE / 2, boxShadow: '2px 3px 10px rgba(0,0,0,0.75)', }, disabled: { backgroundColor: '#dadada', boxShadow: '2px 3px 10px rgba(0,0,0,0.25)', }, }); Slider.isReactNativeComponent = true; export default Slider;