Skip to content

Commit 9e9ccf9

Browse files
committed
Fix slider tooltip positioning
1 parent e31347c commit 9e9ccf9

File tree

4 files changed

+203
-228
lines changed

4 files changed

+203
-228
lines changed

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.dash-slider-root {
22
position: relative;
3+
z-index: 0;
34
display: flex;
45
align-items: center;
56
user-select: none;
@@ -43,11 +44,6 @@
4344
background-color: var(--Dash-Fill-Interactive-Strong);
4445
}
4546

46-
/* Allow Radix to control range height for multi-thumb sliders */
47-
.dash-range-slider-root .dash-slider-range {
48-
height: 4px;
49-
}
50-
5147
.dash-slider-root[data-orientation='vertical'] .dash-slider-range {
5248
width: 100%;
5349
height: auto;
@@ -72,6 +68,11 @@
7268
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
7369
}
7470

71+
.dash-slider-thumb:focus .dash-slider-tooltip,
72+
.dash-slider-thumb:hover .dash-slider-tooltip {
73+
display: block;
74+
}
75+
7576
.dash-slider-thumb[data-disabled] {
7677
cursor: not-allowed;
7778
opacity: 0.5;
@@ -116,6 +117,8 @@
116117
}
117118

118119
.dash-slider-tooltip {
120+
display: none;
121+
position: absolute;
119122
border-radius: var(--Dash-Spacing);
120123
padding: calc(var(--Dash-Spacing) * 3);
121124
font-size: 12px;
@@ -127,6 +130,10 @@
127130
fill: var(--Dash-Fill-Inverse-Strong);
128131
}
129132

133+
.dash-slider-tooltip.always-visible {
134+
display: block;
135+
}
136+
130137
/* Include property to mimic rc-slider behavior */
131138
.dash-slider-root:not([data-included='false']) .dash-slider-range {
132139
background-color: var(--Dash-Fill-Interactive-Strong);
@@ -182,6 +189,7 @@
182189
width: 64px;
183190
margin-top: 8px;
184191
-moz-appearance: textfield;
192+
z-index: -1;
185193
}
186194

187195
/* Hide the number input spinners */

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

Lines changed: 71 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import React, {useEffect, useState, useMemo, useRef} from 'react';
22
import * as RadixSlider from '@radix-ui/react-slider';
3-
import * as Tooltip from '@radix-ui/react-tooltip';
43
import {isNil} from 'ramda';
54

65
import {
76
sanitizeMarks,
87
calcStep,
98
setUndefined,
109
} from '../utils/computeSliderMarkers';
11-
import {
12-
formatSliderTooltip,
13-
transformSliderTooltip,
14-
} from '../utils/formatSliderTooltip';
1510
import {snapToNearestMark} from '../utils/sliderSnapToMark';
1611
import {renderSliderMarks, renderSliderDots} from '../utils/sliderRendering';
1712
import LoadingElement from '../utils/_LoadingElement';
13+
import {Tooltip} from '../utils/sliderTooltip';
1814
import {RangeSliderProps} from '../types';
1915

2016
const MAX_MARKS = 500;
@@ -51,6 +47,7 @@ export default function RangeSlider(props: RangeSliderProps) {
5147
// Track slider dimension (width for horizontal, height for vertical) for conditional input rendering
5248
const [sliderWidth, setSliderWidth] = useState<number | null>(null);
5349
const [showInputs, setShowInputs] = useState<boolean>(value.length === 2);
50+
5451
const sliderRef = useRef<HTMLDivElement>(null);
5552

5653
// Handle initial mount - equivalent to componentWillMount
@@ -178,9 +175,8 @@ export default function RangeSlider(props: RangeSliderProps) {
178175
processedMarks &&
179176
typeof processedMarks === 'object'
180177
) {
181-
adjustedValue = newValue.map(val =>
182-
snapToNearestMark(val, processedMarks)
183-
);
178+
const marks = processedMarks;
179+
adjustedValue = newValue.map(val => snapToNearestMark(val, marks));
184180
}
185181

186182
setValue(adjustedValue);
@@ -197,25 +193,6 @@ export default function RangeSlider(props: RangeSliderProps) {
197193
}
198194
};
199195

