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

Commit

Permalink
Merge pull request #888 from almarklein/drag_value2
Browse files Browse the repository at this point in the history
Adding drag_value to Slider
  • Loading branch information
alexcjohnson authored Dec 14, 2020
2 parents fdb511f + 6c9bcda commit 7477eeb
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 44 deletions.
21 changes: 13 additions & 8 deletions src/components/RangeSlider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ RangeSlider.propTypes = {
*/
value: PropTypes.arrayOf(PropTypes.number),

/**
* The value of the input during a drag
*/
drag_value: PropTypes.arrayOf(PropTypes.number),

/**
* allowCross could be set as true to allow those handles to cross.
*/
Expand Down Expand Up @@ -145,18 +150,18 @@ RangeSlider.propTypes = {
verticalHeight: PropTypes.number,

/**
* Determines when the component should update
* its value. If `mouseup`, then the slider
* will only trigger its value when the user has
* finished dragging the slider. If `drag`, then
* the slider will update its value continuously
* as it is being dragged.
* Only use `drag` if your updates are fast.
* Determines when the component should update its `value`
* property. If `mouseup` (the default) then the slider
* will only trigger its value when the user has finished
* dragging the slider. If `drag`, then the slider will
* update its value continuously as it is being dragged.
* Note that for the latter case, the `drag_value`
* property could be used instead.
*/
updatemode: PropTypes.oneOf(['mouseup', 'drag']),

/**
* Dash-assigned callback that gets fired when the value changes.
* Dash-assigned callback that gets fired when the value or drag_value changes.
*/
setProps: PropTypes.func,

Expand Down
22 changes: 14 additions & 8 deletions src/components/Slider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ Slider.propTypes = {
*/
value: PropTypes.number,

/**
* The value of the input during a drag
*/
drag_value: PropTypes.number,

/**
* Additional CSS class for the root DOM node
*/
Expand Down Expand Up @@ -125,18 +130,19 @@ Slider.propTypes = {
verticalHeight: PropTypes.number,

/**
* Determines when the component should update
* its value. If `mouseup`, then the slider
* will only trigger its value when the user has
* finished dragging the slider. If `drag`, then
* the slider will update its value continuously
* as it is being dragged.
* Only use `drag` if your updates are fast.
* Determines when the component should update its `value`
* property. If `mouseup` (the default) then the slider
* will only trigger its value when the user has finished
* dragging the slider. If `drag`, then the slider will
* update its value continuously as it is being dragged.
* If you want different actions during and after drag,
* leave `updatemode` as `mouseup` and use `drag_value`
* for the continuously updating value.
*/
updatemode: PropTypes.oneOf(['mouseup', 'drag']),

/**
* Dash-assigned callback that gets fired when the value changes.
* Dash-assigned callback that gets fired when the value or drag_value changes.
*/
setProps: PropTypes.func,

Expand Down
27 changes: 13 additions & 14 deletions src/fragments/RangeSlider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,11 @@ import {propTypes, defaultProps} from '../components/RangeSlider.react';
export default class RangeSlider extends Component {
constructor(props) {
super(props);
this.propsToState = this.propsToState.bind(this);
this.DashSlider = props.tooltip
? createSliderWithTooltip(Range)
: Range;
this._computeStyle = computeSliderStyle();
this.state = {
value: props.value,
};
}

propsToState(newProps) {
if (newProps.value !== this.props.value) {
this.setState({value: newProps.value});
}
this.state = {value: props.value};
}

UNSAFE_componentWillReceiveProps(newProps) {
Expand All @@ -32,11 +23,17 @@ export default class RangeSlider extends Component {
? createSliderWithTooltip(Range)
: Range;
}
this.propsToState(newProps);
if (newProps.value !== this.props.value) {
this.props.setProps({drag_value: newProps.value});
this.setState({value: newProps.value});
}
}

UNSAFE_componentWillMount() {
this.propsToState(this.props);
if (this.props.value !== null) {
this.props.setProps({drag_value: this.props.value});
this.setState({value: this.props.value});
}
}

render() {
Expand Down Expand Up @@ -84,9 +81,10 @@ export default class RangeSlider extends Component {
<this.DashSlider
onChange={value => {
if (updatemode === 'drag') {
setProps({value});
setProps({value: value, drag_value: value});
} else {
this.setState({value});
this.setState({value: value});
setProps({drag_value: value});
}
}}
onAfterChange={value => {
Expand All @@ -101,6 +99,7 @@ export default class RangeSlider extends Component {
[
'className',
'value',
'drag_value',
'setProps',
'marks',
'updatemode',
Expand Down
27 changes: 13 additions & 14 deletions src/fragments/Slider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,11 @@ import {propTypes, defaultProps} from '../components/Slider.react';
export default class Slider extends Component {
constructor(props) {
super(props);
this.propsToState = this.propsToState.bind(this);
this.DashSlider = props.tooltip
? createSliderWithTooltip(ReactSlider)
: ReactSlider;
this._computeStyle = computeSliderStyle();
this.state = {
value: props.value,
};
}

propsToState(newProps) {
if (newProps.value !== this.props.value) {
this.setState({value: newProps.value});
}
this.state = {value: props.value};
}

UNSAFE_componentWillReceiveProps(newProps) {
Expand All @@ -35,11 +26,17 @@ export default class Slider extends Component {
? createSliderWithTooltip(ReactSlider)
: ReactSlider;
}
this.propsToState(newProps);
if (newProps.value !== this.props.value) {
this.props.setProps({drag_value: newProps.value});
this.setState({value: newProps.value});
}
}

UNSAFE_componentWillMount() {
this.propsToState(this.props);
if (this.props.value !== null) {
this.props.setProps({drag_value: this.props.value});
this.setState({value: this.props.value});
}
}

render() {
Expand Down Expand Up @@ -87,9 +84,10 @@ export default class Slider extends Component {
<this.DashSlider
onChange={value => {
if (updatemode === 'drag') {
setProps({value});
setProps({value: value, drag_value: value});
} else {
this.setState({value});
this.setState({value: value});
setProps({drag_value: value});
}
}}
onAfterChange={value => {
Expand All @@ -114,6 +112,7 @@ export default class Slider extends Component {
'setProps',
'updatemode',
'value',
'drag_value',
'marks',
'verticalHeight',
],
Expand Down
18 changes: 18 additions & 0 deletions tests/dash_core_components_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -100,3 +101,20 @@ def _wait_until_day_is_clickable(self, timeout=1):
@property
def date_picker_day_locator(self):
return 'div[data-visible="true"] td.CalendarDay'

def click_and_hold_at_coord_fractions(self, elem_or_selector, fx, fy):
elem = self._get_element(elem_or_selector)

ActionChains(self.driver).move_to_element_with_offset(
elem, elem.size["width"] * fx, elem.size["height"] * fy
).click_and_hold().perform()

def move_to_coord_fractions(self, elem_or_selector, fx, fy):
elem = self._get_element(elem_or_selector)

ActionChains(self.driver).move_to_element_with_offset(
elem, elem.size["width"] * fx, elem.size["height"] * fy
).perform()

def release(self):
ActionChains(self.driver).release().perform()
81 changes: 81 additions & 0 deletions tests/integration/sliders/test_sliders.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,84 @@ def test_slsl005_slider_tooltip(dash_dcc):
dash_dcc.percy_snapshot(
"slider-make sure tooltips are only visible if parent slider is visible"
)


def test_slsl006_drag_value_slider(dash_dcc):
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Slider(
id="slider",
min=0,
max=20,
step=1,
value=5,
tooltip={"always_visible": True},
),
html.Div(id="out-value"),
html.Div(id="out-drag-value"),
]
)

@app.callback(Output("out-drag-value", "children"), [Input("slider", "drag_value")])
def update_output(value):
return "You have dragged {}".format(value)

@app.callback(Output("out-value", "children"), [Input("slider", "value")])
def update_output(value):
return "You have selected {}".format(value)

dash_dcc.start_server(app)
slider = dash_dcc.find_element("#slider")

dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5")
dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 5")

dash_dcc.click_and_hold_at_coord_fractions(slider, 0.25, 0.25)
dash_dcc.move_to_coord_fractions(slider, 0.75, 0.25)
dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 15")
dash_dcc.move_to_coord_fractions(slider, 0.5, 0.25)
dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 10")
dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5")
dash_dcc.release()
dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 10")


def test_slsl007_drag_value_rangeslider(dash_dcc):
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.RangeSlider(
id="slider",
min=0,
max=20,
step=1,
value=(5, 15),
tooltip={"always_visible": True},
),
html.Div(id="out-value"),
html.Div(id="out-drag-value"),
]
)

@app.callback(Output("out-drag-value", "children"), [Input("slider", "drag_value")])
def update_output(value):
value = value or (None, None)
return "You have dragged {}-{}".format(*value)

@app.callback(Output("out-value", "children"), [Input("slider", "value")])
def update_output(value):
return "You have selected {}-{}".format(*value)

dash_dcc.start_server(app)
slider = dash_dcc.find_element("#slider")

dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5-15")
dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 5-15")

dash_dcc.click_and_hold_at_coord_fractions(slider, 0.25, 0.25)
dash_dcc.move_to_coord_fractions(slider, 0.5, 0.25)
dash_dcc.wait_for_text_to_equal("#out-drag-value", "You have dragged 10-15")
dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 5-15")
dash_dcc.release()
dash_dcc.wait_for_text_to_equal("#out-value", "You have selected 10-15")

0 comments on commit 7477eeb

Please sign in to comment.