Skip to content

Commit b7183a4

Browse files
committed
update tab order of slider inputs
1 parent 0afeaab commit b7183a4

File tree

2 files changed

+75
-71
lines changed

2 files changed

+75
-71
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@
186186
min-width: 64px;
187187
}
188188

189+
.dash-range-slider-max-input {
190+
order: 1;
191+
}
192+
189193
.dash-range-slider-input {
190194
width: 64px;
191195
margin-top: 8px;

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>

0 commit comments

Comments
 (0)