Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Commit

Permalink
Slider tooltips (#564)
Browse files Browse the repository at this point in the history
* Bump rc-slider minor version

This is so we can use the `visible` prop
in `tipProps`, introduced in `rc-slider` 8.6.1
(undocumented in the `rc-slider` repo's HISTORY.md)

See react-component/slider#383

* Add tooltip (basic `tipProps` alias) to Slider and RangeSlider

Adds support for hoverable and persistent (always visible) tooltips

* Remove test css class + undo loading_state propTypes reshuffle

* Add propTypes variations template

* Put `createSliderWithTooltip` in constructor

* Change 'visible' tooltip propType to bool

* Fix Slider.react.js 🍝 from RangeSlider

* Slider tooltip propTypes: `oneOfType[]` -> single `exact`

* Move Slider instantiation from constructor to render method

* Spacing

* Add changelog entry for Slider/RangeSlider tooltips

* Fix markdown syntax + parens

* Prettier (comment + ternary formatting)

* `visible` -> `always_visible`; `position` -> `placement`

* Add DashSlider conditional in componentWillReceiveProps
  • Loading branch information
wbrgss authored Jun 12, 2019
1 parent 5bd6137 commit b72e8b6
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
- Ability to add tooltips to `Slider` and `RangeSlider`, which can be visible always or on hover. Tooltips also take a position argument. [#564](https://github.com/plotly/dash-core-components/pull/564)

### Fixed
- Fixed `min_date_allowed` and `max_date_allowed` bug in `DatePickerRange` [#551]https://github.com/plotly/dash-core-components/issues/551)
- Fixed unwanted `resize()` calls on unmounted `Graph`s [#534](https://github.com/plotly/dash-core-components/issues/534)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"moment": "^2.20.1",
"prop-types": "^15.6.0",
"ramda": "^0.24.1",
"rc-slider": "^8.3.1",
"rc-slider": "^8.6.11",
"react-addons-shallow-compare": "^15.6.0",
"react-dates": "^20.1.0",
"react-docgen": "^3.0.0",
Expand Down
54 changes: 52 additions & 2 deletions src/components/RangeSlider.react.js
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.
Expand All @@ -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;
}

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);
}

Expand All @@ -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}
Expand All @@ -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});
Expand All @@ -58,6 +82,7 @@ export default class RangeSlider extends Component {
setProps({value});
}
}}
tipProps={tipProps}
value={value}
{...omit(
['className', 'value', 'setProps', 'updatemode'],
Expand Down Expand Up @@ -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([
'left',
'right',
'top',
'bottom',
'topLeft',
'topRight',
'bottomLeft',
'bottomRight',
]),
}),

/**
* Value by which increments or decrements are made
*/
Expand Down
54 changes: 52 additions & 2 deletions src/components/Slider.react.js
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]';
Expand All @@ -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);
}

Expand All @@ -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}
Expand All @@ -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});
Expand All @@ -58,6 +82,7 @@ export default class Slider extends Component {
setProps({value});
}
}}
tipProps={tooltip}
value={value}
{...omit(
['className', 'setProps', 'updatemode', 'value'],
Expand Down Expand Up @@ -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
*/
Expand Down

0 comments on commit b72e8b6

Please sign in to comment.