Skip to content

Commit b660877

Browse files
committed
feat: Add enterDelay and leaveDelay props (#14)
* feat: Add enterDelay and leaveDelay props, #10 * fix: Fix position className assignation, #10
1 parent ece5c6b commit b660877

File tree

6 files changed

+320
-153
lines changed

6 files changed

+320
-153
lines changed

README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ yarn add @untemps/svelte-use-tooltip
4545
position: 'right',
4646
animated: true,
4747
animationEnterClassName: 'tooltip-enter',
48-
animationLeaveClassName: 'tooltip-leave',
48+
animationLeaveClassName: 'tooltip-leave',
49+
enterDelay: 200,
50+
leaveDelay: 400,
4951
disabled: false
5052
}
5153
} class="tooltip__target">
@@ -102,18 +104,20 @@ yarn add @untemps/svelte-use-tooltip
102104

103105
## API
104106

105-
| Props | Type | Default | Description |
106-
| -------------------------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------- |
107-
| `content` | string | null | Text content to display in the tooltip. |
108-
| `contentSelector` | string | null | Selector of the content to display in the tooltip. |
109-
| `contentClone` | boolean | null | Flag to clone the content to display in the tooltip. If false, the content is removed from its previous parent. |
110-
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). |
111-
| `containerClassName` | string | null | Class name to apply to the tooltip container. |
112-
| `position` | string | 'top' | Position of the tooltip. Available values: 'top', 'bottom', 'left', 'right' |
113-
| `animated` | boolean | false | Flag to animate tooltip transitions. |
114-
| `animationEnterClassName` | string | null | Class name to apply to the tooltip enter transition. |
115-
| `animationLeaveClassName` | string | null | Class name to apply to the tooltip leave transition. |
116-
| `disabled` | boolean | false | Flag to disable the tooltip content. |
107+
| Props | Type | Default | Description |
108+
|---------------------------|---------|---------|-----------------------------------------------------------------------------------------------------------------|
109+
| `content` | string | null | Text content to display in the tooltip. |
110+
| `contentSelector` | string | null | Selector of the content to display in the tooltip. |
111+
| `contentClone` | boolean | null | Flag to clone the content to display in the tooltip. If false, the content is removed from its previous parent. |
112+
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). |
113+
| `containerClassName` | string | null | Class name to apply to the tooltip container. |
114+
| `position` | string | 'top' | Position of the tooltip. Available values: 'top', 'bottom', 'left', 'right' |
115+
| `animated` | boolean | false | Flag to animate tooltip transitions. |
116+
| `animationEnterClassName` | string | null | Class name to apply to the tooltip enter transition. |
117+
| `animationLeaveClassName` | string | null | Class name to apply to the tooltip leave transition. |
118+
| `enterDelay` | number | 0 | Delay before showing the tooltip. |
119+
| `leaveDelay` | number | 0 | Delay before hiding the tooltip. |
120+
| `disabled` | boolean | false | Flag to disable the tooltip content. |
117121

118122
### Content Actions
119123