200-
// Format tooltip content
201-
const formatTooltipContent = (value: number, index: number) => {
202-
let displayValue: string | number = value;
203-
if (tooltip?.transform) {
204-
displayValue = transformSliderTooltip(tooltip.transform, value);
205-
}
206-
return (
207-
<div
208-
id={`${id}-tooltip-${index + 1}-content`}
209-
style={tooltip?.style}
210-
>
211-
{formatSliderTooltip(
212-
tooltip?.template || '{value}',
213-
displayValue
214-
)}
215-
</div>
216-
);
217-
};
218-
219196
return (
220197
<LoadingElement>
221198
{loadingProps => (
@@ -289,100 +266,73 @@ export default function RangeSlider(props: RangeSliderProps) {
289266
className="dash-slider-wrapper"
290267
onClickCapture={e => e.preventDefault()} // prevent interactions from "clicking" the parent, particularly when slider is inside a label tag
291268
>
292-
<Tooltip.Provider>
293-
<RadixSlider.Root
294-
ref={sliderRef}
295-
className={`dash-slider-root dash-range-slider-root ${
296-
renderedMarks ? 'has-marks' : ''
297-
} ${className || ''}`.trim()}
298-
style={{
299-
position: 'relative',
300-
...(vertical && {
301-
height: `${verticalHeight}px`,
302-
}),
303-
}}
304-
value={value}
305-
onValueChange={handleValueChange}
306-
onValueCommit={handleValueCommit}
307-
min={minMaxValues.min_mark}
308-
max={minMaxValues.max_mark}
309-
step={stepValue}
310-
disabled={disabled}
311-
orientation={
312-
vertical ? 'vertical' : 'horizontal'
313-
}
314-
data-included={included !== false}
315-
minStepsBetweenThumbs={
316-
typeof pushable === 'number'
317-
? pushable
318-
: undefined
319-
}
320-
>
321-
<RadixSlider.Track className="dash-slider-track">
322-
{included !== false && (
323-
<RadixSlider.Range className="dash-slider-range" />
324-
)}
325-
</RadixSlider.Track>
326-
{renderedMarks &&
327-
renderSliderMarks(
328-
renderedMarks,
329-
!!vertical,
330-
minMaxValues,
331-
!!dots
332-
)}
333-
{dots &&
334-
stepValue &&
335-
renderSliderDots(
336-
stepValue,
337-
minMaxValues,
338-
!!vertical
339-
)}
340-
{/* Render thumbs with tooltips for each value */}
341-
{value.map((val, index) => {
342-
const thumbClassName = `dash-slider-thumb dash-slider-thumb-${
343-
index + 1
344-
}`;
345-
346-
return tooltip ? (
347-
<Tooltip.Root
348-
key={index}
349-
open={
350-
tooltip.always_visible ||
351-
undefined
352-
}
353-
>
354-
<Tooltip.Trigger asChild>
355-
<RadixSlider.Thumb
356-
className={thumbClassName}
357-
/>
358-
</Tooltip.Trigger>
359-
<Tooltip.Portal>
360-
<Tooltip.Content
361-
className="dash-slider-tooltip"
362-
side={
363-
vertical
364-
? 'right'
365-
: 'top'
366-
}
367-
align="center"
368-
>
369-
{formatTooltipContent(
370-
val,
371-
index
372-
)}
373-
<Tooltip.Arrow />
374-
</Tooltip.Content>
375-
</Tooltip.Portal>
376-
</Tooltip.Root>
377-
) : (
378-
<RadixSlider.Thumb
379-
key={index}
380-
className={thumbClassName}
381-
/>
382-
);
383-
})}
384-
</RadixSlider.Root>
385-
</Tooltip.Provider>
269+
<RadixSlider.Root
270+
ref={sliderRef}
271+
className={`dash-slider-root ${
272+
renderedMarks ? 'has-marks' : ''
273+
} ${className || ''}`.trim()}
274+
style={{
275+
...(vertical && {
276+
height: `${verticalHeight}px`,
277+
}),
278+
}}
279+
value={value}
280+
onValueChange={handleValueChange}
281+
onValueCommit={handleValueCommit}
282+
min={minMaxValues.min_mark}
283+
max={minMaxValues.max_mark}
284+
step={stepValue}
285+
disabled={disabled}
286+
orientation={vertical ? 'vertical' : 'horizontal'}
287+
data-included={included !== false}
288+
minStepsBetweenThumbs={
289+
typeof pushable === 'number'
290+
? pushable
291+
: undefined
292+
}
293+
>
294+
<RadixSlider.Track className="dash-slider-track">
295+
{included !== false && (
296+
<RadixSlider.Range className="dash-slider-range" />
297+
)}
298+
</RadixSlider.Track>
299+
{renderedMarks &&
300+
renderSliderMarks(
301+
renderedMarks,
302+
!!vertical,
303+
minMaxValues,
304+
!!dots
305+
)}
306+
{dots &&
307+
stepValue &&
308+
renderSliderDots(
309+
stepValue,
310+
minMaxValues,
311+
!!vertical
312+
)}
313+
{/* Render thumbs with tooltips for each value */}
314+
{value.map((val, index) => {
315+
const thumbClassName = `dash-slider-thumb dash-slider-thumb-${
316+
index + 1
317+
}`;
318+
319+
return (
320+
<RadixSlider.Thumb
321+
key={'thumb' + index}
322+
className={thumbClassName}
323+
>
324+
{tooltip && (
325+
<Tooltip
326+
id={id}
327+
index={index}
328+
value={val}
329+
tooltip={tooltip}
330+
/>
331+
)}
332+
</RadixSlider.Thumb>
333+
);
334+
})}
335+
</RadixSlider.Root>
386336
</div>
387337
{showInputs && !vertical && (
388338
<input

0 commit comments

Comments
 (0)