-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Slider] Remove style-propable mixin and react-dom #3332
Changes from 3 commits
14f65cc
2aa64ef
f392585
906b16a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import StylePropable from './mixins/style-propable'; | ||
import Transitions from './styles/transitions'; | ||
import FocusRipple from './ripples/focus-ripple'; | ||
import getMuiTheme from './styles/getMuiTheme'; | ||
|
@@ -40,6 +38,122 @@ const valueInRangePropType = (props, propName, componentName) => { | |
} | ||
}; | ||
|
||
const getStyles = (props, state) => { | ||
const { | ||
slider, | ||
} = state.muiTheme; | ||
|
||
const fillGutter = slider.handleSize / 2; | ||
const disabledGutter = slider.trackSize + slider.handleSizeDisabled / 2; | ||
const calcDisabledSpacing = props.disabled ? ` - ${disabledGutter}px` : ''; | ||
|
||
const styles = { | ||
root: { | ||
touchCallout: 'none', | ||
userSelect: 'none', | ||
cursor: 'default', | ||
height: slider.handleSizeActive, | ||
position: 'relative', | ||
marginTop: 24, | ||
marginBottom: 48, | ||
}, | ||
track: { | ||
position: 'absolute', | ||
top: (slider.handleSizeActive - slider.trackSize) / 2, | ||
left: 0, | ||
width: '100%', | ||
height: slider.trackSize, | ||
}, | ||
filledAndRemaining: { | ||
position: 'absolute', | ||
top: 0, | ||
height: '100%', | ||
transition: Transitions.easeOut(null, 'margin'), | ||
}, | ||
handle: { | ||
boxSizing: 'border-box', | ||
position: 'absolute', | ||
cursor: 'pointer', | ||
pointerEvents: 'inherit', | ||
top: 0, | ||
left: '0%', | ||
zIndex: 1, | ||
margin: `${(slider.trackSize / 2)}px 0 0 0`, | ||
width: slider.handleSize, | ||
height: slider.handleSize, | ||
backgroundColor: slider.selectionColor, | ||
backgroundClip: 'padding-box', | ||
border: '0px solid transparent', | ||
borderRadius: '50%', | ||
transform: 'translate(-50%, -50%)', | ||
transition: | ||
`${Transitions.easeOut('450ms', 'background')}, ${ | ||
Transitions.easeOut('450ms', 'border-color')}, ${ | ||
Transitions.easeOut('450ms', 'width')}, ${ | ||
Transitions.easeOut('450ms', 'height')}`, | ||
overflow: 'visible', | ||
outline: 'none', | ||
}, | ||
handleWhenDisabled: { | ||
boxSizing: 'content-box', | ||
cursor: 'not-allowed', | ||
backgroundColor: slider.trackColor, | ||
width: slider.handleSizeDisabled, | ||
height: slider.handleSizeDisabled, | ||
border: 'none', | ||
}, | ||
handleWhenPercentZero: { | ||
border: `${slider.trackSize}px solid ${slider.handleColorZero}`, | ||
backgroundColor: slider.handleFillColor, | ||
boxShadow: 'none', | ||
}, | ||
handleWhenPercentZeroAndDisabled: { | ||
cursor: 'not-allowed', | ||
width: slider.handleSizeDisabled, | ||
height: slider.handleSizeDisabled, | ||
}, | ||
handleWhenPercentZeroAndFocused: { | ||
border: `${slider.trackSize}px solid ${slider.trackColorSelected}`, | ||
}, | ||
handleWhenActive: { | ||
width: slider.handleSizeActive, | ||
height: slider.handleSizeActive, | ||
}, | ||
ripple: { | ||
height: slider.handleSize, | ||
width: slider.handleSize, | ||
overflow: 'visible', | ||
}, | ||
rippleWhenPercentZero: { | ||
top: -slider.trackSize, | ||
left: -slider.trackSize, | ||
}, | ||
rippleInner: { | ||
height: '300%', | ||
width: '300%', | ||
top: -slider.handleSize, | ||
left: -slider.handleSize, | ||
}, | ||
rippleColor: { | ||
fill: state.percent === 0 ? slider.handleColorZero : slider.rippleColor, | ||
}, | ||
}; | ||
styles.filled = Object.assign({}, styles.filledAndRemaining, { | ||
left: 0, | ||
backgroundColor: (props.disabled) ? slider.trackColor : slider.selectionColor, | ||
marginRight: fillGutter, | ||
width: `calc(${(state.percent * 100)}%${calcDisabledSpacing})`, | ||
}); | ||
styles.remaining = Object.assign({}, styles.filledAndRemaining, { | ||
right: 0, | ||
backgroundColor: (state.hovered || state.focused) | ||
&& !props.disabled ? slider.trackColorSelected : slider.trackColor, | ||
marginLeft: fillGutter, | ||
width: `calc(${((1 - state.percent) * 100)}%${calcDisabledSpacing})`, | ||
}); | ||
|
||
return styles; | ||
}; | ||
|
||
const Slider = React.createClass({ | ||
|
||
|
@@ -142,10 +256,6 @@ const Slider = React.createClass({ | |
muiTheme: React.PropTypes.object, | ||
}, | ||
|
||
mixins: [ | ||
StylePropable, | ||
], | ||
|
||
getDefaultProps() { | ||
return { | ||
disabled: false, | ||
|
@@ -192,119 +302,6 @@ const Slider = React.createClass({ | |
} | ||
}, | ||
|
||
getTheme() { | ||
return this.state.muiTheme.slider; | ||
}, | ||
|
||
getStyles() { | ||
const fillGutter = this.getTheme().handleSize / 2; | ||
const disabledGutter = this.getTheme().trackSize + this.getTheme().handleSizeDisabled / 2; | ||
const calcDisabledSpacing = this.props.disabled ? ` -${disabledGutter}px` : ''; | ||
const styles = { | ||
root: { | ||
touchCallout: 'none', | ||
userSelect: 'none', | ||
cursor: 'default', | ||
height: this.getTheme().handleSizeActive, | ||
position: 'relative', | ||
marginTop: 24, | ||
marginBottom: 48, | ||
}, | ||
track: { | ||
position: 'absolute', | ||
top: (this.getTheme().handleSizeActive - this.getTheme().trackSize) / 2, | ||
left: 0, | ||
width: '100%', | ||
height: this.getTheme().trackSize, | ||
}, | ||
filledAndRemaining: { | ||
position: 'absolute', | ||
top: 0, | ||
height: '100%', | ||
transition: Transitions.easeOut(null, 'margin'), | ||
}, | ||
handle: { | ||
boxSizing: 'border-box', | ||
position: 'absolute', | ||
cursor: 'pointer', | ||
pointerEvents: 'inherit', | ||
top: 0, | ||
left: '0%', | ||
zIndex: 1, | ||
margin: `${(this.getTheme().trackSize / 2)}px 0 0 0`, | ||
width: this.getTheme().handleSize, | ||
height: this.getTheme().handleSize, | ||
backgroundColor: this.getTheme().selectionColor, | ||
backgroundClip: 'padding-box', | ||
border: '0px solid transparent', | ||
borderRadius: '50%', | ||
transform: 'translate(-50%, -50%)', | ||
transition: | ||
`${Transitions.easeOut('450ms', 'background')}, ${ | ||
Transitions.easeOut('450ms', 'border-color')}, ${ | ||
Transitions.easeOut('450ms', 'width')}, ${ | ||
Transitions.easeOut('450ms', 'height')}`, | ||
overflow: 'visible', | ||
}, | ||
handleWhenDisabled: { | ||
boxSizing: 'content-box', | ||
cursor: 'not-allowed', | ||
backgroundColor: this.getTheme().trackColor, | ||
width: this.getTheme().handleSizeDisabled, | ||
height: this.getTheme().handleSizeDisabled, | ||
border: 'none', | ||
}, | ||
handleWhenPercentZero: { | ||
border: `${this.getTheme().trackSize}px solid ${this.getTheme().handleColorZero}`, | ||
backgroundColor: this.getTheme().handleFillColor, | ||
boxShadow: 'none', | ||
}, | ||
handleWhenPercentZeroAndDisabled: { | ||
cursor: 'not-allowed', | ||
width: this.getTheme().handleSizeDisabled, | ||
height: this.getTheme().handleSizeDisabled, | ||
}, | ||
handleWhenPercentZeroAndFocused: { | ||
border: `${this.getTheme().trackSize}px solid ${this.getTheme().trackColorSelected}`, | ||
}, | ||
handleWhenActive: { | ||
width: this.getTheme().handleSizeActive, | ||
height: this.getTheme().handleSizeActive, | ||
}, | ||
ripple: { | ||
height: this.getTheme().handleSize, | ||
width: this.getTheme().handleSize, | ||
overflow: 'visible', | ||
}, | ||
rippleWhenPercentZero: { | ||
top: -this.getTheme().trackSize, | ||
left: -this.getTheme().trackSize, | ||
}, | ||
rippleInner: { | ||
height: '300%', | ||
width: '300%', | ||
top: -this.getTheme().handleSize, | ||
left: -this.getTheme().handleSize, | ||
}, | ||
}; | ||
styles.filled = this.mergeStyles(styles.filledAndRemaining, { | ||
left: 0, | ||
backgroundColor: (this.props.disabled) ? | ||
this.getTheme().trackColor : | ||
this.getTheme().selectionColor, | ||
marginRight: fillGutter, | ||
width: `calc(${(this.state.percent * 100)}%${calcDisabledSpacing})`, | ||
}); | ||
styles.remaining = this.mergeStyles(styles.filledAndRemaining, { | ||
right: 0, | ||
backgroundColor: this.getTheme().trackColor, | ||
marginLeft: fillGutter, | ||
width: `calc(${((1 - this.state.percent) * 100)}%${calcDisabledSpacing})`, | ||
}); | ||
|
||
return styles; | ||
}, | ||
|
||
|
||
// Needed to prevent text selection when dragging the slider handler. | ||
// In the future, we should consider use <input type="range"> to avoid | ||
|
@@ -437,7 +434,7 @@ const Slider = React.createClass({ | |
}, | ||
|
||
_getTrackLeft() { | ||
return ReactDOM.findDOMNode(this.refs.track).getBoundingClientRect().left; | ||
return this.refs.track.getBoundingClientRect().left; | ||
}, | ||
|
||
handleMouseUp(e) { | ||
|
@@ -472,7 +469,7 @@ const Slider = React.createClass({ | |
}, | ||
|
||
_dragX(e, pos) { | ||
const max = ReactDOM.findDOMNode(this.refs.track).clientWidth; | ||
const max = this.refs.track.clientWidth; | ||
if (pos < 0) pos = 0; else if (pos > max) pos = max; | ||
this._updateWithChangeEvent(e, pos / max); | ||
}, | ||
|
@@ -492,77 +489,76 @@ const Slider = React.createClass({ | |
let percent = this.state.percent; | ||
if (percent > 1) percent = 1; else if (percent < 0) percent = 0; | ||
|
||
const styles = this.getStyles(); | ||
const sliderStyles = this.mergeStyles(styles.root, this.props.style); | ||
const handleStyles = percent === 0 ? this.mergeStyles( | ||
const styles = getStyles(this.props, this.state); | ||
const sliderStyles = Object.assign({}, styles.root, this.props.style); | ||
const handleStyles = percent === 0 ? Object.assign( | ||
{}, | ||
styles.handle, | ||
styles.handleWhenPercentZero, | ||
this.state.active && styles.handleWhenActive, | ||
this.state.focused && {outline: 'none'}, | ||
(this.state.hovered || this.state.focused) && !this.props.disabled | ||
&& styles.handleWhenPercentZeroAndFocused, | ||
this.props.disabled && styles.handleWhenPercentZeroAndDisabled | ||
) : this.mergeStyles( | ||
) : Object.assign( | ||
{}, | ||
styles.handle, | ||
this.state.active && styles.handleWhenActive, | ||
this.state.focused && {outline: 'none'}, | ||
this.props.disabled && styles.handleWhenDisabled, | ||
{ | ||
left: `${(percent * 100)}%`, | ||
} | ||
); | ||
const rippleStyle = this.mergeStyles( | ||
const rippleStyle = Object.assign( | ||
{}, | ||
styles.ripple, | ||
percent === 0 && styles.rippleWhenPercentZero | ||
); | ||
const remainingStyles = styles.remaining; | ||
if ((this.state.hovered || this.state.focused) && !this.props.disabled) { | ||
remainingStyles.backgroundColor = this.getTheme().trackColorSelected; | ||
} | ||
|
||
const rippleShowCondition = (this.state.hovered || this.state.focused) && !this.state.active; | ||
const rippleColor = this.state.percent === 0 ? this.getTheme().handleColorZero : this.getTheme().rippleColor; | ||
|
||
let focusRipple; | ||
if (!this.props.disabled && !this.props.disableFocusRipple) { | ||
focusRipple = ( | ||
<FocusRipple | ||
ref="focusRipple" | ||
key="focusRipple" | ||
style={this.mergeStyles(rippleStyle)} | ||
style={rippleStyle} | ||
innerStyle={styles.rippleInner} | ||
show={rippleShowCondition} | ||
muiTheme={this.state.muiTheme} | ||
color={rippleColor} | ||
color={styles.rippleColor.fill} | ||
/> | ||
); | ||
} | ||
|
||
let handleDragProps = {}; | ||
|
||
if (!this.props.disabled) { | ||
handleDragProps = { | ||
onTouchStart: this._onHandleTouchStart, | ||
onMouseDown: this._onHandleMouseDown, | ||
}; | ||
} | ||
|
||
const { | ||
prepareStyles, | ||
} = this.state.muiTheme; | ||
|
||
return ( | ||
<div {...others } style={this.prepareStyles(this.props.style)}> | ||
<div {...others} style={prepareStyles(Object.assign({}, this.props.style))}> | ||
<span>{this.props.description}</span> | ||
<span>{this.props.error}</span> | ||
<div | ||
style={this.prepareStyles(sliderStyles)} | ||
style={prepareStyles(sliderStyles)} | ||
onFocus={this.handleFocus} | ||
onBlur={this.handleBlur} | ||
onMouseDown={this.handleMouseDown} | ||
onMouseEnter={this.handleMouseEnter} | ||
onMouseLeave={this.handleMouseLeave} | ||
onMouseUp={this.handleMouseUp} | ||
> | ||
<div ref="track" style={this.prepareStyles(styles.track)}> | ||
<div style={this.prepareStyles(styles.filled)}></div> | ||
<div style={this.prepareStyles(remainingStyles)}></div> | ||
<div style={this.prepareStyles(handleStyles)} tabIndex={0} {...handleDragProps}> | ||
<div ref="track" style={prepareStyles(styles.track)}> | ||
<div style={prepareStyles(styles.filled)}></div> | ||
<div style={prepareStyles(styles.remaining)}></div> | ||
<div style={prepareStyles(handleStyles)} tabIndex={0} {...handleDragProps}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On L37, we can save an allocation by taking the empty object off. let handleDragProps; // = {}; removed
if (!this.props.disabled) {
handleDragProps = {
onTouchStart: this._onHandleTouchStart,
onMouseDown: this._onHandleMouseDown,
};
}
// Or write as
const handleDragProps = !this.props.disabled && {
onTouchStart: this._onHandleTouchStart,
onMouseDown: this._onHandleMouseDown,
}; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can stick with your first approach, since the last one will initialise the variable with false or an object There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good! |
||
{focusRipple} | ||
</div> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean with these:
handleWhenDisabled
,handledWhenPercentZero,
handleWhenPercentZeroAndDisabled`, etc. it would be nice if we could replace all of these wit ha single handle key so that the we didn't need Object.assign call below.This can probably be solved by ternary for some keys or if there's too much, something like what we did with badge should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They were already in the code actually. I will try hard to change that, but it will take some time because there are a lot of cases that need to be handled (pun intended 😄)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I know! Not your fault. 😄
😆