@moises.ai/design-system 4.18.1 → 4.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,9 @@ export const PanControl = ({
22
22
  disabled,
23
23
  minValue = -0.65,
24
24
  maxValue = 0.65,
25
+ showTooltip = true,
26
+ tooltipDelayDuration = 0,
27
+ tooltipCloseDelay = 500,
25
28
  }) => {
26
29
  const containerRef = useRef(null)
27
30
  const [isDragging, setIsDragging] = useState(false)
@@ -30,17 +33,31 @@ export const PanControl = ({
30
33
  const startYRef = useRef(0)
31
34
  const pendingNormRef = useRef(value)
32
35
  const rafRef = useRef(0)
36
+ const openTimeoutRef = useRef(null)
37
+ const closeTimeoutRef = useRef(null)
38
+ const tooltipTimingRef = useRef({
39
+ tooltipDelayDuration,
40
+ tooltipCloseDelay,
41
+ })
42
+ tooltipTimingRef.current = { tooltipDelayDuration, tooltipCloseDelay }
33
43
 
34
44
  const [knobFocused, setKnobFocused] = useState(false)
35
- const [hoverOpen, setHoverOpen] = useState(false)
45
+ const [isHovering, setIsHovering] = useState(false)
36
46
 
37
47
  useEffect(() => {
38
48
  if (disabled) {
39
- setHoverOpen(false)
49
+ setIsHovering(false)
40
50
  setKnobFocused(false)
41
51
  }
42
52
  }, [disabled])
43
53
 
54
+ useEffect(() => {
55
+ return () => {
56
+ if (openTimeoutRef.current != null) clearTimeout(openTimeoutRef.current)
57
+ if (closeTimeoutRef.current != null) clearTimeout(closeTimeoutRef.current)
58
+ }
59
+ }, [])
60
+
44
61
  useEffect(() => {
45
62
  if (isDragging) {
46
63
  const style = document.createElement('style')
@@ -187,8 +204,107 @@ export const PanControl = ({
187
204
  const displayNorm = clampNorm(denormalize(value, minValue, maxValue))
188
205
  const ariaPanPct = Math.round(displayNorm * 100)
189
206
 
207
+ const clearOpenTimeout = () => {
208
+ if (openTimeoutRef.current != null) {
209
+ clearTimeout(openTimeoutRef.current)
210
+ openTimeoutRef.current = null
211
+ }
212
+ }
213
+
214
+ const clearCloseTimeout = () => {
215
+ if (closeTimeoutRef.current != null) {
216
+ clearTimeout(closeTimeoutRef.current)
217
+ closeTimeoutRef.current = null
218
+ }
219
+ }
220
+
221
+ const handlePointerEnter = () => {
222
+ if (disabled) return
223
+ clearCloseTimeout()
224
+ clearOpenTimeout()
225
+ const { tooltipDelayDuration: delay } = tooltipTimingRef.current
226
+ if (delay <= 0) {
227
+ setIsHovering(true)
228
+ return
229
+ }
230
+ openTimeoutRef.current = setTimeout(() => {
231
+ openTimeoutRef.current = null
232
+ setIsHovering(true)
233
+ }, delay)
234
+ }
235
+
236
+ const handlePointerLeave = () => {
237
+ clearOpenTimeout()
238
+ const { tooltipCloseDelay: delay } = tooltipTimingRef.current
239
+ if (delay <= 0) {
240
+ setIsHovering(false)
241
+ return
242
+ }
243
+ closeTimeoutRef.current = setTimeout(() => {
244
+ closeTimeoutRef.current = null
245
+ setIsHovering(false)
246
+ }, delay)
247
+ }
248
+
190
249
  const tooltipOpen =
191
- !disabled && (isDragging || knobFocused || hoverOpen)
250
+ !disabled && (isDragging || knobFocused || isHovering)
251
+
252
+ const pan = (
253
+ <div
254
+ role="slider"
255
+ tabIndex={disabled ? -1 : 0}
256
+ aria-label="Pan"
257
+ aria-valuemin={-100}
258
+ aria-valuemax={100}
259
+ aria-valuenow={ariaPanPct}
260
+ aria-valuetext={panValueText}
261
+ aria-disabled={disabled}
262
+ className={classNames(
263
+ styles.pan,
264
+ isDragging && styles.active,
265
+ disabled && styles.disabled,
266
+ )}
267
+ onPointerDown={onPointerDown}
268
+ onPointerMove={onPointerMove}
269
+ onPointerUp={onPointerUp}
270
+ onPointerCancel={onPointerUp}
271
+ onPointerEnter={handlePointerEnter}
272
+ onPointerLeave={handlePointerLeave}
273
+ onFocus={() => setKnobFocused(true)}
274
+ onBlur={() => setKnobFocused(false)}
275
+ onKeyDown={handleKnobKeyDown}
276
+ >
277
+ <svg width={20} height={20} viewBox="0 0 20 20" fill="none">
278
+ <circle cx={KNOB_CENTER_X} cy={KNOB_CENTER_Y} r={10} />
279
+ <circle
280
+ cx={KNOB_CENTER_X}
281
+ cy={KNOB_CENTER_Y}
282
+ r={KNOB_RADIUS}
283
+ stroke="#D3EDF8"
284
+ strokeOpacity={0.113725}
285
+ />
286
+ {value !== 0 && (
287
+ <path
288
+ d={arcPath}
289
+ stroke={arcColor}
290
+ strokeLinecap="round"
291
+ strokeWidth={1}
292
+ fill="none"
293
+ />
294
+ )}
295
+ <g
296
+ transform={`rotate(${pointerRotation} ${KNOB_CENTER_X} ${KNOB_CENTER_Y})`}
297
+ >
298
+ <path
299
+ d="M10 0.5 L10 6"
300
+ stroke={pointerColor}
301
+ strokeLinecap="round"
302
+ strokeWidth={1}
303
+ />
304
+ </g>
305
+ </svg>
306
+ </div>
307
+ )
192
308
 
193
309
  return (
194
310
  <div
@@ -198,70 +314,20 @@ export const PanControl = ({
198
314
  onClick={handleClick}
199
315
  style={{ cursor: disabled ? 'default' : 'ns-resize' }}
200
316
  >
201
- <Tooltip
202
- content={panValueText}
203
- open={tooltipOpen}
204
- onOpenChange={(next) => {
205
- if (!disabled) setHoverOpen(next)
206
- }}
207
- side="bottom"
208
- align="center"
209
- sideOffset={3}
210
- delayDuration={0}
211
- >
212
- <div
213
- role="slider"
214
- tabIndex={disabled ? -1 : 0}
215
- aria-label="Pan"
216
- aria-valuemin={-100}
217
- aria-valuemax={100}
218
- aria-valuenow={ariaPanPct}
219
- aria-valuetext={panValueText}
220
- aria-disabled={disabled}
221
- className={classNames(
222
- styles.pan,
223
- isDragging && styles.active,
224
- disabled && styles.disabled,
225
- )}
226
- onPointerDown={onPointerDown}
227
- onPointerMove={onPointerMove}
228
- onPointerUp={onPointerUp}
229
- onPointerCancel={onPointerUp}
230
- onFocus={() => setKnobFocused(true)}
231
- onBlur={() => setKnobFocused(false)}
232
- onKeyDown={handleKnobKeyDown}
317
+ {showTooltip ? (
318
+ <Tooltip
319
+ content={panValueText}
320
+ open={tooltipOpen}
321
+ delayDuration={tooltipDelayDuration}
322
+ side="bottom"
323
+ align="center"
324
+ sideOffset={3}
233
325
  >
234
- <svg width={20} height={20} viewBox="0 0 20 20" fill="none">
235
- <circle cx={KNOB_CENTER_X} cy={KNOB_CENTER_Y} r={10} />
236
- <circle
237
- cx={KNOB_CENTER_X}
238
- cy={KNOB_CENTER_Y}
239
- r={KNOB_RADIUS}
240
- stroke="#D3EDF8"
241
- strokeOpacity={0.113725}
242
- />
243
- {value !== 0 && (
244
- <path
245
- d={arcPath}
246
- stroke={arcColor}
247
- strokeLinecap="round"
248
- strokeWidth={1}
249
- fill="none"
250
- />
251
- )}
252
- <g
253
- transform={`rotate(${pointerRotation} ${KNOB_CENTER_X} ${KNOB_CENTER_Y})`}
254
- >
255
- <path
256
- d="M10 0.5 L10 6"
257
- stroke={pointerColor}
258
- strokeLinecap="round"
259
- strokeWidth={1}
260
- />
261
- </g>
262
- </svg>
263
- </div>
264
- </Tooltip>
326
+ {pan}
327
+ </Tooltip>
328
+ ) : (
329
+ pan
330
+ )}
265
331
  </div>
266
332
  )
267
333
  }
@@ -1,6 +1,6 @@
1
1
  import { PanControl } from './PanControl'
2
2
  import { useState } from 'react'
3
- import { Flex } from '@radix-ui/themes'
3
+ import { Flex, Text } from '@radix-ui/themes'
4
4
 
5
5
  export default {
6
6
  title: 'Components/PanControl',
@@ -20,13 +20,24 @@ export default {
20
20
  ' <PanControl\n' +
21
21
  ' value={panValue}\n' +
22
22
  ' onChange={setPanValue}\n' +
23
+ ' tooltipDelayDuration={0}\n' +
24
+ ' tooltipCloseDelay={500}\n' +
23
25
  ' />\n' +
24
26
  ' )\n' +
25
27
  '}\n' +
26
- '```',
28
+ '```\n\n' +
29
+ '## Tooltip\n\n' +
30
+ 'Shows the current pan value on hover/focus/drag. Use `tooltipDelayDuration` and `tooltipCloseDelay` to control open/close timing, or `showTooltip={false}` to hide it.',
27
31
  },
28
32
  },
29
33
  },
34
+ args: {
35
+ showTooltip: true,
36
+ tooltipDelayDuration: 0,
37
+ tooltipCloseDelay: 500,
38
+ minValue: -0.65,
39
+ maxValue: 0.65,
40
+ },
30
41
  argTypes: {
31
42
  value: {
32
43
  description:
@@ -75,15 +86,35 @@ export default {
75
86
  defaultValue: { summary: 0.65 },
76
87
  },
77
88
  },
89
+ showTooltip: {
90
+ control: 'boolean',
91
+ description: 'Shows the pan value tooltip on hover/focus/drag',
92
+ table: {
93
+ type: { summary: 'boolean' },
94
+ defaultValue: { summary: true },
95
+ },
96
+ },
97
+ tooltipDelayDuration: {
98
+ control: 'number',
99
+ description: 'Ms before the tooltip opens on hover',
100
+ table: {
101
+ type: { summary: 'number' },
102
+ defaultValue: { summary: 0 },
103
+ },
104
+ },
105
+ tooltipCloseDelay: {
106
+ control: 'number',
107
+ description: 'Ms the tooltip stays open after the pointer leaves',
108
+ table: {
109
+ type: { summary: 'number' },
110
+ defaultValue: { summary: 500 },
111
+ },
112
+ },
78
113
  },
79
114
  tags: ['autodocs'],
80
115
  }
81
116
 
82
117
  export const Default = {
83
- args: {
84
- minValue: -0.65,
85
- maxValue: 0.65,
86
- },
87
118
  render: (args) => {
88
119
  const [value, setValue] = useState(0)
89
120
  return <PanControl {...args} value={value} onChange={setValue} />
@@ -98,3 +129,41 @@ export const Disabled = {
98
129
  )
99
130
  },
100
131
  }
132
+
133
+ export const WithoutTooltip = {
134
+ args: {
135
+ showTooltip: false,
136
+ },
137
+ render: (args) => {
138
+ const [value, setValue] = useState(0)
139
+ return <PanControl {...args} value={value} onChange={setValue} />
140
+ },
141
+ }
142
+
143
+ export const TooltipTiming = {
144
+ name: 'Tooltip timing',
145
+ args: {
146
+ tooltipDelayDuration: 200,
147
+ tooltipCloseDelay: 500,
148
+ },
149
+ render: (args) => {
150
+ const [value, setValue] = useState(0)
151
+ return (
152
+ <Flex direction="column" align="center" gap="2">
153
+ <PanControl {...args} value={value} onChange={setValue} />
154
+ <Text size="1" color="gray">
155
+ Opens after {args.tooltipDelayDuration}ms · closes{' '}
156
+ {args.tooltipCloseDelay}ms after leave
157
+ </Text>
158
+ </Flex>
159
+ )
160
+ },
161
+ parameters: {
162
+ docs: {
163
+ description: {
164
+ story:
165
+ 'Adjust `tooltipDelayDuration` (open) and `tooltipCloseDelay` (close grace) via controls.',
166
+ },
167
+ },
168
+ },
169
+ }
@@ -1,16 +1,17 @@
1
- import { Flex, Text } from '@radix-ui/themes'
2
- import { useCallback, useContext, useMemo, useState } from 'react'
1
+ import { Flex, Text, Spinner } from '@radix-ui/themes'
2
+ import { useCallback, useContext, useEffect, useMemo, useState } from 'react'
3
3
  import { ArrowLeftIcon } from '../../../icons'
4
4
  import { ProjectsListContext } from '../context'
5
5
  import { NumberPicker } from '../../NumberPicker/NumberPicker'
6
6
  import { UserIcon } from '../../../icons'
7
+ import { Button } from '../../Button/Button'
7
8
  import styles from './ProjectTrackVoice.module.css'
8
9
 
9
10
  const ProjectTrackVoice = ({
10
11
  ...props
11
12
  }) => {
12
13
  const { onClickTrack } = useContext(ProjectsListContext)
13
- const { projectId, id, title, cover, transfers, audioUrl, onChangeTransfer } = props
14
+ const { projectId, id, title, cover, transfers, audioUrl, onChangeTransfer, loading: _loading } = props
14
15
 
15
16
  const hasTransfers = useMemo(() => transfers && transfers.length > 0, [transfers])
16
17
 
@@ -18,6 +19,12 @@ const ProjectTrackVoice = ({
18
19
  const min = useMemo(() => hasTransfers ? Math.min(...transfers?.map((transfer) => parseInt(transfer.pitchShift))) : 0, [transfers])
19
20
  const max = useMemo(() => hasTransfers ? Math.max(...transfers?.map((transfer) => parseInt(transfer.pitchShift))) : 0, [transfers])
20
21
 
22
+ const [loading, setLoading] = useState(_loading)
23
+
24
+ useEffect(() => {
25
+ setLoading(_loading)
26
+ }, [_loading])
27
+
21
28
  const getAudioUrl = useCallback((pitchShift) => {
22
29
  return hasTransfers ? transfers?.find((transfer) => parseInt(transfer.pitchShift) === pitchShift)?.audioUrl : audioUrl
23
30
  }, [hasTransfers, transfers, audioUrl])
@@ -33,20 +40,32 @@ const ProjectTrackVoice = ({
33
40
 
34
41
  const handleClickTrack = useCallback((e) => {
35
42
  e.stopPropagation()
43
+
44
+ if (loading) {
45
+ return
46
+ }
47
+
48
+ const processTrack = (!hasTransfers && !audioUrl)
49
+
50
+ if (processTrack) {
51
+ setLoading(true)
52
+ }
53
+
36
54
  onClickTrack?.({
37
55
  ...props,
38
56
  id,
39
57
  title,
40
- audioUrl: getAudioUrl(pitchShiftSelected),
58
+ audioUrl: hasTransfers || audioUrl ? getAudioUrl(pitchShiftSelected) : null,
59
+ processTrack,
41
60
  })
42
- }, [onClickTrack, props, id, title, getAudioUrl, pitchShiftSelected])
61
+ }, [onClickTrack, props, id, title, getAudioUrl, pitchShiftSelected, hasTransfers, loading, audioUrl])
43
62
 
44
63
  return (
45
64
  <Flex direction="column" gap="1">
46
65
  <Flex
47
66
  direction="row"
48
67
  gap="3"
49
- className={styles.itemTrack}
68
+ className={`${styles.itemTrack} ${(!hasTransfers && !audioUrl) || loading ? styles.disabledHover : ''}`}
50
69
  onClick={handleClickTrack}
51
70
  >
52
71
  <div className={styles.cover}>
@@ -73,12 +92,24 @@ const ProjectTrackVoice = ({
73
92
  </Text>
74
93
  </Flex>
75
94
 
76
- <NumberPicker
77
- min={min}
78
- max={max}
79
- value={pitchShiftSelected}
80
- onChange={handleChangeTransfer}
81
- />
95
+ {!hasTransfers && !audioUrl && !loading ? (
96
+ <Flex align="center" justify="center" p="2">
97
+ <Button variant="soft" color="gray" size="1">
98
+ Process
99
+ </Button>
100
+ </Flex>
101
+ ) : loading ? (
102
+ <Flex align="center" justify="center" p="2">
103
+ <Spinner />
104
+ </Flex>
105
+ ) : (
106
+ <NumberPicker
107
+ min={min}
108
+ max={max}
109
+ value={pitchShiftSelected}
110
+ onChange={handleChangeTransfer}
111
+ />
112
+ )}
82
113
  </Flex>
83
114
  </Flex>
84
115
  )
@@ -1,13 +1,17 @@
1
1
  .itemTrack {
2
- cursor: pointer;
3
2
  border-radius: var(--radius-3);
4
3
  overflow: hidden;
4
+ cursor: default;
5
+
6
+ &:not(.disabledHover) {
7
+ cursor: pointer;
8
+ }
5
9
 
6
10
  .iconArrowLeft {
7
11
  display: none;
8
12
  }
9
13
 
10
- &:hover {
14
+ &:not(.disabledHover):hover {
11
15
  background: var(--neutral-alpha-2);
12
16
  box-shadow: 0 24px 24px -16px rgba(0, 0, 0, 0.40);
13
17
 
@@ -250,3 +250,67 @@ export const WithTrackVoice = {
250
250
  )
251
251
  },
252
252
  }
253
+
254
+ export const WithTrackVoiceStates = {
255
+ args: {
256
+ projects: [{
257
+ "id": "3842c898-9e0c-41e8-8927-7d9f1111111167c50bc6",
258
+ "title": "vocals - Billie Bossa Nova",
259
+ "artist": "Billie Bossa Nova",
260
+ "cover": null,
261
+ "duration": 30.72,
262
+ "type": "voice",
263
+ "tracks": [
264
+ {
265
+ "id": "q8pzli0h38ptcx21q09h2al-0",
266
+ "title": "Joyce",
267
+ "type": "voice",
268
+ "loading": true,
269
+ },
270
+ {
271
+ "id": "q8pzli0h38ptcxq09h2al-0",
272
+ "title": "Ana",
273
+ "type": "voice",
274
+ "cover": "https://picsum.photos/101/101",
275
+ "transfers": [],
276
+ }
277
+ ]
278
+ }],
279
+ onProjectClick: (project, opened) => {
280
+ console.log('project', project)
281
+ console.log('opened', opened)
282
+ },
283
+ onClickTrack: (track) => {
284
+ console.log('track', track)
285
+ },
286
+ onInsertAllTracks: (tracks) => {
287
+ console.log('insert-all-tracks', tracks)
288
+ },
289
+ onChangeTransfer: (projectId, track) => {
290
+ console.log('change-transfer', projectId, track)
291
+ },
292
+ },
293
+ render: (args) => {
294
+ return (
295
+ <Flex width="300px">
296
+ <ProjectsList
297
+ projects={args.projects}
298
+ onClickTrack={args.onClickTrack}
299
+ onInsertAllTracks={args.onInsertAllTracks}
300
+ onProjectClick={args.onProjectClick}
301
+ >
302
+ {({ projectId, tracks }) =>
303
+ tracks.map((track) => (
304
+ <ProjectsList.TrackVoice
305
+ projectId={projectId}
306
+ key={track.id}
307
+ {...track}
308
+ onChangeTransfer={args.onChangeTransfer}
309
+ />
310
+ ))
311
+ }
312
+ </ProjectsList>
313
+ </Flex>
314
+ )
315
+ },
316
+ }
@@ -15,6 +15,10 @@ import styles from './SliderLibrary.module.css'
15
15
  * @property {boolean} [disabled=false] - Disables interaction and dims the slider.
16
16
  * @property {boolean} [showTooltip=true] - Renders the DS Tooltip below the thumb on
17
17
  * hover/focus/drag with the current value.
18
+ * @property {number} [tooltipDelayDuration=0] - Time in ms from hover enter until the
19
+ * tooltip opens. Drag and keyboard focus open immediately.
20
+ * @property {number} [tooltipCloseDelay=500] - Time in ms the tooltip stays open after
21
+ * the pointer leaves the thumb (or re-enters within this window).
18
22
  * @property {(value: number) => React.ReactNode} [formatValue] - Formats the value for
19
23
  * display in the tooltip. Defaults to the raw number.
20
24
  * @property {(value: number) => void} [onThumbDoubleClick] - Fires when the thumb is
@@ -58,6 +62,8 @@ export const SliderLibrary = forwardRef(function SliderLibrary(
58
62
  step = 1,
59
63
  disabled = false,
60
64
  showTooltip = true,
65
+ tooltipDelayDuration = 0,
66
+ tooltipCloseDelay = 500,
61
67
  formatValue,
62
68
  onThumbDoubleClick,
63
69
  className,
@@ -68,6 +74,8 @@ export const SliderLibrary = forwardRef(function SliderLibrary(
68
74
  const ariaLabel = props['aria-label']
69
75
  const internalRef = useRef(null)
70
76
  const lastInteractionRef = useRef(null)
77
+ const openTimeoutRef = useRef(null)
78
+ const closeTimeoutRef = useRef(null)
71
79
  const [keyboardFocus, setKeyboardFocus] = useState(false)
72
80
  const [isHovering, setIsHovering] = useState(false)
73
81
  const [isDragging, setIsDragging] = useState(false)
@@ -75,8 +83,21 @@ export const SliderLibrary = forwardRef(function SliderLibrary(
75
83
  const stateRef = useRef({ value, min, max, step, disabled, onValueChange })
76
84
  stateRef.current = { value, min, max, step, disabled, onValueChange }
77
85
 
86
+ const tooltipTimingRef = useRef({
87
+ tooltipDelayDuration,
88
+ tooltipCloseDelay,
89
+ })
90
+ tooltipTimingRef.current = { tooltipDelayDuration, tooltipCloseDelay }
91
+
78
92
  const wheelRef = useRef({ accum: 0, axis: null, lastTime: 0 })
79
93
 
94
+ useEffect(() => {
95
+ return () => {
96
+ if (openTimeoutRef.current != null) clearTimeout(openTimeoutRef.current)
97
+ if (closeTimeoutRef.current != null) clearTimeout(closeTimeoutRef.current)
98
+ }
99
+ }, [])
100
+
80
101
  useEffect(() => {
81
102
  const onKey = () => {
82
103
  lastInteractionRef.current = 'keyboard'
@@ -181,13 +202,50 @@ export const SliderLibrary = forwardRef(function SliderLibrary(
181
202
  if (!disabled) setIsDragging(true)
182
203
  }
183
204
 
205
+ const clearOpenTimeout = () => {
206
+ if (openTimeoutRef.current != null) {
207
+ clearTimeout(openTimeoutRef.current)
208
+ openTimeoutRef.current = null
209
+ }
210
+ }
211
+
212
+ const clearCloseTimeout = () => {
213
+ if (closeTimeoutRef.current != null) {
214
+ clearTimeout(closeTimeoutRef.current)
215
+ closeTimeoutRef.current = null
216
+ }
217
+ }
218
+
184
219
  const handleThumbFocus = () => {
185
220
  if (lastInteractionRef.current === 'keyboard') setKeyboardFocus(true)
186
221
  }
187
222
  const handleThumbBlur = () => setKeyboardFocus(false)
188
223
  const handleThumbPointerDown = () => setKeyboardFocus(false)
189
- const handleThumbPointerEnter = () => setIsHovering(true)
190
- const handleThumbPointerLeave = () => setIsHovering(false)
224
+ const handleThumbPointerEnter = () => {
225
+ clearCloseTimeout()
226
+ clearOpenTimeout()
227
+ const { tooltipDelayDuration: delay } = tooltipTimingRef.current
228
+ if (delay <= 0) {
229
+ setIsHovering(true)
230
+ return
231
+ }
232
+ openTimeoutRef.current = setTimeout(() => {
233
+ openTimeoutRef.current = null
234
+ setIsHovering(true)
235
+ }, delay)
236
+ }
237
+ const handleThumbPointerLeave = () => {
238
+ clearOpenTimeout()
239
+ const { tooltipCloseDelay: delay } = tooltipTimingRef.current
240
+ if (delay <= 0) {
241
+ setIsHovering(false)
242
+ return
243
+ }
244
+ closeTimeoutRef.current = setTimeout(() => {
245
+ closeTimeoutRef.current = null
246
+ setIsHovering(false)
247
+ }, delay)
248
+ }
191
249
  const handleThumbDoubleClick = () => {
192
250
  if (!disabled) onThumbDoubleClick?.(value)
193
251
  }
@@ -230,7 +288,7 @@ export const SliderLibrary = forwardRef(function SliderLibrary(
230
288
  <Tooltip
231
289
  content={displayValue}
232
290
  open={tooltipOpen}
233
- delayDuration={0}
291
+ delayDuration={tooltipDelayDuration}
234
292
  side="bottom"
235
293
  sideOffset={8}
236
294
  updatePositionStrategy="always"