-
-
Notifications
You must be signed in to change notification settings - Fork 144
Slider tooltips #564
Slider tooltips #564
Changes from all commits
4a1c16d
c920c02
6ffe732
ca42f0e
90e2fd1
fd7c768
01a203e
c2e16d3
fb755c9
37470e6
592a5fb
11292cb
0c08d79
e6f8026
224ec57
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,7 +1,7 @@ | ||
import React, {Component} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import {omit} from 'ramda'; | ||
import {Range} from 'rc-slider'; | ||
import {Range, createSliderWithTooltip} from 'rc-slider'; | ||
|
||
/** | ||
* A double slider with two handles. | ||
|
@@ -11,13 +11,21 @@ export default class RangeSlider extends Component { | |
constructor(props) { | ||
super(props); | ||
this.propsToState = this.propsToState.bind(this); | ||
this.DashSlider = props.tooltip | ||
? createSliderWithTooltip(Range) | ||
: Range; | ||
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. This will break if someone starts out with no tooltips and adds them later. 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. OK — I added this back to the render method; that should be fine right? 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 second thought, putting this in the I'm not sure I actually understand the problem with this in the constructor. If I have a hot-reload app, and I add/remove the This is a simple app I'm using to testimport dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
server = app.server
app.layout = html.Div([
html.H1("Tooltips"),
html.Br(),
html.H1("Slider, always visible"),
dcc.Slider(
id='my-slider',
min=0,
max=20,
step=0.5,
value=10,
tooltip={'always_visible': True}
),
html.Br(),
html.H1("RangeSlider, on hover"),
dcc.RangeSlider(
id='my-range-slider',
min=0,
max=20,
step=0.5,
value=[5,10],
tooltip={'placement': 'bottom'}
),
])
if __name__ == '__main__':
app.run_server(debug=True) 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. The problem is if 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. Ah right, of course. I've added the same conditional to |
||
} | ||
|
||
propsToState(newProps) { | ||
this.setState({value: newProps.value}); | ||
} | ||
|
||
componentWillReceiveProps(newProps) { | ||
if (newProps.tooltip !== this.props.tooltip) { | ||
this.DashSlider = newProps.tooltip | ||
? createSliderWithTooltip(Range) | ||
: Range; | ||
} | ||
this.propsToState(newProps); | ||
} | ||
|
||
|
@@ -31,11 +39,27 @@ export default class RangeSlider extends Component { | |
id, | ||
loading_state, | ||
setProps, | ||
tooltip, | ||
updatemode, | ||
vertical, | ||
} = this.props; | ||
const value = this.state.value; | ||
|
||
let tipProps; | ||
if (tooltip && tooltip.always_visible) { | ||
/** | ||
* clone `tooltip` but with renamed key `always_visible` -> `visible` | ||
* the rc-tooltip API uses `visible`, but `always_visible is more semantic | ||
* assigns the new (renamed) key to the old key and deletes the old key | ||
*/ | ||
tipProps = Object.assign(tooltip, { | ||
visible: tooltip.always_visible, | ||
}); | ||
delete tipProps.always_visible; | ||
} else { | ||
tipProps = tooltip; | ||
} | ||
|
||
return ( | ||
<div | ||
id={id} | ||
|
@@ -45,7 +69,7 @@ export default class RangeSlider extends Component { | |
className={className} | ||
style={vertical ? {height: '100%'} : {}} | ||
> | ||
<Range | ||
<this.DashSlider | ||
onChange={value => { | ||
if (updatemode === 'drag') { | ||
setProps({value}); | ||
|
@@ -58,6 +82,7 @@ export default class RangeSlider extends Component { | |
setProps({value}); | ||
} | ||
}} | ||
tipProps={tipProps} | ||
value={value} | ||
{...omit( | ||
['className', 'value', 'setProps', 'updatemode'], | ||
|
@@ -152,6 +177,31 @@ RangeSlider.propTypes = { | |
*/ | ||
pushable: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]), | ||
|
||
tooltip: PropTypes.exact({ | ||
/** | ||
* Determines whether tooltips should always be visible | ||
* (as opposed to the default, visible on hover) | ||
*/ | ||
always_visible: PropTypes.bool, | ||
|
||
/** | ||
* Determines the placement of tooltips | ||
* See https://github.com/react-component/tooltip#api | ||
* top/bottom{*} sets the _origin_ of the tooltip, so e.g. `topLeft` will | ||
* in reality appear to be on the top right of the handle | ||
*/ | ||
placement: PropTypes.oneOf([ | ||
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 made a mistake before setting the key as |
||
'left', | ||
'right', | ||
'top', | ||
'bottom', | ||
'topLeft', | ||
'topRight', | ||
'bottomLeft', | ||
'bottomRight', | ||
]), | ||
}), | ||
|
||
/** | ||
* Value by which increments or decrements are made | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import React, {Component} from 'react'; | ||
import ReactSlider from 'rc-slider'; | ||
import ReactSlider, {createSliderWithTooltip} from 'rc-slider'; | ||
import PropTypes from 'prop-types'; | ||
import {omit} from 'ramda'; | ||
import './css/[email protected]'; | ||
|
@@ -11,13 +11,21 @@ export default class Slider extends Component { | |
constructor(props) { | ||
super(props); | ||
this.propsToState = this.propsToState.bind(this); | ||
this.DashSlider = props.tooltip | ||
? createSliderWithTooltip(ReactSlider) | ||
: ReactSlider; | ||
} | ||
|
||
propsToState(newProps) { | ||
this.setState({value: newProps.value}); | ||
} | ||
|
||
componentWillReceiveProps(newProps) { | ||
if (newProps.tooltip !== this.props.tooltip) { | ||
this.DashSlider = newProps.tooltip | ||
? createSliderWithTooltip(ReactSlider) | ||
: ReactSlider; | ||
} | ||
this.propsToState(newProps); | ||
} | ||
|
||
|
@@ -31,11 +39,27 @@ export default class Slider extends Component { | |
id, | ||
loading_state, | ||
setProps, | ||
tooltip, | ||
updatemode, | ||
vertical, | ||
} = this.props; | ||
const value = this.state.value; | ||
|
||
let tipProps; | ||
if (tooltip && tooltip.always_visible) { | ||
/** | ||
* clone `tooltip` but with renamed key `always_visible` -> `visible` | ||
* the rc-tooltip API uses `visible`, but `always_visible is more semantic | ||
* assigns the new (renamed) key to the old key and deletes the old key | ||
*/ | ||
tipProps = Object.assign(tooltip, { | ||
visible: tooltip.always_visible, | ||
}); | ||
delete tipProps.always_visible; | ||
} else { | ||
tipProps = tooltip; | ||
} | ||
|
||
return ( | ||
<div | ||
id={id} | ||
|
@@ -45,7 +69,7 @@ export default class Slider extends Component { | |
className={className} | ||
style={vertical ? {height: '100%'} : {}} | ||
> | ||
<ReactSlider | ||
<this.DashSlider | ||
onChange={value => { | ||
if (updatemode === 'drag') { | ||
setProps({value}); | ||
|
@@ -58,6 +82,7 @@ export default class Slider extends Component { | |
setProps({value}); | ||
} | ||
}} | ||
tipProps={tooltip} | ||
value={value} | ||
{...omit( | ||
['className', 'setProps', 'updatemode', 'value'], | ||
|
@@ -133,6 +158,31 @@ Slider.propTypes = { | |
*/ | ||
max: PropTypes.number, | ||
|
||
tooltip: PropTypes.exact({ | ||
/** | ||
* Determines whether tooltips should always be visible | ||
* (as opposed to the default, visible on hover) | ||
*/ | ||
always_visible: PropTypes.bool, | ||
|
||
/** | ||
* Determines the placement of tooltips | ||
* See https://github.com/react-component/tooltip#api | ||
* top/bottom{*} sets the _origin_ of the tooltip, so e.g. `topLeft` will | ||
* in reality appear to be on the top right of the handle | ||
*/ | ||
placement: PropTypes.oneOf([ | ||
'left', | ||
'right', | ||
'top', | ||
'bottom', | ||
'topLeft', | ||
'topRight', | ||
'bottomLeft', | ||
'bottomRight', | ||
]), | ||
}), | ||
|
||
/** | ||
* Value by which increments or decrements are made | ||
*/ | ||
|
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.
Necessary minor upgrade that adds the
tipProps
API (undocumented; last update to the changelog / HISTORY.MD is from 2016).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.
Seems like its repo has moved to https://github.com/react-component/slider -
HISTORY.MD
is still pretty sparse there, buttipProps
appears to have been added back in 8.1.something. Anyway, I'm happy to have this up to date!