Skip to content

Commit 8cd1946

Browse files
authored
Merge pull request #3444 from plotly/bugfix/slider-bugfixes
dcc redesign: existing component bugfixes
2 parents 1113af6 + 4ed1f65 commit 8cd1946

File tree

4 files changed

+88
-72
lines changed

4 files changed

+88
-72
lines changed

components/dash-core-components/src/components/RangeSlider.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ export default function RangeSlider({
1818
persistence_type = PersistenceTypes.local,
1919
// eslint-disable-next-line no-magic-numbers
2020
verticalHeight = 400,
21-
step = 1,
21+
step = undefined,
2222
...props
2323
}: RangeSliderProps) {
24+
// Some considerations for the default value of `step`:
25+
// If the range consists of integers, default to a value of `1`
26+
// Otherwise, leave it undefined
27+
if (Number.isInteger(props.min) && Number.isInteger(props.max)) {
28+
step = 1;
29+
}
30+
2431
return (
2532
<Suspense fallback={null}>
2633
<RealRangeSlider

components/dash-core-components/src/components/css/sliders.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
}
5151

5252
.dash-slider-thumb {
53+
position: relative;
54+
z-index: 1;
5355
display: block;
5456
width: 16px;
5557
height: 16px;
@@ -185,10 +187,16 @@
185187
min-width: 64px;
186188
}
187189

190+
.dash-range-slider-max-input {
191+
order: 1;
192+
}
193+
188194
.dash-range-slider-input {
189195
width: 64px;
190196
margin-top: 8px;
197+
-webkit-appearance: textfield;
191198
-moz-appearance: textfield;
199+
appearance: textfield;
192200
}
193201

194202
/* Hide the number input spinners */

components/dash-core-components/src/fragments/RangeSlider.tsx

Lines changed: 71 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,77 @@ export default function RangeSlider(props: RangeSliderProps) {
262262
disabled={disabled}
263263
/>
264264
)}
265+
{showInputs && !vertical && (
266+
<input
267+
type="number"
268+
className="dash-input-container dash-range-slider-input dash-range-slider-max-input"
269+
value={value[value.length - 1] ?? ''}
270+
onChange={e => {
271+
const inputValue = e.target.value;
272+
// Allow empty string (user is clearing the field)
273+
if (inputValue === '') {
274+
// Don't update props while user is typing, just update local state
275+
const newValue = [...value];
276+
newValue[newValue.length - 1] = '' as any;
277+
setValue(newValue);
278+
} else {
279+
const newMax = parseFloat(inputValue);
280+
const constrainedMax = Math.max(
281+
minMaxValues.min_mark,
282+
Math.min(minMaxValues.max_mark, newMax)
283+
);
284+
285+
if (newMax === constrainedMax) {
286+
const newValue = [...value];
287+
newValue[newValue.length - 1] = newMax;
288+
setProps({
289+
value: newValue,
290+
drag_value: newValue,
291+
});
292+
}
293+
}
294+
}}
295+
onBlur={e => {
296+
const inputValue = e.target.value;
297+
let newMax: number;
298+
299+
// If empty, default to current value or max_mark
300+
if (inputValue === '') {
301+
newMax =
302+
value[value.length - 1] ??
303+
minMaxValues.max_mark;
304+
} else {
305+
newMax = parseFloat(inputValue);
306+
newMax = isNaN(newMax)
307+
? minMaxValues.max_mark
308+
: newMax;
309+
}
310+
311+
const constrainedMax = Math.min(
312+
minMaxValues.max_mark,
313+
Math.max(
314+
value[0] ?? minMaxValues.min_mark,
315+
newMax
316+
)
317+
);
318+
const newValue = [...value];
319+
newValue[newValue.length - 1] = constrainedMax;
320+
setValue(newValue);
321+
if (updatemode === 'mouseup') {
322+
setProps({value: newValue});
323+
}
324+
}}
325+
pattern="^\\d*\\.?\\d*$"
326+
min={
327+
value.length === 1
328+
? minMaxValues.min_mark
329+
: value[0]
330+
}
331+
max={minMaxValues.max_mark}
332+
step={step || undefined}
333+
disabled={disabled}
334+
/>
335+
)}
265336
<div
266337
className="dash-slider-wrapper"
267338
onClickCapture={e => e.preventDefault()} // prevent interactions from "clicking" the parent, particularly when slider is inside a label tag
@@ -334,77 +405,6 @@ export default function RangeSlider(props: RangeSliderProps) {
334405
})}
335406
</RadixSlider.Root>
336407
</div>
337-
{showInputs && !vertical && (
338-
<input
339-
type="number"
340-
className="dash-input-container dash-range-slider-input"
341-
value={value[value.length - 1] ?? ''}
342-
onChange={e => {
343-
const inputValue = e.target.value;
344-
// Allow empty string (user is clearing the field)
345-
if (inputValue === '') {
346-
// Don't update props while user is typing, just update local state
347-
const newValue = [...value];
348-
newValue[newValue.length - 1] = '' as any;
349-
setValue(newValue);
350-
} else {
351-
const newMax = parseFloat(inputValue);
352-
const constrainedMax = Math.max(
353-
minMaxValues.min_mark,
354-
Math.min(minMaxValues.max_mark, newMax)
355-
);
356-
357-
if (newMax === constrainedMax) {
358-
const newValue = [...value];
359-
newValue[newValue.length - 1] = newMax;
360-
setProps({
361-
value: newValue,
362-
drag_value: newValue,
363-
});
364-
}
365-
}
366-
}}
367-
onBlur={e => {
368-
const inputValue = e.target.value;
369-
let newMax: number;
370-
371-
// If empty, default to current value or max_mark
372-
if (inputValue === '') {
373-
newMax =
374-
value[value.length - 1] ??
375-
minMaxValues.max_mark;
376-
} else {
377-
newMax = parseFloat(inputValue);
378-
newMax = isNaN(newMax)
379-
? minMaxValues.max_mark
380-
: newMax;
381-
}
382-
383-
const constrainedMax = Math.min(
384-
minMaxValues.max_mark,
385-
Math.max(
386-
value[0] ?? minMaxValues.min_mark,
387-
newMax
388-
)
389-
);
390-
const newValue = [...value];
391-
newValue[newValue.length - 1] = constrainedMax;
392-
setValue(newValue);
393-
if (updatemode === 'mouseup') {
394-
setProps({value: newValue});
395-
}
396-
}}
397-
pattern="^\\d*\\.?\\d*$"
398-
min={
399-
value.length === 1
400-
? minMaxValues.min_mark
401-
: value[0]
402-
}
403-
max={minMaxValues.max_mark}
404-
step={step || undefined}
405-
disabled={disabled}
406-
/>
407-
)}
408408
</div>
409409
)}
410410
</LoadingElement>

components/dash-core-components/tests/integration/misc/test_dcc_components_as_props.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def test_mdcap001_dcc_components_as_props(dash_dcc):
5454

5555
search_input = dash_dcc.find_element("#dropdown .dash-dropdown-search")
5656
search_input.send_keys("4")
57+
sleep(0.25)
5758
options = dash_dcc.find_elements("#dropdown .dash-dropdown-option")
5859

5960
wait.until(lambda: len(options) == 1, 1)

0 commit comments

Comments
 (0)