dev/src/App.svelte

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<script>
22
import { useTooltip } from '../../src'
33
4-
let textContent = null
4+
let tooltipTextContent = null
55
let useCustomTooltipClass = false
66
let tooltipPosition = 'top'
77
let isTooltipDisabled = false
88
let animateTooltip = false
99
let useCustomAnimationEnterClass = false
1010
let useCustomAnimationLeaveClass = false
11+
let tooltipEnterDelay = 200
12+
let tooltipLeaveDelay = 200
1113
1214
const _onTooltipClick = (arg) => {
1315
console.log(arg)
@@ -19,8 +21,8 @@
1921
<div
2022
use:useTooltip={{
2123
position: tooltipPosition,
22-
content: textContent,
23-
contentSelector: !textContent?.length ? '.tooltip__content' : null,
24+
content: tooltipTextContent,
25+
contentSelector: !tooltipTextContent?.length ? '.tooltip__content' : null,
2426
contentClone: true,
2527
contentActions: {
2628
'*': {
@@ -31,10 +33,12 @@
3133
},
3234
},
3335
containerClassName: useCustomTooltipClass ? 'tooltip' : null,
34-
disabled: isTooltipDisabled,
3536
animated: animateTooltip,
3637
animationEnterClassName: useCustomAnimationEnterClass ? 'tooltip-enter' : null,
3738
animationLeaveClassName: useCustomAnimationLeaveClass ? 'tooltip-leave' : null,
39+
enterDelay: tooltipEnterDelay,
40+
leaveDelay: tooltipLeaveDelay,
41+
disabled: isTooltipDisabled
3842
}}
3943
class="target"
4044
>
@@ -51,7 +55,7 @@
5155
<fieldset>
5256
<label>
5357
Tooltip Text Content:
54-
<input type="text" bind:value={textContent} />
58+
<input type="text" bind:value={tooltipTextContent} />
5559
</label>
5660
</fieldset>
5761
<fieldset>
@@ -79,16 +83,28 @@
7983
</fieldset>
8084
<fieldset>
8185
<label>
82-
Use Custom Animation Enter Class:
86+
Use Custom Tooltip Animation Enter Class:
8387
<input type="checkbox" bind:checked={useCustomAnimationEnterClass} />
8488
</label>
8589
</fieldset>
8690
<fieldset>
8791
<label>
88-
Use Custom Animation Leave Class:
92+
Use Custom Tooltip Animation Leave Class:
8993
<input type="checkbox" bind:checked={useCustomAnimationLeaveClass} />
9094
</label>
9195
</fieldset>
96+
<fieldset>
97+
<label>
98+
Tooltip Enter Delay (ms):
99+
<input type="number" step={100} min={0} bind:value={tooltipEnterDelay} />
100+
</label>
101+
</fieldset>
102+
<fieldset>
103+
<label>
104+
Tooltip Leave Delay (ms):
105+
<input type="number" step={100} min={0} bind:value={tooltipLeaveDelay} />
106+
</label>
107+
</fieldset>
92108
<fieldset>
93109
<label>
94110
Disable Tooltip:

jest/jest.setup.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import '@testing-library/jest-dom/extend-expect'
33

44
expect.extend({ toBeInTheDocument, toHaveAttribute, toHaveStyle })
55

6-
global._createElement = (id = 'foo', className = 'bar', ariaLabel = 'gag') => {
6+
global._createElement = (id = 'foo', attrs) => {
77
const el = document.createElement('div')
88
el.setAttribute('id', id)
9-
el.setAttribute('class', className)
10-
el.setAttribute('aria-label', ariaLabel)
9+
for (let key in attrs) {
10+
el.setAttribute(key, attrs[key])
11+
}
1112
document.body.appendChild(el)
1213
return el
1314
}

src/Tooltip.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class Tooltip {
99

1010
#observer = null
1111
#events = []
12+
#enterDelay = 0
13+
#leaveDelay = 0
14+
#delay = null
1215

1316
#tooltip = null
1417

@@ -44,25 +47,30 @@ class Tooltip {
4447
animated,
4548
animationEnterClassName,
4649
animationLeaveClassName,
50+
enterDelay,
51+
leaveDelay,
4752
disabled
4853
) {
4954
this.#target = target
5055
this.#content = content
5156
this.#contentSelector = contentSelector
57+
this.#contentClone = contentClone || false
5258
this.#contentActions = contentActions
53-
this.#contentClone = contentClone
5459
this.#containerClassName = containerClassName
55-
this.#position = position
56-
this.#animated = animated
60+
this.#position = position || 'top'
61+
this.#animated = animated || false
5762
this.#animationEnterClassName = animationEnterClassName || '__tooltip-enter'
5863
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
64+
this.#enterDelay = enterDelay || 0
65+
this.#leaveDelay = leaveDelay || 0
5966

6067
this.#observer = new DOMObserver()
6168

6269
this.#target.title = ''
6370
this.#target.setAttribute('style', 'position: relative')
6471

6572
this.#createTooltip()
73+
this.#tooltip.classList.add(this.#containerClassName || '__tooltip', `__tooltip-${this.#position}`)
6674

6775
disabled ? this.#disableTarget() : this.#enableTarget()
6876

@@ -79,31 +87,41 @@ class Tooltip {
7987
animated,
8088
animationEnterClassName,
8189
animationLeaveClassName,
90+
enterDelay,
91+
leaveDelay,
8292
disabled
8393
) {
8494
const hasContentChanged = contentSelector !== this.#contentSelector || content !== this.#content
8595
const hasContainerClassNameChanged = containerClassName !== this.#containerClassName
96+
const oldPosition = this.#position
97+
const hasPositionChanged = position !== this.#position
8698
const hasToDisableTarget = disabled && this.#boundEnterHandler
8799
const hasToEnableTarget = !disabled && !this.#boundEnterHandler
88100

89101
this.#content = content
90102
this.#contentSelector = contentSelector
91-
this.#contentClone = contentClone
103+
this.#contentClone = contentClone || false
92104
this.#contentActions = contentActions
93105
this.#containerClassName = containerClassName
94-
this.#position = position
95-
this.#animated = animated
106+
this.#position = position || 'top'
107+
this.#animated = animated || false
96108
this.#animationEnterClassName = animationEnterClassName || '__tooltip-enter'
97109
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
110+
this.#enterDelay = enterDelay || 0
111+
this.#leaveDelay = leaveDelay || 0
98112

99113
if (hasContentChanged) {
100114
this.#removeTooltipFromTarget()
101-
102115
this.#createTooltip()
103116
}
104117

105118
if (hasContainerClassNameChanged) {
106-
this.#tooltip.className = this.#containerClassName || `__tooltip __tooltip-${this.#position}`
119+
this.#tooltip.classList.add(this.#containerClassName || '__tooltip')
120+
}
121+
122+
if (hasPositionChanged) {
123+
this.#tooltip.classList.remove(`__tooltip-${oldPosition}`)
124+
this.#tooltip.classList.add(`__tooltip-${this.#position}`)
107125
}
108126

109127
if (hasToDisableTarget) {
@@ -118,6 +136,8 @@ class Tooltip {
118136

119137
this.#disableTarget()
120138

139+
this.#clearDelay()
140+
121141
this.#observer?.clear()
122142
this.#observer = null
123143
}
@@ -140,7 +160,6 @@ class Tooltip {
140160

141161
#createTooltip() {
142162
this.#tooltip = document.createElement('div')
143-
this.#tooltip.className = this.#containerClassName || `__tooltip __tooltip-${this.#position}`
144163

145164
if (this.#contentSelector) {
146165
this.#observer
@@ -229,6 +248,22 @@ class Tooltip {
229248
this.#events = []
230249
}
231250

251+
#waitForDelay(delay) {
252+
this.#clearDelay()
253+
return new Promise(
254+
(resolve) =>
255+
(this.#delay = setTimeout(() => {
256+
this.#clearDelay()
257+
resolve()
258+
}, delay))
259+
)
260+
}
261+
262+
#clearDelay() {
263+
clearTimeout(this.#delay)
264+
this.#delay = null
265+
}
266+
232267
#transitionTooltip(direction) {
233268
return new Promise((resolve) => {
234269
let classToAdd, classToRemove
@@ -260,10 +295,12 @@ class Tooltip {
260295
}
261296

262297
async #onTargetEnter() {
298+
await this.#waitForDelay(this.#enterDelay)
263299
await this.#appendTooltipToTarget()
264300
}
265301

266302
async #onTargetLeave() {
303+
await this.#waitForDelay(this.#leaveDelay)
267304
await this.#removeTooltipFromTarget()
268305
}
269306
}

0 commit comments

Comments
 (0)